273 lines
7.5 KiB
C++
273 lines
7.5 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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 <char> buffer;
|
|
if (Platform::Get().io->FileLoad(pt->GetString(), buffer))
|
|
vertex.Set(buffer, &buffer[buffer.GetCount()]);
|
|
}
|
|
else if ((pt->name == "Pixel") || (pt->name == "Fragment"))
|
|
{
|
|
Array <char> buffer;
|
|
if (Platform::Get().io->FileLoad(pt->GetString(), buffer))
|
|
pixel.Set(buffer, &buffer[buffer.GetCount()]);
|
|
}
|
|
else if (pt->name == "Geometry")
|
|
{
|
|
Array <char> buffer;
|
|
if (Platform::Get().io->FileLoad(pt->GetString(), buffer))
|
|
geometry.Set(buffer, &buffer[buffer.GetCount()]);
|
|
}
|
|
else
|
|
__LOG_W__ << "Unknown tag '" << pt->name << "' in <Shader>.\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;
|
|
}
|
|
//------------------------------------------------------------------------------
|