src/raytracermodule.cc
author Radek Brich <radek.brich@devl.cz>
Mon, 05 May 2008 15:31:14 +0200
branchpyrit
changeset 92 9af5c039b678
parent 91 9d66d323c354
child 93 96d65f841791
permissions -rw-r--r--
add MSVC compiler support, make it default for Windows new header file simd.h for SSE abstraction and helpers add mselect pseudo instruction for common or(and(...), andnot(...)) replace many SSE intrinsics with new names new MemoryPool class (mempool.h) for faster KdNode allocation remove setMaxDepth() from Octree and KdTree, make max_depth const, it should be defined in constructor and never changed, change after building tree would cause error in traversal modify DefaultSampler to generate nice 2x2 packets of samples for packet tracing optimize Box and BBox::intersect_packet add precomputed invdir attribute to RayPacket scons build system: check for pthread library on Windows check for SDL generate include/config.h with variables detected by scons configuration move auxiliary files to build/ add sanity checks add writable operator[] to Vector

/*
 * raytracermodule.cc: Python module
 *
 * 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 <Python.h>

#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 {
	PyObject_HEAD
	Light *light;
} LightObject;

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.9, cg = 0.9, cb = 0.9;

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

typedef struct {
	PyObject_HEAD
	Camera *camera;
} CameraObject;

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


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

typedef struct {
	PyObject_HEAD
	Material *material;
} MaterialObject;

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 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."},
	{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.3;

	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;

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

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

	Py_INCREF(Py_None);
	return Py_None;
}


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

typedef struct {
	PyObject_HEAD
	NormalVertex *nvertex;
} NormalVertexObject;

static PyObject *NormalVertex_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
static void NormalVertex_Destructor(PyObject* self);
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 */
	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;
	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->nvertex = new NormalVertex(((NormalVertexObject*)TVer)->nvertex);
	}
	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->nvertex = new NormalVertex(Vector(vx, vy, vz), Vector(nx, ny, nz));
	}
	return (PyObject*)v;
}

static void NormalVertex_Destructor(PyObject* self)
{
	delete ((NormalVertexObject *)self)->nvertex;
	self->ob_type->tp_free(self);
}

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;

	((NormalVertexObject *)self)->nvertex->setNormal(Vector(nx,ny,nz).normalize());

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

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

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

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

typedef struct {
	ShapeObject shape;
} SphereObject;

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[] = {"centre", "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 ===========================

typedef struct {
	ShapeObject shape;
} BoxObject;

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

//=========================== 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)
{
	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);
}

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

typedef struct {
	PyObject_HEAD
	Sampler *sampler;
} SamplerObject;

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

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

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

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

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

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

typedef struct {
	PyObject_HEAD
	Raytracer *raytracer;
	vector<PyObject*> *children;
} RaytracerObject;

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[] = {
	{"Raytracer", (PyCFunction) Raytracer_Constructor,
		METH_VARARGS, "Raytracer object constructor."},
	{"Light", (PyCFunction) Light_Constructor,
		METH_VARARGS | METH_KEYWORDS, "Light source object constructor."},
	{"Camera", (PyCFunction) Camera_Constructor,
		METH_VARARGS | METH_KEYWORDS, "Camera 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."},
	{"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 initpyrit(void)
{
	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;
}