Merge branch 'master' into x3d_pugi_migration

pull/4079/head
René Martin 2021-09-07 15:04:08 +02:00
parent 6db142ee51
commit 3001d88172
295 changed files with 5518 additions and 11500 deletions

2
.gitignore vendored
View File

@ -25,7 +25,7 @@ CMakeSettings.json
# Output # Output
bin/ bin/
lib/ lib/
x64/
# QtCreator # QtCreator
CMakeLists.txt.user CMakeLists.txt.user

View File

@ -44,10 +44,10 @@ CMAKE_MINIMUM_REQUIRED( VERSION 3.10 )
option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
include("cmake/HunterGate.cmake") include("cmake-modules/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.23.293.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.23.311.tar.gz"
SHA1 "e8e5470652db77149d9b38656db2a6c0b7642693" SHA1 "1a82b9b73055879181cb1466b2ab5d48ee8ae410"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
@ -135,11 +135,11 @@ IF ( WIN32 )
# Use subset of Windows.h # Use subset of Windows.h
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
"If the Assimp view tool is built. (requires DirectX)"
OFF )
IF(MSVC) IF(MSVC)
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
"If the Assimp view tool is built. (requires DirectX)"
OFF )
OPTION( ASSIMP_INSTALL_PDB OPTION( ASSIMP_INSTALL_PDB
"Install MSVC debug files." "Install MSVC debug files."
ON ) ON )
@ -268,6 +268,8 @@ ELSEIF(MSVC)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od") SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF")
ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
IF(NOT ASSIMP_HUNTER_ENABLED) IF(NOT ASSIMP_HUNTER_ENABLED)
SET(CMAKE_CXX_STANDARD 11) SET(CMAKE_CXX_STANDARD 11)
@ -395,14 +397,14 @@ set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-hunter-config.cmake.in") set(CMAKE_CONFIG_TEMPLATE_FILE "cmake-modules/assimp-hunter-config.cmake.in")
set(NAMESPACE "${PROJECT_NAME}::") set(NAMESPACE "${PROJECT_NAME}::")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake") set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
ELSE() ELSE()
set(CONFIG_INSTALL_DIR "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") set(CONFIG_INSTALL_DIR "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-plain-config.cmake.in") set(CMAKE_CONFIG_TEMPLATE_FILE "cmake-modules/assimp-plain-config.cmake.in")
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE)
set(NAMESPACE "${PROJECT_NAME_LOWERCASE}::") set(NAMESPACE "${PROJECT_NAME_LOWERCASE}::")
set(TARGETS_EXPORT_NAME "${PROJECT_NAME_LOWERCASE}Targets") set(TARGETS_EXPORT_NAME "${PROJECT_NAME_LOWERCASE}Targets")

View File

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

View File

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

View File

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

View File

@ -68,8 +68,8 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() {
unsigned int idx(NotSet); unsigned int idx(NotSet);
for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) { for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
std::string s = mScene->mMaterials[i].mName; std::string s = mScene->mMaterials[i].mName;
for (std::string::iterator it = s.begin(); it != s.end(); ++it) { for (char & it : s) {
*it = static_cast<char>(::tolower(static_cast<unsigned char>(*it))); it = static_cast<char>(::tolower(static_cast<unsigned char>(it)));
} }
if (std::string::npos == s.find("default")) continue; if (std::string::npos == s.find("default")) continue;
@ -79,12 +79,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() {
mScene->mMaterials[i].mDiffuse.r != mScene->mMaterials[i].mDiffuse.r !=
mScene->mMaterials[i].mDiffuse.b) continue; mScene->mMaterials[i].mDiffuse.b) continue;
if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || if (ContainsTextures(i)) {
mScene->mMaterials[i].sTexBump.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 ||
mScene->mMaterials[i].sTexShininess.mMapName.length() != 0) {
continue; continue;
} }
idx = i; idx = i;

View File

@ -348,16 +348,16 @@ struct Texture {
// empty // empty
} }
Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)), Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(other.mTextureBlend),
mMapName(std::move(other.mMapName)), mMapName(std::move(other.mMapName)),
mOffsetU(std::move(other.mOffsetU)), mOffsetU(other.mOffsetU),
mOffsetV(std::move(other.mOffsetV)), mOffsetV(other.mOffsetV),
mScaleU(std::move(other.mScaleU)), mScaleU(other.mScaleU),
mScaleV(std::move(other.mScaleV)), mScaleV(other.mScaleV),
mRotation(std::move(other.mRotation)), mRotation(other.mRotation),
mMapMode(std::move(other.mMapMode)), mMapMode(other.mMapMode),
bPrivate(std::move(other.bPrivate)), bPrivate(other.bPrivate),
iUVSrc(std::move(other.iUVSrc)) { iUVSrc(other.iUVSrc) {
// empty // empty
} }
@ -366,16 +366,16 @@ struct Texture {
return *this; return *this;
} }
mTextureBlend = std::move(other.mTextureBlend); mTextureBlend = other.mTextureBlend;
mMapName = std::move(other.mMapName); mMapName = std::move(other.mMapName);
mOffsetU = std::move(other.mOffsetU); mOffsetU = other.mOffsetU;
mOffsetV = std::move(other.mOffsetV); mOffsetV = other.mOffsetV;
mScaleU = std::move(other.mScaleU); mScaleU = other.mScaleU;
mScaleV = std::move(other.mScaleV); mScaleV = other.mScaleV;
mRotation = std::move(other.mRotation); mRotation = other.mRotation;
mMapMode = std::move(other.mMapMode); mMapMode = other.mMapMode;
bPrivate = std::move(other.bPrivate); bPrivate = other.bPrivate;
iUVSrc = std::move(other.iUVSrc); iUVSrc = other.iUVSrc;
return *this; return *this;
} }
@ -461,13 +461,13 @@ struct Material {
//! Move constructor. This is explicitly written because MSVC doesn't support defaulting it //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)), Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)),
mDiffuse(std::move(other.mDiffuse)), mDiffuse(other.mDiffuse),
mSpecularExponent(std::move(other.mSpecularExponent)), mSpecularExponent(other.mSpecularExponent),
mShininessStrength(std::move(other.mShininessStrength)), mShininessStrength(other.mShininessStrength),
mSpecular(std::move(other.mSpecular)), mSpecular(other.mSpecular),
mAmbient(std::move(other.mAmbient)), mAmbient(other.mAmbient),
mShading(std::move(other.mShading)), mShading(other.mShading),
mTransparency(std::move(other.mTransparency)), mTransparency(other.mTransparency),
sTexDiffuse(std::move(other.sTexDiffuse)), sTexDiffuse(std::move(other.sTexDiffuse)),
sTexOpacity(std::move(other.sTexOpacity)), sTexOpacity(std::move(other.sTexOpacity)),
sTexSpecular(std::move(other.sTexSpecular)), sTexSpecular(std::move(other.sTexSpecular)),
@ -475,10 +475,10 @@ struct Material {
sTexBump(std::move(other.sTexBump)), sTexBump(std::move(other.sTexBump)),
sTexEmissive(std::move(other.sTexEmissive)), sTexEmissive(std::move(other.sTexEmissive)),
sTexShininess(std::move(other.sTexShininess)), sTexShininess(std::move(other.sTexShininess)),
mBumpHeight(std::move(other.mBumpHeight)), mBumpHeight(other.mBumpHeight),
mEmissive(std::move(other.mEmissive)), mEmissive(other.mEmissive),
sTexAmbient(std::move(other.sTexAmbient)), sTexAmbient(std::move(other.sTexAmbient)),
mTwoSided(std::move(other.mTwoSided)) { mTwoSided(other.mTwoSided) {
// empty // empty
} }
@ -488,13 +488,13 @@ struct Material {
} }
mName = std::move(other.mName); mName = std::move(other.mName);
mDiffuse = std::move(other.mDiffuse); mDiffuse = other.mDiffuse;
mSpecularExponent = std::move(other.mSpecularExponent); mSpecularExponent = other.mSpecularExponent;
mShininessStrength = std::move(other.mShininessStrength), mShininessStrength = other.mShininessStrength,
mSpecular = std::move(other.mSpecular); mSpecular = other.mSpecular;
mAmbient = std::move(other.mAmbient); mAmbient = other.mAmbient;
mShading = std::move(other.mShading); mShading = other.mShading;
mTransparency = std::move(other.mTransparency); mTransparency = other.mTransparency;
sTexDiffuse = std::move(other.sTexDiffuse); sTexDiffuse = std::move(other.sTexDiffuse);
sTexOpacity = std::move(other.sTexOpacity); sTexOpacity = std::move(other.sTexOpacity);
sTexSpecular = std::move(other.sTexSpecular); sTexSpecular = std::move(other.sTexSpecular);
@ -502,10 +502,10 @@ struct Material {
sTexBump = std::move(other.sTexBump); sTexBump = std::move(other.sTexBump);
sTexEmissive = std::move(other.sTexEmissive); sTexEmissive = std::move(other.sTexEmissive);
sTexShininess = std::move(other.sTexShininess); sTexShininess = std::move(other.sTexShininess);
mBumpHeight = std::move(other.mBumpHeight); mBumpHeight = other.mBumpHeight;
mEmissive = std::move(other.mEmissive); mEmissive = other.mEmissive;
sTexAmbient = std::move(other.sTexAmbient); sTexAmbient = std::move(other.sTexAmbient);
mTwoSided = std::move(other.mTwoSided); mTwoSided = other.mTwoSided;
return *this; return *this;
} }

View File

@ -208,6 +208,15 @@ protected:
*/ */
void ReplaceDefaultMaterial(); void ReplaceDefaultMaterial();
bool ContainsTextures(unsigned int i) const {
return !mScene->mMaterials[i].sTexDiffuse.mMapName.empty() ||
!mScene->mMaterials[i].sTexBump.mMapName.empty() ||
!mScene->mMaterials[i].sTexOpacity.mMapName.empty() ||
!mScene->mMaterials[i].sTexEmissive.mMapName.empty() ||
!mScene->mMaterials[i].sTexSpecular.mMapName.empty() ||
!mScene->mMaterials[i].sTexShininess.mMapName.empty() ;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Convert the whole scene /** Convert the whole scene
*/ */

View File

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

View File

@ -80,13 +80,21 @@ namespace XmlTag {
const char* const item = "item"; const char* const item = "item";
const char* const objectid = "objectid"; const char* const objectid = "objectid";
const char* const transform = "transform"; const char* const transform = "transform";
const char *const path = "path";
// Material definitions // Material definitions
const char* const basematerials = "basematerials"; const char* const basematerials = "basematerials";
const char* const basematerials_id = "id";
const char* const basematerials_base = "base"; const char* const basematerials_base = "base";
const char* const basematerials_name = "name"; const char* const basematerials_name = "name";
const char* const basematerials_displaycolor = "displaycolor"; const char* const basematerials_displaycolor = "displaycolor";
const char* const texture_2d = "m:texture2d";
const char *const texture_group = "m:texture2dgroup";
const char *const texture_content_type = "contenttype";
const char *const texture_tilestyleu = "tilestyleu";
const char *const texture_tilestylev = "tilestylev";
const char *const texture_2d_coord = "m:tex2coord";
const char *const texture_cuurd_u = "u";
const char *const texture_cuurd_v = "v";
// Meta info tags // Meta info tags
const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml"; const char* const CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
@ -103,7 +111,7 @@ namespace XmlTag {
const char* const PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture"; const char* const PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
const char* const PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; const char* const PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
const char* const PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"; const char* const PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
} }
} // Namespace D3MF } // Namespace D3MF
} // Namespace Assimp } // Namespace Assimp

View File

@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFImporter.h" #include "D3MFImporter.h"
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include "XmlSerializer.h"
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
@ -61,513 +62,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <vector> #include <vector>
#include <iomanip> #include <iomanip>
#include <string.h> #include <cstring>
namespace Assimp { namespace Assimp {
namespace D3MF {
enum class ResourceType {
RT_Object,
RT_BaseMaterials,
RT_Unknown
}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
class Resource {
public:
int mId;
Resource(int id) :
mId(id) {
// empty
}
virtual ~Resource() {
// empty
}
virtual ResourceType getType() const {
return ResourceType::RT_Unknown;
}
};
class BaseMaterials : public Resource {
public:
std::vector<aiMaterial *> mMaterials;
std::vector<unsigned int> mMaterialIndex;
BaseMaterials(int id) :
Resource(id),
mMaterials(),
mMaterialIndex() {
// empty
}
~BaseMaterials() = default;
ResourceType getType() const override {
return ResourceType::RT_BaseMaterials;
}
};
struct Component {
int mObjectId;
aiMatrix4x4 mTransformation;
};
class Object : public Resource {
public:
std::vector<aiMesh *> mMeshes;
std::vector<unsigned int> mMeshIndex;
std::vector<Component> mComponents;
std::string mName;
Object(int id) :
Resource(id),
mName(std::string("Object_") + ai_to_string(id)) {
// empty
}
~Object() = default;
ResourceType getType() const override {
return ResourceType::RT_Object;
}
};
class XmlSerializer {
public:
XmlSerializer(XmlParser *xmlParser) :
mResourcesDictionnary(),
mMaterialCount(0),
mMeshCount(0),
mXmlParser(xmlParser) {
// empty
}
~XmlSerializer() {
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it ) {
delete it->second;
}
}
void ImportXml(aiScene *scene) {
if (nullptr == scene) {
return;
}
scene->mRootNode = new aiNode(XmlTag::RootTag);
XmlNode node = mXmlParser->getRootNode().child(XmlTag::model);
if (node.empty()) {
return;
}
XmlNode resNode = node.child(XmlTag::resources);
for (auto &currentNode : resNode.children()) {
const std::string currentNodeName = currentNode.name();
if (currentNodeName == XmlTag::object) {
ReadObject(currentNode);
} else if (currentNodeName == XmlTag::basematerials) {
ReadBaseMaterials(currentNode);
} else if (currentNodeName == XmlTag::meta) {
ReadMetadata(currentNode);
}
}
XmlNode buildNode = node.child(XmlTag::build);
for (auto &currentNode : buildNode.children()) {
const std::string currentNodeName = currentNode.name();
if (currentNodeName == XmlTag::item) {
int objectId = -1;
std::string transformationMatrixStr;
aiMatrix4x4 transformationMatrix;
getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId);
bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transformationMatrixStr);
auto it = mResourcesDictionnary.find(objectId);
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object *>(it->second);
if (hasTransform) {
transformationMatrix = parseTransformMatrix(transformationMatrixStr);
}
addObjectToNode(scene->mRootNode, obj, transformationMatrix);
}
}
}
// import the metadata
if (!mMetaData.empty()) {
const size_t numMeta = mMetaData.size();
scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
for (size_t i = 0; i < numMeta; ++i) {
aiString val(mMetaData[i].value);
scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
}
}
// import the meshes
scene->mNumMeshes = static_cast<unsigned int>(mMeshCount);
if (scene->mNumMeshes != 0) {
scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) {
if (it->second->getType() == ResourceType::RT_Object) {
Object *obj = static_cast<Object *>(it->second);
ai_assert(nullptr != obj);
for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) {
scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i];
}
}
}
}
// import the materials
scene->mNumMaterials = mMaterialCount;
if (scene->mNumMaterials != 0) {
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); ++it) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) {
scene->mMaterials[baseMaterials->mMaterialIndex[i]] = baseMaterials->mMaterials[i];
}
}
}
}
}
private:
void addObjectToNode(aiNode *parent, Object *obj, aiMatrix4x4 nodeTransform) {
ai_assert(nullptr != obj);
aiNode *sceneNode = new aiNode(obj->mName);
sceneNode->mNumMeshes = static_cast<unsigned int>(obj->mMeshes.size());
sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes];
std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes);
sceneNode->mTransformation = nodeTransform;
if (nullptr != parent) {
parent->addChildren(1, &sceneNode);
}
for (size_t i = 0; i < obj->mComponents.size(); ++i) {
Component c = obj->mComponents[i];
auto it = mResourcesDictionnary.find(c.mObjectId);
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
addObjectToNode(sceneNode, static_cast<Object *>(it->second), c.mTransformation);
}
}
}
bool getNodeAttribute(const XmlNode &node, const std::string &attribute, std::string &value) {
pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str());
if (!objectAttribute.empty()) {
value = objectAttribute.as_string();
return true;
}
return false;
}
bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) {
std::string strValue;
bool ret = getNodeAttribute(node, attribute, strValue);
if (ret) {
value = std::atoi(strValue.c_str());
return true;
}
return false;
}
aiMatrix4x4 parseTransformMatrix(std::string matrixStr) {
// split the string
std::vector<float> numbers;
std::string currentNumber;
for (size_t i = 0; i < matrixStr.size(); ++i) {
const char c = matrixStr[i];
if (c == ' ') {
if (currentNumber.size() > 0) {
float f = std::stof(currentNumber);
numbers.push_back(f);
currentNumber.clear();
}
} else {
currentNumber.push_back(c);
}
}
if (currentNumber.size() > 0) {
const float f = std::stof(currentNumber);
numbers.push_back(f);
}
aiMatrix4x4 transformMatrix;
transformMatrix.a1 = numbers[0];
transformMatrix.b1 = numbers[1];
transformMatrix.c1 = numbers[2];
transformMatrix.d1 = 0;
transformMatrix.a2 = numbers[3];
transformMatrix.b2 = numbers[4];
transformMatrix.c2 = numbers[5];
transformMatrix.d2 = 0;
transformMatrix.a3 = numbers[6];
transformMatrix.b3 = numbers[7];
transformMatrix.c3 = numbers[8];
transformMatrix.d3 = 0;
transformMatrix.a4 = numbers[9];
transformMatrix.b4 = numbers[10];
transformMatrix.c4 = numbers[11];
transformMatrix.d4 = 1;
return transformMatrix;
}
void ReadObject(XmlNode &node) {
int id = -1, pid = -1, pindex = -1;
bool hasId = getNodeAttribute(node, XmlTag::id, id);
bool hasPid = getNodeAttribute(node, XmlTag::pid, pid);
bool hasPindex = getNodeAttribute(node, XmlTag::pindex, pindex);
if (!hasId) {
return;
}
Object *obj = new Object(id);
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh(currentNode);
mesh->mName.Set(ai_to_string(id));
if (hasPid) {
auto it = mResourcesDictionnary.find(pid);
if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
}
}
obj->mMeshes.push_back(mesh);
obj->mMeshIndex.push_back(mMeshCount);
mMeshCount++;
} else if (currentName == D3MF::XmlTag::components) {
for (XmlNode &currentSubNode : currentNode.children()) {
const std::string subNodeName = currentSubNode.name();
if (subNodeName == D3MF::XmlTag::component) {
int objectId = -1;
std::string componentTransformStr;
aiMatrix4x4 componentTransform;
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::transform, componentTransformStr)) {
componentTransform = parseTransformMatrix(componentTransformStr);
}
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId)) {
obj->mComponents.push_back({ objectId, componentTransform });
}
}
}
}
}
mResourcesDictionnary.insert(std::make_pair(id, obj));
}
aiMesh *ReadMesh(XmlNode &node) {
aiMesh *mesh = new aiMesh();
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::vertices) {
ImportVertices(currentNode, mesh);
} else if (currentName == XmlTag::triangles) {
ImportTriangles(currentNode, mesh);
}
}
return mesh;
}
void ReadMetadata(XmlNode &node) {
pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name);
const std::string name = attribute.as_string();
const std::string value = node.value();
if (name.empty()) {
return;
}
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back(entry);
}
void ImportVertices(XmlNode &node, aiMesh *mesh) {
std::vector<aiVector3D> vertices;
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::vertex) {
vertices.push_back(ReadVertex(currentNode));
}
}
mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
}
aiVector3D ReadVertex(XmlNode &node) {
aiVector3D vertex;
vertex.x = ai_strtof(node.attribute(XmlTag::x).as_string(), nullptr);
vertex.y = ai_strtof(node.attribute(XmlTag::y).as_string(), nullptr);
vertex.z = ai_strtof(node.attribute(XmlTag::z).as_string(), nullptr);
return vertex;
}
void ImportTriangles(XmlNode &node, aiMesh *mesh) {
std::vector<aiFace> faces;
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::triangle) {
aiFace face = ReadTriangle(currentNode);
faces.push_back(face);
int pid = 0, p1 = 0;
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
if (hasPid && hasP1) {
auto it = mResourcesDictionnary.find(pid);
if (it != mResourcesDictionnary.end()) {
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
}
// TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material
}
}
}
}
mesh->mNumFaces = static_cast<unsigned int>(faces.size());
mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
std::copy(faces.begin(), faces.end(), mesh->mFaces);
}
aiFace ReadTriangle(XmlNode &node) {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v1).as_string()));
face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
return face;
}
void ReadBaseMaterials(XmlNode &node) {
int id = -1;
if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) {
BaseMaterials *baseMaterials = new BaseMaterials(id);
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == XmlTag::basematerials_base) {
baseMaterials->mMaterialIndex.push_back(mMaterialCount);
baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id));
++mMaterialCount;
}
}
mResourcesDictionnary.insert(std::make_pair(id, baseMaterials));
}
}
bool parseColor(const char *color, aiColor4D &diffuse) {
if (nullptr == color) {
return false;
}
//format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
const size_t len = strlen(color);
if (9 != len && 7 != len) {
return false;
}
const char *buf(color);
if ('#' != buf[0]) {
return false;
}
char r[3] = { buf[1], buf[2], '\0' };
diffuse.r = static_cast<ai_real>(strtol(r, nullptr, 16)) / ai_real(255.0);
char g[3] = { buf[3], buf[4], '\0' };
diffuse.g = static_cast<ai_real>(strtol(g, nullptr, 16)) / ai_real(255.0);
char b[3] = { buf[5], buf[6], '\0' };
diffuse.b = static_cast<ai_real>(strtol(b, nullptr, 16)) / ai_real(255.0);
if (7 == len)
return true;
char a[3] = { buf[7], buf[8], '\0' };
diffuse.a = static_cast<ai_real>(strtol(a, nullptr, 16)) / ai_real(255.0);
return true;
}
void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
const char *color = node.attribute(XmlTag::basematerials_displaycolor).as_string();
aiColor4D diffuse;
if (parseColor(color, diffuse)) {
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
}
}
aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) {
aiMaterial *material = new aiMaterial();
material->mNumProperties = 0;
std::string name;
bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name);
std::string stdMaterialName;
const std::string strId(ai_to_string(basematerialsId));
stdMaterialName += "id";
stdMaterialName += strId;
stdMaterialName += "_";
if (hasName) {
stdMaterialName += std::string(name);
} else {
stdMaterialName += "basemat_";
stdMaterialName += ai_to_string(mMaterialCount - basematerialsId);
}
aiString assimpMaterialName(stdMaterialName);
material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME);
assignDiffuseColor(node, material);
return material;
}
private:
struct MetaEntry {
std::string name;
std::string value;
};
std::vector<MetaEntry> mMetaData;
std::map<unsigned int, Resource *> mResourcesDictionnary;
unsigned int mMaterialCount, mMeshCount;
XmlParser *mXmlParser;
};
} //namespace D3MF
using namespace D3MF; using namespace D3MF;
@ -597,7 +94,9 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
const std::string extension(GetExtension(filename)); const std::string extension(GetExtension(filename));
if (extension == desc.mFileExtensions) { if (extension == desc.mFileExtensions) {
return true; return true;
} else if (!extension.length() || checkSig) { }
if (!extension.length() || checkSig) {
if (nullptr == pIOHandler) { if (nullptr == pIOHandler) {
return false; return false;
} }
@ -611,7 +110,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
return false; return false;
} }
void D3MFImporter::SetupProperties(const Importer * /*pImp*/) { void D3MFImporter::SetupProperties(const Importer*) {
// empty // empty
} }
@ -626,6 +125,15 @@ void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene,
if (xmlParser.parse(opcPackage.RootStream())) { if (xmlParser.parse(opcPackage.RootStream())) {
XmlSerializer xmlSerializer(&xmlParser); XmlSerializer xmlSerializer(&xmlParser);
xmlSerializer.ImportXml(pScene); xmlSerializer.ImportXml(pScene);
const std::vector<aiTexture*> &tex = opcPackage.GetEmbeddedTextures();
if (!tex.empty()) {
pScene->mNumTextures = static_cast<unsigned int>(tex.size());
pScene->mTextures = new aiTexture *[pScene->mNumTextures];
for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {
pScene->mTextures[i] = tex[i];
}
}
} }
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2021, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -47,17 +46,40 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
// ---------------------------------------------------------------------------
/// @brief The 3MF-importer class. /// @brief The 3MF-importer class.
///
/// Implements the basic topology import and embedded textures.
// ---------------------------------------------------------------------------
class D3MFImporter : public BaseImporter { class D3MFImporter : public BaseImporter {
public: public:
/// @brief The default class constructor.
D3MFImporter(); D3MFImporter();
~D3MFImporter();
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const; /// @brief The class destructor.
void SetupProperties(const Importer *pImp); ~D3MFImporter() override;
const aiImporterDesc *GetInfo() const;
/// @brief Performs the data format detection.
/// @param pFile The filename to check.
/// @param pIOHandler The used IO-System.
/// @param checkSig true for signature checking.
/// @return true for can be loaded, false for not.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
/// @brief Not used
/// @param pImp Not used
void SetupProperties(const Importer *pImp) override;
/// @brief The importer description getter.
/// @return The info
const aiImporterDesc *GetInfo() const override;
protected: protected:
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler); /// @brief Internal read function, performs the file parsing.
/// @param pFile The filename
/// @param pScene The scene to load in.
/// @param pIOHandler The io-system
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
}; };
} // Namespace Assimp } // Namespace Assimp

