mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-09-13 11:43:15 +08:00
Merge remote-tracking branch 'origin/devel' into generic_extension_support
# Conflicts: # tiny_gltf.h
This commit is contained in:
commit
341fc31aee
20
README.md
20
README.md
@ -51,7 +51,8 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
|
|
||||||
* Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR
|
* Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR
|
||||||
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF
|
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF
|
||||||
* Your projects here!(Plese send PR)
|
* [TinyGltfImporter](http://doc.magnum.graphics/magnum/classMagnum_1_1Trade_1_1TinyGltfImporter.html) plugin for [Magnum](https://github.com/mosra/magnum), a lightweight and modular C++11/C++14 graphics middleware for games and data visualization.
|
||||||
|
* Your projects here! (Please send PR)
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
@ -71,12 +72,13 @@ TinyGLTF uses the following third party libraries.
|
|||||||
|
|
||||||
* json.hpp : Copyright (c) 2013-2017 Niels Lohmann. MIT license.
|
* json.hpp : Copyright (c) 2013-2017 Niels Lohmann. MIT license.
|
||||||
* base64 : Copyright (C) 2004-2008 René Nyffenegger
|
* base64 : Copyright (C) 2004-2008 René Nyffenegger
|
||||||
* stb_image.h : v2.08 - public domain image loader - http://nothings.org/stb_image.h
|
* stb_image.h : v2.08 - public domain image loader - [Github link](https://github.com/nothings/stb/blob/master/stb_image.h)
|
||||||
|
* stb_image_write.h : v1.09 - public domain image writer - [Github link](https://github.com/nothings/stb/blob/master/stb_image_write.h)
|
||||||
|
|
||||||
|
|
||||||
## Build and example
|
## Build and example
|
||||||
|
|
||||||
Copy `stb_image.h`, `json.hpp` and `tiny_gltf.h` to your project.
|
Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your project.
|
||||||
|
|
||||||
### Loading glTF 2.0 model
|
### Loading glTF 2.0 model
|
||||||
|
|
||||||
@ -84,6 +86,7 @@ Copy `stb_image.h`, `json.hpp` and `tiny_gltf.h` to your project.
|
|||||||
// Define these only in *one* .cc file.
|
// Define these only in *one* .cc file.
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
|
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
|
||||||
#include "tiny_gltf.h"
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
@ -109,10 +112,17 @@ if (!ret) {
|
|||||||
|
|
||||||
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
||||||
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
|
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
|
||||||
|
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
|
||||||
|
|
||||||
### Saving gltTF 2.0 model
|
### Saving gltTF 2.0 model
|
||||||
|
* [ ] Buffers.
|
||||||
T.B.W.
|
* [x] To file
|
||||||
|
* [x] Embedded
|
||||||
|
* [ ] Draco compressed?
|
||||||
|
* [x] Images
|
||||||
|
* [x] To file
|
||||||
|
* [x] Embedded
|
||||||
|
* [ ] Binary(.glb)
|
||||||
|
|
||||||
## Running tests.
|
## Running tests.
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory> // c++11
|
#include <memory> // c++11
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
#include <tiny_gltf.h>
|
#include <tiny_gltf.h>
|
||||||
|
|
||||||
namespace example {
|
namespace example {
|
||||||
|
@ -3,10 +3,20 @@
|
|||||||
|
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
||||||
|
//#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If using a modern Microsoft Compiler, this define supress compilation
|
||||||
|
// warnings in stb_image_write
|
||||||
|
//#define STBI_MSC_SECURE_CRT
|
||||||
|
|
||||||
#include "tiny_gltf.h"
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[]) {
|
||||||
{
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
std::cout << "Needs input.gltf output.gltf" << std::endl;
|
std::cout << "Needs input.gltf output.gltf" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -17,6 +27,8 @@ int main(int argc, char *argv[])
|
|||||||
std::string err;
|
std::string err;
|
||||||
std::string input_filename(argv[1]);
|
std::string input_filename(argv[1]);
|
||||||
std::string output_filename(argv[2]);
|
std::string output_filename(argv[2]);
|
||||||
|
std::string embedded_filename =
|
||||||
|
output_filename.substr(0, output_filename.size() - 5) + "-Embedded.gltf";
|
||||||
|
|
||||||
// assume ascii glTF.
|
// assume ascii glTF.
|
||||||
bool ret = loader.LoadASCIIFromFile(&model, &err, input_filename.c_str());
|
bool ret = loader.LoadASCIIFromFile(&model, &err, input_filename.c_str());
|
||||||
@ -28,6 +40,10 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
loader.WriteGltfSceneToFile(&model, output_filename);
|
loader.WriteGltfSceneToFile(&model, output_filename);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
// Embedd buffers and images
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
loader.WriteGltfSceneToFile(&model, embedded_filename, true, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#define TINYGLTF_IMPLEMENTATION
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
#include "tiny_gltf.h"
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
1831
stb_image_write.h
Normal file
1831
stb_image_write.h
Normal file
File diff suppressed because it is too large
Load Diff
335
tiny_gltf.h
335
tiny_gltf.h
@ -4,7 +4,7 @@
|
|||||||
//
|
//
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2015 - 2017 Syoyo Fujita, Aurélien Chatelain and many
|
// Copyright (c) 2015 - 2018 Syoyo Fujita, Aurélien Chatelain and many
|
||||||
// contributors.
|
// contributors.
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@ -733,6 +733,12 @@ enum SectionCheck {
|
|||||||
typedef bool (*LoadImageDataFunction)(Image *, std::string *, int, int,
|
typedef bool (*LoadImageDataFunction)(Image *, std::string *, int, int,
|
||||||
const unsigned char *, int, void *);
|
const unsigned char *, int, void *);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
|
||||||
|
///
|
||||||
|
typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *,
|
||||||
|
Image *, bool, void *);
|
||||||
|
|
||||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||||
// Declaration of default image loader callback
|
// Declaration of default image loader callback
|
||||||
bool LoadImageData(Image *image, std::string *err, int req_width,
|
bool LoadImageData(Image *image, std::string *err, int req_width,
|
||||||
@ -740,6 +746,12 @@ bool LoadImageData(Image *image, std::string *err, int req_width,
|
|||||||
void *);
|
void *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
// Declaration of default image writer callback
|
||||||
|
bool WriteImageData(const std::string *basepath, const std::string *filename,
|
||||||
|
Image *image, bool embedImages, void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
class TinyGLTF {
|
class TinyGLTF {
|
||||||
public:
|
public:
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@ -795,16 +807,20 @@ class TinyGLTF {
|
|||||||
///
|
///
|
||||||
/// Write glTF to file.
|
/// Write glTF to file.
|
||||||
///
|
///
|
||||||
bool WriteGltfSceneToFile(
|
bool WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||||
Model *model,
|
bool embedImages,
|
||||||
const std::string &
|
bool embedBuffers /*, bool writeBinary*/);
|
||||||
filename /*, bool embedImages, bool embedBuffers, bool writeBinary*/);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set callback to use for loading image data
|
/// Set callback to use for loading image data
|
||||||
///
|
///
|
||||||
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
|
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set callback to use for writing image data
|
||||||
|
///
|
||||||
|
void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
/// Loads glTF asset from string(memory).
|
/// Loads glTF asset from string(memory).
|
||||||
@ -826,6 +842,14 @@ class TinyGLTF {
|
|||||||
nullptr;
|
nullptr;
|
||||||
#endif
|
#endif
|
||||||
void *load_image_user_data_ = nullptr;
|
void *load_image_user_data_ = nullptr;
|
||||||
|
|
||||||
|
WriteImageDataFunction WriteImageData =
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
&tinygltf::WriteImageData;
|
||||||
|
#else
|
||||||
|
nullptr;
|
||||||
|
#endif
|
||||||
|
void *write_image_user_data_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@ -855,6 +879,7 @@ class TinyGLTF {
|
|||||||
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||||
#pragma clang diagnostic ignored "-Wpadded"
|
#pragma clang diagnostic ignored "-Wpadded"
|
||||||
#pragma clang diagnostic ignored "-Wc++98-compat"
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
|
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
||||||
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
|
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
|
||||||
#pragma clang diagnostic ignored "-Wswitch-enum"
|
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
@ -869,6 +894,18 @@ class TinyGLTF {
|
|||||||
#if __has_warning("-Wcast-qual")
|
#if __has_warning("-Wcast-qual")
|
||||||
#pragma clang diagnostic ignored "-Wcast-qual"
|
#pragma clang diagnostic ignored "-Wcast-qual"
|
||||||
#endif
|
#endif
|
||||||
|
#if __has_warning("-Wmissing-variable-declarations")
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
|
||||||
|
#endif
|
||||||
|
#if __has_warning("-Wmissing-prototypes")
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#endif
|
||||||
|
#if __has_warning("-Wcast-align")
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-align"
|
||||||
|
#endif
|
||||||
|
#if __has_warning("-Wnewline-eof")
|
||||||
|
#pragma clang diagnostic ignored "-Wnewline-eof"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "./json.hpp"
|
#include "./json.hpp"
|
||||||
@ -877,6 +914,10 @@ class TinyGLTF {
|
|||||||
#include "./stb_image.h"
|
#include "./stb_image.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
#include "./stb_image_write.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
@ -1018,12 +1059,11 @@ static std::string FindFile(const std::vector<std::string> &paths,
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::string GetFilePathExtension(const std::string& FileName)
|
static std::string GetFilePathExtension(const std::string &FileName) {
|
||||||
//{
|
if (FileName.find_last_of(".") != std::string::npos)
|
||||||
// if(FileName.find_last_of(".") != std::string::npos)
|
return FileName.substr(FileName.find_last_of(".") + 1);
|
||||||
// return FileName.substr(FileName.find_last_of(".")+1);
|
return "";
|
||||||
// return "";
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
static std::string GetBaseDir(const std::string &filepath) {
|
static std::string GetBaseDir(const std::string &filepath) {
|
||||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||||
@ -1032,11 +1072,11 @@ static std::string GetBaseDir(const std::string &filepath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path
|
// https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path
|
||||||
std::string GetBaseFilename(const std::string &filepath) {
|
static std::string GetBaseFilename(const std::string &filepath) {
|
||||||
return filepath.substr(filepath.find_last_of("/\\") + 1);
|
return filepath.substr(filepath.find_last_of("/\\") + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::string base64_encode(unsigned char const* , unsigned int len);
|
std::string base64_encode(unsigned char const *, unsigned int len);
|
||||||
std::string base64_decode(std::string const &s);
|
std::string base64_decode(std::string const &s);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1082,6 +1122,46 @@ static inline bool is_base64(unsigned char c) {
|
|||||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string base64_encode(unsigned char const *bytes_to_encode,
|
||||||
|
unsigned int in_len) {
|
||||||
|
std::string ret;
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
unsigned char char_array_3[3];
|
||||||
|
unsigned char char_array_4[4];
|
||||||
|
|
||||||
|
while (in_len--) {
|
||||||
|
char_array_3[i++] = *(bytes_to_encode++);
|
||||||
|
if (i == 3) {
|
||||||
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
|
char_array_4[1] =
|
||||||
|
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||||
|
char_array_4[2] =
|
||||||
|
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||||
|
|
||||||
|
for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
for (j = i; j < 3; j++) char_array_3[j] = '\0';
|
||||||
|
|
||||||
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
|
char_array_4[1] =
|
||||||
|
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||||
|
char_array_4[2] =
|
||||||
|
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
|
||||||
|
for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
|
||||||
|
|
||||||
|
while ((i++ < 3)) ret += '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::string base64_decode(std::string const &encoded_string) {
|
std::string base64_decode(std::string const &encoded_string) {
|
||||||
int in_len = static_cast<int>(encoded_string.size());
|
int in_len = static_cast<int>(encoded_string.size());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -1258,6 +1338,121 @@ bool LoadImageData(Image *image, std::string *err, int req_width,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void TinyGLTF::SetImageWriter(WriteImageDataFunction func, void *user_data) {
|
||||||
|
WriteImageData = func;
|
||||||
|
write_image_user_data_ = user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
static void WriteToMemory_stbi(void *context, void *data, int size) {
|
||||||
|
std::vector<unsigned char> *buffer =
|
||||||
|
reinterpret_cast<std::vector<unsigned char> *>(context);
|
||||||
|
|
||||||
|
unsigned char *pData = reinterpret_cast<unsigned char *>(data);
|
||||||
|
|
||||||
|
buffer->insert(buffer->end(), pData, pData + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteImageData(const std::string *basepath, const std::string *filename,
|
||||||
|
Image *image, bool embedImages, void *) {
|
||||||
|
const std::string ext = GetFilePathExtension(*filename);
|
||||||
|
|
||||||
|
if (embedImages) {
|
||||||
|
// Write image to memory and embed in output
|
||||||
|
std::string header;
|
||||||
|
std::vector<unsigned char> data;
|
||||||
|
|
||||||
|
if (ext == "png") {
|
||||||
|
stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
|
||||||
|
image->height, image->component, &image->image[0],
|
||||||
|
0);
|
||||||
|
header = "data:image/png;base64,";
|
||||||
|
} else if (ext == "jpg") {
|
||||||
|
stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width,
|
||||||
|
image->height, image->component, &image->image[0],
|
||||||
|
100);
|
||||||
|
header = "data:image/jpeg;base64,";
|
||||||
|
} else if (ext == "bmp") {
|
||||||
|
stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width,
|
||||||
|
image->height, image->component, &image->image[0]);
|
||||||
|
header = "data:image/bmp;base64,";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.size()) {
|
||||||
|
image->uri =
|
||||||
|
header +
|
||||||
|
base64_encode(&data[0], static_cast<unsigned int>(data.size()));
|
||||||
|
} else {
|
||||||
|
// Throw error?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Write image to disc
|
||||||
|
|
||||||
|
const std::string imagefilepath = JoinPath(*basepath, *filename);
|
||||||
|
if (ext == "png") {
|
||||||
|
stbi_write_png(imagefilepath.c_str(), image->width, image->height,
|
||||||
|
image->component, &image->image[0], 0);
|
||||||
|
} else if (ext == "jpg") {
|
||||||
|
// TODO (Bowald): Give user the option to set output quality?
|
||||||
|
const int quality = 100;
|
||||||
|
stbi_write_jpg(imagefilepath.c_str(), image->width, image->height,
|
||||||
|
image->component, &image->image[0], quality);
|
||||||
|
} else if (ext == "bmp") {
|
||||||
|
stbi_write_bmp(imagefilepath.c_str(), image->width, image->height,
|
||||||
|
image->component, &image->image[0]);
|
||||||
|
} else {
|
||||||
|
// Throw error? Cant output requested format.
|
||||||
|
}
|
||||||
|
image->uri = *filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static std::string MimeToExt(const std::string &mimeType) {
|
||||||
|
if (mimeType == "image/jpeg") {
|
||||||
|
return "jpg";
|
||||||
|
} else if (mimeType == "image/png") {
|
||||||
|
return "png";
|
||||||
|
} else if (mimeType == "image/bmp") {
|
||||||
|
return "bmp";
|
||||||
|
} else if (mimeType == "image/gif") {
|
||||||
|
return "gif";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
||||||
|
bool embedImages,
|
||||||
|
WriteImageDataFunction *WriteImageData = nullptr,
|
||||||
|
void *user_data = nullptr) {
|
||||||
|
std::string filename;
|
||||||
|
std::string ext;
|
||||||
|
|
||||||
|
// If image have uri. Use it it as a filename
|
||||||
|
if (image.uri.size()) {
|
||||||
|
filename = GetBaseFilename(image.uri);
|
||||||
|
ext = GetFilePathExtension(filename);
|
||||||
|
|
||||||
|
} else if (image.name.size()) {
|
||||||
|
ext = MimeToExt(image.mimeType);
|
||||||
|
// Otherwise use name as filename
|
||||||
|
filename = image.name + "." + ext;
|
||||||
|
} else {
|
||||||
|
ext = MimeToExt(image.mimeType);
|
||||||
|
// Fallback to index of image as filename
|
||||||
|
filename = std::to_string(index) + "." + ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If callback is set, modify image data object
|
||||||
|
if (*WriteImageData != nullptr) {
|
||||||
|
std::string uri;
|
||||||
|
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsDataURI(const std::string &in) {
|
static bool IsDataURI(const std::string &in) {
|
||||||
std::string header = "data:application/octet-stream;base64,";
|
std::string header = "data:application/octet-stream;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
@ -1298,8 +1493,8 @@ static bool IsDataURI(const std::string &in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool DecodeDataURI(std::vector<unsigned char> *out,
|
static bool DecodeDataURI(std::vector<unsigned char> *out,
|
||||||
const std::string &in, size_t reqBytes,
|
std::string &mime_type, const std::string &in,
|
||||||
bool checkSize) {
|
size_t reqBytes, bool checkSize) {
|
||||||
std::string header = "data:application/octet-stream;base64,";
|
std::string header = "data:application/octet-stream;base64,";
|
||||||
std::string data;
|
std::string data;
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
@ -1309,6 +1504,7 @@ static bool DecodeDataURI(std::vector<unsigned char> *out,
|
|||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
header = "data:image/jpeg;base64,";
|
header = "data:image/jpeg;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
|
mime_type = "image/jpeg";
|
||||||
data = base64_decode(in.substr(header.size())); // cut mime string.
|
data = base64_decode(in.substr(header.size())); // cut mime string.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1316,6 +1512,7 @@ static bool DecodeDataURI(std::vector<unsigned char> *out,
|
|||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
header = "data:image/png;base64,";
|
header = "data:image/png;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
|
mime_type = "image/png";
|
||||||
data = base64_decode(in.substr(header.size())); // cut mime string.
|
data = base64_decode(in.substr(header.size())); // cut mime string.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1323,6 +1520,7 @@ static bool DecodeDataURI(std::vector<unsigned char> *out,
|
|||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
header = "data:image/bmp;base64,";
|
header = "data:image/bmp;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
|
mime_type = "image/bmp";
|
||||||
data = base64_decode(in.substr(header.size())); // cut mime string.
|
data = base64_decode(in.substr(header.size())); // cut mime string.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1330,6 +1528,7 @@ static bool DecodeDataURI(std::vector<unsigned char> *out,
|
|||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
header = "data:image/gif;base64,";
|
header = "data:image/gif;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
|
mime_type = "image/gif";
|
||||||
data = base64_decode(in.substr(header.size())); // cut mime string.
|
data = base64_decode(in.substr(header.size())); // cut mime string.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1337,6 +1536,7 @@ static bool DecodeDataURI(std::vector<unsigned char> *out,
|
|||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
header = "data:text/plain;base64,";
|
header = "data:text/plain;base64,";
|
||||||
if (in.find(header) == 0) {
|
if (in.find(header) == 0) {
|
||||||
|
mime_type = "text/plain";
|
||||||
data = base64_decode(in.substr(header.size()));
|
data = base64_decode(in.substr(header.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1739,8 +1939,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseImage(Image *image, std::string *err, const json &o,
|
static bool ParseImage(Image *image, std::string *err, const json &o,
|
||||||
const std::string &basedir, bool is_binary,
|
const std::string &basedir,
|
||||||
const unsigned char *bin_data, size_t bin_size,
|
|
||||||
LoadImageDataFunction *LoadImageData = nullptr,
|
LoadImageDataFunction *LoadImageData = nullptr,
|
||||||
void *user_data = nullptr) {
|
void *user_data = nullptr) {
|
||||||
// A glTF image must either reference a bufferView or an image uri
|
// A glTF image must either reference a bufferView or an image uri
|
||||||
@ -1753,7 +1952,9 @@ static bool ParseImage(Image *image, std::string *err, const json &o,
|
|||||||
if (hasBufferView && hasURI) {
|
if (hasBufferView && hasURI) {
|
||||||
// Should not both defined.
|
// Should not both defined.
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Only one of `bufferView` or `uri` should be defined, but both are defined for Image.\n";
|
(*err) +=
|
||||||
|
"Only one of `bufferView` or `uri` should be defined, but both are "
|
||||||
|
"defined for Image.\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1809,7 +2010,7 @@ static bool ParseImage(Image *image, std::string *err, const json &o,
|
|||||||
std::vector<unsigned char> img;
|
std::vector<unsigned char> img;
|
||||||
|
|
||||||
if (IsDataURI(uri)) {
|
if (IsDataURI(uri)) {
|
||||||
if (!DecodeDataURI(&img, uri, 0, false)) {
|
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to decode 'uri' for image parameter.\n";
|
(*err) += "Failed to decode 'uri' for image parameter.\n";
|
||||||
}
|
}
|
||||||
@ -1931,7 +2132,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (IsDataURI(buffer->uri)) {
|
if (IsDataURI(buffer->uri)) {
|
||||||
if (!DecodeDataURI(&buffer->data, buffer->uri, bytes, true)) {
|
std::string mime_type;
|
||||||
|
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes, true)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
|
(*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
|
||||||
}
|
}
|
||||||
@ -2934,8 +3136,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Image image;
|
Image image;
|
||||||
if (!ParseImage(&image, err, it.value(), base_dir, is_binary_,
|
if (!ParseImage(&image, err, it.value(), base_dir, &this->LoadImageData,
|
||||||
bin_data_, bin_size_, &this->LoadImageData,
|
|
||||||
load_image_user_data_)) {
|
load_image_user_data_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3318,8 +3519,9 @@ static void SerializeNumberArrayProperty(const std::string &key,
|
|||||||
for (unsigned int i = 0; i < value.size(); ++i) {
|
for (unsigned int i = 0; i < value.size(); ++i) {
|
||||||
vals.push_back(static_cast<double>(value[i]));
|
vals.push_back(static_cast<double>(value[i]));
|
||||||
}
|
}
|
||||||
|
if (!vals.is_null()) {
|
||||||
obj[key] = vals;
|
obj[key] = vals;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeStringProperty(const std::string &key,
|
static void SerializeStringProperty(const std::string &key,
|
||||||
@ -3398,6 +3600,14 @@ static void SerializeValue(const std::string &key, const Value &value,
|
|||||||
obj[key] = ret;
|
obj[key] = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
||||||
|
json &o) {
|
||||||
|
std::string header = "data:application/octet-stream;base64,";
|
||||||
|
std::string encodedData =
|
||||||
|
base64_encode(&data[0], static_cast<unsigned int>(data.size()));
|
||||||
|
SerializeStringProperty("uri", header + encodedData, o);
|
||||||
|
}
|
||||||
|
|
||||||
static void SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
static void SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
||||||
const std::string &binFilename) {
|
const std::string &binFilename) {
|
||||||
std::ofstream output(binFilename.c_str(), std::ofstream::binary);
|
std::ofstream output(binFilename.c_str(), std::ofstream::binary);
|
||||||
@ -3534,6 +3744,13 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
|
|||||||
SerializeExtensionMap(asset.extensions, o);
|
SerializeExtensionMap(asset.extensions, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SerializeGltfBuffer(Buffer &buffer, json &o) {
|
||||||
|
SerializeNumberProperty("byteLength", buffer.data.size(), o);
|
||||||
|
SerializeGltfBufferData(buffer.data, o);
|
||||||
|
|
||||||
|
if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o);
|
||||||
|
}
|
||||||
|
|
||||||
static void SerializeGltfBuffer(Buffer &buffer, json &o,
|
static void SerializeGltfBuffer(Buffer &buffer, json &o,
|
||||||
const std::string &binFilename,
|
const std::string &binFilename,
|
||||||
const std::string &binBaseFilename) {
|
const std::string &binBaseFilename) {
|
||||||
@ -3547,16 +3764,25 @@ static void SerializeGltfBuffer(Buffer &buffer, json &o,
|
|||||||
static void SerializeGltfBufferView(BufferView &bufferView, json &o) {
|
static void SerializeGltfBufferView(BufferView &bufferView, json &o) {
|
||||||
SerializeNumberProperty("buffer", bufferView.buffer, o);
|
SerializeNumberProperty("buffer", bufferView.buffer, o);
|
||||||
SerializeNumberProperty<size_t>("byteLength", bufferView.byteLength, o);
|
SerializeNumberProperty<size_t>("byteLength", bufferView.byteLength, o);
|
||||||
SerializeNumberProperty<size_t>("byteStride", bufferView.byteStride, o);
|
|
||||||
SerializeNumberProperty<size_t>("byteOffset", bufferView.byteOffset, o);
|
|
||||||
SerializeNumberProperty("target", bufferView.target, o);
|
|
||||||
|
|
||||||
|
// byteStride is optional, minimum allowed is 4
|
||||||
|
if (bufferView.byteStride >= 4) {
|
||||||
|
SerializeNumberProperty<size_t>("byteStride", bufferView.byteStride, o);
|
||||||
|
}
|
||||||
|
// byteOffset is optional, default is 0
|
||||||
|
if (bufferView.byteOffset > 0) {
|
||||||
|
SerializeNumberProperty<size_t>("byteOffset", bufferView.byteOffset, o);
|
||||||
|
}
|
||||||
|
// Target is optional, check if it contains a valid value
|
||||||
|
if (bufferView.target == TINYGLTF_TARGET_ARRAY_BUFFER ||
|
||||||
|
bufferView.target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER) {
|
||||||
|
SerializeNumberProperty("target", bufferView.target, o);
|
||||||
|
}
|
||||||
if (bufferView.name.size()) {
|
if (bufferView.name.size()) {
|
||||||
SerializeStringProperty("name", bufferView.name, o);
|
SerializeStringProperty("name", bufferView.name, o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only external textures are serialized for now
|
|
||||||
static void SerializeGltfImage(Image &image, json &o) {
|
static void SerializeGltfImage(Image &image, json &o) {
|
||||||
SerializeStringProperty("uri", image.uri, o);
|
SerializeStringProperty("uri", image.uri, o);
|
||||||
|
|
||||||
@ -3597,8 +3823,16 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
primitive["attributes"] = attributes;
|
primitive["attributes"] = attributes;
|
||||||
|
|
||||||
|
// Indicies is optional
|
||||||
|
if (gltfPrimitive.indices > -1) {
|
||||||
SerializeNumberProperty<int>("indices", gltfPrimitive.indices, primitive);
|
SerializeNumberProperty<int>("indices", gltfPrimitive.indices, primitive);
|
||||||
SerializeNumberProperty<int>("material", gltfPrimitive.material, primitive);
|
}
|
||||||
|
// Material is optional
|
||||||
|
if (gltfPrimitive.material > -1) {
|
||||||
|
SerializeNumberProperty<int>("material", gltfPrimitive.material,
|
||||||
|
primitive);
|
||||||
|
}
|
||||||
SerializeNumberProperty<int>("mode", gltfPrimitive.mode, primitive);
|
SerializeNumberProperty<int>("mode", gltfPrimitive.mode, primitive);
|
||||||
|
|
||||||
// Morph targets
|
// Morph targets
|
||||||
@ -3738,7 +3972,9 @@ static void SerializeGltfSkin(Skin &skin, json &o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfTexture(Texture &texture, json &o) {
|
static void SerializeGltfTexture(Texture &texture, json &o) {
|
||||||
|
if (texture.sampler > -1) {
|
||||||
SerializeNumberProperty("sampler", texture.sampler, o);
|
SerializeNumberProperty("sampler", texture.sampler, o);
|
||||||
|
}
|
||||||
SerializeNumberProperty("source", texture.source, o);
|
SerializeNumberProperty("source", texture.source, o);
|
||||||
|
|
||||||
if (texture.extras.Size()) {
|
if (texture.extras.Size()) {
|
||||||
@ -3754,10 +3990,10 @@ static void WriteGltfFile(const std::string &output,
|
|||||||
gltfFile << content << std::endl;
|
gltfFile << content << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TinyGLTF::WriteGltfSceneToFile(
|
bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||||
Model *model,
|
bool embedImages = false,
|
||||||
const std::string
|
bool embedBuffers = false
|
||||||
&filename /*, bool embedImages, bool embedBuffers, bool writeBinary*/) {
|
/*, bool writeBinary*/) {
|
||||||
json output;
|
json output;
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
@ -3796,19 +4032,23 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
} else {
|
} else {
|
||||||
binFilename = binFilename + ".bin";
|
binFilename = binFilename + ".bin";
|
||||||
}
|
}
|
||||||
std::string binSaveFilePath = GetBaseDir(filename);
|
std::string baseDir = GetBaseDir(filename);
|
||||||
if (binSaveFilePath.empty()) {
|
if (baseDir.empty()) {
|
||||||
binSaveFilePath = "./";
|
baseDir = "./";
|
||||||
}
|
}
|
||||||
|
|
||||||
binSaveFilePath = JoinPath(binSaveFilePath, binFilename);
|
std::string binSaveFilePath = JoinPath(baseDir, binFilename);
|
||||||
|
|
||||||
// BUFFERS (We expect only one buffer here)
|
// BUFFERS (We expect only one buffer here)
|
||||||
json buffers;
|
json buffers;
|
||||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||||
json buffer;
|
json buffer;
|
||||||
|
if (embedBuffers) {
|
||||||
|
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||||
|
} else {
|
||||||
SerializeGltfBuffer(model->buffers[i], buffer, binSaveFilePath,
|
SerializeGltfBuffer(model->buffers[i], buffer, binSaveFilePath,
|
||||||
binFilename);
|
binFilename);
|
||||||
|
}
|
||||||
buffers.push_back(buffer);
|
buffers.push_back(buffer);
|
||||||
}
|
}
|
||||||
output["buffers"] = buffers;
|
output["buffers"] = buffers;
|
||||||
@ -3835,15 +4075,21 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IMAGES
|
// IMAGES
|
||||||
|
if (model->images.size()) {
|
||||||
json images;
|
json images;
|
||||||
for (unsigned int i = 0; i < model->images.size(); ++i) {
|
for (unsigned int i = 0; i < model->images.size(); ++i) {
|
||||||
json image;
|
json image;
|
||||||
|
|
||||||
|
UpdateImageObject(model->images[i], baseDir, int(i), embedImages,
|
||||||
|
&this->WriteImageData, &this->write_image_user_data_);
|
||||||
SerializeGltfImage(model->images[i], image);
|
SerializeGltfImage(model->images[i], image);
|
||||||
images.push_back(image);
|
images.push_back(image);
|
||||||
}
|
}
|
||||||
output["images"] = images;
|
output["images"] = images;
|
||||||
|
}
|
||||||
|
|
||||||
// MATERIALS
|
// MATERIALS
|
||||||
|
if (model->materials.size()) {
|
||||||
json materials;
|
json materials;
|
||||||
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
||||||
json material;
|
json material;
|
||||||
@ -3851,8 +4097,10 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
materials.push_back(material);
|
materials.push_back(material);
|
||||||
}
|
}
|
||||||
output["materials"] = materials;
|
output["materials"] = materials;
|
||||||
|
}
|
||||||
|
|
||||||
// MESHES
|
// MESHES
|
||||||
|
if (model->meshes.size()) {
|
||||||
json meshes;
|
json meshes;
|
||||||
for (unsigned int i = 0; i < model->meshes.size(); ++i) {
|
for (unsigned int i = 0; i < model->meshes.size(); ++i) {
|
||||||
json mesh;
|
json mesh;
|
||||||
@ -3860,8 +4108,10 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
meshes.push_back(mesh);
|
meshes.push_back(mesh);
|
||||||
}
|
}
|
||||||
output["meshes"] = meshes;
|
output["meshes"] = meshes;
|
||||||
|
}
|
||||||
|
|
||||||
// NODES
|
// NODES
|
||||||
|
if (model->nodes.size()) {
|
||||||
json nodes;
|
json nodes;
|
||||||
for (unsigned int i = 0; i < model->nodes.size(); ++i) {
|
for (unsigned int i = 0; i < model->nodes.size(); ++i) {
|
||||||
json node;
|
json node;
|
||||||
@ -3869,11 +4119,15 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
nodes.push_back(node);
|
nodes.push_back(node);
|
||||||
}
|
}
|
||||||
output["nodes"] = nodes;
|
output["nodes"] = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
// SCENE
|
// SCENE
|
||||||
|
if (model->defaultScene > -1) {
|
||||||
SerializeNumberProperty<int>("scene", model->defaultScene, output);
|
SerializeNumberProperty<int>("scene", model->defaultScene, output);
|
||||||
|
}
|
||||||
|
|
||||||
// SCENES
|
// SCENES
|
||||||
|
if (model->scenes.size()) {
|
||||||
json scenes;
|
json scenes;
|
||||||
for (unsigned int i = 0; i < model->scenes.size(); ++i) {
|
for (unsigned int i = 0; i < model->scenes.size(); ++i) {
|
||||||
json currentScene;
|
json currentScene;
|
||||||
@ -3881,6 +4135,7 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
scenes.push_back(currentScene);
|
scenes.push_back(currentScene);
|
||||||
}
|
}
|
||||||
output["scenes"] = scenes;
|
output["scenes"] = scenes;
|
||||||
|
}
|
||||||
|
|
||||||
// SKINS
|
// SKINS
|
||||||
if (model->skins.size()) {
|
if (model->skins.size()) {
|
||||||
@ -3894,6 +4149,7 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TEXTURES
|
// TEXTURES
|
||||||
|
if (model->textures.size()) {
|
||||||
json textures;
|
json textures;
|
||||||
for (unsigned int i = 0; i < model->textures.size(); ++i) {
|
for (unsigned int i = 0; i < model->textures.size(); ++i) {
|
||||||
json texture;
|
json texture;
|
||||||
@ -3901,8 +4157,10 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
textures.push_back(texture);
|
textures.push_back(texture);
|
||||||
}
|
}
|
||||||
output["textures"] = textures;
|
output["textures"] = textures;
|
||||||
|
}
|
||||||
|
|
||||||
// SAMPLERS
|
// SAMPLERS
|
||||||
|
if (model->samplers.size()) {
|
||||||
json samplers;
|
json samplers;
|
||||||
for (unsigned int i = 0; i < model->samplers.size(); ++i) {
|
for (unsigned int i = 0; i < model->samplers.size(); ++i) {
|
||||||
json sampler;
|
json sampler;
|
||||||
@ -3910,8 +4168,10 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
samplers.push_back(sampler);
|
samplers.push_back(sampler);
|
||||||
}
|
}
|
||||||
output["samplers"] = samplers;
|
output["samplers"] = samplers;
|
||||||
|
}
|
||||||
|
|
||||||
// CAMERAS
|
// CAMERAS
|
||||||
|
if (model->cameras.size()) {
|
||||||
json cameras;
|
json cameras;
|
||||||
for (unsigned int i = 0; i < model->cameras.size(); ++i) {
|
for (unsigned int i = 0; i < model->cameras.size(); ++i) {
|
||||||
json camera;
|
json camera;
|
||||||
@ -3919,18 +4179,19 @@ bool TinyGLTF::WriteGltfSceneToFile(
|
|||||||
cameras.push_back(camera);
|
cameras.push_back(camera);
|
||||||
}
|
}
|
||||||
output["cameras"] = cameras;
|
output["cameras"] = cameras;
|
||||||
|
}
|
||||||
|
|
||||||
// EXTENSIONS
|
// EXTENSIONS
|
||||||
SerializeExtensionMap(model->extensions, output);
|
SerializeExtensionMap(model->extensions, output);
|
||||||
|
|
||||||
// LIGHTS as KHR_lights_cmn
|
// LIGHTS as KHR_lights_cmn
|
||||||
|
if (model->lights.size()) {
|
||||||
json lights;
|
json lights;
|
||||||
for (unsigned int i = 0; i < model->lights.size(); ++i) {
|
for (unsigned int i = 0; i < model->lights.size(); ++i) {
|
||||||
json light;
|
json light;
|
||||||
SerializeGltfLight(model->lights[i], light);
|
SerializeGltfLight(model->lights[i], light);
|
||||||
lights.push_back(light);
|
lights.push_back(light);
|
||||||
}
|
}
|
||||||
if (model->lights.size() > 0) {
|
|
||||||
json khr_lights_cmn;
|
json khr_lights_cmn;
|
||||||
khr_lights_cmn["lights"] = lights;
|
khr_lights_cmn["lights"] = lights;
|
||||||
json ext_j;
|
json ext_j;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user