]> git.sesse.net Git - casparcg/blob - core/producer/frame/image_transform.cpp
2.0. video_format: Renamed video_mode to field_mode. image_mixer: Refactored field...
[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         , field_mode_(field_mode::progressive)\r
36 {\r
37         std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0);\r
38         std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0);\r
39         std::fill(clip_translation_.begin(), clip_translation_.end(), 0.0);\r
40         std::fill(clip_scale_.begin(), clip_scale_.end(), 1.0);\r
41 }\r
42 \r
43 void image_transform::set_opacity(double value)\r
44 {\r
45         opacity_ = std::max(value, 0.0);\r
46 }\r
47 \r
48 double image_transform::get_opacity() const\r
49 {\r
50         return opacity_;\r
51 }\r
52 \r
53 void image_transform::set_brightness(double value)\r
54 {\r
55         brightness_ = std::max(0.0, value);\r
56 }\r
57 \r
58 double image_transform::get_brightness() const\r
59 {\r
60         return brightness_;\r
61 }\r
62 \r
63 void image_transform::set_contrast(double value)\r
64 {\r
65         contrast_ = std::max(0.0, value);\r
66 }\r
67 \r
68 double image_transform::get_contrast() const\r
69 {\r
70         return contrast_;\r
71 }\r
72 \r
73 void image_transform::set_saturation(double value)\r
74 {\r
75         saturation_ = std::max(0.0, value);\r
76 }\r
77 \r
78 double image_transform::get_saturation() const\r
79 {\r
80         return saturation_;\r
81 }\r
82 \r
83 void image_transform::set_levels(const image_transform::levels& value)\r
84 {\r
85         levels_ = value;\r
86 }\r
87 \r
88 image_transform::levels image_transform::get_levels() const\r
89 {\r
90         return levels_;\r
91 }\r
92 \r
93 \r
94 void image_transform::set_fill_translation(double x, double y)\r
95 {\r
96         fill_translation_[0] = x;\r
97         fill_translation_[1] = y;\r
98 }\r
99 \r
100 void image_transform::set_fill_scale(double x, double y)\r
101 {\r
102         fill_scale_[0] = x;\r
103         fill_scale_[1] = y;     \r
104 }\r
105 \r
106 std::array<double, 2> image_transform::get_fill_translation() const\r
107 {\r
108         return fill_translation_;\r
109 }\r
110 \r
111 std::array<double, 2> image_transform::get_fill_scale() const\r
112 {\r
113         return fill_scale_;\r
114 }\r
115 \r
116 void image_transform::set_clip_translation(double x, double y)\r
117 {\r
118         clip_translation_[0] = x;\r
119         clip_translation_[1] = y;\r
120 }\r
121 \r
122 void image_transform::set_clip_scale(double x, double y)\r
123 {\r
124         clip_scale_[0] = x;\r
125         clip_scale_[1] = y;     \r
126 }\r
127 \r
128 std::array<double, 2> image_transform::get_clip_translation() const\r
129 {\r
130         return clip_translation_;\r
131 }\r
132 \r
133 std::array<double, 2> image_transform::get_clip_scale() const\r
134 {\r
135         return clip_scale_;\r
136 }\r
137 \r
138 void image_transform::set_field_mode(field_mode::type field_mode)\r
139 {\r
140         field_mode_ = field_mode;\r
141 }\r
142 \r
143 field_mode::type image_transform::get_field_mode() const\r
144 {\r
145         return field_mode_;\r
146 }\r
147 \r
148 image_transform& image_transform::operator*=(const image_transform &other)\r
149 {\r
150         opacity_                                *= other.opacity_;      \r
151         brightness_                             *= other.brightness_;\r
152         contrast_                               *= other.contrast_;\r
153         saturation_                             *= other.saturation_;\r
154 \r
155         levels_.min_input               = std::max(levels_.min_input, other.levels_.min_input);\r
156         levels_.max_input               = std::min(levels_.max_input, other.levels_.max_input);\r
157         \r
158         levels_.min_output              = std::max(levels_.min_output, other.levels_.min_output);\r
159         levels_.max_output              = std::min(levels_.max_output, other.levels_.max_output);\r
160 \r
161         levels_.gamma                   *= other.levels_.gamma;\r
162 \r
163         field_mode_                             = static_cast<field_mode::type>(field_mode_ & other.field_mode_);\r
164         is_key_                                 |= other.is_key_;\r
165         fill_translation_[0]    += other.fill_translation_[0]*fill_scale_[0];\r
166         fill_translation_[1]    += other.fill_translation_[1]*fill_scale_[1];\r
167         fill_scale_[0]                  *= other.fill_scale_[0];\r
168         fill_scale_[1]                  *= other.fill_scale_[1];\r
169         clip_translation_[0]    += other.clip_translation_[0]*clip_scale_[0];\r
170         clip_translation_[1]    += other.clip_translation_[1]*clip_scale_[1];\r
171         clip_scale_[0]                  *= other.clip_scale_[0];\r
172         clip_scale_[1]                  *= other.clip_scale_[1];\r
173         return *this;\r
174 }\r
175 \r
176 const image_transform image_transform::operator*(const image_transform &other) const\r
177 {\r
178         return image_transform(*this) *= other;\r
179 }\r
180 \r
181 void image_transform::set_is_key(bool value){is_key_ = value;}\r
182 bool image_transform::get_is_key() const{return is_key_;}\r
183 \r
184 image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener)\r
185 {       \r
186         auto do_tween = [](double time, double source, double dest, double duration, const tweener_t& tweener)\r
187         {\r
188                 return tweener(time, source, dest-source, duration);\r
189         };\r
190         \r
191         image_transform result; \r
192         result.set_is_key                       (source.get_is_key() | dest.get_is_key());\r
193         result.set_field_mode           (static_cast<field_mode::type>(source.get_field_mode() & dest.get_field_mode()));\r
194         result.set_brightness           (do_tween(time, source.get_brightness(), dest.get_brightness(), duration, tweener));\r
195         result.set_contrast                     (do_tween(time, source.get_contrast(), dest.get_contrast(), duration, tweener));\r
196         result.set_saturation           (do_tween(time, source.get_saturation(), dest.get_saturation(), duration, tweener));\r
197         result.set_opacity                      (do_tween(time, source.get_opacity(), dest.get_opacity(), duration, tweener));\r
198         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
199         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
200         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
201         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
202         \r
203         auto s_levels = source.get_levels();\r
204         auto d_levels = dest.get_levels();\r
205 \r
206         d_levels.max_input = do_tween(time, s_levels.max_input, d_levels.max_input, duration, tweener);\r
207         d_levels.min_input = do_tween(time, s_levels.min_input, d_levels.min_input, duration, tweener);\r
208         \r
209         d_levels.max_output = do_tween(time, s_levels.max_output, d_levels.max_output, duration, tweener);\r
210         d_levels.min_output = do_tween(time, s_levels.min_output, d_levels.min_output, duration, tweener);\r
211 \r
212         d_levels.gamma = do_tween(time, s_levels.gamma, d_levels.gamma, duration, tweener);\r
213 \r
214         result.set_levels(d_levels);\r
215 \r
216         return result;\r
217 }\r
218 \r
219 bool operator<(const image_transform& lhs, const image_transform& rhs)\r
220 {\r
221         return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0;\r
222 }\r
223 \r
224 bool operator==(const image_transform& lhs, const image_transform& rhs)\r
225 {\r
226         return memcmp(&lhs, &rhs, sizeof(image_transform)) == 0;\r
227 }\r
228 \r
229 bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
230 {\r
231         return !(lhs == rhs);\r
232 }\r
233 \r
234 }}