View File

@ -43,14 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/XmlParser.h> #include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOStream.hpp> #include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/texture.h>
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
@ -64,11 +63,12 @@ namespace Assimp {
namespace D3MF { namespace D3MF {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr; using OpcPackageRelationshipPtr = std::shared_ptr<OpcPackageRelationship>;
class OpcPackageRelationshipReader { class OpcPackageRelationshipReader {
public: public:
OpcPackageRelationshipReader(XmlParser &parser) { OpcPackageRelationshipReader(XmlParser &parser) :
m_relationShips() {
XmlNode root = parser.getRootNode(); XmlNode root = parser.getRootNode();
ParseRootNode(root); ParseRootNode(root);
} }
@ -91,6 +91,7 @@ public:
if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) { if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) {
return false; return false;
} }
return true; return true;
} }
@ -100,7 +101,7 @@ public:
} }
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
std::string name = currentNode.name(); const std::string name = currentNode.name();
if (name == "Relationship") { if (name == "Relationship") {
OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID).as_string(); relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID).as_string();
@ -116,11 +117,23 @@ public:
std::vector<OpcPackageRelationshipPtr> m_relationShips; std::vector<OpcPackageRelationshipPtr> m_relationShips;
}; };
static bool IsEmbeddedTexture( const std::string &filename ) {
const std::string extension = BaseImporter::GetExtension(filename);
if (extension == "jpg" || extension == "png") {
std::string::size_type pos = filename.find("thumbnail");
if (pos == std::string::npos) {
return false;
}
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream(nullptr), mRootStream(nullptr),
mZipArchive() { mZipArchive() {
mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile)); mZipArchive = new ZipArchiveIOSystem(pIOHandler, rFile);
if (!mZipArchive->isOpen()) { if (!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file ", rFile, "."); throw DeadlyImportError("Failed to open file ", rFile, ".");
} }
@ -141,7 +154,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
} }
std::string rootFile = ReadPackageRootRelationship(fileStream); std::string rootFile = ReadPackageRootRelationship(fileStream);
if (rootFile.size() > 0 && rootFile[0] == '/') { if (!rootFile.empty() && rootFile[0] == '/') {
rootFile = rootFile.substr(1); rootFile = rootFile.substr(1);
if (rootFile[0] == '/') { if (rootFile[0] == '/') {
// deal with zip-bug // deal with zip-bug
@ -158,9 +171,12 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
if (nullptr == mRootStream) { if (nullptr == mRootStream) {
throw DeadlyImportError("Cannot open root-file in archive : " + rootFile); throw DeadlyImportError("Cannot open root-file in archive : " + rootFile);
} }
} else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { } else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file); ASSIMP_LOG_WARN("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file);
} else if (IsEmbeddedTexture(file)) {
IOStream *fileStream = mZipArchive->Open(file.c_str());
LoadEmbeddedTextures(fileStream, file);
mZipArchive->Close(fileStream);
} else { } else {
ASSIMP_LOG_WARN("Ignored file of unknown type: ", file); ASSIMP_LOG_WARN("Ignored file of unknown type: ", file);
} }
@ -169,20 +185,26 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
D3MFOpcPackage::~D3MFOpcPackage() { D3MFOpcPackage::~D3MFOpcPackage() {
mZipArchive->Close(mRootStream); mZipArchive->Close(mRootStream);
delete mZipArchive;
mZipArchive = nullptr;
} }
IOStream *D3MFOpcPackage::RootStream() const { IOStream *D3MFOpcPackage::RootStream() const {
return mRootStream; return mRootStream;
} }
static const std::string ModelRef = "3D/3dmodel.model"; const std::vector<aiTexture *> &D3MFOpcPackage::GetEmbeddedTextures() const {
return mEmbeddedTextures;
}
static const char *const ModelRef = "3D/3dmodel.model";
bool D3MFOpcPackage::validate() { bool D3MFOpcPackage::validate() {
if (nullptr == mRootStream || nullptr == mZipArchive) { if (nullptr == mRootStream || nullptr == mZipArchive) {
return false; return false;
} }
return mZipArchive->Exists(ModelRef.c_str()); return mZipArchive->Exists(ModelRef);
} }
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
@ -204,6 +226,31 @@ std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
return (*itr)->target; return (*itr)->target;
} }
void D3MFOpcPackage::LoadEmbeddedTextures(IOStream *fileStream, const std::string &filename) {
if (nullptr == fileStream) {
return;
}
const size_t size = fileStream->FileSize();
if (0 == size) {
return;
}
unsigned char *data = new unsigned char[size];
fileStream->Read(data, 1, size);
aiTexture *texture = new aiTexture;
std::string embName = "*" + filename;
texture->mFilename.Set(embName.c_str());
texture->mWidth = static_cast<unsigned int>(size);
texture->mHeight = 0;
texture->achFormatHint[0] = 'p';
texture->achFormatHint[1] = 'n';
texture->achFormatHint[2] = 'g';
texture->achFormatHint[3] = '\0';
texture->pcData = (aiTexel*) data;
mEmbeddedTextures.emplace_back(texture);
}
} // Namespace D3MF } // Namespace D3MF
} // Namespace Assimp } // Namespace Assimp

View File

@ -46,8 +46,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
struct aiTexture;
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem;
class ZipArchiveIOSystem;
namespace D3MF { namespace D3MF {
@ -63,16 +66,19 @@ public:
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate(); bool validate();
const std::vector<aiTexture*> &GetEmbeddedTextures() const;
protected: protected:
std::string ReadPackageRootRelationship(IOStream* stream); std::string ReadPackageRootRelationship(IOStream* stream);
void LoadEmbeddedTextures(IOStream *fileStream, const std::string &filename);
private: private:
IOStream* mRootStream; IOStream* mRootStream;
std::unique_ptr<ZipArchiveIOSystem> mZipArchive; ZipArchiveIOSystem *mZipArchive;
std::vector<aiTexture *> mEmbeddedTextures;
}; };
} // Namespace D3MF } // namespace D3MF
} // Namespace Assimp } // namespace Assimp
#endif // D3MFOPCPACKAGE_H #endif // D3MFOPCPACKAGE_H

View File

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

View File

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

View File

@ -95,8 +95,8 @@ struct Material : public D3DS::Material {
Material(Material &&other) AI_NO_EXCEPT Material(Material &&other) AI_NO_EXCEPT
: D3DS::Material(std::move(other)), : D3DS::Material(std::move(other)),
avSubMaterials(std::move(other.avSubMaterials)), avSubMaterials(std::move(other.avSubMaterials)),
pcInstance(std::move(other.pcInstance)), pcInstance(other.pcInstance),
bNeed(std::move(other.bNeed)) { bNeed(other.bNeed) {
other.pcInstance = nullptr; other.pcInstance = nullptr;
} }
@ -108,8 +108,8 @@ struct Material : public D3DS::Material {
//D3DS::Material::operator=(std::move(other)); //D3DS::Material::operator=(std::move(other));
avSubMaterials = std::move(other.avSubMaterials); avSubMaterials = std::move(other.avSubMaterials);
pcInstance = std::move(other.pcInstance); pcInstance = other.pcInstance;
bNeed = std::move(other.bNeed); bNeed = other.bNeed;
other.pcInstance = nullptr; other.pcInstance = nullptr;

View File

@ -172,7 +172,7 @@ inline size_t Write<aiQuaternion>(IOStream *stream, const aiQuaternion &v) {
t += Write<float>(stream, v.z); t += Write<float>(stream, v.z);
ai_assert(t == 16); ai_assert(t == 16);
return 16; return t;
} }
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------

View File

@ -41,12 +41,17 @@ public:
enum { enum {
Flag_DoNotIndent = 0x1, Flag_DoNotIndent = 0x1,
Flag_WriteSpecialFloats = 0x2, Flag_WriteSpecialFloats = 0x2,
Flag_SkipWhitespaces = 0x4
}; };
JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) : JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
out(out), first(), flags(flags) { out(out), indent (""), newline("\n"), space(" "), buff (), first(false), flags(flags) {
// make sure that all formatting happens using the standard, C locale and not the user's current locale // make sure that all formatting happens using the standard, C locale and not the user's current locale
buff.imbue(std::locale("C")); buff.imbue(std::locale("C"));
if (flags & Flag_SkipWhitespaces) {
newline = "";
space = "";
}
} }
~JSONWriter() { ~JSONWriter() {
@ -70,7 +75,7 @@ public:
void Key(const std::string &name) { void Key(const std::string &name) {
AddIndentation(); AddIndentation();
Delimit(); Delimit();
buff << '\"' + name + "\": "; buff << '\"' + name + "\":" << space;
} }
template <typename Literal> template <typename Literal>
@ -78,12 +83,12 @@ public:
AddIndentation(); AddIndentation();
Delimit(); Delimit();
LiteralToString(buff, name) << '\n'; LiteralToString(buff, name) << newline;
} }
template <typename Literal> template <typename Literal>
void SimpleValue(const Literal &s) { void SimpleValue(const Literal &s) {
LiteralToString(buff, s) << '\n'; LiteralToString(buff, s) << newline;
} }
void SimpleValue(const void *buffer, size_t len) { void SimpleValue(const void *buffer, size_t len) {
@ -102,7 +107,7 @@ public:
} }
} }
buff << '\"' << cur_out << "\"\n"; buff << '\"' << cur_out << "\"" << newline;
delete[] cur_out; delete[] cur_out;
} }
@ -115,7 +120,7 @@ public:
} }
} }
first = true; first = true;
buff << "{\n"; buff << "{" << newline;
PushIndent(); PushIndent();
} }
@ -123,7 +128,7 @@ public:
PopIndent(); PopIndent();
AddIndentation(); AddIndentation();
first = false; first = false;
buff << "}\n"; buff << "}" << newline;
} }
void StartArray(bool is_element = false) { void StartArray(bool is_element = false) {
@ -135,19 +140,19 @@ public:
} }
} }
first = true; first = true;
buff << "[\n"; buff << "[" << newline;
PushIndent(); PushIndent();
} }
void EndArray() { void EndArray() {
PopIndent(); PopIndent();
AddIndentation(); AddIndentation();
buff << "]\n"; buff << "]" << newline;
first = false; first = false;
} }
void AddIndentation() { void AddIndentation() {
if (!(flags & Flag_DoNotIndent)) { if (!(flags & Flag_DoNotIndent) && !(flags & Flag_SkipWhitespaces)) {
buff << indent; buff << indent;
} }
} }
@ -156,7 +161,7 @@ public:
if (!first) { if (!first) {
buff << ','; buff << ',';
} else { } else {
buff << ' '; buff << space;
first = false; first = false;
} }
} }
@ -227,7 +232,9 @@ private:
private: private:
Assimp::IOStream &out; Assimp::IOStream &out;
std::string indent, newline; std::string indent;
std::string newline;
std::string space;
std::stringstream buff; std::stringstream buff;
bool first; bool first;
@ -765,7 +772,7 @@ void Write(JSONWriter &out, const aiScene &ai) {
out.EndObj(); out.EndObj();
} }
void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) { void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *pProperties) {
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt")); std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
if (!str) { if (!str) {
throw DeadlyExportError("could not open output file"); throw DeadlyExportError("could not open output file");
@ -782,7 +789,12 @@ void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *sc
splitter.Execute(scenecopy_tmp); splitter.Execute(scenecopy_tmp);
// XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
unsigned int flags = JSONWriter::Flag_WriteSpecialFloats;
if (pProperties->GetPropertyBool("JSON_SKIP_WHITESPACES", false)) {
flags |= JSONWriter::Flag_SkipWhitespaces;
}
JSONWriter s(*str, flags);
Write(s, *scenecopy_tmp); Write(s, *scenecopy_tmp);
} catch (...) { } catch (...) {

View File

@ -143,7 +143,7 @@ AI_WONT_RETURN void B3DImporter::Oops() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Fail(string str) { AI_WONT_RETURN void B3DImporter::Fail(const string &str) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
ASSIMP_LOG_ERROR("Error in B3D file data: ", str); ASSIMP_LOG_ERROR("Error in B3D file data: ", str);
#endif #endif

View File

@ -96,7 +96,7 @@ private:
}; };
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void Fail(const std::string &str) AI_WONT_RETURN_SUFFIX;
void ReadTEXS(); void ReadTEXS();
void ReadBRUS(); void ReadBRUS();

View File

@ -679,7 +679,7 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
BuildDefaultMaterial(conv_data); BuildDefaultMaterial(conv_data);
for (std::shared_ptr<Material> mat : conv_data.materials_raw) { for (const std::shared_ptr<Material> &mat : conv_data.materials_raw) {
// reset per material global counters // reset per material global counters
for (size_t i = 0; i < sizeof(conv_data.next_texture) / sizeof(conv_data.next_texture[0]); ++i) { for (size_t i = 0; i < sizeof(conv_data.next_texture) / sizeof(conv_data.next_texture[0]); ++i) {

View File

@ -146,8 +146,14 @@ void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
ThrowException("failed to read document " + pFile); ThrowException("failed to read document " + pFile);
} }
// Generate the root-node
pScene->mRootNode = new aiNode("<C4DRoot>"); pScene->mRootNode = new aiNode("<C4DRoot>");
// convert left-handed to right-handed
pScene->mRootNode->mTransformation.a1 = 0.01f;
pScene->mRootNode->mTransformation.b2 = 0.01f;
pScene->mRootNode->mTransformation.c3 = -0.01f;
// first convert all materials // first convert all materials
ReadMaterials(doc->GetFirstMaterial()); ReadMaterials(doc->GetFirstMaterial());

View File

@ -230,7 +230,7 @@ void COBImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertTexture(std::shared_ptr<Texture> tex, aiMaterial *out, aiTextureType type) { void ConvertTexture(const std::shared_ptr<Texture> &tex, aiMaterial *out, aiTextureType type) {
const aiString path(tex->path); const aiString path(tex->path);
out->AddProperty(&path, AI_MATKEY_TEXTURE(type, 0)); out->AddProperty(&path, AI_MATKEY_TEXTURE(type, 0));
out->AddProperty(&tex->transform, 1, AI_MATKEY_UVTRANSFORM(type, 0)); out->AddProperty(&tex->transform, 1, AI_MATKEY_UVTRANSFORM(type, 0));

View File

@ -135,14 +135,15 @@ bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool
// XML - too generic, we need to open the file and search for typical keywords // XML - too generic, we need to open the file and search for typical keywords
if (extension == "xml" || !extension.length() || checkSig) { if (extension == "xml" || !extension.length() || checkSig) {
/* If CanRead() is called in order to check whether we // If CanRead() is called in order to check whether we
* support a specific file extension in general pIOHandler // support a specific file extension in general pIOHandler
* might be nullptr and it's our duty to return true here. // might be nullptr and it's our duty to return true here.
*/ if (nullptr == pIOHandler) {
if (!pIOHandler) {
return true; return true;
} }
static const char *tokens[] = { "<collada" }; static const char* tokens[] = {
"<collada"
};
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} }
@ -573,7 +574,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
// now place all mesh references we gathered in the target node // now place all mesh references we gathered in the target node
pTarget->mNumMeshes = static_cast<unsigned int>(newMeshRefs.size()); pTarget->mNumMeshes = static_cast<unsigned int>(newMeshRefs.size());
if (newMeshRefs.size()) { if (!newMeshRefs.empty()) {
struct UIntTypeConverter { struct UIntTypeConverter {
unsigned int operator()(const size_t &v) const { unsigned int operator()(const size_t &v) const {
return static_cast<unsigned int>(v); return static_cast<unsigned int>(v);
@ -619,6 +620,10 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
dstMesh->mName = pSrcMesh->mId; dstMesh->mName = pSrcMesh->mId;
} }
if (pSrcMesh->mPositions.empty()) {
return dstMesh.release();
}
// count the vertices addressed by its faces // count the vertices addressed by its faces
const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace, const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace,
pSrcMesh->mFaceSize.begin() + pStartFace + pSubMesh.mNumFaces, size_t(0)); pSrcMesh->mFaceSize.begin() + pStartFace + pSubMesh.mNumFaces, size_t(0));
@ -1682,7 +1687,7 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
// store the material // store the material
mMaterialIndexByName[matIt->first] = newMats.size(); mMaterialIndexByName[matIt->first] = newMats.size();
newMats.push_back(std::pair<Effect *, aiMaterial *>(&effect, mat)); newMats.emplace_back(&effect, mat);
} }
// ScenePreprocessor generates a default material automatically if none is there. // ScenePreprocessor generates a default material automatically if none is there.
// All further code here in this loader works well without a valid material so // All further code here in this loader works well without a valid material so

View File

@ -170,10 +170,10 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
ColladaParser::~ColladaParser() { ColladaParser::~ColladaParser() {
for (auto & it : mNodeLibrary) { for (auto &it : mNodeLibrary) {
delete it.second; delete it.second;
} }
for (auto & it : mMeshLibrary) { for (auto &it : mMeshLibrary) {
delete it.second; delete it.second;
} }
} }
@ -231,11 +231,7 @@ void ColladaParser::UriDecodePath(aiString &ss) {
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
// I need to filter it without destroying linux paths starting with "/somewhere" // I need to filter it without destroying linux paths starting with "/somewhere"
#if defined(_MSC_VER)
if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') { if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
#else
if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
#endif
--ss.length; --ss.length;
::memmove(ss.data, ss.data + 1, ss.length); ::memmove(ss.data, ss.data + 1, ss.length);
ss.data[ss.length] = 0; ss.data[ss.length] = 0;
@ -396,7 +392,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
std::string animName; std::string animName;
if (!XmlParser::getStdStrAttribute(node, "name", animName)) { if (!XmlParser::getStdStrAttribute(node, "name", animName)) {
if (!XmlParser::getStdStrAttribute( node, "id", animName )) { if (!XmlParser::getStdStrAttribute(node, "id", animName)) {
animName = std::string("animation_") + ai_to_string(mAnimationClipLibrary.size()); animName = std::string("animation_") + ai_to_string(mAnimationClipLibrary.size());
} }
} }
@ -420,7 +416,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
void ColladaParser::PostProcessControllers() { void ColladaParser::PostProcessControllers() {
std::string meshId; std::string meshId;
for (auto & it : mControllerLibrary) { for (auto &it : mControllerLibrary) {
meshId = it.second.mMeshId; meshId = it.second.mMeshId;
if (meshId.empty()) { if (meshId.empty()) {
continue; continue;
@ -445,7 +441,7 @@ void ColladaParser::PostProcessRootAnimations() {
} }
Animation temp; Animation temp;
for (auto & it : mAnimationClipLibrary) { for (auto &it : mAnimationClipLibrary) {
std::string clipName = it.first; std::string clipName = it.first;
Animation *clip = new Animation(); Animation *clip = new Animation();
@ -453,7 +449,7 @@ void ColladaParser::PostProcessRootAnimations() {
temp.mSubAnims.push_back(clip); temp.mSubAnims.push_back(clip);
for (std::string animationID : it.second) { for (const std::string &animationID : it.second) {
AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID); AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID);
if (animation != mAnimationLibrary.end()) { if (animation != mAnimationLibrary.end()) {
@ -552,7 +548,7 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
pParent->mSubAnims.push_back(anim); pParent->mSubAnims.push_back(anim);
} }
for (const auto & channel : channels) { for (const auto &channel : channels) {
anim->mChannels.push_back(channel.second); anim->mChannels.push_back(channel.second);
} }
@ -626,8 +622,6 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode); XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
XmlNode currentNode; XmlNode currentNode;
while (xmlIt.getNext(currentNode)) { while (xmlIt.getNext(currentNode)) {
//for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "morph") { if (currentName == "morph") {
controller.mType = Morph; controller.mType = Morph;
@ -644,7 +638,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
} else if (currentName == "skin") { } else if (currentName == "skin") {
std::string id; std::string id;
if (XmlParser::getStdStrAttribute(currentNode, "source", id)) { if (XmlParser::getStdStrAttribute(currentNode, "source", id)) {
controller.mMeshId = id.substr(1, id.size()-1); controller.mMeshId = id.substr(1, id.size() - 1);
} }
} else if (currentName == "bind_shape_matrix") { } else if (currentName == "bind_shape_matrix") {
std::string v; std::string v;
@ -698,7 +692,7 @@ void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pCo
} else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) { } else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) {
pController.mJointOffsetMatrixSource = attrSource; pController.mJointOffsetMatrixSource = attrSource;
} else { } else {
throw DeadlyImportError("Unknown semantic \"" , attrSemantic , "\" in <joints> data <input> element"); throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <joints> data <input> element");
} }
} }
} }
@ -708,7 +702,7 @@ void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pCo
// Reads the joint weights for the given controller // Reads the joint weights for the given controller
void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) { void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) {
// Read vertex count from attributes and resize the array accordingly // Read vertex count from attributes and resize the array accordingly
int vertexCount=0; int vertexCount = 0;
XmlParser::getIntAttribute(node, "count", vertexCount); XmlParser::getIntAttribute(node, "count", vertexCount);
pController.mWeightCounts.resize(vertexCount); pController.mWeightCounts.resize(vertexCount);
@ -723,7 +717,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
// local URLS always start with a '#'. We don't support global URLs // local URLS always start with a '#'. We don't support global URLs
if (attrSource[0] != '#') { if (attrSource[0] != '#') {
throw DeadlyImportError( "Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element"); throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element");
} }
channel.mAccessor = attrSource + 1; channel.mAccessor = attrSource + 1;
@ -777,7 +771,7 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "image") { if (currentName == "image") {
std::string id; std::string id;
if (XmlParser::getStdStrAttribute( currentNode, "id", id )) { if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
mImageLibrary[id] = Image(); mImageLibrary[id] = Image();
// read on from there // read on from there
ReadImage(currentNode, mImageLibrary[id]); ReadImage(currentNode, mImageLibrary[id]);
@ -920,7 +914,7 @@ void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
if (currentName == "instance_effect") { if (currentName == "instance_effect") {
std::string url; std::string url;
readUrlAttribute(currentNode, url); readUrlAttribute(currentNode, url);
pMaterial.mEffect = url.c_str(); pMaterial.mEffect = url;
} }
} }
} }
@ -1361,8 +1355,8 @@ void ColladaParser::ReadMesh(XmlNode &node, Mesh &pMesh) {
} else if (currentName == "vertices") { } else if (currentName == "vertices") {
ReadVertexData(currentNode, pMesh); ReadVertexData(currentNode, pMesh);
} else if (currentName == "triangles" || currentName == "lines" || currentName == "linestrips" || } else if (currentName == "triangles" || currentName == "lines" || currentName == "linestrips" ||
currentName == "polygons" || currentName == "polylist" || currentName == "trifans" || currentName == "polygons" || currentName == "polylist" || currentName == "trifans" ||
currentName == "tristrips") { currentName == "tristrips") {
ReadIndexData(currentNode, pMesh); ReadIndexData(currentNode, pMesh);
} }
} }
@ -1439,9 +1433,8 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
throw DeadlyImportError("Expected more values while reading float_array contents."); throw DeadlyImportError("Expected more values while reading float_array contents.");
} }
ai_real value;
// read a number // read a number
//SkipSpacesAndLineEnd(&content); ai_real value;
content = fast_atoreal_move<ai_real>(content, value); content = fast_atoreal_move<ai_real>(content, value);
data.mValues.push_back(value); data.mValues.push_back(value);
// skip whitespace after it // skip whitespace after it
@ -1489,11 +1482,10 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) {
std::string name; std::string name;
if (XmlParser::hasAttribute(currentNode, "name")) { if (XmlParser::hasAttribute(currentNode, "name")) {
XmlParser::getStdStrAttribute(currentNode, "name", name); XmlParser::getStdStrAttribute(currentNode, "name", name);
//name = mReader->getAttributeValue(attrName);
// analyse for common type components and store it's sub-offset in the corresponding field // analyse for common type components and store it's sub-offset in the corresponding field
/* Cartesian coordinates */ // Cartesian coordinates
if (name == "X") if (name == "X")
acc.mSubOffset[0] = acc.mParams.size(); acc.mSubOffset[0] = acc.mParams.size();
else if (name == "Y") else if (name == "Y")
@ -1674,12 +1666,9 @@ void ColladaParser::ReadInputChannel(XmlNode &node, std::vector<InputChannel> &p
// read set if texture coordinates // read set if texture coordinates
if (channel.mType == IT_Texcoord || channel.mType == IT_Color) { if (channel.mType == IT_Texcoord || channel.mType == IT_Color) {
int attrSet = -1; unsigned int attrSet = 0;
if (XmlParser::hasAttribute(node, "set")) { if (XmlParser::getUIntAttribute(node, "set", attrSet))
XmlParser::getIntAttribute(node, "set", attrSet); channel.mIndex = attrSet;
}
channel.mIndex = attrSet;
} }
// store, if valid type // store, if valid type
@ -1704,20 +1693,20 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
// determine the expected number of indices // determine the expected number of indices
size_t expectedPointCount = 0; size_t expectedPointCount = 0;
switch (pPrimType) { switch (pPrimType) {
case Prim_Polylist: { case Prim_Polylist: {
for (size_t i : pVCount) for (size_t i : pVCount)
expectedPointCount += i; expectedPointCount += i;
break; break;
} }
case Prim_Lines: case Prim_Lines:
expectedPointCount = 2 * pNumPrimitives; expectedPointCount = 2 * pNumPrimitives;
break; break;
case Prim_Triangles: case Prim_Triangles:
expectedPointCount = 3 * pNumPrimitives; expectedPointCount = 3 * pNumPrimitives;
break; break;
default: default:
// other primitive types don't state the index count upfront... we need to guess // other primitive types don't state the index count upfront... we need to guess
break; break;
} }
// and read all indices into a temporary array // and read all indices into a temporary array
@ -1727,7 +1716,7 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
} }
// It is possible to not contain any indices // It is possible to not contain any indices
if (pNumPrimitives > 0) { if (pNumPrimitives > 0) {
std::string v; std::string v;
XmlParser::getValueAsString(node, v); XmlParser::getValueAsString(node, v);
const char *content = v.c_str(); const char *content = v.c_str();
@ -1925,87 +1914,87 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz
// now we reinterpret it according to the type we're reading here // now we reinterpret it according to the type we're reading here
switch (pInput.mType) { switch (pInput.mType) {
case IT_Position: // ignore all position streams except 0 - there can be only one position case IT_Position: // ignore all position streams except 0 - there can be only one position
if (pInput.mIndex == 0) { if (pInput.mIndex == 0) {
pMesh.mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2])); pMesh.mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2]));
} else { } else {
ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported"); ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported");
} }
break; break;
case IT_Normal: case IT_Normal:
// pad to current vertex count if necessary
if (pMesh.mNormals.size() < pMesh.mPositions.size() - 1)
pMesh.mNormals.insert(pMesh.mNormals.end(), pMesh.mPositions.size() - pMesh.mNormals.size() - 1, aiVector3D(0, 1, 0));
// ignore all normal streams except 0 - there can be only one normal
if (pInput.mIndex == 0) {
pMesh.mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2]));
} else {
ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported");
}
break;
case IT_Tangent:
// pad to current vertex count if necessary
if (pMesh.mTangents.size() < pMesh.mPositions.size() - 1)
pMesh.mTangents.insert(pMesh.mTangents.end(), pMesh.mPositions.size() - pMesh.mTangents.size() - 1, aiVector3D(1, 0, 0));
// ignore all tangent streams except 0 - there can be only one tangent
if (pInput.mIndex == 0) {
pMesh.mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2]));
} else {
ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported");
}
break;
case IT_Bitangent:
// pad to current vertex count if necessary
if (pMesh.mBitangents.size() < pMesh.mPositions.size() - 1) {
pMesh.mBitangents.insert(pMesh.mBitangents.end(), pMesh.mPositions.size() - pMesh.mBitangents.size() - 1, aiVector3D(0, 0, 1));
}
// ignore all bitangent streams except 0 - there can be only one bitangent
if (pInput.mIndex == 0) {
pMesh.mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2]));
} else {
ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported");
}
break;
case IT_Texcoord:
// up to 4 texture coord sets are fine, ignore the others
if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) {
// pad to current vertex count if necessary // pad to current vertex count if necessary
if (pMesh.mNormals.size() < pMesh.mPositions.size() - 1) if (pMesh.mTexCoords[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
pMesh.mNormals.insert(pMesh.mNormals.end(), pMesh.mPositions.size() - pMesh.mNormals.size() - 1, aiVector3D(0, 1, 0)); pMesh.mTexCoords[pInput.mIndex].insert(pMesh.mTexCoords[pInput.mIndex].end(),
pMesh.mPositions.size() - pMesh.mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0));
// ignore all normal streams except 0 - there can be only one normal pMesh.mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2]));
if (pInput.mIndex == 0) { if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) {
pMesh.mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2])); pMesh.mNumUVComponents[pInput.mIndex] = 3;
} else {
ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported");
} }
break; } else {
case IT_Tangent: ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
}
break;
case IT_Color:
// up to 4 color sets are fine, ignore the others
if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) {
// pad to current vertex count if necessary // pad to current vertex count if necessary
if (pMesh.mTangents.size() < pMesh.mPositions.size() - 1) if (pMesh.mColors[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
pMesh.mTangents.insert(pMesh.mTangents.end(), pMesh.mPositions.size() - pMesh.mTangents.size() - 1, aiVector3D(1, 0, 0)); pMesh.mColors[pInput.mIndex].insert(pMesh.mColors[pInput.mIndex].end(),
pMesh.mPositions.size() - pMesh.mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1));
// ignore all tangent streams except 0 - there can be only one tangent aiColor4D result(0, 0, 0, 1);
if (pInput.mIndex == 0) { for (size_t i = 0; i < pInput.mResolved->mSize; ++i) {
pMesh.mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]];
} else {
ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported");
}
break;
case IT_Bitangent:
// pad to current vertex count if necessary
if (pMesh.mBitangents.size() < pMesh.mPositions.size() - 1) {
pMesh.mBitangents.insert(pMesh.mBitangents.end(), pMesh.mPositions.size() - pMesh.mBitangents.size() - 1, aiVector3D(0, 0, 1));
} }
pMesh.mColors[pInput.mIndex].push_back(result);
} else {
ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
}
// ignore all bitangent streams except 0 - there can be only one bitangent break;
if (pInput.mIndex == 0) { default:
pMesh.mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); // IT_Invalid and IT_Vertex
} else { ai_assert(false && "shouldn't ever get here");
ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported");
}
break;
case IT_Texcoord:
// up to 4 texture coord sets are fine, ignore the others
if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) {
// pad to current vertex count if necessary
if (pMesh.mTexCoords[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
pMesh.mTexCoords[pInput.mIndex].insert(pMesh.mTexCoords[pInput.mIndex].end(),
pMesh.mPositions.size() - pMesh.mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0));
pMesh.mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2]));
if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) {
pMesh.mNumUVComponents[pInput.mIndex] = 3;
}
} else {
ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
}
break;
case IT_Color:
// up to 4 color sets are fine, ignore the others
if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) {
// pad to current vertex count if necessary
if (pMesh.mColors[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
pMesh.mColors[pInput.mIndex].insert(pMesh.mColors[pInput.mIndex].end(),
pMesh.mPositions.size() - pMesh.mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1));
aiColor4D result(0, 0, 0, 1);
for (size_t i = 0; i < pInput.mResolved->mSize; ++i) {
result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]];
}
pMesh.mColors[pInput.mIndex].push_back(result);
} else {
ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
}
break;
default:
// IT_Invalid and IT_Vertex
ai_assert(false && "shouldn't ever get here");
} }
} }
@ -2170,10 +2159,10 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform
// read as many parameters and store in the transformation // read as many parameters and store in the transformation
for (unsigned int a = 0; a < sNumParameters[pType]; a++) { for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
// skip whitespace before the number
SkipSpacesAndLineEnd(&content);
// read a number // read a number
content = fast_atoreal_move<ai_real>(content, tf.f[a]); content = fast_atoreal_move<ai_real>(content, tf.f[a]);
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
} }
// place the transformation at the queue of the node // place the transformation at the queue of the node
@ -2215,8 +2204,8 @@ void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::Seman
void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) { void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) {
// Attempt to load any undefined Collada::Image in ImageLibrary // Attempt to load any undefined Collada::Image in ImageLibrary
for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) { for (auto & it : mImageLibrary) {
Collada::Image &image = (*it).second; Collada::Image &image = it.second;
if (image.mImageData.empty()) { if (image.mImageData.empty()) {
std::unique_ptr<IOStream> image_file(zip_archive.Open(image.mFileName.c_str())); std::unique_ptr<IOStream> image_file(zip_archive.Open(image.mFileName.c_str()));

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2021, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -917,8 +917,10 @@ void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root
} else if (line) { } else if (line) {
const std::vector<unsigned int> &indices = ConvertLine(*line, root_node); const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
} else { } else if (geo) {
FBXImporter::LogWarn("ignoring unrecognized geometry: ", geo->Name()); FBXImporter::LogWarn("ignoring unrecognized geometry: ", geo->Name());
} else {
FBXImporter::LogWarn("skipping null geometry");
} }
} }
@ -1766,6 +1768,7 @@ void FBXConverter::TrySetTextureProperties(aiMaterial *out_mat, const TextureMap
// XXX handle all kinds of UV transformations // XXX handle all kinds of UV transformations
uvTrafo.mScaling = tex->UVScaling(); uvTrafo.mScaling = tex->UVScaling();
uvTrafo.mTranslation = tex->UVTranslation(); uvTrafo.mTranslation = tex->UVTranslation();
uvTrafo.mRotation = tex->UVRotation();
out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0); out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0);
const PropertyTable &props = tex->Props(); const PropertyTable &props = tex->Props();
@ -1885,6 +1888,7 @@ void FBXConverter::TrySetTextureProperties(aiMaterial *out_mat, const LayeredTex
// XXX handle all kinds of UV transformations // XXX handle all kinds of UV transformations
uvTrafo.mScaling = tex->UVScaling(); uvTrafo.mScaling = tex->UVScaling();
uvTrafo.mTranslation = tex->UVTranslation(); uvTrafo.mTranslation = tex->UVTranslation();
uvTrafo.mRotation = tex->UVRotation();
out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex); out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex);
const PropertyTable &props = tex->Props(); const PropertyTable &props = tex->Props();
@ -2129,7 +2133,7 @@ void FBXConverter::SetShadingPropertiesCommon(aiMaterial *out_mat, const Propert
if (ok) { if (ok) {
out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE); out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
} else { } else {
const aiColor3D &emissiveColor = GetColorPropertyFromMaterial(props, "Maya|emissive", ok); const aiColor3D &emissiveColor = GetColorProperty(props, "Maya|emissive", ok);
if (ok) { if (ok) {
out_mat->AddProperty(&emissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE); out_mat->AddProperty(&emissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE);
} }
@ -2216,7 +2220,7 @@ void FBXConverter::SetShadingPropertiesCommon(aiMaterial *out_mat, const Propert
} }
// PBR material information // PBR material information
const aiColor3D &baseColor = GetColorPropertyFromMaterial(props, "Maya|base_color", ok); const aiColor3D &baseColor = GetColorProperty(props, "Maya|base_color", ok);
if (ok) { if (ok) {
out_mat->AddProperty(&baseColor, 1, AI_MATKEY_BASE_COLOR); out_mat->AddProperty(&baseColor, 1, AI_MATKEY_BASE_COLOR);
} }
@ -2324,6 +2328,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial *out_mat, const PropertyTa
// XXX handle all kinds of UV transformations // XXX handle all kinds of UV transformations
uvTrafo.mScaling = tex->UVScaling(); uvTrafo.mScaling = tex->UVScaling();
uvTrafo.mTranslation = tex->UVTranslation(); uvTrafo.mTranslation = tex->UVTranslation();
uvTrafo.mRotation = tex->UVRotation();
out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0); out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0);
int uvIndex = 0; int uvIndex = 0;
@ -2599,7 +2604,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
anim->mMorphMeshChannels = new aiMeshMorphAnim *[numMorphMeshChannels]; anim->mMorphMeshChannels = new aiMeshMorphAnim *[numMorphMeshChannels];
anim->mNumMorphMeshChannels = numMorphMeshChannels; anim->mNumMorphMeshChannels = numMorphMeshChannels;
unsigned int i = 0; unsigned int i = 0;
for (auto morphAnimIt : morphAnimDatas) { for (const auto &morphAnimIt : morphAnimDatas) {
morphAnimData *animData = morphAnimIt.second; morphAnimData *animData = morphAnimIt.second;
unsigned int numKeys = static_cast<unsigned int>(animData->size()); unsigned int numKeys = static_cast<unsigned int>(animData->size());
aiMeshMorphAnim *meshMorphAnim = new aiMeshMorphAnim(); aiMeshMorphAnim *meshMorphAnim = new aiMeshMorphAnim();

View File

@ -57,9 +57,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <memory>
#include <functional> #include <functional>
#include <map> #include <map>
#include <memory>
#include <utility>
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -248,10 +249,8 @@ Object::~Object()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props) FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<const PropertyTable> props) :
: props(props) props(std::move(props)), doc(doc) {
, doc(doc)
{
// empty // empty
} }

