src/raytracermodule.cc
author Radek Brich <radek.brich@devl.cz>
Mon, 19 May 2008 22:59:04 +0200
branchpyrit
changeset 98 64638385798a
parent 97 2a853d284a6a
child 99 f3abdaa2e8fb
permissions -rw-r--r--
add sections about demos to README update doxygen comments

/*
 * raytracermodule.cc: raytracer module for Python
 *
 * This file is part of Pyrit Ray Tracer.
 *
 * Copyright 2006, 2007, 2008  Radek Brich
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "raytracermodule.h"

#include <vector>


//=========================== Light Source Object ===========================

static PyObject *Light_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static void Light_Destructor(PyObject* self);
static PyObject *Light_castShadows(PyObject* self, PyObject* args);

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;
	static char *kwdlist[] = {"position", "colour", NULL};
	PyObject *TPos, *TCol = NULL;
	Float px, py, pz;
	Float cr = 0.9f, cg = 0.9f, cb = 0.9f;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!|O!", kwdlist,
		&PyTuple_Type, &TPos, &PyTuple_Type, &TCol))
		return NULL;

	if (!PyArg_ParseTuple(TPos, "fff", &px, &py, &pz))
		return NULL;
	if (TCol && !PyArg_ParseTuple(TCol, "fff", &cr, &cg, &cb))
		return NULL;

	v = PyObject_New(LightObject, &LightType);
	v->light = new Light(Vector(px, py, pz), Colour(cr, cg, cb));
	return (PyObject*)v;
}

static void Light_Destructor(PyObject* self)
{
	delete ((LightObject *)self)->light;
	self->ob_type->tp_free(self);
}

static PyObject *Light_castShadows(PyObject* self, PyObject* args)
{
	int shadows = 1;

	if (!PyArg_ParseTuple(args, "i", &shadows))
		return NULL;

	((LightObject *)self)->light->castShadows(shadows);

	Py_INCREF(Py_None);
	return Py_None;
}

//=========================== Camera Object ===========================

static PyObject *Camera_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static void Camera_Destructor(PyObject* self);
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 PyMethodDef CameraMethods[] = {
	{"setEye", (PyCFunction)Camera_setEye, METH_VARARGS, "Set eye of the camera."},
	{"setAngle", (PyCFunction)Camera_setAngle, METH_VARARGS, "Set vertical angle of view."},
	{"rotate", (PyCFunction)Camera_rotate, METH_VARARGS, "Rotate camera with a quaternion."},
	{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;
	static char *kwdlist[] = {"eye", "lookat", "up", "p", "u", "v", NULL};
	PyObject *TEye = NULL, *TLookAt = NULL, *TUp = NULL,
		*Tp = NULL, *Tu = NULL, *Tv = NULL;
	Float ex=0.0,  ey=0.0, ez=10.0;
	Float lax=0.0, lay=0.0, laz=0.0;
	Float upx=0.0, upy=1.0, upz=0.0;
	Float px=0.0,  py=0.0, pz=-1.0;
	Float ux=-1.0, uy=0.0, uz=0.0;
	Float vx=0.0,  vy=1.0, vz=0.0;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "|O!O!O!O!O!O!", kwdlist,
		&PyTuple_Type, &TEye, &PyTuple_Type, &TLookAt, &PyTuple_Type, &TUp,
		&PyTuple_Type, &Tp, &PyTuple_Type, &Tu, &PyTuple_Type, &Tv))
		return NULL;

	if (TEye)
		if (!PyArg_ParseTuple(TEye, "fff", &ex, &ey, &ez))
			return NULL;

	if (TLookAt)
		if (!PyArg_ParseTuple(TLookAt, "fff", &lax, &lay, &laz))
			return NULL;

	if (TUp)
		if (!PyArg_ParseTuple(TUp, "fff", &upx, &upy, &upz))
			return NULL;

	if (Tp)
		if (!PyArg_ParseTuple(Tp, "fff", &px, &py, &pz))
			return NULL;

	if (Tu)
		if (!PyArg_ParseTuple(Tu, "fff", &ux, &uy, &uz))
			return NULL;

	if (Tv)
		if (!PyArg_ParseTuple(Tv, "fff", &vx, &vy, &vz))
			return NULL;

	v = PyObject_New(CameraObject, &CameraType);
	if (TLookAt)
		v->camera = new Camera(Vector(ex, ey, ez),
			Vector(lax, lay, laz), Vector(upx, upy, upz));
	else
		v->camera = new Camera(Vector(ex, ey, ez),
			Vector(px, py, pz), Vector(ux, uy, uz), Vector(vx, vy, vz));
	return (PyObject*)v;
}

static void Camera_Destructor(PyObject* self)
{
	delete ((CameraObject *)self)->camera;
	self->ob_type->tp_free(self);
}

static PyObject *Camera_setEye(PyObject* self, PyObject* args)
{
	PyObject *TEye = NULL;
	Float ex=0.0,  ey=0.0, ez=10.0;

	if (!PyArg_ParseTuple(args, "O!", &PyTuple_Type, &TEye))
		return NULL;

	if (TEye)
		if (!PyArg_ParseTuple(TEye, "fff", &ex, &ey, &ez))
			return NULL;

	((CameraObject *)self)->camera->setEye(Vector(ex, ey, ez));

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *Camera_setAngle(PyObject* self, PyObject* args)
{
	Float angle;

	if (!PyArg_ParseTuple(args, "f", &angle))
		return NULL;

	((CameraObject *)self)->camera->setAngle(angle);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *Camera_rotate(PyObject* self, PyObject* args)
{
	PyObject *Tq = NULL;
	Float qa, qb, qc, qd;

	if (!PyArg_ParseTuple(args, "O!", &PyTuple_Type, &Tq))
		return NULL;

	if (!PyArg_ParseTuple(Tq, "ffff", &qa, &qb, &qc, &qd))
		return NULL;

	((CameraObject *)self)->camera->rotate(Quaternion(qa, qb, qc, qd).normalize());

	Py_INCREF(Py_None);
	return Py_None;
}


//=========================== Pixmap Object ===========================

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)
{
	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* Pixmap_getWidth(PyObject* self, PyObject* args)
{
	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getWidth());
}

static PyObject* Pixmap_getHeight(PyObject* self, PyObject* args)
{
	return Py_BuildValue("i", ((PixmapObject *)self)->pixmap->getHeight());
}

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


//=========================== TextureMap Object (abstract) ===========================

static void TextureMap_Destructor(PyObject* self);

static PyMethodDef TextureMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject TextureMapType =
TYPE_OBJECT(
	"TextureMap",                  /* tp_name */
	sizeof(TextureMapObject),      /* tp_basicsize */
	TextureMap_Destructor,         /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"TextureMap type (abstract)",  /* tp_doc */
	TextureMapMethods,             /* tp_methods */
	0,                             /* tp_members */
	0,                             /* tp_base */
	0                              /* tp_init */
);

