]> git.sesse.net Git - casparcg/blob - core/mixer/image/image_kernel.cpp
2.0.0.2: clip-rect and fix-rect works now properly with transitions.
[casparcg] / core / mixer / image / image_kernel.cpp
1 #include "../../StdAfx.h"\r
2 \r
3 #include "image_kernel.h"\r
4 \r
5 #include "image_transform.h"\r
6 \r
7 #include <common/exception/exceptions.h>\r
8 #include <common/gl/gl_check.h>\r
9 \r
10 #include <Glee.h>\r
11 \r
12 #include <boost/noncopyable.hpp>\r
13 \r
14 #include <unordered_map>\r
15 \r
16 namespace caspar { namespace core {\r
17 \r
18 class shader_program\r
19 {\r
20         GLuint program_;\r
21 public:\r
22 \r
23         shader_program() : program_(0) {}\r
24         shader_program(const std::string& vertex_source_str, const std::string& fragment_source_str) : program_(0)\r
25         {\r
26                 GLint success;\r
27         \r
28                 const char* vertex_source = vertex_source_str.c_str();\r
29                                                 \r
30                 auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);\r
31                                         \r
32                 GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));\r
33                 GL(glCompileShaderARB(vertex_shader));\r
34 \r
35                 GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
36                 if (success == GL_FALSE)\r
37                 {\r
38                         char info[2048];\r
39                         GL(glGetInfoLogARB(vertex_shader, sizeof(info), 0, info));\r
40                         GL(glDeleteObjectARB(vertex_shader));\r
41                         std::stringstream str;\r
42                         str << "Failed to compile vertex shader:" << std::endl << info << std::endl;\r
43                         BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));\r
44                 }\r
45                         \r
46                 const char* fragment_source = fragment_source_str.c_str();\r
47                                                 \r
48                 auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);\r
49                                         \r
50                 GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));\r
51                 GL(glCompileShaderARB(fragmemt_shader));\r
52 \r
53                 GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
54                 if (success == GL_FALSE)\r
55                 {\r
56                         char info[2048];\r
57                         GL(glGetInfoLogARB(fragmemt_shader, sizeof(info), 0, info));\r
58                         GL(glDeleteObjectARB(fragmemt_shader));\r
59                         std::stringstream str;\r
60                         str << "Failed to compile fragment shader:" << std::endl << info << std::endl;\r
61                         BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));\r
62                 }\r
63                         \r
64                 program_ = glCreateProgramObjectARB();\r
65                         \r
66                 GL(glAttachObjectARB(program_, vertex_shader));\r
67                 GL(glAttachObjectARB(program_, fragmemt_shader));\r
68 \r
69                 GL(glLinkProgramARB(program_));\r
70                         \r
71                 GL(glDeleteObjectARB(vertex_shader));\r
72                 GL(glDeleteObjectARB(fragmemt_shader));\r
73 \r
74                 GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));\r
75                 if (success == GL_FALSE)\r
76                 {\r
77                         char info[2048];\r
78                         GL(glGetInfoLogARB(program_, sizeof(info), 0, info));\r
79                         GL(glDeleteObjectARB(program_));\r
80                         std::stringstream str;\r
81                         str << "Failed to link shader program:" << std::endl << info << std::endl;\r
82                         BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));\r
83                 }\r
84                 GL(glUseProgramObjectARB(program_));\r
85                 glUniform1i(glGetUniformLocation(program_, "plane[0]"), 0);\r
86                 glUniform1i(glGetUniformLocation(program_, "plane[1]"), 1);\r
87                 glUniform1i(glGetUniformLocation(program_, "plane[2]"), 2);\r
88                 glUniform1i(glGetUniformLocation(program_, "plane[3]"), 3);\r
89         }\r
90 \r
91         GLint get_location(const char* name)\r
92         {\r
93                 GLint loc = glGetUniformLocation(program_, name);\r
94                 return loc;\r
95         }\r
96 \r
97         shader_program& operator=(shader_program&& other) \r
98         {\r
99                 program_ = other.program_; \r
100                 other.program_ = 0; \r
101                 return *this;\r
102         }\r
103 \r
104         ~shader_program()\r
105         {\r
106                 glDeleteProgram(program_);\r
107         }\r
108 \r
109         void use()\r
110         {       \r
111                 GL(glUseProgramObjectARB(program_));            \r
112         }\r
113 };\r
114 \r
115 GLubyte progressive_pattern[] = {\r
116         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
117         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
118         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
119         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
120         \r
121 GLubyte upper_pattern[] = {\r
122         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
123         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
124         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
125         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};\r
126                 \r
127 GLubyte lower_pattern[] = {\r
128         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
129         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
130         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
131         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};\r
132 \r
133 struct image_kernel::implementation\r
134 {       \r
135         std::unordered_map<pixel_format::type, shader_program> shaders_;\r
136 \r
137 public:\r
138         std::unordered_map<pixel_format::type, shader_program>& shaders()\r
139         {\r
140                 GL(glEnable(GL_POLYGON_STIPPLE));\r
141                 GL(glEnable(GL_BLEND));\r
142                 GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));  \r
143 \r
144                 if(shaders_.empty())\r
145                 {\r
146                 std::string common_vertex = \r
147                         "void main()                                                                                                                    "\r
148                         "{                                                                                                                                              "\r
149                         "       gl_TexCoord[0] = gl_MultiTexCoord0;                                                                     "\r
150                         "       gl_FrontColor = gl_Color;                                                                                       "\r
151                         "       gl_Position = ftransform();                                                                                     "\r
152                         "}                                                                                                                                              ";\r
153 \r
154                 std::string common_fragment = \r
155                         "uniform sampler2D      plane[4];                                                                                       "\r
156                         "uniform float          color_gain;                                                                                     "\r
157                                                                                                                                                                 \r
158                         // NOTE: YCbCr, ITU-R, http://www.intersil.com/data/an/an9717.pdf               \r
159                         // TODO: Support for more yuv formats might be needed.                                  \r
160                         "vec4 ycbcra_to_bgra(float y, float cb, float cr, float a)                              "\r
161                         "{                                                                                                                                              "\r
162                         "       cb -= 0.5;                                                                                                                      "\r
163                         "       cr -= 0.5;                                                                                                                      "\r
164                         "       y = 1.164*(y-0.0625);                                                                                           "\r
165                         "                                                                                                                                               "\r
166                         "       vec4 color;                                                                                                                     "\r
167                         "       color.r = y + 1.596 * cr;                                                                                       "\r
168                         "       color.g = y - 0.813 * cr - 0.337633 * cb;                                                       "\r
169                         "       color.b = y + 2.017 * cb;                                                                                       "\r
170                         "       color.a = a;                                                                                                            "\r
171                         "                                                                                                                                               "\r
172                         "       return color;                                                                                                           "\r
173                         "}                                                                                                                                              "                       \r
174                         "                                                                                                                                               ";\r
175                         \r
176                 shaders_[pixel_format::abgr] = shader_program(common_vertex, common_fragment +\r
177 \r
178                         "void main()                                                                                                                    "\r
179                         "{                                                                                                                                              "\r
180                         "       vec4 abgr = texture2D(plane[0], gl_TexCoord[0].st);                                     "\r
181                         "       gl_FragColor = abgr.argb * color_gain;                                                          "\r
182                         "}                                                                                                                                              ");\r
183                 \r
184                 shaders_[pixel_format::argb]= shader_program(common_vertex, common_fragment +\r
185 \r
186                         "void main()                                                                                                                    "       \r
187                         "{                                                                                                                                              "\r
188                         "       vec4 argb = texture2D(plane[0], gl_TexCoord[0].st);                                     "\r
189                         "       gl_FragColor = argb.grab * gl_Color * color_gain;                                       "\r
190                         "}                                                                                                                                              ");\r
191                 \r
192                 shaders_[pixel_format::bgra]= shader_program(common_vertex, common_fragment +\r
193 \r
194                         "void main()                                                                                                                    "\r
195                         "{                                                                                                                                              "\r
196                         "       vec4 bgra = texture2D(plane[0], gl_TexCoord[0].st);                                     "\r
197                         "       gl_FragColor = bgra.rgba * gl_Color * color_gain;                                       "\r
198                         "}                                                                                                                                              ");\r
199                 \r
200                 shaders_[pixel_format::rgba] = shader_program(common_vertex, common_fragment +\r
201 \r
202                         "void main()                                                                                                                    "\r
203                         "{                                                                                                                                              "\r
204                         "       vec4 rgba = texture2D(plane[0], gl_TexCoord[0].st);                                     "\r
205                         "       gl_FragColor = rgba.bgra * gl_Color * color_gain;                                       "\r
206                         "}                                                                                                                                              ");\r
207                 \r
208                 shaders_[pixel_format::ycbcr] = shader_program(common_vertex, common_fragment +\r
209 \r
210                         "void main()                                                                                                                    "\r
211                         "{                                                                                                                                              "\r
212                         "       float y  = texture2D(plane[0], gl_TexCoord[0].st).r;"\r
213                         "       float cb = texture2D(plane[1], gl_TexCoord[0].st).r;"\r
214                         "       float cr = texture2D(plane[2], gl_TexCoord[0].st).r;"\r
215                         "       float a = 1.0;                                                                                                          "       \r
216                         "       gl_FragColor = ycbcra_to_bgra(y, cb, cr, a) * gl_Color * color_gain;"\r
217                         "}                                                                                                                                              ");\r
218                 \r
219                 shaders_[pixel_format::ycbcra] = shader_program(common_vertex, common_fragment +\r
220 \r
221                         "void main()                                                                                                                    "\r
222                         "{                                                                                                                                              "\r
223                         "       float y  = texture2D(plane[0], gl_TexCoord[0].st).r;"\r
224                         "       float cb = texture2D(plane[1], gl_TexCoord[0].st).r;"\r
225                         "       float cr = texture2D(plane[2], gl_TexCoord[0].st).r;"\r
226                         "       float a  = texture2D(plane[3], gl_TexCoord[0].st).r;"\r
227                         "       gl_FragColor = ycbcra_to_bgra(y, cb, cr, a) * gl_Color * color_gain;"\r
228                         "}                                                                                                                                              ");\r
229                 }\r
230                 return shaders_;\r
231         }\r
232 };\r
233 \r
234 image_kernel::image_kernel() : impl_(new implementation()){}\r
235 \r
236 void image_kernel::apply(pixel_format::type pix_fmt, const image_transform& transform)\r
237 {\r
238         impl_->shaders()[pix_fmt].use();\r
239 \r
240         GL(glUniform1f(impl_->shaders()[pix_fmt].get_location("color_gain"), static_cast<GLfloat>(transform.get_gain())));\r
241 \r
242         if(transform.get_mode() == video_mode::upper)\r
243                 glPolygonStipple(upper_pattern);\r
244         else if(transform.get_mode() == video_mode::lower)\r
245                 glPolygonStipple(lower_pattern);\r
246         else\r
247                 glPolygonStipple(progressive_pattern);\r
248 }\r
249 \r
250 }}