From 11f2a57b1d27aaf02f27d8e5d88c312b292f254c Mon Sep 17 00:00:00 2001 From: Ronag Date: Fri, 19 Aug 2011 20:56:00 +0000 Subject: [PATCH] 2.0. image_mixer: Refactored blend-modes. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1239 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- core/core.vcxproj | 7 ++ core/core.vcxproj.filters | 6 + core/mixer/image/blend_modes.cpp | 73 ++++++++++++ core/mixer/image/blend_modes.h | 45 +++++++ core/mixer/image/image_kernel.cpp | 32 ++--- core/mixer/image/image_kernel.h | 17 ++- core/mixer/image/image_mixer.cpp | 152 ++++++++++++------------ core/mixer/image/image_mixer.h | 4 +- core/mixer/mixer.cpp | 12 +- core/mixer/mixer.h | 5 + core/producer/frame/image_transform.cpp | 79 ------------ core/producer/frame/image_transform.h | 46 +------ protocol/amcp/AMCPCommandsImpl.cpp | 11 +- 13 files changed, 259 insertions(+), 230 deletions(-) create mode 100644 core/mixer/image/blend_modes.cpp create mode 100644 core/mixer/image/blend_modes.h diff --git a/core/core.vcxproj b/core/core.vcxproj index 36394f632..64d8785a9 100644 --- a/core/core.vcxproj +++ b/core/core.vcxproj @@ -250,6 +250,7 @@ + @@ -297,6 +298,12 @@ ../../../StdAfx.h ../../../StdAfx.h + + ../../StdAfx.h + ../../StdAfx.h + ../../StdAfx.h + ../../StdAfx.h + ../../StdAfx.h ../../StdAfx.h diff --git a/core/core.vcxproj.filters b/core/core.vcxproj.filters index f6a853479..24ab83665 100644 --- a/core/core.vcxproj.filters +++ b/core/core.vcxproj.filters @@ -127,6 +127,9 @@ source\mixer\image + + source\mixer\image + @@ -208,5 +211,8 @@ source\mixer\image + + source\mixer\image + \ No newline at end of file diff --git a/core/mixer/image/blend_modes.cpp b/core/mixer/image/blend_modes.cpp new file mode 100644 index 000000000..d60d41198 --- /dev/null +++ b/core/mixer/image/blend_modes.cpp @@ -0,0 +1,73 @@ +#include "../../StdAfx.h" + +#include "blend_modes.h" + +#include + +namespace caspar { namespace core { + +blend_mode::type get_blend_mode(const std::wstring& str) +{ + if(boost::iequals(str, L"normal")) + return blend_mode::normal; + else if(boost::iequals(str, L"lighten")) + return blend_mode::lighten; + else if(boost::iequals(str, L"darken")) + return blend_mode::darken; + else if(boost::iequals(str, L"multiply")) + return blend_mode::multiply; + else if(boost::iequals(str, L"average")) + return blend_mode::average; + else if(boost::iequals(str, L"add")) + return blend_mode::add; + else if(boost::iequals(str, L"subtract")) + return blend_mode::subtract; + else if(boost::iequals(str, L"difference")) + return blend_mode::difference; + else if(boost::iequals(str, L"negation")) + return blend_mode::negation; + else if(boost::iequals(str, L"exclusion")) + return blend_mode::exclusion; + else if(boost::iequals(str, L"screen")) + return blend_mode::screen; + else if(boost::iequals(str, L"overlay")) + return blend_mode::overlay; + else if(boost::iequals(str, L"soft_light")) + return blend_mode::soft_light; + else if(boost::iequals(str, L"hard_light")) + return blend_mode::hard_light; + else if(boost::iequals(str, L"color_dodge")) + return blend_mode::color_dodge; + else if(boost::iequals(str, L"color_burn")) + return blend_mode::color_burn; + else if(boost::iequals(str, L"linear_dodge")) + return blend_mode::linear_dodge; + else if(boost::iequals(str, L"linear_burn")) + return blend_mode::linear_burn; + else if(boost::iequals(str, L"linear_light")) + return blend_mode::linear_light; + else if(boost::iequals(str, L"vivid_light")) + return blend_mode::vivid_light; + else if(boost::iequals(str, L"pin_light")) + return blend_mode::pin_light; + else if(boost::iequals(str, L"hard_mix")) + return blend_mode::hard_mix; + else if(boost::iequals(str, L"reflect")) + return blend_mode::reflect; + else if(boost::iequals(str, L"glow")) + return blend_mode::glow; + else if(boost::iequals(str, L"phoenix")) + return blend_mode::phoenix; + else if(boost::iequals(str, L"contrast")) + return blend_mode::contrast; + else if(boost::iequals(str, L"saturation")) + return blend_mode::saturation; + else if(boost::iequals(str, L"color")) + return blend_mode::color; + else if(boost::iequals(str, L"luminosity")) + return blend_mode::luminosity; + + return blend_mode::normal; +} + +}} \ No newline at end of file diff --git a/core/mixer/image/blend_modes.h b/core/mixer/image/blend_modes.h new file mode 100644 index 000000000..1684639ed --- /dev/null +++ b/core/mixer/image/blend_modes.h @@ -0,0 +1,45 @@ +#pragma once + +namespace caspar { namespace core { + +struct blend_mode +{ + enum type + { + normal = 0, + lighten, + darken, + multiply, + average, + add, + subtract, + difference, + negation, + exclusion, + screen, + overlay, + soft_light, + hard_light, + color_dodge, + color_burn, + linear_dodge, + linear_burn, + linear_light, + vivid_light, + pin_light, + hard_mix, + reflect, + glow, + phoenix, + contrast, + saturation, + color, + luminosity, + replace, + blend_mode_count + }; +}; + +blend_mode::type get_blend_mode(const std::wstring& str); + +}} \ No newline at end of file diff --git a/core/mixer/image/image_kernel.cpp b/core/mixer/image/image_kernel.cpp index dae98a0e0..4a837172d 100644 --- a/core/mixer/image/image_kernel.cpp +++ b/core/mixer/image/image_kernel.cpp @@ -59,7 +59,7 @@ GLubyte lower_pattern[] = { struct image_kernel::implementation : boost::noncopyable { std::shared_ptr shader_; - bool advanced_blend_modes_; + bool blend_modes_; void draw(ogl_device& ogl, render_item&& item, @@ -97,7 +97,7 @@ struct image_kernel::implementation : boost::noncopyable // Setup shader if(!shader_) - shader_ = get_image_shader(ogl, advanced_blend_modes_); + shader_ = get_image_shader(ogl, blend_modes_); ogl.use(*shader_); @@ -111,30 +111,28 @@ struct image_kernel::implementation : boost::noncopyable shader_->set("has_local_key", local_key); shader_->set("has_layer_key", layer_key); shader_->set("pixel_format", item.pix_desc.pix_fmt); - shader_->set("opacity", item.transform.get_opacity()); + shader_->set("opacity", item.transform.get_is_key() ? 1.0 : item.transform.get_opacity()); // Setup blend_func - if(advanced_blend_modes_) + if(item.transform.get_is_key()) + item.blend_mode = blend_mode::normal; + + if(blend_modes_) { background->bind(6); shader_->set("background", texture_id::background); - shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode()); + shader_->set("blend_mode", item.blend_mode); } else { - switch(item.transform.get_blend_mode()) + switch(item.blend_mode) { - case image_transform::blend_mode::add: - ogl.blend_func_separate(GL_ONE, GL_ONE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - break; - case image_transform::blend_mode::replace: + case blend_mode::replace: ogl.blend_func_separate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE); break; - case image_transform::blend_mode::screen: - ogl.blend_func_separate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - case image_transform::blend_mode::normal: + case blend_mode::normal: default: ogl.blend_func_separate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break; @@ -230,7 +228,7 @@ struct image_kernel::implementation : boost::noncopyable item.textures.clear(); ogl.yield(); // Return resources to pool as early as possible. - if(advanced_blend_modes_) + if(blend_modes_) { // http://www.opengl.org/registry/specs/NV/texture_barrier.txt // This allows us to use framebuffer (background) both as source and target while blending. @@ -240,7 +238,11 @@ struct image_kernel::implementation : boost::noncopyable }; image_kernel::image_kernel() : impl_(new implementation()){} -void image_kernel::draw(ogl_device& ogl, render_item&& item, const safe_ptr& background, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) +void image_kernel::draw(ogl_device& ogl, + render_item&& item, + const safe_ptr& background, + const std::shared_ptr& local_key, + const std::shared_ptr& layer_key) { impl_->draw(ogl, std::move(item), background, local_key, layer_key); } diff --git a/core/mixer/image/image_kernel.h b/core/mixer/image/image_kernel.h index 07078e870..9debd7fd3 100644 --- a/core/mixer/image/image_kernel.h +++ b/core/mixer/image/image_kernel.h @@ -19,6 +19,8 @@ */ #pragma once +#include "blend_modes.h" + #include #include @@ -38,19 +40,22 @@ struct render_item image_transform transform; video_mode::type mode; const void* tag; + blend_mode::type blend_mode; - render_item(const pixel_format_desc& pix_desc, const std::vector>& textures, const image_transform& transform, video_mode::type mode, const void* tag) + render_item(const pixel_format_desc& pix_desc, const std::vector>& textures, const image_transform& transform, video_mode::type mode, const void* tag, blend_mode::type blend_mode) : pix_desc(pix_desc) , textures(textures) , transform(transform) , mode(mode) - , tag(tag){} + , tag(tag) + , blend_mode(blend_mode){} render_item(render_item&& other) : pix_desc(other.pix_desc) , textures(std::move(other.textures)) , transform(other.transform) , mode(other.mode) - , tag(other.tag){} + , tag(other.tag) + , blend_mode(blend_mode){} }; bool operator==(const render_item& lhs, const render_item& rhs); @@ -59,7 +64,11 @@ class image_kernel : boost::noncopyable { public: image_kernel(); - void draw(ogl_device& ogl, render_item&& item, const safe_ptr& background, const std::shared_ptr& local_key = nullptr, const std::shared_ptr& layer_key = nullptr); + void draw(ogl_device& ogl, + render_item&& item, + const safe_ptr& background, + const std::shared_ptr& local_key = nullptr, + const std::shared_ptr& layer_key = nullptr); private: struct implementation; safe_ptr impl_; diff --git a/core/mixer/image/image_mixer.cpp b/core/mixer/image/image_mixer.cpp index 61920dbd5..edf382133 100644 --- a/core/mixer/image/image_mixer.cpp +++ b/core/mixer/image/image_mixer.cpp @@ -58,6 +58,7 @@ struct image_mixer::implementation : boost::noncopyable std::vector transform_stack_; std::vector mode_stack_; + std::stack blend_stack_; std::deque> layers_; // layer/stream/items @@ -91,7 +92,7 @@ public: if(boost::range::find(mode_stack_, video_mode::upper) != mode_stack_.end() && boost::range::find(mode_stack_, video_mode::lower) != mode_stack_.end()) return; - core::render_item item(frame.get_pixel_format_desc(), frame.get_textures(), transform_stack_.back(), mode_stack_.back(), frame.tag()); + core::render_item item(frame.get_pixel_format_desc(), frame.get_textures(), transform_stack_.back(), mode_stack_.back(), frame.tag(), blend_stack_.top()); auto& layer = layers_.back(); @@ -105,13 +106,15 @@ public: mode_stack_.pop_back(); } - void begin_layer() + void begin_layer(blend_mode::type blend_mode) { + blend_stack_.push(blend_mode); layers_.push_back(layer()); } void end_layer() { + blend_stack_.pop(); } boost::unique_future> render() @@ -151,34 +154,34 @@ public: return; std::pair> local_key_buffer; - - //if(has_overlapping_items(layer, layer.front().transform.get_blend_mode())) - //{ - // auto local_draw_buffer = create_device_buffer(4); + + if(has_overlapping_items(layer, layer.front().blend_mode)) + { + auto local_draw_buffer = create_device_buffer(4); - // auto local_blend_mode = layer.front().transform.get_blend_mode(); + auto local_blend_mode = layer.front().blend_mode; - // int fields = 0; - // BOOST_FOREACH(auto& item, layer) - // { - // if(fields & item.mode) - // item.transform.set_blend_mode(image_transform::blend_mode::normal); // Disable blending, it will be used when merging back into render stack. - // else - // { - // item.transform.set_blend_mode(image_transform::blend_mode::replace); // Target field is empty, no blending, just copy - // fields |= item.mode; - // } - - // draw_item(std::move(item), local_draw_buffer, local_key_buffer, layer_key_buffer); - // } - - // kernel_.draw(channel_.ogl(), create_render_item(local_draw_buffer, local_blend_mode), draw_buffer, nullptr, nullptr); - //} - //else // fast path - //{ + int fields = 0; + BOOST_FOREACH(auto& item, layer) + { + if(fields & item.mode) + item.blend_mode = blend_mode::normal; // Disable blending, it will be used when merging back into render stack. + else + { + item.blend_mode = blend_mode::replace; // Target field is empty, no blending, just copy + fields |= item.mode; + } + + draw_item(std::move(item), local_draw_buffer, local_key_buffer, layer_key_buffer); + } + + kernel_.draw(channel_.ogl(), create_render_item(local_draw_buffer, local_blend_mode), draw_buffer, nullptr, nullptr); + } + else // fast path + { BOOST_FOREACH(auto& item, layer) draw_item(std::move(item), draw_buffer, local_key_buffer, layer_key_buffer); - //} + } CASPAR_ASSERT(local_key_buffer.first == 0 || local_key_buffer.first == core::video_mode::progressive); @@ -197,11 +200,7 @@ public: local_key_buffer.first = 0; local_key_buffer.second = create_device_buffer(1); } - - // No transparency for key - item.transform.set_opacity(1.0); - item.transform.set_blend_mode(image_transform::blend_mode::normal); - + local_key_buffer.first |= item.mode; kernel_.draw(channel_.ogl(), std::move(item), make_safe(local_key_buffer.second), nullptr, nullptr); } @@ -219,49 +218,52 @@ public: } //// TODO: Optimize - //bool has_overlapping_items(const layer& layer, image_transform::blend_mode::type blend_mode) - //{ - // if(layer.size() < 2) - // return false; - // - // implementation::layer fill; - - // std::copy_if(layer.begin(), layer.end(), std::back_inserter(fill), [&](const render_item& item) - // { - // return !item.transform.get_is_key(); - // }); - // - // if(blend_mode == image_transform::blend_mode::normal) // Only overlap if opacity - // { - // return std::any_of(fill.begin(), fill.end(), [&](const render_item& item) - // { - // return item.transform.get_opacity() < 1.0 - 0.001; - // }); - // } - - // // Simple solution, just check if we have differnt video streams / tags. - // return std::any_of(fill.begin(), fill.end(), [&](const render_item& item) - // { - // return item.tag != fill.front().tag; - // }); - //} - // - //render_item create_render_item(const safe_ptr& buffer, image_transform::blend_mode::type blend_mode) - //{ - // CASPAR_ASSERT(buffer->stride() == 4 && "Only used for bgra textures"); - - // pixel_format_desc desc; - // desc.pix_fmt = pixel_format::bgra; - // desc.planes.push_back(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); - - // std::vector> textures; - // textures.push_back(buffer); - // - // image_transform transform; - // transform.set_blend_mode(blend_mode); - - // return render_item(desc, std::move(textures), transform, video_mode::progressive, nullptr); - //} + bool has_overlapping_items(const layer& layer, blend_mode::type blend_mode) + { + if(layer.size() < 2) + return false; + + if(blend_mode == blend_mode::normal) + return false; + + return std::any_of(layer.begin(), layer.end(), [&](const render_item& item) + { + return item.tag != layer.front().tag; + }); + + //std::copy_if(layer.begin(), layer.end(), std::back_inserter(fill), [&](const render_item& item) + //{ + // return !item.transform.get_is_key(); + //}); + // + //if(blend_mode == blend_mode::normal) // only overlap if opacity + //{ + // return std::any_of(fill.begin(), fill.end(), [&](const render_item& item) + // { + // return item.transform.get_opacity() < 1.0 - 0.001; + // }); + //} + + //// simple solution, just check if we have differnt video streams / tags. + //return std::any_of(fill.begin(), fill.end(), [&](const render_item& item) + //{ + // return item.tag != fill.front().tag; + //}); + } + + render_item create_render_item(const safe_ptr& buffer, blend_mode::type blend_mode) + { + CASPAR_ASSERT(buffer->stride() == 4 && "Only used for bgra textures"); + + pixel_format_desc desc; + desc.pix_fmt = pixel_format::bgra; + desc.planes.push_back(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); + + std::vector> textures; + textures.push_back(buffer); + + return render_item(desc, std::move(textures), image_transform(), video_mode::progressive, nullptr, blend_mode); + } safe_ptr create_device_buffer(size_t stride) { @@ -282,7 +284,7 @@ void image_mixer::visit(core::write_frame& frame){impl_->visit(frame);} void image_mixer::end(){impl_->end();} boost::unique_future> image_mixer::render(){return impl_->render();} safe_ptr image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc){return impl_->create_frame(tag, desc);} -void image_mixer::begin_layer(){impl_->begin_layer();} +void image_mixer::begin_layer(blend_mode::type blend_mode){impl_->begin_layer(blend_mode);} void image_mixer::end_layer(){impl_->end_layer();} image_mixer& image_mixer::operator=(image_mixer&& other) { diff --git a/core/mixer/image/image_mixer.h b/core/mixer/image/image_mixer.h index 2900276a8..15beb66c0 100644 --- a/core/mixer/image/image_mixer.h +++ b/core/mixer/image/image_mixer.h @@ -19,6 +19,8 @@ */ #pragma once +#include "blend_modes.h" + #include #include @@ -43,7 +45,7 @@ public: virtual void visit(core::write_frame& frame); virtual void end(); - void begin_layer(); + void begin_layer(blend_mode::type blend_mode); void end_layer(); image_mixer& operator=(image_mixer&& other); diff --git a/core/mixer/mixer.cpp b/core/mixer/mixer.cpp index 3a7939320..e06bd2df1 100644 --- a/core/mixer/mixer.cpp +++ b/core/mixer/mixer.cpp @@ -100,6 +100,8 @@ struct mixer::implementation : boost::noncopyable boost::fusion::map, boost::fusion::pair> transforms_; + std::unordered_map blend_modes_; + std::queue>, std::vector>> buffer_; const size_t buffer_size_; @@ -184,6 +186,11 @@ public: }); } + void set_blend_mode(int index, blend_mode::type value) + { + blend_modes_[index] = value; + } + std::wstring print() const { return L"mixer"; @@ -197,7 +204,8 @@ private: BOOST_FOREACH(auto& frame, frames) { - image_mixer_.begin_layer(); + auto blend_it = blend_modes_.find(frame.first); + image_mixer_.begin_layer(blend_it != blend_modes_.end() ? blend_it->second : blend_mode::normal); auto frame1 = make_safe(frame.second); frame1->get_image_transform() = image_transforms[frame.first].fetch_and_tick(1); @@ -252,5 +260,5 @@ void mixer::set_image_transform(int index, const core::image_transform& transfor void mixer::set_audio_transform(int index, const core::audio_transform& transform, unsigned int mix_duration, const std::wstring& tween){impl_->set_transform(index, transform, mix_duration, tween);} void mixer::apply_image_transform(int index, const std::function& transform, unsigned int mix_duration, const std::wstring& tween){impl_->apply_transform(index, transform, mix_duration, tween);} void mixer::apply_audio_transform(int index, const std::function& transform, unsigned int mix_duration, const std::wstring& tween){impl_->apply_transform(index, transform, mix_duration, tween);} - +void mixer::set_blend_mode(int index, blend_mode::type value){impl_->set_blend_mode(index, value);} }} \ No newline at end of file diff --git a/core/mixer/mixer.h b/core/mixer/mixer.h index f0f1c4796..198935c87 100644 --- a/core/mixer/mixer.h +++ b/core/mixer/mixer.h @@ -19,6 +19,8 @@ */ #pragma once +#include "image/blend_modes.h" + #include "../producer/frame/frame_factory.h" #include @@ -42,6 +44,7 @@ struct pixel_format; class mixer : public core::frame_factory { public: + explicit mixer(video_channel_context& video_channel); safe_ptr execute(const std::map>& frames); // nothrow @@ -58,6 +61,8 @@ public: void apply_image_transform(int index, const std::function& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear"); void apply_audio_transform(int index, const std::function& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear"); + void set_blend_mode(int index, blend_mode::type value); + private: struct implementation; safe_ptr impl_; diff --git a/core/producer/frame/image_transform.cpp b/core/producer/frame/image_transform.cpp index 7ca46e75c..369da5891 100644 --- a/core/producer/frame/image_transform.cpp +++ b/core/producer/frame/image_transform.cpp @@ -24,8 +24,6 @@ #include -#include - namespace caspar { namespace core { image_transform::image_transform() @@ -34,7 +32,6 @@ image_transform::image_transform() , contrast_(1.0) , saturation_(1.0) , is_key_(false) - , blend_mode_(image_transform::blend_mode::normal) { std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0); std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0); @@ -137,20 +134,9 @@ std::array image_transform::get_clip_scale() const return clip_scale_; } -void image_transform::set_blend_mode(image_transform::blend_mode::type value) -{ - blend_mode_ = value; -} - -image_transform::blend_mode::type image_transform::get_blend_mode() const -{ - return blend_mode_; -} - image_transform& image_transform::operator*=(const image_transform &other) { opacity_ *= other.opacity_; - blend_mode_ = std::max(blend_mode_, other.blend_mode_); brightness_ *= other.brightness_; contrast_ *= other.contrast_; saturation_ *= other.saturation_; @@ -191,7 +177,6 @@ image_transform tween(double time, const image_transform& source, const image_tr }; image_transform result; - result.set_blend_mode (std::max(source.get_blend_mode(), dest.get_blend_mode())); result.set_is_key (source.get_is_key() | dest.get_is_key()); result.set_brightness (do_tween(time, source.get_brightness(), dest.get_brightness(), duration, tweener)); result.set_contrast (do_tween(time, source.get_contrast(), dest.get_contrast(), duration, tweener)); @@ -218,70 +203,6 @@ image_transform tween(double time, const image_transform& source, const image_tr return result; } -image_transform::blend_mode::type get_blend_mode(const std::wstring& str) -{ - if(boost::iequals(str, L"normal")) - return image_transform::blend_mode::normal; - else if(boost::iequals(str, L"lighten")) - return image_transform::blend_mode::lighten; - else if(boost::iequals(str, L"darken")) - return image_transform::blend_mode::darken; - else if(boost::iequals(str, L"multiply")) - return image_transform::blend_mode::multiply; - else if(boost::iequals(str, L"average")) - return image_transform::blend_mode::average; - else if(boost::iequals(str, L"add")) - return image_transform::blend_mode::add; - else if(boost::iequals(str, L"subtract")) - return image_transform::blend_mode::subtract; - else if(boost::iequals(str, L"difference")) - return image_transform::blend_mode::difference; - else if(boost::iequals(str, L"negation")) - return image_transform::blend_mode::negation; - else if(boost::iequals(str, L"exclusion")) - return image_transform::blend_mode::exclusion; - else if(boost::iequals(str, L"screen")) - return image_transform::blend_mode::screen; - else if(boost::iequals(str, L"overlay")) - return image_transform::blend_mode::overlay; - else if(boost::iequals(str, L"soft_light")) - return image_transform::blend_mode::soft_light; - else if(boost::iequals(str, L"hard_light")) - return image_transform::blend_mode::hard_light; - else if(boost::iequals(str, L"color_dodge")) - return image_transform::blend_mode::color_dodge; - else if(boost::iequals(str, L"color_burn")) - return image_transform::blend_mode::color_burn; - else if(boost::iequals(str, L"linear_dodge")) - return image_transform::blend_mode::linear_dodge; - else if(boost::iequals(str, L"linear_burn")) - return image_transform::blend_mode::linear_burn; - else if(boost::iequals(str, L"linear_light")) - return image_transform::blend_mode::linear_light; - else if(boost::iequals(str, L"vivid_light")) - return image_transform::blend_mode::vivid_light; - else if(boost::iequals(str, L"pin_light")) - return image_transform::blend_mode::pin_light; - else if(boost::iequals(str, L"hard_mix")) - return image_transform::blend_mode::hard_mix; - else if(boost::iequals(str, L"reflect")) - return image_transform::blend_mode::reflect; - else if(boost::iequals(str, L"glow")) - return image_transform::blend_mode::glow; - else if(boost::iequals(str, L"phoenix")) - return image_transform::blend_mode::phoenix; - else if(boost::iequals(str, L"contrast")) - return image_transform::blend_mode::contrast; - else if(boost::iequals(str, L"saturation")) - return image_transform::blend_mode::saturation; - else if(boost::iequals(str, L"color")) - return image_transform::blend_mode::color; - else if(boost::iequals(str, L"luminosity")) - return image_transform::blend_mode::luminosity; - - return image_transform::blend_mode::normal; -} - bool operator<(const image_transform& lhs, const image_transform& rhs) { return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0; diff --git a/core/producer/frame/image_transform.h b/core/producer/frame/image_transform.h index 97b34d37d..f116d383e 100644 --- a/core/producer/frame/image_transform.h +++ b/core/producer/frame/image_transform.h @@ -33,44 +33,6 @@ class image_transform { public: - struct blend_mode - { - enum type - { - normal = 0, - lighten, - darken, - multiply, - average, - add, - subtract, - difference, - negation, - exclusion, - screen, - overlay, - soft_light, - hard_light, - color_dodge, - color_burn, - linear_dodge, - linear_burn, - linear_light, - vivid_light, - pin_light, - hard_mix, - reflect, - glow, - phoenix, - contrast, - saturation, - color, - luminosity, - replace, - blend_mode_count - }; - }; - struct levels { levels() @@ -122,10 +84,7 @@ public: void set_is_key(bool value); bool get_is_key() const; - - void set_blend_mode(blend_mode::type value); - blend_mode::type get_blend_mode() const; - + private: double opacity_; double gain_; @@ -140,11 +99,8 @@ private: std::array clip_scale_; video_mode::type mode_; bool is_key_; - blend_mode::type blend_mode_; }; -image_transform::blend_mode::type get_blend_mode(const std::wstring& str); - image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener); bool operator<(const image_transform& lhs, const image_transform& rhs); diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index 51a7aadee..cb136da78 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -316,16 +316,9 @@ bool MixerCommand::DoExecute() } else if(_parameters[1] == L"BLEND") { - auto blend_str = _parameters.at(2); - - auto transform = [=](image_transform transform) -> image_transform - { - transform.set_blend_mode(get_blend_mode(blend_str)); - return transform; - }; - + auto blend_str = _parameters.at(2); int layer = GetLayerIndex(); - GetChannel()->mixer()->apply_image_transform(GetLayerIndex(), transform); + GetChannel()->mixer()->set_blend_mode(GetLayerIndex(), get_blend_mode(blend_str)); } else if(_parameters[1] == L"BRIGHTNESS") { -- 2.39.2