Browse Source

Revert "Remove OnSetAttribute hooks from Light, Terrain, Zone, OffMeshConnection, CollisionShape, Constraint, Constraint2D and RigidBody components."

This reverts commit c55bbb423063d5b9babdd43ddc5e5f9bb24c8465.
Eugene Kozlov 8 years ago
parent
commit
a97ad88ead

+ 26 - 89
Source/Urho3D/Graphics/Light.cpp

@@ -149,24 +149,38 @@ void Light::RegisterObject(Context* context)
     URHO3D_ACCESSOR_ATTRIBUTE("Shadow Fade Distance", GetShadowFadeDistance, SetShadowFadeDistance, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Shadow Intensity", GetShadowIntensity, SetShadowIntensity, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Shadow Resolution", GetShadowResolution, SetShadowResolution, float, 1.0f, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Focus To Scene", GetShadowFocusFlag, SetShadowFocusFlag, bool, true, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Non-uniform View", GetShadowFocusNonUniform, SetShadowFocusNonUniform, bool, true, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Auto-Reduce Size", GetShadowFocusAutoSize, SetShadowFocusAutoSize, bool, true, AM_DEFAULT);
-    URHO3D_MIXED_ACCESSOR_ATTRIBUTE("CSM Splits", GetShadowCascadeSplits, SetShadowCascadeSplits,
-        Vector4, Vector4(DEFAULT_SHADOWSPLIT, 0.0f, 0.0f, 0.0f), AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("CSM Fade Start", GetShadowCascadeFadeStart, SetShadowCascadeFadeStart, float, DEFAULT_SHADOWFADESTART, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("CSM Bias Auto Adjust", GetShadowCascadeBiasAutoAdjust, SetShadowCascadeBiasAutoAdjust, float, DEFAULT_BIASAUTOADJUST, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("View Size Quantize", GetShadowFocusQuantize, SetShadowFocusQuantize, float, DEFAULT_SHADOWQUANTIZE, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("View Size Minimum", GetShadowFocusMinView, SetShadowFocusMinView, float, DEFAULT_SHADOWMINVIEW, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Depth Constant Bias", GetShadowConstantBias, SetShadowConstantBias, float, DEFAULT_CONSTANTBIAS, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Depth Slope Bias", GetShadowSlopeScaledBias, SetShadowSlopeScaledBias, float, DEFAULT_SLOPESCALEDBIAS, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Normal Offset", GetShadowNormalOffset, SetShadowNormalOffset, float, DEFAULT_NORMALOFFSET, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Focus To Scene", bool, shadowFocus_.focus_, true, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Non-uniform View", bool, shadowFocus_.nonUniform_, true, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Auto-Reduce Size", bool, shadowFocus_.autoSize_, true, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("CSM Splits", Vector4, shadowCascade_.splits_, Vector4(DEFAULT_SHADOWSPLIT, 0.0f, 0.0f, 0.0f), AM_DEFAULT);
+    URHO3D_ATTRIBUTE("CSM Fade Start", float, shadowCascade_.fadeStart_, DEFAULT_SHADOWFADESTART, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("CSM Bias Auto Adjust", float, shadowCascade_.biasAutoAdjust_, DEFAULT_BIASAUTOADJUST, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("View Size Quantize", float, shadowFocus_.quantize_, DEFAULT_SHADOWQUANTIZE, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("View Size Minimum", float, shadowFocus_.minView_, DEFAULT_SHADOWMINVIEW, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Depth Constant Bias", float, shadowBias_.constantBias_, DEFAULT_CONSTANTBIAS, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Depth Slope Bias", float, shadowBias_.slopeScaledBias_, DEFAULT_SLOPESCALEDBIAS, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Normal Offset", float, shadowBias_.normalOffset_, DEFAULT_NORMALOFFSET, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Near/Farclip Ratio", float, shadowNearFarRatio_, DEFAULT_SHADOWNEARFARRATIO, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Max Extrusion", GetShadowMaxExtrusion, SetShadowMaxExtrusion, float, DEFAULT_SHADOWMAXEXTRUSION, AM_DEFAULT);
     URHO3D_ATTRIBUTE("View Mask", int, viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Light Mask", int, lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
 }
 
+void Light::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    // Validate the bias, cascade & focus parameters
+    if (attr.offset_ >= offsetof(Light, shadowBias_) && attr.offset_ < (offsetof(Light, shadowBias_) + sizeof(BiasParameters)))
+        shadowBias_.Validate();
+    else if (attr.offset_ >= offsetof(Light, shadowCascade_) &&
+             attr.offset_ < (offsetof(Light, shadowCascade_) + sizeof(CascadeParameters)))
+        shadowCascade_.Validate();
+    else if (attr.offset_ >= offsetof(Light, shadowFocus_) &&
+             attr.offset_ < (offsetof(Light, shadowFocus_) + sizeof(FocusParameters)))
+        shadowFocus_.Validate();
+}
+
 void Light::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     // Do not record a raycast result for a directional light, as it would block all other results
@@ -372,27 +386,6 @@ void Light::SetShadowBias(const BiasParameters& parameters)
     MarkNetworkUpdate();
 }
 
-void Light::SetShadowConstantBias(float constantBias)
-{
-    shadowBias_.constantBias_ = constantBias;
-    shadowBias_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowSlopeScaledBias(float slopeScaledBias)
-{
-    shadowBias_.slopeScaledBias_ = slopeScaledBias;
-    shadowBias_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowNormalOffset(float normalOffset)
-{
-    shadowBias_.normalOffset_ = normalOffset;
-    shadowBias_.Validate();
-    MarkNetworkUpdate();
-}
-
 void Light::SetShadowCascade(const CascadeParameters& parameters)
 {
     shadowCascade_ = parameters;
@@ -400,27 +393,6 @@ void Light::SetShadowCascade(const CascadeParameters& parameters)
     MarkNetworkUpdate();
 }
 
-void Light::SetShadowCascadeSplits(const Vector4& value)
-{
-    memcpy(shadowCascade_.splits_, value.Data(), sizeof(Vector4));
-    shadowCascade_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowCascadeFadeStart(float fadeStart)
-{
-    shadowCascade_.fadeStart_ = fadeStart;
-    shadowCascade_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowCascadeBiasAutoAdjust(float biasAutoAdjust)
-{
-    shadowCascade_.biasAutoAdjust_ = biasAutoAdjust;
-    shadowCascade_.Validate();
-    MarkNetworkUpdate();
-}
-
 void Light::SetShadowFocus(const FocusParameters& parameters)
 {
     shadowFocus_ = parameters;
@@ -428,41 +400,6 @@ void Light::SetShadowFocus(const FocusParameters& parameters)
     MarkNetworkUpdate();
 }
 
-void Light::SetShadowFocusFlag(bool focus)
-{
-    shadowFocus_.focus_ = focus;
-    shadowFocus_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowFocusNonUniform(bool nonUniform)
-{
-    shadowFocus_.nonUniform_ = nonUniform;
-    shadowFocus_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowFocusAutoSize(bool autoSize)
-{
-    shadowFocus_.autoSize_ = autoSize;
-    shadowFocus_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowFocusQuantize(float quantize)
-{
-    shadowFocus_.quantize_ = quantize;
-    shadowFocus_.Validate();
-    MarkNetworkUpdate();
-}
-
-void Light::SetShadowFocusMinView(float minView)
-{
-    shadowFocus_.minView_ = minView;
-    shadowFocus_.Validate();
-    MarkNetworkUpdate();
-}
-
 void Light::SetShadowFadeDistance(float distance)
 {
     shadowFadeDistance_ = Max(distance, 0.0f);

+ 30 - 44
Source/Urho3D/Graphics/Light.h

@@ -163,6 +163,8 @@ public:
     /// Register object factory. Drawable must be registered first.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute change.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Process octree raycast. May be called from a worker thread.
     virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Calculate distance and prepare batches for rendering. May be called from worker thread(s), possibly re-entrantly.
@@ -200,32 +202,10 @@ public:
     void SetShadowFadeDistance(float distance);
     /// Set shadow depth bias parameters.
     void SetShadowBias(const BiasParameters& parameters);
-    /// Set shadow constant bias.
-    void SetShadowConstantBias(float constantBias);
-    /// Set shadow slope scaled bias.
-    void SetShadowSlopeScaledBias(float slopeScaledBias);
-    /// Set shadow normal offset multiplier.
-    void SetShadowNormalOffset(float normalOffset);
     /// Set directional light cascaded shadow parameters.
     void SetShadowCascade(const CascadeParameters& parameters);
-    /// Set shadow cascade splits.
-    void SetShadowCascadeSplits(const Vector4& value);
-    /// Set shadow cascade fade start.
-    void SetShadowCascadeFadeStart(float fadeStart);
-    /// Set shadow cascade automatic depth bias adjustment strength.
-    void SetShadowCascadeBiasAutoAdjust(float biasAutoAdjust);
     /// Set shadow map focusing parameters.
     void SetShadowFocus(const FocusParameters& parameters);
-    /// Set shadow focus flag.
-    void SetShadowFocusFlag(bool focus);
-    /// Set shadow non-uniform focus flag.
-    void SetShadowFocusNonUniform(bool nonUniform);
-    /// Set shadow focus auto-size.
-    void SetShadowFocusAutoSize(bool autoSize);
-    /// Set shadow focus quantization.
-    void SetShadowFocusQuantize(float quantize);
-    /// Set shadow focus minimum view size.
-    void SetShadowFocusMinView(float minView);
     /// Set light intensity in shadow between 0.0 - 1.0. 0.0 (the default) gives fully dark shadows.
     void SetShadowIntensity(float intensity);
     /// Set shadow resolution between 0.25 - 1.0. Determines the shadow map to use.
@@ -241,84 +221,90 @@ public:
 
     /// Return light type.
     LightType GetLightType() const { return lightType_; }
+
     /// Return vertex lighting mode.
     bool GetPerVertex() const { return perVertex_; }
+
     /// Return color.
     const Color& GetColor() const { return color_; }
+
     /// Return the temperature of the light in Kelvin.
     float GetTemperature() const { return temperature_; }
+
     /// Return area light mode radius. Works only with PBR shaders.
     float GetRadius() const { return lightRad_; }
+
     /// Return area tube light length. Works only with PBR shaders.
     float GetLength() const { return lightLength_; }
+
     /// Return if light uses temperature and brightness in lumens.
     bool GetUsePhysicalValues() const { return usePhysicalValues_; }
+
     /// Return the color value of the temperature in Kelvin.
     Color GetColorFromTemperature() const;
+
     /// Return specular intensity.
     float GetSpecularIntensity() const { return specularIntensity_; }
+
     /// Return brightness multiplier. Specified in lumens when "use physical values" is enabled.
     float GetBrightness() const { return brightness_; }
+
     /// Return effective color, multiplied by brightness and affected by temperature when "use physical values" is enabled. Alpha is always 1 so that can compare against the default black color to detect a light with no effect.
     Color GetEffectiveColor() const;
+
     /// Return effective specular intensity, multiplied by absolute value of brightness.
     float GetEffectiveSpecularIntensity() const { return specularIntensity_ * Abs(brightness_); }
+
     /// Return range.
     float GetRange() const { return range_; }
+
     /// Return spotlight field of view.
     float GetFov() const { return fov_; }
+
     /// Return spotlight aspect ratio.
     float GetAspectRatio() const { return aspectRatio_; }
+
     /// Return fade start distance.
     float GetFadeDistance() const { return fadeDistance_; }
+
     /// Return shadow fade start distance.
     float GetShadowFadeDistance() const { return shadowFadeDistance_; }
+
     /// Return shadow depth bias parameters.
     const BiasParameters& GetShadowBias() const { return shadowBias_; }
-    /// Return shadow constant bias.
-    float GetShadowConstantBias() const { return shadowBias_.constantBias_; }
-    /// Return shadow slope scaled bias.
-    float GetShadowSlopeScaledBias() const { return shadowBias_.slopeScaledBias_; }
-    /// Return shadow normal offset multiplier.
-    float GetShadowNormalOffset() const { return shadowBias_.normalOffset_; }
+
     /// Return directional light cascaded shadow parameters.
     const CascadeParameters& GetShadowCascade() const { return shadowCascade_; }
-    /// Return shadow cascade splits.
-    Vector4 GetShadowCascadeSplits() const { return Vector4(shadowCascade_.splits_); }
-    /// Return shadow cascade fade start.
-    float GetShadowCascadeFadeStart() const { return shadowCascade_.fadeStart_; }
-    /// Return shadow cascade automatic depth bias adjustment strength.
-    float GetShadowCascadeBiasAutoAdjust() const { return shadowCascade_.biasAutoAdjust_; }
+
     /// Return shadow map focus parameters.
     const FocusParameters& GetShadowFocus() const { return shadowFocus_; }
-    /// Return shadow focus flag.
-    bool GetShadowFocusFlag() const { return shadowFocus_.focus_; }
-    /// Return shadow non-uniform focus flag.
-    bool GetShadowFocusNonUniform() const { return shadowFocus_.nonUniform_; }
-    /// Return shadow focus auto-size.
-    bool GetShadowFocusAutoSize() const { return shadowFocus_.autoSize_; }
-    /// Return shadow focus quantization.
-    float GetShadowFocusQuantize() const { return shadowFocus_.quantize_; }
-    /// Return shadow focus minimum view size.
-    float GetShadowFocusMinView() const { return shadowFocus_.minView_; }
+
     /// Return light intensity in shadow.
     float GetShadowIntensity() const { return shadowIntensity_; }
+
     /// Return shadow resolution.
     float GetShadowResolution() const { return shadowResolution_; }
+
     /// Return shadow camera near/far clip distance ratio.
     float GetShadowNearFarRatio() const { return shadowNearFarRatio_; }
+
     /// Return maximum shadow extrusion distance for directional lights.
     float GetShadowMaxExtrusion() const { return shadowMaxExtrusion_; }
+
     /// Return range attenuation texture.
     Texture* GetRampTexture() const { return rampTexture_; }
+
     /// Return spotlight attenuation texture.
     Texture* GetShapeTexture() const { return shapeTexture_; }
+
     /// Return spotlight frustum.
     Frustum GetFrustum() const;
     /// Return spotlight frustum in the specified view space.
     Frustum GetViewSpaceFrustum(const Matrix3x4& view) const;
+
     /// Return number of shadow map cascade splits for a directional light, considering also graphics API limitations.
     int GetNumShadowSplits() const;
+
     /// Return whether light has negative (darkening) color.
     bool IsNegative() const { return GetEffectiveColor().SumRGB() < 0.0f; }
 

+ 20 - 48
Source/Urho3D/Graphics/Terrain.cpp

@@ -128,14 +128,14 @@ void Terrain::RegisterObject(Context* context)
         AM_DEFAULT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()),
         AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("North Neighbor NodeID", GetNorthNeighborNodeID, SetNorthNeighborNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
-    URHO3D_ACCESSOR_ATTRIBUTE("South Neighbor NodeID", GetSouthNeighborNodeID, SetSouthNeighborNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
-    URHO3D_ACCESSOR_ATTRIBUTE("West Neighbor NodeID", GetWestNeighborNodeID, SetWestNeighborNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
-    URHO3D_ACCESSOR_ATTRIBUTE("East Neighbor NodeID", GetEastNeighborNodeID, SetEastNeighborNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
-    URHO3D_ACCESSOR_ATTRIBUTE("Vertex Spacing", GetSpacing, SetSpacingAttr, Vector3, DEFAULT_SPACING, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("North Neighbor NodeID", unsigned, northID_, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ATTRIBUTE("South Neighbor NodeID", unsigned, southID_, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ATTRIBUTE("West Neighbor NodeID", unsigned, westID_, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ATTRIBUTE("East Neighbor NodeID", unsigned, eastID_, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ATTRIBUTE("Vertex Spacing", Vector3, spacing_, DEFAULT_SPACING, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Patch Size", GetPatchSize, SetPatchSizeAttr, int, DEFAULT_PATCH_SIZE, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Max LOD Levels", GetMaxLodLevels, SetMaxLodLevelsAttr, unsigned, MAX_LOD_LEVELS, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Smooth Height Map", GetSmoothing, SetSmoothingAttr, bool, false, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Smooth Height Map", bool, smoothing_, false, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Is Occluder", IsOccluder, SetOccluder, bool, false, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Cast Shadows", GetCastShadows, SetCastShadows, bool, false, AM_DEFAULT);
@@ -150,6 +150,20 @@ void Terrain::RegisterObject(Context* context)
     URHO3D_ACCESSOR_ATTRIBUTE("Occlusion LOD level", GetOcclusionLodLevel, SetOcclusionLodLevelAttr, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
 }
 
+void Terrain::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    // Change of any non-accessor attribute requires recreation of the terrain, or setting the neighbor terrains
+    if (!attr.accessor_)
+    {
+        if (attr.mode_ & AM_NODEID)
+            neighborsDirty_ = true;
+        else
+            recreateTerrain_ = true;
+    }
+}
+
 void Terrain::ApplyAttributes()
 {
     if (recreateTerrain_)
@@ -803,39 +817,6 @@ void Terrain::SetHeightMapAttr(const ResourceRef& value)
     SetHeightMapInternal(image, false);
 }
 
-void Terrain::SetNorthNeighborNodeIDAttr(unsigned nodeID)
-{
-    northID_ = nodeID;
-    neighborsDirty_ = true;
-}
-
-void Terrain::SetSouthNeighborNodeIDAttr(unsigned nodeID)
-{
-    southID_ = nodeID;
-    neighborsDirty_ = true;
-}
-
-void Terrain::SetWestNeighborNodeIDAttr(unsigned nodeID)
-{
-    westID_ = nodeID;
-    neighborsDirty_ = true;
-}
-
-void Terrain::SetEastNeighborNodeIDAttr(unsigned nodeID)
-{
-    eastID_ = nodeID;
-    neighborsDirty_ = true;
-}
-
-void Terrain::SetSpacingAttr(const Vector3& value)
-{
-    if (value != spacing_)
-    {
-        spacing_ = value;
-        recreateTerrain_ = true;
-    }
-}
-
 void Terrain::SetPatchSizeAttr(int value)
 {
     if (value < MIN_PATCH_SIZE || value > MAX_PATCH_SIZE || !IsPowerOfTwo((unsigned)value))
@@ -860,15 +841,6 @@ void Terrain::SetMaxLodLevelsAttr(unsigned value)
     }
 }
 
-void Terrain::SetSmoothingAttr(bool enable)
-{
-    if (enable != smoothing_)
-    {
-        smoothing_ = enable;
-        recreateTerrain_ = true;
-    }
-}
-
 void Terrain::SetOcclusionLodLevelAttr(unsigned value)
 {
     if (value != occlusionLodLevel_)

+ 24 - 20
Source/Urho3D/Graphics/Terrain.h

@@ -47,6 +47,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
     /// Handle enabled/disabled state change.
@@ -103,16 +105,22 @@ public:
 
     /// Return patch quads per side.
     int GetPatchSize() const { return patchSize_; }
+
     /// Return vertex and height spacing.
     const Vector3& GetSpacing() const { return spacing_; }
+
     /// Return heightmap size in vertices.
     const IntVector2& GetNumVertices() const { return numVertices_; }
+
     /// Return heightmap size in patches.
     const IntVector2& GetNumPatches() const { return numPatches_; }
+
     /// Return maximum number of LOD levels for terrain patches. This can be between 1-4.
     unsigned GetMaxLodLevels() const { return maxLodLevels_; }
+    
     /// Return LOD level used for occlusion.
     unsigned GetOcclusionLodLevel() const { return occlusionLodLevel_; }
+    
     /// Return whether smoothing is in use.
     bool GetSmoothing() const { return smoothing_; }
 
@@ -137,44 +145,52 @@ public:
 
     /// Return north neighbor terrain.
     Terrain* GetNorthNeighbor() const { return north_; }
+    
     /// Return south neighbor terrain.
     Terrain* GetSouthNeighbor() const { return south_; }
+    
     /// Return west neighbor terrain.
     Terrain* GetWestNeighbor() const { return west_; }
+    
     /// Return east neighbor terrain.
     Terrain* GetEastNeighbor() const { return east_; }
-    /// Return north neighbor terrain.
-    unsigned GetNorthNeighborNodeID() const { return northID_; }
-    /// Return south neighbor terrain.
-    unsigned GetSouthNeighborNodeID() const { return southID_; }
-    /// Return west neighbor terrain.
-    unsigned GetWestNeighborNodeID() const { return westID_; }
-    /// Return east neighbor terrain.
-    unsigned GetEastNeighborNodeID() const { return eastID_; }
+
     /// Return raw height data.
     SharedArrayPtr<float> GetHeightData() const { return heightData_; }
+
     /// Return draw distance.
     float GetDrawDistance() const { return drawDistance_; }
+
     /// Return shadow draw distance.
     float GetShadowDistance() const { return shadowDistance_; }
+
     /// Return LOD bias.
     float GetLodBias() const { return lodBias_; }
+
     /// Return view mask.
     unsigned GetViewMask() const { return viewMask_; }
+
     /// Return light mask.
     unsigned GetLightMask() const { return lightMask_; }
+
     /// Return shadow mask.
     unsigned GetShadowMask() const { return shadowMask_; }
+
     /// Return zone mask.
     unsigned GetZoneMask() const { return zoneMask_; }
+
     /// Return maximum number of per-pixel lights.
     unsigned GetMaxLights() const { return maxLights_; }
+
     /// Return visible flag.
     bool IsVisible() const { return visible_; }
+
     /// Return shadowcaster flag.
     bool GetCastShadows() const { return castShadows_; }
+
     /// Return occluder flag.
     bool IsOccluder() const { return occluder_; }
+
     /// Return occludee flag.
     bool IsOccludee() const { return occludee_; }
 
@@ -186,22 +202,10 @@ public:
     void SetHeightMapAttr(const ResourceRef& value);
     /// Set material attribute.
     void SetMaterialAttr(const ResourceRef& value);
-    /// Set north neighbor node ID attribute.
-    void SetNorthNeighborNodeIDAttr(unsigned nodeID);
-    /// Set south neighbor node ID attribute.
-    void SetSouthNeighborNodeIDAttr(unsigned nodeID);
-    /// Set west neighbor node ID attribute.
-    void SetWestNeighborNodeIDAttr(unsigned nodeID);
-    /// Set east neighbor node ID attribute.
-    void SetEastNeighborNodeIDAttr(unsigned nodeID);
-    /// Set vertex spacing attribute.
-    void SetSpacingAttr(const Vector3& value);
     /// Set patch size attribute.
     void SetPatchSizeAttr(int value);
     /// Set max LOD levels attribute.
     void SetMaxLodLevelsAttr(unsigned value);
-    /// Set smoothing attribute.
-    void SetSmoothingAttr(bool enable);
     /// Set occlusion LOD level attribute.
     void SetOcclusionLodLevelAttr(unsigned value);
     /// Return heightmap attribute.

+ 13 - 18
Source/Urho3D/Graphics/Zone.cpp

@@ -73,8 +73,8 @@ void Zone::RegisterObject(Context* context)
     context->RegisterFactory<Zone>(SCENE_CATEGORY);
 
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Bounding Box Min", GetBoundingBoxMin, SetBoundingBoxMin, Vector3, DEFAULT_BOUNDING_BOX_MIN, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Bounding Box Max", GetBoundingBoxMax, SetBoundingBoxMax, Vector3, DEFAULT_BOUNDING_BOX_MAX, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Bounding Box Min", Vector3, boundingBox_.min_, DEFAULT_BOUNDING_BOX_MIN, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Bounding Box Max", Vector3, boundingBox_.max_, DEFAULT_BOUNDING_BOX_MAX, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Ambient Color", Color, ambientColor_, DEFAULT_AMBIENT_COLOR, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Fog Color", Color, fogColor_, DEFAULT_FOG_COLOR, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Fog Start", float, fogStart_, DEFAULT_FOG_START, AM_DEFAULT);
@@ -84,7 +84,7 @@ void Zone::RegisterObject(Context* context)
     URHO3D_ATTRIBUTE("Height Fog Mode", bool, heightFog_, false, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Override Mode", bool, override_, false, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Ambient Gradient", bool, ambientGradient_, false, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Priority", GetPriority, SetPriority, int, 0, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Priority", int, priority_, 0, AM_DEFAULT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Zone Texture", GetZoneTextureAttr, SetZoneTextureAttr, ResourceRef,
         ResourceRef(TextureCube::GetTypeStatic()), AM_DEFAULT);
     URHO3D_ATTRIBUTE("Light Mask", int, lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
@@ -92,6 +92,16 @@ void Zone::RegisterObject(Context* context)
     URHO3D_ACCESSOR_ATTRIBUTE("Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
 }
 
+void Zone::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    // If bounding box or priority changes, dirty the drawable as applicable
+    if ((attr.offset_ >= offsetof(Zone, boundingBox_) && attr.offset_ < (offsetof(Zone, boundingBox_) + sizeof(BoundingBox))) ||
+        attr.offset_ == offsetof(Zone, priority_))
+        OnMarkedDirty(node_);
+}
+
 void Zone::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 {
     if (debug && IsEnabledEffective())
@@ -105,20 +115,6 @@ void Zone::SetBoundingBox(const BoundingBox& box)
     MarkNetworkUpdate();
 }
 
-void Zone::SetBoundingBoxMin(const Vector3& boxMin)
-{
-    boundingBox_.min_ = boxMin;
-    OnMarkedDirty(node_);
-    MarkNetworkUpdate();
-}
-
-void Zone::SetBoundingBoxMax(const Vector3& boxMax)
-{
-    boundingBox_.max_ = boxMax;
-    OnMarkedDirty(node_);
-    MarkNetworkUpdate();
-}
-
 void Zone::SetAmbientColor(const Color& color)
 {
     ambientColor_ = color;
@@ -164,7 +160,6 @@ void Zone::SetFogHeightScale(float scale)
 void Zone::SetPriority(int priority)
 {
     priority_ = priority;
-    OnMarkedDirty(node_);
     MarkNetworkUpdate();
 }
 

+ 11 - 10
Source/Urho3D/Graphics/Zone.h

@@ -42,15 +42,13 @@ public:
     /// Register object factory. Drawable must be registered first.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Visualize the component as debug geometry.
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
 
     /// Set local-space bounding box. Will be used as an oriented bounding box to test whether objects or the camera are inside.
     void SetBoundingBox(const BoundingBox& box);
-    /// Set local-space bounding box min.
-    void SetBoundingBoxMin(const Vector3& boxMin);
-    /// Set local-space bounding box max.
-    void SetBoundingBoxMax(const Vector3& boxMax);
     /// Set ambient color
     void SetAmbientColor(const Color& color);
     /// Set fog color.
@@ -77,12 +75,6 @@ public:
     /// Return inverse world transform.
     const Matrix3x4& GetInverseWorldTransform() const;
 
-    /// Return local-space bounding box.
-    const BoundingBox& GetBoundingBox() const { return boundingBox_; }
-    /// Return local-space bounding box min.
-    const Vector3& GetBoundingBoxMin() const { return boundingBox_.min_; }
-    /// Return local-space bounding box max.
-    const Vector3& GetBoundingBoxMax() const { return boundingBox_.max_; }
     /// Return zone's own ambient color, disregarding gradient mode.
     const Color& GetAmbientColor() const { return ambientColor_; }
 
@@ -93,22 +85,31 @@ public:
 
     /// Return fog color.
     const Color& GetFogColor() const { return fogColor_; }
+
     /// Return fog start distance.
     float GetFogStart() const { return fogStart_; }
+
     /// Return fog end distance.
     float GetFogEnd() const { return fogEnd_; }
+
     /// Return fog height distance relative to the scene node's world position.
     float GetFogHeight() const { return fogHeight_; }
+
     /// Return fog height scale.
     float GetFogHeightScale() const { return fogHeightScale_; }
+
     /// Return zone priority.
     int GetPriority() const { return priority_; }
+
     /// Return whether height fog mode is enabled.
     bool GetHeightFog() const { return heightFog_; }
+
     /// Return whether override mode is enabled.
     bool GetOverride() const { return override_; }
+
     /// Return whether ambient gradient mode is enabled.
     bool GetAmbientGradient() const { return ambientGradient_; }
+
     /// Return zone texture.
     Texture* GetZoneTexture() const { return zoneTexture_; }
 

+ 11 - 5
Source/Urho3D/Navigation/OffMeshConnection.cpp

@@ -58,13 +58,21 @@ void OffMeshConnection::RegisterObject(Context* context)
     context->RegisterFactory<OffMeshConnection>(NAVIGATION_CATEGORY);
 
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Endpoint NodeID", GetEndPointNodeID, SetEndPointNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ATTRIBUTE("Endpoint NodeID", int, endPointID_, 0, AM_DEFAULT | AM_NODEID);
     URHO3D_ATTRIBUTE("Radius", float, radius_, DEFAULT_RADIUS, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Bidirectional", bool, bidirectional_, true, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Flags Mask", unsigned, mask_, DEFAULT_MASK_FLAG, AM_DEFAULT);
     URHO3D_ATTRIBUTE("Area Type", unsigned, areaId_, DEFAULT_AREA, AM_DEFAULT);
 }
 
+void OffMeshConnection::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    if (attr.offset_ == offsetof(OffMeshConnection, endPointID_))
+        endPointDirty_ = true;
+}
+
 void OffMeshConnection::ApplyAttributes()
 {
     if (endPointDirty_)
@@ -119,11 +127,9 @@ void OffMeshConnection::SetEndPoint(Node* node)
     MarkNetworkUpdate();
 }
 
-void OffMeshConnection::SetEndPointNodeIDAttr(unsigned nodeID)
+Node* OffMeshConnection::GetEndPoint() const
 {
-    endPointID_ = nodeID;
-    endPointDirty_ = true;
-    MarkNetworkUpdate();
+    return endPoint_;
 }
 
 }

+ 7 - 5
Source/Urho3D/Navigation/OffMeshConnection.h

@@ -40,6 +40,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
     /// Visualize the component as debug geometry.
@@ -47,8 +49,6 @@ public:
 
     /// Set endpoint node.
     void SetEndPoint(Node* node);
-    /// Set endpoint node ID.
-    void SetEndPointNodeIDAttr(unsigned nodeID);
     /// Set radius.
     void SetRadius(float radius);
     /// Set bidirectional flag. Default true.
@@ -59,15 +59,17 @@ public:
     void SetAreaID(unsigned newAreaID);
 
     /// Return endpoint node.
-    Node* GetEndPoint() const { return endPoint_; }
-    /// Return endpoint node ID.
-    unsigned GetEndPointNodeID() const { return endPointID_; }
+    Node* GetEndPoint() const;
+
     /// Return radius.
     float GetRadius() const { return radius_; }
+
     /// Return whether is bidirectional.
     bool IsBidirectional() const { return bidirectional_; }
+
     /// Return the user assigned mask
     unsigned GetMask() const { return mask_; }
+
     /// Return the user assigned area ID
     unsigned GetAreaID() const { return areaId_; }
 

+ 14 - 40
Source/Urho3D/Physics/CollisionShape.cpp

@@ -422,14 +422,23 @@ void CollisionShape::RegisterObject(Context* context)
     context->RegisterFactory<CollisionShape>(PHYSICS_CATEGORY);
 
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-    URHO3D_ENUM_ACCESSOR_ATTRIBUTE("Shape Type", GetShapeType, SetShapeTypeAttr, ShapeType, typeNames, SHAPE_BOX, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Size", GetSize, SetSizeAttr, Vector3, Vector3::ONE, AM_DEFAULT);
+    URHO3D_ENUM_ATTRIBUTE("Shape Type", shapeType_, typeNames, SHAPE_BOX, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Size", Vector3, size_, Vector3::ONE, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Offset Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Offset Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_DEFAULT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("LOD Level", GetLodLevel, SetLodLevelAttr, unsigned, 0, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Collision Margin", GetMargin, SetMarginAttr, float, DEFAULT_COLLISION_MARGIN, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("CustomGeometry ComponentID", GetCustomGeometryID, SetCustomGeometryIDAttr, unsigned, 0, AM_DEFAULT | AM_COMPONENTID);
+    URHO3D_ATTRIBUTE("LOD Level", int, lodLevel_, 0, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Collision Margin", float, margin_, DEFAULT_COLLISION_MARGIN, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("CustomGeometry ComponentID", unsigned, customGeometryID_, 0, AM_DEFAULT | AM_COMPONENTID);
+}
+
+void CollisionShape::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    // Change of any non-accessor attribute requires recreation of the collision shape
+    if (!attr.accessor_)
+        recreateShape_ = true;
 }
 
 void CollisionShape::ApplyAttributes()
@@ -888,20 +897,6 @@ void CollisionShape::NotifyRigidBody(bool updateMass)
     }
 }
 
-void CollisionShape::SetShapeTypeAttr(ShapeType type)
-{
-    shapeType_ = type;
-    recreateShape_ = true;
-    MarkNetworkUpdate();
-}
-
-void CollisionShape::SetSizeAttr(const Vector3& value)
-{
-    size_ = value;
-    recreateShape_ = true;
-    MarkNetworkUpdate();
-}
-
 void CollisionShape::SetModelAttr(const ResourceRef& value)
 {
     ResourceCache* cache = GetSubsystem<ResourceCache>();
@@ -910,27 +905,6 @@ void CollisionShape::SetModelAttr(const ResourceRef& value)
     MarkNetworkUpdate();
 }
 
-void CollisionShape::SetLodLevelAttr(unsigned value)
-{
-    lodLevel_ = value;
-    recreateShape_ = true;
-    MarkNetworkUpdate();
-}
-
-void CollisionShape::SetMarginAttr(float value)
-{
-    margin_ = value;
-    recreateShape_ = true;
-    MarkNetworkUpdate();
-}
-
-void CollisionShape::SetCustomGeometryIDAttr(unsigned componentID)
-{
-    customGeometryID_ = componentID;
-    recreateShape_ = true;
-    MarkNetworkUpdate();
-}
-
 ResourceRef CollisionShape::GetModelAttr() const
 {
     return GetResourceRef(model_, Model::GetTypeStatic());

+ 12 - 12
Source/Urho3D/Physics/CollisionShape.h

@@ -138,6 +138,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
     /// Handle enabled/disabled state change.
@@ -195,43 +197,41 @@ public:
 
     /// Return Bullet collision shape.
     btCollisionShape* GetCollisionShape() const { return shape_.Get(); }
+
     /// Return the shared geometry data.
     CollisionGeometryData* GetGeometryData() const { return geometry_; }
+
     /// Return physics world.
     PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }
+
     /// Return shape type.
     ShapeType GetShapeType() const { return shapeType_; }
+
     /// Return shape size.
     const Vector3& GetSize() const { return size_; }
+
     /// Return offset position.
     const Vector3& GetPosition() const { return position_; }
+
     /// Return offset rotation.
     const Quaternion& GetRotation() const { return rotation_; }
+
     /// Return collision margin.
     float GetMargin() const { return margin_; }
-    /// Return custom geometry component ID.
-    unsigned GetCustomGeometryID() const { return customGeometryID_; }
+
     /// Return triangle mesh / convex hull model.
     Model* GetModel() const { return model_; }
+
     /// Return model LOD level.
     unsigned GetLodLevel() const { return lodLevel_; }
+
     /// Return world-space bounding box.
     BoundingBox GetWorldBoundingBox() const;
 
     /// Update the new collision shape to the RigidBody.
     void NotifyRigidBody(bool updateMass = true);
-    /// Set shape type attribute.
-    void SetShapeTypeAttr(ShapeType type);
-    /// Set size attribute.
-    void SetSizeAttr(const Vector3& value);
     /// Set model attribute.
     void SetModelAttr(const ResourceRef& value);
-    /// Set model LOD level attribute.
-    void SetLodLevelAttr(unsigned value);
-    /// Set collision margin attribute.
-    void SetMarginAttr(float value);
-    /// Set custom geometry component ID attribute.
-    void SetCustomGeometryIDAttr(unsigned componentID);
     /// Return model attribute.
     ResourceRef GetModelAttr() const;
     /// Release the collision shape.

+ 32 - 59
Source/Urho3D/Physics/Constraint.cpp

@@ -84,17 +84,42 @@ void Constraint::RegisterObject(Context* context)
     context->RegisterFactory<Constraint>(PHYSICS_CATEGORY);
 
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-    URHO3D_ENUM_ACCESSOR_ATTRIBUTE("Constraint Type", GetConstraintType, SetConstraintTypeAttr, ConstraintType, typeNames, CONSTRAINT_POINT, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Position", GetPosition, SetPositionAttr, Vector3, Vector3::ZERO, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Rotation", GetRotation, SetRotationAttr, Quaternion, Quaternion::IDENTITY, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Other Body Position", GetOtherPosition, SetOtherPositionAttr, Vector3, Vector3::ZERO, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Other Body Rotation", GetOtherRotation, SetOtherRotationAttr, Quaternion, Quaternion::IDENTITY, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Other Body NodeID", GetOtherBodyNodeID, SetOtherBodyNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ENUM_ATTRIBUTE("Constraint Type", constraintType_, typeNames, CONSTRAINT_POINT, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Position", Vector3, position_, Vector3::ZERO, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Rotation", Quaternion, rotation_, Quaternion::IDENTITY, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Other Body Position", Vector3, otherPosition_, Vector3::ZERO, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Other Body Rotation", Quaternion, otherRotation_, Quaternion::IDENTITY, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Other Body NodeID", unsigned, otherBodyNodeID_, 0, AM_DEFAULT | AM_NODEID);
     URHO3D_ACCESSOR_ATTRIBUTE("High Limit", GetHighLimit, SetHighLimit, Vector2, Vector2::ZERO, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Low Limit", GetLowLimit, SetLowLimit, Vector2, Vector2::ZERO, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("ERP Parameter", GetERP, SetERP, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("CFM Parameter", GetCFM, SetCFM, float, 0.0f, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Disable Collision", GetDisableCollision, SetDisableCollitionAttr, bool, false, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Disable Collision", bool, disableCollision_, false, AM_DEFAULT);
+}
+
+void Constraint::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    if (!attr.accessor_)
+    {
+        // Convenience for editing static constraints: if not connected to another body, adjust world position to match local
+        // (when deserializing, the proper other body position will be read after own position, so this calculation is safely
+        // overridden and does not accumulate constraint error
+        if (attr.offset_ == offsetof(Constraint, position_) && constraint_ && !otherBody_)
+        {
+            btTransform ownBody = constraint_->getRigidBodyA().getWorldTransform();
+            btVector3 worldPos = ownBody * ToBtVector3(position_ * cachedWorldScale_ - ownBody_->GetCenterOfMass());
+            otherPosition_ = ToVector3(worldPos);
+        }
+
+        // Certain attribute changes require recreation of the constraint
+        if (attr.offset_ == offsetof(Constraint, constraintType_) || attr.offset_ == offsetof(Constraint, otherBodyNodeID_) ||
+            attr.offset_ == offsetof(Constraint, disableCollision_))
+            recreateConstraint_ = true;
+        else
+            framesDirty_ = true;
+    }
 }
 
 void Constraint::ApplyAttributes()
@@ -344,58 +369,6 @@ Vector3 Constraint::GetWorldPosition() const
         return Vector3::ZERO;
 }
 
-void Constraint::SetConstraintTypeAttr(ConstraintType type)
-{
-    constraintType_ = type;
-    recreateConstraint_ = true;
-}
-
-void Constraint::SetPositionAttr(const Vector3& position)
-{
-    position_ = position;
-    framesDirty_ = true;
-
-    // Convenience for editing static constraints: if not connected to another body, adjust world position to match local
-    // (when deserializing, the proper other body position will be read after own position, so this calculation is safely
-    // overridden and does not accumulate constraint error
-    if (constraint_ && !otherBody_)
-    {
-        btTransform ownBody = constraint_->getRigidBodyA().getWorldTransform();
-        btVector3 worldPos = ownBody * ToBtVector3(position_ * cachedWorldScale_ - ownBody_->GetCenterOfMass());
-        otherPosition_ = ToVector3(worldPos);
-    }
-}
-
-void Constraint::SetRotationAttr(const Quaternion& rotation)
-{
-    rotation_ = rotation;
-    framesDirty_ = true;
-}
-
-void Constraint::SetOtherPositionAttr(const Vector3& position)
-{
-    otherPosition_ = position;
-    framesDirty_ = true;
-}
-
-void Constraint::SetOtherRotationAttr(const Quaternion& rotation)
-{
-    otherRotation_ = rotation;
-    framesDirty_ = true;
-}
-
-void Constraint::SetOtherBodyNodeIDAttr(unsigned nodeID)
-{
-    otherBodyNodeID_ = nodeID;
-    recreateConstraint_ = true;
-}
-
-void Constraint::SetDisableCollitionAttr(bool value)
-{
-    disableCollision_ = value;
-    recreateConstraint_ = true;
-}
-
 void Constraint::ReleaseConstraint()
 {
     if (constraint_)

+ 16 - 17
Source/Urho3D/Physics/Constraint.h

@@ -57,6 +57,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
     /// Handle enabled/disabled state change.
@@ -97,52 +99,49 @@ public:
 
     /// Return physics world.
     PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }
+
     /// Return Bullet constraint.
     btTypedConstraint* GetConstraint() const { return constraint_.Get(); }
+
     /// Return constraint type.
     ConstraintType GetConstraintType() const { return constraintType_; }
+
     /// Return rigid body in own scene node.
     RigidBody* GetOwnBody() const { return ownBody_; }
+
     /// Return the other rigid body. May be null if connected to the static world.
     RigidBody* GetOtherBody() const { return otherBody_; }
-    /// Return the other rigid body node ID.
-    unsigned GetOtherBodyNodeID() const { return otherBodyNodeID_; }
+
     /// Return constraint position relative to own body.
     const Vector3& GetPosition() const { return position_; }
+
     /// Return constraint rotation relative to own body.
     const Quaternion& GetRotation() const { return rotation_; }
+
     /// Return constraint position relative to other body.
     const Vector3& GetOtherPosition() const { return otherPosition_; }
+
     /// Return constraint rotation relative to other body.
     const Quaternion& GetOtherRotation() const { return otherRotation_; }
+
     /// Return constraint world position, calculated from own body.
     Vector3 GetWorldPosition() const;
+
     /// Return high limit.
     const Vector2& GetHighLimit() const { return highLimit_; }
+
     /// Return low limit.
     const Vector2& GetLowLimit() const { return lowLimit_; }
+
     /// Return constraint error reduction parameter.
     float GetERP() const { return erp_; }
+
     /// Return constraint force mixing parameter.
     float GetCFM() const { return cfm_; }
+
     /// Return whether collisions between connected bodies are disabled.
     bool GetDisableCollision() const { return disableCollision_; }
 
-    /// Set constraint type attribute.
-    void SetConstraintTypeAttr(ConstraintType type);
-    /// Set position attribute.
-    void SetPositionAttr(const Vector3& position);
-    /// Set rotation attribute.
-    void SetRotationAttr(const Quaternion& rotation);
-    /// Set other body position attribute.
-    void SetOtherPositionAttr(const Vector3& position);
-    /// Set other body rotation attribute.
-    void SetOtherRotationAttr(const Quaternion& rotation);
-    /// Set other body node ID attribute.
-    void SetOtherBodyNodeIDAttr(unsigned nodeID);
-    /// Set disable collision attribute.
-    void SetDisableCollitionAttr(bool value);
-
     /// Release the constraint.
     void ReleaseConstraint();
     /// Apply constraint frames.

+ 16 - 43
Source/Urho3D/Physics/RigidBody.cpp

@@ -98,7 +98,7 @@ void RigidBody::RegisterObject(Context* context)
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Physics Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE | AM_NOEDIT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Physics Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE | AM_NOEDIT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Mass", GetMass, SetMassAttr, float, DEFAULT_MASS, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Mass", float, mass_, DEFAULT_MASS, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Friction", GetFriction, SetFriction, float, DEFAULT_FRICTION, AM_DEFAULT);
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Anisotropic Friction", GetAnisotropicFriction, SetAnisotropicFriction, Vector3, Vector3::ONE,
         AM_DEFAULT);
@@ -113,21 +113,30 @@ void RigidBody::RegisterObject(Context* context)
     URHO3D_ACCESSOR_ATTRIBUTE("Angular Damping", GetAngularDamping, SetAngularDamping, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.8f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Angular Rest Threshold", GetAngularRestThreshold, SetAngularRestThreshold, float, 1.0f, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Collision Layer", GetCollisionLayer, SetCollisionLayerAttr, unsigned, DEFAULT_COLLISION_LAYER, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Collision Mask", GetCollisionMask, SetCollisionMaskAttr, unsigned, DEFAULT_COLLISION_MASK, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Collision Layer", int, collisionLayer_, DEFAULT_COLLISION_LAYER, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Collision Mask", int, collisionMask_, DEFAULT_COLLISION_MASK, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Contact Threshold", GetContactProcessingThreshold, SetContactProcessingThreshold, float, BT_LARGE_FLOAT,
         AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("CCD Radius", GetCcdRadius, SetCcdRadius, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("CCD Motion Threshold", GetCcdMotionThreshold, SetCcdMotionThreshold, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Network Angular Velocity", GetNetAngularVelocityAttr, SetNetAngularVelocityAttr, PODVector<unsigned char>,
         Variant::emptyBuffer, AM_NET | AM_LATESTDATA | AM_NOEDIT);
-    URHO3D_ENUM_ACCESSOR_ATTRIBUTE("Collision Event Mode", GetCollisionEventMode, SetCollisionEventModeAttr, CollisionEventMode, collisionEventModeNames, COLLISION_ACTIVE, AM_DEFAULT);
+    URHO3D_ENUM_ATTRIBUTE("Collision Event Mode", collisionEventMode_, collisionEventModeNames, COLLISION_ACTIVE, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Use Gravity", GetUseGravity, SetUseGravity, bool, true, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Is Kinematic", IsKinematic, SetKinematicAttr, bool, false, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Is Trigger", IsTrigger, SetTriggerAttr, bool, false, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Is Kinematic", bool, kinematic_, false, AM_DEFAULT);
+    URHO3D_ATTRIBUTE("Is Trigger", bool, trigger_, false, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Gravity Override", GetGravityOverride, SetGravityOverride, Vector3, Vector3::ZERO, AM_DEFAULT);
 }
 
+void RigidBody::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    // Change of any non-accessor attribute requires the rigid body to be re-added to the physics world
+    if (!attr.accessor_)
+        readdBody_ = true;
+}
+
 void RigidBody::ApplyAttributes()
 {
     if (readdBody_)
@@ -261,7 +270,7 @@ void RigidBody::SetRotation(const Quaternion& rotation)
                 interpTrans.setOrigin(worldTrans.getOrigin());
             body_->setInterpolationWorldTransform(interpTrans);
         }
-
+        
         body_->updateInertiaTensor();
 
         Activate();
@@ -842,24 +851,6 @@ void RigidBody::UpdateGravity()
     }
 }
 
-void RigidBody::SetMassAttr(float mass)
-{
-    mass_ = mass;
-    readdBody_ = true;
-}
-
-void RigidBody::SetCollisionLayerAttr(unsigned layer)
-{
-    collisionLayer_ = layer;
-    readdBody_ = true;
-}
-
-void RigidBody::SetCollisionMaskAttr(unsigned mask)
-{
-    collisionMask_ = mask;
-    readdBody_ = true;
-}
-
 void RigidBody::SetNetAngularVelocityAttr(const PODVector<unsigned char>& value)
 {
     float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
@@ -867,24 +858,6 @@ void RigidBody::SetNetAngularVelocityAttr(const PODVector<unsigned char>& value)
     SetAngularVelocity(buf.ReadPackedVector3(maxVelocity));
 }
 
-void RigidBody::SetCollisionEventModeAttr(CollisionEventMode mode)
-{
-    collisionEventMode_ = mode;
-    readdBody_ = true;
-}
-
-void RigidBody::SetKinematicAttr(bool value)
-{
-    kinematic_ = value;
-    readdBody_ = true;
-}
-
-void RigidBody::SetTriggerAttr(bool value)
-{
-    trigger_ = value;
-    readdBody_ = true;
-}
-
 const PODVector<unsigned char>& RigidBody::GetNetAngularVelocityAttr() const
 {
     float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;

+ 15 - 12
Source/Urho3D/Physics/RigidBody.h

@@ -59,6 +59,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
     /// Handle enabled/disabled state change.
@@ -149,12 +151,16 @@ public:
 
     /// Return physics world.
     PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }
+
     /// Return Bullet rigid body.
     btRigidBody* GetBody() const { return body_.Get(); }
+
     /// Return Bullet compound collision shape.
     btCompoundShape* GetCompoundShape() const { return compoundShape_.Get(); }
+
     /// Return mass.
     float GetMass() const { return mass_; }
+
     /// Return rigid body position in world space.
     Vector3 GetPosition() const;
     /// Return rigid body rotation in world space.
@@ -191,22 +197,31 @@ public:
     float GetCcdRadius() const;
     /// Return continuous collision detection motion-per-simulation-step threshold.
     float GetCcdMotionThreshold() const;
+
     /// Return whether rigid body uses gravity.
     bool GetUseGravity() const { return useGravity_; }
+
     /// Return gravity override. If zero (default), uses the physics world's gravity.
     const Vector3& GetGravityOverride() const { return gravityOverride_; }
+
     /// Return center of mass offset.
     const Vector3& GetCenterOfMass() const { return centerOfMass_; }
+
     /// Return kinematic mode flag.
     bool IsKinematic() const { return kinematic_; }
+
     /// Return whether this RigidBody is acting as a trigger.
     bool IsTrigger() const { return trigger_; }
+
     /// Return whether rigid body is active (not sleeping.)
     bool IsActive() const;
+
     /// Return collision layer.
     unsigned GetCollisionLayer() const { return collisionLayer_; }
+
     /// Return collision mask.
     unsigned GetCollisionMask() const { return collisionMask_; }
+
     /// Return collision event signaling mode.
     CollisionEventMode GetCollisionEventMode() const { return collisionEventMode_; }
 
@@ -219,20 +234,8 @@ public:
     void UpdateMass();
     /// Update gravity parameters to the Bullet rigid body.
     void UpdateGravity();
-    /// Set mass attribute.
-    void SetMassAttr(float mass);
-    /// Set collision layer attribute.
-    void SetCollisionLayerAttr(unsigned layer);
-    /// Set collision mask attribute.
-    void SetCollisionMaskAttr(unsigned mask);
     /// Set network angular velocity attribute.
     void SetNetAngularVelocityAttr(const PODVector<unsigned char>& value);
-    /// Set collision event signaling mode attribute.
-    void SetCollisionEventModeAttr(CollisionEventMode mode);
-    /// Set rigid body kinematic mode attribute.
-    void SetKinematicAttr(bool value);
-    /// Set rigid body trigger mode attribute.
-    void SetTriggerAttr(bool value);
     /// Return network angular velocity attribute.
     const PODVector<unsigned char>& GetNetAngularVelocityAttr() const;
     /// Add a constraint that refers to this rigid body.

+ 9 - 8
Source/Urho3D/Urho2D/Constraint2D.cpp

@@ -55,7 +55,15 @@ Constraint2D::~Constraint2D()
 void Constraint2D::RegisterObject(Context* context)
 {
     URHO3D_ACCESSOR_ATTRIBUTE("Collide Connected", GetCollideConnected, SetCollideConnected, bool, false, AM_DEFAULT);
-    URHO3D_ACCESSOR_ATTRIBUTE("Other Body NodeID", GetOtherBodyNodeID, SetOtherBodyNodeIDAttr, unsigned, 0, AM_DEFAULT | AM_NODEID);
+    URHO3D_ATTRIBUTE("Other Body NodeID", unsigned, otherBodyNodeID_, 0, AM_DEFAULT | AM_NODEID);
+}
+
+void Constraint2D::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    if (!attr.accessor_ && attr.offset_ == offsetof(Constraint2D, otherBodyNodeID_))
+        otherBodyNodeIDDirty_ = true;
 }
 
 void Constraint2D::ApplyAttributes()
@@ -132,13 +140,6 @@ void Constraint2D::SetOtherBody(RigidBody2D* body)
     MarkNetworkUpdate();
 }
 
-void Constraint2D::SetOtherBodyNodeIDAttr(unsigned nodeID)
-{
-    otherBodyNodeID_ = nodeID;
-    otherBodyNodeIDDirty_ = true;
-    MarkNetworkUpdate();
-}
-
 void Constraint2D::SetCollideConnected(bool collideConnected)
 {
     if (collideConnected == collideConnected_)

+ 7 - 5
Source/Urho3D/Urho2D/Constraint2D.h

@@ -45,6 +45,8 @@ public:
     /// Register object factory.
     static void RegisterObject(Context* context);
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
     /// Handle enabled/disabled state change.
@@ -56,23 +58,23 @@ public:
 
     /// Set other rigid body.
     void SetOtherBody(RigidBody2D* body);
-    /// Set other rigid body node ID.
-    void SetOtherBodyNodeIDAttr(unsigned nodeID);
     /// Set collide connected.
     void SetCollideConnected(bool collideConnected);
-    /// Set attached constraint (for gear).
+    /// Set attached constriant (for gear).
     void SetAttachedConstraint(Constraint2D* constraint);
 
     /// Return owner body.
     RigidBody2D* GetOwnerBody() const { return ownerBody_; }
+
     /// Return other body.
     RigidBody2D* GetOtherBody() const { return otherBody_; }
-    /// Return other body node ID.
-    unsigned GetOtherBodyNodeID() const { return otherBodyNodeID_; }
+
     /// Return collide connected.
     bool GetCollideConnected() const { return collideConnected_; }
+
     /// Return attached constraint (for gear).
     Constraint2D* GetAttachedConstraint() const { return attachedConstraint_; }
+
     /// Return Box2D joint.
     b2Joint* GetJoint() const { return joint_; }