BGE debug API and actuator

This patch adds some new debug methods to the KX_GameObject for manually adding the debug list and bge.render for controlling the debug visualization.
It also adds a new debug actuator, which allows to control the same functions.

This patch is a updated version of T33701.

Thread on Blenderartists:
http://blenderartists.org/forum/showthread.php?264745-Debug-proerties-for-added-objects-patch&p=2256018&viewfull=1#post2256018

Reviewers: moguri

Reviewed By: moguri

Differential Revision: https://developer.blender.org/D635
This commit is contained in:
HG1 2014-07-11 15:18:43 -07:00 committed by Mitchell Stokes
parent 9327816593
commit 984d6c8677
15 changed files with 398 additions and 9 deletions

@ -301,6 +301,34 @@ Functions
Disable the motion blur effect.
.. function:: showFramerate(enable)
Show or hide the framerate.
:type enable: boolean
.. function:: showProfile(enable)
Show or hide the profile.
:type enable: boolean
.. function:: showProperties(enable)
Show or hide the debug properties.
:type enable: boolean
.. function:: autoDebugList(enable)
Enable or disable auto adding debug properties to the debug list.
:type enable: boolean
.. function:: clearDebugList()
Clears the debug property list.
.. function:: setVsync(value)
Set the vsync value

@ -363,6 +363,18 @@ base class --- :class:`SCA_IObject`
:type: float
.. attribute:: debug
If true, the object's debug properties will be displayed on screen.
:type: boolean
.. attribute:: debugRecursive
If true, the object's and children's debug properties will be displayed on screen.
:type: boolean
.. method:: endObject()
Delete this object, can be used in place of the EndObject Actuator.
@ -857,3 +869,11 @@ base class --- :class:`SCA_IObject`
:return: Whether or not the action is playing
:rtype: boolean
.. method:: addDebugProperty (name, debug = True)
Adds a single debug property to the debug list.
:arg name: name of the property that added to the debug list.
:type name: string
:arg debug: the debug state.
:type debug: boolean

