TGEA/TGB, GCC-XML, and Python
by Prairie Games · 11/26/2007 (2:41 pm) · 11 comments
I recently spent a couple weeks evaluating technology options for our next game. It felt good to be in this mode... though, I think it felt better coming to a resolution. :)
We're going with Torque Game Engine Advanced. I also really want to use Torque Game Builder for the 2D and minigame elements. TGB is really, really advanced compared to the stock TGE/TGEA 2D game stuff. I think this will work out great. We've got TGB rendering using Direct3D9 and I should be able to get them glued together nicely with Python.
We've gathered a fair amount of experience using Torque and Python together. I've been satisfied hooking into the TorqueScript console using its "everything is a string" design. This gives us access to console objects and the ability to expose Python functions to the console system. It is pretty basic and has worked out pretty well...
While evaluating Ogre and Qt as a possible solutions for rendering/GUI, I checked out their Python wrappers: Python-Ogre and PyQT. They both use GCC-XML to parse the C++ code, generate an XML representation, and automatically generate binding code from the XML. This was really interesting... and a long story short: it works out great with Torque.
Here's the process:
1. GCC-XML is used to compile the Torque header files and generate a full XML representation of the namespaces, classes, enumerations, etc
2. I wrote a custom tool to take the C++ information generated by GCC-XML, filter it using pygccxml, and automatically generate a SIP interface file
3. SIP then generates the wrapper sources. Importantly, the wrapper code is in 100% C++, tight, and quite efficient. SIP generates very good bindings compared to tools like SWIG, Boost::Python, etc. It was written for PyQT and that rocks :)
There are some really, really big wins over the "everything is a string" method of the previous PyTorque bindings. The biggest thing is that it is now possible to derive new script classes directly from Torque C++ classes with full inheritance, virtual methods, variable access, enumerations, structures, etc... it is all accessible. There's quite a bit of new functionality... some of which is described in the example below. This is really powerul stuff!!!
I've been looking into C# a bit too... and it would definitely be possible to generate similar bindings using GCC-XML. I will probably look into this more once IronPython (Microsoft's Python implementation built on the DLR) is more mature.... that won't be for this game :)
I've got a bit more work to do on the bindings... want to get an integration pass done with TGEA + TGB... and then, WOOHOO!!!
-Josh Engebretson
President
Prairie Games, Inc
MMOWorkshop.com
Here's some example usage
We're going with Torque Game Engine Advanced. I also really want to use Torque Game Builder for the 2D and minigame elements. TGB is really, really advanced compared to the stock TGE/TGEA 2D game stuff. I think this will work out great. We've got TGB rendering using Direct3D9 and I should be able to get them glued together nicely with Python.
We've gathered a fair amount of experience using Torque and Python together. I've been satisfied hooking into the TorqueScript console using its "everything is a string" design. This gives us access to console objects and the ability to expose Python functions to the console system. It is pretty basic and has worked out pretty well...
While evaluating Ogre and Qt as a possible solutions for rendering/GUI, I checked out their Python wrappers: Python-Ogre and PyQT. They both use GCC-XML to parse the C++ code, generate an XML representation, and automatically generate binding code from the XML. This was really interesting... and a long story short: it works out great with Torque.
Here's the process:
1. GCC-XML is used to compile the Torque header files and generate a full XML representation of the namespaces, classes, enumerations, etc
2. I wrote a custom tool to take the C++ information generated by GCC-XML, filter it using pygccxml, and automatically generate a SIP interface file
3. SIP then generates the wrapper sources. Importantly, the wrapper code is in 100% C++, tight, and quite efficient. SIP generates very good bindings compared to tools like SWIG, Boost::Python, etc. It was written for PyQT and that rocks :)
There are some really, really big wins over the "everything is a string" method of the previous PyTorque bindings. The biggest thing is that it is now possible to derive new script classes directly from Torque C++ classes with full inheritance, virtual methods, variable access, enumerations, structures, etc... it is all accessible. There's quite a bit of new functionality... some of which is described in the example below. This is really powerul stuff!!!
I've been looking into C# a bit too... and it would definitely be possible to generate similar bindings using GCC-XML. I will probably look into this more once IronPython (Microsoft's Python implementation built on the DLR) is more mature.... that won't be for this game :)
I've got a bit more work to do on the bindings... want to get an integration pass done with TGEA + TGB... and then, WOOHOO!!!
-Josh Engebretson
President
Prairie Games, Inc
MMOWorkshop.com
Here's some example usage
[b]#The pytgb.engine module is a (fast) Python C++ wrapper for TGB
#The module is automatically generated by a tool which leverages:
# GCC-XML: http://www.gccxml.org
# pygccxml: http://www.language-binding.net/pygccxml/pygccxml.html
# SIP: http://www.riverbankcomputing.co.uk/sip/index.php[/b]
from pytgb.engine import *
[b]#This isn't your daddy's TorqueScript...
#You can derive script classes directly from C++ classes with full inheritance[/b]
class MyBitmapButtonCtrl(GuiBitmapButtonCtrl):
def __init__(self):
[b]#We can call into the C++ constructor![/b]
GuiBitmapButtonCtrl.__init__(self)
[b]#Fields can be set/read and feature automatic type conversion[/b]
self.toolTip = "Click me!"
self.visible = True
[b]#C++ Enumerations are fully supported[/b]
self.buttonType = self.ButtonTypePush
[b]#Dynamic variables can be set and read [/b]
self.setDataField("myDynamicValue", "", "Wahwahweewah!")
[b]#Our own Python attributes can of course be added[/b]
self.coolness = True
[b]#It is possible to override any virtual class method... defined in C++![/b]
def onAction(self):
#We can call base classes implementation.
self.parentClass.onAction(self)
print "I was clicked!"
def inspectPostApply(self):
self.parentClass.inspectPostApply(self)
print "I've been applied!"
def onAdd(self):
self.parentClass.onAdd(self)
print "I've been added!"
[b]#We can also add entirely new methods (and expose them to the console system... or not!)[/b]
def setCoolness(self, value):
self.coolness = value
def getCoolness(self):
return self.coolness
[b]#This behaves exactly like the IMPLEMENT_CONOBJECT macro C++ side.
#It hooks our (dynamic) Python class into the Torque console system
#as a first class citizen![/b]
IMPLEMENT_CONOBJECT(MyBitmapButtonCtrl)
[b]#If you need to access methods from TorqueScript...
#they can be exposed as ConsoleMethods (just like C++ side)
#Though, keep in mind that we can derive new Python classes from C++ classes.
#So, you often wouldn't need to expose them for scripting purposes![/b]
ConsoleMethod(MyBitmapButtonCtrl.setCoolness, "(boolean)", 3, 3)
ConsoleMethod(MyBitmapButtonCtrl.getCoolness, "boolean ()", 2, 2)
[b]#Console functions can also be exposed[/b]
def HelloWorld():
return "Hello World!"
[b]#Again, just like C++ side[/b]
ConsoleFunction(HelloWorld, "()", 1, 1)
[b]#Console funtions can also take arguments[/b]
def HelloWorldWithArgument(arg):
return "Hello World with Argument: %s", arg
ConsoleFunction(HelloWorldWithArgument, "(argument)", 2, 2)
[b]#Let's initialize TGB (this includes any platform specific stuff, for fonts or whatever)[/b]
TGBInitialize()
[b]#We're running the main loop here... neat[/b]
while Game.isRunning():
Game.mainLoop()
[b]#Once we're out of the main loop, it is time to shut the system down[/b]
Game.mainShutdown()
[b]#Finally, let's clean up any platform specifics[/b]
TGBShutdown()
#2
11/26/2007 (4:20 pm)
Wow, this is all way over my head but it sounds awesome!
#3
11/26/2007 (5:06 pm)
Good stuff...
#4
I've written a script which uses GCC-XML (via pygccxml) to automatically generate the interface files. This is using the actual header files from Torque and the project... so if they change, it's trivial to regenerate the interfaces. I've written some C++ code to get things all jiving together. It is getting interesting now.
GCC-XML (and pygccxml which is just a nice way to interact with the XML compiler data) could be used for all kinds of stuff. It is a really cool code analysis system...
11/26/2007 (7:27 pm)
@Jay: SIP is pretty darned great at generating efficient wrappers. They also compile fast and have a small footprint. The interface language, Python module, and C++ support functions help a lot too for corner cases.I've written a script which uses GCC-XML (via pygccxml) to automatically generate the interface files. This is using the actual header files from Torque and the project... so if they change, it's trivial to regenerate the interfaces. I've written some C++ code to get things all jiving together. It is getting interesting now.
GCC-XML (and pygccxml which is just a nice way to interact with the XML compiler data) could be used for all kinds of stuff. It is a really cool code analysis system...
#6
11/27/2007 (5:52 am)
Good stuff.
#7
11/27/2007 (7:01 am)
Python is easy!!! V Cool. I wonder though, have you worked out a reload script system so you do basically edit and continue but in Python? I've always found that difficult.
#8
Correct me where I am wrong but this is how I translated your .plan;
GCC-XML -> Custom C++ bit -> pygccxml -> SIP gives Python access to all the TGB and TGEA goodness.
Would this allow you to use 100% Python to write TGB and TGEA based games?
Sammual
11/27/2007 (11:01 am)
I'm lost.Correct me where I am wrong but this is how I translated your .plan;
GCC-XML -> Custom C++ bit -> pygccxml -> SIP gives Python access to all the TGB and TGEA goodness.
Would this allow you to use 100% Python to write TGB and TGEA based games?
Sammual
#9
I'm in situation, when at couple of places (server-side) I need to do something to gain more performance. I'm thinking about moving the stuff into engine/c++, or -- if the python in torque is at least 2-3 times faster than TS, I'll pick it up..
Can you share your experience on that?
ty
12/02/2007 (6:09 am)
Josh, can you tell apprx how fast the Python comparing to the TS?I'm in situation, when at couple of places (server-side) I need to do something to gain more performance. I'm thinking about moving the stuff into engine/c++, or -- if the python in torque is at least 2-3 times faster than TS, I'll pick it up..
Can you share your experience on that?
ty
#10
I developed a complete ruby binding for torque and my approach was to generate the interface from the documentation string, which holds the type information of the parameters (I had to fix some parts of the documentation). The argument types are parsed and each ruby interface method checks the arguments for type safety. Additionally class fields exposed in the engine are accessible by ruby and converted to the right type.
Using this interface I rewrote almost all torque scripts of the tgea distribution and it works quite well. Using your interface generation method, I could generate a tighter ruby binding, which exposes all c++ methods and would circumvent the string conversion of arguments. Are you inclined to share the code?
P.S.: Overriding virtual methods seems to me only achievable by generating a c++ class or am I missing something?
01/20/2008 (4:17 am)
This is really interesting!I developed a complete ruby binding for torque and my approach was to generate the interface from the documentation string, which holds the type information of the parameters (I had to fix some parts of the documentation). The argument types are parsed and each ruby interface method checks the arguments for type safety. Additionally class fields exposed in the engine are accessible by ruby and converted to the right type.
Using this interface I rewrote almost all torque scripts of the tgea distribution and it works quite well. Using your interface generation method, I could generate a tighter ruby binding, which exposes all c++ methods and would circumvent the string conversion of arguments. Are you inclined to share the code?
P.S.: Overriding virtual methods seems to me only achievable by generating a c++ class or am I missing something?
#11
01/20/2008 (4:20 am)
@bank: python should be faster than torque script. I did some silly benchmarks, comparing ruby with torque script and ruby was definitely faster. Python is bytecode-based, so I expect it to be even faster. 
Torque 3D Owner Jay Barnson
If I wasn't already halfway through the code of my current project in TorqueScript, I'd be on this in a heartbeat. I've kinda been out of the Python development space for about three years now, and it seems like a lot has changed and improved since then. I'd never heard of SIP before. Is it really as simple as you make it look?