Browse Source

Optimization: DecalSet & ScriptInstance unsubscribe from scene update when disabled.

Lasse Öörni 12 years ago
parent
commit
1930041147

+ 49 - 20
Engine/Graphics/DecalSet.cpp

@@ -196,6 +196,13 @@ void DecalSet::ApplyAttributes()
         AssignBoneNodes();
 }
 
+void DecalSet::OnSetEnabled()
+{
+    Drawable::OnSetEnabled();
+    
+    UpdateEventSubscription(true);
+}
+
 void DecalSet::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     // Do not return raycast hits
@@ -444,20 +451,16 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
     numVertices_ += newDecal.vertices_.Size();
     numIndices_ += newDecal.indices_.Size();
     
-    // Subscribe to scene post-update if defined a time-limited decal
-    Scene* scene = GetScene();
-    if (!subscribed_ && newDecal.timeToLive_ > 0.0f && scene)
-    {
-        SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(DecalSet, HandleScenePostUpdate));
-        subscribed_ = true;
-    }
-    
     // Remove oldest decals if total vertices exceeded
     while (decals_.Size() && (numVertices_ > maxVertices_ || numIndices_ > maxIndices_))
         RemoveDecals(1);
     
     LOGDEBUG("Added decal with " + String(newDecal.vertices_.Size()) + " vertices");
     
+    // If new decal is time limited, subscribe to scene post-update
+    if (newDecal.timeToLive_ > 0.0f && !subscribed_)
+        UpdateEventSubscription(false);
+    
     MarkDecalsDirty();
     return true;
 }
@@ -510,8 +513,6 @@ void DecalSet::SetDecalsAttr(VariantVector value)
     
     skinned_ = value[index++].GetBool();
     unsigned numDecals = value[index++].GetInt();
-
-    bool hasTimeLimitedDecal = false;
     
     while (numDecals--)
     {
@@ -545,16 +546,6 @@ void DecalSet::SetDecalsAttr(VariantVector value)
         newDecal.CalculateBoundingBox();
         numVertices_ += newDecal.vertices_.Size();
         numIndices_ += newDecal.indices_.Size();
-        
-        if (!hasTimeLimitedDecal && newDecal.timeToLive_ > 0.0f)
-            hasTimeLimitedDecal = true;
-    }
-
-    // Subscribe to scene post-update if defined a time-limited decal
-    if (!subscribed_ && hasTimeLimitedDecal && scene)
-    {
-        SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(DecalSet, HandleScenePostUpdate));
-        subscribed_ = true;
     }
     
     if (skinned_)
@@ -582,6 +573,7 @@ void DecalSet::SetDecalsAttr(VariantVector value)
         skinningDirty_ = true;
     }
     
+    UpdateEventSubscription(true);
     UpdateBatch();
     MarkDecalsDirty();
     bufferSizeDirty_ = true;
@@ -1123,6 +1115,43 @@ void DecalSet::AssignBoneNodes()
     }
 }
 