static void TextureMap_Destructor(PyObject* self)
{
	delete ((TextureMapObject *)self)->texturemap;
	self->ob_type->tp_free(self);
}


//=========================== PlanarMap Object ===========================

static PyObject *PlanarMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef PlanarMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject PlanarMapType =
TYPE_OBJECT(
	"PlanarMap",                    /* tp_name */
	sizeof(PlanarMapObject),        /* tp_basicsize */
	0,                              /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"PlanarMap type",               /* tp_doc */
	PlanarMapMethods,               /* tp_methods */
	0,                              /* tp_members */
	&TextureMapType,                /* tp_base */
	0                               /* tp_init */
);

static PyObject* PlanarMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	PlanarMapObject *v;
	static char *kwdlist[] = {"center", "size", NULL};
	PyObject *Tcenter = NULL;
	Vector center;
	Float size;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
		&PyTuple_Type, &Tcenter, &size))
		return NULL;

	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
		return NULL;

	v = PyObject_New(PlanarMapObject, &PlanarMapType);
	v->texturemap.texturemap = new PlanarMap(center, size);
	return (PyObject*)v;
}


//=========================== CubicMap Object ===========================

static PyObject *CubicMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef CubicMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject CubicMapType =
TYPE_OBJECT(
	"CubicMap",                    /* tp_name */
	sizeof(CubicMapObject),        /* tp_basicsize */
	0,                              /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"CubicMap type",               /* tp_doc */
	CubicMapMethods,               /* tp_methods */
	0,                              /* tp_members */
	&TextureMapType,                /* tp_base */
	0                               /* tp_init */
);

