Skip to content

Commit

Permalink
UPBGE: Use CValue for VideoTexture Texture class.
Browse files Browse the repository at this point in the history
Previously none of the classes with a python proxy in the VideoTexture
part was using the PyObjectPlus or CValue classes. These both class are
a standard in the way to define a python proxy in the source of the
game engine.
The power of PyObjectPlus is to use a second proxy called PyObjectPlus_Proxy
which can be invalidate when the target object is freed. For example
when a game object is freed the python proxy is invalidated to avoid
acces to any functions of the game object.

The problem solved by PyObjectPlus_Proxy is found in the VideoTexture
part but in a more deeper way: None Texture object are freed when restarting
the game or a scene, worse when the module owning these instance is
freed at the end of the game the restore of the original bind code is
made too late because the RAS_Texture is a dangling pointer.

To solve this issue Texture now inherite of CValue. Texture python
functions and attributes are converted to follow PyObjectPlus standard.
But as Texture is instatiated from python via a python constructor
we have to keep Texture_init and Texture_new because PyObjectPlus is not
managing it.

When Texture_new is called the create Texture instance is added in a
global list name "textures". This list is used to track existing instance
to freed at game or scene reload. When the game or the scene reload the
global function Texture::FreeAllTextures is called with a scene as argument.
The function iterate on all instances and delete them if theirs game object
scene match with the scene passed. At this time the python proxy is still
existing but invalidated.
In the case where the instacne is directly freed from python the function
DestructFromPython is overrided in Texture and remove itself form the
textures list.

As Texture isntance are python owned and internally owned a little issue
was noticed in the function PyObjectPlus::InvalidateProxy: The python
proxy is always deferenced even if it is python owned. In this case
we steal a reference from an other object. To solve this issue a simple
check is made to avoid deferencing the python proxy.

In the same way inheriting Texture of CValue, the workaround of BlendType
template is replaced by function for game object, camera:

ConvertPythonToGameObject
ConvertPythonToCamera

Only scene is still using:

PyObject_TypeCheck(scene, &KX_Scene::Type)
  • Loading branch information
panzergame committed Sep 25, 2016
1 parent 1bb42eb commit ef7fbd8
Show file tree
Hide file tree
Showing 19 changed files with 295 additions and 332 deletions.
1 change: 1 addition & 0 deletions source/gameengine/Converter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(INC
../Rasterizer
../Rasterizer/RAS_OpenGLRasterizer
../SceneGraph
../VideoTexture
../../blender
../../blender/blenkernel
../../blender/blenlib
Expand Down
9 changes: 9 additions & 0 deletions source/gameengine/Converter/KX_BlenderSceneConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
#include "BLI_winstuff.h"
#endif

#ifdef WITH_PYTHON
# include "Texture.h" // For FreeAllTextures. Must be included after BLI_winstuff.h.
#endif // WITH_PYTHON


/* This list includes only data type definitions */
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
Expand Down Expand Up @@ -297,6 +302,10 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
delete world;
}

#ifdef WITH_PYTHON
Texture::FreeAllTextures(scene);
#endif // WITH_PYTHON

// delete the scene first as it will stop the use of entities
scene->Release();

Expand Down
17 changes: 7 additions & 10 deletions source/gameengine/Expressions/intern/PyObjectPlus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,7 @@
PyObjectPlus::~PyObjectPlus()
{
#ifdef WITH_PYTHON
if (m_proxy) {
BGE_PROXY_REF(m_proxy)= NULL;
Py_DECREF(m_proxy); /* Remove own reference, python may still have 1 */
}
// assert(ob_refcnt==0);
InvalidateProxy();
#endif
}

