From 250b980002419746fc099c7633b9600a15afb1c6 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 20 May 2011 16:34:52 -0600 Subject: Add Canvases to the Python module. --- libdimension-python/Canvas.c | 171 ++++++++++++++++++++++++++++++++++ libdimension-python/Canvas.h | 30 ++++++ libdimension-python/Makefile.am | 4 +- libdimension-python/Scene.c | 22 +++-- libdimension-python/dimension.c | 4 + libdimension-python/tests/Makefile.am | 1 + libdimension-python/tests/canvas.py | 57 ++++++++++++ libdimension-python/tests/demo.py | 13 ++- 8 files changed, 290 insertions(+), 12 deletions(-) create mode 100644 libdimension-python/Canvas.c create mode 100644 libdimension-python/Canvas.h create mode 100755 libdimension-python/tests/canvas.py diff --git a/libdimension-python/Canvas.c b/libdimension-python/Canvas.c new file mode 100644 index 0000000..6cce310 --- /dev/null +++ b/libdimension-python/Canvas.c @@ -0,0 +1,171 @@ +/************************************************************************* + * 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 "Color.h" +#include "Canvas.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, PyObject *kwds) +{ + dmnsn_color color; + if (!dmnsn_py_Color_args(&color, args, kwds)) + return NULL; + + dmnsn_clear_canvas(self->canvas, color); + + 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 | METH_KEYWORDS, + "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 new file mode 100644 index 0000000..53d09c1 --- /dev/null +++ b/libdimension-python/Canvas.h @@ -0,0 +1,30 @@ +/************************************************************************* + * 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" + +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/Makefile.am b/libdimension-python/Makefile.am index e75ffad..e2d2049 100644 --- a/libdimension-python/Makefile.am +++ b/libdimension-python/Makefile.am @@ -26,7 +26,9 @@ AM_CFLAGS = $(Python_CFLAGS) AM_LDFLAGS = $(Python_LDFLAGS) pyexec_LTLIBRARIES = dimension.la -dimension_la_SOURCES = Color.c \ +dimension_la_SOURCES = Canvas.c \ + Canvas.h \ + Color.c \ Color.h \ Matrix.c \ Matrix.h \ diff --git a/libdimension-python/Scene.c b/libdimension-python/Scene.c index 6323402..29a623a 100644 --- a/libdimension-python/Scene.c +++ b/libdimension-python/Scene.c @@ -18,20 +18,22 @@ * . * *************************************************************************/ +#include "Canvas.h" #include "Scene.h" -static PyObject * -dmnsn_py_Scene_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - dmnsn_py_Scene *self; - self = (dmnsn_py_Scene *)type->tp_alloc(type, 0); - self->scene = dmnsn_new_scene(); - return (PyObject *)self; -} - static int dmnsn_py_Scene_init(dmnsn_py_Scene *self, PyObject *args, PyObject *kwds) { + static char *kwlist[] = { "canvas", NULL }; + + dmnsn_py_Canvas *canvas; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, + &dmnsn_py_CanvasType, &canvas)) + return -1; + + dmnsn_delete_scene(self->scene); + self->scene = dmnsn_new_scene(); + dmnsn_scene_set_canvas(self->scene, canvas->canvas); return 0; } @@ -60,11 +62,11 @@ PyTypeObject dmnsn_py_SceneType = { .tp_methods = dmnsn_py_Scene_methods, .tp_getset = dmnsn_py_Scene_getsetters, .tp_init = (initproc)dmnsn_py_Scene_init, - .tp_new = dmnsn_py_Scene_new, }; 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/dimension.c b/libdimension-python/dimension.c index f47dfbc..03e2aaa 100644 --- a/libdimension-python/dimension.c +++ b/libdimension-python/dimension.c @@ -22,6 +22,7 @@ #include "Vector.h" #include "Matrix.h" #include "Color.h" +#include "Canvas.h" #include "Scene.h" static PyObject * @@ -73,6 +74,7 @@ PyInit_dimension(void) if (!dmnsn_py_init_VectorType() || !dmnsn_py_init_MatrixType() || !dmnsn_py_init_ColorType() + || !dmnsn_py_init_CanvasType() || !dmnsn_py_init_SceneType()) return NULL; @@ -104,6 +106,8 @@ PyInit_dimension(void) 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, "Scene", (PyObject *)&dmnsn_py_SceneType); return module; diff --git a/libdimension-python/tests/Makefile.am b/libdimension-python/tests/Makefile.am index 48e1129..70c2f35 100644 --- a/libdimension-python/tests/Makefile.am +++ b/libdimension-python/tests/Makefile.am @@ -19,6 +19,7 @@ TESTS = geometry.py \ color.py \ + canvas.py \ demo.py TESTS_ENVIRONMENT = PYTHONPATH=$(top_builddir)/libdimension-python/.libs diff --git a/libdimension-python/tests/canvas.py b/libdimension-python/tests/canvas.py new file mode 100755 index 0000000..e69d2d9 --- /dev/null +++ b/libdimension-python/tests/canvas.py @@ -0,0 +1,57 @@ +#!/usr/bin/python3 + +######################################################################### +# Copyright (C) 2010-2011 Tavian Barnes # +# # +# This file is part of The Dimension Test Suite. # +# # +# The Dimension Test Suite 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 Test Suite is distributed in the hope that it will be # +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty # +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +######################################################################### + +from dimension import * +import errno + +# Treat warnings as errors for tests +dieOnWarnings(True) + +canvas = Canvas(768, 480) + +assert canvas.width == 768, canvas.width +assert canvas.height == 480, canvas.height + +havePNG = True +try: + canvas.optimizePNG() +except OSError as e: + if e.errno == errno.ENOSYS: + havePNG = False + else: + raise + +haveGL = True +try: + canvas.optimizeGL() +except OSError as e: + if e.errno == errno.ENOSYS: + haveGL = False + else: + raise + +canvas.clear(Blue) + +if havePNG: + canvas.writePNG('png.png') + +#if haveGL: +# canvas.drawGL() diff --git a/libdimension-python/tests/demo.py b/libdimension-python/tests/demo.py index e9cdc7b..187f4ef 100755 --- a/libdimension-python/tests/demo.py +++ b/libdimension-python/tests/demo.py @@ -24,4 +24,15 @@ from dimension import * # Treat warnings as errors for tests dieOnWarnings(True) -scene = Scene() +canvas = Canvas(width = 768, height = 480) + +havePNG = True +try: + canvas.optimizePNG() +except OSError as e: + if e.errno == errno.ENOSYS: + havePNG = False + else: + raise + +scene = Scene(canvas = canvas) -- cgit v1.2.3