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