src/raytracermodule.cc
branchpyrit
changeset 0 3547b885df7e
child 1 e74bf781067e
equal deleted inserted replaced
-1:000000000000 0:3547b885df7e
       
     1 /*
       
     2  * C++ RayTracer
       
     3  * Module for Python
       
     4  * file: raytracermodule.cc
       
     5  *
       
     6  * Radek Brich, 2006
       
     7  */
       
     8 
       
     9 #include <Python.h>
       
    10 #include <vector>
       
    11 #include "scene.h"
       
    12 #include "raytracer.h"
       
    13 
       
    14 //=========================== Light Source Object ===========================
       
    15 
       
    16 typedef struct {
       
    17 	PyObject_HEAD
       
    18 	Light *light;
       
    19 } LightObject;
       
    20 
       
    21 static PyObject *Light_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
       
    22 static void Light_Destructor(PyObject* self);
       
    23 static PyObject *Light_Getattr(PyObject *self, char *name);
       
    24 static PyObject *Light_castshadows(PyObject* self, PyObject* args);
       
    25 
       
    26 static PyTypeObject LightType = {
       
    27 	PyObject_HEAD_INIT(NULL)
       
    28 	0,				/*ob_size*/
       
    29 	"Light",			/*tp_name*/
       
    30 	sizeof(LightObject),		/*tp_basicsize*/
       
    31 	0,				/*tp_itemsize*/
       
    32 	/* methods */
       
    33 	Light_Destructor,		/*tp_dealloc*/
       
    34 	0,				/*tp_print*/
       
    35 	Light_Getattr,			/*tp_getattr*/
       
    36 	0,				/*tp_setattr*/
       
    37 	0,				/*tp_compare*/
       
    38 	0,				/*tp_repr*/
       
    39 	0,				/*tp_as_number*/
       
    40 	0,				/*tp_as_sequence*/
       
    41 	0,				/*tp_as_mapping*/
       
    42 	0,				/*tp_hash */
       
    43 };
       
    44 
       
    45 static PyMethodDef LightMethods[] = {
       
    46 	{"castshadows", (PyCFunction)Light_castshadows, METH_VARARGS, "Enable or disable shadows from this light."},
       
    47 	{NULL, NULL}
       
    48 };
       
    49 
       
    50 static PyObject* Light_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
       
    51 {
       
    52 	LightObject *v;
       
    53 	static char *kwdlist[] = {"position", "colour", NULL};
       
    54 	PyObject *TPos, *TCol = NULL;
       
    55 	float px, py, pz;
       
    56 	float cr = 1.0, cg = 1.0, cb = 1.0;
       
    57 
       
    58 	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!|O!", kwdlist,
       
    59 		&PyTuple_Type, &TPos, &PyTuple_Type, &TCol))
       
    60 		return NULL;
       
    61 
       
    62 	if (!PyArg_ParseTuple(TPos, "fff", &px, &py, &pz))
       
    63 		return NULL;
       
    64 	if (TCol && !PyArg_ParseTuple(TCol, "fff", &cr, &cg, &cb))
       
    65 		return NULL;
       
    66 
       
    67 	v = PyObject_New(LightObject, &LightType);
       
    68 	v->light = new Light(Vector3(px, py, pz), Colour(cr, cg, cb));
       
    69 	return (PyObject*)v;
       
    70 }
       
    71 
       
    72 static void Light_Destructor(PyObject* self)
       
    73 {
       
    74 	delete ((LightObject *)self)->light;
       
    75 	PyObject_Del(self);
       
    76 }
       
    77 
       
    78 static PyObject *Light_Getattr(PyObject *self, char *name)
       
    79 {
       
    80 	return Py_FindMethod(LightMethods, self, name);
       
    81 }
       
    82 
       
    83 static PyObject *Light_castshadows(PyObject* self, PyObject* args)
       
    84 {
       
    85 	int shadows = 1;
       
    86 
       
    87 	if (!PyArg_ParseTuple(args, "i", &shadows))
       
    88 		return NULL;
       
    89 
       
    90 	((LightObject *)self)->light->castshadows(shadows);
       
    91 
       
    92 	Py_INCREF(Py_None);
       
    93 	return Py_None;
       
    94 }
       
    95 
       
    96 //=========================== Material Object ===========================
       
    97 
       
    98 typedef struct {
       
    99 	PyObject_HEAD
       
   100 	Material *material;
       
   101 } MaterialObject;
       
   102 
       
   103 static PyObject *Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
       
   104 static void Material_Destructor(PyObject* self);
       
   105 static PyObject *Material_Getattr(PyObject *self, char *name);
       
   106 
       
   107 static PyTypeObject MaterialType = {
       
   108 	PyObject_HEAD_INIT(NULL)
       
   109 	0,				/*ob_size*/
       
   110 	"Material",			/*tp_name*/
       
   111 	sizeof(MaterialObject),		/*tp_basicsize*/
       
   112 	0,				/*tp_itemsize*/
       
   113 	/* methods */
       
   114 	Material_Destructor,		/*tp_dealloc*/
       
   115 	0,				/*tp_print*/
       
   116 	Material_Getattr,			/*tp_getattr*/
       
   117 	0,				/*tp_setattr*/
       
   118 	0,				/*tp_compare*/
       
   119 	0,				/*tp_repr*/
       
   120 	0,				/*tp_as_number*/
       
   121 	0,				/*tp_as_sequence*/
       
   122 	0,				/*tp_as_mapping*/
       
   123 	0,				/*tp_hash */
       
   124 };
       
   125 
       
   126 static PyMethodDef MaterialMethods[] = {
       
   127 	{NULL, NULL}
       
   128 };
       
   129 
       
   130 static PyObject* Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
       
   131 {
       
   132 	MaterialObject *v;
       
   133 	static char *kwdlist[] = {"colour", NULL};
       
   134 	PyObject *TCol = NULL;
       
   135 	float cr=1.0, cg=1.0, cb=1.0;
       
   136 
       
   137 	if (!PyArg_ParseTupleAndKeywords(args, kwd, "|O!", kwdlist,
       
   138 		&PyTuple_Type, &TCol))
       
   139 		return NULL;
       
   140 
       
   141 	if (!PyArg_ParseTuple(TCol, "fff", &cr, &cg, &cb))
       
   142 		return NULL;
       
   143 
       
   144 	v = PyObject_New(MaterialObject, &MaterialType);
       
   145 	v->material = new Material(Colour(cr, cg, cb));
       
   146 	return (PyObject*)v;
       
   147 }
       
   148 
       
   149 static void Material_Destructor(PyObject* self)
       
   150 {
       
   151 	delete ((MaterialObject *)self)->material;
       
   152 	PyObject_Del(self);
       
   153 }
       
   154 
       
   155 static PyObject *Material_Getattr(PyObject *self, char *name)
       
   156 {
       
   157 	return Py_FindMethod(MaterialMethods, self, name);
       
   158 }
       
   159 
       
   160 //=========================== Sphere Object ===========================
       
   161 
       
   162 typedef struct {
       
   163 	PyObject_HEAD
       
   164 	Sphere *shape;
       
   165 } SphereObject;
       
   166 
       
   167 static PyObject *Sphere_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
       
   168 static void Sphere_Destructor(PyObject* self);
       
   169 static PyObject *Sphere_Getattr(PyObject *self, char *name);
       
   170 
       
   171 static PyTypeObject SphereType = {
       
   172 	PyObject_HEAD_INIT(NULL)
       
   173 	0,				/*ob_size*/
       
   174 	"Sphere",			/*tp_name*/
       
   175 	sizeof(SphereObject),		/*tp_basicsize*/
       
   176 	0,				/*tp_itemsize*/
       
   177 	/* methods */
       
   178 	Sphere_Destructor,		/*tp_dealloc*/
       
   179 	0,				/*tp_print*/
       
   180 	Sphere_Getattr,			/*tp_getattr*/
       
   181 	0,				/*tp_setattr*/
       
   182 	0,				/*tp_compare*/
       
   183 	0,				/*tp_repr*/
       
   184 	0,				/*tp_as_number*/
       
   185 	0,				/*tp_as_sequence*/
       
   186 	0,				/*tp_as_mapping*/
       
   187 	0,				/*tp_hash */
       
   188 };
       
   189 
       
   190 static PyMethodDef SphereMethods[] = {
       
   191 	{NULL, NULL}
       
   192 };
       
   193 
       
   194 static PyObject* Sphere_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
       
   195 {
       
   196 	SphereObject *v;
       
   197 	MaterialObject *material;
       
   198 	static char *kwdlist[] = {"centre", "radius", "material", NULL};
       
   199 	PyObject *TCentre = NULL;
       
   200 	float cx, cy, cz, radius;
       
   201 
       
   202 	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!fO!", kwdlist,
       
   203 		&PyTuple_Type, &TCentre, &radius, &MaterialType, &material))
       
   204 		return NULL;
       
   205 
       
   206 	if (!PyArg_ParseTuple(TCentre, "fff", &cx, &cy, &cz))
       
   207 		return NULL;
       
   208 
       
   209 	v = PyObject_New(SphereObject, &SphereType);
       
   210 	v->shape = new Sphere(Vector3(cx, cy, cz), radius, material->material);
       
   211 	Py_INCREF(material);
       
   212 	return (PyObject*)v;
       
   213 }
       
   214 
       
   215 static void Sphere_Destructor(PyObject* self)
       
   216 {
       
   217 	delete ((SphereObject *)self)->shape;
       
   218 	PyObject_Del(self);
       
   219 }
       
   220 
       
   221 static PyObject *Sphere_Getattr(PyObject *self, char *name)
       
   222 {
       
   223 	return Py_FindMethod(SphereMethods, self, name);
       
   224 }
       
   225 
       
   226 //=========================== Plane Object ===========================
       
   227 
       
   228 typedef struct {
       
   229 	PyObject_HEAD
       
   230 	Plane *shape;
       
   231 } PlaneObject;
       
   232 
       
   233 static PyObject *Plane_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
       
   234 static void Plane_Destructor(PyObject* self);
       
   235 static PyObject *Plane_Getattr(PyObject *self, char *name);
       
   236 
       
   237 static PyTypeObject PlaneType = {
       
   238 	PyObject_HEAD_INIT(NULL)
       
   239 	0,				/*ob_size*/
       
   240 	"Plane",			/*tp_name*/
       
   241 	sizeof(PlaneObject),		/*tp_basicsize*/
       
   242 	0,				/*tp_itemsize*/
       
   243 	/* methods */
       
   244 	Plane_Destructor,		/*tp_dealloc*/
       
   245 	0,				/*tp_print*/
       
   246 	Plane_Getattr,			/*tp_getattr*/
       
   247 	0,				/*tp_setattr*/
       
   248 	0,				/*tp_compare*/
       
   249 	0,				/*tp_repr*/
       
   250 	0,				/*tp_as_number*/
       
   251 	0,				/*tp_as_sequence*/
       
   252 	0,				/*tp_as_mapping*/
       
   253 	0,				/*tp_hash */
       
   254 };
       
   255 
       
   256 static PyMethodDef PlaneMethods[] = {
       
   257 	{NULL, NULL}
       
   258 };
       
   259 
       
   260 static PyObject* Plane_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
       
   261 {
       
   262 	PlaneObject *v;
       
   263 	MaterialObject *material;
       
   264 	static char *kwdlist[] = {"normal", "d", "material", NULL};
       
   265 	PyObject *TNorm = NULL;
       
   266 	float nx, ny, nz, d;
       
   267 
       
   268 	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!fO!", kwdlist,
       
   269 		&PyTuple_Type, &TNorm, &d, &MaterialType, &material))
       
   270 		return NULL;
       
   271 
       
   272 	if (!PyArg_ParseTuple(TNorm, "fff", &nx, &ny, &nz))
       
   273 		return NULL;
       
   274 
       
   275 	v = PyObject_New(PlaneObject, &PlaneType);
       
   276 	v->shape = new Plane(Vector3(nx, ny, nz), d, material->material);
       
   277 	Py_INCREF(material);
       
   278 	return (PyObject*)v;
       
   279 }
       
   280 
       
   281 static void Plane_Destructor(PyObject* self)
       
   282 {
       
   283 	delete ((PlaneObject *)self)->shape;
       
   284 	PyObject_Del(self);
       
   285 }
       
   286 
       
   287 static PyObject *Plane_Getattr(PyObject *self, char *name)
       
   288 {
       
   289 	return Py_FindMethod(PlaneMethods, self, name);
       
   290 }
       
   291 
       
   292 //=========================== Triangle Object ===========================
       
   293 
       
   294 typedef struct {
       
   295 	PyObject_HEAD
       
   296 	Triangle *shape;
       
   297 } TriangleObject;
       
   298 
       
   299 static PyObject *Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
       
   300 static void Triangle_Destructor(PyObject* self);
       
   301 static PyObject *Triangle_Getattr(PyObject *self, char *name);
       
   302 
       
   303 static PyTypeObject TriangleType = {
       
   304 	PyObject_HEAD_INIT(NULL)
       
   305 	0,				/*ob_size*/
       
   306 	"Triangle",			/*tp_name*/
       
   307 	sizeof(TriangleObject),		/*tp_basicsize*/
       
   308 	0,				/*tp_itemsize*/
       
   309 	/* methods */
       
   310 	Triangle_Destructor,		/*tp_dealloc*/
       
   311 	0,				/*tp_print*/
       
   312 	Triangle_Getattr,			/*tp_getattr*/
       
   313 	0,				/*tp_setattr*/
       
   314 	0,				/*tp_compare*/
       
   315 	0,				/*tp_repr*/
       
   316 	0,				/*tp_as_number*/
       
   317 	0,				/*tp_as_sequence*/
       
   318 	0,				/*tp_as_mapping*/
       
   319 	0,				/*tp_hash */
       
   320 };
       
   321 
       
   322 static PyMethodDef TriangleMethods[] = {
       
   323 	{NULL, NULL}
       
   324 };
       
   325 
       
   326 static PyObject* Triangle_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
       
   327 {
       
   328 	TriangleObject *v;
       
   329 	MaterialObject *material;
       
   330 	static char *kwdlist[] = {"A", "B", "C", "material", NULL};
       
   331 	PyObject *A = NULL, *B = NULL, *C = NULL;
       
   332 	float ax, ay, az, bx, by, bz, cx, cy, cz;
       
   333 
       
   334 	if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!O!", kwdlist,
       
   335 		&PyTuple_Type, &A, &PyTuple_Type, &B, &PyTuple_Type, &C,
       
   336 		&MaterialType, &material))
       
   337 		return NULL;
       
   338 
       
   339 	if (!PyArg_ParseTuple(A, "fff", &ax, &ay, &az))
       
   340 		return NULL;
       
   341 
       
   342 	if (!PyArg_ParseTuple(B, "fff", &bx, &by, &bz))
       
   343 		return NULL;
       
   344 
       
   345 	if (!PyArg_ParseTuple(C, "fff", &cx, &cy, &cz))
       
   346 		return NULL;
       
   347 
       
   348 	v = PyObject_New(TriangleObject, &TriangleType);
       
   349 	v->shape = new Triangle(Vector3(ax, ay, az), Vector3(bx, by, bz),
       
   350 		Vector3(cx, cy, cz), material->material);
       
   351 	Py_INCREF(material);
       
   352 	return (PyObject*)v;
       
   353 }
       
   354 
       
   355 static void Triangle_Destructor(PyObject* self)
       
   356 {
       
   357 	delete ((TriangleObject *)self)->shape;
       
   358 	PyObject_Del(self);
       
   359 }
       
   360 
       
   361 static PyObject *Triangle_Getattr(PyObject *self, char *name)
       
   362 {
       
   363 	return Py_FindMethod(TriangleMethods, self, name);
       
   364 }
       
   365 
       
   366 //=========================== Raytracer Object ===========================
       
   367 
       
   368 typedef struct {
       
   369 	PyObject_HEAD
       
   370 	Raytracer *raytracer;
       
   371 	vector<PyObject*> *children;
       
   372 } RaytracerObject;
       
   373 
       
   374 static PyObject *Raytracer_Constructor(PyObject* self, PyObject* args);
       
   375 static void Raytracer_Destructor(PyObject* self);
       
   376 static PyObject *Raytracer_Getattr(PyObject *self, char *name);
       
   377 static PyObject *Raytracer_render(PyObject* self, PyObject* args);
       
   378 static PyObject *Raytracer_addshape(PyObject* self, PyObject* args);
       
   379 static PyObject *Raytracer_addlight(PyObject* self, PyObject* args);
       
   380 static PyObject *Raytracer_ambientocclusion(PyObject* self, PyObject* args, PyObject *kwd);
       
   381 
       
   382 static PyTypeObject RaytracerType = {
       
   383 	PyObject_HEAD_INIT(NULL)
       
   384 	0,				/*ob_size*/
       
   385 	"Raytracer",			/*tp_name*/
       
   386 	sizeof(RaytracerObject),	/*tp_basicsize*/
       
   387 	0,				/*tp_itemsize*/
       
   388 	/* methods */
       
   389 	Raytracer_Destructor,		/*tp_dealloc*/
       
   390 	0,				/*tp_print*/
       
   391 	Raytracer_Getattr,		/*tp_getattr*/
       
   392 	0,				/*tp_setattr*/
       
   393 	0,				/*tp_compare*/
       
   394 	0,				/*tp_repr*/
       
   395 	0,				/*tp_as_number*/
       
   396 	0,				/*tp_as_sequence*/
       
   397 	0,				/*tp_as_mapping*/
       
   398 	0,				/*tp_hash */
       
   399 };
       
   400 
       
   401 static PyMethodDef RaytracerMethods[] = {
       
   402 	{"render", (PyCFunction)Raytracer_render, METH_VARARGS, "Render scene and return image data."},
       
   403 	{"addshape", (PyCFunction)Raytracer_addshape, METH_VARARGS, "Add new shape to scene."},
       
   404 	{"addlight", (PyCFunction)Raytracer_addlight, METH_VARARGS, "Add new light source to scene."},
       
   405 	{"ambientocclusion", (PyCFunction)Raytracer_ambientocclusion, METH_VARARGS | METH_KEYWORDS,
       
   406 		"Set ambient occlusion parametrs - samples: int (0 = disable), distance: float, angle: float."},
       
   407 	{NULL, NULL}
       
   408 };
       
   409 
       
   410 static PyObject* Raytracer_Constructor(PyObject* self, PyObject* args)
       
   411 {
       
   412 	RaytracerObject *v;
       
   413 
       
   414 	if(!PyArg_ParseTuple(args, ""))
       
   415 		return NULL;
       
   416 
       
   417 	v = PyObject_New(RaytracerObject, &RaytracerType);
       
   418 	v->raytracer = new Raytracer();
       
   419 	v->children = new vector<PyObject*>();
       
   420 
       
   421 	return (PyObject*)v;
       
   422 }
       
   423 
       
   424 static void Raytracer_Destructor(PyObject* self)
       
   425 {
       
   426 	vector<PyObject*>::iterator o;
       
   427 	for (o = ((RaytracerObject *)self)->children->begin();
       
   428 		o != ((RaytracerObject *)self)->children->end(); o++)
       
   429 		Py_DECREF(*o);
       
   430 	delete ((RaytracerObject *)self)->raytracer;
       
   431 	PyObject_Del(self);
       
   432 }
       
   433 
       
   434 static PyObject *Raytracer_Getattr(PyObject *self, char *name)
       
   435 {
       
   436 	return Py_FindMethod(RaytracerMethods, self, name);
       
   437 }
       
   438 
       
   439 static PyObject* Raytracer_render(PyObject* self, PyObject* args)
       
   440 {
       
   441 	int w = 0, h = 0;
       
   442 	char *chardata;
       
   443 	float *data;
       
   444 	PyObject *o;
       
   445 
       
   446 	if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
       
   447 		return NULL;
       
   448 
       
   449 	printf("[PyRit] Raytracing...\n");
       
   450 	data = ((RaytracerObject *)self)->raytracer->render(w, h);
       
   451 	if (!data) {
       
   452 		Py_INCREF(Py_None);
       
   453 		return Py_None;
       
   454 	}
       
   455 
       
   456 	// convert data to char
       
   457 	printf("[PyRit] Converting image data (float to char)...\n");
       
   458 	chardata = (char *) malloc(w*h*3);
       
   459 	float *d = data;
       
   460 	for (char *c = chardata; c != chardata + w*h*3; c++, d++) {
       
   461 		if (*d > 1.0)
       
   462 			*c = 255;
       
   463 		else
       
   464 			*c = (unsigned char)(*d * 255.0);
       
   465 	}
       
   466 	free(data);
       
   467 	o = Py_BuildValue("s#", chardata, w*h*3);
       
   468 	free(chardata);
       
   469 	printf("[PyRit] Done.\n");
       
   470 	return o;
       
   471 }
       
   472 
       
   473 static PyObject* Raytracer_addshape(PyObject* self, PyObject* args)
       
   474 {
       
   475 	PyObject *obj;
       
   476 
       
   477 	if (!PyArg_ParseTuple(args, "O", &obj))
       
   478 		return NULL;
       
   479 
       
   480 	((RaytracerObject *)self)->raytracer->addshape(
       
   481 		((PlaneObject*)obj)->shape);
       
   482 
       
   483 	((RaytracerObject *)self)->children->push_back(obj);
       
   484 	Py_INCREF(obj);
       
   485 	Py_INCREF(Py_None);
       
   486 	return Py_None;
       
   487 }
       
   488 
       
   489 static PyObject* Raytracer_addlight(PyObject* self, PyObject* args)
       
   490 {
       
   491 	LightObject *lightobj;
       
   492 
       
   493 	if (!PyArg_ParseTuple(args, "O!", &LightType, &lightobj))
       
   494 		return NULL;
       
   495 	((RaytracerObject *)self)->raytracer->addlight(lightobj->light);
       
   496 	((RaytracerObject *)self)->children->push_back((PyObject*)lightobj);
       
   497 	Py_INCREF(lightobj);
       
   498 	Py_INCREF(Py_None);
       
   499 	return Py_None;
       
   500 }
       
   501 
       
   502 static PyObject* Raytracer_ambientocclusion(PyObject* self, PyObject* args, PyObject *kwd)
       
   503 {
       
   504 	int samples = 0;
       
   505 	float distance = 0.0, angle = 0.0;
       
   506 	static char *kwdlist[] = {"samples", "distance", "angle", NULL};
       
   507 
       
   508 	if (!PyArg_ParseTupleAndKeywords(args, kwd, "iff", kwdlist,
       
   509 		&samples, &distance, &angle))
       
   510 		return NULL;
       
   511 
       
   512 	((RaytracerObject *)self)->raytracer->ambientocclusion(samples, distance, angle);
       
   513 	Py_INCREF(Py_None);
       
   514 	return Py_None;
       
   515 }
       
   516 
       
   517 //=========================== Module Methods ===========================
       
   518 
       
   519 static PyMethodDef ModuleMethods[] = {
       
   520 	{"Raytracer", (PyCFunction) Raytracer_Constructor,
       
   521 		METH_VARARGS, "Raytracer object constructor."},
       
   522 	{"Light", (PyCFunction) Light_Constructor,
       
   523 		METH_VARARGS | METH_KEYWORDS, "Light source object constructor."},
       
   524 	{"Material", (PyCFunction) Material_Constructor,
       
   525 		METH_VARARGS | METH_KEYWORDS, "Material object constructor."},
       
   526 	{"Sphere", (PyCFunction) Sphere_Constructor,
       
   527 		METH_VARARGS | METH_KEYWORDS, "Sphere object constructor."},
       
   528 	{"Plane", (PyCFunction) Plane_Constructor,
       
   529 		METH_VARARGS | METH_KEYWORDS, "Plane object constructor."},
       
   530 	{"Triangle", (PyCFunction) Triangle_Constructor,
       
   531 		METH_VARARGS | METH_KEYWORDS, "Triangle object constructor."},
       
   532 	{NULL, NULL}
       
   533 };
       
   534 
       
   535 
       
   536 extern "C" void initraytracer(void)
       
   537 {
       
   538 	Py_InitModule("raytracer", ModuleMethods);
       
   539 }