diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-06-09 00:08:19 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-06-09 00:08:19 +0400 |
commit | c8b4cf92067ffeb625aa39003baf5d8f7c3f0025 (patch) | |
tree | c6c50dbc3d90a65fca6c1ca56a93e4a57cf7e154 /source/gameengine/Ketsji | |
parent | e93db433a086a3e739c0f4026cd500f0b595b0f1 (diff) | |
parent | d76a6f5231c015c35123d22e1f5c3ffcdfbf9bbd (diff) |
2.50:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19820:HEAD
Notes:
* Game and sequencer RNA, and sequencer header are now out of date
a bit after changes in trunk.
* I didn't know how to port these bugfixes, most likely they are
not needed anymore.
* Fix "duplicate strip" always increase the user count for ipo.
* IPO pinning on sequencer strips was lost during Undo.
Diffstat (limited to 'source/gameengine/Ketsji')
110 files changed, 4120 insertions, 1739 deletions
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index 3df483b0598..a0a61d01bb2 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -20,41 +20,33 @@ BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lig : mScene(scene), mMat(ma), - mLightLayer(lightlayer) + mLightLayer(lightlayer), + mGPUMat(NULL) { mBlenderScene = scene->GetBlenderScene(); mBlendMode = GPU_BLEND_SOLID; - if(mMat) - GPU_material_from_blender(mBlenderScene, mMat); + ReloadMaterial(); } BL_BlenderShader::~BL_BlenderShader() { - if(mMat && GPU_material_from_blender(mBlenderScene, mMat)) - GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + if(mGPUMat) + GPU_material_unbind(mGPUMat); } -bool BL_BlenderShader::Ok() +void BL_BlenderShader::ReloadMaterial() { - return VerifyShader(); -} - -bool BL_BlenderShader::VerifyShader() -{ - if(mMat) - return (GPU_material_from_blender(mBlenderScene, mMat) != 0); - else - return false; + mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat) : NULL; } void BL_BlenderShader::SetProg(bool enable, double time) { if(VerifyShader()) { if(enable) - GPU_material_bind(GPU_material_from_blender(mBlenderScene, mMat), mLightLayer, mBlenderScene->lay, time); + GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time); else - GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + GPU_material_unbind(mGPUMat); } } @@ -66,7 +58,7 @@ int BL_BlenderShader::GetAttribNum() if(!VerifyShader()) return enabled; - GPU_material_vertex_attributes(GPU_material_from_blender(mBlenderScene, mMat), &attribs); + GPU_material_vertex_attributes(mGPUMat, &attribs); for(i = 0; i < attribs.totlayer; i++) if(attribs.layer[i].glindex+1 > enabled) @@ -89,7 +81,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) if(!VerifyShader()) return; - gpumat = GPU_material_from_blender(mBlenderScene, mMat); + gpumat = mGPUMat; if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { GPU_material_vertex_attributes(gpumat, &attribs); @@ -131,7 +123,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4]; GPUMaterial *gpumat; - gpumat = GPU_material_from_blender(mBlenderScene, mMat); + gpumat = mGPUMat; if(!gpumat || !GPU_material_bound(gpumat)) return; diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index 5c1f59f94ad..9af53bfc863 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -32,19 +32,28 @@ private: struct Material *mMat; int mLightLayer; int mBlendMode; + GPUMaterial *mGPUMat; - bool VerifyShader(); + bool VerifyShader() + { + return (NULL != mGPUMat); + } public: BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer); virtual ~BL_BlenderShader(); - bool Ok(); + bool Ok() + { + // same as VerifyShared + return (NULL != mGPUMat); + } void SetProg(bool enable, double time=0.0); int GetAttribNum(); void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); + void ReloadMaterial(); int GetBlendMode(); bool Equals(BL_BlenderShader *blshader); diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp index 7e3d6984f19..c63b9d55306 100644 --- a/source/gameengine/Ketsji/BL_Material.cpp +++ b/source/gameengine/Ketsji/BL_Material.cpp @@ -28,6 +28,11 @@ int getNumTexChannels( Material *mat ) BL_Material::BL_Material() { + Initialize(); +} + +void BL_Material::Initialize() +{ rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; @@ -52,7 +57,7 @@ BL_Material::BL_Material() mode = 0; material = 0; tface = 0; - material_index = 0; + materialindex = 0; amb=0.5f; num_enabled = 0; num_users = 1; diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index 0eaa234566c..4f572f95891 100644 --- a/source/gameengine/Ketsji/BL_Material.h +++ b/source/gameengine/Ketsji/BL_Material.h @@ -44,6 +44,7 @@ private: public: // ----------------------------------- BL_Material(); + void Initialize(); int IdMode; unsigned int ras_mode; @@ -54,6 +55,7 @@ public: int tile,tilexrep[MAXTEX],tileyrep[MAXTEX]; STR_String matname; STR_String mtexname[MAXTEX]; + int materialindex; float matcolor[4]; float speccolor[3]; @@ -68,8 +70,6 @@ public: int mode; int num_enabled; - int material_index; - BL_Mapping mapping[MAXTEX]; STR_String imageId[MAXTEX]; diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 88d920043e0..c5c517c8a65 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -734,6 +734,10 @@ PyObject* BL_Shader::py_getattro(PyObject *attr) py_getattro_up(PyObjectPlus); } +PyObject* BL_Shader::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} + PyMethodDef BL_Shader::Methods[] = { @@ -772,8 +776,13 @@ PyAttributeDef BL_Shader::Attributes[] = { }; PyTypeObject BL_Shader::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "BL_Shader", sizeof(PyObjectPlus_Proxy), 0, diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index 08cad5071fd..7db40e778ae 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -203,6 +203,7 @@ public: // Python interface virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual PyObject* py_repr(void) { return PyString_FromFormat("BL_Shader\n\tvertex shader:%s\n\n\tfragment shader%s\n\n", vertProg, fragProg); } // ----------------------------------- diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index ca9ce4dc50c..4aaa49a8493 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -30,11 +30,10 @@ FILE(GLOB SRC *.cpp) #SET(SRC # ${SRC} # ../../../source/blender/python/api2_2x/Mathutils.c +# ../../../source/blender/python/api2_2x/Geometry.c # ../../../source/blender/python/api2_2x/constant.c # ../../../source/blender/python/api2_2x/euler.c -# ../../../source/blender/python/api2_2x/gen_utils.c # ../../../source/blender/python/api2_2x/matrix.c -# ../../../source/blender/python/api2_2x/point.c # ../../../source/blender/python/api2_2x/quat.c # ../../../source/blender/python/api2_2x/vector.c # ../../../source/blender/python/api2_2x/bpy_internal_import.c diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt index fa0ca378c6b..d9a9fc54f4b 100644 --- a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt +++ b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt @@ -30,9 +30,11 @@ SET(INC . ../../../../source/kernel/gen_system ../../../../intern/string + ../../../../intern/moto/include ../../../../source/gameengine/Ketsji ../../../../source/gameengine/GameLogic ../../../../source/gameengine/Expressions + ../../../../source/gameengine/SceneGraph ../../../../source/gameengine/Network ${PYTHON_INC} ) diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp index eee8e9f6827..738f64713b0 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp @@ -61,12 +61,12 @@ void KX_NetworkEventManager::NextFrame() // each frame, the logicmanager will call the network // eventmanager to look for network events, and process it's // 'network' sensors - set<class SCA_ISensor*>::iterator it; - - for (it = m_sensors.begin(); !(it==m_sensors.end()); it++) { + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) + { // printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime); // process queue - (*it)->Activate(m_logicmgr, NULL); + (*it)->Activate(m_logicmgr); } // now a list of triggerer sensors has been built diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp index 2483a6bfb39..63773352d96 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp @@ -75,7 +75,7 @@ bool KX_NetworkMessageActuator::Update() m_toPropName, GetParent()->GetName(), m_subject, - GetParent()->GetPropertyText(m_body,"")); + GetParent()->GetPropertyText(m_body)); } else { m_networkscene->SendMessage( @@ -93,9 +93,6 @@ CValue* KX_NetworkMessageActuator::GetReplica() new KX_NetworkMessageActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; } @@ -105,8 +102,13 @@ CValue* KX_NetworkMessageActuator::GetReplica() /* Integration hooks -------------------------------------------------- */ PyTypeObject KX_NetworkMessageActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_NetworkMessageActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -157,6 +159,10 @@ PyObject* KX_NetworkMessageActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); } +PyObject* KX_NetworkMessageActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_NetworkMessageActuator::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_IActuator); } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h index 850f825b8f3..cf92fd46fe0 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h @@ -62,6 +62,7 @@ public: /* ------------------------------------------------------------ */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // Deprecated -----> diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index 7782567943e..8ddcd87b66f 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -79,15 +79,13 @@ CValue* KX_NetworkMessageSensor::GetReplica() { CValue* replica = new KX_NetworkMessageSensor(*this); if (replica == NULL) return NULL; - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } // Return true only for flank (UP and DOWN) -bool KX_NetworkMessageSensor::Evaluate(CValue* event) +bool KX_NetworkMessageSensor::Evaluate() { bool result = false; bool WasUp = m_IsUp; @@ -104,8 +102,8 @@ bool KX_NetworkMessageSensor::Evaluate(CValue* event) m_SubjectList = NULL; } - STR_String toname=GetParent()->GetName(); - STR_String subject = this->m_subject; + STR_String& toname=GetParent()->GetName(); + STR_String& subject = this->m_subject; vector<NG_NetworkMessage*> messages = m_NetworkScene->FindMessages(toname,"",subject,true); @@ -125,9 +123,9 @@ bool KX_NetworkMessageSensor::Evaluate(CValue* event) for (mesit=messages.begin();mesit!=messages.end();mesit++) { // save the body - STR_String body = (*mesit)->GetMessageText(); + const STR_String& body = (*mesit)->GetMessageText(); // save the subject - STR_String messub = (*mesit)->GetSubject(); + const STR_String& messub = (*mesit)->GetSubject(); #ifdef NAN_NET_DEBUG if (body) { cout << "body [" << body << "]\n"; @@ -168,8 +166,13 @@ bool KX_NetworkMessageSensor::IsPositiveTrigger() /* Integration hooks --------------------------------------------------- */ PyTypeObject KX_NetworkMessageSensor::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_NetworkMessageSensor", sizeof(PyObjectPlus_Proxy), 0, @@ -227,6 +230,10 @@ PyObject* KX_NetworkMessageSensor::py_getattro(PyObject *attr) { py_getattro_up(SCA_ISensor); } +PyObject* KX_NetworkMessageSensor::py_getattro_dict() { + py_getattro_dict_up(SCA_ISensor); +} + int KX_NetworkMessageSensor::py_setattro(PyObject *attr, PyObject *value) { return SCA_ISensor::py_setattro(attr, value); } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h index ac0e880d25c..53183f33826 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -63,7 +63,7 @@ public: virtual ~KX_NetworkMessageSensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); void EndFrame(); @@ -73,6 +73,7 @@ public: /* ------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // Deprecated -----> diff --git a/source/gameengine/Ketsji/KXNetwork/Makefile b/source/gameengine/Ketsji/KXNetwork/Makefile index ddcb03600d5..365ed8fc9c3 100644 --- a/source/gameengine/Ketsji/KXNetwork/Makefile +++ b/source/gameengine/Ketsji/KXNetwork/Makefile @@ -38,8 +38,10 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../Expressions CPPFLAGS += -I../../GameLogic +CPPFLAGS += -I../../SceneGraph CPPFLAGS += -I../../Network CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I.. diff --git a/source/gameengine/Ketsji/KXNetwork/SConscript b/source/gameengine/Ketsji/KXNetwork/SConscript index b417edf6413..f350b2ce25a 100644 --- a/source/gameengine/Ketsji/KXNetwork/SConscript +++ b/source/gameengine/Ketsji/KXNetwork/SConscript @@ -3,9 +3,9 @@ Import ('env') sources = env.Glob('*.cpp') -incs = '. #source/kernel/gen_system #intern/string #source/gameengine/Ketsji' +incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Ketsji' incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions' -incs += ' #source/gameengine/Network' +incs += ' #source/gameengine/Network #source/gameengine/SceneGraph' incs += ' ' + env['BF_PYTHON_INC'] diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 849332008ce..30057fc039d 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -43,35 +43,48 @@ BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL; //static PyObject *gTextureDict = 0; KX_BlenderMaterial::KX_BlenderMaterial( - KX_Scene *scene, - BL_Material *data, - bool skin, - int lightlayer, PyTypeObject *T ) : PyObjectPlus(T), - RAS_IPolyMaterial( - STR_String( data->texname[0] ), - STR_String( data->matname ), // needed for physics! - data->tile, - data->tilexrep[0], - data->tileyrep[0], - data->mode, - data->transp, - ((data->ras_mode &ALPHA)!=0), - ((data->ras_mode &ZSORT)!=0), - lightlayer - ), - mMaterial(data), + RAS_IPolyMaterial(), + mMaterial(NULL), mShader(0), mBlenderShader(0), - mScene(scene), + mScene(NULL), mUserDefBlend(0), mModified(0), mConstructed(false), mPass(0) +{ +} +void KX_BlenderMaterial::Initialize( + KX_Scene *scene, + BL_Material *data, + bool skin, + int lightlayer) { + RAS_IPolyMaterial::Initialize( + data->texname[0], + data->matname, + data->materialindex, + data->tile, + data->tilexrep[0], + data->tileyrep[0], + data->mode, + data->transp, + ((data->ras_mode &ALPHA)!=0), + ((data->ras_mode &ZSORT)!=0), + lightlayer + ); + mMaterial = data; + mShader = 0; + mBlenderShader = 0; + mScene = scene; + mUserDefBlend = 0; + mModified = 0; + mConstructed = false; + mPass = 0; // -------------------------------- // RAS_IPolyMaterial variables... m_flag |= RAS_BLENDERMAT; @@ -95,7 +108,6 @@ KX_BlenderMaterial::KX_BlenderMaterial( ); } m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(COLLIDER|USE_LIGHT)); - } KX_BlenderMaterial::~KX_BlenderMaterial() @@ -106,7 +118,6 @@ KX_BlenderMaterial::~KX_BlenderMaterial() OnExit(); } - MTFace* KX_BlenderMaterial::GetMTFace(void) const { // fonts on polys @@ -120,14 +131,41 @@ unsigned int* KX_BlenderMaterial::GetMCol(void) const return mMaterial->rgb; } -void KX_BlenderMaterial::OnConstruction() +void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const +{ + if (mMaterial) { + *rgba++ = (unsigned char) (mMaterial->matcolor[0]*255.0); + *rgba++ = (unsigned char) (mMaterial->matcolor[1]*255.0); + *rgba++ = (unsigned char) (mMaterial->matcolor[2]*255.0); + *rgba++ = (unsigned char) (mMaterial->matcolor[3]*255.0); + } else + RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); +} + +Material *KX_BlenderMaterial::GetBlenderMaterial() const +{ + return mMaterial->material; +} + +Scene* KX_BlenderMaterial::GetBlenderScene() const +{ + return mScene->GetBlenderScene(); +} + +void KX_BlenderMaterial::ReleaseMaterial() +{ + if (mBlenderShader) + mBlenderShader->ReloadMaterial(); +} + +void KX_BlenderMaterial::OnConstruction(int layer) { if (mConstructed) // when material are reused between objects return; if(mMaterial->glslmat) - SetBlenderGLSLShader(); + SetBlenderGLSLShader(layer); // for each unique material... int i; @@ -377,10 +415,12 @@ KX_BlenderMaterial::ActivatShaders( } else rasty->SetLines(false); + ActivatGLMaterials(rasty); + ActivateTexGen(rasty); } - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + //ActivatGLMaterials(rasty); + //ActivateTexGen(rasty); } void @@ -469,10 +509,12 @@ KX_BlenderMaterial::ActivateMat( } else rasty->SetLines(false); + ActivatGLMaterials(rasty); + ActivateTexGen(rasty); } - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + //ActivatGLMaterials(rasty); + //ActivateTexGen(rasty); } bool @@ -601,8 +643,7 @@ void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const if (mode &USECUSTOMUV) { - STR_String str = mMaterial->mapping[i].uvCoName; - if (!str.IsEmpty()) + if (!mMaterial->mapping[i].uvCoName.IsEmpty()) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i); continue; } @@ -749,12 +790,20 @@ PyMethodDef KX_BlenderMaterial::Methods[] = }; PyAttributeDef KX_BlenderMaterial::Attributes[] = { + //KX_PYATTRIBUTE_TODO("shader"), + //KX_PYATTRIBUTE_TODO("materialIndex"), + //KX_PYATTRIBUTE_TODO("blending"), { NULL } //Sentinel }; PyTypeObject KX_BlenderMaterial::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_BlenderMaterial", sizeof(PyObjectPlus_Proxy), 0, @@ -784,6 +833,10 @@ PyObject* KX_BlenderMaterial::py_getattro(PyObject *attr) py_getattro_up(PyObjectPlus); } +PyObject* KX_BlenderMaterial::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} + int KX_BlenderMaterial::py_setattro(PyObject *attr, PyObject *pyvalue) { return PyObjectPlus::py_setattro(attr, pyvalue); @@ -846,10 +899,10 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") } -void KX_BlenderMaterial::SetBlenderGLSLShader(void) +void KX_BlenderMaterial::SetBlenderGLSLShader(int layer) { if(!mBlenderShader) - mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer); + mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, layer); if(!mBlenderShader->Ok()) { delete mBlenderShader; @@ -859,7 +912,7 @@ void KX_BlenderMaterial::SetBlenderGLSLShader(void) KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") { - return PyInt_FromLong( mMaterial->material_index ); + return PyInt_FromLong( GetMaterialIndex() ); } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" ) diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 48d4730ab07..b29f2df98db 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -24,11 +24,13 @@ class KX_BlenderMaterial : public PyObjectPlus, public RAS_IPolyMaterial public: // -------------------------------- KX_BlenderMaterial( + PyTypeObject* T=&Type + ); + void Initialize( class KX_Scene* scene, BL_Material* mat, bool skin, - int lightlayer, - PyTypeObject* T=&Type + int lightlayer ); virtual ~KX_BlenderMaterial(); @@ -73,7 +75,6 @@ public: Image * getImage (unsigned int idx) { return (idx < MAXTEX && mMaterial) ? mMaterial->img[idx] : NULL; } - // for ipos void UpdateIPO( MT_Vector4 rgba, MT_Vector3 specrgb, @@ -83,6 +84,7 @@ public: // -------------------------------- virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *pyvalue); virtual PyObject* py_repr(void) { return PyString_FromString(mMaterial->matname.ReadPtr()); } @@ -95,7 +97,7 @@ public: // -------------------------------- // pre calculate to avoid pops/lag at startup - virtual void OnConstruction( ); + virtual void OnConstruction(int layer); static void EndFrame(); @@ -110,12 +112,16 @@ private: bool mModified; bool mConstructed; // if false, don't clean on exit - void SetBlenderGLSLShader(); + void SetBlenderGLSLShader(int layer); void ActivatGLMaterials( RAS_IRasterizer* rasty )const; void ActivateTexGen( RAS_IRasterizer *ras ) const; bool UsesLighting(RAS_IRasterizer *rasty) const; + void GetMaterialRGBAColor(unsigned char *rgba) const; + Material* GetBlenderMaterial() const; + Scene* GetBlenderScene() const; + void ReleaseMaterial(); // message centers void setTexData( bool enable,RAS_IRasterizer *ras); diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp index 831f9241fec..748b0667061 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp @@ -17,13 +17,17 @@ #include "BulletSoftBody/btSoftBody.h" -KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool compound) -: KX_IPhysicsController(dyna,compound,(PHY_IPhysicsController*)this), +KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool compound) +: KX_IPhysicsController(dyna,sensor,compound,(PHY_IPhysicsController*)this), CcdPhysicsController(ci), m_savedCollisionFlags(0), +m_savedCollisionFilterGroup(0), +m_savedCollisionFilterMask(0), +m_savedMass(0.0), +m_savedDyna(false), +m_suspended(false), m_bulletChildShape(NULL) { - } KX_BulletPhysicsController::~KX_BulletPhysicsController () @@ -88,7 +92,13 @@ void KX_BulletPhysicsController::SetObject (SG_IObject* object) gameobj->SetPhysicsController(this,gameobj->IsDynamic()); CcdPhysicsController::setNewClientInfo(gameobj->getClientInfo()); - + if (m_bSensor) + { + // use a different callback function for sensor object, + // bullet will not synchronize, we must do it explicitely + SG_Callbacks& callbacks = gameobj->GetSGNode()->GetCallBackFunctions(); + callbacks.m_updatefunc = KX_GameObject::SynchronizeTransformFunc; + } } MT_Scalar KX_BulletPhysicsController::GetRadius() @@ -170,6 +180,20 @@ void KX_BulletPhysicsController::setScaling(const MT_Vector3& scaling) { CcdPhysicsController::setScaling(scaling.x(),scaling.y(),scaling.z()); } +void KX_BulletPhysicsController::SetTransform() +{ + 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]); + CcdPhysicsController::forceWorldTransform(rot, pos); +} + MT_Scalar KX_BulletPhysicsController::GetMass() { if (GetSoftBody()) @@ -258,7 +282,7 @@ void KX_BulletPhysicsController::AddCompoundChild(KX_IPhysicsController* chil // add to parent compound shapeinfo GetShapeInfo()->AddShape(proxyShapeInfo); // create new bullet collision shape from the object shapeinfo and set scaling - btCollisionShape* newChildShape = proxyShapeInfo->CreateBulletShape(); + btCollisionShape* newChildShape = proxyShapeInfo->CreateBulletShape(childCtrl->GetMargin()); newChildShape->setLocalScaling(relativeScale); // add bullet collision shape to parent compound collision shape compoundShape->addChildShape(proxyShapeInfo->m_childTrans,newChildShape); @@ -337,8 +361,7 @@ void KX_BulletPhysicsController::RemoveCompoundChild(KX_IPhysicsController* c void KX_BulletPhysicsController::SetMass(MT_Scalar newmass) { btRigidBody *body = GetRigidBody(); - if (body && body->getActivationState() != DISABLE_SIMULATION && - newmass>MT_EPSILON && GetMass()>MT_EPSILON) + if (body && !m_suspended && newmass>MT_EPSILON && GetMass()>MT_EPSILON) { btVector3 grav = body->getGravity(); btVector3 accel = grav / GetMass(); @@ -356,34 +379,37 @@ void KX_BulletPhysicsController::SetMass(MT_Scalar newmass) void KX_BulletPhysicsController::SuspendDynamics(bool ghost) { btRigidBody *body = GetRigidBody(); - if (body && body->getActivationState() != DISABLE_SIMULATION) + if (body && !m_suspended && !IsSensor()) { btBroadphaseProxy* handle = body->getBroadphaseHandle(); m_savedCollisionFlags = body->getCollisionFlags(); m_savedMass = GetMass(); + m_savedDyna = m_bDyna; m_savedCollisionFilterGroup = handle->m_collisionFilterGroup; m_savedCollisionFilterMask = handle->m_collisionFilterMask; - m_savedActivationState = body->getActivationState(); - body->forceActivationState(DISABLE_SIMULATION); + m_suspended = true; GetPhysicsEnvironment()->updateCcdPhysicsController(this, 0.0, btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + m_bDyna = false; } } void KX_BulletPhysicsController::RestoreDynamics() { btRigidBody *body = GetRigidBody(); - if (body && body->getActivationState() == DISABLE_SIMULATION) + if (body && m_suspended) { GetPhysicsEnvironment()->updateCcdPhysicsController(this, m_savedMass, m_savedCollisionFlags, m_savedCollisionFilterGroup, m_savedCollisionFilterMask); - body->forceActivationState(m_savedActivationState); + body->activate(); + m_bDyna = m_savedDyna; + m_suspended = false; } } @@ -438,12 +464,12 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly) { - if (GetRigidBody()) - GetRigidBody()->activate(true); - if (!m_bDyna) + if (!m_bDyna && !m_bSensor) { - GetCollisionObject()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + btCollisionObject* object = GetRigidBody(); + object->setActivationState(ACTIVE_TAG); + object->setCollisionFlags(object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } else { if (!nondynaonly) diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.h b/source/gameengine/Ketsji/KX_BulletPhysicsController.h index b39098206f7..755b1cbd780 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.h +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h @@ -13,11 +13,13 @@ private: short int m_savedCollisionFilterGroup; short int m_savedCollisionFilterMask; MT_Scalar m_savedMass; + bool m_savedDyna; + bool m_suspended; btCollisionShape* m_bulletChildShape; public: - KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool compound); + KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool compound); virtual ~KX_BulletPhysicsController (); /////////////////////////////////// @@ -40,6 +42,7 @@ public: virtual void setOrientation(const MT_Matrix3x3& orn); virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); + virtual void SetTransform(); virtual MT_Scalar GetMass(); virtual void SetMass(MT_Scalar newmass); virtual MT_Vector3 GetLocalInertia(); diff --git a/source/gameengine/Ketsji/KX_CDActuator.cpp b/source/gameengine/Ketsji/KX_CDActuator.cpp index 121d4512265..8511526fd5f 100644 --- a/source/gameengine/Ketsji/KX_CDActuator.cpp +++ b/source/gameengine/Ketsji/KX_CDActuator.cpp @@ -74,9 +74,6 @@ CValue* KX_CDActuator::GetReplica() { KX_CDActuator* replica = new KX_CDActuator(*this); replica->ProcessReplica(); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -158,8 +155,13 @@ bool KX_CDActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_CDActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SoundActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -212,7 +214,7 @@ int KX_CDActuator::pyattr_setGain(void *self, const struct KX_PYATTRIBUTE_DEF *a { KX_CDActuator* act = static_cast<KX_CDActuator*>(self); SND_CDObject::Instance()->SetGain(act->m_gain); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_CDActuator::py_getattro(PyObject *attr) @@ -220,6 +222,10 @@ PyObject* KX_CDActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_CDActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_CDActuator::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_IActuator); diff --git a/source/gameengine/Ketsji/KX_CDActuator.h b/source/gameengine/Ketsji/KX_CDActuator.h index b674755e59f..2fd05ab72e5 100644 --- a/source/gameengine/Ketsji/KX_CDActuator.h +++ b/source/gameengine/Ketsji/KX_CDActuator.h @@ -82,6 +82,7 @@ public: /* -------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // Deprecated -----> diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index c8575424751..ba4d6e22872 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -28,6 +28,7 @@ * Camera in the gameengine. Cameras are also used for views. */ +#include "GL/glew.h" #include "KX_Camera.h" #include "KX_Scene.h" #include "KX_PythonInit.h" @@ -41,15 +42,17 @@ KX_Camera::KX_Camera(void* sgReplicationInfo, SG_Callbacks callbacks, const RAS_CameraData& camdata, bool frustum_culling, + bool delete_node, PyTypeObject *T) : KX_GameObject(sgReplicationInfo,callbacks,T), m_camdata(camdata), m_dirty(true), m_normalized(false), - m_frustum_culling(frustum_culling && camdata.m_perspective), + m_frustum_culling(frustum_culling), m_set_projection_matrix(false), - m_set_frustum_center(false) + m_set_frustum_center(false), + m_delete_node(delete_node) { // setting a name would be nice... m_name = "cam"; @@ -63,6 +66,12 @@ KX_Camera::KX_Camera(void* sgReplicationInfo, KX_Camera::~KX_Camera() { + if (m_delete_node && m_pSGNode) + { + // for shadow camera, avoids memleak + delete m_pSGNode; + m_pSGNode = NULL; + } } @@ -71,15 +80,16 @@ CValue* KX_Camera::GetReplica() KX_Camera* replica = new KX_Camera(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); - ProcessReplica(replica); + replica->ProcessReplica(); return replica; } - -void KX_Camera::ProcessReplica(KX_Camera* replica) + +void KX_Camera::ProcessReplica() { - KX_GameObject::ProcessReplica(replica); + KX_GameObject::ProcessReplica(); + // replicated camera are always registered in the scene + m_delete_node = false; } MT_Transform KX_Camera::GetWorldToCamera() const @@ -190,6 +200,11 @@ float KX_Camera::GetLens() const return m_camdata.m_lens; } +float KX_Camera::GetScale() const +{ + return m_camdata.m_scale; +} + float KX_Camera::GetCameraNear() const @@ -270,80 +285,83 @@ void KX_Camera::ExtractFrustumSphere() MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix; clip_camcs_matrix.invert(); - // detect which of the corner of the far clipping plane is the farthest to the origin - MT_Vector4 nfar; // far point in device normalized coordinate - MT_Point3 farpoint; // most extreme far point in camera coordinate - MT_Point3 nearpoint;// most extreme near point in camera coordinate - MT_Point3 farcenter(0.,0.,0.);// center of far cliping plane in camera coordinate - MT_Scalar F=1.0, N; // square distance of far and near point to origin - MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0 - MT_Scalar e, s; // far and near clipping distance (<0) - MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance - MT_Scalar z; // projection of sphere center on z axis (<0) - // tmp value - MT_Vector4 npoint(1., 1., 1., 1.); - MT_Vector4 hpoint; - MT_Point3 point; - MT_Scalar len; - for (int i=0; i<4; i++) - { - hpoint = clip_camcs_matrix*npoint; - point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]); - len = point.dot(point); - if (len > F) - { - nfar = npoint; - farpoint = point; - F = len; - } - // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane - len = npoint[0]; - npoint[0] = -npoint[1]; - npoint[1] = len; - farcenter += point; - } - // the far center is the average of the far clipping points - farcenter *= 0.25; - // the extreme near point is the opposite point on the near clipping plane - nfar.setValue(-nfar[0], -nfar[1], -1., 1.); - nfar = clip_camcs_matrix*nfar; - nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]); - N = nearpoint.dot(nearpoint); - e = farpoint[2]; - s = nearpoint[2]; - // projection on XY plane for distance to axis computation - MT_Point2 farxy(farpoint[0], farpoint[1]); - // f is forced positive by construction - f = farxy.length(); - // get corresponding point on the near plane - farxy *= s/e; - // this formula preserve the sign of n - n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length(); - c = MT_Point2(farcenter[0], farcenter[1]).length()/e; - // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case - z = (F-N)/(2.0*(e-s+c*(f-n))); - m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z); - m_frustum_radius = m_frustum_center.distance(farpoint); - -#if 0 - // The most extreme points on the near and far plane. (normalized device coords) - MT_Vector4 hnear(1., 1., 0., 1.), hfar(1., 1., 1., 1.); - - // Transform to hom camera local space - hnear = clip_camcs_matrix*hnear; - hfar = clip_camcs_matrix*hfar; - - // Tranform to 3d camera local space. - MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]); - MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); - - // Compute center - // don't use camera data in case the user specifies the matrix directly - m_frustum_center = MT_Point3(0., 0., - (nearpoint.dot(nearpoint) - farpoint.dot(farpoint))/(2.0*(nearpoint[2]-farpoint[2] /*m_camdata.m_clipend - m_camdata.m_clipstart*/))); - m_frustum_radius = m_frustum_center.distance(farpoint); -#endif - + if (m_projection_matrix[3][3] == MT_Scalar(0.0)) + { + // frustrum projection + // detect which of the corner of the far clipping plane is the farthest to the origin + MT_Vector4 nfar; // far point in device normalized coordinate + MT_Point3 farpoint; // most extreme far point in camera coordinate + MT_Point3 nearpoint;// most extreme near point in camera coordinate + MT_Point3 farcenter(0.,0.,0.);// center of far cliping plane in camera coordinate + MT_Scalar F=-1.0, N; // square distance of far and near point to origin + MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0 + MT_Scalar e, s; // far and near clipping distance (<0) + MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance + MT_Scalar z; // projection of sphere center on z axis (<0) + // tmp value + MT_Vector4 npoint(1., 1., 1., 1.); + MT_Vector4 hpoint; + MT_Point3 point; + MT_Scalar len; + for (int i=0; i<4; i++) + { + hpoint = clip_camcs_matrix*npoint; + point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]); + len = point.dot(point); + if (len > F) + { + nfar = npoint; + farpoint = point; + F = len; + } + // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane + len = npoint[0]; + npoint[0] = -npoint[1]; + npoint[1] = len; + farcenter += point; + } + // the far center is the average of the far clipping points + farcenter *= 0.25; + // the extreme near point is the opposite point on the near clipping plane + nfar.setValue(-nfar[0], -nfar[1], -1., 1.); + nfar = clip_camcs_matrix*nfar; + nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]); + // this is a frustrum projection + N = nearpoint.dot(nearpoint); + e = farpoint[2]; + s = nearpoint[2]; + // projection on XY plane for distance to axis computation + MT_Point2 farxy(farpoint[0], farpoint[1]); + // f is forced positive by construction + f = farxy.length(); + // get corresponding point on the near plane + farxy *= s/e; + // this formula preserve the sign of n + n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length(); + c = MT_Point2(farcenter[0], farcenter[1]).length()/e; + // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case + z = (F-N)/(2.0*(e-s+c*(f-n))); + m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z); + m_frustum_radius = m_frustum_center.distance(farpoint); + } + else + { + // orthographic projection + // The most extreme points on the near and far plane. (normalized device coords) + MT_Vector4 hnear(1., 1., 1., 1.), hfar(-1., -1., -1., 1.); + + // Transform to hom camera local space + hnear = clip_camcs_matrix*hnear; + hfar = clip_camcs_matrix*hfar; + + // Tranform to 3d camera local space. + MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]); + MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); + + // just use mediant point + m_frustum_center = (farpoint + nearpoint)*0.5; + m_frustum_radius = m_frustum_center.distance(farpoint); + } // Transform to world space. m_frustum_center = GetCameraToWorld()(m_frustum_center); m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]); @@ -474,11 +492,16 @@ PyMethodDef KX_Camera::Methods[] = { KX_PYMETHODTABLE_O(KX_Camera, pointInsideFrustum), KX_PYMETHODTABLE_NOARGS(KX_Camera, getCameraToWorld), KX_PYMETHODTABLE_NOARGS(KX_Camera, getWorldToCamera), - KX_PYMETHODTABLE_NOARGS(KX_Camera, getProjectionMatrix), - KX_PYMETHODTABLE_O(KX_Camera, setProjectionMatrix), - KX_PYMETHODTABLE_O(KX_Camera, enableViewport), KX_PYMETHODTABLE(KX_Camera, setViewport), KX_PYMETHODTABLE_NOARGS(KX_Camera, setOnTop), + KX_PYMETHODTABLE_O(KX_Camera, getScreenPosition), + KX_PYMETHODTABLE(KX_Camera, getScreenVect), + KX_PYMETHODTABLE(KX_Camera, getScreenRay), + + // DEPRECATED + KX_PYMETHODTABLE_O(KX_Camera, enableViewport), + KX_PYMETHODTABLE_NOARGS(KX_Camera, getProjectionMatrix), + KX_PYMETHODTABLE_O(KX_Camera, setProjectionMatrix), {NULL,NULL} //Sentinel }; @@ -492,7 +515,9 @@ PyAttributeDef KX_Camera::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("near", KX_Camera, pyattr_get_near, pyattr_set_near), KX_PYATTRIBUTE_RW_FUNCTION("far", KX_Camera, pyattr_get_far, pyattr_set_far), - KX_PYATTRIBUTE_RO_FUNCTION("projection_matrix", KX_Camera, pyattr_get_projection_matrix), + KX_PYATTRIBUTE_RW_FUNCTION("useViewport", KX_Camera, pyattr_get_use_viewport, pyattr_set_use_viewport), + + KX_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera, pyattr_get_projection_matrix, pyattr_set_projection_matrix), KX_PYATTRIBUTE_RO_FUNCTION("modelview_matrix", KX_Camera, pyattr_get_modelview_matrix), KX_PYATTRIBUTE_RO_FUNCTION("camera_to_world", KX_Camera, pyattr_get_camera_to_world), KX_PYATTRIBUTE_RO_FUNCTION("world_to_camera", KX_Camera, pyattr_get_world_to_camera), @@ -506,8 +531,13 @@ PyAttributeDef KX_Camera::Attributes[] = { }; PyTypeObject KX_Camera::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_Camera", sizeof(PyObjectPlus_Proxy), 0, @@ -544,6 +574,10 @@ PyObject* KX_Camera::py_getattro(PyObject *attr) py_getattro_up(KX_GameObject); } +PyObject* KX_Camera::py_getattro_dict() { + py_getattro_dict_up(KX_GameObject); +} + int KX_Camera::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(KX_GameObject); @@ -678,6 +712,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getProjectionMatrix, "\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n" ) { + ShowDeprecationWarning("getProjectionMatrix()", "the projection_matrix property"); return PyObjectFrom(GetProjectionMatrix()); /* new ref */ } @@ -723,6 +758,8 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, setProjectionMatrix, "\tcam = co.getOwner()\n" "\tcam.setProjectionMatrix(Perspective(-1.0, 1.0, -1.0, 1.0, 0.1, 1))\n") { + ShowDeprecationWarning("setProjectionMatrix(mat)", "the projection_matrix property"); + MT_Matrix4x4 mat; if (!PyMatTo(value, mat)) { @@ -739,8 +776,9 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, enableViewport, "Sets this camera's viewport status\n" ) { - int viewport = PyObject_IsTrue(value); + ShowDeprecationWarning("enableViewport(bool)", "the useViewport property"); + int viewport = PyObject_IsTrue(value); if (viewport == -1) { PyErr_SetString(PyExc_ValueError, "camera.enableViewport(bool): KX_Camera, expected True/False or 0/1"); return NULL; @@ -770,10 +808,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, setOnTop, "setOnTop()\n" "Sets this camera's viewport on top\n") { - class KX_Scene* scene; - - scene = KX_GetActiveScene(); - MT_assert(scene); + class KX_Scene* scene = KX_GetActiveScene(); scene->SetCameraOnTop(this); Py_RETURN_NONE; } @@ -790,11 +825,11 @@ int KX_Camera::pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *at int param = PyObject_IsTrue( value ); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.perspective = bool: KX_Camera, expected True/False or 0/1"); - return -1; + return PY_SET_ATTR_FAIL; } self->m_camdata.m_perspective= param; - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_Camera::pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -809,12 +844,12 @@ int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater then zero"); - return -1; + return PY_SET_ATTR_FAIL; } self->m_camdata.m_lens= param; self->m_set_projection_matrix = false; - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_Camera::pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -829,12 +864,12 @@ int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater then zero"); - return -1; + return PY_SET_ATTR_FAIL; } self->m_camdata.m_clipstart= param; self->m_set_projection_matrix = false; - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_Camera::pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -849,14 +884,34 @@ int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater then zero"); - return -1; + return PY_SET_ATTR_FAIL; } self->m_camdata.m_clipend= param; self->m_set_projection_matrix = false; - return 0; + return PY_SET_ATTR_SUCCESS; +} + + +PyObject* KX_Camera::pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyBool_FromLong(self->GetViewport()); +} + +int KX_Camera::pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + int param = PyObject_IsTrue( value ); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.useViewport = bool: KX_Camera, expected True or False"); + return PY_SET_ATTR_FAIL; + } + self->EnableViewport((bool)param); + return PY_SET_ATTR_SUCCESS; } + PyObject* KX_Camera::pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_Camera* self= static_cast<KX_Camera*>(self_v); @@ -868,10 +923,10 @@ int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_D KX_Camera* self= static_cast<KX_Camera*>(self_v); MT_Matrix4x4 mat; if (!PyMatTo(value, mat)) - return -1; + return PY_SET_ATTR_FAIL; self->SetProjectionMatrix(mat); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -900,3 +955,197 @@ PyObject* KX_Camera::pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF * PyObject* KX_Camera::pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { return PyInt_FromLong(INTERSECT); } + +bool ConvertPythonToCamera(PyObject * value, KX_Camera **object, bool py_none_ok, const char *error_prefix) +{ + if (value==NULL) { + PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); + *object = NULL; + return false; + } + + if (value==Py_None) { + *object = NULL; + + if (py_none_ok) { + return true; + } else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_Camera or a KX_Camera name, None is invalid", error_prefix); + return false; + } + } + + if (PyString_Check(value)) { + STR_String value_str = PyString_AsString(value); + *object = KX_GetActiveScene()->FindCamera(value_str); + + if (*object) { + return true; + } else { + PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_Camera in this scene", error_prefix, PyString_AsString(value)); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_Camera::Type)) { + *object = static_cast<KX_Camera*>BGE_PROXY_REF(value); + + /* sets the error */ + if (*object==NULL) { + PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + return false; + } + + return true; + } + + *object = NULL; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera, a string or None", error_prefix); + } else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera or a string", error_prefix); + } + + return false; +} + +KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition, +"getScreenPosition()\n" +) + +{ + MT_Vector3 vect; + KX_GameObject *obj = NULL; + + if (!PyVecTo(value, vect)) + { + if(ConvertPythonToGameObject(value, &obj, true, "")) + { + PyErr_Clear(); + vect = MT_Vector3(obj->NodeGetWorldPosition()); + } + else + { + PyErr_SetString(PyExc_TypeError, "Error in getScreenPosition. Expected a Vector3 or a KX_GameObject or a string for a name of a KX_GameObject"); + return NULL; + } + } + + GLint viewport[4]; + GLdouble win[3]; + GLdouble modelmatrix[16]; + GLdouble projmatrix[16]; + + MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix(); + MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); + + m_modelmatrix.getValue(modelmatrix); + m_projmatrix.getValue(projmatrix); + + glGetIntegerv(GL_VIEWPORT, viewport); + + gluProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]); + + vect[0] = (win[0] - viewport[0]) / viewport[2]; + vect[1] = (win[1] - viewport[1]) / viewport[3]; + + vect[1] = 1.0 - vect[1]; //to follow Blender window coordinate system (Top-Down) + + PyObject* ret = PyTuple_New(2); + if(ret){ + PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(vect[0])); + PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(vect[1])); + return ret; + } + + return NULL; +} + +KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect, +"getScreenVect()\n" +) +{ + double x,y; + if (!PyArg_ParseTuple(args,"dd:getScreenVect",&x,&y)) + return NULL; + + y = 1.0 - y; //to follow Blender window coordinate system (Top-Down) + + MT_Vector3 vect; + MT_Point3 campos, screenpos; + + GLint viewport[4]; + GLdouble win[3]; + GLdouble modelmatrix[16]; + GLdouble projmatrix[16]; + + MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix(); + MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); + + m_modelmatrix.getValue(modelmatrix); + m_projmatrix.getValue(projmatrix); + + glGetIntegerv(GL_VIEWPORT, viewport); + + vect[0] = x * viewport[2]; + vect[1] = y * viewport[3]; + + vect[0] += viewport[0]; + vect[1] += viewport[1]; + + glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &vect[2]); + gluUnProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]); + + campos = this->GetCameraLocation(); + screenpos = MT_Point3(win[0], win[1], win[2]); + vect = campos-screenpos; + + vect.normalize(); + return PyObjectFrom(vect); +} + +KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenRay, +"getScreenRay()\n" +) +{ + MT_Vector3 vect; + double x,y,dist; + char *propName = NULL; + + if (!PyArg_ParseTuple(args,"ddd|s:getScreenRay",&x,&y,&dist,&propName)) + return NULL; + + PyObject* argValue = PyTuple_New(2); + if (argValue) { + PyTuple_SET_ITEM(argValue, 0, PyFloat_FromDouble(x)); + PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(y)); + } + + if(!PyVecTo(PygetScreenVect(argValue), vect)) + { + Py_DECREF(argValue); + PyErr_SetString(PyExc_TypeError, + "Error in getScreenRay. Invalid 2D coordinate. Expected a normalized 2D screen coordinate, a distance and an optional property argument"); + return NULL; + } + Py_DECREF(argValue); + + dist = -dist; + vect += this->GetCameraLocation(); + + argValue = (propName?PyTuple_New(3):PyTuple_New(2)); + if (argValue) { + PyTuple_SET_ITEM(argValue, 0, PyObjectFrom(vect)); + PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(dist)); + if (propName) + PyTuple_SET_ITEM(argValue, 2, PyString_FromString(propName)); + + PyObject* ret= this->PyrayCastTo(argValue,NULL); + Py_DECREF(argValue); + return ret; + } + + return NULL; +} + diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h index 4accd4bc2f1..aef21cd91e4 100644 --- a/source/gameengine/Ketsji/KX_Camera.h +++ b/source/gameengine/Ketsji/KX_Camera.h @@ -41,6 +41,9 @@ #include "IntValue.h" #include "RAS_CameraData.h" +/* utility conversion function */ +bool ConvertPythonToCamera(PyObject * value, KX_Camera **object, bool py_none_ok, const char *error_prefix); + class KX_Camera : public KX_GameObject { Py_Header; @@ -110,6 +113,11 @@ protected: bool m_set_frustum_center; /** + * whether the camera should delete the node itself (only for shadow camera) + */ + bool m_delete_node; + + /** * Extracts the camera clip frames from the projection and world-to-camera matrices. */ void ExtractClipPlanes(); @@ -135,7 +143,7 @@ public: enum { INSIDE, INTERSECT, OUTSIDE } ; - KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, PyTypeObject *T = &Type); + KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, bool delete_node = false, PyTypeObject *T = &Type); virtual ~KX_Camera(); /** @@ -146,15 +154,7 @@ public: virtual CValue* GetReplica( ); - - /** - * Inherited from CValue -- Makes sure any internal - * data owned by this class is deep copied. Called internally - */ - virtual void - ProcessReplica( - KX_Camera* replica - ); + virtual void ProcessReplica(); MT_Transform GetWorldToCamera() const; MT_Transform GetCameraToWorld() const; @@ -193,6 +193,8 @@ public: /** Gets the aperture. */ float GetLens() const; + /** Gets the ortho scale. */ + float GetScale() const; /** Gets the near clip distance. */ float GetCameraNear() const; /** Gets the far clip distance. */ @@ -277,7 +279,12 @@ public: KX_PYMETHOD_DOC_VARARGS(KX_Camera, setViewport); KX_PYMETHOD_DOC_NOARGS(KX_Camera, setOnTop); + KX_PYMETHOD_DOC_O(KX_Camera, getScreenPosition); + KX_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenVect); + KX_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenRay); + virtual PyObject* py_getattro(PyObject *attr); /* lens, near, far, projection_matrix */ + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *pyvalue); static PyObject* pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); @@ -290,6 +297,9 @@ public: static PyObject* pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index 8ef9f318142..f8557dac2c4 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.cpp +++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp @@ -82,8 +82,6 @@ GetReplica( ) { KX_CameraActuator* replica = new KX_CameraActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -371,8 +369,13 @@ bool KX_CameraActuator::string2axischoice(const char *axisString) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_CameraActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_CameraActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -416,7 +419,7 @@ PyAttributeDef KX_CameraActuator::Attributes[] = { KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_minHeight), KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_maxHeight), KX_PYATTRIBUTE_FLOAT_RW("height",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_height), - KX_PYATTRIBUTE_BOOL_RW("xy",KX_CameraActuator,m_x), + KX_PYATTRIBUTE_BOOL_RW("useXY",KX_CameraActuator,m_x), KX_PYATTRIBUTE_RW_FUNCTION("object", KX_CameraActuator, pyattr_get_object, pyattr_set_object), {NULL} }; @@ -425,6 +428,10 @@ PyObject* KX_CameraActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); } +PyObject* KX_CameraActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_CameraActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); } @@ -447,7 +454,7 @@ PyObject* KX_CameraActuator::PyGetObject(PyObject* args) Py_RETURN_NONE; if (ret_name_only) - return PyString_FromString(m_ob->GetName()); + return PyString_FromString(m_ob->GetName().ReadPtr()); else return m_ob->GetProxy(); } @@ -554,7 +561,7 @@ const char KX_CameraActuator::SetXY_doc[] = "\t1=x, 0=y\n"; PyObject* KX_CameraActuator::PySetXY(PyObject* args) { - ShowDeprecationWarning("setXY()", "the xy property"); + ShowDeprecationWarning("setXY()", "the useXY property"); int value; if(PyArg_ParseTuple(args,"i:setXY", &value)) { @@ -590,7 +597,7 @@ int KX_CameraActuator::pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF KX_GameObject *gameobj; if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_CameraActuator")) - return 1; // ConvertPythonToGameObject sets the error + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error if (self->m_ob) self->m_ob->UnregisterActuator(self); @@ -598,7 +605,7 @@ int KX_CameraActuator::pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF if ((self->m_ob = (SCA_IObject*)gameobj)) self->m_ob->RegisterActuator(self); - return 0; + return PY_SET_ATTR_SUCCESS; } /* eof */ diff --git a/source/gameengine/Ketsji/KX_CameraActuator.h b/source/gameengine/Ketsji/KX_CameraActuator.h index 9298e1e868d..efa4e2f38d7 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.h +++ b/source/gameengine/Ketsji/KX_CameraActuator.h @@ -121,6 +121,7 @@ private : /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); /* set object to look at */ diff --git a/source/gameengine/Ketsji/KX_ClientObjectInfo.h b/source/gameengine/Ketsji/KX_ClientObjectInfo.h index 7345edb054b..077ac96f0ac 100644 --- a/source/gameengine/Ketsji/KX_ClientObjectInfo.h +++ b/source/gameengine/Ketsji/KX_ClientObjectInfo.h @@ -50,8 +50,9 @@ struct KX_ClientObjectInfo STATIC, ACTOR, RESERVED1, - RADAR, - NEAR + SENSOR, + OBSENSOR, + OBACTORSENSOR } m_type; KX_GameObject* m_gameobject; void* m_auxilary_info; @@ -84,6 +85,7 @@ public: } bool isActor() { return m_type <= ACTOR; } + bool isSensor() { return m_type >= SENSOR && m_type <= OBACTORSENSOR; } }; #endif //__KX_CLIENTOBJECT_INFO_H diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index c2b4db2de8e..bd03dea486b 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -565,8 +565,13 @@ bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ConstraintActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_ConstraintActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -625,7 +630,7 @@ PyAttributeDef KX_ConstraintActuator::Attributes[] = { KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_refDirection,3,pyattr_check_direction), KX_PYATTRIBUTE_INT_RW("option",0,0xFFFF,false,KX_ConstraintActuator,m_option), KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_ConstraintActuator,m_activeTime), - KX_PYATTRIBUTE_STRING_RW("property",0,32,true,KX_ConstraintActuator,m_property), + KX_PYATTRIBUTE_STRING_RW("propName",0,32,true,KX_ConstraintActuator,m_property), KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound), KX_PYATTRIBUTE_FLOAT_RW("distance",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound), KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_maximumBound), @@ -639,6 +644,10 @@ PyObject* KX_ConstraintActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_ConstraintActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_ConstraintActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); @@ -749,9 +758,9 @@ PyObject* KX_ConstraintActuator::PyGetDirection(){ ShowDeprecationWarning("getDirection()", "the direction property"); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_refDirection[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_refDirection[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_refDirection[2])); return retVal; } diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index 98f6fcd7906..40607b44947 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -132,8 +132,6 @@ protected: virtual CValue* GetReplica() { KX_ConstraintActuator* replica = new KX_ConstraintActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -144,6 +142,7 @@ protected: /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); static int pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index 7c3abb49159..c5cf67af67d 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp @@ -48,24 +48,48 @@ KX_ConstraintWrapper::KX_ConstraintWrapper( KX_ConstraintWrapper::~KX_ConstraintWrapper() { } -//python integration methods -PyObject* KX_ConstraintWrapper::PyTestMethod(PyObject* args, PyObject* kwds) -{ - Py_RETURN_NONE; -} -PyObject* KX_ConstraintWrapper::PyGetConstraintId(PyObject* args, PyObject* kwds) +PyObject* KX_ConstraintWrapper::PyGetConstraintId() { return PyInt_FromLong(m_constraintId); } +PyObject* KX_ConstraintWrapper::PyGetParam(PyObject* args, PyObject* kwds) +{ + int dof; + float value; + + if (!PyArg_ParseTuple(args,"i:getParam",&dof)) + return NULL; + + value = m_physenv->getConstraintParam(m_constraintId,dof); + return PyFloat_FromDouble(value); + +} + +PyObject* KX_ConstraintWrapper::PySetParam(PyObject* args, PyObject* kwds) +{ + int dof; + float minLimit,maxLimit; + + if (!PyArg_ParseTuple(args,"iff:setParam",&dof,&minLimit,&maxLimit)) + return NULL; + + m_physenv->setConstraintParam(m_constraintId,dof,minLimit,maxLimit); + Py_RETURN_NONE; +} //python specific stuff PyTypeObject KX_ConstraintWrapper::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_ConstraintWrapper", sizeof(PyObjectPlus_Proxy), 0, @@ -87,45 +111,33 @@ PyParentObject KX_ConstraintWrapper::Parents[] = { NULL }; -PyObject* KX_ConstraintWrapper::py_getattro(PyObject *attr) +//here you can search for existing data members (like mass,friction etc.) +PyObject* KX_ConstraintWrapper::py_getattro(PyObject *attr) { - //here you can search for existing data members (like mass,friction etc.) py_getattro_up(PyObjectPlus); } -int KX_ConstraintWrapper::py_setattro(PyObject *attr,PyObject* pyobj) +PyObject* KX_ConstraintWrapper::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} + +int KX_ConstraintWrapper::py_setattro(PyObject *attr,PyObject* value) { - int result = 1; - /* what the heck is this supposed to do?, needs attention */ - if (PyList_Check(pyobj)) - { - result = 0; - } - if (PyFloat_Check(pyobj)) - { - result = 0; - - } - if (PyInt_Check(pyobj)) - { - result = 0; - } - if (PyString_Check(pyobj)) - { - result = 0; - } - if (result) - result = PyObjectPlus::py_setattro(attr,pyobj); - return result; + py_setattro_up(PyObjectPlus); }; + + + PyMethodDef KX_ConstraintWrapper::Methods[] = { - {"testMethod",(PyCFunction) KX_ConstraintWrapper::sPyTestMethod, METH_VARARGS}, - {"getConstraintId",(PyCFunction) KX_ConstraintWrapper::sPyGetConstraintId, METH_VARARGS}, + {"getConstraintId",(PyCFunction) KX_ConstraintWrapper::sPyGetConstraintId, METH_NOARGS}, + {"setParam",(PyCFunction) KX_ConstraintWrapper::sPySetParam, METH_VARARGS}, + {"getParam",(PyCFunction) KX_ConstraintWrapper::sPyGetParam, METH_VARARGS}, {NULL,NULL} //Sentinel }; PyAttributeDef KX_ConstraintWrapper::Attributes[] = { + //KX_PYATTRIBUTE_TODO("constraintId"), { NULL } //Sentinel }; diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h index 6e67d842cb6..03813e0f167 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.h +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.h @@ -36,14 +36,16 @@ class KX_ConstraintWrapper : public PyObjectPlus { Py_Header; virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); public: KX_ConstraintWrapper(PHY_ConstraintType ctype,int constraintId,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type); virtual ~KX_ConstraintWrapper (); int getConstraintId() { return m_constraintId;}; - KX_PYMETHOD(KX_ConstraintWrapper,TestMethod); - KX_PYMETHOD(KX_ConstraintWrapper,GetConstraintId); + KX_PYMETHOD_NOARGS(KX_ConstraintWrapper,GetConstraintId); + KX_PYMETHOD(KX_ConstraintWrapper,SetParam); + KX_PYMETHOD(KX_ConstraintWrapper,GetParam); private: int m_constraintId; diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h index 3534500e619..74042366bae 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h @@ -47,6 +47,7 @@ class RAS_MeshObject; class KX_Scene; +struct DerivedMesh; typedef enum { KX_BOUNDBOX, @@ -82,6 +83,7 @@ struct KX_ObjectProperties bool m_ghost; class KX_GameObject* m_dynamic_parent; bool m_isactor; + bool m_sensor; bool m_concave; bool m_isdeformable; bool m_disableSleeping; @@ -124,6 +126,7 @@ struct KX_ObjectProperties float m_soft_kAHR; /* Anchors hardness [0,1] */ int m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ int m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ + float m_soft_welding; /* threshold to remove duplicate/nearby vertices */ ///////////////////////// @@ -136,6 +139,8 @@ struct KX_ObjectProperties ///////////////////////// double m_margin; + float m_contactProcessingThreshold; + KX_BoundBoxClass m_boundclass; union { KX_BoxBounds box; @@ -182,6 +187,7 @@ bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj); void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, + struct DerivedMesh* dm, class KX_Scene* kxscene, struct PHY_ShapeProps* shapeprops, struct PHY_MaterialProps* smmaterial, diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp index 08e2ea30414..51c41c0686d 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp @@ -34,7 +34,7 @@ // defines USE_ODE to choose physics engine #include "KX_ConvertPhysicsObject.h" -#include "KX_GameObject.h" +#include "BL_DeformableGameObject.h" #include "RAS_MeshObject.h" #include "KX_Scene.h" #include "SYS_System.h" @@ -52,6 +52,10 @@ #include "KX_MotionState.h" // bridge between motionstate and scenegraph node +extern "C"{ + #include "BKE_DerivedMesh.h" +} + #ifdef USE_ODE #include "KX_OdePhysicsController.h" @@ -670,11 +674,11 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, class KX_SoftBodyDeformer : public RAS_Deformer { - class RAS_MeshObject* m_pMeshObject; - class KX_GameObject* m_gameobj; + class RAS_MeshObject* m_pMeshObject; + class BL_DeformableGameObject* m_gameobj; public: - KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,KX_GameObject* gameobj) + KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,BL_DeformableGameObject* gameobj) :m_pMeshObject(pMeshObject), m_gameobj(gameobj) { @@ -687,7 +691,15 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, }; virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map) { - //printf("relink\n"); + void **h_obj = (*map)[m_gameobj]; + + if (h_obj) { + m_gameobj = (BL_DeformableGameObject*)(*h_obj); + m_pMeshObject = m_gameobj->GetMesh(0); + } else { + m_gameobj = NULL; + m_pMeshObject = NULL; + } } virtual bool Apply(class RAS_IPolyMaterial *polymat) { @@ -749,14 +761,27 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, virtual bool Update(void) { //printf("update\n"); + m_bDynamic = true; return true;//?? } - virtual RAS_Deformer *GetReplica(class KX_GameObject* replica) + virtual bool UpdateBuckets(void) { - KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(replica->GetMesh(0),replica); - return deformer; + // this is to update the mesh slots outside the rasterizer, + // no need to do it for this deformer, it's done in any case in Apply() + return false; } + virtual RAS_Deformer *GetReplica() + { + KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(*this); + deformer->ProcessReplica(); + return deformer; + } + virtual void ProcessReplica() + { + // we have two pointers to deal with but we cannot do it now, will be done in Relink + m_bDynamic = false; + } virtual bool SkipVertexTransform() { return true; @@ -771,6 +796,7 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, + struct DerivedMesh* dm, class KX_Scene* kxscene, struct PHY_ShapeProps* shapeprops, struct PHY_MaterialProps* smmaterial, @@ -782,12 +808,12 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, bool isbulletdyna = false; + bool isbulletsensor = false; CcdConstructionInfo ci; class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo(); - if (!objprop->m_dyna) { ci.m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT; @@ -806,6 +832,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_margin = objprop->m_margin; shapeInfo->m_radius = objprop->m_radius; isbulletdyna = objprop->m_dyna; + isbulletsensor = objprop->m_sensor; ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f); @@ -825,7 +852,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1); shapeInfo->m_shapeType = PHY_SHAPE_SPHERE; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; }; case KX_BOUNDBOX: @@ -838,7 +865,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, shapeInfo->m_halfExtend /= 2.0; shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute(); shapeInfo->m_shapeType = PHY_SHAPE_BOX; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; }; case KX_BOUNDCYLINDER: @@ -849,7 +876,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, objprop->m_boundobject.c.m_height * 0.5f ); shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } @@ -858,45 +885,41 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, shapeInfo->m_radius = objprop->m_boundobject.c.m_radius; shapeInfo->m_height = objprop->m_boundobject.c.m_height; shapeInfo->m_shapeType = PHY_SHAPE_CONE; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } case KX_BOUNDPOLYTOPE: { - shapeInfo->SetMesh(meshobj, true,false); - bm = shapeInfo->CreateBulletShape(); + shapeInfo->SetMesh(meshobj, dm,true,false); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } case KX_BOUNDMESH: { - - if (!ci.m_mass ||objprop->m_softbody) - { - // mesh shapes can be shared, check first if we already have a shape on that mesh - class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, false); - if (sharedShapeInfo != NULL) - { - delete shapeInfo; - shapeInfo = sharedShapeInfo; - shapeInfo->AddRef(); - } else - { - shapeInfo->SetMesh(meshobj, false,false); - } - - // Soft bodies require welding. Only avoid remove doubles for non-soft bodies! - if (objprop->m_softbody) - shapeInfo->setVertexWeldingThreshold1(0.01f); //todo: expose this to the UI + bool useGimpact = ((ci.m_mass || isbulletsensor) && !objprop->m_softbody); - bm = shapeInfo->CreateBulletShape(); - //no moving concave meshes, so don't bother calculating inertia - //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + // mesh shapes can be shared, check first if we already have a shape on that mesh + class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, dm, false,useGimpact); + if (sharedShapeInfo != NULL) + { + delete shapeInfo; + shapeInfo = sharedShapeInfo; + shapeInfo->AddRef(); } else { - shapeInfo->SetMesh(meshobj, false,true); - bm = shapeInfo->CreateBulletShape(); + shapeInfo->SetMesh(meshobj, dm, false,useGimpact); + } + + // Soft bodies require welding. Only avoid remove doubles for non-soft bodies! + if (objprop->m_softbody) + { + shapeInfo->setVertexWeldingThreshold1(objprop->m_soft_welding); //todo: expose this to the UI } + bm = shapeInfo->CreateBulletShape(ci.m_margin); + //should we compute inertia for dynamic shape? + //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + break; } } @@ -911,7 +934,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, return; } - bm->setMargin(ci.m_margin); + //bm->setMargin(ci.m_margin); if (objprop->m_isCompoundChild) @@ -926,39 +949,27 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, assert(colShape->isCompound()); btCompoundShape* compoundShape = (btCompoundShape*)colShape; - // compute the local transform from parent, this may include a parent inverse node + // compute the local transform from parent, this may include several node in the chain SG_Node* gameNode = gameobj->GetSGNode(); - SG_Node* parentInverseNode = gameNode->GetSGParent(); - if (parentInverseNode && parentInverseNode->GetSGClientObject() != NULL) - // this is not a parent inverse node, cancel it - parentInverseNode = NULL; - // now combine the parent inverse node and the game node - MT_Point3 childPos = gameNode->GetLocalPosition(); - MT_Matrix3x3 childRot = gameNode->GetLocalOrientation(); - MT_Vector3 childScale = gameNode->GetLocalScale(); - if (parentInverseNode) - { - const MT_Point3& parentInversePos = parentInverseNode->GetLocalPosition(); - const MT_Matrix3x3& parentInverseRot = parentInverseNode->GetLocalOrientation(); - const MT_Vector3& parentInverseScale = parentInverseNode->GetLocalScale(); - childRot = parentInverseRot * childRot; - childScale = parentInverseScale * childScale; - childPos = parentInversePos+parentInverseScale*(parentInverseRot*childPos); - } - - shapeInfo->m_childScale.setValue(childScale.x(),childScale.y(),childScale.z()); + SG_Node* parentNode = objprop->m_dynamic_parent->GetSGNode(); + // relative transform + MT_Vector3 parentScale = parentNode->GetWorldScaling(); + parentScale[0] = MT_Scalar(1.0)/parentScale[0]; + parentScale[1] = MT_Scalar(1.0)/parentScale[1]; + parentScale[2] = MT_Scalar(1.0)/parentScale[2]; + MT_Vector3 relativeScale = gameNode->GetWorldScaling() * parentScale; + MT_Matrix3x3 parentInvRot = parentNode->GetWorldOrientation().transposed(); + MT_Vector3 relativePos = parentInvRot*((gameNode->GetWorldPosition()-parentNode->GetWorldPosition())*parentScale); + MT_Matrix3x3 relativeRot = parentInvRot*gameNode->GetWorldOrientation(); + + shapeInfo->m_childScale.setValue(relativeScale[0],relativeScale[1],relativeScale[2]); bm->setLocalScaling(shapeInfo->m_childScale); - - shapeInfo->m_childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z())); - float rotval[12]; - childRot.getValue(rotval); - btMatrix3x3 newRot; - newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]); - newRot = newRot.transpose(); - - shapeInfo->m_childTrans.setBasis(newRot); + shapeInfo->m_childTrans.getOrigin().setValue(relativePos[0],relativePos[1],relativePos[2]); + float rot[12]; + relativeRot.getValue(rot); + shapeInfo->m_childTrans.getBasis().setFromOpenGLSubMatrix(rot); + parentShapeInfo->AddShape(shapeInfo); - compoundShape->addChildShape(shapeInfo->m_childTrans,bm); //do some recalc? //recalc inertia for rigidbody @@ -969,6 +980,8 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, compoundShape->calculateLocalInertia(mass,localInertia); rigidbody->setMassProps(mass,localInertia); } + // delete motionstate as it's not used + delete motionstate; return; } @@ -1081,26 +1094,32 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_soft_numclusteriterations= objprop->m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ //////////////////// - - ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter); - ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); + ci.m_collisionFilterGroup = + (isbulletsensor) ? short(CcdConstructionInfo::SensorFilter) : + (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : + short(CcdConstructionInfo::StaticFilter); + ci.m_collisionFilterMask = + (isbulletsensor) ? short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter) : + (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : + short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody; + + ci.m_contactProcessingThreshold = objprop->m_contactProcessingThreshold;//todo: expose this in advanced settings, just like margin, default to 10000 or so ci.m_bSoft = objprop->m_softbody; + ci.m_bSensor = isbulletsensor; MT_Vector3 scaling = gameobj->NodeGetWorldScaling(); ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]); - KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna,objprop->m_hasCompoundChildren); + KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna,isbulletsensor,objprop->m_hasCompoundChildren); // shapeInfo is reference counted, decrement now as we don't use it anymore if (shapeInfo) shapeInfo->Release(); - if (objprop->m_in_active_layer) + gameobj->SetPhysicsController(physicscontroller,isbulletdyna); + // don't add automatically sensor object, they are added when a collision sensor is registered + if (!isbulletsensor && objprop->m_in_active_layer) { env->addCcdPhysicsController( physicscontroller); } - - - - gameobj->SetPhysicsController(physicscontroller,isbulletdyna); physicscontroller->setNewClientInfo(gameobj->getClientInfo()); { btRigidBody* rbody = physicscontroller->GetRigidBody(); @@ -1159,7 +1178,9 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, } bool isActor = objprop->m_isactor; - gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC); + gameobj->getClientInfo()->m_type = + (isbulletsensor) ? ((isActor) ? KX_ClientObjectInfo::OBACTORSENSOR : KX_ClientObjectInfo::OBSENSOR) : + (isActor) ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC; // store materialname in auxinfo, needed for touchsensors if (meshobj) { @@ -1187,9 +1208,8 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, if (softBody && gameobj->GetMesh(0))//only the first mesh, if any { //should be a mesh then, so add a soft body deformer - KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),gameobj); + KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),(BL_DeformableGameObject*)gameobj); gameobj->SetDeformer(softbodyDeformer); - } } diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index 321370f9f3f..daa31379985 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -43,29 +43,30 @@ KX_Dome::KX_Dome ( RAS_IRenderTools* rendertools, /// engine KX_KetsjiEngine* engine, - - float size, //size for adjustments + short res, //resolution of the mesh short mode, //mode - fisheye, truncated, warped, panoramic, ... short angle, float resbuf, //size adjustment of the buffer + short tilt, struct Text* warptext ): - m_canvas(canvas), - m_rasterizer(rasterizer), - m_rendertools(rendertools), - m_engine(engine), + dlistSupported(false), + canvaswidth(-1), canvasheight(-1), m_drawingmode(engine->GetDrawType()), - m_size(size), m_resolution(res), m_mode(mode), m_angle(angle), m_resbuffer(resbuf), - canvaswidth(-1), canvasheight(-1), - dlistSupported(false) + m_tilt(tilt), + m_canvas(canvas), + m_rasterizer(rasterizer), + m_rendertools(rendertools), + m_engine(engine) { warp.usemesh = false; + fboSupported = false; if (mode >= DOME_NUM_MODES) m_mode = DOME_FISHEYE; @@ -107,15 +108,9 @@ KX_Dome::KX_Dome ( CreateMeshDome250(); m_numfaces = 5; } break; - case DOME_TRUNCATED: - cubetop.resize(1); - cubebottom.resize(1); - cubeleft.resize(2); - cuberight.resize(2); - - m_angle = 180; - CreateMeshDome180(); - m_numfaces = 4; + case DOME_ENVMAP: + m_angle = 360; + m_numfaces = 6; break; case DOME_PANORAM_SPH: cubeleft.resize(2); @@ -129,6 +124,25 @@ KX_Dome::KX_Dome ( CreateMeshPanorama(); m_numfaces = 6; break; + default: //DOME_TRUNCATED_FRONT and DOME_TRUNCATED_REAR + if (m_angle <= 180){ + cubetop.resize(1); + cubebottom.resize(1); + cubeleft.resize(2); + cuberight.resize(2); + + CreateMeshDome180(); + m_numfaces = 4; + }else if (m_angle > 180){ + cubetop.resize(2); + cubebottom.resize(2); + cubeleft.resize(2); + cubefront.resize(2); + cuberight.resize(2); + + CreateMeshDome250(); + m_numfaces = 5; + } break; } m_numimages =(warp.usemesh?m_numfaces+1:m_numfaces); @@ -137,23 +151,27 @@ KX_Dome::KX_Dome ( CreateGLImages(); + if(warp.usemesh) + fboSupported = CreateFBO(); + dlistSupported = CreateDL(); } // destructor KX_Dome::~KX_Dome (void) { - GLuint m_numimages = m_numfaces; - ClearGLImages(); + if(fboSupported) + glDeleteFramebuffersEXT(1, &warp.fboId); + if(dlistSupported) glDeleteLists(dlistId, (GLsizei) m_numimages); } void KX_Dome::SetViewPort(GLuint viewport[4]) { - if(canvaswidth != m_canvas->GetWidth() || canvasheight != m_canvas->GetHeight()) + if(canvaswidth != m_viewport.GetWidth() || canvasheight != m_viewport.GetHeight()) { m_viewport.SetLeft(viewport[0]); m_viewport.SetBottom(viewport[1]); @@ -180,9 +198,9 @@ void KX_Dome::CreateGLImages(void) } if(warp.usemesh){ glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagewidth, warp.imageheight, 0, GL_RGB8, + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagesize, warp.imagesize, 0, GL_RGB8, GL_UNSIGNED_BYTE, 0); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagewidth, warp.imageheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagesize, warp.imagesize, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -207,12 +225,25 @@ void KX_Dome::CalculateImageSize(void) - reduce the buffer for better performace - create a power of 2 texture bigger than the buffer */ +/* +Blender handles Canvas size differently when in fullscreen mode. +We are manually checking for that. Although it's a hack, it works. + +Bug reported here: #18655 - Inconsistency of pixels in canvas dimensions when in maximized mode (affecting BGE Dome) +http://projects.blender.org/tracker/?func=detail&aid=18655&group_id=9&atid=125 +*/ canvaswidth = m_canvas->GetWidth(); canvasheight = m_canvas->GetHeight(); + bool fullscreen(false); //XXX HACK + fullscreen = (canvaswidth != m_viewport.GetWidth()); + m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth); - m_buffersize *= m_resbuffer; //reduce buffer size for better performance + m_buffersize = (int)(m_buffersize*m_resbuffer); //reduce buffer size for better performance + + if (fullscreen) //XXX HACK + m_buffersize --; int i = 0; while ((1 << i) <= m_buffersize) @@ -220,27 +251,25 @@ void KX_Dome::CalculateImageSize(void) m_imagesize = (1 << i); if (warp.usemesh){ - warp.bufferwidth = canvaswidth; - warp.bufferheight = canvasheight; - - i = 0; - while ((1 << i) <= warp.bufferwidth) - i++; - warp.imagewidth = (1 << i); + // warp FBO needs to be up to twice as big as m_buffersize to get more resolution + warp.imagesize = m_imagesize; + if (m_buffersize == m_imagesize) + warp.imagesize *= 2; - i = 0; - while ((1 << i) <= warp.bufferheight) - i++; - warp.imageheight = (1 << i); + //if FBO is not working/supported, we use the canvas dimension as buffer + warp.bufferwidth = canvaswidth; + warp.bufferheight = canvasheight; } + + //XXX HACK + canvaswidth = m_viewport.GetWidth(); + canvasheight = m_viewport.GetHeight(); } bool KX_Dome::CreateDL(){ - int i,j; - dlistId = glGenLists((GLsizei) m_numimages); if (dlistId != 0) { - if(m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED){ + if(m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED_FRONT || m_mode == DOME_TRUNCATED_REAR){ glNewList(dlistId, GL_COMPILE); GLDrawTriangles(cubetop, nfacestop); glEndList(); @@ -312,6 +341,46 @@ bool KX_Dome::CreateDL(){ return true; } +bool KX_Dome::CreateFBO(void) +{ + if (!GLEW_EXT_framebuffer_object) + { + printf("Dome Error: FrameBuffer unsupported. Using low resolution warp image."); + return false; + } + + glGenFramebuffersEXT(1, &warp.fboId); + if(warp.fboId==0) + { + printf("Dome Error: Invalid frame buffer object. Using low resolution warp image."); + return false; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, domefacesId[m_numfaces], 0); + + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if(status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) + { + printf("Dome Error: FrameBuffer settings unsupported. Using low resolution warp image."); + return false; + } + else if(status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + glDeleteFramebuffersEXT(1, &warp.fboId); + return false; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + //nothing failed: we can use the whole FBO as buffersize + warp.bufferwidth = warp.bufferheight = warp.imagesize; + return true; +} + void KX_Dome::GLDrawTriangles(vector <DomeFace>& face, int nfaces) { int i,j; @@ -328,8 +397,9 @@ void KX_Dome::GLDrawTriangles(vector <DomeFace>& face, int nfaces) void KX_Dome::GLDrawWarpQuads(void) { int i, j, i2; - float uv_width = (float)(warp.bufferwidth-1) / warp.imagewidth; - float uv_height = (float)(warp.bufferheight-1) / warp.imageheight; + + float uv_width = (float)(warp.bufferwidth) / warp.imagesize; + float uv_height = (float)(warp.bufferheight) / warp.imagesize; if(warp.mode ==2 ){ glBegin(GL_QUADS); @@ -386,7 +456,7 @@ void KX_Dome::GLDrawWarpQuads(void) } glEnd(); } else{ - printf("Error: Warp Mode unsupported. Try 1 for Polar Mesh or 2 for Fisheye.\n"); + printf("Dome Error: Warp Mode %d unsupported. Try 1 for Polar Mesh or 2 for Fisheye.\n", warp.mode); } } @@ -415,20 +485,22 @@ y varies from -1 to 1 u and v vary from 0 to 1 i ranges from 0 to 1, if negative don't draw that mesh node */ - int i,j,k; + int i; int nodeX=0, nodeY=0; vector<STR_String> columns, lines; lines = text.Explode('\n'); if(lines.size() < 6){ - printf("Error: Warp Mesh File with insufficient data!\n"); + printf("Dome Error: Warp Mesh File with insufficient data!\n"); return false; } columns = lines[1].Explode(' '); + if(columns.size() == 1) + columns = lines[1].Explode('\t'); if(columns.size() !=2){ - printf("Error: Warp Mesh File incorrect. The second line should contain: width height.\n"); + printf("Dome Error: Warp Mesh File incorrect. The second line should contain: width height.\n"); return false; } @@ -437,14 +509,16 @@ i ranges from 0 to 1, if negative don't draw that mesh node warp.n_width = atoi(columns[0]); warp.n_height = atoi(columns[1]); - if (lines.size() < 2 + (warp.n_width * warp.n_height)){ - printf("Error: Warp Mesh File with insufficient data!\n"); + if ((int)lines.size() < 2 + (warp.n_width * warp.n_height)){ + printf("Dome Error: Warp Mesh File with insufficient data!\n"); return false; }else{ warp.nodes = vector<vector<WarpMeshNode> > (warp.n_height, vector<WarpMeshNode>(warp.n_width)); for(i=2; i-2 < (warp.n_width*warp.n_height); i++){ columns = lines[i].Explode(' '); + if(columns.size() == 1) + columns = lines[i].Explode('\t'); if (columns.size() == 5){ nodeX = (i-2)%warp.n_width; @@ -458,7 +532,7 @@ i ranges from 0 to 1, if negative don't draw that mesh node } else{ warp.nodes.clear(); - printf("Error: Warp Mesh File with wrong number of fields. You should use 5: x y u v i.\n"); + printf("Dome Error: Warp Mesh File with wrong number of fields. You should use 5: x y u v i.\n"); return false; } } @@ -1373,7 +1447,7 @@ void KX_Dome::CalculateFrustum(KX_Camera * cam) /* // manually creating a 90º Field of View Frustum - the original formula: + the original formula: top = tan(fov*3.14159/360.0) * near [for fov in degrees] fov*0.5 = arctan ((top-bottom)*0.5 / near) [for fov in radians] bottom = -top @@ -1411,11 +1485,14 @@ Uses 4 cameras for angles up to 180º Uses 5 cameras for angles up to 250º Uses 6 cameras for angles up to 360º */ + int i; float deg45 = MT_PI / 4; MT_Scalar c = cos(deg45); MT_Scalar s = sin(deg45); - if ((m_mode == DOME_FISHEYE && m_angle <= 180)|| m_mode == DOME_TRUNCATED){ + if (m_angle <= 180 && (m_mode == DOME_FISHEYE + || m_mode == DOME_TRUNCATED_FRONT + || m_mode == DOME_TRUNCATED_REAR)){ m_locRot[0] = MT_Matrix3x3( // 90º - Top c, -s, 0.0, @@ -1437,7 +1514,9 @@ Uses 6 cameras for angles up to 360º 0.0, 1.0, 0.0, s, 0.0, c); - } else if ((m_mode == DOME_FISHEYE && m_angle > 180)){ + } else if (m_mode == DOME_ENVMAP || (m_angle > 180 && (m_mode == DOME_FISHEYE + || m_mode == DOME_TRUNCATED_FRONT + || m_mode == DOME_TRUNCATED_REAR))){ m_locRot[0] = MT_Matrix3x3( // 90º - Top 1.0, 0.0, 0.0, @@ -1464,7 +1543,7 @@ Uses 6 cameras for angles up to 360º 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); - m_locRot[5] = MT_Matrix3x3( // 180º - Back - NOT USING + m_locRot[5] = MT_Matrix3x3( // 180º - Back - USED for ENVMAP only -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,-1.0); @@ -1501,6 +1580,23 @@ Uses 6 cameras for angles up to 360º 0.0, 1.0, 0.0, s, 0.0, c); } + + // rotating the camera in horizontal axis + if (m_tilt) + { + float tiltdeg = ((m_tilt % 360) * 2 * MT_PI) / 360; + c = cos(tiltdeg); + s = sin(tiltdeg); + + MT_Matrix3x3 tilt_mat = MT_Matrix3x3( + 1.0, 0.0, 0.0, + 0.0, c, -s, + 0.0, s, c + ); + + for (i =0;i<6;i++) + m_locRot[i] = tilt_mat * m_locRot[i]; + } } void KX_Dome::RotateCamera(KX_Camera* cam, int i) @@ -1515,8 +1611,7 @@ void KX_Dome::RotateCamera(KX_Camera* cam, int i) MT_Transform camtrans(cam->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(), - cam->GetCameraLocation(), cam->GetCameraOrientation()); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); // restore the original orientation @@ -1527,30 +1622,49 @@ void KX_Dome::RotateCamera(KX_Camera* cam, int i) void KX_Dome::Draw(void) { + if (fboSupported){ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); + + glViewport(0,0,warp.imagesize, warp.imagesize); + glScissor(0,0,warp.imagesize, warp.imagesize); + } + switch(m_mode){ case DOME_FISHEYE: DrawDomeFisheye(); break; - case DOME_TRUNCATED: - DrawDomeFisheye(); + case DOME_ENVMAP: + DrawEnvMap(); break; case DOME_PANORAM_SPH: DrawPanorama(); break; + case DOME_TRUNCATED_FRONT: + DrawDomeFisheye(); + break; + case DOME_TRUNCATED_REAR: + DrawDomeFisheye(); + break; } if(warp.usemesh) { - glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), warp.bufferwidth, warp.bufferheight); + if(fboSupported) + { + m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + else + { + glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), warp.bufferwidth, warp.bufferheight); + } DrawDomeWarped(); } } -void KX_Dome::DrawDomeFisheye(void) +void KX_Dome::DrawEnvMap(void) { - int i,j; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -1563,28 +1677,17 @@ void KX_Dome::DrawDomeFisheye(void) float ortho_width, ortho_height; if (warp.usemesh) - glOrtho((-1.0), 1.0, (-1.0), 1.0, -20.0, 10.0); //stretch the image to reduce resolution lost + glOrtho((-1.0), 1.0, (-0.66), 0.66, -20.0, 10.0); //stretch the image to reduce resolution lost - else if(m_mode == DOME_TRUNCATED){ - ortho_width = 1.0; - ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; - - ortho_width /= m_size; - ortho_height /= m_size; - - glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0); - } else { - if (can_width < can_height){ + else { + if (can_width/3 <= can_height/2){ ortho_width = 1.0; ortho_height = (float)can_height/can_width; }else{ - ortho_width = (float)can_width/can_height; - ortho_height = 1.0; + ortho_height = 2.0f / 3; + ortho_width = (float)can_width/can_height * ortho_height; } - ortho_width /= m_size; - ortho_height /= m_size; - glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); } @@ -1592,6 +1695,150 @@ void KX_Dome::DrawDomeFisheye(void) glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + gluLookAt(0.0,0.0,1.0, 0.0,0.0,0.0, 0.0,1.0,0.0); + + glPolygonMode(GL_FRONT, GL_FILL); + glShadeModel(GL_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + glEnable(GL_TEXTURE_2D); + glColor3f(1.0,1.0,1.0); + + float uv_ratio = (float)(m_buffersize-1) / m_imagesize; + double onebythree = 1.0f / 3; + + // domefacesId[0] => (top) + glBindTexture(GL_TEXTURE_2D, domefacesId[0]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-onebythree,-2 * onebythree, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(onebythree,-2 * onebythree, 3.0f); + glEnd(); + + // domefacesId[1] => (bottom) + glBindTexture(GL_TEXTURE_2D, domefacesId[1]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f(-onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-1.0f, 0.0f, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-1.0f,-2 * onebythree, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(-onebythree,-2 * onebythree, 3.0f); + glEnd(); + + // domefacesId[2] => -90º (left) + glBindTexture(GL_TEXTURE_2D, domefacesId[2]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f(-onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-1.0f, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-1.0f, 0.0f, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(-onebythree, 0.0f, 3.0f); + glEnd(); + + // domefacesId[3] => 90º (right) + glBindTexture(GL_TEXTURE_2D, domefacesId[3]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( 1.0f, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f( onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f( onebythree, 0.0f, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(1.0f, 0.0f, 3.0f); + glEnd(); + + // domefacesId[4] => 0º (front) + glBindTexture(GL_TEXTURE_2D, domefacesId[4]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( 1.0f, 0.0f, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f( onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f( onebythree,-2 * onebythree, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(1.0f, -2 * onebythree, 3.0f); + glEnd(); + + // domefacesId[5] => 180º (back) + glBindTexture(GL_TEXTURE_2D, domefacesId[5]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-onebythree, 0.0f, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(onebythree, 0.0f, 3.0f); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); +} + +void KX_Dome::DrawDomeFisheye(void) +{ + int i; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Making the viewport always square + + int can_width = m_viewport.GetRight(); + int can_height = m_viewport.GetTop(); + + float ortho_width, ortho_height; + + if(m_mode == DOME_FISHEYE) { + if (warp.usemesh) + glOrtho((-1.0), 1.0, (-1.0), 1.0, -20.0, 10.0); //stretch the image to reduce resolution lost + + else { + if (can_width < can_height){ + ortho_width = 1.0; + ortho_height = (float)can_height/can_width; + }else{ + ortho_width = (float)can_width/can_height; + ortho_height = 1.0; + } + + glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); + } + } + else if(m_mode == DOME_TRUNCATED_FRONT) + { + ortho_width = 1.0; + ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; + + glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0); + } + else { //m_mode == DOME_TRUNCATED_REAR + ortho_width = 1.0; + ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; + + glOrtho((-ortho_width), ortho_width, (-ortho_width), ortho_height, -20.0, 10.0); + } + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0); if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) @@ -1641,7 +1888,7 @@ void KX_Dome::DrawDomeFisheye(void) void KX_Dome::DrawPanorama(void) { - int i,j; + int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -1666,9 +1913,6 @@ void KX_Dome::DrawPanorama(void) ortho_width = (float)can_width/can_height * 0.5; ortho_height = 0.5; } - - ortho_width /= m_size; - ortho_height /= m_size; glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); } @@ -1728,8 +1972,6 @@ void KX_Dome::DrawPanorama(void) void KX_Dome::DrawDomeWarped(void) { - int i,j; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -1739,7 +1981,6 @@ void KX_Dome::DrawDomeWarped(void) int can_height = m_viewport.GetTop(); double screen_ratio = can_width/ (double) can_height; - screen_ratio /= m_size; glOrtho(-screen_ratio,screen_ratio,-1.0,1.0,-20.0,10.0); @@ -1762,10 +2003,6 @@ void KX_Dome::DrawDomeWarped(void) glEnable(GL_TEXTURE_2D); glColor3f(1.0,1.0,1.0); - - float uv_width = (float)(warp.bufferwidth-1) / warp.imagewidth; - float uv_height = (float)(warp.bufferheight-1) / warp.imageheight; - if (dlistSupported){ glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); glCallList(dlistId + m_numfaces); @@ -1806,8 +2043,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) MT_Transform camtrans(cam->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(), - cam->GetCameraLocation(), cam->GetCameraOrientation()); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0); cam->SetModelviewMatrix(viewmat); scene->CalculateVisibleMeshes(m_rasterizer,cam); @@ -1816,4 +2052,5 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) // restore the original orientation cam->NodeSetLocalOrientation(camori); cam->NodeUpdateGS(0.f); -}
\ No newline at end of file +} + diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h index 786e04b4385..20b60ef0173 100644 --- a/source/gameengine/Ketsji/KX_Dome.h +++ b/source/gameengine/Ketsji/KX_Dome.h @@ -38,13 +38,14 @@ Developed as part of a Research and Development project for SAT - La Société des #include "MEM_guardedalloc.h" #include "BKE_text.h" -//#include "BLI_blenlib.h" //Dome modes: limit hardcoded in buttons_scene.c -#define DOME_FISHEYE 1 -#define DOME_TRUNCATED 2 -#define DOME_PANORAM_SPH 3 -#define DOME_NUM_MODES 4 +#define DOME_FISHEYE 1 +#define DOME_TRUNCATED_FRONT 2 +#define DOME_TRUNCATED_REAR 3 +#define DOME_ENVMAP 4 +#define DOME_PANORAM_SPH 5 +#define DOME_NUM_MODES 6 /// class for render 3d scene @@ -60,12 +61,12 @@ public: RAS_IRenderTools* m_rendertools, /// engine KX_KetsjiEngine* m_engine, - - float size, + short res, short mode, short angle, float resbuf, + short tilt, struct Text* warptext ); @@ -74,6 +75,7 @@ public: //openGL checks: bool dlistSupported; + bool fboSupported; //openGL names: GLuint domefacesId[7]; // ID of the images -- room for 7 images, using only 4 for 180º x 360º dome, 6 for panoramic and +1 for warp mesh @@ -93,8 +95,9 @@ public: bool usemesh; int mode; int n_width, n_height; //nodes width and height - int imagewidth, imageheight; + int imagesize; int bufferwidth, bufferheight; + GLuint fboId; vector <vector <WarpMeshNode> > nodes; } warp; @@ -116,7 +119,7 @@ public: void CalculateFrustum(KX_Camera* cam); void RotateCamera(KX_Camera* cam, int i); - //Mesh Creating Functions + //Mesh creation Functions void CreateMeshDome180(void); void CreateMeshDome250(void); void CreateMeshPanorama(void); @@ -131,6 +134,7 @@ public: void GLDrawWarpQuads(void); void Draw(void); void DrawDomeFisheye(void); + void DrawEnvMap(void); void DrawPanorama(void); void DrawDomeWarped(void); @@ -139,6 +143,8 @@ public: void ClearGLImages(void);//called on resize bool CreateDL(void); //create Display Lists void ClearDL(void); //remove Display Lists + bool CreateFBO(void);//create FBO (for warp mesh) + void ClearFBO(void); //remove FBO void CalculateCameraOrientation(); void CalculateImageSize(); //set m_imagesize @@ -153,13 +159,13 @@ protected: int m_buffersize; // canvas small dimension int m_numfaces; // 4 to 6 depending on the kind of dome image int m_numimages; //numfaces +1 if we have warp mesh - - float m_size; // size to adjust + short m_resolution; //resolution to tesselate the mesh short m_mode; // the mode (truncated, warped, panoramic,...) short m_angle; //the angle of the fisheye float m_radangle; //the angle of the fisheye in radians float m_resbuffer; //the resolution of the buffer + short m_tilt; //the dome tilt (camera rotation on horizontal axis) RAS_Rect m_viewport; @@ -181,3 +187,4 @@ protected: }; #endif + diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index 8b587c6f7de..28bf12f5e87 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -73,8 +73,6 @@ CValue* KX_GameActuator::GetReplica() { KX_GameActuator* replica = new KX_GameActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -151,6 +149,8 @@ bool KX_GameActuator::Update() } else { printf("Warning: could not create marshal buffer\n"); } + if (marshal_buffer) + delete [] marshal_buffer; } break; } @@ -208,8 +208,13 @@ bool KX_GameActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_GameActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_GameActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -249,16 +254,20 @@ PyMethodDef KX_GameActuator::Methods[] = }; PyAttributeDef KX_GameActuator::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("file",0,100,false,KX_GameActuator,m_filename), + KX_PYATTRIBUTE_STRING_RW("fileName",0,100,false,KX_GameActuator,m_filename), + KX_PYATTRIBUTE_INT_RW("mode", KX_GAME_NODEF+1, KX_GAME_MAX-1, true, KX_GameActuator, m_mode), { NULL } //Sentinel }; -PyObject* -KX_GameActuator::py_getattro(PyObject *attr) +PyObject* KX_GameActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); } +PyObject* KX_GameActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_GameActuator::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_IActuator); @@ -272,7 +281,7 @@ const char KX_GameActuator::GetFile_doc[] = "get the name of the file to start.\n"; PyObject* KX_GameActuator::PyGetFile(PyObject* args, PyObject* kwds) { - ShowDeprecationWarning("getFile()", "the file property"); + ShowDeprecationWarning("getFile()", "the fileName property"); return PyString_FromString(m_filename); } @@ -284,7 +293,7 @@ PyObject* KX_GameActuator::PySetFile(PyObject* args, PyObject* kwds) { char* new_file; - ShowDeprecationWarning("setFile()", "the file property"); + ShowDeprecationWarning("setFile()", "the fileName property"); if (!PyArg_ParseTuple(args, "s:setFile", &new_file)) { diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h index 570cb2e68ef..b2b1d6ec2b9 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.h +++ b/source/gameengine/Ketsji/KX_GameActuator.h @@ -78,6 +78,7 @@ protected: /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // Deprecated functions -----> diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index bea0fcff2af..7f417b325c8 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -49,6 +49,8 @@ typedef unsigned long uint_ptr; #include "RAS_IPolygonMaterial.h" #include "KX_BlenderMaterial.h" #include "KX_GameObject.h" +#include "KX_Camera.h" // only for their ::Type +#include "KX_Light.h" // only for their ::Type #include "RAS_MeshObject.h" #include "KX_MeshProxy.h" #include "KX_PolyProxy.h" @@ -63,6 +65,7 @@ typedef unsigned long uint_ptr; #include "KX_RayCast.h" #include "KX_PythonInit.h" #include "KX_PyMath.h" +#include "KX_PythonSeq.h" #include "SCA_IActuator.h" #include "SCA_ISensor.h" #include "SCA_IController.h" @@ -187,38 +190,23 @@ double KX_GameObject::GetNumber() -STR_String KX_GameObject::GetName() +STR_String& KX_GameObject::GetName() { return m_name; } -void KX_GameObject::SetName(STR_String name) +void KX_GameObject::SetName(const char *name) { m_name = name; }; // Set the name of the value - - -void KX_GameObject::ReplicaSetName(STR_String name) -{ -} - - - - - - KX_IPhysicsController* KX_GameObject::GetPhysicsController() { return m_pPhysicsController1; } - - - - KX_GameObject* KX_GameObject::GetParent() { KX_GameObject* result = NULL; @@ -238,7 +226,7 @@ KX_GameObject* KX_GameObject::GetParent() } -void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) +void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj, bool addToCompound, bool ghost) { // check on valid node in case a python controller holds a reference to a deleted object if (obj && GetSGNode() && obj->GetSGNode() && GetSGNode()->GetSGParent() != obj->GetSGNode()) @@ -259,7 +247,7 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) if (m_pPhysicsController1) { - m_pPhysicsController1->SuspendDynamics(true); + m_pPhysicsController1->SuspendDynamics(ghost); } // Set us to our new scale, position, and orientation scale2[0] = 1.0/scale2[0]; @@ -280,7 +268,7 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) Release(); // if the new parent is a compound object, add this object shape to the compound shape. // step 0: verify this object has physical controller - if (m_pPhysicsController1) + if (m_pPhysicsController1 && addToCompound) { // step 1: find the top parent (not necessarily obj) KX_GameObject* rootobj = (KX_GameObject*)obj->GetSGNode()->GetRootSGParent()->GetSGClientObject(); @@ -326,33 +314,75 @@ void KX_GameObject::RemoveParent(KX_Scene *scene) rootobj->m_pPhysicsController1->RemoveCompoundChild(m_pPhysicsController1); } m_pPhysicsController1->RestoreDynamics(); + if (m_pPhysicsController1->IsDyna() && rootobj->m_pPhysicsController1) + { + // dynamic object should remember the velocity they had while being parented + MT_Point3 childPoint = GetSGNode()->GetWorldPosition(); + MT_Point3 rootPoint = rootobj->GetSGNode()->GetWorldPosition(); + MT_Point3 relPoint; + relPoint = (childPoint-rootPoint); + MT_Vector3 linVel = rootobj->m_pPhysicsController1->GetVelocity(relPoint); + MT_Vector3 angVel = rootobj->m_pPhysicsController1->GetAngularVelocity(); + m_pPhysicsController1->SetLinearVelocity(linVel, false); + m_pPhysicsController1->SetAngularVelocity(angVel, false); + } } // graphically, the object hasn't change place, no need to update m_pGraphicController } } -void KX_GameObject::ProcessReplica(KX_GameObject* replica) +void KX_GameObject::ProcessReplica() { - 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; - replica->m_state = 0; + SCA_IObject::ProcessReplica(); + + m_pPhysicsController1 = NULL; + m_pGraphicController = NULL; + m_pSGNode = NULL; + m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); + m_pClient_info->m_gameobject = this; + m_state = 0; if(m_attr_dict) - replica->m_attr_dict= PyDict_Copy(m_attr_dict); + m_attr_dict= PyDict_Copy(m_attr_dict); + +} + +static void setGraphicController_recursive(SG_Node* node) +{ + NodeList& children = node->GetSGChildren(); + + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* childnode = (*childit); + KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj != NULL) // This is a GameObject + clientgameobj->ActivateGraphicController(false); + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + setGraphicController_recursive(childnode); + } } +void KX_GameObject::ActivateGraphicController(bool recurse) +{ + if (m_pGraphicController) + { + m_pGraphicController->Activate(m_bVisible); + } + if (recurse) + { + setGraphicController_recursive(GetSGNode()); + } +} + CValue* KX_GameObject::GetReplica() { KX_GameObject* replica = new KX_GameObject(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); - ProcessReplica(replica); + replica->ProcessReplica(); return replica; } @@ -421,6 +451,7 @@ double* KX_GameObject::GetOpenGLMatrix() m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; trans.scale(scaling[0], scaling[1], scaling[2]); trans.getValue(fl); + GetSGNode()->ClearDirty(); } return fl; } @@ -428,8 +459,18 @@ double* KX_GameObject::GetOpenGLMatrix() void KX_GameObject::AddMeshUser() { for (size_t i=0;i<m_meshes.size();i++) - m_meshes[i]->AddMeshUser(this); - + { + m_meshes[i]->AddMeshUser(this, &m_meshSlots, GetDeformer()); + } + // set the part of the mesh slot that never change + double* fl = GetOpenGLMatrixPtr()->getPointer(); + + SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); + RAS_MeshSlot* ms; + for(mit.begin(); !mit.end(); ++mit) + { + (*mit)->m_OpenGLMatrix = fl; + } UpdateBuckets(false); } @@ -453,10 +494,27 @@ static void UpdateBuckets_recursive(SG_Node* node) void KX_GameObject::UpdateBuckets( bool recursive ) { if (GetSGNode()) { - double* fl = GetOpenGLMatrixPtr()->getPointer(); + RAS_MeshSlot *ms; + + if (GetSGNode()->IsDirty()) + GetOpenGLMatrix(); - for (size_t i=0;i<m_meshes.size();i++) - m_meshes[i]->UpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled); + SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); + for(mit.begin(); !mit.end(); ++mit) + { + ms = *mit; + ms->m_bObjectColor = m_bUseObjectColor; + ms->m_RGBAcolor = m_objectColor; + ms->m_bVisible = m_bVisible; + ms->m_bCulled = m_bCulled || !m_bVisible; + if (!ms->m_bCulled) + ms->m_bucket->ActivateMesh(ms); + + /* split if necessary */ +#ifdef USE_SPLIT + ms->Split(); +#endif + } if (recursive) { UpdateBuckets_recursive(GetSGNode()); @@ -476,11 +534,11 @@ void KX_GameObject::RemoveMeshes() 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 + // HACK: saves function call for dynamic object, they are handled differently + if (m_pPhysicsController1 && !m_pPhysicsController1->IsDyna()) + // 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 + // done during physics simulation m_pPhysicsController1->SetSumoTransform(true); if (m_pGraphicController) // update the culling tree @@ -493,6 +551,20 @@ void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* s ((KX_GameObject*)gameobj)->UpdateTransform(); } +void KX_GameObject::SynchronizeTransform() +{ + // only used for sensor object, do full synchronization as bullet doesn't do it + if (m_pPhysicsController1) + m_pPhysicsController1->SetTransform(); + if (m_pGraphicController) + m_pGraphicController->SetGraphicTransform(); +} + +void KX_GameObject::SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene) +{ + ((KX_GameObject*)gameobj)->SynchronizeTransform(); +} + void KX_GameObject::SetDebugColor(unsigned int bgra) { @@ -613,6 +685,8 @@ KX_GameObject::SetVisible( { if (GetSGNode()) { m_bVisible = v; + if (m_pGraphicController) + m_pGraphicController->Activate(m_bVisible); if (recursive) setVisible_recursive(GetSGNode(), v); } @@ -1081,7 +1155,6 @@ CListValue* KX_GameObject::GetChildrenRecursive() /* ------- python stuff ---------------------------------------------------*/ PyMethodDef KX_GameObject::Methods[] = { - {"setWorldPosition", (PyCFunction) KX_GameObject::sPySetWorldPosition, METH_O}, {"applyForce", (PyCFunction) KX_GameObject::sPyApplyForce, METH_VARARGS}, {"applyTorque", (PyCFunction) KX_GameObject::sPyApplyTorque, METH_VARARGS}, {"applyRotation", (PyCFunction) KX_GameObject::sPyApplyRotation, METH_VARARGS}, @@ -1100,7 +1173,7 @@ PyMethodDef KX_GameObject::Methods[] = { {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS}, {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS}, {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O}, - {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_O}, + {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_VARARGS}, {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, {"setOcclusion",(PyCFunction) KX_GameObject::sPySetOcclusion, METH_VARARGS}, {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS}, @@ -1116,10 +1189,15 @@ PyMethodDef KX_GameObject::Methods[] = { KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), KX_PYMETHODTABLE_O(KX_GameObject, getVectTo), KX_PYMETHODTABLE(KX_GameObject, sendMessage), - + + // dict style access for props + {"has_key",(PyCFunction) KX_GameObject::sPyhas_key, METH_O}, + {"get",(PyCFunction) KX_GameObject::sPyget, METH_VARARGS}, + // deprecated {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_NOARGS}, {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_O}, + {"setWorldPosition", (PyCFunction) KX_GameObject::sPySetWorldPosition, METH_O}, {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_NOARGS}, {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_O}, {"getState",(PyCFunction) KX_GameObject::sPyGetState, METH_NOARGS}, @@ -1147,13 +1225,14 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), - KX_PYATTRIBUTE_RO_FUNCTION("worldOrientation",KX_GameObject,pyattr_get_worldOrientation), + KX_PYATTRIBUTE_RW_FUNCTION("worldOrientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_worldOrientation), KX_PYATTRIBUTE_RW_FUNCTION("localPosition", KX_GameObject, pyattr_get_localPosition, pyattr_set_localPosition), KX_PYATTRIBUTE_RW_FUNCTION("worldPosition", KX_GameObject, pyattr_get_worldPosition, pyattr_set_worldPosition), - KX_PYATTRIBUTE_RW_FUNCTION("localScaling", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), - KX_PYATTRIBUTE_RO_FUNCTION("worldScaling", KX_GameObject, pyattr_get_worldScaling), - - KX_PYATTRIBUTE_RO_FUNCTION("__dict__", KX_GameObject, pyattr_get_dir_dict), + KX_PYATTRIBUTE_RW_FUNCTION("localScale", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), + KX_PYATTRIBUTE_RO_FUNCTION("worldScale", KX_GameObject, pyattr_get_worldScaling), + KX_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), + KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), + KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), /* Experemental, dont rely on these yet */ KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors), @@ -1193,8 +1272,8 @@ PyObject* KX_GameObject::PyReplaceMesh(PyObject* value) PyObject* KX_GameObject::PyEndObject() { - KX_Scene *scene = KX_GetActiveScene(); + scene->DelayedRemoveObject(this); Py_RETURN_NONE; @@ -1208,21 +1287,6 @@ PyObject* KX_GameObject::PyGetPosition() return PyObjectFrom(NodeGetWorldPosition()); } - -Py_ssize_t KX_GameObject::Map_Len(PyObject* self_v) -{ - KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); - - if (self==NULL) /* not sure what to do here */ - return 0; - - Py_ssize_t len= self->GetPropertyCount(); - if(self->m_attr_dict) - len += PyDict_Size(self->m_attr_dict); - return len; -} - - PyObject *KX_GameObject::Map_GetItem(PyObject *self_v, PyObject *item) { KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); @@ -1231,7 +1295,7 @@ PyObject *KX_GameObject::Map_GetItem(PyObject *self_v, PyObject *item) PyObject* pyconvert; if (self==NULL) { - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return NULL; } @@ -1265,7 +1329,7 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) PyErr_Clear(); if (self==NULL) { - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); return -1; } @@ -1281,7 +1345,7 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) if (del==0) { if(attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" could not be set", attr_str); - else PyErr_SetString(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key could not be set"); + else PyErr_SetString(PyExc_KeyError, "del gameOb[key]: KX_GameObject, key could not be deleted"); return -1; } else if (self->m_attr_dict) { @@ -1292,9 +1356,9 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) int set= 0; /* as CValue */ - if(attr_str) + if(attr_str && BGE_PROXY_CHECK_TYPE(val)==0) /* dont allow GameObjects for eg to be assigned to CValue props */ { - CValue* vallie = self->ConvertPythonToValue(val); + CValue* vallie = self->ConvertPythonToValue(val, ""); /* error unused */ if(vallie) { @@ -1345,17 +1409,21 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) return 0; /* success */ } - +/* Cant set the len otherwise it can evaluate as false */ PyMappingMethods KX_GameObject::Mapping = { - (lenfunc)KX_GameObject::Map_Len, /*inquiry mp_length */ + (lenfunc)NULL , /*inquiry mp_length */ (binaryfunc)KX_GameObject::Map_GetItem, /*binaryfunc mp_subscript */ (objobjargproc)KX_GameObject::Map_SetItem, /*objobjargproc mp_ass_subscript */ }; - PyTypeObject KX_GameObject::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_GameObject", sizeof(PyObjectPlus_Proxy), 0, @@ -1396,8 +1464,10 @@ PyObject* KX_GameObject::pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DE { KX_GameObject* self= static_cast<KX_GameObject*>(self_v); KX_GameObject* parent = self->GetParent(); - if (parent) + if (parent) { + parent->Release(); /* self->GetParent() AddRef's */ return parent->GetProxy(); + } Py_RETURN_NONE; } @@ -1415,13 +1485,13 @@ int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrd MT_Scalar val = PyFloat_AsDouble(value); if (val < 0.0f) { /* also accounts for non float */ PyErr_SetString(PyExc_AttributeError, "gameOb.mass = float: KX_GameObject, expected a float zero or above"); - return 1; + return PY_SET_ATTR_FAIL; } if (spc) spc->SetMass(val); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1438,13 +1508,13 @@ int KX_GameObject::pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF MT_Scalar val = PyFloat_AsDouble(value); if (val < 0.0f) { /* also accounts for non float */ PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMin = float: KX_GameObject, expected a float zero or above"); - return 1; + return PY_SET_ATTR_FAIL; } if (spc) spc->SetLinVelocityMin(val); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1461,13 +1531,13 @@ int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF MT_Scalar val = PyFloat_AsDouble(value); if (val < 0.0f) { /* also accounts for non float */ PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMax = float: KX_GameObject, expected a float zero or above"); - return 1; + return PY_SET_ATTR_FAIL; } if (spc) spc->SetLinVelocityMax(val); - return 0; + return PY_SET_ATTR_SUCCESS; } @@ -1483,12 +1553,12 @@ int KX_GameObject::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *at int param = PyObject_IsTrue( value ); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "gameOb.visible = bool: KX_GameObject, expected True or False"); - return 1; + return PY_SET_ATTR_FAIL; } self->SetVisible(param, false); self->UpdateBuckets(false); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1502,11 +1572,11 @@ int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_D KX_GameObject* self= static_cast<KX_GameObject*>(self_v); MT_Point3 pos; if (!PyVecTo(value, pos)) - return 1; + return PY_SET_ATTR_FAIL; self->NodeSetWorldPosition(pos); self->NodeUpdateGS(0.f); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1523,11 +1593,11 @@ int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_D KX_GameObject* self= static_cast<KX_GameObject*>(self_v); MT_Point3 pos; if (!PyVecTo(value, pos)) - return 1; + return PY_SET_ATTR_FAIL; self->NodeSetLocalPosition(pos); self->NodeUpdateGS(0.f); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1546,6 +1616,26 @@ PyObject* KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYAT return PyObjectFrom(self->NodeGetWorldOrientation()); } +int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + + /* if value is not a sequence PyOrientationTo makes an error */ + MT_Matrix3x3 rot; + if (!PyOrientationTo(value, rot, "gameOb.worldOrientation = sequence: KX_GameObject, ")) + return PY_SET_ATTR_FAIL; + + if (self->GetSGNode() && self->GetSGNode()->GetSGParent()) { + self->NodeSetLocalOrientation(self->GetSGNode()->GetSGParent()->GetWorldOrientation().inverse()*rot); + } + else { + self->NodeSetLocalOrientation(rot); + } + + self->NodeUpdateGS(0.f); + return PY_SET_ATTR_SUCCESS; +} + PyObject* KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self= static_cast<KX_GameObject*>(self_v); @@ -1561,12 +1651,12 @@ int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUT /* if value is not a sequence PyOrientationTo makes an error */ MT_Matrix3x3 rot; - if (!PyOrientationTo(value, rot, "gameOb.orientation = sequence: KX_GameObject, ")) - return NULL; + if (!PyOrientationTo(value, rot, "gameOb.localOrientation = sequence: KX_GameObject, ")) + return PY_SET_ATTR_FAIL; self->NodeSetLocalOrientation(rot); self->NodeUpdateGS(0.f); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1589,11 +1679,11 @@ int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DE KX_GameObject* self= static_cast<KX_GameObject*>(self_v); MT_Vector3 scale; if (!PyVecTo(value, scale)) - return 1; + return PY_SET_ATTR_FAIL; self->NodeSetLocalScale(scale); self->NodeUpdateGS(0.f); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1615,12 +1705,12 @@ int KX_GameObject::pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF SG_Node* sg_parent= self->GetSGNode()->GetSGParent(); if (val < 0.0f) { /* also accounts for non float */ PyErr_SetString(PyExc_AttributeError, "gameOb.timeOffset = float: KX_GameObject, expected a float zero or above"); - return 1; + return PY_SET_ATTR_FAIL; } if (sg_parent && sg_parent->IsSlowParent()) static_cast<KX_SlowParentRelation *>(sg_parent->GetParentRelation())->SetTimeOffset(val); } - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1639,16 +1729,16 @@ int KX_GameObject::pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attr if (state_i == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "gameOb.state = int: KX_GameObject, expected an int bit field"); - return 1; + return PY_SET_ATTR_FAIL; } state |= state_i; if ((state & ((1<<30)-1)) == 0) { PyErr_SetString(PyExc_AttributeError, "gameOb.state = int: KX_GameObject, state bitfield was not between 0 and 30 (1<<0 and 1<<29)"); - return 1; + return PY_SET_ATTR_FAIL; } self->SetState(state); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -1657,10 +1747,10 @@ PyObject* KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DE PyObject *meshes= PyList_New(self->m_meshes.size()); int i; - for(i=0; i < self->m_meshes.size(); i++) + for(i=0; i < (int)self->m_meshes.size(); i++) { KX_MeshProxy* meshproxy = new KX_MeshProxy(self->m_meshes[i]); - PyList_SET_ITEM(meshes, i, meshproxy->GetProxy()); + PyList_SET_ITEM(meshes, i, meshproxy->NewProxy(true)); } return meshes; @@ -1669,69 +1759,40 @@ PyObject* KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DE /* experemental! */ PyObject* KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self= static_cast<KX_GameObject*>(self_v); - SCA_SensorList& sensors= self->GetSensors(); - PyObject* resultlist = PyList_New(sensors.size()); - - for (unsigned int index=0;index<sensors.size();index++) - PyList_SET_ITEM(resultlist, index, sensors[index]->GetProxy()); - - return resultlist; + return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_SENSORS); } PyObject* KX_GameObject::pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self= static_cast<KX_GameObject*>(self_v); - SCA_ControllerList& controllers= self->GetControllers(); - PyObject* resultlist = PyList_New(controllers.size()); - - for (unsigned int index=0;index<controllers.size();index++) - PyList_SET_ITEM(resultlist, index, controllers[index]->GetProxy()); - - return resultlist; + return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONTROLLERS); } PyObject* KX_GameObject::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { + return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_ACTUATORS); +} + +PyObject* KX_GameObject::pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ KX_GameObject* self= static_cast<KX_GameObject*>(self_v); - SCA_ActuatorList& actuators= self->GetActuators(); - PyObject* resultlist = PyList_New(actuators.size()); - - for (unsigned int index=0;index<actuators.size();index++) - PyList_SET_ITEM(resultlist, index, actuators[index]->GetProxy()); - - return resultlist; + return self->GetChildren()->NewProxy(true); } -/* __dict__ only for the purpose of giving useful dir() results */ -PyObject* KX_GameObject::pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject* KX_GameObject::pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return self->GetChildrenRecursive()->NewProxy(true); +} + +PyObject* KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self= static_cast<KX_GameObject*>(self_v); - PyObject *dict_str = PyString_FromString("__dict__"); - PyObject *dict= py_getattr_dict(self->SCA_IObject::py_getattro(dict_str), Type.tp_dict); - Py_DECREF(dict_str); - - if(dict==NULL) - return NULL; - - /* Not super fast getting as a list then making into dict keys but its only for dir() */ - PyObject *list= self->ConvertKeysToPython(); - if(list) - { - int i; - for(i=0; i<PyList_Size(list); i++) - PyDict_SetItem(dict, PyList_GET_ITEM(list, i), Py_None); - } - else - PyErr_Clear(); - - Py_DECREF(list); - /* Add m_attr_dict if we have it */ - if(self->m_attr_dict) - PyDict_Update(dict, self->m_attr_dict); + if(self->m_attr_dict==NULL) + self->m_attr_dict= PyDict_New(); - return dict; + Py_INCREF(self->m_attr_dict); + return self->m_attr_dict; } /* We need these because the macros have a return in them */ @@ -1772,11 +1833,38 @@ PyObject* KX_GameObject::py_getattro(PyObject *attr) return object; } +PyObject* KX_GameObject::py_getattro_dict() { + //py_getattro_dict_up(SCA_IObject); + PyObject *dict= py_getattr_dict(SCA_IObject::py_getattro_dict(), Type.tp_dict); + if(dict==NULL) + return NULL; + + /* normally just return this but KX_GameObject has some more items */ + + + /* Not super fast getting as a list then making into dict keys but its only for dir() */ + PyObject *list= ConvertKeysToPython(); + if(list) + { + int i; + for(i=0; i<PyList_Size(list); i++) + PyDict_SetItem(dict, PyList_GET_ITEM(list, i), Py_None); + } + else + PyErr_Clear(); + + Py_DECREF(list); + + /* Add m_attr_dict if we have it */ + if(m_attr_dict) + PyDict_Update(dict, m_attr_dict); + + return dict; +} + int KX_GameObject::py_setattro(PyObject *attr, PyObject *value) // py_setattro method { - int ret; - - ret= py_setattro__internal(attr, value); + int ret= py_setattro__internal(attr, value); if (ret==PY_SET_ATTR_SUCCESS) { /* remove attribute in our own dict to avoid double ups */ @@ -1789,7 +1877,7 @@ int KX_GameObject::py_setattro(PyObject *attr, PyObject *value) // py_setattro m if (ret==PY_SET_ATTR_COERCE_FAIL) { /* CValue attribute exists, remove CValue and add PyDict value */ - RemoveProperty(STR_String(PyString_AsString(attr))); + RemoveProperty(PyString_AsString(attr)); ret= PY_SET_ATTR_MISSING; } @@ -1814,16 +1902,18 @@ int KX_GameObject::py_setattro(PyObject *attr, PyObject *value) // py_setattro m int KX_GameObject::py_delattro(PyObject *attr) { + ShowDeprecationWarning("del ob.attr", "del ob['attr'] for user defined properties"); + char *attr_str= PyString_AsString(attr); - if (RemoveProperty(STR_String(attr_str))) // XXX - should call CValues instead but its only 2 lines here - return 0; + if (RemoveProperty(attr_str)) // XXX - should call CValues instead but its only 2 lines here + return PY_SET_ATTR_SUCCESS; if (m_attr_dict && (PyDict_DelItem(m_attr_dict, attr) == 0)) - return 0; + return PY_SET_ATTR_SUCCESS; PyErr_Format(PyExc_AttributeError, "del gameOb.myAttr: KX_GameObject, attribute \"%s\" dosnt exist", attr_str); - return 1; + return PY_SET_ATTR_MISSING; } @@ -2008,14 +2098,8 @@ PyObject* KX_GameObject::PyGetVelocity(PyObject* args) MT_Point3 point(0.0,0.0,0.0); PyObject* pypos = NULL; - if (PyArg_ParseTuple(args, "|O:getVelocity", &pypos)) - { - if (pypos) - PyVecTo(pypos, point); - } - else { + if (!PyArg_ParseTuple(args, "|O:getVelocity", &pypos) || (pypos && !PyVecTo(pypos, point))) return NULL; - } if (m_pPhysicsController1) { @@ -2075,35 +2159,49 @@ PyObject* KX_GameObject::PyGetParent() { ShowDeprecationWarning("getParent()", "the parent property"); KX_GameObject* parent = this->GetParent(); - if (parent) + if (parent) { + parent->Release(); /* self->GetParent() AddRef's */ return parent->GetProxy(); + } Py_RETURN_NONE; } -PyObject* KX_GameObject::PySetParent(PyObject* value) +PyObject* KX_GameObject::PySetParent(PyObject* args) { + KX_Scene *scene = KX_GetActiveScene(); + PyObject* pyobj; KX_GameObject *obj; - if (!ConvertPythonToGameObject(value, &obj, false, "gameOb.setParent(value): KX_GameObject")) - return NULL; + int addToCompound=1, ghost=1; - this->SetParent(KX_GetActiveScene(), obj); + if (!PyArg_ParseTuple(args,"O|ii:setParent", &pyobj, &addToCompound, &ghost)) { + return NULL; // Python sets a simple error + } + if (!ConvertPythonToGameObject(pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject")) + return NULL; + if (obj) + this->SetParent(scene, obj, addToCompound, ghost); Py_RETURN_NONE; } PyObject* KX_GameObject::PyRemoveParent() { KX_Scene *scene = KX_GetActiveScene(); + this->RemoveParent(scene); Py_RETURN_NONE; } PyObject* KX_GameObject::PyGetChildren() { + ShowDeprecationWarning("getChildren()", "the children property"); + return GetChildren()->NewProxy(true); } PyObject* KX_GameObject::PyGetChildrenRecursive() { + ShowDeprecationWarning("getChildrenRecursive()", "the childrenRecursive property"); + return GetChildrenRecursive()->NewProxy(true); } @@ -2203,23 +2301,15 @@ PyObject* KX_GameObject::PyGetOrientation() //keywords PyObject* KX_GameObject::PySetOrientation(PyObject* value) { ShowDeprecationWarning("setOrientation()", "the orientation property"); - MT_Matrix3x3 matrix; - if (PyObject_IsMT_Matrix(value, 3) && PyMatTo(value, matrix)) - { - NodeSetLocalOrientation(matrix); - NodeUpdateGS(0.f); - Py_RETURN_NONE; - } + MT_Matrix3x3 rot; + + /* if value is not a sequence PyOrientationTo makes an error */ + if (!PyOrientationTo(value, rot, "gameOb.setOrientation(sequence): KX_GameObject, ")) + return NULL; - MT_Quaternion quat; - if (PyVecTo(value, quat)) - { - matrix.setRotation(quat); - NodeSetLocalOrientation(matrix); - NodeUpdateGS(0.f); - Py_RETURN_NONE; - } - return NULL; + NodeSetLocalOrientation(rot); + NodeUpdateGS(0.f); + Py_RETURN_NONE; } PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* args) @@ -2256,7 +2346,7 @@ PyObject* KX_GameObject::PyGetAxisVect(PyObject* value) PyObject* KX_GameObject::PySetPosition(PyObject* value) { - ShowDeprecationWarning("setPosition()", "the position property"); + ShowDeprecationWarning("setPosition()", "the localPosition property"); MT_Point3 pos; if (PyVecTo(value, pos)) { @@ -2270,6 +2360,7 @@ PyObject* KX_GameObject::PySetPosition(PyObject* value) PyObject* KX_GameObject::PySetWorldPosition(PyObject* value) { + ShowDeprecationWarning("setWorldPosition()", "the worldPosition property"); MT_Point3 pos; if (PyVecTo(value, pos)) { @@ -2474,6 +2565,34 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, Py_RETURN_NONE; } +/* faster then Py_BuildValue since some scripts call raycast a lot */ +static PyObject *none_tuple_3() +{ + PyObject *ret= PyTuple_New(3); + PyTuple_SET_ITEM(ret, 0, Py_None); + PyTuple_SET_ITEM(ret, 1, Py_None); + PyTuple_SET_ITEM(ret, 2, Py_None); + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + return ret; +} +static PyObject *none_tuple_4() +{ + PyObject *ret= PyTuple_New(4); + PyTuple_SET_ITEM(ret, 0, Py_None); + PyTuple_SET_ITEM(ret, 1, Py_None); + PyTuple_SET_ITEM(ret, 2, Py_None); + PyTuple_SET_ITEM(ret, 3, Py_None); + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + return ret; +} + KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n" " If no hit, return (None,None,None) or (None,None,None,None).\n" @@ -2541,12 +2660,14 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, if (dist != 0.0f) { MT_Vector3 toDir = toPoint-fromPoint; if (MT_fuzzyZero(toDir.length2())) { - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + return none_tuple_3(); } toDir.normalize(); toPoint = fromPoint + (dist) * toDir; } else if (MT_fuzzyZero((toPoint-fromPoint).length2())) { - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + return none_tuple_3(); } PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); @@ -2594,9 +2715,11 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, } // no hit if (poly) - return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + //return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + return none_tuple_4(); else - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + return none_tuple_3(); } KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, @@ -2606,6 +2729,7 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, "body = Message body (string)" "to = Name of object to send the message to") { + KX_Scene *scene = KX_GetActiveScene(); char* subject; char* body = (char *)""; char* to = (char *)""; @@ -2613,12 +2737,58 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, if (!PyArg_ParseTuple(args, "s|sss:sendMessage", &subject, &body, &to)) return NULL; + + scene->GetNetworkScene()->SendMessage(to, from, subject, body); + Py_RETURN_NONE; +} - KX_GetActiveScene()->GetNetworkScene()->SendMessage(to, from, subject, body); +/* dict style access */ - Py_RETURN_NONE; + +/* Matches python dict.get(key, [default]) */ +PyObject* KX_GameObject::Pyget(PyObject *args) +{ + PyObject *key; + PyObject* def = Py_None; + PyObject* ret; + + if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) + return NULL; + + + if(PyString_Check(key)) { + CValue *item = GetProperty(PyString_AsString(key)); + if (item) { + ret = item->ConvertValueToPython(); + if(ret) + return ret; + else + return item->GetProxy(); + } + } + + if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) { + Py_INCREF(ret); + return ret; + } + + Py_INCREF(def); + return def; +} + +/* Matches python dict.has_key() */ +PyObject* KX_GameObject::Pyhas_key(PyObject* value) +{ + if(PyString_Check(value) && GetProperty(PyString_AsString(value))) + Py_RETURN_TRUE; + + if (m_attr_dict && PyDict_GetItem(m_attr_dict, value)) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; } + /* --------------------------------------------------------------------- * Some stuff taken from the header * --------------------------------------------------------------------- */ @@ -2641,6 +2811,7 @@ void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter) } } + bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok, const char *error_prefix) { if (value==NULL) { @@ -2671,12 +2842,15 @@ bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py } } - if (PyObject_TypeCheck(value, &KX_GameObject::Type)) { + if ( PyObject_TypeCheck(value, &KX_GameObject::Type) || + PyObject_TypeCheck(value, &KX_LightObject::Type) || + PyObject_TypeCheck(value, &KX_Camera::Type) ) + { *object = static_cast<KX_GameObject*>BGE_PROXY_REF(value); /* sets the error */ if (*object==NULL) { - PyErr_Format(PyExc_RuntimeError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); return false; } diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index ec02dc17b75..dbdea97031d 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -77,6 +77,7 @@ protected: STR_String m_text; int m_layer; std::vector<RAS_MeshObject*> m_meshes; + SG_QList m_meshSlots; // head of mesh slots of this struct Object* m_pBlenderObject; struct Object* m_pBlenderGroupObject; @@ -170,7 +171,7 @@ public: /** * Sets the parent of this object to a game object */ - void SetParent(KX_Scene *scene, KX_GameObject *obj); + void SetParent(KX_Scene *scene, KX_GameObject *obj, bool addToCompound=true, bool ghost=true); /** * Removes the parent of this object to a game object @@ -192,11 +193,6 @@ public: ~KX_GameObject( ); - CValue* - AddRef() { - /* temporarily to find memleaks */ return CValue::AddRef(); - } - /** * @section Stuff which is here due to poor design. * Inherited from CValue and needs an implementation. @@ -245,7 +241,7 @@ public: /** * Inherited from CValue -- returns the name of this object. */ - STR_String + STR_String& GetName( ); @@ -254,15 +250,7 @@ public: */ void SetName( - STR_String name - ); - - /** - * Inherited from CValue -- does nothing. - */ - void - ReplicaSetName( - STR_String name + const char *name ); /** @@ -279,9 +267,7 @@ public: * data owned by this class is deep copied. Called internally */ virtual void - ProcessReplica( - KX_GameObject* replica - ); + ProcessReplica(); /** * Return the linear velocity of the game object. @@ -395,6 +381,10 @@ public: { m_pGraphicController = graphiccontroller; } + /* + * @add/remove the graphic controller to the physic system + */ + void ActivateGraphicController(bool recurse); /** * @section Coordinate system manipulation functions @@ -570,6 +560,13 @@ public: static void UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene); /** + * only used for sensor objects + */ + void SynchronizeTransform(); + + static void SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene); + + /** * Function to set IPO option at start of IPO */ void @@ -816,6 +813,7 @@ public: */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // py_setattro method virtual int py_delattro(PyObject *attr); virtual PyObject* py_repr(void) @@ -860,7 +858,7 @@ public: KX_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse); KX_PYMETHOD_O(KX_GameObject,SetCollisionMargin); KX_PYMETHOD_NOARGS(KX_GameObject,GetParent); - KX_PYMETHOD_O(KX_GameObject,SetParent); + KX_PYMETHOD_VARARGS(KX_GameObject,SetParent); KX_PYMETHOD_NOARGS(KX_GameObject,RemoveParent); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive); @@ -874,6 +872,11 @@ public: KX_PYMETHOD_DOC_O(KX_GameObject,getDistanceTo); KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo); KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage); + + /* Dict access */ + KX_PYMETHOD_VARARGS(KX_GameObject,get); + KX_PYMETHOD_O(KX_GameObject,has_key); + /* attributes */ static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); @@ -893,6 +896,7 @@ public: static PyObject* pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); @@ -903,9 +907,9 @@ public: static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_meshes(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - /* for dir(), python3 uses __dir__() */ - static PyObject* pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); /* Experemental! */ static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp index 55a7e2ade60..bd7e09d1dda 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp +++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp @@ -194,7 +194,8 @@ bool KX_IpoSGController::Update(double currentTime) else newPosition = m_ipo_start_point + newPosition; } - ob->SetLocalPosition(newPosition); + if (m_game_object) + m_game_object->NodeSetLocalPosition(newPosition); } } //modifies orientation? @@ -233,7 +234,8 @@ bool KX_IpoSGController::Update(double currentTime) rotation = m_ipo_start_orient * rotation; else rotation = rotation * m_ipo_start_orient; - ob->SetLocalOrientation(rotation); + if (m_game_object) + m_game_object->NodeSetLocalOrientation(rotation); } } else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) { if (m_ipo_euler_initialized) { @@ -265,7 +267,8 @@ bool KX_IpoSGController::Update(double currentTime) else if (m_ipo_channels_active[OB_DROT_Z]) { roll += m_ipo_xform.GetDeltaEulerAngles()[2]; } - ob->SetLocalOrientation(MT_Vector3(yaw, pitch, roll)); + if (m_game_object) + m_game_object->NodeSetLocalOrientation(MT_Vector3(yaw, pitch, roll)); } } else if (m_ipo_start_initialized) { // only DROT, treat as Add @@ -286,7 +289,8 @@ bool KX_IpoSGController::Update(double currentTime) // dRot are always local MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll)); rotation = m_ipo_start_orient * rotation; - ob->SetLocalOrientation(rotation); + if (m_game_object) + m_game_object->NodeSetLocalOrientation(rotation); } } //modifies scale? @@ -322,8 +326,8 @@ bool KX_IpoSGController::Update(double currentTime) if (m_ipo_add) { newScale = m_ipo_start_scale * newScale; } - - ob->SetLocalScale(newScale); + if (m_game_object) + m_game_object->NodeSetLocalScale(newScale); } m_modified=false; @@ -342,6 +346,7 @@ SG_Controller* KX_IpoSGController::GetReplica(class SG_Node* destnode) KX_IpoSGController* iporeplica = new KX_IpoSGController(*this); // clear object that ipo acts on in the replica. iporeplica->ClearObject(); + iporeplica->SetGameObject((KX_GameObject*)destnode->GetSGClientObject()); // dirty hack, ask Gino for a better solution in the ipo implementation // hacken en zagen, in what we call datahiding, not written for replication :( diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.cpp b/source/gameengine/Ketsji/KX_IPhysicsController.cpp index a38222c5f7e..673acabd774 100644 --- a/source/gameengine/Ketsji/KX_IPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_IPhysicsController.cpp @@ -35,9 +35,10 @@ #include "PHY_DynamicTypes.h" -KX_IPhysicsController::KX_IPhysicsController(bool dyna, bool compound, void* userdata) +KX_IPhysicsController::KX_IPhysicsController(bool dyna, bool sensor, bool compound, void* userdata) : m_bDyna(dyna), + m_bSensor(sensor), m_bCompound(compound), m_suspendDynamics(false), m_userdata(userdata) diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.h b/source/gameengine/Ketsji/KX_IPhysicsController.h index 10b66da7b76..81c01045071 100644 --- a/source/gameengine/Ketsji/KX_IPhysicsController.h +++ b/source/gameengine/Ketsji/KX_IPhysicsController.h @@ -49,11 +49,12 @@ class KX_IPhysicsController : public SG_Controller { protected: bool m_bDyna; + bool m_bSensor; bool m_bCompound; bool m_suspendDynamics; void* m_userdata; public: - KX_IPhysicsController(bool dyna,bool compound, void* userdata); + KX_IPhysicsController(bool dyna,bool sensor,bool compound, void* userdata); virtual ~KX_IPhysicsController(); @@ -74,6 +75,7 @@ public: virtual void getOrientation(MT_Quaternion& orn)=0; virtual void setOrientation(const MT_Matrix3x3& orn)=0; + virtual void SetTransform()=0; //virtual void setOrientation(const MT_Quaternion& orn)=0; virtual void setPosition(const MT_Point3& pos)=0; virtual void setScaling(const MT_Vector3& scaling)=0; @@ -100,10 +102,18 @@ public: m_bDyna = isDynamic; } + void SetSensor(bool isSensor) { + m_bSensor = isSensor; + } + bool IsDyna(void) { return m_bDyna; } + bool IsSensor(void) { + return m_bSensor; + } + bool IsCompound(void) { return m_bCompound; } diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp index f04e3c79a8e..3ec0598ac03 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.cpp +++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp @@ -164,14 +164,14 @@ bool KX_IpoActuator::Update(double curtime, bool frame) // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! bool bNegativeEvent = false; - int numevents = 0; + bool numevents = false; bool bIpoStart = false; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); if (frame) { - numevents = m_events.size(); + numevents = m_posevent || m_negevent; bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); } @@ -273,7 +273,7 @@ bool KX_IpoActuator::Update(double curtime, bool frame) { result = false; m_bNegativeEvent = false; - numevents = 0; + numevents = false; } if (!m_bIpoPlaying) { @@ -413,8 +413,13 @@ int KX_IpoActuator::string2mode(char* modename) { /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_IpoActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_IpoActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -440,9 +445,8 @@ PyParentObject KX_IpoActuator::Parents[] = { }; PyMethodDef KX_IpoActuator::Methods[] = { - {"set", (PyCFunction) KX_IpoActuator::sPySet, METH_VARARGS, (PY_METHODCHAR)Set_doc}, - // deprecated + {"set", (PyCFunction) KX_IpoActuator::sPySet, METH_VARARGS, (PY_METHODCHAR)Set_doc}, {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc}, @@ -460,11 +464,11 @@ PyMethodDef KX_IpoActuator::Methods[] = { }; PyAttributeDef KX_IpoActuator::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_RW("startFrame", 0, 300000, KX_IpoActuator, m_startframe), - KX_PYATTRIBUTE_FLOAT_RW("endFrame", 0, 300000, KX_IpoActuator, m_endframe), + KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, 300000, KX_IpoActuator, m_startframe), + KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, 300000, KX_IpoActuator, m_endframe), KX_PYATTRIBUTE_STRING_RW("propName", 0, 64, false, KX_IpoActuator, m_propname), KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 64, false, KX_IpoActuator, m_framepropname), - KX_PYATTRIBUTE_INT_RW("type", KX_ACT_IPO_NODEF+1, KX_ACT_IPO_MAX-1, true, KX_IpoActuator, m_type), + KX_PYATTRIBUTE_INT_RW("mode", KX_ACT_IPO_NODEF+1, KX_ACT_IPO_MAX-1, true, KX_IpoActuator, m_type), KX_PYATTRIBUTE_BOOL_RW("useIpoAsForce", KX_IpoActuator, m_ipo_as_force), KX_PYATTRIBUTE_BOOL_RW("useIpoAdd", KX_IpoActuator, m_ipo_add), KX_PYATTRIBUTE_BOOL_RW("useIpoLocal", KX_IpoActuator, m_ipo_local), @@ -477,6 +481,10 @@ PyObject* KX_IpoActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); } +PyObject* KX_IpoActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_IpoActuator::py_setattro(PyObject *attr, PyObject *value) // py_setattro method { py_setattro_up(SCA_IActuator); @@ -492,7 +500,7 @@ const char KX_IpoActuator::Set_doc[] = "\tSet the properties of the actuator.\n"; PyObject* KX_IpoActuator::PySet(PyObject* args) { - ShowDeprecationWarning("set()", "a number properties"); + ShowDeprecationWarning("set()", "a range properties"); /* sets modes PLAY, PINGPONG, FLIPPER, LOOPSTOP, LOOPEND */ /* arg 1 = mode string, arg 2 = startframe, arg3 = stopframe, */ @@ -554,7 +562,7 @@ const char KX_IpoActuator::SetStart_doc[] = "\tSet the frame from which the ipo starts playing.\n"; PyObject* KX_IpoActuator::PySetStart(PyObject* args) { - ShowDeprecationWarning("setStart()", "the startFrame property"); + ShowDeprecationWarning("setStart()", "the frameStart property"); float startArg; if(!PyArg_ParseTuple(args, "f:setStart", &startArg)) { @@ -570,7 +578,7 @@ const char KX_IpoActuator::GetStart_doc[] = "getStart()\n" "\tReturns the frame from which the ipo starts playing.\n"; PyObject* KX_IpoActuator::PyGetStart() { - ShowDeprecationWarning("getStart()", "the startFrame property"); + ShowDeprecationWarning("getStart()", "the frameStart property"); return PyFloat_FromDouble(m_startframe); } @@ -580,7 +588,7 @@ const char KX_IpoActuator::SetEnd_doc[] = "\t - frame: last frame to use (int)\n" "\tSet the frame at which the ipo stops playing.\n"; PyObject* KX_IpoActuator::PySetEnd(PyObject* args) { - ShowDeprecationWarning("setEnd()", "the endFrame property"); + ShowDeprecationWarning("setEnd()", "the frameEnd property"); float endArg; if(!PyArg_ParseTuple(args, "f:setEnd", &endArg)) { return NULL; @@ -595,7 +603,7 @@ const char KX_IpoActuator::GetEnd_doc[] = "getEnd()\n" "\tReturns the frame at which the ipo stops playing.\n"; PyObject* KX_IpoActuator::PyGetEnd() { - ShowDeprecationWarning("getEnd()", "the endFrame property"); + ShowDeprecationWarning("getEnd()", "the frameEnd property"); return PyFloat_FromDouble(m_endframe); } @@ -661,7 +669,7 @@ const char KX_IpoActuator::SetType_doc[] = "\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" "\tSet the operation mode of the actuator.\n"; PyObject* KX_IpoActuator::PySetType(PyObject* args) { - ShowDeprecationWarning("setType()", "the type property"); + ShowDeprecationWarning("setType()", "the mode property"); int typeArg; if (!PyArg_ParseTuple(args, "i:setType", &typeArg)) { @@ -680,7 +688,7 @@ const char KX_IpoActuator::GetType_doc[] = "getType()\n" "\tReturns the operation mode of the actuator.\n"; PyObject* KX_IpoActuator::PyGetType() { - ShowDeprecationWarning("getType()", "the type property"); + ShowDeprecationWarning("getType()", "the mode property"); return PyInt_FromLong(m_type); } diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h index 184ad5512de..9ea597def1e 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.h +++ b/source/gameengine/Ketsji/KX_IpoActuator.h @@ -128,8 +128,6 @@ public: virtual CValue* GetReplica() { KX_IpoActuator* replica = new KX_IpoActuator(*this);//m_float,GetName()); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -142,6 +140,7 @@ public: /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); //KX_PYMETHOD_DOC diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 83a2fa8a448..b30b79e7f23 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -77,6 +77,8 @@ #include "RAS_FramingManager.h" #include "stdio.h" +#include "DNA_world_types.h" +#include "DNA_scene_types.h" // If define: little test for Nzc: guarded drawing. If the canvas is // not valid, skip rendering this frame. @@ -97,6 +99,8 @@ const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { }; double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE; +int KX_KetsjiEngine::m_maxLogicFrame = 5; +int KX_KetsjiEngine::m_maxPhysicsFrame = 5; double KX_KetsjiEngine::m_anim_framerate = 25.0; double KX_KetsjiEngine::m_suspendedtime = 0.0; double KX_KetsjiEngine::m_suspendeddelta = 0.0; @@ -145,8 +149,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_stereo(false), m_curreye(0), - m_usedome(false), - m_logger(NULL), // Set up timing info display variables @@ -164,7 +166,9 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_overrideFrameColor(false), m_overrideFrameColorR(0.0), m_overrideFrameColorG(0.0), - m_overrideFrameColorB(0.0) + m_overrideFrameColorB(0.0), + + m_usedome(false) { // Initialize the time logger m_logger = new KX_TimeCategoryLogger (25); @@ -261,9 +265,9 @@ void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter) m_sceneconverter = sceneconverter; } -void KX_KetsjiEngine::InitDome(float size, short res, short mode, short angle, float resbuf, struct Text* text) +void KX_KetsjiEngine::InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text) { - m_dome = new KX_Dome(m_canvas, m_rasterizer, m_rendertools,this, size, res, mode, angle, resbuf, text); + m_dome = new KX_Dome(m_canvas, m_rasterizer, m_rendertools,this, res, mode, angle, resbuf, tilt, text); m_usedome = true; } @@ -271,7 +275,6 @@ void KX_KetsjiEngine::RenderDome() { GLuint viewport[4]={0}; glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); -// unsigned int m_viewport[4] = {viewport[0], viewport[1], viewport[2], viewport[3]}; m_dome->SetViewPort(viewport); @@ -295,11 +298,6 @@ void KX_KetsjiEngine::RenderDome() return; KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) - { - // do this only once per scene - (*sceneit)->UpdateMeshTransformations(); - } int n_renders=m_dome->GetNumberRenders();// usually 4 or 6 for (int i=0;i<n_renders;i++){ @@ -353,7 +351,6 @@ void KX_KetsjiEngine::RenderDome() m_dome->BindImages(i); } -// m_dome->Dome_PostRender(scene, cam, stereomode); m_canvas->EndFrame();//XXX do we really need that? m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); @@ -381,7 +378,8 @@ void KX_KetsjiEngine::RenderDome() m_dome->Draw(); - //run 2dfilters + // run the 2dfilters and motion blur once for all the scenes + PostRenderFrame(); EndFrame(); } @@ -398,7 +396,20 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo) m_firstframe = true; m_bInitialized = true; - m_ticrate = DEFAULT_LOGIC_TIC_RATE; + // there is always one scene enabled at startup + World* world = m_scenes[0]->GetBlenderScene()->world; + if (world) + { + m_ticrate = world->ticrate; + m_maxLogicFrame = world->maxlogicstep; + m_maxPhysicsFrame = world->maxphystep; + } + else + { + m_ticrate = DEFAULT_LOGIC_TIC_RATE; + m_maxLogicFrame = 5; + m_maxPhysicsFrame = 5; + } if (m_game2ipo) { @@ -511,7 +522,8 @@ void KX_KetsjiEngine::EndFrame() bool KX_KetsjiEngine::NextFrame() { - + double timestep = 1.0/m_ticrate; + double framestep = timestep; // static hidden::Clock sClock; m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true); @@ -520,7 +532,7 @@ m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true); //sClock.reset(); if (m_bFixedTime) - m_clockTime += 1./m_ticrate; + m_clockTime += timestep; else { @@ -548,24 +560,29 @@ else // PIL_sleep_ms(1); KX_SceneList::iterator sceneit; - int frameOut = 5; - if (frames>frameOut) + if (frames>m_maxPhysicsFrame) { // printf("framedOut: %d\n",frames); - m_frameTime+=(frames-frameOut)*(1.0/m_ticrate); - frames = frameOut; + m_frameTime+=(frames-m_maxPhysicsFrame)*timestep; + frames = m_maxPhysicsFrame; } bool doRender = frames>0; + if (frames > m_maxLogicFrame) + { + framestep = (frames*timestep)/m_maxLogicFrame; + frames = m_maxLogicFrame; + } + while (frames) { - m_frameTime += 1.0/m_ticrate; + m_frameTime += framestep; for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) // for each scene, call the proceed functions @@ -644,7 +661,7 @@ else // Perform physics calculations on the scene. This can involve // many iterations of the physics solver. - scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,1.0/m_ticrate);//m_deltatimerealDeltaTime); + scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime); m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE); @@ -717,7 +734,7 @@ else // Perform physics calculations on the scene. This can involve // many iterations of the physics solver. m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); - scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,0.f); + scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,timestep,timestep); // Update scenegraph after physics step. This maps physics calculations // into node positions. m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); @@ -817,8 +834,8 @@ void KX_KetsjiEngine::Render() // pass the scene's worldsettings to the rasterizer SetWorldSettings(scene->GetWorldInfo()); - // do this only once per scene - scene->UpdateMeshTransformations(); + // this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes + //scene->UpdateMeshTransformations(); // shadow buffers RenderShadowBuffers(scene); @@ -906,9 +923,6 @@ void KX_KetsjiEngine::Render() } } // if(m_rasterizer->Stereo()) - // run the 2dfilters and motion blur once for all the scenes - PostRenderFrame(); - EndFrame(); } @@ -1000,7 +1014,7 @@ void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi) wi->getAmbientColorBlue() ); - if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED) + if (m_drawingmode >= RAS_IRasterizer::KX_SOLID) { if (wi->hasMist()) { @@ -1012,10 +1026,6 @@ void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi) wi->getMistColorBlue() ); } - else - { - m_rasterizer->DisableFog(); - } } } } @@ -1097,7 +1107,7 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect area = userviewport; } - else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { + else if ( !m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { RAS_FramingManager::ComputeViewport( scene->GetFramingType(), m_canvas->GetDisplayArea(), @@ -1117,16 +1127,13 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) { - CListValue *objectlist = scene->GetObjectList(); + CListValue *lightlist = scene->GetLightList(); int i, drawmode; m_rendertools->SetAuxilaryClientInfo(scene); - for(i=0; i<objectlist->GetCount(); i++) { - KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i); - - if(!gameobj->IsLight()) - continue; + for(i=0; i<lightlist->GetCount(); i++) { + KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i); KX_LightObject *light = (KX_LightObject*)gameobj; @@ -1135,7 +1142,7 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) { /* make temporary camera */ RAS_CameraData camdata = RAS_CameraData(); - KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false); + KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true); cam->SetName("__shadow__cam__"); MT_Transform camtrans; @@ -1167,13 +1174,11 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) { bool override_camera; RAS_Rect viewport, area; - float left, right, bottom, top, nearfrust, farfrust, focallength; - const float ortho = 100.0; + float nearfrust, farfrust, focallength; // KX_Camera* cam = scene->GetActiveCamera(); if (!cam) return; - GetSceneViewport(scene, cam, area, viewport); // store the computed viewport in the scene @@ -1191,19 +1196,24 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) override_camera = override_camera && (cam->GetName() == "__default__cam__"); if (override_camera && m_overrideCamUseOrtho) { - MT_CmMatrix4x4 projmat = m_overrideCamProjMat; - m_rasterizer->SetProjectionMatrix(projmat); + m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat); + if (!cam->hasValidProjectionMatrix()) { + // needed to get frustrum planes for culling + MT_Matrix4x4 projmat; + projmat.setValue(m_overrideCamProjMat.getPointer()); + cam->SetProjectionMatrix(projmat); + } } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() ) { m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); } else { RAS_FrameFrustum frustum; - float lens = cam->GetLens(); bool orthographic = !cam->GetCameraData()->m_perspective; nearfrust = cam->GetCameraNear(); farfrust = cam->GetCameraFar(); focallength = cam->GetFocalLength(); + MT_Matrix4x4 projmat; if(override_camera) { nearfrust = m_overrideCamNear; @@ -1211,50 +1221,58 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) } if (orthographic) { - lens *= ortho; - nearfrust = (nearfrust + 1.0)*ortho; - farfrust *= ortho; - } - - RAS_FramingManager::ComputeFrustum( - scene->GetFramingType(), - area, - viewport, - lens, - nearfrust, - farfrust, - frustum - ); - left = frustum.x1 * m_cameraZoom; - right = frustum.x2 * m_cameraZoom; - bottom = frustum.y1 * m_cameraZoom; - top = frustum.y2 * m_cameraZoom; - nearfrust = frustum.camnear; - farfrust = frustum.camfar; + RAS_FramingManager::ComputeOrtho( + scene->GetFramingType(), + area, + viewport, + cam->GetScale(), + nearfrust, + farfrust, + frustum + ); + if (!cam->GetViewport()) { + frustum.x1 *= m_cameraZoom; + frustum.x2 *= m_cameraZoom; + frustum.y1 *= m_cameraZoom; + frustum.y2 *= m_cameraZoom; + } + projmat = m_rasterizer->GetOrthoMatrix( + frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); - MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( - left, right, bottom, top, nearfrust, farfrust, focallength); + } else { + RAS_FramingManager::ComputeFrustum( + scene->GetFramingType(), + area, + viewport, + cam->GetLens(), + nearfrust, + farfrust, + frustum + ); + if (!cam->GetViewport()) { + frustum.x1 *= m_cameraZoom; + frustum.x2 *= m_cameraZoom; + frustum.y1 *= m_cameraZoom; + frustum.y2 *= m_cameraZoom; + } + projmat = m_rasterizer->GetFrustumMatrix( + frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength); + } cam->SetProjectionMatrix(projmat); // Otherwise the projection matrix for each eye will be the same... - if (m_rasterizer->Stereo()) + if (!orthographic && m_rasterizer->Stereo()) cam->InvalidateProjectionMatrix(); } MT_Transform camtrans(cam->GetWorldToCamera()); - if (!cam->GetCameraData()->m_perspective) - camtrans.getOrigin()[2] *= ortho; MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(), - cam->GetCameraLocation(), cam->GetCameraOrientation()); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); - //redundant, already done in Render() - //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 @@ -1274,6 +1292,9 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) scene->GetPhysicsEnvironment()->debugDrawWorld(); m_rasterizer->FlushDebugLines(); + + //it's running once for every scene (i.e. overlay scenes have it running twice). That's not the ideal. + PostRenderFrame(); } void KX_KetsjiEngine::PostRenderFrame() @@ -1401,7 +1422,7 @@ void KX_KetsjiEngine::RenderDebugProperties() m_canvas->GetWidth(), m_canvas->GetHeight()); double time = m_logger->GetAverage((KX_TimeCategory)j); - debugtxt.Format("%2.2f %%", time/tottime * 100.f); + debugtxt.Format("%.3fms (%2.2f %%)", time*1000.f, time/tottime * 100.f); m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, debugtxt.Ptr(), xcoord + 60 ,ycoord, @@ -1719,6 +1740,26 @@ void KX_KetsjiEngine::SetTicRate(double ticrate) m_ticrate = ticrate; } +int KX_KetsjiEngine::GetMaxLogicFrame() +{ + return m_maxLogicFrame; +} + +void KX_KetsjiEngine::SetMaxLogicFrame(int frame) +{ + m_maxLogicFrame = frame; +} + +int KX_KetsjiEngine::GetMaxPhysicsFrame() +{ + return m_maxPhysicsFrame; +} + +void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame) +{ + m_maxPhysicsFrame = frame; +} + double KX_KetsjiEngine::GetAnimFrameRate() { return m_anim_framerate; @@ -1729,6 +1770,11 @@ double KX_KetsjiEngine::GetClockTime(void) const return m_clockTime; } +double KX_KetsjiEngine::GetRealTime(void) const +{ + return m_kxsystem->GetTimeInSeconds(); +} + void KX_KetsjiEngine::SetAnimFrameRate(double framerate) { m_anim_framerate = framerate; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index a8ccd6100d7..6fa379e551a 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -103,6 +103,8 @@ private: double m_previousClockTime;//previous clock time double m_remainingTime; + static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ + static int m_maxPhysicsFrame; /* maximum number of consecutive physics frame */ static double m_ticrate; static double m_anim_framerate; /* for animation playback only - ipo and action */ @@ -210,7 +212,7 @@ public: RAS_IRenderTools* GetRenderTools(){return m_rendertools;}; /// Dome functions - void InitDome(float size, short res, short mode, short angle, float resbuf, struct Text* text); + void InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text); void EndDome(); void RenderDome(); bool m_usedome; @@ -269,6 +271,7 @@ public: */ double GetClockTime(void) const; + double GetRealTime(void) const; /** * Returns the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" @@ -283,6 +286,22 @@ public: * Sets the number of logic updates per second. */ static void SetTicRate(double ticrate); + /** + * Gets the maximum number of logic frame before render frame + */ + static int GetMaxLogicFrame(); + /** + * Sets the maximum number of logic frame before render frame + */ + static void SetMaxLogicFrame(int frame); + /** + * Gets the maximum number of physics frame before render frame + */ + static int GetMaxPhysicsFrame(); + /** + * Sets the maximum number of physics frame before render frame + */ + static void SetMaxPhysicsFrame(int frame); /** * Gets the framerate for playing animations. (actions and ipos) diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 713838c88ec..fe575384a35 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -82,10 +82,7 @@ CValue* KX_LightObject::GetReplica() KX_LightObject* replica = new KX_LightObject(*this); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - - ProcessReplica(replica); + replica->ProcessReplica(); replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr(); m_rendertools->AddLight(&replica->m_lightobj); @@ -105,8 +102,11 @@ void KX_LightObject::Update() { GPULamp *lamp; - if((lamp = GetGPULamp())) { + if((lamp = GetGPULamp()) != NULL && GetSGNode()) { float obmat[4][4]; + // lights don't get their openGL matrix updated, do it now + if (GetSGNode()->IsDirty()) + GetOpenGLMatrix(); double *dobmat = GetOpenGLMatrixPtr()->getPointer(); for(int i=0; i<4; i++) @@ -114,6 +114,8 @@ void KX_LightObject::Update() obmat[i][j] = (float)*dobmat; GPU_lamp_update(lamp, m_lightobj.m_layer, obmat); + GPU_lamp_update_colors(lamp, m_lightobj.m_red, m_lightobj.m_green, + m_lightobj.m_blue, m_lightobj.m_energy); } } @@ -163,8 +165,7 @@ void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_T /* setup rasterizer transformations */ ras->SetProjectionMatrix(projectionmat); - ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(), - cam->GetCameraLocation(), cam->GetCameraOrientation()); + ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); } void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras) @@ -173,160 +174,23 @@ void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras) GPU_lamp_shadow_buffer_unbind(lamp); } -PyObject* KX_LightObject::py_getattro(PyObject *attr) -{ - char *attr_str= PyString_AsString(attr); - - if (!strcmp(attr_str, "layer")) - return PyInt_FromLong(m_lightobj.m_layer); - - if (!strcmp(attr_str, "energy")) - return PyFloat_FromDouble(m_lightobj.m_energy); - - if (!strcmp(attr_str, "distance")) - return PyFloat_FromDouble(m_lightobj.m_distance); - - if (!strcmp(attr_str, "colour") || !strcmp(attr_str, "color")) - return Py_BuildValue("[fff]", m_lightobj.m_red, m_lightobj.m_green, m_lightobj.m_blue); - - if (!strcmp(attr_str, "lin_attenuation")) - return PyFloat_FromDouble(m_lightobj.m_att1); - - if (!strcmp(attr_str, "quad_attenuation")) - return PyFloat_FromDouble(m_lightobj.m_att2); - - if (!strcmp(attr_str, "spotsize")) - return PyFloat_FromDouble(m_lightobj.m_spotsize); - - if (!strcmp(attr_str, "spotblend")) - return PyFloat_FromDouble(m_lightobj.m_spotblend); - - if (!strcmp(attr_str, "SPOT")) - return PyInt_FromLong(RAS_LightObject::LIGHT_SPOT); - - if (!strcmp(attr_str, "SUN")) - return PyInt_FromLong(RAS_LightObject::LIGHT_SUN); - - if (!strcmp(attr_str, "NORMAL")) - return PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL); - - if (!strcmp(attr_str, "type")) - return PyInt_FromLong(m_lightobj.m_type); - - py_getattro_up(KX_GameObject); -} - +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ -int KX_LightObject::py_setattro(PyObject *attr, PyObject *pyvalue) -{ - char *attr_str= PyString_AsString(attr); - - if (PyInt_Check(pyvalue)) - { - int value = PyInt_AsLong(pyvalue); - if (!strcmp(attr_str, "layer")) - { - m_lightobj.m_layer = value; - return PY_SET_ATTR_SUCCESS; - } - - if (!strcmp(attr_str, "type")) - { - if (value >= RAS_LightObject::LIGHT_SPOT && value <= RAS_LightObject::LIGHT_NORMAL) - m_lightobj.m_type = (RAS_LightObject::LightType) value; - return PY_SET_ATTR_SUCCESS; - } - } - - if (PyFloat_Check(pyvalue) || PyInt_Check(pyvalue)) - { - float value = PyFloat_AsDouble(pyvalue); - if (!strcmp(attr_str, "energy")) - { - m_lightobj.m_energy = value; - return PY_SET_ATTR_SUCCESS; - } - - if (!strcmp(attr_str, "distance")) - { - m_lightobj.m_distance = value; - return PY_SET_ATTR_SUCCESS; - } - - if (!strcmp(attr_str, "lin_attenuation")) - { - m_lightobj.m_att1 = value; - return PY_SET_ATTR_SUCCESS; - } - - if (!strcmp(attr_str, "quad_attenuation")) - { - m_lightobj.m_att2 = value; - return PY_SET_ATTR_SUCCESS; - } - - if (!strcmp(attr_str, "spotsize")) - { - m_lightobj.m_spotsize = value; - return PY_SET_ATTR_SUCCESS; - } - - if (!strcmp(attr_str, "spotblend")) - { - m_lightobj.m_spotblend = value; - return PY_SET_ATTR_SUCCESS; - } - } - - if (PySequence_Check(pyvalue)) - { - if (!strcmp(attr_str, "colour") || !strcmp(attr_str, "color")) - { - MT_Vector3 color; - if (PyVecTo(pyvalue, color)) - { - m_lightobj.m_red = color[0]; - m_lightobj.m_green = color[1]; - m_lightobj.m_blue = color[2]; - return PY_SET_ATTR_SUCCESS; - } - return PY_SET_ATTR_FAIL; - } - } - - if (!strcmp(attr_str, "SPOT") || !strcmp(attr_str, "SUN") || !strcmp(attr_str, "NORMAL")) - { - PyErr_Format(PyExc_RuntimeError, "Attribute %s is read only.", attr_str); - return PY_SET_ATTR_FAIL; - } - - return KX_GameObject::py_setattro(attr, pyvalue); +PyObject* KX_LightObject::py_getattro_dict() { + py_getattro_dict_up(KX_GameObject); } -PyMethodDef KX_LightObject::Methods[] = { - {NULL,NULL} //Sentinel -}; - -PyAttributeDef KX_LightObject::Attributes[] = { - KX_PYATTRIBUTE_DUMMY("layer"), - KX_PYATTRIBUTE_DUMMY("energy"), - KX_PYATTRIBUTE_DUMMY("distance"), - KX_PYATTRIBUTE_DUMMY("colour"), - KX_PYATTRIBUTE_DUMMY("color"), - KX_PYATTRIBUTE_DUMMY("lin_attenuation"), - KX_PYATTRIBUTE_DUMMY("quad_attenuation"), - KX_PYATTRIBUTE_DUMMY("spotsize"), - KX_PYATTRIBUTE_DUMMY("spotblend"), - KX_PYATTRIBUTE_DUMMY("SPOT"), - KX_PYATTRIBUTE_DUMMY("SUN"), - KX_PYATTRIBUTE_DUMMY("NORMAL"), - KX_PYATTRIBUTE_DUMMY("type"), - { NULL } //Sentinel -}; PyTypeObject KX_LightObject::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_LightObject", sizeof(PyObjectPlus_Proxy), 0, @@ -352,3 +216,103 @@ PyParentObject KX_LightObject::Parents[] = { &CValue::Type, NULL }; + +PyMethodDef KX_LightObject::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef KX_LightObject::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("layer", 1, 20, true, KX_LightObject, m_lightobj.m_layer), + KX_PYATTRIBUTE_FLOAT_RW("energy", 0, 10, KX_LightObject, m_lightobj.m_energy), + KX_PYATTRIBUTE_FLOAT_RW("distance", 0.01, 5000, KX_LightObject, m_lightobj.m_distance), + KX_PYATTRIBUTE_RW_FUNCTION("color", KX_LightObject, pyattr_get_color, pyattr_set_color), + KX_PYATTRIBUTE_RW_FUNCTION("colour", KX_LightObject, pyattr_get_color, pyattr_set_color), + KX_PYATTRIBUTE_FLOAT_RW("lin_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att1), + KX_PYATTRIBUTE_FLOAT_RW("quad_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att2), + KX_PYATTRIBUTE_FLOAT_RW("spotsize", 1, 180, KX_LightObject, m_lightobj.m_spotsize), + KX_PYATTRIBUTE_FLOAT_RW("spotblend", 0, 1, KX_LightObject, m_lightobj.m_spotblend), + KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst), + KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst), + KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst), + KX_PYATTRIBUTE_RW_FUNCTION("type", KX_LightObject, pyattr_get_type, pyattr_set_type), + { NULL } //Sentinel +}; + +PyObject* KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + return Py_BuildValue("[fff]", self->m_lightobj.m_red, self->m_lightobj.m_green, self->m_lightobj.m_blue); +} + +int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + + MT_Vector3 color; + if (PyVecTo(value, color)) + { + self->m_lightobj.m_red = color[0]; + self->m_lightobj.m_green = color[1]; + self->m_lightobj.m_blue = color[2]; + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +PyObject* KX_LightObject::pyattr_get_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + PyObject* retvalue; + + const char* type = attrdef->m_name; + + if(strcmp(type, "SPOT")) { + retvalue = PyInt_FromLong(RAS_LightObject::LIGHT_SPOT); + } else if (strcmp(type, "SUN")) { + retvalue = PyInt_FromLong(RAS_LightObject::LIGHT_SUN); + } else if (strcmp(type, "NORMAL")) { + retvalue = PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL); + } + + return retvalue; +} + +PyObject* KX_LightObject::pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + return PyInt_FromLong(self->m_lightobj.m_type); +} + +int KX_LightObject::pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value) +{ + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + int val = PyInt_AsLong(value); + if((val==-1 && PyErr_Occurred()) || val<0 || val>2) { + PyErr_SetString(PyExc_ValueError, "light.type= val: KX_LightObject, expected an int between 0 and 2"); + return PY_SET_ATTR_FAIL; + } + + switch(val) { + case 0: + self->m_lightobj.m_type = self->m_lightobj.LIGHT_SPOT; + break; + case 1: + self->m_lightobj.m_type = self->m_lightobj.LIGHT_SUN; + break; + case 2: + self->m_lightobj.m_type = self->m_lightobj.LIGHT_NORMAL; + break; + } + + return PY_SET_ATTR_SUCCESS; +} + + +PyObject* KX_LightObject::py_getattro(PyObject *attr) +{ + py_getattro_up(KX_GameObject); +} + +int KX_LightObject::py_setattro(PyObject *attr, PyObject *value) +{ + py_setattro_up(KX_GameObject); +} diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index 4559954c8d7..35f25515e3b 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -63,8 +63,16 @@ public: void Update(); virtual PyObject* py_getattro(PyObject *attr); /* lens, near, far, projection_matrix */ + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *pyvalue); + /* attributes */ + static PyObject* pyattr_get_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value); + static PyObject* pyattr_get_typeconst(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value); + virtual bool IsLight(void) { return true; } }; diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index 6be1da55ff8..11effa1ca98 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -46,8 +46,13 @@ #include "PyObjectPlus.h" PyTypeObject KX_MeshProxy::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_MeshProxy", sizeof(PyObjectPlus_Proxy), 0, @@ -66,7 +71,6 @@ PyTypeObject KX_MeshProxy::Type = { PyParentObject KX_MeshProxy::Parents[] = { &KX_MeshProxy::Type, - &SCA_IObject::Type, &CValue::Type, &PyObjectPlus::Type, NULL @@ -105,17 +109,21 @@ void KX_MeshProxy::SetMeshModified(bool v) PyObject* KX_MeshProxy::py_getattro(PyObject *attr) { - py_getattro_up(SCA_IObject); + py_getattro_up(CValue); +} + +PyObject* KX_MeshProxy::py_getattro_dict() { + py_getattro_dict_up(CValue); } int KX_MeshProxy::py_setattro(PyObject *attr, PyObject* value) { - py_setattro_up(SCA_IObject); + py_setattro_up(CValue); } KX_MeshProxy::KX_MeshProxy(RAS_MeshObject* mesh) - : SCA_IObject(&Type), m_meshobj(mesh) + : CValue(&Type), m_meshobj(mesh) { } @@ -131,10 +139,9 @@ CValue* KX_MeshProxy::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValu const STR_String & KX_MeshProxy::GetText() {return m_meshobj->GetName();}; double KX_MeshProxy::GetNumber() { return -1;} -STR_String KX_MeshProxy::GetName() { return m_meshobj->GetName();} -void KX_MeshProxy::SetName(STR_String name) { }; +STR_String& KX_MeshProxy::GetName() { return m_meshobj->GetName();} +void KX_MeshProxy::SetName(const char *name) { }; CValue* KX_MeshProxy::GetReplica() { return NULL;} -void KX_MeshProxy::ReplicaSetName(STR_String name) {}; // stuff for python integration @@ -213,24 +220,20 @@ PyObject* KX_MeshProxy::PyGetVertexArrayLength(PyObject* args, PyObject* kwds) PyObject* KX_MeshProxy::PyGetVertex(PyObject* args, PyObject* kwds) { - int vertexindex= 1; - int matindex= 1; - PyObject* vertexob = NULL; + int vertexindex; + int matindex; - if (PyArg_ParseTuple(args,"ii:getVertex",&matindex,&vertexindex)) - { - RAS_TexVert* vertex = m_meshobj->GetVertex(matindex,vertexindex); - if (vertex) - { - vertexob = (new KX_VertexProxy(this, vertex))->NewProxy(true); - } - } - else { + if (!PyArg_ParseTuple(args,"ii:getVertex",&matindex,&vertexindex)) + return NULL; + + RAS_TexVert* vertex = m_meshobj->GetVertex(matindex,vertexindex); + + if(vertex==NULL) { + PyErr_SetString(PyExc_ValueError, "mesh.getVertex(mat_idx, vert_idx): KX_MeshProxy, could not get a vertex at the given indicies"); return NULL; } - - return vertexob; - + + return (new KX_VertexProxy(this, vertex))->NewProxy(true); } PyObject* KX_MeshProxy::PyGetPolygon(PyObject* args, PyObject* kwds) @@ -262,8 +265,12 @@ PyObject* KX_MeshProxy::PyGetPolygon(PyObject* args, PyObject* kwds) KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh, "Reinstance the physics mesh.") { +#if 0 //this needs to be reviewed, it is dependend on Sumo/Solid. Who is using this ? - Py_RETURN_NONE;//(KX_ReInstanceShapeFromMesh(m_meshobj)) ? Py_RETURN_TRUE : Py_RETURN_FALSE; + if(KX_ReInstanceShapeFromMesh(m_meshobj)) + Py_RETURN_TRUE; +#endif + Py_RETURN_FALSE; } PyObject* KX_MeshProxy::pyattr_get_materials(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -341,7 +348,7 @@ bool ConvertPythonToMesh(PyObject * value, RAS_MeshObject **object, bool py_none /* sets the error */ if (*object==NULL) { - PyErr_Format(PyExc_RuntimeError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); return false; } diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h index aeecefc09e6..bfdd4be4118 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ b/source/gameengine/Ketsji/KX_MeshProxy.h @@ -34,7 +34,7 @@ /* utility conversion function */ bool ConvertPythonToMesh(PyObject * value, class RAS_MeshObject **object, bool py_none_ok, const char *error_prefix); -class KX_MeshProxy : public SCA_IObject +class KX_MeshProxy : public CValue { Py_Header; @@ -51,13 +51,13 @@ public: virtual const STR_String & GetText(); virtual double GetNumber(); virtual RAS_MeshObject* GetMesh() { return m_meshobj; } - virtual STR_String GetName(); - virtual void SetName(STR_String name); // Set the name of the value - virtual void ReplicaSetName(STR_String name); + virtual STR_String& GetName(); + virtual void SetName(const char *name); // Set the name of the value virtual CValue* GetReplica(); // stuff for python integration virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); // Deprecated diff --git a/source/gameengine/Ketsji/KX_MotionState.cpp b/source/gameengine/Ketsji/KX_MotionState.cpp index b4d58dccfdf..60455d33312 100644 --- a/source/gameengine/Ketsji/KX_MotionState.cpp +++ b/source/gameengine/Ketsji/KX_MotionState.cpp @@ -73,6 +73,11 @@ void KX_MotionState::getWorldOrientation(float* ori) mat.getValue(ori); } +void KX_MotionState::setWorldOrientation(const float* ori) +{ + m_node->SetLocalOrientation(ori); +} + void KX_MotionState::setWorldPosition(float posX,float posY,float posZ) { m_node->SetLocalPosition(MT_Point3(posX,posY,posZ)); diff --git a/source/gameengine/Ketsji/KX_MotionState.h b/source/gameengine/Ketsji/KX_MotionState.h index 7ba3ca2f85c..0e43e88fbeb 100644 --- a/source/gameengine/Ketsji/KX_MotionState.h +++ b/source/gameengine/Ketsji/KX_MotionState.h @@ -45,6 +45,7 @@ public: 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 setWorldOrientation(const float* ori); virtual void calculateWorldTransformations(); }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index 87b5c81392d..fde10a493db 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -86,7 +86,7 @@ void KX_MouseFocusSensor::Init() m_hitNormal.setValue(0,0,1); } -bool KX_MouseFocusSensor::Evaluate(CValue* event) +bool KX_MouseFocusSensor::Evaluate() { bool result = false; bool obHasFocus = false; @@ -119,7 +119,7 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event) * mode is never used, because the converter never makes this * sensor for a mouse-key event. It is here for * completeness. */ - result = SCA_MouseSensor::Evaluate(event); + result = SCA_MouseSensor::Evaluate(); m_positive_event = (m_val!=0); } @@ -197,13 +197,15 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) * division by 0.0...*/ RAS_Rect area, viewport; + short m_y_inv = m_kxengine->GetCanvas()->GetHeight()-m_y; + m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport); /* Check if the mouse is in the viewport */ if (( m_x < viewport.m_x2 && // less then right m_x > viewport.m_x1 && // more then then left - m_y < viewport.m_y2 && // below top - m_y > viewport.m_y1) == 0) // above bottom + m_y_inv < viewport.m_y2 && // below top + m_y_inv > viewport.m_y1) == 0) // above bottom { return false; } @@ -217,6 +219,10 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) MT_Vector4 frompoint; MT_Vector4 topoint; + /* m_y_inv - inverting for a bounds check is only part of it, now make relative to view bounds */ + m_y_inv = (viewport.m_y2 - m_y_inv) + viewport.m_y1; + + /* There's some strangeness I don't fully get here... These values * _should_ be wrong! - see from point Z values */ @@ -229,19 +235,18 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) * behind of the near and far clip planes. */ frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0, - 1.0 - (2 * (m_y - y_lb) / height), + 1.0 - (2 * (m_y_inv - y_lb) / height), + /*cam->GetCameraData()->m_perspective ? 0.0:cdata->m_clipstart,*/ /* real clipstart is scaled in ortho for some reason, zero is ok */ 0.0, /* nearclip, see above comments */ 1.0 ); topoint.setValue( (2 * (m_x-x_lb) / width) - 1.0, - 1.0 - (2 * (m_y-y_lb) / height), - 1.0, /* farclip, see above comments */ + 1.0 - (2 * (m_y_inv-y_lb) / height), + cam->GetCameraData()->m_perspective ? 1.0:cam->GetCameraData()->m_clipend, /* farclip, see above comments */ 1.0 ); /* camera to world */ MT_Transform wcs_camcs_tranform = cam->GetWorldToCamera(); - if (!cam->GetCameraData()->m_perspective) - wcs_camcs_tranform.getOrigin()[2] *= 100.0; MT_Transform cams_wcs_transform; cams_wcs_transform.invert(wcs_camcs_tranform); @@ -335,8 +340,13 @@ const MT_Vector3& KX_MouseFocusSensor::HitNormal() const /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_MouseFocusSensor::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_MouseFocusSensor", sizeof(PyObjectPlus_Proxy), 0, @@ -387,6 +397,10 @@ PyObject* KX_MouseFocusSensor::py_getattro(PyObject *attr) { py_getattro_up(SCA_MouseSensor); } +PyObject* KX_MouseFocusSensor::py_getattro_dict() { + py_getattro_dict_up(SCA_MouseSensor); +} + const char KX_MouseFocusSensor::GetHitObject_doc[] = "getHitObject()\n" diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 8de1f88c5c3..29d674eb305 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -63,13 +63,13 @@ class KX_MouseFocusSensor : public SCA_MouseSensor virtual CValue* GetReplica() { CValue* replica = new KX_MouseFocusSensor(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; }; /** * @attention Overrides default evaluate. */ - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual void Init(); virtual bool IsPositiveTrigger() { @@ -89,7 +89,8 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); KX_PYMETHOD_DOC_NOARGS(KX_MouseFocusSensor,GetRayTarget); KX_PYMETHOD_DOC_NOARGS(KX_MouseFocusSensor,GetRaySource); diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp index 0489b7090e9..44842b7f5b3 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.cpp +++ b/source/gameengine/Ketsji/KX_NearSensor.cpp @@ -36,6 +36,7 @@ #include "KX_Scene.h" // needed to create a replica #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" +#include "PHY_IMotionState.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -62,7 +63,7 @@ KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr, { gameobj->getClientInfo()->m_sensors.remove(this); - m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::NEAR); + m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR); m_client_info->m_sensors.push_back(this); //DT_ShapeHandle shape = (DT_ShapeHandle) vshape; @@ -81,81 +82,50 @@ void KX_NearSensor::SynchronizeTransform() // not linked to the parent object, must synchronize it. if (m_physCtrl) { + PHY_IMotionState* motionState = m_physCtrl->GetMotionState(); KX_GameObject* parent = ((KX_GameObject*)GetParent()); - MT_Vector3 pos = parent->NodeGetWorldPosition(); - MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation(); - m_physCtrl->setPosition(pos.x(),pos.y(),pos.z()); - m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w()); - m_physCtrl->calcXform(); + const MT_Point3& pos = parent->NodeGetWorldPosition(); + float ori[12]; + parent->NodeGetWorldOrientation().getValue(ori); + motionState->setWorldPosition(pos[0], pos[1], pos[2]); + motionState->setWorldOrientation(ori); + m_physCtrl->WriteMotionStateToDynamics(true); } } -void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman) -{ - if (m_physCtrl) - { - touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl); - } -} - -void KX_NearSensor::UnregisterSumo(KX_TouchEventManager* touchman) +CValue* KX_NearSensor::GetReplica() { - if (m_physCtrl) - { - touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl); - } + KX_NearSensor* replica = new KX_NearSensor(*this); + replica->ProcessReplica(); + return replica; } -CValue* KX_NearSensor::GetReplica() +void KX_NearSensor::ProcessReplica() { - KX_NearSensor* replica = new KX_NearSensor(*this); - replica->m_colliders = new CListValue(); - replica->Init(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + KX_TouchSensor::ProcessReplica(); - replica->m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::NEAR); + m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR); - if (replica->m_physCtrl) + if (m_physCtrl) { - replica->m_physCtrl = replica->m_physCtrl->GetReplica(); - if (replica->m_physCtrl) + m_physCtrl = m_physCtrl->GetReplica(); + if (m_physCtrl) { //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl); - replica->m_physCtrl->SetMargin(m_Margin); - replica->m_physCtrl->setNewClientInfo(replica->m_client_info); + m_physCtrl->SetMargin(m_Margin); + m_physCtrl->setNewClientInfo(m_client_info); } } - //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; } - - void KX_NearSensor::ReParent(SCA_IObject* parent) { + SCA_ISensor::ReParent(parent); m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); m_client_info->m_sensors.push_back(this); - - -/* KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); - client_info->m_gameobject = gameobj; - client_info->m_auxilary_info = NULL; - - client_info->m_sensors.push_back(this); - SCA_ISensor::ReParent(parent); -*/ - //Not needed, was done in GetReplica() already - //bool parentUpdated = false; - //((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL,parentUpdated); - //SynchronizeTransform(); - SCA_ISensor::ReParent(parent); + //Synchronize here with the actual parent. + SynchronizeTransform(); } @@ -177,7 +147,7 @@ KX_NearSensor::~KX_NearSensor() } -bool KX_NearSensor::Evaluate(CValue* event) +bool KX_NearSensor::Evaluate() { bool result = false; // KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent()); @@ -286,8 +256,13 @@ bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData /* ------------------------------------------------------------------------- */ PyTypeObject KX_NearSensor::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_NearSensor", sizeof(PyObjectPlus_Proxy), 0, @@ -334,6 +309,10 @@ PyObject* KX_NearSensor::py_getattro(PyObject *attr) py_getattro_up(KX_TouchSensor); } +PyObject* KX_NearSensor::py_getattro_dict() { + py_getattro_dict_up(KX_TouchSensor); +} + int KX_NearSensor::py_setattro(PyObject*attr, PyObject* value) { py_setattro_up(KX_TouchSensor); diff --git a/source/gameengine/Ketsji/KX_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h index 26c5feb4e67..63099e181a0 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.h +++ b/source/gameengine/Ketsji/KX_NearSensor.h @@ -70,19 +70,21 @@ public: virtual ~KX_NearSensor(); virtual void SynchronizeTransform(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual void ProcessReplica(); + virtual bool Evaluate(); virtual void ReParent(SCA_IObject* parent); virtual bool NewHandleCollision(void* obj1,void* obj2, const PHY_CollData * coll_data); virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2); - virtual void RegisterSumo(KX_TouchEventManager *touchman); - virtual void UnregisterSumo(KX_TouchEventManager* touchman); + virtual bool BroadPhaseSensorFilterCollision(void*obj1,void*obj2) { return false; }; + virtual sensortype GetSensorType() { return ST_NEAR; } /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); //No methods diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 861c5757971..eaae04d406d 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -31,6 +31,7 @@ #include "KX_ObjectActuator.h" #include "KX_GameObject.h" +#include "KX_PyMath.h" // For PyVecTo - should this include be put in PyObjectPlus? #include "KX_IPhysicsController.h" #ifdef HAVE_CONFIG_H @@ -44,6 +45,7 @@ KX_ObjectActuator:: KX_ObjectActuator( SCA_IObject* gameobj, + KX_GameObject* refobj, const MT_Vector3& force, const MT_Vector3& torque, const MT_Vector3& dloc, @@ -68,6 +70,7 @@ KX_ObjectActuator( m_previous_error(0.0,0.0,0.0), m_error_accumulator(0.0,0.0,0.0), m_bitLocalFlag (flag), + m_reference(refobj), m_active_combined_velocity (false), m_linear_damping_active(false), m_angular_damping_active(false) @@ -76,10 +79,20 @@ KX_ObjectActuator( { // in servo motion, the force is local if the target velocity is local m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity; + + m_pid = m_torque; } + if (m_reference) + m_reference->RegisterActuator(this); UpdateFuzzyFlags(); } +KX_ObjectActuator::~KX_ObjectActuator() +{ + if (m_reference) + m_reference->UnregisterActuator(this); +} + bool KX_ObjectActuator::Update() { @@ -128,11 +141,23 @@ bool KX_ObjectActuator::Update() if (mass < MT_EPSILON) return false; MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); + if (m_reference) + { + const MT_Point3& mypos = parent->NodeGetWorldPosition(); + const MT_Point3& refpos = m_reference->NodeGetWorldPosition(); + MT_Point3 relpos; + relpos = (mypos-refpos); + MT_Vector3 vel= m_reference->GetVelocity(relpos); + if (m_bitLocalFlag.LinearVelocity) + // must convert in local space + vel = parent->NodeGetWorldOrientation().transposed()*vel; + v -= vel; + } MT_Vector3 e = m_linear_velocity - v; MT_Vector3 dv = e - m_previous_error; MT_Vector3 I = m_error_accumulator + e; - m_force = m_torque.x()*e+m_torque.y()*I+m_torque.z()*dv; + m_force = m_pid.x()*e+m_pid.y()*I+m_pid.z()*dv; // to automatically adapt the PID coefficient to mass; m_force *= mass; if (m_bitLocalFlag.Torque) @@ -253,13 +278,37 @@ CValue* KX_ObjectActuator::GetReplica() KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName()); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; } +void KX_ObjectActuator::ProcessReplica() +{ + SCA_IActuator::ProcessReplica(); + if (m_reference) + m_reference->RegisterActuator(this); +} +bool KX_ObjectActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == (SCA_IObject*)m_reference) + { + // this object is being deleted, we cannot continue to use it as reference. + m_reference = NULL; + return true; + } + return false; +} + +void KX_ObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_reference]; + if (h_obj) { + if (m_reference) + m_reference->UnregisterActuator(this); + m_reference = (KX_GameObject*)(*h_obj); + m_reference->RegisterActuator(this); + } +} /* some 'standard' utilities... */ bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type) @@ -277,8 +326,13 @@ bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ObjectActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_ObjectActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -304,6 +358,7 @@ PyParentObject KX_ObjectActuator::Parents[] = { }; PyMethodDef KX_ObjectActuator::Methods[] = { + // Deprecated -----> {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_NOARGS}, {"setForce", (PyCFunction) KX_ObjectActuator::sPySetForce, METH_VARARGS}, {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_NOARGS}, @@ -327,18 +382,188 @@ PyMethodDef KX_ObjectActuator::Methods[] = { {"setPID", (PyCFunction) KX_ObjectActuator::sPyGetPID, METH_NOARGS}, {"getPID", (PyCFunction) KX_ObjectActuator::sPySetPID, METH_VARARGS}, - + // <----- Deprecated {NULL,NULL} //Sentinel }; PyAttributeDef KX_ObjectActuator::Attributes[] = { + KX_PYATTRIBUTE_VECTOR_RW_CHECK("force", -1000, 1000, false, KX_ObjectActuator, m_force, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalForce", KX_ObjectActuator, m_bitLocalFlag.Force), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("torque", -1000, 1000, false, KX_ObjectActuator, m_torque, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalTorque", KX_ObjectActuator, m_bitLocalFlag.Torque), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("dLoc", -1000, 1000, false, KX_ObjectActuator, m_dloc, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalDLoc", KX_ObjectActuator, m_bitLocalFlag.DLoc), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("dRot", -1000, 1000, false, KX_ObjectActuator, m_drot, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalDRot", KX_ObjectActuator, m_bitLocalFlag.DRot), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("linV", -1000, 1000, false, KX_ObjectActuator, m_linear_velocity, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalLinV", KX_ObjectActuator, m_bitLocalFlag.LinearVelocity), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("angV", -1000, 1000, false, KX_ObjectActuator, m_angular_velocity, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalAngV", KX_ObjectActuator, m_bitLocalFlag.AngularVelocity), + KX_PYATTRIBUTE_SHORT_RW("damping", 0, 1000, false, KX_ObjectActuator, m_damping), + KX_PYATTRIBUTE_RW_FUNCTION("forceLimitX", KX_ObjectActuator, pyattr_get_forceLimitX, pyattr_set_forceLimitX), + KX_PYATTRIBUTE_RW_FUNCTION("forceLimitY", KX_ObjectActuator, pyattr_get_forceLimitY, pyattr_set_forceLimitY), + KX_PYATTRIBUTE_RW_FUNCTION("forceLimitZ", KX_ObjectActuator, pyattr_get_forceLimitZ, pyattr_set_forceLimitZ), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("pid", -100, 200, true, KX_ObjectActuator, m_pid, PyCheckPid), + KX_PYATTRIBUTE_RW_FUNCTION("reference", KX_ObjectActuator,pyattr_get_reference,pyattr_set_reference), { NULL } //Sentinel }; PyObject* KX_ObjectActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); -}; +} + + +PyObject* KX_ObjectActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + +int KX_ObjectActuator::py_setattro(PyObject *attr, PyObject *value) +{ + py_setattro_up(SCA_IActuator); +} + +/* Attribute get/set functions */ + +PyObject* KX_ObjectActuator::pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + PyObject *retVal = PyList_New(3); + + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[0])); + PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.Torque)); + + return retVal; +} + +int KX_ObjectActuator::pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + + PyObject* seq = PySequence_Fast(value, ""); + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) + { + self->m_drot[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); + self->m_dloc[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); + self->m_bitLocalFlag.Torque = (PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0); + + if (!PyErr_Occurred()) + { + Py_DECREF(seq); + return PY_SET_ATTR_SUCCESS; + } + } + + Py_XDECREF(seq); + + PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool"); + return PY_SET_ATTR_FAIL; +} + +PyObject* KX_ObjectActuator::pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + PyObject *retVal = PyList_New(3); + + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[1])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[1])); + PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DLoc)); + + return retVal; +} + +int KX_ObjectActuator::pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + + PyObject* seq = PySequence_Fast(value, ""); + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) + { + self->m_drot[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); + self->m_dloc[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); + self->m_bitLocalFlag.DLoc = (PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0); + + if (!PyErr_Occurred()) + { + Py_DECREF(seq); + return PY_SET_ATTR_SUCCESS; + } + } + + Py_XDECREF(seq); + + PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool"); + return PY_SET_ATTR_FAIL; +} + +PyObject* KX_ObjectActuator::pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + PyObject *retVal = PyList_New(3); + + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[2])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[2])); + PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DRot)); + + return retVal; +} + +int KX_ObjectActuator::pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + + PyObject* seq = PySequence_Fast(value, ""); + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) + { + self->m_drot[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); + self->m_dloc[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); + self->m_bitLocalFlag.DRot = (PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0); + + if (!PyErr_Occurred()) + { + Py_DECREF(seq); + return PY_SET_ATTR_SUCCESS; + } + } + + Py_XDECREF(seq); + + PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool"); + return PY_SET_ATTR_FAIL; +} + +PyObject* KX_ObjectActuator::pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self); + if (!actuator->m_reference) + Py_RETURN_NONE; + + return actuator->m_reference->GetProxy(); +} + +int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self); + KX_GameObject *refOb; + + if (!ConvertPythonToGameObject(value, &refOb, true, "actu.reference = value: KX_ObjectActuator")) + return PY_SET_ATTR_FAIL; + + if (actuator->m_reference) + actuator->m_reference->UnregisterActuator(actuator); + + if(refOb==NULL) { + actuator->m_reference= NULL; + } + else { + actuator->m_reference = refOb; + actuator->m_reference->RegisterActuator(actuator); + } + + return PY_SET_ATTR_SUCCESS; +} + /* 1. set ------------------------------------------------------------------ */ /* Removed! */ @@ -346,18 +571,20 @@ PyObject* KX_ObjectActuator::py_getattro(PyObject *attr) { /* 2. getForce */ PyObject* KX_ObjectActuator::PyGetForce() { + ShowDeprecationWarning("getForce()", "the force and the useLocalForce properties"); PyObject *retVal = PyList_New(4); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_force[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_force[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_force[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Force)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_force[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_force[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_force[2])); + PyList_SET_ITEM(retVal, 3, BoolToPyArg(m_bitLocalFlag.Force)); return retVal; } /* 3. setForce */ PyObject* KX_ObjectActuator::PySetForce(PyObject* args) { + ShowDeprecationWarning("setForce()", "the force and the useLocalForce properties"); float vecArg[3]; int bToggle = 0; if (!PyArg_ParseTuple(args, "fffi:setForce", &vecArg[0], &vecArg[1], @@ -373,18 +600,20 @@ PyObject* KX_ObjectActuator::PySetForce(PyObject* args) /* 4. getTorque */ PyObject* KX_ObjectActuator::PyGetTorque() { + ShowDeprecationWarning("getTorque()", "the torque and the useLocalTorque properties"); PyObject *retVal = PyList_New(4); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Torque)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_torque[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_torque[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_torque[2])); + PyList_SET_ITEM(retVal, 3, BoolToPyArg(m_bitLocalFlag.Torque)); return retVal; } /* 5. setTorque */ PyObject* KX_ObjectActuator::PySetTorque(PyObject* args) { + ShowDeprecationWarning("setTorque()", "the torque and the useLocalTorque properties"); float vecArg[3]; int bToggle = 0; if (!PyArg_ParseTuple(args, "fffi:setTorque", &vecArg[0], &vecArg[1], @@ -400,18 +629,20 @@ PyObject* KX_ObjectActuator::PySetTorque(PyObject* args) /* 6. getDLoc */ PyObject* KX_ObjectActuator::PyGetDLoc() { + ShowDeprecationWarning("getDLoc()", "the dLoc and the useLocalDLoc properties"); PyObject *retVal = PyList_New(4); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_dloc[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_dloc[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DLoc)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_dloc[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_dloc[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_dloc[2])); + PyList_SET_ITEM(retVal, 3, BoolToPyArg(m_bitLocalFlag.DLoc)); return retVal; } /* 7. setDLoc */ PyObject* KX_ObjectActuator::PySetDLoc(PyObject* args) { + ShowDeprecationWarning("setDLoc()", "the dLoc and the useLocalDLoc properties"); float vecArg[3]; int bToggle = 0; if(!PyArg_ParseTuple(args, "fffi:setDLoc", &vecArg[0], &vecArg[1], @@ -427,18 +658,20 @@ PyObject* KX_ObjectActuator::PySetDLoc(PyObject* args) /* 8. getDRot */ PyObject* KX_ObjectActuator::PyGetDRot() { + ShowDeprecationWarning("getDRot()", "the dRot and the useLocalDRot properties"); PyObject *retVal = PyList_New(4); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_drot[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_drot[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DRot)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_drot[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_drot[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_drot[2])); + PyList_SET_ITEM(retVal, 3, BoolToPyArg(m_bitLocalFlag.DRot)); return retVal; } /* 9. setDRot */ PyObject* KX_ObjectActuator::PySetDRot(PyObject* args) { + ShowDeprecationWarning("setDRot()", "the dRot and the useLocalDRot properties"); float vecArg[3]; int bToggle = 0; if (!PyArg_ParseTuple(args, "fffi:setDRot", &vecArg[0], &vecArg[1], @@ -453,18 +686,20 @@ PyObject* KX_ObjectActuator::PySetDRot(PyObject* args) /* 10. getLinearVelocity */ PyObject* KX_ObjectActuator::PyGetLinearVelocity() { + ShowDeprecationWarning("getLinearVelocity()", "the linV and the useLocalLinV properties"); PyObject *retVal = PyList_New(4); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.LinearVelocity)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); + PyList_SET_ITEM(retVal, 3, BoolToPyArg(m_bitLocalFlag.LinearVelocity)); return retVal; } /* 11. setLinearVelocity */ PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* args) { + ShowDeprecationWarning("setLinearVelocity()", "the linV and the useLocalLinV properties"); float vecArg[3]; int bToggle = 0; if (!PyArg_ParseTuple(args, "fffi:setLinearVelocity", &vecArg[0], &vecArg[1], @@ -480,17 +715,19 @@ PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* args) { /* 12. getAngularVelocity */ PyObject* KX_ObjectActuator::PyGetAngularVelocity() { + ShowDeprecationWarning("getAngularVelocity()", "the angV and the useLocalAngV properties"); PyObject *retVal = PyList_New(4); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.AngularVelocity)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2])); + PyList_SET_ITEM(retVal, 3, BoolToPyArg(m_bitLocalFlag.AngularVelocity)); return retVal; } /* 13. setAngularVelocity */ PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* args) { + ShowDeprecationWarning("setAngularVelocity()", "the angV and the useLocalAngV properties"); float vecArg[3]; int bToggle = 0; if (!PyArg_ParseTuple(args, "fffi:setAngularVelocity", &vecArg[0], &vecArg[1], @@ -505,6 +742,7 @@ PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* args) { /* 13. setDamping */ PyObject* KX_ObjectActuator::PySetDamping(PyObject* args) { + ShowDeprecationWarning("setDamping()", "the damping property"); int damping = 0; if (!PyArg_ParseTuple(args, "i:setDamping", &damping) || damping < 0 || damping > 1000) { return NULL; @@ -515,22 +753,25 @@ PyObject* KX_ObjectActuator::PySetDamping(PyObject* args) { /* 13. getVelocityDamping */ PyObject* KX_ObjectActuator::PyGetDamping() { + ShowDeprecationWarning("getDamping()", "the damping property"); return Py_BuildValue("i",m_damping); } /* 6. getForceLimitX */ PyObject* KX_ObjectActuator::PyGetForceLimitX() { + ShowDeprecationWarning("getForceLimitX()", "the forceLimitX property"); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[0])); - PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.Torque)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_drot[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_dloc[0])); + PyList_SET_ITEM(retVal, 2, BoolToPyArg(m_bitLocalFlag.Torque)); return retVal; } /* 7. setForceLimitX */ PyObject* KX_ObjectActuator::PySetForceLimitX(PyObject* args) { + ShowDeprecationWarning("setForceLimitX()", "the forceLimitX property"); float vecArg[2]; int bToggle = 0; if(!PyArg_ParseTuple(args, "ffi:setForceLimitX", &vecArg[0], &vecArg[1], &bToggle)) { @@ -545,17 +786,19 @@ PyObject* KX_ObjectActuator::PySetForceLimitX(PyObject* args) /* 6. getForceLimitY */ PyObject* KX_ObjectActuator::PyGetForceLimitY() { + ShowDeprecationWarning("getForceLimitY()", "the forceLimitY property"); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[1])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1])); - PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DLoc)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_drot[1])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_dloc[1])); + PyList_SET_ITEM(retVal, 2, BoolToPyArg(m_bitLocalFlag.DLoc)); return retVal; } /* 7. setForceLimitY */ PyObject* KX_ObjectActuator::PySetForceLimitY(PyObject* args) { + ShowDeprecationWarning("setForceLimitY()", "the forceLimitY property"); float vecArg[2]; int bToggle = 0; if(!PyArg_ParseTuple(args, "ffi:setForceLimitY", &vecArg[0], &vecArg[1], &bToggle)) { @@ -570,17 +813,19 @@ PyObject* KX_ObjectActuator::PySetForceLimitY(PyObject* args) /* 6. getForceLimitZ */ PyObject* KX_ObjectActuator::PyGetForceLimitZ() { + ShowDeprecationWarning("getForceLimitZ()", "the forceLimitZ property"); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[2])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[2])); - PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DRot)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_drot[2])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_dloc[2])); + PyList_SET_ITEM(retVal, 2, BoolToPyArg(m_bitLocalFlag.DRot)); return retVal; } /* 7. setForceLimitZ */ PyObject* KX_ObjectActuator::PySetForceLimitZ(PyObject* args) { + ShowDeprecationWarning("setForceLimitZ()", "the forceLimitZ property"); float vecArg[2]; int bToggle = 0; if(!PyArg_ParseTuple(args, "ffi:setForceLimitZ", &vecArg[0], &vecArg[1], &bToggle)) { @@ -595,22 +840,24 @@ PyObject* KX_ObjectActuator::PySetForceLimitZ(PyObject* args) /* 4. getPID */ PyObject* KX_ObjectActuator::PyGetPID() { + ShowDeprecationWarning("getPID()", "the pid property"); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_pid[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_pid[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_pid[2])); return retVal; } /* 5. setPID */ PyObject* KX_ObjectActuator::PySetPID(PyObject* args) { + ShowDeprecationWarning("setPID()", "the pid property"); float vecArg[3]; if (!PyArg_ParseTuple(args, "fff:setPID", &vecArg[0], &vecArg[1], &vecArg[2])) { return NULL; } - m_torque.setValue(vecArg); + m_pid.setValue(vecArg); Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h index a812942a0ae..f9bd2a0c748 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.h +++ b/source/gameengine/Ketsji/KX_ObjectActuator.h @@ -35,8 +35,10 @@ #include "SCA_IActuator.h" #include "MT_Vector3.h" +class KX_GameObject; + // -// Bitfield that stores the flags for each CValue derived class +// Stores the flags for each CValue derived class // struct KX_LocalFlags { KX_LocalFlags() : @@ -55,20 +57,20 @@ struct KX_LocalFlags { { } - unsigned short Force : 1; - unsigned short Torque : 1; - unsigned short DRot : 1; - unsigned short DLoc : 1; - unsigned short LinearVelocity : 1; - unsigned short AngularVelocity : 1; - unsigned short AddOrSetLinV : 1; - unsigned short ServoControl : 1; - unsigned short ZeroForce : 1; - unsigned short ZeroTorque : 1; - unsigned short ZeroDRot : 1; - unsigned short ZeroDLoc : 1; - unsigned short ZeroLinearVelocity : 1; - unsigned short ZeroAngularVelocity : 1; + bool Force; + bool Torque; + bool DRot; + bool DLoc; + bool LinearVelocity; + bool AngularVelocity; + bool AddOrSetLinV; + bool ServoControl; + bool ZeroForce; + bool ZeroTorque; + bool ZeroDRot; + bool ZeroDLoc; + bool ZeroLinearVelocity; + bool ZeroAngularVelocity; }; class KX_ObjectActuator : public SCA_IActuator @@ -80,7 +82,8 @@ class KX_ObjectActuator : public SCA_IActuator MT_Vector3 m_dloc; MT_Vector3 m_drot; MT_Vector3 m_linear_velocity; - MT_Vector3 m_angular_velocity; + MT_Vector3 m_angular_velocity; + MT_Vector3 m_pid; MT_Scalar m_linear_length2; MT_Scalar m_angular_length2; // used in damping @@ -91,7 +94,7 @@ class KX_ObjectActuator : public SCA_IActuator MT_Vector3 m_previous_error; MT_Vector3 m_error_accumulator; KX_LocalFlags m_bitLocalFlag; - + KX_GameObject* m_reference; // A hack bool -- oh no sorry everyone // This bool is used to check if we have informed // the physics object that we are no longer @@ -120,6 +123,7 @@ public: KX_ObjectActuator( SCA_IObject* gameobj, + KX_GameObject* refobj, const MT_Vector3& force, const MT_Vector3& torque, const MT_Vector3& dloc, @@ -130,8 +134,11 @@ public: const KX_LocalFlags& flag, PyTypeObject* T=&Type ); - + ~KX_ObjectActuator(); CValue* GetReplica(); + void ProcessReplica(); + bool UnlinkObject(SCA_IObject* clientobj); + void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); void SetForceLoc(const double force[3]) { /*m_force=force;*/ } void UpdateFuzzyFlags() @@ -154,6 +161,8 @@ public: /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); + virtual int py_setattro(PyObject *attr, PyObject *value); KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForce); KX_PYMETHOD_VARARGS(KX_ObjectActuator,SetForce); @@ -177,6 +186,53 @@ public: KX_PYMETHOD_VARARGS(KX_ObjectActuator,SetForceLimitZ); KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetPID); KX_PYMETHOD_VARARGS(KX_ObjectActuator,SetPID); + + /* Attributes */ + static PyObject* pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + // This lets the attribute macros use UpdateFuzzyFlags() + static int PyUpdateFuzzyFlags(void *self, const PyAttributeDef *attrdef) + { + KX_ObjectActuator* act = reinterpret_cast<KX_ObjectActuator*>(self); + act->UpdateFuzzyFlags(); + return 0; + } + + // This is the keep the PID values in check after they are assigned with Python + static int PyCheckPid(void *self, const PyAttributeDef *attrdef) + { + KX_ObjectActuator* act = reinterpret_cast<KX_ObjectActuator*>(self); + + //P 0 to 200 + if (act->m_pid[0] < 0) { + act->m_pid[0] = 0; + } else if (act->m_pid[0] > 200) { + act->m_pid[0] = 200; + } + + //I 0 to 3 + if (act->m_pid[1] < 0) { + act->m_pid[1] = 0; + } else if (act->m_pid[1] > 3) { + act->m_pid[1] = 3; + } + + //D -100 to 100 + if (act->m_pid[2] < -100) { + act->m_pid[2] = -100; + } else if (act->m_pid[2] > 100) { + act->m_pid[2] = 100; + } + + return 0; + } }; #endif //__KX_OBJECTACTUATOR diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.h b/source/gameengine/Ketsji/KX_OdePhysicsController.h index 21b7e632d83..8c3974c38a3 100644 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.h +++ b/source/gameengine/Ketsji/KX_OdePhysicsController.h @@ -70,6 +70,7 @@ public: virtual void setOrientation(const MT_Matrix3x3& orn); virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); + virtual void SetTransform() {} virtual MT_Scalar GetMass(); virtual MT_Vector3 getReactionForce(); virtual void setRigidBody(bool rigid); diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index 0093cf5f313..cd2ed456c48 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -48,10 +48,14 @@ KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj, int mode, + bool addToCompound, + bool ghost, SCA_IObject *ob, PyTypeObject* T) : SCA_IActuator(gameobj, T), m_mode(mode), + m_addToCompound(addToCompound), + m_ghost(ghost), m_ob(ob) { if (m_ob) @@ -73,8 +77,6 @@ CValue* KX_ParentActuator::GetReplica() KX_ParentActuator* replica = new KX_ParentActuator(*this); // replication just copy the m_base pointer => common random generator replica->ProcessReplica(); - CValue::AddDataToReplica(replica); - return replica; } @@ -123,7 +125,7 @@ bool KX_ParentActuator::Update() switch (m_mode) { case KX_PARENT_SET: if (m_ob) - obj->SetParent(scene, (KX_GameObject*)m_ob); + obj->SetParent(scene, (KX_GameObject*)m_ob, m_addToCompound, m_ghost); break; case KX_PARENT_REMOVE: obj->RemoveParent(scene); @@ -139,8 +141,13 @@ bool KX_ParentActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ParentActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_ParentActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -175,6 +182,9 @@ PyMethodDef KX_ParentActuator::Methods[] = { PyAttributeDef KX_ParentActuator::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("object", KX_ParentActuator, pyattr_get_object, pyattr_set_object), + KX_PYATTRIBUTE_INT_RW("mode", KX_PARENT_NODEF+1, KX_PARENT_MAX-1, true, KX_ParentActuator, m_mode), + KX_PYATTRIBUTE_BOOL_RW("compound", KX_ParentActuator, m_addToCompound), + KX_PYATTRIBUTE_BOOL_RW("ghost", KX_ParentActuator, m_ghost), { NULL } //Sentinel }; @@ -193,7 +203,7 @@ int KX_ParentActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE KX_GameObject *gameobj; if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_ParentActuator")) - return 1; // ConvertPythonToGameObject sets the error + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error if (actuator->m_ob != NULL) actuator->m_ob->UnregisterActuator(actuator); @@ -203,7 +213,7 @@ int KX_ParentActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE if (actuator->m_ob) actuator->m_ob->RegisterActuator(actuator); - return 0; + return PY_SET_ATTR_SUCCESS; } @@ -211,6 +221,10 @@ PyObject* KX_ParentActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); } +PyObject* KX_ParentActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_ParentActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); } @@ -259,7 +273,7 @@ PyObject* KX_ParentActuator::PyGetObject(PyObject* args) Py_RETURN_NONE; if (ret_name_only) - return PyString_FromString(m_ob->GetName()); + return PyString_FromString(m_ob->GetName().ReadPtr()); else return m_ob->GetProxy(); } diff --git a/source/gameengine/Ketsji/KX_ParentActuator.h b/source/gameengine/Ketsji/KX_ParentActuator.h index f9f0b73b876..148375e994c 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.h +++ b/source/gameengine/Ketsji/KX_ParentActuator.h @@ -46,6 +46,9 @@ class KX_ParentActuator : public SCA_IActuator /** Mode */ int m_mode; + /** option */ + bool m_addToCompound; + bool m_ghost; /** Object to set as parent */ SCA_IObject *m_ob; @@ -57,11 +60,14 @@ class KX_ParentActuator : public SCA_IActuator KX_PARENT_NODEF = 0, KX_PARENT_SET, KX_PARENT_REMOVE, + KX_PARENT_MAX }; KX_ParentActuator(class SCA_IObject* gameobj, int mode, + bool addToCompound, + bool ghost, SCA_IObject *ob, PyTypeObject* T=&Type); virtual ~KX_ParentActuator(); @@ -77,6 +83,7 @@ class KX_ParentActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); /* These are used to get and set m_ob */ diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp index fda639c09e0..c968e50957e 100644 --- a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp +++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp @@ -113,8 +113,13 @@ PyAttributeDef KX_PhysicsObjectWrapper::Attributes[] = { //python specific stuff PyTypeObject KX_PhysicsObjectWrapper::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_PhysicsObjectWrapper", sizeof(PyObjectPlus_Proxy), 0, @@ -136,11 +141,14 @@ PyParentObject KX_PhysicsObjectWrapper::Parents[] = { NULL }; -PyObject* KX_PhysicsObjectWrapper::py_getattro(PyObject *attr) +PyObject* KX_PhysicsObjectWrapper::py_getattro(PyObject *attr) { py_getattro_up(PyObjectPlus); } +PyObject* KX_PhysicsObjectWrapper::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} int KX_PhysicsObjectWrapper::py_setattro(PyObject *attr,PyObject *pyobj) { diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h index 7e10dc3ccf4..1b59686babc 100644 --- a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h +++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h @@ -37,6 +37,7 @@ class KX_PhysicsObjectWrapper : public PyObjectPlus Py_Header; virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); public: KX_PhysicsObjectWrapper(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type); diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp index 2e5dd72db0e..b56b5500c39 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.cpp +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -39,8 +39,13 @@ #include "KX_PyMath.h" PyTypeObject KX_PolyProxy::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_PolyProxy", sizeof(PyObjectPlus_Proxy), 0, @@ -59,8 +64,8 @@ PyTypeObject KX_PolyProxy::Type = { PyParentObject KX_PolyProxy::Parents[] = { &KX_PolyProxy::Type, - &SCA_IObject::Type, &CValue::Type, + &PyObjectPlus::Type, NULL }; @@ -79,6 +84,7 @@ PyMethodDef KX_PolyProxy::Methods[] = { PyAttributeDef KX_PolyProxy::Attributes[] = { /* All dummy's so they come up in a dir() */ + //KX_PYATTRIBUTE_TODO("DummyProps"), KX_PYATTRIBUTE_DUMMY("matname"), KX_PYATTRIBUTE_DUMMY("texture"), KX_PYATTRIBUTE_DUMMY("material"), @@ -156,7 +162,11 @@ PyObject* KX_PolyProxy::py_getattro(PyObject *attr) { return PyInt_FromLong(m_polygon->IsCollider()); } - py_getattro_up(SCA_IObject); + py_getattro_up(CValue); +} + +PyObject* KX_PolyProxy::py_getattro_dict() { + py_getattro_dict_up(CValue); } KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon) @@ -176,11 +186,9 @@ CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { re STR_String sPolyName="polygone"; const STR_String & KX_PolyProxy::GetText() {return sPolyName;}; double KX_PolyProxy::GetNumber() { return -1;} -STR_String KX_PolyProxy::GetName() { return sPolyName;} -void KX_PolyProxy::SetName(STR_String) { }; +STR_String& KX_PolyProxy::GetName() { return sPolyName;} +void KX_PolyProxy::SetName(const char *) { }; CValue* KX_PolyProxy::GetReplica() { return NULL;} -void KX_PolyProxy::ReplicaSetName(STR_String) {}; - // stuff for python integration diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h index 275e65da810..d8fd36fec6c 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.h +++ b/source/gameengine/Ketsji/KX_PolyProxy.h @@ -31,7 +31,7 @@ #include "SCA_IObject.h" -class KX_PolyProxy : public SCA_IObject +class KX_PolyProxy : public CValue { Py_Header; protected: @@ -46,14 +46,14 @@ public: CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); const STR_String & GetText(); double GetNumber(); - STR_String GetName(); - void SetName(STR_String name); // Set the name of the value - void ReplicaSetName(STR_String name); + STR_String& GetName(); + void SetName(const char *name); // Set the name of the value CValue* GetReplica(); // stuff for python integration virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex) KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex) diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index 46d04486cc6..506c167a905 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -51,22 +51,37 @@ #include "KX_PyMath.h" -KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, - Material *material, - int tile, - int tilexrep, - int tileyrep, - int mode, - int transp, - bool alpha, - bool zsort, - int lightlayer, - struct MTFace* tface, - unsigned int* mcol, - PyTypeObject *T) +KX_PolygonMaterial::KX_PolygonMaterial(PyTypeObject *T) : PyObjectPlus(T), - RAS_IPolyMaterial(texname, - STR_String(material?material->id.name:""), + RAS_IPolyMaterial(), + + m_tface(NULL), + m_mcol(NULL), + m_material(NULL), + m_pymaterial(NULL), + m_pass(0) +{ +} + +void KX_PolygonMaterial::Initialize( + const STR_String &texname, + Material* ma, + int materialindex, + int tile, + int tilexrep, + int tileyrep, + int mode, + int transp, + bool alpha, + bool zsort, + int lightlayer, + struct MTFace* tface, + unsigned int* mcol) +{ + RAS_IPolyMaterial::Initialize( + texname, + ma?ma->id.name:"", + materialindex, tile, tilexrep, tileyrep, @@ -74,13 +89,12 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, transp, alpha, zsort, - lightlayer), - m_tface(tface), - m_mcol(mcol), - m_material(material), - m_pymaterial(0), - m_pass(0) -{ + lightlayer); + m_tface = tface; + m_mcol = mcol; + m_material = ma; + m_pymaterial = 0; + m_pass = 0; } KX_PolygonMaterial::~KX_PolygonMaterial() @@ -158,15 +172,32 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c rasty->SetLines(true); else rasty->SetLines(false); + rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); + rasty->SetShinyness(m_shininess); + rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); + if (m_material) + rasty->SetPolygonOffset(-m_material->zoffs, 0.0); } - rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); - rasty->SetShinyness(m_shininess); - rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); - if (m_material) - rasty->SetPolygonOffset(-m_material->zoffs, 0.0); + //rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); + //rasty->SetShinyness(m_shininess); + //rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); + //if (m_material) + // rasty->SetPolygonOffset(-m_material->zoffs, 0.0); +} + +void KX_PolygonMaterial::GetMaterialRGBAColor(unsigned char *rgba) const +{ + if (m_material) { + *rgba++ = (unsigned char) (m_material->r*255.0); + *rgba++ = (unsigned char) (m_material->g*255.0); + *rgba++ = (unsigned char) (m_material->b*255.0); + *rgba++ = (unsigned char) (m_material->alpha*255.0); + } else + RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); } + //---------------------------------------------------------------------------- //Python @@ -189,7 +220,7 @@ PyAttributeDef KX_PolygonMaterial::Attributes[] = { KX_PYATTRIBUTE_INT_RW("tilexrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tilexrep), KX_PYATTRIBUTE_INT_RW("tileyrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tileyrep), KX_PYATTRIBUTE_INT_RW("drawingmode", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_drawingmode), - KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer), + //KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer), KX_PYATTRIBUTE_BOOL_RW("transparent", KX_PolygonMaterial, m_alpha), KX_PYATTRIBUTE_BOOL_RW("zsort", KX_PolygonMaterial, m_zsort), @@ -208,8 +239,13 @@ PyAttributeDef KX_PolygonMaterial::Attributes[] = { }; PyTypeObject KX_PolygonMaterial::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_PolygonMaterial", sizeof(PyObjectPlus_Proxy), 0, @@ -237,6 +273,10 @@ PyObject* KX_PolygonMaterial::py_getattro(PyObject *attr) py_getattro_up(PyObjectPlus); } +PyObject* KX_PolygonMaterial::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} + int KX_PolygonMaterial::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(PyObjectPlus); @@ -346,10 +386,10 @@ int KX_PolygonMaterial::pyattr_set_diffuse(void *self_v, const KX_PYATTRIBUTE_DE MT_Vector3 vec; if (!PyVecTo(value, vec)) - return -1; + return PY_SET_ATTR_FAIL; self->m_diffuse= vec; - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_PolygonMaterial::pyattr_get_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -364,8 +404,8 @@ int KX_PolygonMaterial::pyattr_set_specular(void *self_v, const KX_PYATTRIBUTE_D MT_Vector3 vec; if (!PyVecTo(value, vec)) - return -1; + return PY_SET_ATTR_FAIL; self->m_specular= vec; - return 0; + return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h index 9865a66e836..89ecb026da9 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -53,14 +53,14 @@ private: MTFace* m_tface; unsigned int* m_mcol; Material* m_material; - PyObject* m_pymaterial; mutable int m_pass; public: - - KX_PolygonMaterial(const STR_String &texname, + KX_PolygonMaterial(PyTypeObject *T = &Type); + void Initialize(const STR_String &texname, Material* ma, + int materialindex, int tile, int tilexrep, int tileyrep, @@ -70,8 +70,8 @@ public: bool zsort, int lightlayer, struct MTFace* tface, - unsigned int* mcol, - PyTypeObject *T = &Type); + unsigned int* mcol); + virtual ~KX_PolygonMaterial(); /** @@ -107,8 +107,8 @@ public: { return m_mcol; } - - + virtual void GetMaterialRGBAColor(unsigned char *rgba) const; + KX_PYMETHOD_DOC(KX_PolygonMaterial, updateTexture); KX_PYMETHOD_DOC(KX_PolygonMaterial, setTexture); KX_PYMETHOD_DOC(KX_PolygonMaterial, activate); @@ -117,6 +117,7 @@ public: KX_PYMETHOD_DOC(KX_PolygonMaterial, loadProgram); virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *pyvalue); virtual PyObject* py_repr(void) { return PyString_FromString(m_material ? ((ID *)m_material)->name+2 : ""); } diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index 2c65c184a9c..a098d99864f 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -33,6 +33,7 @@ #include "KX_PhysicsObjectWrapper.h" #include "PHY_IPhysicsController.h" #include "PHY_IVehicle.h" +#include "MT_Matrix3x3.h" #include "PyObjectPlus.h" @@ -404,6 +405,8 @@ static PyObject* gPyCreateConstraint(PyObject* self, int physicsid=0,physicsid2 = 0,constrainttype=0,extrainfo=0; int len = PyTuple_Size(args); int success = 1; + int flag = 0; + float pivotX=1,pivotY=1,pivotZ=1,axisX=0,axisY=0,axisZ=1; if (len == 3) { @@ -420,6 +423,11 @@ static PyObject* gPyCreateConstraint(PyObject* self, success = PyArg_ParseTuple(args,"iiiffffff",&physicsid,&physicsid2,&constrainttype, &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ); } + else if (len == 10) + { + success = PyArg_ParseTuple(args,"iiiffffffi",&physicsid,&physicsid2,&constrainttype, + &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag); + } else if (len==4) { success = PyArg_ParseTuple(args,"iiii",&physicsid,&physicsid2,&constrainttype,&extrainfo); @@ -435,7 +443,31 @@ static PyObject* gPyCreateConstraint(PyObject* self, PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2; if (physctrl) //TODO:check for existance of this pointer! { - int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0); + PHY_ConstraintType ct = (PHY_ConstraintType) constrainttype; + int constraintid =0; + + if (ct == PHY_GENERIC_6DOF_CONSTRAINT) + { + //convert from euler angle into axis + float radsPerDeg = 6.283185307179586232f / 360.f; + + //we need to pass a full constraint frame, not just axis + //localConstraintFrameBasis + MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*axisX,radsPerDeg*axisY,radsPerDeg*axisZ)); + MT_Vector3 axis0 = localCFrame.getColumn(0); + MT_Vector3 axis1 = localCFrame.getColumn(1); + MT_Vector3 axis2 = localCFrame.getColumn(2); + + constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype, + pivotX,pivotY,pivotZ, + (float)axis0.x(),(float)axis0.y(),(float)axis0.z(), + (float)axis1.x(),(float)axis1.y(),(float)axis1.z(), + (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag); + + } else + { + constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0); + } KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment()); @@ -565,6 +597,19 @@ static struct PyMethodDef physicsconstraints_methods[] = { }; +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef PhysicsConstraints_module_def = { + {}, /* m_base */ + "PhysicsConstraints", /* m_name */ + PhysicsConstraints_module_documentation, /* m_doc */ + 0, /* m_size */ + physicsconstraints_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif PyObject* initPythonConstraintBinding() { @@ -573,10 +618,24 @@ PyObject* initPythonConstraintBinding() PyObject* m; PyObject* d; - - m = Py_InitModule4("PhysicsConstraints", physicsconstraints_methods, + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "PhysicsConstraints" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + +#if (PY_VERSION_HEX >= 0x03000000) + m = PyModule_Create(&PhysicsConstraints_module_def); +#else + m = Py_InitModule4("PhysicsConstraints", physicsconstraints_methods, PhysicsConstraints_module_documentation, (PyObject*)NULL,PYTHON_API_VERSION); +#endif + } // Add some symbolic constants to the module d = PyModule_GetDict(m); diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp index 0093a72808e..051d7ae7dba 100644 --- a/source/gameengine/Ketsji/KX_PyMath.cpp +++ b/source/gameengine/Ketsji/KX_PyMath.cpp @@ -75,9 +75,8 @@ bool PyObject_IsMT_Matrix(PyObject *pymat, unsigned int rank) return false; } -bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &mat, const char *error_prefix) +bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &rot, const char *error_prefix) { - MT_Matrix3x3 rot; int size= PySequence_Size(pyval); if (size == 4) diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 00f7c5cad93..a7ce4bc6930 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -40,6 +40,7 @@ #include "MT_Matrix4x4.h" #include "KX_Python.h" +#include "PyObjectPlus.h" inline unsigned int Size(const MT_Matrix4x4&) { return 4; } inline unsigned int Size(const MT_Matrix3x3&) { return 3; } @@ -116,6 +117,19 @@ bool PyVecTo(PyObject* pyval, T& vec) return true; } + else if (BGE_PROXY_CHECK_TYPE(pyval)) + { /* note, include this check because PySequence_Check does too much introspection + * on the PyObject (like getting its __class__, on a BGE type this means searching up + * the parent list each time only to discover its not a sequence. + * GameObjects are often used as an alternative to vectors so this is a common case + * better to do a quick check for it, likely the error below will be ignored. + * + * This is not 'correct' since we have proxy type CListValues's which could + * contain floats/ints but there no cases of CValueLists being this way + */ + PyErr_Format(PyExc_AttributeError, "expected a sequence type"); + return false; + } else if (PySequence_Check(pyval)) { unsigned int numitems = PySequence_Size(pyval); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index ffcf7d7162e..fc3e48f504c 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -49,6 +49,9 @@ #include "KX_KetsjiEngine.h" #include "KX_RadarSensor.h" #include "KX_RaySensor.h" +#include "KX_SceneActuator.h" +#include "KX_GameActuator.h" +#include "KX_ParentActuator.h" #include "KX_SCA_DynamicActuator.h" #include "SCA_IInputDevice.h" @@ -83,10 +86,16 @@ #include "KX_PythonInitTypes.h" +/* we only need this to get a list of libraries from the main struct */ +#include "DNA_ID.h" + extern "C" { - #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. #include "bpy_internal_import.h" /* from the blender python api, but we want to import text too! */ +#if PY_VERSION_HEX < 0x03000000 + #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. + #include "Geometry.h" // Blender.Geometry module copied here so the blenderlayer can use. #include "BGL.h" +#endif } #endif @@ -100,13 +109,13 @@ extern "C" { //#include "BPY_extern.h" #endif +#include "BKE_main.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BLI_blenlib.h" #include "GPU_material.h" static void setSandbox(TPythonSecurityLevel level); -static void clearGameModules(); // 'local' copy of canvas ptr, for window height/width python scripts static RAS_ICanvas* gp_Canvas = NULL; @@ -114,6 +123,9 @@ static KX_Scene* gp_KetsjiScene = NULL; static KX_KetsjiEngine* gp_KetsjiEngine = NULL; static RAS_IRasterizer* gp_Rasterizer = NULL; static char gp_GamePythonPath[FILE_MAXDIR + FILE_MAXFILE] = ""; +static char gp_GamePythonPathOrig[FILE_MAXDIR + FILE_MAXFILE] = ""; // not super happy about this, but we need to remember the first loaded file for the global/dict load save +static PyObject *gp_OrigPythonSysPath= NULL; +static PyObject *gp_OrigPythonSysModules= NULL; void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) { @@ -220,13 +232,13 @@ static PyObject* gPyGetSpectrum(PyObject*) for (int index = 0; index < 512; index++) { - PyList_SetItem(resultlist, index, PyFloat_FromDouble(spectrum[index])); + PyList_SET_ITEM(resultlist, index, PyFloat_FromDouble(spectrum[index])); } } else { for (int index = 0; index < 512; index++) { - PyList_SetItem(resultlist, index, PyFloat_FromDouble(0.0)); + PyList_SET_ITEM(resultlist, index, PyFloat_FromDouble(0.0)); } } @@ -286,6 +298,36 @@ static PyObject* gPyGetLogicTicRate(PyObject*) return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate()); } +static PyObject* gPySetMaxLogicFrame(PyObject*, PyObject* args) +{ + int frame; + if (!PyArg_ParseTuple(args, "i:setMaxLogicFrame", &frame)) + return NULL; + + KX_KetsjiEngine::SetMaxLogicFrame(frame); + Py_RETURN_NONE; +} + +static PyObject* gPyGetMaxLogicFrame(PyObject*) +{ + return PyInt_FromLong(KX_KetsjiEngine::GetMaxLogicFrame()); +} + +static PyObject* gPySetMaxPhysicsFrame(PyObject*, PyObject* args) +{ + int frame; + if (!PyArg_ParseTuple(args, "i:setMaxPhysicsFrame", &frame)) + return NULL; + + KX_KetsjiEngine::SetMaxPhysicsFrame(frame); + Py_RETURN_NONE; +} + +static PyObject* gPyGetMaxPhysicsFrame(PyObject*) +{ + return PyInt_FromLong(KX_KetsjiEngine::GetMaxPhysicsFrame()); +} + static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args) { float ticrate; @@ -477,6 +519,10 @@ static struct PyMethodDef game_methods[] = { {"setGravity",(PyCFunction) gPySetGravity, METH_O, (PY_METHODCHAR)"set Gravitation"}, {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS, (PY_METHODCHAR)"get audio spectrum"}, {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (PY_METHODCHAR)"stop using the audio dsp (for performance reasons)"}, + {"getMaxLogicFrame", (PyCFunction) gPyGetMaxLogicFrame, METH_NOARGS, (PY_METHODCHAR)"Gets the max number of logic frame per render frame"}, + {"setMaxLogicFrame", (PyCFunction) gPySetMaxLogicFrame, METH_VARARGS, (PY_METHODCHAR)"Sets the max number of logic frame per render frame"}, + {"getMaxPhysicsFrame", (PyCFunction) gPyGetMaxPhysicsFrame, METH_NOARGS, (PY_METHODCHAR)"Gets the max number of physics frame per render frame"}, + {"setMaxPhysicsFrame", (PyCFunction) gPySetMaxPhysicsFrame, METH_VARARGS, (PY_METHODCHAR)"Sets the max number of physics farme per render frame"}, {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the logic tic rate"}, {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the logic tic rate"}, {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the physics tic rate"}, @@ -487,7 +533,6 @@ static struct PyMethodDef game_methods[] = { {NULL, (PyCFunction) NULL, 0, NULL } }; - static PyObject* gPyGetWindowHeight(PyObject*, PyObject* args) { return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetHeight() : 0)); @@ -636,6 +681,17 @@ static PyObject* gPySetMistColor(PyObject*, PyObject* value) Py_RETURN_NONE; } +static PyObject* gPyDisableMist(PyObject*) +{ + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available"); + return NULL; + } + gp_Rasterizer->DisableFog(); + + Py_RETURN_NONE; +} static PyObject* gPySetMistStart(PyObject*, PyObject* args) @@ -724,7 +780,7 @@ static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) Py_RETURN_NONE; } -static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) +static PyObject* gPyDisableMotionBlur(PyObject*) { if (!gp_Rasterizer) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.disableMotionBlur(), Rasterizer not available"); @@ -780,16 +836,17 @@ static PyObject* gPySetGLSLMaterialSetting(PyObject*, /* display lists and GLSL materials need to be remade */ if(G.fileflags != fileflags) { + GPU_materials_free(); if(gp_KetsjiEngine) { KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); KX_SceneList::iterator it; for(it=scenes->begin(); it!=scenes->end(); it++) - if((*it)->GetBucketManager()) + if((*it)->GetBucketManager()) { (*it)->GetBucketManager()->ReleaseDisplayLists(); + (*it)->GetBucketManager()->ReleaseMaterials(); + } } - - GPU_materials_free(); } Py_RETURN_NONE; @@ -850,7 +907,7 @@ static PyObject* gPyGetMaterialType(PyObject*) { int flag; - if(G.fileflags & (G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL)) + if(G.fileflags & G_FILE_GAME_MAT_GLSL) flag = KX_BLENDER_GLSL_MATERIAL; else if(G.fileflags & G_FILE_GAME_MAT) flag = KX_BLENDER_MULTITEX_MATERIAL; @@ -904,11 +961,12 @@ static struct PyMethodDef rasterizer_methods[] = { METH_VARARGS, "setMousePosition(int x,int y)"}, {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_O,"set Background Color (rgb)"}, {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_O,"set Ambient Color (rgb)"}, + {"disableMist",(PyCFunction)gPyDisableMist,METH_NOARGS,"turn off mist"}, {"setMistColor",(PyCFunction)gPySetMistColor,METH_O,"set Mist Color (rgb)"}, {"setMistStart",(PyCFunction)gPySetMistStart,METH_VARARGS,"set Mist Start(rgb)"}, {"setMistEnd",(PyCFunction)gPySetMistEnd,METH_VARARGS,"set Mist End(rgb)"}, {"enableMotionBlur",(PyCFunction)gPyEnableMotionBlur,METH_VARARGS,"enable motion blur"}, - {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_VARARGS,"disable motion blur"}, + {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_NOARGS,"disable motion blur"}, {"setEyeSeparation", (PyCFunction) gPySetEyeSeparation, METH_VARARGS, "set the eye separation for stereo mode"}, @@ -938,7 +996,19 @@ static char Rasterizer_module_documentation[] = "This is the Python API for the game engine of Rasterizer" ; - +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef GameLogic_module_def = { + {}, /* m_base */ + "GameLogic", /* m_name */ + GameLogic_module_documentation, /* m_doc */ + 0, /* m_size */ + game_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack to get gravity hook { @@ -950,12 +1020,29 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack gp_KetsjiScene = scene; gUseVisibilityTemp=false; - - // Create the module and add the functions - m = Py_InitModule4("GameLogic", game_methods, - GameLogic_module_documentation, - (PyObject*)NULL,PYTHON_API_VERSION); - + + PyObjectPlus::ClearDeprecationWarning(); /* Not that nice to call here but makes sure warnings are reset between loading scenes */ + + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "GameLogic" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + // Create the module and add the functions +#if (PY_VERSION_HEX >= 0x03000000) + m = PyModule_Create(&GameLogic_module_def); +#else + m = Py_InitModule4("GameLogic", game_methods, + GameLogic_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); +#endif + } + // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -1172,6 +1259,28 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_LOCAL, KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCAL); KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_DOROTFH, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DOROTFH); + /* Game Actuator Modes */ + KX_MACRO_addTypesToDict(d, KX_GAME_LOAD, KX_GameActuator::KX_GAME_LOAD); + KX_MACRO_addTypesToDict(d, KX_GAME_START, KX_GameActuator::KX_GAME_START); + KX_MACRO_addTypesToDict(d, KX_GAME_RESTART, KX_GameActuator::KX_GAME_RESTART); + KX_MACRO_addTypesToDict(d, KX_GAME_QUIT, KX_GameActuator::KX_GAME_QUIT); + KX_MACRO_addTypesToDict(d, KX_GAME_SAVECFG, KX_GameActuator::KX_GAME_SAVECFG); + KX_MACRO_addTypesToDict(d, KX_GAME_LOADCFG, KX_GameActuator::KX_GAME_LOADCFG); + + /* Scene Actuator Modes */ + KX_MACRO_addTypesToDict(d, KX_SCENE_RESTART, KX_SceneActuator::KX_SCENE_RESTART); + KX_MACRO_addTypesToDict(d, KX_SCENE_SET_SCENE, KX_SceneActuator::KX_SCENE_SET_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_SET_CAMERA, KX_SceneActuator::KX_SCENE_SET_CAMERA); + KX_MACRO_addTypesToDict(d, KX_SCENE_ADD_FRONT_SCENE, KX_SceneActuator::KX_SCENE_ADD_FRONT_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_ADD_BACK_SCENE, KX_SceneActuator::KX_SCENE_ADD_BACK_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_REMOVE_SCENE, KX_SceneActuator::KX_SCENE_REMOVE_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_SUSPEND, KX_SceneActuator::KX_SCENE_SUSPEND); + KX_MACRO_addTypesToDict(d, KX_SCENE_RESUME, KX_SceneActuator::KX_SCENE_RESUME); + + /* Parent Actuator Modes */ + KX_MACRO_addTypesToDict(d, KX_PARENT_SET, KX_ParentActuator::KX_PARENT_SET); + KX_MACRO_addTypesToDict(d, KX_PARENT_REMOVE, KX_ParentActuator::KX_PARENT_REMOVE); + // Check for errors if (PyErr_Occurred()) { @@ -1238,7 +1347,7 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) /* quick hack for GamePython modules TODO: register builtin modules properly by ExtendInittab */ if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") || - !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils") || !strcmp(name, "BGL")) { + !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils") || !strcmp(name, "BGL") || !strcmp(name, "Geometry")) { return PyImport_ImportModuleEx(name, globals, locals, fromlist); } @@ -1359,20 +1468,141 @@ void setSandbox(TPythonSecurityLevel level) } } +/* Explanation of + * + * - backupPySysObjects() : stores sys.path in gp_OrigPythonSysPath + * - initPySysObjects(main) : initializes the blendfile and library paths + * - restorePySysObjects() : restores sys.path from gp_OrigPythonSysPath + * + * These exist so the current blend dir "//" can always be used to import modules from. + * the reason we need a few functions for this is that python is not only used by the game engine + * so we cant just add to sys.path all the time, it would leave pythons state in a mess. + * It would also be incorrect since loading blend files for new levels etc would alwasy add to sys.path + * + * To play nice with blenders python, the sys.path is backed up and the current blendfile along + * with all its lib paths are added to the sys path. + * When loading a new blendfile, the original sys.path is restored and the new paths are added over the top. + */ + +/** + * So we can have external modules mixed with our blend files. + */ +static void backupPySysObjects(void) +{ + PyObject *sys_path= PySys_GetObject("path"); /* should never fail */ + PyObject *sys_mods= PySys_GetObject("modules"); /* should never fail */ + + /* paths */ + Py_XDECREF(gp_OrigPythonSysPath); /* just incase its set */ + gp_OrigPythonSysPath = PyList_GetSlice(sys_path, 0, INT_MAX); /* copy the list */ + + /* modules */ + Py_XDECREF(gp_OrigPythonSysModules); /* just incase its set */ + gp_OrigPythonSysModules = PyDict_Copy(sys_mods); /* copy the list */ + +} + +/* for initPySysObjects only, + * takes a blend path and adds a scripts dir from it + * + * "/home/me/foo.blend" -> "/home/me/scripts" + */ +static void initPySysObjects__append(PyObject *sys_path, char *filename) +{ + PyObject *item; + char expanded[FILE_MAXDIR + FILE_MAXFILE]; + + BLI_split_dirfile_basic(filename, expanded, NULL); /* get the dir part of filename only */ + BLI_convertstringcode(expanded, gp_GamePythonPath); /* filename from lib->filename is (always?) absolute, so this may not be needed but it wont hurt */ + BLI_cleanup_file(gp_GamePythonPath, expanded); /* Dont use BLI_cleanup_dir because it adds a slash - BREAKS WIN32 ONLY */ + item= PyString_FromString(expanded); + +// printf("SysPath - '%s', '%s', '%s'\n", expanded, filename, gp_GamePythonPath); + + if(PySequence_Index(sys_path, item) == -1) { + PyErr_Clear(); /* PySequence_Index sets a ValueError */ + PyList_Insert(sys_path, 0, item); + } + + Py_DECREF(item); +} +static void initPySysObjects(Main *maggie) +{ + PyObject *sys_path= PySys_GetObject("path"); /* should never fail */ + + if (gp_OrigPythonSysPath==NULL) { + /* backup */ + backupPySysObjects(); + } + else { + /* get the original sys path when the BGE started */ + PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath); + } + + Library *lib= (Library *)maggie->library.first; + + while(lib) { + /* lib->name wont work in some cases (on win32), + * even when expanding with gp_GamePythonPath, using lib->filename is less trouble */ + initPySysObjects__append(sys_path, lib->filename); + lib= (Library *)lib->id.next; + } + + initPySysObjects__append(sys_path, gp_GamePythonPath); + +// fprintf(stderr, "\nNew Path: %d ", PyList_Size(sys_path)); +// PyObject_Print(sys_path, stderr, 0); +} + +static void restorePySysObjects(void) +{ + if (gp_OrigPythonSysPath==NULL) + return; + + PyObject *sys_path= PySys_GetObject("path"); /* should never fail */ + PyObject *sys_mods= PySys_GetObject("modules"); /* should never fail */ + + /* paths */ + PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath); + Py_DECREF(gp_OrigPythonSysPath); + gp_OrigPythonSysPath= NULL; + + /* modules */ + PyDict_Clear(sys_mods); + PyDict_Update(sys_mods, gp_OrigPythonSysModules); + Py_DECREF(gp_OrigPythonSysModules); + gp_OrigPythonSysModules= NULL; + + +// fprintf(stderr, "\nRestore Path: %d ", PyList_Size(sys_path)); +// PyObject_Print(sys_path, stderr, 0); +} + /** * Python is not initialised. */ PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv) { + /* Yet another gotcha in the py api + * Cant run PySys_SetArgv more then once because this adds the + * binary dir to the sys.path each time. + * Id have thaught python being totally restarted would make this ok but + * somehow it remembers the sys.path - Campbell + */ + static bool first_time = true; + +#if (PY_VERSION_HEX < 0x03000000) STR_String pname = progname; Py_SetProgramName(pname.Ptr()); +#endif Py_NoSiteFlag=1; Py_FrozenFlag=1; Py_Initialize(); - if(argv) /* browser plugins dont currently set this */ +#if (PY_VERSION_HEX < 0x03000000) + if(argv && first_time) /* browser plugins dont currently set this */ PySys_SetArgv(argc, argv); - +#endif //importBlenderModules() setSandbox(level); @@ -1380,24 +1610,37 @@ PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur /* XXX 2.5 bpy_import_main_set(maggie); */ + initPySysObjects(maggie); + + first_time = false; + + PyObjectPlus::ClearDeprecationWarning(); + PyObject* moduleobj = PyImport_AddModule("__main__"); return PyModule_GetDict(moduleobj); } void exitGamePlayerPythonScripting() -{ - //clearGameModules(); // were closing python anyway +{ + /* since python restarts we cant let the python backup of the sys.path hang around in a global pointer */ + restorePySysObjects(); /* get back the original sys.path and clear the backup */ + Py_Finalize(); /* XXX 2.5 bpy_import_main_set(NULL); */ + PyObjectPlus::ClearDeprecationWarning(); } + + /** * Python is already initialized. */ PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie) { +#if (PY_VERSION_HEX < 0x03000000) STR_String pname = progname; Py_SetProgramName(pname.Ptr()); +#endif Py_NoSiteFlag=1; Py_FrozenFlag=1; @@ -1406,53 +1649,35 @@ PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLev /* XXX 2.5 bpy_import_main_set(maggie); */ - /* run this to clear game modules and user modules which - * may contain references to in game data */ - clearGameModules(); + initPySysObjects(maggie); + PyObjectPlus::NullDeprecationWarning(); + PyObject* moduleobj = PyImport_AddModule("__main__"); return PyModule_GetDict(moduleobj); } -static void clearModule(PyObject *modules, const char *name) -{ - PyObject *mod= PyDict_GetItemString(modules, name); - - if (mod==NULL) - return; - - PyDict_Clear(PyModule_GetDict(mod)); /* incase there are any circular refs */ - PyDict_DelItemString(modules, name); -} - -static void clearGameModules() -{ - /* Note, user modules could still reference these modules - * but since the dict's are cleared their members wont be accessible */ - - PyObject *modules= PySys_GetObject((char *)"modules"); - clearModule(modules, "Expression"); - clearModule(modules, "CValue"); - clearModule(modules, "PhysicsConstraints"); - clearModule(modules, "GameLogic"); - clearModule(modules, "Rasterizer"); - clearModule(modules, "GameKeys"); - clearModule(modules, "VideoTexture"); - clearModule(modules, "Mathutils"); - clearModule(modules, "BGL"); - PyErr_Clear(); // incase some of these were alredy removed. - - /* clear user defined modules */ - /* XXX 2.5 bpy_text_clear_modules(); */ -} - void exitGamePythonScripting() { - clearGameModules(); + restorePySysObjects(); /* get back the original sys.path and clear the backup */ /* XXX 2.5 bpy_import_main_set(NULL); */ + PyObjectPlus::ClearDeprecationWarning(); } +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef Rasterizer_module_def = { + {}, /* m_base */ + "Rasterizer", /* m_name */ + Rasterizer_module_documentation, /* m_doc */ + 0, /* m_size */ + rasterizer_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) { @@ -1464,10 +1689,25 @@ PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) PyObject* d; PyObject* item; - // Create the module and add the functions - m = Py_InitModule4("Rasterizer", rasterizer_methods, + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "Rasterizer" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + // Create the module and add the functions +#if (PY_VERSION_HEX >= 0x03000000) + m = PyModule_Create(&Rasterizer_module_def); +#else + m = Py_InitModule4("Rasterizer", rasterizer_methods, Rasterizer_module_documentation, (PyObject*)NULL,PYTHON_API_VERSION); +#endif + } // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -1517,7 +1757,12 @@ static PyObject* gPyEventToString(PyObject*, PyObject* value) dict = PyModule_GetDict(mod); while (PyDict_Next(dict, &pos, &key, &val)) { +#if (PY_VERSION_HEX >= 0x03000000) + if (PyObject_RichCompareBool(value, val, Py_EQ)) { +#else if (PyObject_Compare(value, val)==0) { +#endif + ret = key; break; } @@ -1559,17 +1804,44 @@ static struct PyMethodDef gamekeys_methods[] = { }; +#if (PY_VERSION_HEX >= 0x03000000) +static struct PyModuleDef GameKeys_module_def = { + {}, /* m_base */ + "GameKeys", /* m_name */ + GameKeys_module_documentation, /* m_doc */ + 0, /* m_size */ + gamekeys_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; +#endif PyObject* initGameKeys() { PyObject* m; PyObject* d; PyObject* item; - - // Create the module and add the functions - m = Py_InitModule4("GameKeys", gamekeys_methods, + + /* Use existing module where possible */ + m = PyImport_ImportModule( "GameKeys" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + // Create the module and add the functions +#if (PY_VERSION_HEX >= 0x03000000) + m = PyModule_Create(&GameKeys_module_def); +#else + m = Py_InitModule4("GameKeys", gamekeys_methods, GameKeys_module_documentation, (PyObject*)NULL,PYTHON_API_VERSION); +#endif + } // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -1698,15 +1970,26 @@ PyObject* initGameKeys() return d; } +#if PY_VERSION_HEX < 0x03000000 PyObject* initMathutils() { return NULL; //XXX Mathutils_Init("Mathutils"); // Use as a top level module in BGE } +PyObject* initGeometry() +{ + return NULL; // XXX Geometry_Init("Geometry"); // Use as a top level module in BGE +} + PyObject* initBGL() { return NULL; // XXX 2.5 BGL_Init("BGL"); // Use as a top level module in BGE } +#else // TODO Py3k conversion +PyObject* initMathutils() {Py_INCREF(Py_None);return Py_None;} +PyObject* initGeometry() {Py_INCREF(Py_None);return Py_None;} +PyObject* initBGL() {Py_INCREF(Py_None);return Py_None;} +#endif void KX_SetActiveScene(class KX_Scene* scene) { @@ -1794,9 +2077,9 @@ int loadGamePythonConfig(char *marshal_buffer, int marshal_length) void pathGamePythonConfig( char *path ) { - int len = strlen(gp_GamePythonPath); + int len = strlen(gp_GamePythonPathOrig); // Always use the first loaded blend filename - BLI_strncpy(path, gp_GamePythonPath, sizeof(gp_GamePythonPath)); + BLI_strncpy(path, gp_GamePythonPathOrig, sizeof(gp_GamePythonPathOrig)); /* replace extension */ if (BLI_testextensie(path, ".blend")) { @@ -1809,5 +2092,16 @@ void pathGamePythonConfig( char *path ) void setGamePythonPath(char *path) { BLI_strncpy(gp_GamePythonPath, path, sizeof(gp_GamePythonPath)); + BLI_cleanup_file(NULL, gp_GamePythonPath); /* not absolutely needed but makes resolving path problems less confusing later */ + + if (gp_GamePythonPathOrig[0] == '\0') + BLI_strncpy(gp_GamePythonPathOrig, path, sizeof(gp_GamePythonPathOrig)); } +// we need this so while blender is open (not blenderplayer) +// loading new blendfiles will reset this on starting the +// engine but loading blend files within the BGE wont overwrite gp_GamePythonPathOrig +void resetGamePythonPath() +{ + gp_GamePythonPathOrig[0] == '\0'; +} diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 11360197b95..8f102d13a18 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -45,6 +45,7 @@ PyObject* initGameKeys(); PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas); PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, struct Main *maggie, int argc, char** argv); PyObject* initMathutils(); +PyObject* initGeometry(); PyObject* initBGL(); PyObject* initVideoTexture(void); void exitGamePlayerPythonScripting(); @@ -52,6 +53,7 @@ PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLev void exitGamePythonScripting(); void setGamePythonPath(char *path); +void resetGamePythonPath(); void pathGamePythonConfig( char *path ); int saveGamePythonConfig( char **marshal_buffer); int loadGamePythonConfig(char *marshal_buffer, int marshal_length); diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp index dcd11b551a1..83c4dcbb34c 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -51,6 +51,7 @@ #include "KX_PhysicsObjectWrapper.h" #include "KX_PolyProxy.h" #include "KX_PolygonMaterial.h" +#include "KX_PythonSeq.h" #include "KX_SCA_AddObjectActuator.h" #include "KX_SCA_EndObjectActuator.h" #include "KX_SCA_ReplaceMeshActuator.h" @@ -84,6 +85,7 @@ #include "SCA_PropertySensor.h" #include "SCA_PythonController.h" #include "SCA_RandomActuator.h" +#include "SCA_IController.h" void initPyObjectPlusType(PyTypeObject **parents) @@ -225,9 +227,10 @@ void initPyTypes(void) PyType_Ready_Attr(dict, SCA_RandomSensor); PyType_Ready_Attr(dict, SCA_XNORController); PyType_Ready_Attr(dict, SCA_XORController); + PyType_Ready_Attr(dict, SCA_IController); - - + /* Normal python type */ + PyType_Ready(&KX_PythonSeq_Type); } #endif
\ No newline at end of file diff --git a/source/gameengine/Ketsji/KX_PythonSeq.cpp b/source/gameengine/Ketsji/KX_PythonSeq.cpp new file mode 100644 index 00000000000..cc8021fc2e4 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonSeq.cpp @@ -0,0 +1,382 @@ +/** + * $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: none of this file. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + * Readonly sequence wrapper for lookups on logic bricks + */ + + +#include "KX_PythonSeq.h" +#include "KX_GameObject.h" +#include "SCA_ISensor.h" +#include "SCA_IController.h" +#include "SCA_IActuator.h" + + +PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type ) +{ + KX_PythonSeq *seq = PyObject_NEW( KX_PythonSeq, &KX_PythonSeq_Type); + seq->base = base; + Py_INCREF(base); /* so we can always access to check if its valid */ + seq->type = type; + seq->iter = -1; /* init */ + return (PyObject *)seq; + } + + static void KX_PythonSeq_dealloc( KX_PythonSeq * self ) +{ + Py_DECREF(self->base); + PyObject_DEL( self ); +} + +static Py_ssize_t KX_PythonSeq_len( PyObject * self ) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return -1; + } + + switch(((KX_PythonSeq *)self)->type) { + case KX_PYGENSEQ_CONT_TYPE_SENSORS: + return ((SCA_IController *)self_plus)->GetLinkedSensors().size(); + case KX_PYGENSEQ_CONT_TYPE_ACTUATORS: + return ((SCA_IController *)self_plus)->GetLinkedActuators().size(); + case KX_PYGENSEQ_OB_TYPE_SENSORS: + return ((KX_GameObject *)self_plus)->GetSensors().size(); + case KX_PYGENSEQ_OB_TYPE_CONTROLLERS: + return ((KX_GameObject *)self_plus)->GetControllers().size(); + case KX_PYGENSEQ_OB_TYPE_ACTUATORS: + return ((KX_GameObject *)self_plus)->GetActuators().size(); + default: + /* Should never happen */ + PyErr_SetString(PyExc_SystemError, "invalid type, internal error"); + return -1; + } +} + +static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + switch(((KX_PythonSeq *)self)->type) { + case KX_PYGENSEQ_CONT_TYPE_SENSORS: + { + vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors(); + if(index<0) index += linkedsensors.size(); + if(index<0 || index>= linkedsensors.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedsensors[index]->GetProxy(); + } + case KX_PYGENSEQ_CONT_TYPE_ACTUATORS: + { + vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators(); + if(index<0) index += linkedactuators.size(); + if(index<0 || index>= linkedactuators.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedactuators[index]->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_SENSORS: + { + SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors(); + if(index<0) index += linkedsensors.size(); + if(index<0 || index>= linkedsensors.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedsensors[index]->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_CONTROLLERS: + { + SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers(); + if(index<0) index += linkedcontrollers.size(); + if(index<0 || index>= linkedcontrollers.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedcontrollers[index]->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_ACTUATORS: + { + SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators(); + if(index<0) index += linkedactuators.size(); + if(index<0 || index>= linkedactuators.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedactuators[index]->GetProxy(); + } + } + + PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug"); + return NULL; +} + + +static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + char *name = NULL; + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + if (PyInt_Check(key)) { + return KX_PythonSeq_getIndex(self, PyInt_AS_LONG( key )); + } else if ( PyString_Check(key) ) { + name = PyString_AsString( key ); + } else { + PyErr_SetString( PyExc_TypeError, "expected a string or an index" ); + return NULL; + } + + switch(((KX_PythonSeq *)self)->type) { + case KX_PYGENSEQ_CONT_TYPE_SENSORS: + { + vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors(); + SCA_ISensor* sensor; + for (unsigned int index=0;index<linkedsensors.size();index++) { + sensor = linkedsensors[index]; + if (sensor->GetName() == name) + return sensor->GetProxy(); + } + break; + } + case KX_PYGENSEQ_CONT_TYPE_ACTUATORS: + { + vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators(); + SCA_IActuator* actuator; + for (unsigned int index=0;index<linkedactuators.size();index++) { + actuator = linkedactuators[index]; + if (actuator->GetName() == name) + return actuator->GetProxy(); + } + break; + } + case KX_PYGENSEQ_OB_TYPE_SENSORS: + { + SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors(); + SCA_ISensor *sensor; + for (unsigned int index=0;index<linkedsensors.size();index++) { + sensor= linkedsensors[index]; + if (sensor->GetName() == name) + return sensor->GetProxy(); + } + break; + } + case KX_PYGENSEQ_OB_TYPE_CONTROLLERS: + { + SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers(); + SCA_IController *controller; + for (unsigned int index=0;index<linkedcontrollers.size();index++) { + controller= linkedcontrollers[index]; + if (controller->GetName() == name) + return controller->GetProxy(); + } + break; + } + case KX_PYGENSEQ_OB_TYPE_ACTUATORS: + { + SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators(); + SCA_IActuator *actuator; + for (unsigned int index=0;index<linkedactuators.size();index++) { + actuator= linkedactuators[index]; + if (actuator->GetName() == name) + return actuator->GetProxy(); + } + break; + } + } + + PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name); + return NULL; +} + +static PyMappingMethods KX_PythonSeq_as_mapping = { + KX_PythonSeq_len, /* mp_length */ + KX_PythonSeq_subscript, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + + +/* + * Initialize the interator index + */ + +static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self) +{ + if(BGE_PROXY_REF(self->base)==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + /* create a new iterator if were alredy using this one */ + if (self->iter == -1) { + self->iter = 0; + Py_INCREF(self); + return (PyObject *)self; + } else { + return KX_PythonSeq_CreatePyObject(self->base, self->type); + } + } + + +/* + * Return next KX_PythonSeq iter. + */ + +static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self) +{ + PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter); + + self->iter++; + if( object==NULL ) { + self->iter= -1; /* for reuse */ + PyErr_SetString(PyExc_StopIteration, "iterator at end"); + } + return object; /* can be NULL for end of iterator */ +} + + +static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b ) /* TODO - python3.x wants richcmp */ +{ + return ( a->type == b->type && a->base == b->base) ? 0 : -1; +} + +/* + * repr function + * convert to a list and get its string value + */ +static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self ) +{ + PyObject *list = PySequence_List((PyObject *)self); + PyObject *repr = PyObject_Repr(list); + Py_DECREF(list); + return repr; +} + + +/*****************************************************************************/ +/* Python KX_PythonSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject KX_PythonSeq_Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + /* For printing, in format "<module>.<name>" */ + "KX_PythonSeq", /* char *tp_name; */ + sizeof( KX_PythonSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + ( cmpfunc ) KX_PythonSeq_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) KX_PythonSeq_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + &KX_PythonSeq_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + NULL, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/gameengine/Ketsji/KX_PythonSeq.h b/source/gameengine/Ketsji/KX_PythonSeq.h new file mode 100644 index 00000000000..15a016224a9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonSeq.h @@ -0,0 +1,60 @@ +/** + * $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): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + * Readonly sequence wrapper for lookups on logic bricks + */ + +#ifndef _adr_py_seq_h_ // only process once, +#define _adr_py_seq_h_ // even if multiply included + +#include "PyObjectPlus.h" + +// ------------------------- +enum KX_PYGENSEQ_TYPE { + KX_PYGENSEQ_CONT_TYPE_SENSORS, + KX_PYGENSEQ_CONT_TYPE_ACTUATORS, + KX_PYGENSEQ_OB_TYPE_SENSORS, + KX_PYGENSEQ_OB_TYPE_CONTROLLERS, + KX_PYGENSEQ_OB_TYPE_ACTUATORS +}; + +/* The Main PyType Object defined in Main.c */ +extern PyTypeObject KX_PythonSeq_Type; + +#define BPy_KX_PythonSeq_Check(v) \ + ((v)->ob_type == &KX_PythonSeq_Type) + +typedef struct { + PyObject_VAR_HEAD + PyObject *base; + short type; + short iter; +} KX_PythonSeq; + +PyObject *KX_PythonSeq_CreatePyObject(PyObject *base, short type); + +#endif // _adr_py_seq_h_ diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index 8277e7ef19c..064dc9126ac 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -30,6 +30,7 @@ #include "KX_GameObject.h" #include "KX_PyMath.h" #include "PHY_IPhysicsController.h" +#include "PHY_IMotionState.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -66,7 +67,7 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr, m_coneheight(coneheight), m_axis(axis) { - m_client_info->m_type = KX_ClientObjectInfo::RADAR; + m_client_info->m_type = KX_ClientObjectInfo::SENSOR; //m_client_info->m_clientobject = gameobj; //m_client_info->m_auxilary_info = NULL; //sumoObj->setClientObject(&m_client_info); @@ -80,35 +81,10 @@ KX_RadarSensor::~KX_RadarSensor() CValue* KX_RadarSensor::GetReplica() { KX_RadarSensor* replica = new KX_RadarSensor(*this); - replica->m_colliders = new CListValue(); - replica->Init(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - - replica->m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::RADAR); - - if (replica->m_physCtrl) - { - replica->m_physCtrl = replica->m_physCtrl->GetReplica(); - if (replica->m_physCtrl) - { - replica->m_physCtrl->setNewClientInfo(replica->m_client_info); - } - } - - //todo: make sure replication works fine! - //>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); - //Wrong: see KX_TouchSensor - //bool parentUpdated = false; - //((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL,parentUpdated); - replica->SynchronizeTransform(); - + replica->ProcessReplica(); return replica; } - /** * Transforms the collision object. A cone is not correctly centered * for usage. */ @@ -188,11 +164,13 @@ void KX_RadarSensor::SynchronizeTransform() if (m_physCtrl) { - MT_Quaternion orn = trans.getRotation(); - MT_Point3 pos = trans.getOrigin(); - m_physCtrl->setPosition(pos[0],pos[1],pos[2]); - m_physCtrl->setOrientation(orn[0],orn[1],orn[2],orn[3]); - m_physCtrl->calcXform(); + PHY_IMotionState* motionState = m_physCtrl->GetMotionState(); + const MT_Point3& pos = trans.getOrigin(); + float ori[12]; + trans.getBasis().getValue(ori); + motionState->setWorldPosition(pos[0], pos[1], pos[2]); + motionState->setWorldOrientation(ori); + m_physCtrl->WriteMotionStateToDynamics(true); } } @@ -212,9 +190,9 @@ PyObject* KX_RadarSensor::PyGetConeOrigin() { PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_cone_origin[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_cone_origin[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_cone_origin[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_cone_origin[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_cone_origin[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_cone_origin[2])); return retVal; } @@ -228,9 +206,9 @@ PyObject* KX_RadarSensor::PyGetConeTarget() { PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_cone_target[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_cone_target[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_cone_target[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_cone_target[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_cone_target[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_cone_target[2])); return retVal; } @@ -251,8 +229,13 @@ PyObject* KX_RadarSensor::PyGetConeHeight() { /* Python Integration Hooks */ /* ------------------------------------------------------------------------- */ PyTypeObject KX_RadarSensor::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_RadarSensor", sizeof(PyObjectPlus_Proxy), 0, @@ -294,6 +277,7 @@ PyMethodDef KX_RadarSensor::Methods[] = { PyAttributeDef KX_RadarSensor::Attributes[] = { KX_PYATTRIBUTE_FLOAT_ARRAY_RO("coneOrigin", KX_RadarSensor, m_cone_origin, 3), KX_PYATTRIBUTE_FLOAT_ARRAY_RO("coneTarget", KX_RadarSensor, m_cone_target, 3), + KX_PYATTRIBUTE_FLOAT_RO("distance", KX_RadarSensor, m_coneheight), KX_PYATTRIBUTE_FLOAT_RW("angle", 0, 360, KX_RadarSensor, m_coneradius), KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RadarSensor, m_axis), {NULL} //Sentinel @@ -304,6 +288,10 @@ PyObject* KX_RadarSensor::py_getattro(PyObject *attr) py_getattro_up(KX_NearSensor); } +PyObject* KX_RadarSensor::py_getattro_dict() { + py_getattro_dict_up(KX_NearSensor); +} + int KX_RadarSensor::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(KX_NearSensor); diff --git a/source/gameengine/Ketsji/KX_RadarSensor.h b/source/gameengine/Ketsji/KX_RadarSensor.h index c3a941696ce..2e5a0e68bed 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.h +++ b/source/gameengine/Ketsji/KX_RadarSensor.h @@ -90,7 +90,9 @@ public: }; virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); + virtual sensortype GetSensorType() { return ST_RADAR; } //Deprecated -----> KX_PYMETHOD_DOC_NOARGS(KX_RadarSensor,GetConeOrigin); diff --git a/source/gameengine/Ketsji/KX_RayEventManager.cpp b/source/gameengine/Ketsji/KX_RayEventManager.cpp index 1af29151adf..50fa4f5e310 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.cpp +++ b/source/gameengine/Ketsji/KX_RayEventManager.cpp @@ -44,9 +44,10 @@ using namespace std; void KX_RayEventManager::NextFrame() { - for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*i)->Activate(m_logicmgr, NULL); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index 06c04dbf10d..78a61e9d95e 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -88,8 +88,7 @@ KX_RaySensor::~KX_RaySensor() CValue* KX_RaySensor::GetReplica() { KX_RaySensor* replica = new KX_RaySensor(*this); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); return replica; @@ -179,7 +178,7 @@ bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo* client) return true; } -bool KX_RaySensor::Evaluate(CValue* event) +bool KX_RaySensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; @@ -321,8 +320,13 @@ bool KX_RaySensor::Evaluate(CValue* event) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_RaySensor::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_RaySensor", sizeof(PyObjectPlus_Proxy), 0, @@ -362,7 +366,7 @@ PyAttributeDef KX_RaySensor::Attributes[] = { KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_RaySensor, m_bFindMaterial), KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_RaySensor, m_bXRay), KX_PYATTRIBUTE_FLOAT_RW("range", 0, 10000, KX_RaySensor, m_distance), - KX_PYATTRIBUTE_STRING_RW("property", 0, 100, false, KX_RaySensor, m_propertyname), + KX_PYATTRIBUTE_STRING_RW("propName", 0, 100, false, KX_RaySensor, m_propertyname), KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RaySensor, m_axis), KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitPosition", KX_RaySensor, m_hitPosition, 3), KX_PYATTRIBUTE_FLOAT_ARRAY_RO("rayDirection", KX_RaySensor, m_rayDirection, 3), @@ -404,9 +408,9 @@ PyObject* KX_RaySensor::PyGetHitPosition() PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_hitPosition[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_hitPosition[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_hitPosition[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_hitPosition[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_hitPosition[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_hitPosition[2])); return retVal; } @@ -420,9 +424,9 @@ PyObject* KX_RaySensor::PyGetRayDirection() PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_rayDirection[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_rayDirection[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_rayDirection[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_rayDirection[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_rayDirection[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_rayDirection[2])); return retVal; } @@ -436,9 +440,9 @@ PyObject* KX_RaySensor::PyGetHitNormal() PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_hitNormal[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_hitNormal[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_hitNormal[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_hitNormal[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_hitNormal[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_hitNormal[2])); return retVal; } @@ -449,6 +453,10 @@ PyObject* KX_RaySensor::py_getattro(PyObject *attr) { py_getattro_up(SCA_ISensor); } +PyObject* KX_RaySensor::py_getattro_dict() { + py_getattro_dict_up(SCA_ISensor); +} + int KX_RaySensor::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_ISensor); } diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index a5d7d15c60c..9efb046742f 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -67,7 +67,7 @@ public: virtual ~KX_RaySensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); @@ -87,6 +87,7 @@ public: virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // Deprecated -----> diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index c45d89a2815..75435b97797 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -86,7 +86,7 @@ KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator() if (m_OriginalObject) m_OriginalObject->UnregisterActuator(this); if (m_lastCreatedObject) - m_lastCreatedObject->Release(); + m_lastCreatedObject->UnregisterActuator(this); } @@ -124,7 +124,6 @@ CValue* KX_SCA_AddObjectActuator::GetReplica() // this will copy properties and so on... replica->ProcessReplica(); - CValue::AddDataToReplica(replica); return replica; } @@ -145,6 +144,12 @@ bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj) m_OriginalObject = NULL; return true; } + if (clientobj == m_lastCreatedObject) + { + // this object is being deleted, we cannot continue to track it. + m_lastCreatedObject = NULL; + return true; + } return false; } @@ -166,8 +171,13 @@ void KX_SCA_AddObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SCA_AddObjectActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SCA_AddObjectActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -231,7 +241,7 @@ int KX_SCA_AddObjectActuator::pyattr_set_object(void *self, const struct KX_PYAT KX_GameObject *gameobj; if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SCA_AddObjectActuator")) - return 1; // ConvertPythonToGameObject sets the error + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error if (actuator->m_OriginalObject != NULL) actuator->m_OriginalObject->UnregisterActuator(actuator); @@ -241,7 +251,7 @@ int KX_SCA_AddObjectActuator::pyattr_set_object(void *self, const struct KX_PYAT if (actuator->m_OriginalObject) actuator->m_OriginalObject->RegisterActuator(actuator); - return 0; + return PY_SET_ATTR_SUCCESS; } PyObject* KX_SCA_AddObjectActuator::pyattr_get_objectLastCreated(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) @@ -259,6 +269,10 @@ PyObject* KX_SCA_AddObjectActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_SCA_AddObjectActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_SCA_AddObjectActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); @@ -347,7 +361,7 @@ PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* args) Py_RETURN_NONE; if (ret_name_only) - return PyString_FromString(m_OriginalObject->GetName()); + return PyString_FromString(m_OriginalObject->GetName().ReadPtr()); else return m_OriginalObject->GetProxy(); } @@ -455,13 +469,21 @@ void KX_SCA_AddObjectActuator::InstantAddObject() // keep a copy of the last object, to allow python scripters to change it if (m_lastCreatedObject) { - //careful with destruction, it might still have outstanding collision callbacks - m_scene->DelayedReleaseObject(m_lastCreatedObject); - m_lastCreatedObject->Release(); + //Let's not keep a reference to the object: it's bad, if the object is deleted + //this will force to keep a "zombie" in the game for no good reason. + //m_scene->DelayedReleaseObject(m_lastCreatedObject); + //m_lastCreatedObject->Release(); + + //Instead we use the registration mechanism + m_lastCreatedObject->UnregisterActuator(this); + m_lastCreatedObject = NULL; } m_lastCreatedObject = replica; - m_lastCreatedObject->AddRef(); + // no reference + //m_lastCreatedObject->AddRef(); + // but registration + m_lastCreatedObject->RegisterActuator(this); // finished using replica? then release it replica->Release(); } diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h index 4ece5a6d83b..6746b7d1bc6 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h @@ -111,6 +111,7 @@ public: Update(); virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); SCA_IObject* diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp index 83dfdc2484c..a50764a54e6 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp @@ -50,8 +50,13 @@ PyTypeObject KX_SCA_DynamicActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SCA_DynamicActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -85,7 +90,7 @@ PyMethodDef KX_SCA_DynamicActuator::Methods[] = { }; PyAttributeDef KX_SCA_DynamicActuator::Attributes[] = { - KX_PYATTRIBUTE_SHORT_RW("operation",0,4,false,KX_SCA_DynamicActuator,m_dyn_operation), + KX_PYATTRIBUTE_SHORT_RW("mode",0,4,false,KX_SCA_DynamicActuator,m_dyn_operation), KX_PYATTRIBUTE_FLOAT_RW("mass",0.0,FLT_MAX,KX_SCA_DynamicActuator,m_setmass), { NULL } //Sentinel }; @@ -96,6 +101,10 @@ PyObject* KX_SCA_DynamicActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_SCA_DynamicActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_SCA_DynamicActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); @@ -112,7 +121,7 @@ KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, setOperation, "\t 3 = disable rigid body\n" "Change the dynamic status of the parent object.\n") { - ShowDeprecationWarning("setOperation()", "the operation property"); + ShowDeprecationWarning("setOperation()", "the mode property"); int dyn_operation; if (!PyArg_ParseTuple(args, "i:setOperation", &dyn_operation)) @@ -132,7 +141,7 @@ KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, getOperation, "Returns the operation type of this actuator.\n" ) { - ShowDeprecationWarning("getOperation()", "the operation property"); + ShowDeprecationWarning("getOperation()", "the mode property"); return PyInt_FromLong((long)m_dyn_operation); } @@ -210,10 +219,6 @@ CValue* KX_SCA_DynamicActuator::GetReplica() return NULL; replica->ProcessReplica(); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; }; diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h index 99855124bdb..4add707f8cd 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h @@ -75,6 +75,7 @@ class KX_SCA_DynamicActuator : public SCA_IActuator virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); /* 1. setOperation */ diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp index 3b42577810e..728254e7f48 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp @@ -82,8 +82,6 @@ CValue* KX_SCA_EndObjectActuator::GetReplica() if (replica == NULL) return NULL; replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -94,8 +92,13 @@ CValue* KX_SCA_EndObjectActuator::GetReplica() /* ------------------------------------------------------------------------- */ PyTypeObject KX_SCA_EndObjectActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SCA_EndObjectActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -136,4 +139,8 @@ PyObject* KX_SCA_EndObjectActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_SCA_EndObjectActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + /* eof */ diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h index 2940246f443..70d72f1f8da 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h @@ -65,6 +65,7 @@ class KX_SCA_EndObjectActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); }; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp index 38f8d581d55..00842d7012a 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp @@ -53,8 +53,13 @@ PyTypeObject KX_SCA_ReplaceMeshActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SCA_ReplaceMeshActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -99,6 +104,10 @@ PyObject* KX_SCA_ReplaceMeshActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_SCA_ReplaceMeshActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_SCA_ReplaceMeshActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); @@ -119,10 +128,10 @@ int KX_SCA_ReplaceMeshActuator::pyattr_set_mesh(void *self, const struct KX_PYAT RAS_MeshObject* new_mesh; if (!ConvertPythonToMesh(value, &new_mesh, true, "actuator.mesh = value: KX_SCA_ReplaceMeshActuator")) - return 1; + return PY_SET_ATTR_FAIL; actuator->m_mesh = new_mesh; - return 0; + return PY_SET_ATTR_SUCCESS; } /* 1. setMesh */ @@ -213,9 +222,6 @@ CValue* KX_SCA_ReplaceMeshActuator::GetReplica() replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; }; diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h index 7a18df2356d..0e7f7852701 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h @@ -72,6 +72,7 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator void InstantReplaceMesh(); virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); static PyObject* pyattr_get_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp index 0e7571031e8..cb933419c57 100644 --- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp +++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp @@ -125,7 +125,9 @@ UpdateChildCoordinates( else { child->SetWorldFromLocalTransform(); } - child->SetModified(false); + child->ClearModified(); + // this node must always be updated, so reschedule it for next time + child->ActivateRecheduleUpdateCallback(); return valid_parent_transform; } diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp index c3b0c21c8e0..c49b6d671a7 100644 --- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp +++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp @@ -63,7 +63,7 @@ UpdateChildCoordinates( if (parent==NULL) { /* Simple case */ child->SetWorldFromLocalTransform(); - child->SetModified(false); + child->ClearModified(); return true; //false; } else { @@ -75,7 +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); + child->ClearModified(); return true; } } @@ -137,7 +137,7 @@ UpdateChildCoordinates( child->SetWorldPosition(child->GetLocalPosition()); child->SetWorldOrientation(child->GetLocalOrientation()); - child->SetModified(false); + child->ClearModified(); return true; //parent != NULL; } @@ -259,7 +259,9 @@ UpdateChildCoordinates( child->SetWorldScale(child_w_scale); child->SetWorldPosition(child_w_pos); child->SetWorldOrientation(child_w_rotation); - child->SetModified(false); + child->ClearModified(); + // this node must always be updated, so reschedule it for next time + child->ActivateRecheduleUpdateCallback(); return true; //parent != NULL; } diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index aa7bd65f240..c0d8a7090c4 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -34,7 +34,7 @@ #include "KX_Scene.h" #include "MT_assert.h" - +#include "SND_Scene.h" #include "KX_KetsjiEngine.h" #include "KX_BlenderMaterial.h" #include "RAS_IPolygonMaterial.h" @@ -80,6 +80,7 @@ #include "KX_BlenderSceneConverter.h" #include "KX_MotionState.h" +#include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_DeformableGameObject.h" @@ -110,7 +111,22 @@ void* KX_SceneDestructionFunc(SG_IObject* node,void* gameobj,void* scene) return NULL; }; -SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks(KX_SceneReplicationFunc,KX_SceneDestructionFunc,KX_GameObject::UpdateTransformFunc); +bool KX_Scene::KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene) +{ + return ((SG_Node*)node)->Schedule(((KX_Scene*)scene)->m_sghead); +} + +bool KX_Scene::KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene) +{ + return ((SG_Node*)node)->Reschedule(((KX_Scene*)scene)->m_sghead); +} + +SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks( + KX_SceneReplicationFunc, + KX_SceneDestructionFunc, + KX_GameObject::UpdateTransformFunc, + KX_Scene::KX_ScenegraphUpdateFunc, + KX_Scene::KX_ScenegraphRescheduleFunc); // temporarily var until there is a button in the userinterface // (defined in KX_PythonInit.cpp) @@ -148,7 +164,6 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_lightlist= new CListValue(); m_inactivelist = new CListValue(); m_euthanasyobjects = new CListValue(); - m_delayReleaseObjects = new CListValue(); m_logicmgr = new SCA_LogicManager(); @@ -192,9 +207,6 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_rootnode = NULL; m_bucketmanager=new RAS_BucketManager(); - - m_canvasDesignWidth = 0; - m_canvasDesignHeight = 0; m_attr_dict = PyDict_New(); /* new ref */ } @@ -231,8 +243,6 @@ KX_Scene::~KX_Scene() if (m_euthanasyobjects) m_euthanasyobjects->Release(); - if (m_delayReleaseObjects) - m_delayReleaseObjects->Release(); if (m_logicmgr) delete m_logicmgr; @@ -254,13 +264,6 @@ KX_Scene::~KX_Scene() Py_DECREF(m_attr_dict); } -void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat) -{ - m_projectionmat = pmat; -} - - - RAS_BucketManager* KX_Scene::GetBucketManager() { return m_bucketmanager; @@ -408,11 +411,11 @@ void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gam KX_GameObject* orgobj = (KX_GameObject*)gameobj; if (NewRemoveObject(orgobj) != 0) { - // object is not yet deleted (this can happen when it hangs in an add object actuator - // last object created reference. It's a bad situation, don't know how to fix it exactly - // The least I can do, is remove the reference to the node in the object as the node - // 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) + // object is not yet deleted because a reference is hanging somewhere. + // This should not happen anymore since we use proxy object for Python + // confident enough to put an assert? + //assert(false); + printf("Zombie object! name=%s\n", orgobj->GetName().ReadPtr()); orgobj->SetSGNode(NULL); PHY_IGraphicController* ctrl = orgobj->GetGraphicController(); if (ctrl) @@ -477,6 +480,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal // this is the list of object that are send to the graphics pipeline m_objectlist->Add(newobj->AddRef()); + if (newobj->IsLight()) + m_lightlist->Add(newobj->AddRef()); newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. @@ -537,8 +542,9 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj) vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators(); // disconnect the sensors and actuators - cont->UnlinkAllSensors(); - cont->UnlinkAllActuators(); + // do it directly on the list at this controller is not connected to anything at this stage + cont->GetLinkedSensors().clear(); + cont->GetLinkedActuators().clear(); // now relink each sensor for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++) @@ -716,16 +722,20 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // set the replica's relative scale with the rootnode's scale replica->NodeSetRelativeScale(newscale); - MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); - replica->NodeSetLocalOrientation(newori); MT_Point3 offset(group->dupli_ofs); MT_Point3 newpos = groupobj->NodeGetWorldPosition() + newscale*(groupobj->NodeGetWorldOrientation() * (gameobj->NodeGetWorldPosition()-offset)); replica->NodeSetLocalPosition(newpos); - + // set the orientation after position for softbody! + MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); + replica->NodeSetLocalOrientation(newori); + // update scenegraph for entire tree of children replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius()); + // we can now add the graphic controller to the physic engine + replica->ActivateGraphicController(true); + // done with replica replica->Release(); } @@ -836,6 +846,8 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius()); + // the size is correct, we can add the graphic controller to the physic engine + replica->ActivateGraphicController(true); // now replicate logic vector<KX_GameObject*>::iterator git; @@ -889,7 +901,7 @@ void KX_Scene::RemoveObject(class CValue* gameobj) { KX_GameObject* newobj = (KX_GameObject*) gameobj; - // first disconnect child from parent + // disconnect child from parent SG_Node* node = newobj->GetSGNode(); if (node) @@ -903,12 +915,6 @@ void KX_Scene::RemoveObject(class CValue* gameobj) //newobj->SetSGNode(0); } -void KX_Scene::DelayedReleaseObject(CValue* gameobj) -{ - m_delayReleaseObjects->Add(gameobj->AddRef()); -} - - void KX_Scene::DelayedRemoveObject(class CValue* gameobj) { //KX_GameObject* newobj = (KX_GameObject*) gameobj; @@ -925,6 +931,13 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) int ret; KX_GameObject* newobj = (KX_GameObject*) gameobj; + /* Invalidate the python reference, since the object may exist in script lists + * its possible that it wont be automatically invalidated, so do it manually here, + * + * if for some reason the object is added back into the scene python can always get a new Proxy + */ + newobj->InvalidateProxy(); + // keep the blender->game object association up to date // note that all the replicas of an object will have the same // blender object, that's why we need to check the game object @@ -954,7 +967,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) for (SCA_ActuatorList::iterator ita = actuators.begin(); !(ita==actuators.end());ita++) { - m_logicmgr->RemoveDestroyedActuator(*ita); + m_logicmgr->RemoveActuator(*ita); } // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject @@ -1038,6 +1051,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName())); Mesh* blendmesh = mesh->GetMesh(); + bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(blendobj); bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE; bool bHasDvert = blendmesh->dvert != NULL; bool bHasArmature = @@ -1053,10 +1067,39 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) if (oldblendobj==NULL) { std::cout << "warning: ReplaceMesh() new mesh is not used in an object from the current scene, you will get incorrect behavior" << std::endl; - bHasShapeKey= bHasDvert= bHasArmature= false; + bHasShapeKey= bHasDvert= bHasArmature=bHasModifier= false; } - if (bHasShapeKey) + if (bHasModifier) + { + BL_ModifierDeformer* modifierDeformer; + if (bHasShapeKey || bHasArmature) + { + modifierDeformer = new BL_ModifierDeformer( + newobj, + m_blenderScene, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + true, + static_cast<BL_ArmatureObject*>( parentobj ) + ); + releaseParent= false; + modifierDeformer->LoadShapeDrivers(blendobj->parent); + } + else + { + modifierDeformer = new BL_ModifierDeformer( + newobj, + m_blenderScene, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + false, + NULL + ); + } + newobj->SetDeformer(modifierDeformer); + } + else if (bHasShapeKey) { BL_ShapeDeformer* shapeDeformer; if (bHasArmature) @@ -1066,6 +1109,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, + true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; @@ -1078,6 +1122,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), false, + true, NULL ); } @@ -1090,6 +1135,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, + true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; @@ -1112,24 +1158,6 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) gameobj->AddMeshUser(); } - - -MT_CmMatrix4x4& KX_Scene::GetViewMatrix() -{ - MT_Scalar cammat[16]; - m_active_camera->GetWorldToCamera().getValue(cammat); - m_viewmat = cammat; - return m_viewmat; -} - - - -MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix() -{ - return m_projectionmat; -} - - KX_Camera* KX_Scene::FindCamera(KX_Camera* cam) { list<KX_Camera*>::iterator it = m_cameras.begin(); @@ -1423,24 +1451,17 @@ void KX_Scene::LogicEndFrame() { m_logicmgr->EndFrame(); int numobj = m_euthanasyobjects->GetCount(); - int i; - for (i = numobj - 1; i >= 0; i--) - { - KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i); - // KX_Scene::RemoveObject will also remove the object from this list - // that's why we start from the end - this->RemoveObject(gameobj); - } - numobj= m_delayReleaseObjects->GetCount(); - for (i = numobj-1;i>=0;i--) + KX_GameObject* obj; + + while ((numobj = m_euthanasyobjects->GetCount()) > 0) { - KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i); - // This list is not for object removal, but just object release - gameobj->Release(); + // remove the object from this list to make sure we will not hit it again + obj = (KX_GameObject*)m_euthanasyobjects->GetValue(numobj-1); + m_euthanasyobjects->Remove(numobj-1); + obj->Release(); + RemoveObject(obj); } - // empty the list as we have removed all references - m_delayReleaseObjects->Resize(0); } @@ -1450,15 +1471,28 @@ void KX_Scene::LogicEndFrame() */ void KX_Scene::UpdateParents(double curtime) { -// int numrootobjects = GetRootParentList()->GetCount(); + // we use the SG dynamic list + SG_Node* node; - for (int i=0; i<GetRootParentList()->GetCount(); i++) + while ((node = SG_Node::GetNextScheduled(m_sghead)) != NULL) { - KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); - parentobj->NodeUpdateGS(curtime); + node->UpdateWorldData(curtime); } -} + //for (int i=0; i<GetRootParentList()->GetCount(); i++) + //{ + // KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); + // parentobj->NodeUpdateGS(curtime); + //} + + // the list must be empty here + assert(m_sghead.Empty()); + // some nodes may be ready for reschedule, move them to schedule list for next time + while ((node = SG_Node::GetNextRescheduled(m_sghead)) != NULL) + { + node->Schedule(m_sghead); + } +} RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated) @@ -1579,8 +1613,13 @@ double KX_Scene::getSuspendedDelta() //Python PyTypeObject KX_Scene::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_Scene", sizeof(PyObjectPlus_Proxy), 0, @@ -1604,9 +1643,9 @@ PyParentObject KX_Scene::Parents[] = { }; PyMethodDef KX_Scene::Methods[] = { - KX_PYMETHODTABLE(KX_Scene, getLightList), - KX_PYMETHODTABLE(KX_Scene, getObjectList), - KX_PYMETHODTABLE(KX_Scene, getName), + KX_PYMETHODTABLE_NOARGS(KX_Scene, getLightList), + KX_PYMETHODTABLE_NOARGS(KX_Scene, getObjectList), + KX_PYMETHODTABLE_NOARGS(KX_Scene, getName), KX_PYMETHODTABLE(KX_Scene, addObject), {NULL,NULL} //Sentinel @@ -1624,46 +1663,81 @@ PyObject* KX_Scene::pyattr_get_objects(void *self_v, const KX_PYATTRIBUTE_DEF *a return self->GetObjectList()->GetProxy(); } +PyObject* KX_Scene::pyattr_get_objects_inactive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetInactiveList()->GetProxy(); +} + +PyObject* KX_Scene::pyattr_get_lights(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetLightList()->GetProxy(); +} + +PyObject* KX_Scene::pyattr_get_cameras(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + /* With refcounts in this case... + * the new CListValue is owned by python, so its possible python holds onto it longer then the BGE + * however this is the same with "scene.objects + []", when you make a copy by adding lists. + */ + + KX_Scene* self= static_cast<KX_Scene*>(self_v); + CListValue* clist = new CListValue(); + + /* return self->GetCameras()->GetProxy(); */ + + list<KX_Camera*>::iterator it = self->GetCameras()->begin(); + while (it != self->GetCameras()->end()) { + clist->Add((*it)->AddRef()); + it++; + } + + return clist->NewProxy(true); +} + PyObject* KX_Scene::pyattr_get_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_Scene* self= static_cast<KX_Scene*>(self_v); return self->GetActiveCamera()->GetProxy(); } -/* __dict__ only for the purpose of giving useful dir() results */ -PyObject* KX_Scene::pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) + +int KX_Scene::pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_Scene* self= static_cast<KX_Scene*>(self_v); - /* Useually done by py_getattro_up but in this case we want to include m_attr_dict dict */ - PyObject *dict_str= PyString_FromString("__dict__"); - PyObject *dict= py_getattr_dict(self->PyObjectPlus::py_getattro(dict_str), Type.tp_dict); - Py_DECREF(dict_str); + KX_Camera *camOb; - PyDict_Update(dict, self->m_attr_dict); - return dict; + if (!ConvertPythonToCamera(value, &camOb, false, "scene.active_camera = value: KX_Scene")) + return PY_SET_ATTR_FAIL; + + self->SetActiveCamera(camOb); + return PY_SET_ATTR_SUCCESS; } + PyAttributeDef KX_Scene::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), - KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), - KX_PYATTRIBUTE_RO_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera), - KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), - KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), + KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), + KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), + KX_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive), KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), + KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), + 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), + KX_PYATTRIBUTE_BOOL_RO("dbvt_culling", KX_Scene, m_dbvt_culling), { NULL } //Sentinel }; - PyObject* KX_Scene::py_getattro__internal(PyObject *attr) { py_getattro_up(PyObjectPlus); } -int KX_Scene::py_setattro__internal(PyObject *attr, PyObject *pyvalue) +int KX_Scene::py_setattro__internal(PyObject *attr, PyObject *value) { - return PyObjectPlus::py_setattro(attr, pyvalue); + py_setattro_up(PyObjectPlus); } PyObject* KX_Scene::py_getattro(PyObject *attr) @@ -1685,6 +1759,18 @@ PyObject* KX_Scene::py_getattro(PyObject *attr) return object; } +PyObject* KX_Scene::py_getattro_dict() { + //py_getattro_dict_up(PyObjectPlus); + + PyObject *dict= py_getattr_dict(PyObjectPlus::py_getattro_dict(), Type.tp_dict); + if(dict==NULL) + return NULL; + + /* normally just return this but KX_Scene has some more items */ + + PyDict_Update(dict, m_attr_dict); + return dict; +} int KX_Scene::py_setattro(PyObject *attr, PyObject *value) { @@ -1715,6 +1801,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getLightList, "Returns a list of all lights in the scene.\n" ) { + ShowDeprecationWarning("getLightList()", "the lights property"); return m_lightlist->GetProxy(); } @@ -1723,7 +1810,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getObjectList, "Returns a list of all game objects in the scene.\n" ) { - // ShowDeprecationWarning("getObjectList()", "the objects property"); // XXX Grr, why doesnt this work? + ShowDeprecationWarning("getObjectList()", "the objects property"); return m_objectlist->GetProxy(); } @@ -1732,6 +1819,7 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getName, "Returns the name of the scene.\n" ) { + ShowDeprecationWarning("getName()", "the name property"); return PyString_FromString(GetName()); } @@ -1753,5 +1841,9 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject, SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time); + + // release here because AddReplicaObject AddRef's + // the object is added to the scene so we dont want python to own a reference + replica->Release(); return replica->GetProxy(); -}
\ No newline at end of file +} diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index a06c66ec5dd..79d3f7fd828 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -32,8 +32,6 @@ #include "KX_PhysicsEngineEnums.h" -#include "MT_CmMatrix4x4.h" - #include <vector> #include <set> #include <list> @@ -43,7 +41,7 @@ #include "SG_IObject.h" #include "SCA_IScene.h" #include "MT_Transform.h" -#include "SND_Scene.h" + #include "RAS_FramingManager.h" #include "RAS_Rect.h" @@ -110,16 +108,16 @@ protected: * LogicEndFrame() via a call to RemoveObject(). */ CListValue* m_euthanasyobjects; - /** - * The list of objects that couldn't be released during logic update. - * for example, AddObject actuator sometimes releases an object that was cached from previous frame - */ - CListValue* m_delayReleaseObjects; CListValue* m_objectlist; CListValue* m_parentlist; // all 'root' parents CListValue* m_lightlist; CListValue* m_inactivelist; // all objects that are not in the active layer + + SG_QList m_sghead; // list of nodes that needs scenegraph update + // the Dlist is not object that must be updated + // the Qlist is for objects that needs to be rescheduled + // for updates after udpate is over (slow parent, bone parent) /** * The tree of objects in the scene. @@ -191,20 +189,6 @@ protected: */ KX_Camera* m_active_camera; - /** - * The projection and view matrices of this scene - * The projection matrix is computed externally by KX_Engine - * The view mat is stored as a side effect of GetViewMatrix() - * and is totally unnessary. - */ - MT_CmMatrix4x4 m_projectionmat; - MT_CmMatrix4x4 m_viewmat; - - /** Desired canvas width set at design time. */ - unsigned int m_canvasDesignWidth; - /** Desired canvas height set at design time. */ - unsigned int m_canvasDesignHeight; - /** * Another temporary variable outstaying its welcome * used in AddReplicaObject to map game objects to their @@ -318,6 +302,8 @@ public: /** * Update all transforms according to the scenegraph. */ + static bool KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene); + static bool KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene); void UpdateParents(double curtime); void DupliGroupRecurse(CValue* gameobj, int level); bool IsObjectInGroup(CValue* gameobj) @@ -335,8 +321,6 @@ public: void RemoveObject(CValue* gameobj); void DelayedRemoveObject(CValue* gameobj); - void DelayedReleaseObject(CValue* gameobj); - int NewRemoveObject(CValue* gameobj); void ReplaceMesh(CValue* gameobj, void* meshobj); @@ -422,25 +406,6 @@ public: class KX_Camera* ); - /** Return the viewmatrix as used by the last frame. */ - MT_CmMatrix4x4& - GetViewMatrix( - ); - - /** - * Return the projectionmatrix as used by the last frame. This is - * set by hand :) - */ - MT_CmMatrix4x4& - GetProjectionMatrix( - ); - - /** Sets the projection matrix. */ - void - SetProjectionMatrix( - MT_CmMatrix4x4& pmat - ); - /** * Activates new desired canvas width set at design time. * @param width The new desired width. @@ -592,14 +557,16 @@ public: /* attributes */ static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_objects(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_objects_inactive(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_lights(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_cameras(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_active_camera(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - /* for dir(), python3 uses __dir__() */ - static PyObject* pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - + static int pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); virtual PyObject* py_getattro(PyObject *attr); /* name, active_camera, gravity, suspended, viewport, framing, activity_culling, activity_culling_radius */ - virtual int py_setattro(PyObject *attr, PyObject *pyvalue); + virtual PyObject* py_getattro_dict(); + + virtual int py_setattro(PyObject *attr, PyObject *value); virtual int py_delattro(PyObject *attr); virtual PyObject* py_repr(void) { return PyString_FromString(GetName().ReadPtr()); } diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp index f54d8542260..1b790ec9824 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.cpp +++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp @@ -76,9 +76,6 @@ CValue* KX_SceneActuator::GetReplica() { KX_SceneActuator* replica = new KX_SceneActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; } @@ -226,8 +223,13 @@ KX_Scene* KX_SceneActuator::FindScene(char * sceneName) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SceneActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SceneActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -262,7 +264,7 @@ PyMethodDef KX_SceneActuator::Methods[] = //Deprecated functions ------> {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, (PY_METHODCHAR)SetUseRestart_doc}, {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, (PY_METHODCHAR)SetScene_doc}, - {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, (PY_METHODCHAR)SetCamera_doc}, + {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_O, (PY_METHODCHAR)SetCamera_doc}, {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_NOARGS, (PY_METHODCHAR)GetUseRestart_doc}, {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_NOARGS, (PY_METHODCHAR)GetScene_doc}, {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_NOARGS, (PY_METHODCHAR)GetCamera_doc}, @@ -273,6 +275,8 @@ PyMethodDef KX_SceneActuator::Methods[] = PyAttributeDef KX_SceneActuator::Attributes[] = { KX_PYATTRIBUTE_STRING_RW("scene",0,32,true,KX_SceneActuator,m_nextSceneName), KX_PYATTRIBUTE_RW_FUNCTION("camera",KX_SceneActuator,pyattr_get_camera,pyattr_set_camera), + KX_PYATTRIBUTE_BOOL_RW("useRestart", KX_SceneActuator, m_restart), + KX_PYATTRIBUTE_INT_RW("mode", KX_SCENE_NODEF+1, KX_SCENE_MAX-1, true, KX_SceneActuator, m_mode), { NULL } //Sentinel }; @@ -281,6 +285,10 @@ PyObject* KX_SceneActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_SceneActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_SceneActuator::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_IActuator); @@ -300,51 +308,21 @@ int KX_SceneActuator::pyattr_set_camera(void *self, const struct KX_PYATTRIBUTE_ KX_SceneActuator* actuator = static_cast<KX_SceneActuator*>(self); KX_Camera *camOb; - if(value==Py_None) - { - if (actuator->m_camera) - actuator->m_camera->UnregisterActuator(actuator); - + if (!ConvertPythonToCamera(value, &camOb, true, "actu.camera = value: KX_SceneActuator")) + return PY_SET_ATTR_FAIL; + + if (actuator->m_camera) + actuator->m_camera->UnregisterActuator(actuator); + + if(camOb==NULL) { actuator->m_camera= NULL; - return 0; } - - if (PyObject_TypeCheck(value, &KX_Camera::Type)) - { - KX_Camera *camOb= static_cast<KX_Camera*>BGE_PROXY_REF(value); - - if(camOb==NULL) - { - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); - return 1; - } - - if (actuator->m_camera) - actuator->m_camera->UnregisterActuator(actuator); - + else { actuator->m_camera = camOb; actuator->m_camera->RegisterActuator(actuator); - return 0; - } - - if (PyString_Check(value)) - { - char *camName = PyString_AsString(value); - - camOb = actuator->FindCamera(camName); - if (camOb) - { - if (actuator->m_camera) - actuator->m_camera->UnregisterActuator(actuator); - actuator->m_camera = camOb; - actuator->m_camera->RegisterActuator(actuator); - return 0; - } - PyErr_SetString(PyExc_TypeError, "not a valid camera name"); - return 1; } - PyErr_SetString(PyExc_TypeError, "expected a string or a camera object reference"); - return 1; + + return PY_SET_ATTR_SUCCESS; } @@ -355,7 +333,7 @@ const char KX_SceneActuator::SetUseRestart_doc[] = "\tSet flag to 1 to restart the scene.\n" ; PyObject* KX_SceneActuator::PySetUseRestart(PyObject* args) { - ShowDeprecationWarning("setUseRestart()", "(no replacement)"); + ShowDeprecationWarning("setUseRestart()", "the useRestart property"); int boolArg; if (!PyArg_ParseTuple(args, "i:setUseRestart", &boolArg)) @@ -376,7 +354,7 @@ const char KX_SceneActuator::GetUseRestart_doc[] = "\tReturn whether the scene will be restarted.\n" ; PyObject* KX_SceneActuator::PyGetUseRestart() { - ShowDeprecationWarning("getUseRestart()", "(no replacement)"); + ShowDeprecationWarning("getUseRestart()", "the useRestart property"); return PyInt_FromLong(!(m_restart == 0)); } @@ -423,47 +401,24 @@ const char KX_SceneActuator::SetCamera_doc[] = "setCamera(camera)\n" "\t- camera: string\n" "\tSet the camera to switch to.\n" ; -PyObject* KX_SceneActuator::PySetCamera(PyObject* args) +PyObject* KX_SceneActuator::PySetCamera(PyObject* value) { ShowDeprecationWarning("setCamera()", "the camera property"); - PyObject *cam; - if (PyArg_ParseTuple(args, "O!:setCamera", &KX_Camera::Type, &cam)) - { - KX_Camera *new_camera; - - new_camera = static_cast<KX_Camera*>BGE_PROXY_REF(cam); - if(new_camera==NULL) - { - PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG); - return NULL; - } - - if (m_camera) - m_camera->UnregisterActuator(this); - - m_camera= new_camera; - - m_camera->RegisterActuator(this); - Py_RETURN_NONE; - } - PyErr_Clear(); - - /* one argument: a scene, ignore the rest */ - char *camName; - if(!PyArg_ParseTuple(args, "s:setCamera", &camName)) - { + KX_Camera *camOb; + + if (!ConvertPythonToCamera(value, &camOb, true, "actu.setCamera(value): KX_SceneActuator")) return NULL; + + if (m_camera) + m_camera->UnregisterActuator(this); + + if(camOb==NULL) { + m_camera= NULL; } - - KX_Camera *camOb = FindCamera(camName); - if (camOb) - { - if (m_camera) - m_camera->UnregisterActuator(this); + else { m_camera = camOb; m_camera->RegisterActuator(this); } - Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h index 803c5106a60..2412dd02590 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.h +++ b/source/gameengine/Ketsji/KX_SceneActuator.h @@ -93,6 +93,7 @@ class KX_SceneActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); /* 1. set */ @@ -107,7 +108,7 @@ class KX_SceneActuator : public SCA_IActuator /* 5. getScene: */ KX_PYMETHOD_DOC_NOARGS(KX_SceneActuator,GetScene); /* 6. setCamera: */ - KX_PYMETHOD_DOC_VARARGS(KX_SceneActuator,SetCamera); + KX_PYMETHOD_DOC_O(KX_SceneActuator,SetCamera); /* 7. getCamera: */ KX_PYMETHOD_DOC_NOARGS(KX_SceneActuator,GetCamera); diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 412be497c5a..5c02a2db646 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -83,19 +83,19 @@ CValue* KX_SoundActuator::GetReplica() { KX_SoundActuator* replica = new KX_SoundActuator(*this); replica->ProcessReplica(); + return replica; +}; + +void KX_SoundActuator::ProcessReplica() +{ + SCA_IActuator::ProcessReplica(); if (m_soundObject) { SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject); - replica->setSoundObject(soundobj); + setSoundObject(soundobj); m_soundScene->AddObject(soundobj); } - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; -}; - - +} bool KX_SoundActuator::Update(double curtime, bool frame) { @@ -234,8 +234,13 @@ void KX_SoundActuator::setSoundObject(class SND_SoundObject* soundobject) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SoundActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_SoundActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -290,7 +295,7 @@ PyMethodDef KX_SoundActuator::Methods[] = { }; PyAttributeDef KX_SoundActuator::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("filename", KX_SoundActuator, pyattr_get_filename, pyattr_set_filename), + KX_PYATTRIBUTE_RW_FUNCTION("fileName", KX_SoundActuator, pyattr_get_filename, pyattr_set_filename), KX_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain), KX_PYATTRIBUTE_RW_FUNCTION("pitch", KX_SoundActuator, pyattr_get_pitch, pyattr_set_pitch), KX_PYATTRIBUTE_RW_FUNCTION("rollOffFactor", KX_SoundActuator, pyattr_get_rollOffFactor, pyattr_set_rollOffFactor), @@ -298,7 +303,7 @@ PyAttributeDef KX_SoundActuator::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("position", KX_SoundActuator, pyattr_get_position, pyattr_set_position), KX_PYATTRIBUTE_RW_FUNCTION("velocity", KX_SoundActuator, pyattr_get_velocity, pyattr_set_velocity), KX_PYATTRIBUTE_RW_FUNCTION("orientation", KX_SoundActuator, pyattr_get_orientation, pyattr_set_orientation), - KX_PYATTRIBUTE_ENUM_RW("type",KX_SoundActuator::KX_SOUNDACT_NODEF+1,KX_SoundActuator::KX_SOUNDACT_MAX-1,false,KX_SoundActuator,m_type), + KX_PYATTRIBUTE_ENUM_RW("mode",KX_SoundActuator::KX_SOUNDACT_NODEF+1,KX_SoundActuator::KX_SOUNDACT_MAX-1,false,KX_SoundActuator,m_type), { NULL } //Sentinel }; @@ -340,6 +345,10 @@ PyObject* KX_SoundActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_SoundActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_SoundActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); } @@ -355,7 +364,7 @@ PyObject* KX_SoundActuator::pyattr_get_filename(void *self, const struct KX_PYAT char* name = objectname.Ptr(); if (!name) { - PyErr_SetString(PyExc_RuntimeError, "value = actuator.filename: KX_SoundActuator, unable to get sound filename"); + PyErr_SetString(PyExc_RuntimeError, "value = actuator.fileName: KX_SoundActuator, unable to get sound fileName"); return NULL; } else return PyString_FromString(name); @@ -441,13 +450,13 @@ int KX_SoundActuator::pyattr_set_filename(void *self, const struct KX_PYATTRIBUT // void *soundPointer = NULL; /*unused*/ if (!PyArg_Parse(value, "s", &soundName)) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) { actuator->m_soundObject->SetObjectName(soundName); } - return 0; + return PY_SET_ATTR_SUCCESS; } @@ -456,12 +465,12 @@ int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DE float gain = 1.0; KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); if (!PyArg_Parse(value, "f", &gain)) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) actuator->m_soundObject->SetGain(gain); - return 0; + return PY_SET_ATTR_SUCCESS; } int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -469,12 +478,12 @@ int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_D float pitch = 1.0; KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); if (!PyArg_Parse(value, "f", &pitch)) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) actuator->m_soundObject->SetPitch(pitch); - return 0; + return PY_SET_ATTR_SUCCESS; } int KX_SoundActuator::pyattr_set_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -482,12 +491,12 @@ int KX_SoundActuator::pyattr_set_rollOffFactor(void *self, const struct KX_PYATT KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); float rollofffactor = 1.0; if (!PyArg_Parse(value, "f", &rollofffactor)) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) actuator->m_soundObject->SetRollOffFactor(rollofffactor); - return 0; + return PY_SET_ATTR_SUCCESS; } int KX_SoundActuator::pyattr_set_looping(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -495,12 +504,12 @@ int KX_SoundActuator::pyattr_set_looping(void *self, const struct KX_PYATTRIBUTE KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); int looping = 1; if (!PyArg_Parse(value, "i", &looping)) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) actuator->m_soundObject->SetLoopMode(looping); - return 0; + return PY_SET_ATTR_SUCCESS; } int KX_SoundActuator::pyattr_set_position(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -510,12 +519,12 @@ int KX_SoundActuator::pyattr_set_position(void *self, const struct KX_PYATTRIBUT KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); if (!PyArg_ParseTuple(value, "fff", &pos[0], &pos[1], &pos[2])) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) actuator->m_soundObject->SetPosition(MT_Vector3(pos)); - return 0; + return PY_SET_ATTR_SUCCESS; } int KX_SoundActuator::pyattr_set_velocity(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -525,12 +534,12 @@ int KX_SoundActuator::pyattr_set_velocity(void *self, const struct KX_PYATTRIBUT if (!PyArg_ParseTuple(value, "fff", &vel[0], &vel[1], &vel[2])) - return 1; + return PY_SET_ATTR_FAIL; if (actuator->m_soundObject) actuator->m_soundObject->SetVelocity(MT_Vector3(vel)); - return 0; + return PY_SET_ATTR_SUCCESS; } @@ -542,21 +551,22 @@ int KX_SoundActuator::pyattr_set_orientation(void *self, const struct KX_PYATTRI /* if value is not a sequence PyOrientationTo makes an error */ if (!PyOrientationTo(value, rot, "actuator.orientation = value: KX_SoundActuator")) - return NULL; + return PY_SET_ATTR_FAIL; + /* Since not having m_soundObject didn't do anything in the old version, + * it probably should be kept that way */ if (!actuator->m_soundObject) - return 0; /* Since not having m_soundObject didn't do anything in the old version, - * it probably should be kept that way */ + return PY_SET_ATTR_SUCCESS; actuator->m_soundObject->SetOrientation(rot); - return 0; + return PY_SET_ATTR_SUCCESS; } // Deprecated -----> PyObject* KX_SoundActuator::PySetFilename(PyObject* args) { char *soundName = NULL; - ShowDeprecationWarning("setFilename()", "the filename property"); + ShowDeprecationWarning("setFilename()", "the fileName property"); // void *soundPointer = NULL; /*unused*/ if (!PyArg_ParseTuple(args, "s", &soundName)) @@ -567,7 +577,7 @@ PyObject* KX_SoundActuator::PySetFilename(PyObject* args) PyObject* KX_SoundActuator::PyGetFilename() { - ShowDeprecationWarning("getFilename()", "the filename property"); + ShowDeprecationWarning("getFilename()", "the fileName property"); if (!m_soundObject) { return PyString_FromString(""); @@ -576,7 +586,7 @@ PyObject* KX_SoundActuator::PyGetFilename() char* name = objectname.Ptr(); if (!name) { - PyErr_SetString(PyExc_RuntimeError, "Unable to get sound filename"); + PyErr_SetString(PyExc_RuntimeError, "Unable to get sound fileName"); return NULL; } else return PyString_FromString(name); @@ -750,7 +760,7 @@ PyObject* KX_SoundActuator::PySetOrientation(PyObject* args) PyObject* KX_SoundActuator::PySetType(PyObject* args) { int typeArg; - ShowDeprecationWarning("setType()", "the type property"); + ShowDeprecationWarning("setType()", "the mode property"); if (!PyArg_ParseTuple(args, "i:setType", &typeArg)) { return NULL; @@ -766,7 +776,7 @@ PyObject* KX_SoundActuator::PySetType(PyObject* args) PyObject* KX_SoundActuator::PyGetType() { - ShowDeprecationWarning("getType()", "the type property"); + ShowDeprecationWarning("getType()", "the mode property"); return PyInt_FromLong(m_type); } // <----- diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h index d5e678bbecd..a7491355667 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.h +++ b/source/gameengine/Ketsji/KX_SoundActuator.h @@ -75,12 +75,14 @@ public: virtual bool Update(double curtime, bool frame); CValue* GetReplica(); + void ProcessReplica(); /* -------------------------------------------------------------------- */ /* Python interface --------------------------------------------------- */ /* -------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, startSound); diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp index 976e7ea5204..f6979eee0f4 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.cpp +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -55,6 +55,9 @@ KX_StateActuator::~KX_StateActuator( // intentionally empty } +// used to put state actuator to be executed before any other actuators +SG_QList KX_StateActuator::m_stateActuatorHead; + CValue* KX_StateActuator::GetReplica( void @@ -62,8 +65,6 @@ KX_StateActuator::GetReplica( { KX_StateActuator* replica = new KX_StateActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -72,7 +73,10 @@ KX_StateActuator::Update() { bool bNegativeEvent = IsNegativeEvent(); unsigned int objMask; - + + // execution of state actuator means that we are in the execution phase, reset this pointer + // because all the active actuator of this object will be removed for sure. + m_gameobj->m_firstState = NULL; RemoveAllEvents(); if (bNegativeEvent) return false; @@ -101,6 +105,31 @@ KX_StateActuator::Update() return false; } +// this function is only used to deactivate actuators outside the logic loop +// e.g. when an object is deleted. +void KX_StateActuator::Deactivate() +{ + if (QDelink()) + { + // the actuator was in the active list + if (m_stateActuatorHead.QEmpty()) + // no more state object active + m_stateActuatorHead.Delink(); + } +} + +void KX_StateActuator::Activate(SG_DList& head) +{ + // sort the state actuators per object on the global list + if (QEmpty()) + { + InsertSelfActiveQList(m_stateActuatorHead, &m_gameobj->m_firstState); + // add front to make sure it runs before other actuators + head.AddFront(&m_stateActuatorHead); + } +} + + /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ @@ -109,8 +138,13 @@ KX_StateActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_StateActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_StateActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -156,7 +190,11 @@ PyAttributeDef KX_StateActuator::Attributes[] = { PyObject* KX_StateActuator::py_getattro(PyObject *attr) { py_getattro_up(SCA_IActuator); -}; +} + +PyObject* KX_StateActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} int KX_StateActuator::py_setattro(PyObject *attr, PyObject* value) { diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h index 4a64894259d..a4191a4c5fd 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.h +++ b/source/gameengine/Ketsji/KX_StateActuator.h @@ -33,6 +33,13 @@ #include "SCA_IActuator.h" + +/* + * Use of SG_DList : element of actuator being deactivated + * Head: SCA_LogicManager::m_removedActuators + * Use of SG_QList : element of global activated state actuator list + * Head: KX_StateActuator::m_stateActuatorHead + */ class KX_StateActuator : public SCA_IActuator { Py_Header; @@ -46,6 +53,11 @@ class KX_StateActuator : public SCA_IActuator OP_NEG, OP_COUNT }; + // SG_Dlist: element of objects with active actuators, always put in front of the list + // Head: SCA_LogicManager::m_activeActuators + // SG_QList: Head of active state actuators list globally + // Elements: KX_StateActuator + static SG_QList m_stateActuatorHead; int m_operation; int m_mask; @@ -71,11 +83,15 @@ class KX_StateActuator : public SCA_IActuator virtual bool Update(); + virtual void Deactivate(); + virtual void Activate(SG_DList& head); + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); //KX_PYMETHOD_DOC KX_PYMETHOD_DOC_VARARGS(KX_StateActuator,SetOperation); diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.h b/source/gameengine/Ketsji/KX_SumoPhysicsController.h index 083d89896f6..278994c6ae7 100644 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.h +++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.h @@ -53,7 +53,7 @@ public: class SM_Object* sumoObj, class PHY_IMotionState* motionstate ,bool dyna) - : KX_IPhysicsController(dyna,false,NULL) , + : KX_IPhysicsController(dyna,false,false,NULL) , SumoPhysicsController(sumoScene,/*solidscene,*/sumoObj,motionstate,dyna) { }; @@ -83,6 +83,7 @@ public: virtual void getOrientation(MT_Quaternion& orn); virtual void setOrientation(const MT_Matrix3x3& orn); + virtual void SetTransform() {} virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 48d4cf59a2b..712a512995e 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -85,14 +85,35 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, PHY_IPhysicsController* ctrl = static_cast<PHY_IPhysicsController*>(object1); KX_ClientObjectInfo* info = (ctrl) ? static_cast<KX_ClientObjectInfo*>(ctrl->getNewClientInfo()) : NULL; // This call back should only be called for controllers of Near and Radar sensor - if (info && - info->m_sensors.size() == 1 && - (info->m_type == KX_ClientObjectInfo::NEAR || - info->m_type == KX_ClientObjectInfo::RADAR)) + if (!info) + return true; + + switch (info->m_type) { - // only one sensor for this type of object - KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin()); - return touchsensor->BroadPhaseFilterCollision(object1,object2); + case KX_ClientObjectInfo::SENSOR: + if (info->m_sensors.size() == 1) + { + // only one sensor for this type of object + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin()); + return touchsensor->BroadPhaseFilterCollision(object1,object2); + } + break; + case KX_ClientObjectInfo::OBSENSOR: + case KX_ClientObjectInfo::OBACTORSENSOR: + // this object may have multiple collision sensors, + // check is any of them is interested in this object + for(std::list<SCA_ISensor*>::iterator it = info->m_sensors.begin(); + it != info->m_sensors.end(); + ++it) + { + if ((*it)->GetSensorType() == SCA_ISensor::ST_TOUCH) + { + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*it); + if (touchsensor->BroadPhaseSensorFilterCollision(object1, object2)) + return true; + } + } + return false; } return true; } @@ -100,7 +121,7 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); - if (m_sensors.insert(touchsensor).second) + if (m_sensors.AddBack(touchsensor)) // the sensor was effectively inserted, register it touchsensor->RegisterSumo(this); } @@ -108,7 +129,7 @@ void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); - if (m_sensors.erase(touchsensor)) + if (touchsensor->Delink()) // the sensor was effectively removed, unregister it touchsensor->UnregisterSumo(this); } @@ -117,12 +138,10 @@ void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) void KX_TouchEventManager::EndFrame() { - set<SCA_ISensor*>::iterator it; - for ( it = m_sensors.begin(); - !(it==m_sensors.end());it++) + SG_DList::iterator<KX_TouchSensor> it(m_sensors); + for (it.begin();!it.end();++it) { - ((KX_TouchSensor*)*it)->EndFrame(); - + (*it)->EndFrame(); } } @@ -130,12 +149,11 @@ void KX_TouchEventManager::EndFrame() void KX_TouchEventManager::NextFrame() { - if (m_sensors.size() > 0) + if (!m_sensors.Empty()) { - set<SCA_ISensor*>::iterator it; - - for (it = m_sensors.begin();!(it==m_sensors.end());++it) - static_cast<KX_TouchSensor*>(*it)->SynchronizeTransform(); + SG_DList::iterator<KX_TouchSensor> it(m_sensors); + for (it.begin();!it.end();++it) + (*it)->SynchronizeTransform(); for (std::set<NewCollision>::iterator cit = m_newCollisions.begin(); cit != m_newCollisions.end(); ++cit) { @@ -161,7 +179,7 @@ void KX_TouchEventManager::NextFrame() m_newCollisions.clear(); - for (it = m_sensors.begin();!(it==m_sensors.end());++it) - (*it)->Activate(m_logicmgr,NULL); + for (it.begin();!it.end();++it) + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index 5a6e8e6f501..c06acd4a873 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -66,10 +66,10 @@ void KX_TouchSensor::UnregisterToManager() { // before unregistering the sensor, make sure we release all references EndFrame(); - m_eventmgr->RemoveSensor(this); + SCA_ISensor::UnregisterToManager(); } -bool KX_TouchSensor::Evaluate(CValue* event) +bool KX_TouchSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; @@ -142,13 +142,17 @@ KX_TouchSensor::~KX_TouchSensor() CValue* KX_TouchSensor::GetReplica() { KX_TouchSensor* replica = new KX_TouchSensor(*this); - replica->m_colliders = new CListValue(); - replica->Init(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } +void KX_TouchSensor::ProcessReplica() +{ + SCA_ISensor::ProcessReplica(); + m_colliders = new CListValue(); + Init(); +} + void KX_TouchSensor::ReParent(SCA_IObject* parent) { KX_GameObject *gameobj = static_cast<KX_GameObject *>(parent); @@ -169,21 +173,69 @@ void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman) { if (m_physCtrl) { - touchman->GetPhysicsEnvironment()->requestCollisionCallback(m_physCtrl); - // collision - // Deprecated - + if (touchman->GetPhysicsEnvironment()->requestCollisionCallback(m_physCtrl)) + { + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo()); + if (client_info->isSensor()) + touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl); + } } } - void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman) { if (m_physCtrl) { - touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl); + if (touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl)) + { + // no more sensor on the controller, can remove it if it is a sensor object + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo()); + if (client_info->isSensor()) + touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl); + } } } +// this function is called only for sensor objects +// return true if the controller can collide with the object +bool KX_TouchSensor::BroadPhaseSensorFilterCollision(void*obj1,void*obj2) +{ + assert(obj1==m_physCtrl && obj2); + + KX_GameObject* myobj = (KX_GameObject*)GetParent(); + KX_GameObject* myparent = myobj->GetParent(); + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(((PHY_IPhysicsController*)obj2)->getNewClientInfo()); + KX_ClientObjectInfo* my_client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo()); + KX_GameObject* otherobj = ( client_info ? client_info->m_gameobject : NULL); + + // first, decrement refcount as GetParent() increases it + if (myparent) + myparent->Release(); + + // we can only check on persistent characteristic: m_link and m_suspended are not + // good candidate because they are transient. That must be handled at another level + if (!otherobj || + otherobj == myparent || // don't interact with our parent + (my_client_info->m_type == KX_ClientObjectInfo::OBACTORSENSOR && + client_info->m_type != KX_ClientObjectInfo::ACTOR)) // only with actor objects + return false; + + bool found = m_touchedpropname.IsEmpty(); + if (!found) + { + if (m_bFindMaterial) + { + if (client_info->m_auxilary_info) + { + found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info)); + } + } else + { + found = (otherobj->GetProperty(m_touchedpropname) != NULL); + } + } + return found; +} + bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata) { // KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr; @@ -242,8 +294,13 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll /* ------------------------------------------------------------------------- */ /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_TouchSensor::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_TouchSensor", sizeof(PyObjectPlus_Proxy), 0, @@ -283,11 +340,11 @@ PyMethodDef KX_TouchSensor::Methods[] = { }; PyAttributeDef KX_TouchSensor::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("property",0,100,false,KX_TouchSensor,m_touchedpropname), + KX_PYATTRIBUTE_STRING_RW("propName",0,100,false,KX_TouchSensor,m_touchedpropname), KX_PYATTRIBUTE_BOOL_RW("useMaterial",KX_TouchSensor,m_bFindMaterial), - KX_PYATTRIBUTE_BOOL_RW("pulseCollisions",KX_TouchSensor,m_bTouchPulse), - KX_PYATTRIBUTE_RO_FUNCTION("objectHit", KX_TouchSensor, pyattr_get_object_hit), - KX_PYATTRIBUTE_RO_FUNCTION("objectHitList", KX_TouchSensor, pyattr_get_object_hit_list), + KX_PYATTRIBUTE_BOOL_RW("usePulseCollision",KX_TouchSensor,m_bTouchPulse), + KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_TouchSensor, pyattr_get_object_hit), + KX_PYATTRIBUTE_RO_FUNCTION("hitObjectList", KX_TouchSensor, pyattr_get_object_hit_list), { NULL } //Sentinel }; @@ -296,6 +353,10 @@ PyObject* KX_TouchSensor::py_getattro(PyObject *attr) py_getattro_up(SCA_ISensor); } +PyObject* KX_TouchSensor::py_getattro_dict() { + py_getattro_dict_up(SCA_ISensor); +} + int KX_TouchSensor::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_ISensor); @@ -312,7 +373,7 @@ const char KX_TouchSensor::SetProperty_doc[] = "\tmaterials."; PyObject* KX_TouchSensor::PySetProperty(PyObject* value) { - ShowDeprecationWarning("setProperty()", "the propertyName property"); + ShowDeprecationWarning("setProperty()", "the propName property"); char *nameArg= PyString_AsString(value); if (nameArg==NULL) { PyErr_SetString(PyExc_ValueError, "expected a "); @@ -329,6 +390,8 @@ const char KX_TouchSensor::GetProperty_doc[] = "\tgetTouchMaterial() to find out whether this sensor\n" "\tlooks for properties or materials."; PyObject* KX_TouchSensor::PyGetProperty() { + ShowDeprecationWarning("getProperty()", "the propName property"); + return PyString_FromString(m_touchedpropname); } @@ -337,7 +400,7 @@ const char KX_TouchSensor::GetHitObject_doc[] = ; PyObject* KX_TouchSensor::PyGetHitObject() { - ShowDeprecationWarning("getHitObject()", "the objectHit property"); + ShowDeprecationWarning("getHitObject()", "the hitObject property"); /* to do: do Py_IncRef if the object is already known in Python */ /* otherwise, this leaks memory */ if (m_hitObject) @@ -353,7 +416,7 @@ const char KX_TouchSensor::GetHitObjectList_doc[] = "\tbut only those matching the property/material condition.\n"; PyObject* KX_TouchSensor::PyGetHitObjectList() { - ShowDeprecationWarning("getHitObjectList()", "the objectHitList property"); + ShowDeprecationWarning("getHitObjectList()", "the hitObjectList property"); /* to do: do Py_IncRef if the object is already known in Python */ /* otherwise, this leaks memory */ /* Edit, this seems ok and not to leak memory - Campbell */ return m_colliders->GetProxy(); diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index 15ef653c1b2..476c63e89db 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -84,8 +84,9 @@ public: virtual ~KX_TouchSensor(); virtual CValue* GetReplica(); + virtual void ProcessReplica(); virtual void SynchronizeTransform(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual void Init(); virtual void ReParent(SCA_IObject* parent); @@ -102,7 +103,8 @@ public: // obj1 = sensor physical controller, obj2 = physical controller of second object // return value = true if collision should be checked on pair of object virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2) { return true; } - + virtual bool BroadPhaseSensorFilterCollision(void*obj1,void*obj2); + virtual sensortype GetSensorType() { return ST_TOUCH; } virtual bool IsPositiveTrigger() { @@ -121,6 +123,7 @@ public: /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); //Deprecated -----> diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index fbf43de6cf4..5a50d0fb944 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -83,6 +83,10 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, // if so, store the initial local rotation // this is needed to revert the effect of the parent inverse node (TBC) m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation(); + // use registration mechanism rather than AddRef, it creates zombie objects + m_parentobj->RegisterActuator(this); + // GetParent did AddRef, undo here + m_parentobj->Release(); } } } @@ -189,7 +193,7 @@ KX_TrackToActuator::~KX_TrackToActuator() if (m_object) m_object->UnregisterActuator(this); if (m_parentobj) - m_parentobj->Release(); + m_parentobj->UnregisterActuator(this); } /* end of destructor */ void KX_TrackToActuator::ProcessReplica() @@ -198,7 +202,7 @@ void KX_TrackToActuator::ProcessReplica() if (m_object) m_object->RegisterActuator(this); if (m_parentobj) - m_parentobj->AddRef(); + m_parentobj->RegisterActuator(this); SCA_IActuator::ProcessReplica(); } @@ -211,6 +215,11 @@ bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj) m_object = NULL; return true; } + if (clientobj == m_parentobj) + { + m_parentobj = NULL; + return true; + } return false; } @@ -227,9 +236,9 @@ void KX_TrackToActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) void **h_parobj = (*obj_map)[m_parentobj]; if (h_parobj) { if (m_parentobj) - m_parentobj->Release(); + m_parentobj->UnregisterActuator(this); m_parentobj= (KX_GameObject*)(*h_parobj); - m_parentobj->AddRef(); + m_parentobj->RegisterActuator(this); } } @@ -425,8 +434,13 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_TrackToActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_TrackToActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -490,7 +504,7 @@ int KX_TrackToActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUT KX_GameObject *gameobj; if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_TrackToActuator")) - return 1; // ConvertPythonToGameObject sets the error + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error if (actuator->m_object != NULL) actuator->m_object->UnregisterActuator(actuator); @@ -500,7 +514,7 @@ int KX_TrackToActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUT if (actuator->m_object) actuator->m_object->RegisterActuator(actuator); - return 0; + return PY_SET_ATTR_SUCCESS; } @@ -509,6 +523,10 @@ PyObject* KX_TrackToActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_TrackToActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_TrackToActuator::py_setattro(PyObject *attr, PyObject* value) { py_setattro_up(SCA_IActuator); diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h index 99505f93cfe..c4cc2b1f062 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.h +++ b/source/gameengine/Ketsji/KX_TrackToActuator.h @@ -61,8 +61,6 @@ class KX_TrackToActuator : public SCA_IActuator virtual CValue* GetReplica() { KX_TrackToActuator* replica = new KX_TrackToActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -73,6 +71,7 @@ class KX_TrackToActuator : public SCA_IActuator /* Python part */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject* value); /* These are used to get and set m_ob */ diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index 1a6fb196db5..8146d04a878 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -273,8 +273,13 @@ PyObject* KX_VehicleWrapper::PyGetConstraintType(PyObject* args) //python specific stuff PyTypeObject KX_VehicleWrapper::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_VehicleWrapper", sizeof(PyObjectPlus_Proxy), 0, @@ -303,32 +308,13 @@ PyObject* KX_VehicleWrapper::py_getattro(PyObject *attr) py_getattro_up(PyObjectPlus); } -int KX_VehicleWrapper::py_setattro(PyObject *attr,PyObject* pyobj) -{ - /* TODO - strange setattr, needs updating */ - PyTypeObject* type = pyobj->ob_type; - int result = 1; - - if (type == &PyList_Type) - { - result = 0; - } - if (type == &PyFloat_Type) - { - result = 0; +PyObject* KX_VehicleWrapper::py_getattro_dict() { + py_getattro_dict_up(PyObjectPlus); +} - } - if (type == &PyInt_Type) - { - result = 0; - } - if (type == &PyString_Type) - { - result = 0; - } - if (result) - result = PyObjectPlus::py_setattro(attr,pyobj); - return result; +int KX_VehicleWrapper::py_setattro(PyObject *attr,PyObject* value) +{ + py_setattro_up(PyObjectPlus); }; diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.h b/source/gameengine/Ketsji/KX_VehicleWrapper.h index de7fe75cfba..c2b5e3d9251 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.h +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.h @@ -13,6 +13,7 @@ class KX_VehicleWrapper : public PyObjectPlus { Py_Header; virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); std::vector<PHY_IMotionState*> m_motionStates; diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp index 88f63334285..4b0ad083473 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.cpp +++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp @@ -37,8 +37,13 @@ #include "KX_PyMath.h" PyTypeObject KX_VertexProxy::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_VertexProxy", sizeof(PyObjectPlus_Proxy), 0, @@ -57,8 +62,8 @@ PyTypeObject KX_VertexProxy::Type = { PyParentObject KX_VertexProxy::Parents[] = { &KX_VertexProxy::Type, - &SCA_IObject::Type, &CValue::Type, + &PyObjectPlus::Type, NULL }; @@ -79,6 +84,7 @@ PyMethodDef KX_VertexProxy::Methods[] = { }; PyAttributeDef KX_VertexProxy::Attributes[] = { + //KX_PYATTRIBUTE_TODO("DummyProps"), KX_PYATTRIBUTE_DUMMY("x"), KX_PYATTRIBUTE_DUMMY("y"), @@ -156,7 +162,11 @@ KX_VertexProxy::py_getattro(PyObject *attr) return PyObjectFrom(MT_Vector3(m_vertex->getNormal())); } - py_getattro_up(SCA_IObject); + py_getattro_up(CValue); +} + +PyObject* KX_VertexProxy::py_getattro_dict() { + py_getattro_dict_up(CValue); } int KX_VertexProxy::py_setattro(PyObject *attr, PyObject *pyvalue) @@ -312,7 +322,7 @@ int KX_VertexProxy::py_setattro(PyObject *attr, PyObject *pyvalue) } } - return SCA_IObject::py_setattro(attr, pyvalue); + return CValue::py_setattro(attr, pyvalue); } KX_VertexProxy::KX_VertexProxy(KX_MeshProxy*mesh, RAS_TexVert* vertex) @@ -333,11 +343,9 @@ CValue* KX_VertexProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { STR_String sVertexName="vertex"; const STR_String & KX_VertexProxy::GetText() {return sVertexName;}; double KX_VertexProxy::GetNumber() { return -1;} -STR_String KX_VertexProxy::GetName() { return sVertexName;} -void KX_VertexProxy::SetName(STR_String) { }; +STR_String& KX_VertexProxy::GetName() { return sVertexName;} +void KX_VertexProxy::SetName(const char *) { }; CValue* KX_VertexProxy::GetReplica() { return NULL;} -void KX_VertexProxy::ReplicaSetName(STR_String) {}; - // stuff for python integration @@ -427,9 +435,10 @@ PyObject* KX_VertexProxy::PyGetUV2() PyObject* KX_VertexProxy::PySetUV2(PyObject* args) { MT_Point2 vec; - unsigned int unit=0; + unsigned int unit= RAS_TexVert::SECOND_UV; + PyObject* list= NULL; - if(!PyArg_ParseTuple(args, "Oi:setUV2", &list, &unit)) + if(!PyArg_ParseTuple(args, "O|i:setUV2", &list, &unit)) return NULL; if (!PyVecTo(list, vec)) diff --git a/source/gameengine/Ketsji/KX_VertexProxy.h b/source/gameengine/Ketsji/KX_VertexProxy.h index 67a15d96768..42db5fbc322 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.h +++ b/source/gameengine/Ketsji/KX_VertexProxy.h @@ -31,7 +31,7 @@ #include "SCA_IObject.h" -class KX_VertexProxy : public SCA_IObject +class KX_VertexProxy : public CValue { Py_Header; protected: @@ -47,14 +47,14 @@ public: CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); const STR_String & GetText(); double GetNumber(); - STR_String GetName(); - void SetName(STR_String name); // Set the name of the value - void ReplicaSetName(STR_String name); + STR_String& GetName(); + void SetName(const char *name); // Set the name of the value CValue* GetReplica(); // stuff for python integration virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *pyvalue); KX_PYMETHOD_NOARGS(KX_VertexProxy,GetXYZ); diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp index ba59d0d3d47..d848065ad73 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp @@ -64,8 +64,6 @@ KX_VisibilityActuator::GetReplica( { KX_VisibilityActuator* replica = new KX_VisibilityActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -94,8 +92,13 @@ KX_VisibilityActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_VisibilityActuator::Type = { - PyObject_HEAD_INIT(NULL) - 0, +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif "KX_VisibilityActuator", sizeof(PyObjectPlus_Proxy), 0, @@ -133,8 +136,8 @@ KX_VisibilityActuator::Methods[] = { PyAttributeDef KX_VisibilityActuator::Attributes[] = { KX_PYATTRIBUTE_BOOL_RW("visibility", KX_VisibilityActuator, m_visible), - KX_PYATTRIBUTE_BOOL_RW("occlusion", KX_VisibilityActuator, m_occlusion), - KX_PYATTRIBUTE_BOOL_RW("recursion", KX_VisibilityActuator, m_recursive), + KX_PYATTRIBUTE_BOOL_RW("useOcclusion", KX_VisibilityActuator, m_occlusion), + KX_PYATTRIBUTE_BOOL_RW("useRecursion", KX_VisibilityActuator, m_recursive), { NULL } //Sentinel }; @@ -143,6 +146,10 @@ PyObject* KX_VisibilityActuator::py_getattro(PyObject *attr) py_getattro_up(SCA_IActuator); } +PyObject* KX_VisibilityActuator::py_getattro_dict() { + py_getattro_dict_up(SCA_IActuator); +} + int KX_VisibilityActuator::py_setattro(PyObject *attr, PyObject *value) { py_setattro_up(SCA_IActuator); diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.h b/source/gameengine/Ketsji/KX_VisibilityActuator.h index 04633bce665..45aba50f645 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.h +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.h @@ -70,6 +70,7 @@ class KX_VisibilityActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ virtual PyObject* py_getattro(PyObject *attr); + virtual PyObject* py_getattro_dict(); virtual int py_setattro(PyObject *attr, PyObject *value); // Deprecated -----> diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 921aba9c11f..5ab15c9eab3 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -8,25 +8,28 @@ defs = '' # XXX 2.5 # Mathutils C files. -#sources.extend([\ -# '#source/blender/python/api2_2x/Mathutils.c',\ -# '#source/blender/python/api2_2x/constant.c',\ -# '#source/blender/python/api2_2x/euler.c',\ -# '#source/blender/python/api2_2x/gen_utils.c',\ -# '#source/blender/python/api2_2x/matrix.c',\ -# '#source/blender/python/api2_2x/point.c',\ -# '#source/blender/python/api2_2x/quat.c',\ -# '#source/blender/python/api2_2x/vector.c',\ -#]) -# -#sources.extend([\ -# '#source/blender/python/api2_2x/bpy_internal_import.c' -#]) -# -# -#sources.extend([\ -# '#source/blender/python/api2_2x/BGL.c' -#]) +""" +if not env['BF_PYTHON_VERSION'].startswith('3'): + # TODO - py3 support + sources.extend([\ + '#source/blender/python/api2_2x/Mathutils.c',\ + '#source/blender/python/api2_2x/Geometry.c',\ + '#source/blender/python/api2_2x/euler.c',\ + '#source/blender/python/api2_2x/matrix.c',\ + '#source/blender/python/api2_2x/quat.c',\ + '#source/blender/python/api2_2x/vector.c',\ + '#source/blender/python/api2_2x/constant.c',\ + ]) + + sources.extend([\ + '#source/blender/python/api2_2x/BGL.c' + ]) + +sources.extend([\ + '#source/blender/python/api2_2x/bpy_internal_import.c' +]) +""" + incs = '. #source/blender/python/api2_2x' # Only for Mathutils! and bpy_internal_import.h, be very careful |