Browse Source

Added JSON loading support for materials.

Nick Royer 10 years ago
parent
commit
ecdb9f84c4
2 changed files with 275 additions and 2 deletions
  1. 266 2
      Source/Urho3D/Graphics/Material.cpp
  2. 9 0
      Source/Urho3D/Graphics/Material.h

+ 266 - 2
Source/Urho3D/Graphics/Material.cpp

@@ -36,6 +36,7 @@
 #include "../IO/VectorBuffer.h"
 #include "../IO/VectorBuffer.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/ResourceCache.h"
 #include "../Resource/XMLFile.h"
 #include "../Resource/XMLFile.h"
+#include "../Resource/JSONFile.h"
 #include "../Scene/Scene.h"
 #include "../Scene/Scene.h"
 #include "../Scene/SceneEvents.h"
 #include "../Scene/SceneEvents.h"
 #include "../Scene/ValueAnimation.h"
 #include "../Scene/ValueAnimation.h"
@@ -197,7 +198,7 @@ bool Material::BeginLoad(Deserializer& source)
     if (!graphics)
     if (!graphics)
         return true;
         return true;
 
 
-    loadXMLFile_ = new XMLFile(context_);
+    loadXMLFile_ = new XMLFile(context_);    
     if (loadXMLFile_->Load(source))
     if (loadXMLFile_->Load(source))
     {
     {
         // If async loading, scan the XML content beforehand for technique & texture resources
         // If async loading, scan the XML content beforehand for technique & texture resources
@@ -241,10 +242,64 @@ bool Material::BeginLoad(Deserializer& source)
     }
     }
     else
     else
     {
     {
+        // Attempt to load a JSON file
         ResetToDefaults();
         ResetToDefaults();
         loadXMLFile_.Reset();
         loadXMLFile_.Reset();
-        return false;
+
+        // Attempt to load from JSON file instead
+        loadJSONFile_ = new JSONFile(context_);
+        if (loadJSONFile_->Load(source))
+        {
+            // If async loading, scan the XML content beforehand for technique & texture resources
+            // and request them to also be loaded. Can not do anything else at this point
+            if (GetAsyncLoadState() == ASYNC_LOADING)
+            {
+                ResourceCache* cache = GetSubsystem<ResourceCache>();
+                const JSONValue& rootVal = loadJSONFile_->GetRoot();
+
+                JSONArray techniqueArray = rootVal.Get("techniques").GetArray();
+                for (unsigned i = 0; i < techniqueArray.Size(); i++)
+                {
+                    const JSONValue& techVal = techniqueArray[i];
+                    cache->BackgroundLoadResource<Technique>(techVal.Get("name").GetString(), true, this);
+                }
+
+                JSONObject textureObject = rootVal.Get("textures").GetObject();
+                for (JSONObject::ConstIterator it = textureObject.Begin(); it != textureObject.End(); it++)
+                {
+                    String unitString = it->first_;
+                    String name = it->second_.GetString();
+                    // Detect cube maps by file extension: they are defined by an XML file
+                    /// \todo Differentiate with 3D textures by actually reading the XML content
+                    if (GetExtension(name) == ".xml")
+                    {
+    #ifdef DESKTOP_GRAPHICS
+                        TextureUnit unit = TU_DIFFUSE;
+                        unit = ParseTextureUnitName(unitString);
+
+                        if (unit == TU_VOLUMEMAP)
+                            cache->BackgroundLoadResource<Texture3D>(name, true, this);
+                        else
+    #endif
+                            cache->BackgroundLoadResource<TextureCube>(name, true, this);
+                    }
+                    else
+                        cache->BackgroundLoadResource<Texture2D>(name, true, this);
+                }
+            }
+
+            // JSON material was successfully loaded
+            return true;
+        }
+        else
+        {
+            // All loading failed
+            ResetToDefaults();
+            loadJSONFile_.Reset();
+            return false;
+        }
     }
     }
+
 }
 }
 
 
 bool Material::EndLoad()
 bool Material::EndLoad()
@@ -400,6 +455,137 @@ bool Material::Load(const XMLElement& source)
     return true;
     return true;
 }
 }
 
 