static PyObject* CubicMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	CubicMapObject *v;
	static char *kwdlist[] = {"center", "size", NULL};
	PyObject *Tcenter = NULL;
	Vector center;
	Float size;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
		&PyTuple_Type, &Tcenter, &size))
		return NULL;

	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
		return NULL;

	v = PyObject_New(CubicMapObject, &CubicMapType);
	v->texturemap.texturemap = new CubicMap(center, size);
	return (PyObject*)v;
}


//=========================== CylinderMap Object ===========================

static PyObject *CylinderMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef CylinderMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject CylinderMapType =
TYPE_OBJECT(
	"CylinderMap",                    /* tp_name */
	sizeof(CylinderMapObject),        /* tp_basicsize */
	0,                              /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"CylinderMap type",               /* tp_doc */
	CylinderMapMethods,               /* tp_methods */
	0,                              /* tp_members */
	&TextureMapType,                /* tp_base */
	0                               /* tp_init */
);

static PyObject* CylinderMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	CylinderMapObject *v;
	static char *kwdlist[] = {"center", "size", NULL};
	PyObject *Tcenter = NULL;
	Vector center;
	Float size;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
		&PyTuple_Type, &Tcenter, &size))
		return NULL;

	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
		return NULL;

	v = PyObject_New(CylinderMapObject, &CylinderMapType);
	v->texturemap.texturemap = new CylinderMap(center, size);
	return (PyObject*)v;
}


//=========================== SphereMap Object ===========================

static PyObject *SphereMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef SphereMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject SphereMapType =
TYPE_OBJECT(
	"SphereMap",                    /* tp_name */
	sizeof(SphereMapObject),        /* tp_basicsize */
	0,                              /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"SphereMap type",               /* tp_doc */
	SphereMapMethods,               /* tp_methods */
	0,                              /* tp_members */
	&TextureMapType,                /* tp_base */
	0                               /* tp_init */
);

static PyObject* SphereMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	SphereMapObject *v;
	static char *kwdlist[] = {"center", "size", NULL};
	PyObject *Tcenter = NULL;
	Vector center;
	Float size;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!f", kwdlist,
		&PyTuple_Type, &Tcenter, &size))
		return NULL;

	if (!PyArg_ParseTuple(Tcenter, "fff", &center.x, &center.y, &center.z))
		return NULL;

	v = PyObject_New(SphereMapObject, &SphereMapType);
	v->texturemap.texturemap = new SphereMap(center, size);
	return (PyObject*)v;
}


//=========================== ColourMap Object (abstract) ===========================

static void ColourMap_Destructor(PyObject* self);

static PyMethodDef ColourMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject ColourMapType =
TYPE_OBJECT(
	"ColourMap",                  /* tp_name */
	sizeof(ColourMapObject),      /* tp_basicsize */
	ColourMap_Destructor,         /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"ColourMap type (abstract)",  /* tp_doc */
	ColourMapMethods,             /* tp_methods */
	0,                            /* tp_members */
	0,                            /* tp_base */
	0                             /* tp_init */
);

static void ColourMap_Destructor(PyObject* self)
{
	delete ((ColourMapObject *)self)->colourmap;
	self->ob_type->tp_free(self);
}


//=========================== LinearColourMap Object ===========================

static PyObject *LinearColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef LinearColourMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject LinearColourMapType =
TYPE_OBJECT(
	"LinearColourMap",                    /* tp_name */
	sizeof(LinearColourMapObject),        /* tp_basicsize */
	0,                                    /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"LinearColourMap type",               /* tp_doc */
	LinearColourMapMethods,               /* tp_methods */
	0,                                    /* tp_members */
	&ColourMapType,                       /* tp_base */
	0                                     /* tp_init */
);

static PyObject* LinearColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	LinearColourMapObject *v;
	static char *kwdlist[] = {"clow", "chigh", NULL};
	PyObject *Tclow = NULL;
	PyObject *Tchigh = NULL;
	Vector clow, chigh;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
		&PyTuple_Type, &Tclow, &PyTuple_Type, &Tchigh))
		return NULL;

	if (!PyArg_ParseTuple(Tclow, "fff", &clow.x, &clow.y, &clow.z))
		return NULL;
	if (!PyArg_ParseTuple(Tchigh, "fff", &chigh.x, &chigh.y, &chigh.z))
		return NULL;

	v = PyObject_New(LinearColourMapObject, &LinearColourMapType);
	v->colourmap.colourmap = new LinearColourMap(clow, chigh);
	return (PyObject*)v;
}


//=========================== BoundColourMap Object ===========================

static PyObject *BoundColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static void BoundColourMap_Destructor(PyObject* self);