View File

@ -500,6 +500,10 @@ public:
return uvScaling; return uvScaling;
} }
const ai_real &UVRotation() const {
return uvRotation;
}
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
return *props.get(); return *props.get();
@ -517,6 +521,7 @@ public:
private: private:
aiVector2D uvTrans; aiVector2D uvTrans;
aiVector2D uvScaling; aiVector2D uvScaling;
ai_real uvRotation;
std::string type; std::string type;
std::string relativeFileName; std::string relativeFileName;

View File

@ -144,9 +144,8 @@ void FBX::Node::AddP70time(
// public member functions for writing nodes to stream // public member functions for writing nodes to stream
void FBX::Node::Dump( void FBX::Node::Dump(
std::shared_ptr<Assimp::IOStream> outfile, const std::shared_ptr<Assimp::IOStream> &outfile,
bool binary, int indent bool binary, int indent) {
) {
if (binary) { if (binary) {
Assimp::StreamWriterLE outstream(outfile); Assimp::StreamWriterLE outstream(outfile);
DumpBinary(outstream); DumpBinary(outstream);

View File

@ -157,9 +157,8 @@ public: // member functions for writing data to a file or stream
// write the full node to the given file or stream // write the full node to the given file or stream
void Dump( void Dump(
std::shared_ptr<Assimp::IOStream> outfile, const std::shared_ptr<Assimp::IOStream> &outfile,
bool binary, int indent bool binary, int indent);
);
void Dump(Assimp::StreamWriterLE &s, bool binary, int indent); void Dump(Assimp::StreamWriterLE &s, bool binary, int indent);
// these other functions are for writing data piece by piece. // these other functions are for writing data piece by piece.

View File

@ -541,10 +541,17 @@ void FBXExporter::WriteReferences ()
// (before any actual data is written) // (before any actual data is written)
// --------------------------------------------------------------- // ---------------------------------------------------------------
size_t count_nodes(const aiNode* n) { size_t count_nodes(const aiNode* n, const aiNode* root) {
size_t count = 1; size_t count;
if (n == root) {
count = n->mNumMeshes; // (not counting root node)
} else if (n->mNumMeshes > 1) {
count = n->mNumMeshes + 1;
} else {
count = 1;
}
for (size_t i = 0; i < n->mNumChildren; ++i) { for (size_t i = 0; i < n->mNumChildren; ++i) {
count += count_nodes(n->mChildren[i]); count += count_nodes(n->mChildren[i], root);
} }
return count; return count;
} }
@ -714,7 +721,7 @@ void FBXExporter::WriteDefinitions ()
// Model / FbxNode // Model / FbxNode
// <~~ node hierarchy // <~~ node hierarchy
count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node) count = int32_t(count_nodes(mScene->mRootNode, mScene->mRootNode));
if (count) { if (count) {
n = FBX::Node("ObjectType", "Model"); n = FBX::Node("ObjectType", "Model");
n.AddChild("Count", count); n.AddChild("Count", count);
@ -1681,6 +1688,10 @@ void FBXExporter::WriteObjects ()
// link the image data to the texture // link the image data to the texture
connections.emplace_back("C", "OO", image_uid, texture_uid); connections.emplace_back("C", "OO", image_uid, texture_uid);
aiUVTransform trafo;
unsigned int max = sizeof(aiUVTransform);
aiGetMaterialFloatArray(mat, AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE, 0), (ai_real *)&trafo, &max);
// now write the actual texture node // now write the actual texture node
FBX::Node tnode("Texture"); FBX::Node tnode("Texture");
// TODO: some way to determine texture name? // TODO: some way to determine texture name?
@ -1691,6 +1702,9 @@ void FBXExporter::WriteObjects ()
tnode.AddChild("Version", int32_t(202)); tnode.AddChild("Version", int32_t(202));
tnode.AddChild("TextureName", texture_name); tnode.AddChild("TextureName", texture_name);
FBX::Node p("Properties70"); FBX::Node p("Properties70");
p.AddP70vectorA("Translation", trafo.mTranslation[0], trafo.mTranslation[1], 0.0);
p.AddP70vectorA("Rotation", 0, 0, trafo.mRotation);
p.AddP70vectorA("Scaling", trafo.mScaling[0], trafo.mScaling[1], 0.0);
p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify
//p.AddP70string("UVSet", ""); // TODO: how should this work? //p.AddP70string("UVSet", ""); // TODO: how should this work?
p.AddP70bool("UseMaterial", 1); p.AddP70bool("UseMaterial", 1);
@ -2196,7 +2210,65 @@ void FBXExporter::WriteObjects ()
bpnode.Dump(outstream, binary, indent); bpnode.Dump(outstream, binary, indent);
}*/ }*/
// TODO: cameras, lights // lights
indent = 1;
lights_uids.clear();
for (size_t li = 0; li < mScene->mNumLights; ++li) {
aiLight* l = mScene->mLights[li];
int64_t uid = generate_uid();
const std::string lightNodeAttributeName = l->mName.C_Str() + FBX::SEPARATOR + "NodeAttribute";
FBX::Node lna("NodeAttribute");
lna.AddProperties(uid, lightNodeAttributeName, "Light");
FBX::Node lnap("Properties70");
// Light color.
lnap.AddP70colorA("Color", l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b);
// TODO Assimp light description is quite concise and do not handle light intensity.
// Default value to 1000W.
lnap.AddP70numberA("Intensity", 1000);
// FBXLight::EType conversion
switch (l->mType) {
case aiLightSource_POINT:
lnap.AddP70enum("LightType", 0);
break;
case aiLightSource_DIRECTIONAL:
lnap.AddP70enum("LightType", 1);
break;
case aiLightSource_SPOT:
lnap.AddP70enum("LightType", 2);
lnap.AddP70numberA("InnerAngle", AI_RAD_TO_DEG(l->mAngleInnerCone));
lnap.AddP70numberA("OuterAngle", AI_RAD_TO_DEG(l->mAngleOuterCone));
break;
// TODO Assimp do not handle 'area' nor 'volume' lights, but FBX does.
/*case aiLightSource_AREA:
lnap.AddP70enum("LightType", 3);
lnap.AddP70enum("AreaLightShape", 0); // 0=Rectangle, 1=Sphere
break;
case aiLightSource_VOLUME:
lnap.AddP70enum("LightType", 4);
break;*/
default:
break;
}
// Did not understood how to configure the decay so disabling attenuation.
lnap.AddP70enum("DecayType", 0);
// Dump to FBX stream
lna.AddChild(lnap);
lna.AddChild("TypeFlags", FBX::FBXExportProperty("Light"));
lna.AddChild("GeometryVersion", FBX::FBXExportProperty(int32_t(124)));
lna.Dump(outstream, binary, indent);
// Store name and uid (will be used later when parsing scene nodes)
lights_uids[l->mName.C_Str()] = uid;
}
// TODO: cameras
// write nodes (i.e. model hierarchy) // write nodes (i.e. model hierarchy)
// start at root node // start at root node
@ -2600,10 +2672,19 @@ void FBXExporter::WriteModelNodes(
// and connect them // and connect them
connections.emplace_back("C", "OO", node_attribute_uid, node_uid); connections.emplace_back("C", "OO", node_attribute_uid, node_uid);
} else { } else {
// generate a null node so we can add children to it const auto& lightIt = lights_uids.find(node->mName.C_Str());
WriteModelNode( if(lightIt != lights_uids.end()) {
outstream, binary, node, node_uid, "Null", transform_chain // Node has a light connected to it.
); WriteModelNode(
outstream, binary, node, node_uid, "Light", transform_chain
);
connections.emplace_back("C", "OO", lightIt->second, node_uid);
} else {
// generate a null node so we can add children to it
WriteModelNode(
outstream, binary, node, node_uid, "Null", transform_chain
);
}
} }
// if more than one child mesh, make nodes for each mesh // if more than one child mesh, make nodes for each mesh
@ -2625,17 +2706,14 @@ void FBXExporter::WriteModelNodes(
], ],
new_node_uid new_node_uid
); );
// write model node
FBX::Node m("Model"); aiNode new_node;
// take name from mesh name, if it exists // take name from mesh name, if it exists
std::string name = mScene->mMeshes[node->mMeshes[i]]->mName.C_Str(); new_node.mName = mScene->mMeshes[node->mMeshes[i]]->mName;
name += FBX::SEPARATOR + "Model"; // write model node
m.AddProperties(new_node_uid, name, "Mesh"); WriteModelNode(
m.AddChild("Version", int32_t(232)); outstream, binary, &new_node, new_node_uid, "Mesh", std::vector<std::pair<std::string,aiVector3D>>()
FBX::Node p("Properties70"); );
p.AddP70enum("InheritType", 1);
m.AddChild(p);
m.Dump(outstream, binary, 1);
} }
} }
@ -2647,16 +2725,14 @@ void FBXExporter::WriteModelNodes(
} }
} }
void FBXExporter::WriteAnimationCurveNode( void FBXExporter::WriteAnimationCurveNode(
StreamWriterLE& outstream, StreamWriterLE &outstream,
int64_t uid, int64_t uid,
const std::string& name, // "T", "R", or "S" const std::string &name, // "T", "R", or "S"
aiVector3D default_value, aiVector3D default_value,
std::string property_name, // "Lcl Translation" etc const std::string &property_name, // "Lcl Translation" etc
int64_t layer_uid, int64_t layer_uid,
int64_t node_uid int64_t node_uid) {
) {
FBX::Node n("AnimationCurveNode"); FBX::Node n("AnimationCurveNode");
n.AddProperties(uid, name + FBX::SEPARATOR + "AnimCurveNode", ""); n.AddProperties(uid, name + FBX::SEPARATOR + "AnimCurveNode", "");
FBX::Node p("Properties70"); FBX::Node p("Properties70");
@ -2671,7 +2747,6 @@ void FBXExporter::WriteAnimationCurveNode(
this->connections.emplace_back("C", "OP", uid, node_uid, property_name); this->connections.emplace_back("C", "OP", uid, node_uid, property_name);
} }
void FBXExporter::WriteAnimationCurve( void FBXExporter::WriteAnimationCurve(
StreamWriterLE& outstream, StreamWriterLE& outstream,
double default_value, double default_value,

View File

@ -63,10 +63,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiScene; struct aiScene;
struct aiNode; struct aiNode;
//struct aiMaterial; struct aiLight;
namespace Assimp namespace Assimp {
{
class IOSystem; class IOSystem;
class IOStream; class IOStream;
class ExportProperties; class ExportProperties;
@ -95,6 +94,7 @@ namespace Assimp
std::vector<int64_t> mesh_uids; std::vector<int64_t> mesh_uids;
std::vector<int64_t> material_uids; std::vector<int64_t> material_uids;
std::map<const aiNode*,int64_t> node_uids; std::map<const aiNode*,int64_t> node_uids;
std::map<std::string,int64_t> lights_uids;
// this crude unique-ID system is actually fine // this crude unique-ID system is actually fine
int64_t last_uid = 999999; int64_t last_uid = 999999;
@ -154,14 +154,13 @@ namespace Assimp
FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs
); );
void WriteAnimationCurveNode( void WriteAnimationCurveNode(
StreamWriterLE& outstream, StreamWriterLE &outstream,
int64_t uid, int64_t uid,
const std::string& name, // "T", "R", or "S" const std::string &name, // "T", "R", or "S"
aiVector3D default_value, aiVector3D default_value,
std::string property_name, // "Lcl Translation" etc const std::string &property_name, // "Lcl Translation" etc
int64_t animation_layer_uid, int64_t animation_layer_uid,
int64_t node_uid int64_t node_uid);
);
void WriteAnimationCurve( void WriteAnimationCurve(
StreamWriterLE& outstream, StreamWriterLE& outstream,
double default_value, double default_value,

View File

@ -210,6 +210,11 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const
uvTrans.y = trans.y; uvTrans.y = trans.y;
} }
const aiVector3D &rotation = PropertyGet<aiVector3D>(*props, "Rotation", ok);
if (ok) {
uvRotation = rotation.z;
}
// resolve video links // resolve video links
if(doc.Settings().readTextures) { if(doc.Settings().readTextures) {
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID()); const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());

View File

@ -192,6 +192,10 @@ Scope::Scope(Parser& parser,bool topLevel)
} }
const std::string& str = n->StringContents(); const std::string& str = n->StringContents();
if (str.empty()) {
ParseError("unexpected content: empty string.");
}
elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
// Element() should stop at the next Key token (or right after a Close token) // Element() should stop at the next Key token (or right after a Close token)
@ -642,8 +646,7 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4); uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -733,8 +736,7 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4); uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -816,8 +818,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4); uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -892,8 +893,7 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * 4; uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -954,8 +954,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4); uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -1019,8 +1018,7 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * 4; uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -1088,8 +1086,7 @@ void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * 8; uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }
@ -1150,8 +1147,7 @@ void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
ai_assert(data == end); ai_assert(data == end);
uint64_t dataToRead = static_cast<uint64_t>(count) * 8; uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
ai_assert(buff.size() == dataToRead); if (dataToRead != buff.size()) {
if (dataToRead > buff.size()) {
ParseError("Invalid read size (binary)",&el); ParseError("Invalid read size (binary)",&el);
} }

