|
@@ -41,621 +41,184 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
|
|
|
|
|
|
#include "glTFImporter.h"
|
|
|
-#include "StreamReader.h"
|
|
|
-#include "DefaultIOSystem.h"
|
|
|
|
|
|
-#include <boost/scoped_ptr.hpp>
|
|
|
+#include "StringComparison.h"
|
|
|
+
|
|
|
+#include "boost/scoped_ptr.hpp"
|
|
|
|
|
|
#include <assimp/Importer.hpp>
|
|
|
#include <assimp/scene.h>
|
|
|
#include <assimp/ai_assert.h>
|
|
|
#include <assimp/DefaultLogger.hpp>
|
|
|
+#include <boost/shared_ptr.hpp>
|
|
|
|
|
|
-#include "glTFFileData.h"
|
|
|
-#include "glTFUtil.h"
|
|
|
-
|
|
|
-#define RAPIDJSON_HAS_STDSTRING 1
|
|
|
-#include <rapidjson/rapidjson.h>
|
|
|
-#include <rapidjson/document.h>
|
|
|
-#include <rapidjson/error/en.h>
|
|
|
-
|
|
|
-using namespace rapidjson;
|
|
|
+#include "glTFAsset.h"
|
|
|
|
|
|
using namespace Assimp;
|
|
|
-using namespace Assimp::glTF;
|
|
|
-
|
|
|
-
|
|
|
-using boost::shared_ptr;
|
|
|
-using boost::scoped_ptr;
|
|
|
-
|
|
|
-// (cannot typedef' templated classes, and "using" is c++11)
|
|
|
-#define Ptr shared_ptr
|
|
|
-
|
|
|
-// (used everywhere, and cannot use "auto")
|
|
|
-typedef rapidjson::Value::MemberIterator MemIt;
|
|
|
+using namespace glTF;
|
|
|
|
|
|
|
|
|
//
|
|
|
-// JSON Value reading helpers
|
|
|
+// glTFImporter
|
|
|
//
|
|
|
|
|
|
+static const aiImporterDesc desc = {
|
|
|
+ "glTF Importer",
|
|
|
+ "",
|
|
|
+ "",
|
|
|
+ "",
|
|
|
+ aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour
|
|
|
+ | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ "gltf glb"
|
|
|
+};
|
|
|
|
|
|
-#define GETF(VAL, OUT) { if ((VAL).IsNumber()) (OUT) = static_cast<float>((VAL).GetDouble()); }
|
|
|
-
|
|
|
-template<class T>
|
|
|
-struct ReadHelper { };
|
|
|
-
|
|
|
-template<> struct ReadHelper<int> { static bool Read(Value& val, int& out) {
|
|
|
- return val.IsInt() ? val.GetInt(), true : false;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<unsigned int> { static bool Read(Value& val, unsigned int& out) {
|
|
|
- return val.IsInt() ? out = static_cast<unsigned int>(val.GetInt()), true : false;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<float> { static bool Read(Value& val, float& out) {
|
|
|
- return val.IsNumber() ? out = static_cast<float>(val.GetDouble()), true : false;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<const char*> { static bool Read(Value& val, const char*& out) {
|
|
|
- return val.IsString() ? out = val.GetString(), true : false;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<std::string> { static bool Read(Value& val, std::string& out) {
|
|
|
- return val.IsString() ? out = val.GetString(), true : false;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<aiColor3D> { static bool Read(Value& v, aiColor3D& out) {
|
|
|
- if (!v.IsArray() || v.Size() < 3) return false;
|
|
|
- GETF(v[0], out.r); GETF(v[1], out.g); GETF(v[2], out.b);
|
|
|
- return true;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<aiVector3D> { static bool Read(Value& v, aiVector3D& out) {
|
|
|
- if (!v.IsArray() || v.Size() != 3) return false;
|
|
|
- GETF(v[0], out.x); GETF(v[1], out.y); GETF(v[2], out.z);
|
|
|
- return true;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<aiQuaternion> { static bool Read(Value& v, aiQuaternion& out) {
|
|
|
- if (!v.IsArray() || v.Size() != 4) return false;
|
|
|
- GETF(v[0], out.x); GETF(v[1], out.y); GETF(v[2], out.z); GETF(v[3], out.w);
|
|
|
- return true;
|
|
|
-}};
|
|
|
-
|
|
|
-template<> struct ReadHelper<aiMatrix4x4> { static bool Read(Value& v, aiMatrix4x4& o) {
|
|
|
- if (!v.IsArray() || v.Size() != 16) return false;
|
|
|
- GETF(v[ 0], o.a1); GETF(v[ 1], o.b1); GETF(v[ 2], o.c1); GETF(v[ 3], o.d1);
|
|
|
- GETF(v[ 4], o.a2); GETF(v[ 5], o.b2); GETF(v[ 6], o.c2); GETF(v[ 7], o.d2);
|
|
|
- GETF(v[ 8], o.a3); GETF(v[ 9], o.b3); GETF(v[10], o.c3); GETF(v[11], o.d3);
|
|
|
- GETF(v[12], o.a4); GETF(v[13], o.b4); GETF(v[14], o.c4); GETF(v[15], o.d4);
|
|
|
- return true;
|
|
|
-}};
|
|
|
-
|
|
|
-template<class T>
|
|
|
-inline static bool Read(Value& val, T& out)
|
|
|
+glTFImporter::glTFImporter()
|
|
|
+: BaseImporter()
|
|
|
{
|
|
|
- return ReadHelper<T>::Read(val, out);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
-template<class T>
|
|
|
-inline static bool ReadMember(Value& obj, const char* id, T& out)
|
|
|
+glTFImporter::~glTFImporter()
|
|
|
{
|
|
|
- MemIt it = obj.FindMember(id);
|
|
|
- if (it != obj.MemberEnd()) {
|
|
|
- return ReadHelper<T>::Read(it->value, out);
|
|
|
- }
|
|
|
- return false;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
-template<class T>
|
|
|
-inline static T TryReadMember(Value& obj, const char* id, T defaultValue)
|
|
|
+const aiImporterDesc* glTFImporter::GetInfo() const
|
|
|
{
|
|
|
- T out;
|
|
|
- return ReadMember(obj, id, out) ? out : defaultValue;
|
|
|
+ return &desc;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-//! References a sequence of loaded elements (e.g. meshes)
|
|
|
-typedef std::pair<unsigned int, unsigned int> Range;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-//
|
|
|
-// glTFReader class
|
|
|
-//
|
|
|
-
|
|
|
-//! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID
|
|
|
-template< class T, class INST, T(INST::*FACTORY_FN)(const char*, Value&)>
|
|
|
-class LazyDict
|
|
|
+bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
|
|
{
|
|
|
- typedef typename std::gltf_unordered_map<std::string, T> Map;
|
|
|
-
|
|
|
- Value* mDict; //! JSON dictionary object
|
|
|
- const char* mDictId; //! ID of the dictionary object
|
|
|
- INST& mInstance; //! The reader object instance
|
|
|
- Map mReadObjs; //! The read objects
|
|
|
-
|
|
|
-public:
|
|
|
- LazyDict(INST& instance, const char* dictId)
|
|
|
- : mDictId(dictId), mInstance(instance)
|
|
|
- {
|
|
|
- Document& doc = mInstance.GetDocument();
|
|
|
-
|
|
|
- MemIt it = doc.FindMember(dictId);
|
|
|
- mDict = (it != doc.MemberEnd() && it->value.IsObject()) ? &it->value : 0;
|
|
|
- }
|
|
|
-
|
|
|
- T Get(const char* id)
|
|
|
- {
|
|
|
- if (!mDict) return T(); // section was missing
|
|
|
-
|
|
|
- typename Map::iterator it = mReadObjs.find(id);
|
|
|
- if (it != mReadObjs.end()) { // already created?
|
|
|
- return it->second;
|
|
|
- }
|
|
|
-
|
|
|
- // read it from the JSON object
|
|
|
- MemIt obj = mDict->FindMember(id);
|
|
|
- if (obj == mDict->MemberEnd()) {
|
|
|
- throw DeadlyImportError("Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\"");
|
|
|
- }
|
|
|
-
|
|
|
- // create an instance of the given type
|
|
|
- T val = (mInstance.*FACTORY_FN)(id, obj->value);
|
|
|
- mReadObjs[id] = val;
|
|
|
- return val;
|
|
|
- }
|
|
|
-};
|
|
|
+ const std::string& extension = GetExtension(pFile);
|
|
|
|
|
|
-struct Buffer;
|
|
|
-struct BufferView;
|
|
|
-struct Accessor;
|
|
|
+ if (extension == "gltf" || extension == "glb")
|
|
|
+ return true;
|
|
|
|
|
|
-struct Image;
|
|
|
-struct Texture;
|
|
|
+ if ((checkSig || !extension.length()) && pIOHandler) {
|
|
|
+ char buffer[4];
|
|
|
|
|
|
-//! Handles the reading of the glTF JSON document
|
|
|
-class glTFReader
|
|
|
-{
|
|
|
- aiScene* mScene;
|
|
|
- Document& mDoc;
|
|
|
- IOSystem& mIO;
|
|
|
-
|
|
|
- // Vectors of imported objects, will be copied to mScene
|
|
|
- std::vector<aiMaterial*> mImpMaterials;
|
|
|
- std::vector<aiMesh*> mImpMeshes;
|
|
|
- std::vector<aiTexture*> mImpTextures;
|
|
|
-
|
|
|
- Extensions mExtensions;
|
|
|
-
|
|
|
- Ptr<Buffer> mBodyBuffer; //! Special buffer containing the body data
|
|
|
-
|
|
|
-
|
|
|
- Ptr<Buffer> LoadBuffer(const char* id, Value& obj);
|
|
|
- Ptr<BufferView> LoadBufferView(const char* id, Value& obj);
|
|
|
- Ptr<Accessor> LoadAccessor(const char* id, Value& obj);
|
|
|
-
|
|
|
- Ptr<Image> LoadImage(const char* id, Value& obj);
|
|
|
- Ptr<Texture> LoadTexture(const char* id, Value& obj);
|
|
|
-
|
|
|
- aiNode* LoadNode(const char* id, Value& node);
|
|
|
- Range LoadMesh(const char* id, Value& mesh);
|
|
|
- unsigned int LoadMaterial(const char* id, Value& material);
|
|
|
-
|
|
|
- typedef glTFReader T; // (to shorten next declarations)
|
|
|
-
|
|
|
- LazyDict<Ptr<Accessor>, T, &T::LoadAccessor> mAccessors;
|
|
|
- //LazyDict<Animation*, T, &T::LoadAnimation> mAnimations;
|
|
|
- //LazyDict<Asset*, T, &T::LoadAsset> mAssets;
|
|
|
- LazyDict<Ptr<Buffer>, T, &T::LoadBuffer> mBuffers;
|
|
|
- LazyDict<Ptr<BufferView>, T, &T::LoadBufferView> mBufferViews;
|
|
|
- //LazyDict<Camera*, T, &T::LoadCamera> mCameras;
|
|
|
- LazyDict<Ptr<Image>, T, &T::LoadImage> mImages;
|
|
|
- LazyDict<unsigned int, T, &T::LoadMaterial> mMaterials;
|
|
|
- LazyDict<Range, T, &T::LoadMesh> mMeshes;
|
|
|
- LazyDict<aiNode*, T, &T::LoadNode> mNodes;
|
|
|
- //LazyDict<Ptr<Program>, T, &T::LoadProgram> mPrograms;
|
|
|
- //LazyDict<Ptr<Sampler>, T, &T::LoadSampler> mSamplers;
|
|
|
- //LazyDict<Ptr<Shader>, T, &T::LoadShader> mShaders;
|
|
|
- //LazyDict<Ptr<Skin>, T, &T::LoadSkin> mSkins;
|
|
|
- //LazyDict<Ptr<Technique>,T, &T::LoadTechnique> mTechniques;
|
|
|
- LazyDict<Ptr<Texture>, T, &T::LoadTexture> mTextures;
|
|
|
-
|
|
|
-
|
|
|
- void LoadScene(Value& scene)
|
|
|
- {
|
|
|
- MemIt nodesm = scene.FindMember("nodes");
|
|
|
- if (nodesm != scene.MemberEnd() && nodesm->value.IsArray()) {
|
|
|
- Value& nodes = nodesm->value;
|
|
|
-
|
|
|
- unsigned int numRootNodes = nodes.Size();
|
|
|
- if (numRootNodes == 1) { // a single root node: use it
|
|
|
- if (nodes[0].IsString()) {
|
|
|
- mScene->mRootNode = mNodes.Get(nodes[0].GetString());
|
|
|
- }
|
|
|
+ boost::scoped_ptr<IOStream> pStream(pIOHandler->Open(pFile));
|
|
|
+ if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) {
|
|
|
+ if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) {
|
|
|
+ return true; // Has GLB header
|
|
|
}
|
|
|
- else if (numRootNodes > 1) { // more than one root node: create a fake root
|
|
|
- aiNode* root = new aiNode("ROOT");
|
|
|
- root->mChildren = new aiNode*[numRootNodes];
|
|
|
- for (unsigned int i = 0; i < numRootNodes; ++i) {
|
|
|
- if (nodes[i].IsString()) {
|
|
|
- aiNode* node = mNodes.Get(nodes[i].GetString());
|
|
|
- if (node) {
|
|
|
- node->mParent = root;
|
|
|
- root->mChildren[root->mNumChildren++] = node;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- mScene->mRootNode = root;
|
|
|
+ else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0
|
|
|
+ || memcmp(buffer, "{\n ", sizeof(buffer)) == 0) {
|
|
|
+ // seems a JSON file, and we're the only format that can read them
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- //if (!mScene->mRootNode) {
|
|
|
- //mScene->mRootNode = new aiNode("EMPTY");
|
|
|
- //}
|
|
|
}
|
|
|
|
|
|
- void SetMaterialColorProperty(aiMaterial* mat, Value& vals, const char* propName, aiTextureType texType,
|
|
|
- const char* pKey, unsigned int type, unsigned int idx);
|
|
|
-
|
|
|
- void CopyData()
|
|
|
- {
|
|
|
- // TODO: it does not split the loaded vertices, should it?
|
|
|
- mScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
|
|
-
|
|
|
- if (mImpMaterials.empty()) {
|
|
|
- mImpMaterials.push_back(new aiMaterial());
|
|
|
- }
|
|
|
-
|
|
|
- if (mImpMaterials.size()) {
|
|
|
- mScene->mNumMaterials = mImpMaterials.size();
|
|
|
- mScene->mMaterials = new aiMaterial*[mImpMaterials.size()];
|
|
|
- std::swap_ranges(mImpMaterials.begin(), mImpMaterials.end(), mScene->mMaterials);
|
|
|
- }
|
|
|
-
|
|
|
- if (mImpMeshes.size()) {
|
|
|
- mScene->mNumMeshes = mImpMeshes.size();
|
|
|
- mScene->mMeshes = new aiMesh*[mImpMeshes.size()];
|
|
|
- std::swap_ranges(mImpMeshes.begin(), mImpMeshes.end(), mScene->mMeshes);
|
|
|
- }
|
|
|
-
|
|
|
- if (mImpTextures.size()) {
|
|
|
- mScene->mNumTextures = mImpTextures.size();
|
|
|
- mScene->mTextures = new aiTexture*[mImpTextures.size()];
|
|
|
- std::swap_ranges(mImpTextures.begin(), mImpTextures.end(), mScene->mTextures);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-public:
|
|
|
- glTFReader(aiScene* scene, Document& document, IOSystem& iohandler, shared_ptr<Buffer>& bodyBuff) :
|
|
|
- mScene(scene),
|
|
|
- mDoc(document),
|
|
|
- mIO(iohandler),
|
|
|
- mBodyBuffer(bodyBuff),
|
|
|
- mAccessors(*this, "accessors"),
|
|
|
- //mAnimations(*this, "animations"),
|
|
|
- //mAssets(*this, "assets"),
|
|
|
- mBuffers(*this, "buffers"),
|
|
|
- mBufferViews(*this, "bufferViews"),
|
|
|
- //mCameras(*this, "cameras"),
|
|
|
- mImages(*this, "images"),
|
|
|
- mMaterials(*this, "materials"),
|
|
|
- mMeshes(*this, "meshes"),
|
|
|
- mNodes(*this, "nodes"),
|
|
|
- //mPrograms(*this, "programs"),
|
|
|
- //mSamplers(*this, "samplers"),
|
|
|
- //mShaders(*this, "shaders"),
|
|
|
- //mSkins(*this, "skins"),
|
|
|
- //mTechniques(*this, "techniques"),
|
|
|
- mTextures(*this, "textures")
|
|
|
- {
|
|
|
- memset(&mExtensions, 0, sizeof(mExtensions));
|
|
|
- }
|
|
|
-
|
|
|
- Document& GetDocument()
|
|
|
- {
|
|
|
- return mDoc;
|
|
|
- }
|
|
|
-
|
|
|
- //! Main function
|
|
|
- void Load()
|
|
|
- {
|
|
|
- // read the used extensions
|
|
|
- MemIt extensionsUsed = mDoc.FindMember("extensionsUsed");
|
|
|
- if (extensionsUsed != mDoc.MemberEnd() && extensionsUsed->value.IsArray()) {
|
|
|
- std::gltf_unordered_map<std::string, bool> exts;
|
|
|
-
|
|
|
- for (unsigned int i = 0; i < extensionsUsed->value.Size(); ++i) {
|
|
|
- if (extensionsUsed->value[i].IsString()) {
|
|
|
- exts[extensionsUsed->value[i].GetString()] = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (exts.find("KHR_binary_glTF") != exts.end()) {
|
|
|
- mExtensions.KHR_binary_glTF = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- const char* sceneId = 0;
|
|
|
-
|
|
|
- // the "scene" property specifies which scene to load
|
|
|
- {
|
|
|
- MemIt scene = mDoc.FindMember("scene");
|
|
|
- if (scene != mDoc.MemberEnd() && scene->value.IsString()) {
|
|
|
- sceneId = scene->value.GetString();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- MemIt scene;
|
|
|
-
|
|
|
- MemIt scenes = mDoc.FindMember("scenes");
|
|
|
- if (scenes != mDoc.MemberEnd() && scenes->value.IsObject()) {
|
|
|
- if (sceneId) {
|
|
|
- scene = scenes->value.FindMember(sceneId);
|
|
|
- if (scene == scenes->value.MemberEnd()) {
|
|
|
- //ThrowException("Missing scene!");
|
|
|
- }
|
|
|
- }
|
|
|
- else { // if not specified, use the first one
|
|
|
- scene = scenes->value.MemberBegin();
|
|
|
- }
|
|
|
- }
|
|
|
+ return false;
|
|
|
+}
|
|
|
|
|
|
- if (scene != scenes->value.MemberEnd()) {
|
|
|
- LoadScene(scene->value);
|
|
|
- }
|
|
|
|
|
|
- CopyData();
|
|
|
- }
|
|
|
-};
|
|
|
|
|
|
-struct Buffer
|
|
|
+static void CopyValue(const glTF::vec3& v, aiColor3D& out)
|
|
|
{
|
|
|
-private:
|
|
|
- std::size_t byteLength;
|
|
|
- shared_ptr<uint8_t> data;
|
|
|
-
|
|
|
-public:
|
|
|
- Buffer(shared_ptr<uint8_t>& d, std::size_t length)
|
|
|
- : data(d), byteLength(length)
|
|
|
- { }
|
|
|
-
|
|
|
- std::size_t GetLength() const
|
|
|
- {
|
|
|
- return byteLength;
|
|
|
- }
|
|
|
-
|
|
|
- uint8_t* GetPointer()
|
|
|
- {
|
|
|
- return data.get();
|
|
|
- }
|
|
|
-
|
|
|
- static Buffer* FromStream(IOStream& stream, std::size_t length = 0, std::size_t baseOffset = 0)
|
|
|
- {
|
|
|
- if (!length) {
|
|
|
- length = stream.FileSize();
|
|
|
- }
|
|
|
-
|
|
|
- if (baseOffset) {
|
|
|
- stream.Seek(baseOffset, aiOrigin_SET);
|
|
|
- }
|
|
|
-
|
|
|
- shared_ptr<uint8_t> data(new uint8_t[length]);
|
|
|
-
|
|
|
-
|
|
|
- if (stream.Read(data.get(), length, 1) != 1) {
|
|
|
- throw DeadlyImportError("Unable to load buffer from file!");
|
|
|
- }
|
|
|
-
|
|
|
- return new Buffer(data, length);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
+ out.r = v[0]; out.g = v[1]; out.b = v[2];
|
|
|
+}
|
|
|
|
|
|
-Ptr<Buffer> glTFReader::LoadBuffer(const char* id, Value& obj)
|
|
|
+static void CopyValue(const glTF::vec4& v, aiColor4D& out)
|
|
|
{
|
|
|
- if (!obj.IsObject()) return Ptr<Buffer>();
|
|
|
-
|
|
|
- if (mExtensions.KHR_binary_glTF && strcmp(id, "KHR_binary_glTF") == 0) {
|
|
|
- return mBodyBuffer;
|
|
|
- }
|
|
|
- else {
|
|
|
- const char* uri = TryReadMember<const char*>(obj, "uri", 0);
|
|
|
-
|
|
|
- Buffer* b = 0;
|
|
|
- if (IsDataURI(uri)) {
|
|
|
- const char* comma = strchr(uri, ',');
|
|
|
- *const_cast<char*>(comma) = '\0';
|
|
|
-
|
|
|
- bool isBase64 = (strstr(uri, "base64") != 0);
|
|
|
- if (isBase64) {
|
|
|
- uint8_t* data;
|
|
|
- std::size_t dataLen = DecodeBase64(comma + 1, data);
|
|
|
- shared_ptr<uint8_t> dataptr(data);
|
|
|
- b = new Buffer(dataptr, dataLen);
|
|
|
- }
|
|
|
- }
|
|
|
- else if (uri) { // Local file
|
|
|
- unsigned int byteLength = TryReadMember(obj, "byteLength", 0u);
|
|
|
-
|
|
|
- scoped_ptr<IOStream> file(mIO.Open(uri));
|
|
|
- b = Buffer::FromStream(*file.get(), byteLength);
|
|
|
- }
|
|
|
- return Ptr<Buffer>(b);
|
|
|
- }
|
|
|
+ out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3];
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-struct BufferView
|
|
|
+static void CopyValue(const glTF::vec4& v, aiColor3D& out)
|
|
|
{
|
|
|
- Ptr<Buffer> buffer;
|
|
|
- unsigned int byteOffset;
|
|
|
- unsigned int byteLength;
|
|
|
-
|
|
|
- BufferView() {}
|
|
|
-
|
|
|
- BufferView(Value& obj)
|
|
|
- {
|
|
|
- Read(obj);
|
|
|
- }
|
|
|
-
|
|
|
- void Read(Value& obj)
|
|
|
- {
|
|
|
- if (!obj.IsObject()) return;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-};
|
|
|
+ out.r = v[0]; out.g = v[1]; out.b = v[2];
|
|
|
+}
|
|
|
|
|
|
-Ptr<BufferView> glTFReader::LoadBufferView(const char* id, Value& obj)
|
|
|
+static void CopyValue(const glTF::vec3& v, aiVector3D& out)
|
|
|
{
|
|
|
- if (!obj.IsObject()) return Ptr<BufferView>();
|
|
|
-
|
|
|
-
|
|
|
- const char* bufferId = TryReadMember<const char*>(obj, "buffer", 0);
|
|
|
- if (!bufferId) return Ptr<BufferView>();
|
|
|
-
|
|
|
- BufferView* bv = new BufferView();
|
|
|
-
|
|
|
- bv->buffer = mBuffers.Get(bufferId);
|
|
|
- bv->byteOffset = TryReadMember(obj, "byteOffset", 0u);
|
|
|
- bv->byteLength = TryReadMember(obj, "byteLength", 0u);
|
|
|
-
|
|
|
- return Ptr<BufferView>(bv);
|
|
|
+ out.x = v[0]; out.y = v[1]; out.z = v[2];
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-struct Accessor
|
|
|
+static void CopyValue(const glTF::vec4& v, aiQuaternion& out)
|
|
|
{
|
|
|
- Ptr<BufferView> bufferView;
|
|
|
- unsigned int byteOffset;
|
|
|
- unsigned int byteStride;
|
|
|
- ComponentType componentType;
|
|
|
- unsigned int count;
|
|
|
- std::string type; // "SCALAR", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4"
|
|
|
- //unsigned int max;
|
|
|
- ///unsigned int min;
|
|
|
-
|
|
|
- unsigned int numComponents;
|
|
|
- unsigned int bytesPerComponent;
|
|
|
- unsigned int elemSize;
|
|
|
-
|
|
|
- uint8_t* data;
|
|
|
-
|
|
|
- inline uint8_t* GetPointer()
|
|
|
- {
|
|
|
- if (!bufferView || !bufferView->buffer) return 0;
|
|
|
-
|
|
|
- std::size_t offset = byteOffset + bufferView->byteOffset;
|
|
|
- return bufferView->buffer->GetPointer() + offset;
|
|
|
- }
|
|
|
-
|
|
|
- template<class T>
|
|
|
- void ExtractData(T*& outData, unsigned int* outCount = 0, unsigned int* outComponents = 0)
|
|
|
- {
|
|
|
- ai_assert(data);
|
|
|
-
|
|
|
- const std::size_t totalSize = elemSize * count;
|
|
|
-
|
|
|
- const std::size_t targetElemSize = sizeof(T);
|
|
|
- ai_assert(elemSize <= targetElemSize);
|
|
|
+ out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3];
|
|
|
+}
|
|
|
|
|
|
- ai_assert(count*byteStride <= bufferView->byteLength);
|
|
|
+static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o)
|
|
|
+{
|
|
|
+ o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3];
|
|
|
+ o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7];
|
|
|
+ o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11];
|
|
|
+ o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
|
|
|
+}
|
|
|
|
|
|
- outData = new T[count];
|
|
|
- if (byteStride == elemSize && targetElemSize == elemSize) {
|
|
|
- memcpy(outData, data, totalSize);
|
|
|
- }
|
|
|
- else {
|
|
|
- for (std::size_t i = 0; i < count; ++i) {
|
|
|
- memcpy(outData + i, data + i*byteStride, elemSize);
|
|
|
+inline void SetMaterialColorProperty(std::vector<int>& embeddedTexIdxs, Asset& r, glTF::TexProperty prop, aiMaterial* mat,
|
|
|
+ aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx)
|
|
|
+{
|
|
|
+ if (prop.texture) {
|
|
|
+ if (prop.texture->source) {
|
|
|
+ aiString uri(prop.texture->source->uri);
|
|
|
+
|
|
|
+ int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
|
|
|
+ if (texIdx != -1) { // embedded
|
|
|
+ // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
|
|
+ uri.data[0] = '*';
|
|
|
+ uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- if (outCount) *outCount = count;
|
|
|
- if (outComponents) *outComponents = numComponents;
|
|
|
- }
|
|
|
|
|
|
- //! Gets the i-th value as defined by the accessor
|
|
|
- template<class T>
|
|
|
- T GetValue(int i)
|
|
|
- {
|
|
|
- ai_assert(data);
|
|
|
- ai_assert(i*byteStride < bufferView->byteLength);
|
|
|
- T value = T();
|
|
|
- memcpy(&value, data + i*byteStride, elemSize);
|
|
|
- //value >>= 8 * (sizeof(T) - elemSize);
|
|
|
- return value;
|
|
|
+ mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- //! Gets the i-th value as defined by the accessor
|
|
|
- unsigned int GetUInt(int i)
|
|
|
- {
|
|
|
- return GetValue<unsigned int>(i);
|
|
|
+ else {
|
|
|
+ aiColor4D col;
|
|
|
+ CopyValue(prop.color, col);
|
|
|
+ if (col.r != 1.f || col.g != 1.f || col.b != 1.f || col.a != 1.f) {
|
|
|
+ mat->AddProperty(&col, 1, pKey, type, idx);
|
|
|
+ }
|
|
|
}
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
-Ptr<Accessor> glTFReader::LoadAccessor(const char* id, Value& obj)
|
|
|
+void glTFImporter::ImportMaterials(glTF::Asset& r)
|
|
|
{
|
|
|
- if (!obj.IsObject()) return Ptr<Accessor>();
|
|
|
+ mScene->mNumMaterials = r.materials.Size();
|
|
|
+ mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
|
|
|
|
|
|
- Accessor* a = new Accessor();
|
|
|
+ for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
|
|
|
+ aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial();
|
|
|
|
|
|
- const char* bufferViewId = TryReadMember<const char*>(obj, "bufferView", 0);
|
|
|
- if (bufferViewId) {
|
|
|
- a->bufferView = mBufferViews.Get(bufferViewId);
|
|
|
- }
|
|
|
+ Material& mat = r.materials[i];
|
|
|
|
|
|
- int compType = TryReadMember(obj, "componentType", unsigned(ComponentType_BYTE));
|
|
|
-
|
|
|
- a->byteOffset = TryReadMember(obj, "byteOffset", 0u);
|
|
|
- a->byteStride = TryReadMember(obj, "byteStride", 0u);
|
|
|
- a->componentType = static_cast<ComponentType>(compType);
|
|
|
- a->count = TryReadMember(obj, "count", 0u);
|
|
|
- a->type = TryReadMember(obj, "type", "");
|
|
|
-
|
|
|
- a->numComponents = 1; // "SCALAR"
|
|
|
- if (a->type == "VEC2") a->numComponents = 2;
|
|
|
- else if (a->type == "VEC3") a->numComponents = 3;
|
|
|
- else if (a->type == "VEC4") a->numComponents = 4;
|
|
|
- else if (a->type == "MAT2") a->numComponents = 4;
|
|
|
- else if (a->type == "MAT3") a->numComponents = 9;
|
|
|
- else if (a->type == "MAT4") a->numComponents = 16;
|
|
|
-
|
|
|
- switch (a->componentType) {
|
|
|
- case ComponentType_SHORT:
|
|
|
- case ComponentType_UNSIGNED_SHORT:
|
|
|
- a->bytesPerComponent = 2;
|
|
|
- break;
|
|
|
-
|
|
|
- case ComponentType_FLOAT:
|
|
|
- a->bytesPerComponent = 4;
|
|
|
- break;
|
|
|
-
|
|
|
- //case Accessor::ComponentType_BYTE:
|
|
|
- //case Accessor::ComponentType_UNSIGNED_BYTE:
|
|
|
- default:
|
|
|
- a->bytesPerComponent = 1;
|
|
|
- }
|
|
|
+ /*if (!mat.name.empty())*/ {
|
|
|
+ aiString str(mat.id /*mat.name*/);
|
|
|
+ aimat->AddProperty(&str, AI_MATKEY_NAME);
|
|
|
+ }
|
|
|
|
|
|
- a->elemSize = a->numComponents * a->bytesPerComponent;
|
|
|
- if (!a->byteStride) a->byteStride = a->elemSize;
|
|
|
+ SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
|
|
|
+ SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
|
|
|
+ SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
|
|
|
|
|
|
- a->data = a->GetPointer();
|
|
|
+ if (mat.shininess > 0.f) {
|
|
|
+ aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return Ptr<Accessor>(a);
|
|
|
+ if (mScene->mNumMaterials == 0) {
|
|
|
+ mScene->mNumMaterials = 1;
|
|
|
+ mScene->mMaterials = new aiMaterial*[1];
|
|
|
+ mScene->mMaterials[0] = new aiMaterial();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static inline void setFace(aiFace& face, int a)
|
|
|
+
|
|
|
+inline void SetFace(aiFace& face, int a)
|
|
|
{
|
|
|
face.mNumIndices = 1;
|
|
|
face.mIndices = new unsigned int[1];
|
|
|
face.mIndices[0] = a;
|
|
|
}
|
|
|
|
|
|
-static inline void setFace(aiFace& face, int a, int b)
|
|
|
+inline void SetFace(aiFace& face, int a, int b)
|
|
|
{
|
|
|
face.mNumIndices = 2;
|
|
|
face.mIndices = new unsigned int[2];
|
|
@@ -663,7 +226,7 @@ static inline void setFace(aiFace& face, int a, int b)
|
|
|
face.mIndices[1] = b;
|
|
|
}
|
|
|
|
|
|
-static inline void setFace(aiFace& face, int a, int b, int c)
|
|
|
+inline void SetFace(aiFace& face, int a, int b, int c)
|
|
|
{
|
|
|
face.mNumIndices = 3;
|
|
|
face.mIndices = new unsigned int[3];
|
|
@@ -672,541 +235,390 @@ static inline void setFace(aiFace& face, int a, int b, int c)
|
|
|
face.mIndices[2] = c;
|
|
|
}
|
|
|
|
|
|
-Range glTFReader::LoadMesh(const char* id, Value& mesh)
|
|
|
-{
|
|
|
- Range range;
|
|
|
- range.first = mImpMeshes.size();
|
|
|
- range.second = mImpMeshes.size();
|
|
|
-
|
|
|
- MemIt primitives = mesh.FindMember("primitives");
|
|
|
- if (primitives != mesh.MemberEnd() && primitives->value.IsArray()) {
|
|
|
- for (unsigned int i = 0; i < primitives->value.Size(); ++i) {
|
|
|
- Value& primitive = primitives->value[i];
|
|
|
-
|
|
|
- aiMesh* aimesh = new aiMesh();
|
|
|
- mImpMeshes.push_back(aimesh);
|
|
|
- ++range.second;
|
|
|
-
|
|
|
- MemIt mode = primitive.FindMember("mode");
|
|
|
- if (mode != primitive.MemberEnd() && mode->value.IsInt()) {
|
|
|
- switch (mode->value.GetInt()) {
|
|
|
- case PrimitiveMode_POINTS:
|
|
|
- aimesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
|
|
- break;
|
|
|
-
|
|
|
- case PrimitiveMode_LINES:
|
|
|
- case PrimitiveMode_LINE_LOOP:
|
|
|
- case PrimitiveMode_LINE_STRIP:
|
|
|
- aimesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
|
|
- break;
|
|
|
-
|
|
|
- case PrimitiveMode_TRIANGLES:
|
|
|
- case PrimitiveMode_TRIANGLE_STRIP:
|
|
|
- case PrimitiveMode_TRIANGLE_FAN:
|
|
|
- aimesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+void glTFImporter::ImportMeshes(glTF::Asset& r)
|
|
|
+{
|
|
|
+ std::vector<aiMesh*> meshes;
|
|
|
|
|
|
- MemIt attrs = primitive.FindMember("attributes");
|
|
|
- if (attrs != primitive.MemberEnd() && attrs->value.IsObject()) {
|
|
|
- for (MemIt it = attrs->value.MemberBegin(); it != attrs->value.MemberEnd(); ++it) {
|
|
|
- if (!it->value.IsString()) continue;
|
|
|
- const char* attr = it->name.GetString();
|
|
|
- const char* accessorId = it->value.GetString();
|
|
|
+ unsigned int k = 0;
|
|
|
|
|
|
- Ptr<Accessor> accessor = mAccessors.Get(accessorId);
|
|
|
- if (!accessor) continue;
|
|
|
+ for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
|
|
+ Mesh& mesh = r.meshes[m];
|
|
|
|
|
|
- if (strcmp(attr, "POSITION") == 0) {
|
|
|
- accessor->ExtractData(aimesh->mVertices, &aimesh->mNumVertices);
|
|
|
- }
|
|
|
- else if (strcmp(attr, "NORMAL") == 0) {
|
|
|
- accessor->ExtractData(aimesh->mNormals);
|
|
|
- }
|
|
|
- else if (strncmp(attr, "TEXCOORD_", 9) == 0) {
|
|
|
- int idx = attr[9] - '0';
|
|
|
- if (idx >= 0 && idx <= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
|
|
- accessor->ExtractData(aimesh->mTextureCoords[idx], 0, &aimesh->mNumUVComponents[idx]);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ meshOffsets.push_back(k);
|
|
|
+ k += mesh.primitives.size();
|
|
|
|
|
|
- MemIt indices = primitive.FindMember("indices");
|
|
|
- if (indices != primitive.MemberEnd() && indices->value.IsString()) {
|
|
|
- Ptr<Accessor> acc = mAccessors.Get(indices->value.GetString());
|
|
|
- if (acc) {
|
|
|
- aiFace* faces = 0;
|
|
|
- std::size_t nFaces = 0;
|
|
|
-
|
|
|
- int primitiveMode = mode->value.GetInt();
|
|
|
- switch (primitiveMode) {
|
|
|
- case PrimitiveMode_POINTS: {
|
|
|
- nFaces = acc->count;
|
|
|
- faces = new aiFace[nFaces];
|
|
|
- for (unsigned int i = 0; i < acc->count; ++i) {
|
|
|
- setFace(faces[i], acc->GetUInt(i));
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
+ for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
|
|
|
+ Mesh::Primitive& prim = mesh.primitives[p];
|
|
|
|
|
|
- case PrimitiveMode_LINES: {
|
|
|
- nFaces = acc->count / 2;
|
|
|
- faces = new aiFace[nFaces];
|
|
|
- for (unsigned int i = 0; i < acc->count; i += 2) {
|
|
|
- setFace(faces[i / 2], acc->GetUInt(i), acc->GetUInt(i + 1));
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- case PrimitiveMode_LINE_LOOP:
|
|
|
- case PrimitiveMode_LINE_STRIP: {
|
|
|
- nFaces = acc->count - ((primitiveMode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
|
|
- faces = new aiFace[nFaces];
|
|
|
- setFace(faces[0], acc->GetUInt(0), acc->GetUInt(1));
|
|
|
- for (unsigned int i = 2; i < acc->count; ++i) {
|
|
|
- setFace(faces[i - 1], faces[i - 2].mIndices[1], acc->GetUInt(i));
|
|
|
- }
|
|
|
- if (primitiveMode == PrimitiveMode_LINE_LOOP) { // close the loop
|
|
|
- setFace(faces[acc->count - 1], faces[acc->count - 2].mIndices[1], faces[0].mIndices[0]);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- case PrimitiveMode_TRIANGLES: {
|
|
|
- nFaces = acc->count / 3;
|
|
|
- faces = new aiFace[nFaces];
|
|
|
- for (unsigned int i = 0; i < acc->count; i += 3) {
|
|
|
- setFace(faces[i / 3], acc->GetUInt(i), acc->GetUInt(i + 1), acc->GetUInt(i + 2));
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case PrimitiveMode_TRIANGLE_STRIP: {
|
|
|
- nFaces = acc->count - 2;
|
|
|
- faces = new aiFace[nFaces];
|
|
|
- setFace(faces[0], acc->GetUInt(0), acc->GetUInt(1), acc->GetUInt(2));
|
|
|
- for (unsigned int i = 3; i < acc->count; ++i) {
|
|
|
- setFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], acc->GetUInt(i));
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case PrimitiveMode_TRIANGLE_FAN:
|
|
|
- nFaces = acc->count - 2;
|
|
|
- faces = new aiFace[nFaces];
|
|
|
- setFace(faces[0], acc->GetUInt(0), acc->GetUInt(1), acc->GetUInt(2));
|
|
|
- for (unsigned int i = 3; i < acc->count; ++i) {
|
|
|
- setFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], acc->GetUInt(i));
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
+ aiMesh* aim = new aiMesh();
|
|
|
+ meshes.push_back(aim);
|
|
|
|
|
|
- if (faces) {
|
|
|
- aimesh->mFaces = faces;
|
|
|
- aimesh->mNumFaces = nFaces;
|
|
|
- }
|
|
|
- }
|
|
|
+ aim->mName = mesh.id;
|
|
|
+ if (mesh.primitives.size() > 1) {
|
|
|
+ size_t& len = aim->mName.length;
|
|
|
+ aim->mName.data[len] = '-';
|
|
|
+ len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, MAXLEN - len - 1, p);
|
|
|
}
|
|
|
|
|
|
+ switch (prim.mode) {
|
|
|
+ case PrimitiveMode_POINTS:
|
|
|
+ aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PrimitiveMode_LINES:
|
|
|
+ case PrimitiveMode_LINE_LOOP:
|
|
|
+ case PrimitiveMode_LINE_STRIP:
|
|
|
+ aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PrimitiveMode_TRIANGLES:
|
|
|
+ case PrimitiveMode_TRIANGLE_STRIP:
|
|
|
+ case PrimitiveMode_TRIANGLE_FAN:
|
|
|
+ aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- MemIt material = primitive.FindMember("material");
|
|
|
- if (material != primitive.MemberEnd() && material->value.IsString()) {
|
|
|
- aimesh->mMaterialIndex = mMaterials.Get(material->value.GetString());
|
|
|
+ Mesh::Primitive::Attributes& attr = prim.attributes;
|
|
|
+ if (attr.position.size() > 0 && attr.position[0]) {
|
|
|
+ aim->mNumVertices = attr.position[0]->count;
|
|
|
+ attr.position[0]->ExtractData(aim->mVertices);
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- return range;
|
|
|
-}
|
|
|
+ if (attr.normal.size() > 0 && attr.normal[0]) {
|
|
|
+ attr.normal[0]->ExtractData(aim->mNormals);
|
|
|
+ }
|
|
|
|
|
|
+ for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
|
|
|
+ attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
|
|
|
+ aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
|
|
|
+ }
|
|
|
|
|
|
-struct Image
|
|
|
-{
|
|
|
- aiString uri;
|
|
|
-};
|
|
|
|
|
|
-struct Texture
|
|
|
-{
|
|
|
- Ptr<Image> source;
|
|
|
-};
|
|
|
+ if (prim.indices) {
|
|
|
+ aiFace* faces = 0;
|
|
|
+ size_t nFaces = 0;
|
|
|
|
|
|
-Ptr<Image> glTFReader::LoadImage(const char* id, Value& obj)
|
|
|
-{
|
|
|
+ unsigned int count = prim.indices->count;
|
|
|
|
|
|
- Image* img = new Image();
|
|
|
+ Accessor::Indexer data = prim.indices->GetIndexer();
|
|
|
|
|
|
- std::size_t embeddedDataLen = 0;
|
|
|
- uint8_t* embeddedData = 0;
|
|
|
- const char* mimeType = 0;
|
|
|
+ switch (prim.mode) {
|
|
|
+ case PrimitiveMode_POINTS: {
|
|
|
+ nFaces = count;
|
|
|
+ faces = new aiFace[nFaces];
|
|
|
+ for (unsigned int i = 0; i < count; ++i) {
|
|
|
+ SetFace(faces[i], data.GetUInt(i));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- // Check for extensions first (to detect binary embedded data)
|
|
|
- MemIt extensions = obj.FindMember("extensions");
|
|
|
- if (extensions != obj.MemberEnd()) {
|
|
|
- Value& exts = extensions->value;
|
|
|
+ case PrimitiveMode_LINES: {
|
|
|
+ nFaces = count / 2;
|
|
|
+ faces = new aiFace[nFaces];
|
|
|
+ for (unsigned int i = 0; i < count; i += 2) {
|
|
|
+ SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- MemIt KHR_binary_glTF = exts.FindMember("KHR_binary_glTF");
|
|
|
- if (KHR_binary_glTF != exts.MemberEnd() && KHR_binary_glTF->value.IsObject()) {
|
|
|
+ case PrimitiveMode_LINE_LOOP:
|
|
|
+ case PrimitiveMode_LINE_STRIP: {
|
|
|
+ nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
|
|
+ faces = new aiFace[nFaces];
|
|
|
+ SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
|
|
|
+ for (unsigned int i = 2; i < count; ++i) {
|
|
|
+ SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
|
|
|
+ }
|
|
|
+ if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
|
|
+ SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- int width = TryReadMember(KHR_binary_glTF->value, "width", 0);
|
|
|
- int height = TryReadMember(KHR_binary_glTF->value, "height", 0);
|
|
|
-
|
|
|
- ReadMember(KHR_binary_glTF->value, "mimeType", mimeType);
|
|
|
-
|
|
|
- const char* bufferViewId;
|
|
|
- if (ReadMember(KHR_binary_glTF->value, "bufferView", bufferViewId)) {
|
|
|
- Ptr<BufferView> bv = mBufferViews.Get(bufferViewId);
|
|
|
- if (bv) {
|
|
|
- embeddedDataLen = bv->byteLength;
|
|
|
- embeddedData = new uint8_t[embeddedDataLen];
|
|
|
- memcpy(embeddedData, bv->buffer->GetPointer() + bv->byteOffset, embeddedDataLen);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!embeddedDataLen) {
|
|
|
- const char* uri;
|
|
|
- if (ReadMember(obj, "uri", uri)) {
|
|
|
- if (IsDataURI(uri)) {
|
|
|
- const char* comma = strchr(uri, ',');
|
|
|
- *const_cast<char*>(comma) = '\0';
|
|
|
-
|
|
|
- bool isBase64 = (strstr(uri, "base64") != 0);
|
|
|
- if (isBase64) {
|
|
|
- embeddedDataLen = DecodeBase64(comma + 1, embeddedData);
|
|
|
+ case PrimitiveMode_TRIANGLES: {
|
|
|
+ nFaces = count / 3;
|
|
|
+ faces = new aiFace[nFaces];
|
|
|
+ for (unsigned int i = 0; i < count; i += 3) {
|
|
|
+ SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case PrimitiveMode_TRIANGLE_STRIP: {
|
|
|
+ nFaces = count - 2;
|
|
|
+ faces = new aiFace[nFaces];
|
|
|
+ SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
|
|
+ for (unsigned int i = 3; i < count; ++i) {
|
|
|
+ SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case PrimitiveMode_TRIANGLE_FAN:
|
|
|
+ nFaces = count - 2;
|
|
|
+ faces = new aiFace[nFaces];
|
|
|
+ SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
|
|
+ for (unsigned int i = 3; i < count; ++i) {
|
|
|
+ SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- const char* sc = strchr(uri, ';');
|
|
|
- if (sc != 0) {
|
|
|
- *const_cast<char*>(sc) = '\0';
|
|
|
- mimeType = uri;
|
|
|
+ if (faces) {
|
|
|
+ aim->mFaces = faces;
|
|
|
+ aim->mNumFaces = nFaces;
|
|
|
}
|
|
|
}
|
|
|
- else {
|
|
|
- img->uri = uri;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Add the embedded texture
|
|
|
- if (embeddedDataLen > 0) {
|
|
|
- aiTexture* tex = new aiTexture();
|
|
|
- mImpTextures.push_back(tex);
|
|
|
|
|
|
- tex->mWidth = static_cast<unsigned int>(embeddedDataLen);
|
|
|
- tex->mHeight = 0;
|
|
|
- tex->pcData = reinterpret_cast<aiTexel*>(embeddedData);
|
|
|
|
|
|
- if (mimeType) {
|
|
|
- const char* ext = strchr(mimeType, '/') + 1;
|
|
|
- if (ext) {
|
|
|
- if (strcmp(ext, "jpeg") == 0) ext = "jpg";
|
|
|
-
|
|
|
- std::size_t len = strlen(ext);
|
|
|
- if (len <= 3) {
|
|
|
- strcpy(tex->achFormatHint, ext);
|
|
|
- }
|
|
|
+ if (prim.material) {
|
|
|
+ aim->mMaterialIndex = prim.material.GetIndex();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
|
|
- img->uri.data[0] = '*';
|
|
|
- img->uri.length = 1 + ASSIMP_itoa10(img->uri.data + 1, MAXLEN - 1, mImpTextures.size() - 1);
|
|
|
}
|
|
|
|
|
|
- return Ptr<Image>(img);
|
|
|
+ meshOffsets.push_back(k);
|
|
|
+
|
|
|
+ CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
|
|
|
}
|
|
|
|
|
|
-Ptr<Texture> glTFReader::LoadTexture(const char* id, Value& obj)
|
|
|
+void glTFImporter::ImportCameras(glTF::Asset& r)
|
|
|
{
|
|
|
- Texture* tex = new Texture();
|
|
|
+ if (!r.cameras.Size()) return;
|
|
|
|
|
|
- const char* source;
|
|
|
- if (ReadMember(obj, "source", source)) {
|
|
|
- tex->source = mImages.Get(source);
|
|
|
- }
|
|
|
+ mScene->mNumCameras = r.cameras.Size();
|
|
|
+ mScene->mCameras = new aiCamera*[r.cameras.Size()];
|
|
|
|
|
|
- return Ptr<Texture>(tex);
|
|
|
-}
|
|
|
+ for (size_t i = 0; i < r.cameras.Size(); ++i) {
|
|
|
+ Camera& cam = r.cameras[i];
|
|
|
|
|
|
-void glTFReader::SetMaterialColorProperty(aiMaterial* mat, Value& vals, const char* propName, aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx)
|
|
|
-{
|
|
|
- MemIt prop = vals.FindMember(propName);
|
|
|
- if (prop != vals.MemberEnd()) {
|
|
|
- aiColor3D col;
|
|
|
- if (Read(prop->value, col)) {
|
|
|
- mat->AddProperty(&col, 1, pKey, type, idx);
|
|
|
+ aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
|
|
|
+
|
|
|
+ if (cam.type == Camera::Perspective) {
|
|
|
+
|
|
|
+ aicam->mAspect = cam.perspective.aspectRatio;
|
|
|
+ aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect;
|
|
|
+ aicam->mClipPlaneFar = cam.perspective.zfar;
|
|
|
+ aicam->mClipPlaneNear = cam.perspective.znear;
|
|
|
}
|
|
|
- else if (prop->value.IsString()) {
|
|
|
- Ptr<Texture> tex = mTextures.Get(prop->value.GetString());
|
|
|
- if (tex && tex->source) {
|
|
|
- mat->AddProperty(&tex->source->uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
|
|
|
- }
|
|
|
+ else {
|
|
|
+ // assimp does not support orthographic cameras
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-unsigned int glTFReader::LoadMaterial(const char* id, Value& material)
|
|
|
+void glTFImporter::ImportLights(glTF::Asset& r)
|
|
|
{
|
|
|
- aiMaterial* mat = new aiMaterial();
|
|
|
- mImpMaterials.push_back(mat);
|
|
|
+ if (!r.lights.Size()) return;
|
|
|
|
|
|
- const char* name;
|
|
|
- if (ReadMember(material, "name", name)) {
|
|
|
- aiString str(name);
|
|
|
- mat->AddProperty(&str, AI_MATKEY_NAME);
|
|
|
- }
|
|
|
+ mScene->mNumLights = r.lights.Size();
|
|
|
+ mScene->mLights = new aiLight*[r.lights.Size()];
|
|
|
|
|
|
- MemIt values = material.FindMember("values");
|
|
|
- if (values != material.MemberEnd() && values->value.IsObject()) {
|
|
|
- Value& vals = values->value;
|
|
|
+ for (size_t i = 0; i < r.lights.Size(); ++i) {
|
|
|
+ Light& l = r.lights[i];
|
|
|
|
|
|
- SetMaterialColorProperty(mat, vals, "diffuse", aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
|
|
|
- SetMaterialColorProperty(mat, vals, "specular", aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
|
|
|
- SetMaterialColorProperty(mat, vals, "ambient", aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
|
|
|
+ aiLight* ail = mScene->mLights[i] = new aiLight();
|
|
|
|
|
|
- float shininess;
|
|
|
- if (ReadMember(vals, "shininess", shininess)) {
|
|
|
- mat->AddProperty(&shininess, 1, AI_MATKEY_SHININESS);
|
|
|
- }
|
|
|
- }
|
|
|
+ switch (l.type) {
|
|
|
+ case Light::Type_directional:
|
|
|
+ ail->mType = aiLightSource_DIRECTIONAL; break;
|
|
|
|
|
|
- MemIt extensions = material.FindMember("values");
|
|
|
- if (extensions != material.MemberEnd() && extensions->value.IsObject()) {
|
|
|
- Value& exts = extensions->value;
|
|
|
+ case Light::Type_point:
|
|
|
+ ail->mType = aiLightSource_POINT; break;
|
|
|
|
|
|
- MemIt KHR_materials_common = exts.FindMember("KHR_materials_common");
|
|
|
- if (KHR_materials_common != exts.MemberEnd() && KHR_materials_common->value.IsObject()) {
|
|
|
- // TODO: support KHR_materials_common (https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_common)
|
|
|
+ case Light::Type_spot:
|
|
|
+ ail->mType = aiLightSource_SPOT; break;
|
|
|
+
|
|
|
+ case Light::Type_ambient:
|
|
|
+ ail->mType = aiLightSource_AMBIENT; break;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- return static_cast<unsigned int>(mImpMaterials.size() - 1);
|
|
|
+ CopyValue(l.color, ail->mColorAmbient);
|
|
|
+ CopyValue(l.color, ail->mColorDiffuse);
|
|
|
+ CopyValue(l.color, ail->mColorSpecular);
|
|
|
+
|
|
|
+ ail->mAngleOuterCone = l.falloffAngle;
|
|
|
+ ail->mAngleInnerCone = l.falloffExponent; // TODO fix this, it does not look right at all
|
|
|
+
|
|
|
+ ail->mAttenuationConstant = l.constantAttenuation;
|
|
|
+ ail->mAttenuationLinear = l.linearAttenuation;
|
|
|
+ ail->mAttenuationQuadratic = l.quadraticAttenuation;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-aiNode* glTFReader::LoadNode(const char* id, Value& node)
|
|
|
-{
|
|
|
- aiNode* ainode = new aiNode(id);
|
|
|
|
|
|
- //MemIt name = node.FindMember("name");
|
|
|
- //if (name != node.MemberEnd() && name->value.IsString()) {
|
|
|
- // strcpy(ainode->mName.data, name->value.GetString());
|
|
|
- //}
|
|
|
+aiNode* ImportNode(aiScene* pScene, glTF::Asset& r, std::vector<unsigned int>& meshOffsets, glTF::Ref<glTF::Node>& ptr)
|
|
|
+{
|
|
|
+ Node& node = *ptr;
|
|
|
|
|
|
- MemIt children = node.FindMember("children");
|
|
|
- if (children != node.MemberEnd() && children->value.IsArray()) {
|
|
|
+ aiNode* ainode = new aiNode(node.id);
|
|
|
|
|
|
- ainode->mChildren = new aiNode*[children->value.Size()];
|
|
|
- //ainode->mNumChildren = 0;
|
|
|
+ if (!node.children.empty()) {
|
|
|
+ ainode->mNumChildren = node.children.size();
|
|
|
+ ainode->mChildren = new aiNode*[ainode->mNumChildren];
|
|
|
|
|
|
- for (unsigned int i = 0; i < children->value.Size(); ++i) {
|
|
|
- Value& child = children->value[i];
|
|
|
- if (child.IsString()) {
|
|
|
- // get/create the child node
|
|
|
- aiNode* aichild = mNodes.Get(child.GetString());
|
|
|
- if (aichild) {
|
|
|
- aichild->mParent = ainode;
|
|
|
- ainode->mChildren[ainode->mNumChildren++] = aichild;
|
|
|
- }
|
|
|
- }
|
|
|
+ for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
|
|
|
+ aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
|
|
|
+ child->mParent = ainode;
|
|
|
+ ainode->mChildren[i] = child;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- aiMatrix4x4& transf = ainode->mTransformation;
|
|
|
-
|
|
|
- MemIt matrix = node.FindMember("matrix");
|
|
|
- if (matrix != node.MemberEnd()) {
|
|
|
- Read(matrix->value, transf);
|
|
|
+ aiMatrix4x4 matrix = ainode->mTransformation;
|
|
|
+ if (node.matrix.isPresent) {
|
|
|
+ CopyValue(node.matrix.value, matrix);
|
|
|
}
|
|
|
else {
|
|
|
- MemIt translation = node.FindMember("translation");
|
|
|
- if (translation != node.MemberEnd()) {
|
|
|
+ if (node.translation.isPresent) {
|
|
|
aiVector3D trans;
|
|
|
- if (Read(matrix->value, trans)) {
|
|
|
- aiMatrix4x4 m;
|
|
|
- aiMatrix4x4::Translation(trans, m);
|
|
|
- transf = m * transf;
|
|
|
- }
|
|
|
+ CopyValue(node.translation.value, trans);
|
|
|
+ aiMatrix4x4 t;
|
|
|
+ aiMatrix4x4::Translation(trans, t);
|
|
|
+ matrix = t * matrix;
|
|
|
}
|
|
|
|
|
|
- MemIt scale = node.FindMember("scale");
|
|
|
- if (scale != node.MemberEnd()) {
|
|
|
+ if (node.scale.isPresent) {
|
|
|
aiVector3D scal(1.f);
|
|
|
- if (Read(matrix->value, scal)) {
|
|
|
- aiMatrix4x4 m;
|
|
|
- aiMatrix4x4::Scaling(scal, m);
|
|
|
- transf = m * transf;
|
|
|
- }
|
|
|
+ CopyValue(node.scale.value, scal);
|
|
|
+ aiMatrix4x4 s;
|
|
|
+ aiMatrix4x4::Scaling(scal, s);
|
|
|
+ matrix = s * matrix;
|
|
|
}
|
|
|
|
|
|
- MemIt rotation = node.FindMember("rotation");
|
|
|
- if (rotation != node.MemberEnd()) {
|
|
|
+
|
|
|
+ if (node.rotation.isPresent) {
|
|
|
aiQuaternion rot;
|
|
|
- if (Read(matrix->value, rot)) {
|
|
|
- transf = aiMatrix4x4(rot.GetMatrix()) * transf;
|
|
|
- }
|
|
|
+ CopyValue(node.rotation.value, rot);
|
|
|
+ matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- MemIt meshes = node.FindMember("meshes");
|
|
|
- if (meshes != node.MemberEnd() && meshes->value.IsArray()) {
|
|
|
- std::size_t numMeshes = (std::size_t)meshes->value.Size();
|
|
|
+ if (!node.meshes.empty()) {
|
|
|
+ int count = 0;
|
|
|
+ for (size_t i = 0; i < node.meshes.size(); ++i) {
|
|
|
+ int idx = node.meshes[i].GetIndex();
|
|
|
+ count += meshOffsets[idx + 1] - meshOffsets[idx];
|
|
|
+ }
|
|
|
|
|
|
- std::vector<unsigned int> meshList;
|
|
|
+ ainode->mNumMeshes = count;
|
|
|
+ ainode->mMeshes = new unsigned int[count];
|
|
|
|
|
|
- for (std::size_t i = 0; i < numMeshes; ++i) {
|
|
|
- if (meshes->value[i].IsString()) {
|
|
|
- Range range = mMeshes.Get(meshes->value[i].GetString());
|
|
|
- for (unsigned int m = range.first; m < range.second; ++m) {
|
|
|
- meshList.push_back(m);
|
|
|
- }
|
|
|
+ int k = 0;
|
|
|
+ for (size_t i = 0; i < node.meshes.size(); ++i) {
|
|
|
+ int idx = node.meshes[i].GetIndex();
|
|
|
+ for (size_t j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) {
|
|
|
+ ainode->mMeshes[k] = j;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (meshList.size()) {
|
|
|
- ainode->mNumMeshes = meshList.size();
|
|
|
- ainode->mMeshes = new unsigned int[meshList.size()];
|
|
|
- std::swap_ranges(meshList.begin(), meshList.end(), ainode->mMeshes);
|
|
|
- }
|
|
|
+ if (node.camera) {
|
|
|
+ pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
|
|
|
}
|
|
|
|
|
|
- // TODO load "skeletons", "skin", "jointName", "camera"
|
|
|
+ if (node.light) {
|
|
|
+ pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
|
|
|
+ }
|
|
|
|
|
|
return ainode;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-//
|
|
|
-// glTFImporter methods
|
|
|
-//
|
|
|
-
|
|
|
-template<> const std::string LogFunctions<glTFImporter>::log_prefix = "glTF: ";
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-static const aiImporterDesc desc = {
|
|
|
- "glTF Importer",
|
|
|
- "",
|
|
|
- "",
|
|
|
- "",
|
|
|
- aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour
|
|
|
- | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
|
|
|
- 0,
|
|
|
- 0,
|
|
|
- 0,
|
|
|
- 0,
|
|
|
- "gltf glb"
|
|
|
-};
|
|
|
-
|
|
|
-glTFImporter::glTFImporter()
|
|
|
-: BaseImporter()
|
|
|
+void glTFImporter::ImportNodes(glTF::Asset& r)
|
|
|
{
|
|
|
+ if (!r.scene) return;
|
|
|
|
|
|
-}
|
|
|
-
|
|
|
-glTFImporter::~glTFImporter() {
|
|
|
+ std::vector< Ref<Node> > rootNodes = r.scene->nodes;
|
|
|
|
|
|
-}
|
|
|
-
|
|
|
-bool glTFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const {
|
|
|
- const std::string& extension = GetExtension(pFile);
|
|
|
- if (extension == "gltf" || extension == "glb") {
|
|
|
- return true;
|
|
|
+ // The root nodes
|
|
|
+ unsigned int numRootNodes = rootNodes.size();
|
|
|
+ if (numRootNodes == 1) { // a single root node: use it
|
|
|
+ mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
|
|
|
+ }
|
|
|
+ else if (numRootNodes > 1) { // more than one root node: create a fake root
|
|
|
+ aiNode* root = new aiNode("ROOT");
|
|
|
+ root->mChildren = new aiNode*[numRootNodes];
|
|
|
+ for (unsigned int i = 0; i < numRootNodes; ++i) {
|
|
|
+ aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
|
|
|
+ node->mParent = root;
|
|
|
+ root->mChildren[root->mNumChildren++] = node;
|
|
|
+ }
|
|
|
+ mScene->mRootNode = root;
|
|
|
}
|
|
|
- return false;
|
|
|
-}
|
|
|
|
|
|
-const aiImporterDesc* glTFImporter::GetInfo() const {
|
|
|
- return &desc;
|
|
|
+ //if (!mScene->mRootNode) {
|
|
|
+ // mScene->mRootNode = new aiNode("EMPTY");
|
|
|
+ //}
|
|
|
}
|
|
|
|
|
|
-void glTFImporter::ReadBinaryHeader(IOStream& stream)
|
|
|
+void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r)
|
|
|
{
|
|
|
- GLB_Header header;
|
|
|
- if (stream.Read(&header, sizeof(header), 1) != 1) {
|
|
|
- ThrowException("Unable to read the file header");
|
|
|
- }
|
|
|
-
|
|
|
- if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
|
|
|
- ThrowException("Invalid binary glTF file");
|
|
|
- }
|
|
|
-
|
|
|
- AI_SWAP4(header.version);
|
|
|
- if (header.version != 1) {
|
|
|
- ThrowException("Unsupported binary glTF version");
|
|
|
- }
|
|
|
+ embeddedTexIdxs.resize(r.images.Size(), -1);
|
|
|
|
|
|
- AI_SWAP4(header.sceneFormat);
|
|
|
- if (header.sceneFormat != SceneFormat_JSON) {
|
|
|
- ThrowException("Unsupported binary glTF scene format");
|
|
|
+ int numEmbeddedTexs = 0;
|
|
|
+ for (size_t i = 0; i < r.images.Size(); ++i) {
|
|
|
+ if (r.images[i].HasData())
|
|
|
+ numEmbeddedTexs += 1;
|
|
|
}
|
|
|
|
|
|
- AI_SWAP4(header.length);
|
|
|
- AI_SWAP4(header.sceneLength);
|
|
|
+ if (numEmbeddedTexs == 0)
|
|
|
+ return;
|
|
|
|
|
|
- mSceneLength = static_cast<std::size_t>(header.sceneLength);
|
|
|
-
|
|
|
- mBodyOffset = sizeof(header) + mSceneLength;
|
|
|
- mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
|
|
|
+ mScene->mTextures = new aiTexture*[numEmbeddedTexs];
|
|
|
|
|
|
- mBodyLength = header.length - mBodyOffset;
|
|
|
-}
|
|
|
+ // Add the embedded textures
|
|
|
+ for (size_t i = 0; i < r.images.Size(); ++i) {
|
|
|
+ Image img = r.images[i];
|
|
|
+ if (!img.HasData()) continue;
|
|
|
|
|
|
-void glTFImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) {
|
|
|
- scoped_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
|
|
- if (!stream) {
|
|
|
- ThrowException("Could not open file for reading");
|
|
|
- }
|
|
|
+ int idx = mScene->mNumTextures++;
|
|
|
+ embeddedTexIdxs[i] = idx;
|
|
|
|
|
|
- // is binary? then read the header
|
|
|
- if (GetExtension(pFile) == "glb") {
|
|
|
- ReadBinaryHeader(*stream);
|
|
|
- }
|
|
|
- else {
|
|
|
- mSceneLength = stream->FileSize();
|
|
|
- mBodyLength = 0;
|
|
|
- }
|
|
|
+ aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
|
|
|
|
|
|
+ size_t length = img.GetDataLength();
|
|
|
+ void* data = img.StealData();
|
|
|
|
|
|
- // read the scene data
|
|
|
+ tex->mWidth = static_cast<unsigned int>(length);
|
|
|
+ tex->mHeight = 0;
|
|
|
+ tex->pcData = reinterpret_cast<aiTexel*>(data);
|
|
|
|
|
|
- scoped_ptr<char> sceneData = new char[mSceneLength + 1];
|
|
|
- sceneData[mSceneLength] = '\0';
|
|
|
+ if (!img.mimeType.empty()) {
|
|
|
+ const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
|
|
|
+ if (ext) {
|
|
|
+ if (strcmp(ext, "jpeg") == 0) ext = "jpg";
|
|
|
|
|
|
- if (stream->Read(sceneData, 1, mSceneLength) != mSceneLength) {
|
|
|
- ThrowException("Could not read the file contents");
|
|
|
+ size_t len = strlen(ext);
|
|
|
+ if (len <= 3) {
|
|
|
+ strcpy(tex->achFormatHint, ext);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
|
|
|
|
|
- // parse the JSON document
|
|
|
+ this->mScene = pScene;
|
|
|
+
|
|
|
+ // read the asset file
|
|
|
+ glTF::Asset asset(pIOHandler);
|
|
|
+ asset.Load(pFile, GetExtension(pFile) == "glb");
|
|
|
|
|
|
- Document doc;
|
|
|
- doc.ParseInsitu(sceneData);
|
|
|
|
|
|
- if (doc.HasParseError()) {
|
|
|
- char buffer[32];
|
|
|
- ASSIMP_itoa10(buffer, doc.GetErrorOffset());
|
|
|
- ThrowException(std::string("JSON parse error, offset ") + buffer + ": "
|
|
|
- + GetParseError_En(doc.GetParseError()));
|
|
|
- }
|
|
|
+ //
|
|
|
+ // Copy the data out
|
|
|
+ //
|
|
|
|
|
|
- if (!doc.IsObject()) {
|
|
|
- ThrowException("gltf file must be a JSON object!");
|
|
|
- }
|
|
|
+ ImportEmbeddedTextures(asset);
|
|
|
+ ImportMaterials(asset);
|
|
|
|
|
|
+ ImportMeshes(asset);
|
|
|
|
|
|
- // Buffer instance for the current file embedded contents
|
|
|
- shared_ptr<Buffer> bodyBuffer;
|
|
|
- if (mBodyLength > 0) {
|
|
|
- bodyBuffer.reset(Buffer::FromStream(*stream, mBodyLength, mBodyOffset));
|
|
|
- }
|
|
|
+ ImportCameras(asset);
|
|
|
+ ImportLights(asset);
|
|
|
+
|
|
|
+ ImportNodes(asset);
|
|
|
|
|
|
- // import the data
|
|
|
- glTFReader reader(pScene, doc, *pIOHandler, bodyBuffer);
|
|
|
- reader.Load();
|
|
|
+ // TODO: it does not split the loaded vertices, should it?
|
|
|
+ pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
|
|
|
|
|
if (pScene->mNumMeshes == 0) {
|
|
|
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|