Boost Python和OGRE - 使用等效代码的不同结果

时间:2014-09-07 16:29:19

标签: python c++ boost boost-python ogre

我将重新发布what I posted on the OGRE forums

我不确定在这里发帖或者在“在实践中使用OGRE”论坛是否更好,但我会试一试,因为这是主板上最常用的部分。

所以我正在为我自己的框架进行绑定,它在内部使用OGRE,我绑定了核心对象,并且大多数情况下它们工作正常(输入和窗口正常工作),但我有这个问题我无法到达底部 - Python应用程序的视口始终是黑色的(除了相机之外我没有其他对象,只是设置视口的背景颜色)。

奇怪的是 - C ++中的完全等效工作正常,但python绑定的代码却没有。日志中没有显示任何重要信息。

以下是我绑定对象的方法:

#include "boost/python.hpp"
#include "boost/exception/diagnostic_information.hpp"
#include "Demo.hpp"
#include "Demo.cpp"
#include "XMLLevelLoader.h"

void addResourceLocation(const Crimson::String& group, const Crimson::String& loc)
{
    Ogre::ResourceGroupManager* resmgr = Ogre::ResourceGroupManager::getSingletonPtr();
    resmgr->addResourceLocation(loc, "FileSystem", group);
}

void initResourceGroup(const Crimson::String& group)
{
    Ogre::ResourceGroupManager* resmgr = Ogre::ResourceGroupManager::getSingletonPtr();
    resmgr->initialiseResourceGroup(group);
}

class AppWrapper : public Crimson::Application, public boost::python::wrapper<Crimson::Application>
{
public:
    void onKeyDown(const SDL_KeyboardEvent& e)
    {
        boost::python::override over = this->get_override("onKeyDown");
        if (over)
            over(e);
    }
    using Crimson::Application::mQuit;
};

