/**
 * $Id: KX_GameObject.cpp,v 1.9 2004/07/17 05:28:21 kester Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 * Game object wrapper
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef WIN32
// This warning tells us about truncation of __long__ stl-generated names.
// It can occasionally cause DevStudio to have internal compiler warnings.
#pragma warning( disable : 4786 )     
#endif


#define KX_INERTIA_INFINITE 10000
#include "RAS_IPolygonMaterial.h"
#include "KX_GameObject.h"
#include "RAS_MeshObject.h"
#include "KX_MeshProxy.h"
#include <stdio.h> // printf
#include "SG_Controller.h"
#include "KX_IPhysicsController.h"
#include "SG_Node.h"
#include "SG_Controller.h"
#include "KX_ClientObjectInfo.h"
#include "RAS_BucketManager.h"

#include "KX_PyMath.h"

// This file defines relationships between parents and children
// in the game engine.

#include "KX_SG_NodeRelationships.h"

KX_GameObject::KX_GameObject(
	void* sgReplicationInfo,
	SG_Callbacks callbacks,
	PyTypeObject* T
) : 
	SCA_IObject(T),
	m_bDyna(false),
	m_bSuspendDynamics(false),
	m_bUseObjectColor(false),
	m_bVisible(true),
	m_pPhysicsController1(NULL)
{
	m_ignore_activity_culling = false;
	m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR);
	m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks);
	
	// define the relationship between this node and it's parent.
	
	KX_NormalParentRelation * parent_relation = 
		KX_NormalParentRelation::New();
	m_pSGNode->SetParentRelation(parent_relation);
	

};



KX_GameObject::~KX_GameObject()
{
	// is this delete somewhere ?
	//if (m_sumoObj)
	//	delete m_sumoObj;
	delete m_pClient_info;
	//if (m_pSGNode)
	//	delete m_pSGNode;
	
}



CValue* KX_GameObject::	Calc(VALUE_OPERATOR op, CValue *val) 
{
	return NULL;
}



CValue* KX_GameObject::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
{
	return NULL;
}



const STR_String & KX_GameObject::GetText()
{
	return m_text;
}



float KX_GameObject::GetNumber()
{
	return 0;
}



STR_String KX_GameObject::GetName()
{
	return m_name;
}



void KX_GameObject::SetName(STR_String name)
{
	m_name = name;
};								// Set the name of the value



void KX_GameObject::ReplicaSetName(STR_String name)
{
}






KX_IPhysicsController* KX_GameObject::GetPhysicsController()
{
	return m_pPhysicsController1;
}





KX_GameObject* KX_GameObject::GetParent()
{
	KX_GameObject* result = NULL;
	SG_Node* node = m_pSGNode;
	
	while (node && !result)
	{
		node = node->GetSGParent();
		if (node)
			result = (KX_GameObject*)node->GetSGClientObject();
	}
	
	if (result)
		result->AddRef();

	return result;
	
}



void KX_GameObject::ProcessReplica(KX_GameObject* replica)
{
	replica->m_pPhysicsController1 = NULL;
	replica->m_pSGNode = NULL;
	replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
	replica->m_pClient_info->m_clientobject = replica;
}



CValue* KX_GameObject::GetReplica()
{
	KX_GameObject* replica = new KX_GameObject(*this);
	
	// this will copy properties and so on...
	CValue::AddDataToReplica(replica);
	ProcessReplica(replica);
	
	return replica;
}



void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local)
{
	if (m_pPhysicsController1)
		m_pPhysicsController1->ApplyForce(force,local);
}



void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local)
{
	if (m_pPhysicsController1)
		m_pPhysicsController1->ApplyTorque(torque,local);
}



void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local)
{
	if (m_pPhysicsController1) // (IsDynamic())
	{
		m_pPhysicsController1->RelativeTranslate(dloc,local);
	}
	GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local);
}



void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local)
{
	MT_Matrix3x3 rotmat(drot);
	rotmat.transpose();
	
	if (m_pPhysicsController1) // (IsDynamic())
		m_pPhysicsController1->RelativeRotate(rotmat,local); 
	// in worldspace
	GetSGNode()->RelativeRotate(rotmat,local);
}



/**
GetOpenGL Matrix, returns an OpenGL 'compatible' matrix
*/
double*	KX_GameObject::GetOpenGLMatrix()
{
	// todo: optimize and only update if necessary
	double* fl = m_OpenGL_4x4Matrix.getPointer();
	MT_Transform trans;
	
	trans.setOrigin(GetSGNode()->GetWorldPosition());
	trans.setBasis(GetSGNode()->GetWorldOrientation());
	
	MT_Vector3 scaling = GetSGNode()->GetWorldScaling();
	
	trans.scale(scaling[0], scaling[1], scaling[2]);
	trans.getValue(fl);

	return fl;
}



