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