BGE Scenegraph and View frustrum culling improvement.
authorBenoit Bolsee <benoit.bolsee@online.be>
Tue, 7 Apr 2009 22:14:06 +0000 (22:14 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Tue, 7 Apr 2009 22:14:06 +0000 (22:14 +0000)
This commit contains a number of performance improvements for the
BGE in the Scenegraph (parent relation between objects in the
scene) and view frustrum culling.

The scenegraph improvement consists in avoiding position update
if the object has not moved since last update and the removal
of redundant updates and synchronization with the physics engine.

The view frustrum culling improvement consists in using the DBVT
broadphase facility of Bullet to build a tree of graphical objects
in the scene. The elements of the tree are Aabb boxes (Aligned
Axis Bounding Boxes) enclosing the objects. This provides good
precision in closed and opened scenes. This new culling system
is enabled by default but just in case, it can be disabled with
a button in the World settings. There is no do_version in this
commit but it will be added before the 2.49 release. For now you
must manually enable the DBVT culling option in World settings
when you open an old file.

The above improvements speed up scenegraph and culling up to 5x.
However, this performance improvement is only visible when
you have hundreds or thousands of objects.

The main interest of the DBVT tree is to allow easy occlusion
culling and automatic LOD system. This will be the object of further
improvements.

54 files changed:
extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
projectfiles_vc9/gameengine/gameplayer/ghost/GP_ghost.vcproj
projectfiles_vc9/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj
projectfiles_vc9/gameengine/physics/PHY_Physics/PHY_Physics.vcproj
source/blender/blenkernel/intern/world.c
source/blender/makesdna/DNA_world_types.h
source/blender/src/buttons_shading.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/KX_BlenderSceneConverter.cpp
source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
source/gameengine/Ketsji/KX_Camera.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_Light.cpp
source/gameengine/Ketsji/KX_MotionState.cpp
source/gameengine/Ketsji/KX_MotionState.h
source/gameengine/Ketsji/KX_NearSensor.cpp
source/gameengine/Ketsji/KX_RadarSensor.cpp
source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h
source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp
source/gameengine/Ketsji/KX_SG_NodeRelationships.h
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
source/gameengine/Physics/Bullet/CcdGraphicController.cpp [new file with mode: 0644]
source/gameengine/Physics/Bullet/CcdGraphicController.h [new file with mode: 0644]
source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.h
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
source/gameengine/Physics/common/PHY_DynamicTypes.h
source/gameengine/Physics/common/PHY_IController.cpp [new file with mode: 0644]
source/gameengine/Physics/common/PHY_IController.h [new file with mode: 0644]
source/gameengine/Physics/common/PHY_IGraphicController.cpp [new file with mode: 0644]
source/gameengine/Physics/common/PHY_IGraphicController.h [new file with mode: 0644]
source/gameengine/Physics/common/PHY_IMotionState.h
source/gameengine/Physics/common/PHY_IPhysicsController.h
source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
source/gameengine/Rasterizer/RAS_BucketManager.cpp
source/gameengine/Rasterizer/RAS_FramingManager.h
source/gameengine/Rasterizer/RAS_MaterialBucket.h
source/gameengine/SceneGraph/SG_BBox.cpp
source/gameengine/SceneGraph/SG_BBox.h
source/gameengine/SceneGraph/SG_IObject.cpp
source/gameengine/SceneGraph/SG_IObject.h
source/gameengine/SceneGraph/SG_Node.cpp
source/gameengine/SceneGraph/SG_Node.h
source/gameengine/SceneGraph/SG_ParentRelation.h
source/gameengine/SceneGraph/SG_Spatial.cpp
source/gameengine/SceneGraph/SG_Spatial.h

index 457e26b..b6231a8 100644 (file)
@@ -350,12 +350,13 @@ int       btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps,
                for (int i=0;i<clampedSimulationSteps;i++)
                {
                        internalSingleStepSimulation(fixedTimeStep);
-                       synchronizeMotionStates();
+                       //for Blender, no need to synchronize here, it is done in blender anyway
+                       //synchronizeMotionStates();
                }
 
        } 
-
-       synchronizeMotionStates();
+       //else
+       //      synchronizeMotionStates();
 
        clearForces();
 
index 9fa3751..336c40e 100644 (file)
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/MACHINE:I386"\r
-                               AdditionalDependencies="odelib.lib fmodvc.lib ws2_32.lib vfw32.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib openal_static.lib libjpeg.lib dxguid.lib libeay32.lib libpng.lib libz.lib qtmlClient.lib SDL.lib freetype2ST.lib python25_d.lib pthreadVSE2.lib pthreadVC2.lib Half.lib Iex.lib IlmImf.lib IlmThread.lib Imath.lib avcodec-52.lib avformat-52.lib avutil-50.lib swscale-0.lib avdevice-52.lib"\r
+                               AdditionalDependencies="odelib.lib fmodvc.lib ws2_32.lib vfw32.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib openal_static.lib libjpeg.lib dxguid.lib libeay32.lib libpng.lib libz.lib qtmlClient.lib SDL.lib freetype2ST.lib python25.lib pthreadVSE2.lib pthreadVC2.lib Half.lib Iex.lib IlmImf.lib IlmThread.lib Imath.lib avcodec-52.lib avformat-52.lib avutil-50.lib swscale-0.lib avdevice-52.lib"\r
                                OutputFile="..\..\..\..\bin\blenderplayer.exe"\r
                                LinkIncremental="1"\r
                                SuppressStartupBanner="true"\r
index 8c22733..c941704 100644 (file)
                        Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
                        >\r
+                       <File\r
+                               RelativePath="..\..\..\..\..\source\gameengine\Physics\Bullet\CcdGraphicController.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\..\..\source\gameengine\Physics\Bullet\CcdPhysicsController.cpp"\r
                                >\r
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
                        >\r
+                       <File\r
+                               RelativePath="..\..\..\..\..\source\gameengine\Physics\Bullet\CcdGraphicController.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\..\..\source\gameengine\Physics\Bullet\CcdPhysicsController.h"\r
                                >\r
index 582aed5..5441c5b 100644 (file)
@@ -4,6 +4,7 @@
        Version="9,00"\r
        Name="PHY_Physics"\r
        ProjectGUID="{E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}"\r
+       RootNamespace="PHY_Physics"\r
        TargetFrameworkVersion="131072"\r
        >\r
        <Platforms>\r
                        Name="Source Files"\r
                        Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
                        >\r
+                       <File\r
+                               RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_IController.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_IGraphicController.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_IMotionState.cpp"\r
                                >\r
                                RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_DynamicTypes.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_IController.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_IGraphicController.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\..\..\source\gameengine\Physics\common\PHY_IMotionState.h"\r
                                >\r
index 2e89ce3..594d18f 100644 (file)
@@ -106,6 +106,7 @@ World *add_world(char *name)
        wrld->ao_approx_error= 0.25f;
        
        wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default
+       wrld->mode = WO_DBVT_CAMERA_CULLING;    // DBVT culling by default
        wrld->preview = NULL;
 
        return wrld;
