/* ----------------------------------------------------------------------------- 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 *ShaderBlock::BlockMapFromMetaTag(Tag &tag) { if (tag.name != "Map") return NULL; // Allocate block map. Array *block_map = new Array (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 *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 *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 &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 &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 &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 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; } //------------------------------------------------------------------------------