src/raytracermodule.cc
branchpyrit
changeset 90 f6a72eb99631
parent 89 fcf1487b398b
child 91 9d66d323c354
--- a/src/raytracermodule.cc	Tue Apr 29 13:56:29 2008 +0200
+++ b/src/raytracermodule.cc	Tue Apr 29 23:31:08 2008 +0200
@@ -28,8 +28,53 @@
 
 #include <vector>
 #include "raytracer.h"
+#include "octree.h"
 #include "kdtree.h"
 
+#define TYPE_OBJECT(name, basicsize, dealloc, flags, doc, methods, members, base, init) \
+{ \
+	PyObject_HEAD_INIT(NULL) \
+	0,                          /* ob_size */ \
+	(name),                     /* tp_name */ \
+	(basicsize),                /* tp_basicsize*/ \
+	0,                          /* tp_itemsize*/ \
+	(dealloc),                  /* tp_dealloc*/ \
+	0,                          /* tp_print*/\
+	0,                          /* tp_getattr*/\
+	0,                          /* tp_setattr*/\
+	0,                          /* tp_compare*/\
+	0,                          /* tp_repr*/\
+	0,                          /* tp_as_number*/\
+	0,                          /* tp_as_sequence*/\
+	0,                          /* tp_as_mapping*/\
+	0,                          /* tp_hash */\
+	0,                          /* tp_call*/\
+	0,                          /* tp_str*/\
+	PyObject_GenericGetAttr,    /* tp_getattro*/\
+	0,                          /* tp_setattro*/\
+	0,                          /* tp_as_buffer*/\
+	(flags),                    /* tp_flags*/\
+	(doc),                      /* tp_doc */\
+	0,                          /* tp_traverse */\
+	0,                          /* tp_clear */\
+	0,                          /* tp_richcompare */\
+	0,                          /* tp_weaklistoffset */\
+	0,                          /* tp_iter */\
+	0,                          /* tp_iternext */\
+	(methods),                  /* tp_methods */\
+	(members),                  /* tp_members */\
+	0,                          /* tp_getset */\
+	(base),                     /* tp_base */\
+	0,                          /* tp_dict */ \
+	0,                          /* tp_descr_get */ \
+	0,                          /* tp_descr_set */ \
+	0,                          /* tp_dictoffset */ \
+	(init),                     /* tp_init */ \
+	0,                          /* tp_alloc */ \
+	0,                          /* tp_new */ \
+	0,                          /* tp_free */ \
+}
+
 //=========================== Light Source Object ===========================
 
 typedef struct {
@@ -39,33 +84,26 @@
 
 static PyObject *Light_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Light_Destructor(PyObject* self);
-static PyObject *Light_Getattr(PyObject *self, char *name);
 static PyObject *Light_castShadows(PyObject* self, PyObject* args);
 
-static PyTypeObject LightType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Light",			/*tp_name*/
-	sizeof(LightObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Light_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Light_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
-
 static PyMethodDef LightMethods[] = {
 	{"castShadows", (PyCFunction)Light_castShadows, METH_VARARGS, "Enable or disable shadows from this light."},
 	{NULL, NULL}
 };
 
+static PyTypeObject LightType =
+TYPE_OBJECT(
+	"Light",                    /* tp_name */
+	sizeof(LightObject),        /* tp_basicsize */
+	Light_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Light type",               /* tp_doc */
+	LightMethods,               /* tp_methods */
+	0,                          /* tp_members */
+	0,                          /* tp_base */
+	0                           /* tp_init */
+);
+
 static PyObject* Light_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
 	LightObject *v;
@@ -91,12 +129,7 @@
 static void Light_Destructor(PyObject* self)
 {
 	delete ((LightObject *)self)->light;
-	PyObject_Del(self);
-}
-
-static PyObject *Light_Getattr(PyObject *self, char *name)
-{
-	return Py_FindMethod(LightMethods, self, name);
+	self->ob_type->tp_free(self);
 }
 
 static PyObject *Light_castShadows(PyObject* self, PyObject* args)
@@ -121,30 +154,10 @@
 
 static PyObject *Camera_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Camera_Destructor(PyObject* self);
-static PyObject *Camera_Getattr(PyObject *self, char *name);
 static PyObject *Camera_setEye(PyObject* self, PyObject* args);
 static PyObject *Camera_setAngle(PyObject* self, PyObject* args);
 static PyObject *Camera_rotate(PyObject* self, PyObject* args);
 
-static PyTypeObject CameraType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Camera",			/*tp_name*/
-	sizeof(CameraObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Camera_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Camera_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
-
 static PyMethodDef CameraMethods[] = {
 	{"setEye", (PyCFunction)Camera_setEye, METH_VARARGS, "Set eye of the camera."},
 	{"setAngle", (PyCFunction)Camera_setAngle, METH_VARARGS, "Set vertical angle of view."},
@@ -152,6 +165,19 @@
 	{NULL, NULL}
 };
 
+static PyTypeObject CameraType =
+TYPE_OBJECT(
+	"Camera",                    /* tp_name */
+	sizeof(CameraObject),        /* tp_basicsize */
+	Camera_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Camera type",               /* tp_doc */
+	CameraMethods,               /* tp_methods */
+	0,                           /* tp_members */
+	0,                           /* tp_base */
+	0                            /* tp_init */
+);
+
 static PyObject* Camera_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
 	CameraObject *v;
@@ -207,15 +233,9 @@
 static void Camera_Destructor(PyObject* self)
 {
 	delete ((CameraObject *)self)->camera;
-	PyObject_Del(self);
+	self->ob_type->tp_free(self);
 }
 
-static PyObject *Camera_Getattr(PyObject *self, char *name)
-{
-	return Py_FindMethod(CameraMethods, self, name);
-}
-
-
 static PyObject *Camera_setEye(PyObject* self, PyObject* args)
 {
 	PyObject *TEye = NULL;
@@ -274,31 +294,11 @@
 
 static PyObject *Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Material_Destructor(PyObject* self);
-static PyObject *Material_Getattr(PyObject *self, char *name);
 static PyObject *Material_setPhong(PyObject* self, PyObject* args);
 static PyObject *Material_setReflectivity(PyObject* self, PyObject* args);
 static PyObject *Material_setTransmissivity(PyObject* self, PyObject* args);
 static PyObject *Material_setSmooth(PyObject* self, PyObject* args);
 
-static PyTypeObject MaterialType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Material",			/*tp_name*/
-	sizeof(MaterialObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Material_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Material_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
-
 static PyMethodDef MaterialMethods[] = {
 	{"setPhong", (PyCFunction)Material_setPhong, METH_VARARGS, "Set ambient, diffuse, specular and shininess Phong model constants."},
 	{"setReflectivity", (PyCFunction)Material_setReflectivity, METH_VARARGS, "Set reflectivity."},
@@ -307,6 +307,19 @@
 	{NULL, NULL}
 };
 
+static PyTypeObject MaterialType =
+TYPE_OBJECT(
+	"Material",                    /* tp_name */
+	sizeof(MaterialObject),        /* tp_basicsize */
+	Material_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Material type",               /* tp_doc */
+	MaterialMethods,               /* tp_methods */
+	0,                             /* tp_members */
+	0,                             /* tp_base */
+	0                              /* tp_init */
+);
+
 static PyObject* Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
 	MaterialObject *v;
@@ -330,12 +343,7 @@
 static void Material_Destructor(PyObject* self)
 {
 	delete ((MaterialObject *)self)->material;
-	PyObject_Del(self);
-}
-
-static PyObject *Material_Getattr(PyObject *self, char *name)
-{
-	return Py_FindMethod(MaterialMethods, self, name);
+	self->ob_type->tp_free(self);
 }
 
 static PyObject *Material_setPhong(PyObject* self, PyObject* args)
@@ -400,33 +408,26 @@
 
 static PyObject *NormalVertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void NormalVertex_Destructor(PyObject* self);
-static PyObject *NormalVertex_Getattr(PyObject *self, char *name);
 static PyObject *NormalVertex_setNormal(PyObject* self, PyObject* args);
 
-static PyTypeObject NormalVertexType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"NormalVertex",			/*tp_name*/
-	sizeof(NormalVertexObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	NormalVertex_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	NormalVertex_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
-
 static PyMethodDef NormalVertexMethods[] = {
 	{"setNormal", (PyCFunction)NormalVertex_setNormal, METH_VARARGS, "Set normal of this vertex."},
 	{NULL, NULL}
 };
 
+static PyTypeObject NormalVertexType =
+TYPE_OBJECT(
+	"NormalVertex",                    /* tp_name */
+	sizeof(NormalVertexObject),        /* tp_basicsize */
+	NormalVertex_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"NormalVertex type",               /* tp_doc */
+	NormalVertexMethods,               /* tp_methods */
+	0,                                 /* tp_members */
+	0,                                 /* tp_base */
+	0                                  /* tp_init */
+);
+
 static PyObject* NormalVertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
 	NormalVertexObject *v;
@@ -462,12 +463,7 @@
 static void NormalVertex_Destructor(PyObject* self)
 {
 	delete ((NormalVertexObject *)self)->nvertex;
-	PyObject_Del(self);
-}
-
-static PyObject *NormalVertex_Getattr(PyObject *self, char *name)
-{
-	return Py_FindMethod(NormalVertexMethods, self, name);
+	self->ob_type->tp_free(self);
 }
 
 static PyObject *NormalVertex_setNormal(PyObject* self, PyObject* args)
@@ -487,40 +483,121 @@
 	return Py_None;
 }
 
+//=========================== Shape Object (abstract) ===========================
+
+typedef struct {
+	PyObject_HEAD
+	Shape *shape;
+} ShapeObject;
+
+static void Shape_Destructor(PyObject* self);
+
+static PyMethodDef ShapeMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject ShapeType =
+TYPE_OBJECT(
+	"Shape",                    /* tp_name */
+	sizeof(ShapeObject),        /* tp_basicsize */
+	Shape_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Shape type (abstract)",    /* tp_doc */
+	ShapeMethods,               /* tp_methods */
+	0,                          /* tp_members */
+	0,                          /* tp_base */
+	0                           /* tp_init */
+);
+
+static void Shape_Destructor(PyObject* self)
+{
+	delete ((ShapeObject *)self)->shape;
+	self->ob_type->tp_free(self);
+}
+
+//=========================== Triangle Object ===========================
+
+typedef struct {
+	ShapeObject shape;
+} TriangleObject;
+
+static PyObject *Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static PyObject *Triangle_getNormal(PyObject* self, PyObject* args);
+
+static PyMethodDef TriangleMethods[] = {
+	{"getNormal", (PyCFunction)Triangle_getNormal, METH_NOARGS, "Get normal of whole triangle."},
+	{NULL, NULL}
+};
+
+static PyTypeObject TriangleType =
+TYPE_OBJECT(
+	"Triangle",                    /* tp_name */
+	sizeof(TriangleObject),        /* tp_basicsize */
+	0,                             /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Triangle type",               /* tp_doc */
+	TriangleMethods,               /* tp_methods */
+	0,                             /* tp_members */
+	&ShapeType,                    /* tp_base */
+	0                              /* tp_init */
+);
+
+static PyObject* Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+{
+	TriangleObject *v;
+	MaterialObject *material;
+	static char *kwdlist[] = {"A", "B", "C", "material", NULL};
+	NormalVertexObject *A, *B, *C;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!O!", kwdlist,
+		&NormalVertexType, &A, &NormalVertexType, &B, &NormalVertexType, &C,
+		&MaterialType, &material))
+		return NULL;
+
+	v = PyObject_New(TriangleObject, &TriangleType);
+	v->shape.shape = new Triangle(A->nvertex, B->nvertex, C->nvertex, material->material);
+	Py_INCREF(material);
+	Py_INCREF(A);
+	Py_INCREF(B);
+	Py_INCREF(C);
+	return (PyObject*)v;
+}
+
+static PyObject* Triangle_getNormal(PyObject* self, PyObject* args)
+{
+	PyObject *obj;
+
+	Vector3 N = ((Triangle*)((TriangleObject *)self)->shape.shape)->getNormal();
+
+	obj = Py_BuildValue("(fff)", N.x, N.y, N.z);
+	return obj;
+}
+
 //=========================== Sphere Object ===========================
 
 typedef struct {
-	PyObject_HEAD
-	Sphere *shape;
+	ShapeObject shape;
 } SphereObject;
 
 static PyObject *Sphere_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
-static void Sphere_Destructor(PyObject* self);
-static PyObject *Sphere_Getattr(PyObject *self, char *name);
-
-static PyTypeObject SphereType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Sphere",			/*tp_name*/
-	sizeof(SphereObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Sphere_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Sphere_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
 
 static PyMethodDef SphereMethods[] = {
 	{NULL, NULL}
 };
 
+static PyTypeObject SphereType =
+TYPE_OBJECT(
+	"Sphere",                    /* tp_name */
+	sizeof(SphereObject),        /* tp_basicsize */
+	0,                           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Sphere type",               /* tp_doc */
+	SphereMethods,               /* tp_methods */
+	0,                           /* tp_members */
+	&ShapeType,                  /* tp_base */
+	0                            /* tp_init */
+);
+
 static PyObject* Sphere_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
 	SphereObject *v;
@@ -537,56 +614,36 @@
 		return NULL;
 
 	v = PyObject_New(SphereObject, &SphereType);
-	v->shape = new Sphere(Vector3(cx, cy, cz), radius, material->material);
+	v->shape.shape = new Sphere(Vector3(cx, cy, cz), radius, material->material);
 	Py_INCREF(material);
 	return (PyObject*)v;
 }
 
-static void Sphere_Destructor(PyObject* self)
-{
-	delete ((SphereObject *)self)->shape;
-	PyObject_Del(self);
-}
-
-static PyObject *Sphere_Getattr(PyObject *self, char *name)
-{
-	return Py_FindMethod(SphereMethods, self, name);
-}
-
 //=========================== Box Object ===========================
 
 typedef struct {
-	PyObject_HEAD
-	Box *shape;
+	ShapeObject shape;
 } BoxObject;
 
 static PyObject *Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
-static void Box_Destructor(PyObject* self);
-static PyObject *Box_Getattr(PyObject *self, char *name);
-
-static PyTypeObject BoxType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Box",			/*tp_name*/
-	sizeof(BoxObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Box_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Box_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
 
 static PyMethodDef BoxMethods[] = {
 	{NULL, NULL}
 };
 
+static PyTypeObject BoxType =
+TYPE_OBJECT(
+	"Box",                    /* tp_name */
+	sizeof(BoxObject),        /* tp_basicsize */
+	0,                        /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Box type",               /* tp_doc */
+	BoxMethods,               /* tp_methods */
+	0,                        /* tp_members */
+	&ShapeType,               /* tp_base */
+	0                         /* tp_init */
+);
+
 static PyObject* Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
 	BoxObject *v;
@@ -607,98 +664,325 @@
 		return NULL;
 
 	v = PyObject_New(BoxObject, &BoxType);
-	v->shape = new Box(Vector3(lx, ly, lz), Vector3(hx, hy, hz), material->material);
+	v->shape.shape = new Box(Vector3(lx, ly, lz), Vector3(hx, hy, hz), material->material);
 	Py_INCREF(material);
 	return (PyObject*)v;
 }
 
-static void Box_Destructor(PyObject* self)
+//=========================== Pixmap Object ===========================
+
+typedef struct {
+	PyObject_HEAD
+	const Pixmap *pixmap;
+} PixmapObject;
+
+static PyObject* Pixmap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static PyObject* Pixmap_getWidth(PyObject* self, PyObject* args);
+static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args);
+static PyObject* Pixmap_getCharData(PyObject* self, PyObject* args);
+static PyObject* Pixmap_writePNG(PyObject* self, PyObject* args);
+
+static PyMethodDef PixmapMethods[] = {
+	{"getWidth", (PyCFunction)Pixmap_getWidth, METH_NOARGS, "Get width of pixmap."},
+	{"getHeight", (PyCFunction)Pixmap_getHeight, METH_NOARGS, "Get height of pixmap."},
+	{"getCharData", (PyCFunction)Pixmap_getCharData, METH_NOARGS, "Get raw byte data."},
+	{"writePNG", (PyCFunction)Pixmap_writePNG, METH_VARARGS, "Write pixmap to PNG file."},
+	{NULL, NULL}
+};
+
+static PyTypeObject PixmapType =
+TYPE_OBJECT(
+	"Pixmap",                    /* tp_name */
+	sizeof(PixmapObject),        /* tp_basicsize */
+	0,                           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Pixmap type",               /* tp_doc */
+	PixmapMethods,               /* tp_methods */
+	0,                           /* tp_members */
+	0,                           /* tp_base */
+	0                            /* tp_init */
+);
+
+static PyObject* Pixmap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
-	delete ((BoxObject *)self)->shape;
-	PyObject_Del(self);
+	int w = 0, h = 0;
+	PixmapObject *v;
+
+	if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
+		return NULL;
+
+	v = PyObject_New(PixmapObject, &PixmapType);
+	v->pixmap = new Pixmap(w, h);
+	return (PyObject*)v;
 }
 
-static PyObject *Box_Getattr(PyObject *self, char *name)
+static PyObject* Pixmap_getWidth(PyObject* self, PyObject* args)
 {
-	return Py_FindMethod(BoxMethods, self, name);
+	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getWidth());
+}
+
+static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args)
+{
+	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getHeight());
 }
 
