From 1bf306d4d93cc21c220a3f31835023e49e84dd2d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 22 May 2011 14:22:07 -0600 Subject: Add cameras, objects, and spheres to Python module. --- libdimension-python/Camera.c | 92 ++++++++++++++++++++++++++ libdimension-python/Camera.h | 28 ++++++++ libdimension-python/Canvas.c | 13 ++-- libdimension-python/Canvas.h | 2 - libdimension-python/Color.c | 36 +++-------- libdimension-python/Color.h | 3 - libdimension-python/Makefile.am | 10 ++- libdimension-python/Matrix.c | 15 ++--- libdimension-python/Matrix.h | 10 +-- libdimension-python/Object.c | 73 +++++++++++++++++++++ libdimension-python/Object.h | 28 ++++++++ libdimension-python/PerspectiveCamera.c | 111 ++++++++++++++++++++++++++++++++ libdimension-python/PerspectiveCamera.h | 28 ++++++++ libdimension-python/Scene.c | 59 +++++++++++++++-- libdimension-python/Scene.h | 2 - libdimension-python/Sphere.c | 76 ++++++++++++++++++++++ libdimension-python/Sphere.h | 29 +++++++++ libdimension-python/Vector.c | 69 ++++++++++---------- libdimension-python/Vector.h | 4 +- libdimension-python/dimension-python.h | 14 ++++ libdimension-python/dimension.c | 28 ++++---- libdimension-python/tests/demo.py | 16 ++++- libdimension-python/tests/geometry.py | 4 +- 23 files changed, 637 insertions(+), 113 deletions(-) create mode 100644 libdimension-python/Camera.c create mode 100644 libdimension-python/Camera.h create mode 100644 libdimension-python/Object.c create mode 100644 libdimension-python/Object.h create mode 100644 libdimension-python/PerspectiveCamera.c create mode 100644 libdimension-python/PerspectiveCamera.h create mode 100644 libdimension-python/Sphere.c create mode 100644 libdimension-python/Sphere.h diff --git a/libdimension-python/Camera.c b/libdimension-python/Camera.c new file mode 100644 index 0000000..17347d7 --- /dev/null +++ b/libdimension-python/Camera.c @@ -0,0 +1,92 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#include "dimension-python.h" + +static int +dmnsn_py_Camera_init(dmnsn_py_Camera *self, PyObject *args, PyObject *kwds) +{ + if (kwds || (args && !PyArg_ParseTuple(args, ""))) + return -1; + + return 0; +} + +static void +dmnsn_py_Camera_dealloc(dmnsn_py_Camera *self) +{ + dmnsn_delete_camera(self->camera); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject * +dmnsn_py_Camera_initialize(dmnsn_py_Camera *self) +{ + PyErr_SetString(PyExc_TypeError, "Attempt to initialize base Camera"); + return NULL; +} + +static PyObject * +dmnsn_py_Camera_transform(dmnsn_py_Camera *self, PyObject *args) +{ + dmnsn_py_Matrix *matrix; + if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_MatrixType, &matrix)) + return NULL; + + if (!self->camera) { + PyErr_SetString(PyExc_TypeError, "Attempt to transform base Camera"); + return NULL; + } + + self->camera->trans = dmnsn_matrix_mul(matrix->m, self->camera->trans); + Py_INCREF(Py_None); + return Py_None; +} + +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 new file mode 100644 index 0000000..8642f2c --- /dev/null +++ b/libdimension-python/Camera.h @@ -0,0 +1,28 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +typedef struct dmnsn_py_Camera { + PyObject_HEAD + dmnsn_camera *camera; +} dmnsn_py_Camera; + +extern PyTypeObject dmnsn_py_CameraType; + +bool dmnsn_py_init_CameraType(void); diff --git a/libdimension-python/Canvas.c b/libdimension-python/Canvas.c index 6cce310..c5063d0 100644 --- a/libdimension-python/Canvas.c +++ b/libdimension-python/Canvas.c @@ -18,8 +18,7 @@ * . * *************************************************************************/ -#include "Color.h" -#include "Canvas.h" +#include "dimension-python.h" static int dmnsn_py_Canvas_init(dmnsn_py_Canvas *self, PyObject *args, PyObject *kwds) @@ -74,13 +73,13 @@ dmnsn_py_Canvas_optimizeGL(dmnsn_py_Canvas *self) } static PyObject * -dmnsn_py_Canvas_clear(dmnsn_py_Canvas *self, PyObject *args, PyObject *kwds) +dmnsn_py_Canvas_clear(dmnsn_py_Canvas *self, PyObject *args) { - dmnsn_color color; - if (!dmnsn_py_Color_args(&color, args, kwds)) + dmnsn_py_Color *color; + if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_ColorType, &color)) return NULL; - dmnsn_clear_canvas(self->canvas, color); + dmnsn_clear_canvas(self->canvas, color->c); Py_INCREF(Py_None); return Py_None; @@ -124,7 +123,7 @@ static PyMethodDef dmnsn_py_Canvas_methods[] = { "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 | METH_KEYWORDS, + { "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" }, diff --git a/libdimension-python/Canvas.h b/libdimension-python/Canvas.h index 53d09c1..0714e53 100644 --- a/libdimension-python/Canvas.h +++ b/libdimension-python/Canvas.h @@ -18,8 +18,6 @@ * . * *************************************************************************/ -#include "dimension-python.h" - typedef struct dmnsn_py_Canvas { PyObject_HEAD dmnsn_canvas *canvas; diff --git a/libdimension-python/Color.c b/libdimension-python/Color.c index c147603..529aab2 100644 --- a/libdimension-python/Color.c +++ b/libdimension-python/Color.c @@ -18,37 +18,21 @@ * . * *************************************************************************/ -#include "Color.h" +#include "dimension-python.h" -bool -dmnsn_py_Color_args(dmnsn_color *c, PyObject *args, PyObject *kwds) +static int +dmnsn_py_Color_init(dmnsn_py_Color *self, PyObject *args, PyObject *kwds) { - c->trans = 0.0; - c->filter = 0.0; + self->c.trans = 0.0; + self->c.filter = 0.0; static char *kwlist[] = { "red", "green", "blue", "trans", "filter", NULL }; - if (PyArg_ParseTupleAndKeywords(args, kwds, "ddd|dd", kwlist, - &c->R, &c->G, &c->B, &c->trans, &c->filter)) { - return true; - } else { - if (kwds) - return false; - - PyErr_Clear(); - - dmnsn_py_Color *col; - if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_ColorType, &col)) - return false; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ddd|dd", kwlist, + &self->c.R, &self->c.G, &self->c.B, + &self->c.trans, &self->c.filter)) + return -1; - *c = col->c; - return true; - } -} - -static int -dmnsn_py_Color_init(dmnsn_py_Color *self, PyObject *args, PyObject *kwds) -{ - return dmnsn_py_Color_args(&self->c, args, kwds) ? 0 : -1; + return 0; } static PyObject * diff --git a/libdimension-python/Color.h b/libdimension-python/Color.h index 1fbf5ed..2749f2f 100644 --- a/libdimension-python/Color.h +++ b/libdimension-python/Color.h @@ -18,8 +18,6 @@ * . * *************************************************************************/ -#include "dimension-python.h" - typedef struct dmnsn_py_Color { PyObject_HEAD dmnsn_color c; @@ -27,7 +25,6 @@ typedef struct dmnsn_py_Color { extern PyTypeObject dmnsn_py_ColorType; -bool dmnsn_py_Color_args(dmnsn_color *v, PyObject *args, PyObject *kwds); bool dmnsn_py_init_ColorType(void); /* Color constants */ diff --git a/libdimension-python/Makefile.am b/libdimension-python/Makefile.am index e2d2049..9919a1a 100644 --- a/libdimension-python/Makefile.am +++ b/libdimension-python/Makefile.am @@ -26,14 +26,22 @@ AM_CFLAGS = $(Python_CFLAGS) AM_LDFLAGS = $(Python_LDFLAGS) pyexec_LTLIBRARIES = dimension.la -dimension_la_SOURCES = Canvas.c \ +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 \ diff --git a/libdimension-python/Matrix.c b/libdimension-python/Matrix.c index b18b2d7..0219965 100644 --- a/libdimension-python/Matrix.c +++ b/libdimension-python/Matrix.c @@ -18,8 +18,7 @@ * . * *************************************************************************/ -#include "Vector.h" -#include "Matrix.h" +#include "dimension-python.h" static int dmnsn_py_Matrix_init(dmnsn_py_Matrix *self, PyObject *args, PyObject *kwds) @@ -42,10 +41,10 @@ dmnsn_py_Matrix_init(dmnsn_py_Matrix *self, PyObject *args, PyObject *kwds) } PyObject * -dmnsn_py_Matrix_scale(PyObject *self, PyObject *args, PyObject *kwds) +dmnsn_py_Matrix_scale(PyObject *self, PyObject *args) { dmnsn_vector scale; - if (!dmnsn_py_Vector_args(&scale, args, kwds)) + if (!PyArg_ParseTuple(args, "O&", dmnsn_py_VectorParse, &scale)) return NULL; dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); @@ -56,10 +55,10 @@ dmnsn_py_Matrix_scale(PyObject *self, PyObject *args, PyObject *kwds) } PyObject * -dmnsn_py_Matrix_translate(PyObject *self, PyObject *args, PyObject *kwds) +dmnsn_py_Matrix_translate(PyObject *self, PyObject *args) { dmnsn_vector translate; - if (!dmnsn_py_Vector_args(&translate, args, kwds)) + if (!PyArg_ParseTuple(args, "O&", dmnsn_py_VectorParse, &translate)) return NULL; dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); @@ -70,10 +69,10 @@ dmnsn_py_Matrix_translate(PyObject *self, PyObject *args, PyObject *kwds) } PyObject * -dmnsn_py_Matrix_rotate(PyObject *self, PyObject *args, PyObject *kwds) +dmnsn_py_Matrix_rotate(PyObject *self, PyObject *args) { dmnsn_vector rotate; - if (!dmnsn_py_Vector_args(&rotate, args, kwds)) + if (!PyArg_ParseTuple(args, "O&", dmnsn_py_VectorParse, &rotate)) return NULL; dmnsn_py_Matrix *ret = PyObject_New(dmnsn_py_Matrix, &dmnsn_py_MatrixType); diff --git a/libdimension-python/Matrix.h b/libdimension-python/Matrix.h index 6299618..fa34da6 100644 --- a/libdimension-python/Matrix.h +++ b/libdimension-python/Matrix.h @@ -18,8 +18,6 @@ * . * *************************************************************************/ -#include "dimension-python.h" - typedef struct dmnsn_py_Matrix { PyObject_HEAD dmnsn_matrix m; @@ -30,8 +28,6 @@ extern PyTypeObject dmnsn_py_MatrixType; bool dmnsn_py_init_MatrixType(void); /* Global methods */ -PyObject *dmnsn_py_Matrix_scale(PyObject *self, PyObject *args, PyObject *kwds); -PyObject *dmnsn_py_Matrix_translate(PyObject *self, PyObject *args, - PyObject *kwds); -PyObject *dmnsn_py_Matrix_rotate(PyObject *self, PyObject *args, - PyObject *kwds); +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 new file mode 100644 index 0000000..5942d3d --- /dev/null +++ b/libdimension-python/Object.c @@ -0,0 +1,73 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#include "dimension-python.h" + +static int +dmnsn_py_Object_init(dmnsn_py_Object *self, PyObject *args, PyObject *kwds) +{ + if (kwds || (args && !PyArg_ParseTuple(args, ""))) + return -1; + + return 0; +} + +static void +dmnsn_py_Object_dealloc(dmnsn_py_Object *self) +{ + dmnsn_delete_object(self->object); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject * +dmnsn_py_Object_initialize(dmnsn_py_Object *self) +{ + PyErr_SetString(PyExc_TypeError, "Attempt to initialize base Object"); + return NULL; +} + +static PyMethodDef dmnsn_py_Object_methods[] = { + { "initialize", (PyCFunction)dmnsn_py_Object_initialize, METH_NOARGS, + "Initialize 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 new file mode 100644 index 0000000..11b35f1 --- /dev/null +++ b/libdimension-python/Object.h @@ -0,0 +1,28 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +typedef struct dmnsn_py_Object { + PyObject_HEAD + dmnsn_object *object; +} dmnsn_py_Object; + +extern PyTypeObject dmnsn_py_ObjectType; + +bool dmnsn_py_init_ObjectType(void); diff --git a/libdimension-python/PerspectiveCamera.c b/libdimension-python/PerspectiveCamera.c new file mode 100644 index 0000000..f144498 --- /dev/null +++ b/libdimension-python/PerspectiveCamera.c @@ -0,0 +1,111 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#include "dimension-python.h" + +static int +dmnsn_py_PerspectiveCamera_init(dmnsn_py_PerspectiveCamera *self, + PyObject *args, PyObject *kwds) +{ + if (dmnsn_py_CameraType.tp_init((PyObject *)self, NULL, NULL) < 0) + return -1; + + static char *kwlist[] = { "location", "look_at", NULL }; + + dmnsn_vector location, look_at; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&", kwlist, + &dmnsn_py_VectorParse, &location, + &dmnsn_py_VectorParse, &look_at)) + return -1; + + self->location = location; + self->look_at = look_at; + + dmnsn_delete_camera(self->base.camera); + self->base.camera = dmnsn_new_perspective_camera(); + DMNSN_INCREF(self->base.camera); + return 0; +} + +static PyObject * +dmnsn_py_PerspectiveCamera_initialize(dmnsn_py_PerspectiveCamera *self) +{ + dmnsn_vector look_at = dmnsn_vector_sub(self->look_at, self->location); + + /* Align the camera with the look_at point */ + + dmnsn_vector right = dmnsn_x; + dmnsn_vector up = dmnsn_y; + dmnsn_vector forward = dmnsn_z; + + dmnsn_vector theta = dmnsn_vector_mul( + dmnsn_vector_axis_angle(forward, look_at, up), + up + ); + dmnsn_matrix align = dmnsn_rotation_matrix(theta); + + right = dmnsn_transform_vector(align, right); + forward = dmnsn_transform_vector(align, forward); + + theta = dmnsn_vector_mul( + dmnsn_vector_axis_angle(forward, look_at, right), + right + ); + align = dmnsn_matrix_mul(dmnsn_rotation_matrix(theta), align); + + /* Translate the camera to the location */ + dmnsn_matrix move = dmnsn_translation_matrix(self->location); + + dmnsn_matrix trans = dmnsn_matrix_mul(move, align); + self->base.camera->trans = dmnsn_matrix_mul(self->base.camera->trans, + trans); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef dmnsn_py_PerspectiveCamera_methods[] = { + { "initialize", (PyCFunction)dmnsn_py_PerspectiveCamera_initialize, + METH_NOARGS, "Initialize a perspective camera" }, + { NULL } +}; + +static PyGetSetDef dmnsn_py_PerspectiveCamera_getsetters[] = { + { NULL } +}; + +PyTypeObject dmnsn_py_PerspectiveCameraType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "dimension.PerspectiveCamera", + .tp_basicsize = sizeof(dmnsn_py_PerspectiveCamera), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_doc = "Dimension perspective camera", + .tp_methods = dmnsn_py_PerspectiveCamera_methods, + .tp_getset = dmnsn_py_PerspectiveCamera_getsetters, + .tp_init = (initproc)dmnsn_py_PerspectiveCamera_init, + .tp_base = &dmnsn_py_CameraType, +}; + +bool +dmnsn_py_init_PerspectiveCameraType(void) +{ + dmnsn_py_PerspectiveCameraType.tp_new = PyType_GenericNew; + return PyType_Ready(&dmnsn_py_PerspectiveCameraType) >= 0; +} diff --git a/libdimension-python/PerspectiveCamera.h b/libdimension-python/PerspectiveCamera.h new file mode 100644 index 0000000..e6696e6 --- /dev/null +++ b/libdimension-python/PerspectiveCamera.h @@ -0,0 +1,28 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +typedef struct dmnsn_py_PerspectiveCamera { + dmnsn_py_Camera base; + dmnsn_vector location, look_at; +} dmnsn_py_PerspectiveCamera; + +extern PyTypeObject dmnsn_py_PerspectiveCameraType; + +bool dmnsn_py_init_PerspectiveCameraType(void); diff --git a/libdimension-python/Scene.c b/libdimension-python/Scene.c index 29a623a..0e43ec9 100644 --- a/libdimension-python/Scene.c +++ b/libdimension-python/Scene.c @@ -18,22 +18,57 @@ * . * *************************************************************************/ -#include "Canvas.h" -#include "Scene.h" +#include "dimension-python.h" static int dmnsn_py_Scene_init(dmnsn_py_Scene *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = { "canvas", NULL }; + dmnsn_delete_scene(self->scene); + self->scene = dmnsn_new_scene(); + + static char *kwlist[] = { "canvas", "camera", "objects", NULL }; dmnsn_py_Canvas *canvas; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, - &dmnsn_py_CanvasType, &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_delete_scene(self->scene); - self->scene = dmnsn_new_scene(); 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; } @@ -44,7 +79,17 @@ dmnsn_py_Scene_dealloc(dmnsn_py_Scene *self) 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 } }; diff --git a/libdimension-python/Scene.h b/libdimension-python/Scene.h index d94bd14..bf69326 100644 --- a/libdimension-python/Scene.h +++ b/libdimension-python/Scene.h @@ -18,8 +18,6 @@ * . * *************************************************************************/ -#include "dimension-python.h" - typedef struct dmnsn_py_Scene { PyObject_HEAD dmnsn_scene *scene; diff --git a/libdimension-python/Sphere.c b/libdimension-python/Sphere.c new file mode 100644 index 0000000..c2d5157 --- /dev/null +++ b/libdimension-python/Sphere.c @@ -0,0 +1,76 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#include "dimension-python.h" + +static int +dmnsn_py_Sphere_init(dmnsn_py_Sphere *self, PyObject *args, PyObject *kwds) +{ + if (dmnsn_py_ObjectType.tp_init((PyObject *)self, NULL, NULL) < 0) + return -1; + + static char *kwlist[] = { "radius", "center", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "dO&", kwlist, + &self->radius, + &dmnsn_py_VectorParse, &self->center)) + return -1; + + dmnsn_delete_object(self->base.object); + self->base.object = dmnsn_new_sphere(); + DMNSN_INCREF(self->base.object); + return 0; +} + +static PyObject * +dmnsn_py_Sphere_initialize(dmnsn_py_Sphere *self) +{ + 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 new file mode 100644 index 0000000..eccd1d0 --- /dev/null +++ b/libdimension-python/Sphere.h @@ -0,0 +1,29 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +typedef struct dmnsn_py_Sphere { + dmnsn_py_Object base; + double radius; + dmnsn_vector center; +} dmnsn_py_Sphere; + +extern PyTypeObject dmnsn_py_SphereType; + +bool dmnsn_py_init_SphereType(void); diff --git a/libdimension-python/Vector.c b/libdimension-python/Vector.c index 6a1928f..67f3397 100644 --- a/libdimension-python/Vector.c +++ b/libdimension-python/Vector.c @@ -18,34 +18,37 @@ * . * *************************************************************************/ -#include "Vector.h" +#include "dimension-python.h" -bool -dmnsn_py_Vector_args(dmnsn_vector *v, PyObject *args, PyObject *kwds) +int +dmnsn_py_VectorParse(PyObject *object, void *ptr) { - static char *kwlist[] = { "x", "y", "z", NULL }; - if (PyArg_ParseTupleAndKeywords(args, kwds, "ddd", kwlist, - &v->x, &v->y, &v->z)) { - return true; + 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 { - if (kwds) - return false; - PyErr_Clear(); - - dmnsn_py_Vector *vec; - if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_VectorType, &vec)) - return false; - - *v = vec->v; - return true; + 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) { - return dmnsn_py_Vector_args(&self->v, args, kwds) ? 0 : -1; + 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 * @@ -239,15 +242,15 @@ dmnsn_py_Vector_negative(PyObject *rhs) PyObject * dmnsn_py_Vector_cross(PyObject *self, PyObject *args) { - dmnsn_py_Vector *lhs, *rhs; - if (!PyArg_ParseTuple(args, "O!O!", - &dmnsn_py_VectorType, &lhs, - &dmnsn_py_VectorType, &rhs)) + 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->v, rhs->v); + ret->v = dmnsn_vector_cross(lhs, rhs); } return (PyObject *)ret; } @@ -255,27 +258,27 @@ dmnsn_py_Vector_cross(PyObject *self, PyObject *args) PyObject * dmnsn_py_Vector_dot(PyObject *self, PyObject *args) { - dmnsn_py_Vector *lhs, *rhs; - if (!PyArg_ParseTuple(args, "O!O!", - &dmnsn_py_VectorType, &lhs, - &dmnsn_py_VectorType, &rhs)) + 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->v, rhs->v)); + return PyFloat_FromDouble(dmnsn_vector_dot(lhs, rhs)); } PyObject * dmnsn_py_Vector_proj(PyObject *self, PyObject *args) { - dmnsn_py_Vector *u, *d; - if (!PyArg_ParseTuple(args, "O!O!", - &dmnsn_py_VectorType, &u, - &dmnsn_py_VectorType, &d)) + 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->v, d->v); + ret->v = dmnsn_vector_proj(u, d); } return (PyObject *)ret; } diff --git a/libdimension-python/Vector.h b/libdimension-python/Vector.h index d7e4e05..89357f2 100644 --- a/libdimension-python/Vector.h +++ b/libdimension-python/Vector.h @@ -18,8 +18,6 @@ * . * *************************************************************************/ -#include "dimension-python.h" - typedef struct dmnsn_py_Vector { PyObject_HEAD dmnsn_vector v; @@ -27,7 +25,7 @@ typedef struct dmnsn_py_Vector { extern PyTypeObject dmnsn_py_VectorType; -bool dmnsn_py_Vector_args(dmnsn_vector *v, PyObject *args, PyObject *kwds); +int dmnsn_py_VectorParse(PyObject *object, void *ptr); bool dmnsn_py_init_VectorType(void); /* Global methods */ diff --git a/libdimension-python/dimension-python.h b/libdimension-python/dimension-python.h index f365c2c..41f08c2 100644 --- a/libdimension-python/dimension-python.h +++ b/libdimension-python/dimension-python.h @@ -18,6 +18,20 @@ * . * *************************************************************************/ +#ifndef DMNSN_PYTHON_H +#define DMNSN_PYTHON_H + #define PY_SSIZE_T_CLEAN #include #include "dimension.h" +#include "Vector.h" +#include "Matrix.h" +#include "Color.h" +#include "Canvas.h" +#include "Camera.h" +#include "PerspectiveCamera.h" +#include "Object.h" +#include "Sphere.h" +#include "Scene.h" + +#endif /* DMNSN_PYTHON_H */ diff --git a/libdimension-python/dimension.c b/libdimension-python/dimension.c index 03e2aaa..0ebdab3 100644 --- a/libdimension-python/dimension.c +++ b/libdimension-python/dimension.c @@ -19,11 +19,6 @@ *************************************************************************/ #include "dimension-python.h" -#include "Vector.h" -#include "Matrix.h" -#include "Color.h" -#include "Canvas.h" -#include "Scene.h" static PyObject * dmnsn_py_dieOnWarnings(PyObject *self, PyObject *args) @@ -50,12 +45,12 @@ static PyMethodDef DimensionMethods[] = { { "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 | METH_KEYWORDS, "Scaling." }, - { "translate", (PyCFunction)dmnsn_py_Matrix_translate, - METH_VARARGS | METH_KEYWORDS, "Translation." }, - { "rotate", (PyCFunction)dmnsn_py_Matrix_rotate, - METH_VARARGS | METH_KEYWORDS, "Rotation." }, + { "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 } }; @@ -75,6 +70,10 @@ PyInit_dimension(void) || !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; @@ -108,6 +107,13 @@ PyInit_dimension(void) 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/tests/demo.py b/libdimension-python/tests/demo.py index 187f4ef..982fa60 100755 --- a/libdimension-python/tests/demo.py +++ b/libdimension-python/tests/demo.py @@ -35,4 +35,18 @@ except OSError as e: else: raise -scene = Scene(canvas = canvas) +camera = PerspectiveCamera(location = (0, 0.25, -4), + look_at = Zero) +camera.transform(rotate(53*Y)) + +objects = [] + +sphere = Sphere(radius = 1, center = Zero) +objects.append(sphere) + +scene = Scene(canvas = canvas, + camera = camera, + objects = objects) +scene.raytrace() + +canvas.writePNG('demo.png') diff --git a/libdimension-python/tests/geometry.py b/libdimension-python/tests/geometry.py index 9c79ef5..0c53ad6 100755 --- a/libdimension-python/tests/geometry.py +++ b/libdimension-python/tests/geometry.py @@ -63,12 +63,12 @@ assert str(m) == '\n' \ '[9.0\t10.0\t11.0\t12.0]\n' \ '[0.0\t0.0\t0.0\t1.0]', str(m) -s = scale(1, 2, 3) +s = scale(Vector(1, 2, 3)) assert s == Matrix(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0), s -t = translate(x = 1, y = 2, z = 3) +t = translate((1, 2, 3)) assert t == Matrix(1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3), t -- cgit v1.2.3