]> git.sesse.net Git - casparcg/blob - core/frame/frame_transform.cpp
c08521240528ef3614ea8a375f7d0a7929eebd0a
[casparcg] / core / frame / frame_transform.cpp
1 /*\r
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\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 * Author: Robert Nagy, ronag89@gmail.com\r
20 */\r
21 \r
22 #include "../stdafx.h"\r
23 \r
24 #include "frame_transform.h"\r
25 \r
26 #include <boost/range/algorithm/equal.hpp>\r
27 #include <boost/range/algorithm/fill.hpp>\r
28 \r
29 namespace caspar { namespace core {\r
30                 \r
31 // image_transform\r
32 \r
33 image_transform::image_transform() \r
34         : opacity(1.0)\r
35         , brightness(1.0)\r
36         , contrast(1.0)\r
37         , saturation(1.0)\r
38         , field_mode(field_mode::progressive)\r
39         , is_key(false)\r
40         , is_mix(false)\r
41         , is_still(false)\r
42 {\r
43         boost::range::fill(fill_translation, 0.0);\r
44         boost::range::fill(fill_scale, 1.0);\r
45         boost::range::fill(clip_translation, 0.0);\r
46         boost::range::fill(clip_scale, 1.0);\r
47 }\r
48 \r
49 image_transform& image_transform::operator*=(const image_transform &other)\r
50 {\r
51         opacity                                 *= other.opacity;       \r
52         brightness                              *= other.brightness;\r
53         contrast                                *= other.contrast;\r
54         saturation                              *= other.saturation;\r
55         fill_translation[0]             += other.fill_translation[0]*fill_scale[0];\r
56         fill_translation[1]             += other.fill_translation[1]*fill_scale[1];\r
57         fill_scale[0]                   *= other.fill_scale[0];\r
58         fill_scale[1]                   *= other.fill_scale[1];\r
59         clip_translation[0]             += other.clip_translation[0]*clip_scale[0];\r
60         clip_translation[1]             += other.clip_translation[1]*clip_scale[1];\r
61         clip_scale[0]                   *= other.clip_scale[0];\r
62         clip_scale[1]                   *= other.clip_scale[1];\r
63         levels.min_input                 = std::max(levels.min_input,  other.levels.min_input);\r
64         levels.max_input                 = std::min(levels.max_input,  other.levels.max_input); \r
65         levels.min_output                = std::max(levels.min_output, other.levels.min_output);\r
66         levels.max_output                = std::min(levels.max_output, other.levels.max_output);\r
67         levels.gamma                    *= other.levels.gamma;\r
68         field_mode                               = static_cast<core::field_mode>(field_mode & other.field_mode);\r
69         is_key                                  |= other.is_key;\r
70         is_mix                                  |= other.is_mix;\r
71         is_still                                |= other.is_still;\r
72         return *this;\r
73 }\r
74 \r
75 image_transform image_transform::operator*(const image_transform &other) const\r
76 {\r
77         return image_transform(*this) *= other;\r
78 }\r
79 \r
80 image_transform image_transform::tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween)\r
81 {       \r
82         auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)\r
83         {\r
84                 return tween(time, source, dest-source, duration);\r
85         };\r
86         \r
87         image_transform result; \r
88         result.brightness                       = do_tween(time, source.brightness,                             dest.brightness,                        duration, tween);\r
89         result.contrast                         = do_tween(time, source.contrast,                               dest.contrast,                          duration, tween);\r
90         result.saturation                       = do_tween(time, source.saturation,                             dest.saturation,                        duration, tween);\r
91         result.opacity                          = do_tween(time, source.opacity,                                dest.opacity,                           duration, tween);       \r
92         result.fill_translation[0]      = do_tween(time, source.fill_translation[0],    dest.fill_translation[0],       duration, tween), \r
93         result.fill_translation[1]      = do_tween(time, source.fill_translation[1],    dest.fill_translation[1],       duration, tween);               \r
94         result.fill_scale[0]            = do_tween(time, source.fill_scale[0],                  dest.fill_scale[0],                     duration, tween), \r
95         result.fill_scale[1]            = do_tween(time, source.fill_scale[1],                  dest.fill_scale[1],                     duration, tween);       \r
96         result.clip_translation[0]      = do_tween(time, source.clip_translation[0],    dest.clip_translation[0],       duration, tween), \r
97         result.clip_translation[1]      = do_tween(time, source.clip_translation[1],    dest.clip_translation[1],       duration, tween);               \r
98         result.clip_scale[0]            = do_tween(time, source.clip_scale[0],                  dest.clip_scale[0],                     duration, tween), \r
99         result.clip_scale[1]            = do_tween(time, source.clip_scale[1],                  dest.clip_scale[1],                     duration, tween);\r
100         result.levels.max_input         = do_tween(time, source.levels.max_input,               dest.levels.max_input,          duration, tween);\r
101         result.levels.min_input         = do_tween(time, source.levels.min_input,               dest.levels.min_input,          duration, tween);       \r
102         result.levels.max_output        = do_tween(time, source.levels.max_output,              dest.levels.max_output,         duration, tween);\r
103         result.levels.min_output        = do_tween(time, source.levels.min_output,              dest.levels.min_output,         duration, tween);\r
104         result.levels.gamma                     = do_tween(time, source.levels.gamma,                   dest.levels.gamma,                      duration, tween);\r
105         result.field_mode                       = source.field_mode & dest.field_mode;\r
106         result.is_key                           = source.is_key | dest.is_key;\r
107         result.is_mix                           = source.is_mix | dest.is_mix;\r
108         result.is_still                         = source.is_still | dest.is_still;\r
109         \r
110         return result;\r
111 }\r
112 \r
113 bool operator==(const image_transform& lhs, const image_transform& rhs)\r
114 {\r
115         auto eq = [](double lhs, double rhs)\r
116         {\r
117                 return std::abs(lhs - rhs) < 5e-8;\r
118         };\r
119 \r
120         return \r
121                 eq(lhs.opacity, rhs.opacity) &&\r
122                 eq(lhs.contrast, rhs.contrast) &&\r
123                 eq(lhs.brightness, rhs.brightness) &&\r
124                 eq(lhs.saturation, rhs.saturation) &&\r
125                 boost::range::equal(lhs.fill_translation, rhs.fill_translation, eq) &&\r
126                 boost::range::equal(lhs.fill_scale, rhs.fill_scale, eq) &&\r
127                 boost::range::equal(lhs.clip_translation, rhs.clip_translation, eq) &&\r
128                 boost::range::equal(lhs.clip_scale, rhs.clip_scale, eq) &&\r
129                 lhs.field_mode == rhs.field_mode &&\r
130                 lhs.is_key == rhs.is_key &&\r
131                 lhs.is_mix == rhs.is_mix &&\r
132                 lhs.is_still == rhs.is_still;\r
133 }\r
134 \r
135 bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
136 {\r
137         return !(lhs == rhs);\r
138 }\r
139 \r
140 // audio_transform\r
141                 \r
142 audio_transform::audio_transform() \r
143         : volume(1.0)\r
144 {\r
145 }\r
146 \r
147 audio_transform& audio_transform::operator*=(const audio_transform &other)\r
148 {\r
149         volume                                  *= other.volume;        \r
150         return *this;\r
151 }\r
152 \r
153 audio_transform audio_transform::operator*(const audio_transform &other) const\r
154 {\r
155         return audio_transform(*this) *= other;\r
156 }\r
157 \r
158 audio_transform audio_transform::tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween)\r
159 {       \r
160         auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)\r
161         {\r
162                 return tween(time, source, dest-source, duration);\r
163         };\r
164         \r
165         audio_transform result; \r
166         result.volume                   = do_tween(time, source.volume,                         dest.volume,                    duration, tween);\r
167         \r
168         return result;\r
169 }\r
170 \r
171 bool operator==(const audio_transform& lhs, const audio_transform& rhs)\r
172 {\r
173         auto eq = [](double lhs, double rhs)\r
174         {\r
175                 return std::abs(lhs - rhs) < 5e-8;\r
176         };\r
177 \r
178         return eq(lhs.volume, rhs.volume);\r
179 }\r
180 \r
181 bool operator!=(const audio_transform& lhs, const audio_transform& rhs)\r
182 {\r
183         return !(lhs == rhs);\r
184 }\r
185 \r
186 // frame_transform\r
187 frame_transform::frame_transform()\r
188 {\r
189 }\r
190 \r
191 frame_transform& frame_transform::operator*=(const frame_transform &other)\r
192 {\r
193         image_transform *= other.image_transform;\r
194         audio_transform *= other.audio_transform;\r
195         return *this;\r
196 }\r
197 \r
198 frame_transform frame_transform::operator*(const frame_transform &other) const\r
199 {\r
200         return frame_transform(*this) *= other;\r
201 }\r
202 \r
203 frame_transform frame_transform::tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween)\r
204 {\r
205         frame_transform result;\r
206         result.image_transform = image_transform::tween(time, source.image_transform, dest.image_transform, duration, tween);\r
207         result.audio_transform = audio_transform::tween(time, source.audio_transform, dest.audio_transform, duration, tween);\r
208         return result;\r
209 }\r
210 \r
211 bool operator==(const frame_transform& lhs, const frame_transform& rhs)\r
212 {\r
213         return  lhs.image_transform == rhs.image_transform && \r
214                         lhs.audio_transform == rhs.audio_transform;\r
215 }\r
216 \r
217 bool operator!=(const frame_transform& lhs, const frame_transform& rhs)\r
218 {\r
219         return !(lhs == rhs);\r
220 }\r
221 \r
222 }}