]> git.sesse.net Git - casparcg/blobdiff - core/mixer/image/image_mixer.cpp
2.0. image_mixer: Refactored blend-modes.
[casparcg] / core / mixer / image / image_mixer.cpp
index 61920dbd586c7eff13538fc1c3ab5224c79ec38a..edf38213358bf778182108df2786b70fb24c1000 100644 (file)
@@ -58,6 +58,7 @@ struct image_mixer::implementation : boost::noncopyable
 \r
        std::vector<image_transform>                    transform_stack_;\r
        std::vector<video_mode::type>                   mode_stack_;\r
+       std::stack<blend_mode::type>                    blend_stack_;\r
 \r
        std::deque<std::deque<render_item>>             layers_; // layer/stream/items\r
        \r
@@ -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())\r
                        return;\r
                \r
-               core::render_item item(frame.get_pixel_format_desc(), frame.get_textures(), transform_stack_.back(), mode_stack_.back(), frame.tag());  \r
+               core::render_item item(frame.get_pixel_format_desc(), frame.get_textures(), transform_stack_.back(), mode_stack_.back(), frame.tag(), blend_stack_.top());      \r
 \r
                auto& layer = layers_.back();\r
 \r
@@ -105,13 +106,15 @@ public:
                mode_stack_.pop_back();\r
        }\r
 \r
-       void begin_layer()\r
+       void begin_layer(blend_mode::type blend_mode)\r
        {\r
+               blend_stack_.push(blend_mode);\r
                layers_.push_back(layer());\r
        }\r
 \r
        void end_layer()\r
        {\r
+               blend_stack_.pop();\r
        }\r
        \r
        boost::unique_future<safe_ptr<host_buffer>> render()\r
@@ -151,34 +154,34 @@ public:
                        return;\r
 \r
                std::pair<int, std::shared_ptr<device_buffer>> local_key_buffer;\r
-                                       \r
-               //if(has_overlapping_items(layer, layer.front().transform.get_blend_mode()))\r
-               //{\r
-               //      auto local_draw_buffer = create_device_buffer(4);       \r
+                               \r
+               if(has_overlapping_items(layer, layer.front().blend_mode))\r
+               {\r
+                       auto local_draw_buffer = create_device_buffer(4);       \r
 \r
-               //      auto local_blend_mode = layer.front().transform.get_blend_mode();\r
+                       auto local_blend_mode = layer.front().blend_mode;\r
 \r
-               //      int fields = 0;\r
-               //      BOOST_FOREACH(auto& item, layer)\r
-               //      {\r
-               //              if(fields & item.mode)\r
-               //                      item.transform.set_blend_mode(image_transform::blend_mode::normal); // Disable blending, it will be used when merging back into render stack.\r
-               //              else\r
-               //              {\r
-               //                      item.transform.set_blend_mode(image_transform::blend_mode::replace); // Target field is empty, no blending, just copy\r
-               //                      fields |= item.mode;\r
-               //              }\r
-\r
-               //              draw_item(std::move(item), local_draw_buffer, local_key_buffer, layer_key_buffer);              \r
-               //      }\r
-\r
-               //      kernel_.draw(channel_.ogl(), create_render_item(local_draw_buffer, local_blend_mode), draw_buffer, nullptr, nullptr);\r
-               //}\r
-               //else // fast path\r
-               //{\r
+                       int fields = 0;\r
+                       BOOST_FOREACH(auto& item, layer)\r
+                       {\r
+                               if(fields & item.mode)\r
+                                       item.blend_mode = blend_mode::normal; // Disable blending, it will be used when merging back into render stack.\r
+                               else\r
+                               {\r
+                                       item.blend_mode = blend_mode::replace; // Target field is empty, no blending, just copy\r
+                                       fields |= item.mode;\r
+                               }\r
+\r
+                               draw_item(std::move(item), local_draw_buffer, local_key_buffer, layer_key_buffer);              \r
+                       }\r
+\r
+                       kernel_.draw(channel_.ogl(), create_render_item(local_draw_buffer, local_blend_mode), draw_buffer, nullptr, nullptr);\r
+               }\r
+               else // fast path\r
+               {\r
                        BOOST_FOREACH(auto& item, layer)                \r
                                draw_item(std::move(item), draw_buffer, local_key_buffer, layer_key_buffer);            \r
-               //}                                     \r
+               }                                       \r
 \r
                CASPAR_ASSERT(local_key_buffer.first == 0 || local_key_buffer.first == core::video_mode::progressive);\r
 \r
@@ -197,11 +200,7 @@ public:
                                local_key_buffer.first = 0;\r
                                local_key_buffer.second = create_device_buffer(1);\r
                        }\r
-\r
-                       // No transparency for key\r
-                       item.transform.set_opacity(1.0);\r
-                       item.transform.set_blend_mode(image_transform::blend_mode::normal);\r
-\r
+                       \r
                        local_key_buffer.first |= item.mode;\r
                        kernel_.draw(channel_.ogl(), std::move(item), make_safe(local_key_buffer.second), nullptr, nullptr);\r
                }\r
