- correct python3.1 warning message.
[blender.git] / source / blender / python / generic / mathutils_Color.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Campbell Barton
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/python/generic/mathutils_Color.c
26  *  \ingroup pygen
27  */
28
29
30 #include <Python.h>
31
32 #include "mathutils.h"
33
34 #include "BLI_math.h"
35 #include "BLI_utildefines.h"
36
37 #define COLOR_SIZE 3
38
39 //----------------------------------mathutils.Color() -------------------
40 //makes a new color for you to play with
41 static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
42 {
43         float col[3]= {0.0f, 0.0f, 0.0f};
44
45         if(kwds && PyDict_Size(kwds)) {
46                 PyErr_SetString(PyExc_TypeError, "mathutils.Color(): takes no keyword args");
47                 return NULL;
48         }
49
50         switch(PyTuple_GET_SIZE(args)) {
51         case 0:
52                 break;
53         case 1:
54                 if((mathutils_array_parse(col, COLOR_SIZE, COLOR_SIZE, PyTuple_GET_ITEM(args, 0), "mathutils.Color()")) == -1)
55                         return NULL;
56                 break;
57         default:
58                 PyErr_SetString(PyExc_TypeError, "mathutils.Color(): more then a single arg given");
59                 return NULL;
60         }
61         return newColorObject(col, Py_NEW, type);
62 }
63
64 //-----------------------------METHODS----------------------------
65
66 /* note: BaseMath_ReadCallback must be called beforehand */
67 static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits)
68 {
69         PyObject *ret;
70         int i;
71
72         ret= PyTuple_New(COLOR_SIZE);
73
74         if(ndigits >= 0) {
75                 for(i= 0; i < COLOR_SIZE; i++) {
76                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
77                 }
78         }
79         else {
80                 for(i= 0; i < COLOR_SIZE; i++) {
81                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
82                 }
83         }
84
85         return ret;
86 }
87
88 static char Color_copy_doc[] =
89 ".. function:: copy()\n"
90 "\n"
91 "   Returns a copy of this color.\n"
92 "\n"
93 "   :return: A copy of the color.\n"
94 "   :rtype: :class:`Color`\n"
95 "\n"
96 "   .. note:: use this to get a copy of a wrapped color with no reference to the original data.\n"
97 ;
98 static PyObject *Color_copy(ColorObject *self)
99 {
100         if(BaseMath_ReadCallback(self) == -1)
101                 return NULL;
102
103         return newColorObject(self->col, Py_NEW, Py_TYPE(self));
104 }
105
106 //----------------------------print object (internal)--------------
107 //print the object to screen
108
109 static PyObject *Color_repr(ColorObject * self)
110 {
111         PyObject *ret, *tuple;
112
113         if(BaseMath_ReadCallback(self) == -1)
114                 return NULL;
115
116         tuple= Color_ToTupleExt(self, -1);
117
118         ret= PyUnicode_FromFormat("Color(%R)", tuple);
119
120         Py_DECREF(tuple);
121         return ret;
122 }
123
124 //------------------------tp_richcmpr
125 //returns -1 execption, 0 false, 1 true
126 static PyObject* Color_richcmpr(PyObject *a, PyObject *b, int op)
127 {
128         PyObject *res;
129         int ok= -1; /* zero is true */
130
131         if (ColorObject_Check(a) && ColorObject_Check(b)) {
132                 ColorObject *colA= (ColorObject*)a;
133                 ColorObject *colB= (ColorObject*)b;
134
135                 if(BaseMath_ReadCallback(colA) == -1 || BaseMath_ReadCallback(colB) == -1)
136                         return NULL;
137
138                 ok= EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1) ? 0 : -1;
139         }
140
141         switch (op) {
142         case Py_NE:
143                 ok = !ok; /* pass through */
144         case Py_EQ:
145                 res = ok ? Py_False : Py_True;
146                 break;
147
148         case Py_LT:
149         case Py_LE:
150         case Py_GT:
151         case Py_GE:
152                 res = Py_NotImplemented;
153                 break;
154         default:
155                 PyErr_BadArgument();
156                 return NULL;
157         }
158
159         return Py_INCREF(res), res;
160 }
161
162 //---------------------SEQUENCE PROTOCOLS------------------------
163 //----------------------------len(object)------------------------
164 //sequence length
165 static int Color_len(ColorObject *UNUSED(self))
166 {
167         return COLOR_SIZE;
168 }
169 //----------------------------object[]---------------------------
170 //sequence accessor (get)
171 static PyObject *Color_item(ColorObject * self, int i)
172 {
173         if(i<0) i= COLOR_SIZE-i;
174
175         if(i < 0 || i >= COLOR_SIZE) {
176                 PyErr_SetString(PyExc_IndexError, "color[attribute]: array index out of range");
177                 return NULL;
178         }
179
180         if(BaseMath_ReadIndexCallback(self, i) == -1)
181                 return NULL;
182
183         return PyFloat_FromDouble(self->col[i]);
184
185 }
186 //----------------------------object[]-------------------------
187 //sequence accessor (set)
188 static int Color_ass_item(ColorObject * self, int i, PyObject * value)
189 {
190         float f = PyFloat_AsDouble(value);
191
192         if(f == -1 && PyErr_Occurred()) { // parsed item not a number
193                 PyErr_SetString(PyExc_TypeError, "color[attribute] = x: argument not a number");
194                 return -1;
195         }
196
197         if(i<0) i= COLOR_SIZE-i;
198
199         if(i < 0 || i >= COLOR_SIZE){
200                 PyErr_SetString(PyExc_IndexError, "color[attribute] = x: array assignment index out of range");
201                 return -1;
202         }
203
204         self->col[i] = f;
205
206         if(BaseMath_WriteIndexCallback(self, i) == -1)
207                 return -1;
208
209         return 0;
210 }
211 //----------------------------object[z:y]------------------------
212 //sequence slice (get)
213 static PyObject *Color_slice(ColorObject * self, int begin, int end)
214 {
215         PyObject *tuple;
216         int count;
217
218         if(BaseMath_ReadCallback(self) == -1)
219                 return NULL;
220
221         CLAMP(begin, 0, COLOR_SIZE);
222         if (end<0) end= (COLOR_SIZE + 1) + end;
223         CLAMP(end, 0, COLOR_SIZE);
224         begin= MIN2(begin, end);
225
226         tuple= PyTuple_New(end - begin);
227         for(count= begin; count < end; count++) {
228                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->col[count]));
229         }
230
231         return tuple;
232 }
233 //----------------------------object[z:y]------------------------
234 //sequence slice (set)
235 static int Color_ass_slice(ColorObject * self, int begin, int end, PyObject * seq)
236 {
237         int i, size;
238         float col[COLOR_SIZE];
239
240         if(BaseMath_ReadCallback(self) == -1)
241                 return -1;
242
243         CLAMP(begin, 0, COLOR_SIZE);
244         if (end<0) end= (COLOR_SIZE + 1) + end;
245         CLAMP(end, 0, COLOR_SIZE);
246         begin = MIN2(begin,end);
247
248         if((size=mathutils_array_parse(col, 0, COLOR_SIZE, seq, "mathutils.Color[begin:end] = []")) == -1)
249                 return -1;
250
251         if(size != (end - begin)){
252                 PyErr_SetString(PyExc_TypeError, "color[begin:end] = []: size mismatch in slice assignment");
253                 return -1;
254         }
255
256         for(i= 0; i < COLOR_SIZE; i++)
257                 self->col[begin + i] = col[i];
258
259         (void)BaseMath_WriteCallback(self);
260         return 0;
261 }
262
263 static PyObject *Color_subscript(ColorObject *self, PyObject *item)
264 {
265         if (PyIndex_Check(item)) {
266                 Py_ssize_t i;
267                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
268                 if (i == -1 && PyErr_Occurred())
269                         return NULL;
270                 if (i < 0)
271                         i += COLOR_SIZE;
272                 return Color_item(self, i);
273         } else if (PySlice_Check(item)) {
274                 Py_ssize_t start, stop, step, slicelength;
275
276                 if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
277                         return NULL;
278
279                 if (slicelength <= 0) {
280                         return PyTuple_New(0);
281                 }
282                 else if (step == 1) {
283                         return Color_slice(self, start, stop);
284                 }
285                 else {
286                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with color");
287                         return NULL;
288                 }
289         }
290         else {
291                 PyErr_Format(PyExc_TypeError, "color indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
292                 return NULL;
293         }
294 }
295
296 static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
297 {
298         if (PyIndex_Check(item)) {
299                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
300                 if (i == -1 && PyErr_Occurred())
301                         return -1;
302                 if (i < 0)
303                         i += COLOR_SIZE;
304                 return Color_ass_item(self, i, value);
305         }
306         else if (PySlice_Check(item)) {
307                 Py_ssize_t start, stop, step, slicelength;
308
309                 if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
310                         return -1;
311
312                 if (step == 1)
313                         return Color_ass_slice(self, start, stop, value);
314                 else {
315                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with color");
316                         return -1;
317                 }
318         }
319         else {
320                 PyErr_Format(PyExc_TypeError, "color indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
321                 return -1;
322         }
323 }
324
325 //-----------------PROTCOL DECLARATIONS--------------------------
326 static PySequenceMethods Color_SeqMethods = {
327         (lenfunc) Color_len,                                    /* sq_length */
328         (binaryfunc) NULL,                                              /* sq_concat */
329         (ssizeargfunc) NULL,                                    /* sq_repeat */
330         (ssizeargfunc) Color_item,                              /* sq_item */
331         NULL,                                                                   /* sq_slice, deprecated */
332         (ssizeobjargproc) Color_ass_item,               /* sq_ass_item */
333         NULL,                                                                   /* sq_ass_slice, deprecated */
334         (objobjproc) NULL,                                              /* sq_contains */
335         (binaryfunc) NULL,                                              /* sq_inplace_concat */
336         (ssizeargfunc) NULL,                                    /* sq_inplace_repeat */
337 };
338
339 static PyMappingMethods Color_AsMapping = {
340         (lenfunc)Color_len,
341         (binaryfunc)Color_subscript,
342         (objobjargproc)Color_ass_subscript
343 };
344
345 /* color channel, vector.r/g/b */
346 static PyObject *Color_getChannel( ColorObject * self, void *type )
347 {
348         return Color_item(self, GET_INT_FROM_POINTER(type));
349 }
350
351 static int Color_setChannel(ColorObject * self, PyObject * value, void * type)
352 {
353         return Color_ass_item(self, GET_INT_FROM_POINTER(type), value);
354 }
355
356 /* color channel (HSV), color.h/s/v */
357 static PyObject *Color_getChannelHSV( ColorObject * self, void *type )
358 {
359         float hsv[3];
360         int i= GET_INT_FROM_POINTER(type);
361
362         if(BaseMath_ReadCallback(self) == -1)
363                 return NULL;
364
365         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
366
367         return PyFloat_FromDouble(hsv[i]);
368 }
369
370 static int Color_setChannelHSV(ColorObject * self, PyObject * value, void * type)
371 {
372         float hsv[3];
373         int i= GET_INT_FROM_POINTER(type);
374         float f = PyFloat_AsDouble(value);
375
376         if(f == -1 && PyErr_Occurred()) {
377                 PyErr_SetString(PyExc_TypeError, "color.h/s/v = value: argument not a number");
378                 return -1;
379         }
380
381         if(BaseMath_ReadCallback(self) == -1)
382                 return -1;
383
384         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
385         CLAMP(f, 0.0f, 1.0f);
386         hsv[i] = f;
387         hsv_to_rgb(hsv[0], hsv[1], hsv[2], &(self->col[0]), &(self->col[1]), &(self->col[2]));
388
389         if(BaseMath_WriteCallback(self) == -1)
390                 return -1;
391
392         return 0;
393 }
394
395 /* color channel (HSV), color.h/s/v */
396 static PyObject *Color_getHSV(ColorObject * self, void *UNUSED(closure))
397 {
398         float hsv[3];
399         PyObject *ret;
400
401         if(BaseMath_ReadCallback(self) == -1)
402                 return NULL;
403
404         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
405
406         ret= PyTuple_New(3);
407         PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(hsv[0]));
408         PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(hsv[1]));
409         PyTuple_SET_ITEM(ret, 2, PyFloat_FromDouble(hsv[2]));
410         return ret;
411 }
412
413 static int Color_setHSV(ColorObject * self, PyObject * value, void *UNUSED(closure))
414 {
415         float hsv[3];
416
417         if(mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1)
418                 return -1;
419
420         CLAMP(hsv[0], 0.0f, 1.0f);
421         CLAMP(hsv[1], 0.0f, 1.0f);
422         CLAMP(hsv[2], 0.0f, 1.0f);
423
424         hsv_to_rgb(hsv[0], hsv[1], hsv[2], &(self->col[0]), &(self->col[1]), &(self->col[2]));
425
426         if(BaseMath_WriteCallback(self) == -1)
427                 return -1;
428
429         return 0;
430 }
431
432 /*****************************************************************************/
433 /* Python attributes get/set structure:                                      */
434 /*****************************************************************************/
435 static PyGetSetDef Color_getseters[] = {
436         {(char *)"r", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Red color channel.\n\n:type: float", (void *)0},
437         {(char *)"g", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Green color channel.\n\n:type: float", (void *)1},
438         {(char *)"b", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Blue color channel.\n\n:type: float", (void *)2},
439
440         {(char *)"h", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Hue component in [0, 1].\n\n:type: float", (void *)0},
441         {(char *)"s", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Saturation component in [0, 1].\n\n:type: float", (void *)1},
442         {(char *)"v", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Value component in [0, 1].\n\n:type: float", (void *)2},
443
444         {(char *)"hsv", (getter)Color_getHSV, (setter)Color_setHSV, (char *)"HSV Values in [0, 1].\n\n:type: float triplet", (void *)0},
445
446         {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL},
447         {(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL},
448         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
449 };
450
451
452 //-----------------------METHOD DEFINITIONS ----------------------
453 static struct PyMethodDef Color_methods[] = {
454         {"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
455         {"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
456         {NULL, NULL, 0, NULL}
457 };
458
459 //------------------PY_OBECT DEFINITION--------------------------
460 static char color_doc[] =
461 "This object gives access to Colors in Blender."
462 ;
463 PyTypeObject color_Type = {
464         PyVarObject_HEAD_INIT(NULL, 0)
465         "mathutils.Color",                              //tp_name
466         sizeof(ColorObject),                    //tp_basicsize
467         0,                                                              //tp_itemsize
468         (destructor)BaseMathObject_dealloc,             //tp_dealloc
469         NULL,                                                   //tp_print
470         NULL,                                                   //tp_getattr
471         NULL,                                                   //tp_setattr
472         NULL,                                                   //tp_compare
473         (reprfunc) Color_repr,                  //tp_repr
474         NULL,                   //tp_as_number
475         &Color_SeqMethods,                              //tp_as_sequence
476         &Color_AsMapping,                               //tp_as_mapping
477         NULL,                                                   //tp_hash
478         NULL,                                                   //tp_call
479         NULL,                                                   //tp_str
480         NULL,                                                   //tp_getattro
481         NULL,                                                   //tp_setattro
482         NULL,                                                   //tp_as_buffer
483         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags
484         color_doc, //tp_doc
485         (traverseproc)BaseMathObject_traverse,  //tp_traverse
486         (inquiry)BaseMathObject_clear,  //tp_clear
487         (richcmpfunc)Color_richcmpr,    //tp_richcompare
488         0,                                                              //tp_weaklistoffset
489         NULL,                                                   //tp_iter
490         NULL,                                                   //tp_iternext
491         Color_methods,                                  //tp_methods
492         NULL,                                                   //tp_members
493         Color_getseters,                                //tp_getset
494         NULL,                                                   //tp_base
495         NULL,                                                   //tp_dict
496         NULL,                                                   //tp_descr_get
497         NULL,                                                   //tp_descr_set
498         0,                                                              //tp_dictoffset
499         NULL,                                                   //tp_init
500         NULL,                                                   //tp_alloc
501         Color_new,                                              //tp_new
502         NULL,                                                   //tp_free
503         NULL,                                                   //tp_is_gc
504         NULL,                                                   //tp_bases
505         NULL,                                                   //tp_mro
506         NULL,                                                   //tp_cache
507         NULL,                                                   //tp_subclasses
508         NULL,                                                   //tp_weaklist
509         NULL                                                    //tp_del
510 };
511 //------------------------newColorObject (internal)-------------
512 //creates a new color object
513 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
514  (i.e. it was allocated elsewhere by MEM_mallocN())
515   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
516  (i.e. it must be created here with PyMEM_malloc())*/
517 PyObject *newColorObject(float *col, int type, PyTypeObject *base_type)
518 {
519         ColorObject *self;
520
521         self= base_type ?       (ColorObject *)base_type->tp_alloc(base_type, 0) :
522                                                 (ColorObject *)PyObject_GC_New(ColorObject, &color_Type);
523
524         if(self) {
525                 /* init callbacks as NULL */
526                 self->cb_user= NULL;
527                 self->cb_type= self->cb_subtype= 0;
528
529                 if(type == Py_WRAP){
530                         self->col = col;
531                         self->wrapped = Py_WRAP;
532                 }
533                 else if (type == Py_NEW){
534                         self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float));
535                         if(col)
536                                 copy_v3_v3(self->col, col);
537                         else
538                                 zero_v3(self->col);
539
540                         self->wrapped = Py_NEW;
541                 }
542                 else {
543                         PyErr_SetString(PyExc_RuntimeError, "Color(): invalid type");
544                         return NULL;
545                 }
546         }
547
548         return (PyObject *)self;
549 }
550
551 PyObject *newColorObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
552 {
553         ColorObject *self= (ColorObject *)newColorObject(NULL, Py_NEW, NULL);
554         if(self) {
555                 Py_INCREF(cb_user);
556                 self->cb_user=                  cb_user;
557                 self->cb_type=                  (unsigned char)cb_type;
558                 self->cb_subtype=               (unsigned char)cb_subtype;
559                 PyObject_GC_Track(self);
560         }
561
562         return (PyObject *)self;
563 }