Expand Down Expand Up @@ -91,18 +87,19 @@ void PyObjectPlus::InvalidateProxy() // check typename of each parent
{
#ifdef WITH_PYTHON
if (m_proxy) {
BGE_PROXY_REF(m_proxy)=NULL;
Py_DECREF(m_proxy);
m_proxy= NULL;
BGE_PROXY_REF(m_proxy) = NULL;
// Decrement proxy only if python doesn't own it.
if (!BGE_PROXY_PYOWNS(m_proxy)) {
Py_DECREF(m_proxy);
}
m_proxy = NULL;
}
#endif
}

void PyObjectPlus::DestructFromPython()
{
#ifdef WITH_PYTHON
// Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes
m_proxy = NULL;
delete this;
#endif
}
Expand Down
1 change: 1 addition & 0 deletions source/gameengine/Ketsji/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ set(INC
../Rasterizer
../Rasterizer/RAS_OpenGLRasterizer
../SceneGraph
../VideoTexture
../../blender
../../blender/blenfont
../../blender/blenkernel
Expand Down
8 changes: 4 additions & 4 deletions source/gameengine/Ketsji/KX_PythonInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1995,13 +1995,13 @@ PyMODINIT_FUNC initBGE(void)
PyDict_SetItemString(sys_modules, mod_full, submodule);
Py_INCREF(submodule);

mod_full = "bge.texture";
PyModule_AddObject(mod, SUBMOD, (submodule = initVideoTexturePythonBinding()));
mod_full = "bge.types";
PyModule_AddObject(mod, SUBMOD, (submodule = initGameTypesPythonBinding()));
PyDict_SetItemString(sys_modules, mod_full, submodule);
Py_INCREF(submodule);

mod_full = "bge.types";
PyModule_AddObject(mod, SUBMOD, (submodule = initGameTypesPythonBinding()));
mod_full = "bge.texture";
PyModule_AddObject(mod, SUBMOD, (submodule = initVideoTexturePythonBinding()));
PyDict_SetItemString(sys_modules, mod_full, submodule);
Py_INCREF(submodule);

Expand Down
2 changes: 2 additions & 0 deletions source/gameengine/Ketsji/KX_PythonInitTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
#include "KX_MouseActuator.h"
#include "KX_CollisionContactPoints.h"
#include "EXP_ListWrapper.h"
#include "Texture.h"

static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr)
{
Expand Down Expand Up @@ -295,6 +296,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
PyType_Ready_Attr(dict, SCA_PythonJoystick, init_getset);
PyType_Ready_Attr(dict, SCA_PythonKeyboard, init_getset);
PyType_Ready_Attr(dict, SCA_PythonMouse, init_getset);
PyType_Ready_Attr(dict, Texture, init_getset);
}

