Browse Source

Add double serialization support to Variant, Deserializer/Serializer, XMLElement & JSONValue. Use double to store a Lua object's number attributes. Add editing of double attributes to the editor. Closes #758.

Lasse Öörni 10 years ago
parent
commit
e8af02f453

+ 1 - 1
Source/Urho3D/Container/Str.cpp

@@ -138,7 +138,7 @@ String::String(double value) :
     buffer_(&endZero)
 {
     char tempBuffer[CONVERSION_BUFFER_LENGTH];
-    sprintf(tempBuffer, "%g", value);
+    sprintf(tempBuffer, "%.15g", value);
     *this = tempBuffer;
 }
 

+ 4 - 0
Source/Urho3D/Core/Spline.cpp

@@ -122,6 +122,7 @@ Variant Spline::BezierInterpolation(const Vector<Variant>& knots, float t) const
         case VAR_VECTOR3:
         case VAR_VECTOR4:
         case VAR_COLOR:
+        case VAR_DOUBLE:
             return LinearInterpolation(knots[0], knots[1], t);
         default:
             return Variant::EMPTY;
@@ -139,6 +140,7 @@ Variant Spline::BezierInterpolation(const Vector<Variant>& knots, float t) const
             case VAR_VECTOR3:
             case VAR_VECTOR4:
             case VAR_COLOR:
+            case VAR_DOUBLE:
                 interpolatedKnots.Push(LinearInterpolation(knots[i - 1], knots[i], t));
                 break;
             default:
@@ -163,6 +165,8 @@ Variant Spline::LinearInterpolation(const Variant& lhs, const Variant& rhs, floa
         return lhs.GetVector4().Lerp(rhs.GetVector4(), t);
     case VAR_COLOR:
         return lhs.GetColor().Lerp(rhs.GetColor(), t);
+    case VAR_DOUBLE:
+        return Lerp(lhs.GetDouble(), rhs.GetDouble(), t);
     default:
         return Variant::EMPTY;
     }

+ 13 - 0
Source/Urho3D/Core/StringUtils.cpp

@@ -141,6 +141,19 @@ float ToFloat(const char* source)
     return (float)strtod(source, 0);
 }
 
+double ToDouble(const String& source)
+{
+    return ToDouble(source.CString());
+}
+
+double ToDouble(const char* source)
+{
+    if (!source)
+        return 0;
+
+    return strtod(source, 0);
+}
+
 Color ToColor(const String& source)
 {
     return ToColor(source.CString());

+ 4 - 0
Source/Urho3D/Core/StringUtils.h

@@ -35,6 +35,10 @@ URHO3D_API bool ToBool(const char* source);
 URHO3D_API float ToFloat(const String& source);
 /// Parse a float from a C string.
 URHO3D_API float ToFloat(const char* source);
+/// Parse a double from a string.
+URHO3D_API double ToDouble(const String& source);
+/// Parse a double from a C string.
+URHO3D_API double ToDouble(const char* source);
 /// Parse an integer from a string.
 URHO3D_API int ToInt(const String& source);
 /// Parse an integer from a C string.

+ 19 - 0
Source/Urho3D/Core/Variant.cpp

@@ -58,6 +58,7 @@ static const char* typeNames[] =
     "Matrix3",
     "Matrix3x4",
     "Matrix4",
+    "Double",
     0
 };
 
@@ -178,6 +179,9 @@ bool Variant::operator == (const Variant& rhs) const
     case VAR_MATRIX4:
         return *(reinterpret_cast<const Matrix4*>(value_.ptr_)) == *(reinterpret_cast<const Matrix4*>(rhs.value_.ptr_));
 
+    case VAR_DOUBLE:
+        return *(reinterpret_cast<const double*>(&value_)) == *(reinterpret_cast<const double*>(&rhs.value_));
+
     default:
         return true;
     }
@@ -304,6 +308,10 @@ void Variant::FromString(VariantType type, const char* value)
         *this = ToMatrix4(value);
         break;
         
+    case VAR_DOUBLE:
+        *this = ToDouble(value);
+        break;
+
     default:
         SetType(VAR_NONE);
     }
@@ -390,6 +398,9 @@ String Variant::ToString() const
         
     case VAR_MATRIX4:
         return (reinterpret_cast<const Matrix4*>(value_.ptr_))->ToString();
+
+    case VAR_DOUBLE:
+        return String(*reinterpret_cast<const double*>(&value_));
     }
 }
 
@@ -469,6 +480,9 @@ bool Variant::IsZero() const
     case VAR_MATRIX4:
         return *reinterpret_cast<const Matrix4*>(value_.ptr_) == Matrix4::IDENTITY;
         
+    case VAR_DOUBLE:
+        return *reinterpret_cast<const double*>(&value_) == 0.0;
+
     default:
         return true;
     }
@@ -599,6 +613,11 @@ template<> float Variant::Get<float>() const
     return GetFloat();
 }
 
+template<> double Variant::Get<double>() const
+{
+    return GetDouble();
+}
+
 template<> const Vector2& Variant::Get<const Vector2&>() const
 {
     return GetVector2();

+ 23 - 0
Source/Urho3D/Core/Variant.h

@@ -58,6 +58,7 @@ enum VariantType
     VAR_MATRIX3,
     VAR_MATRIX3X4,
     VAR_MATRIX4,
+    VAR_DOUBLE,
     MAX_VAR_TYPES
 };
 
@@ -217,6 +218,13 @@ public:
         *this = value;
     }
 
+    /// Construct from a double.
+    Variant(double value) :
+        type_(VAR_NONE)
+    {
+        *this = value;
+    }
+
     /// Construct from a Vector2.
     Variant(const Vector2& value) :
         type_(VAR_NONE)
@@ -440,6 +448,14 @@ public:
         return *this;
     }
 