+bool Material::Load(const JSONValue& source)
+{
+    ResetToDefaults();
+
+    if (source.IsNull())
+    {
+        URHO3D_LOGERROR("Can not load material from null JSON element");
+        return false;
+    }
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+    // Load techniques
+    JSONArray techniquesArray = source.Get("techniques").GetArray();
+    techniques_.Clear();
+    techniques_.Reserve(techniquesArray.Size());
+
+    for (unsigned i = 0; i < techniquesArray.Size(); i++)
+    {
+        const JSONValue& techVal = techniquesArray[i];
+        Technique* tech = cache->GetResource<Technique>(techVal.Get("name").GetString());
+        if (tech)
+        {
+            TechniqueEntry newTechnique;
+            newTechnique.technique_ = tech;
+            JSONValue qualityVal = techVal.Get("quality");
+            if (!qualityVal.IsNull())
+                newTechnique.qualityLevel_ = qualityVal.GetInt();
+            JSONValue lodDistanceVal = techVal.Get("loddistance");
+            if (!lodDistanceVal.IsNull())
+                newTechnique.lodDistance_ = lodDistanceVal.GetFloat();
+            techniques_.Push(newTechnique);
+        }
+    }
+
+    SortTechniques();
+
+    // Load textures
+    JSONObject textureObject = source.Get("textures").GetObject();
+    for (JSONObject::ConstIterator it = textureObject.Begin(); it != textureObject.End(); it++)
+    {
+        String textureUnit = it->first_;
+        String textureName = it->second_.GetString();
+
+        TextureUnit unit = TU_DIFFUSE;
+        unit = ParseTextureUnitName(textureUnit);
+
+        if (unit < MAX_TEXTURE_UNITS)
+        {
+            // Detect cube maps by file extension: they are defined by an XML file
+            /// \todo Differentiate with 3D textures by actually reading the XML content
+            if (GetExtension(textureName) == ".xml")
+            {
+#ifdef DESKTOP_GRAPHICS
+                if (unit == TU_VOLUMEMAP)
+                    SetTexture(unit, cache->GetResource<Texture3D>(textureName));
+                else
+#endif
+                    SetTexture(unit, cache->GetResource<TextureCube>(textureName));
+            }
+            else
+                SetTexture(unit, cache->GetResource<Texture2D>(textureName));
+        }
+    }
+
+    // Get shader parameters
+    batchedParameterUpdate_ = true;
+    JSONObject parameterObject = source.Get("shaderParameters").GetObject();
+
+    for (JSONObject::ConstIterator it = parameterObject.Begin(); it != parameterObject.End(); it++)
+    {
+        String name = it->first_;
+        SetShaderParameter(name, ParseShaderParameterValue(it->second_.GetString()));
+    }
+    batchedParameterUpdate_ = false;
+
+    // Load shader parameter animationss
+    JSONObject paramAnimationsObject = source.Get("shaderParameterAnimations").GetObject();
+    for (JSONObject::ConstIterator it = paramAnimationsObject.Begin(); it != paramAnimationsObject.End(); it++)
+    {
+        String name = it->first_;
+        JSONValue paramAnimVal = it->second_;
+
+        SharedPtr<ValueAnimation> animation(new ValueAnimation(context_));
+        if (!animation->LoadJSON(paramAnimVal))
+        {
+            URHO3D_LOGERROR("Could not load parameter animation");
+            return false;
+        }
+
+        String wrapModeString = paramAnimVal.Get("wrapmode").GetString();
+        WrapMode wrapMode = WM_LOOP;
+        for (int i = 0; i <= WM_CLAMP; ++i)
+        {
+            if (wrapModeString == wrapModeNames[i])
+            {
+                wrapMode = (WrapMode)i;
+                break;
+            }
+        }
+
+        float speed = paramAnimVal.Get("speed").GetFloat();
+        SetShaderParameterAnimation(name, animation, wrapMode, speed);
+    }
+
+    JSONValue cullVal = source.Get("cull");
+    if (!cullVal.IsNull())
+        SetCullMode((CullMode)GetStringListIndex(cullVal.GetString().CString(), cullModeNames, CULL_CCW));
+
+    JSONValue shadowCullVal = source.Get("shadowcull");
+    if (!shadowCullVal.IsNull())
+        SetShadowCullMode((CullMode)GetStringListIndex(shadowCullVal.GetString().CString(), cullModeNames, CULL_CCW));
+
+    JSONValue fillVal = source.Get("fill");
+    if (!fillVal.IsNull())
+        SetFillMode((FillMode)GetStringListIndex(fillVal.GetString().CString(), fillModeNames, FILL_SOLID));
+
+    JSONValue depthBiasVal = source.Get("depthbias");
+    if (!depthBiasVal.IsNull())
+        SetDepthBias(BiasParameters(depthBiasVal.Get("constant").GetFloat(), depthBiasVal.Get("slopescaled").GetFloat()));
+
+    JSONValue renderOrderVal = source.Get("renderorder");
+    if (!renderOrderVal.IsNull())
+        SetRenderOrder((unsigned char)renderOrderVal.Get("value").GetUInt());
+
+    RefreshShaderParameterHash();
+    RefreshMemoryUse();
+    CheckOcclusion();
+    return true;
+}
+
 bool Material::Save(XMLElement& dest) const
 bool Material::Save(XMLElement& dest) const
 {
 {
     if (dest.IsNull())
     if (dest.IsNull())
@@ -479,6 +665,84 @@ bool Material::Save(XMLElement& dest) const
     return true;
     return true;
 }
 }
 
 
