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