From 9b758508df283a533a4cfc605545a35f77bc9d5f Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 13 Jun 2011 00:16:27 -0600 Subject: Use Cython for the Python module. --- .gitignore | 1 + libdimension-python/Camera.c | 92 ---- libdimension-python/Camera.h | 28 - libdimension-python/Canvas.c | 170 ------ libdimension-python/Canvas.h | 28 - libdimension-python/Color.c | 303 ----------- libdimension-python/Color.h | 41 -- libdimension-python/Makefile.am | 29 +- libdimension-python/Matrix.c | 292 ---------- libdimension-python/Matrix.h | 33 -- libdimension-python/Object.c | 93 ---- libdimension-python/Object.h | 28 - libdimension-python/PerspectiveCamera.c | 111 ---- libdimension-python/PerspectiveCamera.h | 28 - libdimension-python/Scene.c | 117 ---- libdimension-python/Scene.h | 28 - libdimension-python/Sphere.c | 90 ---- libdimension-python/Sphere.h | 29 - libdimension-python/Vector.c | 380 ------------- libdimension-python/Vector.h | 40 -- libdimension-python/dimension-python.h | 37 -- libdimension-python/dimension.c | 120 ----- libdimension-python/dimension.pxd | 359 +++++++++++++ libdimension-python/dimension.pyx | 910 ++++++++++++++++++++++++++++++++ libdimension-python/tests/demo.py | 138 ++++- libdimension-python/tests/geometry.py | 23 +- 26 files changed, 1418 insertions(+), 2130 deletions(-) delete mode 100644 libdimension-python/Camera.c delete mode 100644 libdimension-python/Camera.h delete mode 100644 libdimension-python/Canvas.c delete mode 100644 libdimension-python/Canvas.h delete mode 100644 libdimension-python/Color.c delete mode 100644 libdimension-python/Color.h delete mode 100644 libdimension-python/Matrix.c delete mode 100644 libdimension-python/Matrix.h delete mode 100644 libdimension-python/Object.c delete mode 100644 libdimension-python/Object.h delete mode 100644 libdimension-python/PerspectiveCamera.c delete mode 100644 libdimension-python/PerspectiveCamera.h delete mode 100644 libdimension-python/Scene.c delete mode 100644 libdimension-python/Scene.h delete mode 100644 libdimension-python/Sphere.c delete mode 100644 libdimension-python/Sphere.h delete mode 100644 libdimension-python/Vector.c delete mode 100644 libdimension-python/Vector.h delete mode 100644 libdimension-python/dimension-python.h delete mode 100644 libdimension-python/dimension.c create mode 100644 libdimension-python/dimension.pxd create mode 100644 libdimension-python/dimension.pyx diff --git a/.gitignore b/.gitignore index d894034..422e2ce 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ Makefile.in /*/doc Doxyfile __pycache__ +libdimension-python/*.c # pkg-config files *.pc diff --git a/libdimension-python/Camera.c b/libdimension-python/Camera.c deleted file mode 100644 index 286c36d..0000000 --- a/libdimension-python/Camera.c +++ /dev/null @@ -1,92 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Camera_init(dmnsn_py_Camera *self, PyObject *args, PyObject *kwds) -{ - if (kwds || (args && !PyArg_ParseTuple(args, ""))) - return -1; - - return 0; -} - -static void -dmnsn_py_Camera_dealloc(dmnsn_py_Camera *self) -{ - dmnsn_delete_camera(self->camera); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject * -dmnsn_py_Camera_initialize(dmnsn_py_Camera *self) -{ - PyErr_SetString(PyExc_TypeError, "Attempt to initialize base Camera"); - return NULL; -} - -static PyObject * -dmnsn_py_Camera_transform(dmnsn_py_Camera *self, PyObject *args) -{ - dmnsn_py_Matrix *trans; - if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_MatrixType, &trans)) - return NULL; - - if (!self->camera) { - PyErr_SetString(PyExc_TypeError, "Attempt to transform base Camera"); - return NULL; - } - - self->camera->trans = dmnsn_matrix_mul(trans->m, self->camera->trans); - Py_INCREF(self); - return (PyObject *)self; -} - -static PyMethodDef dmnsn_py_Camera_methods[] = { - { "initialize", (PyCFunction)dmnsn_py_Camera_initialize, METH_NOARGS, - "Initialize a camera" }, - { "transform", (PyCFunction)dmnsn_py_Camera_transform, METH_VARARGS, - "Transform a camera" }, - { NULL } -}; - -static PyGetSetDef dmnsn_py_Camera_getsetters[] = { - { NULL } -}; - -PyTypeObject dmnsn_py_CameraType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Camera", - .tp_basicsize = sizeof(dmnsn_py_Camera), - .tp_dealloc = (destructor)dmnsn_py_Camera_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = "Dimension camera", - .tp_methods = dmnsn_py_Camera_methods, - .tp_getset = dmnsn_py_Camera_getsetters, - .tp_init = (initproc)dmnsn_py_Camera_init, -}; - -bool -dmnsn_py_init_CameraType(void) -{ - dmnsn_py_CameraType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_CameraType) >= 0; -} diff --git a/libdimension-python/Camera.h b/libdimension-python/Camera.h deleted file mode 100644 index 8642f2c..0000000 --- a/libdimension-python/Camera.h +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Camera { - PyObject_HEAD - dmnsn_camera *camera; -} dmnsn_py_Camera; - -extern PyTypeObject dmnsn_py_CameraType; - -bool dmnsn_py_init_CameraType(void); diff --git a/libdimension-python/Canvas.c b/libdimension-python/Canvas.c deleted file mode 100644 index c5063d0..0000000 --- a/libdimension-python/Canvas.c +++ /dev/null @@ -1,170 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Canvas_init(dmnsn_py_Canvas *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = { "width", "height", NULL }; - - Py_ssize_t width, height; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "nn", kwlist, &width, &height)) - return -1; - - if (width < 0 || height < 0) { - PyErr_SetString(PyExc_ValueError, "Canvas dimensions must be positive"); - return -1; - } - - dmnsn_delete_canvas(self->canvas); - self->canvas = dmnsn_new_canvas(width, height); - DMNSN_INCREF(self->canvas); - dmnsn_clear_canvas(self->canvas, dmnsn_black); - return 0; -} - -static void -dmnsn_py_Canvas_dealloc(dmnsn_py_Canvas *self) -{ - dmnsn_delete_canvas(self->canvas); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject * -dmnsn_py_Canvas_optimizePNG(dmnsn_py_Canvas *self) -{ - if (dmnsn_png_optimize_canvas(self->canvas) != 0) - return PyErr_SetFromErrno(PyExc_OSError); - - /* Re-clear the canvas to clear the optimizer too */ - dmnsn_clear_canvas(self->canvas, dmnsn_black); - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -dmnsn_py_Canvas_optimizeGL(dmnsn_py_Canvas *self) -{ - if (dmnsn_gl_optimize_canvas(self->canvas) != 0) - return PyErr_SetFromErrno(PyExc_OSError); - - /* Re-clear the canvas to clear the optimizer too */ - dmnsn_clear_canvas(self->canvas, dmnsn_black); - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -dmnsn_py_Canvas_clear(dmnsn_py_Canvas *self, PyObject *args) -{ - dmnsn_py_Color *color; - if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_ColorType, &color)) - return NULL; - - dmnsn_clear_canvas(self->canvas, color->c); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -dmnsn_py_Canvas_writePNG(dmnsn_py_Canvas *self, PyObject *args) -{ - PyObject *filenameobj; - if (!PyArg_ParseTuple(args, "O&", PyUnicode_FSConverter, &filenameobj)) - return NULL; - - const char *filename = PyBytes_AS_STRING(filenameobj); - FILE *file = fopen(filename, "wb"); - if (!file) - return PyErr_SetFromErrno(PyExc_OSError); - - if (dmnsn_png_write_canvas(self->canvas, file) != 0) - return PyErr_SetFromErrno(PyExc_OSError); - - if (fclose(file) != 0) - return PyErr_SetFromErrno(PyExc_OSError); - - Py_DECREF(filenameobj); - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -dmnsn_py_Canvas_drawGL(dmnsn_py_Canvas *self) -{ - if (dmnsn_gl_write_canvas(self->canvas) != 0) - return PyErr_SetFromErrno(PyExc_OSError); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef dmnsn_py_Canvas_methods[] = { - { "optimizePNG", (PyCFunction)dmnsn_py_Canvas_optimizePNG, METH_NOARGS, - "Optimize a canvas for PNG output" }, - { "optimizeGL", (PyCFunction)dmnsn_py_Canvas_optimizeGL, METH_NOARGS, - "Optimize a canvas for OpenGL output" }, - { "clear", (PyCFunction)dmnsn_py_Canvas_clear, METH_VARARGS, - "Clear a canvas with a solid color" }, - { "writePNG", (PyCFunction)dmnsn_py_Canvas_writePNG, METH_VARARGS, - "Write a canvas to a PNG file" }, - { "drawGL", (PyCFunction)dmnsn_py_Canvas_drawGL, METH_NOARGS, - "Draw a canvas to the screen with OpenGL" }, - { NULL } -}; - -static PyObject * -dmnsn_py_Canvas_get_width(dmnsn_py_Canvas *self, void *closure) -{ - return PyLong_FromSize_t(self->canvas->width); -} - -static PyObject * -dmnsn_py_Canvas_get_height(dmnsn_py_Canvas *self, void *closure) -{ - return PyLong_FromSize_t(self->canvas->height); -} - -static PyGetSetDef dmnsn_py_Canvas_getsetters[] = { - { "width", (getter)dmnsn_py_Canvas_get_width, NULL, "Canvas width", NULL }, - { "height", (getter)dmnsn_py_Canvas_get_height, NULL, "Canvas height", NULL }, - { NULL } -}; - -PyTypeObject dmnsn_py_CanvasType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Canvas", - .tp_basicsize = sizeof(dmnsn_py_Canvas), - .tp_dealloc = (destructor)dmnsn_py_Canvas_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "Dimension canvas", - .tp_methods = dmnsn_py_Canvas_methods, - .tp_getset = dmnsn_py_Canvas_getsetters, - .tp_init = (initproc)dmnsn_py_Canvas_init, -}; - -bool -dmnsn_py_init_CanvasType(void) -{ - dmnsn_py_CanvasType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_CanvasType) >= 0; -} diff --git a/libdimension-python/Canvas.h b/libdimension-python/Canvas.h deleted file mode 100644 index 0714e53..0000000 --- a/libdimension-python/Canvas.h +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Canvas { - PyObject_HEAD - dmnsn_canvas *canvas; -} dmnsn_py_Canvas; - -extern PyTypeObject dmnsn_py_CanvasType; - -bool dmnsn_py_init_CanvasType(void); diff --git a/libdimension-python/Color.c b/libdimension-python/Color.c deleted file mode 100644 index 3ac92ce..0000000 --- a/libdimension-python/Color.c +++ /dev/null @@ -1,303 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Color_init(dmnsn_py_Color *self, PyObject *args, PyObject *kwds) -{ - self->sRGB.trans = 0.0; - self->sRGB.filter = 0.0; - - static char *kwlist[] = { "red", "green", "blue", "trans", "filter", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ddd|dd", kwlist, - &self->sRGB.R, &self->sRGB.G, &self->sRGB.B, - &self->sRGB.trans, &self->sRGB.filter)) - return -1; - - self->c = dmnsn_color_from_sRGB(self->sRGB); - return 0; -} - -static PyObject * -dmnsn_py_Color_repr(dmnsn_py_Color *self) -{ - PyObject *R = PyFloat_FromDouble(self->sRGB.R); - PyObject *G = PyFloat_FromDouble(self->sRGB.G); - PyObject *B = PyFloat_FromDouble(self->sRGB.B); - PyObject *trans = PyFloat_FromDouble(self->sRGB.trans); - PyObject *filter = PyFloat_FromDouble(self->sRGB.filter); - - if (!R || !G || !B || !trans || !filter) { - Py_XDECREF(filter); - Py_XDECREF(trans); - Py_XDECREF(B); - Py_XDECREF(G); - Py_XDECREF(R); - return NULL; - } - - PyObject *repr = PyUnicode_FromFormat("dimension.Color(%R, %R, %R, %R, %R)", - R, G, B, trans, filter); - Py_XDECREF(filter); - Py_XDECREF(trans); - Py_XDECREF(B); - Py_XDECREF(G); - Py_XDECREF(R); - return repr; -} - -static PyObject * -dmnsn_py_Color_str(dmnsn_py_Color *self) -{ - PyObject *R = PyFloat_FromDouble(self->sRGB.R); - PyObject *G = PyFloat_FromDouble(self->sRGB.G); - PyObject *B = PyFloat_FromDouble(self->sRGB.B); - PyObject *trans = PyFloat_FromDouble(self->sRGB.trans); - PyObject *filter = PyFloat_FromDouble(self->sRGB.filter); - - if (!R || !G || !B || !trans || !filter) { - Py_XDECREF(filter); - Py_XDECREF(trans); - Py_XDECREF(B); - Py_XDECREF(G); - Py_XDECREF(R); - return NULL; - } - - PyObject *str; - if (self->sRGB.filter < dmnsn_epsilon && self->sRGB.trans < dmnsn_epsilon) { - str = PyUnicode_FromFormat("", - R, G, B); - } else { - str = PyUnicode_FromFormat("", - R, G, B, trans, filter); - } - Py_XDECREF(filter); - Py_XDECREF(trans); - Py_XDECREF(B); - Py_XDECREF(G); - Py_XDECREF(R); - return str; -} - -static PyObject * -dmnsn_py_Color_richcompare(PyObject *lhs, PyObject *rhs, int op) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_ColorType) - || !PyObject_TypeCheck(rhs, &dmnsn_py_ColorType)) - { - PyErr_SetString(PyExc_TypeError, - "Colors can only be compared with Colors"); - return NULL; - } - - dmnsn_py_Color *clhs = (dmnsn_py_Color *)lhs; - dmnsn_py_Color *crhs = (dmnsn_py_Color *)rhs; - - double rdiff = (clhs->c.R - crhs->c.R)*(clhs->c.R - crhs->c.R); - double gdiff = (clhs->c.G - crhs->c.G)*(clhs->c.G - crhs->c.G); - double bdiff = (clhs->c.B - crhs->c.B)*(clhs->c.B - crhs->c.B); - double tdiff = (clhs->c.trans - crhs->c.trans) - * (clhs->c.trans - crhs->c.trans); - double fdiff = (clhs->c.filter - crhs->c.filter) - * (clhs->c.filter - crhs->c.filter); - bool equal = sqrt(rdiff + gdiff + bdiff + tdiff + fdiff) < dmnsn_epsilon; - - PyObject *result; - switch (op) { - case Py_EQ: - result = equal ? Py_True : Py_False; - break; - case Py_NE: - result = !equal ? Py_True : Py_False; - break; - default: - result = Py_NotImplemented; - break; - } - - Py_INCREF(result); - return result; -} - -static PyObject * -dmnsn_py_Color_add(PyObject *lhs, PyObject *rhs) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_ColorType) - || !PyObject_TypeCheck(rhs, &dmnsn_py_ColorType)) - { - PyErr_SetString(PyExc_TypeError, - "Colors can only be added to Colors"); - return NULL; - } - - dmnsn_py_Color *ret = PyObject_New(dmnsn_py_Color, &dmnsn_py_ColorType); - if (ret) { - dmnsn_py_Color *clhs = (dmnsn_py_Color *)lhs; - dmnsn_py_Color *crhs = (dmnsn_py_Color *)rhs; - ret->sRGB = dmnsn_color_add(clhs->sRGB, crhs->sRGB); - ret->c = dmnsn_color_from_sRGB(ret->sRGB); - } - return (PyObject *)ret; -} - -static PyObject * -dmnsn_py_Color_mul(PyObject *lhs, PyObject *rhs) -{ - dmnsn_py_Color *col; - double dbl; - - if (PyObject_TypeCheck(lhs, &dmnsn_py_ColorType)) { - col = (dmnsn_py_Color *)lhs; - dbl = PyFloat_AsDouble(rhs); - if (PyErr_Occurred()) - return NULL; - } else { - col = (dmnsn_py_Color *)rhs; - dbl = PyFloat_AsDouble(lhs); - if (PyErr_Occurred()) - return NULL; - } - - dmnsn_py_Color *ret = PyObject_New(dmnsn_py_Color, &dmnsn_py_ColorType); - if (ret) { - ret->sRGB = dmnsn_color_mul(dbl, col->sRGB); - ret->c = dmnsn_color_from_sRGB(ret->sRGB); - } - return (PyObject *)ret; -} - -static int -dmnsn_py_Color_bool(PyObject *obj) -{ - dmnsn_py_Color *col = (dmnsn_py_Color *)obj; - return !dmnsn_color_is_black(col->c); -} - -static PyNumberMethods dmnsn_py_Color_as_number = { - .nb_add = dmnsn_py_Color_add, - .nb_multiply = dmnsn_py_Color_mul, - .nb_bool = dmnsn_py_Color_bool, -}; - -static PyMethodDef dmnsn_py_Color_methods[] = { - { NULL } -}; - -static PyObject * -dmnsn_py_Color_get_red(dmnsn_py_Color *self, void *closure) -{ - return PyFloat_FromDouble(self->sRGB.R); -} - -static PyObject * -dmnsn_py_Color_get_green(dmnsn_py_Color *self, void *closure) -{ - return PyFloat_FromDouble(self->sRGB.G); -} - -static PyObject * -dmnsn_py_Color_get_blue(dmnsn_py_Color *self, void *closure) -{ - return PyFloat_FromDouble(self->sRGB.B); -} - -static PyObject * -dmnsn_py_Color_get_trans(dmnsn_py_Color *self, void *closure) -{ - return PyFloat_FromDouble(self->sRGB.trans); -} - -static PyObject * -dmnsn_py_Color_get_filter(dmnsn_py_Color *self, void *closure) -{ - return PyFloat_FromDouble(self->sRGB.filter); -} - -static PyGetSetDef dmnsn_py_Color_getsetters[] = { - { "red", (getter)dmnsn_py_Color_get_red, NULL, - "Red component", NULL }, - { "green", (getter)dmnsn_py_Color_get_green, NULL, - "Green componant", NULL }, - { "blue", (getter)dmnsn_py_Color_get_blue, NULL, - "Blue componant", NULL }, - { "trans", (getter)dmnsn_py_Color_get_trans, NULL, - "Transmittance component", NULL }, - { "filter", (getter)dmnsn_py_Color_get_filter, NULL, - "Filter component", NULL }, - { NULL } -}; - -PyTypeObject dmnsn_py_ColorType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Color", - .tp_basicsize = sizeof(dmnsn_py_Color), - .tp_repr = (reprfunc)dmnsn_py_Color_repr, - .tp_str = (reprfunc)dmnsn_py_Color_str, - .tp_as_number = &dmnsn_py_Color_as_number, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "Dimension color", - .tp_richcompare = dmnsn_py_Color_richcompare, - .tp_methods = dmnsn_py_Color_methods, - .tp_getset = dmnsn_py_Color_getsetters, - .tp_init = (initproc)dmnsn_py_Color_init, -}; - -#define dmnsn_py_Color_global(name) \ - dmnsn_py_Color name = { \ - PyObject_HEAD_INIT(&dmnsn_py_ColorType) \ - }; - -dmnsn_py_Color_global(dmnsn_py_Black); -dmnsn_py_Color_global(dmnsn_py_White); -dmnsn_py_Color_global(dmnsn_py_Clear); -dmnsn_py_Color_global(dmnsn_py_Red); -dmnsn_py_Color_global(dmnsn_py_Green); -dmnsn_py_Color_global(dmnsn_py_Blue); -dmnsn_py_Color_global(dmnsn_py_Magenta); -dmnsn_py_Color_global(dmnsn_py_Orange); -dmnsn_py_Color_global(dmnsn_py_Yellow); -dmnsn_py_Color_global(dmnsn_py_Cyan); - -bool -dmnsn_py_init_ColorType(void) -{ -#define dmnsn_py_define_global(global, color) \ - do { \ - (global).c = color; \ - (global).sRGB = dmnsn_color_to_sRGB(color); \ - } while (0) - - dmnsn_py_define_global(dmnsn_py_Black, dmnsn_black); - dmnsn_py_define_global(dmnsn_py_White, dmnsn_white); - dmnsn_py_define_global(dmnsn_py_Clear, dmnsn_clear); - dmnsn_py_define_global(dmnsn_py_Red, dmnsn_red); - dmnsn_py_define_global(dmnsn_py_Green, dmnsn_green); - dmnsn_py_define_global(dmnsn_py_Blue, dmnsn_blue); - dmnsn_py_define_global(dmnsn_py_Magenta, dmnsn_magenta); - dmnsn_py_define_global(dmnsn_py_Orange, dmnsn_orange); - dmnsn_py_define_global(dmnsn_py_Yellow, dmnsn_yellow); - dmnsn_py_define_global(dmnsn_py_Cyan, dmnsn_cyan); - - dmnsn_py_ColorType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_ColorType) >= 0; -} diff --git a/libdimension-python/Color.h b/libdimension-python/Color.h deleted file mode 100644 index 533a9e5..0000000 --- a/libdimension-python/Color.h +++ /dev/null @@ -1,41 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Color { - PyObject_HEAD - dmnsn_color c; - dmnsn_color sRGB; -} dmnsn_py_Color; - -extern PyTypeObject dmnsn_py_ColorType; - -bool dmnsn_py_init_ColorType(void); - -/* Color constants */ -extern dmnsn_py_Color dmnsn_py_Black; -extern dmnsn_py_Color dmnsn_py_White; -extern dmnsn_py_Color dmnsn_py_Clear; -extern dmnsn_py_Color dmnsn_py_Red; -extern dmnsn_py_Color dmnsn_py_Green; -extern dmnsn_py_Color dmnsn_py_Blue; -extern dmnsn_py_Color dmnsn_py_Magenta; -extern dmnsn_py_Color dmnsn_py_Orange; -extern dmnsn_py_Color dmnsn_py_Yellow; -extern dmnsn_py_Color dmnsn_py_Cyan; diff --git a/libdimension-python/Makefile.am b/libdimension-python/Makefile.am index 9919a1a..c1f5274 100644 --- a/libdimension-python/Makefile.am +++ b/libdimension-python/Makefile.am @@ -1,5 +1,5 @@ ########################################################################### -## Copyright (C) 2009-2011 Tavian Barnes ## +## Copyright (C) 2011 Tavian Barnes ## ## ## ## This file is part of The Dimension Build Suite. ## ## ## @@ -25,26 +25,13 @@ INCLUDES = -I$(top_srcdir)/libdimension AM_CFLAGS = $(Python_CFLAGS) AM_LDFLAGS = $(Python_LDFLAGS) +dimension.c: dimension.pyx dimension.pxd + cython --line-directives dimension.pyx + pyexec_LTLIBRARIES = dimension.la -dimension_la_SOURCES = Camera.c \ - Camera.h \ - Canvas.c \ - Canvas.h \ - Color.c \ - Color.h \ - Matrix.c \ - Matrix.h \ - Object.c \ - Object.h \ - PerspectiveCamera.c \ - PerspectiveCamera.h \ - Scene.c \ - Scene.h \ - Sphere.c \ - Sphere.h \ - Vector.c \ - Vector.h \ - dimension.c \ - dimension-python.h +dimension_la_SOURCES = dimension.c dimension_la_LDFLAGS = -avoid-version -module dimension_la_LIBADD = $(top_builddir)/libdimension/libdimension.la + +EXTRA_DIST = dimension.pyx \ + dimension.pxd diff --git a/libdimension-python/Matrix.c b/libdimension-python/Matrix.c deleted file mode 100644 index 0219965..0000000 --- a/libdimension-python/Matrix.c +++ /dev/null @@ -1,292 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Matrix_init(dmnsn_py_Matrix *self, PyObject *args, PyObject *kwds) -{ - if (kwds) { - PyErr_SetString(PyExc_TypeError, "Keyword arguments not supported"); - return -1; - } - - if (!PyArg_ParseTuple(args, "dddddddddddd", - &self->m.n[0][0], &self->m.n[0][1], &self->m.n[0][2], - &self->m.n[0][3], - &self->m.n[1][0], &self->m.n[1][1], &self->m.n[1][2], - &self->m.n[1][3], - &self->m.n[2][0], &self->m.n[2][1], &self->m.n[2][2], - &self->m.n[2][3])) - return -1; - - return 0; -} - -PyObject * -dmnsn_py_Matrix_scale(PyObject *self, PyObject *args) -{ - dmnsn_vector scale; - if (!PyArg_ParseTuple(args, "O&", dmnsn_py_VectorParse, &scale)) - return NULL; - - dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); - if (ret) { - ret->m = dmnsn_scale_matrix(scale); - } - return (PyObject *)ret; -} - -PyObject * -dmnsn_py_Matrix_translate(PyObject *self, PyObject *args) -{ - dmnsn_vector translate; - if (!PyArg_ParseTuple(args, "O&", dmnsn_py_VectorParse, &translate)) - return NULL; - - dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); - if (ret) { - ret->m = dmnsn_translation_matrix(translate); - } - return (PyObject *)ret; -} - -PyObject * -dmnsn_py_Matrix_rotate(PyObject *self, PyObject *args) -{ - dmnsn_vector rotate; - if (!PyArg_ParseTuple(args, "O&", dmnsn_py_VectorParse, &rotate)) - return NULL; - - dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); - if (ret) { - ret->m = dmnsn_rotation_matrix(dmnsn_vector_mul(dmnsn_radians(1.0), - rotate)); - } - return (PyObject *)ret; -} - -static PyObject * -dmnsn_py_Matrix_repr(dmnsn_py_Matrix *self) -{ - PyObject *floats[3][4] = { { NULL } }; - bool initialized = true; - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - floats[i][j] = PyFloat_FromDouble(self->m.n[i][j]); - if (!floats[i][j]) { - initialized = false; - break; - } - } - if (!initialized) - break; - } - - if (!initialized) { - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - Py_XDECREF(floats[i][j]); - } - } - return NULL; - } - - PyObject *repr = PyUnicode_FromFormat("dimension.Matrix(%R, %R, %R, %R, " - "%R, %R, %R, %R, " - "%R, %R, %R, %R)", - floats[0][0], floats[0][1], - floats[0][2], floats[0][3], - floats[1][0], floats[1][1], - floats[1][2], floats[1][3], - floats[2][0], floats[2][1], - floats[2][2], floats[2][3]); - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - Py_DECREF(floats[i][j]); - } - } - return repr; -} - -static PyObject * -dmnsn_py_Matrix_str(dmnsn_py_Matrix *self) -{ - PyObject *floats[3][4] = { { NULL } }; - bool initialized = true; - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - floats[i][j] = PyFloat_FromDouble(self->m.n[i][j]); - if (!floats[i][j]) { - initialized = false; - break; - } - } - if (!initialized) - break; - } - - if (!initialized) { - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - Py_XDECREF(floats[i][j]); - } - } - return NULL; - } - - PyObject *str = PyUnicode_FromFormat("\n[%S\t%S\t%S\t%S]\n" - "[%S\t%S\t%S\t%S]\n" - "[%S\t%S\t%S\t%S]\n" - "[0.0\t0.0\t0.0\t1.0]", - floats[0][0], floats[0][1], - floats[0][2], floats[0][3], - floats[1][0], floats[1][1], - floats[1][2], floats[1][3], - floats[2][0], floats[2][1], - floats[2][2], floats[2][3]); - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - Py_DECREF(floats[i][j]); - } - } - return str; -} - -static PyObject * -dmnsn_py_Matrix_richcompare(PyObject *lhs, PyObject *rhs, int op) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_MatrixType) - || !PyObject_TypeCheck(rhs, &dmnsn_py_MatrixType)) - { - PyErr_SetString(PyExc_TypeError, - "Matricies can only be compared with Matricies"); - return NULL; - } - - dmnsn_py_Matrix *mlhs = (dmnsn_py_Matrix *)lhs; - dmnsn_py_Matrix *mrhs = (dmnsn_py_Matrix *)rhs; - - double sqdiff = 0.0; - for (size_t i = 0; i < 3; ++i) { - for (size_t j = 0; j < 4; ++j) { - double diff = mlhs->m.n[i][j] - mrhs->m.n[i][j]; - sqdiff += diff*diff; - } - } - - bool equal = sqrt(sqdiff) < dmnsn_epsilon; - - PyObject *result; - switch (op) { - case Py_EQ: - result = equal ? Py_True : Py_False; - break; - case Py_NE: - result = !equal ? Py_True : Py_False; - break; - default: - result = Py_NotImplemented; - break; - } - - Py_INCREF(result); - return result; -} - -static PyObject * -dmnsn_py_Matrix_mul(PyObject *lhs, PyObject *rhs) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_MatrixType)) { - PyErr_SetString(PyExc_TypeError, - "Left-hand side of matrix multiplication must be a matrix"); - return NULL; - } - - dmnsn_py_Matrix *mlhs = (dmnsn_py_Matrix *)lhs; - - if (PyObject_TypeCheck(rhs, &dmnsn_py_MatrixType)) { - dmnsn_py_Matrix *mrhs = (dmnsn_py_Matrix *)rhs; - dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); - if (ret) { - ret->m = dmnsn_matrix_mul(mlhs->m, mrhs->m); - } - return (PyObject *)ret; - } else if (PyObject_TypeCheck(rhs, &dmnsn_py_VectorType)) { - dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - ret->v = dmnsn_transform_vector(mlhs->m, vrhs->v); - } - return (PyObject *)ret; - } else { - PyErr_SetString(PyExc_TypeError, - "Right-hand side of matrix multiplication must be a matrix" - " or vector"); - return NULL; - } -} - -static PyNumberMethods dmnsn_py_Matrix_as_number = { - .nb_multiply = dmnsn_py_Matrix_mul, -}; - -static PyObject * -dmnsn_py_Matrix_inverse(dmnsn_py_Matrix *self) -{ - dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); - if (ret) { - ret->m = dmnsn_matrix_inverse(self->m); - } - return (PyObject *)ret; -} - -static PyMethodDef dmnsn_py_Matrix_methods[] = { - { "inverse", (PyCFunction)dmnsn_py_Matrix_inverse, METH_NOARGS, - "Return the inverse of the matrix" }, - { NULL } -}; - -static PyGetSetDef dmnsn_py_Matrix_getsetters[] = { - { NULL } -}; - -PyTypeObject dmnsn_py_MatrixType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Matrix", - .tp_basicsize = sizeof(dmnsn_py_Matrix), - .tp_repr = (reprfunc)dmnsn_py_Matrix_repr, - .tp_str = (reprfunc)dmnsn_py_Matrix_str, - .tp_as_number = &dmnsn_py_Matrix_as_number, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "Dimension matrix", - .tp_richcompare = dmnsn_py_Matrix_richcompare, - .tp_methods = dmnsn_py_Matrix_methods, - .tp_getset = dmnsn_py_Matrix_getsetters, - .tp_init = (initproc)dmnsn_py_Matrix_init, -}; - -bool -dmnsn_py_init_MatrixType(void) -{ - dmnsn_py_MatrixType.tp_new = PyType_GenericNew; - Py_INCREF(&dmnsn_py_MatrixType); - return PyType_Ready(&dmnsn_py_MatrixType) >= 0; -} diff --git a/libdimension-python/Matrix.h b/libdimension-python/Matrix.h deleted file mode 100644 index fa34da6..0000000 --- a/libdimension-python/Matrix.h +++ /dev/null @@ -1,33 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Matrix { - PyObject_HEAD - dmnsn_matrix m; -} dmnsn_py_Matrix; - -extern PyTypeObject dmnsn_py_MatrixType; - -bool dmnsn_py_init_MatrixType(void); - -/* Global methods */ -PyObject *dmnsn_py_Matrix_scale(PyObject *self, PyObject *args); -PyObject *dmnsn_py_Matrix_translate(PyObject *self, PyObject *args); -PyObject *dmnsn_py_Matrix_rotate(PyObject *self, PyObject *args); diff --git a/libdimension-python/Object.c b/libdimension-python/Object.c deleted file mode 100644 index b44ff1a..0000000 --- a/libdimension-python/Object.c +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Object_init(dmnsn_py_Object *self, PyObject *args, PyObject *kwds) -{ - if (kwds || (args && !PyArg_ParseTuple(args, ""))) - return -1; - - return 0; -} - -static void -dmnsn_py_Object_dealloc(dmnsn_py_Object *self) -{ - dmnsn_delete_object(self->object); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject * -dmnsn_py_Object_initialize(dmnsn_py_Object *self) -{ - PyErr_SetString(PyExc_TypeError, "Attempt to initialize base Object"); - return NULL; -} - -static PyObject * -dmnsn_py_Object_transform(dmnsn_py_Object *self, PyObject *args) -{ - dmnsn_py_Matrix *trans; - if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_MatrixType, &trans)) - return NULL; - - if (!self->object) { - PyErr_SetString(PyExc_TypeError, "Attempt to transform base Object"); - return NULL; - } - - self->object->trans = dmnsn_matrix_mul(trans->m, self->object->trans); - - Py_INCREF(self); - return (PyObject *)self; -} - -static PyMethodDef dmnsn_py_Object_methods[] = { - { "initialize", (PyCFunction)dmnsn_py_Object_initialize, METH_NOARGS, - "Initialize an object" }, - { "transform", (PyCFunction)dmnsn_py_Object_transform, METH_VARARGS, - "Transform an object" }, - { NULL } -}; - -static PyGetSetDef dmnsn_py_Object_getsetters[] = { - { NULL } -}; - -PyTypeObject dmnsn_py_ObjectType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Object", - .tp_basicsize = sizeof(dmnsn_py_Object), - .tp_dealloc = (destructor)dmnsn_py_Object_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = "Dimension object", - .tp_methods = dmnsn_py_Object_methods, - .tp_getset = dmnsn_py_Object_getsetters, - .tp_init = (initproc)dmnsn_py_Object_init, -}; - -bool -dmnsn_py_init_ObjectType(void) -{ - dmnsn_py_ObjectType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_ObjectType) >= 0; -} diff --git a/libdimension-python/Object.h b/libdimension-python/Object.h deleted file mode 100644 index 11b35f1..0000000 --- a/libdimension-python/Object.h +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Object { - PyObject_HEAD - dmnsn_object *object; -} dmnsn_py_Object; - -extern PyTypeObject dmnsn_py_ObjectType; - -bool dmnsn_py_init_ObjectType(void); diff --git a/libdimension-python/PerspectiveCamera.c b/libdimension-python/PerspectiveCamera.c deleted file mode 100644 index f144498..0000000 --- a/libdimension-python/PerspectiveCamera.c +++ /dev/null @@ -1,111 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_PerspectiveCamera_init(dmnsn_py_PerspectiveCamera *self, - PyObject *args, PyObject *kwds) -{ - if (dmnsn_py_CameraType.tp_init((PyObject *)self, NULL, NULL) < 0) - return -1; - - static char *kwlist[] = { "location", "look_at", NULL }; - - dmnsn_vector location, look_at; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&", kwlist, - &dmnsn_py_VectorParse, &location, - &dmnsn_py_VectorParse, &look_at)) - return -1; - - self->location = location; - self->look_at = look_at; - - dmnsn_delete_camera(self->base.camera); - self->base.camera = dmnsn_new_perspective_camera(); - DMNSN_INCREF(self->base.camera); - return 0; -} - -static PyObject * -dmnsn_py_PerspectiveCamera_initialize(dmnsn_py_PerspectiveCamera *self) -{ - dmnsn_vector look_at = dmnsn_vector_sub(self->look_at, self->location); - - /* Align the camera with the look_at point */ - - dmnsn_vector right = dmnsn_x; - dmnsn_vector up = dmnsn_y; - dmnsn_vector forward = dmnsn_z; - - dmnsn_vector theta = dmnsn_vector_mul( - dmnsn_vector_axis_angle(forward, look_at, up), - up - ); - dmnsn_matrix align = dmnsn_rotation_matrix(theta); - - right = dmnsn_transform_vector(align, right); - forward = dmnsn_transform_vector(align, forward); - - theta = dmnsn_vector_mul( - dmnsn_vector_axis_angle(forward, look_at, right), - right - ); - align = dmnsn_matrix_mul(dmnsn_rotation_matrix(theta), align); - - /* Translate the camera to the location */ - dmnsn_matrix move = dmnsn_translation_matrix(self->location); - - dmnsn_matrix trans = dmnsn_matrix_mul(move, align); - self->base.camera->trans = dmnsn_matrix_mul(self->base.camera->trans, - trans); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef dmnsn_py_PerspectiveCamera_methods[] = { - { "initialize", (PyCFunction)dmnsn_py_PerspectiveCamera_initialize, - METH_NOARGS, "Initialize a perspective camera" }, - { NULL } -}; - -static PyGetSetDef dmnsn_py_PerspectiveCamera_getsetters[] = { - { NULL } -}; - -PyTypeObject dmnsn_py_PerspectiveCameraType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.PerspectiveCamera", - .tp_basicsize = sizeof(dmnsn_py_PerspectiveCamera), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = "Dimension perspective camera", - .tp_methods = dmnsn_py_PerspectiveCamera_methods, - .tp_getset = dmnsn_py_PerspectiveCamera_getsetters, - .tp_init = (initproc)dmnsn_py_PerspectiveCamera_init, - .tp_base = &dmnsn_py_CameraType, -}; - -bool -dmnsn_py_init_PerspectiveCameraType(void) -{ - dmnsn_py_PerspectiveCameraType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_PerspectiveCameraType) >= 0; -} diff --git a/libdimension-python/PerspectiveCamera.h b/libdimension-python/PerspectiveCamera.h deleted file mode 100644 index e6696e6..0000000 --- a/libdimension-python/PerspectiveCamera.h +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_PerspectiveCamera { - dmnsn_py_Camera base; - dmnsn_vector location, look_at; -} dmnsn_py_PerspectiveCamera; - -extern PyTypeObject dmnsn_py_PerspectiveCameraType; - -bool dmnsn_py_init_PerspectiveCameraType(void); diff --git a/libdimension-python/Scene.c b/libdimension-python/Scene.c deleted file mode 100644 index 0e43ec9..0000000 --- a/libdimension-python/Scene.c +++ /dev/null @@ -1,117 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Scene_init(dmnsn_py_Scene *self, PyObject *args, PyObject *kwds) -{ - dmnsn_delete_scene(self->scene); - self->scene = dmnsn_new_scene(); - - static char *kwlist[] = { "canvas", "camera", "objects", NULL }; - - dmnsn_py_Canvas *canvas; - dmnsn_py_Camera *camera; - PyObject *objects; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!O!", kwlist, - &dmnsn_py_CanvasType, &canvas, - &dmnsn_py_CameraType, &camera, - &PyList_Type, &objects)) - return -1; - - dmnsn_scene_set_canvas(self->scene, canvas->canvas); - - if (!PyObject_CallMethod((PyObject *)camera, "initialize", "")) - return -1; - - /* Account for image proportions in camera */ - dmnsn_matrix stretch = dmnsn_scale_matrix( - dmnsn_new_vector( - (double)canvas->canvas->width/canvas->canvas->height, - 1.0, - 1.0 - ) - ); - camera->camera->trans = dmnsn_matrix_mul(camera->camera->trans, stretch); - dmnsn_scene_set_camera(self->scene, camera->camera); - self->scene->background = dmnsn_white; - - Py_ssize_t size = PyList_Size(objects); - for (Py_ssize_t i = 0; i < size; ++i) { - PyObject *obj = PyList_GetItem(objects, i); - if (!PyObject_TypeCheck(obj, &dmnsn_py_ObjectType)) { - PyErr_SetString(PyExc_TypeError, "Expected a list of objects"); - return -1; - } - - if (!PyObject_CallMethod(obj, "initialize", "")) - return -1; - - dmnsn_py_Object *object = (dmnsn_py_Object *)obj; - dmnsn_scene_add_object(self->scene, object->object); - } - - return 0; -} - -static void -dmnsn_py_Scene_dealloc(dmnsn_py_Scene *self) -{ - dmnsn_delete_scene(self->scene); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject * -dmnsn_py_Scene_raytrace(dmnsn_py_Scene *self) -{ - dmnsn_raytrace_scene(self->scene); - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef dmnsn_py_Scene_methods[] = { - { "raytrace", (PyCFunction)dmnsn_py_Scene_raytrace, METH_NOARGS, - "Raytrace a scene" }, - { NULL } -}; - -static PyGetSetDef dmnsn_py_Scene_getsetters[] = { - { NULL } -}; - -PyTypeObject dmnsn_py_SceneType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Scene", - .tp_basicsize = sizeof(dmnsn_py_Scene), - .tp_dealloc = (destructor)dmnsn_py_Scene_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "Dimension scene", - .tp_methods = dmnsn_py_Scene_methods, - .tp_getset = dmnsn_py_Scene_getsetters, - .tp_init = (initproc)dmnsn_py_Scene_init, -}; - -bool -dmnsn_py_init_SceneType(void) -{ - dmnsn_py_SceneType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_SceneType) >= 0; -} diff --git a/libdimension-python/Scene.h b/libdimension-python/Scene.h deleted file mode 100644 index bf69326..0000000 --- a/libdimension-python/Scene.h +++ /dev/null @@ -1,28 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Scene { - PyObject_HEAD - dmnsn_scene *scene; -} dmnsn_py_Scene; - -extern PyTypeObject dmnsn_py_SceneType; - -bool dmnsn_py_init_SceneType(void); diff --git a/libdimension-python/Sphere.c b/libdimension-python/Sphere.c deleted file mode 100644 index c6ec6a6..0000000 --- a/libdimension-python/Sphere.c +++ /dev/null @@ -1,90 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static int -dmnsn_py_Sphere_init(dmnsn_py_Sphere *self, PyObject *args, PyObject *kwds) -{ - if (dmnsn_py_ObjectType.tp_init((PyObject *)self, NULL, NULL) < 0) - return -1; - - static char *kwlist[] = { "radius", "center", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "dO&", kwlist, - &self->radius, - &dmnsn_py_VectorParse, &self->center)) - return -1; - - dmnsn_delete_object(self->base.object); - self->base.object = dmnsn_new_sphere(); - DMNSN_INCREF(self->base.object); - return 0; -} - -static PyObject * -dmnsn_py_Sphere_initialize(dmnsn_py_Sphere *self) -{ - dmnsn_matrix trans = dmnsn_scale_matrix( - dmnsn_new_vector(self->radius, self->radius, self->radius) - ); - trans = dmnsn_matrix_mul(dmnsn_translation_matrix(self->center), trans); - - dmnsn_object *object = self->base.object; - object->trans = dmnsn_matrix_mul(object->trans, trans); - - dmnsn_texture *texture = object->texture; - if (texture) { - dmnsn_matrix trans_inv = dmnsn_matrix_inverse(trans); - texture->trans = dmnsn_matrix_mul(trans_inv, texture->trans); - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef dmnsn_py_Sphere_methods[] = { - { "initialize", (PyCFunction)dmnsn_py_Sphere_initialize, METH_NOARGS, - "Initialize an sphere" }, - { NULL } -}; - -static PyGetSetDef dmnsn_py_Sphere_getsetters[] = { - { NULL } -}; - -PyTypeObject dmnsn_py_SphereType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Sphere", - .tp_basicsize = sizeof(dmnsn_py_Sphere), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = "Dimension sphere", - .tp_methods = dmnsn_py_Sphere_methods, - .tp_getset = dmnsn_py_Sphere_getsetters, - .tp_init = (initproc)dmnsn_py_Sphere_init, - .tp_base = &dmnsn_py_ObjectType, -}; - -bool -dmnsn_py_init_SphereType(void) -{ - dmnsn_py_SphereType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_SphereType) >= 0; -} diff --git a/libdimension-python/Sphere.h b/libdimension-python/Sphere.h deleted file mode 100644 index eccd1d0..0000000 --- a/libdimension-python/Sphere.h +++ /dev/null @@ -1,29 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Sphere { - dmnsn_py_Object base; - double radius; - dmnsn_vector center; -} dmnsn_py_Sphere; - -extern PyTypeObject dmnsn_py_SphereType; - -bool dmnsn_py_init_SphereType(void); diff --git a/libdimension-python/Vector.c b/libdimension-python/Vector.c deleted file mode 100644 index 67f3397..0000000 --- a/libdimension-python/Vector.c +++ /dev/null @@ -1,380 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -int -dmnsn_py_VectorParse(PyObject *object, void *ptr) -{ - dmnsn_vector *res = ptr; - if (PyObject_TypeCheck(object, &dmnsn_py_VectorType)) { - dmnsn_py_Vector *vec = (dmnsn_py_Vector *)object; - *res = vec->v; - return 1; - } else { - PyErr_Clear(); - if (PyArg_ParseTuple(object, "ddd", &res->x, &res->y, &res->z)) { - return 1; - } else { - PyErr_SetString(PyExc_TypeError, "expected a dimension.Vector"); - return 0; - } - } -} - -static int -dmnsn_py_Vector_init(dmnsn_py_Vector *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = { "x", "y", "z", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ddd", kwlist, - &self->v.x, &self->v.y, &self->v.z)) - return -1; - - return 0; -} - -static PyObject * -dmnsn_py_Vector_repr(dmnsn_py_Vector *self) -{ - PyObject *x = PyFloat_FromDouble(self->v.x); - PyObject *y = PyFloat_FromDouble(self->v.y); - PyObject *z = PyFloat_FromDouble(self->v.z); - - if (!x || !y || !x) { - Py_XDECREF(z); - Py_XDECREF(y); - Py_XDECREF(x); - return NULL; - } - - PyObject *repr = PyUnicode_FromFormat("dimension.Vector(%R, %R, %R)", - x, y, z); - Py_DECREF(z); - Py_DECREF(y); - Py_DECREF(x); - return repr; -} - -static PyObject * -dmnsn_py_Vector_str(dmnsn_py_Vector *self) -{ - PyObject *x = PyFloat_FromDouble(self->v.x); - PyObject *y = PyFloat_FromDouble(self->v.y); - PyObject *z = PyFloat_FromDouble(self->v.z); - - if (!x || !y || !x) { - Py_XDECREF(z); - Py_XDECREF(y); - Py_XDECREF(x); - return NULL; - } - - PyObject *str = PyUnicode_FromFormat("<%S, %S, %S>", x, y, z); - Py_DECREF(z); - Py_DECREF(y); - Py_DECREF(x); - return str; -} - -static PyObject * -dmnsn_py_Vector_richcompare(PyObject *lhs, PyObject *rhs, int op) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType) - || !PyObject_TypeCheck(rhs, &dmnsn_py_VectorType)) - { - PyErr_SetString(PyExc_TypeError, - "Vectors can only be compared with Vectors"); - return NULL; - } - - dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; - dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; - - bool equal = - dmnsn_vector_norm(dmnsn_vector_sub(vlhs->v, vrhs->v)) < dmnsn_epsilon; - - PyObject *result; - switch (op) { - case Py_EQ: - result = equal ? Py_True : Py_False; - break; - case Py_NE: - result = !equal ? Py_True : Py_False; - break; - default: - result = Py_NotImplemented; - break; - } - - Py_INCREF(result); - return result; -} - -static PyObject * -dmnsn_py_Vector_add(PyObject *lhs, PyObject *rhs) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType) - || !PyObject_TypeCheck(rhs, &dmnsn_py_VectorType)) - { - PyErr_SetString(PyExc_TypeError, - "Vectors can only be added to Vectors"); - return NULL; - } - - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; - dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; - ret->v = dmnsn_vector_add(vlhs->v, vrhs->v); - } - return (PyObject *)ret; -} - -static PyObject * -dmnsn_py_Vector_sub(PyObject *lhs, PyObject *rhs) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType) - || !PyObject_TypeCheck(rhs, &dmnsn_py_VectorType)) - { - PyErr_SetString(PyExc_TypeError, - "Vectors can only be subtracted from Vectors"); - return NULL; - } - - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; - dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; - ret->v = dmnsn_vector_sub(vlhs->v, vrhs->v); - } - return (PyObject *)ret; -} - -static PyObject * -dmnsn_py_Vector_mul(PyObject *lhs, PyObject *rhs) -{ - dmnsn_py_Vector *vec; - double dbl; - - if (PyObject_TypeCheck(lhs, &dmnsn_py_VectorType)) { - vec = (dmnsn_py_Vector *)lhs; - dbl = PyFloat_AsDouble(rhs); - if (PyErr_Occurred()) - return NULL; - } else { - vec = (dmnsn_py_Vector *)rhs; - dbl = PyFloat_AsDouble(lhs); - if (PyErr_Occurred()) - return NULL; - } - - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - ret->v = dmnsn_vector_mul(dbl, vec->v); - } - return (PyObject *)ret; -} - -static PyObject * -dmnsn_py_Vector_div(PyObject *lhs, PyObject *rhs) -{ - if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType)) { - PyErr_SetString(PyExc_TypeError, - "Vectors can only be divided by scalars"); - return NULL; - } - - double drhs = PyFloat_AsDouble(rhs); - if (PyErr_Occurred()) - return NULL; - - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; - ret->v = dmnsn_vector_div(vlhs->v, drhs); - } - return (PyObject *)ret; -} - -static int -dmnsn_py_Vector_bool(PyObject *obj) -{ - dmnsn_py_Vector *vec = (dmnsn_py_Vector *)obj; - return dmnsn_vector_norm(vec->v) >= dmnsn_epsilon; -} - -static PyObject * -dmnsn_py_Vector_positive(PyObject *rhs) -{ - Py_INCREF(rhs); - return rhs; -} - -static PyObject * -dmnsn_py_Vector_negative(PyObject *rhs) -{ - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; - ret->v = dmnsn_vector_negate(vrhs->v); - } - return (PyObject *)ret; -} - -PyObject * -dmnsn_py_Vector_cross(PyObject *self, PyObject *args) -{ - dmnsn_vector lhs, rhs; - if (!PyArg_ParseTuple(args, "O&O&", - &dmnsn_py_VectorParse, &lhs, - &dmnsn_py_VectorParse, &rhs)) - return NULL; - - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - ret->v = dmnsn_vector_cross(lhs, rhs); - } - return (PyObject *)ret; -} - -PyObject * -dmnsn_py_Vector_dot(PyObject *self, PyObject *args) -{ - dmnsn_vector lhs, rhs; - if (!PyArg_ParseTuple(args, "O&O&", - &dmnsn_py_VectorParse, &lhs, - &dmnsn_py_VectorParse, &rhs)) - return NULL; - - return PyFloat_FromDouble(dmnsn_vector_dot(lhs, rhs)); -} - -PyObject * -dmnsn_py_Vector_proj(PyObject *self, PyObject *args) -{ - dmnsn_vector u, d; - if (!PyArg_ParseTuple(args, "O&O&", - &dmnsn_py_VectorParse, &u, - &dmnsn_py_VectorParse, &d)) - return NULL; - - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - ret->v = dmnsn_vector_proj(u, d); - } - return (PyObject *)ret; -} - -static PyNumberMethods dmnsn_py_Vector_as_number = { - .nb_add = dmnsn_py_Vector_add, - .nb_subtract = dmnsn_py_Vector_sub, - .nb_multiply = dmnsn_py_Vector_mul, - .nb_true_divide = dmnsn_py_Vector_div, - .nb_bool = dmnsn_py_Vector_bool, - .nb_positive = dmnsn_py_Vector_positive, - .nb_negative = dmnsn_py_Vector_negative, -}; - -static PyObject * -dmnsn_py_Vector_norm(dmnsn_py_Vector *self) -{ - return PyFloat_FromDouble(dmnsn_vector_norm(self->v)); -} - -static PyObject * -dmnsn_py_Vector_normalized(dmnsn_py_Vector *self) -{ - dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); - if (ret) { - ret->v = dmnsn_vector_normalized(self->v); - } - return (PyObject *)ret; -} - -static PyMethodDef dmnsn_py_Vector_methods[] = { - { "norm", (PyCFunction)dmnsn_py_Vector_norm, METH_NOARGS, - "Return the magnitude of the vector" }, - { "normalized", (PyCFunction)dmnsn_py_Vector_normalized, METH_NOARGS, - "Return the magnitude of the vector" }, - { NULL } -}; - -static PyObject * -dmnsn_py_Vector_get_x(dmnsn_py_Vector *self, void *closure) -{ - return PyFloat_FromDouble(self->v.x); -} - -static PyObject * -dmnsn_py_Vector_get_y(dmnsn_py_Vector *self, void *closure) -{ - return PyFloat_FromDouble(self->v.y); -} - -static PyObject * -dmnsn_py_Vector_get_z(dmnsn_py_Vector *self, void *closure) -{ - return PyFloat_FromDouble(self->v.z); -} - -static PyGetSetDef dmnsn_py_Vector_getsetters[] = { - { "x", (getter)dmnsn_py_Vector_get_x, NULL, "x coordinate", NULL }, - { "y", (getter)dmnsn_py_Vector_get_y, NULL, "y coordinate", NULL }, - { "z", (getter)dmnsn_py_Vector_get_z, NULL, "z coordinate", NULL }, - { NULL } -}; - -PyTypeObject dmnsn_py_VectorType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "dimension.Vector", - .tp_basicsize = sizeof(dmnsn_py_Vector), - .tp_repr = (reprfunc)dmnsn_py_Vector_repr, - .tp_str = (reprfunc)dmnsn_py_Vector_str, - .tp_as_number = &dmnsn_py_Vector_as_number, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "Dimension vector", - .tp_richcompare = dmnsn_py_Vector_richcompare, - .tp_methods = dmnsn_py_Vector_methods, - .tp_getset = dmnsn_py_Vector_getsetters, - .tp_init = (initproc)dmnsn_py_Vector_init, -}; - -#define dmnsn_py_Vector_global(name) \ - dmnsn_py_Vector name = { \ - PyObject_HEAD_INIT(&dmnsn_py_VectorType) \ - }; - -dmnsn_py_Vector_global(dmnsn_py_Zero); -dmnsn_py_Vector_global(dmnsn_py_X); -dmnsn_py_Vector_global(dmnsn_py_Y); -dmnsn_py_Vector_global(dmnsn_py_Z); - -bool -dmnsn_py_init_VectorType(void) -{ - dmnsn_py_Zero.v = dmnsn_zero; - dmnsn_py_X.v = dmnsn_x; - dmnsn_py_Y.v = dmnsn_y; - dmnsn_py_Z.v = dmnsn_z; - - dmnsn_py_VectorType.tp_new = PyType_GenericNew; - return PyType_Ready(&dmnsn_py_VectorType) >= 0; -} diff --git a/libdimension-python/Vector.h b/libdimension-python/Vector.h deleted file mode 100644 index 89357f2..0000000 --- a/libdimension-python/Vector.h +++ /dev/null @@ -1,40 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct dmnsn_py_Vector { - PyObject_HEAD - dmnsn_vector v; -} dmnsn_py_Vector; - -extern PyTypeObject dmnsn_py_VectorType; - -int dmnsn_py_VectorParse(PyObject *object, void *ptr); -bool dmnsn_py_init_VectorType(void); - -/* Global methods */ -PyObject *dmnsn_py_Vector_cross(PyObject *self, PyObject *args); -PyObject *dmnsn_py_Vector_dot(PyObject *self, PyObject *args); -PyObject *dmnsn_py_Vector_proj(PyObject *self, PyObject *args); - -/* Vector constants */ -extern dmnsn_py_Vector dmnsn_py_Zero; -extern dmnsn_py_Vector dmnsn_py_X; -extern dmnsn_py_Vector dmnsn_py_Y; -extern dmnsn_py_Vector dmnsn_py_Z; diff --git a/libdimension-python/dimension-python.h b/libdimension-python/dimension-python.h deleted file mode 100644 index 41f08c2..0000000 --- a/libdimension-python/dimension-python.h +++ /dev/null @@ -1,37 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#ifndef DMNSN_PYTHON_H -#define DMNSN_PYTHON_H - -#define PY_SSIZE_T_CLEAN -#include -#include "dimension.h" -#include "Vector.h" -#include "Matrix.h" -#include "Color.h" -#include "Canvas.h" -#include "Camera.h" -#include "PerspectiveCamera.h" -#include "Object.h" -#include "Sphere.h" -#include "Scene.h" - -#endif /* DMNSN_PYTHON_H */ diff --git a/libdimension-python/dimension.c b/libdimension-python/dimension.c deleted file mode 100644 index 0ebdab3..0000000 --- a/libdimension-python/dimension.c +++ /dev/null @@ -1,120 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-python.h" - -static PyObject * -dmnsn_py_dieOnWarnings(PyObject *self, PyObject *args) -{ - PyObject *obj; - if (!PyArg_ParseTuple(args, "O", &obj)) - return NULL; - - int istrue = PyObject_IsTrue(obj); - if (istrue == -1) - return NULL; - - dmnsn_die_on_warnings(istrue); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef DimensionMethods[] = { - { "dieOnWarnings", dmnsn_py_dieOnWarnings, METH_VARARGS, - "Turn Dimension warnings into fatal errors." }, - - { "cross", dmnsn_py_Vector_cross, METH_VARARGS, "Cross product." }, - { "dot", dmnsn_py_Vector_dot, METH_VARARGS, "Dot product." }, - { "proj", dmnsn_py_Vector_proj, METH_VARARGS, "Vector projection." }, - - { "scale", (PyCFunction)dmnsn_py_Matrix_scale, METH_VARARGS, - "Scaling." }, - { "translate", (PyCFunction)dmnsn_py_Matrix_translate, METH_VARARGS, - "Translation." }, - { "rotate", (PyCFunction)dmnsn_py_Matrix_rotate, METH_VARARGS, - "Rotation." }, - - { NULL, NULL, 0, NULL } -}; - -static struct PyModuleDef dimensionmodule = { - PyModuleDef_HEAD_INIT, - "dimension", - NULL, - -1, - DimensionMethods -}; - -PyMODINIT_FUNC -PyInit_dimension(void) -{ - if (!dmnsn_py_init_VectorType() - || !dmnsn_py_init_MatrixType() - || !dmnsn_py_init_ColorType() - || !dmnsn_py_init_CanvasType() - || !dmnsn_py_init_CameraType() - || !dmnsn_py_init_PerspectiveCameraType() - || !dmnsn_py_init_ObjectType() - || !dmnsn_py_init_SphereType() - || !dmnsn_py_init_SceneType()) - return NULL; - - PyObject *module = PyModule_Create(&dimensionmodule); - if (!module) - return NULL; - - PyModule_AddObject(module, "Vector", (PyObject *)&dmnsn_py_VectorType); - - /* Vector constants */ - PyModule_AddObject(module, "Zero", (PyObject *)&dmnsn_py_Zero); - PyModule_AddObject(module, "X", (PyObject *)&dmnsn_py_X); - PyModule_AddObject(module, "Y", (PyObject *)&dmnsn_py_Y); - PyModule_AddObject(module, "Z", (PyObject *)&dmnsn_py_Z); - - PyModule_AddObject(module, "Matrix", (PyObject *)&dmnsn_py_MatrixType); - - PyModule_AddObject(module, "Color", (PyObject *)&dmnsn_py_ColorType); - - /* Color constants */ - PyModule_AddObject(module, "Black", (PyObject *)&dmnsn_py_Black); - PyModule_AddObject(module, "White", (PyObject *)&dmnsn_py_White); - PyModule_AddObject(module, "Clear", (PyObject *)&dmnsn_py_Clear); - PyModule_AddObject(module, "Red", (PyObject *)&dmnsn_py_Red); - PyModule_AddObject(module, "Green", (PyObject *)&dmnsn_py_Green); - PyModule_AddObject(module, "Blue", (PyObject *)&dmnsn_py_Blue); - PyModule_AddObject(module, "Magenta", (PyObject *)&dmnsn_py_Magenta); - PyModule_AddObject(module, "Orange", (PyObject *)&dmnsn_py_Orange); - PyModule_AddObject(module, "Yellow", (PyObject *)&dmnsn_py_Yellow); - PyModule_AddObject(module, "Cyan", (PyObject *)&dmnsn_py_Cyan); - - PyModule_AddObject(module, "Canvas", (PyObject *)&dmnsn_py_CanvasType); - - PyModule_AddObject(module, "Camera", (PyObject *)&dmnsn_py_CanvasType); - PyModule_AddObject(module, "PerspectiveCamera", - (PyObject *)&dmnsn_py_PerspectiveCameraType); - - PyModule_AddObject(module, "Object", (PyObject *)&dmnsn_py_ObjectType); - PyModule_AddObject(module, "Sphere", (PyObject *)&dmnsn_py_SphereType); - - PyModule_AddObject(module, "Scene", (PyObject *)&dmnsn_py_SceneType); - - return module; -} diff --git a/libdimension-python/dimension.pxd b/libdimension-python/dimension.pxd new file mode 100644 index 0000000..cd28f24 --- /dev/null +++ b/libdimension-python/dimension.pxd @@ -0,0 +1,359 @@ +######################################################################### +# Copyright (C) 2011 Tavian Barnes # +# # +# This file is part of The Dimension Python Module. # +# # +# The Dimension Python Module is free software; you can redistribute it # +# and/or modify it under the terms of the GNU General Public License as # +# published by the Free Software Foundation; either version 3 of the # +# License, or (at your option) any later version. # +# # +# The Dimension Python Module is distributed in the hope that it will # +# be useful, but WITHOUT ANY WARRANTY; without even the implied # +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See # +# the GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +######################################################################### + +from cpython cimport bool +from libc.math cimport * +from libc.stdio cimport * + +cdef extern from "errno.h": + int errno + +cdef extern from "../libdimension/dimension.h": + + ########### + # Globals # + ########### + + ctypedef void dmnsn_callback_fn(void *ptr) + + void DMNSN_INCREF(void *) + + void dmnsn_die_on_warnings(bint always_die) + + double dmnsn_epsilon + + ########## + # Arrays # + ########## + + ctypedef struct dmnsn_array: + pass + + dmnsn_array *dmnsn_new_array(size_t objsize) + void dmnsn_delete_array(dmnsn_array *array) + + size_t dmnsn_array_size(dmnsn_array *array) + void dmnsn_array_resize(dmnsn_array *array, size_t length) + dmnsn_array *dmnsn_array_copy(dmnsn_array *array) + dmnsn_array *dmnsn_array_split(dmnsn_array *array) + void dmnsn_array_get(dmnsn_array *array, size_t i, void *obj) + void dmnsn_array_set(dmnsn_array *array, size_t i, void *obj) + void *dmnsn_array_first(dmnsn_array *array) + void *dmnsn_array_last(dmnsn_array *array) + void *dmnsn_array_at(dmnsn_array *array, size_t i) + void dmnsn_array_push(dmnsn_array *array, void *obj) + void dmnsn_array_pop(dmnsn_array *array, void *obj) + void dmnsn_array_insert(dmnsn_array *array, size_t i, void *obj) + void dmnsn_array_remove(dmnsn_array *array, size_t i) + void dmnsn_array_apply(dmnsn_array *array, dmnsn_callback_fn *callback) + + ############ + # Geometry # + ############ + + double dmnsn_radians(double degrees) + double dmnsn_degrees(double radians) + + ctypedef struct dmnsn_vector: + double x + double y + double z + + dmnsn_vector dmnsn_new_vector(double x, double y, double z) + + dmnsn_vector dmnsn_vector_negate(dmnsn_vector rhs) + + dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs) + dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs) + dmnsn_vector dmnsn_vector_mul(double lhs, dmnsn_vector rhs) + dmnsn_vector dmnsn_vector_div(dmnsn_vector lhs, double rhs) + + dmnsn_vector dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs) + double dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs) + dmnsn_vector dmnsn_vector_proj(dmnsn_vector u, dmnsn_vector d) + + double dmnsn_vector_norm(dmnsn_vector v) + dmnsn_vector dmnsn_vector_normalized(dmnsn_vector v) + + double dmnsn_vector_axis_angle(dmnsn_vector v1, dmnsn_vector v2, + dmnsn_vector axis) + + dmnsn_vector dmnsn_zero + dmnsn_vector dmnsn_x + dmnsn_vector dmnsn_y + dmnsn_vector dmnsn_z + + ctypedef struct dmnsn_matrix: + double n[3][4] + + dmnsn_matrix dmnsn_new_matrix(double a1, double a2, double a3, double a4, + double b1, double b2, double b3, double b4, + double c1, double c2, double c3, double c4) + + dmnsn_matrix dmnsn_matrix_inverse(dmnsn_matrix m) + + dmnsn_matrix dmnsn_matrix_mul(dmnsn_matrix lhs, dmnsn_matrix rhs) + dmnsn_vector dmnsn_transform_vector(dmnsn_matrix lhs, dmnsn_vector rhs) + + dmnsn_matrix dmnsn_scale_matrix(dmnsn_vector s) + dmnsn_matrix dmnsn_translation_matrix(dmnsn_vector d) + dmnsn_matrix dmnsn_rotation_matrix(dmnsn_vector theta) + + ########## + # Colors # + ########## + + ctypedef struct dmnsn_color: + double R + double G + double B + double trans + double filter + + dmnsn_color dmnsn_new_color(double R, double G, double B) + dmnsn_color dmnsn_new_color5(double R, double G, double B, + double trans, double filter) + + dmnsn_color dmnsn_color_from_sRGB(dmnsn_color color) + dmnsn_color dmnsn_color_to_sRGB(dmnsn_color color) + + double dmnsn_color_intensity(dmnsn_color color) + dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) + dmnsn_color dmnsn_color_mul(double n, dmnsn_color color) + + bint dmnsn_color_is_black(dmnsn_color color) + + dmnsn_color dmnsn_black + dmnsn_color dmnsn_white + dmnsn_color dmnsn_clear + dmnsn_color dmnsn_red + dmnsn_color dmnsn_green + dmnsn_color dmnsn_blue + dmnsn_color dmnsn_magenta + dmnsn_color dmnsn_orange + dmnsn_color dmnsn_yellow + dmnsn_color dmnsn_cyan + + ############ + # Canvases # + ############ + + ctypedef struct dmnsn_canvas: + size_t width + size_t height + + dmnsn_canvas *dmnsn_new_canvas(size_t width, size_t height) + void dmnsn_delete_canvas(dmnsn_canvas *canvas) + + void dmnsn_clear_canvas(dmnsn_canvas *canvas, dmnsn_color color) + + int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) + int dmnsn_png_write_canvas(dmnsn_canvas *canvas, FILE *file) + + int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) + int dmnsn_gl_write_canvas(dmnsn_canvas *canvas) + + ############ + # Patterns # + ############ + + ctypedef struct dmnsn_pattern: + dmnsn_matrix trans + + void dmnsn_delete_pattern(dmnsn_pattern *pattern) + + dmnsn_pattern *dmnsn_new_checker_pattern() + dmnsn_pattern *dmnsn_new_gradient_pattern(dmnsn_vector orientation) + + ######## + # Maps # + ######## + + ctypedef struct dmnsn_map: + pass + + void dmnsn_delete_map(dmnsn_map *map) + + void dmnsn_add_map_entry(dmnsn_map *map, double n, void *obj) + size_t dmnsn_map_size(dmnsn_map *map) + + dmnsn_map *dmnsn_new_color_map() + dmnsn_map *dmnsn_new_pigment_map() + + ############ + # Pigments # + ############ + + ctypedef struct dmnsn_pigment: + dmnsn_matrix trans + + ctypedef enum dmnsn_pigment_map_flags: + DMNSN_PIGMENT_MAP_REGULAR + DMNSN_PIGMENT_MAP_SRGB + + void dmnsn_delete_pigment(dmnsn_pigment *pigment) + + dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_color color) + dmnsn_pigment *dmnsn_new_canvas_pigment(dmnsn_canvas *canvas) + dmnsn_pigment *dmnsn_new_color_map_pigment(dmnsn_pattern *pattern, + dmnsn_map *map, + dmnsn_pigment_map_flags flags) + dmnsn_pigment *dmnsn_new_pigment_map_pigment(dmnsn_pattern *pattern, + dmnsn_map *map, + dmnsn_pigment_map_flags flags) + + ############ + # Finishes # + ############ + + ctypedef struct dmnsn_ambient + ctypedef struct dmnsn_diffuse + ctypedef struct dmnsn_specular + ctypedef struct dmnsn_reflection + + ctypedef struct dmnsn_finish: + dmnsn_ambient *ambient + dmnsn_diffuse *diffuse + dmnsn_specular *specular + dmnsn_reflection *reflection + + dmnsn_finish dmnsn_new_finish() + void dmnsn_delete_finish(dmnsn_finish finish) + + dmnsn_ambient *dmnsn_new_basic_ambient(dmnsn_color ambient) + dmnsn_diffuse *dmnsn_new_lambertian(double diffuse) + dmnsn_specular *dmnsn_new_phong(double specular, double exp) + dmnsn_reflection *dmnsn_new_basic_reflection(dmnsn_color min, dmnsn_color max, + double falloff) + + ############ + # Textures # + ############ + + ctypedef struct dmnsn_texture: + dmnsn_pigment *pigment + dmnsn_finish finish + dmnsn_matrix trans + + dmnsn_texture *dmnsn_new_texture() + void dmnsn_delete_texture(dmnsn_texture *texture) + + void dmnsn_texture_cascade(dmnsn_texture *default_texture, + dmnsn_texture **texture) + + ############# + # Interiors # + ############# + + ctypedef struct dmnsn_interior: + double ior + + dmnsn_interior *dmnsn_new_interior() + void dmnsn_delete_interior(dmnsn_interior *interior) + + ########### + # Objects # + ########### + + ctypedef struct dmnsn_object: + dmnsn_texture *texture + dmnsn_interior *interior + dmnsn_matrix trans + + dmnsn_object *dmnsn_new_object() + void dmnsn_delete_object(dmnsn_object *object) + + dmnsn_object *dmnsn_new_plane(dmnsn_vector normal) + dmnsn_object *dmnsn_new_sphere() + dmnsn_object *dmnsn_new_cube() + dmnsn_object *dmnsn_new_cone(double r1, double r2, bint open) + dmnsn_object *dmnsn_new_torus(double major, double minor) + + dmnsn_object *dmnsn_new_csg_union(dmnsn_array *objects) + dmnsn_object *dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B) + dmnsn_object *dmnsn_new_csg_difference(dmnsn_object *A, dmnsn_object *B) + dmnsn_object *dmnsn_new_csg_merge(dmnsn_object *A, dmnsn_object *B) + + ########## + # Lights # + ########## + + ctypedef struct dmnsn_light + + dmnsn_light *dmnsn_new_light() + void dmnsn_delete_light(dmnsn_light *light) + + dmnsn_light *dmnsn_new_point_light(dmnsn_vector x0, dmnsn_color color) + + ########### + # Cameras # + ########### + + ctypedef struct dmnsn_camera: + dmnsn_matrix trans + + dmnsn_camera *dmnsn_new_camera() + void dmnsn_delete_camera(dmnsn_camera *camera) + + dmnsn_camera *dmnsn_new_perspective_camera() + + ############### + # Sky Spheres # + ############### + + ctypedef struct dmnsn_sky_sphere: + dmnsn_array *pigments + dmnsn_matrix trans + + dmnsn_sky_sphere *dmnsn_new_sky_sphere() + void dmnsn_delete_sky_sphere(dmnsn_sky_sphere *sky_sphere) + + ########## + # Scenes # + ########## + + ctypedef enum dmnsn_quality: + DMNSN_RENDER_NONE + DMNSN_RENDER_PIGMENT + DMNSN_RENDER_LIGHTS + DMNSN_RENDER_FINISH + DMNSN_RENDER_TRANSLUCENCY + DMNSN_RENDER_REFLECTION + DMNSN_RENDER_FULL + + ctypedef struct dmnsn_scene: + dmnsn_color background + dmnsn_sky_sphere *sky_sphere + dmnsn_texture *default_texture + dmnsn_interior *default_interior + + dmnsn_array *objects + dmnsn_array *lights + dmnsn_camera *camera + dmnsn_canvas *canvas + + dmnsn_quality quality + unsigned int reclimit + double adc_bailout + unsigned int nthreads + + dmnsn_scene *dmnsn_new_scene() + void dmnsn_delete_scene(dmnsn_scene *scene) + + void dmnsn_raytrace_scene(dmnsn_scene *scene) diff --git a/libdimension-python/dimension.pyx b/libdimension-python/dimension.pyx new file mode 100644 index 0000000..9a5fd80 --- /dev/null +++ b/libdimension-python/dimension.pyx @@ -0,0 +1,910 @@ +######################################################################### +# Copyright (C) 2011 Tavian Barnes # +# # +# This file is part of The Dimension Python Module. # +# # +# The Dimension Python Module is free software; you can redistribute it # +# and/or modify it under the terms of the GNU General Public License as # +# published by the Free Software Foundation; either version 3 of the # +# License, or (at your option) any later version. # +# # +# The Dimension Python Module is distributed in the hope that it will # +# be useful, but WITHOUT ANY WARRANTY; without even the implied # +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See # +# the GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +######################################################################### + +import os + +########### +# Globals # +########### + +# Make warnings fatal +def dieOnWarnings(alwaysDie): + dmnsn_die_on_warnings(alwaysDie) + +############ +# Geometry # +############ + +cdef class Vector: + cdef dmnsn_vector _v + + def __init__(self, *args, **kwargs): + if len(args) == 1: + if (isinstance(args[0], Vector)): + self._v = (args[0])._v + elif (isinstance(args[0], tuple)): + self._realInit(*args[0]) + elif (args[0] == 0): + self._v = dmnsn_zero + else: + raise TypeError, 'expected a tuple or 0' + else: + self._realInit(*args, **kwargs) + + def _realInit(self, double x, double y, double z): + self._v = dmnsn_new_vector(x, y, z) + + property x: + def __get__(self): + return self._v.x + property y: + def __get__(self): + return self._v.y + property z: + def __get__(self): + return self._v.z + + def __pos__(self): + return self + def __neg__(self): + return _rawVector(dmnsn_vector_negate(self._v)) + def __nonzero__(self): + return dmnsn_vector_norm(self._v) >= dmnsn_epsilon + + def __add__(lhs, rhs): + return _rawVector(dmnsn_vector_add(Vector(lhs)._v, Vector(rhs)._v)) + def __sub__(lhs, rhs): + return _rawVector(dmnsn_vector_sub(Vector(lhs)._v, Vector(rhs)._v)) + def __mul__(lhs, rhs): + if (isinstance(lhs, Vector)): + return _rawVector(dmnsn_vector_mul(rhs, (lhs)._v)) + else: + return _rawVector(dmnsn_vector_mul(lhs, (rhs)._v)) + def __truediv__(Vector lhs not None, double rhs): + return _rawVector(dmnsn_vector_div(lhs._v, rhs)) + + def __richcmp__(lhs, rhs, int op): + equal = (Vector(lhs) - Vector(rhs)).norm() < dmnsn_epsilon + if (op == 2): # == + return equal + elif (op == 3): # != + return not equal + else: + return NotImplemented + + def norm(self): + return dmnsn_vector_norm(self._v) + def normalized(self): + return _rawVector(dmnsn_vector_normalized(self._v)) + + def __repr__(self): + return 'dimension.Vector(%r, %r, %r)' % (self.x, self.y, self.z) + + def __str__(self): + return '<%s, %s, %s>' % (self.x, self.y, self.z) + +cdef _rawVector(dmnsn_vector v): + cdef Vector self = Vector.__new__(Vector) + self._v = v + return self + +def cross(Vector lhs not None, Vector rhs not None): + return _rawVector(dmnsn_vector_cross(lhs._v, rhs._v)) +def dot(Vector lhs not None, Vector rhs not None): + return dmnsn_vector_dot(lhs._v, rhs._v) +def proj(Vector u not None, Vector d not None): + return _rawVector(dmnsn_vector_proj(u._v, d._v)) + +X = _rawVector(dmnsn_x) +Y = _rawVector(dmnsn_y) +Z = _rawVector(dmnsn_z) + +cdef class Matrix: + cdef dmnsn_matrix _m + + def __init__(self, + double a1, double a2, double a3, double a4, + double b1, double b2, double b3, double b4, + double c1, double c2, double c3, double c4): + self._m = dmnsn_new_matrix(a1, a2, a3, a4, + b1, b2, b3, b4, + c1, c2, c3, c4) + + def __nonzero__(self): + cdef double sum = 0.0 + for i in range(3): + for j in range(4): + sum += self._m.n[i][j] + return sqrt(sum) >= dmnsn_epsilon + + def __mul__(Matrix lhs not None, rhs): + if (isinstance(rhs, Matrix)): + return _rawMatrix(dmnsn_matrix_mul(lhs._m, (rhs)._m)) + else: + return _rawVector(dmnsn_transform_vector(lhs._m, (rhs)._v)) + + def __richcmp__(Matrix lhs not None, Matrix rhs not None, int op): + cdef double sum = 0.0 + for i in range(3): + for j in range(4): + diff = lhs._m.n[i][j] - rhs._m.n[i][j] + sum += diff*diff + equal = sqrt(sum) < dmnsn_epsilon + + if (op == 2): # == + return equal + elif (op == 3): # != + return not equal + else: + return NotImplemented + + cpdef Matrix inverse(self): + return _rawMatrix(dmnsn_matrix_inverse(self._m)); + + def __repr__(self): + return \ + 'dimension.Matrix(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \ + (self._m.n[0][0], self._m.n[0][1], self._m.n[0][2], self._m.n[0][3], + self._m.n[1][0], self._m.n[1][1], self._m.n[1][2], self._m.n[1][3], + self._m.n[2][0], self._m.n[2][1], self._m.n[2][2], self._m.n[2][3]) + + def __str__(self): + return \ + '\n[%s\t%s\t%s\t%s]' \ + '\n[%s\t%s\t%s\t%s]' \ + '\n[%s\t%s\t%s\t%s]' \ + '\n[%s\t%s\t%s\t%s]' %\ + (self._m.n[0][0], self._m.n[0][1], self._m.n[0][2], self._m.n[0][3], + self._m.n[1][0], self._m.n[1][1], self._m.n[1][2], self._m.n[1][3], + self._m.n[2][0], self._m.n[2][1], self._m.n[2][2], self._m.n[2][3], + 0.0, 0.0, 0.0, 1.0) + +cdef Matrix _rawMatrix(dmnsn_matrix m): + cdef Matrix self = Matrix.__new__(Matrix) + self._m = m + return self + +def scale(*args, **kwargs): + return _rawMatrix(dmnsn_scale_matrix(Vector(*args, **kwargs)._v)) +def translate(*args, **kwargs): + return _rawMatrix(dmnsn_translation_matrix(Vector(*args, **kwargs)._v)) +def rotate(*args, **kwargs): + cdef Vector rad = dmnsn_radians(1.0)*Vector(*args, **kwargs) + return _rawMatrix(dmnsn_rotation_matrix(rad._v)) +def _rawRotate(*args, **kwargs): + return _rawMatrix(dmnsn_rotation_matrix(Vector(*args, **kwargs)._v)) + +########## +# Colors # +########## + +cdef class Color: + cdef dmnsn_color _c + cdef dmnsn_color _sRGB + + def __init__(self, *args, **kwargs): + if len(args) == 1: + if (isinstance(args[0], Color)): + self._sRGB = (args[0])._sRGB + elif (isinstance(args[0], tuple)): + self._realInit(*args[0]) + else: + self._sRGB = dmnsn_color_mul(args[0], dmnsn_white) + else: + self._realInit(*args, **kwargs) + + self._c = dmnsn_color_from_sRGB(self._sRGB) + + def _realInit(self, double red, double green, double blue, + double trans = 0.0, double filter = 0.0): + self._sRGB = dmnsn_new_color5(red, green, blue, trans, filter) + + property red: + def __get__(self): + return self._sRGB.R + property green: + def __get__(self): + return self._sRGB.G + property blue: + def __get__(self): + return self._sRGB.B + property trans: + def __get__(self): + return self._sRGB.trans + property filter: + def __get__(self): + return self._sRGB.filter + + def __nonzero__(self): + return not dmnsn_color_is_black(self._c) + + def __add__(lhs, rhs): + return _rawsRGBColor(dmnsn_color_add(Color(lhs)._sRGB, Color(rhs)._sRGB)) + def __mul__(lhs, rhs): + if (isinstance(lhs, Color)): + return _rawsRGBColor(dmnsn_color_mul(rhs, (lhs)._sRGB)) + else: + return _rawsRGBColor(dmnsn_color_mul(lhs, (rhs)._sRGB)) + + def __richcmp__(lhs, rhs, int op): + cdef clhs = Color(lhs) + cdef crhs = Color(rhs) + + cdef double rdiff = clhs.red - crhs.red + cdef double gdiff = clhs.green - crhs.green + cdef double bdiff = clhs.blue - crhs.blue + cdef double tdiff = clhs.trans - crhs.trans + cdef double fdiff = clhs.filter - crhs.filter + cdef double sum = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff \ + + tdiff*tdiff + fdiff*fdiff + equal = sqrt(sum) < dmnsn_epsilon + if (op == 2): # == + return equal + elif (op == 3): # != + return not equal + else: + return NotImplemented + + def __repr__(self): + return 'dimension.Color(%r, %r, %r, %r, %r)' % \ + (self.red, self.green, self.blue, self.trans, self.filter) + + def __str__(self): + if (self.trans >= dmnsn_epsilon): + return '' % \ + (self.red, self.green, self.blue, self.trans, self.filter) + else: + return '' % \ + (self.red, self.green, self.blue) + +cdef _rawsRGBColor(dmnsn_color sRGB): + cdef Color self = Color.__new__(Color) + self._sRGB = sRGB + self._c = dmnsn_color_from_sRGB(sRGB) + return self + +cdef _rawColor(dmnsn_color c): + cdef Color self = Color.__new__(Color) + self._c = c + self._sRGB = dmnsn_color_to_sRGB(c) + return self + +Black = _rawColor(dmnsn_black) +White = _rawColor(dmnsn_white) +Clear = _rawColor(dmnsn_clear) +Red = _rawColor(dmnsn_red) +Green = _rawColor(dmnsn_green) +Blue = _rawColor(dmnsn_blue) +Magenta = _rawColor(dmnsn_magenta) +Orange = _rawColor(dmnsn_orange) +Yellow = _rawColor(dmnsn_yellow) +Cyan = _rawColor(dmnsn_cyan) + +############ +# Canvases # +############ + +cdef class Canvas: + cdef dmnsn_canvas *_canvas + + def __cinit__(self, size_t width, size_t height): + self._canvas = dmnsn_new_canvas(width, height) + + def __dealloc__(self): + dmnsn_delete_canvas(self._canvas) + + property width: + def __get__(self): + return self._canvas.width + property height: + def __get__(self): + return self._canvas.height + + def optimizePNG(self): + if dmnsn_png_optimize_canvas(self._canvas) != 0: + raise OSError(errno, os.strerror(errno)) + + def optimizeGL(self): + if dmnsn_gl_optimize_canvas(self._canvas) != 0: + raise OSError(errno, os.strerror(errno)) + + def clear(self, c): + dmnsn_clear_canvas(self._canvas, Color(c)._c) + + def writePNG(self, str path not None): + bpath = path.encode('UTF-8') + cdef char *cpath = bpath + cdef FILE *file = fopen(cpath, "wb") + if file == NULL: + raise OSError(errno, os.strerror(errno)) + + if dmnsn_png_write_canvas(self._canvas, file) != 0: + raise OSError(errno, os.strerror(errno)) + + def drawGL(self): + if dmnsn_gl_write_canvas(self._canvas) != 0: + raise OSError(errno, os.strerror(errno)) + +############ +# Patterns # +############ + +cdef class Pattern: + cdef dmnsn_pattern *_pattern + + def __cinit__(self): + self._pattern = NULL + + def __dealloc__(self): + dmnsn_delete_pattern(self._pattern) + + def transform(self, Matrix trans not None): + if self._pattern == NULL: + raise TypeError('attempt to transform base Pattern') + + self._pattern.trans = dmnsn_matrix_mul(trans._m, self._pattern.trans) + return self + +cdef class Checker(Pattern): + def __init__(self): + self._pattern = dmnsn_new_checker_pattern() + Pattern.__init__(self) + +cdef class Gradient(Pattern): + def __init__(self, orientation): + self._pattern = dmnsn_new_gradient_pattern(Vector(orientation)._v) + Pattern.__init__(self) + +############ +# Pigments # +############ + +cdef class Pigment: + cdef dmnsn_pigment *_pigment + + def __cinit__(self): + self._pigment = NULL + + def __init__(self, arg = None): + if arg is not None: + if (isinstance(arg, Pigment)): + self._pigment = (arg)._pigment + DMNSN_INCREF(self._pigment) + else: + self._pigment = dmnsn_new_solid_pigment(Color(arg)._c) + + def __dealloc__(self): + dmnsn_delete_pigment(self._pigment) + + def transform(self, Matrix trans not None): + if self._pigment == NULL: + raise TypeError('attempt to transform base Pigment') + + self._pigment.trans = dmnsn_matrix_mul(trans._m, self._pigment.trans) + return self + +cdef class ColorMap(Pigment): + def __init__(self, Pattern pattern not None, map, bool sRGB not None = True): + cdef dmnsn_map *color_map = dmnsn_new_color_map() + if hasattr(map, 'items'): + for i, color in map.items(): + dmnsn_add_map_entry(color_map, i, &Color(color)._c) + else: + for i, color in enumerate(map): + dmnsn_add_map_entry(color_map, i/len(map), &Color(color)._c) + + cdef dmnsn_pigment_map_flags flags + if sRGB: + flags = DMNSN_PIGMENT_MAP_SRGB + else: + flags = DMNSN_PIGMENT_MAP_REGULAR + + DMNSN_INCREF(pattern._pattern) + self._pigment = dmnsn_new_color_map_pigment(pattern._pattern, color_map, + flags) + Pigment.__init__(self) + +cdef class PigmentMap(Pigment): + def __init__(self, Pattern pattern not None, map, bool sRGB not None = True): + cdef dmnsn_map *pigment_map = dmnsn_new_pigment_map() + cdef dmnsn_pigment *realPigment + if hasattr(map, 'items'): + for i, pigment in map.items(): + pigment = Pigment(pigment) + realPigment = (pigment)._pigment + DMNSN_INCREF(realPigment) + dmnsn_add_map_entry(pigment_map, i, &realPigment) + else: + for i, pigment in enumerate(map): + pigment = Pigment(pigment) + realPigment = (pigment)._pigment + DMNSN_INCREF(realPigment) + dmnsn_add_map_entry(pigment_map, i/len(map), &realPigment) + + cdef dmnsn_pigment_map_flags flags + if sRGB: + flags = DMNSN_PIGMENT_MAP_SRGB + else: + flags = DMNSN_PIGMENT_MAP_REGULAR + + DMNSN_INCREF(pattern._pattern) + self._pigment = dmnsn_new_pigment_map_pigment(pattern._pattern, pigment_map, + flags) + Pigment.__init__(self) + +############ +# Finishes # +############ + +cdef class Finish: + cdef dmnsn_finish _finish + + def __cinit__(self): + self._finish = dmnsn_new_finish() + + def __dealloc__(self): + dmnsn_delete_finish(self._finish) + + def __add__(Finish lhs not None, Finish rhs not None): + cdef Finish ret = Finish() + + if lhs._finish.ambient != NULL and rhs._finish.ambient != NULL: + raise ValueError('both Finishes provide an ambient contribution') + elif lhs._finish.ambient != NULL: + ret._finish.ambient = lhs._finish.ambient + DMNSN_INCREF(ret._finish.ambient) + elif rhs._finish.ambient != NULL: + ret._finish.ambient = rhs._finish.ambient + DMNSN_INCREF(ret._finish.ambient) + + if lhs._finish.diffuse != NULL and rhs._finish.diffuse != NULL: + raise ValueError('both Finishes provide a diffuse contribution') + elif lhs._finish.diffuse != NULL: + ret._finish.diffuse = lhs._finish.diffuse + DMNSN_INCREF(ret._finish.diffuse) + elif rhs._finish.diffuse != NULL: + ret._finish.diffuse = rhs._finish.diffuse + DMNSN_INCREF(ret._finish.diffuse) + + if lhs._finish.specular != NULL and rhs._finish.specular != NULL: + raise ValueError('both Finishes provide a specular contribution') + elif lhs._finish.specular != NULL: + ret._finish.specular = lhs._finish.specular + DMNSN_INCREF(ret._finish.specular) + elif rhs._finish.specular != NULL: + ret._finish.specular = rhs._finish.specular + DMNSN_INCREF(ret._finish.specular) + + if lhs._finish.reflection != NULL and rhs._finish.reflection != NULL: + raise ValueError('both Finishes provide a reflection contribution') + elif lhs._finish.reflection != NULL: + ret._finish.reflection = lhs._finish.reflection + DMNSN_INCREF(ret._finish.reflection) + elif rhs._finish.reflection != NULL: + ret._finish.reflection = rhs._finish.reflection + DMNSN_INCREF(ret._finish.reflection) + + return ret + +cdef class Ambient(Finish): + def __init__(self, color): + self._finish.ambient = dmnsn_new_basic_ambient(Color(color)._c) + +cdef class Diffuse(Finish): + def __init__(self, double diffuse): + cdef dmnsn_color gray = dmnsn_color_mul(diffuse, dmnsn_white) + diffuse = dmnsn_color_intensity(dmnsn_color_from_sRGB(gray)) + self._finish.diffuse = dmnsn_new_lambertian(diffuse) + +cdef class Phong(Finish): + def __init__(self, double strength, double size = 40.0): + self._finish.specular = dmnsn_new_phong(strength, size) + +cdef class Reflection(Finish): + def __init__(self, min, max = None, double falloff = 1.0): + if max is None: + max = min + self._finish.reflection = dmnsn_new_basic_reflection(Color(min)._c, + Color(max)._c, + falloff) + +############ +# Textures # +############ + +cdef class Texture: + cdef dmnsn_texture *_texture + + def __init__(self, pigment = None, Finish finish = None): + self._texture = dmnsn_new_texture() + + cdef Pigment realPigment + if pigment is not None: + realPigment = Pigment(pigment) + self._texture.pigment = realPigment._pigment + DMNSN_INCREF(self._texture.pigment) + + if finish is not None: + self._texture.finish = finish._finish + if self._texture.finish.ambient != NULL: + DMNSN_INCREF(self._texture.finish.ambient) + if self._texture.finish.diffuse != NULL: + DMNSN_INCREF(self._texture.finish.diffuse) + if self._texture.finish.specular != NULL: + DMNSN_INCREF(self._texture.finish.specular) + if self._texture.finish.reflection != NULL: + DMNSN_INCREF(self._texture.finish.reflection) + + def __dealloc__(self): + dmnsn_delete_texture(self._texture) + +############# +# Interiors # +############# + +cdef class Interior: + cdef dmnsn_interior *_interior + + def __init__(self, double ior = 1.0): + self._interior = dmnsn_new_interior() + self._interior.ior = ior + + def __dealloc__(self): + dmnsn_delete_interior(self._interior) + +########### +# Objects # +########### + +cdef class Object: + cdef dmnsn_object *_object + + def __cinit__(self): + self._object = NULL + + def __init__(self, Texture texture = None, Interior interior = None): + if texture is not None: + self._object.texture = texture._texture + DMNSN_INCREF(self._object.texture) + if interior is not None: + self._object.interior = interior._interior + DMNSN_INCREF(self._object.interior) + + def __dealloc__(self): + dmnsn_delete_object(self._object) + + def transform(self, Matrix trans not None): + if self._object == NULL: + raise TypeError('attempt to transform base Object') + + self._object.trans = dmnsn_matrix_mul(trans._m, self._object.trans) + return self + + # Transform an object without affecting the texture + cdef _intrinsicTransform(self, Matrix trans): + self._object.trans = dmnsn_matrix_mul(self._object.trans, trans._m) + if self._object.texture != NULL: + self._object.texture.trans = dmnsn_matrix_mul(self._object.texture.trans, + trans.inverse()._m) + +cdef class Plane(Object): + def __init__(self, normal, double distance, *args, **kwargs): + self._object = dmnsn_new_plane(Vector(normal)._v) + Object.__init__(self, *args, **kwargs) + + self._intrinsicTransform(translate(distance*Vector(normal))) + +cdef class Sphere(Object): + def __init__(self, center, double radius, *args, **kwargs): + self._object = dmnsn_new_sphere() + Object.__init__(self, *args, **kwargs) + + cdef Matrix trans = translate(Vector(center)) + trans *= scale(radius, radius, radius) + self._intrinsicTransform(trans) + +cdef class Box(Object): + def __init__(self, min, max, *args, **kwargs): + self._object = dmnsn_new_cube() + Object.__init__(self, *args, **kwargs) + + min = Vector(min) + max = Vector(max) + cdef Matrix trans = translate((max + min)/2) + trans *= scale((max - min)/2) + self._intrinsicTransform(trans) + +cdef class Cone(Object): + def __init__(self, bottom, double bottomRadius, top, double topRadius, + bool open not None = False, *args, **kwargs): + self._object = dmnsn_new_cone(bottomRadius, topRadius, open) + Object.__init__(self, *args, **kwargs) + + # Lift the cone to start at the origin, then scale, rotate, and translate + # properly + + cdef Vector dir = Vector(top) - Vector(bottom) + + cdef Matrix trans = translate(Y) + trans = scale(1.0, dir.norm()/2, 1.0)*trans + + cdef double thetaX = dmnsn_vector_axis_angle(dmnsn_y, dir._v, dmnsn_x) + cdef double thetaZ = dmnsn_vector_axis_angle(dmnsn_y, dir._v, dmnsn_z) + trans = _rawRotate(thetaX*X)*_rawRotate(thetaZ*Z)*trans + + trans = translate(bottom)*trans + + self._intrinsicTransform(trans) + +cdef class Cylinder(Cone): + def __init__(self, bottom, top, double radius, bool open not None = False): + Cone.__init__(self, + bottom = bottom, bottomRadius = radius, + top = top, topRadius = radius, + open = open) + +cdef class Torus(Object): + def __init__(self, double majorRadius, double minorRadius, *args, **kwargs): + self._object = dmnsn_new_torus(majorRadius, minorRadius) + Object.__init__(self, *args, **kwargs) + +cdef class Union(Object): + def __init__(self, objects, *args, **kwargs): + if len(objects) < 2: + raise TypeError('expected a list of two or more Objects') + + cdef dmnsn_array *array = dmnsn_new_array(sizeof(dmnsn_object *)) + cdef dmnsn_object *o + + try: + for obj in objects: + o = (obj)._object + DMNSN_INCREF(o) + dmnsn_array_push(array, &o) + + self._object = dmnsn_new_csg_union(array) + finally: + dmnsn_delete_array(array) + + Object.__init__(self, *args, **kwargs) + +cdef class Intersection(Object): + def __init__(self, objects, *args, **kwargs): + if len(objects) < 2: + raise TypeError('expected a list of two or more Objects') + + cdef dmnsn_object *o + + for obj in objects: + if self._object == NULL: + self._object = (obj)._object + DMNSN_INCREF(self._object) + else: + o = (obj)._object + DMNSN_INCREF(o) + self._object = dmnsn_new_csg_intersection(self._object, o) + + Object.__init__(self, *args, **kwargs) + +cdef class Difference(Object): + def __init__(self, objects, *args, **kwargs): + if len(objects) < 2: + raise TypeError('expected a list of two or more Objects') + + cdef dmnsn_object *o + + for obj in objects: + if self._object == NULL: + self._object = (obj)._object + DMNSN_INCREF(self._object) + else: + o = (obj)._object + DMNSN_INCREF(o) + self._object = dmnsn_new_csg_difference(self._object, o) + + Object.__init__(self, *args, **kwargs) + +cdef class Merge(Object): + def __init__(self, objects, *args, **kwargs): + if len(objects) < 2: + raise TypeError('expected a list of two or more Objects') + + cdef dmnsn_object *o + + for obj in objects: + if self._object == NULL: + self._object = (obj)._object + DMNSN_INCREF(self._object) + else: + o = (obj)._object + DMNSN_INCREF(o) + self._object = dmnsn_new_csg_merge(self._object, o) + + Object.__init__(self, *args, **kwargs) + +########## +# Lights # +########## + +cdef class Light: + cdef dmnsn_light *_light + + def __dealloc__(self): + dmnsn_delete_light(self._light) + +cdef class PointLight(Light): + def __init__(self, location, color): + self._light = dmnsn_new_point_light(Vector(location)._v, Color(color)._c) + Light.__init__(self) + +########### +# Cameras # +########### + +cdef class Camera: + cdef dmnsn_camera *_camera + + def __cinit__(self): + self._camera = NULL + + def __dealloc__(self): + dmnsn_delete_camera(self._camera) + + def transform(self, Matrix trans not None): + if self._camera == NULL: + raise TypeError('attempt to transform base Camera') + + self._camera.trans = dmnsn_matrix_mul(trans._m, self._camera.trans) + return self + +cdef class PerspectiveCamera(Camera): + def __init__(self, location = -Z, lookAt = 0, sky = Y, + angle = dmnsn_degrees(atan(0.5))): + self._camera = dmnsn_new_perspective_camera() + Camera.__init__(self) + + # Apply the field of view angle + self.transform(scale(2*tan(dmnsn_radians(angle))*(X + Y) + Z)) + + cdef Vector dir = Vector(lookAt) - Vector(location) + cdef Vector vsky = Vector(sky) + + # Line up the top of the viewport with the sky vector + cdef double thetaSkyX = dmnsn_vector_axis_angle(dmnsn_y, vsky._v, dmnsn_x) + cdef double thetaSkyZ = dmnsn_vector_axis_angle(dmnsn_y, vsky._v, dmnsn_z) + cdef Matrix alignSky = _rawRotate(thetaSkyX*X)*_rawRotate(thetaSkyZ*Z) + self.transform(alignSky) + cdef Vector right = alignSky*X + cdef Vector forward = alignSky*Z + + # Line up the look at point with lookAt + cdef double thetaLookAtSky = dmnsn_vector_axis_angle( + forward._v, dir._v, vsky._v + ) + cdef double thetaLookAtRight = dmnsn_vector_axis_angle( + forward._v, dir._v, right._v + ) + self.transform(_rawRotate(thetaLookAtSky*vsky)) + self.transform(_rawRotate(thetaLookAtRight*right)) + + # Move the camera into position + self.transform(translate(Vector(location))) + +############### +# Sky Spheres # +############### + +cdef class SkySphere: + cdef dmnsn_sky_sphere *_skySphere + + def __init__(self, pigments): + self._skySphere = dmnsn_new_sky_sphere() + + cdef Pigment realPigment + for pigment in pigments: + realPigment = Pigment(pigment) + DMNSN_INCREF(realPigment._pigment) + dmnsn_array_push(self._skySphere.pigments, &realPigment._pigment) + + def __dealloc__(self): + dmnsn_delete_sky_sphere(self._skySphere) + + def transform(self, Matrix trans not None): + self._skySphere.trans = dmnsn_matrix_mul(trans._m, self._skySphere.trans) + return self + +########## +# Scenes # +########## + +cdef class Scene: + cdef dmnsn_scene *_scene + + def __init__(self, Canvas canvas not None, objects, lights, + Camera camera not None): + self._scene = dmnsn_new_scene() + + self._scene.canvas = canvas._canvas + DMNSN_INCREF(self._scene.canvas) + + cdef dmnsn_object *o + for obj in objects: + o = (obj)._object + DMNSN_INCREF(o) + dmnsn_array_push(self._scene.objects, &o) + + cdef dmnsn_light *l + for light in lights: + l = (light)._light + DMNSN_INCREF(l) + dmnsn_array_push(self._scene.lights, &l) + + # Account for image dimensions in the camera + camera._camera.trans = dmnsn_matrix_mul( + camera._camera.trans, + dmnsn_scale_matrix(dmnsn_new_vector(canvas.width/canvas.height, 1.0, 1.0)) + ) + self._scene.camera = camera._camera + DMNSN_INCREF(self._scene.camera) + + property defaultTexture: + def __set__(self, Texture texture not None): + dmnsn_delete_texture(self._scene.default_texture) + self._scene.default_texture = texture._texture + DMNSN_INCREF(self._scene.default_texture) + + property background: + def __get__(self): + return _rawColor(self._scene.background) + def __set__(self, color): + self._scene.background = Color(color)._c + + property skySphere: + def __set__(self, SkySphere skySphere not None): + dmnsn_delete_sky_sphere(self._scene.sky_sphere) + self._scene.sky_sphere = skySphere._skySphere + DMNSN_INCREF(self._scene.sky_sphere) + + property adcBailout: + def __get__(self): + return self._scene.adc_bailout + def __set__(self, double bailout): + self._scene.adc_bailout = bailout + + property recursionLimit: + def __get__(self): + return self._scene.reclimit + def __set__(self, level): + self._scene.reclimit = level + + property nThreads: + def __get__(self): + return self._scene.nthreads + def __set__(self, n): + self._scene.nthreads = n + + def raytrace(self): + # Ensure the default texture is complete + cdef Texture default = Texture(Black) + dmnsn_texture_cascade(default._texture, &self._scene.default_texture) + + dmnsn_raytrace_scene(self._scene) + + def __dealloc__(self): + dmnsn_delete_scene(self._scene) diff --git a/libdimension-python/tests/demo.py b/libdimension-python/tests/demo.py index fd4d193..4b68114 100755 --- a/libdimension-python/tests/demo.py +++ b/libdimension-python/tests/demo.py @@ -24,29 +24,145 @@ from dimension import * # Treat warnings as errors for tests dieOnWarnings(True) +# Canvas canvas = Canvas(width = 768, height = 480) havePNG = True try: - canvas.optimizePNG() + canvas.optimizePNG() except OSError as e: - if e.errno == errno.ENOSYS: - havePNG = False - else: - raise + if e.errno == errno.ENOSYS: + havePNG = False + else: + raise +# Camera camera = PerspectiveCamera(location = (0, 0.25, -4), - look_at = Zero) + lookAt = 0) camera.transform(rotate(53*Y)) +# Lights +lights = [ + PointLight(location = (-15, 20, 10), color = White), +] + +# Objects + +hollowCube = Difference( + [ + Box( + (-1, -1, -1), (1, 1, 1), + + texture = Texture( + pigment = Color(0, 0, 1, trans = 0.75, filter = 1/3), + finish = Reflection(0.5), + ), + interior = Interior( + ior = 1.1, + ), + ) + .transform(rotate(45*X)), + + Sphere( + center = 0, radius = 1.25, + texture = Texture( + pigment = Green, + finish = Phong(strength = 0.2, size = 40), + ), + ) + ], +) + +arrow = Union( + [ + Cylinder(bottom = -1.25*Y, top = 1.25*Y, radius = 0.1), + Cone( + bottom = 1.25*Y, bottomRadius = 0.1, + top = 1.5*Y, topRadius = 0, + open = True + ), + ], + texture = Texture( + pigment = ColorMap( + Gradient(Y), + { + 0/6: Red, + 1/6: Orange, + 2/6: Yellow, + 3/6: Green, + 4/6: Blue, + 5/6: Magenta, + 6/6: Red, + }, + ) + .transform(scale(1, 2.75, 1)) + .transform(translate(-1.25*Y)), + ), +) +arrow.transform(rotate(-45*X)) + +torii = Union( + [ + Torus(majorRadius = 0.15, minorRadius = 0.05) + .transform(translate(-Y)), + + Torus(majorRadius = 0.15, minorRadius = 0.05), + + Torus(majorRadius = 0.15, minorRadius = 0.05) + .transform(translate(Y)), + ], + texture = Texture( + pigment = Blue, + finish = Ambient(1), + ), +) +torii.transform(rotate(-45*X)) + +ground = Plane( + normal = Y, distance = -2, + + texture = Texture( + pigment = PigmentMap( + Checker(), + [ + White, + ColorMap(Checker(), [Black, White]).transform(scale(1/3, 1/3, 1/3)) + ], + ), + ), +) + objects = [ - Sphere(radius = 1, center = Zero) + hollowCube, + arrow, + torii, + ground, ] -scene = Scene(canvas = canvas, - camera = camera, - objects = objects) +# Sky sphere +skySphere = SkySphere( + [ + ColorMap( + pattern = Gradient(Y), + map = { + 0: Orange, + 0.35: Color(0, 0.1, 0.2, trans = 0.1, filter = 0.0), + }, + ), + ] +) + +# Scene +scene = Scene(canvas = canvas, + objects = objects, + lights = lights, + camera = camera) +scene.defaultTexture = Texture(finish = Ambient(0.1) + Diffuse(0.6)) +scene.background = Clear +scene.skySphere = skySphere +scene.adcBailout = 1/255 +scene.recursionLimit = 5 scene.raytrace() if havePNG: - canvas.writePNG('demo.png') + canvas.writePNG('demo.png') diff --git a/libdimension-python/tests/geometry.py b/libdimension-python/tests/geometry.py index 0c53ad6..c1d4f48 100755 --- a/libdimension-python/tests/geometry.py +++ b/libdimension-python/tests/geometry.py @@ -24,10 +24,13 @@ from dimension import * # Treat warnings as errors for tests dieOnWarnings(True) -assert Zero == Vector(0, 0, 0), Zero -assert X == Vector(1, 0, 0), X -assert Y == Vector(0, 1, 0), Y -assert Z == Vector(0, 0, 1), Z +assert 0 == Vector(0, 0, 0), Vector(0) +assert X == Vector(1, 0, 0), X +assert Y == Vector(0, 1, 0), Y +assert Z == Vector(0, 0, 1), Z + +assert Vector((1, 2, 3)) == Vector(1, 2, 3), Vector((1, 2, 3)) +assert Vector(X) == X, Vector(X) v = Vector(1.5, 2.5, 3.5) @@ -44,15 +47,15 @@ assert v.normalized() == v/7, v.normalized() assert v + v == 2*v == v*2 == Vector(4, 6, 12), v + v assert v/2 == v - v/2 == Vector(1, 1.5, 3), v/2 assert +v == v, +v -assert v + -v == Zero, v + -v -assert cross(v, v) == Zero, cross(v, v) +assert v + -v == 0, v + -v +assert cross(v, v) == 0, cross(v, v) assert dot(v, v) == v.norm()**2, dot(v, v) assert v, bool(v) -assert not Zero, not Zero +assert not Vector(0), not Vector(0) assert proj(v, X) == 2*X, proj(v, X) -m = Matrix(1, 2, 3, 4, - 5, 6, 7, 8, +m = Matrix(1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12) assert repr(m) == 'dimension.Matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, \ @@ -68,7 +71,7 @@ assert s == Matrix(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0), s -t = translate((1, 2, 3)) +t = translate(1, 2, 3) assert t == Matrix(1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3), t -- cgit v1.2.3