Merging with trunk up to r38631.
[blender.git] / source / gameengine / Ketsji / KX_Scene.cpp
index 291003594ae5331c746fd497620e355bbf886b4b..a49c1bf4b4cbd48f918ae500277b73d55d786cff 100644 (file)
@@ -15,7 +15,7 @@
  *
  * 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.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  * Ketsji scene. Holds references to all scene data.
  */
 
-#ifdef WIN32
+/** \file gameengine/Ketsji/KX_Scene.cpp
+ *  \ingroup ketsji
+ */
+
+
+#if defined(WIN32) && !defined(FREE_WINDOWS)
 #pragma warning (disable : 4786)
 #endif //WIN32
 
 #include "SCA_IController.h"
 #include "SCA_IActuator.h"
 #include "SG_Node.h"
-#include "SYS_System.h"
+#include "BL_System.h"
 #include "SG_Controller.h"
 #include "SG_IObject.h"
 #include "SG_Tree.h"
 #include "DNA_group_types.h"
 #include "DNA_scene_types.h"
-#include "BKE_anim.h"
 
 #include "KX_SG_NodeRelationships.h"
 
 #include "BL_ModifierDeformer.h"
 #include "BL_ShapeDeformer.h"
 #include "BL_DeformableGameObject.h"
-#include "KX_SoftBodyDeformer.h"
-
-// to get USE_BULLET!
-#include "KX_ConvertPhysicsObject.h"
 
 #ifdef USE_BULLET
+#include "KX_SoftBodyDeformer.h"
+#include "KX_ConvertPhysicsObject.h"
 #include "CcdPhysicsEnvironment.h"
 #include "CcdPhysicsController.h"
 #endif
@@ -139,7 +141,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
                                   class SCA_IInputDevice* mousedevice,
                                   class NG_NetworkDeviceInterface *ndi,
                                   const STR_String& sceneName,
-                                  Scene *scene): 
+                                  Scene *scene,
+                                  class RAS_ICanvas* canvas): 
        PyObjectPlus(),
        m_keyboardmgr(NULL),
        m_mousemgr(NULL),
@@ -170,7 +173,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
        
        m_timemgr = new SCA_TimeEventManager(m_logicmgr);
        m_keyboardmgr = new SCA_KeyboardManager(m_logicmgr,keyboarddevice);
-       m_mousemgr = new SCA_MouseManager(m_logicmgr,mousedevice);
+       m_mousemgr = new SCA_MouseManager(m_logicmgr,mousedevice, canvas);
        
        //SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr);
        //SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr);
@@ -210,7 +213,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
 
        m_bucketmanager=new RAS_BucketManager();
        
-#ifndef DISABLE_PYTHON
+#ifdef WITH_PYTHON
        m_attr_dict = PyDict_New(); /* new ref */
        m_draw_call_pre = NULL;
        m_draw_call_post = NULL;
@@ -264,12 +267,14 @@ KX_Scene::~KX_Scene()
                delete m_bucketmanager;
        }
 
-#ifndef DISABLE_PYTHON
+#ifdef WITH_PYTHON
        PyDict_Clear(m_attr_dict);
-       Py_DECREF(m_attr_dict);
+       /* Py_CLEAR: Py_DECREF's and NULL's */
+       Py_CLEAR(m_attr_dict);
 
-       Py_XDECREF(m_draw_call_pre);
-       Py_XDECREF(m_draw_call_post);
+       /* these may be NULL but the macro checks */
+       Py_CLEAR(m_draw_call_pre);
+       Py_CLEAR(m_draw_call_post);
 #endif
 }
 
@@ -325,7 +330,10 @@ list<class KX_Camera*>* KX_Scene::GetCameras()
        return &m_cameras;
 }
 
-
+list<class KX_FontObject*>* KX_Scene::GetFonts()
+{
+       return &m_fonts;
+}
 
 void KX_Scene::SetFramingType(RAS_FrameSettings & frame_settings)
 {
@@ -407,34 +415,6 @@ bool KX_Scene::IsClearingZBuffer()
        return m_isclearingZbuffer;
 }
 
