/*
* C++ RayTracer
* Module for Python
* file: raytracermodule.cc
*
* Radek Brich, 2006
*/
#include <Python.h>
#include <vector>
#include "scene.h"
#include "raytracer.h"
//=========================== 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_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 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 = 1.0, cg = 1.0, cb = 1.0;
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(Vector3(px, py, pz), Colour(cr, cg, cb));
return (PyObject*)v;
}
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);
}
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;
}
//=========================== 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_Getattr(PyObject *self, char *name);
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[] = {
{NULL, NULL}
};
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 (!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;
PyObject_Del(self);
}
static PyObject *Material_Getattr(PyObject *self, char *name)
{
return Py_FindMethod(MaterialMethods, self, name);
}
//=========================== Sphere Object ===========================
typedef struct {
PyObject_HEAD
Sphere *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 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 = 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;
} 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 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 = new Box(Vector3(lx, ly, lz), Vector3(hx, hy, hz), material->material);
Py_INCREF(material);
return (PyObject*)v;
}
static void Box_Destructor(PyObject* self)
{
delete ((BoxObject *)self)->shape;
PyObject_Del(self);
}
static PyObject *Box_Getattr(PyObject *self, char *name)
{
return Py_FindMethod(BoxMethods, self, name);
}
//=========================== Triangle Object ===========================
typedef struct {
PyObject_HEAD
Triangle *shape;
} 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 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 PyMethodDef TriangleMethods[] = {
{NULL, NULL}
};
static PyObject* Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
TriangleObject *v;
MaterialObject *material;
static char *kwdlist[] = {"A", "B", "C", "material", NULL};
PyObject *A = NULL, *B = NULL, *C = NULL;
Float ax, ay, az, bx, by, bz, cx, cy, cz;
if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!O!", kwdlist,
&PyTuple_Type, &A, &PyTuple_Type, &B, &PyTuple_Type, &C,
&MaterialType, &material))
return NULL;
if (!PyArg_ParseTuple(A, "fff", &ax, &ay, &az))
return NULL;
if (!PyArg_ParseTuple(B, "fff", &bx, &by, &bz))
return NULL;
if (!PyArg_ParseTuple(C, "fff", &cx, &cy, &cz))
return NULL;
v = PyObject_New(TriangleObject, &TriangleType);
v->shape = new Triangle(Vector3(ax, ay, az), Vector3(bx, by, bz),
Vector3(cx, cy, cz), material->material);
Py_INCREF(material);
return (PyObject*)v;
}
static void Triangle_Destructor(PyObject* self)
{
delete ((TriangleObject *)self)->shape;
PyObject_Del(self);
}
static PyObject *Triangle_Getattr(PyObject *self, char *name)
{
return Py_FindMethod(TriangleMethods, self, name);
}
//=========================== 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_Getattr(PyObject *self, char *name);
static PyObject *Raytracer_render(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."},
{"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 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*>();
v->raytracer->setCamera(new Camera());
v->raytracer->setTop(new KdTree());
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;
PyObject_Del(self);
}
static PyObject *Raytracer_Getattr(PyObject *self, char *name)
{
return Py_FindMethod(RaytracerMethods, self, name);
}
static PyObject* Raytracer_render(PyObject* self, PyObject* args)
{
int w = 0, h = 0;
char *chardata;
Float *data;
PyObject *o;
if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
return NULL;
printf("[pyrit] Raytracing...\n");
((RaytracerObject *)self)->raytracer->getTop()->optimize();
data = (Float *) malloc(w*h*3*sizeof(Float));
((RaytracerObject *)self)->raytracer->render(w, h, data);
if (!data) {
Py_INCREF(Py_None);
return Py_None;
}
// convert data to char
printf("[pyrit] Converting image data (float to char)...\n");
chardata = (char *) malloc(w*h*3);
Float *d = data;
for (char *c = chardata; c != chardata + w*h*3; c++, d++) {
if (*d > 1.0)
*c = 255;
else
*c = (unsigned char)(*d * 255.0);
}
free(data);
o = Py_BuildValue("s#", chardata, w*h*3);
free(chardata);
printf("[pyrit] Done.\n");
return o;
}
static PyObject* Raytracer_addshape(PyObject* self, PyObject* args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
((RaytracerObject *)self)->raytracer->addshape(
((BoxObject*)obj)->shape);
((RaytracerObject *)self)->children->push_back(obj);
Py_INCREF(obj);
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."},
{"Material", (PyCFunction) Material_Constructor,
METH_VARARGS | METH_KEYWORDS, "Material 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."},
{NULL, NULL}
};
extern "C" void initraytracer(void)
{
Py_InitModule("raytracer", ModuleMethods);
}