-//=========================== Triangle Object ===========================
+static PyObject *Pixmap_getCharData(PyObject* self, PyObject* args)
+{
+	unsigned char *chardata;
+	int w,h;
+	PyObject *o;
+
+	chardata = ((PixmapObject *)self)->pixmap->getCharData();
+	w = ((PixmapObject *)self)->pixmap->getWidth();
+	h = ((PixmapObject *)self)->pixmap->getHeight();
+	o = Py_BuildValue("s#", chardata, w*h*3);
+	delete[] chardata;
+	return o;
+}
+
+static PyObject *Pixmap_writePNG(PyObject* self, PyObject* args)
+{
+	const char *fname;
+	int res;
+
+	if (!PyArg_ParseTuple(args, "s", &fname))
+		return NULL;
+
+	res = ((PixmapObject *)self)->pixmap->writePNG(fname);
+	return Py_BuildValue("i", res);
+}
+
+//=========================== Sampler Object (abstract) ===========================
 
 typedef struct {
 	PyObject_HEAD
-	Triangle *triangle;
-} TriangleObject;
-
-static PyObject *Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
-static void Triangle_Destructor(PyObject* self);
-static PyObject *Triangle_Getattr(PyObject *self, char *name);
-static PyObject *Triangle_getNormal(PyObject* self, PyObject* args);
+	Sampler *sampler;
+} SamplerObject;
 
