| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- #ifndef GUL_GLTF_LOADER_H
- #define GUL_GLTF_LOADER_H
- #include "MeshPrimitive2.h"
- #include "Image.h"
- #include "math/Transform.h"
- #include <fstream>
- #include <vector>
- #include <nlohmann/json.hpp>
- #include "ImageLoad_stb.h"
- //#include "spdlog/spdlog.h"
- namespace gul
- {
- template<typename T>
- struct typed_id
- {
- uint32_t index=0xFFFFFFFF;
- operator bool() const
- {
- return index != 0xFFFFFFFF;
- }
- };
- struct Sampler
- {
- int magFilter = 9729;
- int minFilter = 9729;
- int wrapS = 10497;
- int wrapT = 10497;
- };
- struct Texture
- {
- typed_id<Sampler> sampler;
- typed_id<Image> source;
- };
- struct Material
- {
- glm::vec3 emissiveFactor = glm::vec3(0,0,0);
- struct
- {
- glm::vec4 baseColorFactor = glm::vec4(1,1,1,1);
- float metallicFactor = 1.0f;
- float roughnessFactor = 1.0f;
- struct
- {
- typed_id<Texture> index;
- int texCoord = 0;
- } baseColorTexture, metallicRoughnessTexture;
- } pbrMetallicRoughness;
- struct
- {
- typed_id<Texture> index;
- int texCoord = 0;
- float scale = 1.0f;
- } normalTexture;
- struct
- {
- typed_id<Texture> index;
- int texCoord = 0;
- float strength = 1.0f;
- } occlusionTexture;
- struct
- {
- typed_id<Texture> index;
- int texCoord = 0;
- } emissiveTexture;
- std::string alphaMode = "OPAQUE";
- float alphaCutOff = 0.5f;
- bool doubleSided = false;
- };
- struct Primitive
- {
- typed_id<MeshPrimitive> primitive;
- typed_id<Material> material;
- };
- struct Mesh
- {
- std::vector<Primitive> primitive;
- };
- struct Node : gul::Transform
- {
- std::vector<uint32_t> children;
- typed_id<Mesh> mesh;
- };
- struct GLTFAsset
- {
- Image& get(typed_id<Image> id)
- {
- return images.at(id.index);
- }
- Mesh& get(typed_id<Mesh> id)
- {
- return meshes.at(id.index);
- }
- std::vector<Node> nodes;
- std::vector<Mesh> meshes;
- //std::vector<Material> materials;
- //std::vector<Texture> textures;
- //std::vector<Sampler> samplers;
- // low level objects
- std::vector<MeshPrimitive> primitives;
- std::vector<Image> images;
- // low
- #define _DEF_VECTOR(type, name) \
- std::vector<type> name;\
- type & get(typed_id<type> id)\
- {\
- return name.at(id.index);\
- }
- _DEF_VECTOR(Material, materials);
- _DEF_VECTOR(Texture, textures);
- _DEF_VECTOR(Sampler, samplers);
- };
- GLTFAsset loadGLTF(std::istream & in, std::string const & rootPath)
- {
- using namespace nlohmann;
- std::map<uint32_t, std::vector<char>> buffers;
- std::vector<VertexAttribute> accessors;
- std::unordered_map<json, uint32_t> meshPrimitives;
- GLTFAsset G;
- json J;
- auto first = in.peek();
- if( first == 0x67 ) // GLTF magic number: 0x46546C67
- {
- // this is a GLB
- uint32_t magic;
- uint32_t version;
- uint32_t length;
- in.read( reinterpret_cast<char*>(&magic), 4);
- in.read( reinterpret_cast<char*>(&version), 4);
- in.read( reinterpret_cast<char*>(&length), 4);
- assert(magic == 0x46546C67);
- uint32_t json_chunk_length;
- uint32_t json_chunk_type;
- in.read( reinterpret_cast<char*>(&json_chunk_length), 4);
- in.read( reinterpret_cast<char*>(&json_chunk_type), 4);
- assert(json_chunk_type == 0x4E4F534A);
- std::string json_string(json_chunk_length, ' ');
- in.read(&json_string[0], json_chunk_length);
- J = json::parse(json_string);
- uint32_t bin_chunk_length;
- uint32_t bin_chunk_type;
- in.read( reinterpret_cast<char*>(&bin_chunk_length), 4);
- in.read( reinterpret_cast<char*>(&bin_chunk_type), 4);
- assert(bin_chunk_type == 0x004E4942);
- buffers[0].resize( bin_chunk_length);
- in.read(buffers[0].data(), bin_chunk_length);
- }
- else
- {
- in >> J;
- uint32_t bi=0;
- for(auto & b : J["buffers"])
- {
- std::cout << "Buffer found: " << b["name"] << std::endl;
- if( b.contains("uri"))
- {
- auto path = rootPath + "/" + b.at("uri").get<std::string>();
- std::ifstream i( path, std::ios_base::binary);
- buffers[bi] =
- std::vector<char>( std::istreambuf_iterator<char>(i),
- std::istreambuf_iterator<char>() );
- }
- ++bi;
- }
- }
- struct Accessor
- {
- uint32_t stride = 0;
- uint32_t componentType = 0;
- std::string type;
- };
- for(auto & a : J["accessors"])
- {
- auto bv_i = a["bufferView"].get<uint32_t>();
- auto & bv = J["bufferViews"][ bv_i ];
- auto b_i = bv["buffer"].get<uint32_t>();
- auto & buffer = buffers[b_i];
- #if 1
- auto type = a.value("type", std::string("UNKNOWN"));
- auto componentType = a.value("componentType", 0u);
- auto count = a.value("count", 0u);
- auto byteOffset = a.value("byteOffset", 0u);
- auto bufferViewByteStride = bv.value("byteStride", 0u);
- auto bufferViewByteOffset = bv.value("byteOffset", 0u);
- auto V = fromGLTFAccessor(buffer.data() + bufferViewByteOffset,
- bufferViewByteStride, count, byteOffset,componentType,type);
- #else
- uint32_t stride=0;
- auto type = a["type"].get<std::string>();
- auto componentType = a["componentType"].get<uint32_t>();
- auto count = a["count"].get<uint32_t>();
- eType _type = {};
- if(type == "SCALAR") _type = eType::SCALAR;
- if(type == "VEC2") _type = eType::VEC2;
- if(type == "VEC3") _type = eType::VEC3;
- if(type == "VEC4") _type = eType::VEC4;
- auto bufferViewData = buffer.data();
- if(bv.contains("byteOffset"))
- {
- bufferViewData += bv.at("byteOffset").get<uint32_t>();
- }
- if(a.contains("byteOffset"))
- {
- bufferViewData += a.at("byteOffset").get<uint32_t>();
- }
- VertexAttribute V( eComponentType(componentType), _type);
- if(bv.contains("byteStride"))
- {
- stride = bv.at("byteStride").get<uint32_t>();
- }
- else
- {
- stride = V.getAttributeSize();
- }
- auto attrSize = V.getAttributeSize();
- for(uint32_t jj=0;jj<count;jj++)
- {
- std::memcpy( static_cast<uint8_t*>(V.data()) + jj*attrSize,
- bufferViewData + jj*stride,
- attrSize);
- }
- #endif
- std::cout << "Accessor Found: " << type << " " << V.getByteSize() << " Count: " << V.attributeCount() << std::endl;
- accessors.push_back( std::move(V) );
- };
- for(auto & i : J["images"])
- {
- if(i.contains("uri"))
- {
- auto path = rootPath + "/" + i.at("uri").get<std::string>();
- #if 1
- G.images.push_back( gul::loadImage(path) );
- #else
- std::ifstream i(path, std::ios_base::binary);
- auto data = std::vector<char>( std::istreambuf_iterator<char>(i), std::istreambuf_iterator<char>() );
- G.images.push_back( gul::loadImage(data.data(), int(data.size())));
- #endif
- }
- else if(i.contains("bufferView"))
- {
- //uint32_t bvi = ;
- auto & b = J["bufferViews"][ i["bufferView"].get<uint32_t>() ] ;
- uint32_t bufferIndex = b["buffer"];
- auto bufferData = buffers[bufferIndex].data();
- if(b.contains("byteOffset"))
- {
- bufferData += b["byteOffset"].get<uint32_t>();
- }
- auto byteLength = b["byteLength"].get<int32_t>();
- auto I = gul::loadImage(bufferData, byteLength);
- G.images.push_back( std::move(I));
- }
- }
- for(auto & v : J["meshes"])
- {
- auto & m = G.meshes.emplace_back();
- for(auto & p : v["primitives"])
- {
- json P;
- P = p["attributes"];
- P["indices"] = p["indices"];
- if(meshPrimitives.count(P) == 0)
- {
- gul::MeshPrimitive M;
- if(P.contains("POSITION")) M.POSITION = accessors[ P["POSITION"].get<uint32_t>() ];
- if(P.contains("NORMAL")) M.NORMAL = accessors[ P["NORMAL"].get<uint32_t>() ];
- if(P.contains("TANGENT")) M.TANGENT = accessors[ P["TANGENT"].get<uint32_t>() ];
- if(P.contains("TEXCOORD_0")) M.TEXCOORD_0 = accessors[ P["TEXCOORD_0"].get<uint32_t>() ];
- if(P.contains("TEXCOORD_1")) M.TEXCOORD_1 = accessors[ P["TEXCOORD_1"].get<uint32_t>() ];
- if(P.contains("JOINTS_0")) M.JOINTS_0 = accessors[ P["JOINTS_0"].get<uint32_t>() ];
- if(P.contains("WEIGHTS_0")) M.WEIGHTS_0 = accessors[ P["WEIGHTS_0"].get<uint32_t>() ];
- if(P.contains("COLOR_0")) M.COLOR_0 = accessors[ P["COLOR_0"].get<uint32_t>() ];
- if(P.contains("indices")) M.INDEX = accessors[ P["indices"].get<uint32_t>() ];
- std::cout << "Mesh found: " << v["name"] << ": " << M.calculateDeviceSize() << std::endl;
- G.primitives.push_back(std::move(M));
- meshPrimitives[P] = uint32_t(G.primitives.size()-1);
- }
- auto & pr = m.primitive.emplace_back();
- pr.primitive.index = meshPrimitives.at(P);
- if(p.count("material"))
- {
- pr.material.index = p.at("material").get<uint32_t>();
- }
- }
- }
- for(auto & n : J["nodes"])
- {
- auto & N = G.nodes.emplace_back();
- if(n.contains("position"))
- {
- N.position.x = n.at("position")[0].get<float>();
- N.position.y = n.at("position")[1].get<float>();
- N.position.z = n.at("position")[2].get<float>();
- }
- if(n.contains("rotation"))
- {
- N.rotation.x = n.at("rotation")[0].get<float>();
- N.rotation.y = n.at("rotation")[1].get<float>();
- N.rotation.z = n.at("rotation")[2].get<float>();
- N.rotation.w = n.at("rotation")[3].get<float>();
- }
- if(n.contains("scale"))
- {
- N.scale.x = n.at("scale")[0].get<float>();
- N.scale.y = n.at("scale")[1].get<float>();
- N.scale.z = n.at("scale")[2].get<float>();
- }
- if(n.contains("children"))
- {
- N.children = n.at("children").get< std::vector<uint32_t> >();
- }
- if(n.contains("mesh"))
- {
- N.mesh.index = n.at("mesh").get< uint32_t >();
- }
- }
- for(auto & t : J["samplers"])
- {
- auto & S = G.samplers.emplace_back();
- if(t.contains("magFilter")) S.magFilter = t["magFilter"].get<int>();
- if(t.contains("minFilter")) S.magFilter = t["minFilter"].get<int>();
- if(t.contains("wrapS")) S.wrapS = t["wrapS"].get<int>();
- if(t.contains("wrapT")) S.wrapT = t["wrapT"].get<int>();
- }
- for(auto & t : J["textures"])
- {
- auto & S = G.textures.emplace_back();
- if(t.contains("sampler")) S.sampler.index = t["sampler"].get<uint32_t>();
- if(t.contains("source")) S.source .index = t["source"].get<uint32_t>();
- }
- for(auto & t : J["materials"])
- {
- auto & S = G.materials.emplace_back();
- //json jj;
- #define _GETIF(VAR, jj, prop)\
- if(jj.contains(#prop))\
- {\
- VAR = jj[#prop].get< decltype(VAR) >();\
- }\
- if(t.contains("normalTexture"))
- {
- auto & normalTexture = t["normalTexture"];
- _GETIF(S.normalTexture.index.index , normalTexture, "index" );
- _GETIF(S.normalTexture.texCoord , normalTexture, "texCoord");
- _GETIF(S.normalTexture.scale , normalTexture, "scale" );
- }
- if(t.contains("occlusionTexture"))
- {
- auto & normalTexture = t["occlusionTexture"];
- _GETIF(S.occlusionTexture.index.index , normalTexture, "index" );
- _GETIF(S.occlusionTexture.texCoord , normalTexture, "texCoord");
- _GETIF(S.occlusionTexture.strength , normalTexture, "strength" );
- }
- if(t.contains("emissiveFactor"))
- {
- auto & bc = t["emissiveFactor"];
- S.emissiveFactor = glm::vec3(bc[0],bc[1],bc[2]);
- }
- if(t.contains("pbrMetallicRoughness"))
- {
- auto & pbrMetallicRoughness = t["pbrMetallicRoughness"];
- if(pbrMetallicRoughness.contains("baseColorFactor"))
- {
- auto & bc = pbrMetallicRoughness["baseColorFactor"];
- S.pbrMetallicRoughness.baseColorFactor = glm::vec4(bc[0],bc[1],bc[2],bc[3]);
- }
- if(pbrMetallicRoughness.contains("baseColorTexture"))
- {
- auto &bc = pbrMetallicRoughness["baseColorTexture"];
- S.pbrMetallicRoughness.baseColorTexture.index.index = bc.value("index", 0u);//bc["index"];
- S.pbrMetallicRoughness.baseColorTexture.texCoord = bc.value("texCoord", 0);
- }
- if(pbrMetallicRoughness.contains("metallicRoughnessTexture"))
- {
- auto &bc = pbrMetallicRoughness["metallicRoughnessTexture"];
- S.pbrMetallicRoughness.metallicRoughnessTexture.index.index = bc.value("index", 0u);
- S.pbrMetallicRoughness.metallicRoughnessTexture.texCoord = bc.value("texCoord", 0);
- }
- if(t.contains("emissiveTexture"))
- {
- auto &bc = t["emissiveTexture"];
- S.emissiveTexture.index.index = bc.value("index", 0u);
- S.emissiveTexture.texCoord = bc.value("texCoord", 0);
- }
- if(t.contains("occlusionTexture"))
- {
- auto &bc = t["occlusionTexture"];
- S.occlusionTexture.index.index = bc.value("index", 0u);
- S.occlusionTexture.texCoord = bc.value("texCoord", 0);
- S.occlusionTexture.strength = bc.value("strength", 1.f);
- }
- S.pbrMetallicRoughness.metallicFactor = pbrMetallicRoughness.value("metallicFactor", 1.0f);
- S.pbrMetallicRoughness.roughnessFactor = pbrMetallicRoughness.value("roughnessFactor", 1.0f);
- if(t.contains("normalTexture"))
- {
- auto &bc = t["normalTexture"];
- S.normalTexture.index.index = bc.value("index", 0u);
- S.normalTexture.texCoord = bc.value("texCoord", 0);
- }
- S.alphaCutOff = t.value("alphaCutOff", 0.5f);
- S.alphaMode = t.value("alphaMode", std::string("OPAQUE"));
- S.doubleSided = t.value("doubleSided", false);
- }
- }
- return G;
- }
- }
- #endif
|