target.Draw(*guide_);\r
\r
glBegin(GL_LINE_STRIP);\r
- glColor4f(c_.red, c_.green, c_.blue, 0.7f); \r
+ glColor4f(c_.red, c_.green, c_.blue, 0.8f); \r
for(size_t n = 0; n < line_data_.size(); ++n) \r
if(line_data_[n].first > -0.5)\r
glVertex3d(x+n*dx, std::max(0.05, std::min(0.95, (1.0f-line_data_[n].first)*0.8 + 0.1f)), 0.0); \r
<ClInclude Include="mixer\gpu\fence.h" />\r
<ClInclude Include="mixer\gpu\shader.h" />\r
<ClInclude Include="mixer\image\blending_glsl.h" />\r
+ <ClInclude Include="mixer\image\image_shader.h" />\r
<ClInclude Include="video_channel.h" />\r
<ClInclude Include="video_channel_context.h" />\r
<ClInclude Include="consumer\output.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="mixer\image\image_shader.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="video_channel.cpp" />\r
<ClCompile Include="consumer\frame_consumer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<ClInclude Include="mixer\gpu\fence.h">\r
<Filter>source\mixer\gpu</Filter>\r
</ClInclude>\r
+ <ClInclude Include="mixer\image\image_shader.h">\r
+ <Filter>source\mixer\image</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="producer\transition\transition_producer.cpp">\r
<ClCompile Include="mixer\gpu\fence.cpp">\r
<Filter>source\mixer\gpu</Filter>\r
</ClCompile>\r
+ <ClCompile Include="mixer\image\image_shader.cpp">\r
+ <Filter>source\mixer\image</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
return it->second;\r
}\r
\r
+ void set(const std::string& name, bool value)\r
+ {\r
+ set(name, value ? 1 : 0);\r
+ }\r
+\r
void set(const std::string& name, int value)\r
{\r
GL(glUniform1i(get_location(name.c_str()), value));\r
\r
\r
shader::shader(const std::string& vertex_source_str, const std::string& fragment_source_str) : impl_(new implementation(vertex_source_str, fragment_source_str)){}\r
+void shader::set(const std::string& name, bool value){impl_->set(name, value);}\r
void shader::set(const std::string& name, int value){impl_->set(name, value);}\r
void shader::set(const std::string& name, float value){impl_->set(name, value);}\r
void shader::set(const std::string& name, double value){impl_->set(name, value);}\r
{\r
public:\r
shader(const std::string& vertex_source_str, const std::string& fragment_source_str);\r
+ void set(const std::string& name, bool value);\r
void set(const std::string& name, int value);\r
void set(const std::string& name, float value);\r
void set(const std::string& name, double value);\r
\r
#include "image_kernel.h"\r
\r
+#include "image_shader.h"\r
+\r
#include "blending_glsl.h"\r
#include "../gpu/shader.h"\r
#include "../gpu/device_buffer.h"\r
\r
struct image_kernel::implementation : boost::noncopyable\r
{ \r
- std::unique_ptr<shader> shader_;\r
+ std::shared_ptr<shader> shader_;\r
bool blend_modes_;\r
- \r
- implementation() : blend_modes_(true)\r
- {\r
- }\r
-\r
- std::string get_blend_color_func()\r
- {\r
- return \r
- \r
- get_adjustement_glsl()\r
- \r
- +\r
-\r
- get_blend_glsl()\r
- \r
- +\r
- \r
- "vec3 get_blend_color(vec3 back, vec3 fore) \n"\r
- "{ \n"\r
- " switch(blend_mode) \n"\r
- " { \n"\r
- " case 0: return BlendNormal(back, fore); \n"\r
- " case 1: return BlendLighten(back, fore); \n"\r
- " case 2: return BlendDarken(back, fore); \n"\r
- " case 3: return BlendMultiply(back, fore); \n"\r
- " case 4: return BlendAverage(back, fore); \n"\r
- " case 5: return BlendAdd(back, fore); \n"\r
- " case 6: return BlendSubstract(back, fore); \n"\r
- " case 7: return BlendDifference(back, fore); \n"\r
- " case 8: return BlendNegation(back, fore); \n"\r
- " case 9: return BlendExclusion(back, fore); \n"\r
- " case 10: return BlendScreen(back, fore); \n"\r
- " case 11: return BlendOverlay(back, fore); \n"\r
- //" case 12: return BlendSoftLight(back, fore); \n"\r
- " case 13: return BlendHardLight(back, fore); \n"\r
- " case 14: return BlendColorDodge(back, fore); \n"\r
- " case 15: return BlendColorBurn(back, fore); \n"\r
- " case 16: return BlendLinearDodge(back, fore); \n"\r
- " case 17: return BlendLinearBurn(back, fore); \n"\r
- " case 18: return BlendLinearLight(back, fore); \n"\r
- " case 19: return BlendVividLight(back, fore); \n"\r
- " case 20: return BlendPinLight(back, fore); \n"\r
- " case 21: return BlendHardMix(back, fore); \n"\r
- " case 22: return BlendReflect(back, fore); \n"\r
- " case 23: return BlendGlow(back, fore); \n"\r
- " case 24: return BlendPhoenix(back, fore); \n"\r
- " case 25: return BlendHue(back, fore); \n"\r
- " case 26: return BlendSaturation(back, fore); \n"\r
- " case 27: return BlendColor(back, fore); \n"\r
- " case 28: return BlendLuminosity(back, fore); \n"\r
- " } \n"\r
- " return BlendNormal(back, fore); \n"\r
- "} \n"\r
- " \n" \r
- "vec4 blend(vec4 fore) \n"\r
- "{ \n"\r
- " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
- " fore.rgb = get_blend_color(back.rgb, fore.rgb); \n"\r
- " return vec4(mix(back.bgr, fore.rgb, fore.a), back.a + fore.a); \n"\r
- "} \n";\r
- }\r
- \r
- std::string get_simple_blend_color_func()\r
- {\r
- return \r
- \r
- get_adjustement_glsl()\r
- \r
- +\r
-\r
- "vec4 blend(vec4 fore) \n"\r
- "{ \n"\r
- " return fore; \n"\r
- "} \n";\r
- }\r
-\r
- std::string get_vertex()\r
- {\r
- return \r
-\r
- "void main() \n"\r
- "{ \n"\r
- " gl_TexCoord[0] = gl_MultiTexCoord0; \n"\r
- " gl_TexCoord[1] = gl_MultiTexCoord1; \n"\r
- " gl_FrontColor = gl_Color; \n"\r
- " gl_Position = ftransform(); \n"\r
- "} \n";\r
- }\r
-\r
- std::string get_fragment()\r
- {\r
- return\r
-\r
- "#version 120 \n"\r
- "uniform sampler2D background; \n"\r
- "uniform sampler2D plane[4]; \n"\r
- "uniform sampler2D local_key; \n"\r
- "uniform sampler2D layer_key; \n"\r
- " \n"\r
- "uniform bool is_hd; \n"\r
- "uniform bool has_local_key; \n"\r
- "uniform bool has_layer_key; \n"\r
- "uniform int blend_mode; \n"\r
- "uniform int alpha_mode; \n"\r
- "uniform int pixel_format; \n"\r
- " \n"\r
- "uniform bool levels; \n"\r
- "uniform float min_input; \n"\r
- "uniform float max_input; \n"\r
- "uniform float gamma; \n"\r
- "uniform float min_output; \n"\r
- "uniform float max_output; \n"\r
- " \n"\r
- "uniform bool csb; \n"\r
- "uniform float brt; \n"\r
- "uniform float sat; \n"\r
- "uniform float con; \n"\r
- " \n" \r
-\r
- +\r
- \r
- (blend_modes_ ? get_blend_color_func() : get_simple_blend_color_func())\r
-\r
- +\r
- \r
- " \n"\r
- "//http://slouken.blogspot.com/2011/02/mpeg-acceleration-with-glsl.html \n"\r
- "vec4 ycbcra_to_rgba_sd(float y, float cb, float cr, float a) \n"\r
- "{ \n"\r
- " // YUV offset \n"\r
- " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n"\r
- " \n"\r
- " // RGB coefficients \n"\r
- " const vec3 Rcoeff = vec3(1.164, 0.000, 1.596); \n"\r
- " const vec3 Gcoeff = vec3(1.164, -0.391, -0.813); \n"\r
- " const vec3 Bcoeff = vec3(1.164, 2.018, 0.000); \n"\r
- " \n"\r
- " vec3 yuv = vec3(y, cr, cb); \n"\r
- " vec4 rgba; \n"\r
- " \n"\r
- " yuv += offset; \n"\r
- " rgba.r = dot(yuv, Rcoeff); \n"\r
- " rgba.g = dot(yuv, Gcoeff); \n"\r
- " rgba.b = dot(yuv, Bcoeff); \n"\r
- " rgba.a = a; \n"\r
- " \n"\r
- " return rgba; \n"\r
- "} \n" \r
- " \n"\r
- "vec4 ycbcra_to_rgba_hd(float y, float cb, float cr, float a) \n"\r
- "{ \n"\r
- " // YUV offset \n"\r
- " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n"\r
- " \n"\r
- " // RGB coefficients \n"\r
- " const vec3 Rcoeff = vec3(1.164, 0.000, 1.793); \n"\r
- " const vec3 Gcoeff = vec3(1.164, -0.213, -0.534); \n"\r
- " const vec3 Bcoeff = vec3(1.164, 2.115, 0.000); \n"\r
- " \n"\r
- " vec3 yuv = vec3(y, cr, cb); \n"\r
- " vec4 rgba; \n"\r
- " \n"\r
- " yuv += offset; \n"\r
- " rgba.r = dot(yuv, Rcoeff); \n"\r
- " rgba.g = dot(yuv, Gcoeff); \n"\r
- " rgba.b = dot(yuv, Bcoeff); \n"\r
- " rgba.a = a; \n"\r
- " \n"\r
- " return rgba; \n"\r
- "} \n" \r
- " \n" \r
- "vec4 ycbcra_to_rgba(float y, float cb, float cr, float a) \n"\r
- "{ \n"\r
- " if(is_hd) \n"\r
- " return ycbcra_to_rgba_hd(y, cb, cr, a); \n"\r
- " else \n"\r
- " return ycbcra_to_rgba_sd(y, cb, cr, a); \n"\r
- "} \n"\r
- " \n"\r
- "vec4 get_rgba_color() \n"\r
- "{ \n"\r
- " switch(pixel_format) \n"\r
- " { \n"\r
- " case 0: //gray \n"\r
- " return vec4(texture2D(plane[0], gl_TexCoord[0].st).rrr, 1.0); \n"\r
- " case 1: //bgra, \n"\r
- " return texture2D(plane[0], gl_TexCoord[0].st).bgra; \n"\r
- " case 2: //rgba, \n"\r
- " return texture2D(plane[0], gl_TexCoord[0].st).rgba; \n"\r
- " case 3: //argb, \n"\r
- " return texture2D(plane[0], gl_TexCoord[0].st).argb; \n"\r
- " case 4: //abgr, \n"\r
- " return texture2D(plane[0], gl_TexCoord[0].st).gbar; \n"\r
- " case 5: //ycbcr, \n"\r
- " { \n"\r
- " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n"\r
- " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n"\r
- " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n"\r
- " return ycbcra_to_rgba(y, cb, cr, 1.0); \n"\r
- " } \n"\r
- " case 6: //ycbcra \n"\r
- " { \n"\r
- " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n"\r
- " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n"\r
- " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n"\r
- " float a = texture2D(plane[3], gl_TexCoord[0].st).r; \n"\r
- " return ycbcra_to_rgba(y, cb, cr, a); \n"\r
- " } \n"\r
- " case 7: //luma \n"\r
- " { \n"\r
- " vec3 y3 = texture2D(plane[0], gl_TexCoord[0].st).rrr; \n"\r
- " return vec4((y3-0.065)/0.859, 1.0); \n"\r
- " } \n"\r
- " } \n"\r
- " return vec4(0.0, 0.0, 0.0, 0.0); \n"\r
- "} \n"\r
- " \n"\r
- "void main() \n"\r
- "{ \n"\r
- " vec4 color = get_rgba_color(); \n"\r
- " if(levels) \n"\r
- " color.rgb = LevelsControl(color.rgb, min_input, max_input, gamma, min_output, max_output); \n"\r
- " if(csb) \n"\r
- " color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con); \n"\r
- " if(has_local_key) \n"\r
- " color.a *= texture2D(local_key, gl_TexCoord[1].st).r; \n"\r
- " if(has_layer_key) \n"\r
- " color.a *= texture2D(layer_key, gl_TexCoord[1].st).r; \n"\r
- " color *= gl_Color; \n"\r
- " color = blend(color); \n"\r
- " gl_FragColor = color.bgra; \n"\r
- "} \n";\r
- }\r
-\r
- void init_shader(ogl_device& ogl)\r
- {\r
- try\r
- { \r
- blend_modes_ = glTextureBarrierNV ? env::properties().get("configuration.mixers.blend-modes", false) : false;\r
- shader_.reset(new shader(get_vertex(), get_fragment()));\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";\r
- \r
- blend_modes_ = false;\r
- shader_.reset(new shader(get_vertex(), get_fragment()));\r
- }\r
- \r
- ogl.enable(GL_TEXTURE_2D);\r
-\r
- if(!blend_modes_)\r
- {\r
- ogl.enable(GL_BLEND);\r
- GL(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE));\r
- CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";\r
- }\r
- }\r
- \r
+ \r
void draw(ogl_device& ogl,\r
render_item&& item,\r
const safe_ptr<device_buffer>& background,\r
\r
if(item.transform.get_opacity() < epsilon)\r
return;\r
-\r
- if(!shader_)\r
- init_shader(ogl);\r
- \r
- if(item.mode == core::video_mode::progressive) \r
- ogl.disable(GL_POLYGON_STIPPLE); \r
- else \r
- {\r
- ogl.enable(GL_POLYGON_STIPPLE);\r
-\r
- if(item.mode == core::video_mode::upper)\r
- ogl.stipple_pattern(upper_pattern);\r
- else if(item.mode == core::video_mode::lower)\r
- ogl.stipple_pattern(lower_pattern);\r
- }\r
-\r
+ \r
// Bind textures\r
\r
for(size_t n = 0; n < item.textures.size(); ++n)\r
item.textures[n]->bind(n);\r
\r
if(local_key)\r
- local_key->bind(4);\r
+ local_key->bind(texture_id::local_key);\r
\r
if(layer_key)\r
- layer_key->bind(5);\r
- \r
+ layer_key->bind(texture_id::layer_key);\r
+ \r
// Setup shader\r
\r
+ if(!shader_)\r
+ shader_ = get_image_shader(ogl, blend_modes_);\r
+ \r
ogl.use(*shader_);\r
\r
- shader_->set("plane[0]", 0);\r
- shader_->set("plane[1]", 1);\r
- shader_->set("plane[2]", 2);\r
- shader_->set("plane[3]", 3);\r
- shader_->set("local_key", 4);\r
- shader_->set("layer_key", 5);\r
- shader_->set("is_hd", item.pix_desc.planes.at(0).height > 700 ? 1 : 0);\r
- shader_->set("has_local_key", local_key ? 1 : 0);\r
- shader_->set("has_layer_key", layer_key ? 1 : 0);\r
+ shader_->set("plane[0]", texture_id::plane0);\r
+ shader_->set("plane[1]", texture_id::plane1);\r
+ shader_->set("plane[2]", texture_id::plane2);\r
+ shader_->set("plane[3]", texture_id::plane3);\r
+ shader_->set("local_key", texture_id::local_key);\r
+ shader_->set("layer_key", texture_id::layer_key);\r
+ shader_->set("is_hd", item.pix_desc.planes.at(0).height > 700 ? 1 : 0);\r
+ shader_->set("has_local_key", local_key);\r
+ shader_->set("has_layer_key", layer_key);\r
shader_->set("pixel_format", item.pix_desc.pix_fmt); \r
\r
// Setup blend_func\r
{\r
background->bind(6);\r
\r
- shader_->set("background", 6);\r
- shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode());\r
- shader_->set("alpha_mode", item.transform.get_alpha_mode());\r
+ shader_->set("background", texture_id::background);\r
+ shader_->set("blend_mode", item.transform.get_is_key() ? core::image_transform::blend_mode::normal : item.transform.get_blend_mode());\r
}\r
\r
+ // Setup image-adjustements\r
+\r
auto levels = item.transform.get_levels();\r
\r
if(levels.min_input > epsilon ||\r
else\r
shader_->set("csb", false); \r
\r
+ // Setup interlacing\r
+\r
+ if(item.mode == core::video_mode::progressive) \r
+ ogl.disable(GL_POLYGON_STIPPLE); \r
+ else \r
+ {\r
+ ogl.enable(GL_POLYGON_STIPPLE);\r
+\r
+ if(item.mode == core::video_mode::upper)\r
+ ogl.stipple_pattern(upper_pattern);\r
+ else if(item.mode == core::video_mode::lower)\r
+ ogl.stipple_pattern(lower_pattern);\r
+ }\r
+\r
// Setup drawing area\r
\r
ogl.viewport(0, 0, background->width(), background->height());\r
auto f_p = item.transform.get_fill_translation();\r
auto f_s = item.transform.get_fill_scale();\r
\r
+ // Set render target\r
+ \r
+ ogl.attach(*background);\r
+ \r
// Draw\r
\r
glBegin(GL_QUADS);\r
glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1, f_p[0] , (f_p[1]+f_s[1])); glVertex2d( f_p[0] *2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
glEnd();\r
\r
+ // Cleanup\r
+\r
ogl.disable(GL_SCISSOR_TEST); \r
\r
item.textures.clear();\r
ogl.yield(); // Return resources to pool as early as possible.\r
\r
if(!blend_modes_)\r
- glTextureBarrierNV(); // This allows us to use framebuffer both as source and target while blending.\r
+ glTextureBarrierNV(); // This allows us to use framebuffer (background) both as source and target while blending.\r
}\r
};\r
\r
\r
std::shared_ptr<device_buffer> local_key_buffer_;\r
std::shared_ptr<device_buffer> layer_key_buffer_;\r
+\r
+ std::shared_ptr<host_buffer> empty_buffer_;\r
\r
public:\r
implementation(video_channel_context& video_channel) \r
layer_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
draw_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
local_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
+\r
+ empty_buffer_ = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::write_only);\r
+ memset(empty_buffer_->data(), 0, empty_buffer_->size());\r
+\r
channel_.ogl().gc();\r
}\r
\r
\r
auto& layer = layers_.back();\r
\r
- auto it = boost::range::find(layer, item);\r
- if(it == layer.end())\r
+ if(boost::range::find(layer, item) == layer.end())\r
layer.push_back(item);\r
}\r
\r
\r
safe_ptr<host_buffer> render(std::deque<layer>&& layers)\r
{\r
+ if(layers.empty())\r
+ return make_safe(empty_buffer_);\r
+\r
if(channel_.get_format_desc().width != write_buffer_->width() || channel_.get_format_desc().height != write_buffer_->height())\r
initialize_buffers();\r
\r
host_buffer->begin_read(write_buffer_->width(), write_buffer_->height(), format(write_buffer_->stride()));\r
\r
GL(glFlush());\r
-\r
+ \r
return host_buffer;\r
}\r
\r
channel_.ogl().yield(); // Try to give it some more time.\r
} \r
\r
- channel_.ogl().attach(*target);\r
kernel_.draw(channel_.ogl(), std::move(item), make_safe(target), local_key, layer_key);\r
}\r
\r
--- /dev/null
+#include "../../StdAfx.h"\r
+\r
+#include "image_shader.h"\r
+\r
+#include "../gpu/shader.h"\r
+#include "../gpu/ogl_device.h"\r
+\r
+#include "blending_glsl.h"\r
+\r
+#include <common/gl/gl_check.h>\r
+#include <common/env.h>\r
+\r
+#include <tbb/mutex.h>\r
+\r
+namespace caspar { namespace core {\r
+\r
+std::shared_ptr<shader> g_shader;\r
+tbb::mutex g_shader_mutex;\r
+bool g_blend_modes = false;\r
+\r
+std::string get_blend_color_func()\r
+{\r
+ return \r
+ \r
+ get_adjustement_glsl()\r
+ \r
+ +\r
+\r
+ get_blend_glsl()\r
+ \r
+ +\r
+ \r
+ "vec3 get_blend_color(vec3 back, vec3 fore) \n"\r
+ "{ \n"\r
+ " switch(blend_mode) \n"\r
+ " { \n"\r
+ " case 0: return BlendNormal(back, fore); \n"\r
+ " case 1: return BlendLighten(back, fore); \n"\r
+ " case 2: return BlendDarken(back, fore); \n"\r
+ " case 3: return BlendMultiply(back, fore); \n"\r
+ " case 4: return BlendAverage(back, fore); \n"\r
+ " case 5: return BlendAdd(back, fore); \n"\r
+ " case 6: return BlendSubstract(back, fore); \n"\r
+ " case 7: return BlendDifference(back, fore); \n"\r
+ " case 8: return BlendNegation(back, fore); \n"\r
+ " case 9: return BlendExclusion(back, fore); \n"\r
+ " case 10: return BlendScreen(back, fore); \n"\r
+ " case 11: return BlendOverlay(back, fore); \n"\r
+ //" case 12: return BlendSoftLight(back, fore); \n"\r
+ " case 13: return BlendHardLight(back, fore); \n"\r
+ " case 14: return BlendColorDodge(back, fore); \n"\r
+ " case 15: return BlendColorBurn(back, fore); \n"\r
+ " case 16: return BlendLinearDodge(back, fore); \n"\r
+ " case 17: return BlendLinearBurn(back, fore); \n"\r
+ " case 18: return BlendLinearLight(back, fore); \n"\r
+ " case 19: return BlendVividLight(back, fore); \n"\r
+ " case 20: return BlendPinLight(back, fore); \n"\r
+ " case 21: return BlendHardMix(back, fore); \n"\r
+ " case 22: return BlendReflect(back, fore); \n"\r
+ " case 23: return BlendGlow(back, fore); \n"\r
+ " case 24: return BlendPhoenix(back, fore); \n"\r
+ " case 25: return BlendHue(back, fore); \n"\r
+ " case 26: return BlendSaturation(back, fore); \n"\r
+ " case 27: return BlendColor(back, fore); \n"\r
+ " case 28: return BlendLuminosity(back, fore); \n"\r
+ " } \n"\r
+ " return BlendNormal(back, fore); \n"\r
+ "} \n"\r
+ " \n" \r
+ "vec4 blend(vec4 fore) \n"\r
+ "{ \n"\r
+ " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
+ " fore.rgb = get_blend_color(back.rgb, fore.rgb); \n"\r
+ " return vec4(mix(back.bgr, fore.rgb, fore.a), back.a + fore.a); \n"\r
+ "} \n";\r
+}\r
+ \r
+std::string get_simple_blend_color_func()\r
+{\r
+ return \r
+ \r
+ get_adjustement_glsl()\r
+ \r
+ +\r
+\r
+ "vec4 blend(vec4 fore) \n"\r
+ "{ \n"\r
+ " return fore; \n"\r
+ "} \n";\r
+}\r
+\r
+std::string get_vertex()\r
+{\r
+ return \r
+\r
+ "void main() \n"\r
+ "{ \n"\r
+ " gl_TexCoord[0] = gl_MultiTexCoord0; \n"\r
+ " gl_TexCoord[1] = gl_MultiTexCoord1; \n"\r
+ " gl_FrontColor = gl_Color; \n"\r
+ " gl_Position = ftransform(); \n"\r
+ "} \n";\r
+}\r
+\r
+std::string get_fragment(bool blend_modes)\r
+{\r
+ return\r
+\r
+ "#version 120 \n"\r
+ "uniform sampler2D background; \n"\r
+ "uniform sampler2D plane[4]; \n"\r
+ "uniform sampler2D local_key; \n"\r
+ "uniform sampler2D layer_key; \n"\r
+ " \n"\r
+ "uniform bool is_hd; \n"\r
+ "uniform bool has_local_key; \n"\r
+ "uniform bool has_layer_key; \n"\r
+ "uniform int blend_mode; \n"\r
+ "uniform int pixel_format; \n"\r
+ " \n"\r
+ "uniform bool levels; \n"\r
+ "uniform float min_input; \n"\r
+ "uniform float max_input; \n"\r
+ "uniform float gamma; \n"\r
+ "uniform float min_output; \n"\r
+ "uniform float max_output; \n"\r
+ " \n"\r
+ "uniform bool csb; \n"\r
+ "uniform float brt; \n"\r
+ "uniform float sat; \n"\r
+ "uniform float con; \n"\r
+ " \n" \r
+\r
+ +\r
+ \r
+ (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())\r
+\r
+ +\r
+ \r
+ " \n"\r
+ "//http://slouken.blogspot.com/2011/02/mpeg-acceleration-with-glsl.html \n"\r
+ "vec4 ycbcra_to_rgba_sd(float y, float cb, float cr, float a) \n"\r
+ "{ \n"\r
+ " // YUV offset \n"\r
+ " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n"\r
+ " \n"\r
+ " // RGB coefficients \n"\r
+ " const vec3 Rcoeff = vec3(1.164, 0.000, 1.596); \n"\r
+ " const vec3 Gcoeff = vec3(1.164, -0.391, -0.813); \n"\r
+ " const vec3 Bcoeff = vec3(1.164, 2.018, 0.000); \n"\r
+ " \n"\r
+ " vec3 yuv = vec3(y, cr, cb); \n"\r
+ " vec4 rgba; \n"\r
+ " \n"\r
+ " yuv += offset; \n"\r
+ " rgba.r = dot(yuv, Rcoeff); \n"\r
+ " rgba.g = dot(yuv, Gcoeff); \n"\r
+ " rgba.b = dot(yuv, Bcoeff); \n"\r
+ " rgba.a = a; \n"\r
+ " \n"\r
+ " return rgba; \n"\r
+ "} \n" \r
+ " \n"\r
+ "vec4 ycbcra_to_rgba_hd(float y, float cb, float cr, float a) \n"\r
+ "{ \n"\r
+ " // YUV offset \n"\r
+ " const vec3 offset = vec3(-0.0625, -0.5, -0.5); \n"\r
+ " \n"\r
+ " // RGB coefficients \n"\r
+ " const vec3 Rcoeff = vec3(1.164, 0.000, 1.793); \n"\r
+ " const vec3 Gcoeff = vec3(1.164, -0.213, -0.534); \n"\r
+ " const vec3 Bcoeff = vec3(1.164, 2.115, 0.000); \n"\r
+ " \n"\r
+ " vec3 yuv = vec3(y, cr, cb); \n"\r
+ " vec4 rgba; \n"\r
+ " \n"\r
+ " yuv += offset; \n"\r
+ " rgba.r = dot(yuv, Rcoeff); \n"\r
+ " rgba.g = dot(yuv, Gcoeff); \n"\r
+ " rgba.b = dot(yuv, Bcoeff); \n"\r
+ " rgba.a = a; \n"\r
+ " \n"\r
+ " return rgba; \n"\r
+ "} \n" \r
+ " \n" \r
+ "vec4 ycbcra_to_rgba(float y, float cb, float cr, float a) \n"\r
+ "{ \n"\r
+ " if(is_hd) \n"\r
+ " return ycbcra_to_rgba_hd(y, cb, cr, a); \n"\r
+ " else \n"\r
+ " return ycbcra_to_rgba_sd(y, cb, cr, a); \n"\r
+ "} \n"\r
+ " \n"\r
+ "vec4 get_rgba_color() \n"\r
+ "{ \n"\r
+ " switch(pixel_format) \n"\r
+ " { \n"\r
+ " case 0: //gray \n"\r
+ " return vec4(texture2D(plane[0], gl_TexCoord[0].st).rrr, 1.0); \n"\r
+ " case 1: //bgra, \n"\r
+ " return texture2D(plane[0], gl_TexCoord[0].st).bgra; \n"\r
+ " case 2: //rgba, \n"\r
+ " return texture2D(plane[0], gl_TexCoord[0].st).rgba; \n"\r
+ " case 3: //argb, \n"\r
+ " return texture2D(plane[0], gl_TexCoord[0].st).argb; \n"\r
+ " case 4: //abgr, \n"\r
+ " return texture2D(plane[0], gl_TexCoord[0].st).gbar; \n"\r
+ " case 5: //ycbcr, \n"\r
+ " { \n"\r
+ " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n"\r
+ " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n"\r
+ " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n"\r
+ " return ycbcra_to_rgba(y, cb, cr, 1.0); \n"\r
+ " } \n"\r
+ " case 6: //ycbcra \n"\r
+ " { \n"\r
+ " float y = texture2D(plane[0], gl_TexCoord[0].st).r; \n"\r
+ " float cb = texture2D(plane[1], gl_TexCoord[0].st).r; \n"\r
+ " float cr = texture2D(plane[2], gl_TexCoord[0].st).r; \n"\r
+ " float a = texture2D(plane[3], gl_TexCoord[0].st).r; \n"\r
+ " return ycbcra_to_rgba(y, cb, cr, a); \n"\r
+ " } \n"\r
+ " case 7: //luma \n"\r
+ " { \n"\r
+ " vec3 y3 = texture2D(plane[0], gl_TexCoord[0].st).rrr; \n"\r
+ " return vec4((y3-0.065)/0.859, 1.0); \n"\r
+ " } \n"\r
+ " } \n"\r
+ " return vec4(0.0, 0.0, 0.0, 0.0); \n"\r
+ "} \n"\r
+ " \n"\r
+ "void main() \n"\r
+ "{ \n"\r
+ " vec4 color = get_rgba_color(); \n"\r
+ " if(levels) \n"\r
+ " color.rgb = LevelsControl(color.rgb, min_input, max_input, gamma, min_output, max_output); \n"\r
+ " if(csb) \n"\r
+ " color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con); \n"\r
+ " if(has_local_key) \n"\r
+ " color.a *= texture2D(local_key, gl_TexCoord[1].st).r; \n"\r
+ " if(has_layer_key) \n"\r
+ " color.a *= texture2D(layer_key, gl_TexCoord[1].st).r; \n"\r
+ " color *= gl_Color; \n"\r
+ " color = blend(color); \n"\r
+ " gl_FragColor = color.bgra; \n"\r
+ "} \n";\r
+}\r
+\r
+safe_ptr<shader> get_image_shader(ogl_device& ogl, bool& blend_modes)\r
+{\r
+ tbb::mutex::scoped_lock lock(g_shader_mutex);\r
+\r
+ if(g_shader)\r
+ {\r
+ blend_modes = g_blend_modes;\r
+ return make_safe(g_shader);\r
+ }\r
+ \r
+ try\r
+ { \r
+ g_blend_modes = glTextureBarrierNV ? env::properties().get("configuration.mixers.blend-modes", false) : false;\r
+ g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)));\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";\r
+ \r
+ g_blend_modes = false;\r
+ g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)));\r
+ }\r
+ \r
+ ogl.enable(GL_TEXTURE_2D);\r
+\r
+ if(!g_blend_modes)\r
+ {\r
+ ogl.enable(GL_BLEND);\r
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);\r
+ CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";\r
+ }\r
+\r
+ blend_modes = g_blend_modes;\r
+ return make_safe(g_shader);\r
+}\r
+\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <common/memory/safe_ptr.h>\r
+\r
+namespace caspar { namespace core {\r
+\r
+class shader;\r
+class ogl_device;\r
+\r
+struct texture_id\r
+{\r
+ enum type\r
+ {\r
+ plane0 = 0,\r
+ plane1,\r
+ plane2,\r
+ plane3,\r
+ local_key,\r
+ layer_key,\r
+ background,\r
+ };\r
+};\r
+\r
+safe_ptr<shader> get_image_shader(ogl_device& ogl, bool& blend_modes);\r
+\r
+\r
+}}
\ No newline at end of file
, is_key_(false)\r
, deinterlace_(false)\r
, blend_mode_(image_transform::blend_mode::normal)\r
- , alpha_mode_(image_transform::alpha_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
return blend_mode_;\r
}\r
\r
-void image_transform::set_alpha_mode(image_transform::alpha_mode::type value)\r
-{\r
- alpha_mode_ = value;\r
-}\r
-\r
-image_transform::alpha_mode::type image_transform::get_alpha_mode() const\r
-{\r
- return alpha_mode_;\r
-}\r
-\r
image_transform& image_transform::operator*=(const image_transform &other)\r
{\r
opacity_ *= other.opacity_; \r
blend_mode_ = std::max(blend_mode_, other.blend_mode_);\r
- alpha_mode_ = std::max(alpha_mode_, other.alpha_mode_);\r
gain_ *= other.gain_;\r
brightness_ *= other.brightness_;\r
contrast_ *= other.contrast_;\r
\r
image_transform result; \r
result.set_blend_mode (std::max(source.get_blend_mode(), dest.get_blend_mode()));\r
- result.set_alpha_mode (std::max(source.get_alpha_mode(), dest.get_alpha_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
return image_transform::blend_mode::normal;\r
}\r
\r
-image_transform::alpha_mode::type get_alpha_mode(const std::wstring& str)\r
-{\r
- if(boost::iequals(str, L"normal"))\r
- return image_transform::alpha_mode::normal;\r
-\r
- return image_transform::alpha_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
blend_mode_count \r
};\r
};\r
-\r
- struct alpha_mode\r
- {\r
- enum type \r
- {\r
- normal = 0,\r
- };\r
- };\r
-\r
+ \r
struct levels\r
{\r
levels() \r
void set_blend_mode(blend_mode::type value);\r
blend_mode::type get_blend_mode() const;\r
\r
- void set_alpha_mode(alpha_mode::type value);\r
- alpha_mode::type get_alpha_mode() const;\r
-\r
private:\r
double opacity_;\r
double gain_;\r
bool is_key_;\r
bool deinterlace_;\r
blend_mode::type blend_mode_;\r
- alpha_mode::type alpha_mode_;\r
};\r
\r
image_transform::blend_mode::type get_blend_mode(const std::wstring& str);\r
-image_transform::alpha_mode::type get_alpha_mode(const std::wstring& str);\r
\r
image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener);\r
\r
int layer = GetLayerIndex();\r
GetChannel()->mixer()->apply_image_transform(GetLayerIndex(), transform); \r
}\r
- else if(_parameters[1] == L"ALPHA")\r
- {\r
- auto blend_str = _parameters.at(2);\r
-\r
- auto transform = [=](image_transform transform) -> image_transform\r
- {\r
- transform.set_alpha_mode(get_alpha_mode(blend_str));\r
- return transform;\r
- };\r
- \r
- int layer = GetLayerIndex();\r
- GetChannel()->mixer()->apply_image_transform(GetLayerIndex(), transform); \r
- }\r
else if(_parameters[1] == L"BRIGHTNESS")\r
{\r
auto value = boost::lexical_cast<double>(_parameters.at(2));\r