@ -70,6 +70,32 @@ std::vector<SCA_DebugProp*>& SCA_IScene::GetDebugProperties()
}
bool SCA_IScene::PropertyInDebugList( class CValue *gameobj, const STR_String &name )
{
for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
!(it==m_debugList.end());++it) {
STR_String debugname = (*it)->m_name;
CValue *debugobj = (*it)->m_obj;
if (debugobj == gameobj && debugname == name)
return true;
}
return false;
}
bool SCA_IScene::ObjectInDebugList( class CValue *gameobj )
{
for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
!(it==m_debugList.end());++it) {
CValue* debugobj = (*it)->m_obj;
if (debugobj == gameobj)
return true;
}
return false;
}
void SCA_IScene::AddDebugProperty(class CValue* debugprop,
const STR_String &name)
@ -84,6 +110,24 @@ void SCA_IScene::AddDebugProperty(class CValue* debugprop,
}
void SCA_IScene::RemoveDebugProperty(class CValue *gameobj,
const STR_String &name)
{
vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
while(it != m_debugList.end()) {
STR_String debugname = (*it)->m_name;
CValue *debugobj = (*it)->m_obj;
if (debugobj == gameobj && debugname == name) {
delete (*it);
m_debugList.erase(it);
break;
}
++it;
}
}
void SCA_IScene::RemoveObjectDebugProperties(class CValue* gameobj)
{
vector<SCA_DebugProp*>::iterator it = m_debugList.begin();

@ -67,9 +67,11 @@ public:
virtual void ReplaceMesh(class CValue* gameobj,
void* meshobj, bool use_gfx, bool use_phys)=0;
std::vector<SCA_DebugProp*>& GetDebugProperties();
bool PropertyInDebugList(class CValue *gameobj, const STR_String &name);
bool ObjectInDebugList(class CValue *gameobj);
void RemoveAllDebugProperties();
void AddDebugProperty(class CValue* debugprop,
const STR_String &name);
void AddDebugProperty(class CValue* debugprop, const STR_String &name);
void RemoveDebugProperty(class CValue *gameobj, const STR_String &name);
void RemoveObjectDebugProperties(class CValue* gameobj);
virtual void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj,

@ -68,6 +68,7 @@ typedef unsigned long uint_ptr;
#include "SCA_IController.h"
#include "NG_NetworkScene.h" //Needed for sendMessage()
#include "KX_ObstacleSimulation.h"
#include "KX_Scene.h"
#include "BKE_object.h"
@ -979,6 +980,44 @@ KX_GameObject::SetOccluder(
}
}
static void setDebug_recursive(SG_Node *node, bool debug)
{
NodeList& children = node->GetSGChildren();
KX_Scene *scene = KX_GetActiveScene();
for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) {
SG_Node *childnode = (*childit);
KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
if (clientgameobj != NULL) {
if (debug) {
if (!scene->ObjectInDebugList(clientgameobj))
scene->AddObjectDebugProperties(clientgameobj);
}
else
scene->RemoveObjectDebugProperties(clientgameobj);
}
/* if the childobj is NULL then this may be an inverse parent link
* so a non recursive search should still look down this node. */
setDebug_recursive(childnode, debug);
}
}
void KX_GameObject::SetUseDebugProperties( bool debug, bool recursive )
{
KX_Scene *scene = KX_GetActiveScene();
if (debug) {
if (!scene->ObjectInDebugList(this))
scene->AddObjectDebugProperties(this);
}
else
scene->RemoveObjectDebugProperties(this);
if (recursive)
setDebug_recursive(GetSGNode(), debug);
}
void
KX_GameObject::SetLayer(
int l
@ -1828,6 +1867,7 @@ PyMethodDef KX_GameObject::Methods[] = {
KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo),
KX_PYMETHODTABLE_O(KX_GameObject, getVectTo),
KX_PYMETHODTABLE(KX_GameObject, sendMessage),
KX_PYMETHODTABLE(KX_GameObject, addDebugProperty),
KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction),
KX_PYMETHODTABLE(KX_GameObject, stopAction),
@ -1880,6 +1920,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive),
KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict),
KX_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor),
KX_PYATTRIBUTE_RW_FUNCTION("debug", KX_GameObject, pyattr_get_debug, pyattr_set_debug),
KX_PYATTRIBUTE_RW_FUNCTION("debugRecursive", KX_GameObject, pyattr_get_debugRecursive, pyattr_set_debugRecursive),
/* experimental, don't rely on these yet */
KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors),
@ -2796,6 +2838,52 @@ PyObject *KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_
return self->m_attr_dict;
}
PyObject *KX_GameObject::pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_Scene *scene = KX_GetActiveScene();
KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
return PyBool_FromLong(scene->ObjectInDebugList(self));
}
int KX_GameObject::pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
int param = PyObject_IsTrue(value);
if (param == -1) {
PyErr_SetString(PyExc_AttributeError, "gameOb.debug = bool: KX_GameObject, expected True or False");
return PY_SET_ATTR_FAIL;
}
self->SetUseDebugProperties(param, false);
return PY_SET_ATTR_SUCCESS;
}
PyObject *KX_GameObject::pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_Scene *scene = KX_GetActiveScene();
KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
return PyBool_FromLong(scene->ObjectInDebugList(self));
}
int KX_GameObject::pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
int param = PyObject_IsTrue(value);
if (param == -1) {
PyErr_SetString(PyExc_AttributeError, "gameOb.debugRecursive = bool: KX_GameObject, expected True or False");
return PY_SET_ATTR_FAIL;
}
self->SetUseDebugProperties(param, true);
return PY_SET_ATTR_SUCCESS;
}
PyObject *KX_GameObject::PyApplyForce(PyObject *args)
{
int local = 0;
@ -3617,6 +3705,29 @@ KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction,
}
KX_PYMETHODDEF_DOC(KX_GameObject, addDebugProperty,
"addDebugProperty(name, visible=1)\n"
"Added or remove a debug property to the debug list.\n")
{
KX_Scene *scene = KX_GetActiveScene();
char *name;
int visible = 1;
if (!PyArg_ParseTuple(args,"s|i:debugProperty", &name , &visible))
return NULL;
if (visible) {
if (!scene->PropertyInDebugList(this, name))
scene->AddDebugProperty(this, name);
}
else {
scene->RemoveDebugProperty(this, name);
}
Py_RETURN_NONE;
}
/* dict style access */

