mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-15 00:36:05 +08:00
Add support for shaders, programs, and techniques
This commit is contained in:
parent
19894c7806
commit
cdf4cb79ed
@ -66,6 +66,36 @@ namespace tinygltf {
|
|||||||
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
|
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
|
||||||
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5127)
|
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5127)
|
||||||
|
|
||||||
|
// Redeclarations of the above for technique.parameters.
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_BYTE (5120)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE (5121)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_SHORT (5122)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT (5123)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_INT (5124)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT (5125)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT (5126)
|
||||||
|
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC2 (35664)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3 (35665)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC4 (35666)
|
||||||
|
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_INT_VEC2 (35667)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_INT_VEC3 (35668)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_INT_VEC4 (35669)
|
||||||
|
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_BOOL (35670)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC2 (35671)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC3 (35672)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC4 (35673)
|
||||||
|
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT2 (35674)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT3 (35675)
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT4 (35676)
|
||||||
|
|
||||||
|
#define TINYGLTF_PARAMETER_TYPE_SAMPLER_2D (35678)
|
||||||
|
|
||||||
|
// End parameter types
|
||||||
|
|
||||||
#define TINYGLTF_TYPE_VEC2 (2)
|
#define TINYGLTF_TYPE_VEC2 (2)
|
||||||
#define TINYGLTF_TYPE_VEC3 (3)
|
#define TINYGLTF_TYPE_VEC3 (3)
|
||||||
#define TINYGLTF_TYPE_VEC4 (4)
|
#define TINYGLTF_TYPE_VEC4 (4)
|
||||||
@ -88,6 +118,9 @@ namespace tinygltf {
|
|||||||
#define TINYGLTF_TARGET_ARRAY_BUFFER (34962)
|
#define TINYGLTF_TARGET_ARRAY_BUFFER (34962)
|
||||||
#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963)
|
#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963)
|
||||||
|
|
||||||
|
#define TINYGLTF_SHADER_TYPE_VERTEX_SHADER (35633)
|
||||||
|
#define TINYGLTF_SHADER_TYPE_FRAGMENT_SHADER (35632)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
std::string string_value;
|
std::string string_value;
|
||||||
std::vector<double> number_array;
|
std::vector<double> number_array;
|
||||||
@ -199,6 +232,36 @@ typedef struct {
|
|||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
} Buffer;
|
} Buffer;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string name;
|
||||||
|
int type;
|
||||||
|
std::vector<unsigned char> source;
|
||||||
|
} Shader;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string name;
|
||||||
|
std::string vertexShader;
|
||||||
|
std::string fragmentShader;
|
||||||
|
std::vector<std::string> attributes;
|
||||||
|
} Program;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
std::string node;
|
||||||
|
std::string semantic;
|
||||||
|
int type;
|
||||||
|
Parameter value;
|
||||||
|
} TechniqueParameter;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::string name;
|
||||||
|
std::string program;
|
||||||
|
std::map<std::string, TechniqueParameter> parameters;
|
||||||
|
std::map<std::string, std::string> attributes;
|
||||||
|
std::map<std::string, std::string> uniforms;
|
||||||
|
} Technique;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
std::string generator;
|
std::string generator;
|
||||||
std::string version;
|
std::string version;
|
||||||
@ -221,6 +284,9 @@ class Scene {
|
|||||||
std::map<std::string, Node> nodes;
|
std::map<std::string, Node> nodes;
|
||||||
std::map<std::string, Texture> textures;
|
std::map<std::string, Texture> textures;
|
||||||
std::map<std::string, Image> images;
|
std::map<std::string, Image> images;
|
||||||
|
std::map<std::string, Shader> shaders;
|
||||||
|
std::map<std::string, Program> programs;
|
||||||
|
std::map<std::string, Technique> techniques;
|
||||||
std::map<std::string, std::vector<std::string> > scenes; // list of nodes
|
std::map<std::string, std::vector<std::string> > scenes; // list of nodes
|
||||||
|
|
||||||
std::string defaultScene;
|
std::string defaultScene;
|
||||||
@ -1412,6 +1478,36 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ParseParameterProperty(Parameter *param, std::string *err,
|
||||||
|
const picojson::object &o,
|
||||||
|
const std::string &prop, bool required)
|
||||||
|
{
|
||||||
|
double num_val;
|
||||||
|
|
||||||
|
// A parameter value can either be a string or an array of either a boolean or
|
||||||
|
// a number. Booleans of any kind aren't supported here. Granted, it
|
||||||
|
// complicates the Parameter structure and breaks it semantically in the sense
|
||||||
|
// that the client probably works off the assumption that if the string is
|
||||||
|
// empty the vector is used, etc. Would a tagged union work?
|
||||||
|
if (ParseStringProperty(¶m->string_value, err, o, prop, false)) {
|
||||||
|
// Found string property.
|
||||||
|
return true;
|
||||||
|
} else if (ParseNumberArrayProperty(¶m->number_array, err,o,prop,false)) {
|
||||||
|
// Found a number array.
|
||||||
|
return true;
|
||||||
|
} else if (ParseNumberProperty(&num_val, err, o, prop, false)) {
|
||||||
|
param->number_array.push_back(num_val);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if(required) {
|
||||||
|
if(err) {
|
||||||
|
(*err) += "parameter must be a string or number / number array.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool ParseMaterial(Material *material, std::string *err,
|
static bool ParseMaterial(Material *material, std::string *err,
|
||||||
const picojson::object &o) {
|
const picojson::object &o) {
|
||||||
ParseStringProperty(&material->name, err, o, "name", false);
|
ParseStringProperty(&material->name, err, o, "name", false);
|
||||||
@ -1419,28 +1515,145 @@ static bool ParseMaterial(Material *material, std::string *err,
|
|||||||
|
|
||||||
material->values.clear();
|
material->values.clear();
|
||||||
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>();
|
||||||
|
|
||||||
picojson::object::const_iterator it(values_object.begin());
|
picojson::object::const_iterator it(values_object.begin());
|
||||||
picojson::object::const_iterator itEnd(values_object.end());
|
picojson::object::const_iterator itEnd(values_object.end());
|
||||||
|
|
||||||
for (; it != itEnd; it++) {
|
for (; it != itEnd; it++) {
|
||||||
// Assume number values.
|
|
||||||
Parameter param;
|
Parameter param;
|
||||||
if (ParseStringProperty(¶m.string_value, err, values_object,
|
if(ParseParameterProperty(¶m, err, values_object, it->first, false)) {
|
||||||
it->first, false)) {
|
material->values[it->first] = param;
|
||||||
// Found string property.
|
|
||||||
} else if (!ParseNumberArrayProperty(¶m.number_array, err,
|
|
||||||
values_object, it->first, false)) {
|
|
||||||
// Fallback to numer property.
|
|
||||||
double value;
|
|
||||||
if (ParseNumberProperty(&value, err, values_object, it->first, false)) {
|
|
||||||
param.number_array.push_back(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
material->values[it->first] = param;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseShader(Shader *shader, std::string *err,
|
||||||
|
const picojson::object &o, const std::string &basedir) {
|
||||||
|
std::string uri;
|
||||||
|
if (!ParseStringProperty(&uri, err, o, "uri", true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load shader source from data uri
|
||||||
|
// TODO: Support ascii or utf-8 data uris.
|
||||||
|
if (IsDataURI(uri)) {
|
||||||
|
if (!DecodeDataURI(&shader->source, uri, 0, false)) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Failed to decode 'uri'.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Assume external file
|
||||||
|
if (!LoadExternalFile(&shader->source, err, uri, basedir, 0, false)) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "Failed to load external 'uri'.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (shader->source.empty()) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "File is empty.\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double type;
|
||||||
|
if (!ParseNumberProperty(&type, err, o, "type", true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
shader->type = static_cast<int>(type);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseProgram(Program *program, std::string *err,
|
||||||
|
const picojson::object &o) {
|
||||||
|
ParseStringProperty(&program->name, err, o, "name", false);
|
||||||
|
|
||||||
|
if(!ParseStringProperty(&program->vertexShader, err,o, "vertexShader",true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!ParseStringProperty(&program->fragmentShader, err, o,
|
||||||
|
"fragmentShader", true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I suppose the list of attributes isn't needed, but a technique doesn't
|
||||||
|
// really make sense without it.
|
||||||
|
ParseStringArrayProperty(&program->attributes, err, o, "attributes", false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseTechniqueParameter(TechniqueParameter *param, std::string *err,
|
||||||
|
const picojson::object &o) {
|
||||||
|
|
||||||
|
double count = 1;
|
||||||
|
ParseNumberProperty(&count, err, o, "count", false);
|
||||||
|
|
||||||
|
double type;
|
||||||
|
if(!ParseNumberProperty(&type, err, o, "type", true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseStringProperty(¶m->node, err, o, "node", false);
|
||||||
|
ParseStringProperty(¶m->semantic, err, o, "semantic", false);
|
||||||
|
|
||||||
|
ParseParameterProperty(¶m->value, err, o, "value", false);
|
||||||
|
|
||||||
|
param->count = static_cast<int>(count);
|
||||||
|
param->type = static_cast<int>(type);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseTechnique(Technique *technique, std::string *err,
|
||||||
|
const picojson::object &o) {
|
||||||
|
ParseStringProperty(&technique->name, err, o, "name", false);
|
||||||
|
|
||||||
|
if(!ParseStringProperty(&technique->program, err, o, "program", true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseStringMapProperty(&technique->attributes, err, o, "attributes", false);
|
||||||
|
ParseStringMapProperty(&technique->uniforms, err, o, "uniforms", false);
|
||||||
|
|
||||||
|
technique->parameters.clear();
|
||||||
|
picojson::object::const_iterator paramsIt = o.find("parameters");
|
||||||
|
|
||||||
|
// Verify parameters is an object
|
||||||
|
if ((paramsIt != o.end()) && (paramsIt->second).is<picojson::object>()) {
|
||||||
|
|
||||||
|
// For each parameter in params_object.
|
||||||
|
const picojson::object ¶ms_object =
|
||||||
|
(paramsIt->second).get<picojson::object>();
|
||||||
|
|
||||||
|
picojson::object::const_iterator it(params_object.begin());
|
||||||
|
picojson::object::const_iterator itEnd(params_object.end());
|
||||||
|
|
||||||
|
for (; it != itEnd; it++) {
|
||||||
|
TechniqueParameter param;
|
||||||
|
|
||||||
|
// Skip non-objects
|
||||||
|
if(!it->second.is<picojson::object>()) continue;
|
||||||
|
|
||||||
|
// Parse the technique parameter
|
||||||
|
const picojson::object& param_obj = it->second.get<picojson::object>();
|
||||||
|
if(ParseTechniqueParameter(¶m, err, param_obj)) {
|
||||||
|
// Add if successful
|
||||||
|
technique->parameters[it->first] = param;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1718,6 +1931,59 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 10. Parse Shader
|
||||||
|
if (v.contains("shaders") && v.get("shaders").is<picojson::object>()) {
|
||||||
|
const picojson::object &root = v.get("shaders").get<picojson::object>();
|
||||||
|
|
||||||
|
picojson::object::const_iterator it(root.begin());
|
||||||
|
picojson::object::const_iterator itEnd(root.end());
|
||||||
|
for(; it != itEnd; ++it)
|
||||||
|
{
|
||||||
|
Shader shader;
|
||||||
|
if(!ParseShader(&shader, err, (it->second).get<picojson::object>(),
|
||||||
|
base_dir)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene->shaders[it->first] = shader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11. Parse Program
|
||||||
|
if (v.contains("programs") && v.get("programs").is<picojson::object>()) {
|
||||||
|
const picojson::object &root = v.get("programs").get<picojson::object>();
|
||||||
|
|
||||||
|
picojson::object::const_iterator it(root.begin());
|
||||||
|
picojson::object::const_iterator itEnd(root.end());
|
||||||
|
for(; it != itEnd; ++it)
|
||||||
|
{
|
||||||
|
Program program;
|
||||||
|
if(!ParseProgram(&program, err, (it->second).get<picojson::object>())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene->programs[it->first] = program;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 12. Parse Technique
|
||||||
|
if (v.contains("techniques") && v.get("techniques").is<picojson::object>()) {
|
||||||
|
const picojson::object &root = v.get("techniques").get<picojson::object>();
|
||||||
|
|
||||||
|
picojson::object::const_iterator it(root.begin());
|
||||||
|
picojson::object::const_iterator itEnd(root.end());
|
||||||
|
for(; it != itEnd; ++it)
|
||||||
|
{
|
||||||
|
Technique technique;
|
||||||
|
if(!ParseTechnique(&technique, err,
|
||||||
|
(it->second).get<picojson::object>())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene->techniques[it->first] = technique;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user