Files
Webcam/include/engine/core/shader_tree_nml.cpp

585 lines
19 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree.h"
#include "core/shader_block.h"
#include "math/vector_nml.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
using NML::Tag;
/// Id of the NOOP shader block.
static String __ShaderBlockNoneTagId("None");
//------------------------------------------------------------------------------
Array <pShaderBlock> *ShaderBlock::BlockMapFromMetaTag(Tag &tag)
{
if (tag.name != "Map")
return NULL;
// Allocate block map.
Array <pShaderBlock> *block_map = new Array <pShaderBlock> (tag.GetChildCount());
if (!block_map)
__ERR__(__LOG_E__ << "Failed to allocate shader block map.\n", NULL)
for (uint n = 0; n < block_map->GetCount(); ++n)
(*block_map)[n] = NULL;
// Fill the block map.
uint block_count = 0;
NMLTagForeach(entry_tag, tag)
if (entry_tag->name == "Entry")
{
ShaderBlock *_block = NULL;
Tag *type_tag = entry_tag->GetTag("Type"),
*parm_tag = entry_tag->GetTag("Param");
//----------------------------------------------------
#define __InstanciateNewShaderBlock(__VAR__, __TYPE__)\
__TYPE__ *__VAR__ = new __TYPE__;\
_block = __VAR__;
#define __ValidateShaderBlockParam\
if (!parm_tag)\
break;
//----------------------------------------------------
if (type_tag)
{
int type;
String type_string(type_tag->GetString());
// Legacy block type support.
if ((type_string == "Sampler 2D") || (type_string == "Sampler Cube"))
type_string = "Texture Sampler";
if (type_string == "Normal Matrix")
type_string = "Normal View Matrix";
// Locate block.
for (type = ShaderBlock::TypeNone; type < ShaderBlock::TypeInvalid; ++type)
if (type_string == ShaderBlock::BlockTypeToString((BlockType)type))
break;
switch (type)
{
case TypeGeometryUV:
{
__InstanciateNewShaderBlock(block, GeometryUVShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Channel;", Variant::VariantInteger))
block->channel = tag->GetInteger();
}
break;
case TypeTextureSampler:
{
__InstanciateNewShaderBlock(block, TextureSamplerShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantString))
{
String sampler_type(tag->GetString());
if (sampler_type == "3D") block->sampler_type = TextureSamplerShaderBlock::Sampler3D;
else if (sampler_type == "Cube") block->sampler_type = TextureSamplerShaderBlock::SamplerCube;
else block->sampler_type = TextureSamplerShaderBlock::Sampler2D;
}
}
break;
case TypeRenderBuffer:
{
__InstanciateNewShaderBlock(block, RenderBufferShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Buffer;", Variant::VariantInteger))
block->buffer = (RenderBufferShaderBlock::RenderBuffer)tag->GetInteger();
}
break;
case TypeTexture:
{
__InstanciateNewShaderBlock(block, TextureShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Texture;", Variant::VariantString))
block->texture = tag->GetString();
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantString))
{
String texture_type(tag->GetString());
if (texture_type == "3D") block->texture_type = TextureShaderBlock::Texture3D;
else if (texture_type == "Cube") block->texture_type = TextureShaderBlock::TextureCube;
else block->texture_type = TextureShaderBlock::Texture2D;
}
}
break;
case TypeConstant:
{
__InstanciateNewShaderBlock(block, ConstantShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantInteger))
block->constant_type = (ShaderInput::DataType)tag->GetInteger();
Vector4 v(0, 0, 0);
if (Tag *tag = parm_tag->GetTag("Value;"))
v.FromMetaTag(*tag);
block->constant[0] = v.x;
block->constant[1] = v.y;
block->constant[2] = v.z;
block->constant[3] = v.w;
}
break;
case TypeColor:
{
__InstanciateNewShaderBlock(block, ColorShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTag("Color;"))
block->color.FromMetaTag(*tag);
}
break;
case TypeMaterialParam:
{
__InstanciateNewShaderBlock(block, MaterialParamShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Param;", Variant::VariantInteger))
block->param = (MaterialParamShaderBlock::MaterialParam)tag->GetInteger();
}
break;
case TypeMaterialTexture:
{
__InstanciateNewShaderBlock(block, MaterialTextureShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Slot;", Variant::VariantInteger))
block->slot = tag->GetInteger();
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantString))
{
String texture_type(tag->GetString());
if (texture_type == "3D") block->texture_type = MaterialTextureShaderBlock::Texture3D;
else if (texture_type == "Cube") block->texture_type = MaterialTextureShaderBlock::TextureCube;
else block->texture_type = MaterialTextureShaderBlock::Texture2D;
}
}
break;
case TypeSwizzle:
{
__InstanciateNewShaderBlock(block, SwizzleShaderBlock)
__ValidateShaderBlockParam
const char *swizzle = "nnnn";
if (Tag *tag = parm_tag->GetTag("Swizzle;"))
swizzle = tag->GetString();
for (int n = 0; n < 4; ++n)
if (swizzle[n] == 'n') block->swizzle[n] = SwizzleShaderBlock::SwizzleNone;
else if (swizzle[n] == 'x') block->swizzle[n] = SwizzleShaderBlock::SwizzleX;
else if (swizzle[n] == 'y') block->swizzle[n] = SwizzleShaderBlock::SwizzleY;
else if (swizzle[n] == 'z') block->swizzle[n] = SwizzleShaderBlock::SwizzleZ;
else if (swizzle[n] == 'w') block->swizzle[n] = SwizzleShaderBlock::SwizzleW;
else
{
__LOG_E__ << "Unexpected end of swizzle mask.\n";
break;
}
}
break;
case TypeBuild:
{
__InstanciateNewShaderBlock(block, BuildShaderBlock)
__ValidateShaderBlockParam
const char *build = "0000";
if (Tag *tag = parm_tag->GetTag("Build;"))
build = tag->GetString();
for (int n = 0; n < 4; ++n)
if (build[n] == '0') block->build[n] = BuildShaderBlock::BuildZero;
else if (build[n] == '1') block->build[n] = BuildShaderBlock::BuildOne;
else if (build[n] == 'x') block->build[n] = BuildShaderBlock::BuildX;
else if (build[n] == 'y') block->build[n] = BuildShaderBlock::BuildY;
else if (build[n] == 'z') block->build[n] = BuildShaderBlock::BuildZ;
else if (build[n] == 'w') block->build[n] = BuildShaderBlock::BuildW;
else
{
__LOG_E__ << "Unexpected end of build mask.\n";
break;
}
}
break;
case TypeGeometryVertex: _block = new GeometryVertexShaderBlock; break;
case TypeGeometrySkinning: _block = new GeometrySkinningShaderBlock; break;
case TypeGeometryNormal: _block = new GeometryNormalShaderBlock; break;
case TypeGeometryVertexColor: _block = new GeometryVertexColorShaderBlock; break;
case TypeGeometryTangentFrame: _block = new GeometryTangentFrameShaderBlock; break;
case TypeScreenUV: _block = new ScreenUVShaderBlock; break;
case TypeViewVector: _block = new ViewVectorShaderBlock; break;
case TypeViewport: _block = new ViewportShaderBlock; break;
case TypeNormalViewMatrix: _block = new NormalViewMatrixShaderBlock; break;
case TypeNormalMatrix: _block = new NormalMatrixShaderBlock; break;
case TypeModelViewMatrix: _block = new ModelViewMatrixShaderBlock; break;
case TypeModelMatrix: _block = new ModelMatrixShaderBlock; break;
case TypeMix: _block = new MixOperatorShaderBlock; break;
case TypeAdd: _block = new AddOperatorShaderBlock; break;
case TypeMul: _block = new MulOperatorShaderBlock; break;
case TypeSub: _block = new SubOperatorShaderBlock; break;
case TypeDiv: _block = new DivOperatorShaderBlock; break;
case TypeDot: _block = new DotOperatorShaderBlock; break;
case TypeCross: _block = new CrossOperatorShaderBlock; break;
case TypeClamp: _block = new ClampShaderBlock; break;
case TypeNormalize: _block = new NormalizeOperatorShaderBlock; break;
case TypeSin: _block = new SinusShaderBlock; break;
case TypeCos: _block = new CosinusShaderBlock; break;
case TypePow: _block = new PowShaderBlock; break;
case TypeAbs: _block = new AbsShaderBlock; break;
case TypeClock: _block = new ClockShaderBlock; break;
case TypeUnpackColorToVector: _block = new UnpackColorToVectorShaderBlock; break;
case TypePackVectorToColor: _block = new PackVectorToColorShaderBlock; break;
default:
__LOG_E__ << "Invalid block type '" << type_string << "'.\n";
break;
}
}
if (_block)
if (Tag *pos_tag = entry_tag->GetTag("Pos"))
tVectorFromMetaTag(_block->pos, *pos_tag);
// Add block to the map.
if (block_map->GetCount() > block_count)
(*block_map)[block_count++] = _block;
else
__LOG_E__ << "Block map full, unexpected error.\n";
}
else __LOG_W__ << "Unexpected tag '" << entry_tag->name << "' in shader map.\n";
return block_map;
}
ShaderBlock *ShaderBlock::BranchFromMetaTag(Tag &tag, Array <pShaderBlock> *block_map)
{
// Load block.
Tag *index_tag = tag.GetTypedTag("Index;", Variant::VariantInteger);
if (!index_tag)
__ERR__(__LOG_E__ << "No block index found.\n", NULL)
// Load map if none provided.
bool drop_map = false;
if (!block_map)
{
Tag *map_tag = tag.GetTag("Map;");
if (!map_tag)
__ERR__(__LOG_E__ << "No map to build shader branch.\n", NULL)
if ((block_map = BlockMapFromMetaTag(*map_tag)) == NULL)
return NULL;
drop_map = true;
}
// Link block to its inputs.
ShaderBlock *block = (*block_map)[index_tag->GetUnsigned()];
if (block && block->GetInputCount())
if (Tag *inputs_tag = tag.GetTag("Input;"))
{
int input_count = 0;
NMLTagForeach(input_tag, *inputs_tag)
if (input_tag && (input_tag->name != __ShaderBlockNoneTagId))
block->SetInput(input_count++, ShaderBlock::BranchFromMetaTag(*input_tag, block_map));
}
if (drop_map)
_safe_delete(block_map);
return block;
}
bool ShaderTree::FromMetaTag(Tag &tag)
{
if (tag.name != "ShaderMap")
return false;
// Load import map.
Tag *map_tag = tag.GetTag("Map;");
Array <pShaderBlock> *block_map = map_tag ? ShaderBlock::BlockMapFromMetaTag(*map_tag) : NULL;
// Sink block position.
if (Tag *pos_tag = tag.GetTag("Pos"))
tVectorFromMetaTag(pos, *pos_tag);
// Read in sinks.
Tag *sink_tag;
if ((sink_tag = tag.GetTag("Vertex:Block;")) != NULL)
sink[SinkVertex] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Normal:Block;")) != NULL)
sink[SinkNormal] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Diffuse:Block;")) != NULL)
sink[SinkDiffuse] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Modulate:Block;")) != NULL)
sink[SinkModulate] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Specular:Block;")) != NULL)
sink[SinkSpecular] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Glossiness:Block;")) != NULL)
sink[SinkGlossiness] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Constant:Block;")) != NULL)
sink[SinkConstant] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Opacity:Block;")) != NULL)
sink[SinkOpacity] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Reflection:Block;")) != NULL)
sink[SinkReflection] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
_safe_delete(block_map);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *ShaderBlock::ParamAsMetaTag() const
{
Tag *parm = new Tag("Param");
switch (type)
{
case TypeGeometryUV:
{
GeometryUVShaderBlock *block = (GeometryUVShaderBlock *)this;
parm->AddChild("Channel", block->channel);
}
break;
case TypeTextureSampler:
{
TextureSamplerShaderBlock *block = (TextureSamplerShaderBlock *)this;
switch (block->sampler_type)
{
default:
case TextureSamplerShaderBlock::Sampler2D: parm->AddChild("Type", "2D"); break;
case TextureSamplerShaderBlock::Sampler3D: parm->AddChild("Type", "3D"); break;
case TextureSamplerShaderBlock::SamplerCube: parm->AddChild("Type", "Cube"); break;
}
}
break;
case TypeRenderBuffer:
{
RenderBufferShaderBlock *block = (RenderBufferShaderBlock *)this;
parm->AddChild("Buffer", (int)block->buffer);
}
break;
case TypeTexture:
{
TextureShaderBlock *block = (TextureShaderBlock *)this;
if (!block->texture.IsEmpty())
parm->AddChild("Texture", block->texture.c_str());
switch (block->texture_type)
{
default:
case TextureShaderBlock::Texture2D: parm->AddChild("Type", "2D"); break;
case TextureShaderBlock::Texture3D: parm->AddChild("Type", "3D"); break;
case TextureShaderBlock::TextureCube: parm->AddChild("Type", "Cube"); break;
}
}
break;
case TypeConstant:
{
ConstantShaderBlock *block = (ConstantShaderBlock *)this;
parm->AddChild("Type", (int)block->constant_type);
parm->AddChild(Vector4(block->constant[0], block->constant[1], block->constant[2], block->constant[3]).AsMetaTag("Value", true));
}
break;
case TypeColor:
{
ColorShaderBlock *block = (ColorShaderBlock *)this;
parm->AddChild(block->color.AsMetaTag("Color", true));
}
break;
case TypeMaterialParam:
{
MaterialParamShaderBlock *block = (MaterialParamShaderBlock *)this;
parm->AddChild("Param", block->param);
}
break;
case TypeMaterialTexture:
{
MaterialTextureShaderBlock *block = (MaterialTextureShaderBlock *)this;
parm->AddChild(new Tag("Slot", block->slot));
switch (block->texture_type)
{
default:
case MaterialTextureShaderBlock::Texture2D: parm->AddChild("Type", "2D"); break;
case MaterialTextureShaderBlock::Texture3D: parm->AddChild("Type", "3D"); break;
case MaterialTextureShaderBlock::TextureCube: parm->AddChild("Type", "Cube"); break;
}
}
break;
case TypeSwizzle:
{
SwizzleShaderBlock *block = (SwizzleShaderBlock *)this;
char swizzle[5];
for (int n = 0; n < 4; ++n)
switch (block->swizzle[n])
{
case SwizzleShaderBlock::SwizzleNone: swizzle[n] = 'n'; break;
case SwizzleShaderBlock::SwizzleX: swizzle[n] = 'x'; break;
case SwizzleShaderBlock::SwizzleY: swizzle[n] = 'y'; break;
case SwizzleShaderBlock::SwizzleZ: swizzle[n] = 'z'; break;
case SwizzleShaderBlock::SwizzleW: swizzle[n] = 'w'; break;
}
swizzle[4] = 0;
parm->AddChild("Swizzle", (const char *)swizzle);
}
break;
case TypeBuild:
{
BuildShaderBlock *block = (BuildShaderBlock *)this;
char build[5];
for (int n = 0; n < 4; ++n)
switch (block->build[n])
{
case BuildShaderBlock::BuildZero: build[n] = '0'; break;
case BuildShaderBlock::BuildOne: build[n] = '1'; break;
case BuildShaderBlock::BuildX: build[n] = 'x'; break;
case BuildShaderBlock::BuildY: build[n] = 'y'; break;
case BuildShaderBlock::BuildZ: build[n] = 'z'; break;
case BuildShaderBlock::BuildW: build[n] = 'w'; break;
}
build[4] = 0;
parm->AddChild("Build", (const char *)build);
}
break;
default:
break;
}
return parm;
}
void ShaderBlock::GatherChildren(List <ShaderBlock *> &children)
{
if (!children.Find(this))
children.Add(this);
for (uint n = 0; n < GetInputCount(); ++n)
if (GetInput(n))
GetInput(n)->GatherChildren(children);
}
Tag *ShaderBlock::BranchAsMetaTag(List <ShaderBlock *> &block_map)
{
// Locate block in map.
uint index = 0;
ListForeachPtr(ShaderBlock *, block, block_map)
{
if (block == this)
break;
index++;
}
if (index == block_map.GetCount())
return NULL;
// Export block and inputs.
Tag *block = new Tag("Block");
block->AddChild("Index", index);
if (GetInputCount())
{
Tag *input = block->AddChild("Input");
for (uint n = 0; n < GetInputCount(); ++n)
input->AddChild(GetInput(n) ? GetInput(n)->BranchAsMetaTag(block_map) : new Tag(__ShaderBlockNoneTagId.c_str()));
}
return block;
}
Tag *ShaderBlock::BlockMapAsMetaTag(const List <ShaderBlock *> &block_map)
{
Tag *map = new Tag("Map");
if (!map)
__ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL);
ListForeachPtr(ShaderBlock *, block, block_map)
if (block)
if (Tag *entry = map->AddChild("Entry"))
{
entry->AddChild("Type", ShaderBlock::BlockTypeToString(block->type));
entry->AddChild(tVectorAsMetaTag(block->pos, "Pos"));
entry->AddChild(block->ParamAsMetaTag());
}
return map;
}
Tag *ShaderTree::AsMetaTag() const
{
Tag *map = new Tag("ShaderMap");
if (!map)
__ERR__(__LOG_E__ << "Could not serialize shader map. Failed to create root tag.\n", NULL);
// Sink block position.
map->AddChild(tVectorAsMetaTag(pos, "Pos"));
// Build block export map.
List <ShaderBlock *> block_map;
for (int n = 0; n < SinkInvalid; ++n)
if (sink[n])
sink[n]->GatherChildren(block_map);
// Serialize map.
map->AddChild(ShaderBlock::BlockMapAsMetaTag(block_map));
// Serialize all sinks.
#define __SerializeShaderMapSink(__SINK__, __LABEL__)\
if (__SINK__)\
{\
Tag *sinktag = map->AddChild(__LABEL__);\
sinktag->AddChild((__SINK__)->BranchAsMetaTag(block_map));\
}
// Serialize shader map.
__SerializeShaderMapSink(sink[SinkVertex], "Vertex")
__SerializeShaderMapSink(sink[SinkNormal], "Normal")
__SerializeShaderMapSink(sink[SinkDiffuse], "Diffuse")
__SerializeShaderMapSink(sink[SinkModulate], "Modulate")
__SerializeShaderMapSink(sink[SinkSpecular], "Specular")
__SerializeShaderMapSink(sink[SinkGlossiness], "Glossiness")
__SerializeShaderMapSink(sink[SinkConstant], "Constant")
__SerializeShaderMapSink(sink[SinkOpacity], "Opacity")
__SerializeShaderMapSink(sink[SinkReflection], "Reflection")
return map;
}
//------------------------------------------------------------------------------