BOOST_PYTHON_MODULE(PyEngine)
{
    using namespace boost::python;
    def("initResourceGroup", initResourceGroup);
    def("addResourceLocation", addResourceLocation);

    enum_<SDL_Scancode>("SDL_Scancode");

    class_<Ogre::ColourValue>("Color", init<const float, const float, const float, const float>())
        .def_readwrite("r", &Ogre::ColourValue::r)
        .def_readwrite("g", &Ogre::ColourValue::g)
        .def_readwrite("b", &Ogre::ColourValue::b)
        .def_readwrite("a", &Ogre::ColourValue::a);

    class_<Ogre::Viewport>("Viewport", init<Ogre::Camera* , Ogre::RenderTarget*, float, float, float, float, int>())
        .def("setBackgroundColour", &Ogre::Viewport::setBackgroundColour);

    class_<Crimson::WindowInfo>("WindowInfo")
        .def_readonly("renderWnd", &Crimson::WindowInfo::renderWnd)
        .def_readonly("sdlWnd", &Crimson::WindowInfo::sdlWnd)
        .def("addViewport", &Crimson::WindowInfo::addViewport, return_value_policy<reference_existing_object>())
        .def("getAspectRatio", &Crimson::WindowInfo::getAspectRatio)
        .def("getWidth", &Crimson::WindowInfo::getWidth)
        .def("getHeight", &Crimson::WindowInfo::getHeight);

    class_<Crimson::Kernel>("Kernel")
        .def("initialize", &Crimson::Kernel::initialize)
        .def("createRenderWindow", &Crimson::Kernel::createRenderWindow, return_value_policy<reference_existing_object>())
        .def("getWindowInfo", &Crimson::Kernel::getWindowInfo, return_value_policy<reference_existing_object>())
        .def("destroy", &Crimson::Kernel::destroy)
        .def("render", &Crimson::Kernel::render);

    class_<Crimson::Actor>("Actor", init<Crimson::Level*, const Crimson::String&, Crimson::Actor*>())
        .def("setPosition", static_cast<void(Crimson::Actor::*)(const Crimson::Vector3&)>(&Crimson::Actor::setPosition))
        .def("getPosition", &Crimson::Actor::getPosition);

    class_ <Crimson::Mesh, bases<Crimson::Actor>>("Mesh", init<Crimson::Level*, const Crimson::String&, const Crimson::String&, Crimson::Actor*>());

    class_ <Crimson::Camera, bases<Crimson::Actor>>("Camera", init<Crimson::Level*, const Crimson::String&, Crimson::Actor*>())
        .def("setAspectRatio", &Crimson::Camera::setAspectRatio);

    class_<rapidxml::xml_node<>, boost::noncopyable>("xml_node", init<rapidxml::node_type>())
        .def("first_node", &rapidxml::xml_node<>::first_node, return_value_policy<reference_existing_object>());

    class_<rapidxml::xml_document<>, boost::noncopyable>("xml_document")
        .def("first_node", &rapidxml::xml_document<>::first_node, return_value_policy<reference_existing_object>())
        .def("parse", &rapidxml::xml_document<>::parse<0>);

    class_<Crimson::Level>("Level", init<Crimson::Kernel*>())
        .def("initialize", &Crimson::Level::initialize)
        .def("destroy", &Crimson::Level::destroy)
        .def("createActor", &Crimson::Level::createActor, return_value_policy<reference_existing_object>())
        .def("createMesh", &Crimson::Level::createMesh, return_value_policy<reference_existing_object>())
        .def("createCamera", &Crimson::Level::createCamera, return_value_policy<reference_existing_object>());

    class_<Crimson::XMLLevelLoader>("XMLLevelLoader", init<Crimson::String>())
        .def("load", &Crimson::XMLLevelLoader::load)
        .def("loadFileAsString", &Crimson::XMLLevelLoader::loadFileAsString)
        .def("loadResources", &Crimson::XMLLevelLoader::loadResources)
        .staticmethod("loadFileAsString")
        .staticmethod("loadResources");

    class_<AppWrapper, boost::noncopyable>("Application")
        .def("initialize", &Crimson::Application::initialize)
        .def("destroy", &Crimson::Application::destroy)
        .def("onKeyDown", &Crimson::Application::onKeyDown)
        .def("start", &Crimson::Application::start)
        .def("updateGraphics", &Crimson::Application::updateGraphics)
        .def("updateInput", &Crimson::Application::updateInput)
        .def("isRunning", &Crimson::Application::isRunning)
        .def("quit", &Crimson::Application::quit)
        .def("getKernel", &Crimson::Application::getKernel, return_value_policy<reference_existing_object>());

    class_<SDL_Keysym>("SDL_Keysym")
        .def_readonly("mod", &SDL_Keysym::mod)
        .def_readonly("scancode", &SDL_Keysym::scancode);

    class_<SDL_KeyboardEvent>("SDL_KeyboardEvent")
        .def_readonly("keysym", &SDL_KeyboardEvent::keysym);

    class_<Ogre::Vector3>("Vector3", init<const float, const float, const float>())
        .def_readwrite("x", &Ogre::Vector3::x)
        .def_readwrite("y", &Ogre::Vector3::y)
        .def_readwrite("z", &Ogre::Vector3::z);
}

Python代码(空白视口):

import sys
from PyEngine import *

# Class definition
class TestPythonApp(Application):
    def initialize(self):
        Application.initialize(self)

        mLevel = Level(self.getKernel())
        mLevel.initialize()

        mCamera = mLevel.createCamera("test", None)
        vp = self.getKernel().getWindowInfo().addViewport(mCamera)
        vp.setBackgroundColour(Color(0.8, 0, 0, 1))
    def start(self):
        while self.isRunning():
            self.updateInput()
            self.updateGraphics(1)

    mLevel  = None
    mCamera = None

# /Class definition

# Script execution
app = TestPythonApp()
app.initialize()
app.start()
app.destroy()

C ++等价物(彩色视口):

- 标题