-void KX_Scene::RunDrawingCallbacks(PyObject* cb_list)
-{
-       int len;
-
-       if (cb_list && (len=PyList_GET_SIZE(cb_list)))
-       {
-               PyObject* args= PyTuple_New(0); // save python creating each call
-               PyObject* func;
-               PyObject* ret;
-
-               // Iterate the list and run the callbacks
-               for (int pos=0; pos < len; pos++)
-               {
-                       func= PyList_GET_ITEM(cb_list, pos);
-                       ret= PyObject_Call(func, args, NULL);
-                       if (ret==NULL) {
-                               PyErr_Print();
-                               PyErr_Clear();
-                       }
-                       else {
-                               Py_DECREF(ret);
-                       }
-               }
-
-               Py_DECREF(args);
-       }
-}
-
 void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer)
 {
        m_isclearingZbuffer = isclearingZbuffer;
@@ -557,7 +537,7 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
 // replica of the hierarchy in order to make cross-links work properly
 // !
 // It is VERY important that the order of sensors and actuators in
-// the replicated object is preserved: it is is used to reconnect the logic.
+// the replicated object is preserved: it is used to reconnect the logic.
 // This method is more robust then using the bricks name in case of complex 
 // group replication. The replication of logic bricks is done in 
 // SCA_IObject::ReParentLogic(), make sure it preserves the order of the bricks.
@@ -842,6 +822,8 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
                // add a timebomb to this object
                // for now, convert between so called frames and realtime
                m_tempObjectList->Add(replica->AddRef());
+               // this convert the life from frames to sort-of seconds, hard coded 0.02 that assumes we have 50 frames per second
+               // if you change this value, make sure you change it in KX_GameObject::pyattr_get_life property too
                CValue *fval = new CFloatValue(lifespan*0.02);
                replica->SetProperty("::timebomb",fval);
                fval->Release();
@@ -989,8 +971,8 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
        {
                m_logicmgr->RemoveSensor(*its);
        }
-       
-    SCA_ControllerList& controllers = newobj->GetControllers();
+
+       SCA_ControllerList& controllers = newobj->GetControllers();
        for (SCA_ControllerList::iterator itc = controllers.begin();
                 !(itc==controllers.end());itc++)
        {
@@ -1042,6 +1024,9 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
        // in case this is a camera
        m_cameras.remove((KX_Camera*)newobj);
 
+       // in case this is a font
+       m_fonts.remove((KX_FontObject*)newobj);
+
        /* currently does nothing, keep incase we need to Unregister something */
 #if 0
        if (m_sceneConverter)
@@ -1094,15 +1079,16 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
                        bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE;
                        bool bHasDvert = blendmesh->dvert != NULL;
                        bool bHasArmature = 
+                               BL_ModifierDeformer::HasArmatureDeformer(blendobj) &&
                                parentobj &&                                                            // current parent is armature
                                parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE &&
                                oldblendobj &&                                                          // needed for mesh deform
                                blendobj->parent &&                                                     // original object had armature (not sure this test is needed)
-                               blendobj->parent->type == OB_ARMATURE && 
-                               blendobj->partype==PARSKEL && 
+                               blendobj->parent->type == OB_ARMATURE &&
                                blendmesh->dvert!=NULL;                                         // mesh has vertex group
+#ifdef USE_BULLET
                        bool bHasSoftBody = (!parentobj && (blendobj->gameflag & OB_SOFT_BODY));
-
+#endif
                        bool releaseParent = true;
 
                        
@@ -1191,11 +1177,13 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
                                );
                                newobj->SetDeformer(meshdeformer);
                        }
+#ifdef USE_BULLET
                        else if (bHasSoftBody)
                        {
                                KX_SoftBodyDeformer *softdeformer = new KX_SoftBodyDeformer(mesh, newobj);
                                newobj->SetDeformer(softdeformer);
                        }
+#endif
 
                        // release parent reference if its not being used 
                        if( releaseParent && parentobj)
@@ -1205,12 +1193,35 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
 
        gameobj->AddMeshUser();
        }
-       
+
+#ifdef USE_BULLET
        if(use_phys) { /* update the new assigned mesh with the physics mesh */
                KX_ReInstanceBulletShapeFromMesh(gameobj, NULL, use_gfx?NULL:mesh);
        }
+#endif
 }
 
+/* Font Object routines */
+void KX_Scene::AddFont(KX_FontObject* font)
+{
+       if (!FindFont(font))
+               m_fonts.push_back(font);
+}
+
+KX_FontObject* KX_Scene::FindFont(KX_FontObject* font)
+{
+       list<KX_FontObject*>::iterator it = m_fonts.begin();
+
+       while ( (it != m_fonts.end()) 
+                       && ((*it) != font) ) {
+         ++it;
+       }
+
+       return ((it == m_fonts.end()) ? NULL : (*it));
+}
+
+
+/* Camera Object routines */
 KX_Camera* KX_Scene::FindCamera(KX_Camera* cam)
 {
        list<KX_Camera*>::iterator it = m_cameras.begin();
@@ -1491,7 +1502,12 @@ void KX_Scene::LogicBeginFrame(double curtime)
        m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate());
 }
 
