Merged changes in the trunk up to revision 45619.
[blender.git] / source / blender / blenlib / intern / math_color_inline.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  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: some of this file.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  * */
25
26 /** \file blender/blenlib/intern/math_color_inline.c
27  *  \ingroup bli
28  */
29
30
31 #include "BLI_math_color.h"
32 #include "BLI_utildefines.h"
33
34 #ifndef __MATH_COLOR_INLINE_C__
35 #define __MATH_COLOR_INLINE_C__
36
37 /******************************** Color Space ********************************/
38
39 MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
40 {
41         linear[0] = srgb_to_linearrgb(srgb[0]);
42         linear[1] = srgb_to_linearrgb(srgb[1]);
43         linear[2] = srgb_to_linearrgb(srgb[2]);
44 }
45
46 MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
47 {
48         srgb[0] = linearrgb_to_srgb(linear[0]);
49         srgb[1] = linearrgb_to_srgb(linear[1]);
50         srgb[2] = linearrgb_to_srgb(linear[2]);
51 }
52
53 MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
54 {
55         srgb_to_linearrgb_v3_v3(linear, srgb);
56         linear[3] = srgb[3];
57 }
58
59 MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4])
60 {
61         linearrgb_to_srgb_v3_v3(srgb, linear);
62         srgb[3] = linear[3];
63 }
64
65 MINLINE void linearrgb_to_srgb_uchar3(unsigned char srgb[3], const float linear[3])
66 {
67         float srgb_f[3];
68
69         linearrgb_to_srgb_v3_v3(srgb_f, linear);
70         F3TOCHAR3(srgb_f, srgb);
71 }
72
73 MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[4])
74 {
75         float srgb_f[4];
76
77         linearrgb_to_srgb_v4(srgb_f, linear);
78         F4TOCHAR4(srgb_f, srgb);
79 }
80
81 /* predivide versions to work on associated/premultipled alpha. if this should
82  * be done or not depends on the background the image will be composited over,
83  * ideally you would never do color space conversion on an image with alpha
84  * because it is ill defined */
85
86 MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4])
87 {
88         float alpha, inv_alpha;
89
90         if (srgb[3] == 1.0f || srgb[3] == 0.0f) {
91                 alpha = 1.0f;
92                 inv_alpha = 1.0f;
93         }
94         else {
95                 alpha = srgb[3];
96                 inv_alpha = 1.0f / alpha;
97         }
98
99         linear[0] = srgb_to_linearrgb(srgb[0] * inv_alpha) * alpha;
100         linear[1] = srgb_to_linearrgb(srgb[1] * inv_alpha) * alpha;
101         linear[2] = srgb_to_linearrgb(srgb[2] * inv_alpha) * alpha;
102         linear[3] = srgb[3];
103 }
104
105 MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4])
106 {
107         float alpha, inv_alpha;
108
109         if (linear[3] == 1.0f || linear[3] == 0.0f) {
110                 alpha = 1.0f;
111                 inv_alpha = 1.0f;
112         }
113         else {
114                 alpha = linear[3];
115                 inv_alpha = 1.0f / alpha;
116         }
117
118         srgb[0] = linearrgb_to_srgb(linear[0] * inv_alpha) * alpha;
119         srgb[1] = linearrgb_to_srgb(linear[1] * inv_alpha) * alpha;
120         srgb[2] = linearrgb_to_srgb(linear[2] * inv_alpha) * alpha;
121         srgb[3] = linear[3];
122 }
123
124 /* LUT accelerated conversions */
125
126 extern float BLI_color_from_srgb_table[256];
127 extern unsigned short BLI_color_to_srgb_table[0x10000];
128
129 MINLINE unsigned short to_srgb_table_lookup(const float f)
130 {
131
132         union {
133                 float f;
134                 unsigned short us[2];
135         } tmp;
136         tmp.f = f;
137 #ifdef __BIG_ENDIAN__
138         return BLI_color_to_srgb_table[tmp.us[0]];
139 #else
140         return BLI_color_to_srgb_table[tmp.us[1]];
141 #endif
142 }
143
144 MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4])
145 {
146         srgb[0] = to_srgb_table_lookup(linear[0]);
147         srgb[1] = to_srgb_table_lookup(linear[1]);
148         srgb[2] = to_srgb_table_lookup(linear[2]);
149         srgb[3] = FTOUSHORT(linear[3]);
150 }
151
152 MINLINE void linearrgb_to_srgb_ushort4_predivide(unsigned short srgb[4], const float linear[4])
153 {
154         float alpha, inv_alpha, t;
155         int i;
156
157         if (linear[3] == 1.0f || linear[3] == 0.0f) {
158                 linearrgb_to_srgb_ushort4(srgb, linear);
159                 return;
160         }
161
162         alpha = linear[3];
163         inv_alpha = 1.0f / alpha;
164
165         for (i = 0; i < 3; ++i) {
166                 t = linear[i] * inv_alpha;
167                 srgb[i] = (t < 1.0f) ? (unsigned short) (to_srgb_table_lookup(t) * alpha) : FTOUSHORT(linearrgb_to_srgb(t) * alpha);
168         }
169
170         srgb[3] = FTOUSHORT(linear[3]);
171 }
172
173 MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
174 {
175         linear[0] = BLI_color_from_srgb_table[srgb[0]];
176         linear[1] = BLI_color_from_srgb_table[srgb[1]];
177         linear[2] = BLI_color_from_srgb_table[srgb[2]];
178         linear[3] = srgb[3] * (1.0f / 255.0f);
179 }
180
181 MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4])
182 {
183         float fsrgb[4];
184         int i;
185
186         if (srgb[3] == 255 || srgb[3] == 0) {
187                 srgb_to_linearrgb_uchar4(linear, srgb);
188                 return;
189         }
190
191         for (i = 0; i < 4; i++)
192                 fsrgb[i] = srgb[i] * (1.0f / 255.0f);
193
194         srgb_to_linearrgb_predivide_v4(linear, fsrgb);
195 }
196
197 /* color macros for themes */
198 #define rgba_char_args_set_fl(col, r, g, b, a)  rgba_char_args_set(col, r * 255, g * 255, b * 255, a * 255)
199
200 MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const char b, const char a)
201 {
202         col[0] = r;
203         col[1] = g;
204         col[2] = b;
205         col[3] = a;
206 }
207
208 MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a)
209 {
210         if (col[3] == 0) {
211                 col[0] = r;
212                 col[1] = g;
213                 col[2] = b;
214                 col[3] = a;
215         }
216 }
217
218 #endif /* __MATH_COLOR_INLINE_C__ */