diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-11-22 17:42:22 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-11-22 17:42:22 +0300 |
commit | c36f78dd41b8d2c714b2a94c43eabe928afea26a (patch) | |
tree | 48856d51a20eb4024f142e1fb68a9d345a291aeb /source/gameengine | |
parent | f4a0c9239ff21a75a336ed3f496dd88d3997d28e (diff) |
[#19258] [patch] Adding drawing capabilities to BGE Python
patch from Mitchell Stokes (moguri)
simple use case
scene.post_draw = [pyOpenGLFunc]
this only needs to be set once, then the funcion runs each redraw.
note, this patch also changes how python scripts run (not modules): Dont clear the namespace after running a script, since functions still use the namespace, BGE API is now better when dealing with stale data.
made some changes to this patch.
- assigning a list didnt decrement the existing list.
- initialize as NULL rather then a blank list
- dont use string comparisons for the callbacks, pass the python list to use instead.
- dont check the list items are callable. python will display an error if they are not.
- use python list macros that dont do any type checking sine blender does this when assigning the list
---- from tracker, edited since an updated patch changes some things.
Here is a patch to be able to draw to the screen with BGE Python. This will be very handy for GUI stuff. This patch
works by having the user register a callback in the scene. Two options are available KX_Scene.pre_draw
and KX_Scene.post_draw. The difference between these is when Python draws to the screen (before or after the BGE).
Each can take a list of functions. Here is an example that draws a blue semi-transparent
Diffstat (limited to 'source/gameengine')
-rw-r--r-- | source/gameengine/GameLogic/SCA_PythonController.cpp | 3 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 6 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_Scene.cpp | 84 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_Scene.h | 15 |
4 files changed, 106 insertions, 2 deletions
diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index ac3e0434d20..aeebce6c7d7 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -465,7 +465,8 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) { /* clear after PyErrPrint - seems it can be using * something in this dictionary and crash? */ - PyDict_Clear(excdict); + // This doesn't appear to be needed anymore + //PyDict_Clear(excdict); Py_DECREF(excdict); } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 6800b2aa871..7f8a8e04e2e 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1306,7 +1306,13 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_RENDER); + // Run any pre-drawing python callbacks + scene->RunDrawingCallbacks(scene->GetPreDrawCB()); + scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); + + // Run any post-drawing python callbacks + scene->RunDrawingCallbacks(scene->GetPostDrawCB()); if (scene->GetPhysicsEnvironment()) scene->GetPhysicsEnvironment()->debugDrawWorld(); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 655c8eedaae..c018dcd387f 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -211,6 +211,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, #ifndef DISABLE_PYTHON m_attr_dict = PyDict_New(); /* new ref */ + m_draw_call_pre = NULL; + m_draw_call_post = NULL; #endif } @@ -264,6 +266,9 @@ KX_Scene::~KX_Scene() #ifndef DISABLE_PYTHON PyDict_Clear(m_attr_dict); Py_DECREF(m_attr_dict); + + Py_XDECREF(m_draw_call_pre); + Py_XDECREF(m_draw_call_post); #endif } @@ -401,6 +406,28 @@ bool KX_Scene::IsClearingZBuffer() return m_isclearingZbuffer; } +void KX_Scene::RunDrawingCallbacks(PyObject* cb_list) +{ + int len; + + if (cb_list && (len=PyList_GET_SIZE(cb_list))) + { + PyObject* func; + PyObject* ret; + + // Iterate the list and run the callbacks + for (int pos=0; pos < len; pos++) + { + func= PyList_GET_ITEM(cb_list, pos); + ret= PyObject_CallObject(func, NULL); + if (ret==NULL) { + PyErr_Print(); + PyErr_Clear(); + } + } + } +} + void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer) { m_isclearingZbuffer = isclearingZbuffer; @@ -1997,6 +2024,61 @@ int KX_Scene::pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *a return PY_SET_ATTR_SUCCESS; } +PyObject* KX_Scene::pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + if(self->m_draw_call_pre==NULL) + self->m_draw_call_pre= PyList_New(0); + else + Py_INCREF(self->m_draw_call_pre); + return self->m_draw_call_pre; +} + +PyObject* KX_Scene::pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + if(self->m_draw_call_post==NULL) + self->m_draw_call_post= PyList_New(0); + else + Py_INCREF(self->m_draw_call_post); + return self->m_draw_call_post; +} + +int KX_Scene::pyattr_set_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + if (!PyList_CheckExact(value)) + { + PyErr_SetString(PyExc_ValueError, "Expected a list"); + return PY_SET_ATTR_FAIL; + } + Py_XDECREF(self->m_draw_call_pre); + + Py_INCREF(value); + self->m_draw_call_pre = value; + + return PY_SET_ATTR_SUCCESS; +} + +int KX_Scene::pyattr_set_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + if (!PyList_CheckExact(value)) + { + PyErr_SetString(PyExc_ValueError, "Expected a list"); + return PY_SET_ATTR_FAIL; + } + Py_XDECREF(self->m_draw_call_post); + + Py_INCREF(value); + self->m_draw_call_post = value; + + return PY_SET_ATTR_SUCCESS; +} PyAttributeDef KX_Scene::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), @@ -2005,6 +2087,8 @@ PyAttributeDef KX_Scene::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), + KX_PYATTRIBUTE_RW_FUNCTION("pre_draw", KX_Scene, pyattr_get_drawing_callback_pre, pyattr_set_drawing_callback_pre), + KX_PYATTRIBUTE_RW_FUNCTION("post_draw", KX_Scene, pyattr_get_drawing_callback_post, pyattr_set_drawing_callback_post), KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), KX_PYATTRIBUTE_FLOAT_RW("activity_culling_radius", 0.5f, FLT_MAX, KX_Scene, m_activity_box_radius), diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 4b01ab39d95..602e919b58d 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -95,6 +95,8 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene #ifndef DISABLE_PYTHON PyObject* m_attr_dict; + PyObject* m_draw_call_pre; + PyObject* m_draw_call_post; #endif struct CullingInfo { @@ -102,7 +104,6 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene CullingInfo(int layer) : m_layer(layer) {} }; - protected: RAS_BucketManager* m_bucketmanager; CListValue* m_tempObjectList; @@ -287,6 +288,12 @@ public: void RenderBuckets(const MT_Transform& cameratransform, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); + + /** + * Run the registered python drawing functions. + */ + void RunDrawingCallbacks(PyObject* cb_list); + /** * Update all transforms according to the scenegraph. */ @@ -544,6 +551,10 @@ public: static PyObject* pyattr_get_cameras(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_active_camera(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_drawing_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_drawing_callback_post(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); virtual PyObject* py_repr(void) { return PyUnicode_FromString(GetName().ReadPtr()); } @@ -551,6 +562,8 @@ public: static PyMappingMethods Mapping; static PySequenceMethods Sequence; + PyObject* GetPreDrawCB() { return m_draw_call_pre; }; + PyObject* GetPostDrawCB() { return m_draw_call_post; }; #endif /** |