void KX_GameObject::Bucketize()
{
	double* fl = GetOpenGLMatrix();

	for (size_t i=0;i<m_meshes.size();i++)
		m_meshes[i]->Bucketize(fl, this, m_bUseObjectColor, m_objectColor);
}



void KX_GameObject::RemoveMeshes()
{
	double* fl = GetOpenGLMatrix();

	for (size_t i=0;i<m_meshes.size();i++)
		m_meshes[i]->RemoveFromBuckets(fl, this);

	//note: meshes can be shared, and are deleted by KX_BlenderSceneConverter

	m_meshes.clear();
}



void KX_GameObject::UpdateNonDynas()
{
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->SetSumoTransform(true);
	}
}



void KX_GameObject::UpdateTransform()
{
	if (m_pPhysicsController1)
		m_pPhysicsController1->SetSumoTransform(false);
}

void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene)
{
	((KX_GameObject*)gameobj)->UpdateTransform();
}


void KX_GameObject::SetDebugColor(unsigned int bgra)
{
	for (size_t i=0;i<m_meshes.size();i++)
		m_meshes[i]->DebugColor(bgra);	
}



void KX_GameObject::ResetDebugColor()
{
	SetDebugColor(0xff000000);
}



void KX_GameObject::UpdateIPO(float curframetime,
							  bool recurse,
							  bool ipo_as_force,
							  bool force_local) 
{

	// The ipo-actuator needs a sumo reference... this is retrieved (unfortunately)
	// by the iposgcontr itself...
//		ipocontr->SetSumoReference(gameobj->GetSumoScene(), 
//								   gameobj->GetSumoObject());


	// The ipo has to be treated as a force, and not a displacement!
	// For this case, we send some settings to the controller. This
	// may need some caching...
	if (ipo_as_force) {
		SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin();

		while (it != GetSGNode()->GetSGControllerList().end()) {
			(*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force);
			(*it)->SetOption(SG_Controller::SG_CONTR_IPO_FORCES_ACT_LOCAL, force_local);
			it++;
		}
	} 

	// The rest is the 'normal' update procedure.
	GetSGNode()->SetSimulatedTime(curframetime,recurse);
	GetSGNode()->UpdateWorldData(curframetime);
	UpdateTransform();
}


/*
void KX_GameObject::RegisterSumoObject(class SM_Scene* sumoScene,
									   DT_SceneHandle solidscene,
									   class SM_Object* sumoObj,
									   const char* matname,
									   bool isDynamic,
									   bool isActor)
{
	m_bDyna = isDynamic;

	// need easy access, not via 'node' etc.
	m_pPhysicsController = new KX_PhysicsController(sumoScene,solidscene,sumoObj,isDynamic);
				
	GetSGNode()->AddSGController(m_pPhysicsController);
	
	m_pClient_info->m_type = (isActor ? 1 : 0);
	m_pClient_info->m_clientobject = this;

	// store materialname in auxinfo, needed for touchsensors
	m_pClient_info->m_auxilary_info = (matname? (void*)(matname+2) : NULL);
	m_pPhysicsController->SetObject(this->GetSGNode());
}
*/

bool
KX_GameObject::GetVisible(
	void
	)
{
	return m_bVisible;
}

void
KX_GameObject::SetVisible(
	bool v
	)
{
	m_bVisible = v;
}

// used by Python, and the actuatorshould _not_ be misused by the
// scene!
void 
KX_GameObject::MarkVisible(
	bool visible
	)
{
	/* If explicit visibility settings are used, this is
	 * determined on this level. Maybe change this to mesh level
	 * later on? */
	
	double* fl = GetOpenGLMatrixPtr()->getPointer();
	for (size_t i=0;i<m_meshes.size();i++)
	{
		m_meshes[i]->MarkVisible(fl,this,visible,m_bUseObjectColor,m_objectColor);
	}
}


// Always use the flag?
void 
KX_GameObject::MarkVisible(
	void
	)
{
	double* fl = GetOpenGLMatrixPtr()->getPointer();
	for (size_t i=0;i<m_meshes.size();i++)
	{
		m_meshes[i]->MarkVisible(fl,
					 this,
					 m_bVisible,
					 m_bUseObjectColor,
					 m_objectColor
			);
	}
}