index ab7e251..a51e970 100644 (file)
@@ -84,6 +84,8 @@ typedef struct World {
         * bit 1: Do stars
         * bit 2: (reserved) depth of field
         * bit 3: (gameengine): Activity culling is enabled.
+        * bit 4: ambient occlusion
+        * bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling 
         */
        short mode;
        int physicsEngine;      /* here it's aligned */
@@ -133,6 +135,7 @@ typedef struct World {
 #define WO_DOF                 4
 #define WO_ACTIVITY_CULLING       8
 #define WO_AMB_OCC                       16
+#define WO_DBVT_CAMERA_CULLING  32
 
 /* aomix */
 #define WO_AOADD       0
index fe4649f..e68c863 100644 (file)
@@ -2181,7 +2181,7 @@ static void world_panel_mistaph(World *wrld)
        uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
 
 #if GAMEBLENDER == 1
-       uiDefButI(block, MENU, 1
+       uiDefButI(block, MENU, B_REDR
 #ifdef USE_ODE
                          "Physics %t|None %x0|Sumo %x2|Ode %x4 |Bullet %x5",
 #else
@@ -2198,6 +2198,8 @@ static void world_panel_mistaph(World *wrld)
        
        /* Gravitation for the game worlds */
        uiDefButF(block, NUMSLI,0, "Grav ", 150,180,150,19,     &(wrld->gravity), 0.0, 25.0, 0, 0,  "Sets the gravitation constant of the game world");
+       if (wrld->physicsEngine == WOPHY_BULLET)
+               uiDefButBitS(block, TOG, WO_DBVT_CAMERA_CULLING, 0, "DBVT culling",     10,160,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles use of optimized Bullet DBVT tree for camera culling");
 #endif
 
        uiBlockSetCol(block, TH_BUT_SETTING1);
index d74243b..3c77f12 100644 (file)
@@ -164,7 +164,11 @@ extern "C" {
 
 // defines USE_ODE to choose physics engine
 #include "KX_ConvertPhysicsObject.h"
-
+#ifdef USE_BULLET
+#include "CcdPhysicsEnvironment.h"
+#include "CcdGraphicController.h"
+#endif
+#include "KX_MotionState.h"
 
 // This file defines relationships between parents and children
 // in the game engine.
@@ -1265,8 +1269,37 @@ static void my_get_local_bounds(Object *ob, float *center, float *size)
 //////////////////////////////////////////////////////
 
 
-
-
+void BL_CreateGraphicObjectNew(KX_GameObject* gameobj,
+                                                          const MT_Point3& localAabbMin,
+                                                          const MT_Point3& localAabbMax,
+                                                          KX_Scene* kxscene,
+                                                          bool isActive,
+                                                          e_PhysicsEngine physics_engine)
+{
+       if (gameobj->GetMeshCount() > 0) 
+       {
+               switch (physics_engine)
+               {
+#ifdef USE_BULLET
+               case UseBullet:
+                       {
+                               CcdPhysicsEnvironment* env = (CcdPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
+                               assert(env);
+                               PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
+                               CcdGraphicController* ctrl = new CcdGraphicController(env, motionstate);
+                               gameobj->SetGraphicController(ctrl);
+                               ctrl->setNewClientInfo(gameobj->getClientInfo());
+                               ctrl->setLocalAabb(localAabbMin, localAabbMax);
+                               if (isActive)
+                                       env->addCcdGraphicController(ctrl);
+                       }
+                       break;
+#endif
+               default:
+                       break;
+               }
+       }
+}
 
 void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
                                                 struct Object* blenderobject,
@@ -1859,8 +1892,10 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
        if (blenderscene->world) {
                kxscene->SetActivityCulling( (blenderscene->world->mode & WO_ACTIVITY_CULLING) != 0);
                kxscene->SetActivityCullingRadius(blenderscene->world->activityBoxRadius);
+               kxscene->SetDbvtCameraCulling((blenderscene->world->mode & WO_DBVT_CAMERA_CULLING) != 0);
        } else {
                kxscene->SetActivityCulling(false);
+               kxscene->SetDbvtCameraCulling(false);
        }
        
        int activeLayerBitInfo = blenderscene->lay;
@@ -1954,7 +1989,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                        gameobj->NodeSetLocalPosition(pos);
                        gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
                        gameobj->NodeSetLocalScale(scale);
-                       gameobj->NodeUpdateGS(0,true);
+                       gameobj->NodeUpdateGS(0);
                        
                        BL_ConvertIpos(blenderobject,gameobj,converter);
                        BL_ConvertMaterialIpos(blenderobject, gameobj, converter);
@@ -2037,7 +2072,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                                objectlist->Add(gameobj->AddRef());
                                //tf.Add(gameobj->GetSGNode());
                                
-                               gameobj->NodeUpdateGS(0,true);
+                               gameobj->NodeUpdateGS(0);
                                gameobj->AddMeshUser();
                
                        }
@@ -2148,7 +2183,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                                                        gameobj->NodeSetLocalPosition(pos);
                                                        gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
                                                        gameobj->NodeSetLocalScale(scale);
-                                                       gameobj->NodeUpdateGS(0,true);
+                                                       gameobj->NodeUpdateGS(0);
                                                        
                                                        BL_ConvertIpos(blenderobject,gameobj,converter);
                                                        BL_ConvertMaterialIpos(blenderobject,gameobj, converter);       
@@ -2226,7 +2261,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                                                                objectlist->Add(gameobj->AddRef());
                                                                //tf.Add(gameobj->GetSGNode());
                                                                
-                                                               gameobj->NodeUpdateGS(0,true);
+                                                               gameobj->NodeUpdateGS(0);
                                                                gameobj->AddMeshUser();
                                                        }
                                                        else
@@ -2377,7 +2412,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                if (gameobj->GetSGNode()->GetSGParent() == 0)
                {
                        parentlist->Add(gameobj->AddRef());
-                       gameobj->NodeUpdateGS(0,true);
+                       gameobj->NodeUpdateGS(0);
                }
        }
        
@@ -2414,6 +2449,22 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,physics_engine,converter,processCompoundChildren);
        }
        
+       // create graphic controller for culling
+       if (kxscene->GetDbvtCameraCulling())
+       {
+               for (i=0; i<sumolist->GetCount();i++)
+               {
+                       KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
+                       if (gameobj->GetMeshCount() > 0) 
+                       {
+                               MT_Point3 box[2];
+                               gameobj->GetSGNode()->BBox().getmm(box, MT_Transform::Identity());
+                               // box[0] is the min, box[1] is the max
+                               bool isactive = objectlist->SearchValue(gameobj);
+                               BL_CreateGraphicObjectNew(gameobj,box[0],box[1],kxscene,isactive,physics_engine);
+                       }
+               }
+       }
        
        //set ini linearVel and int angularVel //rcruiz
        if (converter->addInitFromFrame)
index 97a0819..b0c676a 100644 (file)
@@ -267,9 +267,11 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename,
        Scene *blenderscene = GetBlenderSceneForName(scenename);
 
        e_PhysicsEngine physics_engine = UseBullet;
+       bool useDbvtCulling = false;
        // hook for registration function during conversion.
        m_currentScene = destinationscene;
        destinationscene->SetSceneConverter(this);
+       SG_SetActiveStage(SG_STAGE_CONVERTER);
 
        if (blenderscene)
        {
@@ -281,6 +283,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename,
                        case WOPHY_BULLET:
                                {
                                        physics_engine = UseBullet;
+                                       useDbvtCulling = (blenderscene->world->mode & WO_DBVT_CAMERA_CULLING) != 0;
                                        break;
                                }
                                 
@@ -313,7 +316,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename,
 #ifdef USE_BULLET
                case UseBullet:
                        {
-                               CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment();
+                               CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(useDbvtCulling);
                                ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw());
                                ccdPhysEnv->setDeactivationLinearTreshold(0.8f); // default, can be overridden by Python
                                ccdPhysEnv->setDeactivationAngularTreshold(1.0f); // default, can be overridden by Python
@@ -806,7 +809,7 @@ void        KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo(){
                                        gameobj->NodeSetLocalPosition(pos);
                                        gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz));
                                        gameobj->NodeSetLocalScale(scale);
-                                       gameobj->NodeUpdateGS(0,true);
+                                       gameobj->NodeUpdateGS(0);
                                }
                        }
                }
index 062e9f7..435b2b5 100644 (file)
@@ -417,13 +417,14 @@ void      KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly)
        {
                if (!nondynaonly)
                {
+                       /*
                        btTransform worldTrans;
                        if (GetRigidBody())
                        {
                                GetRigidBody()->getMotionState()->getWorldTransform(worldTrans);
                                GetRigidBody()->setCenterOfMassTransform(worldTrans);
                        }
-                       
+                       */
                        /*
                        scaling?
                        if (m_bDyna)
index 6ed2150..4accd4b 100644 (file)
@@ -45,6 +45,7 @@ class KX_Camera : public KX_GameObject
 {
        Py_Header;
 protected:
+       friend class KX_Scene;
        /** Camera parameters (clips distances, focal lenght). These
         * params are closely tied to Blender. In the gameengine, only the
         * projection and modelview matrices are relevant. There's a
@@ -67,6 +68,7 @@ protected:
         * Storage for the projection matrix that is passed to the
         * rasterizer. */
        MT_Matrix4x4 m_projection_matrix;
+       //MT_Matrix4x4 m_projection_matrix1;
 
        /**
         * Storage for the modelview matrix that is passed to the
@@ -119,6 +121,16 @@ protected:
         * Extracts the bound sphere of the view frustum.
         */
        void ExtractFrustumSphere();
+       /**
+        * return the clip plane
+        */
+       MT_Vector4 *GetNormalizedClipPlanes()
+       {
+               ExtractClipPlanes();
+               NormalizeClipPlanes();
+               return m_planes;
+       }
+
 public:
 
        enum { INSIDE, INTERSECT, OUTSIDE } ;
index 7f99a56..339a955 100644 (file)
@@ -55,6 +55,7 @@ typedef unsigned long uint_ptr;
 #include <stdio.h> // printf
 #include "SG_Controller.h"
 #include "KX_IPhysicsController.h"
+#include "PHY_IGraphicController.h"
 #include "SG_Node.h"
 #include "SG_Controller.h"
 #include "KX_ClientObjectInfo.h"
@@ -91,6 +92,7 @@ KX_GameObject::KX_GameObject(
        m_bVisible(true),
        m_bCulled(true),
        m_pPhysicsController1(NULL),
+       m_pGraphicController(NULL),
        m_pPhysicsEnvironment(NULL),
        m_xray(false),
        m_pHitObject(NULL),
@@ -132,6 +134,10 @@ KX_GameObject::~KX_GameObject()
                }
                m_pSGNode->SetSGClientObject(NULL);
        }
+       if (m_pGraphicController)
+       {
+               delete m_pGraphicController;
+       }
 }
 
 
@@ -249,7 +255,7 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj)
                NodeSetLocalScale(scale1);
                NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2]));
                NodeSetLocalOrientation(invori*NodeGetWorldOrientation());
-               NodeUpdateGS(0.f,true);
+               NodeUpdateGS(0.f);
                // object will now be a child, it must be removed from the parent list
                CListValue* rootlist = scene->GetRootParentList();
                if (rootlist->RemoveValue(this))
@@ -269,6 +275,7 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj)
                                rootobj->m_pPhysicsController1->AddCompoundChild(m_pPhysicsController1);
                        }
                }
+               // graphically, the object hasn't change place, no need to update m_pGraphicController
        }
 }
 
@@ -286,7 +293,7 @@ void KX_GameObject::RemoveParent(KX_Scene *scene)
 
                // Remove us from our parent
                GetSGNode()->DisconnectFromParent();
-               NodeUpdateGS(0.f,true);
+               NodeUpdateGS(0.f);
                // the object is now a root object, add it to the parentlist
                CListValue* rootlist = scene->GetRootParentList();
                if (!rootlist->SearchValue(this))
@@ -303,12 +310,14 @@ void KX_GameObject::RemoveParent(KX_Scene *scene)
                        }
                        m_pPhysicsController1->RestoreDynamics();
                }
+               // graphically, the object hasn't change place, no need to update m_pGraphicController
        }
 }
 
 void KX_GameObject::ProcessReplica(KX_GameObject* replica)
 {
        replica->m_pPhysicsController1 = NULL;
+       replica->m_pGraphicController = NULL;
        replica->m_pSGNode = NULL;
        replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
        replica->m_pClient_info->m_gameobject = replica;
@@ -437,22 +446,18 @@ void KX_GameObject::RemoveMeshes()
        m_meshes.clear();
 }
 
-
-
-void KX_GameObject::UpdateNonDynas()
+void KX_GameObject::UpdateTransform()
 {
        if (m_pPhysicsController1)
-       {
+               // only update the transform of static object, dynamic object are handled differently
+               // note that for bullet, this does not even update the transform of static object
+               // but merely sets there collision flag to "kinematic" because the synchronization is 
+               // done differently during physics simulation
                m_pPhysicsController1->SetSumoTransform(true);
-       }
-}
+       if (m_pGraphicController)
+               // update the culling tree
+               m_pGraphicController->SetGraphicTransform();
 
