Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / plugins / invertvideo / invert.C
diff --git a/cinelerra-5.1/plugins/invertvideo/invert.C b/cinelerra-5.1/plugins/invertvideo/invert.C
new file mode 100644 (file)
index 0000000..d24b10f
--- /dev/null
@@ -0,0 +1,373 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "bchash.h"
+#include "filexml.h"
+#include "guicast.h"
+#include "language.h"
+#include "cicolors.h"
+#include "pluginvclient.h"
+#include "vframe.h"
+
+#include <stdint.h>
+#include <string.h>
+
+
+
+class InvertVideoEffect;
+
+
+class InvertVideoConfig
+{
+public:
+       InvertVideoConfig();
+
+       void copy_from(InvertVideoConfig &src);
+       int equivalent(InvertVideoConfig &src);
+       void interpolate(InvertVideoConfig &prev, 
+               InvertVideoConfig &next, 
+               long prev_frame, 
+               long next_frame, 
+               long current_frame);
+
+       int r, g, b, a;
+};
+
+class InvertVideoEnable : public BC_CheckBox
+{
+public:
+       InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text);
+       int handle_event();
+       InvertVideoEffect *plugin;
+       int *output;
+};
+
+class InvertVideoWindow : public PluginClientWindow
+{
+public:
+       InvertVideoWindow(InvertVideoEffect *plugin);
+       void create_objects();
+       InvertVideoEnable *r, *g, *b, *a;
+       InvertVideoEffect *plugin;
+};
+
+
+class InvertVideoEffect : public PluginVClient
+{
+public:
+       InvertVideoEffect(PluginServer *server);
+       ~InvertVideoEffect();
+       PLUGIN_CLASS_MEMBERS(InvertVideoConfig)
+       int process_buffer(VFrame *frame,
+               int64_t start_position,
+               double frame_rate);
+       int is_realtime();
+       void save_data(KeyFrame *keyframe);
+       void read_data(KeyFrame *keyframe);
+       void update_gui();
+       int handle_opengl();
+};
+
+
+
+
+
+REGISTER_PLUGIN(InvertVideoEffect)
+
+
+
+
+
+
+
+InvertVideoConfig::InvertVideoConfig()
+{
+       r = 1;
+       g = 1;
+       b = 1;
+       a = 1;
+}
+
+void InvertVideoConfig::copy_from(InvertVideoConfig &src)
+{
+       r = src.r;
+       g = src.g;
+       b = src.b;
+       a = src.a;
+}
+
+int InvertVideoConfig::equivalent(InvertVideoConfig &src)
+{
+       return r == src.r && 
+               g == src.g && 
+               b == src.b && 
+               a == src.a;
+}
+
+void InvertVideoConfig::interpolate(InvertVideoConfig &prev, 
+       InvertVideoConfig &next, 
+       long prev_frame, 
+       long next_frame, 
+       long current_frame)
+{
+       r = prev.r;
+       g = prev.g;
+       b = prev.b;
+       a = prev.a;
+}
+
+
+
+
+InvertVideoEnable::InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text)
+ : BC_CheckBox(x, y, *output, text)
+{
+       this->plugin = plugin;
+       this->output = output;
+}
+int InvertVideoEnable::handle_event()
+{
+       *output = get_value();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+InvertVideoWindow::InvertVideoWindow(InvertVideoEffect *plugin)
+ : PluginClientWindow(plugin, 
+       260, 
+       130, 
+       260, 
+       130, 
+       0)
+{
+       this->plugin = plugin;
+}
+
+void InvertVideoWindow::create_objects()
+{
+       int x = 10, y = 10;
+       add_subwindow(r = new InvertVideoEnable(plugin, &plugin->config.r, x, y, _("Invert R")));
+       y += 30;
+       add_subwindow(g = new InvertVideoEnable(plugin, &plugin->config.g, x, y, _("Invert G")));
+       y += 30;
+       add_subwindow(b = new InvertVideoEnable(plugin, &plugin->config.b, x, y, _("Invert B")));
+       y += 30;
+       add_subwindow(a = new InvertVideoEnable(plugin, &plugin->config.a, x, y, _("Invert A")));
+
+       show_window();
+       flush();
+}
+
+
+
+
+
+
+
+
+
+
+InvertVideoEffect::InvertVideoEffect(PluginServer *server)
+ : PluginVClient(server)
+{
+       
+}
+InvertVideoEffect::~InvertVideoEffect()
+{
+       
+}
+
+const char* InvertVideoEffect::plugin_title() { return _("Invert Video"); }
+int InvertVideoEffect::is_realtime() { return 1; }
+
+NEW_WINDOW_MACRO(InvertVideoEffect, InvertVideoWindow)
+LOAD_CONFIGURATION_MACRO(InvertVideoEffect, InvertVideoConfig)
+
+void InvertVideoEffect::update_gui()
+{
+       if(thread)
+       {
+               thread->window->lock_window();
+               load_configuration();
+               ((InvertVideoWindow*)thread->window)->r->update(config.r);
+               ((InvertVideoWindow*)thread->window)->g->update(config.g);
+               ((InvertVideoWindow*)thread->window)->b->update(config.b);
+               ((InvertVideoWindow*)thread->window)->a->update(config.a);
+               thread->window->unlock_window();
+       }
+}
+
+
+void InvertVideoEffect::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+       output.tag.set_title("INVERTVIDEO");
+       output.tag.set_property("R", config.r);
+       output.tag.set_property("G", config.g);
+       output.tag.set_property("B", config.b);
+       output.tag.set_property("A", config.a);
+       output.append_tag();
+       output.tag.set_title("/INVERTVIDEO");
+       output.append_tag();
+       output.append_newline();
+       output.terminate_string();
+}
+
+void InvertVideoEffect::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+       while(!input.read_tag())
+       {
+               if(input.tag.title_is("INVERTVIDEO"))
+               {
+                       config.r = input.tag.get_property("R", config.r);
+                       config.g = input.tag.get_property("G", config.g);
+                       config.b = input.tag.get_property("B", config.b);
+                       config.a = input.tag.get_property("A", config.a);
+               }
+       }
+}
+
+
+#define INVERT_MACRO(type, components, max) \
+{ \
+       for(int i = 0; i < frame->get_h(); i++) \
+       { \
+               type *in_row = (type*)frame->get_rows()[i]; \
+               type *out_row = (type*)frame->get_rows()[i]; \
+ \
+               for(int j = 0; j < w; j++) \
+               { \
+                       if(config.r) out_row[0] = max - in_row[0]; \
+                       if(config.g) out_row[1] = max - in_row[1]; \
+                       if(config.b) out_row[2] = max - in_row[2]; \
+                       if(components == 4) \
+                               if(config.a) out_row[3] = max - in_row[3]; \
+ \
+                       in_row += components; \
+                       out_row += components; \
+               } \
+       } \
+}
+
+int InvertVideoEffect::process_buffer(VFrame *frame,
+       int64_t start_position,
+       double frame_rate)
+{
+       load_configuration();
+
+       read_frame(frame, 
+               0, 
+               start_position, 
+               frame_rate,
+               get_use_opengl());
+
+
+       if(config.r || config.g || config.b || config.a)
+       {
+               if(get_use_opengl())
+               {
+                       run_opengl();
+                       return 0;
+               }
+               int w = frame->get_w();
+
+               switch(frame->get_color_model())
+               {
+                       case BC_RGB_FLOAT:
+                               INVERT_MACRO(float, 3, 1.0)
+                               break;
+                       case BC_RGB888:
+                       case BC_YUV888:
+                               INVERT_MACRO(unsigned char, 3, 0xff)
+                               break;
+                       case BC_RGBA_FLOAT:
+                               INVERT_MACRO(float, 4, 1.0)
+                               break;
+                       case BC_RGBA8888:
+                       case BC_YUVA8888:
+                               INVERT_MACRO(unsigned char, 4, 0xff)
+                               break;
+                       case BC_RGB161616:
+                       case BC_YUV161616:
+                               INVERT_MACRO(uint16_t, 3, 0xffff)
+                               break;
+                       case BC_RGBA16161616:
+                       case BC_YUVA16161616:
+                               INVERT_MACRO(uint16_t, 4, 0xffff)
+                               break;
+               }
+       }
+
+       return 0;
+}
+
+int InvertVideoEffect::handle_opengl()
+{
+#ifdef HAVE_GL
+       static const char *invert_frag = 
+               "uniform sampler2D tex;\n"
+               "uniform bool do_r;\n"
+               "uniform bool do_g;\n"
+               "uniform bool do_b;\n"
+               "uniform bool do_a;\n"
+               "void main()\n"
+               "{\n"
+               "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
+               "       if(do_r) gl_FragColor.r = 1.0 - gl_FragColor.r;\n"
+               "       if(do_g) gl_FragColor.g = 1.0 - gl_FragColor.g;\n"
+               "       if(do_b) gl_FragColor.b = 1.0 - gl_FragColor.b;\n"
+               "       if(do_a) gl_FragColor.a = 1.0 - gl_FragColor.a;\n"
+               "}\n";
+
+       get_output()->to_texture();
+       get_output()->enable_opengl();
+
+       unsigned int frag_shader = 0;
+       frag_shader = VFrame::make_shader(0,
+               invert_frag,
+               0);
+       glUseProgram(frag_shader);
+       glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
+       glUniform1i(glGetUniformLocation(frag_shader, "do_r"), config.r);
+       glUniform1i(glGetUniformLocation(frag_shader, "do_g"), config.g);
+       glUniform1i(glGetUniformLocation(frag_shader, "do_b"), config.b);
+       glUniform1i(glGetUniformLocation(frag_shader, "do_a"), config.a);
+
+
+       VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
+       get_output()->bind_texture(0);
+       get_output()->draw_texture();
+       glUseProgram(0);
+       get_output()->set_opengl_state(VFrame::SCREEN);
+#endif
+       return 0;
+}
+
+