I'll just re-post what I posted on the OGRE forums:
I'm not sure if it would be better to post here, or in the "Using OGRE in practice" forum, but I'll give it a shot, as this is the most frequented section of the boards.
So I'm making bindings for my own framework which uses OGRE internally, I've bound the core objects, and for the most part they work fine (input and windowing works properly), but I've had this one issue which I can't get to the bottom of - the viewport of the Python application is always black (I have no objects other than the camera, just setting the background color of the viewport).
The weird thing is - the exact equivalent in C++ works fine, yet the python-bound code does not. Nothing of importance is shown in the log.
Here's how I bind my objects:
#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);
}
The Python code (blank viewport):
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()
The C++ equivalent (colored viewport):
-- Header
#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;
}
I did a check - mBackColor
(in Ogre::Viewport) is properly set through Python, so that's not the problem.
Also, the Python code works fine for some reason if I put the render loop inside the initialize()
function, but not if it's outside of that. Because of this, I have a feeling it's a context issue (maybe the data gets corrupted when the interpreter gets out of the initialize function or something.
Here's the oddly working Python code:
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()
-- Some info on my framework: Kernel contains and calls Ogre::Root
, mLevel
contains a scene manager, and mCamera
is a regular OGRE camera, just wrapped through my own API for ease of use WindowInfo is another wrapper class that handles window settings (between OGRE and SDL) and I just call renderOneFrame()
in my updateGraphics(delta)
function.
So what am I doing wrong that the python code with the same calls as the C++ calls results in a different outcome?