static PyMethodDef BoundColourMapMethods[] = {
	{NULL, NULL}
};

static PyTypeObject BoundColourMapType =
TYPE_OBJECT(
	"BoundColourMap",                    /* tp_name */
	sizeof(BoundColourMapObject),        /* tp_basicsize */
	BoundColourMap_Destructor,           /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"BoundColourMap type",               /* tp_doc */
	BoundColourMapMethods,               /* tp_methods */
	0,                                   /* tp_members */
	&ColourMapType,                      /* tp_base */
	0                                    /* tp_init */
);

static PyObject* BoundColourMap_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	BoundColourMapObject *v;
	static char *kwdlist[] = {"bounds", "colours", NULL};
	PyObject *Tbounds = NULL;
	PyObject *Tcolours = NULL;
	PyObject *o;
	int num;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
		&PyTuple_Type, &Tbounds, &PyTuple_Type, &Tcolours))
		return NULL;

	/* get lesser of the sizes */
	num = PyTuple_GET_SIZE(Tbounds);
	if (num > PyTuple_GET_SIZE(Tcolours))
		num = PyTuple_GET_SIZE(Tcolours);

	v = PyObject_New(BoundColourMapObject, &BoundColourMapType);

	v->bounds = new Float[num];
	v->colours = new Colour[num];

	for (int i = 0; i < num; i++)
	{
		o = PyTuple_GET_ITEM(Tbounds, i);
		v->bounds[i] = PyFloat_AsDouble(o);
		o = PyTuple_GET_ITEM(Tcolours, i);
		if (!PyArg_ParseTuple(o, "fff", &v->colours[i].r, &v->colours[i].g, &v->colours[i].b))
			return NULL;
	}

	v->colourmap.colourmap = new BoundColourMap(v->bounds, v->colours);
	return (PyObject*)v;
}

static void BoundColourMap_Destructor(PyObject* self)
{
	delete ((BoundColourMapObject *)self)->bounds;
	delete ((BoundColourMapObject *)self)->colours;
	self->ob_type->tp_free(self);
}


//=========================== Texture Object (abstract) ===========================

static void Texture_Destructor(PyObject* self);

static PyMethodDef TextureMethods[] = {
	{NULL, NULL}
};

static PyTypeObject TextureType =
TYPE_OBJECT(
	"Texture",                  /* tp_name */
	sizeof(TextureObject),      /* tp_basicsize */
	Texture_Destructor,         /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"Texture type (abstract)",  /* tp_doc */
	TextureMethods,             /* tp_methods */
	0,                          /* tp_members */
	0,                          /* tp_base */
	0                           /* tp_init */
);

static void Texture_Destructor(PyObject* self)
{
	delete ((TextureObject *)self)->texture;
	self->ob_type->tp_free(self);
}


//=========================== ImageTexture Object ===========================

static PyObject *ImageTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef ImageTextureMethods[] = {
	{NULL, NULL}
};

static PyTypeObject ImageTextureType =
TYPE_OBJECT(
	"ImageTexture",                    /* tp_name */
	sizeof(ImageTextureObject),        /* tp_basicsize */
	0,                                 /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"ImageTexture type",               /* tp_doc */
	ImageTextureMethods,               /* tp_methods */
	0,                                 /* tp_members */
	&TextureType,                      /* tp_base */
	0                                  /* tp_init */
);

static PyObject* ImageTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	ImageTextureObject *v;
	static char *kwdlist[] = {"tmap", "image", NULL};
	TextureMapObject *tmap = NULL;
	PixmapObject *image = NULL;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
		&TextureMapType, &tmap, &PixmapType, &image))
		return NULL;

	v = PyObject_New(ImageTextureObject, &ImageTextureType);
	v->texture.texture = new ImageTexture(tmap->texturemap, image->pixmap);
	Py_INCREF(tmap);
	Py_INCREF(image);
	return (PyObject*)v;
}


//=========================== CheckersTexture Object ===========================

static PyObject *CheckersTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef CheckersTextureMethods[] = {
	{NULL, NULL}
};

static PyTypeObject CheckersTextureType =
TYPE_OBJECT(
	"CheckersTexture",                    /* tp_name */
	sizeof(CheckersTextureObject),        /* tp_basicsize */
	0,                                    /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"CheckersTexture type",               /* tp_doc */
	CheckersTextureMethods,               /* tp_methods */
	0,                                    /* tp_members */
	&TextureType,                         /* tp_base */
	0                                     /* tp_init */
);