View File

@ -52,6 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXDocumentUtil.h" #include "FBXDocumentUtil.h"
#include "FBXProperties.h" #include "FBXProperties.h"
#include <utility>
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -172,10 +174,8 @@ PropertyTable::PropertyTable()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
PropertyTable::PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps) PropertyTable::PropertyTable(const Element &element, std::shared_ptr<const PropertyTable> templateProps) :
: templateProps(templateProps) templateProps(std::move(templateProps)), element(&element) {
, element(&element)
{
const Scope& scope = GetRequiredScope(element); const Scope& scope = GetRequiredScope(element);
for(const ElementMap::value_type& v : scope.Elements()) { for(const ElementMap::value_type& v : scope.Elements()) {
if(v.first != "P") { if(v.first != "P") {
@ -199,7 +199,6 @@ PropertyTable::PropertyTable(const Element& element, std::shared_ptr<const Prope
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
PropertyTable::~PropertyTable() PropertyTable::~PropertyTable()
{ {

View File

@ -513,7 +513,7 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPoly
} }
// we got a list of in-out-combinations of intersections. That should be an even number of intersections, or // we got a list of in-out-combinations of intersections. That should be an even number of intersections, or
// we're fucked. // we are facing a non-recoverable error.
if ((intersections.size() & 1) != 0) { if ((intersections.size() & 1) != 0) {
IFCImporter::LogWarn("Odd number of intersections, can't work with that. Omitting half space boundary check."); IFCImporter::LogWarn("Odd number of intersections, can't work with that. Omitting half space boundary check.");
continue; continue;

View File

@ -740,7 +740,7 @@ bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned
bool fix_orientation = false; bool fix_orientation = false;
std::shared_ptr< TempMesh > meshtmp = std::make_shared<TempMesh>(); std::shared_ptr< TempMesh > meshtmp = std::make_shared<TempMesh>();
if(const Schema_2x3::IfcShellBasedSurfaceModel* shellmod = geo.ToPtr<Schema_2x3::IfcShellBasedSurfaceModel>()) { if(const Schema_2x3::IfcShellBasedSurfaceModel* shellmod = geo.ToPtr<Schema_2x3::IfcShellBasedSurfaceModel>()) {
for(std::shared_ptr<const Schema_2x3::IfcShell> shell :shellmod->SbsmBoundary) { for (const std::shared_ptr<const Schema_2x3::IfcShell> &shell : shellmod->SbsmBoundary) {
try { try {
const ::Assimp::STEP::EXPRESS::ENTITY& e = shell->To<::Assimp::STEP::EXPRESS::ENTITY>(); const ::Assimp::STEP::EXPRESS::ENTITY& e = shell->To<::Assimp::STEP::EXPRESS::ENTITY>();
const Schema_2x3::IfcConnectedFaceSet& fs = conv.db.MustGetObject(e).To<Schema_2x3::IfcConnectedFaceSet>(); const Schema_2x3::IfcConnectedFaceSet& fs = conv.db.MustGetObject(e).To<Schema_2x3::IfcConnectedFaceSet>();

View File

@ -75,7 +75,7 @@ static void FillMaterial(aiMaterial* mat,const IFC::Schema_2x3::IfcSurfaceStyle*
mat->AddProperty(&name,AI_MATKEY_NAME); mat->AddProperty(&name,AI_MATKEY_NAME);
// now see which kinds of surface information are present // now see which kinds of surface information are present
for(std::shared_ptr< const IFC::Schema_2x3::IfcSurfaceStyleElementSelect > sel2 : surf->Styles) { for (const std::shared_ptr<const IFC::Schema_2x3::IfcSurfaceStyleElementSelect> &sel2 : surf->Styles) {
if (const IFC::Schema_2x3::IfcSurfaceStyleShading* shade = sel2->ResolveSelectPtr<IFC::Schema_2x3::IfcSurfaceStyleShading>(conv.db)) { if (const IFC::Schema_2x3::IfcSurfaceStyleShading* shade = sel2->ResolveSelectPtr<IFC::Schema_2x3::IfcSurfaceStyleShading>(conv.db)) {
aiColor4D col_base,col; aiColor4D col_base,col;
@ -134,7 +134,7 @@ unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionDat
for(;range.first != range.second; ++range.first) { for(;range.first != range.second; ++range.first) {
if(const IFC::Schema_2x3::IfcStyledItem* const styled = conv.db.GetObject((*range.first).second)->ToPtr<IFC::Schema_2x3::IfcStyledItem>()) { if(const IFC::Schema_2x3::IfcStyledItem* const styled = conv.db.GetObject((*range.first).second)->ToPtr<IFC::Schema_2x3::IfcStyledItem>()) {
for(const IFC::Schema_2x3::IfcPresentationStyleAssignment& as : styled->Styles) { for(const IFC::Schema_2x3::IfcPresentationStyleAssignment& as : styled->Styles) {
for(std::shared_ptr<const IFC::Schema_2x3::IfcPresentationStyleSelect> sel : as.Styles) { for (const std::shared_ptr<const IFC::Schema_2x3::IfcPresentationStyleSelect> &sel : as.Styles) {
if( const IFC::Schema_2x3::IfcSurfaceStyle* const surf = sel->ResolveSelectPtr<IFC::Schema_2x3::IfcSurfaceStyle>(conv.db) ) { if( const IFC::Schema_2x3::IfcSurfaceStyle* const surf = sel->ResolveSelectPtr<IFC::Schema_2x3::IfcSurfaceStyle>(conv.db) ) {
// try to satisfy from cache // try to satisfy from cache

View File

@ -54,6 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/mesh.h> #include <assimp/mesh.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <utility>
struct aiNode; struct aiNode;
namespace Assimp { namespace Assimp {
@ -137,14 +139,10 @@ struct TempOpening
} }
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
TempOpening(const IFC::Schema_2x3::IfcSolidModel* solid,IfcVector3 extrusionDir, TempOpening(const IFC::Schema_2x3::IfcSolidModel *solid, IfcVector3 extrusionDir,
std::shared_ptr<TempMesh> profileMesh, std::shared_ptr<TempMesh> profileMesh,
std::shared_ptr<TempMesh> profileMesh2D) std::shared_ptr<TempMesh> profileMesh2D) :
: solid(solid) solid(solid), extrusionDir(extrusionDir), profileMesh(std::move(profileMesh)), profileMesh2D(std::move(profileMesh2D)) {
, extrusionDir(extrusionDir)
, profileMesh(profileMesh)
, profileMesh2D(profileMesh2D)
{
} }
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------

View File

@ -318,7 +318,7 @@ void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
} else { } else {
++s; ++s;
} }
std::string::size_type t = src.path.substr(s).find_last_of("."); std::string::size_type t = src.path.substr(s).find_last_of('.');
nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined); nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
return; return;

View File

@ -233,12 +233,12 @@ void M3DImporter::importMaterials(const M3DWrapper &m3d) {
ASSIMP_LOG_DEBUG("M3D: importMaterials ", mScene->mNumMaterials); ASSIMP_LOG_DEBUG("M3D: importMaterials ", mScene->mNumMaterials);
// add a default material as first // add a default material as first
aiMaterial *mat = new aiMaterial; aiMaterial *defaultMat = new aiMaterial;
mat->AddProperty(&name, AI_MATKEY_NAME); defaultMat->AddProperty(&name, AI_MATKEY_NAME);
c.a = 1.0f; c.a = 1.0f;
c.b = c.g = c.r = 0.6f; c.b = c.g = c.r = 0.6f;
mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE); defaultMat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
mScene->mMaterials[0] = mat; mScene->mMaterials[0] = defaultMat;
if (!m3d->nummaterial || !m3d->material) { if (!m3d->nummaterial || !m3d->material) {
return; return;
@ -300,12 +300,12 @@ void M3DImporter::importMaterials(const M3DWrapper &m3d) {
m->prop[j].value.textureid < m3d->numtexture && m->prop[j].value.textureid < m3d->numtexture &&
m3d->texture[m->prop[j].value.textureid].name) { m3d->texture[m->prop[j].value.textureid].name) {
name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png"));
mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index); newMat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
n = 0; n = 0;
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); newMat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
} }
} }
mScene->mMaterials[i + 1] = mat; mScene->mMaterials[i + 1] = newMat;
} }
} }
@ -655,7 +655,7 @@ void M3DImporter::convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned in
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// find a node by name // find a node by name
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) { aiNode *M3DImporter::findNode(aiNode *pNode, const aiString &name) {
ai_assert(pNode != nullptr); ai_assert(pNode != nullptr);
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);

View File

@ -89,8 +89,8 @@ private:
// helper functions // helper functions
aiColor4D mkColor(uint32_t c); aiColor4D mkColor(uint32_t c);
void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
aiNode *findNode(aiNode *pNode, aiString name); aiNode *findNode(aiNode *pNode, const aiString &name);
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces, void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors, std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
std::vector<unsigned int> *vertexids); std::vector<unsigned int> *vertexids);

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef AI_M3DWRAPPER_H_INC #ifndef AI_M3DWRAPPER_H_INC
#define AI_M3DWRAPPER_H_INC #define AI_M3DWRAPPER_H_INC
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER #if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#include <memory> #include <memory>
@ -55,44 +56,75 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Assimp specific M3D configuration. Comment out these defines to remove functionality // Assimp specific M3D configuration. Comment out these defines to remove functionality
//#define ASSIMP_USE_M3D_READFILECB //#define ASSIMP_USE_M3D_READFILECB
// Share stb_image's PNG loader with other importers/exporters instead of bringing our own copy.
#define STBI_ONLY_PNG
#include <stb/stb_image.h>
#include "m3d.h" #include "m3d.h"
namespace Assimp { namespace Assimp {
class IOSystem; class IOSystem;
/// brief The M3D-Wrapper, provudes c++ access to the data.
class M3DWrapper { class M3DWrapper {
m3d_t *m3d_ = nullptr;
unsigned char *saved_output_ = nullptr;
public: public:
// Construct an empty M3D model /// Construct an empty M3D model
explicit M3DWrapper(); explicit M3DWrapper();
// Construct an M3D model from provided buffer /// Construct an M3D model from provided buffer
// NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write. /// @note The m3d.h SDK function does not mark the data as const. Have assumed it does not write.
// BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN /// BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN
explicit M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer); explicit M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer);
~M3DWrapper(); /// Theclasss destructor.
~M3DWrapper();
void reset(); /// Will reset the wrapper, all data will become nullptr.
void reset();
// Name // The Name access, empty string returned when no m3d instance.
inline std::string Name() const { std::string Name() const;
if (m3d_) return std::string(m3d_->name);
return std::string();
}
// Execute a save /// Executes a save.
unsigned char *Save(int quality, int flags, unsigned int &size); unsigned char *Save(int quality, int flags, unsigned int &size);
/// Clearer
void ClearSave(); void ClearSave();
inline explicit operator bool() const { return m3d_ != nullptr; } /// True for m3d instance exists.
explicit operator bool() const;
// Allow direct access to M3D API // Allow direct access to M3D API
inline m3d_t *operator->() const { return m3d_; } m3d_t *operator->() const;
inline m3d_t *M3D() const { return m3d_; } m3d_t *M3D() const;
private:
m3d_t *m3d_ = nullptr;
unsigned char *saved_output_ = nullptr;
}; };
inline std::string M3DWrapper::Name() const {
if (nullptr != m3d_) {
if (nullptr != m3d_->name) {
return std::string(m3d_->name);
}
}
return std::string();
}
inline M3DWrapper::operator bool() const {
return m3d_ != nullptr;
}
inline m3d_t *M3DWrapper::operator->() const {
return m3d_;
}
inline m3d_t *M3DWrapper::M3D() const {
return m3d_;
}
} // namespace Assimp } // namespace Assimp
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -516,13 +516,13 @@ namespace pmx
stream->read((char*) magic, sizeof(char) * 4); stream->read((char*) magic, sizeof(char) * 4);
if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20) if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20)
{ {
throw DeadlyImportError("MMD: Invalid magic number."); throw DeadlyImportError("MMD: Invalid magic number.");
} }
stream->read((char*) &version, sizeof(float)); stream->read((char*) &version, sizeof(float));
if (version != 2.0f && version != 2.1f) if (version != 2.0f && version != 2.1f)
{ {
throw DeadlyImportError("MMD: Unsupported version (must be 2.0 or 2.1): ", ai_to_string(version)); throw DeadlyImportError("MMD: Unsupported version (must be 2.0 or 2.1): ", ai_to_string(version));
} }
this->setting.Read(stream); this->setting.Read(stream);
this->model_name = ReadString(stream, setting.encoding); this->model_name = ReadString(stream, setting.encoding);

View File

@ -162,7 +162,7 @@ void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, I
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Create the data from parsed obj-file // Create the data from parsed obj-file
void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene) { void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene) {
if (0L == pModel) { if (nullptr == pModel) {
return; return;
} }
@ -468,7 +468,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
} }
// Copy all vertex colors // Copy all vertex colors
if (!pModel->m_VertexColors.empty()) { if (vertex < pModel->m_VertexColors.size()) {
const aiVector3D &color = pModel->m_VertexColors[vertex]; const aiVector3D &color = pModel->m_VertexColors[vertex];
pMesh->mColors[0][newIndex] = aiColor4D(color.x, color.y, color.z, 1.0); pMesh->mColors[0][newIndex] = aiColor4D(color.x, color.y, color.z, 1.0);
} }

View File

@ -415,8 +415,8 @@ bool OgreImporter::ReadTextureUnit(const std::string &textureUnitName, stringstr
// User defined Assimp config property to detect texture type from filename. // User defined Assimp config property to detect texture type from filename.
if (m_detectTextureTypeFromFilename) { if (m_detectTextureTypeFromFilename) {
size_t posSuffix = textureRef.find_last_of("."); size_t posSuffix = textureRef.find_last_of('.');
size_t posUnderscore = textureRef.find_last_of("_"); size_t posUnderscore = textureRef.find_last_of('_');
if (posSuffix != string::npos && posUnderscore != string::npos && posSuffix > posUnderscore) { if (posSuffix != string::npos && posUnderscore != string::npos && posSuffix > posUnderscore) {
string identifier = ai_tolower(textureRef.substr(posUnderscore, posSuffix - posUnderscore)); string identifier = ai_tolower(textureRef.substr(posUnderscore, posSuffix - posUnderscore));

View File

@ -419,8 +419,7 @@ bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char>
if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) { if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) {
// add the element to the list of elements // add the element to the list of elements
alElements.push_back(out); alElements.push_back(out);
} else if ( TokenMatch(buffer, "end_header\r", 11) || //checks for header end with /r/n ending } else if (TokenMatch(buffer, "end_header", 10)) { //checks for /n ending, if it doesn't end with /r/n
TokenMatch(buffer, "end_header", 10)) { //checks for /n ending, if it doesn't end with /r/n
// we have reached the end of the header // we have reached the end of the header
break; break;
} else { } else {
@ -501,6 +500,11 @@ bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, DOM *p_pc
} }
streamBuffer.getNextBlock(buffer); streamBuffer.getNextBlock(buffer);
// remove first char if it's /n in case of file with /r/n
if (((char *)&buffer[0])[0] == '\n')
buffer.erase(buffer.begin(), buffer.begin() + 1);
unsigned int bufferSize = static_cast<unsigned int>(buffer.size()); unsigned int bufferSize = static_cast<unsigned int>(buffer.size());
const char *pCur = (char *)&buffer[0]; const char *pCur = (char *)&buffer[0];
if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE)) { if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE)) {

View File

@ -99,7 +99,7 @@ static void extractIds(const std::string &key, int &id1, int &id2) {
return; return;
} }
const std::string::size_type pos = key.find("."); const std::string::size_type pos = key.find('.');
if (std::string::npos == pos) { if (std::string::npos == pos) {
return; return;
} }
@ -208,7 +208,7 @@ void Q3BSPFileImporter::separateMapName(const std::string &importName, std::stri
return; return;
} }
const std::string::size_type pos = importName.rfind(","); const std::string::size_type pos = importName.rfind(',');
if (std::string::npos == pos) { if (std::string::npos == pos) {
archiveName = importName; archiveName = importName;
return; return;

View File

@ -49,21 +49,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "STEPFileEncoding.h" #include "STEPFileEncoding.h"
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <memory>
#include <functional> #include <functional>
#include <memory>
#include <utility>
using namespace Assimp; using namespace Assimp;
namespace EXPRESS = STEP::EXPRESS; namespace EXPRESS = STEP::EXPRESS;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = "") std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = std::string())
{ {
return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) ); return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = "") std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = std::string())
{ {
return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s)); return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s));
} }
@ -87,7 +88,7 @@ static const char *ISO_Token = "ISO-10303-21;";
static const char *FILE_SCHEMA_Token = "FILE_SCHEMA"; static const char *FILE_SCHEMA_Token = "FILE_SCHEMA";
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) { STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) {
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream)); std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(std::move(stream)));
std::unique_ptr<STEP::DB> db = std::unique_ptr<STEP::DB>(new STEP::DB(reader)); std::unique_ptr<STEP::DB> db = std::unique_ptr<STEP::DB>(new STEP::DB(reader));
LineSplitter &splitter = db->GetSplitter(); LineSplitter &splitter = db->GetSplitter();

View File

@ -634,7 +634,7 @@ private:
}; };
template <typename T> template <typename T>
inline bool operator==(std::shared_ptr<LazyObject> lo, T whatever) { inline bool operator==(const std::shared_ptr<LazyObject> &lo, T whatever) {
return *lo == whatever; // XXX use std::forward if we have 0x return *lo == whatever; // XXX use std::forward if we have 0x
} }
@ -816,7 +816,7 @@ public:
typedef std::pair<RefMap::const_iterator, RefMap::const_iterator> RefMapRange; typedef std::pair<RefMap::const_iterator, RefMap::const_iterator> RefMapRange;
private: private:
DB(std::shared_ptr<StreamReaderLE> reader) : DB(const std::shared_ptr<StreamReaderLE> &reader) :
reader(reader), splitter(*reader, true, true), evaluated_count(), schema(nullptr) {} reader(reader), splitter(*reader, true, true), evaluated_count(), schema(nullptr) {}
public: public:

View File

@ -175,12 +175,11 @@ void StepExporter::WriteFile()
fColor.b = 0.8f; fColor.b = 0.8f;
int ind = 100; // the start index to be used int ind = 100; // the start index to be used
int faceEntryLen = 30; // number of entries for a triangle/face std::vector<int> faceEntryLen; // numbers of entries for a triangle/face
// prepare unique (count triangles and vertices) // prepare unique (count triangles and vertices)
VectorIndexUMap uniqueVerts; // use a map to reduce find complexity to log(n) VectorIndexUMap uniqueVerts; // use a map to reduce find complexity to log(n)
VectorIndexUMap::iterator it; VectorIndexUMap::iterator it;
int countFace = 0;
for (unsigned int i=0; i<mScene->mNumMeshes; ++i) for (unsigned int i=0; i<mScene->mNumMeshes; ++i)
{ {
@ -189,7 +188,7 @@ void StepExporter::WriteFile()
{ {
aiFace* face = &(mesh->mFaces[j]); aiFace* face = &(mesh->mFaces[j]);
if (face->mNumIndices == 3) countFace++; if (face->mNumIndices >= 3) faceEntryLen.push_back(15 + 5 * face->mNumIndices);
} }
for (unsigned int j=0; j<mesh->mNumVertices; ++j) for (unsigned int j=0; j<mesh->mNumVertices; ++j)
{ {
@ -218,10 +217,13 @@ void StepExporter::WriteFile()
// write the top of data // write the top of data
mOutput << "DATA" << endstr; mOutput << "DATA" << endstr;
mOutput << "#1=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION(' ',("; mOutput << "#1=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION(' ',(";
for (int i=0; i<countFace; ++i) size_t countFace = faceEntryLen.size();
size_t faceLenIndex = ind + 2 * uniqueVerts.size();
for (size_t i=0; i<countFace; ++i)
{ {
mOutput << "#" << i*faceEntryLen + ind + 2*uniqueVerts.size(); mOutput << "#" << faceLenIndex;
if (i!=countFace-1) mOutput << ","; if (i!=countFace-1) mOutput << ",";
faceLenIndex += faceEntryLen[i];
} }
mOutput << "),#6)" << endstr; mOutput << "),#6)" << endstr;
@ -253,10 +255,12 @@ void StepExporter::WriteFile()
mOutput << "#27=DIRECTION('',(1.0,0.0,0.0))" << endstr; mOutput << "#27=DIRECTION('',(1.0,0.0,0.0))" << endstr;
mOutput << "#28= (NAMED_UNIT(#21)LENGTH_UNIT()SI_UNIT(.MILLI.,.METRE.))" << endstr; mOutput << "#28= (NAMED_UNIT(#21)LENGTH_UNIT()SI_UNIT(.MILLI.,.METRE.))" << endstr;
mOutput << "#29=CLOSED_SHELL('',("; mOutput << "#29=CLOSED_SHELL('',(";
for (int i=0; i<countFace; ++i) faceLenIndex = ind + 2 * uniqueVerts.size() + 8;
for (size_t i=0; i<countFace; ++i)
{ {
mOutput << "#" << i*faceEntryLen + ind + 2*uniqueVerts.size() + 8; mOutput << "#" << faceLenIndex;
if (i!=countFace-1) mOutput << ","; if (i!=countFace-1) mOutput << ",";
faceLenIndex += faceEntryLen[i];
} }
mOutput << "))" << endstr; mOutput << "))" << endstr;
@ -289,28 +293,29 @@ void StepExporter::WriteFile()
{ {
aiFace* face = &(mesh->mFaces[j]); aiFace* face = &(mesh->mFaces[j]);
if (face->mNumIndices != 3) continue; const int numIndices = face->mNumIndices;
if (numIndices < 3) continue;
aiVector3D* v1 = &(mesh->mVertices[face->mIndices[0]]); std::vector<int> pidArray(numIndices, -1); // vertex id
aiVector3D* v2 = &(mesh->mVertices[face->mIndices[1]]); std::vector<aiVector3D> dvArray(numIndices); // edge dir
aiVector3D* v3 = &(mesh->mVertices[face->mIndices[2]]); for (int k = 0; k < numIndices; ++k)
aiVector3D dv12 = *v2 - *v1; {
aiVector3D dv23 = *v3 - *v2; aiVector3D *v1 = &(mesh->mVertices[face->mIndices[k]]);
aiVector3D dv31 = *v1 - *v3; pidArray[k] = uniqueVerts.find(v1)->second;
aiVector3D dv13 = *v3 - *v1;
dv12.Normalize();
dv23.Normalize();
dv31.Normalize();
dv13.Normalize();
aiVector3D dvY = dv12; aiVector3D *v2 = nullptr;
aiVector3D dvX = dvY ^ dv13; if (k + 1 == numIndices)
v2 = &(mesh->mVertices[face->mIndices[0]]);
else
v2 = &(mesh->mVertices[face->mIndices[k + 1]]);
dvArray[k] = *v2 - *v1;
dvArray[k].Normalize();
}
aiVector3D dvY = dvArray[1];
aiVector3D dvX = dvY ^ dvArray[0];
dvX.Normalize(); dvX.Normalize();
int pid1 = uniqueVerts.find(v1)->second;
int pid2 = uniqueVerts.find(v2)->second;
int pid3 = uniqueVerts.find(v3)->second;
// mean vertex color for the face if available // mean vertex color for the face if available
if (mesh->HasVertexColors(0)) if (mesh->HasVertexColors(0))
{ {
@ -339,35 +344,62 @@ void StepExporter::WriteFile()
/* 2 directions of the plane */ /* 2 directions of the plane */
mOutput << "#" << sid+9 << "=PLANE('',#" << sid+10 << ")" << endstr; mOutput << "#" << sid+9 << "=PLANE('',#" << sid+10 << ")" << endstr;
mOutput << "#" << sid+10 << "=AXIS2_PLACEMENT_3D('',#" << pid1 << ", #" << sid+11 << ",#" << sid+12 << ")" << endstr; mOutput << "#" << sid+10 << "=AXIS2_PLACEMENT_3D('',#" << pidArray[0] << ",#" << sid+11 << ",#" << sid+12 << ")" << endstr;
mOutput << "#" << sid + 11 << "=DIRECTION('',(" << dvX.x << "," << dvX.y << "," << dvX.z << "))" << endstr; mOutput << "#" << sid + 11 << "=DIRECTION('',(" << dvX.x << "," << dvX.y << "," << dvX.z << "))" << endstr;
mOutput << "#" << sid + 12 << "=DIRECTION('',(" << dvY.x << "," << dvY.y << "," << dvY.z << "))" << endstr; mOutput << "#" << sid + 12 << "=DIRECTION('',(" << dvY.x << "," << dvY.y << "," << dvY.z << "))" << endstr;
mOutput << "#" << sid+13 << "=FACE_BOUND('',#" << sid+14 << ",.T.)" << endstr; mOutput << "#" << sid+13 << "=FACE_BOUND('',#" << sid+14 << ",.T.)" << endstr;
mOutput << "#" << sid+14 << "=EDGE_LOOP('',(#" << sid+15 << ",#" << sid+16 << ",#" << sid+17 << "))" << endstr; mOutput << "#" << sid+14 << "=EDGE_LOOP('',(";
int edgeLoopStart = sid + 15;
for (int k = 0; k < numIndices; ++k)
{
if (k == 0)
mOutput << "#";
else
mOutput << ",#";
mOutput << edgeLoopStart + k;
}
mOutput << "))" << endstr;
/* edge loop */ /* edge loop */
mOutput << "#" << sid+15 << "=ORIENTED_EDGE('',*,*,#" << sid+18 << ",.T.)" << endstr; int orientedEdgesStart = edgeLoopStart + numIndices;
mOutput << "#" << sid+16 << "=ORIENTED_EDGE('',*,*,#" << sid+19 << ",.T.)" << endstr; for (int k=0; k < numIndices; k++)
mOutput << "#" << sid+17 << "=ORIENTED_EDGE('',*,*,#" << sid+20 << ",.T.)" << endstr; {
mOutput << "#" << edgeLoopStart+k << "=ORIENTED_EDGE('',*,*,#" << orientedEdgesStart + k << ",.T.)" << endstr;
}
/* oriented edges */ /* oriented edges */
mOutput << "#" << sid+18 << "=EDGE_CURVE('',#" << pid1+1 << ",#" << pid2+1 << ",#" << sid+21 << ",.F.)" << endstr; int lineStart = orientedEdgesStart + numIndices;
mOutput << "#" << sid+19 << "=EDGE_CURVE('',#" << pid2+1 << ",#" << pid3+1 << ",#" << sid+22 << ",.T.)" << endstr; for (int k=0; k < numIndices; ++k)
mOutput << "#" << sid+20 << "=EDGE_CURVE('',#" << pid3+1 << ",#" << pid1+1 << ",#" << sid+23 << ",.T.)" << endstr; {
if (k == 0)
mOutput << "#" << orientedEdgesStart+k << "=EDGE_CURVE('',#" << pidArray[k]+1 << ",#" << pidArray[k+1]+1 << ",#" << lineStart+k << ",.F.)" << endstr;
else if (k+1 == numIndices)
mOutput << "#" << orientedEdgesStart+k << "=EDGE_CURVE('',#" << pidArray[k]+1 << ",#" << pidArray[0]+1 << ",#" << lineStart+k << ",.T.)" << endstr;
else
mOutput << "#" << orientedEdgesStart+k << "=EDGE_CURVE('',#" << pidArray[k]+1 << ",#" << pidArray[k+1]+1 << ",#" << lineStart+k << ",.T.)" << endstr;
}
/* 3 lines and 3 vectors for the lines for the 3 edge curves */ /* n lines and n vectors for the lines for the n edge curves */
mOutput << "#" << sid+21 << "=LINE('',#" << pid1 << ",#" << sid+24 << ")" << endstr; int vectorStart = lineStart + numIndices;
mOutput << "#" << sid+22 << "=LINE('',#" << pid2 << ",#" << sid+25 << ")" << endstr; for (int k=0; k < numIndices; ++k)
mOutput << "#" << sid+23 << "=LINE('',#" << pid3 << ",#" << sid+26 << ")" << endstr; {
mOutput << "#" << sid+24 << "=VECTOR('',#" << sid+27 << ",1.0)" << endstr; mOutput << "#" << lineStart+k << "=LINE('',#" << pidArray[k] << ",#" << vectorStart+k << ")" << endstr;
mOutput << "#" << sid+25 << "=VECTOR('',#" << sid+28 << ",1.0)" << endstr; }
mOutput << "#" << sid+26 << "=VECTOR('',#" << sid+29 << ",1.0)" << endstr;
mOutput << "#" << sid+27 << "=DIRECTION('',(" << dv12.x << "," << dv12.y << "," << dv12.z << "))" << endstr; int directionStart = vectorStart + numIndices;
mOutput << "#" << sid+28 << "=DIRECTION('',(" << dv23.x << "," << dv23.y << "," << dv23.z << "))" << endstr; for (int k=0; k < numIndices; ++k)
mOutput << "#" << sid+29 << "=DIRECTION('',(" << dv31.x << "," << dv31.y << "," << dv31.z << "))" << endstr; {
ind += faceEntryLen; // increase counter mOutput << "#" << vectorStart+k << "=VECTOR('',#" << directionStart+k << ",1.0)" << endstr;
}
for (int k=0; k < numIndices; ++k)
{
const aiVector3D &dv = dvArray[k];
mOutput << "#" << directionStart + k << "=DIRECTION('',(" << dv.x << "," << dv.y << "," << dv.z << "))" << endstr;
}
ind += 15 + 5*numIndices; // increase counter
} }
} }

View File

@ -530,8 +530,8 @@ void XFileExporter::writePath(const aiString &path)
while( str.find( "\\\\") != std::string::npos) while( str.find( "\\\\") != std::string::npos)
str.replace( str.find( "\\\\"), 2, "\\"); str.replace( str.find( "\\\\"), 2, "\\");
while( str.find( "\\") != std::string::npos) while (str.find('\\') != std::string::npos)
str.replace( str.find( "\\"), 1, "/"); str.replace(str.find('\\'), 1, "/");
mOutput << str; mOutput << str;

View File

@ -667,9 +667,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
// convert to lower case for easier comparison // convert to lower case for easier comparison
for ( unsigned int c = 0; c < sz.length(); ++c ) { for ( unsigned int c = 0; c < sz.length(); ++c ) {
if ( isalpha( (unsigned char) sz[ c ] ) ) { sz[ c ] = (char) tolower( (unsigned char) sz[ c ] );
sz[ c ] = (char) tolower( (unsigned char) sz[ c ] );
}
} }
// Place texture filename property under the corresponding name // Place texture filename property under the corresponding name

View File

@ -63,9 +63,9 @@ class X3DExporter {
// empty // empty
} }
SAttribute(SAttribute && rhs) : SAttribute(SAttribute &&rhs) AI_NO_EXCEPT :
Name(std::move(rhs.Name)), Name(rhs.Name),
Value(std::move(rhs.Value)) { Value(rhs.Value) {
// empty // empty
} }
}; };

View File

@ -2890,7 +2890,6 @@ void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement &pN
} // if( !meta_list.empty() ) } // if( !meta_list.empty() )
} }
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
} // namespace Assimp } // namespace Assimp