+    /// Assign from a double.
+    Variant& operator = (double rhs)
+    {
+        SetType(VAR_DOUBLE);
+        *(reinterpret_cast<double*>(&value_)) = rhs;
+        return *this;
+    }
+
     /// Assign from a Vector2.
     Variant& operator = (const Vector2& rhs)
     {
@@ -602,6 +618,8 @@ public:
     bool operator == (bool rhs) const { return type_ == VAR_BOOL ? value_.bool_ == rhs : false; }
     /// Test for equality with a float. To return true, both the type and value must match.
     bool operator == (float rhs) const { return type_ == VAR_FLOAT ? value_.float_ == rhs : false; }
+    /// Test for equality with a double. To return true, both the type and value must match.
+    bool operator == (double rhs) const { return type_ == VAR_DOUBLE ? *(reinterpret_cast<const double*>(&value_)) == rhs : false; }
     /// Test for equality with a Vector2. To return true, both the type and value must match.
     bool operator == (const Vector2& rhs) const { return type_ == VAR_VECTOR2 ? *(reinterpret_cast<const Vector2*>(&value_)) == rhs : false; }
     /// Test for equality with a Vector3. To return true, both the type and value must match.
@@ -671,6 +689,8 @@ public:
     bool operator != (bool rhs) const { return !(*this == rhs); }
     /// Test for inequality with a float.
     bool operator != (float rhs) const { return !(*this == rhs); }
+    /// Test for inequality with a double.
+    bool operator != (double rhs) const { return !(*this == rhs); }
     /// Test for inequality with a Vector2.
     bool operator != (const Vector2& rhs) const { return !(*this == rhs); }
     /// Test for inequality with a Vector3.
@@ -729,6 +749,8 @@ public:
     bool GetBool() const { return type_ == VAR_BOOL ? value_.bool_ : false; }
     /// Return float or zero on type mismatch.
     float GetFloat() const { return type_ == VAR_FLOAT ? value_.float_ : 0.0f; }
+    /// Return double or zero on type mismatch.
+    double GetDouble() const { return type_ == VAR_DOUBLE ? *reinterpret_cast<const double*>(&value_) : 0.0; }
     /// Return Vector2 or zero on type mismatch.
     const Vector2& GetVector2() const { return type_ == VAR_VECTOR2 ? *reinterpret_cast<const Vector2*>(&value_) : Vector2::ZERO; }
     /// Return Vector3 or zero on type mismatch.
@@ -833,6 +855,7 @@ template<> inline VariantType GetVariantType<int>() { return VAR_INT; }
 template<> inline VariantType GetVariantType<unsigned>() { return VAR_INT; }
 template<> inline VariantType GetVariantType<bool>() { return VAR_BOOL; }
 template<> inline VariantType GetVariantType<float>() { return VAR_FLOAT; }
+template<> inline VariantType GetVariantType<double>() { return VAR_DOUBLE; }
 template<> inline VariantType GetVariantType<Vector2>() { return VAR_VECTOR2; }
 template<> inline VariantType GetVariantType<Vector3>() { return VAR_VECTOR3; }
 template<> inline VariantType GetVariantType<Vector4>() { return VAR_VECTOR4; }

+ 10 - 0
Source/Urho3D/IO/Deserializer.cpp

@@ -112,6 +112,13 @@ float Deserializer::ReadFloat()
     return ret;
 }
 
+double Deserializer::ReadDouble()
+{
+    double ret;
+    Read(&ret, sizeof ret);
+    return ret;
+}
+
 IntRect Deserializer::ReadIntRect()
 {
     int data[4];
@@ -342,6 +349,9 @@ Variant Deserializer::ReadVariant(VariantType type)
     case VAR_MATRIX4:
         return Variant(ReadMatrix4());
         
+    case VAR_DOUBLE:
+        return Variant(ReadDouble());
+
     default:
         return Variant();
     }

+ 2 - 0
Source/Urho3D/IO/Deserializer.h

@@ -71,6 +71,8 @@ public:
     bool ReadBool();
     /// Read a float.
     float ReadFloat();
+    /// Read a double.
+    double ReadDouble();
     /// Read an IntRect.
     IntRect ReadIntRect();
     /// Read an IntVector2.

+ 8 - 0
Source/Urho3D/IO/Serializer.cpp

@@ -75,6 +75,11 @@ bool Serializer::WriteFloat(float value)
     return Write(&value, sizeof value) == sizeof value;
 }
 
+bool Serializer::WriteDouble(double value)
+{
+    return Write(&value, sizeof value) == sizeof value;
+}
+
 bool Serializer::WriteIntRect(const IntRect& value)
 {
     return Write(value.Data(), sizeof value) == sizeof value;
@@ -295,6 +300,9 @@ bool Serializer::WriteVariantData(const Variant& value)
     case VAR_MATRIX4:
         return WriteMatrix4(value.GetMatrix4());
         
+    case VAR_DOUBLE:
+        return WriteDouble(value.GetDouble());
+
     default:
         return false;
     }

+ 2 - 0
Source/Urho3D/IO/Serializer.h

@@ -64,6 +64,8 @@ public:
     bool WriteBool(bool value);
     /// Write a float.
     bool WriteFloat(float value);
+    /// Write a double.
+    bool WriteDouble(double value);
     /// Write an IntRect.
     bool WriteIntRect(const IntRect& value);
     /// Write an IntVector2.

+ 7 - 7
Source/Urho3D/LuaScript/LuaScriptInstance.cpp