static PyObject* CheckersTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	CheckersTextureObject *v;
	static char *kwdlist[] = {"tmap", "cmap", NULL};
	TextureMapObject *tmap = NULL;
	ColourMapObject *cmap = NULL;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!", kwdlist,
		&TextureMapType, &tmap, &ColourMapType, &cmap))
		return NULL;

	v = PyObject_New(CheckersTextureObject, &CheckersTextureType);
	v->texture.texture = new CheckersTexture(tmap->texturemap, cmap->colourmap);
	Py_INCREF(tmap);
	Py_INCREF(cmap);
	return (PyObject*)v;
}


//=========================== CloudTexture Object ===========================

static PyObject *CloudTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

static PyMethodDef CloudTextureMethods[] = {
	{NULL, NULL}
};

static PyTypeObject CloudTextureType =
TYPE_OBJECT(
	"CloudTexture",                    /* tp_name */
	sizeof(CloudTextureObject),        /* tp_basicsize */
	0,                                    /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"CloudTexture type",               /* tp_doc */
	CloudTextureMethods,               /* tp_methods */
	0,                                    /* tp_members */
	&TextureType,                         /* tp_base */
	0                                     /* tp_init */
);

static PyObject* CloudTexture_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	CloudTextureObject *v;
	static char *kwdlist[] = {"detail", "cmap", NULL};
	Float detail;
	ColourMapObject *cmap = NULL;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "fO!", kwdlist,
		&detail, &ColourMapType, &cmap))
		return NULL;

	v = PyObject_New(CloudTextureObject, &CloudTextureType);
	v->texture.texture = new CloudTexture(detail, cmap->colourmap);
	Py_INCREF(cmap);
	return (PyObject*)v;
}


//=========================== Material Object ===========================

static PyObject *Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static void Material_Destructor(PyObject* self);
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 PyObject *Material_setTexture(PyObject* self, PyObject* args);

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."},
	{"setTransmissivity", (PyCFunction)Material_setTransmissivity, METH_VARARGS, "Set transmissivity and refraction index."},
	{"setSmooth", (PyCFunction)Material_setSmooth, METH_VARARGS, "Set triangle smoothing."},
	{"setTexture", (PyCFunction)Material_setTexture, METH_VARARGS, "Set the texture."},
	{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;
	static char *kwdlist[] = {"colour", NULL};
	PyObject *TCol = NULL;
	Float cr=1.0, cg=1.0, cb=1.0;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "|O!", kwdlist,
		&PyTuple_Type, &TCol))
		return NULL;

	if (TCol)
		if (!PyArg_ParseTuple(TCol, "fff", &cr, &cg, &cb))
			return NULL;

	v = PyObject_New(MaterialObject, &MaterialType);
	v->material = new Material(Colour(cr, cg, cb));
	return (PyObject*)v;
}

static void Material_Destructor(PyObject* self)
{
	delete ((MaterialObject *)self)->material;
	self->ob_type->tp_free(self);
}