View File

@ -250,7 +250,7 @@ void XGLImporter::ReadWorld(XmlNode &node, TempScope &scope) {
} }
} }
aiNode *const nd = ReadObject(node, scope, true); aiNode *const nd = ReadObject(node, scope);
if (!nd) { if (!nd) {
ThrowException("failure reading <world>"); ThrowException("failure reading <world>");
} }
@ -296,16 +296,13 @@ aiLight *XGLImporter::ReadDirectionalLight(XmlNode &node) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope, bool skipFirst/*, const char *closetag */) { aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope) {
aiNode *nd = new aiNode; aiNode *nd = new aiNode;
std::vector<aiNode *> children; std::vector<aiNode *> children;
std::vector<unsigned int> meshes; std::vector<unsigned int> meshes;
try { try {
for (XmlNode &child : node.children()) { for (XmlNode &child : node.children()) {
skipFirst = false;
const std::string &s = ai_stdStrToLower(child.name()); const std::string &s = ai_stdStrToLower(child.name());
if (s == "mesh") { if (s == "mesh") {
const size_t prev = scope.meshes_linear.size(); const size_t prev = scope.meshes_linear.size();

View File

@ -185,7 +185,7 @@ private:
void ReadWorld(XmlNode &node, TempScope &scope); void ReadWorld(XmlNode &node, TempScope &scope);
void ReadLighting(XmlNode &node, TempScope &scope); void ReadLighting(XmlNode &node, TempScope &scope);
aiLight *ReadDirectionalLight(XmlNode &node); aiLight *ReadDirectionalLight(XmlNode &node);
aiNode *ReadObject(XmlNode &node, TempScope &scope, bool skipFirst = false/*, const char *closetag = "object"*/); aiNode *ReadObject(XmlNode &node, TempScope &scope);
bool ReadMesh(XmlNode &node, TempScope &scope); bool ReadMesh(XmlNode &node, TempScope &scope);
void ReadMaterial(XmlNode &node, TempScope &scope); void ReadMaterial(XmlNode &node, TempScope &scope);
aiVector2D ReadVec2(XmlNode &node); aiVector2D ReadVec2(XmlNode &node);

View File

@ -456,11 +456,10 @@ namespace glTF
/// \param [in] pDecodedData - pointer to decoded data array. /// \param [in] pDecodedData - pointer to decoded data array.
/// \param [in] pDecodedData_Length - size of encoded region, in bytes. /// \param [in] pDecodedData_Length - size of encoded region, in bytes.
/// \param [in] pID - ID of the region. /// \param [in] pID - ID of the region.
SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) 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) Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {}
{}
/// \fn ~SEncodedRegion() /// \fn ~SEncodedRegion()
/// Destructor. /// Destructor.
~SEncodedRegion() { delete [] DecodedData; } ~SEncodedRegion() { delete [] DecodedData; }
}; };
@ -1149,8 +1148,7 @@ namespace glTF
void ReadExtensionsUsed(Document& doc); void ReadExtensionsUsed(Document& doc);
IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
}; };
} }

View File

