mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-10 04:03:49 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b7994a4f4 | ||
|
|
c91b6468e8 | ||
|
|
d4f8fcea10 | ||
|
|
ab069ffb40 | ||
|
|
cbf13fef62 | ||
|
|
57074aee04 |
21
LICENSE.lodepng
Normal file
21
LICENSE.lodepng
Normal file
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
10
README.md
10
README.md
@@ -46,14 +46,11 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
* Load from memory
|
||||
* Custom callback handler
|
||||
* [x] Image load
|
||||
* Extensions
|
||||
* [x] Draco mesh decoding
|
||||
|
||||
## Examples
|
||||
|
||||
* [glview](examples/glview) : Simple glTF geometry viewer.
|
||||
* [validator](examples/validator) : Simple glTF validator with JSON schema.
|
||||
* [basic](examples/basic) : Basic glTF viewer with texturing support.
|
||||
|
||||
## Projects using TinyGLTF
|
||||
|
||||
@@ -67,8 +64,7 @@ v2.0.0 release(22 Aug, 2018)!
|
||||
|
||||
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
|
||||
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
||||
* [x] Load Draco compressed mesh
|
||||
* [x] Save Draco compressed mesh
|
||||
* [ ] Load Draco compressed mesh
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] HDR image?
|
||||
* [ ] OpenEXR extension through TinyEXR.
|
||||
@@ -86,6 +82,7 @@ TinyGLTF uses the following third party libraries.
|
||||
* base64 : Copyright (C) 2004-2008 René Nyffenegger
|
||||
* 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)
|
||||
* lodepng : Copyright (c) 2005-2018 Lode Vandevenne. zlib license. https://lodev.org/lodepng/
|
||||
|
||||
|
||||
## Build and example
|
||||
@@ -133,7 +130,7 @@ if (!ret) {
|
||||
* `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.
|
||||
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option woulde be helpful if you do not want load image file during glTF parsing.
|
||||
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
|
||||
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
|
||||
* `TINYGLTF_USE_LODEPNG` : Load 16bit PNG image with lodepng(Valid when `TINYGLTF_NO_STB_IMAGE` was **not** defined). Must defined `LODEPNG_IMPLEMENTATION` in one .cc.
|
||||
|
||||
### Saving gltTF 2.0 model
|
||||
* [ ] Buffers.
|
||||
@@ -175,4 +172,5 @@ $ ./tester_noexcept
|
||||
|
||||
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
|
||||
* stb_image : Public domain.
|
||||
* lodepng : zlib license
|
||||
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Basic glTF viewer
|
||||
|
||||
## Requirements
|
||||
|
||||
* glew
|
||||
* glfw3
|
||||
* premake5(linux)
|
||||
* OpenGL 3.3+ GPU
|
||||
|
||||
## Build on Linux and macOS
|
||||
|
||||
```
|
||||
$ premake5 gmake
|
||||
$ make
|
||||
```
|
||||
|
||||
## Build on Visual Studio
|
||||
|
||||
Plese use solution file located at `basic` folder.
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,44 +0,0 @@
|
||||
solution "basic_viewer"
|
||||
-- location ( "build" )
|
||||
configurations { "Debug", "Release" }
|
||||
platforms {"native", "x64", "x32"}
|
||||
|
||||
project "basic_viewer"
|
||||
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
cppdialect "C++11"
|
||||
files { "main.cpp", "shaders.cpp", "window.cpp" }
|
||||
includedirs { "./" }
|
||||
includedirs { "../../" }
|
||||
includedirs { "../common/glm" }
|
||||
|
||||
configuration { "linux" }
|
||||
linkoptions { "`pkg-config --libs glfw3`" }
|
||||
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
|
||||
|
||||
configuration { "windows" }
|
||||
-- Edit path to glew and GLFW3 fit to your environment.
|
||||
includedirs { "../../../../local/glew-1.13.0/include/" }
|
||||
includedirs { "../../../../local/glfw-3.2.bin.WIN32/include/" }
|
||||
libdirs { "../../../../local/glew-1.13.0/lib/Release/Win32/" }
|
||||
libdirs { "../../../../local/glfw-3.2.bin.WIN32/lib-vc2013/" }
|
||||
links { "glfw3", "gdi32", "winmm", "user32", "glew32", "glu32","opengl32", "kernel32" }
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
|
||||
configuration { "macosx" }
|
||||
includedirs { "/usr/local/include" }
|
||||
buildoptions { "-Wno-deprecated-declarations" }
|
||||
libdirs { "/usr/local/lib" }
|
||||
links { "glfw", "GLEW" }
|
||||
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
|
||||
|
||||
configuration "Debug"
|
||||
defines { "DEBUG" }
|
||||
symbols "On"
|
||||
warnings "Extra"
|
||||
|
||||
configuration "Release"
|
||||
defines { "NDEBUG" }
|
||||
optimize "On"
|
||||
warnings "Extra"
|
||||
@@ -19,7 +19,7 @@ uniform vec3 sun_color; \n\
|
||||
out vec4 color;\n\
|
||||
void main() {\n\
|
||||
float lum = max(dot(normal, normalize(sun_position)), 0.0);\n\
|
||||
color = texture(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
|
||||
color = texture2D(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
|
||||
}\n\
|
||||
";
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(glview)
|
||||
|
||||
set ( CMAKE_PREFIX_PATH cmake )
|
||||
|
||||
set ( DRACO_DIR "" CACHE STRING "Path to draco" )
|
||||
|
||||
find_package ( GLEW REQUIRED )
|
||||
find_package ( GLFW3 REQUIRED )
|
||||
find_package ( OpenGL REQUIRED )
|
||||
@@ -23,16 +21,6 @@ endif (APPLE)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if (${DRACO_DIR} STREQUAL "")
|
||||
else ()
|
||||
# TODO(syoyo): better CMake script for draco
|
||||
add_definitions(-DTINYGLTF_ENABLE_DRACO)
|
||||
include_directories(${DRACO_DIR}/include)
|
||||
|
||||
link_directories(${DRACO_DIR}/lib)
|
||||
set(DRACO_LIBRARY draco)
|
||||
endif ()
|
||||
|
||||
include_directories(
|
||||
../../
|
||||
../common
|
||||
@@ -47,7 +35,6 @@ add_executable(glview
|
||||
)
|
||||
|
||||
target_link_libraries ( glview
|
||||
${DRACO_LIBRARY}
|
||||
${GLFW3_UNIX_LINK_LIBRARIES}
|
||||
${GLEW_LIBRARY}
|
||||
${GLFW3_glfw_LIBRARY}
|
||||
|
||||
@@ -27,17 +27,6 @@ Open .sln in Visual Studio 2013
|
||||
|
||||
When running .exe, glew and glfw dll must exist in the working directory.
|
||||
|
||||
#### Build with Draco(optional)
|
||||
|
||||
Assume CMake build.
|
||||
|
||||
```
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake -DDRACO_DIR=/path/to/draco ../
|
||||
$ make
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] PBR Material
|
||||
|
||||
@@ -677,14 +677,10 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
// std::cout << it->first << std::endl;
|
||||
// FIXME(syoyo): Refactor.
|
||||
// DrawCurves(scene, it->second);
|
||||
if (node.mesh > -1) {
|
||||
assert(node.mesh < model.meshes.size());
|
||||
DrawMesh(model, model.meshes[node.mesh]);
|
||||
}
|
||||
DrawMesh(model, model.meshes[node.mesh]);
|
||||
|
||||
// Draw child nodes.
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
assert(node.children[i] < model.nodes.size());
|
||||
DrawNode(model, model.nodes[node.children[i]]);
|
||||
}
|
||||
|
||||
@@ -790,12 +786,10 @@ int main(int argc, char **argv) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Simple glTF viewer: " << input_filename;
|
||||
char title[1024];
|
||||
sprintf(title, "Simple glTF viewer: %s", input_filename.c_str());
|
||||
|
||||
std::string title = ss.str();
|
||||
|
||||
window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
|
||||
window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
if (window == NULL) {
|
||||
std::cerr << "Failed to open GLFW window. " << std::endl;
|
||||
glfwTerminate();
|
||||
|
||||
6
examples/raytrace/image-impl.cc
Normal file
6
examples/raytrace/image-impl.cc
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define LODEPNG_IMPLEMENTATION
|
||||
#include "lodepng.h"
|
||||
@@ -1,3 +1,5 @@
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
#define LODEPNG_IMPLEMENTATION
|
||||
#include "lodepng.h"
|
||||
@@ -9,7 +9,7 @@ newoption {
|
||||
}
|
||||
|
||||
sources = {
|
||||
"stbi-impl.cc",
|
||||
"img-loaders.cc",
|
||||
"main.cc",
|
||||
"render.cc",
|
||||
"render-config.cc",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define LODEPNG_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
264
tiny_gltf.h
264
tiny_gltf.h
@@ -26,7 +26,6 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Version:
|
||||
// - v2.1.0 Add draco compression.
|
||||
// - v2.0.1 Add comparsion feature(Thanks to @Selmar).
|
||||
// - v2.0.0 glTF 2.0!.
|
||||
//
|
||||
@@ -35,6 +34,7 @@
|
||||
// - jsonhpp: C++ JSON library.
|
||||
// - base64: base64 decode/encode library.
|
||||
// - stb_image: Image loading library.
|
||||
// - lodepng: Load 16bit PNG.
|
||||
//
|
||||
#ifndef TINY_GLTF_H_
|
||||
#define TINY_GLTF_H_
|
||||
@@ -477,8 +477,10 @@ struct Image {
|
||||
std::string name;
|
||||
int width;
|
||||
int height;
|
||||
int component;
|
||||
std::vector<unsigned char> image;
|
||||
int component; // channels. e.g. RGB=3, RGBA=4
|
||||
int bits; // bit depth per channel. 8(byte), 16 or 32.
|
||||
int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually UBYTE(bits = 8) or USHORT(bits = 16)
|
||||
std::vector<unsigned char> image; // width * height * component * (bits/8)
|
||||
int bufferView; // (required if no uri)
|
||||
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
|
||||
// "image/bmp", "image/gif"]
|
||||
@@ -499,6 +501,8 @@ struct Image {
|
||||
width = -1;
|
||||
height = -1;
|
||||
component = -1;
|
||||
bits = -1;
|
||||
pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
||||
}
|
||||
bool operator==(const Image &) const;
|
||||
};
|
||||
@@ -539,9 +543,8 @@ struct BufferView {
|
||||
// understood to be tightly packed
|
||||
int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"]
|
||||
Value extras;
|
||||
bool dracoDecoded; // Flag indicating this has been draco decoded
|
||||
|
||||
BufferView() : byteOffset(0), byteStride(0), dracoDecoded(false) {}
|
||||
BufferView() : byteOffset(0), byteStride(0) {}
|
||||
bool operator==(const BufferView &) const;
|
||||
};
|
||||
|
||||
@@ -660,7 +663,6 @@ struct Primitive {
|
||||
// where each target is a dict with attribues in ["POSITION, "NORMAL",
|
||||
// "TANGENT"] pointing
|
||||
// to their corresponding accessors
|
||||
ExtensionMap extensions;
|
||||
Value extras;
|
||||
|
||||
Primitive() {
|
||||
@@ -1063,19 +1065,18 @@ class TinyGLTF {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
#ifdef TINYGLTF_ENABLE_DRACO
|
||||
#include "draco/core/decoder_buffer.h"
|
||||
#include "draco/compression/decode.h"
|
||||
#endif
|
||||
#include "./json.hpp"
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||
#include "stb_image.h"
|
||||
#include "./stb_image.h"
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#include "stb_image_write.h"
|
||||
#include "./stb_image_write.h"
|
||||
#endif
|
||||
|
||||
#if defined(TINYGLTF_USE_LODEPNG)
|
||||
#include "./lodepng.h"
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -1200,8 +1201,7 @@ bool BufferView::operator==(const BufferView &other) const {
|
||||
return this->buffer == other.buffer && this->byteLength == other.byteLength &&
|
||||
this->byteOffset == other.byteOffset &&
|
||||
this->byteStride == other.byteStride && this->name == other.name &&
|
||||
this->target == other.target && this->extras == other.extras &&
|
||||
this->dracoDecoded == other.dracoDecoded;
|
||||
this->target == other.target && this->extras == other.extras;
|
||||
}
|
||||
bool Camera::operator==(const Camera &other) const {
|
||||
return this->name == other.name && this->extensions == other.extensions &&
|
||||
@@ -1212,6 +1212,7 @@ bool Camera::operator==(const Camera &other) const {
|
||||
bool Image::operator==(const Image &other) const {
|
||||
return this->bufferView == other.bufferView &&
|
||||
this->component == other.component && this->extras == other.extras &&
|
||||
this->bits == other.bits &&
|
||||
this->height == other.height && this->image == other.image &&
|
||||
this->mimeType == other.mimeType && this->name == other.name &&
|
||||
this->uri == other.uri && this->width == other.width;
|
||||
@@ -1608,6 +1609,9 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
|
||||
// some GPU drivers do not support 24-bit images for Vulkan
|
||||
req_comp = 4;
|
||||
|
||||
int bits = 8;
|
||||
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
||||
|
||||
// if image cannot be decoded, ignore parsing and keep it by its path
|
||||
// don't break in this case
|
||||
// FIXME we should only enter this function if the image is embedded. If
|
||||
@@ -1617,11 +1621,28 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
|
||||
unsigned char *data =
|
||||
stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
|
||||
if (!data) {
|
||||
#if defined(TINYGLTF_USE_LODEPNG)
|
||||
// try to load as 16bit PNG RGBA
|
||||
unsigned ret = lodepng_decode_memory(&data, reinterpret_cast<unsigned *>(&w), reinterpret_cast<unsigned *>(&h), bytes, size, LCT_RGBA, /* bitdepth*/16);
|
||||
|
||||
if (ret != 0) {
|
||||
// NOTE: you can use `warn` instead of `err`
|
||||
if (err) {
|
||||
(*err) += "Unknown image format. STB and LodePNG cannot decode image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bits = 16;
|
||||
pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
|
||||
|
||||
#else
|
||||
// NOTE: you can use `warn` instead of `err`
|
||||
if (err) {
|
||||
(*err) += "Unknown image format. STB cannot decode image data for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\". Proably 16bit PNG?\n";
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (w < 1 || h < 1) {
|
||||
@@ -1655,8 +1676,10 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, std::str
|
||||
image->width = w;
|
||||
image->height = h;
|
||||
image->component = req_comp;
|
||||
image->image.resize(static_cast<size_t>(w * h * req_comp));
|
||||
std::copy(data, data + w * h * req_comp, image->image.begin());
|
||||
image->bits = bits;
|
||||
image->pixel_type = pixel_type;
|
||||
image->image.resize(static_cast<size_t>(w * h * req_comp * (bits/8)));
|
||||
std::copy(data, data + w * h * req_comp * (bits/8), image->image.begin());
|
||||
|
||||
free(data);
|
||||
|
||||
@@ -2523,6 +2546,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
// Keep texture path (for textures that cannot be decoded)
|
||||
image->uri = uri;
|
||||
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
||||
// TODO(syoyo): Call LoadImageData callback?
|
||||
return true;
|
||||
#endif
|
||||
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
|
||||
@@ -2737,7 +2761,10 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
|
||||
static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
||||
double bufferView = -1.0;
|
||||
ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor");
|
||||
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true,
|
||||
"Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double byteOffset = 0.0;
|
||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
|
||||
@@ -2819,184 +2846,7 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TINYGLTF_ENABLE_DRACO
|
||||
|
||||
static void DecodeIndexBuffer(draco::Mesh* mesh, size_t componentSize, std::vector<uint8_t>& outBuffer)
|
||||
{
|
||||
if (componentSize == 4)
|
||||
{
|
||||
assert(sizeof(mesh->face(draco::FaceIndex(0))[0]) == componentSize);
|
||||
memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0], outBuffer.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t faceStride = componentSize * 3;
|
||||
for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f)
|
||||
{
|
||||
const draco::Mesh::Face& face = mesh->face(f);
|
||||
if (componentSize == 2)
|
||||
{
|
||||
uint16_t indices[3] = { (uint16_t)face[0].value(), (uint16_t)face[1].value(), (uint16_t)face[2].value() };
|
||||
memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t indices[3] = { (uint8_t)face[0].value(), (uint8_t)face[1].value(), (uint8_t)face[2].value() };
|
||||
memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool GetAttributeForAllPoints(draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector<uint8_t>& outBuffer)
|
||||
{
|
||||
size_t byteOffset = 0;
|
||||
T values[4] = { 0, 0, 0, 0 };
|
||||
for (draco::PointIndex i(0); i < mesh->num_points(); ++i)
|
||||
{
|
||||
const draco::AttributeValueIndex val_index = pAttribute->mapped_index(i);
|
||||
if (!pAttribute->ConvertValue<T>(val_index, pAttribute->num_components(), values))
|
||||
return false;
|
||||
|
||||
memcpy(outBuffer.data() + byteOffset, &values[0], sizeof(T) * pAttribute->num_components());
|
||||
byteOffset += sizeof(T) * pAttribute->num_components();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector<uint8_t>& outBuffer)
|
||||
{
|
||||
bool decodeResult = false;
|
||||
switch (componentType)
|
||||
{
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
decodeResult = GetAttributeForAllPoints<uint8_t>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
decodeResult = GetAttributeForAllPoints<int8_t>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
decodeResult = GetAttributeForAllPoints<uint16_t>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
decodeResult = GetAttributeForAllPoints<int16_t>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
decodeResult = GetAttributeForAllPoints<int32_t>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
decodeResult = GetAttributeForAllPoints<uint32_t>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
decodeResult = GetAttributeForAllPoints<float>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
||||
decodeResult = GetAttributeForAllPoints<double>(mesh, pAttribute, outBuffer);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return decodeResult;
|
||||
}
|
||||
|
||||
static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string *err, const Value &dracoExtensionValue)
|
||||
{
|
||||
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
|
||||
if (!bufferViewValue.IsInt())
|
||||
return false;
|
||||
auto attributesValue = dracoExtensionValue.Get("attributes");
|
||||
if (!attributesValue.IsObject())
|
||||
return false;
|
||||
|
||||
auto attributesObject = attributesValue.Get<Value::Object>();
|
||||
int bufferView = bufferViewValue.Get<int>();
|
||||
|
||||
BufferView& view = model->bufferViews[bufferView];
|
||||
Buffer& buffer = model->buffers[view.buffer];
|
||||
// BufferView has already been decoded
|
||||
if (view.dracoDecoded)
|
||||
return true;
|
||||
view.dracoDecoded = true;
|
||||
|
||||
const char* bufferViewData = reinterpret_cast<const char*>(buffer.data.data() + view.byteOffset);
|
||||
size_t bufferViewSize = view.byteLength;
|
||||
|
||||
// decode draco
|
||||
draco::DecoderBuffer decoderBuffer;
|
||||
decoderBuffer.Init(bufferViewData, bufferViewSize);
|
||||
draco::Decoder decoder;
|
||||
auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
|
||||
if (!decodeResult.ok()) {
|
||||
return false;
|
||||
}
|
||||
const std::unique_ptr<draco::Mesh>& mesh = decodeResult.value();
|
||||
|
||||
// create new bufferView for indices
|
||||
if (primitive->indices >= 0)
|
||||
{
|
||||
int32_t componentSize = GetComponentSizeInBytes(model->accessors[primitive->indices].componentType);
|
||||
Buffer decodedIndexBuffer;
|
||||
decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize);
|
||||
|
||||
DecodeIndexBuffer(mesh.get(), componentSize, decodedIndexBuffer.data);
|
||||
|
||||
model->buffers.emplace_back(std::move(decodedIndexBuffer));
|
||||
|
||||
BufferView decodedIndexBufferView;
|
||||
decodedIndexBufferView.buffer = int(model->buffers.size() - 1);
|
||||
decodedIndexBufferView.byteLength = int(mesh->num_faces() * 3 * componentSize);
|
||||
decodedIndexBufferView.byteOffset = 0;
|
||||
decodedIndexBufferView.byteStride = 0;
|
||||
decodedIndexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||
model->bufferViews.emplace_back(std::move(decodedIndexBufferView));
|
||||
|
||||
model->accessors[primitive->indices].bufferView = int(model->bufferViews.size() - 1);
|
||||
model->accessors[primitive->indices].count = int(mesh->num_faces() * 3);
|
||||
}
|
||||
|
||||
for (const auto& attribute : attributesObject)
|
||||
{
|
||||
if (!attribute.second.IsInt())
|
||||
return false;
|
||||
auto primitiveAttribute = primitive->attributes.find(attribute.first);
|
||||
if (primitiveAttribute == primitive->attributes.end())
|
||||
return false;
|
||||
|
||||
int dracoAttributeIndex = attribute.second.Get<int>();
|
||||
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
|
||||
const auto pBuffer = pAttribute->buffer();
|
||||
const auto componentType = model->accessors[primitiveAttribute->second].componentType;
|
||||
|
||||
// Create a new buffer for this decoded buffer
|
||||
Buffer decodedBuffer;
|
||||
size_t bufferSize = mesh->num_points() * pAttribute->num_components() * GetComponentSizeInBytes(componentType);
|
||||
decodedBuffer.data.resize(bufferSize);
|
||||
|
||||
if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, decodedBuffer.data))
|
||||
return false;
|
||||
|
||||
model->buffers.emplace_back(std::move(decodedBuffer));
|
||||
|
||||
BufferView decodedBufferView;
|
||||
decodedBufferView.buffer = int(model->buffers.size() - 1);
|
||||
decodedBufferView.byteLength = bufferSize;
|
||||
decodedBufferView.byteOffset = pAttribute->byte_offset();
|
||||
decodedBufferView.byteStride = pAttribute->byte_stride();
|
||||
decodedBufferView.target = primitive->indices >= 0 ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER : TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||
model->bufferViews.emplace_back(std::move(decodedBufferView));
|
||||
|
||||
model->accessors[primitiveAttribute->second].bufferView = int(model->bufferViews.size() - 1);
|
||||
model->accessors[primitiveAttribute->second].count = int(mesh->num_points());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
||||
static bool ParsePrimitive(Primitive *primitive, std::string *err,
|
||||
const json &o) {
|
||||
double material = -1.0;
|
||||
ParseNumberProperty(&material, err, o, "material", false);
|
||||
@@ -3036,20 +2886,10 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
||||
|
||||
ParseExtrasProperty(&(primitive->extras), o);
|
||||
|
||||
ParseExtensionsProperty(&primitive->extensions, err, o);
|
||||
|
||||
#ifdef TINYGLTF_ENABLE_DRACO
|
||||
auto dracoExtension = primitive->extensions.find("KHR_draco_mesh_compression");
|
||||
if (dracoExtension != primitive->extensions.end())
|
||||
{
|
||||
ParseDracoExtension(primitive, model, err, dracoExtension->second);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o) {
|
||||
static bool ParseMesh(Mesh *mesh, std::string *err, const json &o) {
|
||||
ParseStringProperty(&mesh->name, err, o, "name", false);
|
||||
|
||||
mesh->primitives.clear();
|
||||
@@ -3058,7 +2898,7 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o)
|
||||
for (json::const_iterator i = primObject.value().begin();
|
||||
i != primObject.value().end(); i++) {
|
||||
Primitive primitive;
|
||||
if (ParsePrimitive(&primitive, model, err, i.value())) {
|
||||
if (ParsePrimitive(&primitive, err, i.value())) {
|
||||
// Only add the primitive if the parsing succeeds.
|
||||
mesh->primitives.push_back(primitive);
|
||||
}
|
||||
@@ -3717,7 +3557,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
return false;
|
||||
}
|
||||
Mesh mesh;
|
||||
if (!ParseMesh(&mesh, model, err, it->get<json>())) {
|
||||
if (!ParseMesh(&mesh, err, it->get<json>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4823,14 +4663,14 @@ static void WriteBinaryGltfFile(const std::string &output,
|
||||
const int padding_size = content.size() % 4;
|
||||
|
||||
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
|
||||
const int length = 12 + 8 + int(content.size()) + padding_size;
|
||||
const int length = 12 + 8 + content.size() + padding_size;
|
||||
|
||||
gltfFile.write(header.c_str(), header.size());
|
||||
gltfFile.write(reinterpret_cast<const char *>(&version), sizeof(version));
|
||||
gltfFile.write(reinterpret_cast<const char *>(&length), sizeof(length));
|
||||
|
||||
// JSON chunk info, then JSON data
|
||||
const int model_length = int(content.size()) + padding_size;
|
||||
const int model_length = content.size() + padding_size;
|
||||
const int model_format = 0x4E4F534A;
|
||||
gltfFile.write(reinterpret_cast<const char *>(&model_length), sizeof(model_length));
|
||||
gltfFile.write(reinterpret_cast<const char *>(&model_format), sizeof(model_format));
|
||||
|
||||
Reference in New Issue
Block a user