From 70e520eaf2fc61a3b889b4dae4acf16c2f76a170 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Thu, 4 Feb 2021 11:50:03 +0100 Subject: [PATCH] Add gltf file class --- inferno/src/inferno/io/file.cpp | 4 +- inferno/src/inferno/io/gltffile.cpp | 100 ++++++++++++++++++++++++++++ inferno/src/inferno/io/gltffile.h | 22 ++++++ 3 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 inferno/src/inferno/io/gltffile.cpp create mode 100644 inferno/src/inferno/io/gltffile.h diff --git a/inferno/src/inferno/io/file.cpp b/inferno/src/inferno/io/file.cpp index 74b8ebb..9b39e89 100644 --- a/inferno/src/inferno/io/file.cpp +++ b/inferno/src/inferno/io/file.cpp @@ -1,5 +1,5 @@ -#include // std::ios -#include // std::make_unique +#include // std::ios +#include // std::make_unique #include "inferno/assert.h" #include "inferno/io/file.h" diff --git a/inferno/src/inferno/io/gltffile.cpp b/inferno/src/inferno/io/gltffile.cpp new file mode 100644 index 0000000..9e93e05 --- /dev/null +++ b/inferno/src/inferno/io/gltffile.cpp @@ -0,0 +1,100 @@ +#include // strcmp ?? +#include // std::ifstream +#include // std::ios + +#include "inferno/assert.h" +#include "inferno/io/file.h" +#include "inferno/io/gltffile.h" +#include "inferno/io/log.h" +#include "inferno/util/string.h" + +namespace Inferno { + + std::pair, std::shared_ptr> GlTFFile::read(const std::string& path) + { + std::string extension = path.substr(path.find_first_of(".")); + + if (extension.compare(".glb") == 0) { + return glb(path); + } + else if (extension.compare(".gltf") == 0) { + ASSERT_NOT_REACHED(); + } + + return {}; + } + + std::pair, std::shared_ptr> GlTFFile::glb(const std::string& path) + { + // Create input stream object and open file + std::ifstream glb(path, std::ios::in | std::ios::binary); + ASSERT(glb.is_open(), "GlTFFile could not open '{}'", path); + + constexpr uint32_t size = 4; + constexpr uint32_t header = 12; + constexpr uint32_t json = 27; // Minimum valid glTF has an asset property with version specifier + + // Get the actual length of the file + uint32_t length = static_cast(File::length(path, glb)); + ASSERT(length > header + json, "GlTFFile too small to be valid '{}'", path); + + // Read header + + char magic[size]; + char version[size]; + char fileLength[size]; + + glb.read(magic, size); + glb.seekg(size * 1); + glb.read(version, size); + glb.seekg(size * 2); + glb.read(fileLength, size); + + // Validate header + + uint32_t magicInt = *reinterpret_cast(magic); + ASSERT(magicInt == 0x46546c67, "GlTF invalid header magic '{}'", magic); + + uint32_t versionInt = *reinterpret_cast(version); + ASSERT(versionInt == 2, "GlTF unsupported version '{}'", versionInt); + + uint32_t fileLengthInt = *reinterpret_cast(fileLength); + ASSERT(fileLengthInt == length, "GlTF file and reported byte size mismatch '{}' '{}'", length, fileLengthInt); + + // Read JSON data + auto jsonChunk = readChunk(glb, header, 0x4e4f534a); + + // Read binary data + auto binaryChunk = readChunk(glb, header + size * 2 + jsonChunk.second, 0x004e4942); + + glb.close(); + + return { jsonChunk.first, binaryChunk.first }; + } + + std::pair, uint32_t> GlTFFile::readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type) + { + constexpr uint32_t size = 4; + + char chunkLength[size]; + char chunkType[size]; + + ifstream.seekg(offset); + ifstream.read(chunkLength, size); + ifstream.seekg(offset + size * 1); + ifstream.read(chunkType, size); + + uint32_t chunkTypeInt = *reinterpret_cast(chunkType); + ASSERT(chunkTypeInt == type, "GlTF invalid chunk type '{}' != '{}'", chunkType, intToHex(type)); + + uint32_t chunkLengthInt = *reinterpret_cast(chunkLength); + // Allocate memory filled with zeros + std::shared_ptr chunkData(new char[chunkLengthInt + 1]); + ifstream.seekg(offset + size * 2); + ifstream.read(chunkData.get(), chunkLengthInt); + chunkData.get()[chunkLengthInt] = '\0'; + + return { chunkData, chunkLengthInt }; + } + +} // namespace Inferno diff --git a/inferno/src/inferno/io/gltffile.h b/inferno/src/inferno/io/gltffile.h new file mode 100644 index 0000000..b33ddd7 --- /dev/null +++ b/inferno/src/inferno/io/gltffile.h @@ -0,0 +1,22 @@ +#ifndef GLTF_FILE_H +#define GLTF_FILE_H + +#include // uint32_t +#include // std::shared_ptr +#include // std::string +#include // std::pair + +namespace Inferno { + + class GlTFFile { + public: + static std::pair, std::shared_ptr> read(const std::string& path); + + private: + static std::pair, std::shared_ptr> glb(const std::string& path); + static std::pair, uint32_t> readChunk(std::ifstream& ifstream, uint32_t offset, uint32_t type); + }; + +} // namespace Inferno + +#endif // GLTF_FILE_H