]> git.sesse.net Git - casparcg/blob - core/frame/frame_transform.cpp
* Refactored to use enum class instead of enum_class.
[casparcg] / core / frame / frame_transform.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../stdafx.h"
23
24 #include "frame_transform.h"
25
26 #include <boost/range/algorithm/equal.hpp>
27 #include <boost/range/algorithm/fill.hpp>
28
29 namespace caspar { namespace core {
30                 
31 // image_transform
32
33 image_transform::image_transform() 
34         : opacity(1.0)
35         , brightness(1.0)
36         , contrast(1.0)
37         , saturation(1.0)
38         , field_mode(field_mode::progressive)
39         , is_key(false)
40         , is_mix(false)
41         , is_still(false)
42 {
43         boost::range::fill(fill_translation, 0.0);
44         boost::range::fill(fill_scale, 1.0);
45         boost::range::fill(clip_translation, 0.0);
46         boost::range::fill(clip_scale, 1.0);
47 }
48
49 image_transform& image_transform::operator*=(const image_transform &other)
50 {
51         opacity                                 *= other.opacity;       
52         brightness                              *= other.brightness;
53         contrast                                *= other.contrast;
54         saturation                              *= other.saturation;
55         fill_translation[0]             += other.fill_translation[0]*fill_scale[0];
56         fill_translation[1]             += other.fill_translation[1]*fill_scale[1];
57         fill_scale[0]                   *= other.fill_scale[0];
58         fill_scale[1]                   *= other.fill_scale[1];
59         clip_translation[0]             += other.clip_translation[0]*clip_scale[0];
60         clip_translation[1]             += other.clip_translation[1]*clip_scale[1];
61         clip_scale[0]                   *= other.clip_scale[0];
62         clip_scale[1]                   *= other.clip_scale[1];
63         levels.min_input                 = std::max(levels.min_input,  other.levels.min_input);
64         levels.max_input                 = std::min(levels.max_input,  other.levels.max_input); 
65         levels.min_output                = std::max(levels.min_output, other.levels.min_output);
66         levels.max_output                = std::min(levels.max_output, other.levels.max_output);
67         levels.gamma                    *= other.levels.gamma;
68         field_mode                               = field_mode & other.field_mode;
69         is_key                                  |= other.is_key;
70         is_mix                                  |= other.is_mix;
71         is_still                                |= other.is_still;
72         return *this;
73 }
74
75 image_transform image_transform::operator*(const image_transform &other) const
76 {
77         return image_transform(*this) *= other;
78 }
79
80 image_transform image_transform::tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween)
81 {       
82         auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)
83         {
84                 return tween(time, source, dest-source, duration);
85         };
86         
87         image_transform result; 
88         result.brightness                       = do_tween(time, source.brightness,                             dest.brightness,                        duration, tween);
89         result.contrast                         = do_tween(time, source.contrast,                               dest.contrast,                          duration, tween);
90         result.saturation                       = do_tween(time, source.saturation,                             dest.saturation,                        duration, tween);
91         result.opacity                          = do_tween(time, source.opacity,                                dest.opacity,                           duration, tween);       
92         result.fill_translation[0]      = do_tween(time, source.fill_translation[0],    dest.fill_translation[0],       duration, tween), 
93         result.fill_translation[1]      = do_tween(time, source.fill_translation[1],    dest.fill_translation[1],       duration, tween);               
94         result.fill_scale[0]            = do_tween(time, source.fill_scale[0],                  dest.fill_scale[0],                     duration, tween), 
95         result.fill_scale[1]            = do_tween(time, source.fill_scale[1],                  dest.fill_scale[1],                     duration, tween);       
96         result.clip_translation[0]      = do_tween(time, source.clip_translation[0],    dest.clip_translation[0],       duration, tween), 
97         result.clip_translation[1]      = do_tween(time, source.clip_translation[1],    dest.clip_translation[1],       duration, tween);               
98         result.clip_scale[0]            = do_tween(time, source.clip_scale[0],                  dest.clip_scale[0],                     duration, tween), 
99         result.clip_scale[1]            = do_tween(time, source.clip_scale[1],                  dest.clip_scale[1],                     duration, tween);
100         result.levels.max_input         = do_tween(time, source.levels.max_input,               dest.levels.max_input,          duration, tween);
101         result.levels.min_input         = do_tween(time, source.levels.min_input,               dest.levels.min_input,          duration, tween);       
102         result.levels.max_output        = do_tween(time, source.levels.max_output,              dest.levels.max_output,         duration, tween);
103         result.levels.min_output        = do_tween(time, source.levels.min_output,              dest.levels.min_output,         duration, tween);
104         result.levels.gamma                     = do_tween(time, source.levels.gamma,                   dest.levels.gamma,                      duration, tween);
105         result.field_mode                       = source.field_mode & dest.field_mode;
106         result.is_key                           = source.is_key | dest.is_key;
107         result.is_mix                           = source.is_mix | dest.is_mix;
108         result.is_still                         = source.is_still | dest.is_still;
109         
110         return result;
111 }
112
113 bool operator==(const image_transform& lhs, const image_transform& rhs)
114 {
115         auto eq = [](double lhs, double rhs)
116         {
117                 return std::abs(lhs - rhs) < 5e-8;
118         };
119
120         return 
121                 eq(lhs.opacity, rhs.opacity) &&
122                 eq(lhs.contrast, rhs.contrast) &&
123                 eq(lhs.brightness, rhs.brightness) &&
124                 eq(lhs.saturation, rhs.saturation) &&
125                 boost::range::equal(lhs.fill_translation, rhs.fill_translation, eq) &&
126                 boost::range::equal(lhs.fill_scale, rhs.fill_scale, eq) &&
127                 boost::range::equal(lhs.clip_translation, rhs.clip_translation, eq) &&
128                 boost::range::equal(lhs.clip_scale, rhs.clip_scale, eq) &&
129                 lhs.field_mode == rhs.field_mode &&
130                 lhs.is_key == rhs.is_key &&
131                 lhs.is_mix == rhs.is_mix &&
132                 lhs.is_still == rhs.is_still;
133 }
134
135 bool operator!=(const image_transform& lhs, const image_transform& rhs)
136 {
137         return !(lhs == rhs);
138 }
139
140 // audio_transform
141                 
142 audio_transform::audio_transform() 
143         : volume(1.0)
144         , is_still(false)
145 {
146 }
147
148 audio_transform& audio_transform::operator*=(const audio_transform &other)
149 {
150         volume   *= other.volume;       
151         is_still |= other.is_still;
152         return *this;
153 }
154
155 audio_transform audio_transform::operator*(const audio_transform &other) const
156 {
157         return audio_transform(*this) *= other;
158 }
159
160 audio_transform audio_transform::tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween)
161 {       
162         auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)
163         {
164                 return tween(time, source, dest-source, duration);
165         };
166         
167         audio_transform result; 
168         result.is_still                 = source.is_still | dest.is_still;
169         result.volume                   = do_tween(time, source.volume,                         dest.volume,                    duration, tween);
170         
171         return result;
172 }
173
174 bool operator==(const audio_transform& lhs, const audio_transform& rhs)
175 {
176         auto eq = [](double lhs, double rhs)
177         {
178                 return std::abs(lhs - rhs) < 5e-8;
179         };
180
181         return eq(lhs.volume, rhs.volume) && lhs.is_still == rhs.is_still;
182 }
183
184 bool operator!=(const audio_transform& lhs, const audio_transform& rhs)
185 {
186         return !(lhs == rhs);
187 }
188
189 // frame_transform
190 frame_transform::frame_transform()
191 {
192 }
193
194 frame_transform& frame_transform::operator*=(const frame_transform &other)
195 {
196         image_transform *= other.image_transform;
197         audio_transform *= other.audio_transform;
198         return *this;
199 }
200
201 frame_transform frame_transform::operator*(const frame_transform &other) const
202 {
203         return frame_transform(*this) *= other;
204 }
205
206 frame_transform frame_transform::tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween)
207 {
208         frame_transform result;
209         result.image_transform = image_transform::tween(time, source.image_transform, dest.image_transform, duration, tween);
210         result.audio_transform = audio_transform::tween(time, source.audio_transform, dest.audio_transform, duration, tween);
211         return result;
212 }
213
214 bool operator==(const frame_transform& lhs, const frame_transform& rhs)
215 {
216         return  lhs.image_transform == rhs.image_transform && 
217                         lhs.audio_transform == rhs.audio_transform;
218 }
219
220 bool operator!=(const frame_transform& lhs, const frame_transform& rhs)
221 {
222         return !(lhs == rhs);
223 }
224
225 }}