@ -1377,7 +1377,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
#undef CHECK_EXT #undef CHECK_EXT
} }
inline IOStream *Asset::OpenFile(std::string path, const char *mode, bool absolute) { inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool absolute) {
#ifdef ASSIMP_API #ifdef ASSIMP_API
(void)absolute; (void)absolute;
return mIOSystem->Open(path, mode); return mIOSystem->Open(path, mode);

View File

@ -195,11 +195,11 @@ inline void CopyValue(const glTFCommon::mat4 &v, aiMatrix4x4 &o) {
inline std::string getCurrentAssetDir(const std::string &pFile) { inline std::string getCurrentAssetDir(const std::string &pFile) {
std::string path = pFile; std::string path = pFile;
int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
if (pos != int(std::string::npos)) { if (pos == int(std::string::npos)) {
path = pFile.substr(0, pos + 1); return std::string();
} }
return path; return pFile.substr(0, pos + 1);
} }
#if _MSC_VER #if _MSC_VER
# pragma warning(pop) # pragma warning(pop)

View File

@ -408,8 +408,7 @@ void glTFExporter::ExportMaterials()
* Search through node hierarchy and find the node containing the given meshID. * Search through node hierarchy and find the node containing the given meshID.
* Returns true on success, and false otherwise. * Returns true on success, and false otherwise.
*/ */
bool FindMeshNode(Ref<Node>& nodeIn, Ref<Node>& meshNode, std::string meshID) bool FindMeshNode(Ref<Node> &nodeIn, Ref<Node> &meshNode, const std::string &meshID) {
{
for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) { for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) {
if (meshID.compare(nodeIn->meshes[i]->id) == 0) { if (meshID.compare(nodeIn->meshes[i]->id) == 0) {
meshNode = nodeIn; meshNode = nodeIn;
@ -530,6 +529,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref<Mesh>& meshRef, Ref<Buf
#if defined(__has_warning) #if defined(__has_warning)
#if __has_warning("-Wunused-but-set-variable") #if __has_warning("-Wunused-but-set-variable")
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif #endif
#endif #endif

View File

@ -356,6 +356,53 @@ struct Nullable {
isPresent(true) {} isPresent(true) {}
}; };
struct CustomExtension {
//
// A struct containing custom extension data added to a glTF2 file
// Has to contain Object, Array, String, Double, Uint64, and Int64 at a minimum
// String, Double, Uint64, and Int64 are stored in the Nullables
// Object and Array are stored in the std::vector
//
std::string name;
Nullable<std::string> mStringValue;
Nullable<double> mDoubleValue;
Nullable<uint64_t> mUint64Value;
Nullable<int64_t> mInt64Value;
Nullable<bool> mBoolValue;
// std::vector<CustomExtension> handles both Object and Array
Nullable<std::vector<CustomExtension>> mValues;
operator bool() const {
return Size() != 0;
}
size_t Size() const {
if (mValues.isPresent) {
return mValues.value.size();
} else if (mStringValue.isPresent || mDoubleValue.isPresent || mUint64Value.isPresent || mInt64Value.isPresent || mBoolValue.isPresent) {
return 1;
}
return 0;
}
CustomExtension() = default;
~CustomExtension() = default;
CustomExtension(const CustomExtension &other) :
name(other.name),
mStringValue(other.mStringValue),
mDoubleValue(other.mDoubleValue),
mUint64Value(other.mUint64Value),
mInt64Value(other.mInt64Value),
mBoolValue(other.mBoolValue),
mValues(other.mValues) {
// empty
}
};
//! Base class for all glTF top-level objects //! Base class for all glTF top-level objects
struct Object { struct Object {
int index; //!< The index of this object within its property container int index; //!< The index of this object within its property container
@ -363,6 +410,9 @@ struct Object {
std::string id; //!< The globally unique ID used to reference this object std::string id; //!< The globally unique ID used to reference this object
std::string name; //!< The user-defined name of this object std::string name; //!< The user-defined name of this object
CustomExtension customExtensions;
CustomExtension extras;
//! Objects marked as special are not exported (used to emulate the binary body buffer) //! Objects marked as special are not exported (used to emulate the binary body buffer)
virtual bool IsSpecial() const { return false; } virtual bool IsSpecial() const { return false; }
@ -377,6 +427,9 @@ struct Object {
inline Value *FindArray(Value &val, const char *id); inline Value *FindArray(Value &val, const char *id);
inline Value *FindObject(Value &val, const char *id); inline Value *FindObject(Value &val, const char *id);
inline Value *FindExtension(Value &val, const char *extensionId); inline Value *FindExtension(Value &val, const char *extensionId);
inline void ReadExtensions(Value &val);
inline void ReadExtras(Value &val);
}; };
// //
@ -408,7 +461,7 @@ public:
/// \param [in] pDecodedData - pointer to decoded data array. /// \param [in] pDecodedData - pointer to decoded data array.
/// \param [in] pDecodedData_Length - size of encoded region, in bytes. /// \param [in] pDecodedData_Length - size of encoded region, in bytes.
/// \param [in] pID - ID of the region. /// \param [in] pID - ID of the region.
SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string pID) : SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
Offset(pOffset), Offset(pOffset),
EncodedData_Length(pEncodedData_Length), EncodedData_Length(pEncodedData_Length),
DecodedData(pDecodedData), DecodedData(pDecodedData),
@ -834,50 +887,6 @@ struct Mesh : public Object {
void Read(Value &pJSON_Object, Asset &pAsset_Root); void Read(Value &pJSON_Object, Asset &pAsset_Root);
}; };
struct CustomExtension : public Object {
//
// A struct containing custom extension data added to a glTF2 file
// Has to contain Object, Array, String, Double, Uint64, and Int64 at a minimum
// String, Double, Uint64, and Int64 are stored in the Nullables
// Object and Array are stored in the std::vector
//
Nullable<std::string> mStringValue;
Nullable<double> mDoubleValue;
Nullable<uint64_t> mUint64Value;
Nullable<int64_t> mInt64Value;
Nullable<bool> mBoolValue;
// std::vector<CustomExtension> handles both Object and Array
Nullable<std::vector<CustomExtension>> mValues;
operator bool() const {
return Size() != 0;
}
size_t Size() const {
if (mValues.isPresent) {
return mValues.value.size();
} else if (mStringValue.isPresent || mDoubleValue.isPresent || mUint64Value.isPresent || mInt64Value.isPresent || mBoolValue.isPresent) {
return 1;
}
return 0;
}
CustomExtension() = default;
CustomExtension(const CustomExtension &other)
: Object(other)
, mStringValue(other.mStringValue)
, mDoubleValue(other.mDoubleValue)
, mUint64Value(other.mUint64Value)
, mInt64Value(other.mInt64Value)
, mBoolValue(other.mBoolValue)
, mValues(other.mValues)
{
}
};
struct Node : public Object { struct Node : public Object {
std::vector<Ref<Node>> children; std::vector<Ref<Node>> children;
std::vector<Ref<Mesh>> meshes; std::vector<Ref<Mesh>> meshes;
@ -896,8 +905,6 @@ struct Node : public Object {
Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper. Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
CustomExtension extensions;
Node() {} Node() {}
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
@ -1188,7 +1195,7 @@ private:
void ReadExtensionsUsed(Document &doc); void ReadExtensionsUsed(Document &doc);
void ReadExtensionsRequired(Document &doc); void ReadExtensionsRequired(Document &doc);
IOStream *OpenFile(std::string path, const char *mode, bool absolute = false); IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
}; };
inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) { inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2021, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -304,6 +303,43 @@ inline Value *FindObject(Document &doc, const char *memberId) {
inline Value *FindExtension(Value &val, const char *extensionId) { inline Value *FindExtension(Value &val, const char *extensionId) {
return FindExtensionInContext(val, extensionId, "the document"); return FindExtensionInContext(val, extensionId, "the document");
} }
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
CustomExtension ret;
ret.name = name;
if (obj.IsObject()) {
ret.mValues.isPresent = true;
for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
auto &val = it->value;
ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
}
} else if (obj.IsArray()) {
ret.mValues.value.reserve(obj.Size());
ret.mValues.isPresent = true;
for (unsigned int i = 0; i < obj.Size(); ++i) {
ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
}
} else if (obj.IsNumber()) {
if (obj.IsUint64()) {
ret.mUint64Value.value = obj.GetUint64();
ret.mUint64Value.isPresent = true;
} else if (obj.IsInt64()) {
ret.mInt64Value.value = obj.GetInt64();
ret.mInt64Value.isPresent = true;
} else if (obj.IsDouble()) {
ret.mDoubleValue.value = obj.GetDouble();
ret.mDoubleValue.isPresent = true;
}
} else if (obj.IsString()) {
ReadValue(obj, ret.mStringValue);
ret.mStringValue.isPresent = true;
} else if (obj.IsBool()) {
ret.mBoolValue.value = obj.GetBool();
ret.mBoolValue.isPresent = true;
}
return ret;
}
} // namespace } // namespace
inline Value *Object::FindString(Value &val, const char *memberId) { inline Value *Object::FindString(Value &val, const char *memberId) {
@ -330,6 +366,18 @@ inline Value *Object::FindExtension(Value &val, const char *extensionId) {
return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str()); return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str());
} }
inline void Object::ReadExtensions(Value &val) {
if (Value *curExtensions = FindObject(val, "extensions")) {
this->customExtensions = glTF2::ReadExtensions("extensions", *curExtensions);
}
}
inline void Object::ReadExtras(Value &val) {
if (Value *curExtras = FindObject(val, "extras")) {
this->extras = glTF2::ReadExtensions("extras", *curExtras);
}
}
#ifdef ASSIMP_ENABLE_DRACO #ifdef ASSIMP_ENABLE_DRACO
template <typename T> template <typename T>
@ -569,6 +617,8 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
inst->oIndex = i; inst->oIndex = i;
ReadMember(obj, "name", inst->name); ReadMember(obj, "name", inst->name);
inst->Read(obj, mAsset); inst->Read(obj, mAsset);
inst->ReadExtensions(obj);
inst->ReadExtras(obj);
Ref<T> result = Add(inst.release()); Ref<T> result = Add(inst.release());
mRecursiveReferenceCheck.erase(i); mRecursiveReferenceCheck.erase(i);
@ -733,12 +783,13 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod
} }
inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) { inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) {
if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return; if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) {
return;
}
for (SEncodedRegion *reg : EncodedRegion_List) { for (SEncodedRegion *reg : EncodedRegion_List) {
if (reg->ID == pID) { if (reg->ID == pID) {
EncodedRegion_Current = reg; EncodedRegion_Current = reg;
return; return;
} }
} }
@ -788,10 +839,13 @@ inline bool Buffer::ReplaceData_joint(const size_t pBufferData_Offset, const siz
} }
inline size_t Buffer::AppendData(uint8_t *data, size_t length) { inline size_t Buffer::AppendData(uint8_t *data, size_t length) {
size_t offset = this->byteLength; const size_t offset = this->byteLength;
// Force alignment to 4 bits // Force alignment to 4 bits
Grow((length + 3) & ~3); const size_t paddedLength = (length + 3) & ~3;
Grow(paddedLength);
memcpy(mData.get() + offset, data, length); memcpy(mData.get() + offset, data, length);
memset(mData.get() + offset + length, 0, paddedLength - length);
return offset; return offset;
} }
@ -820,9 +874,7 @@ inline void Buffer::Grow(size_t amount) {
// //
// struct BufferView // struct BufferView
// //
inline void BufferView::Read(Value &obj, Asset &r) { inline void BufferView::Read(Value &obj, Asset &r) {
if (Value *bufferVal = FindUInt(obj, "buffer")) { if (Value *bufferVal = FindUInt(obj, "buffer")) {
buffer = r.buffers.Retrieve(bufferVal->GetUint()); buffer = r.buffers.Retrieve(bufferVal->GetUint());
} }
@ -842,16 +894,21 @@ inline void BufferView::Read(Value &obj, Asset &r) {
} }
inline uint8_t *BufferView::GetPointer(size_t accOffset) { inline uint8_t *BufferView::GetPointer(size_t accOffset) {
if (!buffer) return nullptr; if (!buffer) {
return nullptr;
}
uint8_t *basePtr = buffer->GetPointer(); uint8_t *basePtr = buffer->GetPointer();
if (!basePtr) return nullptr; if (!basePtr) {
return nullptr;
}
size_t offset = accOffset + byteOffset; size_t offset = accOffset + byteOffset;
if (buffer->EncodedRegion_Current != nullptr) { if (buffer->EncodedRegion_Current != nullptr) {
const size_t begin = buffer->EncodedRegion_Current->Offset; const size_t begin = buffer->EncodedRegion_Current->Offset;
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length; const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
if ((offset >= begin) && (offset < end)) if ((offset >= begin) && (offset < end)) {
return &buffer->EncodedRegion_Current->DecodedData[offset - begin]; return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
}
} }
return basePtr + offset; return basePtr + offset;
@ -877,18 +934,18 @@ inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
while (pIndices != indicesEnd) { while (pIndices != indicesEnd) {
size_t offset; size_t offset;
switch (indicesType) { switch (indicesType) {
case ComponentType_UNSIGNED_BYTE: case ComponentType_UNSIGNED_BYTE:
offset = *pIndices; offset = *pIndices;
break; break;
case ComponentType_UNSIGNED_SHORT: case ComponentType_UNSIGNED_SHORT:
offset = *reinterpret_cast<uint16_t *>(pIndices); offset = *reinterpret_cast<uint16_t *>(pIndices);
break; break;
case ComponentType_UNSIGNED_INT: case ComponentType_UNSIGNED_INT:
offset = *reinterpret_cast<uint32_t *>(pIndices); offset = *reinterpret_cast<uint32_t *>(pIndices);
break; break;
default: default:
// have fun with float and negative values from signed types as indices. // have fun with float and negative values from signed types as indices.
throw DeadlyImportError("Unsupported component type in index."); throw DeadlyImportError("Unsupported component type in index.");
} }
offset *= elementSize; offset *= elementSize;
@ -900,7 +957,6 @@ inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
} }
inline void Accessor::Read(Value &obj, Asset &r) { inline void Accessor::Read(Value &obj, Asset &r) {
if (Value *bufferViewVal = FindUInt(obj, "bufferView")) { if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
} }
@ -909,9 +965,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
{ {
const Value* countValue = FindUInt(obj, "count"); const Value* countValue = FindUInt(obj, "count");
if (!countValue || countValue->GetUint() < 1) if (!countValue)
{ {
throw DeadlyImportError("A strictly positive count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")"); throw DeadlyImportError("A count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
} }
count = countValue->GetUint(); count = countValue->GetUint();
} }
@ -1466,7 +1522,7 @@ inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, con
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
Value *curName = FindMember(pJSON_Object, "name"); Value *curName = FindMember(pJSON_Object, "name");
if (nullptr != curName) { if (nullptr != curName && curName->IsString()) {
name = curName->GetString(); name = curName->GetString();
} }
@ -1612,9 +1668,9 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
} }
} }
Value *extras = FindObject(pJSON_Object, "extras"); Value *curExtras = FindObject(pJSON_Object, "extras");
if (nullptr != extras) { if (nullptr != curExtras) {
if (Value *curTargetNames = FindArray(*extras, "targetNames")) { if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
this->targetNames.resize(curTargetNames->Size()); this->targetNames.resize(curTargetNames->Size());
for (unsigned int i = 0; i < curTargetNames->Size(); ++i) { for (unsigned int i = 0; i < curTargetNames->Size(); ++i) {
Value &targetNameValue = (*curTargetNames)[i]; Value &targetNameValue = (*curTargetNames)[i];
@ -1683,42 +1739,6 @@ inline void Light::Read(Value &obj, Asset & /*r*/) {
} }
} }
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
CustomExtension ret;
ret.name = name;
if (obj.IsObject()) {
ret.mValues.isPresent = true;
for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
auto &val = it->value;
ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
}
} else if (obj.IsArray()) {
ret.mValues.value.reserve(obj.Size());
ret.mValues.isPresent = true;
for (unsigned int i = 0; i < obj.Size(); ++i) {
ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
}
} else if (obj.IsNumber()) {
if (obj.IsUint64()) {
ret.mUint64Value.value = obj.GetUint64();
ret.mUint64Value.isPresent = true;
} else if (obj.IsInt64()) {
ret.mInt64Value.value = obj.GetInt64();
ret.mInt64Value.isPresent = true;
} else if (obj.IsDouble()) {
ret.mDoubleValue.value = obj.GetDouble();
ret.mDoubleValue.isPresent = true;
}
} else if (obj.IsString()) {
ReadValue(obj, ret.mStringValue);
ret.mStringValue.isPresent = true;
} else if (obj.IsBool()) {
ret.mBoolValue.value = obj.GetBool();
ret.mBoolValue.isPresent = true;
}
return ret;
}
inline void Node::Read(Value &obj, Asset &r) { inline void Node::Read(Value &obj, Asset &r) {
if (name.empty()) { if (name.empty()) {
name = id; name = id;
@ -1775,8 +1795,6 @@ inline void Node::Read(Value &obj, Asset &r) {
Value *curExtensions = FindObject(obj, "extensions"); Value *curExtensions = FindObject(obj, "extensions");
if (nullptr != curExtensions) { if (nullptr != curExtensions) {
this->extensions = ReadExtensions("extensions", *curExtensions);
if (r.extensionsUsed.KHR_lights_punctual) { if (r.extensionsUsed.KHR_lights_punctual) {
if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) { if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
Value *curLight = FindUInt(*ext, "light"); Value *curLight = FindUInt(*ext, "light");
@ -2132,7 +2150,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
#undef CHECK_EXT #undef CHECK_EXT
} }
inline IOStream *Asset::OpenFile(std::string path, const char *mode, bool /*absolute*/) { inline IOStream *Asset::OpenFile(const std::string& path, const char *mode, bool /*absolute*/) {
#ifdef ASSIMP_API #ifdef ASSIMP_API
return mIOSystem->Open(path, mode); return mIOSystem->Open(path, mode);
#else #else

View File

@ -88,15 +88,13 @@ namespace Assimp {
} // end of namespace Assimp } // end of namespace Assimp
glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene,
const ExportProperties* pProperties, bool isBinary) const ExportProperties* pProperties, bool isBinary)
: mFilename(filename) : mFilename(filename)
, mIOSystem(pIOSystem) , mIOSystem(pIOSystem)
, mScene(pScene)
, mProperties(pProperties) , mProperties(pProperties)
, mAsset(new Asset(pIOSystem))
{ {
mScene = pScene;
mAsset.reset( new Asset( pIOSystem ) );
// Always on as our triangulation process is aware of this type of encoding // Always on as our triangulation process is aware of this type of encoding
mAsset->extensionsUsed.FB_ngon_encoding = true; mAsset->extensionsUsed.FB_ngon_encoding = true;
@ -436,11 +434,11 @@ inline void SetSamplerWrap(SamplerWrap& wrap, aiTextureMapMode map)
}; };
} }
void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref<Texture> texture, aiTextureType tt, unsigned int slot) void glTF2Exporter::GetTexSampler(const aiMaterial& mat, Ref<Texture> texture, aiTextureType tt, unsigned int slot)
{ {
aiString aId; aiString aId;
std::string id; std::string id;
if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) { if (aiGetMaterialString(&mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) {
id = aId.C_Str(); id = aId.C_Str();
} }
@ -455,49 +453,52 @@ void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref<Texture> texture, a
SamplerMagFilter filterMag; SamplerMagFilter filterMag;
SamplerMinFilter filterMin; SamplerMinFilter filterMin;
if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) { if (aiGetMaterialInteger(&mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) {
SetSamplerWrap(texture->sampler->wrapS, mapU); SetSamplerWrap(texture->sampler->wrapS, mapU);
} }
if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) { if (aiGetMaterialInteger(&mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) {
SetSamplerWrap(texture->sampler->wrapT, mapV); SetSamplerWrap(texture->sampler->wrapT, mapV);
} }
if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) { if (aiGetMaterialInteger(&mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) {
texture->sampler->magFilter = filterMag; texture->sampler->magFilter = filterMag;
} }
if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) { if (aiGetMaterialInteger(&mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) {
texture->sampler->minFilter = filterMin; texture->sampler->minFilter = filterMin;
} }
aiString name; aiString name;
if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) { if (aiGetMaterialString(&mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) {
texture->sampler->name = name.C_Str(); texture->sampler->name = name.C_Str();
} }
} }
} }
void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot) void glTF2Exporter::GetMatTexProp(const aiMaterial& mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot)
{ {
std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName; std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName;
mat->Get(textureKey.c_str(), tt, slot, prop); mat.Get(textureKey.c_str(), tt, slot, prop);
} }
void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot) void glTF2Exporter::GetMatTexProp(const aiMaterial& mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot)
{ {
std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName; std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName;
mat->Get(textureKey.c_str(), tt, slot, prop); mat.Get(textureKey.c_str(), tt, slot, prop);
} }
void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTextureType tt, unsigned int slot = 0) void glTF2Exporter::GetMatTex(const aiMaterial& mat, Ref<Texture>& texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0)
{ {
if (mat->GetTextureCount(tt) > 0) { if (mat.GetTextureCount(tt) > 0) {
aiString tex; aiString tex;
if (mat->Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { // 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(); std::string path = tex.C_Str();
if (path.size() > 0) { if (path.size() > 0) {
@ -515,9 +516,8 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
std::string imgId = mAsset->FindUniqueID("", "image"); std::string imgId = mAsset->FindUniqueID("", "image");
texture->source = mAsset->images.Create(imgId); texture->source = mAsset->images.Create(imgId);
if (path[0] == '*') { // embedded const aiTexture* curTex = mScene->GetEmbeddedTexture(path.c_str());
aiTexture* curTex = mScene->mTextures[atoi(&path[1])]; if (curTex != nullptr) { // embedded
texture->source->name = curTex->mFilename.C_Str(); texture->source->name = curTex->mFilename.C_Str();
//basisu: embedded ktx2, bu //basisu: embedded ktx2, bu
@ -568,45 +568,45 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
} }
} }
void glTF2Exporter::GetMatTex(const aiMaterial* mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0) void glTF2Exporter::GetMatTex(const aiMaterial& mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
{ {
Ref<Texture>& texture = prop.texture; Ref<Texture>& texture = prop.texture;
GetMatTex(mat, texture, tt, slot); GetMatTex(mat, texture, prop.texCoord, tt, slot);
if (texture) { //if (texture) {
GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot); // GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
} //}
} }
void glTF2Exporter::GetMatTex(const aiMaterial* mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) void glTF2Exporter::GetMatTex(const aiMaterial& mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
{ {
Ref<Texture>& texture = prop.texture; Ref<Texture>& texture = prop.texture;
GetMatTex(mat, texture, tt, slot); GetMatTex(mat, texture, prop.texCoord, tt, slot);
if (texture) { if (texture) {
GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot); //GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
GetMatTexProp(mat, prop.scale, "scale", tt, slot); GetMatTexProp(mat, prop.scale, "scale", tt, slot);
} }
} }
void glTF2Exporter::GetMatTex(const aiMaterial* mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) void glTF2Exporter::GetMatTex(const aiMaterial& mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
{ {
Ref<Texture>& texture = prop.texture; Ref<Texture>& texture = prop.texture;
GetMatTex(mat, texture, tt, slot); GetMatTex(mat, texture, prop.texCoord, tt, slot);
if (texture) { if (texture) {
GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot); //GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
GetMatTexProp(mat, prop.strength, "strength", tt, slot); GetMatTexProp(mat, prop.strength, "strength", tt, slot);
} }
} }
aiReturn glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const char* propName, int type, int idx) aiReturn glTF2Exporter::GetMatColor(const aiMaterial& mat, vec4& prop, const char* propName, int type, int idx) const
{ {
aiColor4D col; aiColor4D col;
aiReturn result = mat->Get(propName, type, idx, col); aiReturn result = mat.Get(propName, type, idx, col);
if (result == AI_SUCCESS) { if (result == AI_SUCCESS) {
prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[3] = col.a; prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[3] = col.a;
@ -615,37 +615,116 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const cha
return result; return result;
} }
aiReturn glTF2Exporter::GetMatColor(const aiMaterial* mat, vec3& prop, const char* propName, int type, int idx) aiReturn glTF2Exporter::GetMatColor(const aiMaterial& mat, vec3& prop, const char* propName, int type, int idx) const
{ {
aiColor3D col; aiColor3D col;
aiReturn result = mat->Get(propName, type, idx, col); aiReturn result = mat.Get(propName, type, idx, col);
if (result == AI_SUCCESS) { if (result == AI_SUCCESS) {
prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[0] = col.r;
prop[1] = col.g;
prop[2] = col.b;
} }
return result; return result;
} }
bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) {
bool result = false;
// If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension
// NOTE: This extension is being considered for deprecation (Dec 2020), may be replaced by KHR_material_specular
if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) {
result = true;
} else {
// Don't have explicit glossiness, convert from pbr roughness or legacy shininess
float shininess;
if (mat.Get(AI_MATKEY_ROUGHNESS_FACTOR, shininess) == AI_SUCCESS) {
pbrSG.glossinessFactor = 1.0f - shininess; // Extension defines this way
} else if (mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
pbrSG.glossinessFactor = shininess / 1000;
}
}
if (GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_COLOR_SPECULAR) == AI_SUCCESS) {
result = true;
}
// Add any appropriate textures
GetMatTex(mat, pbrSG.specularGlossinessTexture, aiTextureType_SPECULAR);
result = result || pbrSG.specularGlossinessTexture.texture;
if (result) {
// Likely to always have diffuse
GetMatTex(mat, pbrSG.diffuseTexture, aiTextureType_DIFFUSE);
GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_COLOR_DIFFUSE);
}
return result;
}
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)
return false;
// Default Sheen color factor {0,0,0} disables Sheen, so do not export
if (sheen.sheenColorFactor == defaultSheenFactor)
return false;
mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor);
GetMatTex(mat, sheen.sheenColorTexture, AI_MATKEY_SHEEN_COLOR_TEXTURE);
GetMatTex(mat, sheen.sheenRoughnessTexture, AI_MATKEY_SHEEN_ROUGHNESS_TEXTURE);
return true;
}
bool glTF2Exporter::GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat) {
if (mat.Get(AI_MATKEY_CLEARCOAT_FACTOR, clearcoat.clearcoatFactor) != aiReturn_SUCCESS) {
return false;
}
// Clearcoat factor of zero disables Clearcoat, so do not export
if (clearcoat.clearcoatFactor == 0.0f)
return false;
mat.Get(AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR, clearcoat.clearcoatRoughnessFactor);
GetMatTex(mat, clearcoat.clearcoatTexture, AI_MATKEY_CLEARCOAT_TEXTURE);
GetMatTex(mat, clearcoat.clearcoatRoughnessTexture, AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE);
GetMatTex(mat, clearcoat.clearcoatNormalTexture, AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE);
return true;
}
bool glTF2Exporter::GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission) {
bool result = mat.Get(AI_MATKEY_TRANSMISSION_FACTOR, transmission.transmissionFactor) == aiReturn_SUCCESS;
GetMatTex(mat, transmission.transmissionTexture, AI_MATKEY_TRANSMISSION_TEXTURE);
return result || transmission.transmissionTexture.texture;
}
void glTF2Exporter::ExportMaterials() void glTF2Exporter::ExportMaterials()
{ {
aiString aiName; aiString aiName;
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
const aiMaterial* mat = mScene->mMaterials[i]; ai_assert(mScene->mMaterials[i] != nullptr);
const aiMaterial & mat = *(mScene->mMaterials[i]);
std::string id = "material_" + ai_to_string(i); std::string id = "material_" + ai_to_string(i);
Ref<Material> m = mAsset->materials.Create(id); Ref<Material> m = mAsset->materials.Create(id);
std::string name; std::string name;
if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) {
name = aiName.C_Str(); name = aiName.C_Str();
} }
name = mAsset->FindUniqueID(name, "material"); name = mAsset->FindUniqueID(name, "material");
m->name = name; m->name = name;
GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_BASE_COLOR);
if (!m->pbrMetallicRoughness.baseColorTexture.texture) { if (!m->pbrMetallicRoughness.baseColorTexture.texture) {
//if there wasn't a baseColorTexture defined in the source, fallback to any diffuse texture //if there wasn't a baseColorTexture defined in the source, fallback to any diffuse texture
@ -654,26 +733,26 @@ void glTF2Exporter::ExportMaterials()
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
if (GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR) != AI_SUCCESS) { if (GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_BASE_COLOR) != AI_SUCCESS) {
// if baseColorFactor wasn't defined, then the source is likely not a metallic roughness material. // if baseColorFactor wasn't defined, then the source is likely not a metallic roughness material.
//a fallback to any diffuse color should be used instead //a fallback to any diffuse color should be used instead
GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE); GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE);
} }
if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) { if (mat.Get(AI_MATKEY_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) {
//if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0 //if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
m->pbrMetallicRoughness.metallicFactor = 0; m->pbrMetallicRoughness.metallicFactor = 0;
} }
// get roughness if source is gltf2 file // get roughness if source is gltf2 file
if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor) != AI_SUCCESS) { if (mat.Get(AI_MATKEY_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor) != AI_SUCCESS) {
// otherwise, try to derive and convert from specular + shininess values // otherwise, try to derive and convert from specular + shininess values
aiColor4D specularColor; aiColor4D specularColor;
ai_real shininess; ai_real shininess;
if ( if (
mat->Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS &&
mat->Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS
) { ) {
// convert specular color to luminance // convert specular color to luminance
float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f; float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f;
@ -694,103 +773,60 @@ void glTF2Exporter::ExportMaterials()
GetMatTex(mat, m->emissiveTexture, aiTextureType_EMISSIVE); GetMatTex(mat, m->emissiveTexture, aiTextureType_EMISSIVE);
GetMatColor(mat, m->emissiveFactor, AI_MATKEY_COLOR_EMISSIVE); GetMatColor(mat, m->emissiveFactor, AI_MATKEY_COLOR_EMISSIVE);
mat->Get(AI_MATKEY_TWOSIDED, m->doubleSided); mat.Get(AI_MATKEY_TWOSIDED, m->doubleSided);
mat->Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff); mat.Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff);
float opacity;
aiString alphaMode; aiString alphaMode;
if (mat->Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) {
if (opacity < 1) {
m->alphaMode = "BLEND";
m->pbrMetallicRoughness.baseColorFactor[3] *= opacity;
}
}
if (mat.Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS) {
m->alphaMode = alphaMode.C_Str(); m->alphaMode = alphaMode.C_Str();
} else {
float opacity;
if (mat->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) {
if (opacity < 1) {
m->alphaMode = "BLEND";
m->pbrMetallicRoughness.baseColorFactor[3] *= opacity;
}
}
} }
bool hasPbrSpecularGlossiness = false; {
mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS, hasPbrSpecularGlossiness); // KHR_materials_pbrSpecularGlossiness extension
// NOTE: This extension is being considered for deprecation (Dec 2020)
if (hasPbrSpecularGlossiness) {
if (!mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
}
PbrSpecularGlossiness pbrSG; PbrSpecularGlossiness pbrSG;
if (GetMatSpecGloss(mat, pbrSG)) {
GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_COLOR_DIFFUSE); mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_COLOR_SPECULAR); m->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
if (mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) != AI_SUCCESS) {
float shininess;
if (mat->Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
pbrSG.glossinessFactor = shininess / 1000;
}
} }
GetMatTex(mat, pbrSG.diffuseTexture, aiTextureType_DIFFUSE);
GetMatTex(mat, pbrSG.specularGlossinessTexture, aiTextureType_SPECULAR);
m->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
} }
bool unlit; // glTFv2 is either PBR or Unlit
if (mat->Get(AI_MATKEY_GLTF_UNLIT, unlit) == AI_SUCCESS && unlit) { aiShadingMode shadingMode = aiShadingMode_PBR_BRDF;
mat.Get(AI_MATKEY_SHADING_MODEL, shadingMode);
if (shadingMode == aiShadingMode_Unlit) {
mAsset->extensionsUsed.KHR_materials_unlit = true; mAsset->extensionsUsed.KHR_materials_unlit = true;
m->unlit = true; m->unlit = true;
} } else {
// These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness
if (!m->pbrSpecularGlossiness.isPresent) {
// Sheen
MaterialSheen sheen;
if (GetMatSheen(mat, sheen)) {
mAsset->extensionsUsed.KHR_materials_sheen = true;
m->materialSheen = Nullable<MaterialSheen>(sheen);
}
bool hasMaterialSheen = false; MaterialClearcoat clearcoat;
mat->Get(AI_MATKEY_GLTF_MATERIAL_SHEEN, hasMaterialSheen); if (GetMatClearcoat(mat, clearcoat)) {
mAsset->extensionsUsed.KHR_materials_clearcoat = true;
m->materialClearcoat = Nullable<MaterialClearcoat>(clearcoat);
}
if (hasMaterialSheen) { MaterialTransmission transmission;
mAsset->extensionsUsed.KHR_materials_sheen = true; if (GetMatTransmission(mat, transmission)) {
mAsset->extensionsUsed.KHR_materials_transmission = true;
MaterialSheen sheen; m->materialTransmission = Nullable<MaterialTransmission>(transmission);
}
GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); }
mat->Get(AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor);
GetMatTex(mat, sheen.sheenColorTexture, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE);
GetMatTex(mat, sheen.sheenRoughnessTexture, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE);
m->materialSheen = Nullable<MaterialSheen>(sheen);
}
bool hasMaterialClearcoat = false;
mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT, hasMaterialClearcoat);
if (hasMaterialClearcoat) {
mAsset->extensionsUsed.KHR_materials_clearcoat= true;
MaterialClearcoat clearcoat;
mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR, clearcoat.clearcoatFactor);
mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR, clearcoat.clearcoatRoughnessFactor);
GetMatTex(mat, clearcoat.clearcoatTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE);
GetMatTex(mat, clearcoat.clearcoatRoughnessTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE);
GetMatTex(mat, clearcoat.clearcoatNormalTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE);
m->materialClearcoat = Nullable<MaterialClearcoat>(clearcoat);
}
bool hasMaterialTransmission = false;
mat->Get(AI_MATKEY_GLTF_MATERIAL_TRANSMISSION, hasMaterialTransmission);
if (hasMaterialTransmission) {
mAsset->extensionsUsed.KHR_materials_transmission = true;
MaterialTransmission transmission;
mat->Get(AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR, transmission.transmissionFactor);
GetMatTex(mat, transmission.transmissionTexture, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE);
m->materialTransmission = Nullable<MaterialTransmission>(transmission);
} }
} }
} }
@ -799,8 +835,7 @@ void glTF2Exporter::ExportMaterials()
* Search through node hierarchy and find the node containing the given meshID. * Search through node hierarchy and find the node containing the given meshID.
* Returns true on success, and false otherwise. * Returns true on success, and false otherwise.
*/ */
bool FindMeshNode(Ref<Node>& nodeIn, Ref<Node>& meshNode, std::string meshID) bool FindMeshNode(Ref<Node> &nodeIn, Ref<Node> &meshNode, const std::string &meshID) {
{
for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) { for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) {
if (meshID.compare(nodeIn->meshes[i]->id) == 0) { if (meshID.compare(nodeIn->meshes[i]->id) == 0) {
meshNode = nodeIn; meshNode = nodeIn;
@ -1301,8 +1336,11 @@ unsigned int glTF2Exporter::ExportNode(const aiNode* n, Ref<Node>& parent)
void glTF2Exporter::ExportScene() void glTF2Exporter::ExportScene()
{ {
const char* sceneName = "defaultScene"; // Use the name of the scene if specified
Ref<Scene> scene = mAsset->scenes.Create(sceneName); const std::string sceneName = (mScene->mName.length > 0) ? mScene->mName.C_Str() : "defaultScene";
// Ensure unique
Ref<Scene> scene = mAsset->scenes.Create(mAsset->FindUniqueID(sceneName, ""));
// root node will be the first one exported (idx 0) // root node will be the first one exported (idx 0)
if (mAsset->nodes.Size() > 0) { if (mAsset->nodes.Size() > 0) {

View File

@ -72,6 +72,10 @@ namespace glTF2
struct OcclusionTextureInfo; struct OcclusionTextureInfo;
struct Node; struct Node;
struct Texture; struct Texture;
struct PbrSpecularGlossiness;
struct MaterialSheen;
struct MaterialClearcoat;
struct MaterialTransmission;
// Vec/matrix types, as raw float arrays // Vec/matrix types, as raw float arrays
typedef float (vec2)[2]; typedef float (vec2)[2];
@ -97,15 +101,19 @@ namespace Assimp
protected: protected:
void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); void WriteBinaryData(IOStream* outfile, std::size_t sceneLength);
void GetTexSampler(const aiMaterial* mat, glTF2::Ref<glTF2::Texture> texture, aiTextureType tt, unsigned int slot); void GetTexSampler(const aiMaterial& mat, glTF2::Ref<glTF2::Texture> texture, aiTextureType tt, unsigned int slot);
void GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx); void GetMatTexProp(const aiMaterial& mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx);
void GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx); void GetMatTexProp(const aiMaterial& mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx);
void GetMatTex(const aiMaterial* mat, glTF2::Ref<glTF2::Texture>& texture, aiTextureType tt, unsigned int slot); void GetMatTex(const aiMaterial& mat, glTF2::Ref<glTF2::Texture>& texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot);
void GetMatTex(const aiMaterial* mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot); void GetMatTex(const aiMaterial& mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot);
void GetMatTex(const aiMaterial* mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot); void GetMatTex(const aiMaterial& mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot);
void GetMatTex(const aiMaterial* mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot); void GetMatTex(const aiMaterial& mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot);
aiReturn GetMatColor(const aiMaterial* mat, glTF2::vec4& prop, const char* propName, int type, int idx); aiReturn GetMatColor(const aiMaterial& mat, glTF2::vec4& prop, const char* propName, int type, int idx) const;
aiReturn GetMatColor(const aiMaterial* mat, glTF2::vec3& prop, const char* propName, int type, int idx); aiReturn GetMatColor(const aiMaterial& mat, glTF2::vec3& prop, const char* propName, int type, int idx) const;
bool GetMatSpecGloss(const aiMaterial& mat, glTF2::PbrSpecularGlossiness& pbrSG);
bool GetMatSheen(const aiMaterial& mat, glTF2::MaterialSheen& sheen);
bool GetMatClearcoat(const aiMaterial& mat, glTF2::MaterialClearcoat& clearcoat);
bool GetMatTransmission(const aiMaterial& mat, glTF2::MaterialTransmission& transmission);
void ExportMetadata(); void ExportMetadata();
void ExportMaterials(); void ExportMaterials();
void ExportMeshes(); void ExportMeshes();

View File

@ -165,7 +165,8 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
} }
mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot));
mat->AddProperty(&prop.texCoord, 1, AI_MATKEY_GLTF_TEXTURE_TEXCOORD(texType, texSlot)); const int uvIndex = static_cast<int>(prop.texCoord);
mat->AddProperty(&uvIndex, 1, AI_MATKEY_UVWSRC(texType, texSlot));
if (prop.textureTransformSupported) { if (prop.textureTransformSupported) {
aiUVTransform transform; aiUVTransform transform;
@ -208,6 +209,11 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
if (sampler->minFilter != SamplerMinFilter::UNSET) { if (sampler->minFilter != SamplerMinFilter::UNSET) {
mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot)); mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot));
} }
} else {
// Use glTFv2 default sampler
const aiTextureMapMode default_wrap = aiTextureMapMode_Wrap;
mat->AddProperty(&default_wrap, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
mat->AddProperty(&default_wrap, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
} }
} }
} }
@ -238,16 +244,18 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
aimat->AddProperty(&str, AI_MATKEY_NAME); aimat->AddProperty(&str, AI_MATKEY_NAME);
} }
// Set Assimp DIFFUSE and BASE COLOR to the pbrMetallicRoughness base color and texture for backwards compatibility
// Technically should not load any pbrMetallicRoughness if extensionsRequired contains KHR_materials_pbrSpecularGlossiness
SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_BASE_COLOR);
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE);
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_BASE_COLOR);
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_METALLIC_FACTOR);
aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_ROUGHNESS_FACTOR);
float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor;
roughnessAsShininess *= roughnessAsShininess * 1000; roughnessAsShininess *= roughnessAsShininess * 1000;
@ -259,6 +267,7 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE);
aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
aimat->AddProperty(&mat.pbrMetallicRoughness.baseColorFactor[3], 1, AI_MATKEY_OPACITY);
aiString alphaMode(mat.alphaMode); aiString alphaMode(mat.alphaMode);
aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
@ -268,52 +277,58 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
if (mat.pbrSpecularGlossiness.isPresent) { if (mat.pbrSpecularGlossiness.isPresent) {
PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS);
SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR);
float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f;
aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS);
aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLOSSINESS_FACTOR);
SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE);
SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR);
} }
// glTFv2 is either PBR or Unlit
aiShadingMode shadingMode = aiShadingMode_PBR_BRDF;
if (mat.unlit) { if (mat.unlit) {
aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); shadingMode = aiShadingMode_Unlit;
} }
//KHR_materials_sheen aimat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL);
// KHR_materials_sheen
if (mat.materialSheen.isPresent) { if (mat.materialSheen.isPresent) {
MaterialSheen &sheen = mat.materialSheen.value; MaterialSheen &sheen = mat.materialSheen.value;
// Default value {0,0,0} disables Sheen
aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN); if (sheen.sheenColorFactor != defaultSheenFactor) {
SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_SHEEN_COLOR_FACTOR);
aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR); aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_SHEEN_ROUGHNESS_FACTOR);
SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_SHEEN_COLOR_TEXTURE);
SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_SHEEN_ROUGHNESS_TEXTURE);
}
} }
//KHR_materials_clearcoat // KHR_materials_clearcoat
if (mat.materialClearcoat.isPresent) { if (mat.materialClearcoat.isPresent) {
MaterialClearcoat &clearcoat = mat.materialClearcoat.value; MaterialClearcoat &clearcoat = mat.materialClearcoat.value;
// Default value 0.0 disables clearcoat
aimat->AddProperty(&mat.materialClearcoat.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT); if (clearcoat.clearcoatFactor != 0.0f) {
aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR); aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_CLEARCOAT_FACTOR);
aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR); aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_CLEARCOAT_TEXTURE);
SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE);
SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_CLEARCOAT_NORMAL_TEXTURE);
}
} }
//KHR_materials_transmission // KHR_materials_transmission
if (mat.materialTransmission.isPresent) { if (mat.materialTransmission.isPresent) {
MaterialTransmission &transmission = mat.materialTransmission.value; MaterialTransmission &transmission = mat.materialTransmission.value;
aimat->AddProperty(&mat.materialTransmission.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION); aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_TRANSMISSION_FACTOR);
aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR); SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_TRANSMISSION_TEXTURE);
SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE);
} }
return aimat; return aimat;
@ -977,13 +992,21 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
metadata->Add(extension.name.c_str(), extension.mBoolValue.value); metadata->Add(extension.name.c_str(), extension.mBoolValue.value);
} else if (extension.mValues.isPresent) { } else if (extension.mValues.isPresent) {
aiMetadata val; aiMetadata val;
for (size_t i = 0; i < extension.mValues.value.size(); ++i) { for (auto const & subExtension : extension.mValues.value) {
ParseExtensions(&val, extension.mValues.value[i]); ParseExtensions(&val, subExtension);
} }
metadata->Add(extension.name.c_str(), val); metadata->Add(extension.name.c_str(), val);
} }
} }
void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) {
if (extension.mValues.isPresent) {
for (auto const & subExtension : extension.mValues.value) {
ParseExtensions(metadata, subExtension);
}
}
}
aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) { aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
Node &node = *ptr; Node &node = *ptr;
@ -1002,9 +1025,14 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
} }
} }
if (node.extensions) { if (node.customExtensions || node.extras) {
ainode->mMetaData = new aiMetadata; ainode->mMetaData = new aiMetadata;
ParseExtensions(ainode->mMetaData, node.extensions); if (node.customExtensions) {
ParseExtensions(ainode->mMetaData, node.customExtensions);
}
if (node.extras) {
ParseExtras(ainode->mMetaData, node.extras);
}
} }
GetNodeTransform(ainode->mTransformation, node); GetNodeTransform(ainode->mTransformation, node);
@ -1308,6 +1336,23 @@ std::unordered_map<unsigned int, AnimationSamplers> GatherSamplers(Animation &an
continue; continue;
} }
auto& animsampler = anim.samplers[channel.sampler];
if (!animsampler.input) {
ASSIMP_LOG_WARN("Animation ", anim.name, ": Missing sampler input. Skipping.");
continue;
}
if (!animsampler.output) {
ASSIMP_LOG_WARN("Animation ", anim.name, ": Missing sampler output. Skipping.");
continue;
}
if (animsampler.input->count > animsampler.output->count) {
ASSIMP_LOG_WARN("Animation ", anim.name, ": Number of keyframes in sampler input ", animsampler.input->count, " exceeds number of keyframes in sampler output ", animsampler.output->count);
continue;
}
const unsigned int node_index = channel.target.node.GetIndex(); const unsigned int node_index = channel.target.node.GetIndex();
AnimationSamplers &sampler = samplers[node_index]; AnimationSamplers &sampler = samplers[node_index];
@ -1442,10 +1487,11 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
} }
} }
if (numEmbeddedTexs == 0) if (numEmbeddedTexs == 0) {
return; return;
}
ASSIMP_LOG_DEBUG("Importing ", numEmbeddedTexs, " embedded textures"); ASSIMP_LOG_DEBUG("Importing ", numEmbeddedTexs, " embedded textures");
mScene->mTextures = new aiTexture *[numEmbeddedTexs]; mScene->mTextures = new aiTexture *[numEmbeddedTexs];
std::fill(mScene->mTextures, mScene->mTextures + numEmbeddedTexs, nullptr); std::fill(mScene->mTextures, mScene->mTextures + numEmbeddedTexs, nullptr);
@ -1498,7 +1544,8 @@ void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
const bool hasVersion = !a.asset.version.empty(); const bool hasVersion = !a.asset.version.empty();
const bool hasGenerator = !a.asset.generator.empty(); const bool hasGenerator = !a.asset.generator.empty();
const bool hasCopyright = !a.asset.copyright.empty(); const bool hasCopyright = !a.asset.copyright.empty();
if (hasVersion || hasGenerator || hasCopyright) { const bool hasSceneMetadata = a.scene->customExtensions;
if (hasVersion || hasGenerator || hasCopyright || hasSceneMetadata) {
mScene->mMetaData = new aiMetadata; mScene->mMetaData = new aiMetadata;
if (hasVersion) { if (hasVersion) {
mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version)); mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version));
@ -1509,6 +1556,9 @@ void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
if (hasCopyright) { if (hasCopyright) {
mScene->mMetaData->Add(AI_METADATA_SOURCE_COPYRIGHT, aiString(a.asset.copyright)); mScene->mMetaData->Add(AI_METADATA_SOURCE_COPYRIGHT, aiString(a.asset.copyright));
} }
if (hasSceneMetadata) {
ParseExtensions(mScene->mMetaData, a.scene->customExtensions);
}
} }
} }

