diff options
Diffstat (limited to 'libdimension-python/Color.c')
-rw-r--r-- | libdimension-python/Color.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/libdimension-python/Color.c b/libdimension-python/Color.c new file mode 100644 index 0000000..ae8de2f --- /dev/null +++ b/libdimension-python/Color.c @@ -0,0 +1,310 @@ +/************************************************************************* + * 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 "Color.h" + +bool +dmnsn_py_Color_args(dmnsn_color *c, PyObject *args, PyObject *kwds) +{ + c->filter = 0.0; + c->trans = 0.0; + + static char *kwlist[] = { "red", "green", "blue", "filter", "trans", NULL }; + if (PyArg_ParseTupleAndKeywords(args, kwds, "ddd|dd", kwlist, + &c->R, &c->G, &c->B, &c->filter, &c->trans)) { + return true; + } else { + if (kwds) + return false; + + PyErr_Clear(); + + dmnsn_py_Color *col; + if (!PyArg_ParseTuple(args, "O!", &dmnsn_py_ColorType, &col)) + return false; + + *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; +} + +static PyObject * +dmnsn_py_Color_repr(dmnsn_py_Color *self) +{ + PyObject *R = PyFloat_FromDouble(self->c.R); + PyObject *G = PyFloat_FromDouble(self->c.G); + PyObject *B = PyFloat_FromDouble(self->c.B); + PyObject *filter = PyFloat_FromDouble(self->c.filter); + PyObject *trans = PyFloat_FromDouble(self->c.trans); + + if (!R || !G || !B || !filter || !trans) { + Py_XDECREF(trans); + Py_XDECREF(filter); + 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, filter, trans); + Py_XDECREF(trans); + Py_XDECREF(filter); + 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->c.R); + PyObject *G = PyFloat_FromDouble(self->c.G); + PyObject *B = PyFloat_FromDouble(self->c.B); + PyObject *filter = PyFloat_FromDouble(self->c.filter); + PyObject *trans = PyFloat_FromDouble(self->c.trans); + + if (!R || !G || !B || !filter || !trans) { + Py_XDECREF(trans); + Py_XDECREF(filter); + Py_XDECREF(B); + Py_XDECREF(G); + Py_XDECREF(R); + return NULL; + } + + PyObject *str; + if (self->c.filter < dmnsn_epsilon && self->c.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," + " filter = %S, trans = %S>", + R, G, B, filter, trans); + } + Py_XDECREF(trans); + Py_XDECREF(filter); + 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 fdiff = (clhs->c.filter - crhs->c.filter) + * (clhs->c.filter - crhs->c.filter); + double tdiff = (clhs->c.trans - crhs->c.trans) + * (clhs->c.trans - crhs->c.trans); + bool equal = sqrt(rdiff + gdiff + bdiff + fdiff + tdiff) < 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->c = dmnsn_color_add(clhs->c, crhs->c); + } + 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->c = dmnsn_color_mul(dbl, col->c); + } + 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->c.R); +} + +static PyObject * +dmnsn_py_Color_get_green(dmnsn_py_Color *self, void *closure) +{ + return PyFloat_FromDouble(self->c.G); +} + +static PyObject * +dmnsn_py_Color_get_blue(dmnsn_py_Color *self, void *closure) +{ + return PyFloat_FromDouble(self->c.B); +} + +static PyObject * +dmnsn_py_Color_get_filter(dmnsn_py_Color *self, void *closure) +{ + return PyFloat_FromDouble(self->c.filter); +} + +static PyObject * +dmnsn_py_Color_get_trans(dmnsn_py_Color *self, void *closure) +{ + return PyFloat_FromDouble(self->c.trans); +} + +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 }, + { "filter", (getter)dmnsn_py_Color_get_filter, NULL, + "Filter component", NULL }, + { "trans", (getter)dmnsn_py_Color_get_trans, NULL, + "Transmittance 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) +{ + dmnsn_py_Black.c = dmnsn_black; + dmnsn_py_White.c = dmnsn_white; + dmnsn_py_Clear.c = dmnsn_clear; + dmnsn_py_Red.c = dmnsn_red; + dmnsn_py_Green.c = dmnsn_green; + dmnsn_py_Blue.c = dmnsn_blue; + dmnsn_py_Magenta.c = dmnsn_magenta; + dmnsn_py_Orange.c = dmnsn_orange; + dmnsn_py_Yellow.c = dmnsn_yellow; + dmnsn_py_Cyan.c = dmnsn_cyan; + + dmnsn_py_ColorType.tp_new = PyType_GenericNew; + return PyType_Ready(&dmnsn_py_ColorType) >= 0; +} |