-
-
-void KX_GameObject::UpdateTransform()
-{
-       if (m_pPhysicsController1)
-               m_pPhysicsController1->SetSumoTransform(false);
 }
 
 void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene)
@@ -832,6 +837,7 @@ void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans)
        }
 
        GetSGNode()->SetLocalPosition(trans);
+
 }
 
 
@@ -911,7 +917,7 @@ void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans)
 }
 
 
-void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
+void KX_GameObject::NodeUpdateGS(double time)
 {
        if (GetSGNode())
                GetSGNode()->UpdateWorldData(time);
@@ -1295,7 +1301,7 @@ int KX_GameObject::pyattr_set_position(void *self_v, const KX_PYATTRIBUTE_DEF *a
                return 1;
        
        self->NodeSetLocalPosition(pos);
-       self->NodeUpdateGS(0.f,true);
+       self->NodeUpdateGS(0.f);
        return 0;
 }
 
@@ -1319,10 +1325,10 @@ int KX_GameObject::pyattr_set_orientation(void *self_v, const KX_PYATTRIBUTE_DEF
        if (PyMatTo(value, rot))
        {
                self->NodeSetLocalOrientation(rot);
-               self->NodeUpdateGS(0.f,true);
+               self->NodeUpdateGS(0.f);
                return 0;
        }
-       return 1;
+       PyErr_Clear();
 
        if (PySequence_Size(value) == 4)
        {
@@ -1331,7 +1337,7 @@ int KX_GameObject::pyattr_set_orientation(void *self_v, const KX_PYATTRIBUTE_DEF
                {
                        rot.setRotation(qrot);
                        self->NodeSetLocalOrientation(rot);
-                       self->NodeUpdateGS(0.f,true);
+                       self->NodeUpdateGS(0.f);
                        return 0;
                }
                return 1;
@@ -1344,7 +1350,7 @@ int KX_GameObject::pyattr_set_orientation(void *self_v, const KX_PYATTRIBUTE_DEF
                {
                        rot.setEuler(erot);
                        self->NodeSetLocalOrientation(rot);
-                       self->NodeUpdateGS(0.f,true);
+                       self->NodeUpdateGS(0.f);
                        return 0;
                }
                return 1;
@@ -1368,7 +1374,7 @@ int KX_GameObject::pyattr_set_scaling(void *self_v, const KX_PYATTRIBUTE_DEF *at
                return 1;
 
        self->NodeSetLocalScale(scale);
-       self->NodeUpdateGS(0.f,true);
+       self->NodeUpdateGS(0.f);
        return 0;
 }
 
@@ -1929,7 +1935,7 @@ PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value)
        if (PyObject_IsMT_Matrix(value, 3) && PyMatTo(value, matrix))
        {
                NodeSetLocalOrientation(matrix);
-               NodeUpdateGS(0.f,true);
+               NodeUpdateGS(0.f);
                Py_RETURN_NONE;
        }
 
@@ -1938,7 +1944,7 @@ PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value)
        {
                matrix.setRotation(quat);
                NodeSetLocalOrientation(matrix);
-               NodeUpdateGS(0.f,true);
+               NodeUpdateGS(0.f);
                Py_RETURN_NONE;
        }
        return NULL;
@@ -1959,7 +1965,7 @@ PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args)
                        if (fac> 1.0) fac= 1.0;
                        
                        AlignAxisToVect(vect,axis,fac);
-                       NodeUpdateGS(0.f,true);
+                       NodeUpdateGS(0.f);
                        Py_RETURN_NONE;
                }
        }
@@ -1983,7 +1989,7 @@ PyObject* KX_GameObject::PySetPosition(PyObject* self, PyObject* value)
        if (PyVecTo(value, pos))
        {
                NodeSetLocalPosition(pos);
-               NodeUpdateGS(0.f,true);
+               NodeUpdateGS(0.f);
                Py_RETURN_NONE;
        }
 
@@ -1996,7 +2002,7 @@ PyObject* KX_GameObject::PySetWorldPosition(PyObject* self, PyObject* value)
        if (PyVecTo(value, pos))
        {
                NodeSetWorldPosition(pos);
-               NodeUpdateGS(0.f,true);
+               NodeUpdateGS(0.f);
                Py_RETURN_NONE;
        }
 
index bc6b601..9c7dda5 100644 (file)
@@ -57,6 +57,7 @@ struct KX_ClientObjectInfo;
 class KX_RayCast;
 class RAS_MeshObject;
 class KX_IPhysicsController;
+class PHY_IGraphicController;
 class PHY_IPhysicsEnvironment;
 struct Object;
 
@@ -88,6 +89,7 @@ protected:
        bool                                                            m_bCulled; 
 
        KX_IPhysicsController*                          m_pPhysicsController1;
+       PHY_IGraphicController*                         m_pGraphicController;
        // used for ray casting
        PHY_IPhysicsEnvironment*                        m_pPhysicsEnvironment;
        STR_String                                                      m_testPropName;
@@ -350,6 +352,19 @@ public:
 
        }
 
+       /**
+        * @return a pointer to the graphic controller owner by this class 
+        */
+       PHY_IGraphicController* GetGraphicController()
+       {
+               return m_pGraphicController;
+       }
+
+       void SetGraphicController(PHY_IGraphicController* graphiccontroller) 
+       { 
+               m_pGraphicController = graphiccontroller;
+       }
+
        /**
         * @section Coordinate system manipulation functions
         */
@@ -367,8 +382,7 @@ public:
 
                void                                            
        NodeUpdateGS(
-               double time,
-               bool bInitiator
+               double time
        );
 
        const 
@@ -524,13 +538,6 @@ public:
 
        static void UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene);
 
-       /**
-        * Only update the transform if it's a non-dynamic object
-        */
-               void 
-       UpdateNonDynas(
-       );
-
        /**
         * Function to set IPO option at start of IPO
         */ 
index 97b4213..70ae0e4 100644 (file)
@@ -412,7 +412,7 @@ else
 
 
        // Compute the number of logic frames to do each update (fixed tic bricks)
-       int frames =int(deltatime*m_ticrate);
+       int frames =int(deltatime*m_ticrate+1e-6);
 //     if (frames>1)
 //             printf("****************************************");
 //     printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
@@ -465,12 +465,15 @@ else
 
                                
                                m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_NETWORK);
                                scene->GetNetworkScene()->proceed(m_frameTime);
        
-                               m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
-                               scene->UpdateParents(m_frameTime);
+                               //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               //SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE);
+                               //scene->UpdateParents(m_frameTime);
                                
                                m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_PHYSICS1);
                                // set Python hooks for each scene
                                PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
                                KX_SetActiveScene(scene);
@@ -479,31 +482,37 @@ else
                                
                                // Update scenegraph after physics step. This maps physics calculations
                                // into node positions.         
-                               m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
-                               scene->UpdateParents(m_frameTime);
+                               //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE);
+                               //scene->UpdateParents(m_frameTime);
                                
                                // Process sensors, and controllers
                                m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_CONTROLLER);
                                scene->LogicBeginFrame(m_frameTime);
        
                                // Scenegraph needs to be updated again, because Logic Controllers 
                                // can affect the local matrices.
                                m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE);
                                scene->UpdateParents(m_frameTime);
        
                                // Process actuators
        
                                // Do some cleanup work for this logic frame
                                m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_ACTUATOR);
                                scene->LogicUpdateFrame(m_frameTime, true);
                                
                                scene->LogicEndFrame();
        
                                // Actuators can affect the scenegraph
                                m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
                                scene->UpdateParents(m_frameTime);
                                
                                m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_PHYSICS2);
                                scene->GetPhysicsEnvironment()->beginFrame();
                
                                // Perform physics calculations on the scene. This can involve 
@@ -511,6 +520,7 @@ else
                                scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,1.0/m_ticrate);//m_deltatimerealDeltaTime);
 
                                m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE);
                                scene->UpdateParents(m_frameTime);
                        
                        
@@ -574,6 +584,7 @@ else
                                KX_SetActiveScene(scene);
                                
                                m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_PHYSICS1);
                                scene->UpdateParents(m_clockTime);
 
                                // Perform physics calculations on the scene. This can involve 
@@ -583,6 +594,7 @@ else
                                // Update scenegraph after physics step. This maps physics calculations
                                // into node positions.         
                                m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_PHYSICS2);
                                scene->UpdateParents(m_clockTime);
                                
                                // Do some cleanup work for this logic frame
@@ -591,6 +603,7 @@ else
 
                                // Actuators can affect the scenegraph
                                m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+                               SG_SetActiveStage(SG_STAGE_ACTUATOR);
                                scene->UpdateParents(m_clockTime);
                                 
                                scene->setSuspendedTime(0.0);
@@ -622,6 +635,7 @@ void KX_KetsjiEngine::Render()
        const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
 
        m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+       SG_SetActiveStage(SG_STAGE_RENDER);
 
        // hiding mouse cursor each frame
        // (came back when going out of focus and then back in again)
@@ -1102,14 +1116,22 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
                cam->GetCameraLocation(), cam->GetCameraOrientation());
        cam->SetModelviewMatrix(viewmat);
 
-       scene->UpdateMeshTransformations();
+       //redundant, already done in 
+       //scene->UpdateMeshTransformations();
 
        // The following actually reschedules all vertices to be
        // redrawn. There is a cache between the actual rescheduling
        // and this call though. Visibility is imparted when this call
        // runs through the individual objects.
+
+       m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
+       SG_SetActiveStage(SG_STAGE_CULLING);
+
        scene->CalculateVisibleMeshes(m_rasterizer,cam);
 
+       m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+       SG_SetActiveStage(SG_STAGE_RENDER);
+
        scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
        
        if (scene->GetPhysicsEnvironment())
@@ -1166,15 +1188,17 @@ void KX_KetsjiEngine::AddScene(KX_Scene* scene)
 void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
 {
        bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName));
-       
-               // if there is no activecamera, or the camera is being
-               // overridden we need to construct a temporarily camera
+
+       SG_SetActiveStage(SG_STAGE_SCENE);
+
+       // if there is no activecamera, or the camera is being
+       // overridden we need to construct a temporarily camera
        if (!scene->GetActiveCamera() || override_camera)
        {
                KX_Camera* activecam = NULL;
 
                RAS_CameraData camdata = RAS_CameraData();
-               activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata, false);
+               activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata);
                activecam->SetName("__default__cam__");
        
                        // set transformation
