mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-14 00:25:53 +08:00
commit
1ef603ea2a
@ -28,7 +28,6 @@
|
||||
#include "tiny_gltf.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
#define CheckGLErrors(desc) \
|
||||
@ -55,7 +54,9 @@ float eye[3], lookat[3], up[3];
|
||||
|
||||
GLFWwindow *window;
|
||||
|
||||
typedef struct { GLuint vb; } GLBufferState;
|
||||
typedef struct {
|
||||
GLuint vb;
|
||||
} GLBufferState;
|
||||
|
||||
typedef struct {
|
||||
std::vector<GLuint> diffuseTex; // for each primitive in mesh
|
||||
@ -254,6 +255,26 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) {
|
||||
prevMouseY = mouse_y;
|
||||
}
|
||||
|
||||
static size_t ComponentTypeByteSize(int type) {
|
||||
switch (type) {
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
return sizeof(char);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
return sizeof(short);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
return sizeof(int);
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
return sizeof(float);
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
||||
return sizeof(double);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
// Buffer
|
||||
{
|
||||
@ -264,14 +285,117 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
continue; // Unsupported bufferView.
|
||||
}
|
||||
|
||||
int sparse_accessor = -1;
|
||||
for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) {
|
||||
const auto &accessor = model.accessors[a_i];
|
||||
if (accessor.bufferView == i) {
|
||||
std::cout << i << " is used by accessor " << a_i << std::endl;
|
||||
if (accessor.sparse.isSparse) {
|
||||
std::cout
|
||||
<< "WARN: this bufferView has at least one sparse accessor to "
|
||||
"it. We are going to load the data as patched by this "
|
||||
"sparse accessor, not the original data"
|
||||
<< std::endl;
|
||||
sparse_accessor = a_i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
|
||||
GLBufferState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(bufferView.target, state.vb);
|
||||
std::cout << "buffer.size= " << buffer.data.size()
|
||||
<< ", byteOffset = " << bufferView.byteOffset << std::endl;
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
||||
|
||||
if (sparse_accessor < 0)
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset,
|
||||
GL_STATIC_DRAW);
|
||||
else {
|
||||
const auto accessor = model.accessors[sparse_accessor];
|
||||
// copy the buffer to a temporary one for sparse patching
|
||||
unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength];
|
||||
memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset,
|
||||
bufferView.byteLength);
|
||||
|
||||
const size_t size_of_object_in_buffer =
|
||||
ComponentTypeByteSize(accessor.componentType);
|
||||
const size_t size_of_sparse_indices =
|
||||
ComponentTypeByteSize(accessor.sparse.indices.componentType);
|
||||
|
||||
const auto &indices_buffer_view =
|
||||
model.bufferViews[accessor.sparse.indices.bufferView];
|
||||
const auto &indices_buffer = model.buffers[indices_buffer_view.buffer];
|
||||
|
||||
const auto &values_buffer_view =
|
||||
model.bufferViews[accessor.sparse.values.bufferView];
|
||||
const auto &values_buffer = model.buffers[values_buffer_view.buffer];
|
||||
|
||||
for (size_t sparse_index = 0; sparse_index < accessor.sparse.count;
|
||||
++sparse_index) {
|
||||
int index = 0;
|
||||
// std::cout << "accessor.sparse.indices.componentType = " <<
|
||||
// accessor.sparse.indices.componentType << std::endl;
|
||||
switch (accessor.sparse.indices.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
index = (int)*(
|
||||
unsigned char *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
index = (int)*(
|
||||
unsigned short *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
index = (int)*(
|
||||
unsigned int *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
}
|
||||
std::cout << "updating sparse data at index : " << index
|
||||
<< std::endl;
|
||||
// index is now the target of the sparse index to patch in
|
||||
const unsigned char *read_from =
|
||||
values_buffer.data.data() +
|
||||
(values_buffer_view.byteOffset +
|
||||
accessor.sparse.values.byteOffset) +
|
||||
(sparse_index * (size_of_object_in_buffer * accessor.type));
|
||||
|
||||
/*
|
||||
std::cout << ((float*)read_from)[0] << "\n";
|
||||
std::cout << ((float*)read_from)[1] << "\n";
|
||||
std::cout << ((float*)read_from)[2] << "\n";
|
||||
*/
|
||||
|
||||
unsigned char *write_to =
|
||||
tmp_buffer + index * (size_of_object_in_buffer * accessor.type);
|
||||
|
||||
memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type);
|
||||
}
|
||||
|
||||
// debug:
|
||||
/*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++)
|
||||
{
|
||||
float* b = (float*)tmp_buffer;
|
||||
std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n';
|
||||
}*/
|
||||
|
||||
glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer,
|
||||
GL_STATIC_DRAW);
|
||||
delete[] tmp_buffer;
|
||||
}
|
||||
glBindBuffer(bufferView.target, 0);
|
||||
|
||||
gBufferState[i] = state;
|
||||
@ -279,55 +403,55 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
}
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Texture
|
||||
{
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
// Texture
|
||||
{
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glUseProgram(progId);
|
||||
@ -348,164 +472,164 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Setup curves geometry extension
|
||||
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
|
||||
// Find curves primitive.
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
// Find curves primitive.
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
|
||||
// Currently we only support one primitive per mesh.
|
||||
if (mesh.primitives.size() > 1) {
|
||||
continue;
|
||||
}
|
||||
// Currently we only support one primitive per mesh.
|
||||
if (mesh.primitives.size() > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (primitive.material.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool has_curves = false;
|
||||
if (primitive.extras.IsObject()) {
|
||||
if (primitive.extras.Has("ext_mode")) {
|
||||
const tinygltf::Value::Object &o =
|
||||
primitive.extras.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
|
||||
bool has_curves = false;
|
||||
if (primitive.extras.IsObject()) {
|
||||
if (primitive.extras.Has("ext_mode")) {
|
||||
const tinygltf::Value::Object &o =
|
||||
primitive.extras.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
|
||||
|
||||
if (ext_mode.IsString()) {
|
||||
const std::string &str = ext_mode.Get<std::string>();
|
||||
if (str.compare("curves") == 0) {
|
||||
has_curves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ext_mode.IsString()) {
|
||||
const std::string &str = ext_mode.Get<std::string>();
|
||||
if (str.compare("curves") == 0) {
|
||||
has_curves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_curves) {
|
||||
continue;
|
||||
}
|
||||
if (!has_curves) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Construct curves buffer
|
||||
const tinygltf::Accessor &vtx_accessor =
|
||||
scene.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::Accessor &nverts_accessor =
|
||||
scene.accessors[primitive.attributes.find("NVERTS")->second];
|
||||
const tinygltf::BufferView &vtx_bufferView =
|
||||
scene.bufferViews[vtx_accessor.bufferView];
|
||||
const tinygltf::BufferView &nverts_bufferView =
|
||||
scene.bufferViews[nverts_accessor.bufferView];
|
||||
const tinygltf::Buffer &vtx_buffer =
|
||||
scene.buffers[vtx_bufferView.buffer];
|
||||
const tinygltf::Buffer &nverts_buffer =
|
||||
scene.buffers[nverts_bufferView.buffer];
|
||||
// Construct curves buffer
|
||||
const tinygltf::Accessor &vtx_accessor =
|
||||
scene.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::Accessor &nverts_accessor =
|
||||
scene.accessors[primitive.attributes.find("NVERTS")->second];
|
||||
const tinygltf::BufferView &vtx_bufferView =
|
||||
scene.bufferViews[vtx_accessor.bufferView];
|
||||
const tinygltf::BufferView &nverts_bufferView =
|
||||
scene.bufferViews[nverts_accessor.bufferView];
|
||||
const tinygltf::Buffer &vtx_buffer =
|
||||
scene.buffers[vtx_bufferView.buffer];
|
||||
const tinygltf::Buffer &nverts_buffer =
|
||||
scene.buffers[nverts_bufferView.buffer];
|
||||
|
||||
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
|
||||
// std::endl;
|
||||
|
||||
const int *nverts =
|
||||
reinterpret_cast<const int *>(nverts_buffer.data.data());
|
||||
const float *vtx =
|
||||
reinterpret_cast<const float *>(vtx_buffer.data.data());
|
||||
const int *nverts =
|
||||
reinterpret_cast<const int *>(nverts_buffer.data.data());
|
||||
const float *vtx =
|
||||
reinterpret_cast<const float *>(vtx_buffer.data.data());
|
||||
|
||||
// Convert to GL_LINES data.
|
||||
std::vector<float> line_pts;
|
||||
size_t vtx_offset = 0;
|
||||
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
|
||||
for (int n = 0; n < nverts[k] - 1; n++) {
|
||||
// Convert to GL_LINES data.
|
||||
std::vector<float> line_pts;
|
||||
size_t vtx_offset = 0;
|
||||
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
|
||||
for (int n = 0; n < nverts[k] - 1; n++) {
|
||||
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
|
||||
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
|
||||
|
||||
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
|
||||
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
|
||||
|
||||
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
|
||||
}
|
||||
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
|
||||
}
|
||||
|
||||
vtx_offset += nverts[k];
|
||||
}
|
||||
vtx_offset += nverts[k];
|
||||
}
|
||||
|
||||
GLCurvesState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
|
||||
line_pts.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
GLCurvesState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
|
||||
line_pts.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
state.count = line_pts.size() / 3;
|
||||
gCurvesMesh[mesh.name] = state;
|
||||
state.count = line_pts.size() / 3;
|
||||
gCurvesMesh[mesh.name] = state;
|
||||
|
||||
// Material
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// Material
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -558,12 +682,13 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
(it->first.compare("TEXCOORD_0") == 0)) {
|
||||
if (gGLProgramState.attribs[it->first] >= 0) {
|
||||
// Compute byteStride from Accessor + BufferView combination.
|
||||
int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
||||
int byteStride =
|
||||
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
||||
assert(byteStride != -1);
|
||||
glVertexAttribPointer(gGLProgramState.attribs[it->first], size,
|
||||
accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
byteStride,
|
||||
BUFFER_OFFSET(accessor.byteOffset));
|
||||
accessor.componentType,
|
||||
accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
byteStride, BUFFER_OFFSET(accessor.byteOffset));
|
||||
CheckErrors("vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
|
||||
CheckErrors("enable vertex attrib array");
|
||||
@ -617,32 +742,32 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
(void)scene;
|
||||
(void)scene;
|
||||
|
||||
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
|
||||
return;
|
||||
}
|
||||
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
|
||||
}
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
|
||||
}
|
||||
|
||||
GLCurvesState &state = gCurvesMesh[mesh.name];
|
||||
GLCurvesState &state = gCurvesMesh[mesh.name];
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
|
||||
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
|
||||
CheckErrors("curve: vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
CheckErrors("curve: enable vertex attrib array");
|
||||
}
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
|
||||
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
|
||||
CheckErrors("curve: vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
CheckErrors("curve: enable vertex attrib array");
|
||||
}
|
||||
|
||||
glDrawArrays(GL_LINES, 0, state.count);
|
||||
glDrawArrays(GL_LINES, 0, state.count);
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -693,16 +818,16 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
|
||||
static void DrawModel(tinygltf::Model &model) {
|
||||
#if 0
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
DrawMesh(scene, it->second);
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
for (; it != itEnd; it++) {
|
||||
DrawMesh(scene, it->second);
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
#else
|
||||
//If the glTF asset has at least one scene, and doesn't define a default one
|
||||
//just show the first one we can find
|
||||
// If the glTF asset has at least one scene, and doesn't define a default one
|
||||
// just show the first one we can find
|
||||
assert(model.scenes.size() > 0);
|
||||
int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0;
|
||||
const tinygltf::Scene &scene = model.scenes[scene_to_display];
|
||||
@ -752,7 +877,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
std::string input_filename(argv[1] ? argv[1] : "../../../models/Cube/Cube.gltf");
|
||||
std::string input_filename(argv[1] ? argv[1]
|
||||
: "../../../models/Cube/Cube.gltf");
|
||||
#endif
|
||||
#else
|
||||
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
|
||||
@ -763,7 +889,8 @@ int main(int argc, char **argv) {
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
ret =
|
||||
loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
@ -825,15 +952,14 @@ int main(int argc, char **argv) {
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
const char *shader_frag_filename = "../shader.frag";
|
||||
const char *shader_vert_filename = "../shader.vert";
|
||||
const char *shader_frag_filename = "../shader.frag";
|
||||
const char *shader_vert_filename = "../shader.vert";
|
||||
#endif
|
||||
#else
|
||||
const char *shader_frag_filename = "shader.frag";
|
||||
const char *shader_vert_filename = "shader.vert";
|
||||
#endif
|
||||
|
||||
|
||||
if (false == LoadShader(GL_VERTEX_SHADER, vertId, shader_vert_filename)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -228,7 +228,8 @@ static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) {
|
||||
#endif
|
||||
|
||||
static std::string PrintValue(const std::string &name,
|
||||
const tinygltf::Value &value, const int indent, const bool tag = true) {
|
||||
const tinygltf::Value &value, const int indent,
|
||||
const bool tag = true) {
|
||||
std::stringstream ss;
|
||||
|
||||
if (value.IsObject()) {
|
||||
@ -265,11 +266,10 @@ static std::string PrintValue(const std::string &name,
|
||||
} else if (value.IsArray()) {
|
||||
ss << Indent(indent) << name << " [ ";
|
||||
for (size_t i = 0; i < value.Size(); i++) {
|
||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false);
|
||||
if (i != (value.ArrayLen()-1)) {
|
||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
|
||||
if (i != (value.ArrayLen() - 1)) {
|
||||
ss << ", ";
|
||||
}
|
||||
|
||||
}
|
||||
ss << Indent(indent) << "] ";
|
||||
}
|
||||
@ -330,13 +330,13 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
|
||||
}
|
||||
|
||||
static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent)
|
||||
{
|
||||
static void DumpExtensions(const tinygltf::ExtensionMap &extension,
|
||||
const int indent) {
|
||||
// TODO(syoyo): pritty print Value
|
||||
for (auto &e : extension) {
|
||||
std::cout << Indent(indent) << e.first << std::endl;
|
||||
std::cout << PrintValue("extensions", e.second, indent+1) << std::endl;
|
||||
}
|
||||
std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void Dump(const tinygltf::Model &model) {
|
||||
@ -409,6 +409,30 @@ static void Dump(const tinygltf::Model &model) {
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
if (accessor.sparse.isSparse) {
|
||||
std::cout << Indent(2) << "sparse:" << std::endl;
|
||||
std::cout << Indent(3) << "count : " << accessor.sparse.count
|
||||
<< std::endl;
|
||||
std::cout << Indent(3) << "indices: " << std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "bufferView : " << accessor.sparse.indices.bufferView
|
||||
<< std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "byteOffset : " << accessor.sparse.indices.byteOffset
|
||||
<< std::endl;
|
||||
std::cout << Indent(4) << "componentType: "
|
||||
<< PrintComponentType(accessor.sparse.indices.componentType)
|
||||
<< "(" << accessor.sparse.indices.componentType << ")"
|
||||
<< std::endl;
|
||||
std::cout << Indent(3) << "values : " << std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "bufferView : " << accessor.sparse.values.bufferView
|
||||
<< std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "byteOffset : " << accessor.sparse.values.byteOffset
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,10 +609,11 @@ static void Dump(const tinygltf::Model &model) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// toplevel extensions
|
||||
{
|
||||
std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl;
|
||||
std::cout << "extensions(items=" << model.extensions.size() << ")"
|
||||
<< std::endl;
|
||||
DumpExtensions(model.extensions, 1);
|
||||
}
|
||||
}
|
||||
@ -602,7 +627,7 @@ int main(int argc, char **argv) {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF gltf_ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
std::string warn;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
@ -610,18 +635,19 @@ int main(int argc, char **argv) {
|
||||
if (ext.compare("glb") == 0) {
|
||||
std::cout << "Reading binary glTF" << std::endl;
|
||||
// assume binary glTF.
|
||||
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn,
|
||||
input_filename.c_str());
|
||||
} else {
|
||||
std::cout << "Reading ASCII glTF" << std::endl;
|
||||
// assume ascii glTF.
|
||||
ret = gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
ret =
|
||||
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
}
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
|
454
tiny_gltf.h
454
tiny_gltf.h
@ -149,7 +149,7 @@ namespace tinygltf {
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
|
||||
AAssetManager* asset_manager = nullptr;
|
||||
AAssetManager *asset_manager = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -380,15 +380,15 @@ struct Parameter {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Return the index of a texture coordinate set if this Parameter is a texture map.
|
||||
/// Returned value is only valid if the parameter represent a texture from a
|
||||
/// material
|
||||
/// Return the index of a texture coordinate set if this Parameter is a
|
||||
/// texture map. Returned value is only valid if the parameter represent a
|
||||
/// texture from a material
|
||||
int TextureTexCoord() const {
|
||||
const auto it = json_double_value.find("texCoord");
|
||||
if (it != std::end(json_double_value)) {
|
||||
return int(it->second);
|
||||
}
|
||||
return 0;
|
||||
const auto it = json_double_value.find("texCoord");
|
||||
if (it != std::end(json_double_value)) {
|
||||
return int(it->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Material factor, like the roughness or metalness of a material
|
||||
@ -483,7 +483,7 @@ struct Sampler {
|
||||
magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR),
|
||||
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||
wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT){}
|
||||
wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
|
||||
bool operator==(const Sampler &) const;
|
||||
};
|
||||
|
||||
@ -492,8 +492,9 @@ struct Image {
|
||||
int width;
|
||||
int height;
|
||||
int component;
|
||||
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)
|
||||
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;
|
||||
int bufferView; // (required if no uri)
|
||||
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
|
||||
@ -575,7 +576,19 @@ struct Accessor {
|
||||
std::vector<double> minValues; // optional
|
||||
std::vector<double> maxValues; // optional
|
||||
|
||||
// TODO(syoyo): "sparse"
|
||||
struct {
|
||||
int count;
|
||||
bool isSparse;
|
||||
struct {
|
||||
int byteOffset;
|
||||
int bufferView;
|
||||
int componentType; // a TINYGLTF_COMPONENT_TYPE_ value
|
||||
} indices;
|
||||
struct {
|
||||
int bufferView;
|
||||
int byteOffset;
|
||||
} values;
|
||||
} sparse;
|
||||
|
||||
///
|
||||
/// Utility function to compute byteStride for a given bufferView object.
|
||||
@ -614,7 +627,10 @@ struct Accessor {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Accessor() { bufferView = -1; }
|
||||
Accessor() {
|
||||
bufferView = -1;
|
||||
sparse.isSparse = false;
|
||||
}
|
||||
bool operator==(const tinygltf::Accessor &) const;
|
||||
};
|
||||
|
||||
@ -820,9 +836,9 @@ enum SectionCheck {
|
||||
///
|
||||
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
|
||||
///
|
||||
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, std::string *,
|
||||
int, int, const unsigned char *, int,
|
||||
void *);
|
||||
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
|
||||
std::string *, int, int,
|
||||
const unsigned char *, int, void *);
|
||||
|
||||
///
|
||||
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
|
||||
@ -832,9 +848,9 @@ typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *,
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||
// Declaration of default image loader callback
|
||||
bool LoadImageData(Image *image, const int image_idx, std::string *err, std::string *warn,
|
||||
int req_width, int req_height, const unsigned char *bytes,
|
||||
int size, void *);
|
||||
bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
||||
std::string *warn, int req_width, int req_height,
|
||||
const unsigned char *bytes, int size, void *);
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
@ -954,10 +970,8 @@ class TinyGLTF {
|
||||
/// Write glTF to file.
|
||||
///
|
||||
bool WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||
bool embedImages,
|
||||
bool embedBuffers,
|
||||
bool prettyPrint,
|
||||
bool writeBinary);
|
||||
bool embedImages, bool embedBuffers,
|
||||
bool prettyPrint, bool writeBinary);
|
||||
|
||||
///
|
||||
/// Set callback to use for loading image data
|
||||
@ -1084,8 +1098,8 @@ class TinyGLTF {
|
||||
#endif
|
||||
|
||||
#ifdef TINYGLTF_ENABLE_DRACO
|
||||
#include "draco/core/decoder_buffer.h"
|
||||
#include "draco/compression/decode.h"
|
||||
#include "draco/core/decoder_buffer.h"
|
||||
#endif
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||
@ -1118,7 +1132,7 @@ class TinyGLTF {
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h> // include API for expanding a file path
|
||||
#include <windows.h> // include API for expanding a file path
|
||||
|
||||
#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
@ -1824,16 +1838,17 @@ void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
|
||||
bool FileExists(const std::string &abs_filename, void *) {
|
||||
bool ret;
|
||||
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
|
||||
if (asset_manager) {
|
||||
AAsset* asset = AAssetManager_open(asset_manager, abs_filename.c_str(), AASSET_MODE_STREAMING);
|
||||
if (!asset) {
|
||||
return false;
|
||||
}
|
||||
AAsset_close(asset);
|
||||
ret = true;
|
||||
} else {
|
||||
if (asset_manager) {
|
||||
AAsset *asset = AAssetManager_open(asset_manager, abs_filename.c_str(),
|
||||
AASSET_MODE_STREAMING);
|
||||
if (!asset) {
|
||||
return false;
|
||||
}
|
||||
AAsset_close(asset);
|
||||
ret = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
FILE *fp;
|
||||
@ -1906,7 +1921,8 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||
const std::string &filepath, void *) {
|
||||
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
|
||||
if (asset_manager) {
|
||||
AAsset* asset = AAssetManager_open(asset_manager, filepath.c_str(), AASSET_MODE_STREAMING);
|
||||
AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(),
|
||||
AASSET_MODE_STREAMING);
|
||||
if (!asset) {
|
||||
if (err) {
|
||||
(*err) += "File open error : " + filepath + "\n";
|
||||
@ -2483,12 +2499,13 @@ static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err,
|
||||
json::const_iterator extIt = it.value().begin();
|
||||
for (; extIt != it.value().end(); extIt++) {
|
||||
if (!extIt.value().is_object()) continue;
|
||||
if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) {
|
||||
if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) {
|
||||
if (!extIt.key().empty()) {
|
||||
// create empty object so that an extension object is still of type object
|
||||
extensions[extIt.key()] = Value{ Value::Object{} };
|
||||
// create empty object so that an extension object is still of type
|
||||
// object
|
||||
extensions[extIt.key()] = Value{Value::Object{}};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
(*ret) = extensions;
|
||||
@ -2509,9 +2526,9 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseImage(Image *image, const int image_idx, std::string *err, std::string *warn,
|
||||
const json &o, const std::string &basedir,
|
||||
FsCallbacks *fs,
|
||||
static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
||||
std::string *warn, const json &o,
|
||||
const std::string &basedir, FsCallbacks *fs,
|
||||
LoadImageDataFunction *LoadImageData = nullptr,
|
||||
void *load_image_user_data = nullptr) {
|
||||
// A glTF image must either reference a bufferView or an image uri
|
||||
@ -2528,14 +2545,17 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
if (err) {
|
||||
(*err) +=
|
||||
"Only one of `bufferView` or `uri` should be defined, but both are "
|
||||
"defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
"defined for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasBufferView && !hasURI) {
|
||||
if (err) {
|
||||
(*err) += "Neither required `bufferView` nor `uri` defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
(*err) += "Neither required `bufferView` nor `uri` defined for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name +
|
||||
"\"\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2547,7 +2567,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
double bufferView = -1;
|
||||
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to parse `bufferView` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
|
||||
(*err) += "Failed to parse `bufferView` for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name +
|
||||
"\"\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2577,7 +2599,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
std::string tmp_err;
|
||||
if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
|
||||
(*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) +
|
||||
"] name = \"" + image->name + "\".\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2587,7 +2610,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
if (IsDataURI(uri)) {
|
||||
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to decode 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
|
||||
(*err) += "Failed to decode 'uri' for image[" +
|
||||
std::to_string(image_idx) + "] name = [" + image->name +
|
||||
"]\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2600,7 +2625,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
#endif
|
||||
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
|
||||
if (warn) {
|
||||
(*warn) += "Failed to load external 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
|
||||
(*warn) += "Failed to load external 'uri' for image[" +
|
||||
std::to_string(image_idx) + "] name = [" + image->name +
|
||||
"]\n";
|
||||
}
|
||||
// If the image cannot be loaded, keep uri as image->uri.
|
||||
return true;
|
||||
@ -2608,7 +2635,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std:
|
||||
|
||||
if (img.empty()) {
|
||||
if (warn) {
|
||||
(*warn) += "Image data is empty for image[" + std::to_string(image_idx) + "] name = [" + image->name + "] \n";
|
||||
(*warn) += "Image data is empty for image[" +
|
||||
std::to_string(image_idx) + "] name = [" + image->name +
|
||||
"] \n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2804,6 +2833,51 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
bufferView->byteOffset = static_cast<size_t>(byteOffset);
|
||||
bufferView->byteLength = static_cast<size_t>(byteLength);
|
||||
bufferView->byteStride = static_cast<size_t>(byteStride);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
||||
const json &o) {
|
||||
accessor->sparse.isSparse = true;
|
||||
|
||||
double count = 0.0;
|
||||
ParseNumberProperty(&count, err, o, "count", true);
|
||||
|
||||
const auto indices_iterator = o.find("indices");
|
||||
const auto values_iterator = o.find("values");
|
||||
if (indices_iterator == o.end()) {
|
||||
(*err) = "the sparse object of this accessor doesn't have indices";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (values_iterator == o.end()) {
|
||||
(*err) = "the sparse object ob ths accessor doesn't have values";
|
||||
return false;
|
||||
}
|
||||
|
||||
const json &indices_obj = *indices_iterator;
|
||||
const json &values_obj = *values_iterator;
|
||||
|
||||
double indices_buffer_view = 0.0, indices_byte_offset = 0.0,
|
||||
component_type = 0.0;
|
||||
ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
||||
true);
|
||||
ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
||||
true);
|
||||
ParseNumberProperty(&component_type, err, indices_obj, "componentType", true);
|
||||
|
||||
double values_buffer_view = 0.0, values_byte_offset = 0.0;
|
||||
ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true);
|
||||
ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true);
|
||||
|
||||
accessor->sparse.count = static_cast<int>(count);
|
||||
accessor->sparse.indices.bufferView = static_cast<int>(indices_buffer_view);
|
||||
accessor->sparse.indices.byteOffset = static_cast<int>(indices_byte_offset);
|
||||
accessor->sparse.indices.componentType = static_cast<int>(component_type);
|
||||
accessor->sparse.values.bufferView = static_cast<int>(values_buffer_view);
|
||||
accessor->sparse.values.byteOffset = static_cast<int>(values_byte_offset);
|
||||
|
||||
// todo check theses values
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2889,112 +2963,128 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
||||
|
||||
ParseExtrasProperty(&(accessor->extras), o);
|
||||
|
||||
// check if accessor has a "sparse" object:
|
||||
const auto iterator = o.find("sparse");
|
||||
if (iterator != o.end()) {
|
||||
// here this accessor has a "sparse" subobject
|
||||
return ParseSparseAccessor(accessor, err, *iterator);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TINYGLTF_ENABLE_DRACO
|
||||
|
||||
static void DecodeIndexBuffer(draco::Mesh* mesh, size_t componentSize, std::vector<uint8_t>& outBuffer)
|
||||
{
|
||||
if (componentSize == 4)
|
||||
{
|
||||
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
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
if (!pAttribute->ConvertValue<T>(val_index, pAttribute->num_components(),
|
||||
values))
|
||||
return false;
|
||||
|
||||
memcpy(outBuffer.data() + byteOffset, &values[0], sizeof(T) * pAttribute->num_components());
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
||||
std::string *err,
|
||||
const Value &dracoExtensionValue) {
|
||||
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
|
||||
if (!bufferViewValue.IsInt())
|
||||
return false;
|
||||
if (!bufferViewValue.IsInt()) return false;
|
||||
auto attributesValue = dracoExtensionValue.Get("attributes");
|
||||
if (!attributesValue.IsObject())
|
||||
return false;
|
||||
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 &view = model->bufferViews[bufferView];
|
||||
Buffer &buffer = model->buffers[view.buffer];
|
||||
// BufferView has already been decoded
|
||||
if (view.dracoDecoded)
|
||||
return true;
|
||||
if (view.dracoDecoded) return true;
|
||||
view.dracoDecoded = true;
|
||||
|
||||
const char* bufferViewData = reinterpret_cast<const char*>(buffer.data.data() + view.byteOffset);
|
||||
const char *bufferViewData =
|
||||
reinterpret_cast<const char *>(buffer.data.data() + view.byteOffset);
|
||||
size_t bufferViewSize = view.byteLength;
|
||||
|
||||
// decode draco
|
||||
@ -3005,12 +3095,12 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string
|
||||
if (!decodeResult.ok()) {
|
||||
return false;
|
||||
}
|
||||
const std::unique_ptr<draco::Mesh>& mesh = decodeResult.value();
|
||||
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);
|
||||
if (primitive->indices >= 0) {
|
||||
int32_t componentSize = GetComponentSizeInBytes(
|
||||
model->accessors[primitive->indices].componentType);
|
||||
Buffer decodedIndexBuffer;
|
||||
decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize);
|
||||
|
||||
@ -3020,35 +3110,37 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string
|
||||
|
||||
BufferView decodedIndexBufferView;
|
||||
decodedIndexBufferView.buffer = int(model->buffers.size() - 1);
|
||||
decodedIndexBufferView.byteLength = int(mesh->num_faces() * 3 * componentSize);
|
||||
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].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;
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
size_t bufferSize = mesh->num_points() * pAttribute->num_components() *
|
||||
GetComponentSizeInBytes(componentType);
|
||||
decodedBuffer.data.resize(bufferSize);
|
||||
|
||||
if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, decodedBuffer.data))
|
||||
if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute,
|
||||
decodedBuffer.data))
|
||||
return false;
|
||||
|
||||
model->buffers.emplace_back(std::move(decodedBuffer));
|
||||
@ -3058,11 +3150,15 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string
|
||||
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;
|
||||
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());
|
||||
model->accessors[primitiveAttribute->second].bufferView =
|
||||
int(model->bufferViews.size() - 1);
|
||||
model->accessors[primitiveAttribute->second].count =
|
||||
int(mesh->num_points());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -3112,17 +3208,18 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
||||
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);
|
||||
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, Model *model, std::string *err,
|
||||
const json &o) {
|
||||
ParseStringProperty(&mesh->name, err, o, "name", false);
|
||||
|
||||
mesh->primitives.clear();
|
||||
@ -3797,22 +3894,22 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
// Assign missing bufferView target types
|
||||
// - Look for missing Mesh indices
|
||||
// - Look for missing bufferView targets
|
||||
for (auto &mesh : model->meshes)
|
||||
{
|
||||
for (auto &primitive : mesh.primitives)
|
||||
{
|
||||
if (primitive.indices > -1) // has indices from parsing step, must be Element Array Buffer
|
||||
for (auto &mesh : model->meshes) {
|
||||
for (auto &primitive : mesh.primitives) {
|
||||
if (primitive.indices >
|
||||
-1) // has indices from parsing step, must be Element Array Buffer
|
||||
{
|
||||
model->bufferViews[model->accessors[primitive.indices].bufferView]
|
||||
.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
|
||||
// we could optionally check if acessors' bufferView type is Scalar, as it should be
|
||||
// we could optionally check if acessors' bufferView type is Scalar, as
|
||||
// it should be
|
||||
}
|
||||
}
|
||||
}
|
||||
// find any missing targets, must be an array buffer type if not fulfilled from previous check
|
||||
for (auto &bufferView : model->bufferViews)
|
||||
{
|
||||
if (bufferView.target == 0) // missing target type
|
||||
// find any missing targets, must be an array buffer type if not fulfilled
|
||||
// from previous check
|
||||
for (auto &bufferView : model->bufferViews) {
|
||||
if (bufferView.target == 0) // missing target type
|
||||
{
|
||||
bufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||
}
|
||||
@ -3931,7 +4028,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
for (; it != itEnd; it++, idx++) {
|
||||
if (!it.value().is_object()) {
|
||||
if (err) {
|
||||
(*err) += "image[" + std::to_string(idx) + "] is not a JSON object.";
|
||||
(*err) +=
|
||||
"image[" + std::to_string(idx) + "] is not a JSON object.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -3963,10 +4061,10 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ret = LoadImageData(&image, idx, err, warn, image.width, image.height,
|
||||
&buffer.data[bufferView.byteOffset],
|
||||
static_cast<int>(bufferView.byteLength),
|
||||
load_image_user_data_);
|
||||
bool ret = LoadImageData(
|
||||
&image, idx, err, warn, image.width, image.height,
|
||||
&buffer.data[bufferView.byteOffset],
|
||||
static_cast<int>(bufferView.byteLength), load_image_user_data_);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
@ -4420,7 +4518,7 @@ static void SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
||||
static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
||||
const std::string &binFilename) {
|
||||
std::ofstream output(binFilename.c_str(), std::ofstream::binary);
|
||||
if(!output.is_open()) return false;
|
||||
if (!output.is_open()) return false;
|
||||
output.write(reinterpret_cast<const char *>(&data[0]),
|
||||
std::streamsize(data.size()));
|
||||
output.close();
|
||||
@ -4469,9 +4567,10 @@ static void SerializeExtensionMap(ExtensionMap &extensions, json &o) {
|
||||
if (ValueToJson(extIt->second, &ret)) {
|
||||
extMap[extIt->first] = ret;
|
||||
}
|
||||
if(ret.is_null()) {
|
||||
if (!(extIt->first.empty())) { // name should not be empty, but for sure
|
||||
// create empty object so that an extension name is still included in json.
|
||||
if (ret.is_null()) {
|
||||
if (!(extIt->first.empty())) { // name should not be empty, but for sure
|
||||
// create empty object so that an extension name is still included in
|
||||
// json.
|
||||
extMap[extIt->first] = json({});
|
||||
}
|
||||
}
|
||||
@ -4602,7 +4701,7 @@ static void SerializeGltfBuffer(Buffer &buffer, json &o) {
|
||||
static bool SerializeGltfBuffer(Buffer &buffer, json &o,
|
||||
const std::string &binFilename,
|
||||
const std::string &binBaseFilename) {
|
||||
if(!SerializeGltfBufferData(buffer.data, binFilename)) return false;
|
||||
if (!SerializeGltfBufferData(buffer.data, binFilename)) return false;
|
||||
SerializeNumberProperty("byteLength", buffer.data.size(), o);
|
||||
SerializeStringProperty("uri", binBaseFilename, o);
|
||||
|
||||
@ -4890,9 +4989,10 @@ static void WriteBinaryGltfFile(const std::string &output,
|
||||
const int version = 2;
|
||||
const int padding_size = content.size() % 4;
|
||||
|
||||
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
|
||||
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info,
|
||||
// padding
|
||||
const int length = 12 + 8 + int(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));
|
||||
@ -4900,8 +5000,10 @@ static void WriteBinaryGltfFile(const std::string &output,
|
||||
// JSON chunk info, then JSON data
|
||||
const int model_length = int(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));
|
||||
gltfFile.write(reinterpret_cast<const char *>(&model_length),
|
||||
sizeof(model_length));
|
||||
gltfFile.write(reinterpret_cast<const char *>(&model_format),
|
||||
sizeof(model_format));
|
||||
gltfFile.write(content.c_str(), content.size());
|
||||
|
||||
// Chunk must be multiplies of 4, so pad with spaces
|
||||
@ -4947,7 +5049,8 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||
|
||||
std::string defaultBinFilename = GetBaseFilename(filename);
|
||||
std::string defaultBinFileExt = ".bin";
|
||||
std::string::size_type pos = defaultBinFilename.rfind('.', defaultBinFilename.length());
|
||||
std::string::size_type pos =
|
||||
defaultBinFilename.rfind('.', defaultBinFilename.length());
|
||||
|
||||
if (pos != std::string::npos) {
|
||||
defaultBinFilename = defaultBinFilename.substr(0, pos);
|
||||
@ -4967,28 +5070,27 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||
} else {
|
||||
std::string binSavePath;
|
||||
std::string binUri;
|
||||
if (!model->buffers[i].uri.empty()
|
||||
&& !IsDataURI(model->buffers[i].uri)) {
|
||||
if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
|
||||
binUri = model->buffers[i].uri;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
binUri = defaultBinFilename + defaultBinFileExt;
|
||||
bool inUse = true;
|
||||
int numUsed = 0;
|
||||
while(inUse) {
|
||||
while (inUse) {
|
||||
inUse = false;
|
||||
for (const std::string& usedName : usedUris) {
|
||||
for (const std::string &usedName : usedUris) {
|
||||
if (binUri.compare(usedName) != 0) continue;
|
||||
inUse = true;
|
||||
binUri = defaultBinFilename + std::to_string(numUsed++) + defaultBinFileExt;
|
||||
binUri = defaultBinFilename + std::to_string(numUsed++) +
|
||||
defaultBinFileExt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
usedUris.push_back(binUri);
|
||||
binSavePath = JoinPath(baseDir, binUri);
|
||||
if(!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
|
||||
binUri)) {
|
||||
binSavePath = JoinPath(baseDir, binUri);
|
||||
if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
|
||||
binUri)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user