+/*\r
+* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG.\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+*/\r
#include "../../stdafx.h"\r
\r
#include "image_transform.h"\r
\r
#include <common/utility/assert.h>\r
\r
+#include <boost/algorithm/string.hpp>\r
+\r
namespace caspar { namespace core {\r
\r
image_transform::image_transform() \r
: opacity_(1.0)\r
, gain_(1.0)\r
- , mode_(video_mode::invalid)\r
+ , brightness_(1.0)\r
+ , contrast_(1.0)\r
+ , saturation_(1.0)\r
+ , is_key_(false)\r
+ , deinterlace_(false)\r
+ , blend_mode_(image_transform::blend_mode::normal)\r
{\r
std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0);\r
std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0);\r
- std::fill(key_translation_.begin(), key_translation_.end(), 0.0);\r
- std::fill(key_scale_.begin(), key_scale_.end(), 1.0);\r
+ std::fill(clip_translation_.begin(), clip_translation_.end(), 0.0);\r
+ std::fill(clip_scale_.begin(), clip_scale_.end(), 1.0);\r
}\r
\r
void image_transform::set_opacity(double value)\r
{\r
- opacity_ = value;\r
+ opacity_ = std::max(value, 0.0);\r
}\r
\r
double image_transform::get_opacity() const\r
\r
void image_transform::set_gain(double value)\r
{\r
- gain_ = value;\r
+ gain_ = std::max(0.0, value);\r
}\r
\r
double image_transform::get_gain() const\r
return gain_;\r
}\r
\r
+void image_transform::set_brightness(double value)\r
+{\r
+ brightness_ = std::max(0.0, value);\r
+}\r
+\r
+double image_transform::get_brightness() const\r
+{\r
+ return brightness_;\r
+}\r
+\r
+void image_transform::set_contrast(double value)\r
+{\r
+ contrast_ = std::max(0.0, value);\r
+}\r
+\r
+double image_transform::get_contrast() const\r
+{\r
+ return contrast_;\r
+}\r
+\r
+void image_transform::set_saturation(double value)\r
+{\r
+ saturation_ = std::max(0.0, value);\r
+}\r
+\r
+double image_transform::get_saturation() const\r
+{\r
+ return saturation_;\r
+}\r
+\r
+void image_transform::set_levels(const image_transform::levels& value)\r
+{\r
+ levels_ = value;\r
+}\r
+\r
+image_transform::levels image_transform::get_levels() const\r
+{\r
+ return levels_;\r
+}\r
+\r
+\r
void image_transform::set_fill_translation(double x, double y)\r
{\r
fill_translation_[0] = x;\r
return fill_scale_;\r
}\r
\r
-void image_transform::set_key_translation(double x, double y)\r
+void image_transform::set_clip_translation(double x, double y)\r
{\r
- key_translation_[0] = x;\r
- key_translation_[1] = y;\r
+ clip_translation_[0] = x;\r
+ clip_translation_[1] = y;\r
}\r
\r
-void image_transform::set_key_scale(double x, double y)\r
+void image_transform::set_clip_scale(double x, double y)\r
{\r
- key_scale_[0] = x;\r
- key_scale_[1] = y; \r
+ clip_scale_[0] = x;\r
+ clip_scale_[1] = y; \r
}\r
\r
-std::array<double, 2> image_transform::get_key_translation() const\r
+std::array<double, 2> image_transform::get_clip_translation() const\r
{\r
- return key_translation_;\r
+ return clip_translation_;\r
}\r
\r
-std::array<double, 2> image_transform::get_key_scale() const\r
+std::array<double, 2> image_transform::get_clip_scale() const\r
{\r
- return key_scale_;\r
+ return clip_scale_;\r
}\r
\r
-void image_transform::set_mode(video_mode::type mode)\r
+void image_transform::set_deinterlace(bool value)\r
{\r
- mode_ = mode;\r
+ deinterlace_ = value;\r
}\r
\r
-video_mode::type image_transform::get_mode() const\r
+bool image_transform::get_deinterlace() const\r
{\r
- return mode_;\r
+ return deinterlace_;\r
+}\r
+\r
+void image_transform::set_blend_mode(image_transform::blend_mode::type value)\r
+{\r
+ blend_mode_ = value;\r
+}\r
+\r
+image_transform::blend_mode::type image_transform::get_blend_mode() const\r
+{\r
+ return blend_mode_;\r
}\r
\r
image_transform& image_transform::operator*=(const image_transform &other)\r
{\r
- opacity_ *= other.opacity_;\r
- if(other.mode_ != video_mode::invalid)\r
- mode_ = other.mode_;\r
- gain_ *= other.gain_;\r
- fill_translation_[0] += other.fill_translation_[0]*fill_scale_[0];\r
- fill_translation_[1] += other.fill_translation_[1]*fill_scale_[1];\r
- fill_scale_[0] *= other.fill_scale_[0];\r
- fill_scale_[1] *= other.fill_scale_[1];\r
- key_translation_[0] += other.key_translation_[0]*key_scale_[0];\r
- key_translation_[1] += other.key_translation_[1]*key_scale_[1];\r
- key_scale_[0] *= other.key_scale_[0];\r
- key_scale_[1] *= other.key_scale_[1];\r
+ opacity_ *= other.opacity_; \r
+ blend_mode_ = std::max(blend_mode_, other.blend_mode_);\r
+ gain_ *= other.gain_;\r
+ brightness_ *= other.brightness_;\r
+ contrast_ *= other.contrast_;\r
+ saturation_ *= other.saturation_;\r
+\r
+ levels_.min_input = std::max(levels_.min_input, other.levels_.min_input);\r
+ levels_.max_input = std::min(levels_.max_input, other.levels_.max_input);\r
+ \r
+ levels_.min_output = std::max(levels_.min_output, other.levels_.min_output);\r
+ levels_.max_output = std::min(levels_.max_output, other.levels_.max_output);\r
+\r
+ levels_.gamma *= other.levels_.gamma;\r
+\r
+ deinterlace_ |= other.deinterlace_;\r
+ is_key_ |= other.is_key_;\r
+ fill_translation_[0] += other.fill_translation_[0]*fill_scale_[0];\r
+ fill_translation_[1] += other.fill_translation_[1]*fill_scale_[1];\r
+ fill_scale_[0] *= other.fill_scale_[0];\r
+ fill_scale_[1] *= other.fill_scale_[1];\r
+ clip_translation_[0] += other.clip_translation_[0]*clip_scale_[0];\r
+ clip_translation_[1] += other.clip_translation_[1]*clip_scale_[1];\r
+ clip_scale_[0] *= other.clip_scale_[0];\r
+ clip_scale_[1] *= other.clip_scale_[1];\r
return *this;\r
}\r
\r
return image_transform(*this) *= other;\r
}\r
\r
-image_transform tween(const image_transform& lhs, const image_transform& rhs, const std::function<double(double, double, double)>& tweener, double delta)\r
-{\r
- CASPAR_ASSERT(lhs.get_mode() == rhs.get_mode() || lhs.get_mode() == video_mode::invalid || rhs.get_mode() == video_mode::invalid);\r
+void image_transform::set_is_key(bool value){is_key_ = value;}\r
+bool image_transform::get_is_key() const{return is_key_;}\r
\r
+image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener)\r
+{ \r
+ auto do_tween = [](double time, double source, double dest, double duration, const tweener_t& tweener)\r
+ {\r
+ return tweener(time, source, dest-source, duration);\r
+ };\r
+ \r
image_transform result; \r
- result.set_mode(rhs.get_mode() != video_mode::invalid ? rhs.get_mode() : lhs.get_mode());\r
- result.set_gain(tweener(lhs.get_gain(), rhs.get_gain(), delta));\r
- result.set_opacity(tweener(lhs.get_opacity(), rhs.get_opacity(), delta));\r
- result.set_fill_translation(tweener(lhs.get_fill_translation()[0], rhs.get_fill_translation()[0], delta), tweener(lhs.get_fill_translation()[1], rhs.get_fill_translation()[1], delta));\r
- result.set_fill_scale(tweener(lhs.get_fill_scale()[0], rhs.get_fill_scale()[0], delta), tweener(lhs.get_fill_scale()[1], rhs.get_fill_scale()[1], delta));\r
- result.set_key_translation(tweener(lhs.get_key_translation()[0], rhs.get_key_translation()[0], delta), tweener(lhs.get_key_translation()[1], rhs.get_key_translation()[1], delta));\r
- result.set_key_scale(tweener(lhs.get_key_scale()[0], rhs.get_key_scale()[0], delta), tweener(lhs.get_key_scale()[1], rhs.get_key_scale()[1], delta));\r
+ result.set_blend_mode (std::max(source.get_blend_mode(), dest.get_blend_mode()));\r
+ result.set_is_key (source.get_is_key() | dest.get_is_key());\r
+ result.set_deinterlace (source.get_deinterlace() | dest.get_deinterlace());\r
+ result.set_gain (do_tween(time, source.get_gain(), dest.get_gain(), duration, tweener));\r
+ result.set_brightness (do_tween(time, source.get_brightness(), dest.get_brightness(), duration, tweener));\r
+ result.set_contrast (do_tween(time, source.get_contrast(), dest.get_contrast(), duration, tweener));\r
+ result.set_saturation (do_tween(time, source.get_saturation(), dest.get_saturation(), duration, tweener));\r
+ result.set_opacity (do_tween(time, source.get_opacity(), dest.get_opacity(), duration, tweener));\r
+ 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
+ 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
+ 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
+ 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
\r
+ auto s_levels = source.get_levels();\r
+ auto d_levels = dest.get_levels();\r
+\r
+ d_levels.max_input = do_tween(time, s_levels.max_input, d_levels.max_input, duration, tweener);\r
+ d_levels.min_input = do_tween(time, s_levels.min_input, d_levels.min_input, duration, tweener);\r
+ \r
+ d_levels.max_output = do_tween(time, s_levels.max_output, d_levels.max_output, duration, tweener);\r
+ d_levels.min_output = do_tween(time, s_levels.min_output, d_levels.min_output, duration, tweener);\r
+\r
+ d_levels.gamma = do_tween(time, s_levels.gamma, d_levels.gamma, duration, tweener);\r
+\r
+ result.set_levels(d_levels);\r
+\r
return result;\r
}\r
\r
+image_transform::blend_mode::type get_blend_mode(const std::wstring& str)\r
+{\r
+ if(boost::iequals(str, L"normal"))\r
+ return image_transform::blend_mode::normal;\r
+ else if(boost::iequals(str, L"lighten"))\r
+ return image_transform::blend_mode::lighten;\r
+ else if(boost::iequals(str, L"darken"))\r
+ return image_transform::blend_mode::darken;\r
+ else if(boost::iequals(str, L"multiply"))\r
+ return image_transform::blend_mode::multiply;\r
+ else if(boost::iequals(str, L"average"))\r
+ return image_transform::blend_mode::average;\r
+ else if(boost::iequals(str, L"add"))\r
+ return image_transform::blend_mode::add;\r
+ else if(boost::iequals(str, L"subtract"))\r
+ return image_transform::blend_mode::subtract;\r
+ else if(boost::iequals(str, L"difference"))\r
+ return image_transform::blend_mode::difference;\r
+ else if(boost::iequals(str, L"negation"))\r
+ return image_transform::blend_mode::negation;\r
+ else if(boost::iequals(str, L"exclusion"))\r
+ return image_transform::blend_mode::exclusion;\r
+ else if(boost::iequals(str, L"screen"))\r
+ return image_transform::blend_mode::screen;\r
+ else if(boost::iequals(str, L"overlay"))\r
+ return image_transform::blend_mode::overlay;\r
+ else if(boost::iequals(str, L"soft_light"))\r
+ return image_transform::blend_mode::soft_light;\r
+ else if(boost::iequals(str, L"hard_light"))\r
+ return image_transform::blend_mode::hard_light;\r
+ else if(boost::iequals(str, L"color_dodge"))\r
+ return image_transform::blend_mode::color_dodge;\r
+ else if(boost::iequals(str, L"color_burn"))\r
+ return image_transform::blend_mode::color_burn;\r
+ else if(boost::iequals(str, L"linear_dodge"))\r
+ return image_transform::blend_mode::linear_dodge;\r
+ else if(boost::iequals(str, L"linear_burn"))\r
+ return image_transform::blend_mode::linear_burn;\r
+ else if(boost::iequals(str, L"linear_light"))\r
+ return image_transform::blend_mode::linear_light;\r
+ else if(boost::iequals(str, L"vivid_light"))\r
+ return image_transform::blend_mode::vivid_light;\r
+ else if(boost::iequals(str, L"pin_light"))\r
+ return image_transform::blend_mode::pin_light;\r
+ else if(boost::iequals(str, L"hard_mix"))\r
+ return image_transform::blend_mode::hard_mix;\r
+ else if(boost::iequals(str, L"reflect"))\r
+ return image_transform::blend_mode::reflect;\r
+ else if(boost::iequals(str, L"glow"))\r
+ return image_transform::blend_mode::glow;\r
+ else if(boost::iequals(str, L"phoenix"))\r
+ return image_transform::blend_mode::phoenix;\r
+ else if(boost::iequals(str, L"contrast"))\r
+ return image_transform::blend_mode::contrast;\r
+ else if(boost::iequals(str, L"saturation"))\r
+ return image_transform::blend_mode::saturation;\r
+ else if(boost::iequals(str, L"color"))\r
+ return image_transform::blend_mode::color;\r
+ else if(boost::iequals(str, L"luminosity"))\r
+ return image_transform::blend_mode::luminosity;\r
+ \r
+ return image_transform::blend_mode::normal;\r
+}\r
+\r
+bool operator<(const image_transform& lhs, const image_transform& rhs)\r
+{\r
+ return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0;\r
+}\r
+\r
+bool operator==(const image_transform& lhs, const image_transform& rhs)\r
+{\r
+ return memcmp(&lhs, &rhs, sizeof(image_transform)) == 0;\r
+}\r
+\r
+bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
+{\r
+ return !(lhs == rhs);\r
+}\r
+\r
}}
\ No newline at end of file