@@ -1186,11 +1210,11 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
                        
                        activecam->NodeSetLocalPosition(camtrans.getOrigin());
                        activecam->NodeSetLocalOrientation(camtrans.getBasis());
-                       activecam->NodeUpdateGS(0,true);
+                       activecam->NodeUpdateGS(0);
                } else {
                        activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
                        activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
-                       activecam->NodeUpdateGS(0,true);
+                       activecam->NodeUpdateGS(0);
                }
 
                scene->AddCamera(activecam);
index 7b5b77c..f996f86 100644 (file)
@@ -159,7 +159,7 @@ void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_T
        
        cam->NodeSetLocalPosition(camtrans.getOrigin());
        cam->NodeSetLocalOrientation(camtrans.getBasis());
-       cam->NodeUpdateGS(0,true);
+       cam->NodeUpdateGS(0);
 
        /* setup rasterizer transformations */
        ras->SetProjectionMatrix(projectionmat);
index 15f100a..00d9a32 100644 (file)
@@ -44,7 +44,7 @@ KX_MotionState::~KX_MotionState()
 
 void   KX_MotionState::getWorldPosition(float& posX,float& posY,float& posZ)
 {
-       MT_Point3 pos = m_node->GetWorldPosition();
+       const MT_Point3& pos = m_node->GetWorldPosition();
        posX = pos[0];
        posY = pos[1];
        posZ = pos[2];
@@ -52,7 +52,7 @@ void  KX_MotionState::getWorldPosition(float& posX,float& posY,float& posZ)
 
 void   KX_MotionState::getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)
 {
-       MT_Vector3 scale = m_node->GetWorldScaling();
+       const MT_Vector3& scale = m_node->GetWorldScaling();
        scaleX = scale[0];
        scaleY = scale[1];
        scaleZ = scale[2];
@@ -60,17 +60,23 @@ void        KX_MotionState::getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)
 
 void   KX_MotionState::getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)
 {
-       MT_Quaternion orn = m_node->GetWorldOrientation().getRotation();
+       MT_Quaternion& orn = m_node->GetWorldOrientation().getRotation();
        quatIma0 = orn[0];
        quatIma1 = orn[1];
        quatIma2 = orn[2];
        quatReal = orn[3];
 }
        
+void   KX_MotionState::getWorldOrientation(float* ori)
+{
+       const MT_Matrix3x3& mat = m_node->GetWorldOrientation();
+       mat.getValue(ori);
+}
+       
 void   KX_MotionState::setWorldPosition(float posX,float posY,float posZ)
 {
        m_node->SetLocalPosition(MT_Point3(posX,posY,posZ));
-       m_node->SetWorldPosition(MT_Point3(posX,posY,posZ));
+       //m_node->SetWorldPosition(MT_Point3(posX,posY,posZ));
 }
 
 void   KX_MotionState::setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)
@@ -82,13 +88,15 @@ void        KX_MotionState::setWorldOrientation(float quatIma0,float quatIma1,float qua
        orn[3] = quatReal;
 
        m_node->SetLocalOrientation(orn);
-       m_node->SetWorldOrientation(orn);
+       //m_node->SetWorldOrientation(orn);
 
 }
 
 void   KX_MotionState::calculateWorldTransformations()
 {
-       m_node->ComputeWorldTransforms(NULL);
+       //Not needed, will be done in KX_Scene::UpdateParents() after the physics simulation
+       //bool parentUpdated = false;
+       //m_node->ComputeWorldTransforms(NULL, parentUpdated);
 }
 
  
index c83af66..7ba3ca2 100644 (file)
@@ -44,6 +44,7 @@ public:
        virtual void    getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal);
        virtual void    setWorldPosition(float posX,float posY,float posZ);
        virtual void    setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal);
+       virtual void    getWorldOrientation(float* ori);
 
        virtual void    calculateWorldTransformations();
 };
index cd75321..b9d1939 100644 (file)
@@ -127,13 +127,10 @@ CValue* KX_NearSensor::GetReplica()
                }
                
        }
