فهرست منبع

Draw Pipeline & PhysicsWorld debug geometry automatically if enabled.

Lasse Öörni 15 سال پیش
والد
کامیت
4a18fd3dff

+ 4 - 12
Bin/Data/Scripts/GraphicsTest.as

@@ -495,7 +495,10 @@ void handleUpdate(StringHash eventType, VariantMap& eventData)
         if (input.getKeyPress(' '))
         if (input.getKeyPress(' '))
         {
         {
             drawdebug++;
             drawdebug++;
-            if (drawdebug > 2) drawdebug = 0;
+            if (drawdebug > 2) 
+                drawdebug = 0;                        
+            pipeline.setDrawDebugGeometry(drawdebug == 1);
+            testScene.getPhysicsWorld().setDrawDebugGeometry(drawdebug == 2);
         }
         }
 
 
         if (input.getKeyPress('P'))
         if (input.getKeyPress('P'))
@@ -611,15 +614,4 @@ void handlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
                 Vector3(0.01, 0.01, 0.01)), Color(1.0, 1.0, 1.0), true);
                 Vector3(0.01, 0.01, 0.01)), Color(1.0, 1.0, 1.0), true);
         }
         }
     }
     }
-    
-    // Draw either renderer or physics debug geometry
-    switch (drawdebug)
-    {
-    case 1:
-        pipeline.drawDebugGeometry();
-        break;
-    case 2:
-        testScene.getPhysicsWorld().drawDebugGeometry();
-        break;
-    }
 }
 }

+ 4 - 5
Bin/Data/Scripts/NinjaSnowWar.as

@@ -30,7 +30,6 @@ BorderImage@ sight;
 Controls playerControls;
 Controls playerControls;
 Controls prevPlayerControls;
 Controls prevPlayerControls;
 bool gameOn = false;
 bool gameOn = false;
-bool drawDebug = false;
 int score = 0;
 int score = 0;
 int hiscore = 0;
 int hiscore = 0;
 int maxEnemies = 0;
 int maxEnemies = 0;
@@ -199,7 +198,10 @@ void handleUpdate(StringHash eventType, VariantMap& eventData)
     if (input.getKeyPress(KEY_F1))
     if (input.getKeyPress(KEY_F1))
         debugHud.toggleAll();
         debugHud.toggleAll();
     if (input.getKeyPress(KEY_F2))
     if (input.getKeyPress(KEY_F2))