@ -934,6 +934,11 @@ public:
m_pObstacleSimulation = NULL;
}
/**
* add debug object to the debuglist.
*/
void SetUseDebugProperties(bool debug, bool recursive);
KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; }
CListValue* GetChildren();
@ -993,6 +998,7 @@ public:
KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo);
KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage);
KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh);
KX_PYMETHOD_DOC(KX_GameObject, addDebugProperty);
KX_PYMETHOD_DOC(KX_GameObject, playAction);
KX_PYMETHOD_DOC(KX_GameObject, stopAction);
@ -1060,7 +1066,11 @@ public:
static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
/* Experimental! */
static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);

@ -163,6 +163,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_showProperties(false),
m_showBackground(false),
m_show_debug_properties(false),
m_autoAddDebugProperties(true),
m_animation_record(false),
@ -1897,6 +1898,46 @@ short KX_KetsjiEngine::GetExitKey()
return m_exitkey;
}
void KX_KetsjiEngine::SetShowFramerate(bool frameRate)
{
m_show_framerate = frameRate;
}
bool KX_KetsjiEngine::GetShowFramerate()
{
return m_show_framerate;
}
void KX_KetsjiEngine::SetShowProfile(bool profile)
{
m_show_profile = profile;
}
bool KX_KetsjiEngine::GetShowProfile()
{
return m_show_profile;
}
void KX_KetsjiEngine::SetShowProperties(bool properties)
{
m_show_debug_properties = properties;
}
bool KX_KetsjiEngine::GetShowProperties()
{
return m_show_debug_properties;
}
void KX_KetsjiEngine::SetAutoAddDebugProperties(bool add)
{
m_autoAddDebugProperties = add;
}
bool KX_KetsjiEngine::GetAutoAddDebugProperties()
{
return m_autoAddDebugProperties;
}
void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
{
m_show_framerate = frameRate;

@ -174,8 +174,10 @@ private:
bool m_showProperties;
/** Show background behind text for readability? */
bool m_showBackground;
/** Show debug properties on the game display*/
bool m_show_debug_properties;
/** Automatic add debug properties to the debug list*/
bool m_autoAddDebugProperties;
/** record physics into keyframes */
bool m_animation_record;
@ -352,6 +354,46 @@ public:
static short GetExitKey();
/**
* \Sets the display for frame rate on or off.
*/
void SetShowFramerate(bool frameRate);
/**
* \Gets the display for frame rate on or off.
*/
bool GetShowFramerate();
/**
* \Sets the display for individual components on or off.
*/
void SetShowProfile(bool profile);
/**
* \Gets the display for individual components on or off.
*/
bool GetShowProfile();
/**
* \Sets the display of scene object debug properties on or off.
*/
void SetShowProperties(bool properties);
/**
* \Gets the display of scene object debug properties on or off.
*/
bool GetShowProperties();
/**
* \Sets if the auto adding of scene object debug properties on or off.
*/
bool GetAutoAddDebugProperties();
/**
* \Sets the auto adding of scene object debug properties on or off.
*/
void SetAutoAddDebugProperties(bool add);
/**
* Activates or deactivates timing information display.
* \param frameRate Display for frame rate on or off.

@ -1389,6 +1389,71 @@ static PyObject *gPyGetVsync(PyObject *)
return PyLong_FromLong(gp_Canvas->GetSwapInterval());
}
static PyObject *gPyShowFramerate(PyObject *, PyObject *args)
{
int visible;
if (!PyArg_ParseTuple(args,"i:showFramerate",&visible))
return NULL;
if (visible && gp_KetsjiEngine)
gp_KetsjiEngine->SetShowFramerate(true);
else
gp_KetsjiEngine->SetShowFramerate(false);
Py_RETURN_NONE;
}
static PyObject *gPyShowProfile(PyObject *, PyObject *args)
{
int visible;
if (!PyArg_ParseTuple(args,"i:showProfile",&visible))
return NULL;
if (visible && gp_KetsjiEngine)
gp_KetsjiEngine->SetShowProfile(true);
else
gp_KetsjiEngine->SetShowProfile(false);
Py_RETURN_NONE;
}
static PyObject *gPyShowProperties(PyObject *, PyObject *args)
{
int visible;
if (!PyArg_ParseTuple(args,"i:showProperties",&visible))
return NULL;
if (visible && gp_KetsjiEngine)
gp_KetsjiEngine->SetShowProperties(true);
else
gp_KetsjiEngine->SetShowProperties(false);
Py_RETURN_NONE;
}
static PyObject *gPyAutoDebugList(PyObject *, PyObject *args)
{
int add;
if (!PyArg_ParseTuple(args,"i:autoAddProperties",&add))
return NULL;
if (add && gp_KetsjiEngine)
gp_KetsjiEngine->SetAutoAddDebugProperties(true);
else
gp_KetsjiEngine->SetAutoAddDebugProperties(false);
Py_RETURN_NONE;
}
static PyObject *gPyClearDebugList(PyObject *)
{
if (gp_KetsjiScene)
gp_KetsjiScene->RemoveAllDebugProperties();
Py_RETURN_NONE;
}
static struct PyMethodDef rasterizer_methods[] = {
{"getWindowWidth",(PyCFunction) gPyGetWindowWidth,
METH_VARARGS, "getWindowWidth doc"},
@ -1436,6 +1501,11 @@ static struct PyMethodDef rasterizer_methods[] = {
{"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""},
{"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""},
{"getVsync", (PyCFunction) gPyGetVsync, METH_NOARGS, ""},
{"showFramerate",(PyCFunction) gPyShowFramerate, METH_VARARGS, "show or hide the framerate"},
{"showProfile",(PyCFunction) gPyShowProfile, METH_VARARGS, "show or hide the profile"},
{"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"},
{"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"},
{"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"},
{ NULL, (PyCFunction) NULL, 0, NULL }
};

@ -595,7 +595,9 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
{
/* add properties to debug list, for added objects and DupliGroups */
AddObjectDebugProperties(newobj);
if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) {
AddObjectDebugProperties(newobj);
}
// also relink the controller to sensors/actuators
SCA_ControllerList& controllers = newobj->GetControllers();
//SCA_SensorList& sensors = newobj->GetSensors();
@ -1005,7 +1007,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
int ret;
KX_GameObject* newobj = (KX_GameObject*) gameobj;
/* remove property to debug list */
/* remove property from debug list */
RemoveObjectDebugProperties(newobj);
/* Invalidate the python reference, since the object may exist in script lists
@ -2022,7 +2024,11 @@ bool KX_Scene::MergeScene(KX_Scene *other)
{
KX_GameObject* gameobj = (KX_GameObject*)other->GetObjectList()->GetValue(i);
MergeScene_GameObject(gameobj, this, other);
AddObjectDebugProperties(gameobj); // add properties to debug list for LibLoad objects
/* add properties to debug list for LibLoad objects */
if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) {
AddObjectDebugProperties(gameobj);
}
gameobj->UpdateBuckets(false); /* only for active objects */
}

