Boost Python и OGRE — разные результаты с эквивалентным кодом

Я просто повторно опубликую то, что я публиковал на форумах OGRE:

Я не уверен, будет ли лучше размещать сообщения здесь или на форуме «Использование 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()

Эквивалент С++ (цветное окно просмотра):

-- Заголовок

#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;
}

Я проверил - mBackColorOgre::Viewport) правильно настроен через Python, так что это не проблема.

Кроме того, код Python по какой-то причине отлично работает, если я поместил цикл рендеринга внутри функции initialize(), но не вне ее. Из-за этого у меня такое ощущение, что это проблема контекста (возможно, данные повреждаются, когда интерпретатор выходит из функции инициализации или что-то в этом роде.

Вот странно работающий код 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::Root, mLevel содержит диспетчер сцен, а mCamera - это обычная камера OGRE, просто обернутая через мой собственный API для простоты использования. WindowInfo - еще один класс-оболочка, который обрабатывает настройки окна (между OGRE и SDL), и я просто вызываю renderOneFrame() в своей функции updateGraphics(delta).

Так что же я делаю неправильно, что код Python с теми же вызовами, что и вызовы C++, приводит к другому результату?


person Ilija Boshkov    schedule 07.09.2014    source источник


Ответы (1)


Итак, после установки множества точек останова я обнаружил, что когда интерпретатор выходит из функции initialize(), он уничтожает объекты mLevel и mCamera, потому что (я новичок в 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()
person Ilija Boshkov    schedule 07.09.2014
comment
Итак, эта проблема решена? Прочитав свой собственный ответ на форумах Ogre3D, я предполагаю, что да. Если это так, отметьте свой ответ как принятый. - person Philip Allgaier; 09.09.2014
comment
Да, я думаю, что по какой-то причине я не мог принять свой собственный ответ, сделанный сейчас. - person Ilija Boshkov; 12.09.2014