Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 * Game object wrapper 00027 */ 00028 00034 #if defined(_WIN64) 00035 typedef unsigned __int64 uint_ptr; 00036 #else 00037 typedef unsigned long uint_ptr; 00038 #endif 00039 00040 #if defined(WIN32) && !defined(FREE_WINDOWS) 00041 // This warning tells us about truncation of __long__ stl-generated names. 00042 // It can occasionally cause DevStudio to have internal compiler warnings. 00043 #pragma warning( disable : 4786 ) 00044 #endif 00045 00046 00047 #define KX_INERTIA_INFINITE 10000 00048 #include "RAS_IPolygonMaterial.h" 00049 #include "KX_BlenderMaterial.h" 00050 #include "KX_GameObject.h" 00051 #include "KX_Camera.h" // only for their ::Type 00052 #include "KX_Light.h" // only for their ::Type 00053 #include "KX_FontObject.h" // only for their ::Type 00054 #include "RAS_MeshObject.h" 00055 #include "KX_MeshProxy.h" 00056 #include "KX_PolyProxy.h" 00057 #include <stdio.h> // printf 00058 #include "SG_Controller.h" 00059 #include "KX_IPhysicsController.h" 00060 #include "PHY_IGraphicController.h" 00061 #include "SG_Node.h" 00062 #include "SG_Controller.h" 00063 #include "KX_ClientObjectInfo.h" 00064 #include "RAS_BucketManager.h" 00065 #include "KX_RayCast.h" 00066 #include "KX_PythonInit.h" 00067 #include "KX_PyMath.h" 00068 #include "KX_PythonSeq.h" 00069 #include "KX_ConvertPhysicsObject.h" 00070 #include "SCA_IActuator.h" 00071 #include "SCA_ISensor.h" 00072 #include "SCA_IController.h" 00073 #include "NG_NetworkScene.h" //Needed for sendMessage() 00074 #include "KX_ObstacleSimulation.h" 00075 00076 #include "BL_ActionManager.h" 00077 00078 #include "PyObjectPlus.h" /* python stuff */ 00079 00080 // This file defines relationships between parents and children 00081 // in the game engine. 00082 00083 #include "KX_SG_NodeRelationships.h" 00084 00085 #include "BLI_math.h" 00086 00087 static MT_Point3 dummy_point= MT_Point3(0.0, 0.0, 0.0); 00088 static MT_Vector3 dummy_scaling = MT_Vector3(1.0, 1.0, 1.0); 00089 static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3(1.0, 0.0, 0.0, 00090 0.0, 1.0, 0.0, 00091 0.0, 0.0, 1.0); 00092 00093 KX_GameObject::KX_GameObject( 00094 void* sgReplicationInfo, 00095 SG_Callbacks callbacks) 00096 : SCA_IObject(), 00097 m_bDyna(false), 00098 m_layer(0), 00099 m_pBlenderObject(NULL), 00100 m_pBlenderGroupObject(NULL), 00101 m_bSuspendDynamics(false), 00102 m_bUseObjectColor(false), 00103 m_bIsNegativeScaling(false), 00104 m_bVisible(true), 00105 m_bCulled(true), 00106 m_bOccluder(false), 00107 m_pPhysicsController1(NULL), 00108 m_pGraphicController(NULL), 00109 m_xray(false), 00110 m_pHitObject(NULL), 00111 m_pObstacleSimulation(NULL), 00112 m_actionManager(NULL), 00113 m_isDeformable(false) 00114 #ifdef WITH_PYTHON 00115 , m_attr_dict(NULL) 00116 #endif 00117 { 00118 m_ignore_activity_culling = false; 00119 m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR); 00120 m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks); 00121 00122 // define the relationship between this node and it's parent. 00123 00124 KX_NormalParentRelation * parent_relation = 00125 KX_NormalParentRelation::New(); 00126 m_pSGNode->SetParentRelation(parent_relation); 00127 }; 00128 00129 00130 00131 KX_GameObject::~KX_GameObject() 00132 { 00133 RemoveMeshes(); 00134 00135 // is this delete somewhere ? 00136 //if (m_sumoObj) 00137 // delete m_sumoObj; 00138 delete m_pClient_info; 00139 //if (m_pSGNode) 00140 // delete m_pSGNode; 00141 if (m_pSGNode) 00142 { 00143 // must go through controllers and make sure they will not use us anymore 00144 // This is important for KX_BulletPhysicsControllers that unregister themselves 00145 // from the object when they are deleted. 00146 SGControllerList::iterator contit; 00147 SGControllerList& controllers = m_pSGNode->GetSGControllerList(); 00148 for (contit = controllers.begin();contit!=controllers.end();++contit) 00149 { 00150 (*contit)->ClearObject(); 00151 } 00152 m_pSGNode->SetSGClientObject(NULL); 00153 00154 /* m_pSGNode is freed in KX_Scene::RemoveNodeDestructObject */ 00155 } 00156 if (m_pGraphicController) 00157 { 00158 delete m_pGraphicController; 00159 } 00160 00161 if (m_pObstacleSimulation) 00162 { 00163 m_pObstacleSimulation->DestroyObstacleForObj(this); 00164 } 00165 00166 if (m_actionManager) 00167 { 00168 KX_GetActiveScene()->RemoveAnimatedObject(this); 00169 delete m_actionManager; 00170 } 00171 #ifdef WITH_PYTHON 00172 if (m_attr_dict) { 00173 PyDict_Clear(m_attr_dict); /* incase of circular refs or other weird cases */ 00174 /* Py_CLEAR: Py_DECREF's and NULL's */ 00175 Py_CLEAR(m_attr_dict); 00176 } 00177 #endif // WITH_PYTHON 00178 } 00179 00180 KX_GameObject* KX_GameObject::GetClientObject(KX_ClientObjectInfo* info) 00181 { 00182 if (!info) 00183 return NULL; 00184 return info->m_gameobject; 00185 } 00186 00187 CValue* KX_GameObject:: Calc(VALUE_OPERATOR op, CValue *val) 00188 { 00189 return NULL; 00190 } 00191 00192 00193 00194 CValue* KX_GameObject::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) 00195 { 00196 return NULL; 00197 } 00198 00199 00200 00201 const STR_String & KX_GameObject::GetText() 00202 { 00203 return m_text; 00204 } 00205 00206 00207 00208 double KX_GameObject::GetNumber() 00209 { 00210 return 0; 00211 } 00212 00213 00214 00215 STR_String& KX_GameObject::GetName() 00216 { 00217 return m_name; 00218 } 00219 00220 00221 00222 void KX_GameObject::SetName(const char *name) 00223 { 00224 m_name = name; 00225 }; // Set the name of the value 00226 00227 KX_IPhysicsController* KX_GameObject::GetPhysicsController() 00228 { 00229 return m_pPhysicsController1; 00230 } 00231 00232 KX_GameObject* KX_GameObject::GetParent() 00233 { 00234 KX_GameObject* result = NULL; 00235 SG_Node* node = m_pSGNode; 00236 00237 while (node && !result) 00238 { 00239 node = node->GetSGParent(); 00240 if (node) 00241 result = (KX_GameObject*)node->GetSGClientObject(); 00242 } 00243 00244 if (result) 00245 result->AddRef(); 00246 00247 return result; 00248 00249 } 00250 00251 void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj, bool addToCompound, bool ghost) 00252 { 00253 // check on valid node in case a python controller holds a reference to a deleted object 00254 if (obj && 00255 GetSGNode() && // object is not zombi 00256 obj->GetSGNode() && // object is not zombi 00257 GetSGNode()->GetSGParent() != obj->GetSGNode() && // not already parented to same object 00258 !GetSGNode()->IsAncessor(obj->GetSGNode()) && // no parenting loop 00259 this != obj) // not the object itself 00260 { 00261 // Make sure the objects have some scale 00262 MT_Vector3 scale1 = NodeGetWorldScaling(); 00263 MT_Vector3 scale2 = obj->NodeGetWorldScaling(); 00264 if (fabs(scale2[0]) < FLT_EPSILON || 00265 fabs(scale2[1]) < FLT_EPSILON || 00266 fabs(scale2[2]) < FLT_EPSILON || 00267 fabs(scale1[0]) < FLT_EPSILON || 00268 fabs(scale1[1]) < FLT_EPSILON || 00269 fabs(scale1[2]) < FLT_EPSILON) { return; } 00270 00271 // Remove us from our old parent and set our new parent 00272 RemoveParent(scene); 00273 obj->GetSGNode()->AddChild(GetSGNode()); 00274 00275 if (m_pPhysicsController1) 00276 { 00277 m_pPhysicsController1->SuspendDynamics(ghost); 00278 } 00279 // Set us to our new scale, position, and orientation 00280 scale2[0] = 1.0/scale2[0]; 00281 scale2[1] = 1.0/scale2[1]; 00282 scale2[2] = 1.0/scale2[2]; 00283 scale1 = scale1 * scale2; 00284 MT_Matrix3x3 invori = obj->NodeGetWorldOrientation().inverse(); 00285 MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale2; 00286 00287 NodeSetLocalScale(scale1); 00288 NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); 00289 NodeSetLocalOrientation(invori*NodeGetWorldOrientation()); 00290 NodeUpdateGS(0.f); 00291 // object will now be a child, it must be removed from the parent list 00292 CListValue* rootlist = scene->GetRootParentList(); 00293 if (rootlist->RemoveValue(this)) 00294 // the object was in parent list, decrement ref count as it's now removed 00295 Release(); 00296 // if the new parent is a compound object, add this object shape to the compound shape. 00297 // step 0: verify this object has physical controller 00298 if (m_pPhysicsController1 && addToCompound) 00299 { 00300 // step 1: find the top parent (not necessarily obj) 00301 KX_GameObject* rootobj = (KX_GameObject*)obj->GetSGNode()->GetRootSGParent()->GetSGClientObject(); 00302 // step 2: verify it has a physical controller and compound shape 00303 if (rootobj != NULL && 00304 rootobj->m_pPhysicsController1 != NULL && 00305 rootobj->m_pPhysicsController1->IsCompound()) 00306 { 00307 rootobj->m_pPhysicsController1->AddCompoundChild(m_pPhysicsController1); 00308 } 00309 } 00310 // graphically, the object hasn't change place, no need to update m_pGraphicController 00311 } 00312 } 00313 00314 void KX_GameObject::RemoveParent(KX_Scene *scene) 00315 { 00316 // check on valid node in case a python controller holds a reference to a deleted object 00317 if (GetSGNode() && GetSGNode()->GetSGParent()) 00318 { 00319 // get the root object to remove us from compound object if needed 00320 KX_GameObject* rootobj = (KX_GameObject*)GetSGNode()->GetRootSGParent()->GetSGClientObject(); 00321 // Set us to the right spot 00322 GetSGNode()->SetLocalScale(GetSGNode()->GetWorldScaling()); 00323 GetSGNode()->SetLocalOrientation(GetSGNode()->GetWorldOrientation()); 00324 GetSGNode()->SetLocalPosition(GetSGNode()->GetWorldPosition()); 00325 00326 // Remove us from our parent 00327 GetSGNode()->DisconnectFromParent(); 00328 NodeUpdateGS(0.f); 00329 // the object is now a root object, add it to the parentlist 00330 CListValue* rootlist = scene->GetRootParentList(); 00331 if (!rootlist->SearchValue(this)) 00332 // object was not in root list, add it now and increment ref count 00333 rootlist->Add(AddRef()); 00334 if (m_pPhysicsController1) 00335 { 00336 // in case this controller was added as a child shape to the parent 00337 if (rootobj != NULL && 00338 rootobj->m_pPhysicsController1 != NULL && 00339 rootobj->m_pPhysicsController1->IsCompound()) 00340 { 00341 rootobj->m_pPhysicsController1->RemoveCompoundChild(m_pPhysicsController1); 00342 } 00343 m_pPhysicsController1->RestoreDynamics(); 00344 if (m_pPhysicsController1->IsDyna() && (rootobj != NULL && rootobj->m_pPhysicsController1)) 00345 { 00346 // dynamic object should remember the velocity they had while being parented 00347 MT_Point3 childPoint = GetSGNode()->GetWorldPosition(); 00348 MT_Point3 rootPoint = rootobj->GetSGNode()->GetWorldPosition(); 00349 MT_Point3 relPoint; 00350 relPoint = (childPoint-rootPoint); 00351 MT_Vector3 linVel = rootobj->m_pPhysicsController1->GetVelocity(relPoint); 00352 MT_Vector3 angVel = rootobj->m_pPhysicsController1->GetAngularVelocity(); 00353 m_pPhysicsController1->SetLinearVelocity(linVel, false); 00354 m_pPhysicsController1->SetAngularVelocity(angVel, false); 00355 } 00356 } 00357 // graphically, the object hasn't change place, no need to update m_pGraphicController 00358 } 00359 } 00360 00361 BL_ActionManager* KX_GameObject::GetActionManager() 00362 { 00363 // We only want to create an action manager if we need it 00364 if (!m_actionManager) 00365 { 00366 KX_GetActiveScene()->AddAnimatedObject(this); 00367 m_actionManager = new BL_ActionManager(this); 00368 } 00369 return m_actionManager; 00370 } 00371 00372 bool KX_GameObject::PlayAction(const char* name, 00373 float start, 00374 float end, 00375 short layer, 00376 short priority, 00377 float blendin, 00378 short play_mode, 00379 float layer_weight, 00380 short ipo_flags, 00381 float playback_speed) 00382 { 00383 return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); 00384 } 00385 00386 void KX_GameObject::StopAction(short layer) 00387 { 00388 GetActionManager()->StopAction(layer); 00389 } 00390 00391 bool KX_GameObject::IsActionDone(short layer) 00392 { 00393 return GetActionManager()->IsActionDone(layer); 00394 } 00395 00396 void KX_GameObject::UpdateActionManager(float curtime) 00397 { 00398 GetActionManager()->Update(curtime); 00399 } 00400 00401 float KX_GameObject::GetActionFrame(short layer) 00402 { 00403 return GetActionManager()->GetActionFrame(layer); 00404 } 00405 00406 void KX_GameObject::SetActionFrame(short layer, float frame) 00407 { 00408 GetActionManager()->SetActionFrame(layer, frame); 00409 } 00410 00411 bAction *KX_GameObject::GetCurrentAction(short layer) 00412 { 00413 return GetActionManager()->GetCurrentAction(layer); 00414 } 00415 00416 void KX_GameObject::SetPlayMode(short layer, short mode) 00417 { 00418 GetActionManager()->SetPlayMode(layer, mode); 00419 } 00420 00421 void KX_GameObject::SetTimes(short layer, float start, float end) 00422 { 00423 GetActionManager()->SetTimes(layer, start, end); 00424 } 00425 00426 void KX_GameObject::ProcessReplica() 00427 { 00428 SCA_IObject::ProcessReplica(); 00429 00430 m_pPhysicsController1 = NULL; 00431 m_pGraphicController = NULL; 00432 m_pSGNode = NULL; 00433 m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); 00434 m_pClient_info->m_gameobject = this; 00435 if (m_actionManager) 00436 m_actionManager = new BL_ActionManager(this); 00437 m_state = 0; 00438 00439 KX_Scene* scene = KX_GetActiveScene(); 00440 KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation(); 00441 struct Object* blenderobject = GetBlenderObject(); 00442 if (obssimulation && (blenderobject->gameflag & OB_HASOBSTACLE)) 00443 { 00444 obssimulation->AddObstacleForObj(this); 00445 } 00446 00447 #ifdef WITH_PYTHON 00448 if(m_attr_dict) 00449 m_attr_dict= PyDict_Copy(m_attr_dict); 00450 #endif 00451 00452 } 00453 00454 static void setGraphicController_recursive(SG_Node* node) 00455 { 00456 NodeList& children = node->GetSGChildren(); 00457 00458 for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) 00459 { 00460 SG_Node* childnode = (*childit); 00461 KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); 00462 if (clientgameobj != NULL) // This is a GameObject 00463 clientgameobj->ActivateGraphicController(false); 00464 00465 // if the childobj is NULL then this may be an inverse parent link 00466 // so a non recursive search should still look down this node. 00467 setGraphicController_recursive(childnode); 00468 } 00469 } 00470 00471 00472 void KX_GameObject::ActivateGraphicController(bool recurse) 00473 { 00474 if (m_pGraphicController) 00475 { 00476 m_pGraphicController->Activate(m_bVisible); 00477 } 00478 if (recurse) 00479 { 00480 setGraphicController_recursive(GetSGNode()); 00481 } 00482 } 00483 00484 00485 CValue* KX_GameObject::GetReplica() 00486 { 00487 KX_GameObject* replica = new KX_GameObject(*this); 00488 00489 // this will copy properties and so on... 00490 replica->ProcessReplica(); 00491 00492 return replica; 00493 } 00494 00495 00496 00497 void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local) 00498 { 00499 if (m_pPhysicsController1) 00500 m_pPhysicsController1->ApplyForce(force,local); 00501 } 00502 00503 00504 00505 void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local) 00506 { 00507 if (m_pPhysicsController1) 00508 m_pPhysicsController1->ApplyTorque(torque,local); 00509 } 00510 00511 00512 00513 void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) 00514 { 00515 if (GetSGNode()) 00516 { 00517 if (m_pPhysicsController1) // (IsDynamic()) 00518 { 00519 m_pPhysicsController1->RelativeTranslate(dloc,local); 00520 } 00521 GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local); 00522 } 00523 } 00524 00525 00526 00527 void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local) 00528 { 00529 MT_Matrix3x3 rotmat(drot); 00530 00531 if (GetSGNode()) { 00532 GetSGNode()->RelativeRotate(rotmat,local); 00533 00534 if (m_pPhysicsController1) { // (IsDynamic()) 00535 m_pPhysicsController1->RelativeRotate(rotmat,local); 00536 } 00537 } 00538 } 00539 00540 00541 00545 double* KX_GameObject::GetOpenGLMatrix() 00546 { 00547 // todo: optimize and only update if necessary 00548 double* fl = m_OpenGL_4x4Matrix.getPointer(); 00549 if (GetSGNode()) { 00550 MT_Transform trans; 00551 00552 trans.setOrigin(GetSGNode()->GetWorldPosition()); 00553 trans.setBasis(GetSGNode()->GetWorldOrientation()); 00554 00555 MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); 00556 m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; 00557 trans.scale(scaling[0], scaling[1], scaling[2]); 00558 trans.getValue(fl); 00559 GetSGNode()->ClearDirty(); 00560 } 00561 return fl; 00562 } 00563 00564 void KX_GameObject::UpdateBlenderObjectMatrix(Object* blendobj) 00565 { 00566 if (!blendobj) 00567 blendobj = m_pBlenderObject; 00568 if (blendobj) { 00569 const MT_Matrix3x3& rot = NodeGetWorldOrientation(); 00570 const MT_Vector3& scale = NodeGetWorldScaling(); 00571 const MT_Vector3& pos = NodeGetWorldPosition(); 00572 rot.getValue(blendobj->obmat[0]); 00573 pos.getValue(blendobj->obmat[3]); 00574 mul_v3_fl(blendobj->obmat[0], scale[0]); 00575 mul_v3_fl(blendobj->obmat[1], scale[1]); 00576 mul_v3_fl(blendobj->obmat[2], scale[2]); 00577 } 00578 } 00579 00580 void KX_GameObject::AddMeshUser() 00581 { 00582 for (size_t i=0;i<m_meshes.size();i++) 00583 { 00584 m_meshes[i]->AddMeshUser(this, &m_meshSlots, GetDeformer()); 00585 } 00586 // set the part of the mesh slot that never change 00587 double* fl = GetOpenGLMatrixPtr()->getPointer(); 00588 00589 SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); 00590 // RAS_MeshSlot* ms; 00591 for(mit.begin(); !mit.end(); ++mit) 00592 { 00593 (*mit)->m_OpenGLMatrix = fl; 00594 } 00595 UpdateBuckets(false); 00596 } 00597 00598 static void UpdateBuckets_recursive(SG_Node* node) 00599 { 00600 NodeList& children = node->GetSGChildren(); 00601 00602 for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) 00603 { 00604 SG_Node* childnode = (*childit); 00605 KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); 00606 if (clientgameobj != NULL) // This is a GameObject 00607 clientgameobj->UpdateBuckets(0); 00608 00609 // if the childobj is NULL then this may be an inverse parent link 00610 // so a non recursive search should still look down this node. 00611 UpdateBuckets_recursive(childnode); 00612 } 00613 } 00614 00615 void KX_GameObject::UpdateBuckets( bool recursive ) 00616 { 00617 if (GetSGNode()) { 00618 RAS_MeshSlot *ms; 00619 00620 if (GetSGNode()->IsDirty()) 00621 GetOpenGLMatrix(); 00622 00623 SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); 00624 for(mit.begin(); !mit.end(); ++mit) 00625 { 00626 ms = *mit; 00627 ms->m_bObjectColor = m_bUseObjectColor; 00628 ms->m_RGBAcolor = m_objectColor; 00629 ms->m_bVisible = m_bVisible; 00630 ms->m_bCulled = m_bCulled || !m_bVisible; 00631 if (!ms->m_bCulled) 00632 ms->m_bucket->ActivateMesh(ms); 00633 00634 /* split if necessary */ 00635 #ifdef USE_SPLIT 00636 ms->Split(); 00637 #endif 00638 } 00639 00640 if (recursive) { 00641 UpdateBuckets_recursive(GetSGNode()); 00642 } 00643 } 00644 } 00645 00646 void KX_GameObject::RemoveMeshes() 00647 { 00648 for (size_t i=0;i<m_meshes.size();i++) 00649 m_meshes[i]->RemoveFromBuckets(this); 00650 00651 //note: meshes can be shared, and are deleted by KX_BlenderSceneConverter 00652 00653 m_meshes.clear(); 00654 } 00655 00656 void KX_GameObject::UpdateTransform() 00657 { 00658 // HACK: saves function call for dynamic object, they are handled differently 00659 if (m_pPhysicsController1 && !m_pPhysicsController1->IsDyna()) 00660 // Note that for Bullet, this does not even update the transform of static object 00661 // but merely sets there collision flag to "kinematic" because the synchronization is 00662 // done during physics simulation 00663 m_pPhysicsController1->SetSumoTransform(true); 00664 if (m_pGraphicController) 00665 // update the culling tree 00666 m_pGraphicController->SetGraphicTransform(); 00667 00668 } 00669 00670 void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene) 00671 { 00672 ((KX_GameObject*)gameobj)->UpdateTransform(); 00673 } 00674 00675 void KX_GameObject::SynchronizeTransform() 00676 { 00677 // only used for sensor object, do full synchronization as bullet doesn't do it 00678 if (m_pPhysicsController1) 00679 m_pPhysicsController1->SetTransform(); 00680 if (m_pGraphicController) 00681 m_pGraphicController->SetGraphicTransform(); 00682 } 00683 00684 void KX_GameObject::SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene) 00685 { 00686 ((KX_GameObject*)gameobj)->SynchronizeTransform(); 00687 } 00688 00689 00690 void KX_GameObject::SetDebugColor(unsigned int bgra) 00691 { 00692 for (size_t i=0;i<m_meshes.size();i++) 00693 m_meshes[i]->DebugColor(bgra); 00694 } 00695 00696 00697 00698 void KX_GameObject::ResetDebugColor() 00699 { 00700 SetDebugColor(0xff000000); 00701 } 00702 00703 void KX_GameObject::InitIPO(bool ipo_as_force, 00704 bool ipo_add, 00705 bool ipo_local) 00706 { 00707 SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin(); 00708 00709 while (it != GetSGNode()->GetSGControllerList().end()) { 00710 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true); 00711 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force); 00712 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, ipo_add); 00713 (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, ipo_local); 00714 it++; 00715 } 00716 } 00717 00718 void KX_GameObject::UpdateIPO(float curframetime, 00719 bool recurse) 00720 { 00721 // just the 'normal' update procedure. 00722 GetSGNode()->SetSimulatedTime(curframetime,recurse); 00723 GetSGNode()->UpdateWorldData(curframetime); 00724 UpdateTransform(); 00725 } 00726 00727 // IPO update 00728 void 00729 KX_GameObject::UpdateMaterialData( 00730 dword matname_hash, 00731 MT_Vector4 rgba, 00732 MT_Vector3 specrgb, 00733 MT_Scalar hard, 00734 MT_Scalar spec, 00735 MT_Scalar ref, 00736 MT_Scalar emit, 00737 MT_Scalar alpha 00738 00739 ) 00740 { 00741 int mesh = 0; 00742 if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) { 00743 list<RAS_MeshMaterial>::iterator mit = m_meshes[mesh]->GetFirstMaterial(); 00744 00745 for(; mit != m_meshes[mesh]->GetLastMaterial(); ++mit) 00746 { 00747 RAS_IPolyMaterial* poly = mit->m_bucket->GetPolyMaterial(); 00748 00749 if(poly->GetFlag() & RAS_BLENDERMAT ) 00750 { 00751 KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly); 00752 00753 if (matname_hash == 0) 00754 { 00755 m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); 00756 // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance) 00757 SetObjectColor(rgba); 00758 } 00759 else 00760 { 00761 if (matname_hash == poly->GetMaterialNameHash()) 00762 { 00763 m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); 00764 m_meshes[mesh]->SetVertexColor(poly,rgba); 00765 00766 // no break here, because one blender material can be split into several game engine materials 00767 // (e.g. one uvsphere material is split into one material at poles with ras_mode TRIANGLE and one material for the body 00768 // if here was a break then would miss some vertices if material was split 00769 } 00770 } 00771 } 00772 } 00773 } 00774 } 00775 bool 00776 KX_GameObject::GetVisible( 00777 void 00778 ) 00779 { 00780 return m_bVisible; 00781 } 00782 00783 static void setVisible_recursive(SG_Node* node, bool v) 00784 { 00785 NodeList& children = node->GetSGChildren(); 00786 00787 for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) 00788 { 00789 SG_Node* childnode = (*childit); 00790 KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); 00791 if (clientgameobj != NULL) // This is a GameObject 00792 clientgameobj->SetVisible(v, 0); 00793 00794 // if the childobj is NULL then this may be an inverse parent link 00795 // so a non recursive search should still look down this node. 00796 setVisible_recursive(childnode, v); 00797 } 00798 } 00799 00800 00801 void 00802 KX_GameObject::SetVisible( 00803 bool v, 00804 bool recursive 00805 ) 00806 { 00807 if (GetSGNode()) { 00808 m_bVisible = v; 00809 if (m_pGraphicController) 00810 m_pGraphicController->Activate(m_bVisible); 00811 if (recursive) 00812 setVisible_recursive(GetSGNode(), v); 00813 } 00814 } 00815 00816 static void setOccluder_recursive(SG_Node* node, bool v) 00817 { 00818 NodeList& children = node->GetSGChildren(); 00819 00820 for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) 00821 { 00822 SG_Node* childnode = (*childit); 00823 KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); 00824 if (clientgameobj != NULL) // This is a GameObject 00825 clientgameobj->SetOccluder(v, false); 00826 00827 // if the childobj is NULL then this may be an inverse parent link 00828 // so a non recursive search should still look down this node. 00829 setOccluder_recursive(childnode, v); 00830 } 00831 } 00832 00833 void 00834 KX_GameObject::SetOccluder( 00835 bool v, 00836 bool recursive 00837 ) 00838 { 00839 if (GetSGNode()) { 00840 m_bOccluder = v; 00841 if (recursive) 00842 setOccluder_recursive(GetSGNode(), v); 00843 } 00844 } 00845 00846 void 00847 KX_GameObject::SetLayer( 00848 int l 00849 ) 00850 { 00851 m_layer = l; 00852 } 00853 00854 int 00855 KX_GameObject::GetLayer( 00856 void 00857 ) 00858 { 00859 return m_layer; 00860 } 00861 00862 void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local) 00863 { 00864 if (m_pPhysicsController1) 00865 { 00866 MT_Vector3 lv = local ? NodeGetWorldOrientation() * lin_vel : lin_vel; 00867 m_pPhysicsController1->SetLinearVelocity(lv + m_pPhysicsController1->GetLinearVelocity(), 0); 00868 } 00869 } 00870 00871 00872 00873 void KX_GameObject::setLinearVelocity(const MT_Vector3& lin_vel,bool local) 00874 { 00875 if (m_pPhysicsController1) 00876 m_pPhysicsController1->SetLinearVelocity(lin_vel,local); 00877 } 00878 00879 00880 00881 void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local) 00882 { 00883 if (m_pPhysicsController1) 00884 m_pPhysicsController1->SetAngularVelocity(ang_vel,local); 00885 } 00886 00887 00888 void KX_GameObject::ResolveCombinedVelocities( 00889 const MT_Vector3 & lin_vel, 00890 const MT_Vector3 & ang_vel, 00891 bool lin_vel_local, 00892 bool ang_vel_local 00893 ){ 00894 if (m_pPhysicsController1) 00895 { 00896 00897 MT_Vector3 lv = lin_vel_local ? NodeGetWorldOrientation() * lin_vel : lin_vel; 00898 MT_Vector3 av = ang_vel_local ? NodeGetWorldOrientation() * ang_vel : ang_vel; 00899 m_pPhysicsController1->resolveCombinedVelocities( 00900 lv.x(),lv.y(),lv.z(),av.x(),av.y(),av.z()); 00901 } 00902 } 00903 00904 00905 void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec) 00906 { 00907 m_bUseObjectColor = true; 00908 m_objectColor = rgbavec; 00909 } 00910 00911 const MT_Vector4& KX_GameObject::GetObjectColor() 00912 { 00913 return m_objectColor; 00914 } 00915 00916 void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) 00917 { 00918 MT_Matrix3x3 orimat; 00919 MT_Vector3 vect,ori,z,x,y; 00920 MT_Scalar len; 00921 00922 // check on valid node in case a python controller holds a reference to a deleted object 00923 if (!GetSGNode()) 00924 return; 00925 00926 vect = dir; 00927 len = vect.length(); 00928 if (MT_fuzzyZero(len)) 00929 { 00930 cout << "alignAxisToVect() Error: Null vector!\n"; 00931 return; 00932 } 00933 00934 if (fac<=0.0) { 00935 return; 00936 } 00937 00938 // normalize 00939 vect /= len; 00940 orimat = GetSGNode()->GetWorldOrientation(); 00941 switch (axis) 00942 { 00943 case 0: //x axis 00944 ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis 00945 if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) //is the vector parallel to the pivot? 00946 ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot! 00947 if (fac == 1.0) { 00948 x = vect; 00949 } else { 00950 x = (vect * fac) + ((orimat * MT_Vector3(1.0, 0.0, 0.0)) * (1-fac)); 00951 len = x.length(); 00952 if (MT_fuzzyZero(len)) x = vect; 00953 else x /= len; 00954 } 00955 y = ori.cross(x); 00956 z = x.cross(y); 00957 break; 00958 case 1: //y axis 00959 ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]); 00960 if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) 00961 ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); 00962 if (fac == 1.0) { 00963 y = vect; 00964 } else { 00965 y = (vect * fac) + ((orimat * MT_Vector3(0.0, 1.0, 0.0)) * (1-fac)); 00966 len = y.length(); 00967 if (MT_fuzzyZero(len)) y = vect; 00968 else y /= len; 00969 } 00970 z = ori.cross(y); 00971 x = y.cross(z); 00972 break; 00973 case 2: //z axis 00974 ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); 00975 if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) 00976 ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]); 00977 if (fac == 1.0) { 00978 z = vect; 00979 } else { 00980 z = (vect * fac) + ((orimat * MT_Vector3(0.0, 0.0, 1.0)) * (1-fac)); 00981 len = z.length(); 00982 if (MT_fuzzyZero(len)) z = vect; 00983 else z /= len; 00984 } 00985 x = ori.cross(z); 00986 y = z.cross(x); 00987 break; 00988 default: //wrong input? 00989 cout << "alignAxisToVect(): Wrong axis '" << axis <<"'\n"; 00990 return; 00991 } 00992 x.normalize(); //normalize the vectors 00993 y.normalize(); 00994 z.normalize(); 00995 orimat.setValue( x[0],y[0],z[0], 00996 x[1],y[1],z[1], 00997 x[2],y[2],z[2]); 00998 if (GetSGNode()->GetSGParent() != NULL) 00999 { 01000 // the object is a child, adapt its local orientation so that 01001 // the global orientation is aligned as we want. 01002 MT_Matrix3x3 invori = GetSGNode()->GetSGParent()->GetWorldOrientation().inverse(); 01003 NodeSetLocalOrientation(invori*orimat); 01004 } 01005 else 01006 NodeSetLocalOrientation(orimat); 01007 } 01008 01009 MT_Scalar KX_GameObject::GetMass() 01010 { 01011 if (m_pPhysicsController1) 01012 { 01013 return m_pPhysicsController1->GetMass(); 01014 } 01015 return 0.0; 01016 } 01017 01018 MT_Vector3 KX_GameObject::GetLocalInertia() 01019 { 01020 MT_Vector3 local_inertia(0.0,0.0,0.0); 01021 if (m_pPhysicsController1) 01022 { 01023 local_inertia = m_pPhysicsController1->GetLocalInertia(); 01024 } 01025 return local_inertia; 01026 } 01027 01028 MT_Vector3 KX_GameObject::GetLinearVelocity(bool local) 01029 { 01030 MT_Vector3 velocity(0.0,0.0,0.0), locvel; 01031 MT_Matrix3x3 ori; 01032 if (m_pPhysicsController1) 01033 { 01034 velocity = m_pPhysicsController1->GetLinearVelocity(); 01035 01036 if (local) 01037 { 01038 ori = GetSGNode()->GetWorldOrientation(); 01039 01040 locvel = velocity * ori; 01041 return locvel; 01042 } 01043 } 01044 return velocity; 01045 } 01046 01047 MT_Vector3 KX_GameObject::GetAngularVelocity(bool local) 01048 { 01049 MT_Vector3 velocity(0.0,0.0,0.0), locvel; 01050 MT_Matrix3x3 ori; 01051 if (m_pPhysicsController1) 01052 { 01053 velocity = m_pPhysicsController1->GetAngularVelocity(); 01054 01055 if (local) 01056 { 01057 ori = GetSGNode()->GetWorldOrientation(); 01058 01059 locvel = velocity * ori; 01060 return locvel; 01061 } 01062 } 01063 return velocity; 01064 } 01065 01066 MT_Vector3 KX_GameObject::GetVelocity(const MT_Point3& point) 01067 { 01068 if (m_pPhysicsController1) 01069 { 01070 return m_pPhysicsController1->GetVelocity(point); 01071 } 01072 return MT_Vector3(0.0,0.0,0.0); 01073 } 01074 01075 // scenegraph node stuff 01076 01077 void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans) 01078 { 01079 // check on valid node in case a python controller holds a reference to a deleted object 01080 if (!GetSGNode()) 01081 return; 01082 01083 if (m_pPhysicsController1 && !GetSGNode()->GetSGParent()) 01084 { 01085 // don't update physic controller if the object is a child: 01086 // 1) the transformation will not be right 01087 // 2) in this case, the physic controller is necessarily a static object 01088 // that is updated from the normal kinematic synchronization 01089 m_pPhysicsController1->setPosition(trans); 01090 } 01091 01092 GetSGNode()->SetLocalPosition(trans); 01093 01094 } 01095 01096 01097 01098 void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot) 01099 { 01100 // check on valid node in case a python controller holds a reference to a deleted object 01101 if (!GetSGNode()) 01102 return; 01103 01104 if (m_pPhysicsController1 && !GetSGNode()->GetSGParent()) 01105 { 01106 // see note above 01107 m_pPhysicsController1->setOrientation(rot); 01108 } 01109 GetSGNode()->SetLocalOrientation(rot); 01110 } 01111 01112 void KX_GameObject::NodeSetGlobalOrientation(const MT_Matrix3x3& rot) 01113 { 01114 // check on valid node in case a python controller holds a reference to a deleted object 01115 if (!GetSGNode()) 01116 return; 01117 01118 if (GetSGNode()->GetSGParent()) 01119 GetSGNode()->SetLocalOrientation(GetSGNode()->GetSGParent()->GetWorldOrientation().inverse()*rot); 01120 else 01121 NodeSetLocalOrientation(rot); 01122 } 01123 01124 void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale) 01125 { 01126 // check on valid node in case a python controller holds a reference to a deleted object 01127 if (!GetSGNode()) 01128 return; 01129 01130 if (m_pPhysicsController1 && !GetSGNode()->GetSGParent()) 01131 { 01132 // see note above 01133 m_pPhysicsController1->setScaling(scale); 01134 } 01135 GetSGNode()->SetLocalScale(scale); 01136 } 01137 01138 01139 01140 void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale) 01141 { 01142 if (GetSGNode()) 01143 { 01144 GetSGNode()->RelativeScale(scale); 01145 if (m_pPhysicsController1 && (!GetSGNode()->GetSGParent())) 01146 { 01147 // see note above 01148 // we can use the local scale: it's the same thing for a root object 01149 // and the world scale is not yet updated 01150 MT_Vector3 newscale = GetSGNode()->GetLocalScale(); 01151 m_pPhysicsController1->setScaling(newscale); 01152 } 01153 } 01154 } 01155 01156 void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans) 01157 { 01158 if (!GetSGNode()) 01159 return; 01160 SG_Node* parent = GetSGNode()->GetSGParent(); 01161 if (parent != NULL) 01162 { 01163 // Make sure the objects have some scale 01164 MT_Vector3 scale = parent->GetWorldScaling(); 01165 if (fabs(scale[0]) < FLT_EPSILON || 01166 fabs(scale[1]) < FLT_EPSILON || 01167 fabs(scale[2]) < FLT_EPSILON) 01168 { 01169 return; 01170 } 01171 scale[0] = 1.0/scale[0]; 01172 scale[1] = 1.0/scale[1]; 01173 scale[2] = 1.0/scale[2]; 01174 MT_Matrix3x3 invori = parent->GetWorldOrientation().inverse(); 01175 MT_Vector3 newpos = invori*(trans-parent->GetWorldPosition())*scale; 01176 NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); 01177 } 01178 else 01179 { 01180 NodeSetLocalPosition(trans); 01181 } 01182 } 01183 01184 01185 void KX_GameObject::NodeUpdateGS(double time) 01186 { 01187 if (GetSGNode()) 01188 GetSGNode()->UpdateWorldData(time); 01189 } 01190 01191 01192 01193 const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const 01194 { 01195 // check on valid node in case a python controller holds a reference to a deleted object 01196 if (!GetSGNode()) 01197 return dummy_orientation; 01198 return GetSGNode()->GetWorldOrientation(); 01199 } 01200 01201 const MT_Matrix3x3& KX_GameObject::NodeGetLocalOrientation() const 01202 { 01203 // check on valid node in case a python controller holds a reference to a deleted object 01204 if (!GetSGNode()) 01205 return dummy_orientation; 01206 return GetSGNode()->GetLocalOrientation(); 01207 } 01208 01209 const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const 01210 { 01211 // check on valid node in case a python controller holds a reference to a deleted object 01212 if (!GetSGNode()) 01213 return dummy_scaling; 01214 01215 return GetSGNode()->GetWorldScaling(); 01216 } 01217 01218 const MT_Vector3& KX_GameObject::NodeGetLocalScaling() const 01219 { 01220 // check on valid node in case a python controller holds a reference to a deleted object 01221 if (!GetSGNode()) 01222 return dummy_scaling; 01223 01224 return GetSGNode()->GetLocalScale(); 01225 } 01226 01227 const MT_Point3& KX_GameObject::NodeGetWorldPosition() const 01228 { 01229 // check on valid node in case a python controller holds a reference to a deleted object 01230 if (GetSGNode()) 01231 return GetSGNode()->GetWorldPosition(); 01232 else 01233 return dummy_point; 01234 } 01235 01236 const MT_Point3& KX_GameObject::NodeGetLocalPosition() const 01237 { 01238 // check on valid node in case a python controller holds a reference to a deleted object 01239 if (GetSGNode()) 01240 return GetSGNode()->GetLocalPosition(); 01241 else 01242 return dummy_point; 01243 } 01244 01245 01246 /* Suspend/ resume: for the dynamic behaviour, there is a simple 01247 * method. For the residual motion, there is not. I wonder what the 01248 * correct solution is for Sumo. Remove from the motion-update tree? 01249 * 01250 * So far, only switch the physics and logic. 01251 * */ 01252 01253 void KX_GameObject::Resume(void) 01254 { 01255 if (m_suspended) { 01256 SCA_IObject::Resume(); 01257 if(GetPhysicsController()) 01258 GetPhysicsController()->RestoreDynamics(); 01259 01260 m_suspended = false; 01261 } 01262 } 01263 01264 void KX_GameObject::Suspend() 01265 { 01266 if ((!m_ignore_activity_culling) 01267 && (!m_suspended)) { 01268 SCA_IObject::Suspend(); 01269 if(GetPhysicsController()) 01270 GetPhysicsController()->SuspendDynamics(); 01271 m_suspended = true; 01272 } 01273 } 01274 01275 static void walk_children(SG_Node* node, CListValue* list, bool recursive) 01276 { 01277 if (!node) 01278 return; 01279 NodeList& children = node->GetSGChildren(); 01280 01281 for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) 01282 { 01283 SG_Node* childnode = (*childit); 01284 CValue* childobj = (CValue*)childnode->GetSGClientObject(); 01285 if (childobj != NULL) // This is a GameObject 01286 { 01287 // add to the list 01288 list->Add(childobj->AddRef()); 01289 } 01290 01291 // if the childobj is NULL then this may be an inverse parent link 01292 // so a non recursive search should still look down this node. 01293 if (recursive || childobj==NULL) { 01294 walk_children(childnode, list, recursive); 01295 } 01296 } 01297 } 01298 01299 CListValue* KX_GameObject::GetChildren() 01300 { 01301 CListValue* list = new CListValue(); 01302 walk_children(GetSGNode(), list, 0); /* GetSGNode() is always valid or it would have raised an exception before this */ 01303 return list; 01304 } 01305 01306 CListValue* KX_GameObject::GetChildrenRecursive() 01307 { 01308 CListValue* list = new CListValue(); 01309 walk_children(GetSGNode(), list, 1); 01310 return list; 01311 } 01312 01313 /* --------------------------------------------------------------------- 01314 * Some stuff taken from the header 01315 * --------------------------------------------------------------------- */ 01316 void KX_GameObject::Relink(CTR_Map<CTR_HashedPtr, void*> *map_parameter) 01317 { 01318 // we will relink the sensors and actuators that use object references 01319 // if the object is part of the replicated hierarchy, use the new 01320 // object reference instead 01321 SCA_SensorList& sensorlist = GetSensors(); 01322 SCA_SensorList::iterator sit; 01323 for (sit=sensorlist.begin(); sit != sensorlist.end(); sit++) 01324 { 01325 (*sit)->Relink(map_parameter); 01326 } 01327 SCA_ActuatorList& actuatorlist = GetActuators(); 01328 SCA_ActuatorList::iterator ait; 01329 for (ait=actuatorlist.begin(); ait != actuatorlist.end(); ait++) 01330 { 01331 (*ait)->Relink(map_parameter); 01332 } 01333 } 01334 01335 #ifdef USE_MATHUTILS 01336 01337 /* These require an SGNode */ 01338 #define MATHUTILS_VEC_CB_POS_LOCAL 1 01339 #define MATHUTILS_VEC_CB_POS_GLOBAL 2 01340 #define MATHUTILS_VEC_CB_SCALE_LOCAL 3 01341 #define MATHUTILS_VEC_CB_SCALE_GLOBAL 4 01342 #define MATHUTILS_VEC_CB_INERTIA_LOCAL 5 01343 #define MATHUTILS_VEC_CB_OBJECT_COLOR 6 01344 #define MATHUTILS_VEC_CB_LINVEL_LOCAL 7 01345 #define MATHUTILS_VEC_CB_LINVEL_GLOBAL 8 01346 #define MATHUTILS_VEC_CB_ANGVEL_LOCAL 9 01347 #define MATHUTILS_VEC_CB_ANGVEL_GLOBAL 10 01348 01349 static int mathutils_kxgameob_vector_cb_index= -1; /* index for our callbacks */ 01350 01351 static int mathutils_kxgameob_generic_check(BaseMathObject *bmo) 01352 { 01353 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(bmo->cb_user); 01354 if(self==NULL) 01355 return -1; 01356 01357 return 0; 01358 } 01359 01360 static int mathutils_kxgameob_vector_get(BaseMathObject *bmo, int subtype) 01361 { 01362 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(bmo->cb_user); 01363 if(self==NULL) 01364 return -1; 01365 01366 #define PHYS_ERR(attr) PyErr_SetString(PyExc_AttributeError, "KX_GameObject." attr ", is missing a physics controller") 01367 01368 switch(subtype) { 01369 case MATHUTILS_VEC_CB_POS_LOCAL: 01370 self->NodeGetLocalPosition().getValue(bmo->data); 01371 break; 01372 case MATHUTILS_VEC_CB_POS_GLOBAL: 01373 self->NodeGetWorldPosition().getValue(bmo->data); 01374 break; 01375 case MATHUTILS_VEC_CB_SCALE_LOCAL: 01376 self->NodeGetLocalScaling().getValue(bmo->data); 01377 break; 01378 case MATHUTILS_VEC_CB_SCALE_GLOBAL: 01379 self->NodeGetWorldScaling().getValue(bmo->data); 01380 break; 01381 case MATHUTILS_VEC_CB_INERTIA_LOCAL: 01382 if(!self->GetPhysicsController()) return PHYS_ERR("localInertia"), -1; 01383 self->GetPhysicsController()->GetLocalInertia().getValue(bmo->data); 01384 break; 01385 case MATHUTILS_VEC_CB_OBJECT_COLOR: 01386 self->GetObjectColor().getValue(bmo->data); 01387 break; 01388 case MATHUTILS_VEC_CB_LINVEL_LOCAL: 01389 if(!self->GetPhysicsController()) return PHYS_ERR("localLinearVelocity"), -1; 01390 self->GetLinearVelocity(true).getValue(bmo->data); 01391 break; 01392 case MATHUTILS_VEC_CB_LINVEL_GLOBAL: 01393 if(!self->GetPhysicsController()) return PHYS_ERR("worldLinearVelocity"), -1; 01394 self->GetLinearVelocity(false).getValue(bmo->data); 01395 break; 01396 case MATHUTILS_VEC_CB_ANGVEL_LOCAL: 01397 if(!self->GetPhysicsController()) return PHYS_ERR("localLinearVelocity"), -1; 01398 self->GetAngularVelocity(true).getValue(bmo->data); 01399 break; 01400 case MATHUTILS_VEC_CB_ANGVEL_GLOBAL: 01401 if(!self->GetPhysicsController()) return PHYS_ERR("worldLinearVelocity"), -1; 01402 self->GetAngularVelocity(false).getValue(bmo->data); 01403 break; 01404 01405 } 01406 01407 #undef PHYS_ERR 01408 01409 return 0; 01410 } 01411 01412 static int mathutils_kxgameob_vector_set(BaseMathObject *bmo, int subtype) 01413 { 01414 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(bmo->cb_user); 01415 if(self==NULL) 01416 return -1; 01417 01418 switch(subtype) { 01419 case MATHUTILS_VEC_CB_POS_LOCAL: 01420 self->NodeSetLocalPosition(MT_Point3(bmo->data)); 01421 self->NodeUpdateGS(0.f); 01422 break; 01423 case MATHUTILS_VEC_CB_POS_GLOBAL: 01424 self->NodeSetWorldPosition(MT_Point3(bmo->data)); 01425 self->NodeUpdateGS(0.f); 01426 break; 01427 case MATHUTILS_VEC_CB_SCALE_LOCAL: 01428 self->NodeSetLocalScale(MT_Point3(bmo->data)); 01429 self->NodeUpdateGS(0.f); 01430 break; 01431 case MATHUTILS_VEC_CB_SCALE_GLOBAL: 01432 PyErr_SetString(PyExc_AttributeError, "KX_GameObject.worldScale is read-only"); 01433 return -1; 01434 case MATHUTILS_VEC_CB_INERTIA_LOCAL: 01435 /* read only */ 01436 break; 01437 case MATHUTILS_VEC_CB_OBJECT_COLOR: 01438 self->SetObjectColor(MT_Vector4(bmo->data)); 01439 break; 01440 case MATHUTILS_VEC_CB_LINVEL_LOCAL: 01441 self->setLinearVelocity(MT_Point3(bmo->data),true); 01442 break; 01443 case MATHUTILS_VEC_CB_LINVEL_GLOBAL: 01444 self->setLinearVelocity(MT_Point3(bmo->data),false); 01445 break; 01446 case MATHUTILS_VEC_CB_ANGVEL_LOCAL: 01447 self->setAngularVelocity(MT_Point3(bmo->data),true); 01448 break; 01449 case MATHUTILS_VEC_CB_ANGVEL_GLOBAL: 01450 self->setAngularVelocity(MT_Point3(bmo->data),false); 01451 break; 01452 } 01453 01454 return 0; 01455 } 01456 01457 static int mathutils_kxgameob_vector_get_index(BaseMathObject *bmo, int subtype, int index) 01458 { 01459 /* lazy, avoid repeteing the case statement */ 01460 if(mathutils_kxgameob_vector_get(bmo, subtype) == -1) 01461 return -1; 01462 return 0; 01463 } 01464 01465 static int mathutils_kxgameob_vector_set_index(BaseMathObject *bmo, int subtype, int index) 01466 { 01467 float f= bmo->data[index]; 01468 01469 /* lazy, avoid repeteing the case statement */ 01470 if(mathutils_kxgameob_vector_get(bmo, subtype) == -1) 01471 return -1; 01472 01473 bmo->data[index]= f; 01474 return mathutils_kxgameob_vector_set(bmo, subtype); 01475 } 01476 01477 Mathutils_Callback mathutils_kxgameob_vector_cb = { 01478 mathutils_kxgameob_generic_check, 01479 mathutils_kxgameob_vector_get, 01480 mathutils_kxgameob_vector_set, 01481 mathutils_kxgameob_vector_get_index, 01482 mathutils_kxgameob_vector_set_index 01483 }; 01484 01485 /* Matrix */ 01486 #define MATHUTILS_MAT_CB_ORI_LOCAL 1 01487 #define MATHUTILS_MAT_CB_ORI_GLOBAL 2 01488 01489 static int mathutils_kxgameob_matrix_cb_index= -1; /* index for our callbacks */ 01490 01491 static int mathutils_kxgameob_matrix_get(BaseMathObject *bmo, int subtype) 01492 { 01493 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(bmo->cb_user); 01494 if(self==NULL) 01495 return -1; 01496 01497 switch(subtype) { 01498 case MATHUTILS_MAT_CB_ORI_LOCAL: 01499 self->NodeGetLocalOrientation().getValue3x3(bmo->data); 01500 break; 01501 case MATHUTILS_MAT_CB_ORI_GLOBAL: 01502 self->NodeGetWorldOrientation().getValue3x3(bmo->data); 01503 break; 01504 } 01505 01506 return 0; 01507 } 01508 01509 01510 static int mathutils_kxgameob_matrix_set(BaseMathObject *bmo, int subtype) 01511 { 01512 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(bmo->cb_user); 01513 if(self==NULL) 01514 return -1; 01515 01516 MT_Matrix3x3 mat3x3; 01517 switch(subtype) { 01518 case MATHUTILS_MAT_CB_ORI_LOCAL: 01519 mat3x3.setValue3x3(bmo->data); 01520 self->NodeSetLocalOrientation(mat3x3); 01521 self->NodeUpdateGS(0.f); 01522 break; 01523 case MATHUTILS_MAT_CB_ORI_GLOBAL: 01524 mat3x3.setValue3x3(bmo->data); 01525 self->NodeSetLocalOrientation(mat3x3); 01526 self->NodeUpdateGS(0.f); 01527 break; 01528 } 01529 01530 return 0; 01531 } 01532 01533 Mathutils_Callback mathutils_kxgameob_matrix_cb = { 01534 mathutils_kxgameob_generic_check, 01535 mathutils_kxgameob_matrix_get, 01536 mathutils_kxgameob_matrix_set, 01537 NULL, 01538 NULL 01539 }; 01540 01541 01542 void KX_GameObject_Mathutils_Callback_Init(void) 01543 { 01544 // register mathutils callbacks, ok to run more then once. 01545 mathutils_kxgameob_vector_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb); 01546 mathutils_kxgameob_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_matrix_cb); 01547 } 01548 01549 #endif // USE_MATHUTILS 01550 01551 #ifdef WITH_PYTHON 01552 /* ------- python stuff ---------------------------------------------------*/ 01553 PyMethodDef KX_GameObject::Methods[] = { 01554 {"applyForce", (PyCFunction) KX_GameObject::sPyApplyForce, METH_VARARGS}, 01555 {"applyTorque", (PyCFunction) KX_GameObject::sPyApplyTorque, METH_VARARGS}, 01556 {"applyRotation", (PyCFunction) KX_GameObject::sPyApplyRotation, METH_VARARGS}, 01557 {"applyMovement", (PyCFunction) KX_GameObject::sPyApplyMovement, METH_VARARGS}, 01558 {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, 01559 {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, 01560 {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, 01561 {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, 01562 {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, 01563 {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, 01564 {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, 01565 {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O}, 01566 {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_NOARGS}, 01567 {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_NOARGS}, 01568 {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_NOARGS}, 01569 {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS}, 01570 {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS}, 01571 {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O}, 01572 {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_VARARGS}, 01573 {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, 01574 {"setOcclusion",(PyCFunction) KX_GameObject::sPySetOcclusion, METH_VARARGS}, 01575 {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS}, 01576 01577 01578 {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_NOARGS}, 01579 {"getPropertyNames", (PyCFunction)KX_GameObject::sPyGetPropertyNames,METH_NOARGS}, 01580 {"replaceMesh",(PyCFunction) KX_GameObject::sPyReplaceMesh, METH_VARARGS}, 01581 {"endObject",(PyCFunction) KX_GameObject::sPyEndObject, METH_NOARGS}, 01582 {"reinstancePhysicsMesh", (PyCFunction)KX_GameObject::sPyReinstancePhysicsMesh,METH_VARARGS}, 01583 01584 KX_PYMETHODTABLE(KX_GameObject, rayCastTo), 01585 KX_PYMETHODTABLE(KX_GameObject, rayCast), 01586 KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), 01587 KX_PYMETHODTABLE_O(KX_GameObject, getVectTo), 01588 KX_PYMETHODTABLE(KX_GameObject, sendMessage), 01589 01590 KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction), 01591 KX_PYMETHODTABLE(KX_GameObject, stopAction), 01592 KX_PYMETHODTABLE(KX_GameObject, getActionFrame), 01593 KX_PYMETHODTABLE(KX_GameObject, setActionFrame), 01594 KX_PYMETHODTABLE(KX_GameObject, isPlayingAction), 01595 01596 // dict style access for props 01597 {"get",(PyCFunction) KX_GameObject::sPyget, METH_VARARGS}, 01598 01599 {NULL,NULL} //Sentinel 01600 }; 01601 01602 PyAttributeDef KX_GameObject::Attributes[] = { 01603 KX_PYATTRIBUTE_RO_FUNCTION("name", KX_GameObject, pyattr_get_name), 01604 KX_PYATTRIBUTE_RO_FUNCTION("parent", KX_GameObject, pyattr_get_parent), 01605 KX_PYATTRIBUTE_RO_FUNCTION("life", KX_GameObject, pyattr_get_life), 01606 KX_PYATTRIBUTE_RW_FUNCTION("mass", KX_GameObject, pyattr_get_mass, pyattr_set_mass), 01607 KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMin", KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min), 01608 KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max), 01609 KX_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible), 01610 KX_PYATTRIBUTE_BOOL_RW ("occlusion", KX_GameObject, m_bOccluder), 01611 KX_PYATTRIBUTE_RW_FUNCTION("position", KX_GameObject, pyattr_get_worldPosition, pyattr_set_localPosition), 01612 KX_PYATTRIBUTE_RO_FUNCTION("localInertia", KX_GameObject, pyattr_get_localInertia), 01613 KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_localOrientation), 01614 KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), 01615 KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset), 01616 KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), 01617 KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), 01618 KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), 01619 KX_PYATTRIBUTE_RW_FUNCTION("worldOrientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_worldOrientation), 01620 KX_PYATTRIBUTE_RW_FUNCTION("localPosition", KX_GameObject, pyattr_get_localPosition, pyattr_set_localPosition), 01621 KX_PYATTRIBUTE_RW_FUNCTION("worldPosition", KX_GameObject, pyattr_get_worldPosition, pyattr_set_worldPosition), 01622 KX_PYATTRIBUTE_RW_FUNCTION("localScale", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), 01623 KX_PYATTRIBUTE_RO_FUNCTION("worldScale", KX_GameObject, pyattr_get_worldScaling), 01624 KX_PYATTRIBUTE_RW_FUNCTION("linearVelocity", KX_GameObject, pyattr_get_localLinearVelocity, pyattr_set_worldLinearVelocity), 01625 KX_PYATTRIBUTE_RW_FUNCTION("localLinearVelocity", KX_GameObject, pyattr_get_localLinearVelocity, pyattr_set_localLinearVelocity), 01626 KX_PYATTRIBUTE_RW_FUNCTION("worldLinearVelocity", KX_GameObject, pyattr_get_worldLinearVelocity, pyattr_set_worldLinearVelocity), 01627 KX_PYATTRIBUTE_RW_FUNCTION("angularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_worldAngularVelocity), 01628 KX_PYATTRIBUTE_RW_FUNCTION("localAngularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_localAngularVelocity), 01629 KX_PYATTRIBUTE_RW_FUNCTION("worldAngularVelocity", KX_GameObject, pyattr_get_worldAngularVelocity, pyattr_set_worldAngularVelocity), 01630 KX_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), 01631 KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), 01632 KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), 01633 KX_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor), 01634 01635 /* Experemental, dont rely on these yet */ 01636 KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors), 01637 KX_PYATTRIBUTE_RO_FUNCTION("controllers", KX_GameObject, pyattr_get_controllers), 01638 KX_PYATTRIBUTE_RO_FUNCTION("actuators", KX_GameObject, pyattr_get_actuators), 01639 {NULL} //Sentinel 01640 }; 01641 01642 PyObject* KX_GameObject::PyReplaceMesh(PyObject* args) 01643 { 01644 KX_Scene *scene = KX_GetActiveScene(); 01645 01646 PyObject *value; 01647 int use_gfx= 1, use_phys= 0; 01648 RAS_MeshObject *new_mesh; 01649 01650 if (!PyArg_ParseTuple(args,"O|ii:replaceMesh", &value, &use_gfx, &use_phys)) 01651 return NULL; 01652 01653 if (!ConvertPythonToMesh(value, &new_mesh, false, "gameOb.replaceMesh(value): KX_GameObject")) 01654 return NULL; 01655 01656 scene->ReplaceMesh(this, new_mesh, (bool)use_gfx, (bool)use_phys); 01657 Py_RETURN_NONE; 01658 } 01659 01660 PyObject* KX_GameObject::PyEndObject() 01661 { 01662 KX_Scene *scene = KX_GetActiveScene(); 01663 01664 scene->DelayedRemoveObject(this); 01665 01666 Py_RETURN_NONE; 01667 01668 } 01669 01670 PyObject* KX_GameObject::PyReinstancePhysicsMesh(PyObject* args) 01671 { 01672 KX_GameObject *gameobj= NULL; 01673 RAS_MeshObject *mesh= NULL; 01674 01675 PyObject *gameobj_py= NULL; 01676 PyObject *mesh_py= NULL; 01677 01678 if ( !PyArg_ParseTuple(args,"|OO:reinstancePhysicsMesh",&gameobj_py, &mesh_py) || 01679 (gameobj_py && !ConvertPythonToGameObject(gameobj_py, &gameobj, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) || 01680 (mesh_py && !ConvertPythonToMesh(mesh_py, &mesh, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) 01681 ) { 01682 return NULL; 01683 } 01684 #ifdef USE_BULLET 01685 /* gameobj and mesh can be NULL */ 01686 if(KX_ReInstanceBulletShapeFromMesh(this, gameobj, mesh)) 01687 Py_RETURN_TRUE; 01688 #endif 01689 Py_RETURN_FALSE; 01690 } 01691 01692 static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) 01693 { 01694 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); 01695 const char *attr_str= _PyUnicode_AsString(item); 01696 CValue* resultattr; 01697 PyObject* pyconvert; 01698 01699 if (self==NULL) { 01700 PyErr_SetString(PyExc_SystemError, "val = gameOb[key]: KX_GameObject, "BGE_PROXY_ERROR_MSG); 01701 return NULL; 01702 } 01703 01704 /* first see if the attributes a string and try get the cvalue attribute */ 01705 if(attr_str && (resultattr=self->GetProperty(attr_str))) { 01706 pyconvert = resultattr->ConvertValueToPython(); 01707 return pyconvert ? pyconvert:resultattr->GetProxy(); 01708 } 01709 /* no CValue attribute, try get the python only m_attr_dict attribute */ 01710 else if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) { 01711 01712 if (attr_str) 01713 PyErr_Clear(); 01714 Py_INCREF(pyconvert); 01715 return pyconvert; 01716 } 01717 else { 01718 if(attr_str) PyErr_Format(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key \"%s\" does not exist", attr_str); 01719 else PyErr_SetString(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key does not exist"); 01720 return NULL; 01721 } 01722 01723 } 01724 01725 01726 static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) 01727 { 01728 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); 01729 const char *attr_str= _PyUnicode_AsString(key); 01730 if(attr_str==NULL) 01731 PyErr_Clear(); 01732 01733 if (self==NULL) { 01734 PyErr_SetString(PyExc_SystemError, "gameOb[key] = value: KX_GameObject, "BGE_PROXY_ERROR_MSG); 01735 return -1; 01736 } 01737 01738 if (val==NULL) { /* del ob["key"] */ 01739 int del= 0; 01740 01741 /* try remove both just incase */ 01742 if(attr_str) 01743 del |= (self->RemoveProperty(attr_str)==true) ? 1:0; 01744 01745 if(self->m_attr_dict) 01746 del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0; 01747 01748 if (del==0) { 01749 if(attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" could not be set", attr_str); 01750 else PyErr_SetString(PyExc_KeyError, "del gameOb[key]: KX_GameObject, key could not be deleted"); 01751 return -1; 01752 } 01753 else if (self->m_attr_dict) { 01754 PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */ 01755 } 01756 } 01757 else { /* ob["key"] = value */ 01758 int set= 0; 01759 01760 /* as CValue */ 01761 if(attr_str && PyObject_TypeCheck(val, &PyObjectPlus::Type)==0) /* dont allow GameObjects for eg to be assigned to CValue props */ 01762 { 01763 CValue* vallie = self->ConvertPythonToValue(val, ""); /* error unused */ 01764 01765 if(vallie) 01766 { 01767 CValue* oldprop = self->GetProperty(attr_str); 01768 01769 if (oldprop) 01770 oldprop->SetValue(vallie); 01771 else 01772 self->SetProperty(attr_str, vallie); 01773 01774 vallie->Release(); 01775 set= 1; 01776 01777 /* try remove dict value to avoid double ups */ 01778 if (self->m_attr_dict){ 01779 if (PyDict_DelItem(self->m_attr_dict, key) != 0) 01780 PyErr_Clear(); 01781 } 01782 } 01783 else { 01784 PyErr_Clear(); 01785 } 01786 } 01787 01788 if(set==0) 01789 { 01790 if (self->m_attr_dict==NULL) /* lazy init */ 01791 self->m_attr_dict= PyDict_New(); 01792 01793 01794 if(PyDict_SetItem(self->m_attr_dict, key, val)==0) 01795 { 01796 if(attr_str) 01797 self->RemoveProperty(attr_str); /* overwrite the CValue if it exists */ 01798 set= 1; 01799 } 01800 else { 01801 if(attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" not be added to internal dictionary", attr_str); 01802 else PyErr_SetString(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key not be added to internal dictionary"); 01803 } 01804 } 01805 01806 if(set==0) 01807 return -1; /* pythons error value */ 01808 01809 } 01810 01811 return 0; /* success */ 01812 } 01813 01814 static int Seq_Contains(PyObject *self_v, PyObject *value) 01815 { 01816 KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); 01817 01818 if (self==NULL) { 01819 PyErr_SetString(PyExc_SystemError, "val in gameOb: KX_GameObject, "BGE_PROXY_ERROR_MSG); 01820 return -1; 01821 } 01822 01823 if(PyUnicode_Check(value) && self->GetProperty(_PyUnicode_AsString(value))) 01824 return 1; 01825 01826 if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) 01827 return 1; 01828 01829 return 0; 01830 } 01831 01832 01833 PyMappingMethods KX_GameObject::Mapping = { 01834 (lenfunc)NULL , /*inquiry mp_length */ 01835 (binaryfunc)Map_GetItem, /*binaryfunc mp_subscript */ 01836 (objobjargproc)Map_SetItem, /*objobjargproc mp_ass_subscript */ 01837 }; 01838 01839 PySequenceMethods KX_GameObject::Sequence = { 01840 NULL, /* Cant set the len otherwise it can evaluate as false */ 01841 NULL, /* sq_concat */ 01842 NULL, /* sq_repeat */ 01843 NULL, /* sq_item */ 01844 NULL, /* sq_slice */ 01845 NULL, /* sq_ass_item */ 01846 NULL, /* sq_ass_slice */ 01847 (objobjproc)Seq_Contains, /* sq_contains */ 01848 (binaryfunc) NULL, /* sq_inplace_concat */ 01849 (ssizeargfunc) NULL, /* sq_inplace_repeat */ 01850 }; 01851 01852 PyTypeObject KX_GameObject::Type = { 01853 PyVarObject_HEAD_INIT(NULL, 0) 01854 "KX_GameObject", 01855 sizeof(PyObjectPlus_Proxy), 01856 0, 01857 py_base_dealloc, 01858 0, 01859 0, 01860 0, 01861 0, 01862 py_base_repr, 01863 0, 01864 &Sequence, 01865 &Mapping, 01866 0,0,0, 01867 NULL, 01868 NULL, 01869 0, 01870 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 01871 0,0,0,0,0,0,0, 01872 Methods, 01873 0, 01874 0, 01875 &SCA_IObject::Type, 01876 0,0,0,0,0,0, 01877 py_base_new 01878 }; 01879 01880 PyObject* KX_GameObject::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01881 { 01882 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01883 return PyUnicode_From_STR_String(self->GetName()); 01884 } 01885 01886 PyObject* KX_GameObject::pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01887 { 01888 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01889 KX_GameObject* parent = self->GetParent(); 01890 if (parent) { 01891 parent->Release(); /* self->GetParent() AddRef's */ 01892 return parent->GetProxy(); 01893 } 01894 Py_RETURN_NONE; 01895 } 01896 01897 PyObject* KX_GameObject::pyattr_get_life(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01898 { 01899 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01900 01901 CValue *life = self->GetProperty("::timebomb"); 01902 if (life) 01903 // this convert the timebomb seconds to frames, hard coded 50.0 (assuming 50fps) 01904 // value hardcoded in KX_Scene::AddReplicaObject() 01905 return PyFloat_FromDouble(life->GetNumber() * 50.0); 01906 else 01907 Py_RETURN_NONE; 01908 } 01909 01910 PyObject* KX_GameObject::pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01911 { 01912 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01913 KX_IPhysicsController *spc = self->GetPhysicsController(); 01914 return PyFloat_FromDouble(spc ? spc->GetMass() : 0.0f); 01915 } 01916 01917 int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 01918 { 01919 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01920 KX_IPhysicsController *spc = self->GetPhysicsController(); 01921 MT_Scalar val = PyFloat_AsDouble(value); 01922 if (val < 0.0f) { /* also accounts for non float */ 01923 PyErr_SetString(PyExc_AttributeError, "gameOb.mass = float: KX_GameObject, expected a float zero or above"); 01924 return PY_SET_ATTR_FAIL; 01925 } 01926 01927 if (spc) 01928 spc->SetMass(val); 01929 01930 return PY_SET_ATTR_SUCCESS; 01931 } 01932 01933 PyObject* KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01934 { 01935 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01936 KX_IPhysicsController *spc = self->GetPhysicsController(); 01937 return PyFloat_FromDouble(spc ? spc->GetLinVelocityMin() : 0.0f); 01938 } 01939 01940 int KX_GameObject::pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 01941 { 01942 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01943 KX_IPhysicsController *spc = self->GetPhysicsController(); 01944 MT_Scalar val = PyFloat_AsDouble(value); 01945 if (val < 0.0f) { /* also accounts for non float */ 01946 PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMin = float: KX_GameObject, expected a float zero or above"); 01947 return PY_SET_ATTR_FAIL; 01948 } 01949 01950 if (spc) 01951 spc->SetLinVelocityMin(val); 01952 01953 return PY_SET_ATTR_SUCCESS; 01954 } 01955 01956 PyObject* KX_GameObject::pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01957 { 01958 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01959 KX_IPhysicsController *spc = self->GetPhysicsController(); 01960 return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f); 01961 } 01962 01963 int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 01964 { 01965 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01966 KX_IPhysicsController *spc = self->GetPhysicsController(); 01967 MT_Scalar val = PyFloat_AsDouble(value); 01968 if (val < 0.0f) { /* also accounts for non float */ 01969 PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMax = float: KX_GameObject, expected a float zero or above"); 01970 return PY_SET_ATTR_FAIL; 01971 } 01972 01973 if (spc) 01974 spc->SetLinVelocityMax(val); 01975 01976 return PY_SET_ATTR_SUCCESS; 01977 } 01978 01979 01980 PyObject* KX_GameObject::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 01981 { 01982 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01983 return PyBool_FromLong(self->GetVisible()); 01984 } 01985 01986 int KX_GameObject::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 01987 { 01988 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 01989 int param = PyObject_IsTrue( value ); 01990 if (param == -1) { 01991 PyErr_SetString(PyExc_AttributeError, "gameOb.visible = bool: KX_GameObject, expected True or False"); 01992 return PY_SET_ATTR_FAIL; 01993 } 01994 01995 self->SetVisible(param, false); 01996 self->UpdateBuckets(false); 01997 return PY_SET_ATTR_SUCCESS; 01998 } 01999 02000 PyObject* KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02001 { 02002 #ifdef USE_MATHUTILS 02003 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); 02004 #else 02005 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02006 return PyObjectFrom(self->NodeGetWorldPosition()); 02007 #endif 02008 } 02009 02010 int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02011 { 02012 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02013 MT_Point3 pos; 02014 if (!PyVecTo(value, pos)) 02015 return PY_SET_ATTR_FAIL; 02016 02017 self->NodeSetWorldPosition(pos); 02018 self->NodeUpdateGS(0.f); 02019 return PY_SET_ATTR_SUCCESS; 02020 } 02021 02022 PyObject* KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02023 { 02024 #ifdef USE_MATHUTILS 02025 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); 02026 #else 02027 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02028 return PyObjectFrom(self->NodeGetLocalPosition()); 02029 #endif 02030 } 02031 02032 int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02033 { 02034 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02035 MT_Point3 pos; 02036 if (!PyVecTo(value, pos)) 02037 return PY_SET_ATTR_FAIL; 02038 02039 self->NodeSetLocalPosition(pos); 02040 self->NodeUpdateGS(0.f); 02041 return PY_SET_ATTR_SUCCESS; 02042 } 02043 02044 PyObject* KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02045 { 02046 #ifdef USE_MATHUTILS 02047 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); 02048 #else 02049 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02050 if (self->GetPhysicsController()) 02051 return PyObjectFrom(self->GetPhysicsController()->GetLocalInertia()); 02052 return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); 02053 #endif 02054 } 02055 02056 PyObject* KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02057 { 02058 #ifdef USE_MATHUTILS 02059 return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); 02060 #else 02061 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02062 return PyObjectFrom(self->NodeGetWorldOrientation()); 02063 #endif 02064 } 02065 02066 int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02067 { 02068 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02069 02070 /* if value is not a sequence PyOrientationTo makes an error */ 02071 MT_Matrix3x3 rot; 02072 if (!PyOrientationTo(value, rot, "gameOb.worldOrientation = sequence: KX_GameObject, ")) 02073 return PY_SET_ATTR_FAIL; 02074 02075 self->NodeSetGlobalOrientation(rot); 02076 02077 self->NodeUpdateGS(0.f); 02078 return PY_SET_ATTR_SUCCESS; 02079 } 02080 02081 PyObject* KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02082 { 02083 #ifdef USE_MATHUTILS 02084 return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); 02085 #else 02086 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02087 return PyObjectFrom(self->NodeGetLocalOrientation()); 02088 #endif 02089 } 02090 02091 int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02092 { 02093 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02094 02095 /* if value is not a sequence PyOrientationTo makes an error */ 02096 MT_Matrix3x3 rot; 02097 if (!PyOrientationTo(value, rot, "gameOb.localOrientation = sequence: KX_GameObject, ")) 02098 return PY_SET_ATTR_FAIL; 02099 02100 self->NodeSetLocalOrientation(rot); 02101 self->NodeUpdateGS(0.f); 02102 return PY_SET_ATTR_SUCCESS; 02103 } 02104 02105 PyObject* KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02106 { 02107 #ifdef USE_MATHUTILS 02108 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); 02109 #else 02110 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02111 return PyObjectFrom(self->NodeGetWorldScaling()); 02112 #endif 02113 } 02114 02115 PyObject* KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02116 { 02117 #ifdef USE_MATHUTILS 02118 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); 02119 #else 02120 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02121 return PyObjectFrom(self->NodeGetLocalScaling()); 02122 #endif 02123 } 02124 02125 int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02126 { 02127 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02128 MT_Vector3 scale; 02129 if (!PyVecTo(value, scale)) 02130 return PY_SET_ATTR_FAIL; 02131 02132 self->NodeSetLocalScale(scale); 02133 self->NodeUpdateGS(0.f); 02134 return PY_SET_ATTR_SUCCESS; 02135 } 02136 02137 02138 PyObject* KX_GameObject::pyattr_get_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02139 { 02140 #ifdef USE_MATHUTILS 02141 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); 02142 #else 02143 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02144 return PyObjectFrom(GetLinearVelocity(false)); 02145 #endif 02146 } 02147 02148 int KX_GameObject::pyattr_set_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02149 { 02150 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02151 MT_Vector3 velocity; 02152 if (!PyVecTo(value, velocity)) 02153 return PY_SET_ATTR_FAIL; 02154 02155 self->setLinearVelocity(velocity, false); 02156 02157 return PY_SET_ATTR_SUCCESS; 02158 } 02159 02160 PyObject* KX_GameObject::pyattr_get_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02161 { 02162 #ifdef USE_MATHUTILS 02163 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); 02164 #else 02165 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02166 return PyObjectFrom(GetLinearVelocity(true)); 02167 #endif 02168 } 02169 02170 int KX_GameObject::pyattr_set_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02171 { 02172 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02173 MT_Vector3 velocity; 02174 if (!PyVecTo(value, velocity)) 02175 return PY_SET_ATTR_FAIL; 02176 02177 self->setLinearVelocity(velocity, true); 02178 02179 return PY_SET_ATTR_SUCCESS; 02180 } 02181 02182 PyObject* KX_GameObject::pyattr_get_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02183 { 02184 #ifdef USE_MATHUTILS 02185 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); 02186 #else 02187 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02188 return PyObjectFrom(GetAngularVelocity(false)); 02189 #endif 02190 } 02191 02192 int KX_GameObject::pyattr_set_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02193 { 02194 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02195 MT_Vector3 velocity; 02196 if (!PyVecTo(value, velocity)) 02197 return PY_SET_ATTR_FAIL; 02198 02199 self->setAngularVelocity(velocity, false); 02200 02201 return PY_SET_ATTR_SUCCESS; 02202 } 02203 02204 PyObject* KX_GameObject::pyattr_get_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02205 { 02206 #ifdef USE_MATHUTILS 02207 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); 02208 #else 02209 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02210 return PyObjectFrom(GetAngularVelocity(true)); 02211 #endif 02212 } 02213 02214 int KX_GameObject::pyattr_set_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02215 { 02216 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02217 MT_Vector3 velocity; 02218 if (!PyVecTo(value, velocity)) 02219 return PY_SET_ATTR_FAIL; 02220 02221 self->setAngularVelocity(velocity, true); 02222 02223 return PY_SET_ATTR_SUCCESS; 02224 } 02225 02226 02227 PyObject* KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02228 { 02229 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02230 SG_Node* sg_parent; 02231 if (self->GetSGNode() && (sg_parent = self->GetSGNode()->GetSGParent()) != NULL && sg_parent->IsSlowParent()) { 02232 return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(sg_parent->GetParentRelation())->GetTimeOffset()); 02233 } else { 02234 return PyFloat_FromDouble(0.0); 02235 } 02236 } 02237 02238 int KX_GameObject::pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02239 { 02240 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02241 if (self->GetSGNode()) { 02242 MT_Scalar val = PyFloat_AsDouble(value); 02243 SG_Node* sg_parent= self->GetSGNode()->GetSGParent(); 02244 if (val < 0.0f) { /* also accounts for non float */ 02245 PyErr_SetString(PyExc_AttributeError, "gameOb.timeOffset = float: KX_GameObject, expected a float zero or above"); 02246 return PY_SET_ATTR_FAIL; 02247 } 02248 if (sg_parent && sg_parent->IsSlowParent()) 02249 static_cast<KX_SlowParentRelation *>(sg_parent->GetParentRelation())->SetTimeOffset(val); 02250 } 02251 return PY_SET_ATTR_SUCCESS; 02252 } 02253 02254 PyObject* KX_GameObject::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02255 { 02256 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02257 int state = 0; 02258 state |= self->GetState(); 02259 return PyLong_FromSsize_t(state); 02260 } 02261 02262 int KX_GameObject::pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02263 { 02264 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02265 int state_i = PyLong_AsSsize_t(value); 02266 unsigned int state = 0; 02267 02268 if (state_i == -1 && PyErr_Occurred()) { 02269 PyErr_SetString(PyExc_TypeError, "gameOb.state = int: KX_GameObject, expected an int bit field"); 02270 return PY_SET_ATTR_FAIL; 02271 } 02272 02273 state |= state_i; 02274 if ((state & ((1<<30)-1)) == 0) { 02275 PyErr_SetString(PyExc_AttributeError, "gameOb.state = int: KX_GameObject, state bitfield was not between 0 and 30 (1<<0 and 1<<29)"); 02276 return PY_SET_ATTR_FAIL; 02277 } 02278 self->SetState(state); 02279 return PY_SET_ATTR_SUCCESS; 02280 } 02281 02282 PyObject* KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02283 { 02284 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02285 PyObject *meshes= PyList_New(self->m_meshes.size()); 02286 int i; 02287 02288 for(i=0; i < (int)self->m_meshes.size(); i++) 02289 { 02290 KX_MeshProxy* meshproxy = new KX_MeshProxy(self->m_meshes[i]); 02291 PyList_SET_ITEM(meshes, i, meshproxy->NewProxy(true)); 02292 } 02293 02294 return meshes; 02295 } 02296 02297 PyObject* KX_GameObject::pyattr_get_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02298 { 02299 #ifdef USE_MATHUTILS 02300 return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 4, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); 02301 #else 02302 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02303 return PyObjectFrom(self->GetObjectColor()); 02304 #endif 02305 } 02306 02307 int KX_GameObject::pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 02308 { 02309 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02310 MT_Vector4 obcolor; 02311 if (!PyVecTo(value, obcolor)) 02312 return PY_SET_ATTR_FAIL; 02313 02314 self->SetObjectColor(obcolor); 02315 return PY_SET_ATTR_SUCCESS; 02316 } 02317 02318 /* These are experimental! */ 02319 PyObject* KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02320 { 02321 return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_SENSORS); 02322 } 02323 02324 PyObject* KX_GameObject::pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02325 { 02326 return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONTROLLERS); 02327 } 02328 02329 PyObject* KX_GameObject::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02330 { 02331 return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_ACTUATORS); 02332 } 02333 /* End experimental */ 02334 02335 PyObject* KX_GameObject::pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02336 { 02337 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02338 return self->GetChildren()->NewProxy(true); 02339 } 02340 02341 PyObject* KX_GameObject::pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02342 { 02343 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02344 return self->GetChildrenRecursive()->NewProxy(true); 02345 } 02346 02347 PyObject* KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 02348 { 02349 KX_GameObject* self= static_cast<KX_GameObject*>(self_v); 02350 02351 if(self->m_attr_dict==NULL) 02352 self->m_attr_dict= PyDict_New(); 02353 02354 Py_INCREF(self->m_attr_dict); 02355 return self->m_attr_dict; 02356 } 02357 02358 PyObject* KX_GameObject::PyApplyForce(PyObject* args) 02359 { 02360 int local = 0; 02361 PyObject* pyvect; 02362 02363 if (PyArg_ParseTuple(args, "O|i:applyForce", &pyvect, &local)) { 02364 MT_Vector3 force; 02365 if (PyVecTo(pyvect, force)) { 02366 ApplyForce(force, (local!=0)); 02367 Py_RETURN_NONE; 02368 } 02369 } 02370 return NULL; 02371 } 02372 02373 PyObject* KX_GameObject::PyApplyTorque(PyObject* args) 02374 { 02375 int local = 0; 02376 PyObject* pyvect; 02377 02378 if (PyArg_ParseTuple(args, "O|i:applyTorque", &pyvect, &local)) { 02379 MT_Vector3 torque; 02380 if (PyVecTo(pyvect, torque)) { 02381 ApplyTorque(torque, (local!=0)); 02382 Py_RETURN_NONE; 02383 } 02384 } 02385 return NULL; 02386 } 02387 02388 PyObject* KX_GameObject::PyApplyRotation(PyObject* args) 02389 { 02390 int local = 0; 02391 PyObject* pyvect; 02392 02393 if (PyArg_ParseTuple(args, "O|i:applyRotation", &pyvect, &local)) { 02394 MT_Vector3 rotation; 02395 if (PyVecTo(pyvect, rotation)) { 02396 ApplyRotation(rotation, (local!=0)); 02397 Py_RETURN_NONE; 02398 } 02399 } 02400 return NULL; 02401 } 02402 02403 PyObject* KX_GameObject::PyApplyMovement(PyObject* args) 02404 { 02405 int local = 0; 02406 PyObject* pyvect; 02407 02408 if (PyArg_ParseTuple(args, "O|i:applyMovement", &pyvect, &local)) { 02409 MT_Vector3 movement; 02410 if (PyVecTo(pyvect, movement)) { 02411 ApplyMovement(movement, (local!=0)); 02412 Py_RETURN_NONE; 02413 } 02414 } 02415 return NULL; 02416 } 02417 02418 PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* args) 02419 { 02420 // only can get the velocity if we have a physics object connected to us... 02421 int local = 0; 02422 if (PyArg_ParseTuple(args,"|i:getLinearVelocity",&local)) 02423 { 02424 return PyObjectFrom(GetLinearVelocity((local!=0))); 02425 } 02426 else 02427 { 02428 return NULL; 02429 } 02430 } 02431 02432 PyObject* KX_GameObject::PySetLinearVelocity(PyObject* args) 02433 { 02434 int local = 0; 02435 PyObject* pyvect; 02436 02437 if (PyArg_ParseTuple(args,"O|i:setLinearVelocity",&pyvect,&local)) { 02438 MT_Vector3 velocity; 02439 if (PyVecTo(pyvect, velocity)) { 02440 setLinearVelocity(velocity, (local!=0)); 02441 Py_RETURN_NONE; 02442 } 02443 } 02444 return NULL; 02445 } 02446 02447 PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* args) 02448 { 02449 // only can get the velocity if we have a physics object connected to us... 02450 int local = 0; 02451 if (PyArg_ParseTuple(args,"|i:getAngularVelocity",&local)) 02452 { 02453 return PyObjectFrom(GetAngularVelocity((local!=0))); 02454 } 02455 else 02456 { 02457 return NULL; 02458 } 02459 } 02460 02461 PyObject* KX_GameObject::PySetAngularVelocity(PyObject* args) 02462 { 02463 int local = 0; 02464 PyObject* pyvect; 02465 02466 if (PyArg_ParseTuple(args,"O|i:setAngularVelocity",&pyvect,&local)) { 02467 MT_Vector3 velocity; 02468 if (PyVecTo(pyvect, velocity)) { 02469 setAngularVelocity(velocity, (local!=0)); 02470 Py_RETURN_NONE; 02471 } 02472 } 02473 return NULL; 02474 } 02475 02476 PyObject* KX_GameObject::PySetVisible(PyObject* args) 02477 { 02478 int visible, recursive = 0; 02479 if (!PyArg_ParseTuple(args,"i|i:setVisible",&visible, &recursive)) 02480 return NULL; 02481 02482 SetVisible(visible ? true:false, recursive ? true:false); 02483 UpdateBuckets(recursive ? true:false); 02484 Py_RETURN_NONE; 02485 02486 } 02487 02488 PyObject* KX_GameObject::PySetOcclusion(PyObject* args) 02489 { 02490 int occlusion, recursive = 0; 02491 if (!PyArg_ParseTuple(args,"i|i:setOcclusion",&occlusion, &recursive)) 02492 return NULL; 02493 02494 SetOccluder(occlusion ? true:false, recursive ? true:false); 02495 Py_RETURN_NONE; 02496 } 02497 02498 PyObject* KX_GameObject::PyGetVelocity(PyObject* args) 02499 { 02500 // only can get the velocity if we have a physics object connected to us... 02501 MT_Point3 point(0.0,0.0,0.0); 02502 PyObject* pypos = NULL; 02503 02504 if (!PyArg_ParseTuple(args, "|O:getVelocity", &pypos) || (pypos && !PyVecTo(pypos, point))) 02505 return NULL; 02506 02507 if (m_pPhysicsController1) 02508 { 02509 return PyObjectFrom(m_pPhysicsController1->GetVelocity(point)); 02510 } 02511 else { 02512 return PyObjectFrom(MT_Vector3(0.0,0.0,0.0)); 02513 } 02514 } 02515 02516 PyObject* KX_GameObject::PyGetReactionForce() 02517 { 02518 // only can get the velocity if we have a physics object connected to us... 02519 02520 // XXX - Currently not working with bullet intergration, see KX_BulletPhysicsController.cpp's getReactionForce 02521 /* 02522 if (GetPhysicsController()) 02523 return PyObjectFrom(GetPhysicsController()->getReactionForce()); 02524 return PyObjectFrom(dummy_point); 02525 */ 02526 02527 return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); 02528 02529 } 02530 02531 02532 02533 PyObject* KX_GameObject::PyEnableRigidBody() 02534 { 02535 if(GetPhysicsController()) 02536 GetPhysicsController()->setRigidBody(true); 02537 02538 Py_RETURN_NONE; 02539 } 02540 02541 02542 02543 PyObject* KX_GameObject::PyDisableRigidBody() 02544 { 02545 if(GetPhysicsController()) 02546 GetPhysicsController()->setRigidBody(false); 02547 02548 Py_RETURN_NONE; 02549 } 02550 02551 02552 PyObject* KX_GameObject::PySetParent(PyObject* args) 02553 { 02554 KX_Scene *scene = KX_GetActiveScene(); 02555 PyObject* pyobj; 02556 KX_GameObject *obj; 02557 int addToCompound=1, ghost=1; 02558 02559 if (!PyArg_ParseTuple(args,"O|ii:setParent", &pyobj, &addToCompound, &ghost)) { 02560 return NULL; // Python sets a simple error 02561 } 02562 if (!ConvertPythonToGameObject(pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject")) 02563 return NULL; 02564 if (obj) 02565 this->SetParent(scene, obj, addToCompound, ghost); 02566 Py_RETURN_NONE; 02567 } 02568 02569 PyObject* KX_GameObject::PyRemoveParent() 02570 { 02571 KX_Scene *scene = KX_GetActiveScene(); 02572 02573 this->RemoveParent(scene); 02574 Py_RETURN_NONE; 02575 } 02576 02577 02578 PyObject* KX_GameObject::PySetCollisionMargin(PyObject* value) 02579 { 02580 float collisionMargin = PyFloat_AsDouble(value); 02581 02582 if (collisionMargin==-1 && PyErr_Occurred()) { 02583 PyErr_SetString(PyExc_TypeError, "expected a float"); 02584 return NULL; 02585 } 02586 02587 if (m_pPhysicsController1) 02588 { 02589 m_pPhysicsController1->setMargin(collisionMargin); 02590 Py_RETURN_NONE; 02591 } 02592 PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller"); 02593 return NULL; 02594 } 02595 02596 02597 02598 PyObject* KX_GameObject::PyApplyImpulse(PyObject* args) 02599 { 02600 PyObject* pyattach; 02601 PyObject* pyimpulse; 02602 02603 if (!m_pPhysicsController1) { 02604 PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller"); 02605 return NULL; 02606 } 02607 02608 if (PyArg_ParseTuple(args, "OO:applyImpulse", &pyattach, &pyimpulse)) 02609 { 02610 MT_Point3 attach; 02611 MT_Vector3 impulse; 02612 if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse)) 02613 { 02614 m_pPhysicsController1->applyImpulse(attach, impulse); 02615 Py_RETURN_NONE; 02616 } 02617 02618 } 02619 02620 return NULL; 02621 } 02622 02623 02624 02625 PyObject* KX_GameObject::PySuspendDynamics() 02626 { 02627 SuspendDynamics(); 02628 Py_RETURN_NONE; 02629 } 02630 02631 02632 02633 PyObject* KX_GameObject::PyRestoreDynamics() 02634 { 02635 RestoreDynamics(); 02636 Py_RETURN_NONE; 02637 } 02638 02639 02640 PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* args) 02641 { 02642 PyObject* pyvect; 02643 int axis = 2; //z axis is the default 02644 float fac = 1.0; 02645 02646 if (PyArg_ParseTuple(args,"O|if:alignAxisToVect",&pyvect,&axis, &fac)) 02647 { 02648 MT_Vector3 vect; 02649 if (PyVecTo(pyvect, vect)) 02650 { 02651 if (fac<=0.0) Py_RETURN_NONE; // Nothing to do. 02652 if (fac> 1.0) fac= 1.0; 02653 02654 AlignAxisToVect(vect,axis,fac); 02655 NodeUpdateGS(0.f); 02656 Py_RETURN_NONE; 02657 } 02658 } 02659 return NULL; 02660 } 02661 02662 PyObject* KX_GameObject::PyGetAxisVect(PyObject* value) 02663 { 02664 MT_Vector3 vect; 02665 if (PyVecTo(value, vect)) 02666 { 02667 return PyObjectFrom(NodeGetWorldOrientation() * vect); 02668 } 02669 return NULL; 02670 } 02671 02672 02673 PyObject* KX_GameObject::PyGetPhysicsId() 02674 { 02675 KX_IPhysicsController* ctrl = GetPhysicsController(); 02676 uint_ptr physid=0; 02677 if (ctrl) 02678 { 02679 physid= (uint_ptr)ctrl->GetUserData(); 02680 } 02681 return PyLong_FromSsize_t((long)physid); 02682 } 02683 02684 PyObject* KX_GameObject::PyGetPropertyNames() 02685 { 02686 PyObject *list= ConvertKeysToPython(); 02687 02688 if(m_attr_dict) { 02689 PyObject *key, *value; 02690 Py_ssize_t pos = 0; 02691 02692 while (PyDict_Next(m_attr_dict, &pos, &key, &value)) { 02693 PyList_Append(list, key); 02694 } 02695 } 02696 return list; 02697 } 02698 02699 KX_PYMETHODDEF_DOC_O(KX_GameObject, getDistanceTo, 02700 "getDistanceTo(other): get distance to another point/KX_GameObject") 02701 { 02702 MT_Point3 b; 02703 if (PyVecTo(value, b)) 02704 { 02705 return PyFloat_FromDouble(NodeGetWorldPosition().distance(b)); 02706 } 02707 PyErr_Clear(); 02708 02709 KX_GameObject *other; 02710 if (ConvertPythonToGameObject(value, &other, false, "gameOb.getDistanceTo(value): KX_GameObject")) 02711 { 02712 return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition())); 02713 } 02714 02715 return NULL; 02716 } 02717 02718 KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo, 02719 "getVectTo(other): get vector and the distance to another point/KX_GameObject\n" 02720 "Returns a 3-tuple with (distance,worldVector,localVector)\n") 02721 { 02722 MT_Point3 toPoint, fromPoint; 02723 MT_Vector3 toDir, locToDir; 02724 MT_Scalar distance; 02725 02726 PyObject *returnValue; 02727 02728 if (!PyVecTo(value, toPoint)) 02729 { 02730 PyErr_Clear(); 02731 02732 KX_GameObject *other; 02733 if (ConvertPythonToGameObject(value, &other, false, "")) /* error will be overwritten */ 02734 { 02735 toPoint = other->NodeGetWorldPosition(); 02736 } else 02737 { 02738 PyErr_SetString(PyExc_TypeError, "gameOb.getVectTo(other): KX_GameObject, expected a 3D Vector or KX_GameObject type"); 02739 return NULL; 02740 } 02741 } 02742 02743 fromPoint = NodeGetWorldPosition(); 02744 toDir = toPoint-fromPoint; 02745 distance = toDir.length(); 02746 02747 if (MT_fuzzyZero(distance)) 02748 { 02749 //cout << "getVectTo() Error: Null vector!\n"; 02750 locToDir = toDir = MT_Vector3(0.0,0.0,0.0); 02751 distance = 0.0; 02752 } else { 02753 toDir.normalize(); 02754 locToDir = toDir * NodeGetWorldOrientation(); 02755 } 02756 02757 returnValue = PyTuple_New(3); 02758 if (returnValue) { // very unlikely to fail, python sets a memory error here. 02759 PyTuple_SET_ITEM(returnValue, 0, PyFloat_FromDouble(distance)); 02760 PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(toDir)); 02761 PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(locToDir)); 02762 } 02763 return returnValue; 02764 } 02765 02766 bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) 02767 { 02768 KX_GameObject* hitKXObj = client->m_gameobject; 02769 02770 // if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit 02771 // if not, all objects were tested and the front one may not be the correct one. 02772 if (m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) 02773 { 02774 m_pHitObject = hitKXObj; 02775 return true; 02776 } 02777 // return true to stop RayCast::RayTest from looping, the above test was decisive 02778 // We would want to loop only if we want to get more than one hit point 02779 return true; 02780 } 02781 02782 /* this function is used to pre-filter the object before casting the ray on them. 02783 This is useful for "X-Ray" option when we want to see "through" unwanted object. 02784 */ 02785 bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo* client) 02786 { 02787 KX_GameObject* hitKXObj = client->m_gameobject; 02788 02789 if (client->m_type > KX_ClientObjectInfo::ACTOR) 02790 { 02791 // Unknown type of object, skip it. 02792 // Should not occur as the sensor objects are filtered in RayTest() 02793 printf("Invalid client type %d found in ray casting\n", client->m_type); 02794 return false; 02795 } 02796 02797 // if X-Ray option is selected, skip object that don't match the criteria as we see through them 02798 // if not, test all objects because we don't know yet which one will be on front 02799 if (!m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) 02800 { 02801 return true; 02802 } 02803 // skip the object 02804 return false; 02805 } 02806 02807 KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, 02808 "rayCastTo(other,dist,prop): look towards another point/KX_GameObject and return first object hit within dist that matches prop\n" 02809 " prop = property name that object must have; can be omitted => detect any object\n" 02810 " dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to other\n" 02811 " other = 3-tuple or object reference") 02812 { 02813 MT_Point3 toPoint; 02814 PyObject* pyarg; 02815 float dist = 0.0f; 02816 char *propName = NULL; 02817 02818 if (!PyArg_ParseTuple(args,"O|fs:rayCastTo", &pyarg, &dist, &propName)) { 02819 return NULL; // python sets simple error 02820 } 02821 02822 if (!PyVecTo(pyarg, toPoint)) 02823 { 02824 KX_GameObject *other; 02825 PyErr_Clear(); 02826 02827 if (ConvertPythonToGameObject(pyarg, &other, false, "")) /* error will be overwritten */ 02828 { 02829 toPoint = other->NodeGetWorldPosition(); 02830 } else 02831 { 02832 PyErr_SetString(PyExc_TypeError, "gameOb.rayCastTo(other,dist,prop): KX_GameObject, the first argument to rayCastTo must be a vector or a KX_GameObject"); 02833 return NULL; 02834 } 02835 } 02836 MT_Point3 fromPoint = NodeGetWorldPosition(); 02837 02838 if (dist != 0.0f) 02839 toPoint = fromPoint + dist * (toPoint-fromPoint).safe_normalized(); 02840 02841 PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); 02842 KX_IPhysicsController *spc = GetPhysicsController(); 02843 KX_GameObject *parent = GetParent(); 02844 if (!spc && parent) 02845 spc = parent->GetPhysicsController(); 02846 if (parent) 02847 parent->Release(); 02848 02849 m_pHitObject = NULL; 02850 if (propName) 02851 m_testPropName = propName; 02852 else 02853 m_testPropName.SetLength(0); 02854 KX_RayCast::Callback<KX_GameObject> callback(this,spc); 02855 KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); 02856 02857 if (m_pHitObject) 02858 return m_pHitObject->GetProxy(); 02859 02860 Py_RETURN_NONE; 02861 } 02862 02863 /* faster then Py_BuildValue since some scripts call raycast a lot */ 02864 static PyObject *none_tuple_3() 02865 { 02866 PyObject *ret= PyTuple_New(3); 02867 PyTuple_SET_ITEM(ret, 0, Py_None); 02868 PyTuple_SET_ITEM(ret, 1, Py_None); 02869 PyTuple_SET_ITEM(ret, 2, Py_None); 02870 02871 Py_INCREF(Py_None); 02872 Py_INCREF(Py_None); 02873 Py_INCREF(Py_None); 02874 return ret; 02875 } 02876 static PyObject *none_tuple_4() 02877 { 02878 PyObject *ret= PyTuple_New(4); 02879 PyTuple_SET_ITEM(ret, 0, Py_None); 02880 PyTuple_SET_ITEM(ret, 1, Py_None); 02881 PyTuple_SET_ITEM(ret, 2, Py_None); 02882 PyTuple_SET_ITEM(ret, 3, Py_None); 02883 02884 Py_INCREF(Py_None); 02885 Py_INCREF(Py_None); 02886 Py_INCREF(Py_None); 02887 Py_INCREF(Py_None); 02888 return ret; 02889 } 02890 02891 static PyObject *none_tuple_5() 02892 { 02893 PyObject *ret= PyTuple_New(5); 02894 PyTuple_SET_ITEM(ret, 0, Py_None); 02895 PyTuple_SET_ITEM(ret, 1, Py_None); 02896 PyTuple_SET_ITEM(ret, 2, Py_None); 02897 PyTuple_SET_ITEM(ret, 3, Py_None); 02898 PyTuple_SET_ITEM(ret, 4, Py_None); 02899 02900 Py_INCREF(Py_None); 02901 Py_INCREF(Py_None); 02902 Py_INCREF(Py_None); 02903 Py_INCREF(Py_None); 02904 Py_INCREF(Py_None); 02905 return ret; 02906 } 02907 02908 KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, 02909 "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) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n" 02910 " If no hit, return (None,None,None) or (None,None,None,None) or (None,None,None,None,None).\n" 02911 " to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" 02912 " from = 3-tuple or object reference for origin of ray (if object, use center of object)\n" 02913 " Can be None or omitted => start from self object center\n" 02914 " dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" 02915 " prop = property name that object must have; can be omitted => detect any object\n" 02916 " face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n" 02917 " xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n" 02918 " poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n" 02919 " which can be None if hit object has no mesh or if there is no hit\n" 02920 " 2=>return value is a 5-tuple, the 4th element is the KX_PolyProxy object\n" 02921 " and the 5th element is the vector of UV coordinates at the hit point of the None if there is no UV mapping\n" 02922 " If 0 or omitted, return value is a 3-tuple\n" 02923 "Note: The object on which you call this method matters: the ray will ignore it.\n" 02924 " prop and xray option interact as follow:\n" 02925 " prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n" 02926 " prop off, xray on : idem\n" 02927 " prop on, xray off: return closest hit if it matches prop, no hit otherwise\n" 02928 " prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n") 02929 { 02930 MT_Point3 toPoint; 02931 MT_Point3 fromPoint; 02932 PyObject* pyto; 02933 PyObject* pyfrom = NULL; 02934 float dist = 0.0f; 02935 char *propName = NULL; 02936 KX_GameObject *other; 02937 int face=0, xray=0, poly=0; 02938 02939 if (!PyArg_ParseTuple(args,"O|Ofsiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { 02940 return NULL; // Python sets a simple error 02941 } 02942 02943 if (!PyVecTo(pyto, toPoint)) 02944 { 02945 PyErr_Clear(); 02946 02947 if (ConvertPythonToGameObject(pyto, &other, false, "")) /* error will be overwritten */ 02948 { 02949 toPoint = other->NodeGetWorldPosition(); 02950 } else 02951 { 02952 PyErr_SetString(PyExc_TypeError, "the first argument to rayCast must be a vector or a KX_GameObject"); 02953 return NULL; 02954 } 02955 } 02956 if (!pyfrom || pyfrom == Py_None) 02957 { 02958 fromPoint = NodeGetWorldPosition(); 02959 } 02960 else if (!PyVecTo(pyfrom, fromPoint)) 02961 { 02962 PyErr_Clear(); 02963 02964 if (ConvertPythonToGameObject(pyfrom, &other, false, "")) /* error will be overwritten */ 02965 { 02966 fromPoint = other->NodeGetWorldPosition(); 02967 } else 02968 { 02969 PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject"); 02970 return NULL; 02971 } 02972 } 02973 02974 if (dist != 0.0f) { 02975 MT_Vector3 toDir = toPoint-fromPoint; 02976 if (MT_fuzzyZero(toDir.length2())) { 02977 //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); 02978 return none_tuple_3(); 02979 } 02980 toDir.normalize(); 02981 toPoint = fromPoint + (dist) * toDir; 02982 } else if (MT_fuzzyZero((toPoint-fromPoint).length2())) { 02983 //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); 02984 return none_tuple_3(); 02985 } 02986 02987 PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); 02988 KX_IPhysicsController *spc = GetPhysicsController(); 02989 KX_GameObject *parent = GetParent(); 02990 if (!spc && parent) 02991 spc = parent->GetPhysicsController(); 02992 if (parent) 02993 parent->Release(); 02994 02995 m_pHitObject = NULL; 02996 if (propName) 02997 m_testPropName = propName; 02998 else 02999 m_testPropName.SetLength(0); 03000 m_xray = xray; 03001 // to get the hit results 03002 KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face,(poly==2)); 03003 KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); 03004 03005 if (m_pHitObject) 03006 { 03007 PyObject* returnValue = (poly==2) ? PyTuple_New(5) : (poly) ? PyTuple_New(4) : PyTuple_New(3); 03008 if (returnValue) { // unlikely this would ever fail, if it does python sets an error 03009 PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->GetProxy()); 03010 PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint)); 03011 PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal)); 03012 if (poly) 03013 { 03014 if (callback.m_hitMesh) 03015 { 03016 // if this field is set, then we can trust that m_hitPolygon is a valid polygon 03017 RAS_Polygon* polygon = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); 03018 KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, polygon); 03019 PyTuple_SET_ITEM(returnValue, 3, polyproxy->NewProxy(true)); 03020 if (poly == 2) 03021 { 03022 if (callback.m_hitUVOK) 03023 PyTuple_SET_ITEM(returnValue, 4, PyObjectFrom(callback.m_hitUV)); 03024 else { 03025 Py_INCREF(Py_None); 03026 PyTuple_SET_ITEM(returnValue, 4, Py_None); 03027 } 03028 } 03029 } 03030 else 03031 { 03032 Py_INCREF(Py_None); 03033 PyTuple_SET_ITEM(returnValue, 3, Py_None); 03034 if (poly==2) 03035 { 03036 Py_INCREF(Py_None); 03037 PyTuple_SET_ITEM(returnValue, 4, Py_None); 03038 } 03039 } 03040 } 03041 } 03042 return returnValue; 03043 } 03044 // no hit 03045 if (poly == 2) 03046 return none_tuple_5(); 03047 else if (poly) 03048 return none_tuple_4(); 03049 else 03050 return none_tuple_3(); 03051 } 03052 03053 KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, 03054 "sendMessage(subject, [body, to])\n" 03055 "sends a message in same manner as a message actuator" 03056 "subject = Subject of the message (string)" 03057 "body = Message body (string)" 03058 "to = Name of object to send the message to") 03059 { 03060 KX_Scene *scene = KX_GetActiveScene(); 03061 char* subject; 03062 char* body = (char *)""; 03063 char* to = (char *)""; 03064 const STR_String& from = GetName(); 03065 03066 if (!PyArg_ParseTuple(args, "s|ss:sendMessage", &subject, &body, &to)) 03067 return NULL; 03068 03069 scene->GetNetworkScene()->SendMessage(to, from, subject, body); 03070 Py_RETURN_NONE; 03071 } 03072 03073 static void layer_check(short &layer, const char *method_name) 03074 { 03075 if (layer < 0 || layer >= MAX_ACTION_LAYERS) 03076 { 03077 printf("KX_GameObject.%s(): given layer (%d) is out of range (0 - %d), setting to 0.\n", method_name, layer, MAX_ACTION_LAYERS-1); 03078 layer = 0; 03079 } 03080 } 03081 03082 KX_PYMETHODDEF_DOC(KX_GameObject, playAction, 03083 "playAction(name, start_frame, end_frame, layer=0, priority=0 blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0)\n" 03084 "Plays an action\n") 03085 { 03086 const char* name; 03087 float start, end, blendin=0.f, speed=1.f, layer_weight=0.f; 03088 short layer=0, priority=0; 03089 short ipo_flags=0; 03090 short play_mode=0; 03091 03092 static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", NULL}; 03093 03094 if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhf:playAction", const_cast<char**>(kwlist), 03095 &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed)) 03096 return NULL; 03097 03098 layer_check(layer, "playAction"); 03099 03100 if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX) 03101 { 03102 printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1); 03103 play_mode = BL_Action::ACT_MODE_MAX; 03104 } 03105 03106 if (layer_weight < 0.f || layer_weight > 1.f) 03107 { 03108 printf("KX_GameObject.playAction(): given layer_weight (%f) is out of range (0.0 - 1.0), setting to 0.0", layer_weight); 03109 layer_weight = 0.f; 03110 } 03111 03112 PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed); 03113 03114 Py_RETURN_NONE; 03115 } 03116 03117 KX_PYMETHODDEF_DOC(KX_GameObject, stopAction, 03118 "stopAction(layer=0)\n" 03119 "Stop playing the action on the given layer\n") 03120 { 03121 short layer=0; 03122 03123 if (!PyArg_ParseTuple(args, "|h:stopAction", &layer)) 03124 return NULL; 03125 03126 layer_check(layer, "stopAction"); 03127 03128 StopAction(layer); 03129 03130 Py_RETURN_NONE; 03131 } 03132 03133 KX_PYMETHODDEF_DOC(KX_GameObject, getActionFrame, 03134 "getActionFrame(layer=0)\n" 03135 "Gets the current frame of the action playing in the supplied layer\n") 03136 { 03137 short layer=0; 03138 03139 if (!PyArg_ParseTuple(args, "|h:getActionFrame", &layer)) 03140 return NULL; 03141 03142 layer_check(layer, "getActionFrame"); 03143 03144 return PyFloat_FromDouble(GetActionFrame(layer)); 03145 } 03146 03147 KX_PYMETHODDEF_DOC(KX_GameObject, setActionFrame, 03148 "setActionFrame(frame, layer=0)\n" 03149 "Set the current frame of the action playing in the supplied layer\n") 03150 { 03151 short layer=0; 03152 float frame; 03153 03154 if (!PyArg_ParseTuple(args, "f|h:setActionFrame", &frame, &layer)) 03155 return NULL; 03156 03157 layer_check(layer, "setActionFrame"); 03158 03159 SetActionFrame(layer, frame); 03160 03161 Py_RETURN_NONE; 03162 } 03163 03164 KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, 03165 "isPlayingAction(layer=0)\n" 03166 "Checks to see if there is an action playing in the given layer\n") 03167 { 03168 short layer=0; 03169 03170 if (!PyArg_ParseTuple(args, "|h:isPlayingAction", &layer)) 03171 return NULL; 03172 03173 layer_check(layer, "isPlayingAction"); 03174 03175 return PyBool_FromLong(!IsActionDone(layer)); 03176 } 03177 03178 03179 /* dict style access */ 03180 03181 03182 /* Matches python dict.get(key, [default]) */ 03183 PyObject* KX_GameObject::Pyget(PyObject *args) 03184 { 03185 PyObject *key; 03186 PyObject* def = Py_None; 03187 PyObject* ret; 03188 03189 if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) 03190 return NULL; 03191 03192 03193 if(PyUnicode_Check(key)) { 03194 CValue *item = GetProperty(_PyUnicode_AsString(key)); 03195 if (item) { 03196 ret = item->ConvertValueToPython(); 03197 if(ret) 03198 return ret; 03199 else 03200 return item->GetProxy(); 03201 } 03202 } 03203 03204 if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) { 03205 Py_INCREF(ret); 03206 return ret; 03207 } 03208 03209 Py_INCREF(def); 03210 return def; 03211 } 03212 03213 bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok, const char *error_prefix) 03214 { 03215 if (value==NULL) { 03216 PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); 03217 *object = NULL; 03218 return false; 03219 } 03220 03221 if (value==Py_None) { 03222 *object = NULL; 03223 03224 if (py_none_ok) { 03225 return true; 03226 } else { 03227 PyErr_Format(PyExc_TypeError, "%s, expected KX_GameObject or a KX_GameObject name, None is invalid", error_prefix); 03228 return false; 03229 } 03230 } 03231 03232 if (PyUnicode_Check(value)) { 03233 *object = (KX_GameObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) )); 03234 03235 if (*object) { 03236 return true; 03237 } else { 03238 PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_GameObject in this scene", error_prefix, _PyUnicode_AsString(value)); 03239 return false; 03240 } 03241 } 03242 03243 if ( PyObject_TypeCheck(value, &KX_GameObject::Type) || 03244 PyObject_TypeCheck(value, &KX_LightObject::Type) || 03245 PyObject_TypeCheck(value, &KX_Camera::Type) || 03246 PyObject_TypeCheck(value, &KX_FontObject::Type)) 03247 { 03248 *object = static_cast<KX_GameObject*>BGE_PROXY_REF(value); 03249 03250 /* sets the error */ 03251 if (*object==NULL) { 03252 PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); 03253 return false; 03254 } 03255 03256 return true; 03257 } 03258 03259 *object = NULL; 03260 03261 if (py_none_ok) { 03262 PyErr_Format(PyExc_TypeError, "%s, expect a KX_GameObject, a string or None", error_prefix); 03263 } else { 03264 PyErr_Format(PyExc_TypeError, "%s, expect a KX_GameObject or a string", error_prefix); 03265 } 03266 03267 return false; 03268 } 03269 #endif // WITH_PYTHON