Blender V4.3
mathutils_Color.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10
11#include <Python.h>
12
13#include "mathutils.hh"
14
15#include "BLI_utildefines.h"
16
19
20#ifndef MATH_STANDALONE
21# include "IMB_colormanagement.hh"
22#endif
23
24#ifndef MATH_STANDALONE
25# include "BLI_dynstr.h"
26#endif
27
28#define COLOR_SIZE 3
29
30/* -------------------------------------------------------------------- */
37static PyObject *Color_to_tuple_ex(ColorObject *self, int ndigits)
38{
39 PyObject *ret;
40 int i;
41
42 ret = PyTuple_New(COLOR_SIZE);
43
44 if (ndigits >= 0) {
45 for (i = 0; i < COLOR_SIZE; i++) {
46 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round(double(self->col[i]), ndigits)));
47 }
48 }
49 else {
50 for (i = 0; i < COLOR_SIZE; i++) {
51 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i]));
52 }
53 }
54
55 return ret;
56}
57
60/* -------------------------------------------------------------------- */
64static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
65{
66 float col[3] = {0.0f, 0.0f, 0.0f};
67
68 if (kwds && PyDict_Size(kwds)) {
69 PyErr_SetString(PyExc_TypeError,
70 "mathutils.Color(): "
71 "takes no keyword args");
72 return nullptr;
73 }
74
75 switch (PyTuple_GET_SIZE(args)) {
76 case 0:
77 break;
78 case 1:
80 col, COLOR_SIZE, COLOR_SIZE, PyTuple_GET_ITEM(args, 0), "mathutils.Color()") == -1)
81 {
82 return nullptr;
83 }
84 break;
85 default:
86 PyErr_SetString(PyExc_TypeError,
87 "mathutils.Color(): "
88 "more than a single arg given");
89 return nullptr;
90 }
91 return Color_CreatePyObject(col, type);
92}
93
96/* -------------------------------------------------------------------- */
100#ifndef MATH_STANDALONE
101
103 /* Wrap. */
104 Color_from_scene_linear_to_srgb_doc,
105 ".. function:: from_scene_linear_to_srgb()\n"
106 "\n"
107 " Convert from scene linear to sRGB color space.\n"
108 "\n"
109 " :return: A color in sRGB color space.\n"
110 " :rtype: :class:`Color`\n");
112{
113 float col[3];
115 return Color_CreatePyObject(col, Py_TYPE(self));
116}
117
119 /* Wrap. */
120 Color_from_srgb_to_scene_linear_doc,
121 ".. function:: from_srgb_to_scene_linear()\n"
122 "\n"
123 " Convert from sRGB to scene linear color space.\n"
124 "\n"
125 " :return: A color in scene linear color space.\n"
126 " :rtype: :class:`Color`\n");
128{
129 float col[3];
131 return Color_CreatePyObject(col, Py_TYPE(self));
132}
133
135 /* Wrap. */
136 Color_from_scene_linear_to_xyz_d65_doc,
137 ".. function:: from_scene_linear_to_xyz_d65()\n"
138 "\n"
139 " Convert from scene linear to CIE XYZ (Illuminant D65) color space.\n"
140 "\n"
141 " :return: A color in XYZ color space.\n"
142 " :rtype: :class:`Color`\n");
144{
145 float col[3];
147 return Color_CreatePyObject(col, Py_TYPE(self));
148}
149
151 /* Wrap. */
152 Color_from_xyz_d65_to_scene_linear_doc,
153 ".. function:: from_xyz_d65_to_scene_linear()\n"
154 "\n"
155 " Convert from CIE XYZ (Illuminant D65) to scene linear color space.\n"
156 "\n"
157 " :return: A color in scene linear color space.\n"
158 " :rtype: :class:`Color`\n");
160{
161 float col[3];
163 return Color_CreatePyObject(col, Py_TYPE(self));
164}
165
167 /* Wrap. */
168 Color_from_scene_linear_to_aces_doc,
169 ".. function:: from_scene_linear_to_aces()\n"
170 "\n"
171 " Convert from scene linear to ACES2065-1 linear color space.\n"
172 "\n"
173 " :return: A color in ACES2065-1 linear color space.\n"
174 " :rtype: :class:`Color`\n");
176{
177 float col[3];
179 return Color_CreatePyObject(col, Py_TYPE(self));
180}
181
183 /* Wrap. */
184 Color_from_aces_to_scene_linear_doc,
185 ".. function:: from_aces_to_scene_linear()\n"
186 "\n"
187 " Convert from ACES2065-1 linear to scene linear color space.\n"
188 "\n"
189 " :return: A color in scene linear color space.\n"
190 " :rtype: :class:`Color`\n");
192{
193 float col[3];
195 return Color_CreatePyObject(col, Py_TYPE(self));
196}
197
199 /* Wrap. */
200 Color_from_scene_linear_to_rec709_linear_doc,
201 ".. function:: from_scene_linear_to_rec709_linear()\n"
202 "\n"
203 " Convert from scene linear to Rec.709 linear color space.\n"
204 "\n"
205 " :return: A color in Rec.709 linear color space.\n"
206 " :rtype: :class:`Color`\n");
213
215 /* Wrap. */
216 Color_from_rec709_linear_to_scene_linear_doc,
217 ".. function:: from_rec709_linear_to_scene_linear()\n"
218 "\n"
219 " Convert from Rec.709 linear color space to scene linear color space.\n"
220 "\n"
221 " :return: A color in scene linear color space.\n"
222 " :rtype: :class:`Color`\n");
229
230#endif /* !MATH_STANDALONE */
231
234/* -------------------------------------------------------------------- */
239 /* Wrap. */
240 Color_copy_doc,
241 ".. function:: copy()\n"
242 "\n"
243 " Returns a copy of this color.\n"
244 "\n"
245 " :return: A copy of the color.\n"
246 " :rtype: :class:`Color`\n"
247 "\n"
248 " .. note:: use this to get a copy of a wrapped color with\n"
249 " no reference to the original data.\n");
250static PyObject *Color_copy(ColorObject *self)
251{
252 if (BaseMath_ReadCallback(self) == -1) {
253 return nullptr;
254 }
255
256 return Color_CreatePyObject(self->col, Py_TYPE(self));
257}
258static PyObject *Color_deepcopy(ColorObject *self, PyObject *args)
259{
260 if (!PyC_CheckArgs_DeepCopy(args)) {
261 return nullptr;
262 }
263 return Color_copy(self);
264}
265
268/* -------------------------------------------------------------------- */
272static PyObject *Color_repr(ColorObject *self)
273{
274 PyObject *ret, *tuple;
275
276 if (BaseMath_ReadCallback(self) == -1) {
277 return nullptr;
278 }
279
280 tuple = Color_to_tuple_ex(self, -1);
281
282 ret = PyUnicode_FromFormat("Color(%R)", tuple);
283
284 Py_DECREF(tuple);
285 return ret;
286}
287
288#ifndef MATH_STANDALONE
289static PyObject *Color_str(ColorObject *self)
290{
291 DynStr *ds;
292
293 if (BaseMath_ReadCallback(self) == -1) {
294 return nullptr;
295 }
296
297 ds = BLI_dynstr_new();
298
300 ds, "<Color (r=%.4f, g=%.4f, b=%.4f)>", self->col[0], self->col[1], self->col[2]);
301
302 return mathutils_dynstr_to_py(ds); /* frees ds */
303}
304#endif
305
308/* -------------------------------------------------------------------- */
312static PyObject *Color_richcmpr(PyObject *a, PyObject *b, int op)
313{
314 PyObject *res;
315 int ok = -1; /* zero is true */
316
318 ColorObject *colA = (ColorObject *)a;
319 ColorObject *colB = (ColorObject *)b;
320
321 if (BaseMath_ReadCallback(colA) == -1 || BaseMath_ReadCallback(colB) == -1) {
322 return nullptr;
323 }
324
325 ok = EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1) ? 0 : -1;
326 }
327
328 switch (op) {
329 case Py_NE:
330 ok = !ok;
332 case Py_EQ:
333 res = ok ? Py_False : Py_True;
334 break;
335
336 case Py_LT:
337 case Py_LE:
338 case Py_GT:
339 case Py_GE:
340 res = Py_NotImplemented;
341 break;
342 default:
343 PyErr_BadArgument();
344 return nullptr;
345 }
346
347 return Py_NewRef(res);
348}
349
352/* -------------------------------------------------------------------- */
356static Py_hash_t Color_hash(ColorObject *self)
357{
358 if (BaseMath_ReadCallback(self) == -1) {
359 return -1;
360 }
361
363 return -1;
364 }
365
367}
368
371/* -------------------------------------------------------------------- */
376static Py_ssize_t Color_len(ColorObject * /*self*/)
377{
378 return COLOR_SIZE;
379}
380
382static PyObject *Color_item(ColorObject *self, Py_ssize_t i)
383{
384 if (i < 0) {
385 i = COLOR_SIZE - i;
386 }
387
388 if (i < 0 || i >= COLOR_SIZE) {
389 PyErr_SetString(PyExc_IndexError,
390 "color[item]: "
391 "array index out of range");
392 return nullptr;
393 }
394
395 if (BaseMath_ReadIndexCallback(self, i) == -1) {
396 return nullptr;
397 }
398
399 return PyFloat_FromDouble(self->col[i]);
400}
401
403static int Color_ass_item(ColorObject *self, Py_ssize_t i, PyObject *value)
404{
405 float f;
406
407 if (BaseMath_Prepare_ForWrite(self) == -1) {
408 return -1;
409 }
410
411 f = PyFloat_AsDouble(value);
412 if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */
413 PyErr_SetString(PyExc_TypeError,
414 "color[item] = x: "
415 "assigned value not a number");
416 return -1;
417 }
418
419 if (i < 0) {
420 i = COLOR_SIZE - i;
421 }
422
423 if (i < 0 || i >= COLOR_SIZE) {
424 PyErr_SetString(PyExc_IndexError,
425 "color[item] = x: "
426 "array assignment index out of range");
427 return -1;
428 }
429
430 self->col[i] = f;
431
432 if (BaseMath_WriteIndexCallback(self, i) == -1) {
433 return -1;
434 }
435
436 return 0;
437}
438
440static PyObject *Color_slice(ColorObject *self, int begin, int end)
441{
442 PyObject *tuple;
443 int count;
444
445 if (BaseMath_ReadCallback(self) == -1) {
446 return nullptr;
447 }
448
449 CLAMP(begin, 0, COLOR_SIZE);
450 if (end < 0) {
451 end = (COLOR_SIZE + 1) + end;
452 }
453 CLAMP(end, 0, COLOR_SIZE);
454 begin = std::min(begin, end);
455
456 tuple = PyTuple_New(end - begin);
457 for (count = begin; count < end; count++) {
458 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->col[count]));
459 }
460
461 return tuple;
462}
463
465static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
466{
467 int i, size;
468 float col[COLOR_SIZE];
469
471 return -1;
472 }
473
474 CLAMP(begin, 0, COLOR_SIZE);
475 if (end < 0) {
476 end = (COLOR_SIZE + 1) + end;
477 }
478 CLAMP(end, 0, COLOR_SIZE);
479 begin = std::min(begin, end);
480
481 if ((size = mathutils_array_parse(col, 0, COLOR_SIZE, seq, "mathutils.Color[begin:end] = []")) ==
482 -1)
483 {
484 return -1;
485 }
486
487 if (size != (end - begin)) {
488 PyErr_SetString(PyExc_ValueError,
489 "color[begin:end] = []: "
490 "size mismatch in slice assignment");
491 return -1;
492 }
493
494 for (i = 0; i < COLOR_SIZE; i++) {
495 self->col[begin + i] = col[i];
496 }
497
499 return 0;
500}
501
503static PyObject *Color_subscript(ColorObject *self, PyObject *item)
504{
505 if (PyIndex_Check(item)) {
506 Py_ssize_t i;
507 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
508 if (i == -1 && PyErr_Occurred()) {
509 return nullptr;
510 }
511 if (i < 0) {
512 i += COLOR_SIZE;
513 }
514 return Color_item(self, i);
515 }
516 if (PySlice_Check(item)) {
517 Py_ssize_t start, stop, step, slicelength;
518
519 if (PySlice_GetIndicesEx(item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0) {
520 return nullptr;
521 }
522
523 if (slicelength <= 0) {
524 return PyTuple_New(0);
525 }
526 if (step == 1) {
527 return Color_slice(self, start, stop);
528 }
529
530 PyErr_SetString(PyExc_IndexError, "slice steps not supported with color");
531 return nullptr;
532 }
533
534 PyErr_Format(
535 PyExc_TypeError, "color indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
536 return nullptr;
537}
538
540static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
541{
542 if (PyIndex_Check(item)) {
543 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
544 if (i == -1 && PyErr_Occurred()) {
545 return -1;
546 }
547 if (i < 0) {
548 i += COLOR_SIZE;
549 }
550 return Color_ass_item(self, i, value);
551 }
552 if (PySlice_Check(item)) {
553 Py_ssize_t start, stop, step, slicelength;
554
555 if (PySlice_GetIndicesEx(item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0) {
556 return -1;
557 }
558
559 if (step == 1) {
560 return Color_ass_slice(self, start, stop, value);
561 }
562
563 PyErr_SetString(PyExc_IndexError, "slice steps not supported with color");
564 return -1;
565 }
566
567 PyErr_Format(
568 PyExc_TypeError, "color indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
569 return -1;
570}
571
574/* -------------------------------------------------------------------- */
579static PyObject *Color_add(PyObject *v1, PyObject *v2)
580{
581 ColorObject *color1 = nullptr, *color2 = nullptr;
582 float col[COLOR_SIZE];
583
584 if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
585 PyErr_Format(PyExc_TypeError,
586 "Color addition: (%s + %s) "
587 "invalid type for this operation",
588 Py_TYPE(v1)->tp_name,
589 Py_TYPE(v2)->tp_name);
590 return nullptr;
591 }
592 color1 = (ColorObject *)v1;
593 color2 = (ColorObject *)v2;
594
595 if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) {
596 return nullptr;
597 }
598
599 add_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE);
600
601 return Color_CreatePyObject(col, Py_TYPE(v1));
602}
603
605static PyObject *Color_iadd(PyObject *v1, PyObject *v2)
606{
607 ColorObject *color1 = nullptr, *color2 = nullptr;
608
609 if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
610 PyErr_Format(PyExc_TypeError,
611 "Color addition: (%s += %s) "
612 "invalid type for this operation",
613 Py_TYPE(v1)->tp_name,
614 Py_TYPE(v2)->tp_name);
615 return nullptr;
616 }
617 color1 = (ColorObject *)v1;
618 color2 = (ColorObject *)v2;
619
620 if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1) {
621 return nullptr;
622 }
623
624 add_vn_vn(color1->col, color2->col, COLOR_SIZE);
625
626 (void)BaseMath_WriteCallback(color1);
627 Py_INCREF(v1);
628 return v1;
629}
630
632static PyObject *Color_sub(PyObject *v1, PyObject *v2)
633{
634 ColorObject *color1 = nullptr, *color2 = nullptr;
635 float col[COLOR_SIZE];
636
637 if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
638 PyErr_Format(PyExc_TypeError,
639 "Color subtraction: (%s - %s) "
640 "invalid type for this operation",
641 Py_TYPE(v1)->tp_name,
642 Py_TYPE(v2)->tp_name);
643 return nullptr;
644 }
645 color1 = (ColorObject *)v1;
646 color2 = (ColorObject *)v2;
647
648 if (BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) {
649 return nullptr;
650 }
651
652 sub_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE);
653
654 return Color_CreatePyObject(col, Py_TYPE(v1));
655}
656
658static PyObject *Color_isub(PyObject *v1, PyObject *v2)
659{
660 ColorObject *color1 = nullptr, *color2 = nullptr;
661
662 if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) {
663 PyErr_Format(PyExc_TypeError,
664 "Color subtraction: (%s -= %s) "
665 "invalid type for this operation",
666 Py_TYPE(v1)->tp_name,
667 Py_TYPE(v2)->tp_name);
668 return nullptr;
669 }
670 color1 = (ColorObject *)v1;
671 color2 = (ColorObject *)v2;
672
673 if (BaseMath_ReadCallback_ForWrite(color1) == -1 || BaseMath_ReadCallback(color2) == -1) {
674 return nullptr;
675 }
676
677 sub_vn_vn(color1->col, color2->col, COLOR_SIZE);
678
679 (void)BaseMath_WriteCallback(color1);
680 Py_INCREF(v1);
681 return v1;
682}
683
684static PyObject *color_mul_float(ColorObject *color, const float scalar)
685{
686 float tcol[COLOR_SIZE];
687 mul_vn_vn_fl(tcol, color->col, COLOR_SIZE, scalar);
688 return Color_CreatePyObject(tcol, Py_TYPE(color));
689}
690
692static PyObject *Color_mul(PyObject *v1, PyObject *v2)
693{
694 ColorObject *color1 = nullptr, *color2 = nullptr;
695 float scalar;
696
697 if (ColorObject_Check(v1)) {
698 color1 = (ColorObject *)v1;
699 if (BaseMath_ReadCallback(color1) == -1) {
700 return nullptr;
701 }
702 }
703 if (ColorObject_Check(v2)) {
704 color2 = (ColorObject *)v2;
705 if (BaseMath_ReadCallback(color2) == -1) {
706 return nullptr;
707 }
708 }
709
710 /* make sure v1 is always the vector */
711 if (color1 && color2) {
712 /* col * col, don't support yet! */
713 }
714 else if (color1) {
715 if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR * FLOAT */
716 return color_mul_float(color1, scalar);
717 }
718 }
719 else if (color2) {
720 if (((scalar = PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred()) == 0) { /* FLOAT * COLOR */
721 return color_mul_float(color2, scalar);
722 }
723 }
724 else {
725 BLI_assert_msg(0, "internal error");
726 }
727
728 PyErr_Format(PyExc_TypeError,
729 "Color multiplication: not supported between "
730 "'%.200s' and '%.200s' types",
731 Py_TYPE(v1)->tp_name,
732 Py_TYPE(v2)->tp_name);
733 return nullptr;
734}
735
737static PyObject *Color_div(PyObject *v1, PyObject *v2)
738{
739 ColorObject *color1 = nullptr;
740 float scalar;
741
742 if (ColorObject_Check(v1)) {
743 color1 = (ColorObject *)v1;
744 if (BaseMath_ReadCallback(color1) == -1) {
745 return nullptr;
746 }
747 }
748 else {
749 PyErr_SetString(PyExc_TypeError, "Color division not supported in this order");
750 return nullptr;
751 }
752
753 /* make sure v1 is always the vector */
754 if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR * FLOAT */
755 if (scalar == 0.0f) {
756 PyErr_SetString(PyExc_ZeroDivisionError, "Color division: divide by zero error");
757 return nullptr;
758 }
759 return color_mul_float(color1, 1.0f / scalar);
760 }
761
762 PyErr_Format(PyExc_TypeError,
763 "Color multiplication: not supported between "
764 "'%.200s' and '%.200s' types",
765 Py_TYPE(v1)->tp_name,
766 Py_TYPE(v2)->tp_name);
767 return nullptr;
768}
769
771static PyObject *Color_imul(PyObject *v1, PyObject *v2)
772{
773 ColorObject *color = (ColorObject *)v1;
774 float scalar;
775
776 if (BaseMath_ReadCallback_ForWrite(color) == -1) {
777 return nullptr;
778 }
779
780 /* only support color *= float */
781 if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR *= FLOAT */
782 mul_vn_fl(color->col, COLOR_SIZE, scalar);
783 }
784 else {
785 PyErr_Format(PyExc_TypeError,
786 "Color multiplication: (%s *= %s) "
787 "invalid type for this operation",
788 Py_TYPE(v1)->tp_name,
789 Py_TYPE(v2)->tp_name);
790 return nullptr;
791 }
792
793 (void)BaseMath_WriteCallback(color);
794 Py_INCREF(v1);
795 return v1;
796}
797
799static PyObject *Color_idiv(PyObject *v1, PyObject *v2)
800{
801 ColorObject *color = (ColorObject *)v1;
802 float scalar;
803
804 if (BaseMath_ReadCallback_ForWrite(color) == -1) {
805 return nullptr;
806 }
807
808 /* only support color /= float */
809 if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* COLOR /= FLOAT */
810 if (scalar == 0.0f) {
811 PyErr_SetString(PyExc_ZeroDivisionError, "Color division: divide by zero error");
812 return nullptr;
813 }
814
815 mul_vn_fl(color->col, COLOR_SIZE, 1.0f / scalar);
816 }
817 else {
818 PyErr_Format(PyExc_TypeError,
819 "Color division: (%s /= %s) "
820 "invalid type for this operation",
821 Py_TYPE(v1)->tp_name,
822 Py_TYPE(v2)->tp_name);
823 return nullptr;
824 }
825
826 (void)BaseMath_WriteCallback(color);
827 Py_INCREF(v1);
828 return v1;
829}
830
832static PyObject *Color_neg(ColorObject *self)
833{
834 float tcol[COLOR_SIZE];
835
836 if (BaseMath_ReadCallback(self) == -1) {
837 return nullptr;
838 }
839
840 negate_vn_vn(tcol, self->col, COLOR_SIZE);
841 return Color_CreatePyObject(tcol, Py_TYPE(self));
842}
843
846/* -------------------------------------------------------------------- */
850static PySequenceMethods Color_SeqMethods = {
851 /*sq_length*/ (lenfunc)Color_len,
852 /*sq_concat*/ nullptr,
853 /*sq_repeat*/ nullptr,
854 /*sq_item*/ (ssizeargfunc)Color_item,
855 /*was_sq_slice*/ nullptr, /* DEPRECATED. */
856 /*sq_ass_item*/ (ssizeobjargproc)Color_ass_item,
857 /*was_sq_ass_slice*/ nullptr, /* DEPRECATED. */
858 /*sq_contains*/ nullptr,
859 /*sq_inplace_concat*/ nullptr,
860 /*sq_inplace_repeat*/ nullptr,
861};
862
863static PyMappingMethods Color_AsMapping = {
864 /*mp_length*/ (lenfunc)Color_len,
865 /*mp_subscript*/ (binaryfunc)Color_subscript,
866 /*mp_ass_subscript*/ (objobjargproc)Color_ass_subscript,
867};
868
869static PyNumberMethods Color_NumMethods = {
870 /*nb_add*/ (binaryfunc)Color_add,
871 /*nb_subtract*/ (binaryfunc)Color_sub,
872 /*nb_multiply*/ (binaryfunc)Color_mul,
873 /*nb_remainder*/ nullptr,
874 /*nb_divmod*/ nullptr,
875 /*nb_power*/ nullptr,
876 /*nb_negative*/ (unaryfunc)Color_neg,
877 /*nb_positive*/ (unaryfunc)Color_copy,
878 /*nb_absolute*/ nullptr,
879 /*nb_bool*/ nullptr,
880 /*nb_invert*/ nullptr,
881 /*nb_lshift*/ nullptr,
882 /*nb_rshift*/ nullptr,
883 /*nb_and*/ nullptr,
884 /*nb_xor*/ nullptr,
885 /*nb_or*/ nullptr,
886 /*nb_int*/ nullptr,
887 /*nb_reserved*/ nullptr,
888 /*nb_float*/ nullptr,
889 /*nb_inplace_add*/ Color_iadd,
890 /*nb_inplace_subtract*/ Color_isub,
891 /*nb_inplace_multiply*/ Color_imul,
892 /*nb_inplace_remainder*/ nullptr,
893 /*nb_inplace_power*/ nullptr,
894 /*nb_inplace_lshift*/ nullptr,
895 /*nb_inplace_rshift*/ nullptr,
896 /*nb_inplace_and*/ nullptr,
897 /*nb_inplace_xor*/ nullptr,
898 /*nb_inplace_or*/ nullptr,
899 /*nb_floor_divide*/ nullptr,
900 /*nb_true_divide*/ Color_div,
901 /*nb_inplace_floor_divide*/ nullptr,
902 /*nb_inplace_true_divide*/ Color_idiv,
903 /*nb_index*/ nullptr,
904 /*nb_matrix_multiply*/ nullptr,
905 /*nb_inplace_matrix_multiply*/ nullptr,
906};
907
910/* -------------------------------------------------------------------- */
914/* Color channel (RGB): `color.r/g/b`. */
915
917 /* Wrap. */
918 Color_channel_r_doc,
919 "Red color channel.\n"
920 "\n"
921 ":type: float");
923 /* Wrap. */
924 Color_channel_g_doc,
925 "Green color channel.\n"
926 "\n"
927 ":type: float");
929 /* Wrap. */
930 Color_channel_b_doc,
931 "Blue color channel.\n"
932 "\n"
933 ":type: float");
934
935static PyObject *Color_channel_get(ColorObject *self, void *type)
936{
937 return Color_item(self, POINTER_AS_INT(type));
938}
939
940static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
941{
942 return Color_ass_item(self, POINTER_AS_INT(type), value);
943}
944
945/* Color channel (HSV): `color.h/s/v`. */
946
948 /* Wrap. */
949 Color_channel_hsv_h_doc,
950 "HSV Hue component in [0, 1].\n"
951 "\n"
952 ":type: float");
954 /* Wrap. */
955 Color_channel_hsv_s_doc,
956 "HSV Saturation component in [0, 1].\n"
957 "\n"
958 ":type: float");
960 /* Wrap. */
961 Color_channel_hsv_v_doc,
962 "HSV Value component in [0, 1].\n"
963 "\n"
964 ":type: float");
965
966static PyObject *Color_channel_hsv_get(ColorObject *self, void *type)
967{
968 float hsv[3];
969 const int i = POINTER_AS_INT(type);
970
971 if (BaseMath_ReadCallback(self) == -1) {
972 return nullptr;
973 }
974
975 rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
976
977 return PyFloat_FromDouble(hsv[i]);
978}
979
980static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
981{
982 float hsv[3];
983 const int i = POINTER_AS_INT(type);
984 float f = PyFloat_AsDouble(value);
985
986 if (f == -1 && PyErr_Occurred()) {
987 PyErr_SetString(PyExc_TypeError,
988 "color.h/s/v = value: "
989 "assigned value not a number");
990 return -1;
991 }
992
994 return -1;
995 }
996
997 rgb_to_hsv_v(self->col, hsv);
998 CLAMP(f, 0.0f, 1.0f);
999 hsv[i] = f;
1000 hsv_to_rgb_v(hsv, self->col);
1001
1002 if (BaseMath_WriteCallback(self) == -1) {
1003 return -1;
1004 }
1005
1006 return 0;
1007}
1008
1010 /* Wrap. */
1011 Color_hsv_doc,
1012 "HSV Values in [0, 1].\n"
1013 "\n"
1014 ":type: float triplet");
1016static PyObject *Color_hsv_get(ColorObject *self, void * /*closure*/)
1017{
1018 float hsv[3];
1019 PyObject *ret;
1020
1021 if (BaseMath_ReadCallback(self) == -1) {
1022 return nullptr;
1023 }
1024
1025 rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));
1026
1027 ret = PyTuple_New(3);
1029 ret, PyFloat_FromDouble(hsv[0]), PyFloat_FromDouble(hsv[1]), PyFloat_FromDouble(hsv[2]));
1030 return ret;
1031}
1032
1034static int Color_hsv_set(ColorObject *self, PyObject *value, void * /*closure*/)
1035{
1036 float hsv[3];
1037
1038 if (mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1) {
1039 return -1;
1040 }
1041
1042 if (BaseMath_Prepare_ForWrite(self) == -1) {
1043 return -1;
1044 }
1045
1046 clamp_v3(hsv, 0.0f, 1.0f);
1047 hsv_to_rgb_v(hsv, self->col);
1048
1049 if (BaseMath_WriteCallback(self) == -1) {
1050 return -1;
1051 }
1052
1053 return 0;
1054}
1055
1058/* -------------------------------------------------------------------- */
1062static PyGetSetDef Color_getseters[] = {
1063 {"r",
1064 (getter)Color_channel_get,
1065 (setter)Color_channel_set,
1066 Color_channel_r_doc,
1067 POINTER_FROM_INT(0)},
1068 {"g",
1069 (getter)Color_channel_get,
1070 (setter)Color_channel_set,
1071 Color_channel_g_doc,
1072 POINTER_FROM_INT(1)},
1073 {"b",
1074 (getter)Color_channel_get,
1075 (setter)Color_channel_set,
1076 Color_channel_b_doc,
1077 POINTER_FROM_INT(2)},
1078
1079 {"h",
1080 (getter)Color_channel_hsv_get,
1081 (setter)Color_channel_hsv_set,
1082 Color_channel_hsv_h_doc,
1083 POINTER_FROM_INT(0)},
1084 {"s",
1085 (getter)Color_channel_hsv_get,
1086 (setter)Color_channel_hsv_set,
1087 Color_channel_hsv_s_doc,
1088 POINTER_FROM_INT(1)},
1089 {"v",
1090 (getter)Color_channel_hsv_get,
1091 (setter)Color_channel_hsv_set,
1092 Color_channel_hsv_v_doc,
1093 POINTER_FROM_INT(2)},
1094
1095 {"hsv", (getter)Color_hsv_get, (setter)Color_hsv_set, Color_hsv_doc, nullptr},
1096
1097 {"is_wrapped",
1099 (setter) nullptr,
1101 nullptr},
1102 {"is_frozen",
1104 (setter) nullptr,
1106 nullptr},
1107 {"is_valid",
1109 (setter) nullptr,
1111 nullptr},
1112 {"owner",
1114 (setter) nullptr,
1116 nullptr},
1117 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1118};
1119
1122/* -------------------------------------------------------------------- */
1126#if (defined(__GNUC__) && !defined(__clang__))
1127# pragma GCC diagnostic push
1128# pragma GCC diagnostic ignored "-Wcast-function-type"
1129#endif
1130
1131static PyMethodDef Color_methods[] = {
1132 {"copy", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
1133 {"__copy__", (PyCFunction)Color_copy, METH_NOARGS, Color_copy_doc},
1134 {"__deepcopy__", (PyCFunction)Color_deepcopy, METH_VARARGS, Color_copy_doc},
1135
1136 /* base-math methods */
1137 {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
1138
1139/* Color-space methods. */
1140#ifndef MATH_STANDALONE
1141 {"from_scene_linear_to_srgb",
1143 METH_NOARGS,
1144 Color_from_scene_linear_to_srgb_doc},
1145 {"from_srgb_to_scene_linear",
1147 METH_NOARGS,
1148 Color_from_srgb_to_scene_linear_doc},
1149 {"from_scene_linear_to_xyz_d65",
1151 METH_NOARGS,
1152 Color_from_scene_linear_to_xyz_d65_doc},
1153 {"from_xyz_d65_to_scene_linear",
1155 METH_NOARGS,
1156 Color_from_xyz_d65_to_scene_linear_doc},
1157 {"from_scene_linear_to_aces",
1159 METH_NOARGS,
1160 Color_from_scene_linear_to_aces_doc},
1161 {"from_aces_to_scene_linear",
1163 METH_NOARGS,
1164 Color_from_aces_to_scene_linear_doc},
1165 {"from_scene_linear_to_rec709_linear",
1167 METH_NOARGS,
1168 Color_from_scene_linear_to_rec709_linear_doc},
1169 {"from_rec709_linear_to_scene_linear",
1171 METH_NOARGS,
1172 Color_from_rec709_linear_to_scene_linear_doc},
1173#endif /* !MATH_STANDALONE */
1174
1175 {nullptr, nullptr, 0, nullptr},
1176};
1177
1178#if (defined(__GNUC__) && !defined(__clang__))
1179# pragma GCC diagnostic pop
1180#endif
1181
1184/* -------------------------------------------------------------------- */
1188#ifdef MATH_STANDALONE
1189# define Color_str nullptr
1190#endif
1191
1193 /* Wrap. */
1194 color_doc,
1195 ".. class:: Color(rgb)\n"
1196 "\n"
1197 " This object gives access to Colors in Blender.\n"
1198 "\n"
1199 " Most colors returned by Blender APIs are in scene linear color space, as defined by "
1200 " the OpenColorIO configuration. The notable exception is user interface theming colors, "
1201 " which are in sRGB color space.\n"
1202 "\n"
1203 " :arg rgb: (red, green, blue) color values where (0, 0, 0) is black & (1, 1, 1) is white.\n"
1204 " :type rgb: Sequence[float]\n");
1205PyTypeObject color_Type = {
1206 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
1207 /*tp_name*/ "Color",
1208 /*tp_basicsize*/ sizeof(ColorObject),
1209 /*tp_itemsize*/ 0,
1210 /*tp_dealloc*/ (destructor)BaseMathObject_dealloc,
1211 /*tp_vectorcall_offset*/ 0,
1212 /*tp_getattr*/ nullptr,
1213 /*tp_setattr*/ nullptr,
1214 /*tp_as_async*/ nullptr,
1215 /*tp_repr*/ (reprfunc)Color_repr,
1216 /*tp_as_number*/ &Color_NumMethods,
1217 /*tp_as_sequence*/ &Color_SeqMethods,
1218 /*tp_as_mapping*/ &Color_AsMapping,
1219 /*tp_hash*/ (hashfunc)Color_hash,
1220 /*tp_call*/ nullptr,
1221 /*tp_str*/ (reprfunc)Color_str,
1222 /*tp_getattro*/ nullptr,
1223 /*tp_setattro*/ nullptr,
1224 /*tp_as_buffer*/ nullptr,
1225 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
1226 /*tp_doc*/ color_doc,
1227 /*tp_traverse*/ (traverseproc)BaseMathObject_traverse,
1228 /*tp_clear*/ (inquiry)BaseMathObject_clear,
1229 /*tp_richcompare*/ (richcmpfunc)Color_richcmpr,
1230 /*tp_weaklistoffset*/ 0,
1231 /*tp_iter*/ nullptr,
1232 /*tp_iternext*/ nullptr,
1233 /*tp_methods*/ Color_methods,
1234 /*tp_members*/ nullptr,
1235 /*tp_getset*/ Color_getseters,
1236 /*tp_base*/ nullptr,
1237 /*tp_dict*/ nullptr,
1238 /*tp_descr_get*/ nullptr,
1239 /*tp_descr_set*/ nullptr,
1240 /*tp_dictoffset*/ 0,
1241 /*tp_init*/ nullptr,
1242 /*tp_alloc*/ nullptr,
1243 /*tp_new*/ Color_new,
1244 /*tp_free*/ nullptr,
1245 /*tp_is_gc*/ (inquiry)BaseMathObject_is_gc,
1246 /*tp_bases*/ nullptr,
1247 /*tp_mro*/ nullptr,
1248 /*tp_cache*/ nullptr,
1249 /*tp_subclasses*/ nullptr,
1250 /*tp_weaklist*/ nullptr,
1251 /*tp_del*/ nullptr,
1252 /*tp_version_tag*/ 0,
1253 /*tp_finalize*/ nullptr,
1254 /*tp_vectorcall*/ nullptr,
1255};
1256
1257#ifdef MATH_STANDALONE
1258# define Color_str
1259#endif
1260
1263/* -------------------------------------------------------------------- */
1267PyObject *Color_CreatePyObject(const float col[3], PyTypeObject *base_type)
1268{
1270 float *col_alloc;
1271
1272 col_alloc = static_cast<float *>(PyMem_Malloc(COLOR_SIZE * sizeof(float)));
1273 if (UNLIKELY(col_alloc == nullptr)) {
1274 PyErr_SetString(PyExc_MemoryError,
1275 "Color(): "
1276 "problem allocating data");
1277 return nullptr;
1278 }
1279
1281 if (self) {
1282 self->col = col_alloc;
1283
1284 /* init callbacks as nullptr */
1285 self->cb_user = nullptr;
1286 self->cb_type = self->cb_subtype = 0;
1287
1288 /* NEW */
1289 if (col) {
1290 copy_v3_v3(self->col, col);
1291 }
1292 else {
1293 zero_v3(self->col);
1294 }
1295
1297 }
1298 else {
1299 PyMem_Free(col_alloc);
1300 }
1301
1302 return (PyObject *)self;
1303}
1304
1305PyObject *Color_CreatePyObject_wrap(float col[3], PyTypeObject *base_type)
1306{
1308
1310 if (self) {
1311 /* init callbacks as nullptr */
1312 self->cb_user = nullptr;
1313 self->cb_type = self->cb_subtype = 0;
1314
1315 /* WRAP */
1316 self->col = col;
1318 }
1319
1320 return (PyObject *)self;
1321}
1322
1323PyObject *Color_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_subtype)
1324{
1325 ColorObject *self = (ColorObject *)Color_CreatePyObject(nullptr, nullptr);
1326 if (self) {
1327 Py_INCREF(cb_user);
1328 self->cb_user = cb_user;
1329 self->cb_type = cb_type;
1330 self->cb_subtype = cb_subtype;
1331 BLI_assert(!PyObject_GC_IsTracked((PyObject *)self));
1332 PyObject_GC_Track(self);
1333 }
1334
1335 return (PyObject *)self;
1336}
1337
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define ATTR_FALLTHROUGH
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
double double_round(double x, int ndigits)
Definition math_base.c:28
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
void add_vn_vn(float *array_tar, const float *array_src, int size)
void mul_vn_fl(float *array_tar, int size, float f)
MINLINE void clamp_v3(float vec[3], float min, float max)
void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
void negate_vn_vn(float *array_tar, const float *array_src, int size)
MINLINE void zero_v3(float r[3])
void mul_vn_vn_fl(float *array_tar, const float *array_src, int size, float f)
void sub_vn_vn(float *array_tar, const float *array_src, int size)
unsigned char uchar
#define CLAMP(a, b, c)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_rec709(float rec709[3], const float scene_linear[3])
BLI_INLINE void IMB_colormanagement_aces_to_scene_linear(float scene_linear[3], const float aces[3])
BLI_INLINE void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3])
BLI_INLINE void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_aces(float aces[3], const float scene_linear[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
ATTR_WARN_UNUSED_RESULT const BMVert * v2
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
local_group_size(16, 16) .push_constant(Type b
uint col
int count
int BaseMathObject_is_gc(BaseMathObject *self)
Definition mathutils.cc:711
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition mathutils.cc:69
void BaseMathObject_dealloc(BaseMathObject *self)
Definition mathutils.cc:689
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition mathutils.cc:490
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:97
char BaseMathObject_is_valid_doc[]
Definition mathutils.cc:639
char BaseMathObject_is_wrapped_doc[]
Definition mathutils.cc:625
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *)
Definition mathutils.cc:619
char BaseMathObject_is_frozen_doc[]
Definition mathutils.cc:632
PyObject * mathutils_dynstr_to_py(DynStr *ds)
Definition mathutils.cc:502
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *)
Definition mathutils.cc:634
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition mathutils.cc:653
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *)
Definition mathutils.cc:627
char BaseMathObject_owner_doc[]
Definition mathutils.cc:618
char BaseMathObject_freeze_doc[]
Definition mathutils.cc:645
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *)
Definition mathutils.cc:640
int BaseMathObject_clear(BaseMathObject *self)
Definition mathutils.cc:671
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition mathutils.cc:665
@ BASE_MATH_FLAG_IS_WRAP
Definition mathutils.hh:36
#define BaseMath_ReadCallback_ForWrite(_self)
Definition mathutils.hh:135
#define BaseMath_ReadIndexCallback(_self, _index)
Definition mathutils.hh:129
#define BaseMath_WriteCallback(_self)
Definition mathutils.hh:127
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition mathutils.hh:26
#define BaseMathObject_Prepare_ForHash(_self)
Definition mathutils.hh:150
#define BASE_MATH_FLAG_DEFAULT
Definition mathutils.hh:43
#define BaseMath_Prepare_ForWrite(_self)
Definition mathutils.hh:145
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:125
#define BaseMath_WriteIndexCallback(_self, _index)
Definition mathutils.hh:131
static PyObject * Color_from_scene_linear_to_rec709_linear(ColorObject *self)
static PyObject * Color_str(ColorObject *self)
PyObject * Color_CreatePyObject(const float col[3], PyTypeObject *base_type)
static PyObject * Color_from_xyz_d65_to_scene_linear(ColorObject *self)
PyTypeObject color_Type
static Py_hash_t Color_hash(ColorObject *self)
static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value)
static PyObject * color_mul_float(ColorObject *color, const float scalar)
static PyObject * Color_imul(PyObject *v1, PyObject *v2)
static PyObject * Color_richcmpr(PyObject *a, PyObject *b, int op)
static PyObject * Color_channel_get(ColorObject *self, void *type)
static int Color_ass_item(ColorObject *self, Py_ssize_t i, PyObject *value)
static PySequenceMethods Color_SeqMethods
static PyObject * Color_to_tuple_ex(ColorObject *self, int ndigits)
PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc, ".. function:: from_scene_linear_to_srgb()\n" "\n" " Convert from scene linear to sRGB color space.\n" "\n" " :return: A color in sRGB color space.\n" " :rtype: :class:`Color`\n")
static PyObject * Color_channel_hsv_get(ColorObject *self, void *type)
static PyGetSetDef Color_getseters[]
static int Color_hsv_set(ColorObject *self, PyObject *value, void *)
static PyObject * Color_from_scene_linear_to_xyz_d65(ColorObject *self)
#define COLOR_SIZE
static Py_ssize_t Color_len(ColorObject *)
static PyObject * Color_deepcopy(ColorObject *self, PyObject *args)
static PyObject * Color_iadd(PyObject *v1, PyObject *v2)
static PyObject * Color_copy(ColorObject *self)
static PyObject * Color_idiv(PyObject *v1, PyObject *v2)
static PyObject * Color_neg(ColorObject *self)
static PyObject * Color_div(PyObject *v1, PyObject *v2)
static PyNumberMethods Color_NumMethods
static PyObject * Color_subscript(ColorObject *self, PyObject *item)
static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq)
static PyObject * Color_add(PyObject *v1, PyObject *v2)
static PyObject * Color_from_srgb_to_scene_linear(ColorObject *self)
static PyObject * Color_sub(PyObject *v1, PyObject *v2)
PyObject * Color_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_subtype)
static PyObject * Color_repr(ColorObject *self)
static PyObject * Color_hsv_get(ColorObject *self, void *)
static PyMappingMethods Color_AsMapping
static PyObject * Color_isub(PyObject *v1, PyObject *v2)
static PyObject * Color_mul(PyObject *v1, PyObject *v2)
static PyObject * Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject * Color_from_aces_to_scene_linear(ColorObject *self)
static PyMethodDef Color_methods[]
static int Color_channel_set(ColorObject *self, PyObject *value, void *type)
static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
static PyObject * Color_from_scene_linear_to_aces(ColorObject *self)
static PyObject * Color_item(ColorObject *self, Py_ssize_t i)
PyObject * Color_CreatePyObject_wrap(float col[3], PyTypeObject *base_type)
static PyObject * Color_slice(ColorObject *self, int begin, int end)
static PyObject * Color_from_rec709_linear_to_scene_linear(ColorObject *self)
static PyObject * Color_from_scene_linear_to_srgb(ColorObject *self)
#define ColorObject_Check(v)
int PyC_CheckArgs_DeepCopy(PyObject *args)
header-only utilities
#define PyTuple_SET_ITEMS(op_arg,...)
return ret