/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "core/material.h" #include "core/embedded_resource_handler_interface.h" #include "metafile/nml.h" #include "log/log.h" using namespace GS::Core; using namespace GS::NML; //------------------------------------------------------------------------------ bool Material::FromMetaTag(Tag &tag) { if (tag.name != "Material") __ERR__(__LOG_E__ << "Could not parse material, incorrect root tag (" << tag.name << ").\n", false); Reset(); /* Implementation note. These strings are declared here once for the whole function to benefit from the hash value-based early exit that the String comparison function provide. */ static String _diffuse("Diffuse"), _specular("Specular"), _self("Self"), _ambient("Ambient"), _glossiness("Glossiness"), _reflection("Reflection"), _ior("IOR"), _ath("AlphaThreshold"), _msa("MaxSmoothingAngle"), _opac("Opacity"), _rmask("RenderMask"), _blendop("BlendOp"), _shadermap("ShaderMap"), _shd("Shader"), _stage("TextureStage"), _physic("PhysicMaterial"), _depthbias("DepthBias"); NMLTagForeach(pt, tag) { if (pt->name == _diffuse) diffuse.FromMetaTag(*pt); else if (pt->name == _specular) specular.FromMetaTag(*pt); else if (pt->name == _self) self.FromMetaTag(*pt); else if (pt->name == _ambient) ambient.FromMetaTag(*pt); else if (pt->name == _glossiness) glossiness = Types::Clamp(pt->GetReal(), 0.01f, 16.f); else if (pt->name == _reflection) reflection = pt->GetReal(); else if (pt->name == _ior) irefraction = pt->GetReal(); else if (pt->name == _msa); // Legacy else if (pt->name == _opac) opacity = pt->GetReal(); else if (pt->name == _ath) athreshold = pt->GetReal(); else if (pt->name == _depthbias) depth_bias = pt->GetReal(); else if (pt->name == _shd) shader = pt->GetString(); // Physic material. else if (pt->name == _physic) PhysicMaterial::FromMetaTag(*pt); // Render word. else if (pt->name == _rmask) { static String _shdless("Shadeless"), _smooth("Smoothing"), _add("Additive"), _dbs("DoubleSided"), _usefbuffer("UseFramebuffer"), _skn("Skinned"), _wire("Wireframe"), _unlit("Unlit"), _vcolor("VertexColor"), _soft("SoftBody"), _sub("Subtractive"), _subs("Substractive"), _vnrm("ForceVertexNormal"), _nrmtgt("NormalMapTangent"), _toon("Toon"), _alpha("Alpha"), _atest("AlphaTest"), _parr("ParralaxDisp"), _nozw("NoZWrite"), _nozt("NoZTest"), _nofog("NoFog"), _fixdfunc("FixedFunction"), _asoftz("AlphaSoftZ"), _asmap("AlphaInShadow"); NMLTagForeach(mskt, *pt) { if (mskt->name == _unlit) renderword |= Render_Unlit; else if (mskt->name == _smooth) renderword |= Render_Smooth; else if (mskt->name == _nrmtgt) renderword |= Render_NormalTangent; else if (mskt->name == _nofog) renderword |= Render_NoFog; else if (mskt->name == _dbs) renderword |= Render_DoubleSided; else if (mskt->name == _wire) renderword |= Render_Wire; else if (mskt->name == _vcolor) renderword |= Render_VertexColor; else if (mskt->name == _parr) renderword |= Render_ParralaxDisp; else if (mskt->name == _toon) renderword |= Render_Toon; else if (mskt->name == _nozw) renderword |= Render_NoZWrite; else if (mskt->name == _nozt) renderword |= Render_NoZTest; else if (mskt->name == _asoftz) renderword |= Render_AlphaSoftZ; else if (mskt->name == _asmap) renderword |= Render_AlphaInShadow; else if (mskt->name == _atest) renderword |= Render_AlphaTest; else if (mskt->name == _usefbuffer) renderword |= Render_UseFramebuffer; else if (mskt->name == _skn) renderword |= Render_Skinned; #if 1 // Legacy else if (mskt->name == _add) blendop = Blend_Add; else if (mskt->name == _alpha) blendop = Blend_Alpha; else if (mskt->name == _fixdfunc) blendop = Blend_Alpha; else if (mskt->name == "Lit") ; #endif else __LOG_W__ << "Unknown tag '" << mskt->name << "' in material '" << name << "'.\n"; } } // Blend operator. else if (pt->name == _blendop) { String op(pt->GetString()); if (op == "Add") blendop = Blend_Add; else if (op == "Alpha") blendop = Blend_Alpha; } #if (__PLATFORM_NINTENDO_WII__ == 0) // Shader map. else if (pt->name == _shadermap) IEmbeddedResourceHandler::Get()->ExtractEmbeddedShaderTree(shader, *pt, name); #endif // Texture stage. else if (pt->name == _stage) { Tag *idx = pt->GetTag("Index"); if (idx && (idx->GetType() == Variant::VariantInteger)) { int n = idx->GetInteger(); if ((n >= 0) && (n < 8)) { TextureStage *lvl = &texstage[n]; static String _texture("Texture"), _iuv("UV"); static String _operator("Operator"), _uvsrc("UVSource"); // Reset level. lvl->channel = Channel_None; lvl->op = Operator_Default; lvl->uv_index = 0; // Fetch channel first. Tag *tst = pt->GetTag("Channel"); lvl->channel = tst ? MaterialChannelFromName(tst->GetString()) : Channel_Diffuse; // Pool remaining tags. NMLTagForeach(tst, *pt) { if (tst->name == _texture) lvl->t = tst->GetString(); else if (tst->name == _iuv) lvl->uv_index = (uchar)tst->GetInteger(); else if (tst->name == _operator) { String op(tst->GetString()); if (op == "Multiply") lvl->op = Operator_Multiply; else if (op == "Add") lvl->op = Operator_Add; } // Texture level UV source. else if (tst->name == _uvsrc) { String fnv(tst->GetString()); if (fnv == "UVMap") lvl->uv_mode = UV_UV; else if (fnv == "LSNormal") lvl->uv_mode = UV_LSN; else if (fnv == "FrontMap") lvl->uv_mode = UV_FrontMap; else if (fnv == "SphericalEnvironment") lvl->uv_mode = UV_SphericalEnvironment; else __LOG_W__ << "Unknown UV source for texture stage " << n << " of material '" << name << "'.\n"; } } texstage_count++; } else __LOG_W__ << "Illegal texture stage index " << n << " in material '" << name << "'.\n"; } else __LOG_W__ << "Illegal index tag type in material '" << name << "'.\n"; } #if 1 // Legacy else if (pt->name == "Id") ; #endif else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\n"; } return true; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ Tag *Material::AsMetaTag() const { Tag *material = new Tag("Material"); if (!material) __ERR__(__LOG_E__ << "Could not serialize material '" << name << "'. Failed to create root tag.\n", NULL) // Base properties. if (diffuse != Color::White) material->AddChild(diffuse.AsMetaTag("Diffuse", true)); if (specular != Color::White) material->AddChild(specular.AsMetaTag("Specular")); if (self != Color::Black) material->AddChild(self.AsMetaTag("Self")); if (ambient != Color::White) material->AddChild(ambient.AsMetaTag("Ambient")); if (glossiness != 0.4f) material->AddChild("Glossiness", glossiness); if (opacity != 1) material->AddChild("Opacity", opacity); if (reflection != 0) material->AddChild("Reflection", reflection); if (irefraction != 1) material->AddChild("IOR", irefraction); if (athreshold != 0.1) material->AddChild("AlphaThreshold", athreshold); if (depth_bias != 0) material->AddChild("DepthBias", depth_bias); // Physics. material->AddChild(PhysicMaterial::AsMetaTag()); // Render word. if (renderword != Render_None) { if (Tag *rword = material->AddChild("RenderMask")) { if (renderword & Render_Unlit) rword->AddChild("Unlit"); if (renderword & Render_Smooth) rword->AddChild("Smoothing"); if (renderword & Render_NormalTangent) rword->AddChild("NormalMapTangent"); if (renderword & Render_NoFog) rword->AddChild("NoFog"); if (renderword & Render_DoubleSided) rword->AddChild("DoubleSided"); if (renderword & Render_Wire) rword->AddChild("Wireframe"); if (renderword & Render_VertexColor) rword->AddChild("VertexColor"); if (renderword & Render_ParralaxDisp) rword->AddChild("ParralaxDisp"); if (renderword & Render_Toon) rword->AddChild("Toon"); if (renderword & Render_NoZWrite) rword->AddChild("NoZWrite"); if (renderword & Render_NoZTest) rword->AddChild("NoZTest"); if (renderword & Render_AlphaSoftZ) rword->AddChild("AlphaSoftZ"); if (renderword & Render_AlphaInShadow) rword->AddChild("AlphaInShadow"); if (renderword & Render_AlphaTest) rword->AddChild("AlphaTest"); if (renderword & Render_UseFramebuffer) rword->AddChild("UseFramebuffer"); if (renderword & Render_Skinned) rword->AddChild("Skinned"); } else __LOG_W__ << "Could not serialize material '" << name << "' render word.\n"; } // Blend operator. if (blendop != Blend_None) switch (blendop) { case Blend_Add: material->AddChild("BlendOp", "Add"); break; case Blend_Alpha: material->AddChild("BlendOp", "Alpha"); break; } // Shader id. if (!shader.IsEmpty()) material->AddChild("Shader", shader.c_str()); // Texture stages. for (int n = 0; n < max_texture_stage; n++) { const TextureStage *lvl = &texstage[n]; if (!lvl->t.IsEmpty()) { if (Tag *ts = new Tag("TextureStage")) { material->AddChild(ts); ts->AddChild("Index", n); ts->AddChild("Texture", lvl->t.c_str()); ts->AddChild("UV", lvl->uv_index); if (lvl->op != Operator_Default) switch (lvl->op) { case Operator_Add: ts->AddChild("Operator", "Add"); break; case Operator_Multiply: ts->AddChild("Operator", "Multiply"); break; } if (lvl->channel != Channel_Diffuse) { if (const char *c = MaterialChannelName(lvl->channel)) ts->AddChild("Channel", c); else __LOG_W__ << "Bogus channel in texture stage " << n << " material '" << name << "'.\n"; } if (lvl->uv_mode != UV_UV) switch (lvl->uv_mode) { case UV_UV: ts->AddChild("UVSource", "UVMap"); break; case UV_LSN: ts->AddChild("UVSource", "LSNormal"); break; case UV_FrontMap: ts->AddChild("UVSource", "FrontMap"); break; case UV_SphericalEnvironment: ts->AddChild("UVSource", "SphericalEnvironment"); break; default: __LOG_W__ << "Bogus channel in texture stage " << n << " material '" << name << "'.\n"; break; } } else __LOG_W__ << "Could not serialize a texture stage in material '" << name << "'.\n"; } } return material; } //------------------------------------------------------------------------------