-       //static_cast<KX_TouchEventManager*>(m_eventmgr)->RegisterSensor(this);
-       //todo: make sure replication works fine
-       //>m_sumoObj = new SM_Object(DT_NewSphere(0.0),NULL,NULL,NULL);
-       //replica->m_sumoObj->setMargin(m_Margin);
-       //replica->m_sumoObj->setClientObject(replica->m_client_info);
-       
-       ((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
+       //Wrong: the parent object could be a child, this code works only if it is a root parent.
+       //Anyway, at this stage, the parent object is already synchronized, nothing to do.
+       //bool parentUpdated = false;
+       //((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL, parentUpdated);
        replica->SynchronizeTransform();
        
        return replica;
@@ -154,8 +151,10 @@ void KX_NearSensor::ReParent(SCA_IObject* parent)
        client_info->m_sensors.push_back(this);
        SCA_ISensor::ReParent(parent);
 */
-       ((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
-       SynchronizeTransform();
+       //Not needed, was done in GetReplica() already
+       //bool parentUpdated = false;
+       //((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL,parentUpdated);
+       //SynchronizeTransform();
        SCA_ISensor::ReParent(parent);
 }
 
index 355ac89..b9abe69 100644 (file)
@@ -100,8 +100,9 @@ CValue* KX_RadarSensor::GetReplica()
        //>m_sumoObj = new SM_Object(DT_NewCone(m_coneradius, m_coneheight),NULL,NULL,NULL);
        //replica->m_sumoObj->setMargin(m_Margin);
        //replica->m_sumoObj->setClientObject(replica->m_client_info);
-       
-       ((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
+       //Wrong: see KX_TouchSensor
+       //bool parentUpdated = false;
+       //((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL,parentUpdated);
        replica->SynchronizeTransform();
        
        return replica;
index 151270c..0e75710 100644 (file)
@@ -57,7 +57,8 @@ New(Bone* bone
 KX_BoneParentRelation::
 UpdateChildCoordinates(
        SG_Spatial * child,
-       const SG_Spatial * parent
+       const SG_Spatial * parent,
+       bool& parentUpdated     
 ){
        MT_assert(child != NULL);
        
@@ -67,6 +68,8 @@ UpdateChildCoordinates(
        const MT_Vector3 & child_scale = child->GetLocalScale();
        const MT_Point3 & child_pos = child->GetLocalPosition();
        const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation();
+       // we don't know if the armature has been updated or not, assume yes
+       parentUpdated = true;
 
        // the childs world locations which we will update.     
        
@@ -122,7 +125,7 @@ UpdateChildCoordinates(
        else {
                child->SetWorldFromLocalTransform();
        }
-       
+       child->SetModified(false);
        return valid_parent_transform;
 }
 
index 2a19d8a..c9baf22 100644 (file)
@@ -82,7 +82,8 @@ public :
                bool
        UpdateChildCoordinates(
                SG_Spatial * child,
-               const SG_Spatial * parent
+               const SG_Spatial * parent,
+               bool& parentUpdated
        );
 
        /**
index 0729ec8..87ff3b5 100644 (file)
@@ -51,13 +51,20 @@ New(
 KX_NormalParentRelation::
 UpdateChildCoordinates(
        SG_Spatial * child,
-       const SG_Spatial * parent
+       const SG_Spatial * parent,
+       bool& parentUpdated     
 ){
        MT_assert(child != NULL);
 
+       if (!parentUpdated && !child->IsModified())
+               return false;
+
+       parentUpdated = true;
+
        if (parent==NULL) { /* Simple case */
                child->SetWorldFromLocalTransform();
-               return false;
+               child->SetModified(false);
+               return true; //false;
        }
        else {
                // the childs world locations which we will update.     
@@ -68,6 +75,7 @@ UpdateChildCoordinates(
                child->SetWorldScale(p_world_scale * child->GetLocalScale());
                child->SetWorldOrientation(p_world_rotation * child->GetLocalOrientation());
                child->SetWorldPosition(p_world_pos + p_world_scale * (p_world_rotation * child->GetLocalPosition()));
+               child->SetModified(false);
                return true;
        }
 }
@@ -112,10 +120,15 @@ New(
 KX_VertexParentRelation::
 UpdateChildCoordinates(
        SG_Spatial * child,
-       const SG_Spatial * parent
+       const SG_Spatial * parent,
+       bool& parentUpdated     
 ){
 
        MT_assert(child != NULL);
+
+       if (!parentUpdated && !child->IsModified())
+               return false;
+
        child->SetWorldScale(child->GetLocalScale());
        
        if (parent)
@@ -124,7 +137,8 @@ UpdateChildCoordinates(
                child->SetWorldPosition(child->GetLocalPosition());
        
        child->SetWorldOrientation(child->GetLocalOrientation());
-       return parent != NULL;
+       child->SetModified(false);
+       return true; //parent != NULL;
 }
 
 /** 
@@ -172,10 +186,14 @@ New(
 KX_SlowParentRelation::
 UpdateChildCoordinates(
        SG_Spatial * child,
-       const SG_Spatial * parent
+       const SG_Spatial * parent,
+       bool& parentUpdated     
 ){
        MT_assert(child != NULL);
 
+       // the child will move even if the parent is not
+       parentUpdated = true;
+
        const MT_Vector3 & child_scale = child->GetLocalScale();
        const MT_Point3 & child_pos = child->GetLocalPosition();
        const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation();
@@ -252,8 +270,9 @@ UpdateChildCoordinates(
        child->SetWorldScale(child_w_scale);
        child->SetWorldPosition(child_w_pos);
        child->SetWorldOrientation(child_w_rotation);
+       child->SetModified(false);
        
-       return parent != NULL;
+       return true; //parent != NULL;
 }
 
 /** 
index faa6501..d8fb921 100644 (file)
@@ -71,7 +71,8 @@ public :
                bool
        UpdateChildCoordinates(
                SG_Spatial * child,
-               const SG_Spatial * parent
+               const SG_Spatial * parent,
+               bool& parentUpdated     
        );
 
        /** 
@@ -115,7 +116,8 @@ public :
                bool
        UpdateChildCoordinates(
                SG_Spatial * child,
-               const SG_Spatial * parent
+               const SG_Spatial * parent,
+               bool& parentUpdated     
        );
 
        /** 
@@ -166,7 +168,8 @@ public :
                bool
        UpdateChildCoordinates(
                SG_Spatial * child,
-               const SG_Spatial * parent
+               const SG_Spatial * parent,
+               bool& parentUpdated     
        );
 
        /** 
index 04d6bd7..7eed1cc 100644 (file)
@@ -76,7 +76,9 @@
 #include "NG_NetworkScene.h"
 #include "PHY_IPhysicsEnvironment.h"
 #include "KX_IPhysicsController.h"
+#include "PHY_IGraphicController.h"
 #include "KX_BlenderSceneConverter.h"
+#include "KX_MotionState.h"
 
 #include "BL_ShapeDeformer.h"
 #include "BL_DeformableGameObject.h"
@@ -133,6 +135,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
        m_suspendedtime = 0.0;
        m_suspendeddelta = 0.0;
 
+       m_dbvt_culling = false;
        m_activity_culling = false;
        m_suspend = false;
        m_isclearingZbuffer = true;
@@ -407,6 +410,13 @@ void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gam
                // will in any case be deleted. This ensures that the object will not try to use the node
                // when it is finally deleted (see KX_GameObject destructor)
                orgobj->SetSGNode(NULL);
+               PHY_IGraphicController* ctrl = orgobj->GetGraphicController();
+               if (ctrl)
+               {
+                       // a graphic controller is set, we must delete it as the node will be deleted
+                       delete ctrl;
+                       orgobj->SetGraphicController(NULL);
+               }
        }
        if (node)
                delete node;
@@ -485,7 +495,14 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
                        replicanode->AddSGController(replicacontroller);
                }
        }
-       
+       // replicate graphic controller
+       if (orgobj->GetGraphicController())
+       {
+               PHY_IMotionState* motionstate = new KX_MotionState(newobj->GetSGNode());
+               PHY_IGraphicController* newctrl = orgobj->GetGraphicController()->GetReplica(motionstate);
+               newctrl->setNewClientInfo(newobj->getClientInfo());
+               newobj->SetGraphicController(newctrl);
+       }
        return newobj;
 }
 
@@ -792,6 +809,24 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
                        replica->GetSGNode()->AddChild(childreplicanode);
        }
 
+       // At this stage all the objects in the hierarchy have been duplicated,
+       // we can update the scenegraph, we need it for the duplication of logic
+       MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition();
+       replica->NodeSetLocalPosition(newpos);
+
+       MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation();
+       replica->NodeSetLocalOrientation(newori);
+       
+       // get the rootnode's scale
+       MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale();
+
+       // set the replica's relative scale with the rootnode's scale
+       replica->NodeSetRelativeScale(newscale);
+
+       replica->GetSGNode()->UpdateWorldData(0);
+       replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
+       replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius());
+
        // now replicate logic
        vector<KX_GameObject*>::iterator git;
        for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
@@ -814,21 +849,6 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
                ReplicateLogic((*git));
        }
        
-       MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition();
-       replica->NodeSetLocalPosition(newpos);
-
-       MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation();
-       replica->NodeSetLocalOrientation(newori);
-       
-       // get the rootnode's scale
-       MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale();
-
-       // set the replica's relative scale with the rootnode's scale
-       replica->NodeSetRelativeScale(newscale);
-
-       replica->GetSGNode()->UpdateWorldData(0);
-       replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
-       replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius());
        // check if there are objects with dupligroup in the hierarchy
        vector<KX_GameObject*> duplilist;
        for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
@@ -1163,7 +1183,6 @@ void KX_Scene::UpdateMeshTransformations()
        {
                KX_GameObject* gameobj = (KX_GameObject*)m_objectlist->GetValue(i);
                gameobj->GetOpenGLMatrix();
-//             gameobj->UpdateNonDynas();
        }
 }
 
@@ -1298,21 +1317,46 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam
        }
 }
 
+void KX_Scene::PhysicsCullingCallback(KX_ClientObjectInfo* objectInfo, void* cullingInfo)
+{
+       KX_GameObject* gameobj = objectInfo->m_gameobject;
+       if (!gameobj->GetVisible())
+               // ideally, invisible objects should be removed from the culling tree temporarily
+               return;
+       if(((CullingInfo*)cullingInfo)->m_layer && !(gameobj->GetLayer() & ((CullingInfo*)cullingInfo)->m_layer))
+               // used for shadow: object is not in shadow layer
+               return;
+
+       // make object visible
+       gameobj->SetCulled(false);
+       gameobj->UpdateBuckets(false);
+}
+
 void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int layer)
 {
-// FIXME: When tree is operational
-#if 1
-       // do this incrementally in the future
-       for (int i = 0; i < m_objectlist->GetCount(); i++)
+       bool dbvt_culling = false;
+       if (m_dbvt_culling) 
        {
-               MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer);
+               // test culling through Bullet
+               PHY__Vector4 planes[5];
+               // get the clip planes
+               MT_Vector4* cplanes = cam->GetNormalizedClipPlanes();
+               // and convert
+               planes[0].setValue(cplanes[0].getValue());
+               planes[1].setValue(cplanes[1].getValue());
+               planes[2].setValue(cplanes[2].getValue());
+               planes[3].setValue(cplanes[3].getValue());
+               planes[4].setValue(cplanes[5].getValue());
+               CullingInfo info(layer);
+               dbvt_culling = m_physicsEnvironment->cullingTest(PhysicsCullingCallback,&info,planes,5);
+       }
+       if (!dbvt_culling) {
+               // the physics engine couldn't help us, do it the hard way
+               for (int i = 0; i < m_objectlist->GetCount(); i++)
+               {
+                       MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer);
+               }
        }
-#else
-       if (cam->GetFrustumCulling())
-               MarkVisible(m_objecttree, rasty, cam, layer);
-       else
-               MarkSubTreeVisible(m_objecttree, rasty, true, cam, layer);
-#endif
 }
 
 // logic stuff
@@ -1393,7 +1437,7 @@ void KX_Scene::UpdateParents(double curtime)
        for (int i=0; i<GetRootParentList()->GetCount(); i++)
        {
                KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i);
-               parentobj->NodeUpdateGS(curtime,true);
+               parentobj->NodeUpdateGS(curtime);
        }
 }
 
@@ -1588,6 +1632,7 @@ PyAttributeDef KX_Scene::Attributes[] = {
        KX_PYATTRIBUTE_BOOL_RO("suspended",                     KX_Scene, m_suspend),
        KX_PYATTRIBUTE_BOOL_RO("activity_culling",      KX_Scene, m_activity_culling),
        KX_PYATTRIBUTE_FLOAT_RW("activity_culling_radius", 0.5f, FLT_MAX, KX_Scene, m_activity_box_radius),
+       KX_PYATTRIBUTE_BOOL_RO("dbvt_culling",          KX_Scene, m_dbvt_culling),
        KX_PYATTRIBUTE_RO_FUNCTION("__dict__",          KX_Scene, pyattr_get_dir_dict),
        { NULL }        //Sentinel
 };
index df51fce..9f05ddf 100644 (file)
@@ -85,6 +85,8 @@ class RAS_IRenderTools;
 class SCA_JoystickManager;
 class btCollisionShape;
 class KX_BlenderSceneConverter;
+struct KX_ClientObjectInfo;
+
 /**
  * The KX_Scene holds all data for an independent scene. It relates
  * KX_Objects to the specific objects in the modules.
@@ -92,6 +94,12 @@ class KX_BlenderSceneConverter;
 class KX_Scene : public PyObjectPlus, public SCA_IScene
 {
        Py_Header;
+
+       struct CullingInfo {
+               int m_layer;
+               CullingInfo(int layer) : m_layer(layer) {}
+       };
+
 protected:
        RAS_BucketManager*      m_bucketmanager;
        CListValue*                     m_tempObjectList;
@@ -251,6 +259,11 @@ protected:
         */
        bool m_activity_culling;
        
+       /**
+        * Toggle to enable or disable culling via DBVT broadphase of Bullet.
+        */
+       bool m_dbvt_culling;
+       
        /**
         * The framing settings used by this scene
         */
@@ -269,6 +282,7 @@ protected:
        void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam,int layer=0);
        void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam,int layer=0);
        void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam, int layer=0);
+       static void PhysicsCullingCallback(KX_ClientObjectInfo* objectInfo, void* cullingInfo);
 
        double                          m_suspendedtime;
        double                          m_suspendeddelta;
@@ -530,6 +544,9 @@ public:
        bool IsSuspended();
        bool IsClearingZBuffer();
        void EnableZBufferClearing(bool isclearingZbuffer);
+       // use of DBVT tree for camera culling
+       void SetDbvtCameraCulling(bool b) { m_dbvt_culling = b; };
+       bool GetDbvtCameraCulling() { return m_dbvt_culling; };
        
        void SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter);
 
index dcc87d6..e4aaef1 100644 (file)
@@ -55,6 +55,7 @@ public:
 
        virtual void            removeConstraint(void * constraintid);
        virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
+       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes) { return false; }
 
 
        //gamelogic callbacks
diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp
new file mode 100644 (file)
index 0000000..caf18fd
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "CcdPhysicsEnvironment.h"
+#include "CcdGraphicController.h"
+#include "btBulletDynamicsCommon.h"
+#include "MT_Point3.h"
+
+
+CcdGraphicController::CcdGraphicController (CcdPhysicsEnvironment* phyEnv, PHY_IMotionState* motionState) :
+       m_localAabbMin(0.f, 0.f, 0.f),
+       m_localAabbMax(0.f, 0.f, 0.f),
+       m_motionState(motionState),
+       m_phyEnv(phyEnv),
+       m_handle(NULL),
+       m_newClientInfo(NULL)
+{
+}
+
+CcdGraphicController::~CcdGraphicController()
+{
+       if (m_phyEnv)
+               m_phyEnv->removeCcdGraphicController(this);
+
+       if (m_motionState)
+               delete m_motionState;
+}
+
+void CcdGraphicController::setLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax)
+{
+       m_localAabbMin = aabbMin;
+       m_localAabbMax = aabbMax;
+       SetGraphicTransform();
+}
+
+void CcdGraphicController::setLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax)
+{
+       m_localAabbMin = btVector3(aabbMin[0],aabbMin[1],aabbMin[2]);
+       m_localAabbMax = btVector3(aabbMax[0],aabbMax[1],aabbMax[2]);
+       SetGraphicTransform();
+}
+
+
+void CcdGraphicController::getAabb(btVector3& aabbMin, btVector3& aabbMax)
+{
+       btVector3 pos;
+       btVector3 scale;
+       float ori[12];
+       m_motionState->getWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]);
+       m_motionState->getWorldScaling(scale.m_floats[0],scale.m_floats[1],scale.m_floats[2]);
+       m_motionState->getWorldOrientation(ori);
+       btMatrix3x3 rot(ori[0], ori[4], ori[8],
+                                       ori[1], ori[5], ori[9],
+                                       ori[2], ori[6], ori[10]);
+
+       btVector3 localAabbMin = m_localAabbMin;
+       btVector3 localAabbMax = m_localAabbMax;
+       btVector3 tmpAabbMin = m_localAabbMin * scale;
+       btVector3 tmpAabbMax = m_localAabbMax * scale;
+
+       localAabbMin[0] = (scale.getX() >= 0.) ? tmpAabbMin[0] : tmpAabbMax[0];
+       localAabbMin[1] = (scale.getY() >= 0.) ? tmpAabbMin[1] : tmpAabbMax[1];
+       localAabbMin[2] = (scale.getZ() >= 0.) ? tmpAabbMin[2] : tmpAabbMax[2];
+       localAabbMax[0] = (scale.getX() <= 0.) ? tmpAabbMin[0] : tmpAabbMax[0];
+       localAabbMax[1] = (scale.getY() <= 0.) ? tmpAabbMin[1] : tmpAabbMax[1];
+       localAabbMax[2] = (scale.getZ() <= 0.) ? tmpAabbMin[2] : tmpAabbMax[2];
+
+       btVector3 localHalfExtents = btScalar(0.5)*(localAabbMax-localAabbMin);
+       btVector3 localCenter = btScalar(0.5)*(localAabbMax+localAabbMin);
+       
+       btMatrix3x3 abs_b = rot.absolute();  
+       btVector3 center = rot*localCenter + pos;
+       btVector3 extent = abs_b*localHalfExtents;
+       aabbMin = center - extent;
+       aabbMax = center + extent;
+}
+
+bool CcdGraphicController::SetGraphicTransform()
+{
+       if (!m_handle) 
+               return false;
+       btVector3 aabbMin;
+       btVector3 aabbMax;
+       getAabb(aabbMin, aabbMax);
+       // update Aabb in broadphase
+       m_phyEnv->getCullingTree()->setAabb(m_handle,aabbMin,aabbMax,NULL);
+       return true;
+}
+
+PHY_IGraphicController* CcdGraphicController::GetReplica(class PHY_IMotionState* motionState)
+{
+       CcdGraphicController* replica = new CcdGraphicController(*this);
+       replica->m_motionState = motionState;
+       replica->m_newClientInfo = NULL;
+       replica->m_handle = NULL;
+       m_phyEnv->addCcdGraphicController(replica);
+       return replica;
+}
+
+
diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.h b/source/gameengine/Physics/Bullet/CcdGraphicController.h
new file mode 100644 (file)
index 0000000..8faa094
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose, 
+including commercial applications, and to alter it and redistribute it freely, 
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+#ifndef BULLET2_GRAPHICCONTROLLER_H
+#define BULLET2_GRAPHICCONTROLLER_H
+
+#include "PHY_IGraphicController.h"
+
+#include "btBulletDynamicsCommon.h"
+#include "LinearMath/btTransform.h"
+
+#include "PHY_IMotionState.h"
+#include "MT_Point3.h"
+
+class CcdPhysicsEnvironment;
+class btCollisionObject;
+
+///CcdGraphicController is a graphic object that supports view frustrum culling and occlusion
+class CcdGraphicController : public PHY_IGraphicController     
+{
+public:
+       CcdGraphicController(CcdPhysicsEnvironment* phyEnv, PHY_IMotionState* motionState);
+
+       virtual ~CcdGraphicController();
+
+       void setLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax);
+       void setLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax);
+
+       PHY_IMotionState* GetMotionState() { return m_motionState; }
+       void getAabb(btVector3& aabbMin, btVector3& aabbMax);
+
+       virtual void setBroadphaseHandle(btBroadphaseProxy* handle) { m_handle = handle; }
+       virtual btBroadphaseProxy* getBroadphaseHandle() { return m_handle; }
+
+       ////////////////////////////////////
+       // PHY_IGraphicController interface
+       ////////////////////////////////////
+
+       /**
+        * Updates the Aabb based on the motion state
+        */
+       virtual bool SetGraphicTransform();
+
+       // client info for culling
+       virtual void* getNewClientInfo() { return m_newClientInfo; }
+       virtual void setNewClientInfo(void* clientinfo) { m_newClientInfo = clientinfo; }
+       virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate);
+               
+private:
+       // unscaled aabb corner
+       btVector3 m_localAabbMin;
+       btVector3 m_localAabbMax;
+
+       PHY_IMotionState* m_motionState;
+       CcdPhysicsEnvironment* m_phyEnv;
+       btBroadphaseProxy* m_handle;
+       void* m_newClientInfo;
+
+};
+
+#endif //BULLET2_PHYSICSCONTROLLER_H
index bb2f53a..2283968 100644 (file)
@@ -1245,6 +1245,22 @@ void     DefaultMotionState::getWorldOrientation(float& quatIma0,float& quatIma1,flo
        quatReal = m_worldTransform.getRotation()[3];
 }
                