View File

@ -822,7 +822,10 @@ ADD_ASSIMP_IMPORTER( GLTF
AssetLib/glTF2/glTF2Importer.h AssetLib/glTF2/glTF2Importer.h
) )
ADD_ASSIMP_IMPORTER( 3MF ADD_ASSIMP_IMPORTER(3MF
AssetLib/3MF/3MFTypes.h
AssetLib/3MF/XmlSerializer.h
AssetLib/3MF/XmlSerializer.cpp
AssetLib/3MF/D3MFImporter.h AssetLib/3MF/D3MFImporter.h
AssetLib/3MF/D3MFImporter.cpp AssetLib/3MF/D3MFImporter.cpp
AssetLib/3MF/D3MFOpcPackage.h AssetLib/3MF/D3MFOpcPackage.h
@ -875,6 +878,7 @@ ELSE()
../contrib/pugixml/src/pugiconfig.hpp ../contrib/pugixml/src/pugiconfig.hpp
../contrib/pugixml/src/pugixml.hpp ../contrib/pugixml/src/pugixml.hpp
) )
INCLUDE_DIRECTORIES("../contrib/pugixml/src")
SOURCE_GROUP( Contrib\\Pugixml FILES ${Pugixml_SRCS}) SOURCE_GROUP( Contrib\\Pugixml FILES ${Pugixml_SRCS})
ENDIF() ENDIF()
@ -1035,16 +1039,26 @@ IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(RapidJSON) hunter_add_package(RapidJSON)
find_package(RapidJSON CONFIG REQUIRED) find_package(RapidJSON CONFIG REQUIRED)
ELSE() ELSE()
INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) INCLUDE_DIRECTORIES("../contrib/rapidjson/include")
INCLUDE_DIRECTORIES( "../contrib" ) ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1)
INCLUDE_DIRECTORIES( "../contrib/pugixml/src" )
ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1 )
option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON ) option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON )
if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR) if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR)
ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS ) ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS )
endif() endif()
ENDIF() ENDIF()
# stb
IF(ASSIMP_HUNTER_ENABLED)
hunter_add_package(stb)
find_package(stb CONFIG REQUIRED)
ELSE()
SET( stb_SRCS
../contrib/stb/stb_image.h
)
INCLUDE_DIRECTORIES("../contrib")
SOURCE_GROUP( Contrib\\stb FILES ${stb_SRCS})
ENDIF()
# VC2010 fixes # VC2010 fixes
if(MSVC10) if(MSVC10)
option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
@ -1103,6 +1117,7 @@ SET( assimp_src
${open3dgc_SRCS} ${open3dgc_SRCS}
${ziplib_SRCS} ${ziplib_SRCS}
${Pugixml_SRCS} ${Pugixml_SRCS}
${stb_SRCS}
# Necessary to show the headers in the project when using the VC++ generator: # Necessary to show the headers in the project when using the VC++ generator:
${PUBLIC_HEADERS} ${PUBLIC_HEADERS}
@ -1160,6 +1175,7 @@ IF(ASSIMP_HUNTER_ENABLED)
utf8cpp utf8cpp
zip::zip zip::zip
pugixml pugixml
stb::stb
) )
if (ASSIMP_BUILD_DRACO) if (ASSIMP_BUILD_DRACO)

View File

@ -72,12 +72,25 @@ namespace Assimp {
// underlying structure for aiPropertyStore // underlying structure for aiPropertyStore
typedef BatchLoader::PropertyMap PropertyMap; typedef BatchLoader::PropertyMap PropertyMap;
#if defined(__has_warning)
#if __has_warning("-Wordered-compare-function-pointers")
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wordered-compare-function-pointers"
#endif
#endif
/** Stores the LogStream objects for all active C log streams */ /** Stores the LogStream objects for all active C log streams */
struct mpred { struct mpred {
bool operator()(const aiLogStream &s0, const aiLogStream &s1) const { bool operator()(const aiLogStream &s0, const aiLogStream &s1) const {
return s0.callback < s1.callback && s0.user < s1.user; return s0.callback < s1.callback && s0.user < s1.user;
} }
}; };
#if defined(__has_warning)
#if __has_warning("-Wordered-compare-function-pointers")
#pragma GCC diagnostic pop
#endif
#endif
typedef std::map<aiLogStream, Assimp::LogStream *, mpred> LogStreamMap; typedef std::map<aiLogStream, Assimp::LogStream *, mpred> LogStreamMap;
/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
@ -1251,3 +1264,36 @@ ASSIMP_API void aiQuaternionInterpolate(
ai_assert(nullptr != end); ai_assert(nullptr != end);
aiQuaternion::Interpolate(*dst, *start, *end, factor); aiQuaternion::Interpolate(*dst, *start, *end, factor);
} }
// stb_image is a lightweight image loader. It is shared by:
// - M3D import
// - PBRT export
// Since it's a header-only library, its implementation must be instantiated in some cpp file.
// Don't scatter this task over multiple importers/exporters. Maintain it in a central place (here!).
#define ASSIMP_HAS_PBRT_EXPORT (!ASSIMP_BUILD_NO_EXPORT && !ASSIMP_BUILD_NO_PBRT_EXPORTER)
#define ASSIMP_HAS_M3D ((!ASSIMP_BUILD_NO_EXPORT && !ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER)
#if ASSIMP_HAS_PBRT_EXPORT
# define ASSIMP_NEEDS_STB_IMAGE 1
#elif ASSIMP_HAS_M3D
# define ASSIMP_NEEDS_STB_IMAGE 1
# define STBI_ONLY_PNG
#endif
#if ASSIMP_NEEDS_STB_IMAGE
# if _MSC_VER // "unreferenced function has been removed" (SSE2 detection routine in x64 builds)
# pragma warning(push)
# pragma warning(disable: 4505)
# endif
# define STB_IMAGE_IMPLEMENTATION
# include "stb/stb_image.h"
# if _MSC_VER
# pragma warning(pop)
# endif
#endif

View File