-static PyTypeObject TriangleType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Triangle",			/*tp_name*/
-	sizeof(TriangleObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Triangle_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Triangle_Getattr,			/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
+static void Sampler_Destructor(PyObject* self);
+static PyObject* Sampler_getPixmap(PyObject* self, PyObject* args);
+
+static PyMethodDef SamplerMethods[] = {
+	{"getPixmap", (PyCFunction)Sampler_getPixmap, METH_NOARGS, "Get sampler's pixmap."},
+	{NULL, NULL}
 };
 
-static PyMethodDef TriangleMethods[] = {
-	{"getNormal", (PyCFunction)Triangle_getNormal, METH_NOARGS, "Get normal of whole triangle."},
+static PyTypeObject SamplerType =
+TYPE_OBJECT(
+	"Sampler",                    /* tp_name */
+	sizeof(SamplerObject),        /* tp_basicsize */
+	Sampler_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Sampler type (abstract)",    /* tp_doc */
+	SamplerMethods,               /* tp_methods */
+	0,                            /* tp_members */
+	0,                            /* tp_base */
+	0                             /* tp_init */
+);
+
+static void Sampler_Destructor(PyObject* self)
+{
+	delete ((SamplerObject *)self)->sampler;
+	self->ob_type->tp_free(self);
+}
+
+static PyObject* Sampler_getPixmap(PyObject* self, PyObject* args)
+{
+	PixmapObject *v = PyObject_New(PixmapObject, &PixmapType);
+	v->pixmap = &((SamplerObject *)self)->sampler->getPixmap();
+	return (PyObject*)v;
+}
+
+//=========================== DefaultSampler Object ===========================
+
+typedef struct {
+	SamplerObject sampler;
+} DefaultSamplerObject;
+
+static PyObject *DefaultSampler_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static PyObject* DefaultSampler_setSubsample(PyObject* self, PyObject* args);
+static PyObject* DefaultSampler_setOversample(PyObject* self, PyObject* args);
+
+static PyMethodDef DefaultSamplerMethods[] = {
+	{"setSubsample", (PyCFunction)DefaultSampler_setSubsample, METH_VARARGS, "Set subsampling mode."},
+	{"setOversample", (PyCFunction)DefaultSampler_setOversample, METH_VARARGS, "Set oversampling mode."},
 	{NULL, NULL}
 };
 
-static PyObject* Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+static PyTypeObject DefaultSamplerType =
+TYPE_OBJECT(
+	"DefaultSampler",                    /* tp_name */
+	sizeof(DefaultSamplerObject),        /* tp_basicsize */
+	0,                                   /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"DefaultSampler type",               /* tp_doc */
+	DefaultSamplerMethods,               /* tp_methods */
+	0,                                   /* tp_members */
+	&SamplerType,                        /* tp_base */
+	0                                    /* tp_init */
+);
+
+static PyObject* DefaultSampler_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
 {
-	TriangleObject *v;
-	MaterialObject *material;
-	static char *kwdlist[] = {"A", "B", "C", "material", NULL};
-	NormalVertexObject *A, *B, *C;
+	int w = 0, h = 0;
+	PyObject *o1, *o2;
+	DefaultSamplerObject *v;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!O!", kwdlist,
-		&NormalVertexType, &A, &NormalVertexType, &B, &NormalVertexType, &C,
-		&MaterialType, &material))
+	if (!PyArg_ParseTuple(args, "O|O", &o1, &o2))
 		return NULL;
 
-	v = PyObject_New(TriangleObject, &TriangleType);
-	v->triangle = new Triangle(A->nvertex, B->nvertex, C->nvertex, material->material);
-	Py_INCREF(material);
-	Py_INCREF(A);
-	Py_INCREF(B);
-	Py_INCREF(C);
+	if (PyTuple_Check(o1))
+	{
+		if (!PyArg_ParseTuple(o1, "ii", &w, &h))
+			return NULL;
+	}
+	else
+		if (!PyArg_ParseTuple(args, "ii", &w, &h))
+			return NULL;
+
+	v = PyObject_New(DefaultSamplerObject, &DefaultSamplerType);
+	v->sampler.sampler = new DefaultSampler(w, h);
 	return (PyObject*)v;
 }
 
