Merge branch 'master' into feature/clang-formatting
commit
2e84f5174d
|
@ -253,7 +253,7 @@ ELSEIF(MSVC)
|
|||
IF(MSVC12)
|
||||
ADD_COMPILE_OPTIONS(/wd4351)
|
||||
ENDIF()
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /DEBUG:FULL /Zi")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi")
|
||||
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
||||
IF(NOT HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
|
@ -391,6 +391,11 @@ IF(HUNTER_ENABLED)
|
|||
)
|
||||
ELSE(HUNTER_ENABLED)
|
||||
# cmake configuration files
|
||||
if(${BUILD_SHARED_LIBS})
|
||||
set(BUILD_LIB_TYPE SHARED)
|
||||
else()
|
||||
set(BUILD_LIB_TYPE STATIC)
|
||||
endif()
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
|
||||
IF (is_multi_config)
|
||||
|
|
|
@ -14,6 +14,7 @@ matrix:
|
|||
fast_finish: true
|
||||
|
||||
image:
|
||||
- Visual Studio 2013
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
|
@ -29,11 +30,13 @@ install:
|
|||
- set PATH=C:\Ruby24-x64\bin;%PATH%
|
||||
- set CMAKE_DEFINES -DASSIMP_WERROR=ON
|
||||
- if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH%
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" set CMAKE_GENERATOR_NAME=Visual Studio 16 2019
|
||||
- cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" -A %platform% .
|
||||
# Rename sh.exe as sh.exe in PATH interferes with MinGW
|
||||
# Rename sh.exe as sh.exe in PATH interferes with MinGW - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
|
||||
|
||||
- rename "C:\Program Files\Git\usr\bin\sh.exe" "sh2.exe"
|
||||
- set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
|
||||
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe
|
||||
|
|
|
@ -63,10 +63,13 @@ if(MSVC)
|
|||
else()
|
||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
|
||||
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||
if(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
else(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
if(WIN32)
|
||||
# Handle MinGW compiler.
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
elseif(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
else()
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
endif()
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
|
||||
|
|
|
@ -63,10 +63,13 @@ if(MSVC)
|
|||
else()
|
||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
|
||||
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||
if(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
else(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
if(WIN32)
|
||||
# Handle MinGW compiler.
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
elseif(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
else()
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
endif()
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
|
||||
|
|
|
@ -54,11 +54,7 @@ if(_IMPORT_PREFIX STREQUAL "/")
|
|||
endif()
|
||||
|
||||
# Create imported target assimp::assimp
|
||||
if(@BUILD_SHARED_LIBS@)
|
||||
add_library(assimp::assimp SHARED IMPORTED)
|
||||
else()
|
||||
add_library(assimp::assimp STATIC IMPORTED)
|
||||
endif()
|
||||
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
|
||||
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
|
||||
|
|
|
@ -72,7 +72,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
unsigned int idx( NotSet );
|
||||
for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
|
||||
{
|
||||
std::string &s = mScene->mMaterials[i].mName;
|
||||
std::string s = mScene->mMaterials[i].mName;
|
||||
for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
|
||||
*it = static_cast< char >( ::tolower( *it ) );
|
||||
}
|
||||
|
|
|
@ -670,6 +670,8 @@ SET( PostProcessing_SRCS
|
|||
PostProcessing/MakeVerboseFormat.h
|
||||
PostProcessing/ScaleProcess.cpp
|
||||
PostProcessing/ScaleProcess.h
|
||||
PostProcessing/ArmaturePopulate.cpp
|
||||
PostProcessing/ArmaturePopulate.h
|
||||
PostProcessing/GenBoundingBoxesProcess.cpp
|
||||
PostProcessing/GenBoundingBoxesProcess.h
|
||||
)
|
||||
|
|
|
@ -583,7 +583,7 @@ struct Image
|
|||
/** Embedded image data */
|
||||
std::vector<uint8_t> mImageData;
|
||||
|
||||
/** File format hint ofembedded image data */
|
||||
/** File format hint of embedded image data */
|
||||
std::string mEmbeddedFormat;
|
||||
};
|
||||
|
||||
|
|
|
@ -1735,6 +1735,7 @@ void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Resolves the texture name for the given effect texture entry
|
||||
// and loads the texture data
|
||||
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParser,
|
||||
const Collada::Effect& pEffect, const std::string& pName)
|
||||
{
|
||||
|
@ -1762,7 +1763,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
|
||||
//set default texture file name
|
||||
result.Set(name + ".jpg");
|
||||
ConvertPath(result);
|
||||
ColladaParser::UriDecodePath(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1781,7 +1782,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
|
||||
|
||||
// setup format hint
|
||||
if (imIt->second.mEmbeddedFormat.length() > 3) {
|
||||
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
|
||||
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
|
||||
}
|
||||
strncpy(tex->achFormatHint, imIt->second.mEmbeddedFormat.c_str(), 3);
|
||||
|
@ -1802,61 +1803,10 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
|||
}
|
||||
|
||||
result.Set(imIt->second.mFileName);
|
||||
ConvertPath(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a path read from a collada file to the usual representation
|
||||
void ColladaLoader::ConvertPath(aiString& ss)
|
||||
{
|
||||
// TODO: collada spec, p 22. Handle URI correctly.
|
||||
// For the moment we're just stripping the file:// away to make it work.
|
||||
// Windows doesn't seem to be able to find stuff like
|
||||
// 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
|
||||
if (0 == strncmp(ss.data, "file://", 7))
|
||||
{
|
||||
ss.length -= 7;
|
||||
memmove(ss.data, ss.data + 7, ss.length);
|
||||
ss.data[ss.length] = '\0';
|
||||
}
|
||||
|
||||
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
|
||||
// I need to filter it without destroying linux paths starting with "/somewhere"
|
||||
#if defined( _MSC_VER )
|
||||
if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
|
||||
#else
|
||||
if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') {
|
||||
#endif
|
||||
--ss.length;
|
||||
::memmove(ss.data, ss.data + 1, ss.length);
|
||||
ss.data[ss.length] = 0;
|
||||
}
|
||||
|
||||
// find and convert all %xy special chars
|
||||
char* out = ss.data;
|
||||
for (const char* it = ss.data; it != ss.data + ss.length; /**/)
|
||||
{
|
||||
if (*it == '%' && (it + 3) < ss.data + ss.length)
|
||||
{
|
||||
// separate the number to avoid dragging in chars from behind into the parsing
|
||||
char mychar[3] = { it[1], it[2], 0 };
|
||||
size_t nbr = strtoul16(mychar);
|
||||
it += 3;
|
||||
*out++ = (char)(nbr & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = *it++;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust length and terminator of the shortened string
|
||||
*out = 0;
|
||||
ss.length = (ptrdiff_t)(out - ss.data);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a float value from an accessor and its data array.
|
||||
ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
public:
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
|
||||
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
|
||||
|
||||
protected:
|
||||
/** Return importer meta information.
|
||||
|
@ -184,9 +184,6 @@ protected:
|
|||
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
|
||||
const Collada::Effect& pEffect, const std::string& pName);
|
||||
|
||||
/** Converts a path read from a collada file to the usual representation */
|
||||
void ConvertPath( aiString& ss);
|
||||
|
||||
/** Reads a float value from an accessor and its data array.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
|
|
|
@ -183,13 +183,67 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
|
|||
if (filepath == nullptr)
|
||||
return std::string();
|
||||
|
||||
return std::string(filepath);
|
||||
aiString ai_str(filepath);
|
||||
UriDecodePath(ai_str);
|
||||
|
||||
return std::string(ai_str.C_Str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a path read from a collada file to the usual representation
|
||||
void ColladaParser::UriDecodePath(aiString& ss)
|
||||
{
|
||||
// TODO: collada spec, p 22. Handle URI correctly.
|
||||
// For the moment we're just stripping the file:// away to make it work.
|
||||
// Windows doesn't seem to be able to find stuff like
|
||||
// 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
|
||||
if (0 == strncmp(ss.data, "file://", 7))
|
||||
{
|
||||
ss.length -= 7;
|
||||
memmove(ss.data, ss.data + 7, ss.length);
|
||||
ss.data[ss.length] = '\0';
|
||||
}
|
||||
|
||||
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
|
||||
// I need to filter it without destroying linux paths starting with "/somewhere"
|
||||
#if defined( _MSC_VER )
|
||||
if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
|
||||
#else
|
||||
if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') {
|
||||
#endif
|
||||
--ss.length;
|
||||
::memmove(ss.data, ss.data + 1, ss.length);
|
||||
ss.data[ss.length] = 0;
|
||||
}
|
||||
|
||||
// find and convert all %xy special chars
|
||||
char* out = ss.data;
|
||||
for (const char* it = ss.data; it != ss.data + ss.length; /**/)
|
||||
{
|
||||
if (*it == '%' && (it + 3) < ss.data + ss.length)
|
||||
{
|
||||
// separate the number to avoid dragging in chars from behind into the parsing
|
||||
char mychar[3] = { it[1], it[2], 0 };
|
||||
size_t nbr = strtoul16(mychar);
|
||||
it += 3;
|
||||
*out++ = (char)(nbr & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = *it++;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust length and terminator of the shortened string
|
||||
*out = 0;
|
||||
ai_assert(out > ss.data);
|
||||
ss.length = static_cast<ai_uint32>(out - ss.data);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read bool from text contents of current element
|
||||
bool ColladaParser::ReadBoolFromTextContent()
|
||||
|
@ -1120,7 +1174,12 @@ void ColladaParser::ReadImage(Collada::Image& pImage)
|
|||
if (!mReader->isEmptyElement()) {
|
||||
// element content is filename - hopefully
|
||||
const char* sz = TestTextContent();
|
||||
if (sz)pImage.mFileName = sz;
|
||||
if (sz)
|
||||
{
|
||||
aiString filepath(sz);
|
||||
UriDecodePath(filepath);
|
||||
pImage.mFileName = filepath.C_Str();
|
||||
}
|
||||
TestClosing("init_from");
|
||||
}
|
||||
if (!pImage.mFileName.length()) {
|
||||
|
@ -1153,7 +1212,12 @@ void ColladaParser::ReadImage(Collada::Image& pImage)
|
|||
{
|
||||
// element content is filename - hopefully
|
||||
const char* sz = TestTextContent();
|
||||
if (sz)pImage.mFileName = sz;
|
||||
if (sz)
|
||||
{
|
||||
aiString filepath(sz);
|
||||
UriDecodePath(filepath);
|
||||
pImage.mFileName = filepath.C_Str();
|
||||
}
|
||||
TestClosing("ref");
|
||||
}
|
||||
else if (IsElement("hex") && !pImage.mFileName.length())
|
||||
|
@ -3056,7 +3120,7 @@ void ColladaParser::ReadMaterialVertexInputBinding(Collada::SemanticMappingTable
|
|||
}
|
||||
}
|
||||
|
||||
void Assimp::ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive)
|
||||
void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive)
|
||||
{
|
||||
// Attempt to load any undefined Collada::Image in ImageLibrary
|
||||
for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) {
|
||||
|
|
|
@ -66,12 +66,15 @@ namespace Assimp
|
|||
{
|
||||
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);
|
||||
ColladaParser(IOSystem* pIOHandler, const std::string& pFile);
|
||||
|
||||
/** Destructor */
|
||||
~ColladaParser();
|
||||
|
|
|
@ -131,11 +131,15 @@ corresponding preprocessor flag to selectively disable steps.
|
|||
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||
# include "PostProcessing/ScaleProcess.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
|
||||
# include "PostProcessing/ArmaturePopulate.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
|
||||
# include "PostProcessing/GenBoundingBoxesProcess.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -180,6 +184,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
|
|||
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||
out.push_back( new ScaleProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
|
||||
out.push_back( new ArmaturePopulate());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
|
||||
out.push_back( new PretransformVertices());
|
||||
#endif
|
||||
|
|
|
@ -46,8 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/scene.h>
|
||||
#include "ScenePrivate.h"
|
||||
|
||||
static const unsigned int MajorVersion = 5;
|
||||
static const unsigned int MinorVersion = 0;
|
||||
#include "revision.h"
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Legal information string - don't remove this.
|
||||
|
@ -56,9 +55,9 @@ static const char* LEGAL_INFORMATION =
|
|||
"Open Asset Import Library (Assimp).\n"
|
||||
"A free C/C++ library to import various 3D file formats into applications\n\n"
|
||||
|
||||
"(c) 2008-2017, assimp team\n"
|
||||
"(c) 2006-2019, assimp team\n"
|
||||
"License under the terms and conditions of the 3-clause BSD license\n"
|
||||
"http://assimp.sourceforge.net\n"
|
||||
"http://assimp.org\n"
|
||||
;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -70,13 +69,13 @@ ASSIMP_API const char* aiGetLegalString () {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp minor version
|
||||
ASSIMP_API unsigned int aiGetVersionMinor () {
|
||||
return MinorVersion;
|
||||
return VER_MINOR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp major version
|
||||
ASSIMP_API unsigned int aiGetVersionMajor () {
|
||||
return MajorVersion;
|
||||
return VER_MAJOR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -104,9 +103,6 @@ ASSIMP_API unsigned int aiGetCompileFlags () {
|
|||
return flags;
|
||||
}
|
||||
|
||||
// include current build revision, which is even updated from time to time -- :-)
|
||||
#include "revision.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API unsigned int aiGetVersionRevision() {
|
||||
return GitVersion;
|
||||
|
|
|
@ -44,23 +44,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
aiNode::aiNode()
|
||||
: mName("")
|
||||
, mParent(NULL)
|
||||
, mParent(nullptr)
|
||||
, mNumChildren(0)
|
||||
, mChildren(NULL)
|
||||
, mChildren(nullptr)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(NULL)
|
||||
, mMetaData(NULL) {
|
||||
, mMeshes(nullptr)
|
||||
, mMetaData(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
aiNode::aiNode(const std::string& name)
|
||||
: mName(name)
|
||||
, mParent(NULL)
|
||||
, mParent(nullptr)
|
||||
, mNumChildren(0)
|
||||
, mChildren(NULL)
|
||||
, mChildren(nullptr)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(NULL)
|
||||
, mMetaData(NULL) {
|
||||
, mMeshes(nullptr)
|
||||
, mMetaData(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ aiNode::aiNode(const std::string& name)
|
|||
aiNode::~aiNode() {
|
||||
// delete all children recursively
|
||||
// to make sure we won't crash if the data is invalid ...
|
||||
if (mChildren && mNumChildren)
|
||||
if (mNumChildren && mChildren)
|
||||
{
|
||||
for (unsigned int a = 0; a < mNumChildren; a++)
|
||||
delete mChildren[a];
|
||||
|
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_FBX_COMPILECONFIG_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//
|
||||
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||
|
@ -54,16 +55,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# else
|
||||
# define fbx_unordered_map map
|
||||
# define fbx_unordered_multimap multimap
|
||||
# define fbx_unordered_set set
|
||||
# define fbx_unordered_multiset multiset
|
||||
#endif
|
||||
|
||||
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
# if _MSC_VER > 1600
|
||||
# define fbx_unordered_map unordered_map
|
||||
# define fbx_unordered_multimap unordered_multimap
|
||||
# define fbx_unordered_set unordered_set
|
||||
# define fbx_unordered_multiset unordered_multiset
|
||||
# else
|
||||
# define fbx_unordered_map tr1::unordered_map
|
||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||
# define fbx_unordered_set tr1::unordered_set
|
||||
# define fbx_unordered_multiset tr1::unordered_multiset
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -68,7 +68,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdint>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
@ -77,7 +78,7 @@ namespace Assimp {
|
|||
|
||||
#define MAGIC_NODE_TAG "_$AssimpFbx$"
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones )
|
||||
: defaultMaterialIndex()
|
||||
|
@ -96,6 +97,14 @@ namespace Assimp {
|
|||
// populate the node_anim_chain_bits map, which is needed
|
||||
// to determine which nodes need to be generated.
|
||||
ConvertAnimations();
|
||||
// Embedded textures in FBX could be connected to nothing but to itself,
|
||||
// for instance Texture -> Video connection only but not to the main graph,
|
||||
// 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();
|
||||
}
|
||||
ConvertRootNode();
|
||||
|
||||
if (doc.Settings().readAllMaterials) {
|
||||
|
@ -145,7 +154,7 @@ namespace Assimp {
|
|||
out->mRootNode->mName.Set(unique_name);
|
||||
|
||||
// root has ID 0
|
||||
ConvertNodes(0L, *out->mRootNode);
|
||||
ConvertNodes(0L, out->mRootNode, out->mRootNode);
|
||||
}
|
||||
|
||||
static std::string getAncestorBaseName(const aiNode* node)
|
||||
|
@ -179,8 +188,11 @@ namespace Assimp {
|
|||
GetUniqueName(original_name, unique_name);
|
||||
return unique_name;
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) {
|
||||
/// todo: pre-build node hierarchy
|
||||
/// todo: get bone from stack
|
||||
/// todo: make map of aiBone* to aiNode*
|
||||
/// then update convert clusters to the new format
|
||||
void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
|
||||
|
||||
std::vector<aiNode*> nodes;
|
||||
|
@ -191,62 +203,69 @@ namespace Assimp {
|
|||
|
||||
try {
|
||||
for (const Connection* con : conns) {
|
||||
|
||||
// ignore object-property links
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
// really important we document why this is ignored.
|
||||
FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
|
||||
continue; //?
|
||||
}
|
||||
|
||||
// convert connection source object into Object base class
|
||||
const Object* const object = con->SourceObject();
|
||||
if (nullptr == object) {
|
||||
FBXImporter::LogWarn("failed to convert source object for Model link");
|
||||
FBXImporter::LogError("failed to convert source object for Model link");
|
||||
continue;
|
||||
}
|
||||
|
||||
// FBX Model::Cube, Model::Bone001, etc elements
|
||||
// This detects if we can cast the object into this model structure.
|
||||
const Model* const model = dynamic_cast<const Model*>(object);
|
||||
|
||||
if (nullptr != model) {
|
||||
nodes_chain.clear();
|
||||
post_nodes_chain.clear();
|
||||
|
||||
aiMatrix4x4 new_abs_transform = parent_transform;
|
||||
|
||||
std::string unique_name = MakeUniqueNodeName(model, parent);
|
||||
|
||||
aiMatrix4x4 new_abs_transform = parent->mTransformation;
|
||||
std::string node_name = FixNodeName(model->Name());
|
||||
// even though there is only a single input node, the design of
|
||||
// assimp (or rather: the complicated transformation chain that
|
||||
// is employed by fbx) means that we may need multiple aiNode's
|
||||
// to represent a fbx node's transformation.
|
||||
const bool need_additional_node = GenerateTransformationNodeChain(*model, unique_name, nodes_chain, post_nodes_chain);
|
||||
|
||||
|
||||
// generate node transforms - this includes pivot data
|
||||
// if need_additional_node is true then you t
|
||||
const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
|
||||
|
||||
// assert that for the current node we must have at least a single transform
|
||||
ai_assert(nodes_chain.size());
|
||||
|
||||
if (need_additional_node) {
|
||||
nodes_chain.push_back(new aiNode(unique_name));
|
||||
nodes_chain.push_back(new aiNode(node_name));
|
||||
}
|
||||
|
||||
//setup metadata on newest node
|
||||
SetupNodeMetadata(*model, *nodes_chain.back());
|
||||
|
||||
// link all nodes in a row
|
||||
aiNode* last_parent = &parent;
|
||||
for (aiNode* prenode : nodes_chain) {
|
||||
ai_assert(prenode);
|
||||
aiNode* last_parent = parent;
|
||||
for (aiNode* child : nodes_chain) {
|
||||
ai_assert(child);
|
||||
|
||||
if (last_parent != &parent) {
|
||||
if (last_parent != parent) {
|
||||
last_parent->mNumChildren = 1;
|
||||
last_parent->mChildren = new aiNode*[1];
|
||||
last_parent->mChildren[0] = prenode;
|
||||
last_parent->mChildren[0] = child;
|
||||
}
|
||||
|
||||
prenode->mParent = last_parent;
|
||||
last_parent = prenode;
|
||||
child->mParent = last_parent;
|
||||
last_parent = child;
|
||||
|
||||
new_abs_transform *= prenode->mTransformation;
|
||||
new_abs_transform *= child->mTransformation;
|
||||
}
|
||||
|
||||
// attach geometry
|
||||
ConvertModel(*model, *nodes_chain.back(), new_abs_transform);
|
||||
ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
|
||||
|
||||
// check if there will be any child nodes
|
||||
const std::vector<const Connection*>& child_conns
|
||||
|
@ -258,7 +277,7 @@ namespace Assimp {
|
|||
for (aiNode* postnode : post_nodes_chain) {
|
||||
ai_assert(postnode);
|
||||
|
||||
if (last_parent != &parent) {
|
||||
if (last_parent != parent) {
|
||||
last_parent->mNumChildren = 1;
|
||||
last_parent->mChildren = new aiNode*[1];
|
||||
last_parent->mChildren[0] = postnode;
|
||||
|
@ -280,15 +299,15 @@ namespace Assimp {
|
|||
);
|
||||
}
|
||||
|
||||
// attach sub-nodes (if any)
|
||||
ConvertNodes(model->ID(), *last_parent, new_abs_transform);
|
||||
// recursion call - child nodes
|
||||
ConvertNodes(model->ID(), last_parent, root_node);
|
||||
|
||||
if (doc.Settings().readLights) {
|
||||
ConvertLights(*model, unique_name);
|
||||
ConvertLights(*model, node_name);
|
||||
}
|
||||
|
||||
if (doc.Settings().readCameras) {
|
||||
ConvertCameras(*model, unique_name);
|
||||
ConvertCameras(*model, node_name);
|
||||
}
|
||||
|
||||
nodes.push_back(nodes_chain.front());
|
||||
|
@ -297,11 +316,17 @@ namespace Assimp {
|
|||
}
|
||||
|
||||
if (nodes.size()) {
|
||||
parent.mChildren = new aiNode*[nodes.size()]();
|
||||
parent.mNumChildren = static_cast<unsigned int>(nodes.size());
|
||||
parent->mChildren = new aiNode*[nodes.size()]();
|
||||
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
|
||||
|
||||
std::swap_ranges(nodes.begin(), nodes.end(), parent.mChildren);
|
||||
std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->mNumChildren = 0;
|
||||
parent->mChildren = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
catch (std::exception&) {
|
||||
Util::delete_fun<aiNode> deleter;
|
||||
|
@ -803,7 +828,7 @@ namespace Assimp {
|
|||
// 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));
|
||||
//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
|
||||
|
@ -905,7 +930,8 @@ namespace Assimp {
|
|||
}
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform)
|
||||
void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
const std::vector<const Geometry*>& geos = model.GetGeometry();
|
||||
|
||||
|
@ -917,11 +943,12 @@ namespace Assimp {
|
|||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo);
|
||||
const LineGeometry* const line = dynamic_cast<const LineGeometry*>(geo);
|
||||
if (mesh) {
|
||||
const std::vector<unsigned int>& indices = ConvertMesh(*mesh, model, node_global_transform, nd);
|
||||
const std::vector<unsigned int>& indices = ConvertMesh(*mesh, model, parent, root_node,
|
||||
absolute_transform);
|
||||
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
|
||||
}
|
||||
else if (line) {
|
||||
const std::vector<unsigned int>& indices = ConvertLine(*line, model, node_global_transform, nd);
|
||||
const std::vector<unsigned int>& indices = ConvertLine(*line, model, parent, root_node);
|
||||
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
|
||||
}
|
||||
else {
|
||||
|
@ -930,15 +957,16 @@ namespace Assimp {
|
|||
}
|
||||
|
||||
if (meshes.size()) {
|
||||
nd.mMeshes = new unsigned int[meshes.size()]();
|
||||
nd.mNumMeshes = static_cast<unsigned int>(meshes.size());
|
||||
parent->mMeshes = new unsigned int[meshes.size()]();
|
||||
parent->mNumMeshes = static_cast<unsigned int>(meshes.size());
|
||||
|
||||
std::swap_ranges(meshes.begin(), meshes.end(), nd.mMeshes);
|
||||
std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned int> FBXConverter::ConvertMesh(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
std::vector<unsigned int>
|
||||
FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
std::vector<unsigned int> temp;
|
||||
|
||||
|
@ -962,18 +990,18 @@ namespace Assimp {
|
|||
const MatIndexArray::value_type base = mindices[0];
|
||||
for (MatIndexArray::value_type index : mindices) {
|
||||
if (index != base) {
|
||||
return ConvertMeshMultiMaterial(mesh, model, node_global_transform, nd);
|
||||
return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// faster code-path, just copy the data
|
||||
temp.push_back(ConvertMeshSingleMaterial(mesh, model, node_global_transform, nd));
|
||||
temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
|
||||
return temp;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> FBXConverter::ConvertLine(const LineGeometry& line, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
aiNode *parent, aiNode *root_node)
|
||||
{
|
||||
std::vector<unsigned int> temp;
|
||||
|
||||
|
@ -984,7 +1012,7 @@ namespace Assimp {
|
|||
return temp;
|
||||
}
|
||||
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(line, nd);
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(line, root_node);
|
||||
out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
|
||||
// copy vertices
|
||||
|
@ -1019,7 +1047,7 @@ namespace Assimp {
|
|||
return temp;
|
||||
}
|
||||
|
||||
aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode& nd)
|
||||
aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent)
|
||||
{
|
||||
aiMesh* const out_mesh = new aiMesh();
|
||||
meshes.push_back(out_mesh);
|
||||
|
@ -1036,17 +1064,18 @@ namespace Assimp {
|
|||
}
|
||||
else
|
||||
{
|
||||
out_mesh->mName = nd.mName;
|
||||
out_mesh->mName = parent->mName;
|
||||
}
|
||||
|
||||
return out_mesh;
|
||||
}
|
||||
|
||||
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
||||
const aiMatrix4x4 &absolute_transform, aiNode *parent,
|
||||
aiNode *root_node)
|
||||
{
|
||||
const MatIndexArray& mindices = mesh.GetMaterialIndices();
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
|
||||
|
||||
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
||||
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
||||
|
@ -1113,7 +1142,7 @@ namespace Assimp {
|
|||
binormals = &tempBinormals;
|
||||
}
|
||||
else {
|
||||
binormals = NULL;
|
||||
binormals = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1163,8 +1192,9 @@ namespace Assimp {
|
|||
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
|
||||
}
|
||||
|
||||
if (doc.Settings().readWeights && mesh.DeformerSkin() != NULL) {
|
||||
ConvertWeights(out_mesh, model, mesh, node_global_transform, NO_MATERIAL_SEPARATION);
|
||||
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
|
||||
ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
std::vector<aiAnimMesh*> animMeshes;
|
||||
|
@ -1209,8 +1239,10 @@ namespace Assimp {
|
|||
return static_cast<unsigned int>(meshes.size() - 1);
|
||||
}
|
||||
|
||||
std::vector<unsigned int> FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
std::vector<unsigned int>
|
||||
FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent,
|
||||
aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
const MatIndexArray& mindices = mesh.GetMaterialIndices();
|
||||
ai_assert(mindices.size());
|
||||
|
@ -1221,7 +1253,7 @@ namespace Assimp {
|
|||
for (MatIndexArray::value_type index : mindices) {
|
||||
if (had.find(index) == had.end()) {
|
||||
|
||||
indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, node_global_transform, nd));
|
||||
indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform));
|
||||
had.insert(index);
|
||||
}
|
||||
}
|
||||
|
@ -1229,18 +1261,18 @@ namespace Assimp {
|
|||
return indices;
|
||||
}
|
||||
|
||||
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
MatIndexArray::value_type index,
|
||||
const aiMatrix4x4& node_global_transform,
|
||||
aiNode& nd)
|
||||
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model,
|
||||
MatIndexArray::value_type index,
|
||||
aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
|
||||
|
||||
const MatIndexArray& mindices = mesh.GetMaterialIndices();
|
||||
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
||||
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
||||
|
||||
const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != NULL;
|
||||
const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr;
|
||||
|
||||
unsigned int count_faces = 0;
|
||||
unsigned int count_vertices = 0;
|
||||
|
@ -1300,7 +1332,7 @@ namespace Assimp {
|
|||
binormals = &tempBinormals;
|
||||
}
|
||||
else {
|
||||
binormals = NULL;
|
||||
binormals = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1399,7 +1431,7 @@ namespace Assimp {
|
|||
ConvertMaterialForMesh(out_mesh, model, mesh, index);
|
||||
|
||||
if (process_weights) {
|
||||
ConvertWeights(out_mesh, model, mesh, node_global_transform, index, &reverseMapping);
|
||||
ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, index, &reverseMapping);
|
||||
}
|
||||
|
||||
std::vector<aiAnimMesh*> animMeshes;
|
||||
|
@ -1449,10 +1481,10 @@ namespace Assimp {
|
|||
return static_cast<unsigned int>(meshes.size() - 1);
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
const aiMatrix4x4& node_global_transform,
|
||||
unsigned int materialIndex,
|
||||
std::vector<unsigned int>* outputVertStartIndices)
|
||||
void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo,
|
||||
const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, aiNode *root_node, unsigned int materialIndex,
|
||||
std::vector<unsigned int> *outputVertStartIndices)
|
||||
{
|
||||
ai_assert(geo.DeformerSkin());
|
||||
|
||||
|
@ -1463,13 +1495,12 @@ namespace Assimp {
|
|||
const Skin& sk = *geo.DeformerSkin();
|
||||
|
||||
std::vector<aiBone*> bones;
|
||||
bones.reserve(sk.Clusters().size());
|
||||
|
||||
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
|
||||
ai_assert(no_mat_check || outputVertStartIndices);
|
||||
|
||||
try {
|
||||
|
||||
// iterate over the sub deformers
|
||||
for (const Cluster* cluster : sk.Clusters()) {
|
||||
ai_assert(cluster);
|
||||
|
||||
|
@ -1483,15 +1514,16 @@ namespace Assimp {
|
|||
index_out_indices.clear();
|
||||
out_indices.clear();
|
||||
|
||||
|
||||
// now check if *any* of these weights is contained in the output mesh,
|
||||
// taking notes so we don't need to do it twice.
|
||||
for (WeightIndexArray::value_type index : indices) {
|
||||
|
||||
unsigned int count = 0;
|
||||
const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count);
|
||||
// ToOutputVertexIndex only returns NULL if index is out of bounds
|
||||
// ToOutputVertexIndex only returns nullptr if index is out of bounds
|
||||
// which should never happen
|
||||
ai_assert(out_idx != NULL);
|
||||
ai_assert(out_idx != nullptr);
|
||||
|
||||
index_out_indices.push_back(no_index_sentinel);
|
||||
count_out_indices.push_back(0);
|
||||
|
@ -1520,68 +1552,107 @@ namespace Assimp {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if we found at least one, generate the output bones
|
||||
// XXX this could be heavily simplified by collecting the bone
|
||||
// data in a single step.
|
||||
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
|
||||
count_out_indices, node_global_transform);
|
||||
ConvertCluster(bones, cluster, out_indices, index_out_indices,
|
||||
count_out_indices, absolute_transform, parent, root_node);
|
||||
}
|
||||
|
||||
bone_map.clear();
|
||||
}
|
||||
catch (std::exception&) {
|
||||
catch (std::exception&e) {
|
||||
std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
|
||||
throw;
|
||||
}
|
||||
|
||||
if (bones.empty()) {
|
||||
out->mBones = nullptr;
|
||||
out->mNumBones = 0;
|
||||
return;
|
||||
} else {
|
||||
out->mBones = new aiBone *[bones.size()]();
|
||||
out->mNumBones = static_cast<unsigned int>(bones.size());
|
||||
|
||||
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
|
||||
}
|
||||
|
||||
out->mBones = new aiBone*[bones.size()]();
|
||||
out->mNumBones = static_cast<unsigned int>(bones.size());
|
||||
|
||||
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertCluster(std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl,
|
||||
std::vector<size_t>& out_indices,
|
||||
std::vector<size_t>& index_out_indices,
|
||||
std::vector<size_t>& count_out_indices,
|
||||
const aiMatrix4x4& node_global_transform)
|
||||
const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node )
|
||||
{
|
||||
aiNode * iter = current_node;
|
||||
//printf("Child count: %d", iter->mNumChildren);
|
||||
return iter;
|
||||
}
|
||||
|
||||
aiBone* const bone = new aiBone();
|
||||
bones.push_back(bone);
|
||||
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, aiNode *root_node) {
|
||||
ai_assert(cl); // make sure cluster valid
|
||||
std::string deformer_name = cl->TargetNode()->Name();
|
||||
aiString bone_name = aiString(FixNodeName(deformer_name));
|
||||
|
||||
bone->mName = FixNodeName(cl.TargetNode()->Name());
|
||||
aiBone *bone = nullptr;
|
||||
|
||||
bone->mOffsetMatrix = cl.TransformLink();
|
||||
bone->mOffsetMatrix.Inverse();
|
||||
if (bone_map.count(deformer_name)) {
|
||||
std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name
|
||||
<< std::endl;
|
||||
bone = bone_map[deformer_name];
|
||||
} else {
|
||||
std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl;
|
||||
bone = new aiBone();
|
||||
bone->mName = bone_name;
|
||||
|
||||
bone->mOffsetMatrix = bone->mOffsetMatrix * node_global_transform;
|
||||
// store local transform link for post processing
|
||||
bone->mOffsetMatrix = cl->TransformLink();
|
||||
bone->mOffsetMatrix.Inverse();
|
||||
|
||||
bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
|
||||
aiVertexWeight* cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
||||
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
|
||||
|
||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||
const WeightArray& weights = cl.GetWeights();
|
||||
bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
|
||||
|
||||
const size_t c = index_out_indices.size();
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
const size_t index_index = index_out_indices[i];
|
||||
|
||||
if (index_index == no_index_sentinel) {
|
||||
continue;
|
||||
//
|
||||
// Now calculate the aiVertexWeights
|
||||
//
|
||||
|
||||
aiVertexWeight *cursor = nullptr;
|
||||
|
||||
bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
|
||||
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
||||
|
||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||
const WeightArray& weights = cl->GetWeights();
|
||||
|
||||
const size_t c = index_out_indices.size();
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
const size_t index_index = index_out_indices[i];
|
||||
|
||||
if (index_index == no_index_sentinel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t cc = count_out_indices[i];
|
||||
for (size_t j = 0; j < cc; ++j) {
|
||||
// cursor runs from first element relative to the start
|
||||
// or relative to the start of the next indexes.
|
||||
aiVertexWeight& out_weight = *cursor++;
|
||||
|
||||
out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
|
||||
out_weight.mWeight = weights[i];
|
||||
}
|
||||
}
|
||||
|
||||
const size_t cc = count_out_indices[i];
|
||||
for (size_t j = 0; j < cc; ++j) {
|
||||
aiVertexWeight& out_weight = *cursor++;
|
||||
|
||||
out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
|
||||
out_weight.mWeight = weights[i];
|
||||
}
|
||||
bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
|
||||
}
|
||||
|
||||
std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl;
|
||||
|
||||
// lookup must be populated in case something goes wrong
|
||||
// this also allocates bones to mesh instance outside
|
||||
local_mesh_bones.push_back(bone);
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
|
@ -1711,7 +1782,7 @@ namespace Assimp {
|
|||
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
|
||||
unsigned int index;
|
||||
|
||||
VideoMap::const_iterator it = textures_converted.find(media);
|
||||
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||
if (it != textures_converted.end()) {
|
||||
index = (*it).second;
|
||||
textureReady = true;
|
||||
|
@ -1719,7 +1790,7 @@ namespace Assimp {
|
|||
else {
|
||||
if (media->ContentLength() > 0) {
|
||||
index = ConvertVideo(*media);
|
||||
textures_converted[media] = index;
|
||||
textures_converted[*media] = index;
|
||||
textureReady = true;
|
||||
}
|
||||
}
|
||||
|
@ -2243,13 +2314,13 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
if (media != nullptr && media->ContentLength() > 0) {
|
||||
unsigned int index;
|
||||
|
||||
VideoMap::const_iterator it = textures_converted.find(media);
|
||||
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||
if (it != textures_converted.end()) {
|
||||
index = (*it).second;
|
||||
}
|
||||
else {
|
||||
index = ConvertVideo(*media);
|
||||
textures_converted[media] = index;
|
||||
textures_converted[*media] = index;
|
||||
}
|
||||
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
|
@ -2677,7 +2748,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
// sanity check whether the input is ok
|
||||
static void validateAnimCurveNodes(const std::vector<const AnimationCurveNode*>& curves,
|
||||
bool strictMode) {
|
||||
const Object* target(NULL);
|
||||
const Object* target(nullptr);
|
||||
for (const AnimationCurveNode* node : curves) {
|
||||
if (!target) {
|
||||
target = node->Target();
|
||||
|
@ -2708,7 +2779,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
validateAnimCurveNodes(curves, doc.Settings().strictMode);
|
||||
#endif
|
||||
const AnimationCurveNode* curve_node = NULL;
|
||||
const AnimationCurveNode* curve_node = nullptr;
|
||||
for (const AnimationCurveNode* node : curves) {
|
||||
ai_assert(node);
|
||||
|
||||
|
@ -3556,7 +3627,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
ai_assert(!out->mMeshes);
|
||||
ai_assert(!out->mNumMeshes);
|
||||
|
||||
// note: the trailing () ensures initialization with NULL - not
|
||||
// note: the trailing () ensures initialization with nullptr - not
|
||||
// many C++ users seem to know this, so pointing it out to avoid
|
||||
// confusion why this code works.
|
||||
|
||||
|
@ -3603,6 +3674,47 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
}
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertOrphantEmbeddedTextures()
|
||||
{
|
||||
// in C++14 it could be:
|
||||
// for (auto&& [id, object] : objects)
|
||||
for (auto&& id_and_object : doc.Objects())
|
||||
{
|
||||
auto&& id = std::get<0>(id_and_object);
|
||||
auto&& object = std::get<1>(id_and_object);
|
||||
// If an object doesn't have parent
|
||||
if (doc.ConnectionsBySource().count(id) == 0)
|
||||
{
|
||||
const Texture* realTexture = nullptr;
|
||||
try
|
||||
{
|
||||
const auto& element = object->GetElement();
|
||||
const Token& key = element.KeyToken();
|
||||
const char* obtype = key.begin();
|
||||
const size_t length = static_cast<size_t>(key.end() - key.begin());
|
||||
if (strncmp(obtype, "Texture", length) == 0)
|
||||
{
|
||||
const Texture* texture = static_cast<const Texture*>(object->Get());
|
||||
if (texture->Media() && texture->Media()->ContentLength() > 0)
|
||||
{
|
||||
realTexture = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
if (realTexture)
|
||||
{
|
||||
const Video* media = realTexture->Media();
|
||||
unsigned int index = ConvertVideo(*media);
|
||||
textures_converted[*media] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
|
||||
{
|
||||
|
|
|
@ -123,7 +123,7 @@ private:
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// collect and assign child nodes
|
||||
void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4());
|
||||
void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertLights(const Model& model, const std::string &orig_name );
|
||||
|
@ -179,32 +179,35 @@ private:
|
|||
void SetupNodeMetadata(const Model& model, aiNode& nd);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform);
|
||||
void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
|
||||
std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
std::vector<unsigned int>
|
||||
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
aiNode *parent, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode& nd);
|
||||
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
||||
const aiMatrix4x4 &absolute_transform, aiNode *parent,
|
||||
aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
std::vector<unsigned int>
|
||||
ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
MatIndexArray::value_type index,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index,
|
||||
aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
|
||||
|
@ -217,17 +220,17 @@ private:
|
|||
* - outputVertStartIndices is only used when a material index is specified, it gives for
|
||||
* each output vertex the DOM index it maps to.
|
||||
*/
|
||||
void ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
const aiMatrix4x4& node_global_transform = aiMatrix4x4(),
|
||||
unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
||||
std::vector<unsigned int>* outputVertStartIndices = NULL);
|
||||
|
||||
void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent = NULL, aiNode *root_node = NULL,
|
||||
unsigned int materialIndex = NO_MATERIAL_SEPARATION,
|
||||
std::vector<unsigned int> *outputVertStartIndices = NULL);
|
||||
// lookup
|
||||
static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node );
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertCluster(std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl,
|
||||
std::vector<size_t>& out_indices,
|
||||
std::vector<size_t>& index_out_indices,
|
||||
std::vector<size_t>& count_out_indices,
|
||||
const aiMatrix4x4& node_global_transform);
|
||||
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
|
@ -424,6 +427,10 @@ private:
|
|||
// copy generated meshes, animations, lights, cameras and textures to the output scene
|
||||
void TransferDataToScene();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// FBX file could have embedded textures not connected to anything
|
||||
void ConvertOrphantEmbeddedTextures();
|
||||
|
||||
private:
|
||||
// 0: not assigned yet, others: index is value - 1
|
||||
unsigned int defaultMaterialIndex;
|
||||
|
@ -435,27 +442,47 @@ private:
|
|||
std::vector<aiCamera*> cameras;
|
||||
std::vector<aiTexture*> textures;
|
||||
|
||||
using MaterialMap = std::map<const Material*, unsigned int>;
|
||||
using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
|
||||
MaterialMap materials_converted;
|
||||
|
||||
using VideoMap = std::map<const Video*, unsigned int>;
|
||||
using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
|
||||
VideoMap textures_converted;
|
||||
|
||||
using MeshMap = std::map<const Geometry*, std::vector<unsigned int> >;
|
||||
using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
|
||||
MeshMap meshes_converted;
|
||||
|
||||
// fixed node name -> which trafo chain components have animations?
|
||||
using NodeAnimBitMap = std::map<std::string, unsigned int> ;
|
||||
using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ;
|
||||
NodeAnimBitMap node_anim_chain_bits;
|
||||
|
||||
// number of nodes with the same name
|
||||
using NodeNameCache = std::unordered_map<std::string, unsigned int>;
|
||||
using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>;
|
||||
NodeNameCache mNodeNames;
|
||||
|
||||
// Deformer name is not the same as a bone name - it does contain the bone name though :)
|
||||
// Deformer names in FBX are always unique in an FBX file.
|
||||
std::map<const std::string, aiBone *> bone_map;
|
||||
|
||||
double anim_fps;
|
||||
|
||||
aiScene* const out;
|
||||
const FBX::Document& doc;
|
||||
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
std::vector<aiBone*>& bones);
|
||||
|
||||
void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode*> &node_stack );
|
||||
|
||||
static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes);
|
||||
|
||||
static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -637,6 +637,20 @@ public:
|
|||
return ptr;
|
||||
}
|
||||
|
||||
bool operator==(const Video& other) const
|
||||
{
|
||||
return (
|
||||
type == other.type
|
||||
&& relativeFileName == other.relativeFileName
|
||||
&& fileName == other.fileName
|
||||
);
|
||||
}
|
||||
|
||||
bool operator<(const Video& other) const
|
||||
{
|
||||
return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string type;
|
||||
std::string relativeFileName;
|
||||
|
@ -1005,10 +1019,10 @@ public:
|
|||
// during their entire lifetime (Document). FBX files have
|
||||
// up to many thousands of objects (most of which we never use),
|
||||
// so the memory overhead for them should be kept at a minimum.
|
||||
typedef std::map<uint64_t, LazyObject*> ObjectMap;
|
||||
typedef std::fbx_unordered_map<uint64_t, LazyObject*> ObjectMap;
|
||||
typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
|
||||
|
||||
typedef std::multimap<uint64_t, const Connection*> ConnectionMap;
|
||||
typedef std::fbx_unordered_multimap<uint64_t, const Connection*> ConnectionMap;
|
||||
|
||||
/** DOM class for global document settings, a single instance per document can
|
||||
* be accessed via Document.Globals(). */
|
||||
|
@ -1177,4 +1191,25 @@ private:
|
|||
} // Namespace FBX
|
||||
} // Namespace Assimp
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<const Assimp::FBX::Video>
|
||||
{
|
||||
std::size_t operator()(const Assimp::FBX::Video& video) const
|
||||
{
|
||||
using std::size_t;
|
||||
using std::hash;
|
||||
using std::string;
|
||||
|
||||
size_t res = 17;
|
||||
res = res * 31 + hash<string>()(video.Name());
|
||||
res = res * 31 + hash<string>()(video.RelativeFilename());
|
||||
res = res * 31 + hash<string>()(video.Type());
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // INCLUDED_AI_FBX_DOCUMENT_H
|
||||
|
|
|
@ -48,26 +48,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "FBXImporter.h"
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXConverter.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXUtil.h"
|
||||
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/MemoryIOWrapper.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
template<>
|
||||
const char* LogFunctions<FBXImporter>::Prefix() {
|
||||
static auto prefix = "FBX: ";
|
||||
return prefix;
|
||||
template <>
|
||||
const char *LogFunctions<FBXImporter>::Prefix() {
|
||||
static auto prefix = "FBX: ";
|
||||
return prefix;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
@ -76,131 +76,123 @@ using namespace Assimp::FBX;
|
|||
namespace {
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Autodesk FBX Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"fbx"
|
||||
"Autodesk FBX Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"fbx"
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by #Importer
|
||||
FBXImporter::FBXImporter()
|
||||
{
|
||||
FBXImporter::FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FBXImporter::~FBXImporter()
|
||||
{
|
||||
FBXImporter::~FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool FBXImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
const std::string& extension = GetExtension(pFile);
|
||||
if (extension == std::string( desc.mFileExtensions ) ) {
|
||||
return true;
|
||||
}
|
||||
bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
if (extension == std::string(desc.mFileExtensions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
|
||||
const char* tokens[] = {"fbx"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
|
||||
const char *tokens[] = { "fbx" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// List all extensions handled by this loader
|
||||
const aiImporterDesc* FBXImporter::GetInfo () const
|
||||
{
|
||||
return &desc;
|
||||
const aiImporterDesc *FBXImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void FBXImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||
void FBXImporter::SetupProperties(const Importer *pImp) {
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
}
|
||||
void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
}
|
||||
|
||||
// read entire file into memory - no streaming for this, fbx
|
||||
// files can grow large, but the assimp output data structure
|
||||
// then becomes very large, too. Assimp doesn't support
|
||||
// streaming for its output data structures so the net win with
|
||||
// streaming input data would be very low.
|
||||
std::vector<char> contents;
|
||||
contents.resize(stream->FileSize()+1);
|
||||
stream->Read( &*contents.begin(), 1, contents.size()-1 );
|
||||
contents[ contents.size() - 1 ] = 0;
|
||||
const char* const begin = &*contents.begin();
|
||||
// read entire file into memory - no streaming for this, fbx
|
||||
// files can grow large, but the assimp output data structure
|
||||
// then becomes very large, too. Assimp doesn't support
|
||||
// streaming for its output data structures so the net win with
|
||||
// streaming input data would be very low.
|
||||
std::vector<char> contents;
|
||||
contents.resize(stream->FileSize() + 1);
|
||||
stream->Read(&*contents.begin(), 1, contents.size() - 1);
|
||||
contents[contents.size() - 1] = 0;
|
||||
const char *const begin = &*contents.begin();
|
||||
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin,"Kaydara FBX Binary",18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens,begin,contents.size());
|
||||
}
|
||||
else {
|
||||
Tokenize(tokens,begin);
|
||||
}
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens, begin, contents.size());
|
||||
} else {
|
||||
Tokenize(tokens, begin);
|
||||
}
|
||||
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser,settings);
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser, settings);
|
||||
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||
|
||||
// size relative to cm
|
||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||
// size relative to cm
|
||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||
|
||||
// Set FBX file scale is relative to CM must be converted to M for
|
||||
// assimp universal format (M)
|
||||
SetFileScale( size_relative_to_cm * 0.01f);
|
||||
// Set FBX file scale is relative to CM must be converted to M for
|
||||
// assimp universal format (M)
|
||||
SetFileScale(size_relative_to_cm * 0.01f);
|
||||
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
}
|
||||
catch(std::exception&) {
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#include "ArmaturePopulate.h"
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate::ArmaturePopulate() : BaseProcess()
|
||||
{}
|
||||
|
||||
/// The class destructor.
|
||||
ArmaturePopulate::~ArmaturePopulate()
|
||||
{}
|
||||
|
||||
bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_PopulateArmatureData) != 0;
|
||||
}
|
||||
|
||||
void ArmaturePopulate::SetupProperties(const Importer *pImp) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArmaturePopulate::Execute(aiScene *out) {
|
||||
|
||||
// Now convert all bone positions to the correct mOffsetMatrix
|
||||
std::vector<aiBone *> bones;
|
||||
std::vector<aiNode *> nodes;
|
||||
std::map<aiBone *, aiNode *> bone_stack;
|
||||
BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
|
||||
BuildNodeList(out->mRootNode, nodes);
|
||||
|
||||
BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("Bone stack size: ", bone_stack.size());
|
||||
|
||||
for (std::pair<aiBone *, aiNode *> kvp : bone_stack) {
|
||||
aiBone *bone = kvp.first;
|
||||
aiNode *bone_node = kvp.second;
|
||||
ASSIMP_LOG_DEBUG_F("active node lookup: ", bone->mName.C_Str());
|
||||
// lcl transform grab - done in generate_nodes :)
|
||||
|
||||
// bone->mOffsetMatrix = bone_node->mTransformation;
|
||||
aiNode *armature = GetArmatureRoot(bone_node, bones);
|
||||
|
||||
ai_assert(armature);
|
||||
|
||||
// set up bone armature id
|
||||
bone->mArmature = armature;
|
||||
|
||||
// set this bone node to be referenced properly
|
||||
ai_assert(bone_node);
|
||||
bone->mNode = bone_node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Reprocess all nodes to calculate bone transforms properly based on the REAL
|
||||
* mOffsetMatrix not the local. */
|
||||
/* Before this would use mesh transforms which is wrong for bone transforms */
|
||||
/* Before this would work for simple character skeletons but not complex meshes
|
||||
* with multiple origins */
|
||||
/* Source: sketch fab log cutter fbx */
|
||||
void ArmaturePopulate::BuildBoneList(aiNode *current_node,
|
||||
const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones) {
|
||||
ai_assert(scene);
|
||||
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
|
||||
aiNode *child = current_node->mChildren[nodeId];
|
||||
ai_assert(child);
|
||||
|
||||
// check for bones
|
||||
for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) {
|
||||
ai_assert(child->mMeshes);
|
||||
unsigned int mesh_index = child->mMeshes[meshId];
|
||||
aiMesh *mesh = scene->mMeshes[mesh_index];
|
||||
ai_assert(mesh);
|
||||
|
||||
for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) {
|
||||
aiBone *bone = mesh->mBones[boneId];
|
||||
ai_assert(bone);
|
||||
|
||||
// duplicate meshes exist with the same bones sometimes :)
|
||||
// so this must be detected
|
||||
if (std::find(bones.begin(), bones.end(), bone) == bones.end()) {
|
||||
// add the element once
|
||||
bones.push_back(bone);
|
||||
}
|
||||
}
|
||||
|
||||
// find mesh and get bones
|
||||
// then do recursive lookup for bones in root node hierarchy
|
||||
}
|
||||
|
||||
BuildBoneList(child, root_node, scene, bones);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare flat node list which can be used for non recursive lookups later */
|
||||
void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
|
||||
std::vector<aiNode *> &nodes) {
|
||||
ai_assert(current_node);
|
||||
|
||||
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
|
||||
aiNode *child = current_node->mChildren[nodeId];
|
||||
ai_assert(child);
|
||||
|
||||
nodes.push_back(child);
|
||||
|
||||
BuildNodeList(child, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
/* A bone stack allows us to have multiple armatures, with the same bone names
|
||||
* A bone stack allows us also to retrieve bones true transform even with
|
||||
* duplicate names :)
|
||||
*/
|
||||
void ArmaturePopulate::BuildBoneStack(aiNode *current_node,
|
||||
const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode *> &node_stack) {
|
||||
ai_assert(scene);
|
||||
ai_assert(root_node);
|
||||
ai_assert(!node_stack.empty());
|
||||
|
||||
for (aiBone *bone : bones) {
|
||||
ai_assert(bone);
|
||||
aiNode *node = GetNodeFromStack(bone->mName, node_stack);
|
||||
if (node == nullptr) {
|
||||
node_stack.clear();
|
||||
BuildNodeList(root_node, node_stack);
|
||||
ASSIMP_LOG_DEBUG_F("Resetting bone stack: nullptr element ", bone->mName.C_Str());
|
||||
|
||||
node = GetNodeFromStack(bone->mName, node_stack);
|
||||
|
||||
if (!node) {
|
||||
ASSIMP_LOG_ERROR("serious import issue node for bone was not detected");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("Successfully added bone[", bone->mName.C_Str(), "] to stack and bone node is: ", node->mName.C_Str());
|
||||
|
||||
bone_stack.insert(std::pair<aiBone *, aiNode *>(bone, node));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Returns the armature root node */
|
||||
/* This is required to be detected for a bone initially, it will recurse up
|
||||
* until it cannot find another bone and return the node No known failure
|
||||
* points. (yet)
|
||||
*/
|
||||
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list) {
|
||||
while (bone_node) {
|
||||
if (!IsBoneNode(bone_node->mName, bone_list)) {
|
||||
ASSIMP_LOG_DEBUG_F("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str());
|
||||
return bone_node;
|
||||
}
|
||||
|
||||
bone_node = bone_node->mParent;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_ERROR("GetArmatureRoot() can't find armature!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Simple IsBoneNode check if this could be a bone */
|
||||
bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones) {
|
||||
for (aiBone *bone : bones) {
|
||||
if (bone->mName == bone_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Pop this node by name from the stack if found */
|
||||
/* Used in multiple armature situations with duplicate node / bone names */
|
||||
/* Known flaw: cannot have nodes with bone names, will be fixed in later release
|
||||
*/
|
||||
/* (serious to be fixed) Known flaw: nodes which have more than one bone could
|
||||
* be prematurely dropped from stack */
|
||||
aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes) {
|
||||
std::vector<aiNode *>::iterator iter;
|
||||
aiNode *found = nullptr;
|
||||
for (iter = nodes.begin(); iter < nodes.end(); ++iter) {
|
||||
aiNode *element = *iter;
|
||||
ai_assert(element);
|
||||
// node valid and node name matches
|
||||
if (element->mName == node_name) {
|
||||
found = element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != nullptr) {
|
||||
ASSIMP_LOG_INFO_F("Removed node from stack: ", found->mName.C_Str());
|
||||
// now pop the element from the node list
|
||||
nodes.erase(iter);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// unique names can cause this problem
|
||||
ASSIMP_LOG_ERROR("[Serious] GetNodeFromStack() can't find node from stack!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // Namespace Assimp
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ARMATURE_POPULATE_H_
|
||||
#define ARMATURE_POPULATE_H_
|
||||
|
||||
#include "Common/BaseProcess.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
struct aiNode;
|
||||
struct aiBone;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Armature Populate: This is a post process designed
|
||||
* To save you time when importing models into your game engines
|
||||
* This was originally designed only for fbx but will work with other formats
|
||||
* it is intended to auto populate aiBone data with armature and the aiNode
|
||||
* This is very useful when dealing with skinned meshes
|
||||
* or when dealing with many different skeletons
|
||||
* It's off by default but recommend that you try it and use it
|
||||
* It should reduce down any glue code you have in your
|
||||
* importers
|
||||
* You can contact RevoluPowered <gordon@gordonite.tech>
|
||||
* For more info about this
|
||||
*/
|
||||
class ASSIMP_API ArmaturePopulate : public BaseProcess {
|
||||
public:
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate();
|
||||
|
||||
/// The class destructor.
|
||||
virtual ~ArmaturePopulate();
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual bool IsActive( unsigned int pFlags ) const;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void SetupProperties( const Importer* pImp );
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void Execute( aiScene* pScene );
|
||||
|
||||
static aiNode *GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
static void BuildNodeList(const aiNode *current_node,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode *> &node_stack);
|
||||
};
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
|
||||
#endif // SCALE_PROCESS_H_
|
|
@ -358,7 +358,7 @@ namespace glTF2 {
|
|||
WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
|
||||
|
||||
if (pbrSG.glossinessFactor != 1) {
|
||||
WriteFloat(obj, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
|
||||
WriteFloat(pbrSpecularGlossiness, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
|
||||
}
|
||||
|
||||
WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
|
||||
|
|
|
@ -320,7 +320,9 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
|
|||
if (path[0] == '*') { // embedded
|
||||
aiTexture* tex = mScene->mTextures[atoi(&path[1])];
|
||||
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(tex->pcData);
|
||||
// copy data since lifetime control is handed over to the asset
|
||||
uint8_t* data = new uint8_t[tex->mWidth];
|
||||
memcpy(data, tex->pcData, tex->mWidth);
|
||||
texture->source->SetData(data, tex->mWidth, *mAsset);
|
||||
|
||||
if (tex->achFormatHint[0]) {
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include <cstdint>
|
||||
//using namespace Assimp;
|
||||
|
||||
// For locale independent number conversion
|
||||
#include <sstream>
|
||||
#include <locale>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define IRR_DEBUGPRINT(x) printf((x));
|
||||
|
@ -178,8 +181,11 @@ public:
|
|||
return 0;
|
||||
|
||||
core::stringc c = attrvalue;
|
||||
return static_cast<float>(atof(c.c_str()));
|
||||
//return fast_atof(c.c_str());
|
||||
std::istringstream sstr(c.c_str());
|
||||
sstr.imbue(std::locale("C")); // Locale free number convert
|
||||
float fNum;
|
||||
sstr >> fNum;
|
||||
return fNum;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -128,16 +128,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* GENBOUNDINGBOXES */
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
# undef ASSIMP_API
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/* Define 'ASSIMP_BUILD_DLL_EXPORT' to build a DLL of the library */
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
# ifdef ASSIMP_BUILD_DLL_EXPORT
|
||||
# define ASSIMP_API __declspec(dllexport)
|
||||
# define ASSIMP_API_WINONLY __declspec(dllexport)
|
||||
# pragma warning (disable : 4251)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/* Define 'ASSIMP_DLL' before including Assimp to link to ASSIMP in
|
||||
|
@ -150,7 +148,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# define ASSIMP_API
|
||||
# define ASSIMP_API_WINONLY
|
||||
# endif
|
||||
#elif defined(SWIG)
|
||||
|
||||
/* Do nothing, the relevant defines are all in AssimpSwigPort.i */
|
||||
|
||||
#else
|
||||
# define ASSIMP_API __attribute__ ((visibility("default")))
|
||||
# define ASSIMP_API_WINONLY
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# ifdef ASSIMP_BUILD_DLL_EXPORT
|
||||
# pragma warning (disable : 4251)
|
||||
# endif
|
||||
/* Force the compiler to inline a function, if possible
|
||||
*/
|
||||
# define AI_FORCE_INLINE __forceinline
|
||||
|
@ -158,17 +168,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
/* Tells the compiler that a function never returns. Used in code analysis
|
||||
* to skip dead paths (e.g. after an assertion evaluated to false). */
|
||||
# define AI_WONT_RETURN __declspec(noreturn)
|
||||
|
||||
#elif defined(SWIG)
|
||||
|
||||
/* Do nothing, the relevant defines are all in AssimpSwigPort.i */
|
||||
|
||||
#else
|
||||
|
||||
# define AI_WONT_RETURN
|
||||
|
||||
# define ASSIMP_API __attribute__ ((visibility("default")))
|
||||
# define ASSIMP_API_WINONLY
|
||||
# define AI_FORCE_INLINE inline
|
||||
#endif // (defined _MSC_VER)
|
||||
|
||||
|
|
|
@ -252,6 +252,9 @@ struct aiVertexWeight {
|
|||
};
|
||||
|
||||
|
||||
// Forward declare aiNode (pointer use only)
|
||||
struct aiNode;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief A single bone of a mesh.
|
||||
*
|
||||
|
@ -268,6 +271,16 @@ struct aiBone {
|
|||
//! The maximum value for this member is #AI_MAX_BONE_WEIGHTS.
|
||||
unsigned int mNumWeights;
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
|
||||
// The bone armature node - used for skeleton conversion
|
||||
// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
C_STRUCT aiNode* mArmature;
|
||||
|
||||
// The bone node in the scene - used for skeleton conversion
|
||||
// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
C_STRUCT aiNode* mNode;
|
||||
|
||||
#endif
|
||||
//! The influence weights of this bone, by vertex index.
|
||||
C_STRUCT aiVertexWeight* mWeights;
|
||||
|
||||
|
@ -422,11 +435,11 @@ struct aiAnimMesh
|
|||
/**Anim Mesh name */
|
||||
C_STRUCT aiString mName;
|
||||
|
||||
/** Replacement for aiMesh::mVertices. If this array is non-NULL,
|
||||
/** Replacement for aiMesh::mVertices. If this array is non-nullptr,
|
||||
* it *must* contain mNumVertices entries. The corresponding
|
||||
* array in the host mesh must be non-NULL as well - animation
|
||||
* array in the host mesh must be non-nullptr as well - animation
|
||||
* meshes may neither add or nor remove vertex components (if
|
||||
* a replacement array is NULL and the corresponding source
|
||||
* a replacement array is nullptr and the corresponding source
|
||||
* array is not, the source data is taken instead)*/
|
||||
C_STRUCT aiVector3D* mVertices;
|
||||
|
||||
|
@ -600,7 +613,7 @@ struct aiMesh
|
|||
C_STRUCT aiVector3D* mVertices;
|
||||
|
||||
/** Vertex normals.
|
||||
* The array contains normalized vectors, NULL if not present.
|
||||
* The array contains normalized vectors, nullptr if not present.
|
||||
* The array is mNumVertices in size. Normals are undefined for
|
||||
* point and line primitives. A mesh consisting of points and
|
||||
* lines only may not have normal vectors. Meshes with mixed
|
||||
|
@ -623,7 +636,7 @@ struct aiMesh
|
|||
|
||||
/** Vertex tangents.
|
||||
* The tangent of a vertex points in the direction of the positive
|
||||
* X texture axis. The array contains normalized vectors, NULL if
|
||||
* X texture axis. The array contains normalized vectors, nullptr if
|
||||
* not present. The array is mNumVertices in size. A mesh consisting
|
||||
* of points and lines only may not have normal vectors. Meshes with
|
||||
* mixed primitive types (i.e. lines and triangles) may have
|
||||
|
@ -637,7 +650,7 @@ struct aiMesh
|
|||
|
||||
/** Vertex bitangents.
|
||||
* The bitangent of a vertex points in the direction of the positive
|
||||
* Y texture axis. The array contains normalized vectors, NULL if not
|
||||
* Y texture axis. The array contains normalized vectors, nullptr if not
|
||||
* present. The array is mNumVertices in size.
|
||||
* @note If the mesh contains tangents, it automatically also contains
|
||||
* bitangents.
|
||||
|
@ -646,14 +659,14 @@ struct aiMesh
|
|||
|
||||
/** Vertex color sets.
|
||||
* A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex
|
||||
* colors per vertex. NULL if not present. Each array is
|
||||
* colors per vertex. nullptr if not present. Each array is
|
||||
* mNumVertices in size if present.
|
||||
*/
|
||||
C_STRUCT aiColor4D* mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
|
||||
/** Vertex texture coords, also known as UV channels.
|
||||
* A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per
|
||||
* vertex. NULL if not present. The array is mNumVertices in size.
|
||||
* vertex. nullptr if not present. The array is mNumVertices in size.
|
||||
*/
|
||||
C_STRUCT aiVector3D* mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
|
||||
|
@ -675,7 +688,7 @@ struct aiMesh
|
|||
C_STRUCT aiFace* mFaces;
|
||||
|
||||
/** The number of bones this mesh contains.
|
||||
* Can be 0, in which case the mBones array is NULL.
|
||||
* Can be 0, in which case the mBones array is nullptr.
|
||||
*/
|
||||
unsigned int mNumBones;
|
||||
|
||||
|
@ -773,7 +786,10 @@ struct aiMesh
|
|||
// DO NOT REMOVE THIS ADDITIONAL CHECK
|
||||
if (mNumBones && mBones) {
|
||||
for( unsigned int a = 0; a < mNumBones; a++) {
|
||||
delete mBones[a];
|
||||
if(mBones[a])
|
||||
{
|
||||
delete mBones[a];
|
||||
}
|
||||
}
|
||||
delete [] mBones;
|
||||
}
|
||||
|
|
|
@ -320,6 +320,19 @@ enum aiPostProcessSteps
|
|||
*/
|
||||
aiProcess_FixInfacingNormals = 0x2000,
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
/**
|
||||
* This step generically populates aiBone->mArmature and aiBone->mNode generically
|
||||
* The point of these is it saves you later having to calculate these elements
|
||||
* This is useful when handling rest information or skin information
|
||||
* If you have multiple armatures on your models we strongly recommend enabling this
|
||||
* Instead of writing your own multi-root, multi-armature lookups we have done the
|
||||
* hard work for you :)
|
||||
*/
|
||||
aiProcess_PopulateArmatureData = 0x4000,
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
/** <hr>This step splits meshes with more than one primitive type in
|
||||
* homogeneous sub-meshes.
|
||||
|
@ -537,6 +550,8 @@ enum aiPostProcessSteps
|
|||
*/
|
||||
aiProcess_Debone = 0x4000000,
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
/** <hr>This step will perform a global scale of the model.
|
||||
*
|
||||
|
|
|
@ -110,13 +110,13 @@ struct ASSIMP_API aiNode
|
|||
/** The transformation relative to the node's parent. */
|
||||
C_STRUCT aiMatrix4x4 mTransformation;
|
||||
|
||||
/** Parent node. NULL if this node is the root node. */
|
||||
/** Parent node. nullptr if this node is the root node. */
|
||||
C_STRUCT aiNode* mParent;
|
||||
|
||||
/** The number of child nodes of this node. */
|
||||
unsigned int mNumChildren;
|
||||
|
||||
/** The child nodes of this node. NULL if mNumChildren is 0. */
|
||||
/** The child nodes of this node. nullptr if mNumChildren is 0. */
|
||||
C_STRUCT aiNode** mChildren;
|
||||
|
||||
/** The number of meshes of this node. */
|
||||
|
@ -127,7 +127,7 @@ struct ASSIMP_API aiNode
|
|||
*/
|
||||
unsigned int* mMeshes;
|
||||
|
||||
/** Metadata associated with this node or NULL if there is no metadata.
|
||||
/** Metadata associated with this node or nullptr if there is no metadata.
|
||||
* Whether any metadata is generated depends on the source file format. See the
|
||||
* @link importer_notes @endlink page for more information on every source file
|
||||
* format. Importers that don't document any metadata don't write any.
|
||||
|
@ -149,7 +149,7 @@ struct ASSIMP_API aiNode
|
|||
* of the scene.
|
||||
*
|
||||
* @param name Name to search for
|
||||
* @return NULL or a valid Node if the search was successful.
|
||||
* @return nullptr or a valid Node if the search was successful.
|
||||
*/
|
||||
inline
|
||||
const aiNode* FindNode(const aiString& name) const {
|
||||
|
@ -344,7 +344,7 @@ struct aiScene
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
//! Default constructor - set everything to 0/NULL
|
||||
//! Default constructor - set everything to 0/nullptr
|
||||
ASSIMP_API aiScene();
|
||||
|
||||
//! Destructor
|
||||
|
@ -353,33 +353,33 @@ struct aiScene
|
|||
//! Check whether the scene contains meshes
|
||||
//! Unless no special scene flags are set this will always be true.
|
||||
inline bool HasMeshes() const {
|
||||
return mMeshes != NULL && mNumMeshes > 0;
|
||||
return mMeshes != nullptr && mNumMeshes > 0;
|
||||
}
|
||||
|
||||
//! Check whether the scene contains materials
|
||||
//! Unless no special scene flags are set this will always be true.
|
||||
inline bool HasMaterials() const {
|
||||
return mMaterials != NULL && mNumMaterials > 0;
|
||||
return mMaterials != nullptr && mNumMaterials > 0;
|
||||
}
|
||||
|
||||
//! Check whether the scene contains lights
|
||||
inline bool HasLights() const {
|
||||
return mLights != NULL && mNumLights > 0;
|
||||
return mLights != nullptr && mNumLights > 0;
|
||||
}
|
||||
|
||||
//! Check whether the scene contains textures
|
||||
inline bool HasTextures() const {
|
||||
return mTextures != NULL && mNumTextures > 0;
|
||||
return mTextures != nullptr && mNumTextures > 0;
|
||||
}
|
||||
|
||||
//! Check whether the scene contains cameras
|
||||
inline bool HasCameras() const {
|
||||
return mCameras != NULL && mNumCameras > 0;
|
||||
return mCameras != nullptr && mNumCameras > 0;
|
||||
}
|
||||
|
||||
//! Check whether the scene contains animations
|
||||
inline bool HasAnimations() const {
|
||||
return mAnimations != NULL && mNumAnimations > 0;
|
||||
return mAnimations != nullptr && mNumAnimations > 0;
|
||||
}
|
||||
|
||||
//! Returns a short filename from a full path
|
||||
|
|
|
@ -148,6 +148,7 @@ SET( POST_PROCESSES
|
|||
unit/utRemoveRedundantMaterials.cpp
|
||||
unit/utRemoveVCProcess.cpp
|
||||
unit/utScaleProcess.cpp
|
||||
unit/utArmaturePopulate.cpp
|
||||
unit/utJoinVertices.cpp
|
||||
unit/utRemoveComments.cpp
|
||||
unit/utRemoveComponent.cpp
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -16,7 +16,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
// create a logger from both CPP
|
||||
Assimp::DefaultLogger::create("AssimpLog_Cpp.txt",Assimp::Logger::VERBOSE,
|
||||
aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE);
|
||||
aiDefaultLogStream_STDOUT | aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE);
|
||||
|
||||
// .. and C. They should smoothly work together
|
||||
aiEnableVerboseLogging(AI_TRUE);
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#include "UnitTestPCH.h"
|
||||
#include "TestModelFactory.h"
|
||||
|
||||
|
||||
#include "SceneDiffer.h"
|
||||
#include "AbstractImportExportBase.h"
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/types.h>
|
||||
|
||||
#include "PostProcessing/ArmaturePopulate.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace UnitTest {
|
||||
|
||||
class utArmaturePopulate : public ::testing::Test {
|
||||
// empty
|
||||
};
|
||||
|
||||
TEST_F( utArmaturePopulate, importCheckForArmatureTest) {
|
||||
Assimp::Importer importer;
|
||||
unsigned int mask = aiProcess_PopulateArmatureData | aiProcess_ValidateDataStructure;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/huesitos.fbx", mask);
|
||||
EXPECT_NE( nullptr, scene );
|
||||
EXPECT_EQ(scene->mNumMeshes, 1u);
|
||||
aiMesh* mesh = scene->mMeshes[0];
|
||||
EXPECT_EQ(mesh->mNumFaces, 68u);
|
||||
EXPECT_EQ(mesh->mNumVertices, 256u);
|
||||
EXPECT_GT(mesh->mNumBones, 0u);
|
||||
|
||||
aiBone* exampleBone = mesh->mBones[0];
|
||||
EXPECT_NE(exampleBone, nullptr);
|
||||
EXPECT_NE(exampleBone->mArmature, nullptr);
|
||||
EXPECT_NE(exampleBone->mNode, nullptr);
|
||||
}
|
||||
|
||||
} // Namespace UnitTest
|
||||
} // Namespace Assimp
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "AbstractImportExportBase.h"
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -52,8 +53,19 @@ class utColladaImportExport : public AbstractImportExportBase {
|
|||
public:
|
||||
virtual bool importerTest() {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure );
|
||||
return nullptr != scene;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure);
|
||||
if (scene == nullptr)
|
||||
return false;
|
||||
|
||||
// Expected number of items
|
||||
EXPECT_EQ(scene->mNumMeshes, 1u);
|
||||
EXPECT_EQ(scene->mNumMaterials, 1u);
|
||||
EXPECT_EQ(scene->mNumAnimations, 0u);
|
||||
EXPECT_EQ(scene->mNumTextures, 0u);
|
||||
EXPECT_EQ(scene->mNumLights, 1u);
|
||||
EXPECT_EQ(scene->mNumCameras, 1u);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -64,9 +76,37 @@ TEST_F(utColladaImportExport, importBlenFromFileTest) {
|
|||
class utColladaZaeImportExport : public AbstractImportExportBase {
|
||||
public:
|
||||
virtual bool importerTest() {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure);
|
||||
return nullptr != scene;
|
||||
{
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure);
|
||||
if (scene == nullptr)
|
||||
return false;
|
||||
|
||||
// Expected number of items
|
||||
EXPECT_EQ(scene->mNumMeshes, 1u);
|
||||
EXPECT_EQ(scene->mNumMaterials, 1u);
|
||||
EXPECT_EQ(scene->mNumAnimations, 0u);
|
||||
EXPECT_EQ(scene->mNumTextures, 1u);
|
||||
EXPECT_EQ(scene->mNumLights, 1u);
|
||||
EXPECT_EQ(scene->mNumCameras, 1u);
|
||||
}
|
||||
|
||||
{
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck_nomanifest.zae", aiProcess_ValidateDataStructure);
|
||||
if (scene == nullptr)
|
||||
return false;
|
||||
|
||||
// Expected number of items
|
||||
EXPECT_EQ(scene->mNumMeshes, 1u);
|
||||
EXPECT_EQ(scene->mNumMaterials, 1u);
|
||||
EXPECT_EQ(scene->mNumAnimations, 0u);
|
||||
EXPECT_EQ(scene->mNumTextures, 1u);
|
||||
EXPECT_EQ(scene->mNumLights, 1u);
|
||||
EXPECT_EQ(scene->mNumCameras, 1u);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ TEST_F( utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords ) {
|
|||
EXPECT_EQ(mesh->mNumVertices, 36u);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_nonames.fbx", aiProcess_ValidateDataStructure);
|
||||
|
@ -86,26 +87,6 @@ TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
|
|||
ASSERT_STREQ(root->mName.C_Str(), "RootNode");
|
||||
ASSERT_TRUE(root->mChildren);
|
||||
ASSERT_EQ(root->mNumChildren, 2u);
|
||||
|
||||
const auto child0 = root->mChildren[0];
|
||||
ASSERT_TRUE(child0);
|
||||
ASSERT_STREQ(child0->mName.C_Str(), "RootNode001");
|
||||
ASSERT_TRUE(child0->mChildren);
|
||||
ASSERT_EQ(child0->mNumChildren, 1u);
|
||||
|
||||
const auto child00 = child0->mChildren[0];
|
||||
ASSERT_TRUE(child00);
|
||||
ASSERT_STREQ(child00->mName.C_Str(), "RootNode001001");
|
||||
|
||||
const auto child1 = root->mChildren[1];
|
||||
ASSERT_TRUE(child1);
|
||||
ASSERT_STREQ(child1->mName.C_Str(), "RootNode002");
|
||||
ASSERT_TRUE(child1->mChildren);
|
||||
ASSERT_EQ(child1->mNumChildren, 1u);
|
||||
|
||||
const auto child10 = child1->mChildren[0];
|
||||
ASSERT_TRUE(child10);
|
||||
ASSERT_STREQ(child10->mName.C_Str(), "RootNode002001");
|
||||
}
|
||||
|
||||
TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) {
|
||||
|
@ -137,7 +118,7 @@ TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) {
|
|||
|
||||
const auto child10 = child1->mChildren[0];
|
||||
ASSERT_TRUE(child10);
|
||||
ASSERT_STREQ(child10->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31""001");
|
||||
ASSERT_STREQ(child10->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31");
|
||||
}
|
||||
|
||||
TEST_F(utFBXImporterExporter, importCubesComplexTransform) {
|
||||
|
@ -168,14 +149,14 @@ TEST_F(utFBXImporterExporter, importCubesComplexTransform) {
|
|||
auto parent = child1;
|
||||
const size_t chain_length = 8u;
|
||||
const char* chainStr[chain_length] = {
|
||||
"Cube1001_$AssimpFbx$_Translation",
|
||||
"Cube1001_$AssimpFbx$_RotationPivot",
|
||||
"Cube1001_$AssimpFbx$_RotationPivotInverse",
|
||||
"Cube1001_$AssimpFbx$_ScalingOffset",
|
||||
"Cube1001_$AssimpFbx$_ScalingPivot",
|
||||
"Cube1001_$AssimpFbx$_Scaling",
|
||||
"Cube1001_$AssimpFbx$_ScalingPivotInverse",
|
||||
"Cube1001"
|
||||
"Cube1_$AssimpFbx$_Translation",
|
||||
"Cube1_$AssimpFbx$_RotationPivot",
|
||||
"Cube1_$AssimpFbx$_RotationPivotInverse",
|
||||
"Cube1_$AssimpFbx$_ScalingOffset",
|
||||
"Cube1_$AssimpFbx$_ScalingPivot",
|
||||
"Cube1_$AssimpFbx$_Scaling",
|
||||
"Cube1_$AssimpFbx$_ScalingPivotInverse",
|
||||
"Cube1"
|
||||
};
|
||||
for (size_t i = 0; i < chain_length; ++i) {
|
||||
ASSERT_TRUE(parent->mChildren);
|
||||
|
@ -282,3 +263,23 @@ TEST_F(utFBXImporterExporter, fbxTokenizeTestTest) {
|
|||
//const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/transparentTest2.fbx", aiProcess_ValidateDataStructure);
|
||||
//EXPECT_NE(nullptr, scene);
|
||||
}
|
||||
|
||||
TEST_F(utFBXImporterExporter, importOrphantEmbeddedTextureTest) {
|
||||
// see https://github.com/assimp/assimp/issues/1957
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/box_orphant_embedded_texture.fbx", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
|
||||
EXPECT_EQ(1u, scene->mNumMaterials);
|
||||
aiMaterial *mat = scene->mMaterials[0];
|
||||
ASSERT_NE(nullptr, mat);
|
||||
|
||||
aiString path;
|
||||
aiTextureMapMode modes[2];
|
||||
ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
|
||||
ASSERT_STREQ(path.C_Str(), "..\\Primitives\\GridGrey.tga");
|
||||
|
||||
ASSERT_EQ(1u, scene->mNumTextures);
|
||||
ASSERT_TRUE(scene->mTextures[0]->pcData);
|
||||
ASSERT_EQ(9026u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression used for a texture.";
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ TEST_F( utVersion, aiGetLegalStringTest ) {
|
|||
EXPECT_NE( lv, nullptr );
|
||||
std::string text( lv );
|
||||
|
||||
size_t pos( text.find( std::string( "2017" ) ) );
|
||||
size_t pos( text.find( std::string( "2019" ) ) );
|
||||
EXPECT_NE( pos, std::string::npos );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue