585 lines
19 KiB
C++
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;
|
|
}
|
|
//------------------------------------------------------------------------------
|