@ -877,6 +877,14 @@ void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval)
}
}
int CcdPhysicsEnvironment::GetDebugMode() const
{
if (m_debugDrawer) {
return m_debugDrawer->getDebugMode();
}
return 0;
}
void CcdPhysicsEnvironment::SetDebugMode(int debugMode)
{
if (m_debugDrawer) {

@ -139,6 +139,7 @@ protected:
virtual float GetFixedTimeStep() { return 0.f; }
virtual void SetDebugMode(int debugMode);
virtual int GetDebugMode()const;
virtual void SetGravity(float x,float y,float z);
virtual void GetGravity(MT_Vector3& grav);

@ -78,8 +78,10 @@ float DummyPhysicsEnvironment::GetFixedTimeStep()
return 0.f;
}
int DummyPhysicsEnvironment::GetDebugMode() const
{
return 0;
}
void DummyPhysicsEnvironment::SetGravity(float x,float y,float z)
{

@ -56,6 +56,8 @@ public:
virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep);
virtual float GetFixedTimeStep();
virtual int GetDebugMode() const;
virtual void SetGravity(float x,float y,float z);
virtual void GetGravity(class MT_Vector3& grav);

@ -126,6 +126,8 @@ class PHY_IPhysicsEnvironment
//returns 0.f if no fixed timestep is used
virtual float GetFixedTimeStep()=0;
///getDebugMode return the actual debug visualization state
virtual int GetDebugMode()const=0;
///setDebugMode is used to support several ways of debug lines, contact point visualization
virtual void SetDebugMode(int debugMode) {}
///setNumIterations set the number of iterations for iterative solvers