@@ -131,8 +131,8 @@ void LuaScriptInstance::OnSetAttribute(const AttributeInfo& attr, const Variant&
         case VAR_BOOL:
             lua_pushboolean(luaState_, src.GetBool());
             break;
-        case VAR_FLOAT:
-            lua_pushnumber(luaState_, src.GetFloat());
+        case VAR_DOUBLE:
+            lua_pushnumber(luaState_, src.GetDouble());
             break;
         case VAR_STRING:
             tolua_pushurho3dstring(luaState_, src.GetString());
@@ -237,8 +237,8 @@ void LuaScriptInstance::OnGetAttribute(const AttributeInfo& attr, Variant& dest)
     case VAR_BOOL:
         dest = lua_toboolean(luaState_, -1) != 0;
         break;
-    case VAR_FLOAT:
-        dest = (float)lua_tonumber(luaState_, -1);
+    case VAR_DOUBLE:
+        dest = lua_tonumber(luaState_, -1);
         break;
     case VAR_STRING:
         dest = tolua_tourho3dstring(luaState_, -1, "");
@@ -505,9 +505,9 @@ void LuaScriptInstance::GetScriptAttributes()
     if (lua_istable(luaState_, -1))
     {
         size_t length = lua_objlen(luaState_, -1);
-        for (int i = 1; i <= length; ++i)
+        for (size_t i = 1; i <= length; ++i)
         {
-            lua_pushinteger(luaState_, i);
+            lua_pushinteger(luaState_, (int)i);
             lua_gettable(luaState_, -2);
 
             if (!lua_isstring(luaState_, -1))
@@ -545,7 +545,7 @@ void LuaScriptInstance::GetScriptAttributes()
             info.type_ = VAR_BOOL;
             break;
         case LUA_TNUMBER:
-            info.type_ = VAR_FLOAT;
+            info.type_ = VAR_DOUBLE;
             break;
         case LUA_TSTRING:
             info.type_ = VAR_STRING;

+ 22 - 0
Source/Urho3D/LuaScript/pkgs/Core/Variant.pkg

@@ -25,6 +25,7 @@ enum VariantType
     VAR_MATRIX3,
     VAR_MATRIX3X4,
     VAR_MATRIX4,
+    VAR_DOUBLE,
     MAX_VAR_TYPES
 };
 
@@ -61,6 +62,7 @@ class Variant
     Variant(const StringHash& value);
     Variant(bool value);
     Variant(float value);
+    Variant(double value);
     Variant(const Vector2& value);
     Variant(const Vector3& value);
     Variant(const Vector4& value);
@@ -88,6 +90,7 @@ class Variant
     bool operator == (unsigned rhs) const;
     bool operator == (bool rhs) const;
     bool operator == (float rhs) const;
+    bool operator == (double rhs) const;
     bool operator == (const Vector2& rhs);
     bool operator == (const Vector3& rhs) const;
     bool operator == (const Vector4& rhs) const;
@@ -108,6 +111,7 @@ class Variant
     tolua_outside void VariantSetStringHash @ SetStringHash(const StringHash& value);
     tolua_outside void VariantSetBool @ SetBool(bool value);
     tolua_outside void VariantSetFloat @ SetFloat(float value);
+    tolua_outside void VariantSetDouble @ SetDouble(double value);
     tolua_outside void VariantSetVector2 @ SetVector2(const Vector2& value);
     tolua_outside void VariantSetVector3 @ SetVector3(const Vector3& value);
     tolua_outside void VariantSetVector4 @ SetVector4(const Vector4& value);
@@ -128,6 +132,7 @@ class Variant
     StringHash GetStringHash();
     bool GetBool() const;
     float GetFloat() const;
+    double GetDouble() const;
     const Vector2& GetVector2() const;
     const Vector3& GetVector3() const;
     const Vector4& GetVector4() const;
@@ -165,6 +170,7 @@ class VariantMap
     tolua_outside void VariantMapSetStringHash @ SetStringHash(const String key, const StringHash& value);
     tolua_outside void VariantMapSetBool @ SetBool(const String key, bool value);
     tolua_outside void VariantMapSetFloat @ SetFloat(const String key, float value);
+    tolua_outside void VariantMapSetDouble @ SetDouble(const String key, double value);
     tolua_outside void VariantMapSetVector2 @ SetVector2(const String key, const Vector2 value);
     tolua_outside void VariantMapSetVector3 @ SetVector3(const String key, const Vector3 value);
     tolua_outside void VariantMapSetVector4 @ SetVector4(const String key, const Vector4 value);
@@ -186,6 +192,7 @@ class VariantMap
     tolua_outside StringHash VariantMapGetStringHash @ GetStringHash(const String key);
     tolua_outside bool VariantMapGetBool @ GetBool(const String key);
     tolua_outside float VariantMapGetFloat @ GetFloat(const String key);
+    tolua_outside double VariantMapGetDouble @ GetDouble(const String key);
     tolua_outside const Vector2& VariantMapGetVector2 @ GetVector2(const String key);
     tolua_outside const Vector3& VariantMapGetVector3 @ GetVector3(const String key);
     tolua_outside const Vector4& VariantMapGetVector4 @ GetVector4(const String key);
@@ -229,6 +236,11 @@ static void VariantSetFloat(Variant* variant, float value)
     *variant = value;
 }
 
+static void VariantSetDouble(Variant* variant, double value)
+{
+    *variant = value;
+}
+
 static void VariantSetVector2(Variant* variant, const Vector2& value)
 {
     *variant = value;
@@ -329,6 +341,11 @@ static void VariantMapSetFloat(VariantMap* vmap, const String& key, float value)
     (*vmap)[StringHash(key)] = value;
 }
 
+static void VariantMapSetDouble(VariantMap* vmap, const String& key, double value)
+{
+    (*vmap)[StringHash(key)] = value;
+}
+
 static void VariantMapSetVector2(VariantMap* vmap, const String& key, const Vector2& value)
 {
     (*vmap)[StringHash(key)] = value;
@@ -435,6 +452,11 @@ static float VariantMapGetFloat(const VariantMap* vmap, const String& key)
     return FindVariant(vmap, key).GetFloat();
 }
 
+static double VariantMapGetDouble(const VariantMap* vmap, const String& key)
+{
+    return FindVariant(vmap, key).GetDouble();
+}
+
 static const Vector2& VariantMapGetVector2(const VariantMap* vmap, const String& key)
 {
     return FindVariant(vmap, key).GetVector2();

+ 1 - 0
Source/Urho3D/LuaScript/pkgs/IO/Deserializer.pkg

@@ -19,6 +19,7 @@ class Deserializer
     unsigned char ReadUByte();
     bool ReadBool();
     float ReadFloat();
+    double ReadDouble();
     IntRect ReadIntRect();
     IntVector2 ReadIntVector2();
     Rect ReadRect();

+ 2 - 0
Source/Urho3D/LuaScript/pkgs/IO/File.pkg

@@ -43,6 +43,7 @@ class File : public Object
     unsigned char ReadUByte();
     bool ReadBool();
     float ReadFloat();
+    double ReadDouble();
     IntRect ReadIntRect();
     IntVector2 ReadIntVector2();
     Rect ReadRect();
@@ -86,6 +87,7 @@ class File : public Object
     bool WriteUByte(unsigned char value);
     bool WriteBool(bool value);
     bool WriteFloat(float value);
+    bool WriteDouble(double value);
     bool WriteIntRect(const IntRect& value);
     bool WriteIntVector2(const IntVector2& value);
     bool WriteRect(const Rect& value);

+ 1 - 0
Source/Urho3D/LuaScript/pkgs/IO/Serializer.pkg

@@ -13,6 +13,7 @@ class Serializer
     bool WriteUByte(unsigned char value);
     bool WriteBool(bool value);
     bool WriteFloat(float value);
+    bool WriteDouble(double value);
     bool WriteIntRect(const IntRect& value);
     bool WriteIntVector2(const IntVector2& value);
     bool WriteRect(const Rect& value);

+ 2 - 0
Source/Urho3D/LuaScript/pkgs/IO/VectorBuffer.pkg

@@ -36,6 +36,7 @@ class VectorBuffer
     unsigned char ReadUByte();
     bool ReadBool();
     float ReadFloat();
+    double ReadDouble();
     IntRect ReadIntRect();
     IntVector2 ReadIntVector2();
     Rect ReadRect();
@@ -79,6 +80,7 @@ class VectorBuffer
     bool WriteUByte(unsigned char value);
     bool WriteBool(bool value);
     bool WriteFloat(float value);
+    bool WriteDouble(double value);
     bool WriteIntRect(const IntRect& value);
     bool WriteIntVector2(const IntVector2& value);
     bool WriteRect(const Rect& value);

+ 4 - 0
Source/Urho3D/LuaScript/pkgs/Resource/JSONValue.pkg

@@ -18,6 +18,7 @@ class JSONValue
     void SetInt(const String name, int value);
     void SetBool(const String name, bool value);
     void SetFloat(const String name, float value);
+    void SetDouble(const String name, double value);
     void SetVector2(const String name, const Vector2& value);
     void SetVector3(const String name, const Vector3& value);
     void SetVector4(const String name, const Vector4& value);
@@ -43,6 +44,7 @@ class JSONValue
     int GetInt(const String name) const;
     bool GetBool(const String name) const;
     float GetFloat(const String name) const;
+    double GetDouble(const String name) const;
     Vector2 GetVector2(const String name) const;
     Vector3 GetVector3(const String name) const;
     Vector4 GetVector4(const String name) const;
@@ -68,6 +70,7 @@ class JSONValue
     void AddInt(int value);
     void AddBool(bool value);
     void AddFloat(float value);
+    void AddDouble(double value);
     void AddVector2(const Vector2& value);
     void AddVector3(const Vector3& value);
     void AddVector4(const Vector4& value);
@@ -91,6 +94,7 @@ class JSONValue
     int GetInt(unsigned index) const;
     bool GetBool(unsigned index) const;
     float GetFloat(unsigned index) const;
+    double GetDouble(unsigned index) const;
     Vector2 GetVector2(unsigned index) const;
     Vector3 GetVector3(unsigned index) const;
     Vector4 GetVector4(unsigned index) const;

+ 2 - 0
Source/Urho3D/LuaScript/pkgs/Resource/XMLElement.pkg

@@ -15,6 +15,7 @@ class XMLElement
     bool SetBoundingBox(const BoundingBox& value);
     bool SetColor(const String name, const Color& value);
     bool SetFloat(const String name, float value);
+    bool SetDouble(const String name, double value);
     bool SetUInt(const String name, unsigned value);
     bool SetInt(const String name, int value);
     bool SetIntRect(const String name, const IntRect& value);
@@ -55,6 +56,7 @@ class XMLElement
     BoundingBox GetBoundingBox() const;
     Color GetColor(const String name) const;
     float GetFloat(const String name) const;
+    double GetDouble(const String name) const;
     unsigned GetUInt(const String name) const;
     int GetInt(const String name) const;
     IntRect GetIntRect(const String name) const;

+ 24 - 0
Source/Urho3D/Resource/JSONValue.cpp

@@ -140,6 +140,13 @@ void JSONValue::SetFloat(const String& name, float value)
     AddMember(name, jsonValue);
 }
 
+void JSONValue::SetDouble(const String& name, double value)
+{
+    Value jsonValue;
+    jsonValue.SetDouble(value);
+    AddMember(name, jsonValue);
+}
+
 void JSONValue::SetVector2(const String& name, const Vector2& value)
 {
     SetString(name, value.ToString());
@@ -321,6 +328,11 @@ float JSONValue::GetFloat(const String& name) const
     return (float)GetMember(name).GetDouble();
 }
 
+double JSONValue::GetDouble(const String& name) const
+{
+    return GetMember(name).GetDouble();
+}
+
 Vector2 JSONValue::GetVector2(const String& name) const
 {
     return ToVector2(GetCString(name));
@@ -510,6 +522,13 @@ void JSONValue::AddFloat(float value)
     AddMember(jsonValue);
 }
 
+void JSONValue::AddDouble(double value)
+{
+    Value jsonValue;
+    jsonValue.SetDouble(value);
+    AddMember(jsonValue);
+}
+
 void JSONValue::AddVector2(const Vector2& value)
 {
     AddString(value.ToString());
@@ -668,6 +687,11 @@ float JSONValue::GetFloat(unsigned index) const
     return (float)GetMember(index).GetDouble();
 }
 
+double JSONValue::GetDouble(unsigned index) const
+{
+    return GetMember(index).GetDouble();
+}
+
 Vector2 JSONValue::GetVector2(unsigned index) const
 {
     return ToVector2(GetCString(index));

+ 8 - 0
Source/Urho3D/Resource/JSONValue.h

@@ -86,6 +86,8 @@ public:
     void SetBool(const String& name, bool value);
     /// Set float.
     void SetFloat(const String& name, float value);
+    /// Set double.
+    void SetDouble(const String& name, double value);
     /// Set vector2.
     void SetVector2(const String& name, const Vector2& value);
     /// Set vector3.
@@ -135,6 +137,8 @@ public:
     bool GetBool(const String& name) const;
     /// Return float.
     float GetFloat(const String& name) const;
+    /// Return double.
+    double GetDouble(const String& name) const;
     /// Return vector2.
     Vector2 GetVector2(const String& name) const;
     /// Return vector3.
@@ -185,6 +189,8 @@ public:
     void AddBool(bool value);
     /// Add float.
     void AddFloat(float value);
+    /// Add float.
+    void AddDouble(double value);
     /// Add vector2.
     void AddVector2(const Vector2& value);
     /// Add vector3.
@@ -231,6 +237,8 @@ public:
     bool GetBool(unsigned index) const;
     /// Return float.
     float GetFloat(unsigned index) const;
+    /// Return double.
+    double GetDouble(unsigned index) const;
     /// Return vector2.
     Vector2 GetVector2(unsigned index) const;
     /// Return vector3.

+ 10 - 0
Source/Urho3D/Resource/XMLElement.cpp

@@ -303,6 +303,11 @@ bool XMLElement::SetFloat(const String& name, float value)
     return SetAttribute(name, String(value));
 }
 
+bool XMLElement::SetDouble(const String& name, double value)
+{
+    return SetAttribute(name, String(value));
+}
+
 bool XMLElement::SetUInt(const String& name, unsigned value)
 {
     return SetAttribute(name, String(value));
@@ -706,6 +711,11 @@ float XMLElement::GetFloat(const String& name) const
     return ToFloat(GetAttribute(name));
 }
 
+double XMLElement::GetDouble(const String& name) const
+{
+    return ToDouble(GetAttribute(name));
+}
+
 unsigned XMLElement::GetUInt(const String& name) const
 {
     return ToUInt(GetAttribute(name));

+ 4 - 0
Source/Urho3D/Resource/XMLElement.h

@@ -112,6 +112,8 @@ public:
     bool SetColor(const String& name, const Color& value);
     /// Set a float attribute.
     bool SetFloat(const String& name, float value);
+    /// Set a double attribute.
+    bool SetDouble(const String& name, double value);
     /// Set an unsigned integer attribute.
     bool SetUInt(const String& name, unsigned value);
     /// Set an integer attribute.
@@ -211,6 +213,8 @@ public:
     Color GetColor(const String& name) const;
     /// Return a float attribute, or zero if missing.
     float GetFloat(const String& name) const;
+    /// Return a double attribute, or zero if missing.
+    double GetDouble(const String& name) const;
     /// Return an unsigned integer attribute, or zero if missing.
     unsigned GetUInt(const String& name) const;
     /// Return an integer attribute, or zero if missing.

+ 8 - 0
Source/Urho3D/Scene/Serializable.cpp

@@ -150,6 +150,10 @@ void Serializable::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
         *(reinterpret_cast<IntVector2*>(dest)) = src.GetIntVector2();
         break;
 
+    case VAR_DOUBLE:
+        *(reinterpret_cast<double*>(dest)) = src.GetDouble();
+        break;
+
     default:
         LOGERROR("Unsupported attribute type for OnSetAttribute()");
         return;
@@ -242,6 +246,10 @@ void Serializable::OnGetAttribute(const AttributeInfo& attr, Variant& dest) cons
         dest = *(reinterpret_cast<const IntVector2*>(src));
         break;
 
+    case VAR_DOUBLE:
+        dest = *(reinterpret_cast<const double*>(src));
+        break;
+
     default:
         LOGERROR("Unsupported attribute type for OnGetAttribute()");
         return;

+ 9 - 0
Source/Urho3D/Scene/ValueAnimation.cpp

@@ -339,6 +339,9 @@ Variant ValueAnimation::LinearInterpolation(unsigned index1, unsigned index2, fl
             return IntVector2((int)(v1.x_ * s + v2.x_ * t), (int)(v1.y_ * s + v2.y_ * t));
         }
 
+    case VAR_DOUBLE:
+        return Lerp(value1.GetDouble(), value2.GetDouble(), t);
+
     default:
         LOGERROR("Invalid value type for linear interpolation");
         return Variant::EMPTY;
@@ -388,6 +391,9 @@ Variant ValueAnimation::SplineInterpolation(unsigned index1, unsigned index2, fl
     case VAR_COLOR:
         return v1.GetColor() * h1 + v2.GetColor() * h2 + t1.GetColor() * h3 + t2.GetColor() * h4;
 
+    case VAR_DOUBLE:
+        return v1.GetDouble() * h1 + v2.GetDouble() * h2 + t1.GetDouble() * h3 + t2.GetDouble() * h4;
+
     default:
         LOGERROR("Invalid value type for spline interpolation");
         return Variant::EMPTY;
@@ -438,6 +444,9 @@ Variant ValueAnimation::SubstractAndMultiply(const Variant& value1, const Varian
     case VAR_COLOR:
         return (value1.GetColor() - value2.GetColor()) * t;
 
+    case VAR_DOUBLE:
+        return (value1.GetDouble() - value2.GetDouble()) * t;
+
     default:
         LOGERROR("Invalid value type for spline interpolation's substract and multiply operation");
         return Variant::EMPTY;

+ 2 - 0
Source/Urho3D/Script/APITemplates.h

@@ -250,6 +250,7 @@ template <class T> void RegisterSerializer(asIScriptEngine* engine, const char*
     engine->RegisterObjectMethod(className, "bool WriteUByte(uint8)", asMETHODPR(T, WriteUByte, (unsigned char), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteBool(bool)", asMETHODPR(T, WriteBool, (bool), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteFloat(float)", asMETHODPR(T, WriteFloat, (float), bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "bool WriteDouble(float)", asMETHODPR(T, WriteDouble, (double), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteIntRect(const IntRect&in)", asMETHODPR(T, WriteIntRect, (const IntRect&), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteIntVector2(const IntVector2&in)", asMETHODPR(T, WriteIntVector2, (const IntVector2&), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteVector2(const Vector2&in)", asMETHODPR(T, WriteVector2, (const Vector2&), bool), asCALL_THISCALL);
@@ -301,6 +302,7 @@ template <class T> void RegisterDeserializer(asIScriptEngine* engine, const char
     engine->RegisterObjectMethod(className, "uint8 ReadUByte()", asMETHODPR(T, ReadUByte, (), unsigned char), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool ReadBool()", asMETHODPR(T, ReadBool, (), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float ReadFloat()", asMETHODPR(T, ReadFloat, (), float), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "double ReadDouble()", asMETHODPR(T, ReadDouble, (), double), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntRect ReadIntRect()", asMETHODPR(T, ReadIntRect, (), IntRect), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntVector2 ReadIntVector2()", asMETHODPR(T, ReadIntVector2, (), IntVector2), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Vector2 ReadVector2()", asMETHODPR(T, ReadVector2, (), Vector2), asCALL_THISCALL);

+ 32 - 0
Source/Urho3D/Script/Addons.cpp

@@ -2306,6 +2306,11 @@ static void ConstructStringFloat(float value, String* ptr)
     new(ptr) String(value);
 }
 
+static void ConstructStringDouble(double value, String* ptr)
+{
+    new(ptr)String(value);
+}
+
 static void ConstructStringBool(bool value, String* ptr)
 {
     new(ptr) String(value);
@@ -2377,6 +2382,28 @@ static String StringAddFloatReverse(float value, const String& str)
     return String(value) + str;
 }
 
+static String& StringAssignDouble(double value, String& str)
+{
+    str = String(value);
+    return str;
+}
+
+static String& StringAddAssignDouble(double value, String& str)
+{
+    str += String(value);
+    return str;
+}
+
+static String StringAddDouble(double value, const String& str)
+{
+    return str + String(value);
+}
+
+static String StringAddDoubleReverse(double value, const String& str)
+{
+    return String(value) + str;
+}
+
 static String& StringAssignBool(bool value, String& str)
 {
     str = String(value);
@@ -2454,6 +2481,7 @@ void RegisterString(asIScriptEngine *engine)
     engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(ConstructStringInt), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(uint)", asFUNCTION(ConstructStringUInt), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ConstructStringFloat), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(double)", asFUNCTION(ConstructStringDouble), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(bool)", asFUNCTION(ConstructStringBool), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String& opAssign(int)", asFUNCTION(StringAssignInt), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String& opAddAssign(int)", asFUNCTION(StringAddAssignInt), asCALL_CDECL_OBJLAST);
@@ -2467,6 +2495,10 @@ void RegisterString(asIScriptEngine *engine)
     engine->RegisterObjectMethod("String", "String& opAddAssign(float)", asFUNCTION(StringAddAssignFloat), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String opAdd(float) const", asFUNCTION(StringAddFloat), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String opAdd_r(float) const", asFUNCTION(StringAddFloatReverse), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("String", "String& opAssign(double)", asFUNCTION(StringAssignDouble), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("String", "String& opAddAssign(double)", asFUNCTION(StringAddAssignDouble), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("String", "String opAdd(double) const", asFUNCTION(StringAddDouble), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("String", "String opAdd_r(double) const", asFUNCTION(StringAddDoubleReverse), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String& opAssign(bool)", asFUNCTION(StringAssignBool), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String& opAddAssign(bool)", asFUNCTION(StringAddAssignBool), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "String opAdd(bool) const", asFUNCTION(StringAddBool), asCALL_CDECL_OBJLAST);

+ 11 - 0
Source/Urho3D/Script/CoreAPI.cpp

@@ -185,6 +185,11 @@ static void ConstructVariantFloat(float value, Variant* ptr)
     new(ptr) Variant(value);
 }
 
+static void ConstructVariantDouble(double value, Variant* ptr)
+{
+    new(ptr)Variant(value);
+}
+
 static void ConstructVariantVector2(const Vector2& value, Variant* ptr)
 {
     new(ptr) Variant(value);
@@ -409,6 +414,7 @@ static void RegisterVariant(asIScriptEngine* engine)
     engine->RegisterEnumValue("VariantType", "VAR_MATRIX3", VAR_MATRIX3);
     engine->RegisterEnumValue("VariantType", "VAR_MATRIX3X4", VAR_MATRIX3X4);
     engine->RegisterEnumValue("VariantType", "VAR_MATRIX4", VAR_MATRIX4);
+    engine->RegisterEnumValue("VariantType", "VAR_DOUBLE", VAR_DOUBLE);
 
     engine->RegisterObjectType("ResourceRef", sizeof(ResourceRef), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CK);
     engine->RegisterObjectBehaviour("ResourceRef", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructResourceRef), asCALL_CDECL_OBJLAST);
@@ -443,6 +449,7 @@ static void RegisterVariant(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(const StringHash&in)", asFUNCTION(ConstructVariantStringHash), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(bool)", asFUNCTION(ConstructVariantBool), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ConstructVariantFloat), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(double)", asFUNCTION(ConstructVariantDouble), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(const Vector2&in)", asFUNCTION(ConstructVariantVector2), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(const Vector3&in)", asFUNCTION(ConstructVariantVector3), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(const Vector4&in)", asFUNCTION(ConstructVariantVector4), asCALL_CDECL_OBJLAST);
@@ -470,6 +477,7 @@ static void RegisterVariant(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(const StringHash&in)", asMETHODPR(Variant, operator =, (const StringHash&), Variant&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(bool)", asMETHODPR(Variant, operator =, (bool), Variant&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(float)", asMETHODPR(Variant, operator =, (float), Variant&), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Variant", "Variant& opAssign(double)", asMETHODPR(Variant, operator =, (double), Variant&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(const Vector2&in)", asMETHODPR(Variant, operator =, (const Vector2&), Variant&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(const Vector3&in)", asMETHODPR(Variant, operator =, (const Vector3&), Variant&), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "Variant& opAssign(const Vector4&in)", asMETHODPR(Variant, operator =, (const Vector4&), Variant&), asCALL_THISCALL);
@@ -493,6 +501,7 @@ static void RegisterVariant(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Variant", "bool opEquals(const StringHash&in) const", asMETHODPR(Variant, operator ==, (const StringHash&) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "bool opEquals(bool) const", asMETHODPR(Variant, operator ==, (bool) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "bool opEquals(float) const", asMETHODPR(Variant, operator ==, (float) const, bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Variant", "bool opEquals(double) const", asMETHODPR(Variant, operator ==, (double) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "bool opEquals(const Vector2&in) const", asMETHODPR(Variant, operator ==, (const Vector2&) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "bool opEquals(const Vector3&in) const", asMETHODPR(Variant, operator ==, (const Vector3&) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "bool opEquals(const Vector4&in) const", asMETHODPR(Variant, operator ==, (const Vector4&) const, bool), asCALL_THISCALL);
@@ -515,6 +524,7 @@ static void RegisterVariant(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Variant", "StringHash GetStringHash() const", asMETHOD(Variant, GetStringHash), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "bool GetBool() const", asMETHOD(Variant, GetBool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "float GetFloat() const", asMETHOD(Variant, GetFloat), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Variant", "double GetDouble() const", asMETHOD(Variant, GetDouble), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "const Vector2& GetVector2() const", asMETHOD(Variant, GetVector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "const Vector3& GetVector3() const", asMETHOD(Variant, GetVector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "const Vector4& GetVector4() const", asMETHOD(Variant, GetVector4), asCALL_THISCALL);
@@ -644,6 +654,7 @@ static void RegisterStringUtils(asIScriptEngine* engine)
     engine->RegisterObjectMethod("String", "void Join(String[]&, const String&in)", asFUNCTION(StringJoin), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "bool ToBool() const", asFUNCTIONPR(ToBool, (const String&), bool), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "float ToFloat() const", asFUNCTIONPR(ToFloat, (const String&), float), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("String", "double ToDouble() const", asFUNCTIONPR(ToDouble, (const String&), double), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "int ToInt() const", asFUNCTIONPR(ToInt, (const String&), int), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "uint ToUInt() const", asFUNCTIONPR(ToUInt, (const String&), unsigned), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("String", "Color ToColor() const", asFUNCTIONPR(ToColor, (const String&), Color), asCALL_CDECL_OBJLAST);

+ 6 - 0
Source/Urho3D/Script/ResourceAPI.cpp

@@ -255,6 +255,7 @@ static void RegisterJSONValue(asIScriptEngine* engine)
     engine->RegisterObjectMethod("JSONValue", "void SetInt(const String&in, int)", asMETHOD(JSONValue, SetInt), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void SetBool(const String&in, bool)", asMETHOD(JSONValue, SetBool), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void SetFloat(const String&in, float)", asMETHOD(JSONValue, SetFloat), asCALL_THISCALL);
+    engine->RegisterObjectMethod("JSONValue", "void SetDouble(const String&in, double)", asMETHOD(JSONValue, SetDouble), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void SetVector2(const String&in, const Vector2&in)", asMETHOD(JSONValue, SetVector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void SetVector3(const String&in, const Vector3&in)", asMETHOD(JSONValue, SetVector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void SetVector4(const String&in, const Vector4&in)", asMETHOD(JSONValue, SetVector4), asCALL_THISCALL);
@@ -277,6 +278,7 @@ static void RegisterJSONValue(asIScriptEngine* engine)
     engine->RegisterObjectMethod("JSONValue", "int GetInt(const String&in) const", asMETHODPR(JSONValue, GetInt, (const String&) const, int), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "bool GetBool(const String&in) const", asMETHODPR(JSONValue, GetBool, (const String&) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "float GetFloat(const String&in) const", asMETHODPR(JSONValue, GetFloat, (const String&) const, float), asCALL_THISCALL);
+    engine->RegisterObjectMethod("JSONValue", "double GetDouble(const String&in) const", asMETHODPR(JSONValue, GetDouble, (const String&) const, double), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "Vector2 GetVector2(const String&in) const", asMETHODPR(JSONValue, GetVector2, (const String&) const, Vector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "Vector3 GetVector3(const String&in) const", asMETHODPR(JSONValue, GetVector3, (const String&) const, Vector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "Vector4 GetVector4(const String&in) const", asMETHODPR(JSONValue, GetVector4, (const String&) const, Vector4), asCALL_THISCALL);
@@ -299,6 +301,7 @@ static void RegisterJSONValue(asIScriptEngine* engine)
     engine->RegisterObjectMethod("JSONValue", "void AddInt(int)", asMETHOD(JSONValue, AddInt), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void AddBool(bool)", asMETHOD(JSONValue, AddBool), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void AddFloat(float)", asMETHOD(JSONValue, AddFloat), asCALL_THISCALL);
+    engine->RegisterObjectMethod("JSONValue", "void AddDouble(double)", asMETHOD(JSONValue, AddDouble), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void AddVector2(const Vector2&in)", asMETHOD(JSONValue, AddVector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void AddVector3(const Vector3&in)", asMETHOD(JSONValue, AddVector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "void AddVector4(const Vector4&in)", asMETHOD(JSONValue, AddVector4), asCALL_THISCALL);
@@ -320,6 +323,7 @@ static void RegisterJSONValue(asIScriptEngine* engine)
     engine->RegisterObjectMethod("JSONValue", "int GetInt(uint) const", asMETHODPR(JSONValue, GetInt, (unsigned) const, int), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "bool GetBool(uint) const", asMETHODPR(JSONValue, GetBool, (unsigned) const, bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "float GetFloat(uint) const", asMETHODPR(JSONValue, GetFloat, (unsigned) const, float), asCALL_THISCALL);
+    engine->RegisterObjectMethod("JSONValue", "double GetDouble(uint) const", asMETHODPR(JSONValue, GetDouble, (unsigned) const, double), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "Vector2 GetVector2(uint) const", asMETHODPR(JSONValue, GetVector2, (unsigned) const, Vector2), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "Vector3 GetVector3(uint) const", asMETHODPR(JSONValue, GetVector3, (unsigned) const, Vector3), asCALL_THISCALL);
     engine->RegisterObjectMethod("JSONValue", "Vector4 GetVector4(uint) const", asMETHODPR(JSONValue, GetVector4, (unsigned) const, Vector4), asCALL_THISCALL);
@@ -444,6 +448,7 @@ static void RegisterXMLElement(asIScriptEngine* engine)
     engine->RegisterObjectMethod("XMLElement", "bool SetBoundingBox(const BoundingBox&in)", asMETHOD(XMLElement, SetBoundingBox), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool SetColor(const String&in, const Color&in)", asMETHOD(XMLElement, SetColor), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool SetFloat(const String&in, float)", asMETHOD(XMLElement, SetFloat), asCALL_THISCALL);
+    engine->RegisterObjectMethod("XMLElement", "bool SetDouble(const String&in, double)", asMETHOD(XMLElement, SetDouble), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool SetInt(const String&in, int)", asMETHOD(XMLElement, SetInt), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool SetUInt(const String&in, uint)", asMETHOD(XMLElement, SetUInt), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "bool SetQuaternion(const String&in, const Quaternion&in)", asMETHOD(XMLElement, SetQuaternion), asCALL_THISCALL);
@@ -472,6 +477,7 @@ static void RegisterXMLElement(asIScriptEngine* engine)
     engine->RegisterObjectMethod("XMLElement", "BoundingBox GetBoundingBox() const", asMETHOD(XMLElement, GetBoundingBox), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "Color GetColor(const String&in) const", asMETHOD(XMLElement, GetColor), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "float GetFloat(const String&in) const", asMETHOD(XMLElement, GetFloat), asCALL_THISCALL);
+    engine->RegisterObjectMethod("XMLElement", "double GetDouble(const String&in) const", asMETHOD(XMLElement, GetDouble), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "uint GetUInt(const String&in) const", asMETHOD(XMLElement, GetUInt), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "int GetInt(const String&in) const", asMETHOD(XMLElement, GetInt), asCALL_THISCALL);
     engine->RegisterObjectMethod("XMLElement", "Quaternion GetQuaternion(const String&in) const", asMETHOD(XMLElement, GetQuaternion), asCALL_THISCALL);

+ 19 - 15
bin/Data/Scripts/Editor/AttributeEditor.as

@@ -276,13 +276,13 @@ UIElement@ CreateNumAttributeEditor(ListView@ list, Array<Serializable@>@ serial
 {
     UIElement@ parent = CreateAttributeEditorParent(list, info.name, index, subIndex);
     VariantType type = info.type;
-    uint numCoords = type - VAR_FLOAT + 1;
-    if (type == VAR_QUATERNION)
+    uint numCoords = 1;
+    if (type == VAR_VECTOR2 || type == VAR_INTVECTOR2)
+        numCoords = 2;
+    if (type == VAR_VECTOR3 || type == VAR_QUATERNION)
         numCoords = 3;
-    else if (type == VAR_COLOR || type == VAR_INTRECT)
+    else if (type == VAR_VECTOR4 || type == VAR_COLOR || type == VAR_INTRECT)
         numCoords = 4;
-    else if (type == VAR_INTVECTOR2)
-        numCoords = 2;
 
     for (uint i = 0; i < numCoords; ++i)
     {
@@ -430,7 +430,7 @@ UIElement@ CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializa
         parent = CreateStringAttributeEditor(list, serializables, info, index, subIndex);
     else if (type == VAR_BOOL)
         parent = CreateBoolAttributeEditor(list, serializables, info, index, subIndex);
-    else if ((type >= VAR_FLOAT && type <= VAR_VECTOR4) || type == VAR_QUATERNION || type == VAR_COLOR || type == VAR_INTVECTOR2 || type == VAR_INTRECT)
+    else if ((type >= VAR_FLOAT && type <= VAR_VECTOR4) || type == VAR_QUATERNION || type == VAR_COLOR || type == VAR_INTVECTOR2 || type == VAR_INTRECT || type == VAR_DOUBLE)
         parent = CreateNumAttributeEditor(list, serializables, info, index, subIndex);
     else if (type == VAR_INT)
         parent = CreateIntAttributeEditor(list, serializables, info, index, subIndex);
@@ -596,7 +596,7 @@ void LoadAttributeEditor(UIElement@ parent, const Variant&in value, const Attrib
     }
 
     VariantType type = info.type;
-    if (type == VAR_FLOAT || type == VAR_STRING || type == VAR_BUFFER)
+    if (type == VAR_FLOAT || type == VAR_DOUBLE || type == VAR_STRING || type == VAR_BUFFER)
         SetEditable(SetValue(parent.children[1], value.ToString(), sameValue), editable && sameValue);
     else if (type == VAR_BOOL)
         SetEditable(SetValue(parent.children[1], value.GetBool(), sameValue), editable && sameValue);
@@ -818,6 +818,8 @@ void SanitizeNumericalValue(VariantType type, String& value)
         value = String(value.ToFloat());
     else if (type == VAR_INT || type == VAR_INTRECT || type == VAR_INTVECTOR2)
         value = String(value.ToInt());
+    else if (type == VAR_DOUBLE)
+        value = String(value.ToDouble());
 }
 
 void GetEditorValue(UIElement@ parent, VariantType type, Array<String>@ enumNames, uint coordinate, Array<Variant>& values)
@@ -836,6 +838,8 @@ void GetEditorValue(UIElement@ parent, VariantType type, Array<String>@ enumName
     }
     else if (type == VAR_FLOAT)
         FillValue(values, Variant(attrEdit.text.ToFloat()));
+    else if (type == VAR_DOUBLE)
+        FillValue(values, Variant(attrEdit.text.ToDouble()));
     else if (type == VAR_QUATERNION)
     {
         float value = attrEdit.text.ToFloat();
@@ -977,22 +981,22 @@ void EditAttribute(StringHash eventType, VariantMap& eventData)
 
     if (!dragEditAttribute)
     {
-	    // Store old values so that PostEditAttribute can create undo actions
-	    for (uint i = 0; i < serializables.length; ++i)
-		    oldValues.Push(serializables[i].attributes[index]);
+        // Store old values so that PostEditAttribute can create undo actions
+        for (uint i = 0; i < serializables.length; ++i)
+            oldValues.Push(serializables[i].attributes[index]);
     }
 
     StoreAttributeEditor(parent, serializables, index, subIndex, coordinate);
     for (uint i = 0; i < serializables.length; ++i)
-	    serializables[i].ApplyAttributes();
+        serializables[i].ApplyAttributes();
     
     if (!dragEditAttribute)
     {
-	    // Do the editor post logic after attribute has been modified.
-	    PostEditAttribute(serializables, index, oldValues);
+        // Do the editor post logic after attribute has been modified.
+        PostEditAttribute(serializables, index, oldValues);
     }
 
-    // Update the stored script attributes if this is a ScriptInstance    
+    // Update the stored script attributes if this is a ScriptInstance
     EditScriptAttributes(serializables[0], index);
 
     inEditAttribute = false;
@@ -1000,7 +1004,7 @@ void EditAttribute(StringHash eventType, VariantMap& eventData)
     // If not an intermediate edit, reload the editor fields with validated values
     // (attributes may have interactions; therefore we load everything, not just the value being edited)
     if (!intermediateEdit)
-	    attributesDirty = true;
+        attributesDirty = true;
 }
 
 void LineDragBegin(StringHash eventType, VariantMap& eventData)