+void DecalSet::UpdateEventSubscription(bool checkAllDecals)
+{
+    Scene* scene = GetScene();
+    if (!scene)
+        return;
+    
+    bool enabled = IsEnabledEffective();
+    
+    if (enabled && checkAllDecals)
+    {
+        bool hasTimeLimitedDecals = false;
+        
+        for (List<Decal>::ConstIterator i = decals_.Begin(); i != decals_.End(); ++i)
+        {
+            if (i->timeToLive_ > 0.0f)
+            {
+                hasTimeLimitedDecals = true;
+                break;
+            }
+        }
+        
+        // If no time limited decals, no need to subscribe to scene update
+        enabled = hasTimeLimitedDecals;
+    }
+    
+    if (enabled && !subscribed_)
+    {
+        SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(DecalSet, HandleScenePostUpdate));
+        subscribed_ = true;
+    }
+    else if (!enabled && subscribed_)
+    {
+        UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
+        subscribed_ = false;
+    }
+}
+
 void DecalSet::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
 {
     using namespace ScenePostUpdate;

+ 4 - 0
Engine/Graphics/DecalSet.h

@@ -113,6 +113,8 @@ public:
     
     /// 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.
+    virtual void OnSetEnabled();
     /// 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.
@@ -190,6 +192,8 @@ private:
     void UpdateBatch();
     /// Find bones after loading.
     void AssignBoneNodes();
+    /// Subscribe/unsubscribe from scene post-update as necessary.
+    void UpdateEventSubscription(bool checkAllDecals);
     /// Handle scene post-update event.
     void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
     

+ 1 - 1
Engine/Input/Input.h

@@ -237,7 +237,7 @@ private:
     bool inputFocus_;
     /// Minimized flag.
     bool minimized_;
-    /// Gained focus on this frame -flag.
+    /// Gained focus on this frame flag.
     bool focusedThisFrame_;
     /// Next mouse move suppress flag.
     bool suppressNextMouseMove_;

+ 75 - 32
Engine/Script/ScriptInstance.cpp

@@ -63,11 +63,12 @@ ScriptInstance::ScriptInstance(Context* context) :
     Component(context),
     script_(GetSubsystem<Script>()),
     scriptObject_(0),
-    subscribed_(false),
     fixedUpdateFps_(0),
     fixedUpdateInterval_(0.0f),
     fixedUpdateAcc_(0.0f),
-    fixedPostUpdateAcc_(0.0f)
+    fixedPostUpdateAcc_(0.0f),
+    subscribed_(false),
+    subscribedPostFixed_(false)
 {
     ClearScriptMethods();
     ClearScriptAttributes();
@@ -98,6 +99,11 @@ void ScriptInstance::ApplyAttributes()
         scriptFile_->Execute(scriptObject_, methods_[METHOD_APPLYATTRIBUTES]);
 }
 
+void ScriptInstance::OnSetEnabled()
+{
+    UpdateEventSubscription();
+}
+
 bool ScriptInstance::CreateObject(ScriptFile* scriptFile, const String& className)
 {
     className_ = String::EMPTY; // Do not create object during SetScriptFile()
@@ -183,10 +189,7 @@ void ScriptInstance::DelayedExecute(float delay, bool repeat, const String& decl
     
     // Make sure we are registered to the scene update event, because delayed calls are executed there
     if (!subscribed_)
-    {
-        SubscribeToEvent(GetScene(), E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
-        subscribed_ = true;
-    }
+        UpdateEventSubscription();
 }
 
 void ScriptInstance::ClearDelayedExecute(const String& declaration)
@@ -271,6 +274,9 @@ void ScriptInstance::SetDelayedMethodCallsAttr(PODVector<unsigned char> value)
         i->declaration_ = buf.ReadString();
         i->parameters_ = buf.ReadVariantVector();
     }
+    
+    if (delayedMethodCalls_.Size() && !subscribed_)
+        UpdateEventSubscription();
 }
 
 void ScriptInstance::SetFixedUpdateAccAttr(float value)
@@ -371,6 +377,7 @@ void ScriptInstance::CreateObject()
         ClearDelayedExecute();
         GetScriptMethods();
         GetScriptAttributes();
+        UpdateEventSubscription();
         
         if (methods_[METHOD_START])
             scriptFile_->Execute(scriptObject_, methods_[METHOD_START]);
@@ -391,6 +398,7 @@ void ScriptInstance::ReleaseObject()
         exceptions.Push(E_RELOADFINISHED);
         UnsubscribeFromAllEventsExcept(exceptions, false);
         subscribed_ = false;
+        subscribedPostFixed_ = false;
         
         ClearScriptMethods();
         ClearScriptAttributes();
@@ -418,28 +426,6 @@ void ScriptInstance::GetScriptMethods()
 {
     for (unsigned i = 0; i < MAX_SCRIPT_METHODS; ++i)
         methods_[i] = scriptFile_->GetMethod(scriptObject_, methodDeclarations[i]);
-    
-    // Subscribe to the update events as supported
-    Scene* scene = GetScene();
-    if (scene)
-    {
-        if (methods_[METHOD_UPDATE] || methods_[METHOD_DELAYEDSTART])
-        {
-            SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
-            subscribed_ = true;
-        }
-        if (methods_[METHOD_POSTUPDATE])
-            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
-        
-        PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
-        if (world)
-        {
-            if (methods_[METHOD_FIXEDUPDATE])
-                SubscribeToEvent(world, E_PHYSICSPRESTEP, HANDLER(ScriptInstance, HandlePhysicsPreStep));
-            if (methods_[METHOD_FIXEDPOSTUPDATE])
-                SubscribeToEvent(world, E_PHYSICSPOSTSTEP, HANDLER(ScriptInstance, HandlePhysicsPostStep));
-        }
-    }
 }
 
 void ScriptInstance::GetScriptAttributes()
@@ -488,9 +474,66 @@ void ScriptInstance::GetScriptAttributes()
     }
 }
 