static PyObject *Material_setPhong(PyObject* self, PyObject* args)
{
	Float amb, dif, spec, shin = 0.5;

	if (!PyArg_ParseTuple(args, "fff|f", &amb, &dif, &spec, &shin))
		return NULL;

	((MaterialObject *)self)->material->setPhong(amb, dif, spec, shin);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *Material_setReflectivity(PyObject* self, PyObject* args)
{
	Float refl;

	if (!PyArg_ParseTuple(args, "f", &refl))
		return NULL;

	((MaterialObject *)self)->material->setReflectivity(refl);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *Material_setTransmissivity(PyObject* self, PyObject* args)
{
	Float trans, rindex = 1.3f;

	if (!PyArg_ParseTuple(args, "f|f", &trans, &rindex))
		return NULL;

	((MaterialObject *)self)->material->setTransmissivity(trans, rindex);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Material_setSmooth(PyObject* self, PyObject* args)
{
	int smooth = 1;

	if (!PyArg_ParseTuple(args, "|i", &smooth))
		return NULL;

	((MaterialObject *)self)->material->setSmooth(smooth);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Material_setTexture(PyObject* self, PyObject* args)
{
	TextureObject *tex;

	if (!PyArg_ParseTuple(args, "O!", &TextureType, &tex))
		return NULL;

	((MaterialObject *)self)->material->setTexture(tex->texture);

	Py_INCREF(tex);
	Py_INCREF(Py_None);
	return Py_None;
}


//=========================== Vertex Object ===========================

static PyObject *Vertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static void Vertex_Destructor(PyObject* self);

static PyMethodDef VertexMethods[] = {
	{NULL, NULL}
};

static PyTypeObject VertexType =
TYPE_OBJECT(
	"Vertex",                    /* tp_name */
	sizeof(VertexObject),        /* tp_basicsize */
	Vertex_Destructor,           /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"Vertex type (abstract)",    /* tp_doc */
	VertexMethods,               /* tp_methods */
	0,                           /* tp_members */
	0,                           /* tp_base */
	0                            /* tp_init */
);

static PyObject* Vertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	VertexObject *v;
	static char *kwdlist[] = {"vector", NULL};
	PyObject *TVer = NULL;
	Float vx, vy, vz;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O", kwdlist, &TVer))
		return NULL;

	if (TVer->ob_type == &VertexType)
	{
		v = PyObject_New(VertexObject, &VertexType);
		v->vertex = new Vertex(*((VertexObject*)TVer)->vertex);
	}
	else
	{
		if (!PyArg_ParseTuple(TVer, "fff", &vx, &vy, &vz))
			return NULL;

		v = PyObject_New(VertexObject, &VertexType);
		v->vertex = new Vertex(Vector(vx, vy, vz));
	}
	return (PyObject*)v;
}

static void Vertex_Destructor(PyObject* self)
{
	delete ((VertexObject *)self)->vertex;
	self->ob_type->tp_free(self);
}


//=========================== NormalVertex Object ===========================

static PyObject *NormalVertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static PyObject *NormalVertex_setNormal(PyObject* self, PyObject* args);

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 */
	0,                                 /* tp_dealloc */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
	"NormalVertex type",               /* tp_doc */
	NormalVertexMethods,               /* tp_methods */
	0,                                 /* tp_members */
	&VertexType,                       /* tp_base */
	0                                  /* tp_init */
);

static PyObject* NormalVertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
	NormalVertexObject *v;
	static char *kwdlist[] = {"vector", "normal", NULL};
	PyObject *TVer = NULL;
	PyObject *TNor = NULL;
	Float vx, vy, vz, nx=0, ny=0, nz=0;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O|O!", kwdlist,
		&TVer, &PyTuple_Type, &TNor))
		return NULL;

	if (!TNor && TVer->ob_type == &NormalVertexType)
	{
		v = PyObject_New(NormalVertexObject, &NormalVertexType);
		v->vertex.vertex = new NormalVertex((NormalVertex*)((NormalVertexObject*)TVer)->vertex.vertex);
	}
	else
	{
		if (!PyArg_ParseTuple(TVer, "fff", &vx, &vy, &vz))
			return NULL;

		if (TNor)
			if (!PyArg_ParseTuple(TNor, "fff", &nx, &ny, &nz))
				return NULL;

		v = PyObject_New(NormalVertexObject, &NormalVertexType);
		v->vertex.vertex = new NormalVertex(Vector(vx, vy, vz), Vector(nx, ny, nz));
	}
	return (PyObject*)v;
}

static PyObject *NormalVertex_setNormal(PyObject* self, PyObject* args)
{
	PyObject *TNor = NULL;
	Float nx, ny, nz;

	if (!PyArg_ParseTuple(args, "O!", &PyTuple_Type, &TNor))
		return NULL;

	if (!PyArg_ParseTuple(TNor, "fff", &nx, &ny, &nz))
		return NULL;

	((NormalVertex*)((VertexObject *)self)->vertex)->setNormal(Vector(nx,ny,nz).normalize());

	Py_INCREF(Py_None);
	return Py_None;
}

//=========================== Shape Object (abstract) ===========================

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 ===========================

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};
	VertexObject *A, *B, *C;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!O!", kwdlist,
		&VertexType, &A, &VertexType, &B, &VertexType, &C,
		&MaterialType, &material))
		return NULL;

	v = PyObject_New(TriangleObject, &TriangleType);
	v->shape.shape = new Triangle(A->vertex, B->vertex, C->vertex, 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;

	Vector N = ((Triangle*)((TriangleObject *)self)->shape.shape)->getNormal();

	obj = Py_BuildValue("(fff)", N.x, N.y, N.z);
	return obj;
}

//=========================== Sphere Object ===========================