-
+void KX_Scene::UpdateAnimations(double curtime)
+{
+       // Update any animations
+       for (int i=0; i<GetObjectList()->GetCount(); ++i)
+               ((KX_GameObject*)GetObjectList()->GetValue(i))->UpdateActionManager(curtime);
+}
 
 void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
 {
@@ -1503,7 +1519,7 @@ void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
 void KX_Scene::LogicEndFrame()
 {
        m_logicmgr->EndFrame();
-       int numobj = m_euthanasyobjects->GetCount();
+       int numobj;
 
        KX_GameObject* obj;
 
@@ -1657,10 +1673,14 @@ double KX_Scene::getSuspendedDelta()
        return m_suspendeddelta;
 }
 
-#ifndef DISABLE_PYTHON
-
+short KX_Scene::GetAnimationFPS()
+{
+       return m_blenderScene->r.frs_sec;
+}
 
+#ifdef USE_BULLET
 #include "KX_BulletPhysicsController.h"
+#endif
 
 static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *to)
 {
@@ -1675,16 +1695,19 @@ static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *to)
        }
 
        /* near sensors have physics controllers */
+#ifdef USE_BULLET
        KX_TouchSensor *touch_sensor = dynamic_cast<class KX_TouchSensor *>(brick);
        if(touch_sensor) {
                touch_sensor->GetPhysicsController()->SetPhysicsEnvironment(to->GetPhysicsEnvironment());
        }
+#endif
 }
 
+#ifdef USE_BULLET
 #include "CcdGraphicController.h" // XXX  ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment());
 #include "CcdPhysicsEnvironment.h" // XXX  ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment());
 #include "KX_BulletPhysicsController.h"
-
+#endif
 
 static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene *from)
 {
@@ -1743,8 +1766,13 @@ static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene
        if(sg) {
                if(sg->GetSGClientInfo() == from) {
                        sg->SetSGClientInfo(to);
-               }
 
+                       /* Make sure to grab the children too since they might not be tied to a game object */
+                       NodeList children = sg->GetSGChildren();
+                       for (int i=0; i<children.size(); i++)
+                                       children[i]->SetSGClientInfo(to);
+               }
+#ifdef USE_BULLET
                SGControllerList::iterator contit;
                SGControllerList& controllers = sg->GetSGControllerList();
                for (contit = controllers.begin();contit!=controllers.end();++contit)
@@ -1753,11 +1781,23 @@ static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene
                        if (phys_ctrl)
                                phys_ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment());
                }
+#endif // USE_BULLET
        }
+       /* If the object is a light, update it's scene */
+       if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
+               ((KX_LightObject*)gameobj)->UpdateScene(to);
+
+       /* Add the object to the scene's logic manager */
+       to->GetLogicManager()->RegisterGameObjectName(gameobj->GetName(), gameobj);
+       to->GetLogicManager()->RegisterGameObj(gameobj->GetBlenderObject(), gameobj);
+
+       for (int i=0; i<gameobj->GetMeshCount(); ++i)
+               to->GetLogicManager()->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), gameobj->GetBlenderObject());
 }
 
 bool KX_Scene::MergeScene(KX_Scene *other)
 {
+#ifdef USE_BULLET
        CcdPhysicsEnvironment *env=                     dynamic_cast<CcdPhysicsEnvironment *>(this->GetPhysicsEnvironment());
        CcdPhysicsEnvironment *env_other=       dynamic_cast<CcdPhysicsEnvironment *>(other->GetPhysicsEnvironment());
 
@@ -1767,6 +1807,7 @@ bool KX_Scene::MergeScene(KX_Scene *other)
                printf("\tsource %d, terget %d\n", (int)(env!=NULL), (int)(env_other!=NULL));
                return false;
        }
+#endif // USE_BULLET
 
        if(GetSceneConverter() != other->GetSceneConverter()) {
                printf("KX_Scene::MergeScene: converters differ, aborting\n");
@@ -1774,7 +1815,7 @@ bool KX_Scene::MergeScene(KX_Scene *other)
        }
 
 
-       GetBucketManager()->MergeBucketManager(other->GetBucketManager());
+       GetBucketManager()->MergeBucketManager(other->GetBucketManager(), this);
 
        /* move materials across, assume they both use the same scene-converters */
        GetSceneConverter()->MergeScene(this, other);
@@ -1809,9 +1850,11 @@ bool KX_Scene::MergeScene(KX_Scene *other)
        GetLightList()->MergeList(other->GetLightList());
        other->GetLightList()->ReleaseAndRemoveAll();
 
+#ifdef USE_BULLET
        if(env) /* bullet scene? - dummy scenes dont need touching */
                env->MergeEnvironment(env_other);
