]> git.sesse.net Git - casparcg/blob - core/mixer/image/image_kernel.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[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_mixer.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 }}