-static void Triangle_Destructor(PyObject* self)
+static PyObject* DefaultSampler_setSubsample(PyObject* self, PyObject* args)
+{
+	int size = 0;
+
+	if (!PyArg_ParseTuple(args, "i", &size))
+		return NULL;
+
+	((DefaultSampler *)((DefaultSamplerObject *)self)->sampler.sampler)->setSubsample(size);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject* DefaultSampler_setOversample(PyObject* self, PyObject* args)
 {
-	delete ((TriangleObject *)self)->triangle;
-	PyObject_Del(self);
+	int osa = 0;
+
+	if (!PyArg_ParseTuple(args, "i", &osa))
+		return NULL;
+
+	((DefaultSampler *)((DefaultSamplerObject *)self)->sampler.sampler)->setOversample(osa);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+//=========================== Container Object ===========================
+
+typedef struct {
+	PyObject_HEAD
+	Container *container;
+} ContainerObject;
+
+static PyObject *Container_Constructor(PyObject* self, PyObject* args);
+static void Container_Destructor(PyObject* self);
+static PyObject* Container_optimize(PyObject* self, PyObject* args);
+
+static PyMethodDef ContainerMethods[] = {
+	{"optimize", (PyCFunction)Container_optimize, METH_NOARGS, "Build acceleration structures."},
+	{NULL, NULL}
+};
+
+static PyTypeObject ContainerType =
+TYPE_OBJECT(
+	"Container",                    /* tp_name */
+	sizeof(ContainerObject),        /* tp_basicsize */
+	Container_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Container type",               /* tp_doc */
+	ContainerMethods,               /* tp_methods */
+	0,                              /* tp_members */
+	0,                              /* tp_base */
+	0                               /* tp_init */
+);
+
+static PyObject* Container_Constructor(PyObject* self, PyObject* args)
+{
+	ContainerObject *v;
+	v = PyObject_New(ContainerObject, &ContainerType);
+	v->container = new Container();
+	return (PyObject*)v;
+}
+
+static void Container_Destructor(PyObject* self)
+{
+	delete ((ContainerObject *)self)->container;
+	self->ob_type->tp_free(self);
 }
 
-static PyObject *Triangle_Getattr(PyObject *self, char *name)
+static PyObject* Container_optimize(PyObject* self, PyObject* args)
 {
-	return Py_FindMethod(TriangleMethods, self, name);
+	((ContainerObject *)self)->container->optimize();
+	Py_INCREF(Py_None);
+	return Py_None;
 }
 
-static PyObject* Triangle_getNormal(PyObject* self, PyObject* args)
-{
-	PyObject *obj;
+//=========================== Octree Object ===========================
+
+typedef struct {
+	ContainerObject container;
+} OctreeObject;
+
+static PyObject* Octree_Constructor(PyObject* self, PyObject* args);
+
+static PyMethodDef OctreeMethods[] = {
+	{NULL, NULL}
+};
+
+static PyTypeObject OctreeType =
+TYPE_OBJECT(
+	"Octree",                    /* tp_name */
+	sizeof(OctreeObject),        /* tp_basicsize */
+	0,                           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Octree type",               /* tp_doc */
+	OctreeMethods,               /* tp_methods */
+	0,                           /* tp_members */
+	&ContainerType,              /* tp_base */
+	0                            /* tp_init */
+);
 
-	Vector3 N = ((TriangleObject *)self)->triangle->getNormal();
+static PyObject* Octree_Constructor(PyObject* self, PyObject* args)
+{
+	OctreeObject *v;
+	v = PyObject_New(OctreeObject, &OctreeType);
+	v->container.container = new Octree();
+	return (PyObject*)v;
+}
+
+//=========================== KdTree Object ===========================
+
+typedef struct {
+	ContainerObject container;
+} KdTreeObject;
+
+static PyObject* KdTree_Constructor(PyObject* self, PyObject* args);
+
+static PyMethodDef KdTreeMethods[] = {
+	{NULL, NULL}
+};
 
-	obj = Py_BuildValue("(fff)", N.x, N.y, N.z);
-	return obj;
+static PyTypeObject KdTreeType =
+TYPE_OBJECT(
+	"KdTree",                    /* tp_name */
+	sizeof(KdTreeObject),        /* tp_basicsize */
+	0,                           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"KdTree type",               /* tp_doc */
+	KdTreeMethods,               /* tp_methods */
+	0,                           /* tp_members */
+	&ContainerType,              /* tp_base */
+	0                            /* tp_init */
+);
+
+static PyObject* KdTree_Constructor(PyObject* self, PyObject* args)
+{
+	KdTreeObject *v;
+	v = PyObject_New(KdTreeObject, &KdTreeType);
+	v->container.container = new KdTree();
+	return (PyObject*)v;
 }
 
 //=========================== Raytracer Object ===========================
@@ -711,36 +995,20 @@
 
 static PyObject *Raytracer_Constructor(PyObject* self, PyObject* args);
 static void Raytracer_Destructor(PyObject* self);
-static PyObject *Raytracer_Getattr(PyObject *self, char *name);
 static PyObject *Raytracer_render(PyObject* self, PyObject* args);
+static PyObject *Raytracer_setSampler(PyObject* self, PyObject* args);
 static PyObject *Raytracer_setCamera(PyObject* self, PyObject* args);
+static PyObject *Raytracer_setTop(PyObject* self, PyObject* args);
 static PyObject *Raytracer_setBgColour(PyObject* self, PyObject* args);
 static PyObject *Raytracer_addShape(PyObject* self, PyObject* args);
 static PyObject *Raytracer_addLight(PyObject* self, PyObject* args);
 static PyObject *Raytracer_ambientOcclusion(PyObject* self, PyObject* args, PyObject *kwd);
 
-static PyTypeObject RaytracerType = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Raytracer",			/*tp_name*/
-	sizeof(RaytracerObject),	/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	Raytracer_Destructor,		/*tp_dealloc*/
-	0,				/*tp_print*/
-	Raytracer_Getattr,		/*tp_getattr*/
-	0,				/*tp_setattr*/
-	0,				/*tp_compare*/
-	0,				/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	0,				/*tp_hash */
-};
-
 static PyMethodDef RaytracerMethods[] = {
-	{"render", (PyCFunction)Raytracer_render, METH_VARARGS, "Render scene and return image data."},
+	{"render", (PyCFunction)Raytracer_render, METH_NOARGS, "Render scene."},
+	{"setSampler", (PyCFunction)Raytracer_setSampler, METH_VARARGS, "Set sampler."},
 	{"setCamera", (PyCFunction)Raytracer_setCamera, METH_VARARGS, "Set camera for the scene."},
+	{"setTop", (PyCFunction)Raytracer_setTop, METH_VARARGS, "Set top container for shapes."},
 	{"setBgColour", (PyCFunction)Raytracer_setBgColour, METH_VARARGS, "Set background colour."},
 	{"addShape", (PyCFunction)Raytracer_addShape, METH_VARARGS, "Add new shape to scene."},
 	{"addLight", (PyCFunction)Raytracer_addLight, METH_VARARGS, "Add new light source to scene."},
@@ -749,6 +1017,19 @@
 	{NULL, NULL}
 };
 
+static PyTypeObject RaytracerType =
+TYPE_OBJECT(
+	"Raytracer",                    /* tp_name */
+	sizeof(RaytracerObject),        /* tp_basicsize */
+	Raytracer_Destructor,           /* tp_dealloc */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
+	"Raytracer type",               /* tp_doc */
+	RaytracerMethods,               /* tp_methods */
+	0,                              /* tp_members */
+	0,                              /* tp_base */
+	0                               /* tp_init */
+);
+
 static PyObject* Raytracer_Constructor(PyObject* self, PyObject* args)
 {
 	RaytracerObject *v;
@@ -759,9 +1040,6 @@
 	v = PyObject_New(RaytracerObject, &RaytracerType);
 	v->raytracer = new Raytracer();
 	v->children = new vector<PyObject*>();
-	v->raytracer->setCamera(new Camera());
-	v->raytracer->setTop(new KdTree());
-
 	return (PyObject*)v;
 }
 
@@ -772,41 +1050,28 @@
 		o != ((RaytracerObject *)self)->children->end(); o++)
 		Py_DECREF(*o);
 	delete ((RaytracerObject *)self)->raytracer;
-	PyObject_Del(self);
-}
-
-static PyObject *Raytracer_Getattr(PyObject *self, char *name)
-{
-	return Py_FindMethod(RaytracerMethods, self, name);
+	self->ob_type->tp_free(self);
 }
 
 static PyObject* Raytracer_render(PyObject* self, PyObject* args)
 {
-	int w = 0, h = 0;
-	unsigned char *chardata;
-	Float *data;
-	PyObject *o;
+	((RaytracerObject *)self)->raytracer->render();
+	Py_INCREF(Py_None);
+	return Py_None;
+}
 
