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