+bool Material::Save(JSONValue& dest) const
+{
+    if (dest.IsNull())
+    {
+        URHO3D_LOGERROR("Can not save material to null JSON value");
+        return false;
+    }
+
+    // Write techniques
+    JSONArray techniquesArray;
+    techniquesArray.Reserve(techniques_.Size());
+    for (unsigned i = 0; i < techniques_.Size(); ++i)
+    {
+        const TechniqueEntry& entry = techniques_[i];
+        if (!entry.technique_)
+            continue;
+
+        JSONValue techniqueVal;
+        techniqueVal.Set("name", entry.technique_->GetName());
+        techniqueVal.Set("quality", (int) entry.qualityLevel_);
+        techniqueVal.Set("loddistance", entry.lodDistance_);
+        techniquesArray.Push(techniqueVal);
+    }
+    dest.Set("techniques", techniquesArray);
+
+    // Write texture units
+    JSONValue texturesValue;
+    for (unsigned j = 0; j < MAX_TEXTURE_UNITS; ++j)
+    {
+        Texture* texture = GetTexture((TextureUnit)j);
+        if (texture)
+            texturesValue.Set(textureUnitNames[j], texture->GetName());
+    }
+    dest.Set("textures", texturesValue);
+
+    // Write shader parameters
+    JSONValue shaderParamsVal;
+    for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
+         j != shaderParameters_.End(); ++j)
+    {
+        shaderParamsVal.Set(j->second_.name_, j->second_.value_.ToString());
+    }
+    dest.Set("shaderParameters", shaderParamsVal);
+
+    // Write shader parameter animations
+    JSONValue shaderParamAnimationsVal;
+    for (HashMap<StringHash, SharedPtr<ShaderParameterAnimationInfo> >::ConstIterator j = shaderParameterAnimationInfos_.Begin();
+         j != shaderParameterAnimationInfos_.End(); ++j)
+    {
+        ShaderParameterAnimationInfo* info = j->second_;
+        JSONValue paramAnimationVal;
+        if (!info->GetAnimation()->SaveJSON(paramAnimationVal))
+            return false;
+
+        paramAnimationVal.Set("wrapmode", wrapModeNames[info->GetWrapMode()]);
+        paramAnimationVal.Set("speed", info->GetSpeed());
+        shaderParamAnimationsVal.Set(info->GetName(), paramAnimationVal);
+    }
+    dest.Set("shaderParameterAnimations", shaderParamAnimationsVal);
+
+    // Write culling modes
+    dest.Set("cull", cullModeNames[cullMode_]);
+    dest.Set("shadowcull", cullModeNames[shadowCullMode_]);
+
+    // Write fill mode
+    dest.Set("fill", fillModeNames[fillMode_]);
+
+    // Write depth bias
+    JSONValue depthBiasValue;
+    depthBiasValue.Set("constant", depthBias_.constantBias_);
+    depthBiasValue.Set("slopescaled", depthBias_.slopeScaledBias_);
+
+    // Write render order
+    dest.Set("renderorder", (unsigned) renderOrder_);
+
+    return true;
+}
+
 void Material::SetNumTechniques(unsigned num)
 void Material::SetNumTechniques(unsigned num)
 {
 {
     if (!num)
     if (!num)

+ 9 - 0
Source/Urho3D/Graphics/Material.h

@@ -39,6 +39,7 @@ class Texture;
 class Texture2D;
 class Texture2D;
 class TextureCube;
 class TextureCube;
 class ValueAnimationInfo;
 class ValueAnimationInfo;
+class JSONFile;
 
 
 static const unsigned char DEFAULT_RENDER_ORDER = 128;
 static const unsigned char DEFAULT_RENDER_ORDER = 128;
 
 
@@ -123,6 +124,12 @@ public:
     bool Load(const XMLElement& source);
     bool Load(const XMLElement& source);
     /// Save to an XML element. Return true if successful.
     /// Save to an XML element. Return true if successful.
     bool Save(XMLElement& dest) const;
     bool Save(XMLElement& dest) const;
+
+    /// Load from a JSON value. Return true if successful.
+    bool Load(const JSONValue& source);
+    /// Save to a JSON value. Return true if successful.
+    bool Save(JSONValue& dest) const;
+
     /// Set number of techniques.
     /// Set number of techniques.
     void SetNumTechniques(unsigned num);
     void SetNumTechniques(unsigned num);
     /// Set technique.
     /// Set technique.
@@ -278,6 +285,8 @@ private:
     bool batchedParameterUpdate_;
     bool batchedParameterUpdate_;
     /// XML file used while loading.
     /// XML file used while loading.
     SharedPtr<XMLFile> loadXMLFile_;
     SharedPtr<XMLFile> loadXMLFile_;
+    /// JSON file used while loading.
+    SharedPtr<JSONFile> loadJSONFile_;
     /// Associated scene for shader parameter animation updates.
     /// Associated scene for shader parameter animation updates.
     WeakPtr<Scene> scene_;
     WeakPtr<Scene> scene_;
 };
 };