-	if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
+static PyObject* Raytracer_setSampler(PyObject* self, PyObject* args)
+{
+	SamplerObject *samp;
+
+	if (!PyArg_ParseTuple(args, "O!", &SamplerType, &samp))
 		return NULL;
 
-	printf("[pyrit] Running ray tracer\n");
-	((RaytracerObject *)self)->raytracer->getTop()->optimize();
-	data = (Float *) malloc(w*h*3*sizeof(Float));
-	DefaultSampler sampler(data, w, h);
-	((RaytracerObject *)self)->raytracer->setSampler(&sampler);
-	((RaytracerObject *)self)->raytracer->render();
-	if (!data) {
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
+	((RaytracerObject *)self)->raytracer->setSampler(samp->sampler);
 
-	printf("[pyrit] Converting image data (float to char)\n");
-	chardata = sampler.getPixmap().getCharData();
-	o = Py_BuildValue("s#", chardata, w*h*3);
-	delete[] chardata;
-	printf("[pyrit] Done.\n");
-	return o;
+	Py_INCREF(samp);
+	Py_INCREF(Py_None);
+	return Py_None;
 }
 
 static PyObject* Raytracer_setCamera(PyObject* self, PyObject* args)
@@ -823,6 +1088,20 @@
 	return Py_None;
 }
 