#ifdef USE_MATHUTILS
Expand Down
1 change: 1 addition & 0 deletions source/gameengine/Launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ set(INC
../Rasterizer
../Rasterizer/RAS_OpenGLRasterizer
../SceneGraph
../VideoTexture
../../blender/blenkernel
../../blender/blenlib
../../blender/gpu
Expand Down
8 changes: 8 additions & 0 deletions source/gameengine/Launcher/LA_Launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@

#include "KX_NetworkMessageManager.h"

#ifdef WITH_PYTHON
# include "Texture.h" // For FreeAllTextures.
#endif // WITH_PYTHON

#include "GHOST_ISystem.h"
#include "GHOST_IWindow.h"

Expand Down Expand Up @@ -304,6 +308,10 @@ void LA_Launcher::InitEngine()

void LA_Launcher::ExitEngine()
{
#ifdef WITH_PYTHON
Texture::FreeAllTextures(NULL);
#endif // WITH_PYTHON

DEV_Joystick::Close();
m_ketsjiEngine->StopEngine();

Expand Down
86 changes: 0 additions & 86 deletions source/gameengine/VideoTexture/BlendType.h

This file was deleted.

1 change: 0 additions & 1 deletion source/gameengine/VideoTexture/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ set(SRC
VideoDeckLink.cpp
blendVideoTex.cpp

BlendType.h
Common.h
Exception.h
FilterBase.h
Expand Down
2 changes: 2 additions & 0 deletions source/gameengine/VideoTexture/DeckLink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@

#include <memory.h>

#include "glew-mx.h"

// macro for exception handling and logging
#define CATCH_EXCP catch (Exception & exp) \
{ exp.report(); return NULL; }
Expand Down
1 change: 0 additions & 1 deletion source/gameengine/VideoTexture/DeckLink.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include "DeckLinkAPI.h"

#include "ImageBase.h"
#include "BlendType.h"
#include "Exception.h"


Expand Down
2 changes: 2 additions & 0 deletions source/gameengine/VideoTexture/ImageBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ extern "C" {
#include "bgl.h"
}

#include "glew-mx.h"

#include <vector>
#include <string.h>

Expand Down
2 changes: 0 additions & 2 deletions source/gameengine/VideoTexture/ImageBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@

#include "FilterBase.h"

#include "glew-mx.h"

// forward declarations
struct PyImage;
class ImageSource;
Expand Down
36 changes: 14 additions & 22 deletions source/gameengine/VideoTexture/ImageRender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@

#include "ImageRender.h"
#include "ImageBase.h"
#include "BlendType.h"
#include "Exception.h"
#include "Texture.h"

Expand Down Expand Up @@ -468,12 +467,6 @@ inline ImageRender * getImageRender (PyImage *self)

// python methods

// Blender Scene type
static BlendType<KX_Scene> sceneType ("KX_Scene");
// Blender Camera type
static BlendType<KX_Camera> cameraType ("KX_Camera");


// object initialization
static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
{
Expand All @@ -496,15 +489,18 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
{
// get scene pointer
KX_Scene * scenePtr (NULL);
if (scene != NULL) scenePtr = sceneType.checkType(scene);
// throw exception if scene is not available
if (scenePtr == NULL) THRWEXCP(SceneInvalid, S_OK);
if (!PyObject_TypeCheck(scene, &KX_Scene::Type)) {
THRWEXCP(SceneInvalid, S_OK);
}
else {
scenePtr = static_cast<KX_Scene *>BGE_PROXY_REF(scene);
}

// get camera pointer
KX_Camera * cameraPtr (NULL);
if (camera != NULL) cameraPtr = cameraType.checkType(camera);
// throw exception if camera is not available
if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK);
if (!ConvertPythonToCamera(scenePtr, camera, &cameraPtr, false, "")) {
THRWEXCP(CameraInvalid, S_OK);
}

// get pointer to image structure
PyImage *self = reinterpret_cast<PyImage*>(pySelf);
Expand Down Expand Up @@ -768,28 +764,24 @@ static int ImageMirror_init(PyObject *pySelf, PyObject *args, PyObject *kwds)

// get observer pointer
KX_GameObject * observerPtr (NULL);
if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type))
observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer);
else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type))
observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer);
else
if (!ConvertPythonToGameObject(scenePtr->GetLogicManager(), observer, &observerPtr, false, "")) {
THRWEXCP(ObserverInvalid, S_OK);
}

if (observerPtr==NULL) /* in case the python proxy reference is invalid */
THRWEXCP(ObserverInvalid, S_OK);

// get mirror pointer
KX_GameObject * mirrorPtr (NULL);
if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type))
mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror);
else
if (!ConvertPythonToGameObject(scenePtr->GetLogicManager(), mirror, &mirrorPtr, false, "")) {
THRWEXCP(MirrorInvalid, S_OK);
}

if (mirrorPtr==NULL) /* in case the python proxy reference is invalid */
THRWEXCP(MirrorInvalid, S_OK);

// locate the material in the mirror
RAS_IPolyMaterial * material = getMaterial(mirror, materialID);
RAS_IPolyMaterial * material = getMaterial(mirrorPtr, materialID);
if (material == NULL)
THRWEXCP(MaterialNotAvail, S_OK);

Expand Down
Loading

0 comments on commit ef7fbd8

Please sign in to comment.