+void   DefaultMotionState::getWorldOrientation(float* ori)
+{
+       *ori++ = m_worldTransform.getBasis()[0].x();
+       *ori++ = m_worldTransform.getBasis()[1].x();
+       *ori++ = m_worldTransform.getBasis()[1].x();
+       *ori++ = 0.f;
+       *ori++ = m_worldTransform.getBasis()[0].y();
+       *ori++ = m_worldTransform.getBasis()[1].y();
+       *ori++ = m_worldTransform.getBasis()[1].y();
+       *ori++ = 0.f;
+       *ori++ = m_worldTransform.getBasis()[0].z();
+       *ori++ = m_worldTransform.getBasis()[1].z();
+       *ori++ = m_worldTransform.getBasis()[1].z();
+       *ori++ = 0.f;
+}
+
 void   DefaultMotionState::setWorldPosition(float posX,float posY,float posZ)
 {
        btVector3 pos(posX,posY,posZ);
index 510454a..245cde2 100644 (file)
@@ -544,6 +544,7 @@ class       DefaultMotionState : public PHY_IMotionState
                
                virtual void    setWorldPosition(float posX,float posY,float posZ);
                virtual void    setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal);
+               virtual void    getWorldOrientation(float* ori);
                
                virtual void    calculateWorldTransformations();
                
index dd21e58..cef2f24 100644 (file)
@@ -18,6 +18,7 @@ subject to the following restrictions:
 
 #include "CcdPhysicsEnvironment.h"
 #include "CcdPhysicsController.h"
+#include "CcdGraphicController.h"
 
 #include <algorithm>
 #include "btBulletDynamicsCommon.h"
@@ -316,8 +317,10 @@ static void DrawAabb(btIDebugDraw* debugDrawer,const btVector3& from,const btVec
 
 
 
-CcdPhysicsEnvironment::CcdPhysicsEnvironment(btDispatcher* dispatcher,btOverlappingPairCache* pairCache)
-:m_numIterations(10),
+CcdPhysicsEnvironment::CcdPhysicsEnvironment(bool useDbvtCulling,btDispatcher* dispatcher,btOverlappingPairCache* pairCache)
+:m_cullingCache(NULL),
+m_cullingTree(NULL),
+m_numIterations(10),
 m_scalingPropagated(false),
 m_numTimeSubSteps(1),
 m_ccdMode(0),
@@ -350,6 +353,11 @@ m_ownDispatcher(NULL)
        //m_broadphase = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000));
        //m_broadphase = new btSimpleBroadphase();
        m_broadphase = new btDbvtBroadphase();
+       // avoid any collision in the culling tree
+       if (useDbvtCulling) {
+               m_cullingCache = new btNullPairCache();
+               m_cullingTree = new btDbvtBroadphase(m_cullingCache);
+       }
 
        m_filterCallback = new CcdOverlapFilterCallBack(this);
        m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback);
@@ -364,7 +372,6 @@ m_ownDispatcher(NULL)
        m_gravity = btVector3(0.f,-10.f,0.f);
        m_dynamicsWorld->setGravity(m_gravity);
 
-
 }
 
 void   CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl)
@@ -558,6 +565,41 @@ void CcdPhysicsEnvironment::refreshCcdPhysicsController(CcdPhysicsController* ct
        }
 }
 
+void CcdPhysicsEnvironment::addCcdGraphicController(CcdGraphicController* ctrl)
+{
+       if (m_cullingTree)
+       {
+               btVector3       minAabb;
+               btVector3       maxAabb;
+               ctrl->getAabb(minAabb, maxAabb);
+
+               ctrl->setBroadphaseHandle(m_cullingTree->createProxy(
+                               minAabb,
+                               maxAabb,
+                               INVALID_SHAPE_PROXYTYPE,        // this parameter is not used
+                               ctrl,
+                               0,                                                      // this object does not collision with anything
+                               0,
+                               NULL,                                           // dispatcher => this parameter is not used
+                               0));
+
+               assert(ctrl->getBroadphaseHandle());
+       }
+}
+
+void CcdPhysicsEnvironment::removeCcdGraphicController(CcdGraphicController* ctrl)
+{
+       if (m_cullingTree)
+       {
+               btBroadphaseProxy* bp = ctrl->getBroadphaseHandle();
+               if (bp)
+               {
+                       m_cullingTree->destroyProxy(bp,NULL);
+                       ctrl->setBroadphaseHandle(0);
+               }
+       }
+}
+
 void   CcdPhysicsEnvironment::beginFrame()
 {
 
@@ -593,10 +635,10 @@ bool      CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep)
                (*it)->SynchronizeMotionStates(timeStep);
        }
 