+static PyObject* Raytracer_setTop(PyObject* self, PyObject* args)
+{
+	ContainerObject *cont;
+
+	if (!PyArg_ParseTuple(args, "O!", &ContainerType, &cont))
+		return NULL;
+
+	((RaytracerObject *)self)->raytracer->setTop(cont->container);
+
+	Py_INCREF(cont);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
 static PyObject* Raytracer_setBgColour(PyObject* self, PyObject* args)
 {
 	Float r,g,b;
@@ -838,16 +1117,14 @@
 
 static PyObject* Raytracer_addShape(PyObject* self, PyObject* args)
 {
-	PyObject *obj;
+	ShapeObject *shape;
 
-	if (!PyArg_ParseTuple(args, "O", &obj))
+	if (!PyArg_ParseTuple(args, "O!", &ShapeType, &shape))
 		return NULL;
 
-	((RaytracerObject *)self)->raytracer->addShape(
-		((BoxObject*)obj)->shape);
-
-	((RaytracerObject *)self)->children->push_back(obj);
-	Py_INCREF(obj);
+	((RaytracerObject *)self)->raytracer->addShape(shape->shape);
+	((RaytracerObject *)self)->children->push_back((PyObject*)shape);
+	Py_INCREF(shape);
 	Py_INCREF(Py_None);
 	return Py_None;
 }
@@ -893,17 +1170,50 @@
 		METH_VARARGS | METH_KEYWORDS, "Material object constructor."},
 	{"NormalVertex", (PyCFunction) NormalVertex_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "NormalVertex object constructor."},
+	{"Triangle", (PyCFunction) Triangle_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "Triangle object constructor."},
 	{"Sphere", (PyCFunction) Sphere_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Sphere object constructor."},
 	{"Box", (PyCFunction) Box_Constructor,
 		METH_VARARGS | METH_KEYWORDS, "Box object constructor."},
-	{"Triangle", (PyCFunction) Triangle_Constructor,
-		METH_VARARGS | METH_KEYWORDS, "Triangle object constructor."},
+	{"Pixmap", (PyCFunction) Pixmap_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "Pixmap object constructor."},
+	{"DefaultSampler", (PyCFunction) DefaultSampler_Constructor,
+		METH_VARARGS | METH_KEYWORDS, "DefaultSampler object constructor."},
+	{"Container", (PyCFunction) Container_Constructor,
+		METH_NOARGS, "Container object constructor."},
+	{"Octree", (PyCFunction) Octree_Constructor,
+		METH_NOARGS, "Octree object constructor."},
+	{"KdTree", (PyCFunction) KdTree_Constructor,
+		METH_NOARGS, "KdTree object constructor."},
 	{NULL, NULL}
 };
 
 
-extern "C" void initraytracer(void)
+extern "C" void initpyrit(void)
 {
-	Py_InitModule("raytracer", ModuleMethods);
+	PyObject* m;
+
+	if (PyType_Ready(&RaytracerType) < 0
+	|| PyType_Ready(&LightType) < 0
+	|| PyType_Ready(&CameraType) < 0
+	|| PyType_Ready(&MaterialType) < 0
+	|| PyType_Ready(&NormalVertexType) < 0
+	|| PyType_Ready(&ShapeType) < 0
+	|| PyType_Ready(&TriangleType) < 0
+	|| PyType_Ready(&SphereType) < 0
+	|| PyType_Ready(&BoxType) < 0
+	|| PyType_Ready(&PixmapType) < 0
+	|| PyType_Ready(&SamplerType) < 0
+	|| PyType_Ready(&DefaultSamplerType) < 0
+	|| PyType_Ready(&ContainerType) < 0
+	|| PyType_Ready(&OctreeType) < 0
+	|| PyType_Ready(&KdTreeType) < 0
+	)
+		return;
+
+	m = Py_InitModule3("pyrit", ModuleMethods, "Pyrit ray tracer.");
+
+	if (m == NULL)
+		return;
 }