summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-06-13 00:16:27 -0600
committerTavian Barnes <tavianator@gmail.com>2011-06-13 00:17:16 -0600
commit9b758508df283a533a4cfc605545a35f77bc9d5f (patch)
treedd7e471d07a32bff8702aed3624a084c9c209ccf
parent7acd8ea6673b7a90ed4041408ccf1b024b8a007a (diff)
downloaddimension-9b758508df283a533a4cfc605545a35f77bc9d5f.tar.xz
Use Cython for the Python module.
-rw-r--r--.gitignore1
-rw-r--r--libdimension-python/Camera.c92
-rw-r--r--libdimension-python/Camera.h28
-rw-r--r--libdimension-python/Canvas.c170
-rw-r--r--libdimension-python/Canvas.h28
-rw-r--r--libdimension-python/Color.c303
-rw-r--r--libdimension-python/Color.h41
-rw-r--r--libdimension-python/Makefile.am29
-rw-r--r--libdimension-python/Matrix.c292
-rw-r--r--libdimension-python/Matrix.h33
-rw-r--r--libdimension-python/Object.c93
-rw-r--r--libdimension-python/Object.h28
-rw-r--r--libdimension-python/PerspectiveCamera.c111
-rw-r--r--libdimension-python/PerspectiveCamera.h28
-rw-r--r--libdimension-python/Scene.c117
-rw-r--r--libdimension-python/Scene.h28
-rw-r--r--libdimension-python/Sphere.c90
-rw-r--r--libdimension-python/Sphere.h29
-rw-r--r--libdimension-python/Vector.c380
-rw-r--r--libdimension-python/Vector.h40
-rw-r--r--libdimension-python/dimension-python.h37
-rw-r--r--libdimension-python/dimension.c120
-rw-r--r--libdimension-python/dimension.pxd359
-rw-r--r--libdimension-python/dimension.pyx910
-rwxr-xr-xlibdimension-python/tests/demo.py138
-rwxr-xr-xlibdimension-python/tests/geometry.py23
26 files changed, 1418 insertions, 2130 deletions
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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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("<red = %S, green = %S, blue = %S>",
- R, G, B);
- } else {
- str = PyUnicode_FromFormat("<red = %S, green = %S, blue = %S,"
- " trans = %S, filter = %S>",
- 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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> ##
+## Copyright (C) 2011 Tavian Barnes <tavianator@tavianator.com> ##
## ##
## 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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#ifndef DMNSN_PYTHON_H
-#define DMNSN_PYTHON_H
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-#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 <tavianator@tavianator.com> #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+#########################################################################
+
+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 <tavianator@tavianator.com> #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+#########################################################################
+
+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 = (<Vector>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, (<Vector>lhs)._v))
+ else:
+ return _rawVector(dmnsn_vector_mul(lhs, (<Vector>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, (<Matrix>rhs)._m))
+ else:
+ return _rawVector(dmnsn_transform_vector(lhs._m, (<Vector>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 = (<Color>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, (<Color>lhs)._sRGB))
+ else:
+ return _rawsRGBColor(dmnsn_color_mul(lhs, (<Color>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 '<red = %s, green = %s, blue = %s, trans = %s, filter = %s>' % \
+ (self.red, self.green, self.blue, self.trans, self.filter)
+ else:
+ return '<red = %s, green = %s, blue = %s>' % \
+ (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 = (<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)._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)._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 = (<Object?>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 = (<Object?>obj)._object
+ DMNSN_INCREF(self._object)
+ else:
+ o = (<Object?>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 = (<Object?>obj)._object
+ DMNSN_INCREF(self._object)
+ else:
+ o = (<Object?>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 = (<Object?>obj)._object
+ DMNSN_INCREF(self._object)
+ else:
+ o = (<Object?>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 = (<Object?>obj)._object
+ DMNSN_INCREF(o)
+ dmnsn_array_push(self._scene.objects, &o)
+
+ cdef dmnsn_light *l
+ for light in lights:
+ l = (<Light?>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