2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Robert Nagy, ronag89@gmail.com
22 #include "../../stdafx.h"
24 #include "image_kernel.h"
26 #include "image_shader.h"
27 #include "blending_glsl.h"
29 #include "../util/shader.h"
30 #include "../util/texture.h"
31 #include "../util/device.h"
33 #include <common/except.h>
34 #include <common/gl/gl_check.h>
35 #include <common/env.h>
37 #include <core/video_format.h>
38 #include <core/frame/pixel_format.h>
39 #include <core/frame/frame_transform.h>
41 #include <boost/lexical_cast.hpp>
43 namespace caspar { namespace accelerator { namespace ogl {
45 GLubyte upper_pattern[] = {
46 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,
47 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,
48 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,
49 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};
51 GLubyte lower_pattern[] = {
52 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,
53 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,
54 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,
55 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};
57 struct image_kernel::impl
59 spl::shared_ptr<device> ogl_;
60 spl::shared_ptr<shader> shader_;
63 impl(const spl::shared_ptr<device>& ogl)
65 , shader_(ogl_->invoke([&]{return get_image_shader(blend_modes_);}))
69 void draw(draw_params params)
71 static const double epsilon = 0.001;
73 CASPAR_ASSERT(params.pix_desc.planes.size() == params.textures.size());
75 if(params.textures.empty() || !params.background)
78 if(params.transform.opacity < epsilon)
83 for(int n = 0; n < params.textures.size(); ++n)
84 params.textures[n]->bind(n);
87 params.local_key->bind(texture_id::local_key);
90 params.layer_key->bind(texture_id::layer_key);
96 shader_->set("plane[0]", texture_id::plane0);
97 shader_->set("plane[1]", texture_id::plane1);
98 shader_->set("plane[2]", texture_id::plane2);
99 shader_->set("plane[3]", texture_id::plane3);
100 for(int n = 0; n < params.textures.size(); ++n)
101 shader_->set("plane_size[" + boost::lexical_cast<std::string>(n) + "]",
102 static_cast<float>(params.textures[n]->width()),
103 static_cast<float>(params.textures[n]->height()));
105 shader_->set("local_key", texture_id::local_key);
106 shader_->set("layer_key", texture_id::layer_key);
107 shader_->set("is_hd", params.pix_desc.planes.at(0).height > 700 ? 1 : 0);
108 shader_->set("has_local_key", params.local_key);
109 shader_->set("has_layer_key", params.layer_key);
110 shader_->set("pixel_format", params.pix_desc.format.value());
111 shader_->set("opacity", params.transform.is_key ? 1.0 : params.transform.opacity);
116 if(params.transform.is_key)
117 params.blend_mode = core::blend_mode::normal;
121 params.background->bind(texture_id::background);
123 shader_->set("background", texture_id::background);
124 shader_->set("blend_mode", params.blend_mode.value());
125 shader_->set("keyer", params.keyer.value());
129 GL(glEnable(GL_BLEND));
131 switch(params.keyer.value())
133 case keyer::additive:
134 GL(glBlendFunc(GL_ONE, GL_ONE));
138 GL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
142 // Setup image-adjustements
144 if(params.transform.levels.min_input > epsilon ||
145 params.transform.levels.max_input < 1.0-epsilon ||
146 params.transform.levels.min_output > epsilon ||
147 params.transform.levels.max_output < 1.0-epsilon ||
148 std::abs(params.transform.levels.gamma - 1.0) > epsilon)
150 shader_->set("levels", true);
151 shader_->set("min_input", params.transform.levels.min_input);
152 shader_->set("max_input", params.transform.levels.max_input);
153 shader_->set("min_output", params.transform.levels.min_output);
154 shader_->set("max_output", params.transform.levels.max_output);
155 shader_->set("gamma", params.transform.levels.gamma);
158 shader_->set("levels", false);
160 if(std::abs(params.transform.brightness - 1.0) > epsilon ||
161 std::abs(params.transform.saturation - 1.0) > epsilon ||
162 std::abs(params.transform.contrast - 1.0) > epsilon)
164 shader_->set("csb", true);
166 shader_->set("brt", params.transform.brightness);
167 shader_->set("sat", params.transform.saturation);
168 shader_->set("con", params.transform.contrast);
171 shader_->set("csb", false);
175 if(params.transform.field_mode != core::field_mode::progressive)
177 GL(glEnable(GL_POLYGON_STIPPLE));
179 if(params.transform.field_mode == core::field_mode::upper)
180 glPolygonStipple(upper_pattern);
181 else if(params.transform.field_mode == core::field_mode::lower)
182 glPolygonStipple(lower_pattern);
185 // Setup drawing area
187 GL(glViewport(0, 0, params.background->width(), params.background->height()));
189 auto m_p = params.transform.clip_translation;
190 auto m_s = params.transform.clip_scale;
192 bool scissor = m_p[0] > std::numeric_limits<double>::epsilon() || m_p[1] > std::numeric_limits<double>::epsilon() ||
193 m_s[0] < (1.0 - std::numeric_limits<double>::epsilon()) || m_s[1] < (1.0 - std::numeric_limits<double>::epsilon());
197 double w = static_cast<double>(params.background->width());
198 double h = static_cast<double>(params.background->height());
200 GL(glEnable(GL_SCISSOR_TEST));
201 glScissor(static_cast<int>(m_p[0]*w), static_cast<int>(m_p[1]*h), static_cast<int>(m_s[0]*w), static_cast<int>(m_s[1]*h));
204 auto f_p = params.transform.fill_translation;
205 auto f_s = params.transform.fill_scale;
207 // Synchronize and set render target
211 // http://www.opengl.org/registry/specs/NV/texture_barrier.txt
212 // This allows us to use framebuffer (background) both as source and target while blending.
213 glTextureBarrierNV();
216 params.background->attach();
218 glMatrixMode(GL_MODELVIEW);
220 glTranslated(f_p[0], f_p[1], 0.0);
221 glScaled(f_s[0], f_s[1], 1.0);
223 switch(params.geometry.type())
225 case core::frame_geometry::quad:
227 const std::vector<float>& data = params.geometry.data();
228 float v_left = data[0], v_top = data[1], t_left = data[2], t_top = data[3];
229 float v_right = data[4], v_bottom = data[5], t_right = data[6], t_bottom = data[7];
232 glMultiTexCoord2d(GL_TEXTURE0, t_left, t_top); glVertex2d(v_left, v_top);
233 glMultiTexCoord2d(GL_TEXTURE0, t_right, t_top); glVertex2d(v_right, v_top);
234 glMultiTexCoord2d(GL_TEXTURE0, t_right, t_bottom); glVertex2d(v_right, v_bottom);
235 glMultiTexCoord2d(GL_TEXTURE0, t_left, t_bottom); glVertex2d(v_left, v_bottom);
240 case core::frame_geometry::quad_list:
242 glClientActiveTexture(GL_TEXTURE0);
244 glDisableClientState(GL_EDGE_FLAG_ARRAY);
245 glDisableClientState(GL_COLOR_ARRAY);
246 glDisableClientState(GL_INDEX_ARRAY);
247 glDisableClientState(GL_NORMAL_ARRAY);
249 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
250 glEnableClientState(GL_VERTEX_ARRAY);
252 glTexCoordPointer(2, GL_FLOAT, 4*sizeof(float), &(params.geometry.data().data()[2]));
253 glVertexPointer(2, GL_FLOAT, 4*sizeof(float), params.geometry.data().data());
255 glDrawArrays(GL_QUADS, 0, (GLsizei)params.geometry.data().size()/4); //each vertex is four floats.
257 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
258 glDisableClientState(GL_VERTEX_ARRAY);
269 glMultiTexCoord2d(GL_TEXTURE0, 0.0, 0.0); glVertex2d(0, 0);
270 glMultiTexCoord2d(GL_TEXTURE0, 1.0, 0.0); glVertex2d(1, 0);
271 glMultiTexCoord2d(GL_TEXTURE0, 1.0, 1.0); glVertex2d(1, 1);
272 glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glVertex2d(0, 1);
278 GL(glDisable(GL_SCISSOR_TEST));
279 GL(glDisable(GL_POLYGON_STIPPLE));
280 GL(glDisable(GL_BLEND));
284 image_kernel::image_kernel(const spl::shared_ptr<device>& ogl) : impl_(new impl(ogl)){}
285 image_kernel::~image_kernel(){}
286 void image_kernel::draw(const draw_params& params){impl_->draw(params);}
287 bool image_kernel::has_blend_modes() const{return impl_->blend_modes_;}