Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / plugins / invertvideo / invert.C
blob844e0d26cd1cf8ea0fe54f4fd0f441e727f860b2
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "bchash.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "language.h"
7 #include "picon_png.h"
8 #include "plugincolors.h"
9 #include "pluginvclient.h"
10 #include "vframe.h"
12 #include <stdint.h>
13 #include <string.h>
17 class InvertVideoEffect;
20 class InvertVideoConfig
22 public:
23         InvertVideoConfig();
25         void copy_from(InvertVideoConfig &src);
26         int equivalent(InvertVideoConfig &src);
27         void interpolate(InvertVideoConfig &prev, 
28                 InvertVideoConfig &next, 
29                 long prev_frame, 
30                 long next_frame, 
31                 long current_frame);
33         int r, g, b, a;
36 class InvertVideoEnable : public BC_CheckBox
38 public:
39         InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text);
40         int handle_event();
41         InvertVideoEffect *plugin;
42         int *output;
45 class InvertVideoWindow : public BC_Window
47 public:
48         InvertVideoWindow(InvertVideoEffect *plugin, int x, int y);
49         void create_objects();
50         int close_event();
51         InvertVideoEnable *r, *g, *b, *a;
52         InvertVideoEffect *plugin;
55 PLUGIN_THREAD_HEADER(InvertVideoEffect, InvertVideoThread, InvertVideoWindow)
57 class InvertVideoEffect : public PluginVClient
59 public:
60         InvertVideoEffect(PluginServer *server);
61         ~InvertVideoEffect();
62         int process_buffer(VFrame *frame,
63                 int64_t start_position,
64                 double frame_rate);
65         int is_realtime();
66         char* plugin_title();
67         VFrame* new_picon();
68         int load_defaults();
69         int save_defaults();
70         void save_data(KeyFrame *keyframe);
71         void read_data(KeyFrame *keyframe);
72         void update_gui();
73         int show_gui();
74         void raise_window();
75         int set_string();
76         int load_configuration();
77         int handle_opengl();
79         InvertVideoConfig config;
80         InvertVideoThread *thread;
81         BC_Hash *defaults;
88 REGISTER_PLUGIN(InvertVideoEffect)
96 InvertVideoConfig::InvertVideoConfig()
98         r = 1;
99         g = 1;
100         b = 1;
101         a = 1;
104 void InvertVideoConfig::copy_from(InvertVideoConfig &src)
106         r = src.r;
107         g = src.g;
108         b = src.b;
109         a = src.a;
112 int InvertVideoConfig::equivalent(InvertVideoConfig &src)
114         return r == src.r && 
115                 g == src.g && 
116                 b == src.b && 
117                 a == src.a;
120 void InvertVideoConfig::interpolate(InvertVideoConfig &prev, 
121         InvertVideoConfig &next, 
122         long prev_frame, 
123         long next_frame, 
124         long current_frame)
126         r = prev.r;
127         g = prev.g;
128         b = prev.b;
129         a = prev.a;
135 InvertVideoEnable::InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text)
136  : BC_CheckBox(x, y, *output, text)
138         this->plugin = plugin;
139         this->output = output;
141 int InvertVideoEnable::handle_event()
143         *output = get_value();
144         plugin->send_configure_change();
145         return 1;
152 InvertVideoWindow::InvertVideoWindow(InvertVideoEffect *plugin, int x, int y)
153  : BC_Window(plugin->gui_string, 
154         x, 
155         y, 
156         260, 
157         130, 
158         260, 
159         130, 
160         0, 
161         0,
162         1)
164         this->plugin = plugin;
167 void InvertVideoWindow::create_objects()
169         int x = 10, y = 10;
170         add_subwindow(r = new InvertVideoEnable(plugin, &plugin->config.r, x, y, _("Invert R")));
171         y += 30;
172         add_subwindow(g = new InvertVideoEnable(plugin, &plugin->config.g, x, y, _("Invert G")));
173         y += 30;
174         add_subwindow(b = new InvertVideoEnable(plugin, &plugin->config.b, x, y, _("Invert B")));
175         y += 30;
176         add_subwindow(a = new InvertVideoEnable(plugin, &plugin->config.a, x, y, _("Invert A")));
178         show_window();
179         flush();
182 WINDOW_CLOSE_EVENT(InvertVideoWindow)
188 PLUGIN_THREAD_OBJECT(InvertVideoEffect, InvertVideoThread, InvertVideoWindow)
195 InvertVideoEffect::InvertVideoEffect(PluginServer *server)
196  : PluginVClient(server)
198         PLUGIN_CONSTRUCTOR_MACRO
200 InvertVideoEffect::~InvertVideoEffect()
202         PLUGIN_DESTRUCTOR_MACRO
205 char* InvertVideoEffect::plugin_title() { return N_("Invert Video"); }
206 int InvertVideoEffect::is_realtime() { return 1; }
208 NEW_PICON_MACRO(InvertVideoEffect)
209 SHOW_GUI_MACRO(InvertVideoEffect, InvertVideoThread)
210 RAISE_WINDOW_MACRO(InvertVideoEffect)
211 SET_STRING_MACRO(InvertVideoEffect)
212 LOAD_CONFIGURATION_MACRO(InvertVideoEffect, InvertVideoConfig)
214 void InvertVideoEffect::update_gui()
216         if(thread)
217         {
218                 thread->window->lock_window();
219                 load_configuration();
220                 thread->window->r->update(config.r);
221                 thread->window->g->update(config.g);
222                 thread->window->b->update(config.b);
223                 thread->window->a->update(config.a);
224                 thread->window->unlock_window();
225         }
228 int InvertVideoEffect::load_defaults()
230         char directory[BCTEXTLEN];
231         sprintf(directory, "%sinvertvideo.rc", BCASTDIR);
232         defaults = new BC_Hash(directory);
233         defaults->load();
234         config.r = defaults->get("R", config.r);
235         config.g = defaults->get("G", config.g);
236         config.b = defaults->get("B", config.b);
237         config.a = defaults->get("A", config.a);
238         return 0;
241 int InvertVideoEffect::save_defaults()
243         defaults->update("R", config.r);
244         defaults->update("G", config.g);
245         defaults->update("B", config.b);
246         defaults->update("A", config.a);
247         defaults->save();
248         return 0;
251 void InvertVideoEffect::save_data(KeyFrame *keyframe)
253         FileXML output;
254         output.set_shared_string(keyframe->data, MESSAGESIZE);
255         output.tag.set_title("INVERTVIDEO");
256         output.tag.set_property("R", config.r);
257         output.tag.set_property("G", config.g);
258         output.tag.set_property("B", config.b);
259         output.tag.set_property("A", config.a);
260         output.append_tag();
261         output.tag.set_title("/INVERTVIDEO");
262         output.append_tag();
263         output.terminate_string();
266 void InvertVideoEffect::read_data(KeyFrame *keyframe)
268         FileXML input;
269         input.set_shared_string(keyframe->data, strlen(keyframe->data));
270         while(!input.read_tag())
271         {
272                 if(input.tag.title_is("INVERTVIDEO"))
273                 {
274                         config.r = input.tag.get_property("R", config.r);
275                         config.g = input.tag.get_property("G", config.g);
276                         config.b = input.tag.get_property("B", config.b);
277                         config.a = input.tag.get_property("A", config.a);
278                 }
279         }
283 #define INVERT_MACRO(type, components, max) \
284 { \
285         for(int i = 0; i < frame->get_h(); i++) \
286         { \
287                 type *in_row = (type*)frame->get_rows()[i]; \
288                 type *out_row = (type*)frame->get_rows()[i]; \
290                 for(int j = 0; j < w; j++) \
291                 { \
292                         if(config.r) out_row[0] = max - in_row[0]; \
293                         if(config.g) out_row[1] = max - in_row[1]; \
294                         if(config.b) out_row[2] = max - in_row[2]; \
295                         if(components == 4) \
296                                 if(config.a) out_row[3] = max - in_row[3]; \
298                         in_row += components; \
299                         out_row += components; \
300                 } \
301         } \
304 int InvertVideoEffect::process_buffer(VFrame *frame,
305         int64_t start_position,
306         double frame_rate)
308         load_configuration();
310         read_frame(frame, 
311                 0, 
312                 start_position, 
313                 frame_rate,
314                 get_use_opengl());
317         if(config.r || config.g || config.b || config.a)
318         {
319                 if(get_use_opengl())
320                 {
321                         run_opengl();
322                         return 0;
323                 }
324                 int w = frame->get_w();
326                 switch(frame->get_color_model())
327                 {
328                         case BC_RGB_FLOAT:
329                                 INVERT_MACRO(float, 3, 1.0)
330                                 break;
331                         case BC_RGB888:
332                         case BC_YUV888:
333                                 INVERT_MACRO(unsigned char, 3, 0xff)
334                                 break;
335                         case BC_RGBA_FLOAT:
336                                 INVERT_MACRO(float, 4, 1.0)
337                                 break;
338                         case BC_RGBA8888:
339                         case BC_YUVA8888:
340                                 INVERT_MACRO(unsigned char, 4, 0xff)
341                                 break;
342                         case BC_RGB161616:
343                         case BC_YUV161616:
344                                 INVERT_MACRO(uint16_t, 3, 0xffff)
345                                 break;
346                         case BC_RGBA16161616:
347                         case BC_YUVA16161616:
348                                 INVERT_MACRO(uint16_t, 4, 0xffff)
349                                 break;
350                 }
351         }
353         return 0;
356 int InvertVideoEffect::handle_opengl()
358 #ifdef HAVE_GL
359         static char *invert_frag = 
360                 "uniform sampler2D tex;\n"
361                 "uniform bool do_r;\n"
362                 "uniform bool do_g;\n"
363                 "uniform bool do_b;\n"
364                 "uniform bool do_a;\n"
365                 "void main()\n"
366                 "{\n"
367                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
368                 "       if(do_r) gl_FragColor.r = 1.0 - gl_FragColor.r;\n"
369                 "       if(do_g) gl_FragColor.g = 1.0 - gl_FragColor.g;\n"
370                 "       if(do_b) gl_FragColor.b = 1.0 - gl_FragColor.b;\n"
371                 "       if(do_a) gl_FragColor.a = 1.0 - gl_FragColor.a;\n"
372                 "}\n";
374         get_output()->to_texture();
375         get_output()->enable_opengl();
377         unsigned int frag_shader = 0;
378         frag_shader = VFrame::make_shader(0,
379                 invert_frag,
380                 0);
381         glUseProgram(frag_shader);
382         glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
383         glUniform1i(glGetUniformLocation(frag_shader, "do_r"), config.r);
384         glUniform1i(glGetUniformLocation(frag_shader, "do_g"), config.g);
385         glUniform1i(glGetUniformLocation(frag_shader, "do_b"), config.b);
386         glUniform1i(glGetUniformLocation(frag_shader, "do_a"), config.a);
389         VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
390         get_output()->bind_texture(0);
391         get_output()->draw_texture();
392         glUseProgram(0);
393         get_output()->set_opengl_state(VFrame::SCREEN);
394 #endif