4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
11 * This program 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 this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
29 #include "pluginvclient.h"
37 class InvertVideoEffect;
40 class InvertVideoConfig
45 void copy_from(InvertVideoConfig &src);
46 int equivalent(InvertVideoConfig &src);
47 void interpolate(InvertVideoConfig &prev,
48 InvertVideoConfig &next,
56 class InvertVideoEnable : public BC_CheckBox
59 InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text);
61 InvertVideoEffect *plugin;
65 class InvertVideoWindow : public PluginClientWindow
68 InvertVideoWindow(InvertVideoEffect *plugin);
69 void create_objects();
70 InvertVideoEnable *r, *g, *b, *a;
71 InvertVideoEffect *plugin;
75 class InvertVideoEffect : public PluginVClient
78 InvertVideoEffect(PluginServer *server);
80 PLUGIN_CLASS_MEMBERS(InvertVideoConfig)
81 int process_buffer(VFrame *frame,
82 int64_t start_position,
85 void save_data(KeyFrame *keyframe);
86 void read_data(KeyFrame *keyframe);
95 REGISTER_PLUGIN(InvertVideoEffect)
103 InvertVideoConfig::InvertVideoConfig()
111 void InvertVideoConfig::copy_from(InvertVideoConfig &src)
119 int InvertVideoConfig::equivalent(InvertVideoConfig &src)
127 void InvertVideoConfig::interpolate(InvertVideoConfig &prev,
128 InvertVideoConfig &next,
142 InvertVideoEnable::InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text)
143 : BC_CheckBox(x, y, *output, text)
145 this->plugin = plugin;
146 this->output = output;
148 int InvertVideoEnable::handle_event()
150 *output = get_value();
151 plugin->send_configure_change();
159 InvertVideoWindow::InvertVideoWindow(InvertVideoEffect *plugin)
160 : PluginClientWindow(plugin, xS(150), yS(130), xS(150), yS(130), 0)
162 this->plugin = plugin;
165 void InvertVideoWindow::create_objects()
168 int x = xS(10), y = yS(10);
169 add_subwindow(r = new InvertVideoEnable(plugin, &plugin->config.r, x, y, _("Invert R")));
171 add_subwindow(g = new InvertVideoEnable(plugin, &plugin->config.g, x, y, _("Invert G")));
173 add_subwindow(b = new InvertVideoEnable(plugin, &plugin->config.b, x, y, _("Invert B")));
175 add_subwindow(a = new InvertVideoEnable(plugin, &plugin->config.a, x, y, _("Invert A")));
190 InvertVideoEffect::InvertVideoEffect(PluginServer *server)
191 : PluginVClient(server)
195 InvertVideoEffect::~InvertVideoEffect()
200 const char* InvertVideoEffect::plugin_title() { return N_("Invert Video"); }
201 int InvertVideoEffect::is_realtime() { return 1; }
203 NEW_WINDOW_MACRO(InvertVideoEffect, InvertVideoWindow)
204 LOAD_CONFIGURATION_MACRO(InvertVideoEffect, InvertVideoConfig)
206 void InvertVideoEffect::update_gui()
210 thread->window->lock_window();
211 load_configuration();
212 ((InvertVideoWindow*)thread->window)->r->update(config.r);
213 ((InvertVideoWindow*)thread->window)->g->update(config.g);
214 ((InvertVideoWindow*)thread->window)->b->update(config.b);
215 ((InvertVideoWindow*)thread->window)->a->update(config.a);
216 thread->window->unlock_window();
221 void InvertVideoEffect::save_data(KeyFrame *keyframe)
224 output.set_shared_output(keyframe->xbuf);
225 output.tag.set_title("INVERTVIDEO");
226 output.tag.set_property("R", config.r);
227 output.tag.set_property("G", config.g);
228 output.tag.set_property("B", config.b);
229 output.tag.set_property("A", config.a);
231 output.tag.set_title("/INVERTVIDEO");
233 output.append_newline();
234 output.terminate_string();
237 void InvertVideoEffect::read_data(KeyFrame *keyframe)
240 input.set_shared_input(keyframe->xbuf);
241 while(!input.read_tag())
243 if(input.tag.title_is("INVERTVIDEO"))
245 config.r = input.tag.get_property("R", config.r);
246 config.g = input.tag.get_property("G", config.g);
247 config.b = input.tag.get_property("B", config.b);
248 config.a = input.tag.get_property("A", config.a);
254 #define INVERT_MACRO(type, components, max) \
256 for(int i = 0; i < frame->get_h(); i++) \
258 type *in_row = (type*)frame->get_rows()[i]; \
259 type *out_row = (type*)frame->get_rows()[i]; \
261 for(int j = 0; j < w; j++) \
263 if(config.r) out_row[0] = max - in_row[0]; \
264 if(config.g) out_row[1] = max - in_row[1]; \
265 if(config.b) out_row[2] = max - in_row[2]; \
266 if(components == 4) \
267 if(config.a) out_row[3] = max - in_row[3]; \
269 in_row += components; \
270 out_row += components; \
275 int InvertVideoEffect::process_buffer(VFrame *frame,
276 int64_t start_position,
279 load_configuration();
288 if(config.r || config.g || config.b || config.a)
295 int w = frame->get_w();
297 switch(frame->get_color_model())
300 INVERT_MACRO(float, 3, 1.0)
304 INVERT_MACRO(unsigned char, 3, 0xff)
307 INVERT_MACRO(float, 4, 1.0)
311 INVERT_MACRO(unsigned char, 4, 0xff)
315 INVERT_MACRO(uint16_t, 3, 0xffff)
317 case BC_RGBA16161616:
318 case BC_YUVA16161616:
319 INVERT_MACRO(uint16_t, 4, 0xffff)
327 int InvertVideoEffect::handle_opengl()
330 static const char *invert_frag =
331 "uniform sampler2D tex;\n"
332 "uniform bool do_r;\n"
333 "uniform bool do_g;\n"
334 "uniform bool do_b;\n"
335 "uniform bool do_a;\n"
338 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
339 " if(do_r) gl_FragColor.r = 1.0 - gl_FragColor.r;\n"
340 " if(do_g) gl_FragColor.g = 1.0 - gl_FragColor.g;\n"
341 " if(do_b) gl_FragColor.b = 1.0 - gl_FragColor.b;\n"
342 " if(do_a) gl_FragColor.a = 1.0 - gl_FragColor.a;\n"
345 get_output()->to_texture();
346 get_output()->enable_opengl();
348 unsigned int frag_shader = VFrame::make_shader(0, invert_frag, 0);
349 glUseProgram(frag_shader);
350 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
351 glUniform1i(glGetUniformLocation(frag_shader, "do_r"), config.r);
352 glUniform1i(glGetUniformLocation(frag_shader, "do_g"), config.g);
353 glUniform1i(glGetUniformLocation(frag_shader, "do_b"), config.b);
354 glUniform1i(glGetUniformLocation(frag_shader, "do_a"), config.a);
357 VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
358 get_output()->bind_texture(0);
359 get_output()->draw_texture();
361 get_output()->set_opengl_state(VFrame::SCREEN);