void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local)
{
	if (m_pPhysicsController1)
		m_pPhysicsController1->SetLinearVelocity(lin_vel + m_pPhysicsController1->GetLinearVelocity(),local);
}



void KX_GameObject::setLinearVelocity(const MT_Vector3& lin_vel,bool local)
{
	if (m_pPhysicsController1)
		m_pPhysicsController1->SetLinearVelocity(lin_vel,local);
}



void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local)
{
	if (m_pPhysicsController1)
		m_pPhysicsController1->SetAngularVelocity(ang_vel,local);
}

void KX_GameObject::ResolveCombinedVelocities(
	const MT_Vector3 & lin_vel,
	const MT_Vector3 & ang_vel,
	bool lin_vel_local,
	bool ang_vel_local
){
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->resolveCombinedVelocities(
			lin_vel_local ? NodeGetWorldOrientation() * lin_vel : lin_vel,
			ang_vel_local ? NodeGetWorldOrientation() * ang_vel : ang_vel			
		);		
	}
}


void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec)
{
	m_bUseObjectColor = true;
	m_objectColor = rgbavec;
}



MT_Vector3 KX_GameObject::GetLinearVelocity()
{
	MT_Vector3 velocity(0.0,0.0,0.0);
	
	if (m_pPhysicsController1)
	{
		velocity = m_pPhysicsController1->GetLinearVelocity();
	}
	return velocity;
	
}


// scenegraph node stuff

void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans)
{
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->setPosition(trans);
	}

	GetSGNode()->SetLocalPosition(trans);
}



void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot)
{
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->setOrientation(rot.getRotation());
	}
	
	GetSGNode()->SetLocalOrientation(rot);
}



void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale)
{
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->setScaling(scale);
	}
	
	GetSGNode()->SetLocalScale(scale);
}



void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale)
{
	GetSGNode()->RelativeScale(scale);
}



void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
{
	GetSGNode()->UpdateWorldData(time);
}



const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const
{
	return GetSGNode()->GetWorldOrientation();
}



const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const
{
	return GetSGNode()->GetWorldScaling();
}



const MT_Point3& KX_GameObject::NodeGetWorldPosition() const
{
	return GetSGNode()->GetWorldPosition();
}

/* Suspend/ resume: for the dynamic behaviour, there is a simple
 * method. For the residual motion, there is not. I wonder what the
 * correct solution is for Sumo. Remove from the motion-update tree?
 *
 * So far, only switch the physics and logic.
 * */

void KX_GameObject::Resume(void)
{
	if (m_suspended) {
		SCA_IObject::Resume();
		GetPhysicsController()->RestoreDynamics();

		m_suspended = false;
	}
}

void KX_GameObject::Suspend(void)
{
	if ((!m_ignore_activity_culling) 
		&& (!m_suspended))  {
		SCA_IObject::Suspend();
		GetPhysicsController()->SuspendDynamics();
		m_suspended = true;
	}
}




/* ------- python stuff ---------------------------------------------------*/




