Merge branch 'master' into kimkulling-diable_m3m_issue-4126
commit
0beacc3854
|
@ -42,6 +42,7 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
|
|||
* [.NET](https://bitbucket.org/Starnick/assimpnet/src/master/)
|
||||
* [Pascal](port/AssimpPascal/Readme.md)
|
||||
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
|
||||
* [Javascript/Node.js Interface](https://github.com/kovacsv/assimpjs)
|
||||
* [Unity 3d Plugin](https://ricardoreis.net/trilib-2/)
|
||||
* [Unreal Engine Plugin](https://github.com/irajsb/UE4_Assimp/)
|
||||
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
|
||||
|
|
|
@ -330,6 +330,7 @@ void Discreet3DSExporter::WriteMaterials() {
|
|||
case aiShadingMode_Blinn:
|
||||
case aiShadingMode_CookTorrance:
|
||||
case aiShadingMode_Fresnel:
|
||||
case aiShadingMode_PBR_BRDF: // Possibly should be Discreet3DS::Metal in some cases but this is undocumented
|
||||
shading_mode_out = Discreet3DS::Phong;
|
||||
break;
|
||||
|
||||
|
@ -356,7 +357,10 @@ void Discreet3DSExporter::WriteMaterials() {
|
|||
writer.PutI2(1);
|
||||
}
|
||||
|
||||
WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
|
||||
// Fallback to BASE_COLOR if no DIFFUSE
|
||||
if (!WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE))
|
||||
WriteTexture(mat, aiTextureType_BASE_COLOR, Discreet3DS::CHUNK_MAT_TEXTURE);
|
||||
|
||||
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
|
||||
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
|
||||
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
|
||||
|
@ -367,20 +371,21 @@ void Discreet3DSExporter::WriteMaterials() {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
|
||||
// returns true if the texture existed
|
||||
bool Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
|
||||
aiString path;
|
||||
aiTextureMapMode map_mode[2] = {
|
||||
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
||||
};
|
||||
ai_real blend = 1.0;
|
||||
if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: handle embedded textures properly
|
||||
if (path.data[0] == '*') {
|
||||
ASSIMP_LOG_ERROR("Ignoring embedded texture for export: ", path.C_Str());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkWriter chunk(writer, chunk_flags);
|
||||
|
@ -402,6 +407,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type
|
|||
writer.PutU2(val);
|
||||
}
|
||||
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -73,7 +73,7 @@ public:
|
|||
private:
|
||||
void WriteMeshes();
|
||||
void WriteMaterials();
|
||||
void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
|
||||
bool WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
|
||||
void WriteFaceMaterialChunk(const aiMesh& mesh);
|
||||
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
|
||||
void WriteString(const std::string& s);
|
||||
|
|
|
@ -76,6 +76,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <rapidjson/rapidjson.h>
|
||||
#include <rapidjson/schema.h>
|
||||
|
||||
#if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0)
|
||||
# pragma GCC diagnostic pop
|
||||
|
@ -1092,6 +1093,7 @@ class Asset {
|
|||
|
||||
private:
|
||||
IOSystem *mIOSystem;
|
||||
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
|
||||
|
||||
std::string mCurrentAssetDir;
|
||||
|
||||
|
@ -1153,8 +1155,9 @@ public:
|
|||
Ref<Scene> scene;
|
||||
|
||||
public:
|
||||
Asset(IOSystem *io = nullptr) :
|
||||
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
|
||||
mIOSystem(io),
|
||||
mSchemaDocumentProvider(schemaDocumentProvider),
|
||||
asset(),
|
||||
accessors(*this, "accessors"),
|
||||
animations(*this, "animations"),
|
||||
|
@ -1177,6 +1180,9 @@ public:
|
|||
//! Main function
|
||||
void Load(const std::string &file, bool isBinary = false);
|
||||
|
||||
//! Parse the AssetMetadata and check that the version is 2.
|
||||
bool CanRead(const std::string &pFile, bool isBinary = false);
|
||||
|
||||
//! Enables binary encoding on the asset
|
||||
void SetAsBinary();
|
||||
|
||||
|
@ -1188,6 +1194,11 @@ public:
|
|||
private:
|
||||
void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
|
||||
|
||||
//! Obtain a JSON document from the stream.
|
||||
// \param second argument is a buffer used by the document. It must be kept
|
||||
// alive while the document is in use.
|
||||
Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
|
||||
|
||||
void ReadExtensionsUsed(Document &doc);
|
||||
void ReadExtensionsRequired(Document &doc);
|
||||
|
||||
|
|
|
@ -90,7 +90,6 @@ namespace {
|
|||
//
|
||||
// JSON Value reading helpers
|
||||
//
|
||||
|
||||
inline CustomExtension ReadExtensions(const char *name, Value &obj) {
|
||||
CustomExtension ret;
|
||||
ret.name = name;
|
||||
|
@ -127,6 +126,81 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
inline void CopyData(size_t count, const uint8_t *src, size_t src_stride,
|
||||
uint8_t *dst, size_t dst_stride) {
|
||||
if (src_stride == dst_stride) {
|
||||
memcpy(dst, src, count * src_stride);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t sz = std::min(src_stride, dst_stride);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
memcpy(dst, src, sz);
|
||||
if (sz < dst_stride) {
|
||||
memset(dst + sz, 0, dst_stride - sz);
|
||||
}
|
||||
src += src_stride;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void SetVector(vec4 &v, const float (&in)[4]) {
|
||||
v[0] = in[0];
|
||||
v[1] = in[1];
|
||||
v[2] = in[2];
|
||||
v[3] = in[3];
|
||||
}
|
||||
|
||||
void SetVector(vec3 &v, const float (&in)[3]) {
|
||||
v[0] = in[0];
|
||||
v[1] = in[1];
|
||||
v[2] = in[2];
|
||||
}
|
||||
|
||||
template <int N>
|
||||
inline int Compare(const char *attr, const char (&str)[N]) {
|
||||
return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
|
||||
}
|
||||
|
||||
#if _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4706)
|
||||
#endif // _MSC_VER
|
||||
|
||||
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
|
||||
if ((pos = Compare(attr, "POSITION"))) {
|
||||
v = &(p.attributes.position);
|
||||
} else if ((pos = Compare(attr, "NORMAL"))) {
|
||||
v = &(p.attributes.normal);
|
||||
} else if ((pos = Compare(attr, "TANGENT"))) {
|
||||
v = &(p.attributes.tangent);
|
||||
} else if ((pos = Compare(attr, "TEXCOORD"))) {
|
||||
v = &(p.attributes.texcoord);
|
||||
} else if ((pos = Compare(attr, "COLOR"))) {
|
||||
v = &(p.attributes.color);
|
||||
} else if ((pos = Compare(attr, "JOINT"))) {
|
||||
v = &(p.attributes.joint);
|
||||
} else if ((pos = Compare(attr, "JOINTMATRIX"))) {
|
||||
v = &(p.attributes.jointmatrix);
|
||||
} else if ((pos = Compare(attr, "WEIGHT"))) {
|
||||
v = &(p.attributes.weight);
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
|
||||
if ((pos = Compare(attr, "POSITION"))) {
|
||||
v = &(p.targets[targetIndex].position);
|
||||
} else if ((pos = Compare(attr, "NORMAL"))) {
|
||||
v = &(p.targets[targetIndex].normal);
|
||||
} else if ((pos = Compare(attr, "TANGENT"))) {
|
||||
v = &(p.targets[targetIndex].tangent);
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
inline Value *Object::FindString(Value &val, const char *memberId) {
|
||||
|
@ -456,7 +530,6 @@ Ref<T> LazyDict<T>::Create(const char *id) {
|
|||
//
|
||||
// glTF dictionary objects methods
|
||||
//
|
||||
|
||||
inline Buffer::Buffer() :
|
||||
byteLength(0),
|
||||
type(Type_arraybuffer),
|
||||
|
@ -865,27 +938,6 @@ inline size_t Accessor::GetMaxByteSize() {
|
|||
return (bufferView ? bufferView->byteLength : sparse->data.size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
inline void CopyData(size_t count,
|
||||
const uint8_t *src, size_t src_stride,
|
||||
uint8_t *dst, size_t dst_stride) {
|
||||
if (src_stride == dst_stride) {
|
||||
memcpy(dst, src, count * src_stride);
|
||||
} else {
|
||||
size_t sz = std::min(src_stride, dst_stride);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
memcpy(dst, src, sz);
|
||||
if (sz < dst_stride) {
|
||||
memset(dst + sz, 0, dst_stride - sz);
|
||||
}
|
||||
src += src_stride;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <class T>
|
||||
void Accessor::ExtractData(T *&outData) {
|
||||
uint8_t *data = GetPointer();
|
||||
|
@ -959,11 +1011,12 @@ inline void Accessor::WriteSparseIndices(size_t _count, const void *src_idx, siz
|
|||
ai_assert(indices_dst + _count * indices_dst_stride <= indices_buffer_ptr + sparse->indices->buffer->byteLength);
|
||||
CopyData(_count, indices_src, src_idxStride, indices_dst, indices_dst_stride);
|
||||
}
|
||||
|
||||
inline Accessor::Indexer::Indexer(Accessor &acc) :
|
||||
accessor(acc),
|
||||
data(acc.GetPointer()),
|
||||
elemSize(acc.GetElementSize()),
|
||||
stride(acc.GetStride()) {
|
||||
accessor(acc),
|
||||
data(acc.GetPointer()),
|
||||
elemSize(acc.GetElementSize()),
|
||||
stride(acc.GetStride()) {
|
||||
}
|
||||
|
||||
//! Accesses the i-th value as defined by the accessor
|
||||
|
@ -1241,21 +1294,6 @@ inline void Material::Read(Value &material, Asset &r) {
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void SetVector(vec4 &v, const float (&in)[4]) {
|
||||
v[0] = in[0];
|
||||
v[1] = in[1];
|
||||
v[2] = in[2];
|
||||
v[3] = in[3];
|
||||
}
|
||||
|
||||
void SetVector(vec3 &v, const float (&in)[3]) {
|
||||
v[0] = in[0];
|
||||
v[1] = in[1];
|
||||
v[2] = in[2];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
inline void Material::SetDefaults() {
|
||||
//pbr materials
|
||||
SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
|
||||
|
@ -1294,53 +1332,6 @@ inline void MaterialIOR::SetDefaults() {
|
|||
ior = 1.5f;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <int N>
|
||||
inline int Compare(const char *attr, const char (&str)[N]) {
|
||||
return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
|
||||
}
|
||||
|
||||
#if _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4706)
|
||||
#endif // _MSC_VER
|
||||
|
||||
inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) {
|
||||
if ((pos = Compare(attr, "POSITION"))) {
|
||||
v = &(p.attributes.position);
|
||||
} else if ((pos = Compare(attr, "NORMAL"))) {
|
||||
v = &(p.attributes.normal);
|
||||
} else if ((pos = Compare(attr, "TANGENT"))) {
|
||||
v = &(p.attributes.tangent);
|
||||
} else if ((pos = Compare(attr, "TEXCOORD"))) {
|
||||
v = &(p.attributes.texcoord);
|
||||
} else if ((pos = Compare(attr, "COLOR"))) {
|
||||
v = &(p.attributes.color);
|
||||
} else if ((pos = Compare(attr, "JOINT"))) {
|
||||
v = &(p.attributes.joint);
|
||||
} else if ((pos = Compare(attr, "JOINTMATRIX"))) {
|
||||
v = &(p.attributes.jointmatrix);
|
||||
} else if ((pos = Compare(attr, "WEIGHT"))) {
|
||||
v = &(p.attributes.weight);
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetAttribTargetVector(Mesh::Primitive &p, const int targetIndex, const char *attr, Mesh::AccessorList *&v, int &pos) {
|
||||
if ((pos = Compare(attr, "POSITION"))) {
|
||||
v = &(p.targets[targetIndex].position);
|
||||
} else if ((pos = Compare(attr, "NORMAL"))) {
|
||||
v = &(p.targets[targetIndex].normal);
|
||||
} else if ((pos = Compare(attr, "TANGENT"))) {
|
||||
v = &(p.targets[targetIndex].tangent);
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
|
||||
Value *curName = FindMember(pJSON_Object, "name");
|
||||
if (nullptr != curName && curName->IsString()) {
|
||||
|
@ -1811,28 +1802,15 @@ inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneDa
|
|||
}
|
||||
}
|
||||
|
||||
inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
||||
inline rapidjson::Document Asset::ReadDocument(IOStream &stream, bool isBinary, std::vector<char> &sceneData) {
|
||||
ASSIMP_LOG_DEBUG("Loading GLTF2 asset");
|
||||
mCurrentAssetDir.clear();
|
||||
/*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
|
||||
if (pos != int(std::string::npos)) */
|
||||
|
||||
if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
|
||||
mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
|
||||
}
|
||||
|
||||
shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
|
||||
if (!stream) {
|
||||
throw DeadlyImportError("GLTF: Could not open file for reading");
|
||||
}
|
||||
|
||||
// is binary? then read the header
|
||||
std::vector<char> sceneData;
|
||||
if (isBinary) {
|
||||
SetAsBinary(); // also creates the body buffer
|
||||
ReadBinaryHeader(*stream, sceneData);
|
||||
ReadBinaryHeader(stream, sceneData);
|
||||
} else {
|
||||
mSceneLength = stream->FileSize();
|
||||
mSceneLength = stream.FileSize();
|
||||
mBodyLength = 0;
|
||||
|
||||
// Binary format only supports up to 4GB of JSON, use that as a maximum
|
||||
|
@ -1844,7 +1822,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
|||
sceneData.resize(mSceneLength + 1);
|
||||
sceneData[mSceneLength] = '\0';
|
||||
|
||||
if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
|
||||
if (stream.Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
|
||||
throw DeadlyImportError("GLTF: Could not read the file contents");
|
||||
}
|
||||
}
|
||||
|
@ -1869,6 +1847,40 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
|||
throw DeadlyImportError("GLTF: JSON document root must be a JSON object");
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
inline void Asset::Load(const std::string &pFile, bool isBinary)
|
||||
{
|
||||
mCurrentAssetDir.clear();
|
||||
if (0 != strncmp(pFile.c_str(), AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) {
|
||||
mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile);
|
||||
}
|
||||
|
||||
shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
|
||||
if (!stream) {
|
||||
throw DeadlyImportError("GLTF: Could not open file for reading");
|
||||
}
|
||||
|
||||
std::vector<char> sceneData;
|
||||
rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
|
||||
|
||||
// If a schemaDocumentProvider is available, see if the glTF schema is present.
|
||||
// If so, use it to validate the document.
|
||||
if (mSchemaDocumentProvider) {
|
||||
if (const rapidjson::SchemaDocument *gltfSchema = mSchemaDocumentProvider->GetRemoteDocument("glTF.schema.json", 16)) {
|
||||
// The schemas are found here: https://github.com/KhronosGroup/glTF/tree/main/specification/2.0/schema
|
||||
rapidjson::SchemaValidator validator(*gltfSchema);
|
||||
if (!doc.Accept(validator)) {
|
||||
rapidjson::StringBuffer pathBuffer;
|
||||
validator.GetInvalidSchemaPointer().StringifyUriFragment(pathBuffer);
|
||||
rapidjson::StringBuffer argumentBuffer;
|
||||
validator.GetInvalidDocumentPointer().StringifyUriFragment(argumentBuffer);
|
||||
throw DeadlyImportError("GLTF: The JSON document did not satisfy the glTF2 schema. Schema keyword: ", validator.GetInvalidSchemaKeyword(), ", document path: ", pathBuffer.GetString(), ", argument: ", argumentBuffer.GetString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the buffer instance for the current file embedded contents
|
||||
if (mBodyLength > 0) {
|
||||
if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) {
|
||||
|
@ -1925,6 +1937,21 @@ inline void Asset::Load(const std::string &pFile, bool isBinary) {
|
|||
}
|
||||
}
|
||||
|
||||
inline bool Asset::CanRead(const std::string &pFile, bool isBinary) {
|
||||
try {
|
||||
shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
|
||||
if (!stream) {
|
||||
return false;
|
||||
}
|
||||
std::vector<char> sceneData;
|
||||
rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
|
||||
asset.Read(doc);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void Asset::SetAsBinary() {
|
||||
if (!mBodyBuffer) {
|
||||
mBodyBuffer = buffers.Create("binary_glTF");
|
||||
|
@ -2025,7 +2052,7 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi
|
|||
}
|
||||
|
||||
#if _MSC_VER
|
||||
#pragma warning(pop)
|
||||
# pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
} // namespace glTF2
|
||||
|
|
|
@ -111,19 +111,16 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
|
|||
return &desc;
|
||||
}
|
||||
|
||||
bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig ) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
|
||||
if (extension != "gltf" && extension != "glb") {
|
||||
return false;
|
||||
}
|
||||
if (!checkSig && (extension != "gltf") && (extension != "glb"))
|
||||
return false;
|
||||
|
||||
if (pIOHandler) {
|
||||
glTF2::Asset asset(pIOHandler);
|
||||
asset.Load(pFile, extension == "glb");
|
||||
std::string version = asset.asset.version;
|
||||
return !version.empty() && version[0] == '2';
|
||||
}
|
||||
if (pIOHandler) {
|
||||
glTF2::Asset asset(pIOHandler);
|
||||
return asset.CanRead(pFile, extension == "glb");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1604,7 +1601,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
|||
this->mScene = pScene;
|
||||
|
||||
// read the asset file
|
||||
glTF2::Asset asset(pIOHandler);
|
||||
glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider*>(mSchemaDocumentProvider));
|
||||
asset.Load(pFile, GetExtension(pFile) == "glb");
|
||||
if (asset.scene) {
|
||||
pScene->mName = asset.scene->name;
|
||||
|
@ -1630,4 +1627,8 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
|||
}
|
||||
}
|
||||
|
||||
void glTF2Importer::SetupProperties(const Importer *pImp) {
|
||||
mSchemaDocumentProvider = static_cast<rapidjson::IRemoteSchemaDocumentProvider*>(pImp->GetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER));
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
protected:
|
||||
const aiImporterDesc *GetInfo() const override;
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||
virtual void SetupProperties(const Importer *pImp) override;
|
||||
|
||||
private:
|
||||
void ImportEmbeddedTextures(glTF2::Asset &a);
|
||||
|
@ -80,6 +81,9 @@ private:
|
|||
std::vector<unsigned int> meshOffsets;
|
||||
std::vector<int> embeddedTexIdxs;
|
||||
aiScene *mScene;
|
||||
|
||||
/// An instance of rapidjson::IRemoteSchemaDocumentProvider
|
||||
void *mSchemaDocumentProvider = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
|
|
@ -1072,6 +1072,18 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
|
|||
return existing;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool Importer::SetPropertyPointer(const char* szName, void* value) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
bool existing;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
existing = SetGenericProperty<void*>(pimpl->mPointerProperties, szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(bool);
|
||||
return existing;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
|
||||
|
@ -1104,6 +1116,14 @@ aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& i
|
|||
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
void* Importer::GetPropertyPointer(const char* szName, void* iErrorReturn /*= nullptr*/) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return GetGenericProperty<void*>(pimpl->mPointerProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the memory requirements of a single node
|
||||
inline
|
||||
|
|
|
@ -73,12 +73,12 @@ public:
|
|||
// Data type to store the key hash
|
||||
typedef unsigned int KeyType;
|
||||
|
||||
// typedefs for our four configuration maps.
|
||||
// We don't need more, so there is no need for a generic solution
|
||||
// typedefs for our configuration maps.
|
||||
typedef std::map<KeyType, int> IntPropertyMap;
|
||||
typedef std::map<KeyType, ai_real> FloatPropertyMap;
|
||||
typedef std::map<KeyType, std::string> StringPropertyMap;
|
||||
typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
|
||||
typedef std::map<KeyType, void*> PointerPropertyMap;
|
||||
|
||||
/** IO handler to use for all file accesses. */
|
||||
IOSystem* mIOHandler;
|
||||
|
@ -116,6 +116,9 @@ public:
|
|||
/** List of Matrix properties */
|
||||
MatrixPropertyMap mMatrixProperties;
|
||||
|
||||
/** List of pointer properties */
|
||||
PointerPropertyMap mPointerProperties;
|
||||
|
||||
/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
|
||||
* to be executed before and after every single post-process step */
|
||||
bool bExtraVerbose;
|
||||
|
@ -142,6 +145,7 @@ ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT :
|
|||
mFloatProperties(),
|
||||
mStringProperties(),
|
||||
mMatrixProperties(),
|
||||
mPointerProperties(),
|
||||
bExtraVerbose( false ),
|
||||
mPPShared( nullptr ) {
|
||||
// empty
|
||||
|
|
|
@ -4,7 +4,6 @@ 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,
|
||||
|
@ -40,20 +39,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file RemoveComments.cpp
|
||||
/**
|
||||
* @file RemoveComments.cpp
|
||||
* @brief Defines the CommentRemover utility class
|
||||
*/
|
||||
|
||||
#include <assimp/RemoveComments.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Remove line comments from a file
|
||||
void CommentRemover::RemoveLineComments(const char* szComment,
|
||||
char* szBuffer, char chReplacement /* = ' ' */)
|
||||
{
|
||||
void CommentRemover::RemoveLineComments(const char* szComment, char* szBuffer, char chReplacement /* = ' ' */) {
|
||||
// validate parameters
|
||||
ai_assert(nullptr != szComment);
|
||||
ai_assert(nullptr != szBuffer);
|
||||
|
@ -65,36 +63,28 @@ void CommentRemover::RemoveLineComments(const char* szComment,
|
|||
len = lenBuffer;
|
||||
}
|
||||
|
||||
char *szCurrent = szBuffer;
|
||||
while (*szCurrent) {
|
||||
|
||||
for(size_t i = 0; i < lenBuffer; i++) {
|
||||
// skip over quotes
|
||||
if (*szCurrent == '\"' || *szCurrent == '\'')
|
||||
while (*szCurrent++ && *szCurrent != '\"' && *szCurrent != '\'');
|
||||
if (szBuffer[i] == '\"' || szBuffer[i] == '\'')
|
||||
while (++i < lenBuffer && szBuffer[i] != '\"' && szBuffer[i] != '\'');
|
||||
|
||||
size_t lenRemaining = lenBuffer - (szCurrent - szBuffer);
|
||||
if(lenRemaining < len) {
|
||||
if(lenBuffer - i < len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strncmp(szCurrent,szComment,len)) {
|
||||
while (!IsLineEnd(*szCurrent))
|
||||
*szCurrent++ = chReplacement;
|
||||
|
||||
if (!*szCurrent) {
|
||||
break;
|
||||
if (!strncmp(szBuffer + i,szComment,len)) {
|
||||
while (i < lenBuffer && !IsLineEnd(szBuffer[i])) {
|
||||
szBuffer[i++] = chReplacement;
|
||||
}
|
||||
}
|
||||
++szCurrent;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Remove multi-line comments from a file
|
||||
void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
|
||||
const char* szCommentEnd,char* szBuffer,
|
||||
char chReplacement)
|
||||
{
|
||||
const char* szCommentEnd,char* szBuffer,
|
||||
char chReplacement) {
|
||||
// validate parameters
|
||||
ai_assert(nullptr != szCommentStart);
|
||||
ai_assert(nullptr != szCommentEnd);
|
||||
|
@ -107,18 +97,20 @@ void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
|
|||
|
||||
while (*szBuffer) {
|
||||
// skip over quotes
|
||||
if (*szBuffer == '\"' || *szBuffer == '\'')
|
||||
if (*szBuffer == '\"' || *szBuffer == '\'') {
|
||||
while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\'');
|
||||
}
|
||||
|
||||
if (!strncmp(szBuffer,szCommentStart,len2)) {
|
||||
while (*szBuffer) {
|
||||
if (!::strncmp(szBuffer,szCommentEnd,len)) {
|
||||
for (unsigned int i = 0; i < len;++i)
|
||||
for (unsigned int i = 0; i < len;++i) {
|
||||
*szBuffer++ = chReplacement;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
*szBuffer++ = chReplacement;
|
||||
*szBuffer++ = chReplacement;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -245,6 +245,12 @@ public:
|
|||
*/
|
||||
bool SetPropertyMatrix(const char *szName, const aiMatrix4x4 &sValue);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Set a pointer configuration property.
|
||||
* @see SetPropertyInteger()
|
||||
*/
|
||||
bool SetPropertyPointer(const char *szName, void *sValue);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get a configuration property.
|
||||
* @param szName Name of the property. All supported properties
|
||||
|
@ -297,6 +303,15 @@ public:
|
|||
aiMatrix4x4 GetPropertyMatrix(const char *szName,
|
||||
const aiMatrix4x4 &sErrorReturn = aiMatrix4x4()) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get a pointer configuration property
|
||||
*
|
||||
* The return value remains valid until the property is modified.
|
||||
* @see GetPropertyInteger()
|
||||
*/
|
||||
void* GetPropertyPointer(const char *szName,
|
||||
void *sErrorReturn = nullptr) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Supplies a custom IO handler to the importer to use to open and
|
||||
* access files. If you need the importer to use custom IO logic to
|
||||
|
|
|
@ -547,6 +547,15 @@ enum aiComponent
|
|||
// Various stuff to fine-tune the behaviour of specific importer plugins.
|
||||
// ###########################################################################
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Importers which parse JSON may use this to obtain a pointer to a
|
||||
* rapidjson::IRemoteSchemaDocumentProvider.
|
||||
*
|
||||
* The default value is nullptr
|
||||
* Property type: void*
|
||||
*/
|
||||
#define AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER \
|
||||
"IMPORT_SCHEMA_DOCUMENT_PROVIDER"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Set whether the fbx importer will merge all geometry layers present
|
||||
|
|
|
@ -224,6 +224,19 @@ else()
|
|||
target_sources(unit PUBLIC ${Assimp_SOURCE_DIR}/contrib/gtest/src/gtest-all.cc)
|
||||
endif()
|
||||
|
||||
# RapidJSON
|
||||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
hunter_add_package(RapidJSON)
|
||||
find_package(RapidJSON CONFIG REQUIRED)
|
||||
ELSE()
|
||||
INCLUDE_DIRECTORIES("../contrib/rapidjson/include")
|
||||
ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1)
|
||||
option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON )
|
||||
if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR)
|
||||
ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS )
|
||||
endif()
|
||||
ENDIF()
|
||||
|
||||
IF (ASSIMP_BUILD_DRACO)
|
||||
ADD_DEFINITIONS( -DASSIMP_ENABLE_DRACO )
|
||||
ENDIF()
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,181 @@
|
|||
{
|
||||
"asset": {
|
||||
"generator": "COLLADA2GLTF",
|
||||
"version": "2.0"
|
||||
},
|
||||
"scene": "hello",
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 0,
|
||||
"mode": 4,
|
||||
"material": 0
|
||||
}
|
||||
],
|
||||
"name": "Mesh"
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 36,
|
||||
"max": [
|
||||
23
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.0
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 288,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min": [
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
6.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"type": "VEC2"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
},
|
||||
"name": "Texture"
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "CesiumLogoFlat.png"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9986,
|
||||
"wrapS": 33648,
|
||||
"wrapT": 33071
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 768,
|
||||
"byteLength": 72,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 576,
|
||||
"byteStride": 12,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 576,
|
||||
"byteLength": 192,
|
||||
"byteStride": 8,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 840,
|
||||
"uri": "BoxTextured0.bin"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/LogStream.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <rapidjson/schema.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
|
@ -772,3 +773,60 @@ TEST_F(utglTF2ImportExport, wrongTypes) {
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// This class provides a fake schema to the GLTF importer.
|
||||
/// It just checks that the file has a top-level "scene" property which is an integer.
|
||||
class FakeSchemaProvider : public rapidjson::IRemoteSchemaDocumentProvider
|
||||
{
|
||||
public:
|
||||
FakeSchemaProvider(const char* schemaName) :
|
||||
m_schemaName(schemaName)
|
||||
{
|
||||
rapidjson::Document schemaDoc;
|
||||
schemaDoc.Parse(R"==({"properties":{"scene" : { "type" : "integer" }}, "required": [ "scene" ]})==");
|
||||
EXPECT_FALSE(schemaDoc.HasParseError());
|
||||
m_schema.reset(new rapidjson::SchemaDocument(schemaDoc, m_schemaName.c_str(), static_cast<rapidjson::SizeType>(m_schemaName.size()), this));
|
||||
}
|
||||
|
||||
const rapidjson::SchemaDocument* GetRemoteDocument(const char* uri, rapidjson::SizeType) override {
|
||||
if (m_schemaName == uri) {
|
||||
return m_schema.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_schemaName;
|
||||
std::unique_ptr<const rapidjson::SchemaDocument> m_schema;
|
||||
};
|
||||
}
|
||||
|
||||
TEST_F(utglTF2ImportExport, schemaCheckPass) {
|
||||
FakeSchemaProvider schemaProvider("glTF.schema.json");
|
||||
Assimp::Importer importer;
|
||||
importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider);
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(scene, nullptr);
|
||||
EXPECT_STREQ(importer.GetErrorString(), "");
|
||||
}
|
||||
|
||||
TEST_F(utglTF2ImportExport, schemaCheckFail) {
|
||||
FakeSchemaProvider schemaProvider("glTF.schema.json");
|
||||
Assimp::Importer importer;
|
||||
importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider);
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/SchemaFailures/sceneWrongType.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_EQ(scene, nullptr);
|
||||
const std::string errorString = importer.GetErrorString();
|
||||
EXPECT_NE(errorString.find("The JSON document did not satisfy the glTF2 schema"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(utglTF2ImportExport, noSchemaFound) {
|
||||
// More than one importer might make use the provider, but not all schemas might be present.
|
||||
// Check that the glTF importer handles the case when an non-null provider returns null when asked for schemas.
|
||||
FakeSchemaProvider schemaProvider("missingSchema.json");
|
||||
Assimp::Importer importer;
|
||||
importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider);
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(scene, nullptr);
|
||||
EXPECT_STREQ(importer.GetErrorString(), "");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue