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