-        drawDebug = !drawDebug;
+    {
+        PhysicsWorld@ world = gameScene.getPhysicsWorld();
+        world.setDrawDebugGeometry(!world.getDrawDebugGeometry());
+    }
 
 
     if ((!console.isVisible()) && (input.getKeyPress('P')) && (gameOn))
     if ((!console.isVisible()) && (input.getKeyPress('P')) && (gameOn))
     {
     {
@@ -235,9 +237,6 @@ void handlePostUpdate(StringHash eventType, VariantMap& eventData)
 {
 {
     updateCamera();
     updateCamera();
     updateStatus();
     updateStatus();
-    
-    if (drawDebug)
-        gameScene.getPhysicsWorld().drawDebugGeometry();
 }
 }
 
 
 void handlePoints(StringHash eventType, VariantMap& eventData)
 void handlePoints(StringHash eventType, VariantMap& eventData)

+ 0 - 1
Engine/Engine/Engine.cpp

@@ -34,7 +34,6 @@
 #include "DebugRenderer.h"
 #include "DebugRenderer.h"
 #include "Engine.h"
 #include "Engine.h"
 #include "EngineComponentFactory.h"
 #include "EngineComponentFactory.h"
-#include "EngineEvents.h"
 #include "Input.h"
 #include "Input.h"
 #include "Log.h"
 #include "Log.h"
 #include "Network.h"
 #include "Network.h"

+ 0 - 47
Engine/Engine/EngineEvents.h

@@ -1,47 +0,0 @@
-//
-// Urho3D Engine
-// Copyright (c) 2008-2011 Lasse Öörni
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#ifndef ENGINE_ENGINEEVENTS_H
-#define ENGINE_ENGINEEVENTS_H
-
-#include "Event.h"
-
-//! Application-wide update
-DEFINE_EVENT(EVENT_UPDATE, Update)
-{
-    EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
-}
-
-//! Application-wide post-update
-DEFINE_EVENT(EVENT_POSTUPDATE, PostUpdate)
-{
-    EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
-}
-
-//! Post-rendering update
-DEFINE_EVENT(EVENT_POSTRENDERUPDATE, PostRenderUpdate)
-{
-    EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
-}
-
-#endif // ENGINE_ENGINEEVENTS_H

+ 4 - 1
Engine/Engine/RegisterPhysics.cpp

@@ -87,8 +87,9 @@ static void registerPhysicsWorld(asIScriptEngine* engine)
     engine->RegisterObjectMethod("PhysicsWorld", "void setERP(float)", asMETHOD(PhysicsWorld, setERP), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "void setERP(float)", asMETHOD(PhysicsWorld, setERP), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "void setCFM(float)", asMETHOD(PhysicsWorld, setCFM), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "void setCFM(float)", asMETHOD(PhysicsWorld, setCFM), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "void setContactSurfaceLayer(float)", asMETHOD(PhysicsWorld, setContactSurfaceLayer), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "void setContactSurfaceLayer(float)", asMETHOD(PhysicsWorld, setContactSurfaceLayer), asCALL_THISCALL);
+    engine->RegisterObjectMethod("PhysicsWorld", "void setRandomSeed(uint)", asMETHOD(PhysicsWorld, setRandomSeed), asCALL_THISCALL);
+    engine->RegisterObjectMethod("PhysicsWorld", "void setDrawDebugGeometry(bool)", asMETHOD(PhysicsWorld, setDrawDebugGeometry), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "array<PhysicsRaycastResult>@ raycast(const Ray& in, float, uint)", asFUNCTION(PhysicsWorldRaycast), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("PhysicsWorld", "array<PhysicsRaycastResult>@ raycast(const Ray& in, float, uint)", asFUNCTION(PhysicsWorldRaycast), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("PhysicsWorld", "void drawDebugGeometry()", asMETHOD(PhysicsWorld, drawDebugGeometry), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "Vector3 getGravity() const", asMETHOD(PhysicsWorld, getGravity), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "Vector3 getGravity() const", asMETHOD(PhysicsWorld, getGravity), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "int getFps() const", asMETHOD(PhysicsWorld, getFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "int getFps() const", asMETHOD(PhysicsWorld, getFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "uint getMaxContacts() const", asMETHOD(PhysicsWorld, getMaxContacts), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "uint getMaxContacts() const", asMETHOD(PhysicsWorld, getMaxContacts), asCALL_THISCALL);
@@ -103,6 +104,8 @@ static void registerPhysicsWorld(asIScriptEngine* engine)
     engine->RegisterObjectMethod("PhysicsWorld", "float getERP() const", asMETHOD(PhysicsWorld, getERP), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "float getERP() const", asMETHOD(PhysicsWorld, getERP), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "float getCFM() const", asMETHOD(PhysicsWorld, getCFM), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "float getCFM() const", asMETHOD(PhysicsWorld, getCFM), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "float getContactSurfaceLayer() const", asMETHOD(PhysicsWorld, getContactSurfaceLayer), asCALL_THISCALL);
     engine->RegisterObjectMethod("PhysicsWorld", "float getContactSurfaceLayer() const", asMETHOD(PhysicsWorld, getContactSurfaceLayer), asCALL_THISCALL);
+    engine->RegisterObjectMethod("PhysicsWorld", "uint getRandomSeed() const", asMETHOD(PhysicsWorld, getRandomSeed), asCALL_THISCALL);
+    engine->RegisterObjectMethod("PhysicsWorld", "bool getDrawDebugGeometry() const", asMETHOD(PhysicsWorld, getDrawDebugGeometry), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "PhysicsWorld@+ getPhysicsWorld() const", asFUNCTION(SceneGetPhysicsWorld), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Scene", "PhysicsWorld@+ getPhysicsWorld() const", asFUNCTION(SceneGetPhysicsWorld), asCALL_CDECL_OBJLAST);
     registerRefCasts<EventListener, PhysicsWorld>(engine, "EventListener", "PhysicsWorld");
     registerRefCasts<EventListener, PhysicsWorld>(engine, "EventListener", "PhysicsWorld");
     
     

+ 2 - 1
Engine/Engine/RegisterRenderer.cpp

@@ -819,7 +819,7 @@ static void registerPipeline(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Pipeline", "void setOcclusionBufferSize(int)", asMETHOD(Pipeline, setOcclusionBufferSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "void setOcclusionBufferSize(int)", asMETHOD(Pipeline, setOcclusionBufferSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "void setOccluderSizeThreshold(float)", asMETHOD(Pipeline, setOccluderSizeThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "void setOccluderSizeThreshold(float)", asMETHOD(Pipeline, setOccluderSizeThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "void setEdgeFilter(const EdgeFilterParameters& in)", asMETHOD(Pipeline, setEdgeFilter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "void setEdgeFilter(const EdgeFilterParameters& in)", asMETHOD(Pipeline, setEdgeFilter), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Pipeline", "void drawDebugGeometry()", asMETHOD(Pipeline, drawDebugGeometry), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pipeline", "void setDrawDebugGeometry(bool)", asMETHOD(Pipeline, setDrawDebugGeometry), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumViewports() const", asMETHOD(Pipeline, getNumViewports), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumViewports() const", asMETHOD(Pipeline, getNumViewports), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "Scene@+ getViewportScene(uint) const", asMETHOD(Pipeline, getViewportScene), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "Scene@+ getViewportScene(uint) const", asMETHOD(Pipeline, getViewportScene), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "Camera@+ getViewportCamera(uint) const", asMETHOD(Pipeline, getViewportCamera), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "Camera@+ getViewportCamera(uint) const", asMETHOD(Pipeline, getViewportCamera), asCALL_THISCALL);
@@ -838,6 +838,7 @@ static void registerPipeline(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Pipeline", "int getOcclusionBufferSize() const", asMETHOD(Pipeline, getOcclusionBufferSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "int getOcclusionBufferSize() const", asMETHOD(Pipeline, getOcclusionBufferSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "float getOccluderSizeThreshold() const", asMETHOD(Pipeline, getOccluderSizeThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "float getOccluderSizeThreshold() const", asMETHOD(Pipeline, getOccluderSizeThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "const EdgeFilterParameters& getEdgeFilter() const", asMETHOD(Pipeline, getEdgeFilter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "const EdgeFilterParameters& getEdgeFilter() const", asMETHOD(Pipeline, getEdgeFilter), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pipeline", "bool getDrawDebugGeometry() const", asMETHOD(Pipeline, getDrawDebugGeometry), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumViews() const", asMETHOD(Pipeline, getNumViews), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumViews() const", asMETHOD(Pipeline, getNumViews), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumGeometries(bool) const", asMETHOD(Pipeline, getNumGeometries), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumGeometries(bool) const", asMETHOD(Pipeline, getNumGeometries), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumLights(bool) const", asMETHOD(Pipeline, getNumLights), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pipeline", "uint getNumLights(bool) const", asMETHOD(Pipeline, getNumLights), asCALL_THISCALL);

+ 27 - 13
Engine/Physics/PhysicsWorld.cpp

@@ -31,6 +31,7 @@
 #include "Ray.h"
 #include "Ray.h"
 #include "RigidBody.h"
 #include "RigidBody.h"
 #include "Scene.h"
 #include "Scene.h"
+#include "SceneEvents.h"
 #include "StringUtils.h"
 #include "StringUtils.h"
 #include "VectorBuffer.h"
 #include "VectorBuffer.h"
 #include "XMLElement.h"
 #include "XMLElement.h"
@@ -57,7 +58,7 @@ PhysicsWorld::PhysicsWorld() :
     mBounceThreshold(0.1f),
     mBounceThreshold(0.1f),
     mAngularMaxNetVelocity(256.0f),
     mAngularMaxNetVelocity(256.0f),
     mTimeAcc(0.0f),
     mTimeAcc(0.0f),
-    mDebugDraw(false)
+    mDrawDebugGeometry(false)
 {
 {
     if (!numWorlds)
     if (!numWorlds)
         dInitODE();
         dInitODE();
@@ -72,6 +73,8 @@ PhysicsWorld::PhysicsWorld() :
     
     
     // Enable automatic resting of rigid bodies
     // Enable automatic resting of rigid bodies
     dWorldSetAutoDisableFlag(mWorld, 1);
     dWorldSetAutoDisableFlag(mWorld, 1);
+    
+    subscribeToEvent(EVENT_POSTRENDERUPDATE, EVENT_HANDLER(PhysicsWorld, handlePostRenderUpdate));
 }
 }
 
 
 PhysicsWorld::~PhysicsWorld()
 PhysicsWorld::~PhysicsWorld()
@@ -360,6 +363,11 @@ void PhysicsWorld::setRandomSeed(unsigned seed)
     dRandSetSeed(seed);
     dRandSetSeed(seed);
 }
 }
 
 
+void PhysicsWorld::setDrawDebugGeometry(bool enable)
+{
+    mDrawDebugGeometry = enable;
+}
+
 void PhysicsWorld::raycast(std::vector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask)
 void PhysicsWorld::raycast(std::vector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask)
 {
 {
     PROFILE(Physics_Raycast);
     PROFILE(Physics_Raycast);
@@ -373,18 +381,6 @@ void PhysicsWorld::raycast(std::vector<PhysicsRaycastResult>& result, const Ray&
     std::sort(result.begin(), result.end(), compareRaycastResults);
     std::sort(result.begin(), result.end(), compareRaycastResults);
 }
 }
 
 
-void PhysicsWorld::drawDebugGeometry()
-{
-    DebugRenderer* debug = mScene->getExtension<DebugRenderer>();
-    if (!debug)
-        return;
-    
-    PROFILE(Physics_DrawDebugGeometry);
-    
-    for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
-        (*i)->drawDebugGeometry(debug);
-}
-
 unsigned PhysicsWorld::getRandomSeed() const
 unsigned PhysicsWorld::getRandomSeed() const
 {
 {
     return dRandGetSeed();
     return dRandGetSeed();
@@ -528,6 +524,18 @@ void PhysicsWorld::sendCollisionEvents()
     mCollisionInfos.clear();
     mCollisionInfos.clear();
 }
 }
 
 
+void PhysicsWorld::drawDebugGeometry()
+{
+    DebugRenderer* debug = mScene->getExtension<DebugRenderer>();
+    if (!debug)
+        return;
+    
+    PROFILE(Physics_DrawDebugGeometry);
+    
+    for (std::vector<RigidBody*>::iterator i = mRigidBodies.begin(); i != mRigidBodies.end(); ++i)
+        (*i)->drawDebugGeometry(debug);
+}
+
 void PhysicsWorld::nearCallback(void *userData, dGeomID geomA, dGeomID geomB)
 void PhysicsWorld::nearCallback(void *userData, dGeomID geomA, dGeomID geomB)
 {
 {
     dBodyID bodyA = dGeomGetBody(geomA);
     dBodyID bodyA = dGeomGetBody(geomA);
@@ -683,3 +691,9 @@ void PhysicsWorld::raycastCallback(void *userData, dGeomID geomA, dGeomID geomB)
         result->push_back(newResult);
         result->push_back(newResult);
     }
     }
 }
 }
+
+void PhysicsWorld::handlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
+{
+    if (mDrawDebugGeometry)
+        drawDebugGeometry();
+}

+ 9 - 3
Engine/Physics/PhysicsWorld.h

@@ -138,11 +138,11 @@ public:
     void setTimeAccumulator(float time);
     void setTimeAccumulator(float time);
     //! Set simulation random seed
     //! Set simulation random seed
     void setRandomSeed(unsigned seed);
     void setRandomSeed(unsigned seed);
+    //! Set whether to draw debug geometry
+    void setDrawDebugGeometry(bool enable);
     //! Perform a physics world raycast
     //! Perform a physics world raycast
     void raycast(std::vector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask =
     void raycast(std::vector<PhysicsRaycastResult>& result, const Ray& ray, float maxDistance, unsigned collisionMask =
         M_MAX_UNSIGNED);
         M_MAX_UNSIGNED);
-    //! Add debug geometry to the debug renderer
-    void drawDebugGeometry();
     
     
     //! Return ODE world ID
     //! Return ODE world ID
     dWorldID getWorld() const { return mWorld; }
     dWorldID getWorld() const { return mWorld; }
@@ -180,6 +180,8 @@ public:
     float getTimeAccumulator() const { return mTimeAcc; }
     float getTimeAccumulator() const { return mTimeAcc; }
     //! Return simulation random seed
     //! Return simulation random seed
     unsigned getRandomSeed() const;
     unsigned getRandomSeed() const;
+    //! Return whether to draw debug geometry
+    bool getDrawDebugGeometry() const { return mDrawDebugGeometry; }
     
     
     //! Add a rigid body to keep track of. Called by RigidBody
     //! Add a rigid body to keep track of. Called by RigidBody
     void addRigidBody(RigidBody* body);
     void addRigidBody(RigidBody* body);
@@ -187,12 +189,16 @@ public:
     void removeRigidBody(RigidBody* body);
     void removeRigidBody(RigidBody* body);
     //! Send accumulated collision events
     //! Send accumulated collision events
     void sendCollisionEvents();
     void sendCollisionEvents();
+    //! Add debug geometry to the debug renderer
+    void drawDebugGeometry();
     
     
 private:
 private:
     //! ODE collision callback
     //! ODE collision callback
     static void nearCallback(void *userData, dGeomID geomA, dGeomID geomB);
     static void nearCallback(void *userData, dGeomID geomA, dGeomID geomB);
     //! ODE raycast callback
     //! ODE raycast callback
     static void raycastCallback(void *userData, dGeomID geomA, dGeomID geomB);
     static void raycastCallback(void *userData, dGeomID geomA, dGeomID geomB);
+    //! Handle post render update event. Draw debug geometry here if enabled
+    void handlePostRenderUpdate(StringHash eventType, VariantMap& eventData);
     
     
     //! ODE world ID
     //! ODE world ID
     dWorldID mWorld;
     dWorldID mWorld;
@@ -213,7 +219,7 @@ private:
     //! Simulation step time accumulator
     //! Simulation step time accumulator
     float mTimeAcc;
     float mTimeAcc;
     //! Debug draw flag
     //! Debug draw flag
-    bool mDebugDraw;
+    bool mDrawDebugGeometry;
     //! Rigid bodies
     //! Rigid bodies
     std::vector<RigidBody*> mRigidBodies;
     std::vector<RigidBody*> mRigidBodies;
     //! Collision pairs on this frame
     //! Collision pairs on this frame

+ 61 - 47
Engine/Renderer/Pipeline.cpp

@@ -40,6 +40,7 @@
 #include "RendererImpl.h"
 #include "RendererImpl.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
 #include "Scene.h"
 #include "Scene.h"
+#include "SceneEvents.h"
 #include "StringUtils.h"
 #include "StringUtils.h"
 #include "Texture2D.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "TextureCube.h"
@@ -281,6 +282,7 @@ Pipeline::Pipeline(Renderer* renderer, ResourceCache* cache) :
     mOcclusionBufferSize(256),
     mOcclusionBufferSize(256),
     mOccluderSizeThreshold(0.1f),
     mOccluderSizeThreshold(0.1f),
     mEdgeFilter(EdgeFilterParameters(0.25f, 0.25f, 0.50f, 10.0f)),
     mEdgeFilter(EdgeFilterParameters(0.25f, 0.25f, 0.50f, 10.0f)),
+    mDrawDebugGeometry(false),
     mShadersChangedFrameNumber(M_MAX_UNSIGNED),
     mShadersChangedFrameNumber(M_MAX_UNSIGNED),
     mShadersDirty(true)
     mShadersDirty(true)
 {
 {
@@ -289,8 +291,6 @@ Pipeline::Pipeline(Renderer* renderer, ResourceCache* cache) :
     
     
     LOGINFO("Rendering pipeline created");
     LOGINFO("Rendering pipeline created");
     
     
-    subscribeToEvent(EVENT_WINDOWRESIZED, EVENT_HANDLER(Pipeline, handleWindowResized));
-    
     // Check shader model support
     // Check shader model support
     if (mRenderer->getSM3Support())
     if (mRenderer->getSM3Support())
     {
     {
@@ -317,8 +317,10 @@ Pipeline::Pipeline(Renderer* renderer, ResourceCache* cache) :
         mDrawShadows = false;
         mDrawShadows = false;
     
     
     mViewports.resize(1);
     mViewports.resize(1);
-    
     resetViews();
     resetViews();
+    
+    subscribeToEvent(EVENT_WINDOWRESIZED, EVENT_HANDLER(Pipeline, handleWindowResized));
+    subscribeToEvent(EVENT_POSTRENDERUPDATE, EVENT_HANDLER(Pipeline, handlePostRenderUpdate));
 }
 }
 
 
 Pipeline::~Pipeline()
 Pipeline::~Pipeline()
@@ -458,51 +460,9 @@ void Pipeline::setEdgeFilter(const EdgeFilterParameters& parameters)
     mEdgeFilter = parameters;
     mEdgeFilter = parameters;
 }
 }
 
 
-void Pipeline::drawDebugGeometry()
+void Pipeline::setDrawDebugGeometry(bool enable)
 {
 {
-    PROFILE(Pipeline_DrawDebugGeometry);
-    
-    static std::set<GeometryNode*> processedGeometries;
-    static std::set<Light*> processedLights;
-    processedGeometries.clear();
-    processedLights.clear();
-    
-    for (unsigned i = 0; i < mNumViews; ++i)
-    {
-        // Make sure it's a main view, and process each node only once
-        View* view = mViews[i];
-        if ((!view) || (view->getRenderTarget()))
-            continue;
-        Octree* octree = view->getOctree();
-        if (!octree)
-            continue;
-        Scene* scene = octree->getScene();
-        if (!scene)
-            continue;
-        DebugRenderer* debug = scene->getExtension<DebugRenderer>();
-        if (!debug)
-            continue;
-        
-        const std::vector<GeometryNode*>& geometries = view->getGeometries();
-        const std::vector<Light*>& lights = view->getLights();
-        
-        for (unsigned i = 0; i < geometries.size(); ++i)
-        {
-            if (processedGeometries.find(geometries[i]) == processedGeometries.end())
-            {
-                geometries[i]->drawDebugGeometry(debug);
-                processedGeometries.insert(geometries[i]);
-            }
-        }
-        for (unsigned i = 0; i < lights.size(); ++i)
-        {
-            if (processedLights.find(lights[i]) == processedLights.end())
-            {
-                lights[i]->drawDebugGeometry(debug);
-                processedLights.insert(lights[i]);
-            }
-        }
-    }
+    mDrawDebugGeometry = enable;
 }
 }
 
 
 Scene* Pipeline::getViewportScene(unsigned index) const
 Scene* Pipeline::getViewportScene(unsigned index) const
@@ -731,6 +691,54 @@ bool Pipeline::render()
     return true;
     return true;
 }
 }
 
 
+void Pipeline::drawDebugGeometry()
+{
+    PROFILE(Pipeline_DrawDebugGeometry);
+    
+    //! \todo Because debug geometry is per-scene, if two cameras show views of the same area, occlusion is not shown correctly
+    static std::set<GeometryNode*> processedGeometries;
+    static std::set<Light*> processedLights;
+    processedGeometries.clear();
+    processedLights.clear();
+    
+    for (unsigned i = 0; i < mNumViews; ++i)
+    {
+        // Make sure it's a main view, and process each node only once
+        View* view = mViews[i];
+        if ((!view) || (view->getRenderTarget()))
+            continue;
+        Octree* octree = view->getOctree();
+        if (!octree)
+            continue;
+        Scene* scene = octree->getScene();
+        if (!scene)
+            continue;
+        DebugRenderer* debug = scene->getExtension<DebugRenderer>();
+        if (!debug)
+            continue;
+        
+        const std::vector<GeometryNode*>& geometries = view->getGeometries();
+        const std::vector<Light*>& lights = view->getLights();
+        
+        for (unsigned i = 0; i < geometries.size(); ++i)
+        {
+            if (processedGeometries.find(geometries[i]) == processedGeometries.end())
+            {
+                geometries[i]->drawDebugGeometry(debug);
+                processedGeometries.insert(geometries[i]);
+            }
+        }
+        for (unsigned i = 0; i < lights.size(); ++i)
+        {
+            if (processedLights.find(lights[i]) == processedLights.end())
+            {
+                lights[i]->drawDebugGeometry(debug);
+                processedLights.insert(lights[i]);
+            }
+        }
+    }
+}
+
 void Pipeline::beginFrame(float timeStep)
 void Pipeline::beginFrame(float timeStep)
 {
 {
     mElapsedTime += timeStep;
     mElapsedTime += timeStep;
@@ -1528,3 +1536,9 @@ void Pipeline::handleWindowResized(StringHash eventType, VariantMap& eventData)
     mOcclusionBuffers.clear();
     mOcclusionBuffers.clear();
     resetViews();
     resetViews();
 }
 }
+
+void Pipeline::handlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
+{
+    if (mDrawDebugGeometry)
+        drawDebugGeometry();
+}

+ 14 - 6
Engine/Renderer/Pipeline.h

@@ -152,8 +152,8 @@ public:
     void setOccluderSizeThreshold(float screenSize);
     void setOccluderSizeThreshold(float screenSize);
     //! Set deferred rendering edge filter parameters. Only has effect if nonzero multisample level is set in Renderer::setMode().
     //! Set deferred rendering edge filter parameters. Only has effect if nonzero multisample level is set in Renderer::setMode().
     void setEdgeFilter(const EdgeFilterParameters& parameters);
     void setEdgeFilter(const EdgeFilterParameters& parameters);
-    //! Add debug geometry to the debug renderer(s). Call during EVENT_POSTRENDER to get most accurate results
-    void drawDebugGeometry();
+    //! Set whether to draw debug geometry for all viewports
+    void setDrawDebugGeometry(bool enable);
     
     
     //! Return number of viewports
     //! Return number of viewports
     unsigned getNumViewports() const { return mViewports.size(); }
     unsigned getNumViewports() const { return mViewports.size(); }
@@ -193,6 +193,8 @@ public:
     float getOccluderSizeThreshold() const { return mOccluderSizeThreshold; }
     float getOccluderSizeThreshold() const { return mOccluderSizeThreshold; }
     //! Return deferred rendering edge filter parameters
     //! Return deferred rendering edge filter parameters
     const EdgeFilterParameters& getEdgeFilter() const { return mEdgeFilter; }
     const EdgeFilterParameters& getEdgeFilter() const { return mEdgeFilter; }
+    //! Return whether to draw debug geometry
+    bool getDrawDebugGeometry() const { return mDrawDebugGeometry; }
     //! Return number of views rendered
     //! Return number of views rendered
     unsigned getNumViews() const { return mNumViews; }
     unsigned getNumViews() const { return mNumViews; }
     //! Return number of geometries rendered
     //! Return number of geometries rendered
@@ -224,6 +226,8 @@ public:
     bool update(float timeStep);
     bool update(float timeStep);
     //! Render. Called by Engine
     //! Render. Called by Engine
     bool render();
     bool render();
+    //! Add debug geometry to the debug renderer(s)
+    void drawDebugGeometry();
     
     
 private:
 private:
     //! Begin new frame
     //! Begin new frame
@@ -270,6 +274,8 @@ private:
     void drawSplitLightToStencil(Camera& camera, Light* light, bool clear = false);
     void drawSplitLightToStencil(Camera& camera, Light* light, bool clear = false);
     //! Handle window resized event
     //! Handle window resized event
     void handleWindowResized(StringHash eventType, VariantMap& eventData);
     void handleWindowResized(StringHash eventType, VariantMap& eventData);
+    //! Handle post render update event. Draw debug geometry here if enabled
+    void handlePostRenderUpdate(StringHash eventType, VariantMap& eventData);
     //! Return light vertex shaders
     //! Return light vertex shaders
     const std::vector<SharedPtr<VertexShader> >& getLightVS() const { return mLightVS; }
     const std::vector<SharedPtr<VertexShader> >& getLightVS() const { return mLightVS; }
     //! Return light pixel shaders
     //! Return light pixel shaders
@@ -315,6 +321,10 @@ private:
     std::vector<SharedPtr<Light> > mSplitLightStore;
     std::vector<SharedPtr<Light> > mSplitLightStore;
     //! Occlusion buffers
     //! Occlusion buffers
     std::map<int, SharedPtr<OcclusionBuffer> > mOcclusionBuffers;
     std::map<int, SharedPtr<OcclusionBuffer> > mOcclusionBuffers;
+    //! Viewports
+    std::vector<Viewport> mViewports;
+    //! Views
+    std::vector<SharedPtr<View> > mViews;
     //! Frame number
     //! Frame number
     unsigned mFrameNumber;
     unsigned mFrameNumber;
     //! Number of views
     //! Number of views
@@ -349,6 +359,8 @@ private:
     float mOccluderSizeThreshold;
     float mOccluderSizeThreshold;
     //! Deferred rendering edge filter parameters
     //! Deferred rendering edge filter parameters
     EdgeFilterParameters mEdgeFilter;
     EdgeFilterParameters mEdgeFilter;
+    //! Debug draw flag
+    bool mDrawDebugGeometry;
     //! Frame number on which shaders last changed
     //! Frame number on which shaders last changed
     unsigned mShadersChangedFrameNumber;
     unsigned mShadersChangedFrameNumber;
     //! Shaders need reloading flag
     //! Shaders need reloading flag
@@ -361,10 +373,6 @@ private:
     std::string mShaderPath;
     std::string mShaderPath;
     //! Light shader base name (deferred and prepass have different light shaders)
     //! Light shader base name (deferred and prepass have different light shaders)
     std::string mLightShaderName;
     std::string mLightShaderName;
-    //! Viewports
-    std::vector<Viewport> mViewports;
-    //! Views
-    std::vector<SharedPtr<View> > mViews;
     //! Frame info for rendering
     //! Frame info for rendering
     FrameInfo mFrame;
     FrameInfo mFrame;
     //! Octrees that have been updated during the frame
     //! Octrees that have been updated during the frame

+ 18 - 0
Engine/Scene/SceneEvents.h

@@ -26,12 +26,30 @@
 
 
 #include "Event.h"
 #include "Event.h"
 
 
+//! Application-wide update. Sent by Engine
+DEFINE_EVENT(EVENT_UPDATE, Update)
+{
+    EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
+}
+
 //! Update all non-networked scenes. Sent by Engine
 //! Update all non-networked scenes. Sent by Engine
 DEFINE_EVENT(EVENT_UPDATESCENES, UpdateScenes)
 DEFINE_EVENT(EVENT_UPDATESCENES, UpdateScenes)
 {
 {
     EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
     EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
 }
 }
 
 
+//! Application-wide post-update. Sent by Engine
+DEFINE_EVENT(EVENT_POSTUPDATE, PostUpdate)
+{
+    EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
+}
+
+//! Post-rendering pipeline update. Sent by Engine
+DEFINE_EVENT(EVENT_POSTRENDERUPDATE, PostRenderUpdate)
+{
+    EVENT_PARAM(P_TIMESTEP, TimeStep);          // float
+}
+
 //! Variable timestep scene update
 //! Variable timestep scene update
 DEFINE_EVENT(EVENT_SCENEUPDATE, SceneUpdate)
 DEFINE_EVENT(EVENT_SCENEUPDATE, SceneUpdate)
 {
 {

+ 2 - 7
Examples/NinjaSnowWar/Game.cpp

@@ -31,7 +31,6 @@
 #include "Connection.h"
 #include "Connection.h"
 #include "DebugHud.h"
 #include "DebugHud.h"
 #include "Engine.h"
 #include "Engine.h"
-#include "EngineEvents.h"
 #include "Exception.h"
 #include "Exception.h"
 #include "File.h"
 #include "File.h"
 #include "Font.h"
 #include "Font.h"
@@ -91,7 +90,6 @@ Game::Game() :
     mCameraMaxDist(0.0f),
     mCameraMaxDist(0.0f),
     mCameraSafetyDist(0.0f),
     mCameraSafetyDist(0.0f),
     mCameraRayLength(0.0f),
     mCameraRayLength(0.0f),
-    mDrawDebug(false),
     mGameOn(false),
     mGameOn(false),
     mFirstFrame(false),
     mFirstFrame(false),
     mClientEntityID(0)
     mClientEntityID(0)
@@ -494,10 +492,6 @@ void Game::handlePostUpdate(StringHash eventType, VariantMap& eventData)
     updateCamera();
     updateCamera();
     // Update status panel
     // Update status panel
     updateStatus(timeStep);
     updateStatus(timeStep);
-    
-    // Draw physics debug geometry if necessary
-    if (mDrawDebug)
-        mScene->getExtension<PhysicsWorld>()->drawDebugGeometry();
 }
 }
 
 
 void Game::handlePreStep(StringHash eventType, VariantMap& eventData)
 void Game::handlePreStep(StringHash eventType, VariantMap& eventData)
@@ -844,7 +838,8 @@ void Game::toggleDebugOverlay()
 
 
 void Game::toggleDebugGeometry()
 void Game::toggleDebugGeometry()
 {
 {
-    mDrawDebug = !mDrawDebug;
+    PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
+    world->setDrawDebugGeometry(!world->getDrawDebugGeometry());
 }
 }
 
 
 void Game::togglePause()
 void Game::togglePause()

+ 0 - 1
Examples/NinjaSnowWar/Game.h

@@ -138,7 +138,6 @@ private:
     float mCameraSafetyDist;
     float mCameraSafetyDist;
     float mCameraRayLength;
     float mCameraRayLength;
     float mSensitivity;
     float mSensitivity;
-    bool mDrawDebug;
     bool mGameOn;
     bool mGameOn;
     bool mFirstFrame;
     bool mFirstFrame;
     int mEnemies;
     int mEnemies;