@ -173,7 +173,7 @@ inline static std::string MakeAbsolutePath(const char *in) {
free(ret); free(ret);
} }
#endif #endif
if (!ret) { else {
// preserve the input path, maybe someone else is able to fix // preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter) // the path before it is accessed (e.g. our file system filter)
ASSIMP_LOG_WARN("Invalid path: ", std::string(in)); ASSIMP_LOG_WARN("Invalid path: ", std::string(in));

View File

@ -59,13 +59,16 @@ void CommentRemover::RemoveLineComments(const char* szComment,
ai_assert(nullptr != szBuffer); ai_assert(nullptr != szBuffer);
ai_assert(*szComment); ai_assert(*szComment);
const size_t len = strlen(szComment); size_t len = strlen(szComment);
const size_t lenBuffer = strlen(szBuffer);
if (len > lenBuffer) {
len = lenBuffer;
}
while (*szBuffer) { while (*szBuffer) {
// skip over quotes // skip over quotes
if (*szBuffer == '\"' || *szBuffer == '\'') if (*szBuffer == '\"' || *szBuffer == '\'')
while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\'');
if (!strncmp(szBuffer,szComment,len)) { if (!strncmp(szBuffer,szComment,len)) {
while (!IsLineEnd(*szBuffer)) while (!IsLineEnd(*szBuffer))
*szBuffer++ = chReplacement; *szBuffer++ = chReplacement;

View File

@ -406,11 +406,25 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<At
// Check whether this texture is an embedded texture. // Check whether this texture is an embedded texture.
// In this case the property looks like this: *<n>, // In this case the property looks like this: *<n>,
// where n is the index of the texture. // where n is the index of the texture.
aiString &s = *((aiString *)prop->mData); // Copy here because we overwrite the string data in-place and the buffer inside of aiString
// will be a lie if we just reinterpret from prop->mData. The size of mData is not guaranteed to be
// MAXLEN in size.
aiString s(*(aiString *)prop->mData);
if ('*' == s.data[0]) { if ('*' == s.data[0]) {
// Offset the index and write it back .. // Offset the index and write it back ..
const unsigned int idx = strtoul10(&s.data[1]) + offset[n]; const unsigned int idx = strtoul10(&s.data[1]) + offset[n];
ASSIMP_itoa10(&s.data[1], sizeof(s.data) - 1, idx); const unsigned int oldLen = s.length;
s.length = 1 + ASSIMP_itoa10(&s.data[1], sizeof(s.data) - 1, idx);
// The string changed in size so we need to reallocate the buffer for the property.
if (oldLen < s.length) {
prop->mDataLength += s.length - oldLen;
delete[] prop->mData;
prop->mData = new char[prop->mDataLength];
}
memcpy(prop->mData, static_cast<void*>(&s), prop->mDataLength);
} }
} }

View File

@ -89,6 +89,9 @@ void ScenePreprocessor::ProcessScene() {
ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'"); ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'");
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
if (nullptr == scene->mMeshes[i]) {
continue;
}
scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials; scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials;
} }

View File

@ -47,10 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/material.h> #include <assimp/material.h>
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
const char* TextureTypeToString(aiTextureType in) const char *TextureTypeToString(aiTextureType in) {
{ switch (in) {
switch (in)
{
case aiTextureType_NONE: case aiTextureType_NONE:
return "n/a"; return "n/a";
case aiTextureType_DIFFUSE: case aiTextureType_DIFFUSE:
@ -87,6 +85,12 @@ const char* TextureTypeToString(aiTextureType in)
return "DiffuseRoughness"; return "DiffuseRoughness";
case aiTextureType_AMBIENT_OCCLUSION: case aiTextureType_AMBIENT_OCCLUSION:
return "AmbientOcclusion"; return "AmbientOcclusion";
case aiTextureType_SHEEN:
return "Sheen";
case aiTextureType_CLEARCOAT:
return "Clearcoat";
case aiTextureType_TRANSMISSION:
return "Transmission";
case aiTextureType_UNKNOWN: case aiTextureType_UNKNOWN:
return "Unknown"; return "Unknown";
default: default:

View File

@ -555,17 +555,23 @@ uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void aiMaterial::CopyPropertyList(aiMaterial *pcDest, void aiMaterial::CopyPropertyList(aiMaterial *const pcDest,
const aiMaterial *pcSrc) { const aiMaterial *pcSrc) {
ai_assert(nullptr != pcDest); ai_assert(nullptr != pcDest);
ai_assert(nullptr != pcSrc); ai_assert(nullptr != pcSrc);
ai_assert(pcDest->mNumProperties <= pcDest->mNumAllocated);
ai_assert(pcSrc->mNumProperties <= pcSrc->mNumAllocated);
unsigned int iOldNum = pcDest->mNumProperties; const unsigned int iOldNum = pcDest->mNumProperties;
pcDest->mNumAllocated += pcSrc->mNumAllocated; pcDest->mNumAllocated += pcSrc->mNumAllocated;
pcDest->mNumProperties += pcSrc->mNumProperties; pcDest->mNumProperties += pcSrc->mNumProperties;
const unsigned int numAllocated = pcDest->mNumAllocated;
aiMaterialProperty **pcOld = pcDest->mProperties; aiMaterialProperty **pcOld = pcDest->mProperties;
pcDest->mProperties = new aiMaterialProperty *[pcDest->mNumAllocated]; pcDest->mProperties = new aiMaterialProperty *[numAllocated];
ai_assert(!iOldNum || pcOld);
ai_assert(iOldNum < numAllocated);
if (iOldNum && pcOld) { if (iOldNum && pcOld) {
for (unsigned int i = 0; i < iOldNum; ++i) { for (unsigned int i = 0; i < iOldNum; ++i) {

View File

@ -83,8 +83,7 @@ Other:
#include <sstream> #include <sstream>
#include <string> #include <string>
#define STB_IMAGE_IMPLEMENTATION #include "stb/stb_image.h"
#include "stb_image.h"
using namespace Assimp; using namespace Assimp;
@ -106,14 +105,13 @@ void ExportScenePbrt (
} // end of namespace Assimp } // end of namespace Assimp
// Constructor // Constructor
PbrtExporter::PbrtExporter ( PbrtExporter::PbrtExporter(
const aiScene* pScene, IOSystem* pIOSystem, const aiScene *pScene, IOSystem *pIOSystem,
const std::string path, const std::string file) const std::string &path, const std::string &file) :
: mScene(pScene), mScene(pScene),
mIOSystem(pIOSystem), mIOSystem(pIOSystem),
mPath(path), mPath(path),
mFile(file) mFile(file) {
{
// Export embedded textures. // Export embedded textures.
if (mScene->mNumTextures > 0) if (mScene->mNumTextures > 0)
if (!mIOSystem->CreateDirectory("textures")) if (!mIOSystem->CreateDirectory("textures"))
@ -210,12 +208,12 @@ void PbrtExporter::WriteMetaData() {
aiString* value = aiString* value =
static_cast<aiString*>(pMetaData->mValues[i].mData); static_cast<aiString*>(pMetaData->mValues[i].mData);
std::string svalue = value->C_Str(); std::string svalue = value->C_Str();
std::size_t found = svalue.find_first_of("\n"); std::size_t found = svalue.find_first_of('\n');
mOutput << "\n"; mOutput << "\n";
while (found != std::string::npos) { while (found != std::string::npos) {
mOutput << "# " << svalue.substr(0, found) << "\n"; mOutput << "# " << svalue.substr(0, found) << "\n";
svalue = svalue.substr(found + 1); svalue = svalue.substr(found + 1);
found = svalue.find_first_of("\n"); found = svalue.find_first_of('\n');
} }
mOutput << "# " << svalue << "\n"; mOutput << "# " << svalue << "\n";
break; break;
@ -596,8 +594,8 @@ void PbrtExporter::WriteMaterial(int m) {
} }
mOutput << "\n"; mOutput << "\n";
auto White = [](aiColor3D c) { return c.r == 1 && c.g == 1 && c.b == 1; }; auto White = [](const aiColor3D &c) { return c.r == 1 && c.g == 1 && c.b == 1; };
auto Black = [](aiColor3D c) { return c.r == 0 && c.g == 0 && c.b == 0; }; auto Black = [](const aiColor3D &c) { return c.r == 0 && c.g == 0 && c.b == 0; };
aiColor3D diffuse, specular, transparency; aiColor3D diffuse, specular, transparency;
bool constantDiffuse = (material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse) == AI_SUCCESS && bool constantDiffuse = (material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse) == AI_SUCCESS &&

View File

@ -74,8 +74,8 @@ class PbrtExporter
{ {
public: public:
/// Constructor for a specific scene to export /// Constructor for a specific scene to export
PbrtExporter(const aiScene* pScene, IOSystem* pIOSystem, PbrtExporter(const aiScene *pScene, IOSystem *pIOSystem,
const std::string path, const std::string file); const std::string &path, const std::string &file);
/// Destructor /// Destructor
virtual ~PbrtExporter(); virtual ~PbrtExporter();

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2021, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -41,6 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "EmbedTexturesProcess.h" #include "EmbedTexturesProcess.h"
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include "ProcessHelper.h" #include "ProcessHelper.h"
@ -48,11 +49,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
EmbedTexturesProcess::EmbedTexturesProcess() EmbedTexturesProcess::EmbedTexturesProcess() :
: BaseProcess() { BaseProcess() {
// empty
} }
EmbedTexturesProcess::~EmbedTexturesProcess() { EmbedTexturesProcess::~EmbedTexturesProcess() {
// empty
} }
bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const { bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
@ -62,15 +65,16 @@ bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
void EmbedTexturesProcess::SetupProperties(const Importer* pImp) { void EmbedTexturesProcess::SetupProperties(const Importer* pImp) {
mRootPath = pImp->GetPropertyString("sourceFilePath"); mRootPath = pImp->GetPropertyString("sourceFilePath");
mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u); mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u);
mIOHandler = pImp->GetIOHandler();
} }
void EmbedTexturesProcess::Execute(aiScene* pScene) { void EmbedTexturesProcess::Execute(aiScene* pScene) {
if (pScene == nullptr || pScene->mRootNode == nullptr) return; if (pScene == nullptr || pScene->mRootNode == nullptr || mIOHandler == nullptr){
return;
}
aiString path; aiString path;
uint32_t embeddedTexturesCount = 0u; uint32_t embeddedTexturesCount = 0u;
for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) { for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) {
auto material = pScene->mMaterials[matId]; auto material = pScene->mMaterials[matId];
@ -96,32 +100,36 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
ASSIMP_LOG_INFO("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." ); ASSIMP_LOG_INFO("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." );
} }
bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const { bool EmbedTexturesProcess::addTexture(aiScene *pScene, const std::string &path) const {
std::streampos imageSize = 0; std::streampos imageSize = 0;
std::string imagePath = path; std::string imagePath = path;
// Test path directly // Test path directly
std::ifstream file(imagePath, std::ios::binary | std::ios::ate); if (!mIOHandler->Exists(imagePath)) {
if ((imageSize = file.tellg()) == std::streampos(-1)) {
ASSIMP_LOG_WARN("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder."); ASSIMP_LOG_WARN("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder.");
// Test path in root path // Test path in root path
imagePath = mRootPath + path; imagePath = mRootPath + path;
file.open(imagePath, std::ios::binary | std::ios::ate); if (!mIOHandler->Exists(imagePath)) {
if ((imageSize = file.tellg()) == std::streampos(-1)) {
// Test path basename in root path // Test path basename in root path
imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u); imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
file.open(imagePath, std::ios::binary | std::ios::ate); if (!mIOHandler->Exists(imagePath)) {
if ((imageSize = file.tellg()) == std::streampos(-1)) {
ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, "."); ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, ".");
return false; return false;
} }
} }
} }
IOStream* pFile = mIOHandler->Open(imagePath);
if (pFile == nullptr) {
ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, ".");
return false;
}
imageSize = pFile->FileSize();
aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)]; aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)];
file.seekg(0, std::ios::beg); pFile->Seek(0, aiOrigin_SET);
file.read(reinterpret_cast<char*>(imageContent), imageSize); pFile->Read(reinterpret_cast<char*>(imageContent), imageSize, 1);
mIOHandler->Close(pFile);
// Enlarging the textures table // Enlarging the textures table
unsigned int textureId = pScene->mNumTextures++; unsigned int textureId = pScene->mNumTextures++;

View File

@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct aiNode; struct aiNode;
class IOSystem;
namespace Assimp { namespace Assimp {
/** /**
@ -76,10 +78,11 @@ public:
private: private:
// Resolve the path and add the file content to the scene as a texture. // Resolve the path and add the file content to the scene as a texture.
bool addTexture(aiScene* pScene, std::string path) const; bool addTexture(aiScene *pScene, const std::string &path) const;
private: private:
std::string mRootPath; std::string mRootPath;
IOSystem* mIOHandler = nullptr;
}; };
} // namespace Assimp } // namespace Assimp

View File

@ -170,7 +170,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &n
++it; ++it;
} }
if (join_master && !join.empty()) { if (join_master && !join.empty()) {
join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++); join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%u", count_merged++);
unsigned int out_meshes = 0; unsigned int out_meshes = 0;
for (std::list<aiNode *>::const_iterator it = join.cbegin(); it != join.cend(); ++it) { for (std::list<aiNode *>::const_iterator it = join.cbegin(); it != join.cend(); ++it) {

View File

@ -481,7 +481,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
pScene->mMeshes[i]->mNumBones = 0; pScene->mMeshes[i]->mNumBones = 0;
} }
} else { } else {
apcOutMeshes.reserve(pScene->mNumMaterials << 1u); apcOutMeshes.reserve(static_cast<size_t>(pScene->mNumMaterials) << 1u);
std::list<unsigned int> aiVFormats; std::list<unsigned int> aiVFormats;
std::vector<unsigned int> s(pScene->mNumMeshes, 0); std::vector<unsigned int> s(pScene->mNumMeshes, 0);

View File

@ -127,7 +127,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) {
unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 }; unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 };
std::vector<aiMesh *> outMeshes; std::vector<aiMesh *> outMeshes;
outMeshes.reserve(pScene->mNumMeshes << 1u); outMeshes.reserve(static_cast<size_t>(pScene->mNumMeshes) << 1u);
bool bAnyChanges = false; bool bAnyChanges = false;

View File

@ -1 +0,0 @@
2.3.0

View File

@ -1,31 +0,0 @@
cache: ccache
language: cpp
matrix:
include:
- os: linux
dist: xenial
compiler: clang
- os: linux
dist: xenial
compiler: gcc
- os: osx
compiler: clang
addons:
apt:
packages:
- cmake
script:
# Output version info for compilers, cmake, and make
- ${CC} -v
- ${CXX} -v
- cmake --version
- make --version
# Clone googletest
- pushd .. && git clone https://github.com/google/googletest.git && popd
# Configure and build
- mkdir _travis_build && cd _travis_build
- cmake -G "Unix Makefiles" -DENABLE_TESTS=ON ..
- make -j10
- ./draco_tests

View File

@ -804,7 +804,7 @@ else()
draco_points_enc) draco_points_enc)
# Library targets that consume the object collections. # Library targets that consume the object collections.
if(MSVC OR WIN32) if(MSVC)
# In order to produce a DLL and import library the Windows tools require # In order to produce a DLL and import library the Windows tools require
# that the exported symbols are part of the DLL target. The unfortunate side # that the exported symbols are part of the DLL target. The unfortunate side
# effect of this is that a single configuration cannot output both the # effect of this is that a single configuration cannot output both the
@ -889,9 +889,6 @@ else()
# For Mac, we need to build a .bundle for the unity plugin. # For Mac, we need to build a .bundle for the unity plugin.
if(APPLE) if(APPLE)
set_target_properties(dracodec_unity PROPERTIES BUNDLE true) set_target_properties(dracodec_unity PROPERTIES BUNDLE true)
elseif(NOT unity_decoder_lib_type STREQUAL STATIC)
set_target_properties(dracodec_unity
PROPERTIES SOVERSION ${DRACO_SOVERSION})
endif() endif()
endif() endif()
@ -916,9 +913,6 @@ else()
# For Mac, we need to build a .bundle for the plugin. # For Mac, we need to build a .bundle for the plugin.
if(APPLE) if(APPLE)
set_target_properties(draco_maya_wrapper PROPERTIES BUNDLE true) set_target_properties(draco_maya_wrapper PROPERTIES BUNDLE true)
else()
set_target_properties(draco_maya_wrapper
PROPERTIES SOVERSION ${DRACO_SOVERSION})
endif() endif()
endif() endif()

View File

@ -2,16 +2,16 @@
<img width="350px" src="docs/artwork/draco3d-vert.svg" /> <img width="350px" src="docs/artwork/draco3d-vert.svg" />
</p> </p>
![Build Status: master](https://travis-ci.org/google/draco.svg?branch=master) [![Build Status](https://github.com/google/draco/workflows/Build/badge.svg)](https://github.com/google/draco/actions?query=workflow%3ABuild)
News News
======= =======
### Version 1.4.1 release ### Version 1.4.1 release
* Using the versioned gstatic.com WASM and Javascript decoders is now * Using the versioned www.gstatic.com WASM and Javascript decoders is now
recommended. To use v1.4.1, use this URL: recommended. To use v1.4.1, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.4.1/* * https://www.gstatic.com/draco/versioned/decoders/1.4.1/*
* Replace the * with the files to load. E.g. * Replace the * with the files to load. E.g.
* https://gstatic.com/draco/versioned/decoders/1.4.1/draco_decoder.js * https://www.gstatic.com/draco/versioned/decoders/1.4.1/draco_decoder.js
* This works with the v1.3.6 and v1.4.0 releases, and will work with future * This works with the v1.3.6 and v1.4.0 releases, and will work with future
Draco releases. Draco releases.
* Bug fixes * Bug fixes

View File

@ -6,7 +6,7 @@ set(DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_ 1)
# Utility for controlling the main draco library dependency. This changes in # Utility for controlling the main draco library dependency. This changes in
# shared builds, and when an optional target requires a shared library build. # shared builds, and when an optional target requires a shared library build.
macro(set_draco_target) macro(set_draco_target)
if(MSVC OR WIN32) if(MSVC)
set(draco_dependency draco) set(draco_dependency draco)
set(draco_plugin_dependency ${draco_dependency}) set(draco_plugin_dependency ${draco_dependency})
else() else()
@ -63,6 +63,11 @@ macro(draco_set_build_definitions)
if(BUILD_SHARED_LIBS) if(BUILD_SHARED_LIBS)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
endif() endif()
else()
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
# Ensure 64-bit platforms can support large files.
list(APPEND draco_defines "_LARGEFILE_SOURCE" "_FILE_OFFSET_BITS=64")
endif()
endif() endif()
if(ANDROID) if(ANDROID)
@ -114,4 +119,6 @@ macro(draco_set_build_definitions)
draco_check_emscripten_environment() draco_check_emscripten_environment()
draco_get_required_emscripten_flags(FLAG_LIST_VAR draco_base_cxx_flags) draco_get_required_emscripten_flags(FLAG_LIST_VAR draco_base_cxx_flags)
endif() endif()
draco_configure_sanitizer()
endmacro() endmacro()

View File

@ -1,63 +0,0 @@
if(DRACO_CMAKE_DRACO_FEATURES_CMAKE_)
return()
endif()
set(DRACO_CMAKE_DRACO_FEATURES_CMAKE_ 1)
set(draco_features_file_name "${draco_build_dir}/draco/draco_features.h")
set(draco_features_list)
# Macro that handles tracking of Draco preprocessor symbols for the purpose of
# producing draco_features.h.
#
# draco_enable_feature(FEATURE <feature_name> [TARGETS <target_name>]) FEATURE
# is required. It should be a Draco preprocessor symbol. TARGETS is optional. It
# can be one or more draco targets.
#
# When the TARGETS argument is not present the preproc symbol is added to
# draco_features.h. When it is draco_features.h is unchanged, and
# target_compile_options() is called for each target specified.
macro(draco_enable_feature)
set(def_flags)
set(def_single_arg_opts FEATURE)
set(def_multi_arg_opts TARGETS)
cmake_parse_arguments(DEF "${def_flags}" "${def_single_arg_opts}"
"${def_multi_arg_opts}" ${ARGN})
if("${DEF_FEATURE}" STREQUAL "")
message(FATAL_ERROR "Empty FEATURE passed to draco_enable_feature().")
endif()
# Do nothing/return early if $DEF_FEATURE is already in the list.
list(FIND draco_features_list ${DEF_FEATURE} df_index)
if(NOT df_index EQUAL -1)
return()
endif()
list(LENGTH DEF_TARGETS df_targets_list_length)
if(${df_targets_list_length} EQUAL 0)
list(APPEND draco_features_list ${DEF_FEATURE})
else()
foreach(target ${DEF_TARGETS})
target_compile_definitions(${target} PRIVATE ${DEF_FEATURE})
endforeach()
endif()
endmacro()
# Function for generating draco_features.h.
function(draco_generate_features_h)
file(WRITE "${draco_features_file_name}.new"
"// GENERATED FILE -- DO NOT EDIT\n\n" "#ifndef DRACO_FEATURES_H_\n"
"#define DRACO_FEATURES_H_\n\n")
foreach(feature ${draco_features_list})
file(APPEND "${draco_features_file_name}.new" "#define ${feature}\n")
endforeach()
file(APPEND "${draco_features_file_name}.new"
"\n#endif // DRACO_FEATURES_H_")
# Will replace ${draco_features_file_name} only if the file content has
# changed. This prevents forced Draco rebuilds after CMake runs.
configure_file("${draco_features_file_name}.new"
"${draco_features_file_name}")
file(REMOVE "${draco_features_file_name}.new")
endfunction()

View File

@ -80,6 +80,12 @@ macro(draco_test_cxx_flag)
# Run the actual compile test. # Run the actual compile test.
unset(draco_all_cxx_flags_pass CACHE) unset(draco_all_cxx_flags_pass CACHE)
message("--- Running combined CXX flags test, flags: ${all_cxx_flags}") message("--- Running combined CXX flags test, flags: ${all_cxx_flags}")
# check_cxx_compiler_flag() requires that the flags are a string. When flags
# are passed as a list it will remove the list separators, and attempt to run
# a compile command using list entries concatenated together as a single
# argument. Avoid the problem by forcing the argument to be a string.
draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags)
check_cxx_compiler_flag("${all_cxx_flags}" draco_all_cxx_flags_pass) check_cxx_compiler_flag("${all_cxx_flags}" draco_all_cxx_flags_pass)
if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass) if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass)
@ -194,6 +200,9 @@ macro(draco_test_exe_linker_flag)
else() else()
unset(CMAKE_EXE_LINKER_FLAGS) unset(CMAKE_EXE_LINKER_FLAGS)
endif() endif()
list(APPEND DRACO_EXE_LINKER_FLAGS ${${link_FLAG_LIST_VAR_NAME}})
list(REMOVE_DUPLICATES DRACO_EXE_LINKER_FLAGS)
endmacro() endmacro()
# Runs the draco compiler tests. This macro builds up the list of list var(s) # Runs the draco compiler tests. This macro builds up the list of list var(s)

View File

@ -55,7 +55,7 @@ macro(draco_setup_install_target)
install(TARGETS draco_encoder DESTINATION install(TARGETS draco_encoder DESTINATION
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}") "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
if(WIN32) if(MSVC)
install(TARGETS draco DESTINATION install(TARGETS draco DESTINATION
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
else() else()

View File

@ -5,28 +5,28 @@ set(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_ 1)
# Handles the details of enabling sanitizers. # Handles the details of enabling sanitizers.
macro(draco_configure_sanitizer) macro(draco_configure_sanitizer)
if(DRACO_SANITIZE AND NOT MSVC) if(DRACO_SANITIZE AND NOT EMSCRIPTEN AND NOT MSVC)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(DRACO_SANITIZE MATCHES "cfi") if(DRACO_SANITIZE MATCHES "cfi")
list(APPEND DRACO_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi") list(APPEND SAN_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi")
list(APPEND DRACO_EXE_LINKER_FLAGS "-flto" "-fno-sanitize-trap=cfi" list(APPEND SAN_LINKER_FLAGS "-flto" "-fno-sanitize-trap=cfi"
"-fuse-ld=gold") "-fuse-ld=gold")
endif() endif()
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4 if(${CMAKE_SIZEOF_VOID_P} EQUAL 4
AND DRACO_SANITIZE MATCHES "integer|undefined") AND DRACO_SANITIZE MATCHES "integer|undefined")
list(APPEND DRACO_EXE_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s") list(APPEND SAN_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s")
endif() endif()
endif() endif()
list(APPEND DRACO_CXX_FLAGS "-fsanitize=${DRACO_SANITIZE}") list(APPEND SAN_CXX_FLAGS "-fsanitize=${DRACO_SANITIZE}")
list(APPEND DRACO_EXE_LINKER_FLAGS "-fsanitize=${DRACO_SANITIZE}") list(APPEND SAN_LINKER_FLAGS "-fsanitize=${DRACO_SANITIZE}")
# Make sanitizer callstacks accurate. # Make sanitizer callstacks accurate.
list(APPEND DRACO_CXX_FLAGS "-fno-omit-frame-pointer" list(APPEND SAN_CXX_FLAGS "-fno-omit-frame-pointer")
"-fno-optimize-sibling-calls") list(APPEND SAN_CXX_FLAGS "-fno-optimize-sibling-calls")
draco_test_cxx_flag(FLAG_LIST_VAR_NAMES DRACO_CXX_FLAGS FLAG_REQUIRED) draco_test_cxx_flag(FLAG_LIST_VAR_NAMES SAN_CXX_FLAGS FLAG_REQUIRED)
draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME DRACO_EXE_LINKER_FLAGS) draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME SAN_LINKER_FLAGS)
endif() endif()
endmacro() endmacro()

View File

@ -87,6 +87,7 @@ macro(draco_add_executable)
endif() endif()
add_executable(${exe_NAME} ${exe_SOURCES}) add_executable(${exe_NAME} ${exe_SOURCES})
set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
if(exe_OUTPUT_NAME) if(exe_OUTPUT_NAME)
set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME}) set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
@ -109,10 +110,11 @@ macro(draco_add_executable)
if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS) if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS)
if(${CMAKE_VERSION} VERSION_LESS "3.13") if(${CMAKE_VERSION} VERSION_LESS "3.13")
set(link_flags ${exe_LINK_FLAGS} ${DRACO_EXE_LINKER_FLAGS}) list(APPEND exe_LINK_FLAGS "${DRACO_EXE_LINKER_FLAGS}")
# LINK_FLAGS is managed as a string.
draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
set_target_properties(${exe_NAME} set_target_properties(${exe_NAME}
PROPERTIES LINK_FLAGS ${exe_LINK_FLAGS} PROPERTIES LINK_FLAGS "${exe_LINK_FLAGS}")
${DRACO_EXE_LINKER_FLAGS})
else() else()
target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS} target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
${DRACO_EXE_LINKER_FLAGS}) ${DRACO_EXE_LINKER_FLAGS})
@ -130,7 +132,7 @@ macro(draco_add_executable)
endif() endif()
if(BUILD_SHARED_LIBS AND (MSVC OR WIN32)) if(BUILD_SHARED_LIBS AND (MSVC OR WIN32))
target_compile_definitions(${lib_NAME} PRIVATE "DRACO_BUILDING_DLL=0") target_compile_definitions(${exe_NAME} PRIVATE "DRACO_BUILDING_DLL=0")
endif() endif()
if(exe_LIB_DEPS) if(exe_LIB_DEPS)
@ -163,8 +165,8 @@ endmacro()
# cmake-format: off # cmake-format: off
# - OUTPUT_NAME: Override output file basename. Target basename defaults to # - OUTPUT_NAME: Override output file basename. Target basename defaults to
# NAME. OUTPUT_NAME is ignored when BUILD_SHARED_LIBS is enabled and CMake # NAME. OUTPUT_NAME is ignored when BUILD_SHARED_LIBS is enabled and CMake
# is generating a build for which MSVC or WIN32 are true. This is to avoid # is generating a build for which MSVC is true. This is to avoid output
# output basename collisions with DLL import libraries. # basename collisions with DLL import libraries.
# - TEST: Flag. Presence means treat library as a test. # - TEST: Flag. Presence means treat library as a test.
# - DEFINES: List of preprocessor macro definitions. # - DEFINES: List of preprocessor macro definitions.
# - INCLUDES: list of include directories for the target. # - INCLUDES: list of include directories for the target.
@ -259,7 +261,7 @@ macro(draco_add_library)
endif() endif()
if(lib_OUTPUT_NAME) if(lib_OUTPUT_NAME)
if(NOT (BUILD_SHARED_LIBS AND (MSVC OR WIN32))) if(NOT (BUILD_SHARED_LIBS AND MSVC))
set_target_properties(${lib_NAME} set_target_properties(${lib_NAME}
PROPERTIES OUTPUT_NAME ${lib_OUTPUT_NAME}) PROPERTIES OUTPUT_NAME ${lib_OUTPUT_NAME})
endif() endif()
@ -318,8 +320,12 @@ macro(draco_add_library)
set_target_properties(${lib_NAME} PROPERTIES PREFIX "") set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
endif() endif()
if(lib_TYPE STREQUAL SHARED AND NOT MSVC) # VERSION and SOVERSION as necessary
set_target_properties(${lib_NAME} PROPERTIES SOVERSION ${DRACO_SOVERSION}) if(NOT lib_TYPE STREQUAL STATIC AND NOT lib_TYPE STREQUAL MODULE)
set_target_properties(${lib_NAME} PROPERTIES VERSION ${DRACO_VERSION})
if(NOT MSVC)
set_target_properties(${lib_NAME} PROPERTIES SOVERSION ${DRACO_SOVERSION})
endif()
endif() endif()
if(BUILD_SHARED_LIBS AND (MSVC OR WIN32)) if(BUILD_SHARED_LIBS AND (MSVC OR WIN32))

View File

@ -17,31 +17,31 @@
namespace draco { namespace draco {
void DracoTimer::Start() { void DracoTimer::Start() {
#ifdef _WIN32 #ifdef _WIN32
QueryPerformanceCounter(&tv_start); QueryPerformanceCounter(&tv_start_);
#else #else
gettimeofday(&tv_start, nullptr); gettimeofday(&tv_start_, nullptr);
#endif #endif
} }
void DracoTimer::Stop() { void DracoTimer::Stop() {
#ifdef _WIN32 #ifdef _WIN32
QueryPerformanceCounter(&tv_end); QueryPerformanceCounter(&tv_end_);
#else #else
gettimeofday(&tv_end, nullptr); gettimeofday(&tv_end_, nullptr);
#endif #endif
} }
int64_t DracoTimer::GetInMs() { int64_t DracoTimer::GetInMs() {
#ifdef _WIN32 #ifdef _WIN32
LARGE_INTEGER elapsed = {0}; LARGE_INTEGER elapsed = {0};
elapsed.QuadPart = tv_end.QuadPart - tv_start.QuadPart; elapsed.QuadPart = tv_end_.QuadPart - tv_start_.QuadPart;
LARGE_INTEGER frequency = {0}; LARGE_INTEGER frequency = {0};
QueryPerformanceFrequency(&frequency); QueryPerformanceFrequency(&frequency);
return elapsed.QuadPart * 1000 / frequency.QuadPart; return elapsed.QuadPart * 1000 / frequency.QuadPart;
#else #else
const int64_t seconds = (tv_end.tv_sec - tv_start.tv_sec) * 1000; const int64_t seconds = (tv_end_.tv_sec - tv_start_.tv_sec) * 1000;
const int64_t milliseconds = (tv_end.tv_usec - tv_start.tv_usec) / 1000; const int64_t milliseconds = (tv_end_.tv_usec - tv_start_.tv_usec) / 1000;
return seconds + milliseconds; return seconds + milliseconds;
#endif #endif
} }

View File

@ -20,9 +20,10 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
typedef LARGE_INTEGER timeval; typedef LARGE_INTEGER DracoTimeVal;
#else #else
#include <sys/time.h> #include <sys/time.h>
typedef timeval DracoTimeVal;
#endif #endif
#include <cinttypes> #include <cinttypes>
@ -39,8 +40,8 @@ class DracoTimer {
int64_t GetInMs(); int64_t GetInMs();
private: private:
timeval tv_start; DracoTimeVal tv_start_;
timeval tv_end; DracoTimeVal tv_end_;
}; };
typedef DracoTimer CycleTimer; typedef DracoTimer CycleTimer;

View File

@ -18,6 +18,7 @@
#include <cctype> #include <cctype>
#include <cmath> #include <cmath>
#include <iterator> #include <iterator>
#include <limits>
namespace draco { namespace draco {
namespace parser { namespace parser {
@ -252,7 +253,7 @@ DecoderBuffer ParseLineIntoDecoderBuffer(DecoderBuffer *buffer) {
std::string ToLower(const std::string &str) { std::string ToLower(const std::string &str) {
std::string out; std::string out;
std::transform(str.begin(), str.end(), std::back_inserter(out), [](unsigned char c){return tolower(c);}); std::transform(str.begin(), str.end(), std::back_inserter(out), tolower);
return out; return out;
} }

View File

@ -268,14 +268,14 @@ std::vector<std::string> PlyReader::SplitWords(const std::string &line) {
while ((end = line.find_first_of(" \t\n\v\f\r", start)) != while ((end = line.find_first_of(" \t\n\v\f\r", start)) !=
std::string::npos) { std::string::npos) {
const std::string word(line.substr(start, end - start)); const std::string word(line.substr(start, end - start));
if (!std::all_of(word.begin(), word.end(), [](unsigned char c){return isspace(c);})) { if (!std::all_of(word.begin(), word.end(), isspace)) {
output.push_back(word); output.push_back(word);
} }
start = end + 1; start = end + 1;
} }
const std::string last_word(line.substr(start)); const std::string last_word(line.substr(start));
if (!std::all_of(last_word.begin(), last_word.end(), [](unsigned char c){return isspace(c);})) { if (!std::all_of(last_word.begin(), last_word.end(), isspace)) {
output.push_back(last_word); output.push_back(last_word);
} }
return output; return output;

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