2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG (www.casparcg.com).
\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
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
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
19 * Author: Robert Nagy, ronag89@gmail.com
\r
22 #include "../stdafx.h"
\r
24 #include "frame_transform.h"
\r
26 #include <boost/range/algorithm/equal.hpp>
\r
27 #include <boost/range/algorithm/fill.hpp>
\r
29 namespace caspar { namespace core {
\r
33 image_transform::image_transform()
\r
38 , field_mode(field_mode::progressive)
\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
49 image_transform& image_transform::operator*=(const image_transform &other)
\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
75 image_transform image_transform::operator*(const image_transform &other) const
\r
77 return image_transform(*this) *= other;
\r
80 image_transform image_transform::tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween)
\r
82 auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)
\r
84 return tween(time, source, dest-source, duration);
\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
113 bool operator==(const image_transform& lhs, const image_transform& rhs)
\r
115 auto eq = [](double lhs, double rhs)
\r
117 return std::abs(lhs - rhs) < 5e-8;
\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
135 bool operator!=(const image_transform& lhs, const image_transform& rhs)
\r
137 return !(lhs == rhs);
\r
142 audio_transform::audio_transform()
\r
147 audio_transform& audio_transform::operator*=(const audio_transform &other)
\r
149 volume *= other.volume;
\r
153 audio_transform audio_transform::operator*(const audio_transform &other) const
\r
155 return audio_transform(*this) *= other;
\r
158 audio_transform audio_transform::tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween)
\r
160 auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)
\r
162 return tween(time, source, dest-source, duration);
\r
165 audio_transform result;
\r
166 result.volume = do_tween(time, source.volume, dest.volume, duration, tween);
\r
171 bool operator==(const audio_transform& lhs, const audio_transform& rhs)
\r
173 auto eq = [](double lhs, double rhs)
\r
175 return std::abs(lhs - rhs) < 5e-8;
\r
178 return eq(lhs.volume, rhs.volume);
\r
181 bool operator!=(const audio_transform& lhs, const audio_transform& rhs)
\r
183 return !(lhs == rhs);
\r
187 frame_transform::frame_transform()
\r
191 frame_transform& frame_transform::operator*=(const frame_transform &other)
\r
193 image_transform *= other.image_transform;
\r
194 audio_transform *= other.audio_transform;
\r
198 frame_transform frame_transform::operator*(const frame_transform &other) const
\r
200 return frame_transform(*this) *= other;
\r
203 frame_transform frame_transform::tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween)
\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
211 bool operator==(const frame_transform& lhs, const frame_transform& rhs)
\r
213 return lhs.image_transform == rhs.image_transform &&
\r
214 lhs.audio_transform == rhs.audio_transform;
\r
217 bool operator!=(const frame_transform& lhs, const frame_transform& rhs)
\r
219 return !(lhs == rhs);
\r