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