/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "core/shader.h" #include "metafile/nml.h" #include "filesystem/filesystem.h" #include "platform.h" #include "log/log.h" using namespace GS::Core; using GS::NML::Tag; //------------------------------------------------------------------------------ void Shader::ParseVaryingTag(Tag *tag) { if (!tag || tag->name != "Varying") return; NMLTagForeach(it, *tag) if (it->name == "Variable") { Tag *t_name = it->GetTypedTag("Name", Variant::VariantString), *t_type = it->GetTypedTag("Type", Variant::VariantString); if (t_name && t_type) DeclareVarying(t_name->GetString(), t_type->GetString()); } } void Shader::ParseInputTag(Tag *tag) { if (!tag || tag->name != "Input") return; NMLTagForeach(it, *tag) { ShaderInput::Type type = ShaderInput::None; uint scope = 0; // Parse shader input. if (it->name == "Attribute") { type = ShaderInput::Attribute; scope = ShaderInput::Vertex; } else if (it->name == "Uniform") { type = ShaderInput::Uniform; scope = ShaderInput::Pixel; } if (type != ShaderInput::None) { String input_name; ShaderInput::DataType data_type = ShaderInput::NoData; ShaderInput::Semantic semantic = ShaderInput::Constant; if (Tag *t = it->GetTypedTag("Name", Variant::VariantString)) input_name = t->GetString(); if (Tag *t = it->GetTypedTag("Semantic", Variant::VariantString)) { String cs(t->GetString()); #if 1 // Legacy semantic support (changed with 1.3.0). if (cs == "Texture") cs = "Texture2D"; else if (cs == "NativeTexture") cs = "Texture2D"; else if (cs == "CubeTexture") cs = "TextureCube"; else if (cs == "User") cs = "Constant"; #endif uint n = 0; for (; n < ShaderInput::LastSemantic; ++n) if (cs == ShaderInput::semantic_desc[n].name) { semantic = (ShaderInput::Semantic)n; data_type = ShaderInput::semantic_desc[semantic].data_type; break; } if (n == ShaderInput::LastSemantic) __LOG_E__ << "Unknown shader input semantic '" << cs << "'.\n"; } if (Tag *t = it->GetTag("Type")) { String type(t->GetString()); if (type == "float") data_type = ShaderInput::Float; else if (type == "vec2") data_type = ShaderInput::Vector2; else if (type == "vec3") data_type = ShaderInput::Vector3; else if (type == "vec4") data_type = ShaderInput::Vector4; else if (type == "mat3") data_type = ShaderInput::Matrix3; else if (type == "mat4") data_type = ShaderInput::Matrix4; else __LOG_E__ << "Unknown type '" << type << "' for input '" << input_name << "'.\n"; } if (Tag *t = it->GetTag("Scope")) { scope = 0; if (t->GetTag("Vertex")) scope |= ShaderInput::Vertex; if (t->GetTag("Pixel") || t->GetTag("Fragment")) scope |= ShaderInput::Pixel; } ShaderInput *input = NULL; if (semantic != ShaderInput::LastSemantic) input = DeclareInput(input_name, data_type, semantic, type, (ShaderInput::Scope)scope); else __LOG_W__ << "Unknown shader input semantic in shader '" << name << "'.\n"; if (input) switch (input->semantic) { case ShaderInput::Texture2D: case ShaderInput::TextureCube: if (Tag *t = it->GetTypedTag("Texture", Variant::VariantString)) input->parm_t = t->GetString(); break; case ShaderInput::Constant: if (Tag *t = it->GetTag("Vector")) input->parm_v.FromMetaTag(*t); break; } } } } bool Shader::FromMetaTag(Tag &tag) { if (tag.name != "Shader") return false; Clear(); NMLTagForeach(pt, tag) { if (pt->name == "Name") name = pt->GetString(); else if (pt->name == "Varying") ParseVaryingTag(pt); else if (pt->name == "Input") ParseInputTag(pt); else if (pt->name == "VertexDeclaration") vertex_decl = pt->GetString(); else if (pt->name == "PixelDeclaration") pixel_decl = pt->GetString(); else if (pt->name == "GeometryDeclaration") geometry_decl = pt->GetString(); else if (pt->name == "VertexSource") vertex = pt->GetString(); else if ((pt->name == "PixelSource") || (pt->name == "FragmentSource")) pixel = pt->GetString(); else if (pt->name == "GeometrySource") geometry = pt->GetString(); else if (pt->name == "Vertex") { Array buffer; if (Platform::Get().io->FileLoad(pt->GetString(), buffer)) vertex.Set(buffer, &buffer[buffer.GetCount()]); } else if ((pt->name == "Pixel") || (pt->name == "Fragment")) { Array buffer; if (Platform::Get().io->FileLoad(pt->GetString(), buffer)) pixel.Set(buffer, &buffer[buffer.GetCount()]); } else if (pt->name == "Geometry") { Array buffer; if (Platform::Get().io->FileLoad(pt->GetString(), buffer)) geometry.Set(buffer, &buffer[buffer.GetCount()]); } else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; } return true; } Tag *Shader::AsMetaTag() const { Tag *root = new Tag("Shader"); if (!root) __ERR__(__LOG_E__ << "Could not serialize shader. Failed to create root tag.\n", NULL) if (input_list.GetCount()) if (Tag *it = root->AddChild("Input")) ListForeachPtr(ShaderInput *, input, input_list) { Tag *t = NULL; switch (input->type) { case ShaderInput::Attribute: t = new Tag("Attribute"); break; case ShaderInput::Uniform: t = new Tag("Uniform"); break; } if (!t) continue; t->AddChild("Name", input->name); t->AddChild("Semantic", ShaderInput::semantic_desc[input->semantic].name); if (Tag *st = t->AddChild("Scope")) { if (input->scope & ShaderInput::Vertex) st->AddChild("Vertex"); if (input->scope & ShaderInput::Pixel) st->AddChild("Pixel"); if (input->scope & ShaderInput::Geometry) st->AddChild("Geometry"); } switch (input->semantic) { case ShaderInput::Constant: switch (input->data_type) { case ShaderInput::Float: t->AddChild("Type", "float"); break; case ShaderInput::Vector2: t->AddChild("Type", "vec2"); break; case ShaderInput::Vector3: t->AddChild("Type", "vec3"); break; case ShaderInput::Vector4: t->AddChild("Type", "vec4"); break; case ShaderInput::Matrix3: t->AddChild("Type", "mat3"); break; case ShaderInput::Matrix4: t->AddChild("Type", "mat4"); break; } t->AddChild(input->parm_v.AsMetaTag("Vector")); break; } if (!input->parm_t.IsEmpty()) t->AddChild("Texture", input->parm_t.c_str()); it->AddChild(t); } if (varying_list.GetCount()) if (Tag *it = root->AddChild("Varying")) ListForeachPtr(ShaderVarying *, varying, varying_list) if (Tag *v = it->AddChild("Variable")) { v->AddChild("Name", varying->name); v->AddChild("Type", varying->type); } if (!geometry_decl.IsEmpty()) root->AddChild("GeometryDeclaration", geometry_decl); if (!vertex_decl.IsEmpty()) root->AddChild("VertexDeclaration", vertex_decl); if (!pixel_decl.IsEmpty()) root->AddChild("PixelDeclaration", pixel_decl); if (!geometry.IsEmpty()) root->AddChild("GeometrySource", geometry); if (!vertex.IsEmpty()) root->AddChild("VertexSource", vertex); if (!pixel.IsEmpty()) root->AddChild("PixelSource", pixel); return root; } //------------------------------------------------------------------------------