+void ScriptInstance::UpdateEventSubscription()
+{
+    Scene* scene = GetScene();
+    if (!scene)
+        return;
+    
+    bool enabled = scriptObject_ && IsEnabledEffective();
+    
+    if (enabled)
+    {
+        if (!subscribed_ && (methods_[METHOD_UPDATE] || methods_[METHOD_DELAYEDSTART] || delayedMethodCalls_.Size()))
+        {
+            SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
+            subscribed_ = true;
+        }
+        
+        if (!subscribedPostFixed_)
+        {
+            if (methods_[METHOD_POSTUPDATE])
+                SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
+            
+            PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
+            if (world)
+            {
+                if (methods_[METHOD_FIXEDUPDATE])
+                    SubscribeToEvent(world, E_PHYSICSPRESTEP, HANDLER(ScriptInstance, HandlePhysicsPreStep));
+                if (methods_[METHOD_FIXEDPOSTUPDATE])
+                    SubscribeToEvent(world, E_PHYSICSPOSTSTEP, HANDLER(ScriptInstance, HandlePhysicsPostStep));
+            }
+            
+            subscribedPostFixed_ = true;
+        }
+    }
+    else
+    {
+        if (subscribed_)
+        {
+            UnsubscribeFromEvent(scene, E_SCENEUPDATE);
+            subscribed_ = false;
+        }
+        
+        if (subscribedPostFixed_)
+        {
+            UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
+            
+            PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
+            if (world)
+            {
+                UnsubscribeFromEvent(world, E_PHYSICSPRESTEP);
+                UnsubscribeFromEvent(world, E_PHYSICSPOSTSTEP);
+            }
+            
+            subscribedPostFixed_ = false;
+        }
+    }
+}
+
 void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
 {
-    if (!IsEnabledEffective() || !scriptObject_)
+    if (!scriptObject_)
         return;
     
     using namespace SceneUpdate;
@@ -537,7 +580,7 @@ void ScriptInstance::HandleSceneUpdate(StringHash eventType, VariantMap& eventDa
 
 void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
 {
-    if (!IsEnabledEffective() || !scriptObject_)
+    if (!scriptObject_)
         return;
     
     using namespace ScenePostUpdate;
@@ -549,7 +592,7 @@ void ScriptInstance::HandleScenePostUpdate(StringHash eventType, VariantMap& eve
 
 void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& eventData)
 {
-    if (!IsEnabledEffective() || !scriptObject_)
+    if (!scriptObject_)
         return;
     
     using namespace PhysicsPreStep;
@@ -576,7 +619,7 @@ void ScriptInstance::HandlePhysicsPreStep(StringHash eventType, VariantMap& even
 
 void ScriptInstance::HandlePhysicsPostStep(StringHash eventType, VariantMap& eventData)
 {
-    if (!IsEnabledEffective() || !scriptObject_)
+    if (!scriptObject_)
         return;
     
     using namespace PhysicsPostStep;

+ 8 - 2
Engine/Script/ScriptInstance.h

@@ -84,6 +84,8 @@ public:
     virtual const Vector<AttributeInfo>* GetAttributes() const { return &attributeInfos_; }
     /// 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.
+    virtual void OnSetEnabled();
     /// Add an event handler. Called by script exposed version of SubscribeToEvent().
     virtual void AddEventHandler(StringHash eventType, const String& handlerName);
     /// Add an event handler for a specific sender. Called by script exposed version of SubscribeToEvent().
@@ -149,6 +151,8 @@ private:
     void ClearScriptMethods();
     /// Clear attributes to C++ side attributes only.
     void ClearScriptAttributes();
+    /// Subscribe/unsubscribe from scene updates as necessary.
+    void UpdateEventSubscription();
     /// Handle scene update event.
     void HandleSceneUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle scene post-update event.
@@ -174,8 +178,6 @@ private:
     String className_;
     /// Pointers to supported inbuilt methods.
     asIScriptFunction* methods_[MAX_SCRIPT_METHODS];
-    /// Subscribed to scene update event flag.
-    bool subscribed_;
     /// Fixed update FPS.
     int fixedUpdateFps_;
     /// Fixed update time interval.
@@ -188,6 +190,10 @@ private:
     Vector<DelayedMethodCall> delayedMethodCalls_;
     /// Attributes, including script object variables.
     Vector<AttributeInfo> attributeInfos_;
+    /// Subscribed to scene update events flag.
+    bool subscribed_;
+    /// Subscribed to scene post and fixed update events flag.
+    bool subscribedPostFixed_;
 };
 
 /// Return the Urho3D context of the active script context.