18-09-2011

In recent commits I've worked on two important things: 1) The ability to inherit from C++ classes in Python and 2) the restructuring of Wrappyr so it can be installed and used as a library.

Inheritance from C++ classes in Python
The initial implementation of (single) inheritance from C++ classes in Python is made. It works by generating a subclass for each C++ that has any virtual methods. This subclass overrides all virtual methods and is instantiated with a pointer to a Python object and a pointer to a vtable. This vtable contains function pointers to all methods overridden in Python and null pointers to for the methods which are overridden. Each overridden method checks whether the Python callback in the vtable was filled in and calls that function or calls the parent method. By using a metaclass in Python the vtable is automatically generated so all you have to do is subclass a class.

from Box2D.dynamics import b2World, b2RayCastCallback

class MyRayCastCallback(b2RayCastCallback):
	def ReportFixture(self, fixture, point, normal, fraction):
		print self, fixture, (point.x, point.y), (normal.x, normal.y), fraction
		return 1.0

world = b2World()
world.RayCast(MyRayCastCallback(), b2Vec2(-0.7, -9.0), b2Vec2(0.3, -9.0))

Of course, this example doesn't print anything since the world is not populated with objects yet, but you get the idea. See tests/test_box2d.py in the Wrappyr repository for a working example.

Project restructuring
Another thing that I've wanted to do for a while now is turning Wrappyr into a library and streamlining the process of getting a working Python API from C/C++ code. The work on that has begun. The two Python scripts clang_convert.py and generate_ctypes_api.py have been merged to the generate.py script which lives in the wrappyr package.

In this script I've introduced the concept of a 'package', something I have to give better name some day. A package is simply a class that holds all information needed to generate the Python API. It contains which language (C or C++) the source code is in, methods to retrieve the right classes to process code data (from the Clang export) and a method to preprocess the Ctypes API. This is not yet all that is needed to easily generate the Python API, but it is a step in the right direction. See the README.rst and packages/Box2D.py files in the GitHub repository for more information and an example of a package respectively.


30-08-2011

I've just made a commit to GitHub. The most important changes are that you can now create and use arrrays of C++ classes, and that the generated Python code now does type checks.

Because pointers are used for a number of purposes in C/C++, I've added a new PointerType class (created in XML with the <pointer> element). You can use this to indicate how a pointer is used in the C world. There are three different cases that you'll be able to use and combine:

  • Reference, indicated by the reference boolean attribute. You can use this to say that the pointer is used to pass something by reference instead of value. Combined with array (which is not supported yet), this would mean an array of references. Combined with out parameter, this whould mean that a function uses this pointer to return a pointer. Use this for functions like the following:
    bool get_person_by_name(char* name, person** out);
  • Array, indicated by the array boolean attribute. You can use this to indicate that a function expects or returns a pointer to an array. In C++, this would for example mean:
    new b2Vec2[2];
  • Out parameter, indicated by the outparam boolean attribute. You can use this for function that use pointers to return values. Use this for functions like the following:
    void get_health_and_age(person* p, int* health_out, int* age_out);
Not all cases are handled yet, but a start has been made.

You can now create and use arrays of C++ classes. For each C++, methods are created to create an array of n elements, to delete an array and to get the nth element of an array given a pointer to the first element of an array. They are exposed to the Ctypes API generator by adding the __newarray__, __delarray__ and __arrayitem__ methods to a class. This allows you do things like this.

from wrappyr_runtime import arrayof
from Box2D.common import b2Vec2
from Box2D.collision.shapes import b2PolygonShape

vertices = arrayof(b2Vec2, 3)
vertices[0].Set(0.0, 0.0) # You can get elements by index
vertices[1].Set(1.0, 0.0)
vertices[2].Set(0.0, 1.0)

# Since we created it we know the array size
# and can iterate over it
for vertex in vertices:
	print vertex.x, vertex.y

# If the size of an array is unknown, you iterate over it
# using the elements method to explicitly tell how many
# elements you want to iterate over
for vertex in vertices.elements(3):
	print vertex.x, vertex.y

shape = b2PolygonShape()
shape.Set(vertices, 3) # And you can pass it to functions

I'll now continue to implement something more fun, inheritence from C++ classes in Python.