static PyObject *Sphere_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

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;
	MaterialObject *material;
	static char *kwdlist[] = {"center", "radius", "material", NULL};
	PyObject *TCentre = NULL;
	Float cx, cy, cz, radius;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!fO!", kwdlist,
		&PyTuple_Type, &TCentre, &radius, &MaterialType, &material))
		return NULL;

	if (!PyArg_ParseTuple(TCentre, "fff", &cx, &cy, &cz))
		return NULL;

	v = PyObject_New(SphereObject, &SphereType);
	v->shape.shape = new Sphere(Vector(cx, cy, cz), radius, material->material);
	Py_INCREF(material);
	return (PyObject*)v;
}

//=========================== Box Object ===========================

static PyObject *Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd);

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;
	MaterialObject *material;
	static char *kwdlist[] = {"L", "H", "material", NULL};
	PyObject *TL = NULL;
	PyObject *TH = NULL;
	Float lx, ly, lz, hx, hy, hz;

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!", kwdlist,
		&PyTuple_Type, &TL, &PyTuple_Type, &TH, &MaterialType, &material))
		return NULL;

	if (!PyArg_ParseTuple(TL, "fff", &lx, &ly, &lz))
		return NULL;

	if (!PyArg_ParseTuple(TH, "fff", &hx, &hy, &hz))
		return NULL;

	v = PyObject_New(BoxObject, &BoxType);
	v->shape.shape = new Box(Vector(lx, ly, lz), Vector(hx, hy, hz), material->material);
	Py_INCREF(material);
	return (PyObject*)v;
}


//=========================== Sampler Object (abstract) ===========================

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 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 ===========================

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 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)
{
	int w = 0, h = 0;
	PyObject *o1, *o2;
	DefaultSamplerObject *v;

	if (!PyArg_ParseTuple(args, "O|O", &o1, &o2))
		return NULL;

	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 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)
{
	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 ===========================

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* Container_optimize(PyObject* self, PyObject* args)
{
	((ContainerObject *)self)->container->optimize();
	Py_INCREF(Py_None);
	return Py_None;
}

//=========================== Octree Object ===========================

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 */
);

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 ===========================

static PyObject* KdTree_Constructor(PyObject* self, PyObject* args);

static PyMethodDef KdTreeMethods[] = {
	{NULL, NULL}
};

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 ===========================

