mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-16 20:15:53 +08:00
Support loading binary shader source data for binary glTF.
This commit is contained in:
parent
4904852e4e
commit
3cdfb3bd07
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Tiny glTF loader.
|
// Tiny glTF loader.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2015-2016, Syoyo Fujita.
|
// Copyright (c) 2015-2016, Syoyo Fujita and many contributors.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
// (Licensed under 2-clause BSD liecense)
|
// (Licensed under 2-clause BSD liecense)
|
||||||
//
|
//
|
||||||
@ -31,6 +31,8 @@
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Version:
|
// Version:
|
||||||
|
// - v0.9.4 Support parsing `shader`, `program` and `tecnique` thanks to @lukesanantonio
|
||||||
|
// - v0.9.3 Support binary glTF
|
||||||
// - v0.9.2 Support parsing `texture`
|
// - v0.9.2 Support parsing `texture`
|
||||||
// - v0.9.1 Support loading glTF asset from memory
|
// - v0.9.1 Support loading glTF asset from memory
|
||||||
// - v0.9.0 Initial
|
// - v0.9.0 Initial
|
||||||
@ -245,8 +247,7 @@ typedef struct {
|
|||||||
std::vector<std::string> attributes;
|
std::vector<std::string> attributes;
|
||||||
} Program;
|
} Program;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
int count;
|
int count;
|
||||||
std::string node;
|
std::string node;
|
||||||
std::string semantic;
|
std::string semantic;
|
||||||
@ -939,10 +940,8 @@ static bool ParseStringArrayProperty(std::vector<std::string> *ret,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseStringMapProperty(std::map<std::string, std::string> *ret,
|
static bool ParseStringMapProperty(std::map<std::string, std::string> *ret,
|
||||||
std::string *err,
|
std::string *err, const picojson::object &o,
|
||||||
const picojson::object &o,
|
const std::string &property, bool required) {
|
||||||
const std::string &property,
|
|
||||||
bool required) {
|
|
||||||
picojson::object::const_iterator it = o.find(property);
|
picojson::object::const_iterator it = o.find(property);
|
||||||
if (it == o.end()) {
|
if (it == o.end()) {
|
||||||
if (required) {
|
if (required) {
|
||||||
@ -1140,7 +1139,7 @@ static bool ParseImage(Image *image, std::string *err,
|
|||||||
if (IsDataURI(uri)) {
|
if (IsDataURI(uri)) {
|
||||||
if (!DecodeDataURI(&img, uri, 0, false)) {
|
if (!DecodeDataURI(&img, uri, 0, false)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to decode 'uri'.\n";
|
(*err) += "Failed to decode 'uri' for image parameter.\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1148,13 +1147,13 @@ static bool ParseImage(Image *image, std::string *err,
|
|||||||
// Assume external file
|
// Assume external file
|
||||||
if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) {
|
if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to load external 'uri'.\n";
|
(*err) += "Failed to load external 'uri'. for image parameter\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (img.empty()) {
|
if (img.empty()) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "File is empty.\n";
|
(*err) += "Image is empty.\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1250,8 +1249,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err,
|
|||||||
if (err) {
|
if (err) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Invalid `byteLength'. Must be equal or less than binary size: "
|
ss << "Invalid `byteLength'. Must be equal or less than binary size: "
|
||||||
"`byteLength' = "
|
"`byteLength' = " << byteLength
|
||||||
<< byteLength << ", binary size = " << bin_size << std::endl;
|
<< ", binary size = " << bin_size << std::endl;
|
||||||
(*err) += ss.str();
|
(*err) += ss.str();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1434,8 +1433,8 @@ static bool ParsePrimitive(Primitive *primitive, std::string *err,
|
|||||||
primitive->indices = "";
|
primitive->indices = "";
|
||||||
ParseStringProperty(&primitive->indices, err, o, "indices", false);
|
ParseStringProperty(&primitive->indices, err, o, "indices", false);
|
||||||
|
|
||||||
if(!ParseStringMapProperty(&primitive->attributes, err, o,
|
if (!ParseStringMapProperty(&primitive->attributes, err, o, "attributes",
|
||||||
"attributes", true)) {
|
true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1452,7 +1451,8 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) {
|
|||||||
(primObject->second).get<picojson::array>();
|
(primObject->second).get<picojson::array>();
|
||||||
for (size_t i = 0; i < primArray.size(); i++) {
|
for (size_t i = 0; i < primArray.size(); i++) {
|
||||||
Primitive primitive;
|
Primitive primitive;
|
||||||
if(ParsePrimitive(&primitive, err, primArray[i].get<picojson::object>())){
|
if (ParsePrimitive(&primitive, err,
|
||||||
|
primArray[i].get<picojson::object>())) {
|
||||||
// Only add the primitive if the parsing succeeds.
|
// Only add the primitive if the parsing succeeds.
|
||||||
mesh->primitives.push_back(primitive);
|
mesh->primitives.push_back(primitive);
|
||||||
}
|
}
|
||||||
@ -1494,8 +1494,7 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) {
|
|||||||
|
|
||||||
static bool ParseParameterProperty(Parameter *param, std::string *err,
|
static bool ParseParameterProperty(Parameter *param, std::string *err,
|
||||||
const picojson::object &o,
|
const picojson::object &o,
|
||||||
const std::string &prop, bool required)
|
const std::string &prop, bool required) {
|
||||||
{
|
|
||||||
double num_val;
|
double num_val;
|
||||||
|
|
||||||
// A parameter value can either be a string or an array of either a boolean or
|
// A parameter value can either be a string or an array of either a boolean or
|
||||||
@ -1506,7 +1505,8 @@ static bool ParseParameterProperty(Parameter *param, std::string *err,
|
|||||||
if (ParseStringProperty(¶m->string_value, err, o, prop, false)) {
|
if (ParseStringProperty(¶m->string_value, err, o, prop, false)) {
|
||||||
// Found string property.
|
// Found string property.
|
||||||
return true;
|
return true;
|
||||||
} else if (ParseNumberArrayProperty(¶m->number_array, err,o,prop,false)) {
|
} else if (ParseNumberArrayProperty(¶m->number_array, err, o, prop,
|
||||||
|
false)) {
|
||||||
// Found a number array.
|
// Found a number array.
|
||||||
return true;
|
return true;
|
||||||
} else if (ParseNumberProperty(&num_val, err, o, prop, false)) {
|
} else if (ParseNumberProperty(&num_val, err, o, prop, false)) {
|
||||||
@ -1531,7 +1531,6 @@ static bool ParseMaterial(Material *material, std::string *err,
|
|||||||
picojson::object::const_iterator valuesIt = o.find("values");
|
picojson::object::const_iterator valuesIt = o.find("values");
|
||||||
|
|
||||||
if ((valuesIt != o.end()) && (valuesIt->second).is<picojson::object>()) {
|
if ((valuesIt != o.end()) && (valuesIt->second).is<picojson::object>()) {
|
||||||
|
|
||||||
const picojson::object &values_object =
|
const picojson::object &values_object =
|
||||||
(valuesIt->second).get<picojson::object>();
|
(valuesIt->second).get<picojson::object>();
|
||||||
|
|
||||||
@ -1540,7 +1539,8 @@ static bool ParseMaterial(Material *material, std::string *err,
|
|||||||
|
|
||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
Parameter param;
|
Parameter param;
|
||||||
if(ParseParameterProperty(¶m, err, values_object, it->first, false)) {
|
if (ParseParameterProperty(¶m, err, values_object, it->first,
|
||||||
|
false)) {
|
||||||
material->values[it->first] = param;
|
material->values[it->first] = param;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1550,18 +1550,64 @@ static bool ParseMaterial(Material *material, std::string *err,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseShader(Shader *shader, std::string *err,
|
static bool ParseShader(Shader *shader, std::string *err,
|
||||||
const picojson::object &o, const std::string &basedir) {
|
const picojson::object &o, const std::string &basedir,
|
||||||
|
bool is_binary = false,
|
||||||
|
const unsigned char *bin_data = NULL,
|
||||||
|
size_t bin_size = 0) {
|
||||||
std::string uri;
|
std::string uri;
|
||||||
if (!ParseStringProperty(&uri, err, o, "uri", true)) {
|
if (!ParseStringProperty(&uri, err, o, "uri", true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_binary) {
|
||||||
|
// Still binary glTF accepts external dataURI. First try external resources.
|
||||||
|
bool loaded = false;
|
||||||
|
if (IsDataURI(uri)) {
|
||||||
|
loaded = DecodeDataURI(&shader->source, uri, 0, false);
|
||||||
|
} else {
|
||||||
|
// Assume external .bin file.
|
||||||
|
loaded = LoadExternalFile(&shader->source, err, uri, basedir, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
// load data from (embedded) binary data
|
||||||
|
|
||||||
|
if ((bin_size == 0) || (bin_data == NULL)) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid binary data.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There should be "extensions" property.
|
||||||
|
// "extensions":{"KHR_binary_glTF":{"bufferView": "id", ...
|
||||||
|
|
||||||
|
std::string buffer_view;
|
||||||
|
std::string mime_type;
|
||||||
|
int image_width;
|
||||||
|
int image_height;
|
||||||
|
bool ret = ParseKHRBinaryExtension(o, err, &buffer_view, &mime_type,
|
||||||
|
&image_width, &image_height);
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.compare("data:,") == 0) {
|
||||||
|
// ok
|
||||||
|
} else {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Invalid URI for binary data.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Load shader source from data uri
|
// Load shader source from data uri
|
||||||
// TODO: Support ascii or utf-8 data uris.
|
// TODO: Support ascii or utf-8 data uris.
|
||||||
if (IsDataURI(uri)) {
|
if (IsDataURI(uri)) {
|
||||||
if (!DecodeDataURI(&shader->source, uri, 0, false)) {
|
if (!DecodeDataURI(&shader->source, uri, 0, false)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to decode 'uri'.\n";
|
(*err) += "Failed to decode 'uri' for shader parameter.\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1569,17 +1615,18 @@ static bool ParseShader(Shader *shader, std::string *err,
|
|||||||
// Assume external file
|
// Assume external file
|
||||||
if (!LoadExternalFile(&shader->source, err, uri, basedir, 0, false)) {
|
if (!LoadExternalFile(&shader->source, err, uri, basedir, 0, false)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Failed to load external 'uri'.\n";
|
(*err) += "Failed to load external 'uri' for shader parameter.\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (shader->source.empty()) {
|
if (shader->source.empty()) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "File is empty.\n";
|
(*err) += "shader is empty.\n"; // This may be OK?
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double type;
|
double type;
|
||||||
if (!ParseNumberProperty(&type, err, o, "type", true)) {
|
if (!ParseNumberProperty(&type, err, o, "type", true)) {
|
||||||
@ -1595,11 +1642,12 @@ static bool ParseProgram(Program *program, std::string *err,
|
|||||||
const picojson::object &o) {
|
const picojson::object &o) {
|
||||||
ParseStringProperty(&program->name, err, o, "name", false);
|
ParseStringProperty(&program->name, err, o, "name", false);
|
||||||
|
|
||||||
if(!ParseStringProperty(&program->vertexShader, err,o, "vertexShader",true)) {
|
if (!ParseStringProperty(&program->vertexShader, err, o, "vertexShader",
|
||||||
|
true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!ParseStringProperty(&program->fragmentShader, err, o,
|
if (!ParseStringProperty(&program->fragmentShader, err, o, "fragmentShader",
|
||||||
"fragmentShader", true)) {
|
true)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1612,7 +1660,6 @@ static bool ParseProgram(Program *program, std::string *err,
|
|||||||
|
|
||||||
static bool ParseTechniqueParameter(TechniqueParameter *param, std::string *err,
|
static bool ParseTechniqueParameter(TechniqueParameter *param, std::string *err,
|
||||||
const picojson::object &o) {
|
const picojson::object &o) {
|
||||||
|
|
||||||
double count = 1;
|
double count = 1;
|
||||||
ParseNumberProperty(&count, err, o, "count", false);
|
ParseNumberProperty(&count, err, o, "count", false);
|
||||||
|
|
||||||
@ -1648,7 +1695,6 @@ static bool ParseTechnique(Technique *technique, std::string *err,
|
|||||||
|
|
||||||
// Verify parameters is an object
|
// Verify parameters is an object
|
||||||
if ((paramsIt != o.end()) && (paramsIt->second).is<picojson::object>()) {
|
if ((paramsIt != o.end()) && (paramsIt->second).is<picojson::object>()) {
|
||||||
|
|
||||||
// For each parameter in params_object.
|
// For each parameter in params_object.
|
||||||
const picojson::object ¶ms_object =
|
const picojson::object ¶ms_object =
|
||||||
(paramsIt->second).get<picojson::object>();
|
(paramsIt->second).get<picojson::object>();
|
||||||
@ -1928,7 +1974,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. Parse Texture
|
// 10. Parse Texture
|
||||||
if (v.contains("textures") && v.get("textures").is<picojson::object>()) {
|
if (v.contains("textures") && v.get("textures").is<picojson::object>()) {
|
||||||
const picojson::object &root = v.get("textures").get<picojson::object>();
|
const picojson::object &root = v.get("textures").get<picojson::object>();
|
||||||
|
|
||||||
@ -1945,17 +1991,16 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10. Parse Shader
|
// 11. Parse Shader
|
||||||
if (v.contains("shaders") && v.get("shaders").is<picojson::object>()) {
|
if (v.contains("shaders") && v.get("shaders").is<picojson::object>()) {
|
||||||
const picojson::object &root = v.get("shaders").get<picojson::object>();
|
const picojson::object &root = v.get("shaders").get<picojson::object>();
|
||||||
|
|
||||||
picojson::object::const_iterator it(root.begin());
|
picojson::object::const_iterator it(root.begin());
|
||||||
picojson::object::const_iterator itEnd(root.end());
|
picojson::object::const_iterator itEnd(root.end());
|
||||||
for(; it != itEnd; ++it)
|
for (; it != itEnd; ++it) {
|
||||||
{
|
|
||||||
Shader shader;
|
Shader shader;
|
||||||
if (!ParseShader(&shader, err, (it->second).get<picojson::object>(),
|
if (!ParseShader(&shader, err, (it->second).get<picojson::object>(),
|
||||||
base_dir)) {
|
base_dir, is_binary_, bin_data_, bin_size_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1963,14 +2008,13 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11. Parse Program
|
// 12. Parse Program
|
||||||
if (v.contains("programs") && v.get("programs").is<picojson::object>()) {
|
if (v.contains("programs") && v.get("programs").is<picojson::object>()) {
|
||||||
const picojson::object &root = v.get("programs").get<picojson::object>();
|
const picojson::object &root = v.get("programs").get<picojson::object>();
|
||||||
|
|
||||||
picojson::object::const_iterator it(root.begin());
|
picojson::object::const_iterator it(root.begin());
|
||||||
picojson::object::const_iterator itEnd(root.end());
|
picojson::object::const_iterator itEnd(root.end());
|
||||||
for(; it != itEnd; ++it)
|
for (; it != itEnd; ++it) {
|
||||||
{
|
|
||||||
Program program;
|
Program program;
|
||||||
if (!ParseProgram(&program, err, (it->second).get<picojson::object>())) {
|
if (!ParseProgram(&program, err, (it->second).get<picojson::object>())) {
|
||||||
return false;
|
return false;
|
||||||
@ -1980,14 +2024,13 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12. Parse Technique
|
// 13. Parse Technique
|
||||||
if (v.contains("techniques") && v.get("techniques").is<picojson::object>()) {
|
if (v.contains("techniques") && v.get("techniques").is<picojson::object>()) {
|
||||||
const picojson::object &root = v.get("techniques").get<picojson::object>();
|
const picojson::object &root = v.get("techniques").get<picojson::object>();
|
||||||
|
|
||||||
picojson::object::const_iterator it(root.begin());
|
picojson::object::const_iterator it(root.begin());
|
||||||
picojson::object::const_iterator itEnd(root.end());
|
picojson::object::const_iterator itEnd(root.end());
|
||||||
for(; it != itEnd; ++it)
|
for (; it != itEnd; ++it) {
|
||||||
{
|
|
||||||
Technique technique;
|
Technique technique;
|
||||||
if (!ParseTechnique(&technique, err,
|
if (!ParseTechnique(&technique, err,
|
||||||
(it->second).get<picojson::object>())) {
|
(it->second).get<picojson::object>())) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user