PyMethodDef KX_GameObject::Methods[] = {
	{"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS},  
	{"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_VARARGS},
	{"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_VARARGS},
	{"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_VARARGS},
	{"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_VARARGS},
	{"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS},
	{"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS},
	{"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_VARARGS},
	{"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_VARARGS},
	{"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS},
	{"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_VARARGS},
	{"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_VARARGS},
	{"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_VARARGS},
	{"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_VARARGS},
	{"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_VARARGS},
	{"getMesh", (PyCFunction)KX_GameObject::sPyGetMesh,METH_VARARGS},
	{"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_VARARGS},
	
	
	{NULL,NULL} //Sentinel
};



/*
bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args,
											MT_Vector3& pos,
											MT_Vector3& pos2)
{
	PyObject* pylist;
	PyObject* pylist2;
	bool error = (PyArg_ParseTuple(args,"OO",&pylist,&pylist2)) != 0;

	pos = ConvertPythonPylist(pylist);
	pos2 = ConvertPythonPylist(pylist2);
		
	return error;
}
*/


PyObject* KX_GameObject::sPySetPosition(PyObject* self,
										PyObject* args,
										PyObject* kwds)
{
	return ((KX_GameObject*) self)->PySetPosition(self, args, kwds);
}
	


PyObject* KX_GameObject::PyGetPosition(PyObject* self,
									   PyObject* args, 
									   PyObject* kwds)
{
	return PyObjectFrom(NodeGetWorldPosition());
}



PyTypeObject KX_GameObject::Type = {
	PyObject_HEAD_INIT(&PyType_Type)
		0,
		"KX_GameObject",
		sizeof(KX_GameObject),
		0,
		PyDestructor,
		0,
		__getattr,
		__setattr,
		0, //&MyPyCompare,
		__repr,
		0, //&cvalue_as_number,
		0,
		0,
		0,
		0
};



PyParentObject KX_GameObject::Parents[] = {
	&KX_GameObject::Type,
		&SCA_IObject::Type,
		&CValue::Type,
		NULL
};




PyObject* KX_GameObject::_getattr(const STR_String& attr)
{
	if (m_pPhysicsController1)
	{
		if (attr == "mass")
			return PyFloat_FromDouble(GetPhysicsController()->GetMass());
	}

	if (attr == "parent")
	{	
		KX_GameObject* parent = GetParent();
		if (parent)
		{
			parent->AddRef();
			return parent;
		}
		Py_Return;
	}

	if (attr == "visible")
		return PyInt_FromLong(m_bVisible);
	
	if (attr == "position")
		return PyObjectFrom(NodeGetWorldPosition());
	
	if (attr == "orientation")
		return PyObjectFrom(NodeGetWorldOrientation());
	
	if (attr == "scaling")
		return PyObjectFrom(NodeGetWorldScaling());
		
	if (attr == "name")
		return PyString_FromString(m_name.ReadPtr());
	
	_getattr_up(SCA_IObject);
}

int KX_GameObject::_setattr(const STR_String& attr, PyObject *value)	// _setattr method
{
	if (attr == "mass")
		return 1;
	
	if (attr == "parent")
		return 1;
		
	if (PyInt_Check(value))
	{
		int val = PyInt_AsLong(value);
		if (attr == "visible")
		{
			SetVisible(val != 0);
			return 0;
		}
	}
	
	if (PySequence_Check(value))
	{
		if (attr == "orientation")
		{
			MT_Matrix3x3 rot;
			if (PyObject_IsMT_Matrix(value, 3))
			{
				if (PyMatTo(value, rot))
				{
					NodeSetLocalOrientation(rot);
					return 0;
				}
				return 1;
			}
			
			if (PySequence_Size(value) == 4)
			{
				MT_Quaternion qrot;
				if (PyVecTo(value, qrot))
				{
					rot.setRotation(qrot);
					NodeSetLocalOrientation(rot);
					return 0;
				}
				return 1;
			}
			
			if (PySequence_Size(value) == 3)
			{
				MT_Vector3 erot;
				if (PyVecTo(value, erot))
				{
					rot.setEuler(erot);
					NodeSetLocalOrientation(rot);
					return 0;
				}
				return 1;
			}
			
			return 1;
		}
		
		if (attr == "position")
		{
			MT_Point3 pos;
			if (PyVecTo(value, pos))
			{
				NodeSetLocalPosition(pos);
				return 0;
			}
			return 1;
		}
		
		if (attr == "scaling")
		{
			MT_Vector3 scale;
			if (PyVecTo(value, scale))
			{
				NodeSetLocalScale(scale);
				return 0;
			}
			return 1;
		}
	}
	
	if (PyString_Check(value))
	{
		if (attr == "name")
		{
			m_name = PyString_AsString(value);
			return 0;
		}
	}
	
	return SCA_IObject::_setattr(attr, value);
}


PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, 
											 PyObject* args, 
											 PyObject* kwds)
{
	// only can get the velocity if we have a physics object connected to us...
	return PyObjectFrom(GetLinearVelocity());
}



PyObject* KX_GameObject::PySetVisible(PyObject* self,
									  PyObject* args,
									  PyObject* kwds)
{
	int visible = 1;
	
	if (PyArg_ParseTuple(args,"i",&visible))
	{
		MarkVisible(visible!=0);
		m_bVisible = (visible!=0);
	}
	else
	{
		return NULL;	     
	}
	Py_Return;
	
}



PyObject* KX_GameObject::PyGetVelocity(PyObject* self, 
									   PyObject* args, 
									   PyObject* kwds)
{
	// only can get the velocity if we have a physics object connected to us...
	MT_Vector3 velocity(0.0,0.0,0.0);
	MT_Point3 point(0.0,0.0,0.0);
	
	
	PyObject* pypos = NULL;
	if (PyArg_ParseTuple(args, "|O", &pypos))
	{
		if (pypos)
			PyVecTo(pypos, point);
	}
	
	if (m_pPhysicsController1)
	{
		velocity = m_pPhysicsController1->GetVelocity(point);
	}
	
	return PyObjectFrom(velocity);
}



PyObject* KX_GameObject::PyGetMass(PyObject* self, 
								   PyObject* args, 
								   PyObject* kwds)
{
	PyObject* pymass = NULL;
	
	float mass = GetPhysicsController()->GetMass();
	pymass = PyFloat_FromDouble(mass);

	if (pymass)
		return pymass;
	
	Py_Return;
}



PyObject* KX_GameObject::PyGetReactionForce(PyObject* self, 
											PyObject* args, 
											PyObject* kwds)
{
	// only can get the velocity if we have a physics object connected to us...
	return PyObjectFrom(GetPhysicsController()->getReactionForce());
}



PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self, 
										   PyObject* args, 
										   PyObject* kwds)
{
	
	GetPhysicsController()->setRigidBody(true);

	Py_Return;
}



PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self, 
											PyObject* args, 
											PyObject* kwds)
{
	GetPhysicsController()->setRigidBody(false);

	Py_Return;
}



PyObject* KX_GameObject::PyGetParent(PyObject* self, 
									 PyObject* args, 
									 PyObject* kwds)
{
	KX_GameObject* parent = this->GetParent();
	if (parent)
	{
		parent->AddRef();
		return parent;
	}
	Py_Return;
}



PyObject* KX_GameObject::PyGetMesh(PyObject* self, 
								   PyObject* args, 
								   PyObject* kwds)
{
	int mesh = 0;
	
	if (PyArg_ParseTuple(args, "|i", &mesh))
	{
		if (mesh < m_meshes.size() && mesh >= 0)
		{
			KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]);
			return meshproxy;
		}
	}
	Py_Return;
}



PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, 
										PyObject* args, 
										PyObject* kwds)
{
	
	
	PyObject* pyattach;
	PyObject* pyimpulse;
	
	if (PyArg_ParseTuple(args, "OO", &pyattach, &pyimpulse))
	{
		MT_Point3  attach;
		MT_Vector3 impulse;
	
		if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse) && m_pPhysicsController1)
		{
			m_pPhysicsController1->applyImpulse(attach, impulse);
			Py_Return;
		}

	}
	
	return NULL;
}



PyObject* KX_GameObject::PySuspendDynamics(PyObject* self, 
										   PyObject* args, 
										   PyObject* kwds)
{
	if (m_bSuspendDynamics)
	{
		Py_Return;
	}
	
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->SuspendDynamics();
	}
	m_bSuspendDynamics = true;
	
	Py_Return;
}



PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self, 
										   PyObject* args, 
										   PyObject* kwds)
{
	
	if (!m_bSuspendDynamics)
	{
		Py_Return;
	}
	
	if (m_pPhysicsController1)
	{
		m_pPhysicsController1->RestoreDynamics();
	}
	m_bSuspendDynamics = false;
	
	Py_Return;
}



PyObject* KX_GameObject::PyGetOrientation(PyObject* self,
										  PyObject* args,
										  PyObject* kwds) //keywords
{
	return PyObjectFrom(NodeGetWorldOrientation());
}



PyObject* KX_GameObject::PySetOrientation(PyObject* self, 
										  PyObject* args, 
										  PyObject* kwds)
{
	PyObject* pylist;
	bool	error = false;
	int row,col;
	
	if (PyArg_ParseTuple(args,"O",&pylist))
	{
		MT_Matrix3x3 matrix;
		if (PyObject_IsMT_Matrix(pylist, 3) && PyMatTo(pylist, matrix))
		{
			NodeSetLocalOrientation(matrix);
			Py_Return;
		}
	
		MT_Quaternion quat;
		if (PyVecTo(pylist, quat))
		{
			matrix.setRotation(quat);
			NodeSetLocalOrientation(matrix);
			Py_Return;
		}
	}
	return NULL;
}



PyObject* KX_GameObject::PySetPosition(PyObject* self, 
									   PyObject* args, 
									   PyObject* kwds)
{
	MT_Point3 pos;
	if (PyVecArgTo(args, pos))
	{
		NodeSetLocalPosition(pos);
		Py_Return;
	}
	
	return NULL;
}

PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self,
											   PyObject* args,
											   PyObject* kwds)
{
	KX_IPhysicsController* ctrl = GetPhysicsController();
	int physid=0;
	if (ctrl)
	{
		physid= (int)ctrl->GetUserData();
	}
	return PyInt_FromLong(physid);
}

/* --------------------------------------------------------------------- 
 * Some stuff taken from the header
 * --------------------------------------------------------------------- */
void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter)	
{
	/* intentionally empty ? */
}