@@ -219,49 +218,52 @@ public:
        }\r
 \r
        //// TODO: Optimize\r
-       //bool has_overlapping_items(const layer& layer, image_transform::blend_mode::type blend_mode)\r
-       //{\r
-       //      if(layer.size() < 2)\r
-       //              return false;   \r
-       //      \r
-       //      implementation::layer fill;\r
-\r
-       //      std::copy_if(layer.begin(), layer.end(), std::back_inserter(fill), [&](const render_item& item)\r
-       //      {\r
-       //              return !item.transform.get_is_key();\r
-       //      });\r
-       //              \r
-       //      if(blend_mode == image_transform::blend_mode::normal) // Only overlap if opacity\r
-       //      {\r
-       //              return std::any_of(fill.begin(), fill.end(), [&](const render_item& item)\r
-       //              {\r
-       //                      return item.transform.get_opacity() < 1.0 - 0.001;\r
-       //              });\r
-       //      }\r
-\r
-       //      // Simple solution, just check if we have differnt video streams / tags.\r
-       //      return std::any_of(fill.begin(), fill.end(), [&](const render_item& item)\r
-       //      {\r
-       //              return item.tag != fill.front().tag;\r
-       //      });\r
-       //}                     \r
-       //              \r
-       //render_item create_render_item(const safe_ptr<device_buffer>& buffer, image_transform::blend_mode::type blend_mode)\r
-       //{\r
-       //      CASPAR_ASSERT(buffer->stride() == 4 && "Only used for bgra textures");\r
-\r
-       //      pixel_format_desc desc;\r
-       //      desc.pix_fmt = pixel_format::bgra;\r
-       //      desc.planes.push_back(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4));\r
-\r
-       //      std::vector<safe_ptr<device_buffer>> textures;\r
-       //      textures.push_back(buffer);\r
-       //                      \r
-       //      image_transform transform;\r
-       //      transform.set_blend_mode(blend_mode);\r
-\r
-       //      return render_item(desc, std::move(textures), transform, video_mode::progressive, nullptr);              \r
-       //}\r
+       bool has_overlapping_items(const layer& layer, blend_mode::type blend_mode)\r
+       {\r
+               if(layer.size() < 2)\r
+                       return false;   \r
+               \r
+               if(blend_mode == blend_mode::normal)\r
+                       return false;\r
+                               \r
+               return std::any_of(layer.begin(), layer.end(), [&](const render_item& item)\r
+               {\r
+                       return item.tag != layer.front().tag;\r
+               });\r
+\r
+               //std::copy_if(layer.begin(), layer.end(), std::back_inserter(fill), [&](const render_item& item)\r
+               //{\r
+               //      return !item.transform.get_is_key();\r
+               //});\r
+               //      \r
+               //if(blend_mode == blend_mode::normal) // only overlap if opacity\r
+               //{\r
+               //      return std::any_of(fill.begin(), fill.end(), [&](const render_item& item)\r
+               //      {\r
+               //              return item.transform.get_opacity() < 1.0 - 0.001;\r
+               //      });\r
+               //}\r
+\r
+               //// simple solution, just check if we have differnt video streams / tags.\r
+               //return std::any_of(fill.begin(), fill.end(), [&](const render_item& item)\r
+               //{\r
+               //      return item.tag != fill.front().tag;\r
+               //});\r
+       }                       \r
+               \r
+       render_item create_render_item(const safe_ptr<device_buffer>& buffer, blend_mode::type blend_mode)\r
+       {\r
+               CASPAR_ASSERT(buffer->stride() == 4 && "Only used for bgra textures");\r
+\r
+               pixel_format_desc desc;\r
+               desc.pix_fmt = pixel_format::bgra;\r
+               desc.planes.push_back(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4));\r
+\r
+               std::vector<safe_ptr<device_buffer>> textures;\r
+               textures.push_back(buffer);\r
+                               \r
+               return render_item(desc, std::move(textures), image_transform(), video_mode::progressive, nullptr, blend_mode);          \r
+       }\r
 \r
        safe_ptr<device_buffer> create_device_buffer(size_t stride)\r
        {\r
@@ -282,7 +284,7 @@ void image_mixer::visit(core::write_frame& frame){impl_->visit(frame);}
 void image_mixer::end(){impl_->end();}\r
 boost::unique_future<safe_ptr<host_buffer>> image_mixer::render(){return impl_->render();}\r
 safe_ptr<write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc){return impl_->create_frame(tag, desc);}\r
-void image_mixer::begin_layer(){impl_->begin_layer();}\r
+void image_mixer::begin_layer(blend_mode::type blend_mode){impl_->begin_layer(blend_mode);}\r
 void image_mixer::end_layer(){impl_->end_layer();}\r
 image_mixer& image_mixer::operator=(image_mixer&& other)\r
 {\r