-       for (it=m_controllers.begin(); it!=m_controllers.end(); it++)
-       {
-               (*it)->SynchronizeMotionStates(timeStep);
-       }
+       //for (it=m_controllers.begin(); it!=m_controllers.end(); it++)
+       //{
+       //      (*it)->SynchronizeMotionStates(timeStep);
+       //}
 
        for (i=0;i<m_wrapperVehicles.size();i++)
        {
@@ -1146,6 +1188,50 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac
        return result.m_controller;
 }
 
+struct DbvtCullingCallback : btDbvt::ICollide
+{
+       PHY_CullingCallback m_clientCallback;
+       void* m_userData;
+
+       DbvtCullingCallback(PHY_CullingCallback clientCallback, void* userData)
+       {
+               m_clientCallback = clientCallback;
+               m_userData = userData;
+       }
+
+       void Process(const btDbvtNode* node,btScalar depth)
+       {
+               Process(node);
+       }
+       void Process(const btDbvtNode* leaf)
+       {       
+               btBroadphaseProxy*      proxy=(btBroadphaseProxy*)leaf->data;
+               // the client object is a graphic controller
+               CcdGraphicController* ctrl = static_cast<CcdGraphicController*>(proxy->m_clientObject);
+               KX_ClientObjectInfo* info = (KX_ClientObjectInfo*)ctrl->getNewClientInfo();
+               if (info)
+                       (*m_clientCallback)(info, m_userData);
+       }
+};
+
+bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes)
+{
+       if (!m_cullingTree)
+               return false;
+       DbvtCullingCallback dispatcher(callback, userData);
+       btVector3 planes_n[5];
+       btScalar planes_o[5];
+       if (nplanes > 5)
+               nplanes = 5;
+       for (int i=0; i<nplanes; i++)
+       {
+               planes_n[i].setValue(planes[i][0], planes[i][1], planes[i][2]);
+               planes_o[i] = planes[i][3];
+       }
+       btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher);
+       btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher);              
+       return true;
+}
 
 
 int    CcdPhysicsEnvironment::getNumContactPoints()
@@ -1211,6 +1297,13 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment()
 
        if (NULL != m_broadphase)
                delete m_broadphase;
+
+       if (NULL != m_cullingTree)
+               delete m_cullingTree;
+
+       if (NULL != m_cullingCache)
+               delete m_cullingCache;
+
 }
 
 
index 2f1f0bb..ddbcbe6 100644 (file)
@@ -20,6 +20,7 @@ subject to the following restrictions:
 #include <vector>
 #include <set>
 class CcdPhysicsController;
+class CcdGraphicController;
 #include "LinearMath/btVector3.h"
 #include "LinearMath/btTransform.h"
 
@@ -40,6 +41,7 @@ class btDispatcher;
 class WrapperVehicle;
 class btPersistentManifold;
 class btBroadphaseInterface;
+struct btDbvtBroadphase;
 class btOverlappingPairCache;
 class btIDebugDraw;
 class PHY_IVehicle;
@@ -58,7 +60,10 @@ protected:
        btIDebugDraw*   m_debugDrawer;
        
        class btDefaultCollisionConfiguration* m_collisionConfiguration;
-       class btBroadphaseInterface*                    m_broadphase;
+    class btBroadphaseInterface*               m_broadphase;   // broadphase for dynamic world
+       // for culling only
+       btOverlappingPairCache*                         m_cullingCache;
+       struct btDbvtBroadphase*                        m_cullingTree;  // broadphase for culling
 
        //solver iterations
        int     m_numIterations;
@@ -77,7 +82,7 @@ protected:
        void    processFhSprings(double curTime,float timeStep);
 
        public:
-               CcdPhysicsEnvironment(btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0);
+               CcdPhysicsEnvironment(bool useDbvtCulling, btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0);
 
                virtual         ~CcdPhysicsEnvironment();
 
@@ -167,6 +172,7 @@ protected:
                btTypedConstraint*      getConstraintById(int constraintId);
 
                virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
+               virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes);
 
 
                //Methods for gamelogic collision/physics callbacks
@@ -200,7 +206,12 @@ protected:
 
                void    refreshCcdPhysicsController(CcdPhysicsController* ctrl);
 
+               void    addCcdGraphicController(CcdGraphicController* ctrl);
+
+               void    removeCcdGraphicController(CcdGraphicController* ctrl);
+
                btBroadphaseInterface*  getBroadphase();
+               btDbvtBroadphase*       getCullingTree() { return m_cullingTree; }
 
                btDispatcher*   getDispatcher();
                
index a92b1e7..fae1844 100644 (file)
@@ -70,6 +70,7 @@ public:
        }
 
        virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
+       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes) { return false; }
 
 
        //gamelogic callbacks
index 65b07a7..9942a36 100644 (file)
@@ -76,6 +76,7 @@ public:
        }
 
        virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
+       virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes) { return false; }
 
        
        //gamelogic callbacks
index c5cf92b..7ce4000 100644 (file)
@@ -19,12 +19,42 @@ subject to the following restrictions:
 
 
 
-
+struct KX_ClientObjectInfo;
 class PHY_Shape;
 
 struct PHY__Vector3
 {
        float   m_vec[4];
+
+       operator const float* () const 
+       { 
+               return &m_vec[0];
+       }       
+       operator float* () 
+       { 
+               return &m_vec[0];
+       }       
+};
+
+struct PHY__Vector4
+{
+       float   m_vec[4];
+       PHY__Vector4() {}
+       void setValue(const float *value)
+       {
+               m_vec[0] = *value++;
+               m_vec[1] = *value++;
+               m_vec[2] = *value++;
+               m_vec[3] = *value++;
+       }
+       void setValue(const double *value)
+       {
+               m_vec[0] = (float)(*value++);
+               m_vec[1] = (float)(*value++);
+               m_vec[2] = (float)(*value++);
+               m_vec[3] = (float)(*value++);
+       }
+
        operator const float* () const 
        { 
                return &m_vec[0];
@@ -34,6 +64,7 @@ struct        PHY__Vector3
                return &m_vec[0];
        }       
 };
+
 //typedef      float   PHY__Vector3[4];
 
 enum
@@ -59,7 +90,7 @@ enum
                                                                                   void *client_object1,
                                                                                   void *client_object2,
                                                                                   const PHY_CollData *coll_data);
-               
+       typedef void (*PHY_CullingCallback)(KX_ClientObjectInfo* info, void* param);
 
 
 /// PHY_PhysicsType enumerates all possible Physics Entities.
diff --git a/source/gameengine/Physics/common/PHY_IController.cpp b/source/gameengine/Physics/common/PHY_IController.cpp
new file mode 100644 (file)
index 0000000..47fe9a9
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "PHY_IController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+PHY_IController::~PHY_IController()
+{
+
+}
+
diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h
new file mode 100644 (file)
index 0000000..45e93f9
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef PHY_ICONTROLLER_H
+#define PHY_ICONTROLLER_H
+
+#include "PHY_DynamicTypes.h"
+
+
+
+/**
+       PHY_IController is the abstract simplified Interface to objects 
+       controlled by the physics engine. This includes the physics objects
+       and the graphics object for view frustrum and occlusion culling.
+*/
+class PHY_IController  
+{
+       public:
+               
+               virtual ~PHY_IController();
+               // clientinfo for raycasts for example
+               virtual void*                           getNewClientInfo()=0;
+               virtual void                            setNewClientInfo(void* clientinfo)=0;
+
+};
+
+#endif //PHY_ICONTROLLER_H
+
diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.cpp b/source/gameengine/Physics/common/PHY_IGraphicController.cpp
new file mode 100644 (file)
index 0000000..4dccecd
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "PHY_IGraphicController.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+PHY_IGraphicController::~PHY_IGraphicController()
+{
+
+}
+
diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.h b/source/gameengine/Physics/common/PHY_IGraphicController.h
new file mode 100644 (file)
index 0000000..36b8a97
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef PHY_IGRAPHICCONTROLLER_H
+#define PHY_IGRAPHICCONTROLLER_H
+
+#include "PHY_IController.h"
+
+
+
+/**
+       PHY_IPhysicsController is the abstract simplified Interface to a physical object.
+       It contains the IMotionState and IDeformableMesh Interfaces.
+*/
+class PHY_IGraphicController : public PHY_IController
+{
+
+       public:
+               
+               virtual ~PHY_IGraphicController();
+               /**
+                       SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
+               */
+               virtual bool SetGraphicTransform()=0;
+
+               virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate) {return 0;}
+
+};
+
+#endif //PHY_IGRAPHICCONTROLLER_H
+
index d759b0a..64bb810 100644 (file)
@@ -43,6 +43,8 @@ class PHY_IMotionState
                virtual void    getWorldPosition(float& posX,float& posY,float& posZ)=0;
                virtual void    getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0;
                virtual void    getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)=0;
+               // ori = array 12 floats, [0..3] = first column + 0, [4..7] = second colum, [8..11] = third column
+               virtual void    getWorldOrientation(float* ori)=0;
                
                virtual void    setWorldPosition(float posX,float posY,float posZ)=0;
                virtual void    setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)=0;
index 884e14c..6cba6fa 100644 (file)
@@ -29,7 +29,7 @@
 #ifndef PHY_IPHYSICSCONTROLLER_H
 #define PHY_IPHYSICSCONTROLLER_H
 
-#include "PHY_DynamicTypes.h"
+#include "PHY_IController.h"
 
 
 
@@ -37,7 +37,7 @@
        PHY_IPhysicsController is the abstract simplified Interface to a physical object.
        It contains the IMotionState and IDeformableMesh Interfaces.
 */
