]> git.sesse.net Git - casparcg/blob - core/producer/frame/image_transform.cpp
2.0. image_mixer: Refactored blend-modes.
[casparcg] / core / producer / frame / image_transform.cpp
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\r
5 *\r
6 *    CasparCG is free software: you can redistribute it and/or modify\r
7 *    it under the terms of the GNU General Public License as published by\r
8 *    the Free Software Foundation, either version 3 of the License, or\r
9 *    (at your option) any later version.\r
10 *\r
11 *    CasparCG is distributed in the hope that it will be useful,\r
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 *    GNU General Public License for more details.\r
15 \r
16 *    You should have received a copy of the GNU General Public License\r
17 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 */\r
20 // TODO: Move layer specific stuff out of frame related classes.\r
21 #include "../../stdafx.h"\r
22 \r
23 #include "image_transform.h"\r
24 \r
25 #include <common/utility/assert.h>\r
26 \r
27 namespace caspar { namespace core {\r
28                 \r
29 image_transform::image_transform() \r
30         : opacity_(1.0)\r
31         , brightness_(1.0)\r
32         , contrast_(1.0)\r
33         , saturation_(1.0)\r
34         , is_key_(false)\r
35 {\r
36         std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0);\r
37         std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0);\r
38         std::fill(clip_translation_.begin(), clip_translation_.end(), 0.0);\r
39         std::fill(clip_scale_.begin(), clip_scale_.end(), 1.0);\r
40 }\r
41 \r
42 void image_transform::set_opacity(double value)\r
43 {\r
44         opacity_ = std::max(value, 0.0);\r
45 }\r
46 \r
47 double image_transform::get_opacity() const\r
48 {\r
49         return opacity_;\r
50 }\r
51 \r
52 void image_transform::set_brightness(double value)\r
53 {\r
54         brightness_ = std::max(0.0, value);\r
55 }\r
56 \r
57 double image_transform::get_brightness() const\r
58 {\r
59         return brightness_;\r
60 }\r
61 \r
62 void image_transform::set_contrast(double value)\r
63 {\r
64         contrast_ = std::max(0.0, value);\r
65 }\r
66 \r
67 double image_transform::get_contrast() const\r
68 {\r
69         return contrast_;\r
70 }\r
71 \r
72 void image_transform::set_saturation(double value)\r
73 {\r
74         saturation_ = std::max(0.0, value);\r
75 }\r
76 \r
77 double image_transform::get_saturation() const\r
78 {\r
79         return saturation_;\r
80 }\r
81 \r
82 void image_transform::set_levels(const image_transform::levels& value)\r
83 {\r
84         levels_ = value;\r
85 }\r
86 \r
87 image_transform::levels image_transform::get_levels() const\r
88 {\r
89         return levels_;\r
90 }\r
91 \r
92 \r
93 void image_transform::set_fill_translation(double x, double y)\r
94 {\r
95         fill_translation_[0] = x;\r
96         fill_translation_[1] = y;\r
97 }\r
98 \r
99 void image_transform::set_fill_scale(double x, double y)\r
100 {\r
101         fill_scale_[0] = x;\r
102         fill_scale_[1] = y;     \r
103 }\r
104 \r
105 std::array<double, 2> image_transform::get_fill_translation() const\r
106 {\r
107         return fill_translation_;\r
108 }\r
109 \r
110 std::array<double, 2> image_transform::get_fill_scale() const\r
111 {\r
112         return fill_scale_;\r
113 }\r
114 \r
115 void image_transform::set_clip_translation(double x, double y)\r
116 {\r
117         clip_translation_[0] = x;\r
118         clip_translation_[1] = y;\r
119 }\r
120 \r
121 void image_transform::set_clip_scale(double x, double y)\r
122 {\r
123         clip_scale_[0] = x;\r
124         clip_scale_[1] = y;     \r
125 }\r
126 \r
127 std::array<double, 2> image_transform::get_clip_translation() const\r
128 {\r
129         return clip_translation_;\r
130 }\r
131 \r
132 std::array<double, 2> image_transform::get_clip_scale() const\r
133 {\r
134         return clip_scale_;\r
135 }\r
136 \r
137 image_transform& image_transform::operator*=(const image_transform &other)\r
138 {\r
139         opacity_                                *= other.opacity_;      \r
140         brightness_                             *= other.brightness_;\r
141         contrast_                               *= other.contrast_;\r
142         saturation_                             *= other.saturation_;\r
143 \r
144         levels_.min_input               = std::max(levels_.min_input, other.levels_.min_input);\r
145         levels_.max_input               = std::min(levels_.max_input, other.levels_.max_input);\r
146         \r
147         levels_.min_output              = std::max(levels_.min_output, other.levels_.min_output);\r
148         levels_.max_output              = std::min(levels_.max_output, other.levels_.max_output);\r
149 \r
150         levels_.gamma                   *= other.levels_.gamma;\r
151 \r
152         is_key_                                 |= other.is_key_;\r
153         fill_translation_[0]    += other.fill_translation_[0]*fill_scale_[0];\r
154         fill_translation_[1]    += other.fill_translation_[1]*fill_scale_[1];\r
155         fill_scale_[0]                  *= other.fill_scale_[0];\r
156         fill_scale_[1]                  *= other.fill_scale_[1];\r
157         clip_translation_[0]    += other.clip_translation_[0]*clip_scale_[0];\r
158         clip_translation_[1]    += other.clip_translation_[1]*clip_scale_[1];\r
159         clip_scale_[0]                  *= other.clip_scale_[0];\r
160         clip_scale_[1]                  *= other.clip_scale_[1];\r
161         return *this;\r
162 }\r
163 \r
164 const image_transform image_transform::operator*(const image_transform &other) const\r
165 {\r
166         return image_transform(*this) *= other;\r
167 }\r
168 \r
169 void image_transform::set_is_key(bool value){is_key_ = value;}\r
170 bool image_transform::get_is_key() const{return is_key_;}\r
171 \r
172 image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener)\r
173 {       \r
174         auto do_tween = [](double time, double source, double dest, double duration, const tweener_t& tweener)\r
175         {\r
176                 return tweener(time, source, dest-source, duration);\r
177         };\r
178         \r
179         image_transform result; \r
180         result.set_is_key                       (source.get_is_key() | dest.get_is_key());\r
181         result.set_brightness           (do_tween(time, source.get_brightness(), dest.get_brightness(), duration, tweener));\r
182         result.set_contrast                     (do_tween(time, source.get_contrast(), dest.get_contrast(), duration, tweener));\r
183         result.set_saturation           (do_tween(time, source.get_saturation(), dest.get_saturation(), duration, tweener));\r
184         result.set_opacity                      (do_tween(time, source.get_opacity(), dest.get_opacity(), duration, tweener));\r
185         result.set_fill_translation     (do_tween(time, source.get_fill_translation()[0], dest.get_fill_translation()[0], duration, tweener), do_tween(time, source.get_fill_translation()[1], dest.get_fill_translation()[1], duration, tweener));\r
186         result.set_fill_scale           (do_tween(time, source.get_fill_scale()[0], dest.get_fill_scale()[0], duration, tweener), do_tween(time, source.get_fill_scale()[1], dest.get_fill_scale()[1], duration, tweener));\r
187         result.set_clip_translation     (do_tween(time, source.get_clip_translation()[0], dest.get_clip_translation()[0], duration, tweener), do_tween(time, source.get_clip_translation()[1], dest.get_clip_translation()[1], duration, tweener));\r
188         result.set_clip_scale           (do_tween(time, source.get_clip_scale()[0], dest.get_clip_scale()[0], duration, tweener), do_tween(time, source.get_clip_scale()[1], dest.get_clip_scale()[1], duration, tweener));\r
189         \r
190         auto s_levels = source.get_levels();\r
191         auto d_levels = dest.get_levels();\r
192 \r
193         d_levels.max_input = do_tween(time, s_levels.max_input, d_levels.max_input, duration, tweener);\r
194         d_levels.min_input = do_tween(time, s_levels.min_input, d_levels.min_input, duration, tweener);\r
195         \r
196         d_levels.max_output = do_tween(time, s_levels.max_output, d_levels.max_output, duration, tweener);\r
197         d_levels.min_output = do_tween(time, s_levels.min_output, d_levels.min_output, duration, tweener);\r
198 \r
199         d_levels.gamma = do_tween(time, s_levels.gamma, d_levels.gamma, duration, tweener);\r
200 \r
201         result.set_levels(d_levels);\r
202 \r
203         return result;\r
204 }\r
205 \r
206 bool operator<(const image_transform& lhs, const image_transform& rhs)\r
207 {\r
208         return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0;\r
209 }\r
210 \r
211 bool operator==(const image_transform& lhs, const image_transform& rhs)\r
212 {\r
213         return memcmp(&lhs, &rhs, sizeof(image_transform)) == 0;\r
214 }\r
215 \r
216 bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
217 {\r
218         return !(lhs == rhs);\r
219 }\r
220 \r
221 }}