Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19f2a624a9 | ||
|
|
765b38cf04 | ||
|
|
a916a0eda5 | ||
|
|
c2b05acaa6 | ||
|
|
a828114a1d | ||
|
|
552f3a308d | ||
|
|
784d9615f5 | ||
|
|
6484dd6825 | ||
|
|
bcee205542 | ||
|
|
0904490150 | ||
|
|
7919461951 | ||
|
|
e4fb0e0960 | ||
|
|
d87111983a | ||
|
|
b1dc8cfe56 | ||
|
|
7296ffc3f5 | ||
|
|
b567497a17 | ||
|
|
e1dae1402e | ||
|
|
68f3386c7b | ||
|
|
9e0357a8b6 | ||
|
|
72888c49f6 | ||
|
|
cd7df53a72 | ||
|
|
4457d9300a | ||
|
|
0ef830d2b1 | ||
|
|
e02d51ec24 | ||
|
|
a305d14b8f | ||
|
|
5e69517742 | ||
|
|
1b3ae63527 | ||
|
|
47f004517f | ||
|
|
c14eccefaf | ||
|
|
efe92e9ec1 | ||
|
|
1bf5dd2731 | ||
|
|
26598dc6bd | ||
|
|
76e10b96fc | ||
|
|
b35879989c | ||
|
|
40d896ccc1 | ||
|
|
ba379c20e1 | ||
|
|
92b5c284ce | ||
|
|
9ca9254445 | ||
|
|
7eb5fd0e4e | ||
|
|
80a8807c47 | ||
|
|
d4527d4e87 | ||
|
|
a2543e7151 | ||
|
|
a1e03e3481 | ||
|
|
cfe84b9260 | ||
|
|
52008ec989 | ||
|
|
9b227fc262 | ||
|
|
8a6a1fc2df | ||
|
|
d704824be3 | ||
|
|
bbcefbd034 | ||
|
|
62930076af | ||
|
|
e368a69824 | ||
|
|
3957fbba8b | ||
|
|
8e59287b94 | ||
|
|
c73ff82fc4 | ||
|
|
04858c5d89 | ||
|
|
94178df61b | ||
|
|
1b2f705ee4 | ||
|
|
0dc24ab3a7 | ||
|
|
cf96639119 | ||
|
|
72da1e6d7b | ||
|
|
e3001f1eb7 | ||
|
|
6f31254ae1 | ||
|
|
3a09d19374 | ||
|
|
4ddacdb5df | ||
|
|
466b34cf53 | ||
|
|
aa04ee89f1 | ||
|
|
a6808b868c | ||
|
|
480d6fee2a | ||
|
|
62c9347985 | ||
|
|
ba785910d1 | ||
|
|
caaeef2b56 | ||
|
|
8b1d94d6b1 | ||
|
|
75e7d0f6ef | ||
|
|
d18709b899 | ||
|
|
5143044cc8 | ||
|
|
2fdf52488f | ||
|
|
42766af702 | ||
|
|
bf1f142a72 | ||
|
|
6439305379 | ||
|
|
61ba320a04 | ||
|
|
408b5053a4 |
9
.github/workflows/ccpp.yml
vendored
9
.github/workflows/ccpp.yml
vendored
@@ -13,8 +13,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
#name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
|
||||
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter]
|
||||
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
|
||||
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
|
||||
include:
|
||||
- name: windows-latest-cl.exe
|
||||
@@ -39,9 +38,9 @@ jobs:
|
||||
- name: macos-clang-hunter
|
||||
os: macos-latest
|
||||
toolchain: ninja-clang-cxx17-fpic
|
||||
#- name: windows-msvc-hunter
|
||||
# os: windows-latest
|
||||
# toolchain: ninja-vs-win64-cxx17
|
||||
- name: windows-msvc-hunter
|
||||
os: windows-latest
|
||||
toolchain: ninja-vs-win64-cxx17
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
||||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
include("cmake-modules/HunterGate.cmake")
|
||||
HunterGate(
|
||||
URL "https://github.com/cpp-pm/hunter/archive/v0.23.311.tar.gz"
|
||||
SHA1 "1a82b9b73055879181cb1466b2ab5d48ee8ae410"
|
||||
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
|
||||
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
|
||||
)
|
||||
|
||||
add_definitions(-DASSIMP_USE_HUNTER)
|
||||
@@ -134,12 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
|
||||
OFF
|
||||
)
|
||||
|
||||
IF ( WIN32 )
|
||||
IF (WIN32)
|
||||
# Use subset of Windows.h
|
||||
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
|
||||
|
||||
IF(MSVC)
|
||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
|
||||
OPTION (ASSIMP_BUILD_ASSIMP_VIEW
|
||||
"If the Assimp view tool is built. (requires DirectX)"
|
||||
OFF )
|
||||
|
||||
@@ -150,6 +150,27 @@ IF ( WIN32 )
|
||||
# Multibyte character set is deprecated since at least MSVC2015 (possibly earlier)
|
||||
ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
|
||||
ENDIF()
|
||||
|
||||
# Link statically against c/c++ lib to avoid missing redistriburable such as
|
||||
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
|
||||
# a choice to opt for the shared runtime if they want.
|
||||
option(USE_STATIC_CRT "Link against the static runtime libraries." OFF)
|
||||
|
||||
# The CMAKE_CXX_FLAGS vars can be overriden by some Visual Studio generators, so we use an alternative
|
||||
# global method here:
|
||||
if (${USE_STATIC_CRT})
|
||||
add_compile_options(
|
||||
$<$<CONFIG:>:/MT>
|
||||
$<$<CONFIG:Debug>:/MTd>
|
||||
$<$<CONFIG:Release>:/MT>
|
||||
)
|
||||
else()
|
||||
add_compile_options(
|
||||
$<$<CONFIG:>:/MD>
|
||||
$<$<CONFIG:Debug>:/MDd>
|
||||
$<$<CONFIG:Release>:/MD>
|
||||
)
|
||||
endif()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
@@ -694,11 +715,13 @@ ENDIF()
|
||||
ADD_SUBDIRECTORY( code/ )
|
||||
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||
# The viewer for windows only
|
||||
IF ( WIN32 )
|
||||
IF (WIN32)
|
||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
|
||||
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
||||
ENDIF ()
|
||||
ELSE()
|
||||
MESSAGE("Building Assimp Viewer only supported on Windows.")
|
||||
ENDIF ()
|
||||
# The command line tool
|
||||
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
|
||||
|
||||
@@ -1267,7 +1267,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
||||
const std::vector<aiVector3D> &normals = mesh.GetNormals();
|
||||
if (normals.size()) {
|
||||
ai_assert(normals.size() == vertices.size());
|
||||
out_mesh->mNormals = new aiVector3D[vertices.size()];
|
||||
out_mesh->mNormals = new aiVector3D[count_vertices];
|
||||
}
|
||||
|
||||
// allocate tangents, binormals.
|
||||
@@ -1295,8 +1295,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
||||
ai_assert(tangents.size() == vertices.size());
|
||||
ai_assert(binormals->size() == vertices.size());
|
||||
|
||||
out_mesh->mTangents = new aiVector3D[vertices.size()];
|
||||
out_mesh->mBitangents = new aiVector3D[vertices.size()];
|
||||
out_mesh->mTangents = new aiVector3D[count_vertices];
|
||||
out_mesh->mBitangents = new aiVector3D[count_vertices];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1308,7 +1308,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
||||
break;
|
||||
}
|
||||
|
||||
out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
|
||||
out_mesh->mTextureCoords[i] = new aiVector3D[count_vertices];
|
||||
out_mesh->mNumUVComponents[i] = 2;
|
||||
}
|
||||
|
||||
@@ -1320,7 +1320,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
||||
break;
|
||||
}
|
||||
|
||||
out_mesh->mColors[i] = new aiColor4D[vertices.size()];
|
||||
out_mesh->mColors[i] = new aiColor4D[count_vertices];
|
||||
}
|
||||
|
||||
unsigned int cursor = 0, in_cursor = 0;
|
||||
|
||||
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
@@ -68,23 +67,13 @@ namespace FBX {
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc)
|
||||
: doc(doc)
|
||||
, element(element)
|
||||
, id(id)
|
||||
, flags() {
|
||||
LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) :
|
||||
doc(doc), element(element), id(id), flags() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::~LazyObject()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* LazyObject::Get(bool dieOnError)
|
||||
{
|
||||
const Object* LazyObject::Get(bool dieOnError) {
|
||||
if(IsBeingConstructed() || FailedToConstruct()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -234,17 +223,8 @@ const Object* LazyObject::Get(bool dieOnError)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::Object(uint64_t id, const Element& element, const std::string& name)
|
||||
: element(element)
|
||||
, name(name)
|
||||
, id(id)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::~Object()
|
||||
{
|
||||
Object::Object(uint64_t id, const Element& element, const std::string& name) :
|
||||
element(element), name(name), id(id) {
|
||||
// empty
|
||||
}
|
||||
|
||||
@@ -255,16 +235,8 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<cons
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::~FileGlobalSettings()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser& parser, const ImportSettings& settings)
|
||||
: settings(settings)
|
||||
, parser(parser)
|
||||
{
|
||||
Document::Document(const Parser& parser, const ImportSettings& settings) :
|
||||
settings(settings), parser(parser) {
|
||||
ASSIMP_LOG_DEBUG("Creating FBX Document");
|
||||
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
@@ -285,8 +257,7 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document()
|
||||
{
|
||||
Document::~Document() {
|
||||
for(ObjectMap::value_type& v : objects) {
|
||||
delete v.second;
|
||||
}
|
||||
@@ -348,8 +319,7 @@ void Document::ReadHeader() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadGlobalSettings()
|
||||
{
|
||||
void Document::ReadGlobalSettings() {
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["GlobalSettings"];
|
||||
if ( nullptr == ehead || !ehead->Compound() ) {
|
||||
@@ -370,8 +340,7 @@ void Document::ReadGlobalSettings()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadObjects()
|
||||
{
|
||||
void Document::ReadObjects() {
|
||||
// read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const eobjects = sc["Objects"];
|
||||
@@ -418,8 +387,7 @@ void Document::ReadObjects()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadPropertyTemplates()
|
||||
{
|
||||
void Document::ReadPropertyTemplates() {
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const edefs = sc["Definitions"];
|
||||
@@ -476,8 +444,7 @@ void Document::ReadPropertyTemplates()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections()
|
||||
{
|
||||
void Document::ReadConnections() {
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const econns = sc["Connections"];
|
||||
@@ -524,8 +491,7 @@ void Document::ReadConnections()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const AnimationStack*>& Document::AnimationStacks() const
|
||||
{
|
||||
const std::vector<const AnimationStack*>& Document::AnimationStacks() const {
|
||||
if (!animationStacksResolved.empty() || animationStacks.empty()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
@@ -545,17 +511,15 @@ const std::vector<const AnimationStack*>& Document::AnimationStacks() const
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject* Document::GetObject(uint64_t id) const
|
||||
{
|
||||
LazyObject* Document::GetObject(uint64_t id) const {
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
#define MAX_CLASSNAMES 6
|
||||
constexpr size_t MAX_CLASSNAMES = 6;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const
|
||||
{
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const {
|
||||
std::vector<const Connection*> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
@@ -573,11 +537,9 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, co
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
|
||||
const ConnectionMap& conns,
|
||||
const char* const* classnames,
|
||||
size_t count) const
|
||||
|
||||
{
|
||||
const ConnectionMap& conns,
|
||||
const char* const* classnames,
|
||||
size_t count) const {
|
||||
ai_assert(classnames);
|
||||
ai_assert( count != 0 );
|
||||
ai_assert( count <= MAX_CLASSNAMES);
|
||||
@@ -622,95 +584,72 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
|
||||
{
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const {
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const
|
||||
{
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const {
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsBySourceSequenced(src, arr,1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
|
||||
const char* const* classnames, size_t count) const
|
||||
{
|
||||
const char* const* classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char* classname) const
|
||||
{
|
||||
const char* classname) const {
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsByDestinationSequenced(dest, arr,1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
|
||||
{
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char* const* classnames, size_t count) const
|
||||
|
||||
{
|
||||
const char* const* classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop,
|
||||
const Document& doc)
|
||||
|
||||
: insertionOrder(insertionOrder)
|
||||
, prop(prop)
|
||||
, src(src)
|
||||
, dest(dest)
|
||||
, doc(doc)
|
||||
{
|
||||
const Document& doc) :
|
||||
insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
|
||||
ai_assert(doc.Objects().find(src) != doc.Objects().end());
|
||||
// dest may be 0 (root node)
|
||||
ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::~Connection()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject& Connection::LazySourceObject() const
|
||||
{
|
||||
LazyObject& Connection::LazySourceObject() const {
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject& Connection::LazyDestinationObject() const
|
||||
{
|
||||
LazyObject& Connection::LazyDestinationObject() const {
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* Connection::SourceObject() const
|
||||
{
|
||||
const Object* Connection::SourceObject() const {
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* Connection::DestinationObject() const
|
||||
{
|
||||
const Object* Connection::DestinationObject() const {
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
@@ -719,4 +658,4 @@ const Object* Connection::DestinationObject() const
|
||||
} // !FBX
|
||||
} // !Assimp
|
||||
|
||||
#endif
|
||||
#endif // ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
||||
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
@@ -89,7 +88,7 @@ class LazyObject {
|
||||
public:
|
||||
LazyObject(uint64_t id, const Element& element, const Document& doc);
|
||||
|
||||
~LazyObject();
|
||||
~LazyObject() = default;
|
||||
|
||||
const Object* Get(bool dieOnError = false);
|
||||
|
||||
@@ -139,7 +138,7 @@ class Object {
|
||||
public:
|
||||
Object(uint64_t id, const Element& element, const std::string& name);
|
||||
|
||||
virtual ~Object();
|
||||
virtual ~Object() = default;
|
||||
|
||||
const Element& SourceElement() const {
|
||||
return element;
|
||||
@@ -267,8 +266,7 @@ public:
|
||||
Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||
virtual ~Light();
|
||||
|
||||
enum Type
|
||||
{
|
||||
enum Type {
|
||||
Type_Point,
|
||||
Type_Directional,
|
||||
Type_Spot,
|
||||
@@ -278,8 +276,7 @@ public:
|
||||
Type_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum Decay
|
||||
{
|
||||
enum Decay {
|
||||
Decay_None,
|
||||
Decay_Linear,
|
||||
Decay_Quadratic,
|
||||
@@ -347,7 +344,7 @@ public:
|
||||
|
||||
Model(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||
|
||||
virtual ~Model();
|
||||
virtual ~Model() = default;
|
||||
|
||||
fbx_simple_property(QuaternionInterpolate, int, 0)
|
||||
|
||||
@@ -578,31 +575,27 @@ public:
|
||||
BlendMode_BlendModeCount
|
||||
};
|
||||
|
||||
const Texture* getTexture(int index=0) const
|
||||
{
|
||||
const Texture* getTexture(int index=0) const {
|
||||
return textures[index];
|
||||
|
||||
}
|
||||
int textureCount() const {
|
||||
return static_cast<int>(textures.size());
|
||||
}
|
||||
BlendMode GetBlendMode() const
|
||||
{
|
||||
BlendMode GetBlendMode() const {
|
||||
return blendMode;
|
||||
}
|
||||
float Alpha()
|
||||
{
|
||||
float Alpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const Texture*> textures;
|
||||
BlendMode blendMode;
|
||||
float alpha;
|
||||
};
|
||||
|
||||
typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
|
||||
typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
|
||||
|
||||
using TextureMap = std::fbx_unordered_map<std::string, const Texture*>;
|
||||
using LayeredTextureMap = std::fbx_unordered_map<std::string, const LayeredTexture*>;
|
||||
|
||||
/** DOM class for generic FBX videos */
|
||||
class Video : public Object {
|
||||
@@ -690,8 +683,8 @@ private:
|
||||
LayeredTextureMap layeredTextures;
|
||||
};
|
||||
|
||||
typedef std::vector<int64_t> KeyTimeList;
|
||||
typedef std::vector<float> KeyValueList;
|
||||
using KeyTimeList = std::vector<int64_t>;
|
||||
using KeyValueList = std::vector<float>;
|
||||
|
||||
/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */
|
||||
class AnimationCurve : public Object {
|
||||
@@ -727,7 +720,7 @@ private:
|
||||
};
|
||||
|
||||
// property-name -> animation curve
|
||||
typedef std::map<std::string, const AnimationCurve*> AnimationCurveMap;
|
||||
using AnimationCurveMap = std::map<std::string, const AnimationCurve*>;
|
||||
|
||||
/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */
|
||||
class AnimationCurveNode : public Object {
|
||||
@@ -777,7 +770,7 @@ private:
|
||||
const Document& doc;
|
||||
};
|
||||
|
||||
typedef std::vector<const AnimationCurveNode*> AnimationCurveNodeList;
|
||||
using AnimationCurveNodeList = std::vector<const AnimationCurveNode*>;
|
||||
|
||||
/** Represents a FBX animation layer (i.e. a list of node animations) */
|
||||
class AnimationLayer : public Object {
|
||||
@@ -800,7 +793,7 @@ private:
|
||||
const Document& doc;
|
||||
};
|
||||
|
||||
typedef std::vector<const AnimationLayer*> AnimationLayerList;
|
||||
using AnimationLayerList = std::vector<const AnimationLayer*>;
|
||||
|
||||
/** Represents a FBX animation stack (i.e. a list of animation layers) */
|
||||
class AnimationStack : public Object {
|
||||
@@ -843,8 +836,8 @@ private:
|
||||
std::shared_ptr<const PropertyTable> props;
|
||||
};
|
||||
|
||||
typedef std::vector<float> WeightArray;
|
||||
typedef std::vector<unsigned int> WeightIndexArray;
|
||||
using WeightArray = std::vector<float>;
|
||||
using WeightIndexArray = std::vector<unsigned int>;
|
||||
|
||||
|
||||
/** DOM class for BlendShapeChannel deformers */
|
||||
@@ -956,7 +949,7 @@ class Connection {
|
||||
public:
|
||||
Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, const Document& doc);
|
||||
|
||||
~Connection();
|
||||
~Connection() = default;
|
||||
|
||||
// note: a connection ensures that the source and dest objects exist, but
|
||||
// not that they have DOM representations, so the return value of one of
|
||||
@@ -1011,10 +1004,9 @@ 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::fbx_unordered_map<uint64_t, LazyObject*> ObjectMap;
|
||||
typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
|
||||
|
||||
typedef std::fbx_unordered_multimap<uint64_t, const Connection*> ConnectionMap;
|
||||
using ObjectMap = std::fbx_unordered_map<uint64_t, LazyObject*> ;
|
||||
using PropertyTemplateMap = std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > ;
|
||||
using ConnectionMap = std::fbx_unordered_multimap<uint64_t, const Connection*>;
|
||||
|
||||
/** DOM class for global document settings, a single instance per document can
|
||||
* be accessed via Document.Globals(). */
|
||||
@@ -1022,7 +1014,7 @@ class FileGlobalSettings {
|
||||
public:
|
||||
FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props);
|
||||
|
||||
~FileGlobalSettings();
|
||||
~FileGlobalSettings() = default;
|
||||
|
||||
const PropertyTable& Props() const {
|
||||
ai_assert(props.get());
|
||||
|
||||
@@ -140,11 +140,32 @@ Material::~Material() {
|
||||
// empty
|
||||
}
|
||||
|
||||
aiVector2D uvTrans;
|
||||
aiVector2D uvScaling;
|
||||
ai_real uvRotation;
|
||||
|
||||
std::string type;
|
||||
std::string relativeFileName;
|
||||
std::string fileName;
|
||||
std::string alphaSource;
|
||||
std::shared_ptr<const PropertyTable> props;
|
||||
|
||||
unsigned int crop[4]{};
|
||||
|
||||
const Video* media;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
|
||||
Object(id,element,name),
|
||||
uvTrans(0.0f, 0.0f),
|
||||
uvScaling(1.0f,1.0f),
|
||||
media(0) {
|
||||
uvRotation(0.0f),
|
||||
type(),
|
||||
relativeFileName(),
|
||||
fileName(),
|
||||
alphaSource(),
|
||||
props(),
|
||||
media(nullptr) {
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Type = sc["Type"];
|
||||
|
||||
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
@@ -76,10 +75,6 @@ Model::Model(uint64_t id, const Element &element, const Document &doc, const std
|
||||
ResolveLinks(element, doc);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::~Model() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Model::ResolveLinks(const Element&, const Document &doc) {
|
||||
const char *const arr[] = { "Geometry", "Material", "NodeAttribute" };
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace LWO {
|
||||
|
||||
#define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B')
|
||||
#define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L', 'W', 'O', '2')
|
||||
#define AI_LWO_FOURCC_LWO3 AI_IFF_FOURCC('L', 'W', 'O', '3')
|
||||
#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L', 'X', 'O', 'B')
|
||||
|
||||
// chunks specific to the LWOB format
|
||||
@@ -248,6 +249,57 @@ namespace LWO {
|
||||
#define AI_LWO_SPOT AI_IFF_FOURCC('S', 'P', 'O', 'T')
|
||||
#define AI_LWO_PICK AI_IFF_FOURCC('P', 'I', 'C', 'K')
|
||||
|
||||
// Surface Part
|
||||
#define AI_LWO_NODS AI_IFF_FOURCC('N', 'O', 'D', 'S')
|
||||
#define AI_LWO_NNDS AI_IFF_FOURCC('N', 'N', 'D', 'S')
|
||||
#define AI_LWO_NTAG AI_IFF_FOURCC('N', 'T', 'A', 'G')
|
||||
#define AI_LWO_NRNM AI_IFF_FOURCC('N', 'R', 'N', 'M')
|
||||
#define AI_LWO_NRME AI_IFF_FOURCC('N', 'R', 'M', 'E')
|
||||
#define AI_LWO_NDTA AI_IFF_FOURCC('N', 'D', 'T', 'A')
|
||||
#define AI_LWO_ATTR AI_IFF_FOURCC('A', 'T', 'T', 'R')
|
||||
#define AI_LWO_VERS AI_IFF_FOURCC('V', 'E', 'R', 'S')
|
||||
#define AI_LWO_ENUM AI_IFF_FOURCC('E', 'N', 'U', 'M')
|
||||
#define AI_LWO_ENTR AI_IFF_FOURCC('E', 'N', 'T', 'R')
|
||||
#define AI_LWO_NAME AI_IFF_FOURCC('N', 'A', 'M', 'E')
|
||||
#define AI_LWO_FLAG AI_IFF_FOURCC('F', 'L', 'A', 'G')
|
||||
#define AI_LWO_TAG AI_IFF_FOURCC('T', 'A', 'G', ' ')
|
||||
#define AI_LWO_VALU AI_IFF_FOURCC('V', 'A', 'L', 'U')
|
||||
#define AI_LWO_IBGC AI_IFF_FOURCC('I', 'B', 'G', 'C')
|
||||
#define AI_LWO_IOPC AI_IFF_FOURCC('I', 'O', 'P', 'C')
|
||||
#define AI_LWO_IIMG AI_IFF_FOURCC('I', 'I', 'M', 'G')
|
||||
#define AI_LWO_TXTR AI_IFF_FOURCC('T', 'X', 'T', 'R')
|
||||
|
||||
#define AI_LWO_IFAL AI_IFF_FOURCC('I', 'F', 'A', 'L')
|
||||
#define AI_LWO_ISCL AI_IFF_FOURCC('I', 'S', 'C', 'L')
|
||||
#define AI_LWO_IPOS AI_IFF_FOURCC('I', 'P', 'O', 'S')
|
||||
#define AI_LWO_IROT AI_IFF_FOURCC('I', 'R', 'O', 'T')
|
||||
#define AI_LWO_IBMP AI_IFF_FOURCC('I', 'B', 'M', 'P')
|
||||
#define AI_LWO_IUTD AI_IFF_FOURCC('I', 'U', 'T', 'D')
|
||||
#define AI_LWO_IVTD AI_IFF_FOURCC('I', 'V', 'T', 'D')
|
||||
|
||||
#define AI_LWO_IPIX AI_IFF_FOURCC('I', 'P', 'I', 'X')
|
||||
#define AI_LWO_IMIP AI_IFF_FOURCC('I', 'M', 'I', 'P')
|
||||
#define AI_LWO_IMOD AI_IFF_FOURCC('I', 'M', 'O', 'D')
|
||||
#define AI_LWO_AMOD AI_IFF_FOURCC('A', 'M', 'O', 'D')
|
||||
#define AI_LWO_IINV AI_IFF_FOURCC('I', 'I', 'N', 'V')
|
||||
#define AI_LWO_INCR AI_IFF_FOURCC('I', 'N', 'C', 'R')
|
||||
#define AI_LWO_IAXS AI_IFF_FOURCC('I', 'A', 'X', 'S')
|
||||
#define AI_LWO_IFOT AI_IFF_FOURCC('I', 'F', 'O', 'T')
|
||||
#define AI_LWO_ITIM AI_IFF_FOURCC('I', 'T', 'I', 'M')
|
||||
#define AI_LWO_IWRL AI_IFF_FOURCC('I', 'W', 'R', 'L')
|
||||
#define AI_LWO_IUTI AI_IFF_FOURCC('I', 'U', 'T', 'I')
|
||||
#define AI_LWO_IINX AI_IFF_FOURCC('I', 'I', 'N', 'X')
|
||||
#define AI_LWO_IINY AI_IFF_FOURCC('I', 'I', 'N', 'Y')
|
||||
#define AI_LWO_IINZ AI_IFF_FOURCC('I', 'I', 'N', 'Z')
|
||||
#define AI_LWO_IREF AI_IFF_FOURCC('I', 'R', 'E', 'F')
|
||||
#define AI_LWO_IMST AI_IFF_FOURCC('I', 'M', 'S', 'T')
|
||||
#define AI_LWO_VPVL AI_IFF_FOURCC('V', 'P', 'V', 'L')
|
||||
#define AI_LWO_VPRM AI_IFF_FOURCC('V', 'P', 'R', 'M')
|
||||
#define AI_LWO_IMAP AI_IFF_FOURCC('I', 'M', 'A', 'P')
|
||||
#define AI_LWO_IUVI AI_IFF_FOURCC('I', 'U', 'V', 'I')
|
||||
#define AI_LWO_IUTL AI_IFF_FOURCC('I', 'U', 'T', 'L')
|
||||
#define AI_LWO_IVTL AI_IFF_FOURCC('I', 'V', 'T', 'L')
|
||||
|
||||
// MODO extension - per-vertex normal vectors
|
||||
#define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M')
|
||||
|
||||
@@ -555,6 +607,31 @@ struct Surface {
|
||||
float mAdditiveTransparency;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Data structure for a LWO node
|
||||
*/
|
||||
struct Node {
|
||||
// Name of node
|
||||
std::string mName;
|
||||
|
||||
// RefName of node
|
||||
std::string mRefName;
|
||||
|
||||
// Ref FileName
|
||||
std::string fileName;
|
||||
};
|
||||
|
||||
struct NodeAttribute {
|
||||
//! Color of the surface
|
||||
aiColor3D mColor;
|
||||
|
||||
//! true for two-sided materials
|
||||
bool bDoubleSided;
|
||||
|
||||
//! Various material parameters
|
||||
float mDiffuseValue, mSpecularValue, mTransparency, mGlossiness, mLuminosity, mColorHighlights;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
#define AI_LWO_VALIDATE_CHUNK_LENGTH(length, name, size) \
|
||||
if (length < size) { \
|
||||
|
||||
@@ -83,6 +83,7 @@ static const aiImporterDesc desc = {
|
||||
LWOImporter::LWOImporter() :
|
||||
mIsLWO2(),
|
||||
mIsLXOB(),
|
||||
mIsLWO3(),
|
||||
mLayers(),
|
||||
mCurLayer(),
|
||||
mTags(),
|
||||
@@ -182,16 +183,19 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
||||
mCurLayer->mIndex = (uint16_t) -1;
|
||||
|
||||
// old lightwave file format (prior to v6)
|
||||
mIsLWO2 = false;
|
||||
mIsLWO3 = false;
|
||||
mIsLXOB = false;
|
||||
|
||||
if (AI_LWO_FOURCC_LWOB == fileType) {
|
||||
ASSIMP_LOG_INFO("LWO file format: LWOB (<= LightWave 5.5)");
|
||||
|
||||
mIsLWO2 = false;
|
||||
mIsLXOB = false;
|
||||
LoadLWOBFile();
|
||||
} else if (AI_LWO_FOURCC_LWO2 == fileType) {
|
||||
// New lightwave format
|
||||
mIsLXOB = false;
|
||||
ASSIMP_LOG_INFO("LWO file format: LWO2 (>= LightWave 6)");
|
||||
} else if ( AI_LWO_FOURCC_LWO3 == fileType ) {
|
||||
ASSIMP_LOG_INFO("LWO file format: LWO3 (>= LightWave 2018)");
|
||||
} else if (AI_LWO_FOURCC_LXOB == fileType) {
|
||||
// MODO file format
|
||||
mIsLXOB = true;
|
||||
@@ -207,8 +211,13 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
||||
throw DeadlyImportError("Unknown LWO sub format: ", szBuff);
|
||||
}
|
||||
|
||||
if (AI_LWO_FOURCC_LWOB != fileType) {
|
||||
mIsLWO2 = true;
|
||||
if (AI_LWO_FOURCC_LWOB != fileType) { //
|
||||
if( AI_LWO_FOURCC_LWO3 == fileType ) {
|
||||
mIsLWO3 = true;
|
||||
} else {
|
||||
mIsLWO2 = true;
|
||||
}
|
||||
|
||||
LoadLWO2File();
|
||||
|
||||
// The newer lightwave format allows the user to configure the
|
||||
@@ -442,6 +451,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
|
||||
|
||||
// The RemoveRedundantMaterials step will clean this up later
|
||||
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
|
||||
|
||||
for (unsigned int mat = 0; mat < pScene->mNumMaterials; ++mat) {
|
||||
aiMaterial *pcMat = new aiMaterial();
|
||||
pScene->mMaterials[mat] = pcMat;
|
||||
@@ -687,7 +697,7 @@ void LWOImporter::ResolveClips() {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::AdjustTexturePath(std::string &out) {
|
||||
// --- this function is used for both LWO2 and LWOB
|
||||
if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) {
|
||||
if (!mIsLWO2 && !mIsLWO3 && ::strstr(out.c_str(), "(sequence)")) {
|
||||
|
||||
// remove the (sequence) and append 000
|
||||
ASSIMP_LOG_INFO("LWOB: Sequence of animated texture found. It will be ignored");
|
||||
@@ -730,7 +740,7 @@ void LWOImporter::LoadLWOPoints(unsigned int length) {
|
||||
throw DeadlyImportError("LWO2: Points chunk length is not multiple of vertexLen (12)");
|
||||
}
|
||||
unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
|
||||
if (mIsLWO2) {
|
||||
if (mIsLWO2 || mIsLWO3) {
|
||||
mCurLayer->mTempPoints.reserve(regularSize + (regularSize >> 2u));
|
||||
mCurLayer->mTempPoints.resize(regularSize);
|
||||
|
||||
@@ -1155,6 +1165,76 @@ void LWOImporter::LoadLWO2Clip(unsigned int length) {
|
||||
}
|
||||
}
|
||||
|
||||
void LWOImporter::LoadLWO3Clip(unsigned int length) {
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(length, CLIP, 12);
|
||||
|
||||
mClips.push_back(LWO::Clip());
|
||||
LWO::Clip &clip = mClips.back();
|
||||
|
||||
// first - get the index of the clip
|
||||
clip.idx = GetU4();
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
switch (head.type) {
|
||||
case AI_LWO_STIL:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, STIL, 1);
|
||||
|
||||
// "Normal" texture
|
||||
GetS0(clip.path, head.length);
|
||||
clip.type = Clip::STILL;
|
||||
break;
|
||||
|
||||
case AI_LWO_ISEQ:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ISEQ, 16);
|
||||
// Image sequence. We'll later take the first.
|
||||
{
|
||||
uint8_t digits = GetU1();
|
||||
mFileBuffer++;
|
||||
int16_t offset = GetU2();
|
||||
mFileBuffer += 4;
|
||||
int16_t start = GetU2();
|
||||
mFileBuffer += 4;
|
||||
|
||||
std::string s;
|
||||
std::ostringstream ss;
|
||||
GetS0(s, head.length);
|
||||
|
||||
head.length -= (uint16_t)s.length() + 1;
|
||||
ss << s;
|
||||
ss << std::setw(digits) << offset + start;
|
||||
GetS0(s, head.length);
|
||||
ss << s;
|
||||
clip.path = ss.str();
|
||||
clip.type = Clip::SEQ;
|
||||
}
|
||||
break;
|
||||
|
||||
case AI_LWO_STCC:
|
||||
ASSIMP_LOG_WARN("LWO3: Color shifted images are not supported");
|
||||
break;
|
||||
|
||||
case AI_LWO_ANIM:
|
||||
ASSIMP_LOG_WARN("LWO3: Animated textures are not supported");
|
||||
break;
|
||||
|
||||
case AI_LWO_XREF:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, XREF, 4);
|
||||
|
||||
// Just a cross-reference to another CLIp
|
||||
clip.type = Clip::REF;
|
||||
clip.clipRef = GetU4();
|
||||
break;
|
||||
|
||||
case AI_LWO_NEGA:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, NEGA, 2);
|
||||
clip.negate = (0 != GetU2());
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSIMP_LOG_WARN("LWO3: Encountered unknown CLIP sub-chunk");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Load envelope description
|
||||
void LWOImporter::LoadLWO2Envelope(unsigned int length) {
|
||||
@@ -1265,6 +1345,104 @@ void LWOImporter::LoadLWO2Envelope(unsigned int length) {
|
||||
}
|
||||
}
|
||||
|
||||
void LWOImporter::LoadLWO3Envelope(unsigned int length) {
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + length;
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(length, ENVL, 4);
|
||||
|
||||
mEnvelopes.push_back(LWO::Envelope());
|
||||
LWO::Envelope &envelope = mEnvelopes.back();
|
||||
|
||||
// Get the index of the envelope
|
||||
envelope.index = ReadVSizedIntLWO2(mFileBuffer);
|
||||
|
||||
// ... and read all blocks
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= end) break;
|
||||
LE_NCONST IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
|
||||
if (mFileBuffer + head.length > end)
|
||||
throw DeadlyImportError("LWO3: Invalid envelope chunk length");
|
||||
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
switch (head.type) {
|
||||
// Type & representation of the envelope
|
||||
case AI_LWO_TYPE:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TYPE, 4);
|
||||
mFileBuffer++; // skip user format
|
||||
|
||||
// Determine type of envelope
|
||||
envelope.type = (LWO::EnvelopeType)*mFileBuffer;
|
||||
++mFileBuffer;
|
||||
break;
|
||||
|
||||
// precondition
|
||||
case AI_LWO_PRE:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, PRE, 4);
|
||||
envelope.pre = (LWO::PrePostBehaviour)GetU2();
|
||||
break;
|
||||
|
||||
// postcondition
|
||||
case AI_LWO_POST:
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, POST, 4);
|
||||
envelope.post = (LWO::PrePostBehaviour)GetU2();
|
||||
break;
|
||||
|
||||
// keyframe
|
||||
case AI_LWO_KEY: {
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, KEY, 10);
|
||||
|
||||
envelope.keys.push_back(LWO::Key());
|
||||
LWO::Key &key = envelope.keys.back();
|
||||
|
||||
key.time = GetF4();
|
||||
key.value = GetF4();
|
||||
break;
|
||||
}
|
||||
|
||||
// interval interpolation
|
||||
case AI_LWO_SPAN: {
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPAN, 6);
|
||||
if (envelope.keys.size() < 2)
|
||||
ASSIMP_LOG_WARN("LWO3: Unexpected SPAN chunk");
|
||||
else {
|
||||
LWO::Key &key = envelope.keys.back();
|
||||
switch (GetU4()) {
|
||||
case AI_LWO_STEP:
|
||||
key.inter = LWO::IT_STEP;
|
||||
break;
|
||||
case AI_LWO_LINE:
|
||||
key.inter = LWO::IT_LINE;
|
||||
break;
|
||||
case AI_LWO_TCB:
|
||||
key.inter = LWO::IT_TCB;
|
||||
break;
|
||||
case AI_LWO_HERM:
|
||||
key.inter = LWO::IT_HERM;
|
||||
break;
|
||||
case AI_LWO_BEZI:
|
||||
key.inter = LWO::IT_BEZI;
|
||||
break;
|
||||
case AI_LWO_BEZ2:
|
||||
key.inter = LWO::IT_BEZ2;
|
||||
break;
|
||||
default:
|
||||
ASSIMP_LOG_WARN("LWO3: Unknown interval interpolation mode");
|
||||
};
|
||||
|
||||
// todo ... read params
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSIMP_LOG_WARN("LWO3: Encountered unknown ENVL subchunk");
|
||||
break;
|
||||
}
|
||||
// regardless how much we did actually read, go to the next chunk
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Load file - master function
|
||||
void LWOImporter::LoadLWO2File() {
|
||||
@@ -1272,16 +1450,25 @@ void LWOImporter::LoadLWO2File() {
|
||||
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + fileSize;
|
||||
unsigned int iUnnamed = 0;
|
||||
|
||||
while (true) {
|
||||
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end) break;
|
||||
const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
|
||||
int bufOffset = 0;
|
||||
if( head.type == AI_IFF_FOURCC_FORM ) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO2: Chunk length points behind the file");
|
||||
break;
|
||||
}
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
|
||||
mFileBuffer += bufOffset;
|
||||
if (!head.length) {
|
||||
mFileBuffer = next;
|
||||
continue;
|
||||
@@ -1337,7 +1524,6 @@ void LWOImporter::LoadLWO2File() {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// vertex list
|
||||
case AI_LWO_PNTS: {
|
||||
if (skip)
|
||||
@@ -1399,19 +1585,29 @@ void LWOImporter::LoadLWO2File() {
|
||||
|
||||
// surface chunk
|
||||
case AI_LWO_SURF: {
|
||||
LoadLWO2Surface(head.length);
|
||||
if( mIsLWO3 )
|
||||
LoadLWO3Surface(head.length);
|
||||
else
|
||||
LoadLWO2Surface(head.length);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// clip chunk
|
||||
case AI_LWO_CLIP: {
|
||||
LoadLWO2Clip(head.length);
|
||||
if( mIsLWO3 )
|
||||
LoadLWO3Clip(head.length);
|
||||
else
|
||||
LoadLWO2Clip(head.length);
|
||||
break;
|
||||
}
|
||||
|
||||
// envelope chunk
|
||||
case AI_LWO_ENVL: {
|
||||
LoadLWO2Envelope(head.length);
|
||||
if( mIsLWO3 )
|
||||
LoadLWO3Envelope(head.length);
|
||||
else
|
||||
LoadLWO2Envelope(head.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,8 @@ private:
|
||||
*/
|
||||
inline void GetS0(std::string &out, unsigned int max);
|
||||
inline float GetF4();
|
||||
inline float GetF8();
|
||||
inline uint64_t GetU8();
|
||||
inline uint32_t GetU4();
|
||||
inline uint16_t GetU2();
|
||||
inline uint8_t GetU1();
|
||||
@@ -131,6 +133,7 @@ private:
|
||||
* @param size Maximum size to be read, in bytes.
|
||||
*/
|
||||
void LoadLWO2Surface(unsigned int size);
|
||||
void LoadLWO3Surface(unsigned int size);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads a texture block from a LWO2 file.
|
||||
@@ -197,12 +200,23 @@ private:
|
||||
* @param length Size of the chunk
|
||||
*/
|
||||
void LoadLWO2Clip(unsigned int length);
|
||||
void LoadLWO3Clip(unsigned int length);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load an envelope from an EVL chunk
|
||||
* @param length Size of the chunk
|
||||
*/
|
||||
void LoadLWO2Envelope(unsigned int length);
|
||||
void LoadLWO3Envelope(unsigned int length);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load an nodal blocks from surface form
|
||||
* @param length Size of the chunk
|
||||
*/
|
||||
void LoadNodalBlocks(unsigned int length);
|
||||
void LoadNodes(unsigned int length);
|
||||
void LoadNodeTag(unsigned int length);
|
||||
void LoadNodeData(unsigned int length);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Count vertices and faces in a LWOB/LWO2 file
|
||||
@@ -347,6 +361,8 @@ protected:
|
||||
/** true if the file is a LXOB file*/
|
||||
bool mIsLXOB;
|
||||
|
||||
bool mIsLWO3;
|
||||
|
||||
/** Temporary list of layers from the file */
|
||||
LayerList *mLayers;
|
||||
|
||||
@@ -400,6 +416,22 @@ inline float LWOImporter::GetF4() {
|
||||
return f;
|
||||
}
|
||||
|
||||
inline float LWOImporter::GetF8() {
|
||||
double f;
|
||||
::memcpy(&f, mFileBuffer, 8);
|
||||
mFileBuffer += 8;
|
||||
AI_LSWAP8(f);
|
||||
return (float)f;
|
||||
}
|
||||
|
||||
inline uint64_t LWOImporter::GetU8() {
|
||||
uint64_t f;
|
||||
::memcpy(&f, mFileBuffer, 8);
|
||||
mFileBuffer += 8;
|
||||
AI_LSWAP8(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint32_t LWOImporter::GetU4() {
|
||||
uint32_t f;
|
||||
|
||||
@@ -159,7 +159,7 @@ bool LWOImporter::HandleTextures(aiMaterial *pcMat, const TextureList &in, aiTex
|
||||
|
||||
// The older LWOB format does not use indirect references to clips.
|
||||
// The file name of a texture is directly specified in the tex chunk.
|
||||
if (mIsLWO2) {
|
||||
if (mIsLWO2 || mIsLWO3) {
|
||||
// find the corresponding clip (take the last one if multiple
|
||||
// share the same index)
|
||||
ClipList::iterator end = mClips.end(), candidate = end;
|
||||
@@ -270,7 +270,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
|
||||
aiShadingMode m;
|
||||
if (surf.mSpecularValue && surf.mGlossiness) {
|
||||
float fGloss;
|
||||
if (mIsLWO2) {
|
||||
if (mIsLWO2 || mIsLWO3) {
|
||||
fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0));
|
||||
} else {
|
||||
if (16.0 >= surf.mGlossiness)
|
||||
@@ -688,6 +688,252 @@ void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader * /*head*/,
|
||||
surf.mShaders.push_back(shader);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadNodalBlocks(unsigned int size) {
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= end)
|
||||
break;
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
int bufOffset = 0;
|
||||
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO3: cannot read length; LoadNodalBlocks");
|
||||
}
|
||||
int node_idx = 0;
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
switch (head.type) {
|
||||
case AI_LWO_NNDS:
|
||||
node_idx++;
|
||||
LoadNodes(head.length);
|
||||
break;
|
||||
}
|
||||
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadNodes(unsigned int size) {
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= end)
|
||||
break;
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
int bufOffset = 0;
|
||||
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO3: cannot read length; LoadNodes");
|
||||
}
|
||||
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
switch (head.type) {
|
||||
case AI_LWO_NTAG:
|
||||
LoadNodeTag(head.length);
|
||||
break;
|
||||
}
|
||||
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadNodeTag(unsigned int size) {
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= end)
|
||||
break;
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
int bufOffset = 0;
|
||||
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO3: cannot read length; LoadNodeTag");
|
||||
}
|
||||
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
|
||||
switch (head.type) {
|
||||
case AI_LWO_NDTA:
|
||||
LoadNodeData(head.length);
|
||||
break;
|
||||
}
|
||||
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadNodeData(unsigned int size) {
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||
|
||||
LWO::Surface &surf = mSurfaces->back();
|
||||
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= end)
|
||||
break;
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
int bufOffset = 0;
|
||||
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO3: INVALID LENGTH; LoadNodeData");
|
||||
}
|
||||
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
switch (head.type) {
|
||||
case AI_LWO_VERS:
|
||||
case AI_LWO_ENUM:
|
||||
case AI_LWO_IBGC:
|
||||
case AI_LWO_IOPC:
|
||||
case AI_LWO_IIMG:
|
||||
case AI_LWO_TXTR:
|
||||
case AI_LWO_IFAL:
|
||||
case AI_LWO_ISCL:
|
||||
case AI_LWO_IPOS:
|
||||
case AI_LWO_IROT:
|
||||
case AI_LWO_IBMP:
|
||||
case AI_LWO_IUTD:
|
||||
case AI_LWO_IVTD:
|
||||
|
||||
case AI_LWO_IPIX:
|
||||
case AI_LWO_IMIP:
|
||||
case AI_LWO_IMOD:
|
||||
case AI_LWO_AMOD:
|
||||
case AI_LWO_IINV:
|
||||
case AI_LWO_INCR:
|
||||
case AI_LWO_IAXS:
|
||||
case AI_LWO_IFOT:
|
||||
case AI_LWO_ITIM:
|
||||
case AI_LWO_IWRL:
|
||||
case AI_LWO_IUTI:
|
||||
case AI_LWO_IUVI:
|
||||
case AI_LWO_IINX:
|
||||
case AI_LWO_IINY:
|
||||
case AI_LWO_IINZ:
|
||||
case AI_LWO_IREF:
|
||||
case AI_LWO_IMST:
|
||||
case AI_LWO_IMAP:
|
||||
case AI_LWO_IUTL:
|
||||
case AI_LWO_IVTL:
|
||||
case AI_LWO_VPVL:
|
||||
case AI_LWO_VPRM:
|
||||
mFileBuffer = next;
|
||||
break;
|
||||
case AI_LWO_ENTR:
|
||||
std::string attrName;
|
||||
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= next)
|
||||
break;
|
||||
|
||||
IFF::ChunkHeader head1 = IFF::LoadChunk(mFileBuffer);
|
||||
int bufOffset1 = 0;
|
||||
if (head1.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head1 = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset1 = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head1.length > end) {
|
||||
throw DeadlyImportError("LWO3: cannot read length;");
|
||||
}
|
||||
uint8_t *const next1 = mFileBuffer + head1.length;
|
||||
mFileBuffer += bufOffset1;
|
||||
|
||||
switch (head1.type) {
|
||||
case AI_LWO_FLAG:
|
||||
case AI_LWO_TAG:
|
||||
mFileBuffer = next1;
|
||||
break;
|
||||
case AI_LWO_NAME:
|
||||
GetS0(attrName, head1.length);
|
||||
break;
|
||||
case AI_LWO_VALU:
|
||||
mFileBuffer += 8;
|
||||
|
||||
std::string valueType;
|
||||
GetS0(valueType, 8);
|
||||
|
||||
if (valueType == "int") {
|
||||
static_cast<void>(GetU4());
|
||||
} else if (valueType == "double") {
|
||||
static_cast<void>(GetU8());
|
||||
} else if (valueType == "vparam") {
|
||||
mFileBuffer += 24;
|
||||
|
||||
float value = GetF8();
|
||||
if (attrName == "Diffuse") {
|
||||
surf.mDiffuseValue = value;
|
||||
} else if (attrName == "Specular") {
|
||||
surf.mSpecularValue = value;
|
||||
} else if (attrName == "Transparency") {
|
||||
surf.mTransparency = value;
|
||||
} else if (attrName == "Glossiness") {
|
||||
surf.mGlossiness = value;
|
||||
} else if (attrName == "Luminosity") {
|
||||
surf.mLuminosity = value;
|
||||
} else if (attrName == "Color Highlight") {
|
||||
surf.mColorHighlights = value;
|
||||
} else if (attrName == "Refraction Index") {
|
||||
surf.mIOR = value;
|
||||
} else if (attrName == "Bump Height") {
|
||||
surf.mBumpIntensity = value;
|
||||
}
|
||||
} else if (valueType == "vparam3") {
|
||||
mFileBuffer += 24;
|
||||
|
||||
float value1, value2, value3;
|
||||
value1 = GetF8();
|
||||
value2 = GetF8();
|
||||
value3 = GetF8();
|
||||
|
||||
if (attrName == "Color") {
|
||||
surf.mColor.r = value1;
|
||||
surf.mColor.g = value2;
|
||||
surf.mColor.b = value3;
|
||||
}
|
||||
}
|
||||
|
||||
mFileBuffer = next1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2Surface(unsigned int size) {
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + size;
|
||||
@@ -841,4 +1087,69 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) {
|
||||
}
|
||||
}
|
||||
|
||||
void LWOImporter::LoadLWO3Surface(unsigned int size) {
|
||||
mFileBuffer += 8;
|
||||
LE_NCONST uint8_t *const end = mFileBuffer + size - 12;
|
||||
|
||||
mSurfaces->push_back(LWO::Surface());
|
||||
LWO::Surface &surf = mSurfaces->back();
|
||||
|
||||
GetS0(surf.mName, size);
|
||||
|
||||
// check whether this surface was derived from any other surface
|
||||
std::string derived;
|
||||
GetS0(derived, (unsigned int)(end - mFileBuffer));
|
||||
if (derived.length()) {
|
||||
// yes, find this surface
|
||||
for (SurfaceList::iterator it = mSurfaces->begin(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) {
|
||||
if ((*it).mName == derived) {
|
||||
// we have it ...
|
||||
surf = *it;
|
||||
derived.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (derived.size()) {
|
||||
ASSIMP_LOG_WARN("LWO3: Unable to find source surface: ", derived);
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
if (mFileBuffer + 8 >= end)
|
||||
break;
|
||||
|
||||
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
|
||||
int bufOffset = 0;
|
||||
if( head.type == AI_IFF_FOURCC_FORM ) { // not chunk, it's a form
|
||||
mFileBuffer -= 8;
|
||||
head = IFF::LoadForm(mFileBuffer);
|
||||
bufOffset = 4;
|
||||
}
|
||||
|
||||
if (mFileBuffer + head.length > end) {
|
||||
throw DeadlyImportError("LWO3: cannot read length; LoadLWO3Surface");
|
||||
}
|
||||
|
||||
uint8_t *const next = mFileBuffer + head.length;
|
||||
mFileBuffer += bufOffset;
|
||||
switch (head.type) {
|
||||
case AI_LWO_NODS:
|
||||
LoadNodalBlocks(head.length);
|
||||
break;
|
||||
// polygon sidedness
|
||||
case AI_LWO_SIDE: {
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SIDE, 2);
|
||||
surf.bDoubleSided = (3 == GetU2());
|
||||
break;
|
||||
}
|
||||
// maximum smoothing angle
|
||||
case AI_LWO_SMAN: {
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SMAN, 4);
|
||||
surf.mMaximumSmoothAngle = std::fabs(GetF4());
|
||||
break;
|
||||
}
|
||||
}
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_X_IMPORTER
|
||||
|
||||
@@ -857,6 +857,9 @@ void MDLImporter::CalculateUVCoordinates_MDL5() {
|
||||
const float fHeight = (float)iHeight;
|
||||
aiMesh *pcMesh = this->pScene->mMeshes[0];
|
||||
for (unsigned int i = 0; i < pcMesh->mNumVertices; ++i) {
|
||||
if (!pcMesh->HasTextureCoords(0)) {
|
||||
continue;
|
||||
}
|
||||
pcMesh->mTextureCoords[0][i].x /= fWidth;
|
||||
pcMesh->mTextureCoords[0][i].y /= fHeight;
|
||||
pcMesh->mTextureCoords[0][i].y = 1.0f - pcMesh->mTextureCoords[0][i].y; // DX to OGL
|
||||
|
||||
@@ -493,7 +493,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
||||
size_t iLen2 = iLen + 1;
|
||||
iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
|
||||
memcpy(szFile.data, (const char *)szCurrent, iLen2);
|
||||
szFile.length = (ai_uint32)iLen;
|
||||
szFile.length = static_cast<ai_uint32>(iLen2);
|
||||
|
||||
szCurrent += iLen2;
|
||||
|
||||
|
||||
@@ -605,6 +605,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
|
||||
|
||||
mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
// Preserve the original illum value
|
||||
mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
|
||||
|
||||
// Adding material colors
|
||||
mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
||||
@@ -238,6 +238,7 @@ void ObjFileMtlImporter::load() {
|
||||
|
||||
case 'a': // Anisotropy
|
||||
{
|
||||
++m_DataIt;
|
||||
getFloatValue(m_pModel->m_pCurrentMaterial->anisotropy);
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
} break;
|
||||
|
||||
@@ -117,6 +117,7 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||
unsigned int processed = 0;
|
||||
size_t lastFilePos(0);
|
||||
|
||||
bool insideCstype = false;
|
||||
std::vector<char> buffer;
|
||||
while (streamBuffer.getNextDataLine(buffer, '\\')) {
|
||||
m_DataIt = buffer.begin();
|
||||
@@ -131,6 +132,18 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||
m_progress->UpdateFileRead(processed, progressTotal);
|
||||
}
|
||||
|
||||
// handle cstype section end (http://paulbourke.net/dataformats/obj/)
|
||||
if (insideCstype) {
|
||||
switch (*m_DataIt) {
|
||||
case 'e': {
|
||||
std::string name;
|
||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
||||
insideCstype = name != "end";
|
||||
} break;
|
||||
}
|
||||
goto pf_skip_line;
|
||||
}
|
||||
|
||||
// parse line
|
||||
switch (*m_DataIt) {
|
||||
case 'v': // Parse a vertex texture coordinate
|
||||
@@ -219,6 +232,14 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
|
||||
getObjectName();
|
||||
} break;
|
||||
|
||||
case 'c': // handle cstype section start
|
||||
{
|
||||
std::string name;
|
||||
getNameNoSpace(m_DataIt, m_DataItEnd, name);
|
||||
insideCstype = name == "cstype";
|
||||
goto pf_skip_line;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
pf_skip_line:
|
||||
m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
|
||||
|
||||
@@ -260,20 +260,9 @@ public:
|
||||
VEC4,
|
||||
MAT2,
|
||||
MAT3,
|
||||
MAT4 };
|
||||
|
||||
private:
|
||||
static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
|
||||
|
||||
struct Info {
|
||||
const char *name;
|
||||
unsigned int numComponents;
|
||||
MAT4
|
||||
};
|
||||
|
||||
template <int N>
|
||||
struct data { static const Info infos[NUM_VALUES]; };
|
||||
|
||||
public:
|
||||
inline static Value FromString(const char *str) {
|
||||
for (size_t i = 0; i < NUM_VALUES; ++i) {
|
||||
if (strcmp(data<0>::infos[i].name, str) == 0) {
|
||||
@@ -290,40 +279,31 @@ public:
|
||||
inline static unsigned int GetNumComponents(Value type) {
|
||||
return data<0>::infos[static_cast<size_t>(type)].numComponents;
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
|
||||
struct Info {
|
||||
const char *name;
|
||||
unsigned int numComponents;
|
||||
};
|
||||
|
||||
template <int N>
|
||||
struct data {
|
||||
static const Info infos[NUM_VALUES];
|
||||
};
|
||||
};
|
||||
|
||||
// must match the order of the AttribTypeTraits::Value enum!
|
||||
template <int N>
|
||||
const AttribType::Info
|
||||
AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
|
||||
{ "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 }
|
||||
};
|
||||
|
||||
/*
|
||||
//! A reference to one top-level object, which is valid
|
||||
//! until the Asset instance is destroyed
|
||||
template<class T>
|
||||
class Ref
|
||||
{
|
||||
std::vector<T*>* vector;
|
||||
unsigned int index;
|
||||
|
||||
public:
|
||||
Ref() : vector(0), index(0) {}
|
||||
Ref(std::vector<T*>& vec, unsigned int idx) : vector(&vec), index(idx) {}
|
||||
|
||||
inline unsigned int GetIndex() const
|
||||
{ return index; }
|
||||
|
||||
operator bool() const
|
||||
{ return vector != 0; }
|
||||
|
||||
T* operator->()
|
||||
{ return (*vector)[index]; }
|
||||
|
||||
T& operator*()
|
||||
{ return *((*vector)[index]); }
|
||||
};*/
|
||||
const AttribType::Info AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
|
||||
{ "SCALAR", 1 },
|
||||
{ "VEC2", 2 },
|
||||
{ "VEC3", 3 },
|
||||
{ "VEC4", 4 },
|
||||
{ "MAT2", 4 },
|
||||
{ "MAT3", 9 },
|
||||
{ "MAT4", 16 }
|
||||
};
|
||||
|
||||
//! Base class for all glTF top-level objects
|
||||
struct Object {
|
||||
@@ -333,6 +313,7 @@ struct Object {
|
||||
//! Objects marked as special are not exported (used to emulate the binary body buffer)
|
||||
virtual bool IsSpecial() const { return false; }
|
||||
|
||||
Object() = default;
|
||||
virtual ~Object() {}
|
||||
|
||||
//! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
|
||||
@@ -401,21 +382,19 @@ struct Accessor : public Object {
|
||||
return Indexer(*this);
|
||||
}
|
||||
|
||||
Accessor() {}
|
||||
Accessor() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
//! A buffer points to binary geometry, animation, or skins.
|
||||
struct Buffer : public Object {
|
||||
/********************* Types *********************/
|
||||
public:
|
||||
enum Type {
|
||||
Type_arraybuffer,
|
||||
Type_text
|
||||
};
|
||||
|
||||
/// \struct SEncodedRegion
|
||||
/// Descriptor of encoded region in "bufferView".
|
||||
/// @brief Descriptor of encoded region in "bufferView".
|
||||
struct SEncodedRegion {
|
||||
const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes.
|
||||
const size_t EncodedData_Length; ///< Size of encoded region, in bytes.
|
||||
@@ -423,8 +402,7 @@ public:
|
||||
const size_t DecodedData_Length; ///< Size of decoded region, in bytes.
|
||||
const std::string ID; ///< ID of the region.
|
||||
|
||||
/// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
|
||||
/// Constructor.
|
||||
/// @brief Constructor.
|
||||
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
|
||||
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
|
||||
/// \param [in] pDecodedData - pointer to decoded data array.
|
||||
@@ -433,16 +411,13 @@ public:
|
||||
SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
|
||||
Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {}
|
||||
|
||||
/// \fn ~SEncodedRegion()
|
||||
/// Destructor.
|
||||
~SEncodedRegion() { delete[] DecodedData; }
|
||||
};
|
||||
|
||||
/******************* Variables *******************/
|
||||
|
||||
//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
|
||||
size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
|
||||
//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
|
||||
|
||||
Type type;
|
||||
|
||||
@@ -486,7 +461,6 @@ public:
|
||||
|
||||
bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0);
|
||||
|
||||
/// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
|
||||
/// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
|
||||
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
|
||||
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
|
||||
@@ -495,12 +469,10 @@ public:
|
||||
/// \param [in] pID - ID of the region.
|
||||
void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID);
|
||||
|
||||
/// \fn void EncodedRegion_SetCurrent(const std::string& pID)
|
||||
/// Select current encoded region by ID. \sa EncodedRegion_Current.
|
||||
/// \param [in] pID - ID of the region.
|
||||
void EncodedRegion_SetCurrent(const std::string &pID);
|
||||
|
||||
/// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
|
||||
/// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
|
||||
/// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
|
||||
/// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
|
||||
@@ -558,37 +530,29 @@ struct Camera : public Object {
|
||||
} ortographic;
|
||||
};
|
||||
|
||||
Camera() {}
|
||||
Camera() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
//! Image data used to create a texture.
|
||||
struct Image : public Object {
|
||||
std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
|
||||
|
||||
Ref<BufferView> bufferView;
|
||||
|
||||
std::string mimeType;
|
||||
|
||||
int width, height;
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> mData;
|
||||
size_t mDataLength;
|
||||
|
||||
public:
|
||||
Image();
|
||||
void Read(Value &obj, Asset &r);
|
||||
|
||||
inline bool HasData() const { return mDataLength > 0; }
|
||||
|
||||
inline size_t GetDataLength() const { return mDataLength; }
|
||||
|
||||
inline const uint8_t *GetData() const { return mData.get(); }
|
||||
|
||||
inline uint8_t *StealData();
|
||||
|
||||
inline void SetData(uint8_t *data, size_t length, Asset &r);
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> mData;
|
||||
size_t mDataLength;
|
||||
};
|
||||
|
||||
//! Holds a material property that can be a texture or a color
|
||||
@@ -671,6 +635,7 @@ struct Mesh : public Object {
|
||||
};
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
|
||||
/// \struct SCompression_Open3DGC
|
||||
/// Compression of mesh data using Open3DGC algorithm.
|
||||
struct SCompression_Open3DGC : public SExtension {
|
||||
@@ -703,7 +668,6 @@ struct Mesh : public Object {
|
||||
|
||||
Mesh() {}
|
||||
|
||||
/// \fn ~Mesh()
|
||||
/// Destructor.
|
||||
~Mesh() {
|
||||
for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) {
|
||||
@@ -711,15 +675,13 @@ struct Mesh : public Object {
|
||||
};
|
||||
}
|
||||
|
||||
/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
|
||||
/// Get mesh data from JSON-object and place them to root asset.
|
||||
/// @brief Get mesh data from JSON-object and place them to root asset.
|
||||
/// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
|
||||
/// \param [out] pAsset_Root - reference to root asset where data will be stored.
|
||||
void Read(Value &pJSON_Object, Asset &pAsset_Root);
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
|
||||
/// Decode part of "buffer" which encoded with Open3DGC algorithm.
|
||||
/// @brief Decode part of "buffer" which encoded with Open3DGC algorithm.
|
||||
/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
|
||||
/// \param [out] pAsset_Root - reference to root assed where data will be stored.
|
||||
void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root);
|
||||
@@ -759,7 +721,7 @@ struct Sampler : public Object {
|
||||
SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required)
|
||||
SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required)
|
||||
|
||||
Sampler() {}
|
||||
Sampler() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
void SetDefaults();
|
||||
};
|
||||
@@ -767,12 +729,12 @@ struct Sampler : public Object {
|
||||
struct Scene : public Object {
|
||||
std::vector<Ref<Node>> nodes;
|
||||
|
||||
Scene() {}
|
||||
Scene() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
struct Shader : public Object {
|
||||
Shader() {}
|
||||
Shader() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
@@ -782,7 +744,7 @@ struct Skin : public Object {
|
||||
std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
|
||||
std::string name; //!< The user-defined name of this object.
|
||||
|
||||
Skin() {}
|
||||
Skin() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
@@ -796,7 +758,7 @@ struct Technique : public Object {
|
||||
struct Functions {
|
||||
};
|
||||
|
||||
Technique() {}
|
||||
Technique() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
@@ -805,13 +767,7 @@ struct Texture : public Object {
|
||||
Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required)
|
||||
Ref<Image> source; //!< The ID of the image used by this texture. (required)
|
||||
|
||||
//TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA)
|
||||
//TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
|
||||
|
||||
//TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
|
||||
//TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
|
||||
|
||||
Texture() {}
|
||||
Texture() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
@@ -826,7 +782,6 @@ struct Light : public Object {
|
||||
};
|
||||
|
||||
Type type;
|
||||
|
||||
vec4 color;
|
||||
float distance;
|
||||
float constantAttenuation;
|
||||
@@ -835,9 +790,8 @@ struct Light : public Object {
|
||||
float falloffAngle;
|
||||
float falloffExponent;
|
||||
|
||||
Light() {}
|
||||
Light() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
|
||||
void SetDefaults();
|
||||
};
|
||||
|
||||
@@ -865,15 +819,11 @@ struct Animation : public Object {
|
||||
Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
|
||||
};
|
||||
|
||||
// AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
|
||||
// AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
|
||||
// AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data.
|
||||
|
||||
std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
|
||||
AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
|
||||
std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data.
|
||||
|
||||
Animation() {}
|
||||
Animation() = default;
|
||||
void Read(Value &obj, Asset &r);
|
||||
};
|
||||
|
||||
@@ -963,13 +913,11 @@ struct AssetMetadata {
|
||||
|
||||
//! Root object for a glTF asset
|
||||
class Asset {
|
||||
typedef std::gltf_unordered_map<std::string, int> IdMap;
|
||||
using IdMap = std::gltf_unordered_map<std::string, int>;
|
||||
|
||||
template <class T>
|
||||
friend class LazyDict;
|
||||
|
||||
friend struct Buffer; // To access OpenFile
|
||||
|
||||
friend class AssetWriter;
|
||||
|
||||
private:
|
||||
@@ -1010,12 +958,9 @@ public:
|
||||
LazyDict<Material> materials;
|
||||
LazyDict<Mesh> meshes;
|
||||
LazyDict<Node> nodes;
|
||||
//LazyDict<Program> programs;
|
||||
LazyDict<Sampler> samplers;
|
||||
LazyDict<Scene> scenes;
|
||||
//LazyDict<Shader> shaders;
|
||||
LazyDict<Skin> skins;
|
||||
//LazyDict<Technique> techniques;
|
||||
LazyDict<Texture> textures;
|
||||
|
||||
LazyDict<Light> lights; // KHR_materials_common ext
|
||||
@@ -1024,16 +969,20 @@ public:
|
||||
|
||||
public:
|
||||
Asset(IOSystem *io = 0) :
|
||||
mIOSystem(io), asset(), accessors(*this, "accessors"), animations(*this, "animations"), buffers(*this, "buffers"), bufferViews(*this, "bufferViews"), cameras(*this, "cameras"), images(*this, "images"), materials(*this, "materials"), meshes(*this, "meshes"), nodes(*this, "nodes")
|
||||
//, programs (*this, "programs")
|
||||
,
|
||||
mIOSystem(io),
|
||||
asset(),
|
||||
accessors(*this, "accessors"),
|
||||
animations(*this, "animations"),
|
||||
buffers(*this, "buffers"),
|
||||
bufferViews(*this, "bufferViews"),
|
||||
cameras(*this, "cameras"),
|
||||
images(*this, "images"),
|
||||
materials(*this, "materials"),
|
||||
meshes(*this, "meshes"),
|
||||
nodes(*this, "nodes"),
|
||||
samplers(*this, "samplers"),
|
||||
scenes(*this, "scenes")
|
||||
//, shaders (*this, "shaders")
|
||||
,
|
||||
skins(*this, "skins")
|
||||
//, techniques (*this, "techniques")
|
||||
,
|
||||
scenes(*this, "scenes"),
|
||||
skins(*this, "skins"),
|
||||
textures(*this, "textures"),
|
||||
lights(*this, "lights", "KHR_materials_common") {
|
||||
memset(&extensionsUsed, 0, sizeof(extensionsUsed));
|
||||
|
||||
@@ -237,8 +237,6 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out);
|
||||
#define CHECK_EXT(EXT) \
|
||||
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
|
||||
|
||||
|
||||
|
||||
//! Helper struct to represent values that might not be present
|
||||
template <class T>
|
||||
struct Nullable {
|
||||
|
||||
@@ -106,7 +106,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# define gltf_unordered_map tr1::unordered_map
|
||||
# define gltf_unordered_set tr1::unordered_set
|
||||
# else
|
||||
# define gltf_unordered_map unordered_map
|
||||
# define gltf_unordered_map unordered_map
|
||||
# define gltf_unordered_set unordered_set
|
||||
# endif
|
||||
#endif
|
||||
@@ -1087,29 +1087,11 @@ class Asset {
|
||||
|
||||
template <class T>
|
||||
friend class LazyDict;
|
||||
|
||||
friend struct Buffer; // To access OpenFile
|
||||
|
||||
friend class AssetWriter;
|
||||
|
||||
private:
|
||||
IOSystem *mIOSystem;
|
||||
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
|
||||
|
||||
std::string mCurrentAssetDir;
|
||||
|
||||
size_t mSceneLength;
|
||||
size_t mBodyOffset, mBodyLength;
|
||||
|
||||
std::vector<LazyDictBase *> mDicts;
|
||||
|
||||
IdMap mUsedIds;
|
||||
|
||||
Ref<Buffer> mBodyBuffer;
|
||||
|
||||
Asset(Asset &);
|
||||
Asset &operator=(const Asset &);
|
||||
|
||||
public:
|
||||
//! Keeps info about the enabled extensions
|
||||
struct Extensions {
|
||||
@@ -1125,16 +1107,36 @@ public:
|
||||
bool KHR_draco_mesh_compression;
|
||||
bool FB_ngon_encoding;
|
||||
bool KHR_texture_basisu;
|
||||
|
||||
Extensions() :
|
||||
KHR_materials_pbrSpecularGlossiness(false),
|
||||
KHR_materials_unlit(false),
|
||||
KHR_lights_punctual(false),
|
||||
KHR_texture_transform(false),
|
||||
KHR_materials_sheen(false),
|
||||
KHR_materials_clearcoat(false),
|
||||
KHR_materials_transmission(false),
|
||||
KHR_materials_volume(false),
|
||||
KHR_materials_ior(false),
|
||||
KHR_draco_mesh_compression(false),
|
||||
FB_ngon_encoding(false),
|
||||
KHR_texture_basisu(false) {
|
||||
// empty
|
||||
}
|
||||
} extensionsUsed;
|
||||
|
||||
//! Keeps info about the required extensions
|
||||
struct RequiredExtensions {
|
||||
bool KHR_draco_mesh_compression;
|
||||
bool KHR_texture_basisu;
|
||||
|
||||
RequiredExtensions() : KHR_draco_mesh_compression(false), KHR_texture_basisu(false) {
|
||||
// empty
|
||||
}
|
||||
} extensionsRequired;
|
||||
|
||||
AssetMetadata asset;
|
||||
Value *extras = nullptr;
|
||||
Value *extras;
|
||||
|
||||
// Dictionaries for each type of object
|
||||
|
||||
@@ -1156,10 +1158,12 @@ public:
|
||||
Ref<Scene> scene;
|
||||
|
||||
public:
|
||||
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
|
||||
mIOSystem(io),
|
||||
mSchemaDocumentProvider(schemaDocumentProvider),
|
||||
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
|
||||
mDicts(),
|
||||
extensionsUsed(),
|
||||
extensionsRequired(),
|
||||
asset(),
|
||||
extras(nullptr),
|
||||
accessors(*this, "accessors"),
|
||||
animations(*this, "animations"),
|
||||
buffers(*this, "buffers"),
|
||||
@@ -1173,9 +1177,10 @@ public:
|
||||
samplers(*this, "samplers"),
|
||||
scenes(*this, "scenes"),
|
||||
skins(*this, "skins"),
|
||||
textures(*this, "textures") {
|
||||
memset(&extensionsUsed, 0, sizeof(extensionsUsed));
|
||||
memset(&extensionsRequired, 0, sizeof(extensionsRequired));
|
||||
textures(*this, "textures") ,
|
||||
mIOSystem(io),
|
||||
mSchemaDocumentProvider(schemaDocumentProvider) {
|
||||
// empty
|
||||
}
|
||||
|
||||
//! Main function
|
||||
@@ -1192,18 +1197,31 @@ public:
|
||||
|
||||
Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; }
|
||||
|
||||
Asset(Asset &) = delete;
|
||||
Asset &operator=(const Asset &) = delete;
|
||||
|
||||
private:
|
||||
void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
|
||||
|
||||
//! Obtain a JSON document from the stream.
|
||||
// \param second argument is a buffer used by the document. It must be kept
|
||||
// alive while the document is in use.
|
||||
/// Obtain a JSON document from the stream.
|
||||
/// \param second argument is a buffer used by the document. It must be kept
|
||||
/// alive while the document is in use.
|
||||
Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
|
||||
|
||||
void ReadExtensionsUsed(Document &doc);
|
||||
void ReadExtensionsRequired(Document &doc);
|
||||
|
||||
IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
|
||||
|
||||
private:
|
||||
IOSystem *mIOSystem;
|
||||
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
|
||||
std::string mCurrentAssetDir;
|
||||
size_t mSceneLength;
|
||||
size_t mBodyOffset;
|
||||
size_t mBodyLength;
|
||||
IdMap mUsedIds;
|
||||
Ref<Buffer> mBodyBuffer;
|
||||
};
|
||||
|
||||
inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {
|
||||
|
||||
@@ -179,11 +179,11 @@ inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::Accessor
|
||||
v = &(p.attributes.texcoord);
|
||||
} else if ((pos = Compare(attr, "COLOR"))) {
|
||||
v = &(p.attributes.color);
|
||||
} else if ((pos = Compare(attr, "JOINT"))) {
|
||||
} else if ((pos = Compare(attr, "JOINTS"))) {
|
||||
v = &(p.attributes.joint);
|
||||
} else if ((pos = Compare(attr, "JOINTMATRIX"))) {
|
||||
v = &(p.attributes.jointmatrix);
|
||||
} else if ((pos = Compare(attr, "WEIGHT"))) {
|
||||
} else if ((pos = Compare(attr, "WEIGHTS"))) {
|
||||
v = &(p.attributes.weight);
|
||||
} else
|
||||
return false;
|
||||
|
||||
@@ -515,72 +515,74 @@ void glTF2Exporter::GetMatTexProp(const aiMaterial &mat, float &prop, const char
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0) {
|
||||
if (mat.GetTextureCount(tt) > 0) {
|
||||
aiString tex;
|
||||
if (mat.GetTextureCount(tt) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
aiString tex;
|
||||
|
||||
// Read texcoord (UV map index)
|
||||
mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
|
||||
// Read texcoord (UV map index)
|
||||
mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
|
||||
|
||||
if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
|
||||
std::string path = tex.C_Str();
|
||||
if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
|
||||
std::string path = tex.C_Str();
|
||||
|
||||
if (path.size() > 0) {
|
||||
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
|
||||
if (it != mTexturesByPath.end()) {
|
||||
texture = mAsset->textures.Get(it->second);
|
||||
}
|
||||
if (path.size() > 0) {
|
||||
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
|
||||
if (it != mTexturesByPath.end()) {
|
||||
texture = mAsset->textures.Get(it->second);
|
||||
}
|
||||
|
||||
bool useBasisUniversal = false;
|
||||
if (!texture) {
|
||||
std::string texId = mAsset->FindUniqueID("", "texture");
|
||||
texture = mAsset->textures.Create(texId);
|
||||
mTexturesByPath[path] = texture.GetIndex();
|
||||
bool useBasisUniversal = false;
|
||||
if (!texture) {
|
||||
std::string texId = mAsset->FindUniqueID("", "texture");
|
||||
texture = mAsset->textures.Create(texId);
|
||||
mTexturesByPath[path] = texture.GetIndex();
|
||||
|
||||
std::string imgId = mAsset->FindUniqueID("", "image");
|
||||
texture->source = mAsset->images.Create(imgId);
|
||||
std::string imgId = mAsset->FindUniqueID("", "image");
|
||||
texture->source = mAsset->images.Create(imgId);
|
||||
|
||||
const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
|
||||
if (curTex != nullptr) { // embedded
|
||||
texture->source->name = curTex->mFilename.C_Str();
|
||||
const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
|
||||
if (curTex != nullptr) { // embedded
|
||||
texture->source->name = curTex->mFilename.C_Str();
|
||||
|
||||
//basisu: embedded ktx2, bu
|
||||
if (curTex->achFormatHint[0]) {
|
||||
std::string mimeType = "image/";
|
||||
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
|
||||
mimeType += "jpeg";
|
||||
else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
|
||||
useBasisUniversal = true;
|
||||
mimeType += "ktx";
|
||||
} else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
|
||||
useBasisUniversal = true;
|
||||
mimeType += "ktx2";
|
||||
} else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
|
||||
useBasisUniversal = true;
|
||||
mimeType += "basis";
|
||||
} else
|
||||
mimeType += curTex->achFormatHint;
|
||||
texture->source->mimeType = mimeType;
|
||||
}
|
||||
|
||||
// The asset has its own buffer, see Image::SetData
|
||||
//basisu: "image/ktx2", "image/basis" as is
|
||||
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
|
||||
} else {
|
||||
texture->source->uri = path;
|
||||
if (texture->source->uri.find(".ktx") != std::string::npos ||
|
||||
texture->source->uri.find(".basis") != std::string::npos) {
|
||||
//basisu: embedded ktx2, bu
|
||||
if (curTex->achFormatHint[0]) {
|
||||
std::string mimeType = "image/";
|
||||
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
|
||||
mimeType += "jpeg";
|
||||
else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
|
||||
useBasisUniversal = true;
|
||||
}
|
||||
mimeType += "ktx";
|
||||
} else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
|
||||
useBasisUniversal = true;
|
||||
mimeType += "ktx2";
|
||||
} else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
|
||||
useBasisUniversal = true;
|
||||
mimeType += "basis";
|
||||
} else
|
||||
mimeType += curTex->achFormatHint;
|
||||
texture->source->mimeType = mimeType;
|
||||
}
|
||||
|
||||
//basisu
|
||||
if (useBasisUniversal) {
|
||||
mAsset->extensionsUsed.KHR_texture_basisu = true;
|
||||
mAsset->extensionsRequired.KHR_texture_basisu = true;
|
||||
// The asset has its own buffer, see Image::SetData
|
||||
//basisu: "image/ktx2", "image/basis" as is
|
||||
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
|
||||
} else {
|
||||
texture->source->uri = path;
|
||||
if (texture->source->uri.find(".ktx") != std::string::npos ||
|
||||
texture->source->uri.find(".basis") != std::string::npos) {
|
||||
useBasisUniversal = true;
|
||||
}
|
||||
|
||||
GetTexSampler(mat, texture, tt, slot);
|
||||
}
|
||||
|
||||
//basisu
|
||||
if (useBasisUniversal) {
|
||||
mAsset->extensionsUsed.KHR_texture_basisu = true;
|
||||
mAsset->extensionsRequired.KHR_texture_basisu = true;
|
||||
}
|
||||
|
||||
GetTexSampler(mat, texture, tt, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -588,12 +590,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial &mat, TextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
|
||||
Ref<Texture> &texture = prop.texture;
|
||||
|
||||
GetMatTex(mat, texture, prop.texCoord, tt, slot);
|
||||
|
||||
//if (texture) {
|
||||
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
//}
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
|
||||
@@ -681,12 +678,14 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
|
||||
|
||||
bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) {
|
||||
// Return true if got any valid Sheen properties or textures
|
||||
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS)
|
||||
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Default Sheen color factor {0,0,0} disables Sheen, so do not export
|
||||
if (sheen.sheenColorFactor == defaultSheenFactor)
|
||||
if (sheen.sheenColorFactor == defaultSheenFactor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor);
|
||||
|
||||
@@ -781,9 +780,7 @@ void glTF2Exporter::ExportMaterials() {
|
||||
aiColor4D specularColor;
|
||||
ai_real shininess;
|
||||
|
||||
if (
|
||||
mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS &&
|
||||
mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
|
||||
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
|
||||
// convert specular color to luminance
|
||||
float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f;
|
||||
//normalize shininess (assuming max is 1000) with an inverse exponentional curve
|
||||
@@ -916,7 +913,8 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
|
||||
return parentNodeRef;
|
||||
}
|
||||
|
||||
void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef, std::vector<aiMatrix4x4> &inverseBindMatricesData) {
|
||||
void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef,
|
||||
std::vector<aiMatrix4x4> &inverseBindMatricesData) {
|
||||
if (aimesh->mNumBones < 1) {
|
||||
return;
|
||||
}
|
||||
@@ -986,7 +984,8 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
|
||||
} // End: for-loop mNumMeshes
|
||||
|
||||
Mesh::Primitive &p = meshRef->primitives.back();
|
||||
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
|
||||
vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||
if (vertexJointAccessor) {
|
||||
size_t offset = vertexJointAccessor->bufferView->byteOffset;
|
||||
size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
|
||||
@@ -1069,8 +1068,11 @@ void glTF2Exporter::ExportMeshes() {
|
||||
p.ngonEncoded = (aim->mPrimitiveTypes & aiPrimitiveType_NGONEncodingFlag) != 0;
|
||||
|
||||
/******************* Vertices ********************/
|
||||
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (v) p.attributes.position.push_back(v);
|
||||
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3,
|
||||
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (v) {
|
||||
p.attributes.position.push_back(v);
|
||||
}
|
||||
|
||||
/******************** Normals ********************/
|
||||
// Normalize all normals as the validator can emit a warning otherwise
|
||||
@@ -1080,13 +1082,17 @@ void glTF2Exporter::ExportMeshes() {
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (n) p.attributes.normal.push_back(n);
|
||||
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3,
|
||||
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (n) {
|
||||
p.attributes.normal.push_back(n);
|
||||
}
|
||||
|
||||
/************** Texture coordinates **************/
|
||||
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if (!aim->HasTextureCoords(i))
|
||||
if (!aim->HasTextureCoords(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flip UV y coords
|
||||
if (aim->mNumUVComponents[i] > 1) {
|
||||
@@ -1098,16 +1104,21 @@ void glTF2Exporter::ExportMeshes() {
|
||||
if (aim->mNumUVComponents[i] > 0) {
|
||||
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
|
||||
|
||||
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (tc) p.attributes.texcoord.push_back(tc);
|
||||
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i],
|
||||
AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (tc) {
|
||||
p.attributes.texcoord.push_back(tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************** Vertex colors ****************/
|
||||
for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) {
|
||||
Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (c)
|
||||
Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel],
|
||||
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (c) {
|
||||
p.attributes.color.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
/*************** Vertices indices ****************/
|
||||
@@ -1121,7 +1132,8 @@ void glTF2Exporter::ExportMeshes() {
|
||||
}
|
||||
}
|
||||
|
||||
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
|
||||
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR,
|
||||
ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
switch (aim->mPrimitiveTypes) {
|
||||
@@ -1136,6 +1148,7 @@ void glTF2Exporter::ExportMeshes() {
|
||||
break;
|
||||
default: // aiPrimitiveType_TRIANGLE
|
||||
p.mode = PrimitiveMode_TRIANGLES;
|
||||
break;
|
||||
}
|
||||
|
||||
/*************** Skins ****************/
|
||||
@@ -1155,8 +1168,9 @@ void glTF2Exporter::ExportMeshes() {
|
||||
p.targets.resize(aim->mNumAnimMeshes);
|
||||
for (unsigned int am = 0; am < aim->mNumAnimMeshes; ++am) {
|
||||
aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am];
|
||||
if (bExportTargetNames)
|
||||
m->targetNames.push_back(pAnimMesh->mName.data);
|
||||
if (bExportTargetNames) {
|
||||
m->targetNames.emplace_back(pAnimMesh->mName.data);
|
||||
}
|
||||
// position
|
||||
if (pAnimMesh->HasPositions()) {
|
||||
// NOTE: in gltf it is the diff stored
|
||||
@@ -1319,12 +1333,12 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) {
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
|
||||
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||
node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||
unsigned int idx = ExportNode(n->mChildren[i], node);
|
||||
node->children.push_back(mAsset->nodes.Get(idx));
|
||||
node->children.emplace_back(mAsset->nodes.Get(idx));
|
||||
}
|
||||
|
||||
return node.GetIndex();
|
||||
@@ -1366,12 +1380,12 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
|
||||
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||
node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||
unsigned int idx = ExportNode(n->mChildren[i], node);
|
||||
node->children.push_back(mAsset->nodes.Get(idx));
|
||||
node->children.emplace_back(mAsset->nodes.Get(idx));
|
||||
}
|
||||
|
||||
return node.GetIndex();
|
||||
@@ -1386,7 +1400,7 @@ void glTF2Exporter::ExportScene() {
|
||||
|
||||
// root node will be the first one exported (idx 0)
|
||||
if (mAsset->nodes.Size() > 0) {
|
||||
scene->nodes.push_back(mAsset->nodes.Get(0u));
|
||||
scene->nodes.emplace_back(mAsset->nodes.Get(0u));
|
||||
}
|
||||
|
||||
// set as the default scene
|
||||
@@ -1521,12 +1535,6 @@ void glTF2Exporter::ExportAnimations() {
|
||||
AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
// Assimp documentation states this is not used (not implemented)
|
||||
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
|
||||
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
|
||||
// }
|
||||
|
||||
} // End: for-loop mNumAnimations
|
||||
}
|
||||
|
||||
|
||||
@@ -42,23 +42,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
|
||||
|
||||
#include "AssetLib/glTF2/glTF2Importer.h"
|
||||
#include "PostProcessing/MakeVerboseFormat.h"
|
||||
#include "AssetLib/glTF2/glTF2Asset.h"
|
||||
#include "PostProcessing/MakeVerboseFormat.h"
|
||||
|
||||
#if !defined(ASSIMP_BUILD_NO_EXPORT)
|
||||
#include "AssetLib/glTF2/glTF2AssetWriter.h"
|
||||
#endif
|
||||
|
||||
#include <assimp/CreateAnimMesh.h>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/commonMetaData.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/commonMetaData.h>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@@ -111,7 +111,7 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig ) const {
|
||||
bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string extension = GetExtension(filename);
|
||||
if (!checkSig && (extension != "gltf") && (extension != "glb")) {
|
||||
return false;
|
||||
@@ -127,16 +127,16 @@ bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, b
|
||||
|
||||
static inline aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
|
||||
switch (gltfWrapMode) {
|
||||
case SamplerWrap::Mirrored_Repeat:
|
||||
return aiTextureMapMode_Mirror;
|
||||
case SamplerWrap::Mirrored_Repeat:
|
||||
return aiTextureMapMode_Mirror;
|
||||
|
||||
case SamplerWrap::Clamp_To_Edge:
|
||||
return aiTextureMapMode_Clamp;
|
||||
case SamplerWrap::Clamp_To_Edge:
|
||||
return aiTextureMapMode_Clamp;
|
||||
|
||||
case SamplerWrap::UNSET:
|
||||
case SamplerWrap::Repeat:
|
||||
default:
|
||||
return aiTextureMapMode_Wrap;
|
||||
case SamplerWrap::UNSET:
|
||||
case SamplerWrap::Repeat:
|
||||
default:
|
||||
return aiTextureMapMode_Wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +185,9 @@ static void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
|
||||
// coordinate of the actual meshes during import.
|
||||
const ai_real rcos(cos(-transform.mRotation));
|
||||
const ai_real rsin(sin(-transform.mRotation));
|
||||
transform.mTranslation.x = (static_cast<ai_real>( 0.5 ) * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0];
|
||||
transform.mTranslation.y = ((static_cast<ai_real>( 0.5 ) * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];;
|
||||
transform.mTranslation.x = (static_cast<ai_real>(0.5) * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0];
|
||||
transform.mTranslation.y = ((static_cast<ai_real>(0.5) * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];
|
||||
;
|
||||
|
||||
mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot);
|
||||
}
|
||||
@@ -259,7 +260,10 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_BASE_COLOR);
|
||||
|
||||
// Keep AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE for backwards compatibility
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, aiTextureType_METALNESS);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, aiTextureType_DIFFUSE_ROUGHNESS);
|
||||
|
||||
aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_METALLIC_FACTOR);
|
||||
aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_ROUGHNESS_FACTOR);
|
||||
@@ -305,7 +309,6 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
|
||||
|
||||
aimat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
|
||||
// KHR_materials_sheen
|
||||
if (mat.materialSheen.isPresent) {
|
||||
MaterialSheen &sheen = mat.materialSheen.value;
|
||||
@@ -378,7 +381,7 @@ void glTF2Importer::ImportMaterials(Asset &r) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SetFaceAndAdvance1(aiFace*& face, unsigned int numVertices, unsigned int a) {
|
||||
static inline void SetFaceAndAdvance1(aiFace *&face, unsigned int numVertices, unsigned int a) {
|
||||
if (a >= numVertices) {
|
||||
return;
|
||||
}
|
||||
@@ -388,7 +391,7 @@ static inline void SetFaceAndAdvance1(aiFace*& face, unsigned int numVertices, u
|
||||
++face;
|
||||
}
|
||||
|
||||
static inline void SetFaceAndAdvance2(aiFace*& face, unsigned int numVertices,
|
||||
static inline void SetFaceAndAdvance2(aiFace *&face, unsigned int numVertices,
|
||||
unsigned int a, unsigned int b) {
|
||||
if ((a >= numVertices) || (b >= numVertices)) {
|
||||
return;
|
||||
@@ -400,7 +403,7 @@ static inline void SetFaceAndAdvance2(aiFace*& face, unsigned int numVertices,
|
||||
++face;
|
||||
}
|
||||
|
||||
static inline void SetFaceAndAdvance3(aiFace*& face, unsigned int numVertices, unsigned int a,
|
||||
static inline void SetFaceAndAdvance3(aiFace *&face, unsigned int numVertices, unsigned int a,
|
||||
unsigned int b, unsigned int c) {
|
||||
if ((a >= numVertices) || (b >= numVertices) || (c >= numVertices)) {
|
||||
return;
|
||||
@@ -427,17 +430,16 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign
|
||||
}
|
||||
#endif // ASSIMP_BUILD_DEBUG
|
||||
|
||||
template<typename T>
|
||||
aiColor4D* GetVertexColorsForType(Ref<Accessor> input) {
|
||||
template <typename T>
|
||||
aiColor4D *GetVertexColorsForType(Ref<Accessor> input) {
|
||||
constexpr float max = std::numeric_limits<T>::max();
|
||||
aiColor4t<T>* colors;
|
||||
aiColor4t<T> *colors;
|
||||
input->ExtractData(colors);
|
||||
auto output = new aiColor4D[input->count];
|
||||
for (size_t i = 0; i < input->count; i++) {
|
||||
output[i] = aiColor4D(
|
||||
colors[i].r / max, colors[i].g / max,
|
||||
colors[i].b / max, colors[i].a / max
|
||||
);
|
||||
colors[i].r / max, colors[i].g / max,
|
||||
colors[i].b / max, colors[i].a / max);
|
||||
}
|
||||
delete[] colors;
|
||||
return output;
|
||||
@@ -471,21 +473,21 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||
}
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
case PrimitiveMode_POINTS:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
|
||||
case PrimitiveMode_LINES:
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
case PrimitiveMode_LINES:
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
|
||||
case PrimitiveMode_TRIANGLES:
|
||||
case PrimitiveMode_TRIANGLE_STRIP:
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
case PrimitiveMode_TRIANGLES:
|
||||
case PrimitiveMode_TRIANGLE_STRIP:
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh::Primitive::Attributes &attr = prim.attributes;
|
||||
@@ -528,7 +530,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||
for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
|
||||
if (attr.color[c]->count != aim->mNumVertices) {
|
||||
DefaultLogger::get()->warn("Color stream size in mesh \"", mesh.name,
|
||||
"\" does not match the vertex count");
|
||||
"\" does not match the vertex count");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -551,7 +553,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||
|
||||
if (attr.texcoord[tc]->count != aim->mNumVertices) {
|
||||
DefaultLogger::get()->warn("Texcoord stream size in mesh \"", mesh.name,
|
||||
"\" does not match the vertex count");
|
||||
"\" does not match the vertex count");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -644,77 +646,77 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||
}
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i));
|
||||
}
|
||||
break;
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_LINES: {
|
||||
nFaces = count / 2;
|
||||
if (nFaces * 2 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
|
||||
count = nFaces * 2;
|
||||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1));
|
||||
}
|
||||
break;
|
||||
case PrimitiveMode_LINES: {
|
||||
nFaces = count / 2;
|
||||
if (nFaces * 2 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
|
||||
count = nFaces * 2;
|
||||
}
|
||||
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1));
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i));
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast<int>(count) - 1), faces[0].mIndices[0]);
|
||||
}
|
||||
break;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_TRIANGLES: {
|
||||
nFaces = count / 3;
|
||||
if (nFaces * 3 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||
count = nFaces * 3;
|
||||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1));
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i));
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast<int>(count) - 1), faces[0].mIndices[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_TRIANGLES: {
|
||||
nFaces = count / 3;
|
||||
if (nFaces * 3 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||
count = nFaces * 3;
|
||||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_STRIP: {
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < nFaces; ++i) {
|
||||
//The ordering is to ensure that the triangles are all drawn with the same orientation
|
||||
if ((i + 1) % 2 == 0) {
|
||||
//For even n, vertices n + 1, n, and n + 2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
|
||||
} else {
|
||||
//For odd n, vertices n, n+1, and n+2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_STRIP: {
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < nFaces; ++i) {
|
||||
//The ordering is to ensure that the triangles are all drawn with the same orientation
|
||||
if ((i + 1) % 2 == 0) {
|
||||
//For even n, vertices n + 1, n, and n + 2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
|
||||
} else {
|
||||
//For odd n, vertices n, n+1, and n+2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||
for (unsigned int i = 1; i < nFaces; ++i) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||
for (unsigned int i = 1; i < nFaces; ++i) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
} else { // no indices provided so directly generate from counts
|
||||
|
||||
@@ -722,77 +724,77 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||
unsigned int count = aim->mNumVertices;
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, i);
|
||||
}
|
||||
break;
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_LINES: {
|
||||
nFaces = count / 2;
|
||||
if (nFaces * 2 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
|
||||
count = (unsigned int)nFaces * 2;
|
||||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, i, i + 1);
|
||||
}
|
||||
break;
|
||||
case PrimitiveMode_LINES: {
|
||||
nFaces = count / 2;
|
||||
if (nFaces * 2 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
|
||||
count = (unsigned int)nFaces * 2;
|
||||
}
|
||||
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, 0, 1);
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, i - 1, i);
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, count - 1, 0);
|
||||
}
|
||||
break;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, i, i + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_TRIANGLES: {
|
||||
nFaces = count / 3;
|
||||
if (nFaces * 3 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||
count = (unsigned int)nFaces * 3;
|
||||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, 0, 1);
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, i - 1, i);
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, count - 1, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_TRIANGLES: {
|
||||
nFaces = count / 3;
|
||||
if (nFaces * 3 != count) {
|
||||
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||
count = (unsigned int)nFaces * 3;
|
||||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_STRIP: {
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < nFaces; ++i) {
|
||||
//The ordering is to ensure that the triangles are all drawn with the same orientation
|
||||
if ((i + 1) % 2 == 0) {
|
||||
//For even n, vertices n + 1, n, and n + 2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2);
|
||||
} else {
|
||||
//For odd n, vertices n, n+1, and n+2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_STRIP: {
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < nFaces; ++i) {
|
||||
//The ordering is to ensure that the triangles are all drawn with the same orientation
|
||||
if ((i + 1) % 2 == 0) {
|
||||
//For even n, vertices n + 1, n, and n + 2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2);
|
||||
} else {
|
||||
//For odd n, vertices n, n+1, and n+2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, 1, 2);
|
||||
for (unsigned int i = 1; i < nFaces; ++i) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, i + 1, i + 2);
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, 1, 2);
|
||||
for (unsigned int i = 1; i < nFaces; ++i) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, 0, i + 1, i + 2);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,15 +878,15 @@ void glTF2Importer::ImportLights(glTF2::Asset &r) {
|
||||
aiLight *ail = mScene->mLights[i] = new aiLight();
|
||||
|
||||
switch (light.type) {
|
||||
case Light::Directional:
|
||||
ail->mType = aiLightSource_DIRECTIONAL;
|
||||
break;
|
||||
case Light::Point:
|
||||
ail->mType = aiLightSource_POINT;
|
||||
break;
|
||||
case Light::Spot:
|
||||
ail->mType = aiLightSource_SPOT;
|
||||
break;
|
||||
case Light::Directional:
|
||||
ail->mType = aiLightSource_DIRECTIONAL;
|
||||
break;
|
||||
case Light::Point:
|
||||
ail->mType = aiLightSource_POINT;
|
||||
break;
|
||||
case Light::Spot:
|
||||
ail->mType = aiLightSource_SPOT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ail->mType != aiLightSource_POINT) {
|
||||
@@ -926,7 +928,7 @@ static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) {
|
||||
if (node.matrix.isPresent) {
|
||||
CopyValue(node.matrix.value, matrix);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.translation.isPresent) {
|
||||
aiVector3D trans;
|
||||
@@ -1021,7 +1023,7 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
|
||||
metadata->Add(extension.name, extension.mBoolValue.value);
|
||||
} else if (extension.mValues.isPresent) {
|
||||
aiMetadata val;
|
||||
for (auto const & subExtension : extension.mValues.value) {
|
||||
for (auto const &subExtension : extension.mValues.value) {
|
||||
ParseExtensions(&val, subExtension);
|
||||
}
|
||||
metadata->Add(extension.name, val);
|
||||
@@ -1030,7 +1032,7 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
|
||||
|
||||
void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) {
|
||||
if (extension.mValues.isPresent) {
|
||||
for (auto const & subExtension : extension.mValues.value) {
|
||||
for (auto const &subExtension : extension.mValues.value) {
|
||||
ParseExtensions(metadata, subExtension);
|
||||
}
|
||||
}
|
||||
@@ -1068,11 +1070,10 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
||||
|
||||
if (!node.meshes.empty()) {
|
||||
// GLTF files contain at most 1 mesh per node.
|
||||
if (node.meshes.size() > 1)
|
||||
{
|
||||
if (node.meshes.size() > 1) {
|
||||
throw DeadlyImportError("GLTF: Invalid input, found ", node.meshes.size(),
|
||||
" meshes in ", getContextForErrorMessages(node.id, node.name),
|
||||
", but only 1 mesh per node allowed.");
|
||||
" meshes in ", getContextForErrorMessages(node.id, node.name),
|
||||
", but only 1 mesh per node allowed.");
|
||||
}
|
||||
int mesh_idx = node.meshes[0].GetIndex();
|
||||
int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx];
|
||||
@@ -1083,7 +1084,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
||||
if (node.skin) {
|
||||
for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
|
||||
aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo];
|
||||
unsigned int numBones =static_cast<unsigned int>(node.skin->jointNames.size());
|
||||
unsigned int numBones = static_cast<unsigned int>(node.skin->jointNames.size());
|
||||
|
||||
std::vector<std::vector<aiVertexWeight>> weighting(numBones);
|
||||
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
|
||||
@@ -1222,7 +1223,7 @@ struct AnimationSamplers {
|
||||
Animation::Sampler *weight;
|
||||
};
|
||||
|
||||
aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) {
|
||||
aiNodeAnim *CreateNodeAnim(glTF2::Asset &, Node &node, AnimationSamplers &samplers) {
|
||||
aiNodeAnim *anim = new aiNodeAnim();
|
||||
|
||||
try {
|
||||
@@ -1313,7 +1314,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
|
||||
}
|
||||
}
|
||||
|
||||
aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) {
|
||||
aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset &, Node &node, AnimationSamplers &samplers) {
|
||||
auto *anim = new aiMeshMorphAnim();
|
||||
|
||||
try {
|
||||
@@ -1366,7 +1367,7 @@ std::unordered_map<unsigned int, AnimationSamplers> GatherSamplers(Animation &an
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& animsampler = anim.samplers[channel.sampler];
|
||||
auto &animsampler = anim.samplers[channel.sampler];
|
||||
|
||||
if (!animsampler.input) {
|
||||
ASSIMP_LOG_WARN("Animation ", anim.name, ": Missing sampler input. Skipping.");
|
||||
@@ -1555,9 +1556,9 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
|
||||
if (ext) {
|
||||
if (strcmp(ext, "jpeg") == 0) {
|
||||
ext = "jpg";
|
||||
} else if(strcmp(ext, "ktx2") == 0) { //basisu: ktx remains
|
||||
} else if (strcmp(ext, "ktx2") == 0) { //basisu: ktx remains
|
||||
ext = "kx2";
|
||||
} else if(strcmp(ext, "basis") == 0) { //basisu
|
||||
} else if (strcmp(ext, "basis") == 0) { //basisu
|
||||
ext = "bu";
|
||||
}
|
||||
|
||||
@@ -1570,7 +1571,7 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
|
||||
void glTF2Importer::ImportCommonMetadata(glTF2::Asset &a) {
|
||||
ASSIMP_LOG_DEBUG("Importing metadata");
|
||||
ai_assert(mScene->mMetaData == nullptr);
|
||||
const bool hasVersion = !a.asset.version.empty();
|
||||
@@ -1604,7 +1605,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
||||
this->mScene = pScene;
|
||||
|
||||
// read the asset file
|
||||
glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider*>(mSchemaDocumentProvider));
|
||||
glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider *>(mSchemaDocumentProvider));
|
||||
asset.Load(pFile, GetExtension(pFile) == "glb");
|
||||
if (asset.scene) {
|
||||
pScene->mName = asset.scene->name;
|
||||
@@ -1631,7 +1632,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
||||
}
|
||||
|
||||
void glTF2Importer::SetupProperties(const Importer *pImp) {
|
||||
mSchemaDocumentProvider = static_cast<rapidjson::IRemoteSchemaDocumentProvider*>(pImp->GetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER));
|
||||
mSchemaDocumentProvider = static_cast<rapidjson::IRemoteSchemaDocumentProvider *>(pImp->GetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER));
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||
|
||||
@@ -78,6 +78,7 @@ SET( PUBLIC_HEADERS
|
||||
${HEADER_PATH}/matrix4x4.h
|
||||
${HEADER_PATH}/matrix4x4.inl
|
||||
${HEADER_PATH}/mesh.h
|
||||
${HEADER_PATH}/ObjMaterial.h
|
||||
${HEADER_PATH}/pbrmaterial.h
|
||||
${HEADER_PATH}/GltfMaterial.h
|
||||
${HEADER_PATH}/postprocess.h
|
||||
|
||||
@@ -35,6 +35,17 @@ struct SubChunkHeader
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF form header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct FormHeader
|
||||
{
|
||||
//! Length of the chunk data, in bytes
|
||||
uint32_t length;
|
||||
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
|
||||
((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
|
||||
@@ -77,6 +88,24 @@ inline SubChunkHeader LoadSubChunk(uint8_t*& outFile)
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Copy of the chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline ChunkHeader LoadForm(uint8_t*& outFile)
|
||||
{
|
||||
ChunkHeader head;
|
||||
outFile += 4;
|
||||
::memcpy(&head.length, outFile, 4);
|
||||
outFile += 4;
|
||||
::memcpy(&head.type, outFile, 4);
|
||||
|
||||
AI_LSWAP4(head.length);
|
||||
AI_LSWAP4(head.type);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Read the file header and return the type of the file and its size
|
||||
//! @param outFile Pointer to the file data. The buffer must at
|
||||
|
||||
@@ -122,15 +122,15 @@ voidpf IOSystem2Unzip::open(voidpf opaque, const char *filename, int mode) {
|
||||
voidpf IOSystem2Unzip::opendisk(voidpf opaque, voidpf stream, uint32_t number_disk, int mode) {
|
||||
ZipFile *io_stream = (ZipFile *)stream;
|
||||
voidpf ret = NULL;
|
||||
size_t i;
|
||||
int i;
|
||||
|
||||
char *disk_filename = (char*)malloc(io_stream->m_Filename.length() + 1);
|
||||
strncpy(disk_filename, io_stream->m_Filename.c_str(), io_stream->m_Filename.length() + 1);
|
||||
for (i = io_stream->m_Filename.length() - 1; i >= 0; i -= 1)
|
||||
for (i = (int)io_stream->m_Filename.length() - 1; i >= 0; i -= 1)
|
||||
{
|
||||
if (disk_filename[i] != '.')
|
||||
continue;
|
||||
snprintf(&disk_filename[i], io_stream->m_Filename.length() - i, ".z%02u", number_disk + 1);
|
||||
snprintf(&disk_filename[i], io_stream->m_Filename.length() - size_t(i), ".z%02u", number_disk + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,12 +90,14 @@ void ArmaturePopulate::Execute(aiScene *out) {
|
||||
|
||||
ai_assert(armature);
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
|
||||
// set up bone armature id
|
||||
bone->mArmature = armature;
|
||||
|
||||
// set this bone node to be referenced properly
|
||||
ai_assert(bone_node);
|
||||
bone->mNode = bone_node;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@ PROJECT_NAME = Assimp
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = "v5.0.1. (December 2020)"
|
||||
PROJECT_NUMBER = "v5.2.2 (January 2022)"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer
|
||||
# a quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_BRIEF = The Asset-Importer-Lib API documentation.
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify an logo or icon that is
|
||||
# included in the documentation. The maximum height of the logo should not
|
||||
|
||||
@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
@@ -76,7 +75,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) {
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
|
||||
size_t offset;
|
||||
|
||||
if (!data) return 0;
|
||||
if (!len)len = (uint32_t)::strlen(data);
|
||||
|
||||
@@ -96,7 +96,11 @@ int rem;
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
offset = static_cast<size_t>(sizeof(uint16_t));
|
||||
if (offset < 0) {
|
||||
return 0;
|
||||
}
|
||||
hash ^= data[offset] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
|
||||
@@ -53,6 +53,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <assimp/material.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// the original illum property
|
||||
#define AI_MATKEY_OBJ_ILLUM "$mat.illum", 0, 0
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Pure key names for all obj texture-related properties
|
||||
//! @cond MATS_DOC_FULL
|
||||
|
||||
@@ -331,7 +331,7 @@ enum aiTextureType {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define AI_TEXTURE_TYPE_MAX aiTextureType_UNKNOWN
|
||||
#define AI_TEXTURE_TYPE_MAX aiTextureType_TRANSMISSION
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Get a string for a given aiTextureType
|
||||
|
||||
@@ -130,7 +130,54 @@ AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
|
||||
// Specialisation for a single bool.
|
||||
// Casts floating point and integer to bool
|
||||
template <>
|
||||
AI_FORCE_INLINE
|
||||
aiReturn
|
||||
aiMaterial::Get(const char *pKey, unsigned int type,
|
||||
unsigned int idx, bool &pOut) const {
|
||||
const aiMaterialProperty *prop;
|
||||
const aiReturn ret = ::aiGetMaterialProperty(this, pKey, type, idx,
|
||||
(const aiMaterialProperty **)&prop);
|
||||
if (AI_SUCCESS == ret) {
|
||||
|
||||
switch (prop->mType) {
|
||||
// Type cannot be converted
|
||||
default: return AI_FAILURE;
|
||||
|
||||
case aiPTI_Buffer: {
|
||||
// Native bool value storage
|
||||
if (prop->mDataLength < sizeof(bool)) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
::memcpy(&pOut, prop->mData, sizeof(bool));
|
||||
} break;
|
||||
|
||||
case aiPTI_Float:
|
||||
case aiPTI_Double: {
|
||||
// Read as float and cast to bool
|
||||
float value = 0.0f;
|
||||
if (AI_SUCCESS == ::aiGetMaterialFloat(this, pKey, type, idx, &value)) {
|
||||
pOut = static_cast<bool>(value);
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
return AI_FAILURE;
|
||||
}
|
||||
case aiPTI_Integer: {
|
||||
// Cast to bool
|
||||
const int value = static_cast<int>(*prop->mData);
|
||||
pOut = static_cast<bool>(value);
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE
|
||||
aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
|
||||
unsigned int idx,ai_real* pOut,
|
||||
unsigned int* pMax) const {
|
||||
return ::aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax);
|
||||
|
||||
@@ -61,7 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR AI_MATKEY_METALLIC_FACTOR
|
||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR AI_MATKEY_ROUGHNESS_FACTOR
|
||||
|
||||
//#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS AI_MATKEY_GLOSSINESS_FACTOR
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR AI_MATKEY_GLOSSINESS_FACTOR
|
||||
|
||||
// Use AI_MATKEY_SHADING_MODEL == aiShadingMode_Unlit instead
|
||||
|
||||
@@ -60,7 +60,7 @@ protected:
|
||||
};
|
||||
|
||||
TEST_F(utMesh, emptyMeshHasNoContentTest) {
|
||||
EXPECT_EQ(0, mesh->mName.length);
|
||||
EXPECT_EQ(0u, mesh->mName.length);
|
||||
EXPECT_FALSE(mesh->HasPositions());
|
||||
EXPECT_FALSE(mesh->HasFaces());
|
||||
EXPECT_FALSE(mesh->HasNormals());
|
||||
@@ -69,8 +69,8 @@ TEST_F(utMesh, emptyMeshHasNoContentTest) {
|
||||
EXPECT_FALSE(mesh->HasVertexColors(AI_MAX_NUMBER_OF_COLOR_SETS));
|
||||
EXPECT_FALSE(mesh->HasTextureCoords(0));
|
||||
EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS));
|
||||
EXPECT_EQ(0, mesh->GetNumUVChannels());
|
||||
EXPECT_EQ(0, mesh->GetNumColorChannels());
|
||||
EXPECT_EQ(0u, mesh->GetNumUVChannels());
|
||||
EXPECT_EQ(0u, mesh->GetNumColorChannels());
|
||||
EXPECT_FALSE(mesh->HasBones());
|
||||
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
|
||||
EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS));
|
||||
@@ -80,8 +80,8 @@ TEST_F(utMesh, setTextureCoordsName) {
|
||||
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
|
||||
const aiString texcoords_name("texcoord_name");
|
||||
mesh->SetTextureCoordsName(0, texcoords_name);
|
||||
EXPECT_TRUE(mesh->HasTextureCoordsName(0));
|
||||
EXPECT_FALSE(mesh->HasTextureCoordsName(1));
|
||||
EXPECT_TRUE(mesh->HasTextureCoordsName(0u));
|
||||
EXPECT_FALSE(mesh->HasTextureCoordsName(1u));
|
||||
ASSERT_NE(nullptr, mesh->mTextureCoordsNames);
|
||||
ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]);
|
||||
EXPECT_STREQ(texcoords_name.C_Str(), mesh->mTextureCoordsNames[0]->C_Str());
|
||||
@@ -94,3 +94,4 @@ TEST_F(utMesh, setTextureCoordsName) {
|
||||
EXPECT_EQ(nullptr, mesh->mTextureCoordsNames[0]);
|
||||
EXPECT_EQ(nullptr, mesh->GetTextureCoordsName(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -124,9 +124,9 @@ TEST_F(utColladaExport, testExportLight) {
|
||||
ASSERT_NE(pTest, nullptr);
|
||||
ASSERT_TRUE(pTest->HasLights());
|
||||
|
||||
const unsigned int origNumLights(pTest->mNumLights);
|
||||
const unsigned int origNumLights = pTest->mNumLights;
|
||||
// There are FIVE!!! LIGHTS!!!
|
||||
EXPECT_EQ(5, origNumLights) << "lights.dae should contain five lights";
|
||||
EXPECT_EQ(5u, origNumLights) << "lights.dae should contain five lights";
|
||||
|
||||
std::vector<aiLight> origLights(5);
|
||||
for (size_t i = 0; i < origNumLights; i++) {
|
||||
|
||||
@@ -125,13 +125,154 @@ TEST_F(MaterialSystemTest, testStringProperty) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(MaterialSystemTest, testMaterialNameAccess) {
|
||||
aiMaterial *mat = new aiMaterial();
|
||||
EXPECT_NE(nullptr, mat);
|
||||
|
||||
aiString name = mat->GetName();
|
||||
TEST_F(MaterialSystemTest, testDefaultMaterialName) {
|
||||
aiString name = pcMat->GetName();
|
||||
const int retValue(strncmp(name.C_Str(), AI_DEFAULT_MATERIAL_NAME, name.length));
|
||||
EXPECT_EQ(0, retValue);
|
||||
|
||||
delete mat;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(MaterialSystemTest, testBoolProperty) {
|
||||
const bool valTrue = true;
|
||||
const bool valFalse = false;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&valTrue, 1, "bool_true"));
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&valFalse, 1, "bool_false"));
|
||||
|
||||
bool read = false;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("bool_true", 0, 0, read));
|
||||
EXPECT_TRUE(read) << "read true bool";
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("bool_false", 0, 0, read));
|
||||
EXPECT_FALSE(read) << "read false bool";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(MaterialSystemTest, testCastIntProperty) {
|
||||
int value = 10;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "integer"));
|
||||
value = 0;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "zero"));
|
||||
value = -1;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "negative"));
|
||||
|
||||
// To float
|
||||
float valFloat = 0.0f;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("integer", 0, 0, valFloat));
|
||||
EXPECT_EQ(10.0f, valFloat);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("zero", 0, 0, valFloat));
|
||||
EXPECT_EQ(0.0f, valFloat);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("negative", 0, 0, valFloat));
|
||||
EXPECT_EQ(-1.0f, valFloat);
|
||||
|
||||
// To bool
|
||||
bool valBool = false;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("integer", 0, 0, valBool));
|
||||
EXPECT_EQ(true, valBool);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("zero", 0, 0, valBool));
|
||||
EXPECT_EQ(false, valBool);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("negative", 0, 0, valBool));
|
||||
EXPECT_EQ(true, valBool);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(MaterialSystemTest, testCastFloatProperty) {
|
||||
float value = 150392.63f;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "float"));
|
||||
value = 0;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "zero"));
|
||||
|
||||
// To int
|
||||
int valInt = 0.0f;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("float", 0, 0, valInt));
|
||||
EXPECT_EQ(150392, valInt);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("zero", 0, 0, valInt));
|
||||
EXPECT_EQ(0, valInt);
|
||||
|
||||
// To bool
|
||||
bool valBool = false;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("float", 0, 0, valBool));
|
||||
EXPECT_EQ(true, valBool);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("zero", 0, 0, valBool));
|
||||
EXPECT_EQ(false, valBool);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(MaterialSystemTest, testCastSmallFloatProperty) {
|
||||
float value = 0.0078125f;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "float"));
|
||||
value = 0;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->AddProperty(&value, 1, "zero"));
|
||||
|
||||
// To int
|
||||
int valInt = 0.0f;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("float", 0, 0, valInt));
|
||||
EXPECT_EQ(0, valInt);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("zero", 0, 0, valInt));
|
||||
EXPECT_EQ(0, valInt);
|
||||
|
||||
// To bool
|
||||
bool valBool = false;
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("float", 0, 0, valBool));
|
||||
EXPECT_EQ(true, valBool);
|
||||
EXPECT_EQ(AI_SUCCESS, pcMat->Get("zero", 0, 0, valBool));
|
||||
EXPECT_EQ(false, valBool);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_MSC_VER)
|
||||
// Refuse to compile on Windows if any enum values are not explicitly handled in the switch
|
||||
// TODO: Move this into assimp/Compiler as a macro and add clang/gcc versions so other code can use it
|
||||
__pragma(warning(push));
|
||||
__pragma(warning(error : 4061)); // enumerator 'identifier' in switch of enum 'enumeration' is not explicitly handled by a case label
|
||||
__pragma(warning(error : 4062)); // enumerator 'identifier' in switch of enum 'enumeration' is not handled
|
||||
#endif
|
||||
|
||||
TEST_F(MaterialSystemTest, testMaterialTextureTypeEnum) {
|
||||
// Verify that AI_TEXTURE_TYPE_MAX equals the largest 'real' value in the enum
|
||||
|
||||
int32_t maxTextureType = 0;
|
||||
static constexpr int32_t bigNumber = 255;
|
||||
EXPECT_GT(bigNumber, AI_TEXTURE_TYPE_MAX) << "AI_TEXTURE_TYPE_MAX too large for valid enum test, increase bigNumber";
|
||||
|
||||
// Loop until a value larger than any enum
|
||||
for (int32_t i = 0; i < bigNumber; ++i) {
|
||||
aiTextureType texType = static_cast<aiTextureType>(i);
|
||||
switch (texType) {
|
||||
default: break;
|
||||
#ifndef SWIG
|
||||
case _aiTextureType_Force32Bit: break;
|
||||
#endif
|
||||
// All the real values
|
||||
case aiTextureType_NONE:
|
||||
case aiTextureType_DIFFUSE:
|
||||
case aiTextureType_SPECULAR:
|
||||
case aiTextureType_AMBIENT:
|
||||
case aiTextureType_EMISSIVE:
|
||||
case aiTextureType_HEIGHT:
|
||||
case aiTextureType_NORMALS:
|
||||
case aiTextureType_SHININESS:
|
||||
case aiTextureType_OPACITY:
|
||||
case aiTextureType_DISPLACEMENT:
|
||||
case aiTextureType_LIGHTMAP:
|
||||
case aiTextureType_REFLECTION:
|
||||
case aiTextureType_BASE_COLOR:
|
||||
case aiTextureType_NORMAL_CAMERA:
|
||||
case aiTextureType_EMISSION_COLOR:
|
||||
case aiTextureType_METALNESS:
|
||||
case aiTextureType_DIFFUSE_ROUGHNESS:
|
||||
case aiTextureType_AMBIENT_OCCLUSION:
|
||||
case aiTextureType_SHEEN:
|
||||
case aiTextureType_CLEARCOAT:
|
||||
case aiTextureType_TRANSMISSION:
|
||||
case aiTextureType_UNKNOWN:
|
||||
if (i > maxTextureType)
|
||||
maxTextureType = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(maxTextureType, AI_TEXTURE_TYPE_MAX) << "AI_TEXTURE_TYPE_MAX macro must be equal to the largest valid aiTextureType_XXX";
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
__pragma (warning(pop))
|
||||
#endif
|
||||
|
||||
@@ -50,12 +50,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
const char* AICMD_MSG_INFO_HELP_E =
|
||||
"assimp info <file> [-r] [-v]\n"
|
||||
"\tPrint basic structure of a 3D model\n"
|
||||
"\t-r,--raw: No postprocessing, do a raw import\n"
|
||||
"\t-v,--verbose: Print verbose info such as node transform data\n"
|
||||
"\t-s, --silent: Print only minimal info\n";
|
||||
const char *AICMD_MSG_INFO_HELP_E =
|
||||
"assimp info <file> [-r] [-v]\n"
|
||||
"\tPrint basic structure of a 3D model\n"
|
||||
"\t-r,--raw: No postprocessing, do a raw import\n"
|
||||
"\t-v,--verbose: Print verbose info such as node transform data\n"
|
||||
"\t-s, --silent: Print only minimal info\n";
|
||||
|
||||
const char *TREE_BRANCH_ASCII = "|-";
|
||||
const char *TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4";
|
||||
@@ -73,411 +73,433 @@ const char *TREE_STOP = TREE_STOP_UTF8;
|
||||
const char *TREE_CONTINUE = TREE_CONTINUE_UTF8;
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int CountNodes(const aiNode* root)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (unsigned int a = 0; a < root->mNumChildren; ++a ) {
|
||||
i += CountNodes(root->mChildren[a]);
|
||||
}
|
||||
return 1+i;
|
||||
unsigned int CountNodes(const aiNode *root) {
|
||||
unsigned int i = 0;
|
||||
for (unsigned int a = 0; a < root->mNumChildren; ++a) {
|
||||
i += CountNodes(root->mChildren[a]);
|
||||
}
|
||||
return 1 + i;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int GetMaxDepth(const aiNode* root)
|
||||
{
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
|
||||
cnt = std::max(cnt,GetMaxDepth(root->mChildren[i]));
|
||||
}
|
||||
return cnt+1;
|
||||
unsigned int GetMaxDepth(const aiNode *root) {
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
|
||||
cnt = std::max(cnt, GetMaxDepth(root->mChildren[i]));
|
||||
}
|
||||
return cnt + 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int CountVertices(const aiScene* scene)
|
||||
{
|
||||
unsigned int cnt = 0;
|
||||
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
cnt += scene->mMeshes[i]->mNumVertices;
|
||||
}
|
||||
return cnt;
|
||||
unsigned int CountVertices(const aiScene *scene) {
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
cnt += scene->mMeshes[i]->mNumVertices;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int CountFaces(const aiScene* scene)
|
||||
{
|
||||
unsigned int cnt = 0;
|
||||
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
cnt += scene->mMeshes[i]->mNumFaces;
|
||||
}
|
||||
return cnt;
|
||||
unsigned int CountFaces(const aiScene *scene) {
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
cnt += scene->mMeshes[i]->mNumFaces;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int CountBones(const aiScene* scene)
|
||||
{
|
||||
unsigned int cnt = 0;
|
||||
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
cnt += scene->mMeshes[i]->mNumBones;
|
||||
}
|
||||
return cnt;
|
||||
unsigned int CountBones(const aiScene *scene) {
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
cnt += scene->mMeshes[i]->mNumBones;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int CountAnimChannels(const aiScene* scene)
|
||||
{
|
||||
unsigned int cnt = 0;
|
||||
for(unsigned int i = 0; i < scene->mNumAnimations; ++i) {
|
||||
cnt += scene->mAnimations[i]->mNumChannels;
|
||||
}
|
||||
return cnt;
|
||||
unsigned int CountAnimChannels(const aiScene *scene) {
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
|
||||
cnt += scene->mAnimations[i]->mNumChannels;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int GetAvgFacePerMesh(const aiScene* scene) {
|
||||
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountFaces(scene)/scene->mNumMeshes) : 0;
|
||||
unsigned int GetAvgFacePerMesh(const aiScene *scene) {
|
||||
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountFaces(scene) / scene->mNumMeshes) : 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
unsigned int GetAvgVertsPerMesh(const aiScene* scene) {
|
||||
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountVertices(scene)/scene->mNumMeshes) : 0;
|
||||
unsigned int GetAvgVertsPerMesh(const aiScene *scene) {
|
||||
return (scene->mNumMeshes != 0) ? static_cast<unsigned int>(CountVertices(scene) / scene->mNumMeshes) : 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void FindSpecialPoints(const aiScene* scene,const aiNode* root,aiVector3D special_points[3],const aiMatrix4x4& mat=aiMatrix4x4())
|
||||
{
|
||||
// XXX that could be greatly simplified by using code from code/ProcessHelper.h
|
||||
// XXX I just don't want to include it here.
|
||||
const aiMatrix4x4 trafo = root->mTransformation*mat;
|
||||
for(unsigned int i = 0; i < root->mNumMeshes; ++i) {
|
||||
const aiMesh* mesh = scene->mMeshes[root->mMeshes[i]];
|
||||
void FindSpecialPoints(const aiScene *scene, const aiNode *root, aiVector3D special_points[3], const aiMatrix4x4 &mat = aiMatrix4x4()) {
|
||||
// XXX that could be greatly simplified by using code from code/ProcessHelper.h
|
||||
// XXX I just don't want to include it here.
|
||||
const aiMatrix4x4 trafo = root->mTransformation * mat;
|
||||
for (unsigned int i = 0; i < root->mNumMeshes; ++i) {
|
||||
const aiMesh *mesh = scene->mMeshes[root->mMeshes[i]];
|
||||
|
||||
for(unsigned int a = 0; a < mesh->mNumVertices; ++a) {
|
||||
aiVector3D v = trafo*mesh->mVertices[a];
|
||||
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
|
||||
aiVector3D v = trafo * mesh->mVertices[a];
|
||||
|
||||
special_points[0].x = std::min(special_points[0].x,v.x);
|
||||
special_points[0].y = std::min(special_points[0].y,v.y);
|
||||
special_points[0].z = std::min(special_points[0].z,v.z);
|
||||
special_points[0].x = std::min(special_points[0].x, v.x);
|
||||
special_points[0].y = std::min(special_points[0].y, v.y);
|
||||
special_points[0].z = std::min(special_points[0].z, v.z);
|
||||
|
||||
special_points[1].x = std::max(special_points[1].x,v.x);
|
||||
special_points[1].y = std::max(special_points[1].y,v.y);
|
||||
special_points[1].z = std::max(special_points[1].z,v.z);
|
||||
}
|
||||
}
|
||||
special_points[1].x = std::max(special_points[1].x, v.x);
|
||||
special_points[1].y = std::max(special_points[1].y, v.y);
|
||||
special_points[1].z = std::max(special_points[1].z, v.z);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < root->mNumChildren; ++i) {
|
||||
FindSpecialPoints(scene,root->mChildren[i],special_points,trafo);
|
||||
}
|
||||
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
|
||||
FindSpecialPoints(scene, root->mChildren[i], special_points, trafo);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
void FindSpecialPoints(const aiScene* scene,aiVector3D special_points[3])
|
||||
{
|
||||
special_points[0] = aiVector3D(1e10,1e10,1e10);
|
||||
special_points[1] = aiVector3D(-1e10,-1e10,-1e10);
|
||||
void FindSpecialPoints(const aiScene *scene, aiVector3D special_points[3]) {
|
||||
special_points[0] = aiVector3D(1e10, 1e10, 1e10);
|
||||
special_points[1] = aiVector3D(-1e10, -1e10, -1e10);
|
||||
|
||||
FindSpecialPoints(scene,scene->mRootNode,special_points);
|
||||
special_points[2] = (special_points[0]+special_points[1])*(ai_real)0.5;
|
||||
FindSpecialPoints(scene, scene->mRootNode, special_points);
|
||||
special_points[2] = (special_points[0] + special_points[1]) * (ai_real)0.5;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
std::string FindPTypes(const aiScene* scene)
|
||||
{
|
||||
bool haveit[4] = {0};
|
||||
for(unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
const unsigned int pt = scene->mMeshes[i]->mPrimitiveTypes;
|
||||
if (pt & aiPrimitiveType_POINT) {
|
||||
haveit[0]=true;
|
||||
}
|
||||
if (pt & aiPrimitiveType_LINE) {
|
||||
haveit[1]=true;
|
||||
}
|
||||
if (pt & aiPrimitiveType_TRIANGLE) {
|
||||
haveit[2]=true;
|
||||
}
|
||||
if (pt & aiPrimitiveType_POLYGON) {
|
||||
haveit[3]=true;
|
||||
}
|
||||
}
|
||||
return (haveit[0]?std::string("points"):"")+(haveit[1]?"lines":"")+
|
||||
(haveit[2]?"triangles":"")+(haveit[3]?"n-polygons":"");
|
||||
std::string FindPTypes(const aiScene *scene) {
|
||||
bool haveit[4] = { 0 };
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
const unsigned int pt = scene->mMeshes[i]->mPrimitiveTypes;
|
||||
if (pt & aiPrimitiveType_POINT) {
|
||||
haveit[0] = true;
|
||||
}
|
||||
if (pt & aiPrimitiveType_LINE) {
|
||||
haveit[1] = true;
|
||||
}
|
||||
if (pt & aiPrimitiveType_TRIANGLE) {
|
||||
haveit[2] = true;
|
||||
}
|
||||
if (pt & aiPrimitiveType_POLYGON) {
|
||||
haveit[3] = true;
|
||||
}
|
||||
}
|
||||
return (haveit[0] ? std::string("points") : "") + (haveit[1] ? "lines" : "") +
|
||||
(haveit[2] ? "triangles" : "") + (haveit[3] ? "n-polygons" : "");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Prettily print the node graph to stdout
|
||||
void PrintHierarchy(
|
||||
const aiNode* node,
|
||||
const std::string &indent,
|
||||
bool verbose,
|
||||
bool last = false,
|
||||
bool first = true
|
||||
){
|
||||
// tree visualization
|
||||
std::string branchchar;
|
||||
if (first) { branchchar = ""; }
|
||||
else if (last) { branchchar = TREE_STOP; } // "'-"
|
||||
else { branchchar = TREE_BRANCH; } // "|-"
|
||||
const aiNode *node,
|
||||
const std::string &indent,
|
||||
bool verbose,
|
||||
bool last = false,
|
||||
bool first = true) {
|
||||
// tree visualization
|
||||
std::string branchchar;
|
||||
if (first) {
|
||||
branchchar = "";
|
||||
} else if (last) {
|
||||
branchchar = TREE_STOP;
|
||||
} // "'-"
|
||||
else {
|
||||
branchchar = TREE_BRANCH;
|
||||
} // "|-"
|
||||
|
||||
// print the indent and the branch character and the name
|
||||
std::cout << indent << branchchar << node->mName.C_Str();
|
||||
// print the indent and the branch character and the name
|
||||
std::cout << indent << branchchar << node->mName.C_Str();
|
||||
|
||||
// if there are meshes attached, indicate this
|
||||
if (node->mNumMeshes) {
|
||||
std::cout << " (mesh ";
|
||||
bool sep = false;
|
||||
for (size_t i=0; i < node->mNumMeshes; ++i) {
|
||||
unsigned int mesh_index = node->mMeshes[i];
|
||||
if (sep) { std::cout << ", "; }
|
||||
std::cout << mesh_index;
|
||||
sep = true;
|
||||
}
|
||||
std::cout << ")";
|
||||
}
|
||||
// if there are meshes attached, indicate this
|
||||
if (node->mNumMeshes) {
|
||||
std::cout << " (mesh ";
|
||||
bool sep = false;
|
||||
for (size_t i = 0; i < node->mNumMeshes; ++i) {
|
||||
unsigned int mesh_index = node->mMeshes[i];
|
||||
if (sep) {
|
||||
std::cout << ", ";
|
||||
}
|
||||
std::cout << mesh_index;
|
||||
sep = true;
|
||||
}
|
||||
std::cout << ")";
|
||||
}
|
||||
|
||||
// finish the line
|
||||
std::cout << std::endl;
|
||||
// finish the line
|
||||
std::cout << std::endl;
|
||||
|
||||
// in verbose mode, print the transform data as well
|
||||
if (verbose) {
|
||||
// indent to use
|
||||
std::string indentadd;
|
||||
if (last) { indentadd += " "; }
|
||||
else { indentadd += TREE_CONTINUE; } // "| "..
|
||||
if (node->mNumChildren == 0) { indentadd += " "; }
|
||||
else { indentadd += TREE_CONTINUE; } // .."| "
|
||||
aiVector3D s, r, t;
|
||||
node->mTransformation.Decompose(s, r, t);
|
||||
if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
|
||||
std::cout << indent << indentadd;
|
||||
printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
|
||||
}
|
||||
if (r.x || r.y || r.z) {
|
||||
std::cout << indent << indentadd;
|
||||
printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
|
||||
}
|
||||
if (t.x || t.y || t.z) {
|
||||
std::cout << indent << indentadd;
|
||||
printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
|
||||
}
|
||||
}
|
||||
// in verbose mode, print the transform data as well
|
||||
if (verbose) {
|
||||
// indent to use
|
||||
std::string indentadd;
|
||||
if (last) {
|
||||
indentadd += " ";
|
||||
} else {
|
||||
indentadd += TREE_CONTINUE;
|
||||
} // "| "..
|
||||
if (node->mNumChildren == 0) {
|
||||
indentadd += " ";
|
||||
} else {
|
||||
indentadd += TREE_CONTINUE;
|
||||
} // .."| "
|
||||
aiVector3D s, r, t;
|
||||
node->mTransformation.Decompose(s, r, t);
|
||||
if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
|
||||
std::cout << indent << indentadd;
|
||||
printf(" S:[%f %f %f]\n", s.x, s.y, s.z);
|
||||
}
|
||||
if (r.x || r.y || r.z) {
|
||||
std::cout << indent << indentadd;
|
||||
printf(" R:[%f %f %f]\n", r.x, r.y, r.z);
|
||||
}
|
||||
if (t.x || t.y || t.z) {
|
||||
std::cout << indent << indentadd;
|
||||
printf(" T:[%f %f %f]\n", t.x, t.y, t.z);
|
||||
}
|
||||
}
|
||||
|
||||
// and recurse
|
||||
std::string nextIndent;
|
||||
if (first) { nextIndent = indent; }
|
||||
else if (last) { nextIndent = indent + " "; }
|
||||
else { nextIndent = indent + TREE_CONTINUE; } // "| "
|
||||
for (size_t i = 0; i < node->mNumChildren; ++i) {
|
||||
bool lastone = (i == node->mNumChildren - 1);
|
||||
PrintHierarchy(
|
||||
node->mChildren[i],
|
||||
nextIndent,
|
||||
verbose,
|
||||
lastone,
|
||||
false
|
||||
);
|
||||
}
|
||||
// and recurse
|
||||
std::string nextIndent;
|
||||
if (first) {
|
||||
nextIndent = indent;
|
||||
} else if (last) {
|
||||
nextIndent = indent + " ";
|
||||
} else {
|
||||
nextIndent = indent + TREE_CONTINUE;
|
||||
} // "| "
|
||||
for (size_t i = 0; i < node->mNumChildren; ++i) {
|
||||
bool lastone = (i == node->mNumChildren - 1);
|
||||
PrintHierarchy(
|
||||
node->mChildren[i],
|
||||
nextIndent,
|
||||
verbose,
|
||||
lastone,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Implementation of the assimp info utility to print basic file info
|
||||
int Assimp_Info (const char* const* params, unsigned int num) {
|
||||
// --help
|
||||
if (!strcmp( params[0],"-h")||!strcmp( params[0],"--help")||!strcmp( params[0],"-?") ) {
|
||||
printf("%s",AICMD_MSG_INFO_HELP_E);
|
||||
return AssimpCmdError::Success;
|
||||
}
|
||||
int Assimp_Info(const char *const *params, unsigned int num) {
|
||||
// --help
|
||||
if (!strcmp(params[0], "-h") || !strcmp(params[0], "--help") || !strcmp(params[0], "-?")) {
|
||||
printf("%s", AICMD_MSG_INFO_HELP_E);
|
||||
return AssimpCmdError::Success;
|
||||
}
|
||||
|
||||
// asssimp info <file> [-r]
|
||||
if (num < 1) {
|
||||
printf("assimp info: Invalid number of arguments. "
|
||||
"See \'assimp info --help\'\n");
|
||||
return AssimpCmdError::InvalidNumberOfArguments;
|
||||
}
|
||||
// asssimp info <file> [-r]
|
||||
if (num < 1) {
|
||||
printf("assimp info: Invalid number of arguments. "
|
||||
"See \'assimp info --help\'\n");
|
||||
return AssimpCmdError::InvalidNumberOfArguments;
|
||||
}
|
||||
|
||||
const std::string in = std::string(params[0]);
|
||||
const std::string in = std::string(params[0]);
|
||||
|
||||
// get -r and -v arguments
|
||||
bool raw = false;
|
||||
bool verbose = false;
|
||||
bool silent = false;
|
||||
for(unsigned int i = 1; i < num; ++i) {
|
||||
if (!strcmp(params[i],"--raw")||!strcmp(params[i],"-r")) {
|
||||
raw = true;
|
||||
}
|
||||
if (!strcmp(params[i],"--verbose")||!strcmp(params[i],"-v")) {
|
||||
verbose = true;
|
||||
}
|
||||
if (!strcmp(params[i], "--silent") || !strcmp(params[i], "-s")) {
|
||||
silent = true;
|
||||
}
|
||||
}
|
||||
// get -r and -v arguments
|
||||
bool raw = false;
|
||||
bool verbose = false;
|
||||
bool silent = false;
|
||||
for (unsigned int i = 1; i < num; ++i) {
|
||||
if (!strcmp(params[i], "--raw") || !strcmp(params[i], "-r")) {
|
||||
raw = true;
|
||||
}
|
||||
if (!strcmp(params[i], "--verbose") || !strcmp(params[i], "-v")) {
|
||||
verbose = true;
|
||||
}
|
||||
if (!strcmp(params[i], "--silent") || !strcmp(params[i], "-s")) {
|
||||
silent = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Verbose and silent at the same time are not allowed
|
||||
if ( verbose && silent ) {
|
||||
printf("assimp info: Invalid arguments, verbose and silent at the same time are forbidden. ");
|
||||
return AssimpCmdInfoError::InvalidCombinaisonOfArguments;
|
||||
}
|
||||
// Verbose and silent at the same time are not allowed
|
||||
if (verbose && silent) {
|
||||
printf("assimp info: Invalid arguments, verbose and silent at the same time are forbidden. ");
|
||||
return AssimpCmdInfoError::InvalidCombinaisonOfArguments;
|
||||
}
|
||||
|
||||
// Parse post-processing flags unless -r was specified
|
||||
ImportData import;
|
||||
if (!raw) {
|
||||
// get import flags
|
||||
ProcessStandardArguments(import, params + 1, num - 1);
|
||||
// Parse post-processing flags unless -r was specified
|
||||
ImportData import;
|
||||
if (!raw) {
|
||||
// get import flags
|
||||
ProcessStandardArguments(import, params + 1, num - 1);
|
||||
|
||||
//No custom post process flags defined, we set all the post process flags active
|
||||
if(import.ppFlags == 0)
|
||||
import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality;
|
||||
}
|
||||
//No custom post process flags defined, we set all the post process flags active
|
||||
if (import.ppFlags == 0)
|
||||
import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality;
|
||||
}
|
||||
|
||||
// import the main model
|
||||
const aiScene* scene = ImportModel(import,in);
|
||||
if (!scene) {
|
||||
printf("assimp info: Unable to load input file %s\n",
|
||||
in.c_str());
|
||||
return AssimpCmdError::FailedToLoadInputFile;
|
||||
}
|
||||
// import the main model
|
||||
const aiScene *scene = ImportModel(import, in);
|
||||
if (!scene) {
|
||||
printf("assimp info: Unable to load input file %s\n",
|
||||
in.c_str());
|
||||
return AssimpCmdError::FailedToLoadInputFile;
|
||||
}
|
||||
|
||||
aiMemoryInfo mem;
|
||||
globalImporter->GetMemoryRequirements(mem);
|
||||
aiMemoryInfo mem;
|
||||
globalImporter->GetMemoryRequirements(mem);
|
||||
|
||||
static const char *format_string =
|
||||
"Memory consumption: %i B\n"
|
||||
"Nodes: %i\n"
|
||||
"Maximum depth %i\n"
|
||||
"Meshes: %i\n"
|
||||
"Animations: %i\n"
|
||||
"Textures (embed.): %i\n"
|
||||
"Materials: %i\n"
|
||||
"Cameras: %i\n"
|
||||
"Lights: %i\n"
|
||||
"Vertices: %i\n"
|
||||
"Faces: %i\n"
|
||||
"Bones: %i\n"
|
||||
"Animation Channels: %i\n"
|
||||
"Primitive Types: %s\n"
|
||||
"Average faces/mesh %i\n"
|
||||
"Average verts/mesh %i\n"
|
||||
"Minimum point (%f %f %f)\n"
|
||||
"Maximum point (%f %f %f)\n"
|
||||
"Center point (%f %f %f)\n"
|
||||
|
||||
static const char* format_string =
|
||||
"Memory consumption: %i B\n"
|
||||
"Nodes: %i\n"
|
||||
"Maximum depth %i\n"
|
||||
"Meshes: %i\n"
|
||||
"Animations: %i\n"
|
||||
"Textures (embed.): %i\n"
|
||||
"Materials: %i\n"
|
||||
"Cameras: %i\n"
|
||||
"Lights: %i\n"
|
||||
"Vertices: %i\n"
|
||||
"Faces: %i\n"
|
||||
"Bones: %i\n"
|
||||
"Animation Channels: %i\n"
|
||||
"Primitive Types: %s\n"
|
||||
"Average faces/mesh %i\n"
|
||||
"Average verts/mesh %i\n"
|
||||
"Minimum point (%f %f %f)\n"
|
||||
"Maximum point (%f %f %f)\n"
|
||||
"Center point (%f %f %f)\n"
|
||||
;
|
||||
|
||||
;
|
||||
aiVector3D special_points[3];
|
||||
FindSpecialPoints(scene, special_points);
|
||||
printf(format_string,
|
||||
mem.total,
|
||||
CountNodes(scene->mRootNode),
|
||||
GetMaxDepth(scene->mRootNode),
|
||||
scene->mNumMeshes,
|
||||
scene->mNumAnimations,
|
||||
scene->mNumTextures,
|
||||
scene->mNumMaterials,
|
||||
scene->mNumCameras,
|
||||
scene->mNumLights,
|
||||
CountVertices(scene),
|
||||
CountFaces(scene),
|
||||
CountBones(scene),
|
||||
CountAnimChannels(scene),
|
||||
FindPTypes(scene).c_str(),
|
||||
GetAvgFacePerMesh(scene),
|
||||
GetAvgVertsPerMesh(scene),
|
||||
special_points[0][0], special_points[0][1], special_points[0][2],
|
||||
special_points[1][0], special_points[1][1], special_points[1][2],
|
||||
special_points[2][0], special_points[2][1], special_points[2][2]);
|
||||
|
||||
aiVector3D special_points[3];
|
||||
FindSpecialPoints(scene,special_points);
|
||||
printf(format_string,
|
||||
mem.total,
|
||||
CountNodes(scene->mRootNode),
|
||||
GetMaxDepth(scene->mRootNode),
|
||||
scene->mNumMeshes,
|
||||
scene->mNumAnimations,
|
||||
scene->mNumTextures,
|
||||
scene->mNumMaterials,
|
||||
scene->mNumCameras,
|
||||
scene->mNumLights,
|
||||
CountVertices(scene),
|
||||
CountFaces(scene),
|
||||
CountBones(scene),
|
||||
CountAnimChannels(scene),
|
||||
FindPTypes(scene).c_str(),
|
||||
GetAvgFacePerMesh(scene),
|
||||
GetAvgVertsPerMesh(scene),
|
||||
special_points[0][0],special_points[0][1],special_points[0][2],
|
||||
special_points[1][0],special_points[1][1],special_points[1][2],
|
||||
special_points[2][0],special_points[2][1],special_points[2][2]
|
||||
)
|
||||
;
|
||||
if (silent) {
|
||||
printf("\n");
|
||||
return AssimpCmdError::Success;
|
||||
}
|
||||
|
||||
if (silent)
|
||||
{
|
||||
printf("\n");
|
||||
return AssimpCmdError::Success;
|
||||
}
|
||||
// meshes
|
||||
if (scene->mNumMeshes) {
|
||||
printf("\nMeshes: (name) [vertices / bones / faces | primitive_types]\n");
|
||||
}
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
const aiMesh *mesh = scene->mMeshes[i];
|
||||
printf(" %d (%s)", i, mesh->mName.C_Str());
|
||||
printf(
|
||||
": [%d / %d / %d |",
|
||||
mesh->mNumVertices,
|
||||
mesh->mNumBones,
|
||||
mesh->mNumFaces);
|
||||
const unsigned int ptypes = mesh->mPrimitiveTypes;
|
||||
if (ptypes & aiPrimitiveType_POINT) {
|
||||
printf(" point");
|
||||
}
|
||||
if (ptypes & aiPrimitiveType_LINE) {
|
||||
printf(" line");
|
||||
}
|
||||
if (ptypes & aiPrimitiveType_TRIANGLE) {
|
||||
printf(" triangle");
|
||||
}
|
||||
if (ptypes & aiPrimitiveType_POLYGON) {
|
||||
printf(" polygon");
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
// meshes
|
||||
if (scene->mNumMeshes) {
|
||||
printf("\nMeshes: (name) [vertices / bones / faces | primitive_types]\n");
|
||||
}
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
const aiMesh* mesh = scene->mMeshes[i];
|
||||
printf(" %d (%s)", i, mesh->mName.C_Str());
|
||||
printf(
|
||||
": [%d / %d / %d |",
|
||||
mesh->mNumVertices,
|
||||
mesh->mNumBones,
|
||||
mesh->mNumFaces
|
||||
);
|
||||
const unsigned int ptypes = mesh->mPrimitiveTypes;
|
||||
if (ptypes & aiPrimitiveType_POINT) { printf(" point"); }
|
||||
if (ptypes & aiPrimitiveType_LINE) { printf(" line"); }
|
||||
if (ptypes & aiPrimitiveType_TRIANGLE) { printf(" triangle"); }
|
||||
if (ptypes & aiPrimitiveType_POLYGON) { printf(" polygon"); }
|
||||
printf("]\n");
|
||||
}
|
||||
// materials
|
||||
if (scene->mNumMaterials)
|
||||
printf("\nNamed Materials:");
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||
const aiMaterial *mat = scene->mMaterials[i];
|
||||
aiString name = mat->GetName();
|
||||
printf("\n \'%s\'", name.data);
|
||||
if (mat->mNumProperties)
|
||||
printf(" (prop) [index / bytes | texture semantic]");
|
||||
for (unsigned p = 0; p < mat->mNumProperties; p++) {
|
||||
const aiMaterialProperty *prop = mat->mProperties[p];
|
||||
const aiTextureType textype = static_cast<aiTextureType>(prop->mSemantic);
|
||||
printf("\n %d (%s): [%d / %d | %s]",
|
||||
p,
|
||||
prop->mKey.data,
|
||||
prop->mIndex,
|
||||
prop->mDataLength,
|
||||
TextureTypeToString(textype));
|
||||
}
|
||||
}
|
||||
if (scene->mNumMaterials) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// materials
|
||||
unsigned int total=0;
|
||||
for(unsigned int i = 0;i < scene->mNumMaterials; ++i) {
|
||||
aiString name;
|
||||
if (AI_SUCCESS==aiGetMaterialString(scene->mMaterials[i],AI_MATKEY_NAME,&name)) {
|
||||
printf("%s\n \'%s\'",(total++?"":"\nNamed Materials:" ),name.data);
|
||||
}
|
||||
}
|
||||
if(total) {
|
||||
printf("\n");
|
||||
}
|
||||
// textures
|
||||
unsigned int total = 0;
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||
aiString name;
|
||||
static const aiTextureType types[] = {
|
||||
aiTextureType_NONE,
|
||||
aiTextureType_DIFFUSE,
|
||||
aiTextureType_SPECULAR,
|
||||
aiTextureType_AMBIENT,
|
||||
aiTextureType_EMISSIVE,
|
||||
aiTextureType_HEIGHT,
|
||||
aiTextureType_NORMALS,
|
||||
aiTextureType_SHININESS,
|
||||
aiTextureType_OPACITY,
|
||||
aiTextureType_DISPLACEMENT,
|
||||
aiTextureType_LIGHTMAP,
|
||||
aiTextureType_REFLECTION,
|
||||
aiTextureType_BASE_COLOR,
|
||||
aiTextureType_NORMAL_CAMERA,
|
||||
aiTextureType_EMISSION_COLOR,
|
||||
aiTextureType_METALNESS,
|
||||
aiTextureType_DIFFUSE_ROUGHNESS,
|
||||
aiTextureType_AMBIENT_OCCLUSION,
|
||||
aiTextureType_UNKNOWN
|
||||
};
|
||||
for (unsigned int type = 0; type < sizeof(types) / sizeof(types[0]); ++type) {
|
||||
for (unsigned int idx = 0; AI_SUCCESS == aiGetMaterialString(scene->mMaterials[i],
|
||||
AI_MATKEY_TEXTURE(types[type], idx), &name);
|
||||
++idx) {
|
||||
printf("%s\n \'%s\'", (total++ ? "" : "\nTexture Refs:"), name.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (total) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// textures
|
||||
total=0;
|
||||
for(unsigned int i = 0;i < scene->mNumMaterials; ++i) {
|
||||
aiString name;
|
||||
static const aiTextureType types[] = {
|
||||
aiTextureType_NONE,
|
||||
aiTextureType_DIFFUSE,
|
||||
aiTextureType_SPECULAR,
|
||||
aiTextureType_AMBIENT,
|
||||
aiTextureType_EMISSIVE,
|
||||
aiTextureType_HEIGHT,
|
||||
aiTextureType_NORMALS,
|
||||
aiTextureType_SHININESS,
|
||||
aiTextureType_OPACITY,
|
||||
aiTextureType_DISPLACEMENT,
|
||||
aiTextureType_LIGHTMAP,
|
||||
aiTextureType_REFLECTION,
|
||||
aiTextureType_BASE_COLOR,
|
||||
aiTextureType_NORMAL_CAMERA,
|
||||
aiTextureType_EMISSION_COLOR,
|
||||
aiTextureType_METALNESS,
|
||||
aiTextureType_DIFFUSE_ROUGHNESS,
|
||||
aiTextureType_AMBIENT_OCCLUSION,
|
||||
aiTextureType_UNKNOWN
|
||||
};
|
||||
for(unsigned int type = 0; type < sizeof(types)/sizeof(types[0]); ++type) {
|
||||
for(unsigned int idx = 0;AI_SUCCESS==aiGetMaterialString(scene->mMaterials[i],
|
||||
AI_MATKEY_TEXTURE(types[type],idx),&name); ++idx) {
|
||||
printf("%s\n \'%s\'",(total++?"":"\nTexture Refs:" ),name.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(total) {
|
||||
printf("\n");
|
||||
}
|
||||
// animations
|
||||
total = 0;
|
||||
for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
|
||||
if (scene->mAnimations[i]->mName.length) {
|
||||
printf("%s\n \'%s\'", (total++ ? "" : "\nNamed Animations:"), scene->mAnimations[i]->mName.data);
|
||||
}
|
||||
}
|
||||
if (total) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// animations
|
||||
total=0;
|
||||
for(unsigned int i = 0;i < scene->mNumAnimations; ++i) {
|
||||
if (scene->mAnimations[i]->mName.length) {
|
||||
printf("%s\n \'%s\'",(total++?"":"\nNamed Animations:" ),scene->mAnimations[i]->mName.data);
|
||||
}
|
||||
}
|
||||
if(total) {
|
||||
printf("\n");
|
||||
}
|
||||
// node hierarchy
|
||||
printf("\nNode hierarchy:\n");
|
||||
PrintHierarchy(scene->mRootNode, "", verbose);
|
||||
|
||||
// node hierarchy
|
||||
printf("\nNode hierarchy:\n");
|
||||
PrintHierarchy(scene->mRootNode,"",verbose);
|
||||
|
||||
printf("\n");
|
||||
return AssimpCmdError::Success;
|
||||
printf("\n");
|
||||
return AssimpCmdError::Success;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user