1 /* === S Y N F I G ========================================================= */
2 /*! \file colormatrix.cpp
3 ** \brief Template File
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** ......... ... 2016 Ivan Mahonin
9 **
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
14 **
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
19 ** \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 # include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <cstring>
33
34 #include <synfig/general.h>
35 #include "colormatrix.h"
36
37 #endif
38
39 /* === U S I N G =========================================================== */
40
41 using namespace std;
42 using namespace etl;
43 using namespace synfig;
44
45 /* === M A C R O S ========================================================= */
46
47 /* === G L O B A L S ======================================================= */
48
49 /* === M E T H O D S ======================================================= */
50
51
52 // Internal
53
54 namespace {
55 class Internal
56 {
57 public:
58 template<int channel, int mode_r, int mode_g, int mode_b, int mode_a, int mode_o>
transform(const ColorMatrix & m,const Color & c)59 static inline ColorMatrix::value_type INRETRNAL_FUNC transform(const ColorMatrix &m, const Color &c)
60 {
61 ColorMatrix::value_type x(mode_o ? m[4][channel] : ColorMatrix::value_type(0.0));
62
63 if (mode_r == -1) x -= c.get_r();
64 if (mode_r == 1) x += c.get_r();
65 if (mode_r == 2) x += m[0][channel]*c.get_r();
66
67 if (mode_g == -1) x -= c.get_g();
68 if (mode_g == 1) x += c.get_g();
69 if (mode_g == 2) x += m[1][channel]*c.get_g();
70
71 if (mode_b == -1) x -= c.get_b();
72 if (mode_b == 1) x += c.get_b();
73 if (mode_b == 2) x += m[2][channel]*c.get_b();
74
75 if (mode_a == -1) x -= c.get_a();
76 if (mode_a == 1) x += c.get_a();
77 if (mode_a == 2) x += m[3][channel]*c.get_a();
78
79 return x;
80 }
81
82 template<int channel, int mode_r, int mode_g, int mode_b, int mode_a, int mode_o>
batch_transform(const ColorMatrix & m,ColorMatrix::value_type * dest,const Color * src,const Color * src_end)83 static inline void INRETRNAL_FUNC batch_transform(const ColorMatrix &m, ColorMatrix::value_type *dest, const Color *src, const Color *src_end)
84 {
85 for(; src < src_end; dest += 4, ++src)
86 *dest = transform<channel, mode_r, mode_g, mode_b, mode_a, mode_o>(m, *src);
87 }
88
89
90 // transfrom func generator
91
92 template<int channel, int mode_r, int mode_g, int mode_b, int mode_a, int mode_o>
get_transform_func_crgbao()93 static ColorMatrix::transform_func_ptr INRETRNAL_FUNC get_transform_func_crgbao()
94 { return transform<channel, mode_r, mode_g, mode_b, mode_a, mode_o>; }
95
96 template<int channel, int mode_r, int mode_g, int mode_b, int mode_a>
get_transform_func_crgba(const ColorMatrix & m)97 static ColorMatrix::transform_func_ptr INRETRNAL_FUNC get_transform_func_crgba(const ColorMatrix &m)
98 {
99 return approximate_equal_lp(m[4][channel], ColorMatrix::value_type( 0.0)) ? get_transform_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, 0>()
100 : approximate_equal_lp(m[4][channel], ColorMatrix::value_type( 1.0)) ? get_transform_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, 1>()
101 : approximate_equal_lp(m[4][channel], ColorMatrix::value_type(-1.0)) ? get_transform_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, -1>()
102 : get_transform_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, 2>();
103 }
104
105 template<int channel, int mode_r, int mode_g, int mode_b>
get_transform_func_crgb(const ColorMatrix & m)106 static ColorMatrix::transform_func_ptr INRETRNAL_FUNC get_transform_func_crgb(const ColorMatrix &m)
107 {
108 return approximate_equal_lp(m[3][channel], ColorMatrix::value_type( 0.0)) ? get_transform_func_crgba<channel, mode_r, mode_g, mode_b, 0>(m)
109 : approximate_equal_lp(m[3][channel], ColorMatrix::value_type( 1.0)) ? get_transform_func_crgba<channel, mode_r, mode_g, mode_b, 1>(m)
110 : approximate_equal_lp(m[3][channel], ColorMatrix::value_type(-1.0)) ? get_transform_func_crgba<channel, mode_r, mode_g, mode_b, -1>(m)
111 : get_transform_func_crgba<channel, mode_r, mode_g, mode_b, 2>(m);
112 }
113
114 template<int channel, int mode_r, int mode_g>
get_transform_func_crg(const ColorMatrix & m)115 static ColorMatrix::transform_func_ptr INRETRNAL_FUNC get_transform_func_crg(const ColorMatrix &m)
116 {
117 return approximate_equal_lp(m[2][channel], ColorMatrix::value_type( 0.0)) ? get_transform_func_crgb<channel, mode_r, mode_g, 0>(m)
118 : approximate_equal_lp(m[2][channel], ColorMatrix::value_type( 1.0)) ? get_transform_func_crgb<channel, mode_r, mode_g, 1>(m)
119 : approximate_equal_lp(m[2][channel], ColorMatrix::value_type(-1.0)) ? get_transform_func_crgb<channel, mode_r, mode_g, -1>(m)
120 : get_transform_func_crgb<channel, mode_r, mode_g, 2>(m);
121 }
122
123 template<int channel, int mode_r>
get_transform_func_cr(const ColorMatrix & m)124 static ColorMatrix::transform_func_ptr INRETRNAL_FUNC get_transform_func_cr(const ColorMatrix &m)
125 {
126 return approximate_equal_lp(m[1][channel], ColorMatrix::value_type( 0.0)) ? get_transform_func_crg<channel, mode_r, 0>(m)
127 : approximate_equal_lp(m[1][channel], ColorMatrix::value_type( 1.0)) ? get_transform_func_crg<channel, mode_r, 1>(m)
128 : approximate_equal_lp(m[1][channel], ColorMatrix::value_type(-1.0)) ? get_transform_func_crg<channel, mode_r, -1>(m)
129 : get_transform_func_crg<channel, mode_r, 2>(m);
130 }
131
132 template<int channel>
get_transform_func_c(const ColorMatrix & m)133 static ColorMatrix::transform_func_ptr INRETRNAL_FUNC get_transform_func_c(const ColorMatrix &m)
134 {
135 return approximate_equal_lp(m[0][channel], ColorMatrix::value_type( 0.0)) ? get_transform_func_cr<channel, 0>(m)
136 : approximate_equal_lp(m[0][channel], ColorMatrix::value_type( 1.0)) ? get_transform_func_cr<channel, 1>(m)
137 : approximate_equal_lp(m[0][channel], ColorMatrix::value_type(-1.0)) ? get_transform_func_cr<channel, -1>(m)
138 : get_transform_func_cr<channel, 2>(m);
139 }
140
141
142 // batch func generator
143
144 template<int channel, int mode_r, int mode_g, int mode_b, int mode_a, int mode_o>
get_batch_func_crgbao()145 static ColorMatrix::batch_func_ptr INRETRNAL_FUNC get_batch_func_crgbao()
146 { return batch_transform<channel, mode_r, mode_g, mode_b, mode_a, mode_o>; }
147
148 template<int channel, int mode_r, int mode_g, int mode_b, int mode_a>
get_batch_func_crgba(const ColorMatrix & m)149 static ColorMatrix::batch_func_ptr INRETRNAL_FUNC get_batch_func_crgba(const ColorMatrix &m)
150 {
151 return approximate_equal_lp(m[4][channel], ColorMatrix::value_type( 0.0)) ? get_batch_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, 0>()
152 : approximate_equal_lp(m[4][channel], ColorMatrix::value_type( 1.0)) ? get_batch_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, 1>()
153 : approximate_equal_lp(m[4][channel], ColorMatrix::value_type(-1.0)) ? get_batch_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, -1>()
154 : get_batch_func_crgbao<channel, mode_r, mode_g, mode_b, mode_a, 2>();
155 }
156
157 template<int channel, int mode_r, int mode_g, int mode_b>
get_batch_func_crgb(const ColorMatrix & m)158 static ColorMatrix::batch_func_ptr INRETRNAL_FUNC get_batch_func_crgb(const ColorMatrix &m)
159 {
160 return approximate_equal_lp(m[3][channel], ColorMatrix::value_type( 0.0)) ? get_batch_func_crgba<channel, mode_r, mode_g, mode_b, 0>(m)
161 : approximate_equal_lp(m[3][channel], ColorMatrix::value_type( 1.0)) ? get_batch_func_crgba<channel, mode_r, mode_g, mode_b, 1>(m)
162 : approximate_equal_lp(m[3][channel], ColorMatrix::value_type(-1.0)) ? get_batch_func_crgba<channel, mode_r, mode_g, mode_b, -1>(m)
163 : get_batch_func_crgba<channel, mode_r, mode_g, mode_b, 2>(m);
164 }
165
166 template<int channel, int mode_r, int mode_g>
get_batch_func_crg(const ColorMatrix & m)167 static ColorMatrix::batch_func_ptr INRETRNAL_FUNC get_batch_func_crg(const ColorMatrix &m)
168 {
169 return approximate_equal_lp(m[2][channel], ColorMatrix::value_type( 0.0)) ? get_batch_func_crgb<channel, mode_r, mode_g, 0>(m)
170 : approximate_equal_lp(m[2][channel], ColorMatrix::value_type( 1.0)) ? get_batch_func_crgb<channel, mode_r, mode_g, 1>(m)
171 : approximate_equal_lp(m[2][channel], ColorMatrix::value_type(-1.0)) ? get_batch_func_crgb<channel, mode_r, mode_g, -1>(m)
172 : get_batch_func_crgb<channel, mode_r, mode_g, 2>(m);
173 }
174
175 template<int channel, int mode_r>
get_batch_func_cr(const ColorMatrix & m)176 static ColorMatrix::batch_func_ptr INRETRNAL_FUNC get_batch_func_cr(const ColorMatrix &m)
177 {
178 return approximate_equal_lp(m[1][channel], ColorMatrix::value_type( 0.0)) ? get_batch_func_crg<channel, mode_r, 0>(m)
179 : approximate_equal_lp(m[1][channel], ColorMatrix::value_type( 1.0)) ? get_batch_func_crg<channel, mode_r, 1>(m)
180 : approximate_equal_lp(m[1][channel], ColorMatrix::value_type(-1.0)) ? get_batch_func_crg<channel, mode_r, -1>(m)
181 : get_batch_func_crg<channel, mode_r, 2>(m);
182 }
183
184 template<int channel>
get_batch_func_c(const ColorMatrix & m)185 static ColorMatrix::batch_func_ptr INRETRNAL_FUNC get_batch_func_c(const ColorMatrix &m)
186 {
187 return approximate_equal_lp(m[0][channel], ColorMatrix::value_type( 0.0)) ? get_batch_func_cr<channel, 0>(m)
188 : approximate_equal_lp(m[0][channel], ColorMatrix::value_type( 1.0)) ? get_batch_func_cr<channel, 1>(m)
189 : approximate_equal_lp(m[0][channel], ColorMatrix::value_type(-1.0)) ? get_batch_func_cr<channel, -1>(m)
190 : get_batch_func_cr<channel, 2>(m);
191 }
192 };
193 }
194
195 // BatchProcessor
196
BatchProcessor(const ColorMatrix & matrix)197 ColorMatrix::BatchProcessor::BatchProcessor(const ColorMatrix &matrix):
198 matrix(matrix),
199 zero_all(matrix.is_zero()),
200 zero_r(matrix.is_zero(0)),
201 zero_g(matrix.is_zero(1)),
202 zero_b(matrix.is_zero(2)),
203 zero_a(matrix.is_zero(3)),
204 constant_value(matrix.get_constant()),
205 constant_all(matrix.is_constant()),
206 constant_r(matrix.is_constant(0)),
207 constant_g(matrix.is_constant(1)),
208 constant_b(matrix.is_constant(2)),
209 constant_a(matrix.is_constant(3)),
210 copy_all(matrix.is_copy()),
211 copy_r(matrix.is_copy(0)),
212 copy_g(matrix.is_copy(1)),
213 copy_b(matrix.is_copy(2)),
214 copy_a(matrix.is_copy(3)),
215 affects_transparent(matrix.is_affects_transparent()),
216 transform_func_r(Internal::get_transform_func_c<0>(matrix)),
217 transform_func_g(Internal::get_transform_func_c<1>(matrix)),
218 transform_func_b(Internal::get_transform_func_c<2>(matrix)),
219 transform_func_a(Internal::get_transform_func_c<3>(matrix)),
220 batch_func_r(Internal::get_batch_func_c<0>(matrix)),
221 batch_func_g(Internal::get_batch_func_c<1>(matrix)),
222 batch_func_b(Internal::get_batch_func_c<2>(matrix)),
223 batch_func_a(Internal::get_batch_func_c<3>(matrix))
224 { }
225
226
227 void
process(Color * dest,int dest_stride,const Color * src,int src_stride,int width,int height) const228 ColorMatrix::BatchProcessor::process(Color *dest, int dest_stride, const Color *src, int src_stride, int width, int height) const
229 {
230 if (width <= 0 || height <= 0) return;
231 int dest_dr = dest_stride - width;
232 int src_dr = src_stride - width;
233 Color *dest_end = dest + dest_stride*height;
234 #ifndef NDEBUG
235 const Color *src_end = src + src_stride*height;
236 #endif
237
238 if (zero_all)
239 {
240 if (dest_dr)
241 for(; dest != dest_end; dest += dest_stride)
242 memset(dest, 0, sizeof(*dest)*width);
243 else
244 memset(dest, 0, sizeof(*dest)*width*height);
245 }
246 else
247 if (copy_all)
248 {
249 if (dest == src)
250 {
251 assert(src_stride == dest_stride);
252 }
253 else
254 {
255 assert(src_end <= dest || dest_end <= src);
256 if (dest_dr || src_dr)
257 for(; dest != dest_end; dest += dest_stride, src += src_stride)
258 memcpy(dest, src, sizeof(*dest)*width);
259 else
260 memcpy(dest, src, sizeof(*dest)*width*height);
261 }
262 }
263 else
264 if (constant_all)
265 {
266 if (dest_dr)
267 for(; dest != dest_end; dest += dest_dr)
268 for(Color *dest_row_end = dest + width; dest < dest_row_end; ++dest)
269 *dest = constant_value;
270 else
271 for(; dest != dest_end; ++dest)
272 *dest = constant_value;
273 }
274 else
275 if (dest != src)
276 {
277 assert(src_end <= dest || dest_end <= src);
278 for(; dest != dest_end; dest += dest_dr, src += src_dr)
279 {
280 const Color *src_end = src + width;
281 batch_func_r(matrix, (value_type*)dest + 0, src, src_end);
282 batch_func_g(matrix, (value_type*)dest + 1, src, src_end);
283 batch_func_b(matrix, (value_type*)dest + 2, src, src_end);
284 batch_func_a(matrix, (value_type*)dest + 3, src, src_end);
285 }
286 }
287 else
288 {
289 assert(src_stride == dest_stride);
290 Color c;
291 for(; dest != dest_end; dest += dest_dr)
292 for(Color *dest_row_end = dest + width; dest < dest_row_end; ++dest)
293 {
294 c.set_r(transform_func_r(matrix, *dest));
295 c.set_g(transform_func_g(matrix, *dest));
296 c.set_b(transform_func_b(matrix, *dest));
297 c.set_a(transform_func_a(matrix, *dest));
298 *dest = c;
299 }
300 }
301 }
302
303
304 // ColorMatrix
305
306 bool
is_constant(int channel) const307 ColorMatrix::is_constant(int channel) const
308 {
309 return approximate_equal_lp(m[0][channel], value_type(0.0))
310 && approximate_equal_lp(m[1][channel], value_type(0.0))
311 && approximate_equal_lp(m[2][channel], value_type(0.0))
312 && approximate_equal_lp(m[3][channel], value_type(0.0));
313 }
314
315 bool
is_constant() const316 ColorMatrix::is_constant() const
317 {
318 return is_constant(0)
319 && is_constant(1)
320 && is_constant(2)
321 && is_constant(3);
322 }
323
324 bool
is_zero(int channel) const325 ColorMatrix::is_zero(int channel) const
326 {
327 return is_constant(channel)
328 && approximate_equal_lp(m[4][channel], value_type(0.0));
329 }
330
331 bool
is_zero() const332 ColorMatrix::is_zero() const
333 {
334 return is_zero(0)
335 && is_zero(1)
336 && is_zero(2)
337 && is_zero(3);
338 }
339
340 bool
is_copy(int channel) const341 ColorMatrix::is_copy(int channel) const
342 {
343 return approximate_equal_lp(m[0][channel], value_type(channel == 0 ? 1.0 : 0.0))
344 && approximate_equal_lp(m[1][channel], value_type(channel == 1 ? 1.0 : 0.0))
345 && approximate_equal_lp(m[2][channel], value_type(channel == 2 ? 1.0 : 0.0))
346 && approximate_equal_lp(m[3][channel], value_type(channel == 3 ? 1.0 : 0.0))
347 && approximate_equal_lp(m[4][channel], value_type(channel == 4 ? 1.0 : 0.0));
348 }
349
350 bool
is_copy() const351 ColorMatrix::is_copy() const
352 {
353 return is_copy(0)
354 && is_copy(1)
355 && is_copy(2)
356 && is_copy(3);
357 }
358
is_affects_transparent() const359 bool ColorMatrix::is_affects_transparent() const
360 {
361 return approximate_equal_lp(m03, value_type(0.0))
362 || approximate_equal_lp(m13, value_type(0.0))
363 || approximate_equal_lp(m23, value_type(0.0))
364 || approximate_equal_lp(m43, value_type(0.0));
365 }
366
367 ColorMatrix&
set_scale(value_type r,value_type g,value_type b,value_type a)368 ColorMatrix::set_scale(value_type r, value_type g, value_type b, value_type a)
369 {
370 m00=r; m01=0.0; m02=0.0; m03=0.0; m04=0.0;
371 m10=0.0; m11=g; m12=0.0; m13=0.0; m14=0.0;
372 m20=0.0; m21=0.0; m22=b; m23=0.0; m24=0.0;
373 m30=0.0; m31=0.0; m32=0.0; m33=a; m34=0.0;
374 m40=0.0; m41=0.0; m42=0.0; m43=0.0; m44=1.0;
375 return *this;
376 }
377
378 ColorMatrix&
set_translate(value_type r,value_type g,value_type b,value_type a)379 ColorMatrix::set_translate(value_type r, value_type g, value_type b, value_type a)
380 {
381 m00=1.0; m01=0.0; m02=0.0; m03=0.0; m04=0.0;
382 m10=0.0; m11=1.0; m12=0.0; m13=0.0; m14=0.0;
383 m20=0.0; m21=0.0; m22=1.0; m23=0.0; m24=0.0;
384 m30=0.0; m31=0.0; m32=0.0; m33=1.0; m34=0.0;
385 m40=r; m41=g; m42=b; m43=a; m44=1.0;
386 return *this;
387 }
388
389 ColorMatrix&
set_encode_yuv()390 ColorMatrix::set_encode_yuv()
391 {
392 m00 = 0.299; m01 = -0.168736; m02 = 0.5; m03=0.0; m04=0.0;
393 m10 = 0.587; m11 = -0.331264; m12 = -0.418688; m13=0.0; m14=0.0;
394 m20 = 0.114; m21 = 0.5; m22 = -0.081312; m23=0.0; m24=0.0;
395 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33=1.0; m34=0.0;
396 m40 = 0.0; m41 = 0.0; m42 = 0.0; m43=0.0; m44=1.0;
397 return *this;
398 }
399
400 ColorMatrix&
set_decode_yuv()401 ColorMatrix::set_decode_yuv()
402 {
403 m00 = 1.0; m01 = 1.0; m02 = 1.0; m03=0.0; m04=0.0;
404 m10 = 0.0; m11 = -0.344136; m12 = 1.772; m13=0.0; m14=0.0;
405 m20 = 1.402; m21 = -0.714136; m22 = 0.0; m23=0.0; m24=0.0;
406 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33=1.0; m34=0.0;
407 m40 = 0.0; m41 = 0.0; m42 = 0.0; m43=0.0; m44=1.0;
408 return *this;
409 }
410
411 ColorMatrix&
set_rotate_uv(const Angle & a)412 ColorMatrix::set_rotate_uv(const Angle &a)
413 {
414 value_type c(Angle::cos(a).get());
415 value_type s(Angle::sin(a).get());
416 m00 = 1.0; m01 = 0.0; m02 = 0.0; m03=0.0; m04=0.0;
417 m10 = 0.0; m11 = c; m12 = s; m13=0.0; m14=0.0;
418 m20 = 0.0; m21 = -s; m22 = c; m23=0.0; m24=0.0;
419 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33=1.0; m34=0.0;
420 m40 = 0.0; m41 = 0.0; m42 = 0.0; m43=0.0; m44=1.0;
421 return *this;
422 }
423
424 ColorMatrix&
set_constant(const Color & c)425 ColorMatrix::set_constant(const Color &c)
426 {
427 m00 = 0.0; m01 = 0.0; m02 = 0.0; m03 = 0.0; m04 = 0.0;
428 m10 = 0.0; m11 = 0.0; m12 = 0.0; m13 = 0.0; m14 = 0.0;
429 m20 = 0.0; m21 = 0.0; m22 = 0.0; m23 = 0.0; m24 = 0.0;
430 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33 = 0.0; m34 = 0.0;
431 m40 = c.get_r(); m41 = c.get_g(); m42 = c.get_b(); m43 = c.get_a(); m44 = 1.0;
432 return *this;
433 }
434
435 ColorMatrix&
set_replace_color(const Color & c)436 ColorMatrix::set_replace_color(const Color &c)
437 {
438 m00 = 0.0; m01 = 0.0; m02 = 0.0; m03 = 0.0; m04 = 0.0;
439 m10 = 0.0; m11 = 0.0; m12 = 0.0; m13 = 0.0; m14 = 0.0;
440 m20 = 0.0; m21 = 0.0; m22 = 0.0; m23 = 0.0; m24 = 0.0;
441 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33 = 1.0; m34 = 0.0;
442 m40 = c.get_r(); m41 = c.get_g(); m42 = c.get_b(); m43 = 0.0; m44 = 1.0;
443 return *this;
444 }
445
446 ColorMatrix&
set_replace_alpha(value_type x)447 ColorMatrix::set_replace_alpha(value_type x)
448 {
449 m00 = 1.0; m01 = 0.0; m02 = 0.0; m03 = 0.0; m04 = 0.0;
450 m10 = 0.0; m11 = 1.0; m12 = 0.0; m13 = 0.0; m14 = 0.0;
451 m20 = 0.0; m21 = 0.0; m22 = 1.0; m23 = 0.0; m24 = 0.0;
452 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33 = 0.0; m34 = 0.0;
453 m40 = 0.0; m41 = 0.0; m42 = 0.0; m43 = x; m44 = 1.0;
454 return *this;
455 }
456
457 ColorMatrix&
set_brightness(value_type x)458 ColorMatrix::set_brightness(value_type x)
459 { return set_translate(x, x, x); }
460
461 ColorMatrix&
set_contrast(value_type x)462 ColorMatrix::set_contrast(value_type x)
463 {
464 set_translate(-0.5, -0.5, -0.5);
465 *this *= ColorMatrix().set_scale(x, x, x);
466 *this *= ColorMatrix().set_translate(0.5, 0.5, 0.5);
467 return *this;
468 }
469
470 ColorMatrix&
set_exposure(value_type x)471 ColorMatrix::set_exposure(value_type x)
472 { return set_scale_rgb(exp(x)); }
473
474 ColorMatrix&
set_hue_saturation(const Angle & hue,value_type saturation)475 ColorMatrix::set_hue_saturation(const Angle &hue, value_type saturation)
476 {
477 set_encode_yuv();
478 *this *= ColorMatrix().set_rotate_uv(hue);
479 *this *= ColorMatrix().set_scale(1.0, saturation, saturation);
480 *this *= ColorMatrix().set_decode_yuv();
481 return *this;
482 }
483
484 ColorMatrix&
set_invert_color()485 ColorMatrix::set_invert_color()
486 {
487 m00 = -1.0; m01 = 0.0; m02 = 0.0; m03 = 0.0; m04 = 0.0;
488 m10 = 0.0; m11 = -1.0; m12 = 0.0; m13 = 0.0; m14 = 0.0;
489 m20 = 0.0; m21 = 0.0; m22 = -1.0; m23 = 0.0; m24 = 0.0;
490 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33 = 1.0; m34 = 0.0;
491 m40 = 1.0; m41 = 1.0; m42 = 1.0; m43 = 0.0; m44 = 1.0;
492 return *this;
493 }
494
495 ColorMatrix&
set_invert_alpha()496 ColorMatrix::set_invert_alpha()
497 {
498 m00 = 1.0; m01 = 0.0; m02 = 0.0; m03 = 0.0; m04 = 0.0;
499 m10 = 0.0; m11 = 1.0; m12 = 0.0; m13 = 0.0; m14 = 0.0;
500 m20 = 0.0; m21 = 0.0; m22 = 1.0; m23 = 0.0; m24 = 0.0;
501 m30 = 0.0; m31 = 0.0; m32 = 0.0; m33 = -1.0; m34 = 0.0;
502 m40 = 0.0; m41 = 0.0; m42 = 0.0; m43 = 1.0; m44 = 1.0;
503 return *this;
504 }
505
506 Color
get_transformed(Color color) const507 ColorMatrix::get_transformed(Color color) const
508 {
509 Color out;
510 out.set_r( color.get_r()*m00 + color.get_g()*m10 + color.get_b()*m20 + color.get_a()*m30 + m40 );
511 out.set_g( color.get_r()*m01 + color.get_g()*m11 + color.get_b()*m21 + color.get_a()*m31 + m41 );
512 out.set_b( color.get_r()*m02 + color.get_g()*m12 + color.get_b()*m22 + color.get_a()*m32 + m42 );
513 out.set_a( color.get_r()*m03 + color.get_g()*m13 + color.get_b()*m23 + color.get_a()*m33 + m43 );
514 return out;
515 }
516
517 bool
operator ==(const ColorMatrix & rhs) const518 ColorMatrix::operator==(const ColorMatrix &rhs) const
519 {
520 for(int i = 0; i < 25; ++i)
521 if (!approximate_equal_lp(c[i], rhs.c[i]))
522 return false;
523 return true;
524 }
525
526 ColorMatrix
operator *=(const ColorMatrix & rhs)527 ColorMatrix::operator*=(const ColorMatrix &rhs)
528 {
529 value_type r, g, b, a, w;
530
531 r = m00; g = m01; b = m02; a = m03; w = m04;
532 m00 = r*rhs.m00 + g*rhs.m10 + b*rhs.m20 + a*rhs.m30 + w*rhs.m40;
533 m01 = r*rhs.m01 + g*rhs.m11 + b*rhs.m21 + a*rhs.m31 + w*rhs.m41;
534 m02 = r*rhs.m02 + g*rhs.m12 + b*rhs.m22 + a*rhs.m32 + w*rhs.m42;
535 m03 = r*rhs.m03 + g*rhs.m13 + b*rhs.m23 + a*rhs.m33 + w*rhs.m43;
536 m04 = r*rhs.m04 + g*rhs.m14 + b*rhs.m24 + a*rhs.m34 + w*rhs.m44;
537
538 r = m10; g = m11; b = m12; a = m13; w = m14;
539 m10 = r*rhs.m00 + g*rhs.m10 + b*rhs.m20 + a*rhs.m30 + w*rhs.m40;
540 m11 = r*rhs.m01 + g*rhs.m11 + b*rhs.m21 + a*rhs.m31 + w*rhs.m41;
541 m12 = r*rhs.m02 + g*rhs.m12 + b*rhs.m22 + a*rhs.m32 + w*rhs.m42;
542 m13 = r*rhs.m03 + g*rhs.m13 + b*rhs.m23 + a*rhs.m33 + w*rhs.m43;
543 m14 = r*rhs.m04 + g*rhs.m14 + b*rhs.m24 + a*rhs.m34 + w*rhs.m44;
544
545 r = m20; g = m21; b = m22; a = m23; w = m24;
546 m20 = r*rhs.m00 + g*rhs.m10 + b*rhs.m20 + a*rhs.m30 + w*rhs.m40;
547 m21 = r*rhs.m01 + g*rhs.m11 + b*rhs.m21 + a*rhs.m31 + w*rhs.m41;
548 m22 = r*rhs.m02 + g*rhs.m12 + b*rhs.m22 + a*rhs.m32 + w*rhs.m42;
549 m23 = r*rhs.m03 + g*rhs.m13 + b*rhs.m23 + a*rhs.m33 + w*rhs.m43;
550 m24 = r*rhs.m04 + g*rhs.m14 + b*rhs.m24 + a*rhs.m34 + w*rhs.m44;
551
552 r = m30; g = m31; b = m32; a = m33; w = m34;
553 m30 = r*rhs.m00 + g*rhs.m10 + b*rhs.m20 + a*rhs.m30 + w*rhs.m40;
554 m31 = r*rhs.m01 + g*rhs.m11 + b*rhs.m21 + a*rhs.m31 + w*rhs.m41;
555 m32 = r*rhs.m02 + g*rhs.m12 + b*rhs.m22 + a*rhs.m32 + w*rhs.m42;
556 m33 = r*rhs.m03 + g*rhs.m13 + b*rhs.m23 + a*rhs.m33 + w*rhs.m43;
557 m34 = r*rhs.m04 + g*rhs.m14 + b*rhs.m24 + a*rhs.m34 + w*rhs.m44;
558
559 r = m40; g = m41; b = m42; a = m43; w = m44;
560 m40 = r*rhs.m00 + g*rhs.m10 + b*rhs.m20 + a*rhs.m30 + w*rhs.m40;
561 m41 = r*rhs.m01 + g*rhs.m11 + b*rhs.m21 + a*rhs.m31 + w*rhs.m41;
562 m42 = r*rhs.m02 + g*rhs.m12 + b*rhs.m22 + a*rhs.m32 + w*rhs.m42;
563 m43 = r*rhs.m03 + g*rhs.m13 + b*rhs.m23 + a*rhs.m33 + w*rhs.m43;
564 m44 = r*rhs.m04 + g*rhs.m14 + b*rhs.m24 + a*rhs.m34 + w*rhs.m44;
565
566 return *this;
567 }
568
569 ColorMatrix
operator *=(const value_type & rhs)570 ColorMatrix::operator*=(const value_type &rhs)
571 {
572 m00 *= rhs; m01 *= rhs; m02 *= rhs; m03 *= rhs; m04 *= rhs;
573 m10 *= rhs; m11 *= rhs; m12 *= rhs; m13 *= rhs; m14 *= rhs;
574 m20 *= rhs; m21 *= rhs; m22 *= rhs; m23 *= rhs; m24 *= rhs;
575 m30 *= rhs; m31 *= rhs; m32 *= rhs; m33 *= rhs; m34 *= rhs;
576 m40 *= rhs; m41 *= rhs; m42 *= rhs; m43 *= rhs; m44 *= rhs;
577 return *this;
578 }
579
580 String
get_string(int spaces,String before,String after) const581 ColorMatrix::get_string(int spaces, String before, String after)const
582 {
583 return etl::strprintf(
584 "%*s [%7.2f %7.2f %7.2f %7.2f %7.2f] %s\n"
585 "%*s [%7.2f %7.2f %7.2f %7.2f %7.2f] %s\n"
586 "%*s [%7.2f %7.2f %7.2f %7.2f %7.2f] %s\n"
587 "%*s [%7.2f %7.2f %7.2f %7.2f %7.2f] %s\n"
588 "%*s [%7.2f %7.2f %7.2f %7.2f %7.2f] %s\n",
589 spaces, before.c_str(), m00, m01, m02, m03, m04, after.c_str(),
590 spaces, before.c_str(), m10, m11, m12, m13, m14, after.c_str(),
591 spaces, before.c_str(), m20, m21, m22, m23, m24, after.c_str(),
592 spaces, before.c_str(), m30, m31, m32, m33, m34, after.c_str(),
593 spaces, before.c_str(), m40, m41, m42, m43, m44, after.c_str() );
594 }
595