static PyObject *Raytracer_Constructor(PyObject* self, PyObject* args);
static void Raytracer_Destructor(PyObject* self);
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 PyMethodDef RaytracerMethods[] = {
	{"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."},
	{"ambientOcclusion", (PyCFunction)Raytracer_ambientOcclusion, METH_VARARGS | METH_KEYWORDS,
		"Set ambient occlusion parametrs - samples: int (0 = disable), distance: float, angle: float."},
	{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;

	if(!PyArg_ParseTuple(args, ""))
		return NULL;

	v = PyObject_New(RaytracerObject, &RaytracerType);
	v->raytracer = new Raytracer();
	v->children = new vector<PyObject*>();
	return (PyObject*)v;
}

static void Raytracer_Destructor(PyObject* self)
{
	vector<PyObject*>::iterator o;
	for (o = ((RaytracerObject *)self)->children->begin();
		o != ((RaytracerObject *)self)->children->end(); o++)
		Py_DECREF(*o);
	delete ((RaytracerObject *)self)->raytracer;
	self->ob_type->tp_free(self);
}

static PyObject* Raytracer_render(PyObject* self, PyObject* args)
{
	((RaytracerObject *)self)->raytracer->render();
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Raytracer_setSampler(PyObject* self, PyObject* args)
{
	SamplerObject *samp;

	if (!PyArg_ParseTuple(args, "O!", &SamplerType, &samp))
		return NULL;

	((RaytracerObject *)self)->raytracer->setSampler(samp->sampler);

	Py_INCREF(samp);
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Raytracer_setCamera(PyObject* self, PyObject* args)
{
	CameraObject *cam;

	if (!PyArg_ParseTuple(args, "O!", &CameraType, &cam))
		return NULL;

	((RaytracerObject *)self)->raytracer->setCamera(cam->camera);

	Py_INCREF(cam);
	Py_INCREF(Py_None);
	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;

	if (!PyArg_ParseTuple(args, "(fff)", &r, &g, &b))
		return NULL;

	((RaytracerObject *)self)->raytracer->setBgColour(Colour(r,g,b));

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Raytracer_addShape(PyObject* self, PyObject* args)
{
	ShapeObject *shape;

	if (!PyArg_ParseTuple(args, "O!", &ShapeType, &shape))
		return NULL;

	((RaytracerObject *)self)->raytracer->addShape(shape->shape);
	((RaytracerObject *)self)->children->push_back((PyObject*)shape);
	Py_INCREF(shape);
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Raytracer_addLight(PyObject* self, PyObject* args)
{
	LightObject *lightobj;

	if (!PyArg_ParseTuple(args, "O!", &LightType, &lightobj))
		return NULL;
	((RaytracerObject *)self)->raytracer->addLight(lightobj->light);
	((RaytracerObject *)self)->children->push_back((PyObject*)lightobj);
	Py_INCREF(lightobj);
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject* Raytracer_ambientOcclusion(PyObject* self, PyObject* args, PyObject *kwd)
{
	int samples = 0;
	Float distance = 0.0, angle = 0.0;
	static char *kwdlist[] = {"samples", "distance", "angle", NULL};

	if (!PyArg_ParseTupleAndKeywords(args, kwd, "iff", kwdlist,
		&samples, &distance, &angle))
		return NULL;

	((RaytracerObject *)self)->raytracer->ambientOcclusion(samples, distance, angle);
	Py_INCREF(Py_None);
	return Py_None;
}

//=========================== Module Methods ===========================

static PyMethodDef ModuleMethods[] = {
	{"Light", (PyCFunction) Light_Constructor,
		METH_VARARGS | METH_KEYWORDS, "Light source object constructor."},
	{"Camera", (PyCFunction) Camera_Constructor,
		METH_VARARGS | METH_KEYWORDS, "Camera object constructor."},
	{"Pixmap", (PyCFunction) Pixmap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "Pixmap object constructor."},

	{"PlanarMap", (PyCFunction) PlanarMap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "PlanarMap object constructor."},
	{"CubicMap", (PyCFunction) CubicMap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "CubicMap object constructor."},
	{"SphereMap", (PyCFunction) SphereMap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "SphereMap object constructor."},
	{"CylinderMap", (PyCFunction) CylinderMap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "CylinderMap object constructor."},

	{"LinearColourMap", (PyCFunction) LinearColourMap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "LinearColourMap object constructor."},
	{"BoundColourMap", (PyCFunction) BoundColourMap_Constructor,
		METH_VARARGS | METH_KEYWORDS, "BoundColourMap object constructor."},

	{"ImageTexture", (PyCFunction) ImageTexture_Constructor,
		METH_VARARGS | METH_KEYWORDS, "ImageTexture object constructor."},
	{"CheckersTexture", (PyCFunction) CheckersTexture_Constructor,
		METH_VARARGS | METH_KEYWORDS, "CheckersTexture object constructor."},
	{"CloudTexture", (PyCFunction) CloudTexture_Constructor,
		METH_VARARGS | METH_KEYWORDS, "CloudTexture object constructor."},

	{"Material", (PyCFunction) Material_Constructor,
		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."},
	{"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."},

	{"Raytracer", (PyCFunction) Raytracer_Constructor,
		METH_VARARGS, "Raytracer object constructor."},
	{NULL, NULL}
};


extern "C" void initpyrit(void)
{
	PyObject* m;

	if (PyType_Ready(&RaytracerType) < 0
	|| PyType_Ready(&LightType) < 0
	|| PyType_Ready(&CameraType) < 0
	|| PyType_Ready(&MaterialType) < 0
	|| PyType_Ready(&VertexType) < 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
	|| PyType_Ready(&TextureMapType) < 0
	|| PyType_Ready(&PlanarMapType) < 0
	|| PyType_Ready(&CubicMapType) < 0
	|| PyType_Ready(&CylinderMapType) < 0
	|| PyType_Ready(&SphereMapType) < 0
	|| PyType_Ready(&ColourMapType) < 0
	|| PyType_Ready(&LinearColourMapType) < 0
	|| PyType_Ready(&BoundColourMapType) < 0
	|| PyType_Ready(&TextureType) < 0
	|| PyType_Ready(&ImageTextureType) < 0
	|| PyType_Ready(&CheckersTextureType) < 0
	|| PyType_Ready(&CloudTextureType) < 0
	)
		return;

	m = Py_InitModule3("pyrit", ModuleMethods, "Pyrit ray tracer.");

	if (m == NULL)
		return;
}