9997cd9c1f589c0b90e272b678458ec300e52eca
[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                         ATTR_FALLTHROUGH;
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 static Py_hash_t Color_hash(ColorObject *self)
196 {
197         if (BaseMath_ReadCallback(self) == -1)
198                 return -1;
199
200         if (BaseMathObject_Prepare_ForHash(self) == -1)
201                 return -1;
202
203         return mathutils_array_hash(self->col, COLOR_SIZE);
204 }
205
206 /* ---------------------SEQUENCE PROTOCOLS------------------------ */
207 /* ----------------------------len(object)------------------------ */
208 /* sequence length */
209 static int Color_len(ColorObject *UNUSED(self))
210 {
211         return COLOR_SIZE;
212 }
213 /* ----------------------------object[]--------------------------- */
214 /* sequence accessor (get) */
215 static PyObject *Color_item(ColorObject *self, int i)
216 {
217         if (i < 0) i = COLOR_SIZE - i;
218
219         if (i < 0 || i >= COLOR_SIZE) {
220                 PyErr_SetString(PyExc_IndexError,
221                                 "color[item]: "
222                                 "array index out of range");
223                 return NULL;
224         }
225
226         if (BaseMath_ReadIndexCallback(self, i) == -1)
227                 return NULL;
228
229         return PyFloat_FromDouble(self->col[i]);
230
231 }
232 /* ----------------------------object[]------------------------- */
233 /* sequence accessor (set) */
234 static int Color_ass_item(ColorObject *self, int i, PyObject *value)
235 {
236         float f;
237
238         if (BaseMath_Prepare_ForWrite(self) == -1)
239                 return -1;
240
241         f = PyFloat_AsDouble(value);
242         if (f == -1 && PyErr_Occurred()) {  /* parsed item not a number */
243                 PyErr_SetString(PyExc_TypeError,
244                                 "color[item] = x: "
245                                 "assigned value not a number");
246                 return -1;
247         }
248
249         if (i < 0) i = COLOR_SIZE - i;
250
251         if (i < 0 || i >= COLOR_SIZE) {
252                 PyErr_SetString(PyExc_IndexError, "color[item] = x: "
253                                 "array assignment index out of range");
254                 return -1;
255         }
256
257         self->col[i] = f;
258
259         if (BaseMath_WriteIndexCallback(self, i) == -1)
260                 return -1;
261
262         return 0;
263 }
264 /* ----------------------------object[z:y]------------------------ */
265 /* sequence slice (get) */
266 static PyObject *Color_slice(ColorObject *self, int begin, int end)
267 {
268         PyObject *tuple;
269         int count;
270
271         if (BaseMath_ReadCallback(self) == -1)
272                 return NULL;
273
274         CLAMP(begin, 0, COLOR_SIZE);
275         if (end < 0) end = (COLOR_SIZE + 1) + end;
276         CLAMP(end, 0, COLOR_SIZE);
277         begin = MIN2(begin, end);
278
279         tuple = PyTuple_New(end - begin);
280         for (count = begin; count < end; count++) {
281                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->col[count]));
282         }
283
284         return tuple;
285 }
286 /* ----------------------------object[z:y]------------------------ */
287 /* sequence slice (set) */
288 static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
289 {
290         int i, size;
291         float col[COLOR_SIZE];
292
293         if (BaseMath_ReadCallback_ForWrite(self) == -1)
294                 return -1;
295
296         CLAMP(begin, 0, COLOR_SIZE);
297         if (end < 0) end = (COLOR_SIZE + 1) + end;
298         CLAMP(end, 0, COLOR_SIZE);
299         begin = MIN2(begin, end);
300
301         if ((size = mathutils_array_parse(col, 0, COLOR_SIZE, seq, "mathutils.Color[begin:end] = []")) == -1)
302                 return -1;
303
304         if (size != (end - begin)) {
305                 PyErr_SetString(PyExc_ValueError,
306                                 "color[begin:end] = []: "
307                                 "size mismatch in slice assignment");
308                 return -1;
309         }
310
311         for (i = 0; i < COLOR_SIZE; i++)
312                 self->col[begin + i] = col[i];
313
314         (void)BaseMath_WriteCallback(self);
315         return 0;
316 }
317
318 static PyObject *Color_subscript(ColorObject *self, PyObject *item)
319 {
320         if (PyIndex_Check(item)) {
321                 Py_ssize_t i;
322                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
323                 if (i == -1 && PyErr_Occurred())
324                         return NULL;
325                 if (i < 0)
326                         i += COLOR_SIZE;
327                 return Color_item(self, i);
328         }
329         else if (PySlice_Check(item)) {
330                 Py_ssize_t start, stop, step, slicelength;
331
332                 if (PySlice_GetIndicesEx(item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
333                         return NULL;
334
335                 if (slicelength <= 0) {
336                         return PyTuple_New(0);
337                 }
338                 else if (step == 1) {
339                         return Color_slice(self, start, stop);
340                 }
341                 else {
342                         PyErr_SetString(PyExc_IndexError,
343                                         "slice steps not supported with color");
344                         return NULL;
345                 }
346         }
347         else {
348                 PyErr_Format(PyExc_TypeError,
349                              "color indices must be integers, not %.200s",
350                              Py_TYPE(item)->tp_name);
351                 return NULL;
352         }
353 }
354
355 static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
356 {
357         if (PyIndex_Check(item)) {
358                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
359                 if (i == -1 && PyErr_Occurred())
360                         return -1;
361                 if (i < 0)
362                         i += COLOR_SIZE;
363                 return Color_ass_item(self, i, value);
364         }
365         else if (PySlice_Check(item)) {
366                 Py_ssize_t start, stop, step, slicelength;
367
368                 if (PySlice_GetIndicesEx(item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0)
369                         return -1;
370
371                 if (step == 1)
372                         return Color_ass_slice(self, start, stop, value);
373                 else {
374                         PyErr_SetString(PyExc_IndexError,
375                                         "slice steps not supported with color");
376                         return -1;
377                 }
378         }
379         else {
380                 PyErr_Format(PyExc_TypeError,
381                              "color indices must be integers, not %.200s",
382                              Py_TYPE(item)->tp_name);
383                 return -1;
384         }
385 }
386
387 /* -----------------PROTCOL DECLARATIONS-------------------------- */
388 static PySequenceMethods Color_SeqMethods = {
389         (lenfunc) Color_len,                    /* sq_length */
390         (binaryfunc) NULL,                      /* sq_concat */
391         (ssizeargfunc) NULL,                    /* sq_repeat */
392         (ssizeargfunc) Color_item,              /* sq_item */
393         NULL,                                   /* sq_slice, deprecated */
394         (ssizeobjargproc) Color_ass_item,       /* sq_ass_item */
395         NULL,                                   /* sq_ass_slice, deprecated */
396         (objobjproc) NULL,                      /* sq_contains */
397         (binaryfunc) NULL,                      /* sq_inplace_concat */
398         (ssizeargfunc) NULL,                    /* sq_inplace_repeat */
399 };
400
401 static PyMappingMethods Color_AsMapping = {
402         (lenfunc)Color_len,
403         (binaryfunc)Color_subscript,
404         (objobjargproc)Color_ass_subscript
405 };
406
407 /* numeric */
408
409
410 /* addition: obj + obj */
411 static PyObject *Color_add(PyObject *v1, PyObject *v2)
412 {
413         ColorObject *color1 = NULL, *color2 = NULL;
414         float col[COLOR_SIZE];
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_vnvn(col, color1->col, color2->col, COLOR_SIZE);
430
431         return Color_CreatePyObject(col, Py_TYPE(v1));
432 }
433
434 /* addition in-place: obj += obj */
435 static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
436 {
437         ColorObject *color1 = NULL, *color2 = NULL;
438
439         if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
440                 PyErr_Format(PyExc_TypeError,
441                              "Color addition: (%s += %s) "
442                              "invalid type for this operation",
443                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
444                 return NULL;
445         }
446         color1 = (ColorObject *)v1;
447         color2 = (ColorObject *)v2;
448
449         if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
450                 return NULL;
451
452         add_vn_vn(color1->col, color2->col, COLOR_SIZE);
453
454         (void)BaseMath_WriteCallback(color1);
455         Py_INCREF(v1);
456         return v1;
457 }
458
459 /* subtraction: obj - obj */
460 static PyObject *Color_sub(PyObject *v1, PyObject *v2)
461 {
462         ColorObject *color1 = NULL, *color2 = NULL;
463         float col[COLOR_SIZE];
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_vnvn(col, color1->col, color2->col, COLOR_SIZE);
479
480         return Color_CreatePyObject(col, Py_TYPE(v1));
481 }
482
483 /* subtraction in-place: obj -= obj */
484 static PyObject *Color_isub(PyObject *v1, PyObject *v2)
485 {
486         ColorObject *color1 = NULL, *color2 = NULL;
487
488         if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
489                 PyErr_Format(PyExc_TypeError,
490                              "Color subtraction: (%s -= %s) "
491                              "invalid type for this operation",
492                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
493                 return NULL;
494         }
495         color1 = (ColorObject *)v1;
496         color2 = (ColorObject *)v2;
497
498         if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1)
499                 return NULL;
500
501         sub_vn_vn(color1->col, color2->col, COLOR_SIZE);
502
503         (void)BaseMath_WriteCallback(color1);
504         Py_INCREF(v1);
505         return v1;
506 }
507
508 static PyObject *color_mul_float(ColorObject *color, const float scalar)
509 {
510         float tcol[COLOR_SIZE];
511         mul_vn_vn_fl(tcol, color->col, COLOR_SIZE, scalar);
512         return Color_CreatePyObject(tcol, Py_TYPE(color));
513 }
514
515
516 static PyObject *Color_mul(PyObject *v1, PyObject *v2)
517 {
518         ColorObject *color1 = NULL, *color2 = NULL;
519         float scalar;
520
521         if (ColorObject_Check(v1)) {
522                 color1 = (ColorObject *)v1;
523                 if (BaseMath_ReadCallback(color1) == -1)
524                         return NULL;
525         }
526         if (ColorObject_Check(v2)) {
527                 color2 = (ColorObject *)v2;
528                 if (BaseMath_ReadCallback(color2) == -1)
529                         return NULL;
530         }
531
532
533         /* make sure v1 is always the vector */
534         if (color1 && color2) {
535                 /* col * col, don't support yet! */
536         }
537         else if (color1) {
538                 if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR * FLOAT */
539                         return color_mul_float(color1, scalar);
540                 }
541         }
542         else if (color2) {
543                 if (((scalar = PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred()) == 0) { /* FLOAT * COLOR */
544                         return color_mul_float(color2, scalar);
545                 }
546         }
547         else {
548                 BLI_assert(!"internal error");
549         }
550
551         PyErr_Format(PyExc_TypeError,
552                      "Color multiplication: not supported between "
553                      "'%.200s' and '%.200s' types",
554                      Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
555         return NULL;
556 }
557
558 static PyObject *Color_div(PyObject *v1, PyObject *v2)
559 {
560         ColorObject *color1 = NULL;
561         float scalar;
562
563         if (ColorObject_Check(v1)) {
564                 color1 = (ColorObject *)v1;
565                 if (BaseMath_ReadCallback(color1) == -1)
566                         return NULL;
567         }
568         else {
569                 PyErr_SetString(PyExc_TypeError,
570                                 "Color division not supported in this order");
571                 return NULL;
572         }
573
574         /* make sure v1 is always the vector */
575         if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR * FLOAT */
576                 if (scalar == 0.0f) {
577                         PyErr_SetString(PyExc_ZeroDivisionError,
578                                         "Color division: divide by zero error");
579                         return NULL;
580                 }
581                 return color_mul_float(color1, 1.0f / scalar);
582         }
583
584         PyErr_Format(PyExc_TypeError,
585                      "Color multiplication: not supported between "
586                      "'%.200s' and '%.200s' types",
587                      Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
588         return NULL;
589 }
590
591 /* multiplication in-place: obj *= obj */
592 static PyObject *Color_imul(PyObject *v1, PyObject *v2)
593 {
594         ColorObject *color = (ColorObject *)v1;
595         float scalar;
596
597         if (BaseMath_ReadCallback_ForWrite(color) == -1)
598                 return NULL;
599
600         /* only support color *= float */
601         if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR *= FLOAT */
602                 mul_vn_fl(color->col, COLOR_SIZE, scalar);
603         }
604         else {
605                 PyErr_Format(PyExc_TypeError,
606                              "Color multiplication: (%s *= %s) "
607                              "invalid type for this operation",
608                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
609                 return NULL;
610         }
611
612         (void)BaseMath_WriteCallback(color);
613         Py_INCREF(v1);
614         return v1;
615 }
616
617 /* multiplication in-place: obj *= obj */
618 static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
619 {
620         ColorObject *color = (ColorObject *)v1;
621         float scalar;
622
623         if (BaseMath_ReadCallback_ForWrite(color) == -1)
624                 return NULL;
625
626         /* only support color /= float */
627         if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR /= FLOAT */
628                 if (scalar == 0.0f) {
629                         PyErr_SetString(PyExc_ZeroDivisionError,
630                                         "Color division: divide by zero error");
631                         return NULL;
632                 }
633
634                 mul_vn_fl(color->col, COLOR_SIZE, 1.0f / scalar);
635         }
636         else {
637                 PyErr_Format(PyExc_TypeError,
638                              "Color division: (%s /= %s) "
639                              "invalid type for this operation",
640                              Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
641                 return NULL;
642         }
643
644         (void)BaseMath_WriteCallback(color);
645         Py_INCREF(v1);
646         return v1;
647 }
648
649 /* -obj
650  * returns the negative of this object */
651 static PyObject *Color_neg(ColorObject *self)
652 {
653         float tcol[COLOR_SIZE];
654
655         if (BaseMath_ReadCallback(self) == -1)
656                 return NULL;
657
658         negate_vn_vn(tcol, self->col, COLOR_SIZE);
659         return Color_CreatePyObject(tcol, Py_TYPE(self));
660 }
661
662
663 static PyNumberMethods Color_NumMethods = {
664         (binaryfunc) Color_add, /*nb_add*/
665         (binaryfunc) Color_sub, /*nb_subtract*/
666         (binaryfunc) Color_mul, /*nb_multiply*/
667         NULL,               /*nb_remainder*/
668         NULL,               /*nb_divmod*/
669         NULL,               /*nb_power*/
670         (unaryfunc) Color_neg,   /*nb_negative*/
671         (unaryfunc) Color_copy,  /*tp_positive*/
672         (unaryfunc) NULL,   /*tp_absolute*/
673         (inquiry)   NULL,   /*tp_bool*/
674         (unaryfunc) NULL,   /*nb_invert*/
675         NULL,               /*nb_lshift*/
676         (binaryfunc)NULL,   /*nb_rshift*/
677         NULL,               /*nb_and*/
678         NULL,               /*nb_xor*/
679         NULL,               /*nb_or*/
680         NULL,               /*nb_int*/
681         NULL,               /*nb_reserved*/
682         NULL,               /*nb_float*/
683         Color_iadd,         /* nb_inplace_add */
684         Color_isub,         /* nb_inplace_subtract */
685         Color_imul,         /* nb_inplace_multiply */
686         NULL,               /* nb_inplace_remainder */
687         NULL,               /* nb_inplace_power */
688         NULL,               /* nb_inplace_lshift */
689         NULL,               /* nb_inplace_rshift */
690         NULL,               /* nb_inplace_and */
691         NULL,               /* nb_inplace_xor */
692         NULL,               /* nb_inplace_or */
693         NULL,               /* nb_floor_divide */
694         Color_div,          /* nb_true_divide */
695         NULL,               /* nb_inplace_floor_divide */
696         Color_idiv,         /* nb_inplace_true_divide */
697         NULL,               /* nb_index */
698 };
699
700 /* color channel, vector.r/g/b */
701 PyDoc_STRVAR(Color_channel_r_doc, "Red color channel.\n\n:type: float");
702 PyDoc_STRVAR(Color_channel_g_doc, "Green color channel.\n\n:type: float");
703 PyDoc_STRVAR(Color_channel_b_doc, "Blue color channel.\n\n:type: float");
704
705 static PyObject *Color_channel_get(ColorObject *self, void *type)
706 {
707         return Color_item(self, GET_INT_FROM_POINTER(type));
708 }
709
710 static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
711 {
712         return Color_ass_item(self, GET_INT_FROM_POINTER(type), value);
713 }
714
715 /* color channel (HSV), color.h/s/v */
716 PyDoc_STRVAR(Color_channel_hsv_h_doc, "HSV Hue component in [0, 1].\n\n:type: float");
717 PyDoc_STRVAR(Color_channel_hsv_s_doc, "HSV Saturation component in [0, 1].\n\n:type: float");
718 PyDoc_STRVAR(Color_channel_hsv_v_doc, "HSV Value component in [0, 1].\n\n:type: float");
719
720 static PyObject *Color_channel_hsv_get(ColorObject *self, void *type)
721 {
722         float hsv[3];
723         int i = GET_INT_FROM_POINTER(type);
724
725         if (BaseMath_ReadCallback(self) == -1)
726                 return NULL;
727
728         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
729
730         return PyFloat_FromDouble(hsv[i]);
731 }
732
733 static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
734 {
735         float hsv[3];
736         int i = GET_INT_FROM_POINTER(type);
737         float f = PyFloat_AsDouble(value);
738
739         if (f == -1 && PyErr_Occurred()) {
740                 PyErr_SetString(PyExc_TypeError,
741                                 "color.h/s/v = value: "
742                                 "assigned value not a number");
743                 return -1;
744         }
745
746         if (BaseMath_ReadCallback_ForWrite(self) == -1)
747                 return -1;
748
749         rgb_to_hsv_v(self->col, hsv);
750         CLAMP(f, 0.0f, 1.0f);
751         hsv[i] = f;
752         hsv_to_rgb_v(hsv, self->col);
753
754         if (BaseMath_WriteCallback(self) == -1)
755                 return -1;
756
757         return 0;
758 }
759
760 /* color channel (HSV), color.h/s/v */
761 PyDoc_STRVAR(Color_hsv_doc, "HSV Values in [0, 1].\n\n:type: float triplet");
762 static PyObject *Color_hsv_get(ColorObject *self, void *UNUSED(closure))
763 {
764         float hsv[3];
765         PyObject *ret;
766
767         if (BaseMath_ReadCallback(self) == -1)
768                 return NULL;
769
770         rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
771
772         ret = PyTuple_New(3);
773         PyTuple_SET_ITEMS(ret,
774                 PyFloat_FromDouble(hsv[0]),
775                 PyFloat_FromDouble(hsv[1]),
776                 PyFloat_FromDouble(hsv[2]));
777         return ret;
778 }
779
780 static int Color_hsv_set(ColorObject *self, PyObject *value, void *UNUSED(closure))
781 {
782         float hsv[3];
783
784         if (mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1)
785                 return -1;
786
787         if (BaseMath_Prepare_ForWrite(self) == -1)
788                 return -1;
789
790         CLAMP(hsv[0], 0.0f, 1.0f);
791         CLAMP(hsv[1], 0.0f, 1.0f);
792         CLAMP(hsv[2], 0.0f, 1.0f);
793
794         hsv_to_rgb_v(hsv, self->col);
795
796         if (BaseMath_WriteCallback(self) == -1)
797                 return -1;
798
799         return 0;
800 }
801
802 /*****************************************************************************/
803 /* Python attributes get/set structure:                                      */
804 /*****************************************************************************/
805 static PyGetSetDef Color_getseters[] = {
806         {(char *)"r", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_r_doc, (void *)0},
807         {(char *)"g", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_g_doc, (void *)1},
808         {(char *)"b", (getter)Color_channel_get, (setter)Color_channel_set, Color_channel_b_doc, (void *)2},
809
810         {(char *)"h", (getter)Color_channel_hsv_get, (setter)Color_channel_hsv_set, (char *)Color_channel_hsv_h_doc, (void *)0},
811         {(char *)"s", (getter)Color_channel_hsv_get, (setter)Color_channel_hsv_set, (char *)Color_channel_hsv_s_doc, (void *)1},
812         {(char *)"v", (getter)Color_channel_hsv_get, (setter)Color_channel_hsv_set, (char *)Color_channel_hsv_v_doc, (void *)2},
813
814         {(char *)"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, (char *)Color_hsv_doc, (void *)0},
815
816         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
817         {(char *)"is_frozen",  (getter)BaseMathObject_is_frozen_get,  (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
818         {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
819         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
820 };
821
822
823 /* -----------------------METHOD DEFINITIONS ---------------------- */
824 static struct PyMethodDef Color_methods[] = {
825         {"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
826         {"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc},
827         {"__deepcopy__", (PyCFunction) Color_deepcopy, METH_VARARGS, Color_copy_doc},
828
829         /* base-math methods */
830         {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
831         {NULL, NULL, 0, NULL}
832 };
833
834 /* ------------------PY_OBECT DEFINITION-------------------------- */
835 PyDoc_STRVAR(color_doc,
836 ".. class:: Color(rgb)\n"
837 "\n"
838 "   This object gives access to Colors in Blender.\n"
839 "\n"
840 "   :param rgb: (r, g, b) color values\n"
841 "   :type rgb: 3d vector\n"
842 );
843 PyTypeObject color_Type = {
844         PyVarObject_HEAD_INIT(NULL, 0)
845         "Color",                        /* tp_name */
846         sizeof(ColorObject),            /* tp_basicsize */
847         0,                              /* tp_itemsize */
848         (destructor)BaseMathObject_dealloc,  /* tp_dealloc */
849         NULL,                           /* tp_print */
850         NULL,                           /* tp_getattr */
851         NULL,                           /* tp_setattr */
852         NULL,                           /* tp_compare */
853         (reprfunc) Color_repr,          /* tp_repr */
854         &Color_NumMethods,              /* tp_as_number */
855         &Color_SeqMethods,              /* tp_as_sequence */
856         &Color_AsMapping,               /* tp_as_mapping */
857         (hashfunc)Color_hash,           /* tp_hash */
858         NULL,                           /* tp_call */
859 #ifndef MATH_STANDALONE
860         (reprfunc) Color_str,           /* tp_str */
861 #else
862         NULL,                           /* tp_str */
863 #endif
864         NULL,                           /* tp_getattro */
865         NULL,                           /* tp_setattro */
866         NULL,                           /* tp_as_buffer */
867         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
868         color_doc, /* tp_doc */
869         (traverseproc)BaseMathObject_traverse,  /* tp_traverse */
870         (inquiry)BaseMathObject_clear,  /* tp_clear */
871         (richcmpfunc)Color_richcmpr,    /* tp_richcompare */
872         0,                              /* tp_weaklistoffset */
873         NULL,                           /* tp_iter */
874         NULL,                           /* tp_iternext */
875         Color_methods,                  /* tp_methods */
876         NULL,                           /* tp_members */
877         Color_getseters,                /* tp_getset */
878         NULL,                           /* tp_base */
879         NULL,                           /* tp_dict */
880         NULL,                           /* tp_descr_get */
881         NULL,                           /* tp_descr_set */
882         0,                              /* tp_dictoffset */
883         NULL,                           /* tp_init */
884         NULL,                           /* tp_alloc */
885         Color_new,                      /* tp_new */
886         NULL,                           /* tp_free */
887         NULL,                           /* tp_is_gc */
888         NULL,                           /* tp_bases */
889         NULL,                           /* tp_mro */
890         NULL,                           /* tp_cache */
891         NULL,                           /* tp_subclasses */
892         NULL,                           /* tp_weaklist */
893         NULL                            /* tp_del */
894 };
895
896 PyObject *Color_CreatePyObject(
897         const float col[3],
898         PyTypeObject *base_type)
899 {
900         ColorObject *self;
901         float *col_alloc;
902
903         col_alloc = PyMem_Malloc(COLOR_SIZE * sizeof(float));
904         if (UNLIKELY(col_alloc == NULL)) {
905                 PyErr_SetString(PyExc_MemoryError,
906                                 "Color(): "
907                                 "problem allocating data");
908                 return NULL;
909         }
910
911         self = BASE_MATH_NEW(ColorObject, color_Type, base_type);
912         if (self) {
913                 self->col = col_alloc;
914
915                 /* init callbacks as NULL */
916                 self->cb_user = NULL;
917                 self->cb_type = self->cb_subtype = 0;
918
919                 /* NEW */
920                 if (col)
921                         copy_v3_v3(self->col, col);
922                 else
923                         zero_v3(self->col);
924
925                 self->flag = BASE_MATH_FLAG_DEFAULT;
926         }
927         else {
928                 PyMem_Free(col_alloc);
929         }
930
931         return (PyObject *)self;
932 }
933
934 PyObject *Color_CreatePyObject_wrap(
935         float col[3],
936         PyTypeObject *base_type)
937 {
938         ColorObject *self;
939
940         self = BASE_MATH_NEW(ColorObject, color_Type, base_type);
941         if (self) {
942                 /* init callbacks as NULL */
943                 self->cb_user = NULL;
944                 self->cb_type = self->cb_subtype = 0;
945
946                 /* WRAP */
947                 self->col = col;
948                 self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
949         }
950
951         return (PyObject *)self;
952 }
953
954 PyObject *Color_CreatePyObject_cb(PyObject *cb_user,
955                                   unsigned char cb_type, unsigned char cb_subtype)
956 {
957         ColorObject *self = (ColorObject *)Color_CreatePyObject(NULL, NULL);
958         if (self) {
959                 Py_INCREF(cb_user);
960                 self->cb_user         = cb_user;
961                 self->cb_type         = cb_type;
962                 self->cb_subtype      = cb_subtype;
963                 PyObject_GC_Track(self);
964         }
965
966         return (PyObject *)self;
967 }