smooth triangles (aka Phong shading)
extend Python binding to support vertex normals and smooth triangles
make bunny.py and realtime_dragon smooth, and fix other demos for new triangle constructor
add Vector::operator/=
+ − /*
+ − * 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 (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;
+ − PyObject_Del(self);
+ − }
+ −
+ − static PyObject *Material_Getattr(PyObject *self, char *name)
+ − {
+ − return Py_FindMethod(MaterialMethods, self, name);
+ − }
+ −
+ − //=========================== 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_Getattr(PyObject *self, char *name);
+ − static PyObject *NormalVertex_setNormal(PyObject* self, PyObject* args);
+ −
+ − static PyTypeObject NormalVertexType = {
+ − PyObject_HEAD_INIT(NULL)
+ − 0, /*ob_size*/
+ − "NormalVertex", /*tp_name*/
+ − sizeof(NormalVertexObject), /*tp_basicsize*/
+ − 0, /*tp_itemsize*/
+ − /* methods */
+ − NormalVertex_Destructor, /*tp_dealloc*/
+ − 0, /*tp_print*/
+ − NormalVertex_Getattr, /*tp_getattr*/
+ − 0, /*tp_setattr*/
+ − 0, /*tp_compare*/
+ − 0, /*tp_repr*/
+ − 0, /*tp_as_number*/
+ − 0, /*tp_as_sequence*/
+ − 0, /*tp_as_mapping*/
+ − 0, /*tp_hash */
+ − };
+ −
+ − static PyMethodDef NormalVertexMethods[] = {
+ − {"setNormal", (PyCFunction)NormalVertex_setNormal, METH_VARARGS, "Set normal of this vertex."},
+ − {NULL, NULL}
+ − };
+ −
+ − static 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,
+ − &PyTuple_Type, &TVer, &PyTuple_Type, &TNor))
+ − return NULL;
+ −
+ − 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(Vector3(vx, vy, vz), Vector3(nx, ny, nz));
+ − return (PyObject*)v;
+ − }
+ −
+ − static void NormalVertex_Destructor(PyObject* self)
+ − {
+ − delete ((NormalVertexObject *)self)->nvertex;
+ − PyObject_Del(self);
+ − }
+ −
+ − static PyObject *NormalVertex_Getattr(PyObject *self, char *name)
+ − {
+ − return Py_FindMethod(NormalVertexMethods, self, name);
+ − }
+ −
+ − 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(Vector3(nx,ny,nz).normalize());
+ −
+ − Py_INCREF(Py_None);
+ − return Py_None;
+ − }
+ −
+ − //=========================== 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 *triangle;
+ − } TriangleObject;
+ −
+ − static PyObject *Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+ − static void Triangle_Destructor(PyObject* self);
+ − static PyObject *Triangle_Getattr(PyObject *self, char *name);
+ − static PyObject *Triangle_getNormal(PyObject* self, PyObject* args);
+ − static PyObject *Triangle_setSmooth(PyObject* self, PyObject* args);
+ −
+ − 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[] = {
+ − {"getNormal", (PyCFunction)Triangle_getNormal, METH_NOARGS, "Get normal of whole triangle."},
+ − {"setSmooth", (PyCFunction)Triangle_setSmooth, METH_NOARGS, "Set the triangle smooth."},
+ − {NULL, NULL}
+ − };
+ −
+ − 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->triangle = 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 void Triangle_Destructor(PyObject* self)
+ − {
+ − delete ((TriangleObject *)self)->triangle;
+ − PyObject_Del(self);
+ − }
+ −
+ − static PyObject *Triangle_Getattr(PyObject *self, char *name)
+ − {
+ − return Py_FindMethod(TriangleMethods, self, name);
+ − }
+ −
+ − static PyObject* Triangle_getNormal(PyObject* self, PyObject* args)
+ − {
+ − PyObject *obj;
+ −
+ − Vector3 N = ((TriangleObject *)self)->triangle->getNormal();
+ −
+ − obj = Py_BuildValue("(fff)", N.x, N.y, N.z);
+ − return obj;
+ − }
+ −
+ − static PyObject* Triangle_setSmooth(PyObject* self, PyObject* args)
+ − {
+ − ((TriangleObject *)self)->triangle->setSmooth();
+ − Py_INCREF(Py_None);
+ − return Py_None;
+ − }
+ −
+ − //=========================== 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."},
+ − {"NormalVertex", (PyCFunction) NormalVertex_Constructor,
+ − METH_VARARGS | METH_KEYWORDS, "NormalVertex 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);
+ − }