summaryrefslogtreecommitdiff
path: root/Runtime/Filters/RendererAnimationBinding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Filters/RendererAnimationBinding.cpp')
-rw-r--r--Runtime/Filters/RendererAnimationBinding.cpp407
1 files changed, 407 insertions, 0 deletions
diff --git a/Runtime/Filters/RendererAnimationBinding.cpp b/Runtime/Filters/RendererAnimationBinding.cpp
new file mode 100644
index 0000000..fef77e7
--- /dev/null
+++ b/Runtime/Filters/RendererAnimationBinding.cpp
@@ -0,0 +1,407 @@
+#include "UnityPrefix.h"
+#include "Runtime/Animation/GenericAnimationBindingCache.h"
+#include "Runtime/Animation/AnimationClipBindings.h"
+#include "Renderer.h"
+#include "External/shaderlab/Library/FastPropertyName.h"
+#include "External/shaderlab/Library/properties.h"
+#include "Runtime/Shaders/Material.h"
+#include "Runtime/Shaders/MaterialProperties.h"
+#include "Runtime/Interfaces/IAnimationBinding.h"
+
+#define MATERIAL_ANIMATION 1
+
+class RendererAnimationBinding : public IAnimationBinding
+{
+#if UNITY_EDITOR
+ virtual void GetAllAnimatableProperties (Object& targetObject, std::vector<EditorCurveBinding>& outProperties) const
+ {
+ Renderer& renderer = static_cast<Renderer&> (targetObject);
+
+ for (int i=0;i<renderer.GetMaterialCount();i++)
+ AddPPtrBinding (outProperties, targetObject.GetClassID(), Format("m_Materials.Array.data[%d]", i));
+ }
+#endif
+
+ virtual float GetFloatValue (const UnityEngine::Animation::BoundCurve& bind) const
+ {
+ AssertString("unsupported"); return 0.0F;
+ }
+
+ virtual void SetFloatValue (const UnityEngine::Animation::BoundCurve& bound, float value) const
+ {
+ AssertString("unsupported");
+ }
+
+ virtual void SetPPtrValue (const UnityEngine::Animation::BoundCurve& bound, SInt32 value) const
+ {
+ Renderer& renderer = *static_cast<Renderer*> (bound.targetObject);
+ int index = reinterpret_cast<int> (bound.targetPtr);
+
+ if (index < renderer.GetMaterialCount ())
+ renderer.SetMaterial(PPtr<Material> (value), index);
+ }
+
+ virtual SInt32 GetPPtrValue (const UnityEngine::Animation::BoundCurve& bound) const
+ {
+ Renderer& renderer = *static_cast<Renderer*> (bound.targetObject);
+ int index = reinterpret_cast<int> (bound.targetPtr);
+
+ if (index < renderer.GetMaterialCount ())
+ return renderer.GetMaterial(index).GetInstanceID();
+ else
+ return 0;
+ }
+
+ virtual bool GenerateBinding (const UnityStr& attribute, bool pptrCurve, UnityEngine::Animation::GenericBinding& outputBinding) const
+ {
+ int index = ParseIndexAttributeIndex (attribute, "m_Materials.Array.data[");
+ if (index != -1 && pptrCurve)
+ {
+ outputBinding.attribute = index;
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual ClassIDType BindValue (Object& target, const UnityEngine::Animation::GenericBinding& outputBinding, UnityEngine::Animation::BoundCurve& bound) const
+ {
+ bound.targetPtr = reinterpret_cast<void*> (outputBinding.attribute);
+ return ClassID(Material);
+ }
+};
+
+#if MATERIAL_ANIMATION
+
+const char* kMaterialPrefix = "material.";
+class RendererMaterialAnimationBinding : public IAnimationBinding
+{
+public:
+
+#if UNITY_EDITOR
+ virtual void GetAllAnimatableProperties (Object& targetObject, std::vector<EditorCurveBinding>& outProperties) const
+ {
+ Renderer& renderer = static_cast<Renderer&> (targetObject);
+ if (renderer.GetMaterialCount() == 0)
+ return;
+
+ int startIndex = outProperties.size();
+ for (int i=0;i<renderer.GetMaterialCount();i++)
+ {
+ Material* material = renderer.GetMaterial(i);
+ if (material == NULL)
+ continue;
+
+ ExtractAllMaterialAnimatableAttributes (*material, targetObject.GetClassID(), outProperties, startIndex);
+ }
+ }
+
+ static void ExtractAllMaterialAnimatableAttributes (Material& targetObject, int classID, std::vector<EditorCurveBinding>& outProperties, int startIndex)
+ {
+ Material& material = static_cast<Material&> (targetObject);
+
+ const ShaderLab::PropertySheet& properties = material.GetProperties();
+
+ const string materialPrefix = kMaterialPrefix;
+
+ // Get all float properties
+ const ShaderLab::PropertySheet::Floats& floats = properties.GetFloatsMap();
+ for (ShaderLab::PropertySheet::Floats::const_iterator i=floats.begin();i != floats.end();i++)
+ {
+ AddBindingCheckUnique (outProperties, startIndex, classID, materialPrefix + i->first.GetName());
+ }
+
+ // Get all vector properties
+ const ShaderLab::PropertySheet::Vectors& vectors = properties.GetVectorMap();
+ for (ShaderLab::PropertySheet::Vectors::const_iterator i=vectors.begin();i != vectors.end();i++)
+ {
+ string prefix = materialPrefix + i->first.GetName();
+ if (properties.GetColorTag(i->first))
+ {
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".r");
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".g");
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".b");
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".a");
+ }
+ else
+ {
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".x");
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".y");
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".z");
+ AddBindingCheckUnique (outProperties, startIndex, classID, prefix + ".w");
+ }
+
+ }
+ }
+#endif
+
+ struct MaterialBinding
+ {
+ enum { kFloat4, kColor4, kFloat1 };
+
+ UInt32 propertyName : 28;
+ UInt32 colIndex : 2;
+ UInt32 type : 2;
+ };
+
+ static UInt32 BindingToUInt32 (MaterialBinding binding)
+ {
+ UInt32 data;
+ data = binding.propertyName;
+ data |= binding.colIndex << 28;
+ data |= binding.type << 30;
+ return data;
+ }
+
+ static MaterialBinding UInt32ToBinding (UInt32 data)
+ {
+ MaterialBinding binding;
+ binding.propertyName = data & 0x3FFFFFFF;
+ binding.colIndex = (data >> 28) & 0x3;
+ binding.type = (data >> 30) & 0x3;
+ return binding;
+ }
+
+ virtual float GetFloatValue (const UnityEngine::Animation::BoundCurve& bind) const
+ {
+ Renderer& renderer = *static_cast<Renderer*> (bind.targetObject);
+ MaterialBinding binding = *reinterpret_cast<const MaterialBinding*> (&bind.targetPtr);
+
+ ShaderLab::FastPropertyName name;
+ name.index = binding.propertyName;
+
+ const MaterialPropertyBlock* block = renderer.GetPropertyBlock();
+
+ // Extract from material property block
+ if (block)
+ {
+ if (binding.type == MaterialBinding::kFloat1)
+ {
+ const float* value = block->FindFloat (name);
+ if (value != NULL)
+ return *value;
+ }
+ else if (binding.type == MaterialBinding::kFloat4)
+ {
+ const Vector4f* value = block->FindVector (name);
+ if (value != NULL)
+ return value->GetPtr()[binding.colIndex];
+ }
+ else if (binding.type == MaterialBinding::kColor4)
+ {
+ ColorRGBAf color;
+ if (block->GetColor (name, color))
+ return color.GetPtr()[binding.colIndex];
+ }
+ }
+
+ // Extract from material
+ for (int i=0;i<renderer.GetMaterialCount ();i++)
+ {
+ Material* material = renderer.GetMaterial(0);
+ if (material == NULL)
+ continue;
+ if (!material->HasProperty (name))
+ continue;
+
+ if (binding.type == MaterialBinding::kFloat1)
+ return material->GetFloat(name);
+ else if (binding.type == MaterialBinding::kColor4)
+ return material->GetColor(name).GetPtr()[binding.colIndex];
+ else if (binding.type == MaterialBinding::kFloat4)
+ return material->GetColor(name).GetPtr()[binding.colIndex];
+ }
+
+ return 0.0F;
+ }
+
+ virtual void SetFloatValue (const UnityEngine::Animation::BoundCurve& bound, float value) const
+ {
+ Renderer& renderer = *static_cast<Renderer*> (bound.targetObject);
+ MaterialBinding binding = *reinterpret_cast<const MaterialBinding*> (&bound.targetPtr);
+
+ MaterialPropertyBlock& block = renderer.GetPropertyBlockRememberToUpdateHash();
+
+ ShaderLab::FastPropertyName name;
+ name.index = binding.propertyName;
+
+ if (binding.type == MaterialBinding::kFloat1)
+ {
+ block.ReplacePropertyFloat (name, value);
+ }
+ else if (binding.type == MaterialBinding::kFloat4)
+ {
+ block.ReplacePartialFloatProperty (name, value, 4, binding.colIndex);
+ }
+ else if (binding.type == MaterialBinding::kColor4)
+ {
+ block.ReplacePartialFloatColorProperty (name, value, 4, binding.colIndex);
+ }
+
+ renderer.ComputeCustomPropertiesHash();
+
+ // Force a repaint
+ #if UNITY_EDITOR
+ renderer.SetDirty();
+ #endif
+ }
+
+ virtual void SetPPtrValue (const UnityEngine::Animation::BoundCurve& bound, SInt32 value) const { }
+
+ virtual SInt32 GetPPtrValue (const UnityEngine::Animation::BoundCurve& bound) const { return 0; }
+
+ virtual bool GenerateBinding (const UnityStr& attributeStr, bool pptrCurve, UnityEngine::Animation::GenericBinding& outputBinding) const
+ {
+ if (pptrCurve)
+ return false;
+
+ if (!BeginsWith(attributeStr, kMaterialPrefix))
+ return false;
+
+ MaterialBinding binding;
+
+ const char* attribute = attributeStr.c_str() + strlen(kMaterialPrefix);
+ const char* a = attribute;
+
+ // Parse this:
+ // mainColor.r
+ // mainColor.x
+ // mainColor.y
+ // floatPropertyName
+
+ // Find shader propertyname
+ int dotIndex = -1;
+ const char* lastCharacter;
+ while (*a != 0)
+ {
+ if (*a == '.' && dotIndex == -1)
+ dotIndex = a - attribute;
+ a++;
+ }
+ lastCharacter = a - 1;
+
+ // No '.' found, thus it must be a float property
+ if (dotIndex == -1)
+ {
+ binding.propertyName = ShaderLab::GenerateFastPropertyName28BitHash(attribute);
+ binding.type = MaterialBinding::kFloat1;
+ binding.colIndex = 0;
+ }
+ // Calculate different property types
+ else
+ {
+ binding.propertyName = ShaderLab::GenerateFastPropertyName28BitHash(string(attribute, attribute + dotIndex).c_str());
+
+ // There must be exactly one property ('r', 'g' etc after the .)
+ if (dotIndex + 2 != strlen(attribute))
+ return false;
+
+ binding.type = MaterialBinding::kFloat4;
+ switch (*lastCharacter)
+ {
+ case 'r':
+ case 'g':
+ case 'b':
+ case 'a':
+ binding.type = MaterialBinding::kColor4;
+ }
+
+ switch (*lastCharacter)
+ {
+ // r color or x vector
+ case 'r':
+ case 'x':
+ binding.colIndex = 0;
+ break;
+
+ // g color or y vector
+ case 'g':
+ case 'y':
+ binding.colIndex = 1;
+ break;
+
+ // b or z vector
+ case 'b':
+ case 'z':
+ binding.colIndex = 2;
+ break;
+
+ // alpha or w vector
+ case 'a':
+ case 'w':
+ binding.colIndex = 3;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ outputBinding.attribute = BindingToUInt32 (binding);
+ return true;
+ }
+
+ virtual ClassIDType BindValue (Object& target, const UnityEngine::Animation::GenericBinding& outputBinding, UnityEngine::Animation::BoundCurve& bound) const
+ {
+ MaterialBinding materialBinding = UInt32ToBinding(outputBinding.attribute);
+
+ ShaderLab::FastPropertyName prop;
+ prop.InitBy28BitHash (materialBinding.propertyName);
+ materialBinding.propertyName = prop.index;
+
+ bound.targetPtr = *reinterpret_cast<void**> (&materialBinding);
+ return ClassID(float);
+ }
+};
+#endif
+
+
+static RendererAnimationBinding* gRendererBinding = NULL;
+#if MATERIAL_ANIMATION
+static RendererMaterialAnimationBinding* gMaterialBinding = NULL;
+#endif
+
+void InitializeRendererAnimationBindingInterface ()
+{
+ gRendererBinding = UNITY_NEW (RendererAnimationBinding, kMemAnimation);
+ UnityEngine::Animation::GetGenericAnimationBindingCache ().RegisterIAnimationBinding (ClassID(Renderer), UnityEngine::Animation::kRendererMaterialPPtrBinding, gRendererBinding);
+
+ #if MATERIAL_ANIMATION
+ gMaterialBinding = UNITY_NEW (RendererMaterialAnimationBinding, kMemAnimation);
+ UnityEngine::Animation::GetGenericAnimationBindingCache ().RegisterIAnimationBinding (ClassID(Renderer), UnityEngine::Animation::kRendererMaterialPropertyBinding, gMaterialBinding);
+ #endif
+}
+
+void CleanupRendererAnimationBindingInterface ()
+{
+ UNITY_DELETE (gRendererBinding, kMemAnimation);
+ #if MATERIAL_ANIMATION
+ UNITY_DELETE (gMaterialBinding, kMemAnimation);
+ #endif
+}
+
+
+#if ENABLE_UNIT_TESTS
+#include "External/UnitTest++/src/UnitTest++.h"
+
+SUITE (MaterialBindingTests)
+{
+ TEST (MaterialBindingUInt32Conversion)
+ {
+ RendererMaterialAnimationBinding::MaterialBinding binding;
+ binding.propertyName = 12345678;
+ binding.colIndex = 3;
+ binding.type = 3;
+
+ RendererMaterialAnimationBinding::MaterialBinding converted = RendererMaterialAnimationBinding::UInt32ToBinding (RendererMaterialAnimationBinding::BindingToUInt32 (binding));
+ CHECK_EQUAL (converted.propertyName, binding.propertyName);
+ CHECK_EQUAL (converted.colIndex, binding.colIndex);
+ CHECK_EQUAL (converted.type, binding.type);
+ }
+
+ TEST (MaterialBindingCorrectlyEncodesAllBits)
+ {
+ CHECK_EQUAL ( RendererMaterialAnimationBinding::BindingToUInt32(RendererMaterialAnimationBinding::UInt32ToBinding (0xFFFFFFFF)), 0xFFFFFFFF);
+ CHECK_EQUAL ( RendererMaterialAnimationBinding::BindingToUInt32(RendererMaterialAnimationBinding::UInt32ToBinding (0)), 0);
+ }
+}
+#endif \ No newline at end of file