-class PHY_IPhysicsController   
+class PHY_IPhysicsController : public PHY_IController
 {
 
        public:
@@ -82,9 +82,7 @@ class PHY_IPhysicsController
 
                // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted 
                virtual void            setRigidBody(bool rigid)=0;
-               // clientinfo for raycasts for example
-               virtual void*                           getNewClientInfo()=0;
-               virtual void                            setNewClientInfo(void* clientinfo)=0;
+
                virtual PHY_IPhysicsController* GetReplica() {return 0;}
 
                virtual void    calcXform() =0;
index 226ba3a..5edafe6 100644 (file)
@@ -142,6 +142,8 @@ class PHY_IPhysicsEnvironment
 
                virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0;
 
+               //culling based on physical broad phase
+               virtual bool cullingTest(PHY_CullingCallback callback, void *userData, PHY__Vector4* planeNormals, int planeNumber) = 0;
 
                //Methods for gamelogic collision/physics callbacks
                //todo:
index f7938bb..ec290f8 100644 (file)
@@ -148,6 +148,10 @@ void RAS_BucketManager::RenderAlphaBuckets(
 
                while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools))
                        sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms));
+
+               // make this mesh slot culled automatically for next frame
+               // it will be culled out by frustrum culling
+               sit->m_ms->SetCulled(true);
        }
 
        rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
@@ -170,6 +174,10 @@ void RAS_BucketManager::RenderSolidBuckets(
 
                        while ((*bit)->ActivateMaterial(cameratrans, rasty, rendertools))
                                (*bit)->RenderMeshSlot(cameratrans, rasty, rendertools, *mit);
+
+                       // make this mesh slot culled automatically for next frame
+                       // it will be culled out by frustrum culling
+                       mit->SetCulled(true);
                }
        }
        
index 610bd13..0a226ac 100644 (file)
@@ -163,6 +163,13 @@ struct RAS_FrameFrustum
        float x2,y2;
 };     
 
+/* must match R_CULLING_... from DNA_scene_types.h */
+enum RAS_CullingMode
+{
+       RAS_CULLING_DBVT = 0,
+       RAS_CULLING_NORMAL,
+       RAS_CULLING_NONE
+};
 
 /**
  * @section RAS_FramingManager
index 475f01d..2117703 100644 (file)
@@ -156,6 +156,7 @@ public:
        bool Join(RAS_MeshSlot *target, MT_Scalar distance);
        bool Equals(RAS_MeshSlot *target);
        bool IsCulled();
+       void SetCulled(bool culled) { m_bCulled = culled; }
 };
 
 /* Used by RAS_MeshObject, to point to it's slots in a bucket */
index a44262d..66fcc5c 100644 (file)
@@ -188,6 +188,13 @@ void SG_BBox::getaa(MT_Point3 *box, const MT_Transform &world) const
        *box++ = max;
 }
 
+void SG_BBox::getmm(MT_Point3 *box, const MT_Transform &world) const
+{
+       const MT_Point3 min(world(m_min)), max(world(m_max));
+       *box++ = min;
+       *box++ = max;
+}
+
 void SG_BBox::split(SG_BBox &left, SG_BBox &right) const
 {
        MT_Scalar sizex = m_max[0] - m_min[0];
index b7e8ff6..c39ad26 100644 (file)
@@ -122,6 +122,8 @@ public:
         */
        void getaa(MT_Point3 *box, const MT_Transform &world) const;
        
+       void getmm(MT_Point3 *box, const MT_Transform &world) const;
+
        void split(SG_BBox &left, SG_BBox &right) const;
        
        friend class SG_Tree;
index d0bdac5..fbab403 100644 (file)
@@ -33,6 +33,8 @@
 #include <config.h>
 #endif
 
+SG_Stage gSG_Stage = SG_STAGE_UNKNOWN;
+
 SG_IObject::
 SG_IObject(
        void* clientobj,
index 7f6bdfb..9012b53 100644 (file)
 
 #include <vector>
 
+// used for debugging: stage of the game engine main loop at which a Scenegraph modification is done
+enum SG_Stage
+{
+       SG_STAGE_UNKNOWN = 0,
+       SG_STAGE_NETWORK,
+       SG_STAGE_NETWORK_UPDATE,
+       SG_STAGE_PHYSICS1,
+       SG_STAGE_PHYSICS1_UPDATE,
+       SG_STAGE_CONTROLLER,
+       SG_STAGE_CONTROLLER_UPDATE,
+       SG_STAGE_ACTUATOR,
+       SG_STAGE_ACTUATOR_UPDATE,
+       SG_STAGE_PHYSICS2,
+       SG_STAGE_PHYSICS2_UPDATE,
+       SG_STAGE_SCENE,
+       SG_STAGE_RENDER,
+       SG_STAGE_CONVERTER,
+       SG_STAGE_CULLING,
+       SG_STAGE_MAX
+};
+
+extern SG_Stage gSG_Stage;
+
+inline void SG_SetActiveStage(SG_Stage stage)
+{
+       gSG_Stage = stage;
+}
+       
+
+
 class SG_Controller;
 class SG_IObject;
 
index 8de7ac8..64d9019 100644 (file)
@@ -219,18 +219,19 @@ void SG_Node::RemoveChild(SG_Node* child)
 
 
 
-void SG_Node::UpdateWorldData(double time)
+void SG_Node::UpdateWorldData(double time, bool parentUpdated)
 {
        //if (!GetSGParent())
        //      return;
 
-       if (UpdateSpatialData(GetSGParent(),time))
+       if (UpdateSpatialData(GetSGParent(),time,parentUpdated))
+               // to update the 
                ActivateUpdateTransformCallback();
 
        // update children's worlddata
        for (NodeList::iterator it = m_children.begin();it!=m_children.end();++it)
        {
-               (*it)->UpdateWorldData(time);
+               (*it)->UpdateWorldData(time, parentUpdated);
        }
 }
 
index ffaaad8..2994365 100644 (file)
@@ -175,7 +175,8 @@ public:
 
                void            
        UpdateWorldData(
-               double time
+               double time,
+               bool parentUpdated=false
        );
 
        /**
index 6507cb9..8f45df0 100644 (file)
@@ -69,7 +69,8 @@ public :
                bool
        UpdateChildCoordinates(
                SG_Spatial * child,
-               const SG_Spatial * parent
+               const SG_Spatial * parent,
+               bool& parentUpdated
        ) = 0;
 
        virtual 
index 99aeb3e..2f31768 100644 (file)
@@ -55,7 +55,8 @@ SG_Spatial(
        m_parent_relation (NULL),
        
        m_bbox(MT_Point3(-1.0, -1.0, -1.0), MT_Point3(1.0, 1.0, 1.0)),
-       m_radius(1.0)
+       m_radius(1.0),
+       m_modified(true)
 {
 }
 
@@ -101,6 +102,7 @@ SetParentRelation(
 ){
        delete (m_parent_relation);
        m_parent_relation = relation;
+       m_modified = true;
 }
 
 
@@ -114,7 +116,8 @@ SetParentRelation(
 SG_Spatial::
 UpdateSpatialData(
        const SG_Spatial *parent,
-       double time
+       double time,
+       bool& parentUpdated
 ){
 
     bool bComputesWorldTransform = false;
@@ -135,14 +138,14 @@ UpdateSpatialData(
        // our world coordinates.
 
        if (!bComputesWorldTransform)
-               bComputesWorldTransform = ComputeWorldTransforms(parent);
+               bComputesWorldTransform = ComputeWorldTransforms(parent, parentUpdated);
 
        return bComputesWorldTransform;
 }
 
-bool   SG_Spatial::ComputeWorldTransforms(const SG_Spatial *parent)
+bool   SG_Spatial::ComputeWorldTransforms(const SG_Spatial *parent, bool& parentUpdated)
 {
-       return m_parent_relation->UpdateChildCoordinates(this,parent);
+       return m_parent_relation->UpdateChildCoordinates(this,parent,parentUpdated);
 }
 
 /**
@@ -166,6 +169,7 @@ RelativeTranslate(
                        m_localPosition += trans;
                }
        }
+       m_modified = true;
 }      
        
        void 
@@ -174,6 +178,7 @@ SetLocalPosition(
        const MT_Point3& trans
 ){
        m_localPosition = trans;
+       m_modified = true;
 }
 
        void                            
@@ -194,6 +199,7 @@ RelativeScale(
        const MT_Vector3& scale
 ){
        m_localScaling = m_localScaling * scale;
+       m_modified = true;
 }
 
        void 
@@ -202,6 +208,7 @@ SetLocalScale(
        const MT_Vector3& scale
 ){
        m_localScaling = scale;
+       m_modified = true;
 }
 
 
@@ -229,6 +236,7 @@ RelativeRotate(
                rot 
        :
        (GetWorldOrientation().inverse() * rot * GetWorldOrientation()));
+       m_modified = true;
 }
 
        void 
@@ -236,6 +244,7 @@ SG_Spatial::
 SetLocalOrientation(const MT_Matrix3x3& rot)
 {
        m_localRotation = rot;
+       m_modified = true;
 }
 
 
index 6ccec2a..c2ed80d 100644 (file)
@@ -61,7 +61,7 @@ protected:
        
        SG_BBox                 m_bbox;
        MT_Scalar               m_radius;
-       
+       bool                    m_modified;
 
 public:
 
@@ -180,7 +180,7 @@ public:
 
        MT_Transform GetWorldTransform() const;
 
-       bool    ComputeWorldTransforms(         const SG_Spatial *parent);
+       bool    ComputeWorldTransforms(const SG_Spatial *parent, bool& parentUpdated);
 
        /**
         * Bounding box functions.
@@ -193,9 +193,14 @@ public:
        
        MT_Scalar Radius() const { return m_radius; }
        void SetRadius(MT_Scalar radius) { m_radius = radius; }
+       bool IsModified() { return m_modified; }
        
 protected:
        friend class SG_Controller;
+       friend class KX_BoneParentRelation;
+       friend class KX_VertexParentRelation;
+       friend class KX_SlowParentRelation;
+       friend class KX_NormalParentRelation;
        
        /** 
         * Protected constructor this class is not
@@ -223,8 +228,10 @@ protected:
                bool 
        UpdateSpatialData(
                const SG_Spatial *parent,
-               double time
+               double time,
+               bool& parentUpdated
        );
+       void SetModified(bool modified) { m_modified = modified; }
 
 };