c14b4a0686b99ceb3bfd7aa3357c70e698f60e01
[blender.git] / source / blender / python / mathutils / mathutils_Color.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/mathutils/mathutils_Color.c
24  *  \ingroup pymathutils
25  */
26
27
28 #include <Python.h>
29
30 #include "mathutils.h"
31
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34 #include "BLI_dynstr.h"
35
36 #define COLOR_SIZE 3
37
38 //----------------------------------mathutils.Color() -------------------
39 //makes a new color for you to play with
40 static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
41 {
42         float col[3] = {0.0f, 0.0f, 0.0f};
43
44         if (kwds && PyDict_Size(kwds)) {
45                 PyErr_SetString(PyExc_TypeError,
46                                 "mathutils.Color(): "
47                                 "takes no keyword args");
48                 return NULL;
49         }
50
51         switch (PyTuple_GET_SIZE(args)) {
52                 case 0:
53                         break;
54                 case 1:
55                         if ((mathutils_array_parse(col, COLOR_SIZE, COLOR_SIZE, PyTuple_GET_ITEM(args, 0), "mathutils.Color()")) == -1)
56                                 return NULL;
57                         break;
58                 default:
59                         PyErr_SetString(PyExc_TypeError,
60                                         "mathutils.Color(): "
61                                         "more then a single arg given");
62                         return NULL;
63         }
64         return Color_CreatePyObject(col, Py_NEW, type);
65 }
66
67 //-----------------------------METHODS----------------------------
68
69 /* note: BaseMath_ReadCallback must be called beforehand */
70 static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits)
71 {
72         PyObject *ret;
73         int i;
74
75         ret = PyTuple_New(COLOR_SIZE);
76
77         if (ndigits >= 0) {
78                 for (i = 0; i < COLOR_SIZE; i++) {
79                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits)));
80                 }
81         }
82         else {
83                 for (i = 0; i < COLOR_SIZE; i++) {
84                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
85                 }
86         }
87
88         return ret;
89 }
90
91 PyDoc_STRVAR(Color_copy_doc,
92 ".. function:: copy()\n"
93 "\n"
94 "   Returns a copy of this color.\n"
95 "\n"
96 "   :return: A copy of the color.\n"
97 "   :rtype: :class:`Color`\n"
98 "\n"
99 "   .. note:: use this to get a copy of a wrapped color with\n"
100 "      no reference to the original data.\n"
101 );
102 static PyObject *Color_copy(ColorObject *self)
103 {
104         if (BaseMath_ReadCallback(self) == -1)
105                 return NULL;
106
107         return Color_CreatePyObject(self->col, Py_NEW, Py_TYPE(self));
108 }
109 static PyObject *Color_deepcopy(ColorObject *self, PyObject *args)
110 {
111         if (!mathutils_deepcopy_args_check(args))
112                 return NULL;
113         return Color_copy(self);
114 }
115
116 //----------------------------print object (internal)--------------
117 //print the object to screen
118
119 static PyObject *Color_repr(ColorObject *self)
120 {
121         PyObject *ret, *tuple;
122
123         if (BaseMath_ReadCallback(self) == -1)
124                 return NULL;
125
126         tuple = Color_ToTupleExt(self, -1);
127
128         ret = PyUnicode_FromFormat("Color(%R)", tuple);
129
130         Py_DECREF(tuple);
131         return ret;
132 }
133
134 static PyObject *Color_str(ColorObject *self)
135 {
136         DynStr *ds;
137
138         if (BaseMath_ReadCallback(self) == -1)
139                 return NULL;
140
141         ds = BLI_dynstr_new();
142
143         BLI_dynstr_appendf(ds, "<Color (r=%.4f, g=%.4f, b=%.4f)>",
144                            self->col[0], self->col[1], self->col[2]);
145
146         return mathutils_dynstr_to_py(ds); /* frees ds */
147 }
148
149 //------------------------tp_richcmpr
150 //returns -1 exception, 0 false, 1 true
151 static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
152 {
153         PyObject *res;
154         int ok = -1; /* zero is true */
155
156         if (ColorObject_Check(a) && ColorObject_Check(b)) {
157                 ColorObject *colA = (ColorObject *)a;
158                 ColorObject *colB = (ColorObject *)b;
159
160                 if (BaseMath_ReadCallback(colA) == -1 || BaseMath_ReadCallback(colB) == -1)
161                         return NULL;
162
163                 ok = EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1) ? 0 : -1;
164         }
165
166         switch (op) {
167                 case Py_NE:
168                         ok = !ok; /* pass through */
169                 case Py_EQ:
170                         res = ok ? Py_False : Py_True;
171                         break;
172
173                 case Py_LT:
174                 case Py_LE:
175                 case Py_GT:
176                 case Py_GE:
177                         res = Py_NotImplemented;
178                         break;
179                 default:
180                         PyErr_BadArgument();
181                         return NULL;
182         }
183
184         return Py_INCREF(res), res;
185 }
186
187 //---------------------SEQUENCE PROTOCOLS------------------------
188 //----------------------------len(object)------------------------
189 //sequence length
190 static int Color_len(ColorObject *UNUSED(self))
191 {
192         return COLOR_SIZE;
193 }
194 //----------------------------object[]---------------------------
195 //sequence accessor (get)
196 static PyObject *Color_item(ColorObject *self, int i)
197 {
198         if (i < 0) i = COLOR_SIZE - i;
199
200         if (i < 0 || i >= COLOR_SIZE) {
201                 PyErr_SetString(PyExc_IndexError,
202                                 "color[item]: "
203                                 "array index out of range");
204                 return NULL;
205         }
206
207         if (BaseMath_ReadIndexCallback(self, i) == -1)
208                 return NULL;
209
210         return PyFloat_FromDouble(self->col[i]);
211
212 }
213 //----------------------------object[]-------------------------
214 //sequence accessor (set)
215 static int Color_ass_item(ColorObject *self, int i, PyObject *value)
216 {
217         float f = PyFloat_AsDouble(value);
218
219         if (f == -1 && PyErr_Occurred()) { // parsed item not a number
220                 PyErr_SetString(PyExc_TypeError,
221                                 "color[item] = x: "
222                                 "argument not a number");
223                 return -1;
224         }
225
226         if (i < 0) i = COLOR_SIZE - i;
227
228         if (i < 0 || i >= COLOR_SIZE) {
229                 PyErr_SetString(PyExc_IndexError, "color[item] = x: "
230                                 "array assignment index out of range");
231                 return -1;
232         }
233
234         self->col[i] = f;
235
236         if (BaseMath_WriteIndexCallback(self, i) == -1)
237                 return -1;
238
239         return 0;
240 }
241 //----------------------------object[z:y]------------------------
242 //sequence slice (get)
243 static PyObject *Color_slice(ColorObject *self, int begin, int end)
244 {
245         PyObject *tuple;
246         int count;
247
248         if (BaseMath_ReadCallback(self) == -1)
249                 return NULL;
250
251         CLAMP(begin, 0, COLOR_SIZE);
252         if (end < 0) end = (COLOR_SIZE + 1) + end;
253         CLAMP(end, 0, COLOR_SIZE);
254         begin = MIN2(begin, end);
255
256         tuple = PyTuple_New(end - begin);
257         for (count = begin; count < end; count++) {
258                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->col[count]));
259         }
260
261         return tuple;
262 }
263 //----------------------------object[z:y]------------------------
264 //sequence slice (set)
265 static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
266 {
267         int i, size;
268         float col[COLOR_SIZE];
269
270         if (BaseMath_ReadCallback(self) == -1)
271                 return -1;
272
273         CLAMP(begin, 0, COLOR_SIZE);
274         if (end < 0) end = (COLOR_SIZE + 1) + end;
275         CLAMP(end, 0, COLOR_SIZE);
276         begin = MIN2(begin, end);
277
278         if ((size = mathutils_array_parse(col, 0, COLOR_SIZE, seq, "mathutils.Color[begin:end] = []")) == -1)
279                 return -1;
280
281         if (size != (end - begin)) {
282                 PyErr_SetString(PyExc_ValueError,
283                                 "color[begin:end] = []: "
284                                 "size mismatch in slice assignment");
285                 return -1;
286         }
287
288         for (i = 0; i < COLOR_SIZE; i++)
289                 self->col[begin + i] = col[i];
290
291         (void)BaseMath_WriteCallback(self);
292         return 0;
293 }
294
295 static PyObject *Color_subscript(ColorObject *self, PyObject *item)
296 {
297         if (PyIndex_Check(item)) {
298                 Py_ssize_t i;
299                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
300                 if (i == -1 && PyErr_Occurred())
301                         return NULL;
302                 if (i < 0)
303                         i += COLOR_SIZE;
304                 return Color_item(self, i);
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 NULL;
311
312                 if (slicelength <= 0) {
313                         return PyTuple_New(0);
314                 }
315                 else if (step == 1) {
316                         return Color_slice(self, start, stop);
317                 }
318                 else {
319                         PyErr_SetString(PyExc_IndexError,
320                                         "slice steps not supported with color");
321                         return NULL;
322                 }
323         }
324         else {
325                 PyErr_Format(PyExc_TypeError,
326                              "color indices must be integers, not %.200s",
327                              Py_TYPE(item)->tp_name);
328                 return NULL;
329         }
330 }
331
332 static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
333 {
334         if (PyIndex_Check(item)) {
335                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
336                 if (i == -1 && PyErr_Occurred())
337                         return -1;
338                 if (i < 0)
339                         i += COLOR_SIZE;
340                 return Color_ass_item(self, i, value);
341         }
342         else if (PySlice_Check(item)) {
343                 Py_ssize_t start, stop, step, slicelength;
344
345                 if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
346                         return -1;
347
348                 if (step == 1)
349                         return Color_ass_slice(self, start, stop, value);
350                 else {
351                         PyErr_SetString(PyExc_IndexError,
352                                         "slice steps not supported with color");
353                         return -1;
354                 }
355         }
356         else {
357                 PyErr_Format(PyExc_TypeError,
358                              "color indices must be integers, not %.200s",
359                              Py_TYPE(item)->tp_name);
360                 return -1;
361         }
362 }
363
364 //-----------------PROTCOL DECLARATIONS--------------------------
365 static PySequenceMethods Color_SeqMethods = {
366         (lenfunc) Color_len,                    /* sq_length */
367         (binaryfunc) NULL,                      /* sq_concat */
368         (ssizeargfunc) NULL,                    /* sq_repeat */
369         (ssizeargfunc) Color_item,              /* sq_item */
370         NULL,                                   /* sq_slice, deprecated */
371         (ssizeobjargproc) Color_ass_item,       /* sq_ass_item */
372         NULL,                                   /* sq_ass_slice, deprecated */
373         (objobjproc) NULL,                      /* sq_contains */
374         (binaryfunc) NULL,                      /* sq_inplace_concat */
375         (ssizeargfunc) NULL,                    /* sq_inplace_repeat */
376 };
377
378 static PyMappingMethods Color_AsMapping = {
379         (lenfunc)Color_len,
380         (binaryfunc)Color_subscript,
381         (objobjargproc)Color_ass_subscript
382 };
383
384 /* numeric */
385
386
387 /* addition: obj + obj */
388 static PyObject *Color_add(PyObject *v1, PyObject *v2)
389 {
390         ColorObject *color1 = NULL, *color2 = NULL;
391         float col[COLOR_SIZE];
392
393         if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
394                 PyErr_Format(PyExc_TypeError,
395                              "Color addition: (%s + %s) "
396                              "invalid type for this operation",
397                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
398                 return NULL;
399         }
400         color1 = (ColorObject *)v1;
401         color2 = (ColorObject *)v2;
402
403         if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
404                 return NULL;
405
406         add_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE);
407
408         return Color_CreatePyObject(col, Py_NEW, Py_TYPE(v1));
409 }
410
411 /* addition in-place: obj += obj */
412 static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
413 {
414         ColorObject *color1 = NULL, *color2 = NULL;
415
416         if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
417                 PyErr_Format(PyExc_TypeError,
418                              "Color addition: (%s += %s) "
419                              "invalid type for this operation",
420                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
421                 return NULL;
422         }
423         color1 = (ColorObject *)v1;
424         color2 = (ColorObject *)v2;
425
426         if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
427                 return NULL;
428
429         add_vn_vn(color1->col, color2->col, COLOR_SIZE);
430
431         (void)BaseMath_WriteCallback(color1);
432         Py_INCREF(v1);
433         return v1;
434 }
435
436 /* subtraction: obj - obj */
437 static PyObject *Color_sub(PyObject *v1, PyObject *v2)
438 {
439         ColorObject *color1 = NULL, *color2 = NULL;
440         float col[COLOR_SIZE];
441
442         if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
443                 PyErr_Format(PyExc_TypeError,
444                              "Color subtraction: (%s - %s) "
445                              "invalid type for this operation",
446                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
447                 return NULL;
448         }
449         color1 = (ColorObject *)v1;
450         color2 = (ColorObject *)v2;
451
452         if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
453                 return NULL;
454
455         sub_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE);
456
457         return Color_CreatePyObject(col, Py_NEW, Py_TYPE(v1));
458 }
459
460 /* subtraction in-place: obj -= obj */
461 static PyObject *Color_isub(PyObject *v1, PyObject *v2)
462 {
463         ColorObject *color1 = NULL, *color2 = NULL;
464
465         if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
466                 PyErr_Format(PyExc_TypeError,
467                              "Color subtraction: (%s -= %s) "
468                              "invalid type for this operation",
469                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
470                 return NULL;
471         }
472         color1 = (ColorObject *)v1;
473         color2 = (ColorObject *)v2;
474
475         if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
476                 return NULL;
477
478         sub_vn_vn(color1->col, color2->col, COLOR_SIZE);
479
480         (void)BaseMath_WriteCallback(color1);
481         Py_INCREF(v1);
482         return v1;
483 }
484
485 static PyObject *color_mul_float(ColorObject *color, const float scalar)
486 {
487         float tcol[COLOR_SIZE];
488         mul_vn_vn_fl(tcol, color->col, COLOR_SIZE, scalar);
489         return Color_CreatePyObject(tcol, Py_NEW, Py_TYPE(color));
490 }
491
492
493 static PyObject *Color_mul(PyObject *v1, PyObject *v2)
494 {
495         ColorObject *color1 = NULL, *color2 = NULL;
496         float scalar;
497
498         if (ColorObject_Check(v1)) {
499                 color1 = (ColorObject *)v1;
500                 if (BaseMath_ReadCallback(color1) == -1)
501                         return NULL;
502         }
503         if (ColorObject_Check(v2)) {
504                 color2 = (ColorObject *)v2;
505                 if (BaseMath_ReadCallback(color2) == -1)
506                         return NULL;
507         }
508
509
510         /* make sure v1 is always the vector */
511         if (color1 && color2) {
512                 /* col * col, don't support yet! */
513         }
514         else if (color1) {
515                 if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR * FLOAT */
516                         return color_mul_float(color1, scalar);
517                 }
518         }
519         else if (color2) {
520                 if (((scalar = PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred()) == 0) { /* FLOAT * COLOR */
521                         return color_mul_float(color2, scalar);
522                 }
523         }
524         else {
525                 BLI_assert(!"internal error");
526         }
527
528         PyErr_Format(PyExc_TypeError,
529                      "Color multiplication: not supported between "
530                      "'%.200s' and '%.200s' types",
531                      Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
532         return NULL;
533 }
534
535 static PyObject *Color_div(PyObject *v1, PyObject *v2)
536 {
537         ColorObject *color1 = NULL;
538         float scalar;
539
540         if (ColorObject_Check(v1)) {
541                 color1 = (ColorObject *)v1;
542                 if (BaseMath_ReadCallback(color1) == -1)
543                         return NULL;
544         }
545         else {
546                 PyErr_SetString(PyExc_TypeError,
547                                 "Color division not supported in this order");
548                 return NULL;
549         }
550
551         /* make sure v1 is always the vector */
552         if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR * FLOAT */
553                 if (scalar == 0.0f) {
554                         PyErr_SetString(PyExc_ZeroDivisionError,
555                                         "Color division: divide by zero error");
556                         return NULL;
557                 }
558                 return color_mul_float(color1, 1.0f / scalar);
559         }
560
561         PyErr_Format(PyExc_TypeError,
562                      "Color multiplication: not supported between "
563                      "'%.200s' and '%.200s' types",
564                      Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
565         return NULL;
566 }
567
568 /* multiplication in-place: obj *= obj */
569 static PyObject *Color_imul(PyObject *v1, PyObject *v2)
570 {
571         ColorObject *color = (ColorObject *)v1;
572         float scalar;
573
574         if (BaseMath_ReadCallback(color) == -1)
575                 return NULL;
576
577         /* only support color *= float */
578         if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR *= FLOAT */
579                 mul_vn_fl(color->col, COLOR_SIZE, scalar);
580         }
581         else {
582                 PyErr_Format(PyExc_TypeError,
583                              "Color multiplication: (%s *= %s) "
584                              "invalid type for this operation",
585                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
586                 return NULL;
587         }
588
589         (void)BaseMath_WriteCallback(color);
590         Py_INCREF(v1);
591         return v1;
592 }
593
594 /* multiplication in-place: obj *= obj */
595 static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
596 {
597         ColorObject *color = (ColorObject *)v1;
598         float scalar;
599
600         if (BaseMath_ReadCallback(color) == -1)
601                 return NULL;
602
603         /* only support color /= float */
604         if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR /= FLOAT */
605                 if (scalar == 0.0f) {
606                         PyErr_SetString(PyExc_ZeroDivisionError,
607                                         "Color division: divide by zero error");
608                         return NULL;
609                 }
610
611                 mul_vn_fl(color->col, COLOR_SIZE, 1.0f / scalar);
612         }
613         else {
614                 PyErr_Format(PyExc_TypeError,
615                              "Color division: (%s /= %s) "
616                              "invalid type for this operation",
617                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
618                 return NULL;
619         }
620
621         (void)BaseMath_WriteCallback(color);
622         Py_INCREF(v1);
623         return v1;
624 }
625
626 /* -obj
627  * returns the negative of this object */
628 static PyObject *Color_neg(ColorObject *self)
629 {
630         float tcol[COLOR_SIZE];
631
632         if (BaseMath_ReadCallback(self) == -1)
633                 return NULL;
634
635         negate_vn_vn(tcol, self->col, COLOR_SIZE);
636         return Color_CreatePyObject(tcol, Py_NEW, Py_TYPE(self));
637 }
638
639
640 static PyNumberMethods Color_NumMethods = {
641         (binaryfunc) Color_add, /*nb_add*/
642         (binaryfunc) Color_sub, /*nb_subtract*/
643         (binaryfunc) Color_mul, /*nb_multiply*/
644         NULL,               /*nb_remainder*/
645         NULL,               /*nb_divmod*/
646         NULL,               /*nb_power*/
647         (unaryfunc) Color_neg,   /*nb_negative*/
648         (unaryfunc) Color_copy,  /*tp_positive*/
649         (unaryfunc) NULL,   /*tp_absolute*/
650         (inquiry)   NULL,   /*tp_bool*/
651         (unaryfunc) NULL,   /*nb_invert*/
652         NULL,               /*nb_lshift*/
653         (binaryfunc)NULL,   /*nb_rshift*/
654         NULL,               /*nb_and*/
655         NULL,               /*nb_xor*/
656         NULL,               /*nb_or*/
657         NULL,               /*nb_int*/
658         NULL,               /*nb_reserved*/
659         NULL,               /*nb_float*/
660         Color_iadd,         /* nb_inplace_add */
661         Color_isub,         /* nb_inplace_subtract */
662         Color_imul,         /* nb_inplace_multiply */
663         NULL,               /* nb_inplace_remainder */
664         NULL,               /* nb_inplace_power */
665         NULL,               /* nb_inplace_lshift */
666         NULL,               /* nb_inplace_rshift */
667         NULL,               /* nb_inplace_and */
668         NULL,               /* nb_inplace_xor */
669         NULL,               /* nb_inplace_or */
670         NULL,               /* nb_floor_divide */
671         Color_div,          /* nb_true_divide */
672         NULL,               /* nb_inplace_floor_divide */
673         Color_idiv,         /* nb_inplace_true_divide */
674         NULL,               /* nb_index */
675 };
676
677 /* color channel, vector.r/g/b */
678 PyDoc_STRVAR(Color_channel_r_doc, "Red color channel.\n\n:type: float");
679 PyDoc_STRVAR(Color_channel_g_doc, "Green color channel.\n\n:type: float");
680 PyDoc_STRVAR(Color_channel_b_doc, "Blue color channel.\n\n:type: float");
681
682 static PyObject *Color_channel_get(ColorObject *self, void *type)
683 {
684         return Color_item(self, GET_INT_FROM_POINTER(type));
685 }
686
687 static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
688 {
689         return Color_ass_item(self, GET_INT_FROM_POINTER(type), value);
690 }
691
692 /* color channel (HSV), color.h/s/v */
693 PyDoc_STRVAR(Color_channel_hsv_h_doc, "HSV Hue component in [0, 1].\n\n:type: float");
694 PyDoc_STRVAR(Color_channel_hsv_s_doc, "HSV Saturation component in [0, 1].\n\n:type: float");
695 PyDoc_STRVAR(Color_channel_hsv_v_doc, "HSV Value component in [0, 1].\n\n:type: float");
696
697 static PyObject *Color_channel_hsv_get(ColorObject *self, void *type)
698 {
699         float hsv[3];
700         int i = GET_INT_FROM_POINTER(type);
701
702         if (BaseMath_ReadCallback(self) == -1)
703                 return NULL;
704
705         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
706
707         return PyFloat_FromDouble(hsv[i]);
708 }
709
710 static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
711 {
712         float hsv[3];
713         int i = GET_INT_FROM_POINTER(type);
714         float f = PyFloat_AsDouble(value);
715
716         if (f == -1 && PyErr_Occurred()) {
717                 PyErr_SetString(PyExc_TypeError,
718                                 "color.h/s/v = value: "
719                                 "argument not a number");
720                 return -1;
721         }
722
723         if (BaseMath_ReadCallback(self) == -1)
724                 return -1;
725
726         rgb_to_hsv_v(self->col, hsv);
727         CLAMP(f, 0.0f, 1.0f);
728         hsv[i] = f;
729         hsv_to_rgb_v(hsv, self->col);
730
731         if (BaseMath_WriteCallback(self) == -1)
732                 return -1;
733
734         return 0;
735 }
736
737 /* color channel (HSV), color.h/s/v */
738 PyDoc_STRVAR(Color_hsv_doc, "HSV Values in [0, 1].\n\n:type: float triplet");
739 static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
740 {
741         float hsv[3];
742         PyObject *ret;
743
744         if (BaseMath_ReadCallback(self) == -1)
745                 return NULL;
746
747         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
748
749         ret = PyTuple_New(3);
750         PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(hsv[0]));
751         PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(hsv[1]));
752         PyTuple_SET_ITEM(ret, 2, PyFloat_FromDouble(hsv[2]));
753         return ret;
754 }
755
756 static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closure))
757 {
758         float hsv[3];
759
760         if (mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1)
761                 return -1;
762
763         CLAMP(hsv[0], 0.0f, 1.0f);
764         CLAMP(hsv[1], 0.0f, 1.0f);
765         CLAMP(hsv[2], 0.0f, 1.0f);
766
767         hsv_to_rgb_v(hsv, self->col);
768
769         if (BaseMath_WriteCallback(self) == -1)
770                 return -1;
771
772         return 0;
773 }
774
775 /*****************************************************************************/
776 /* Python attributes get/set structure:                                      */
777 /*****************************************************************************/
778 static PyGetSetDef Color_getseters[] = {
779         {(char *)"r", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_r_doc, (void *)0},
780         {(char *)"g", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_g_doc, (void *)1},
781         {(char *)"b", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_b_doc, (void *)2},
782
783         {(char *)"h", (getter)Color_channel_hsv_get, (setter)Color_channel_hsv_set, (char *)Color_channel_hsv_h_doc, (void *)0},
784         {(char *)"s", (getter)Color_channel_hsv_get, (setter)Color_channel_hsv_set, (char *)Color_channel_hsv_s_doc, (void *)1},
785         {(char *)"v", (getter)Color_channel_hsv_get, (setter)Color_channel_hsv_set, (char *)Color_channel_hsv_v_doc, (void *)2},
786
787         {(char *)"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, (char *)Color_hsv_doc, (void *)0},
788
789         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
790         {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
791         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
792 };
793
794
795 //-----------------------METHOD DEFINITIONS ----------------------
796 static struct PyMethodDef Color_methods[] = {
797         {"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
798         {"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
799         {"__deepcopy__", (PyCFunction) Color_deepcopy, METH_VARARGS, Color_copy_doc},
800         {NULL, NULL, 0, NULL}
801 };
802
803 //------------------PY_OBECT DEFINITION--------------------------
804 PyDoc_STRVAR(color_doc,
805 "This object gives access to Colors in Blender."
806 );
807 PyTypeObject color_Type = {
808         PyVarObject_HEAD_INIT(NULL, 0)
809         "Color",                        //tp_name
810         sizeof(ColorObject),            //tp_basicsize
811         0,                              //tp_itemsize
812         (destructor)BaseMathObject_dealloc,     //tp_dealloc
813         NULL,                           //tp_print
814         NULL,                           //tp_getattr
815         NULL,                           //tp_setattr
816         NULL,                           //tp_compare
817         (reprfunc) Color_repr,          //tp_repr
818         &Color_NumMethods,              //tp_as_number
819         &Color_SeqMethods,              //tp_as_sequence
820         &Color_AsMapping,               //tp_as_mapping
821         NULL,                           //tp_hash
822         NULL,                           //tp_call
823         (reprfunc) Color_str,           //tp_str
824         NULL,                           //tp_getattro
825         NULL,                           //tp_setattro
826         NULL,                           //tp_as_buffer
827         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags
828         color_doc, //tp_doc
829         (traverseproc)BaseMathObject_traverse,  //tp_traverse
830         (inquiry)BaseMathObject_clear,  //tp_clear
831         (richcmpfunc)Color_richcmpr,    //tp_richcompare
832         0,                              //tp_weaklistoffset
833         NULL,                           //tp_iter
834         NULL,                           //tp_iternext
835         Color_methods,                  //tp_methods
836         NULL,                           //tp_members
837         Color_getseters,                //tp_getset
838         NULL,                           //tp_base
839         NULL,                           //tp_dict
840         NULL,                           //tp_descr_get
841         NULL,                           //tp_descr_set
842         0,                              //tp_dictoffset
843         NULL,                           //tp_init
844         NULL,                           //tp_alloc
845         Color_new,                      //tp_new
846         NULL,                           //tp_free
847         NULL,                           //tp_is_gc
848         NULL,                           //tp_bases
849         NULL,                           //tp_mro
850         NULL,                           //tp_cache
851         NULL,                           //tp_subclasses
852         NULL,                           //tp_weaklist
853         NULL                            //tp_del
854 };
855 //------------------------Color_CreatePyObject (internal)-------------
856 //creates a new color object
857 /* pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
858  *  (i.e. it was allocated elsewhere by MEM_mallocN())
859  *   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
860  *  (i.e. it must be created here with PyMEM_malloc())*/
861 PyObject *Color_CreatePyObject(float col[3], int type, PyTypeObject *base_type)
862 {
863         ColorObject *self;
864
865         self = base_type ?  (ColorObject *)base_type->tp_alloc(base_type, 0) :
866                             (ColorObject *)PyObject_GC_New(ColorObject, &color_Type);
867
868         if (self) {
869                 /* init callbacks as NULL */
870                 self->cb_user = NULL;
871                 self->cb_type = self->cb_subtype = 0;
872
873                 if (type == Py_WRAP) {
874                         self->col = col;
875                         self->wrapped = Py_WRAP;
876                 }
877                 else if (type == Py_NEW) {
878                         self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float));
879                         if (col)
880                                 copy_v3_v3(self->col, col);
881                         else
882                                 zero_v3(self->col);
883
884                         self->wrapped = Py_NEW;
885                 }
886                 else {
887                         Py_FatalError("Color(): invalid type!");
888                 }
889         }
890
891         return (PyObject *)self;
892 }
893
894 PyObject *Color_CreatePyObject_cb(PyObject *cb_user,
895                                   unsigned char cb_type, unsigned char cb_subtype)
896 {
897         ColorObject *self = (ColorObject *)Color_CreatePyObject(NULL, Py_NEW, NULL);
898         if (self) {
899                 Py_INCREF(cb_user);
900                 self->cb_user         = cb_user;
901                 self->cb_type         = cb_type;
902                 self->cb_subtype      = cb_subtype;
903                 PyObject_GC_Track(self);
904         }
905
906         return (PyObject *)self;
907 }