-
+#endif
+       
        /* merge logic */
        {
                SCA_LogicManager *logicmgr=                     GetLogicManager();
@@ -1823,7 +1866,7 @@ bool KX_Scene::MergeScene(KX_Scene *other)
                //SCA_EventManager *evtmgr;
                SCA_EventManager *evtmgr_other;
 
-               for(int i= 0; i < evtmgrs.size(); i++) {
+               for(unsigned int i= 0; i < evtmgrs.size(); i++) {
                        evtmgr_other= logicmgr_other->FindEventManager(evtmgrs[i]->GetType());
 
                        if(evtmgr_other) /* unlikely but possible one scene has a joystick and not the other */
@@ -1831,10 +1874,60 @@ bool KX_Scene::MergeScene(KX_Scene *other)
 
                        /* when merging objects sensors are moved across into the new manager, dont need to do this here */
                }
+
+               /* grab any timer properties from the other scene */
+               SCA_TimeEventManager *timemgr=          GetTimeEventManager();
+               SCA_TimeEventManager *timemgr_other=    other->GetTimeEventManager();
+               vector<CValue*> times = timemgr_other->GetTimeValues();
+
+               for(unsigned int i= 0; i < times.size(); i++) {
+                       timemgr->AddTimeProperty(times[i]);
+               }
+               
        }
        return true;
 }
 
+void KX_Scene::Update2DFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text)
+{
+       m_filtermanager.EnableFilter(propNames, gameObj, filtermode, pass, text);
+}
+
+void KX_Scene::Render2DFilters(RAS_ICanvas* canvas)
+{
+       m_filtermanager.RenderFilters(canvas);
+}
+
+#ifdef WITH_PYTHON
+
+void KX_Scene::RunDrawingCallbacks(PyObject* cb_list)
+{
+       int len;
+
+       if (cb_list && (len=PyList_GET_SIZE(cb_list)))
+       {
+               PyObject* args= PyTuple_New(0); // save python creating each call
+               PyObject* func;
+               PyObject* ret;
+
+               // Iterate the list and run the callbacks
+               for (int pos=0; pos < len; pos++)
+               {
+                       func= PyList_GET_ITEM(cb_list, pos);
+                       ret= PyObject_Call(func, args, NULL);
+                       if (ret==NULL) {
+                               PyErr_Print();
+                               PyErr_Clear();
+                       }
+                       else {
+                               Py_DECREF(ret);
+                       }
+               }
+
+               Py_DECREF(args);
+       }
+}
+
 //----------------------------------------------------------------------------
 //Python
 
@@ -1868,6 +1961,8 @@ PyMethodDef KX_Scene::Methods[] = {
        KX_PYMETHODTABLE(KX_Scene, end),
        KX_PYMETHODTABLE(KX_Scene, restart),
        KX_PYMETHODTABLE(KX_Scene, replace),
+       KX_PYMETHODTABLE(KX_Scene, suspend),
+       KX_PYMETHODTABLE(KX_Scene, resume),
        
        /* dict style access */
        KX_PYMETHODTABLE(KX_Scene, get),
@@ -1977,6 +2072,8 @@ PySequenceMethods KX_Scene::Sequence = {
        NULL,           /* sq_ass_item */
        NULL,           /* sq_ass_slice */
        (objobjproc)Seq_Contains,       /* sq_contains */
+       (binaryfunc) NULL, /* sq_inplace_concat */
+       (ssizeargfunc) NULL, /* sq_inplace_repeat */
 };
 
 PyObject* KX_Scene::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
@@ -2049,8 +2146,7 @@ PyObject* KX_Scene::pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATT
 
        if(self->m_draw_call_pre==NULL)
                self->m_draw_call_pre= PyList_New(0);
-       else
-               Py_INCREF(self->m_draw_call_pre);
+       Py_INCREF(self->m_draw_call_pre);
        return self->m_draw_call_pre;
 }
 
@@ -2060,8 +2156,7 @@ PyObject* KX_Scene::pyattr_get_drawing_callback_post(void *self_v, const KX_PYAT
 
        if(self->m_draw_call_post==NULL)
                self->m_draw_call_post= PyList_New(0);
-       else
-               Py_INCREF(self->m_draw_call_post);
+       Py_INCREF(self->m_draw_call_post);
        return self->m_draw_call_post;
 }
 
@@ -2174,6 +2269,24 @@ KX_PYMETHODDEF_DOC(KX_Scene, replace,
        Py_RETURN_NONE;
 }
 
+KX_PYMETHODDEF_DOC(KX_Scene, suspend,
+                                       "suspend()\n"
+                                       "Suspends this scene.\n")
+{
+       Suspend();
+       
+       Py_RETURN_NONE;
+}
+
+KX_PYMETHODDEF_DOC(KX_Scene, resume,
+                                       "resume()\n"
+                                       "Resumes this scene.\n")
+{
+       Resume();
+       
+       Py_RETURN_NONE;
+}
+
 /* Matches python dict.get(key, [default]) */
 KX_PYMETHODDEF_DOC(KX_Scene, get, "")
 {
@@ -2193,4 +2306,4 @@ KX_PYMETHODDEF_DOC(KX_Scene, get, "")
        return def;
 }
 
-#endif // DISABLE_PYTHON
+#endif // WITH_PYTHON