#ifndef PYAPP_HPP
#define PYAPP_HPP
#include "Application.h"
#include "XMLLevelLoader.h"

class PythonApp : public Crimson::Application
{
public:
    bool initialize();
    void start();

protected:
    Crimson::Camera*    mCamera;
    Crimson::Level*     mLevel;
};
#endif

-- Source:
bool PythonApp::initialize()
{
    Application::initialize();

    mLevel = new Crimson::Level(mKernel);
    mLevel->initialize();
    mCamera = mLevel->createCamera("cam");
    Ogre::Viewport* vp = mKernel->getWindowInfo()->addViewport(mCamera);
    vp->setBackgroundColour(Ogre::ColourValue(0.7f, 0.8f, 0.7f));

    return true;
}

void PythonApp::start()
{
    while (isRunning())
    {
        updateInput();
        updateGraphics(1);
    }
}

int main(int argc, char* argv[])
{
    PythonApp game;
    game.initialize();
    game.start();
    game.destroy();

    return 0;
}

我做了检查 - mBackColor(在 Ogre :: Viewport 中)通过Python正确设置,所以这不是问题。

此外,如果我将渲染循环放在initialize()函数中,Python代码可以正常工作,但如果它不在其中,则不行。因此,我感觉这是一个上下文问题(当解释器退出初始化函数时,可能会损坏数据。

这是奇怪的Python代码:

import sys
from PyEngine import *

# Class definition
class TestPythonApp(Application):
    def initialize(self):
        Application.initialize(self)

        mLevel = Level(self.getKernel())
        mLevel.initialize()

        mCamera = mLevel.createCamera("test", None)
        vp = self.getKernel().getWindowInfo().addViewport(mCamera)
        vp.setBackgroundColour(Color(0.8, 0, 0, 1))
        self.start() # Moved line app.start() to here.
    def start(self):
        while self.isRunning():
            self.updateInput()
            self.updateGraphics(1)

    mLevel  = None
    mCamera = None

# /Class definition

# Script execution
app = TestPythonApp()
app.initialize()
#app.start() # This moved up to initialize makes it work
app.destroy()

- 关于我的框架的一些信息:内核包含和调用Ogre::RootmLevel包含一个场景管理器,mCamera是一个普通的OGRE摄像头,只是通过我自己的API包装易用性WindowInfo是另一个处理窗口设置的包装类(在OGRE和SDL之间),我只需在renderOneFrame()函数中调用updateGraphics(delta)

那么我错误的是,与C ++调用具有相同调用的python代码导致了不同的结果?

1 个答案:

答案 0 :(得分:0)

好的,所以在设置了很多断点后,我发现当解释器退出函数initialize()时,它会销毁mLevelmCamera对象,因为(我是Python的新手,我是)我忘了在Python中自我/这并不暗示,因此我的对象因Ogre::SceneManager的破坏而被破坏(删除mLevel时)。

更新(工作)代码:

import sys
from PyEngine import *

# Class definition
class TestPythonApp(Application):
    def initialize(self):
        Application.initialize(self)

        self.mLevel = Level(self.getKernel())
        self.mLevel.initialize()

        self.mCamera = self.mLevel.createCamera("test", None)
        self.mViewport = self.getKernel().getWindowInfo().addViewport(self.mCamera)
        self.mViewport.setBackgroundColour(Color(0.8, 0, 0, 1))
        print("Object: %s, of size: %d" % (self.mViewport, sys.getsizeof(self.mViewport)))
        #self.start();
    def start(self):
        while self.isRunning():
            self.updateInput()
            self.updateGraphics(1)

    mLevel   = None
    mViewport = None
    mCamera      = None

# /Class definition

# Script execution
app = TestPythonApp()
print("Initing");
app.initialize()
print("Object: %s, of size: %d" % (app.mViewport, sys.getsizeof(app.mViewport)))
app.start() # This moved up to initialize makes it work
app.destroy()