add auto zoombar/status color, fix 3 batchrender boobies, rotate plugin tweaks, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / invertvideo / invert.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "language.h"
28 #include "bccolors.h"
29 #include "pluginvclient.h"
30 #include "vframe.h"
31
32 #include <stdint.h>
33 #include <string.h>
34
35
36
37 class InvertVideoEffect;
38
39
40 class InvertVideoConfig
41 {
42 public:
43         InvertVideoConfig();
44
45         void copy_from(InvertVideoConfig &src);
46         int equivalent(InvertVideoConfig &src);
47         void interpolate(InvertVideoConfig &prev,
48                 InvertVideoConfig &next,
49                 long prev_frame,
50                 long next_frame,
51                 long current_frame);
52
53         int r, g, b, a;
54 };
55
56 class InvertVideoEnable : public BC_CheckBox
57 {
58 public:
59         InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text);
60         int handle_event();
61         InvertVideoEffect *plugin;
62         int *output;
63 };
64
65 class InvertVideoWindow : public PluginClientWindow
66 {
67 public:
68         InvertVideoWindow(InvertVideoEffect *plugin);
69         void create_objects();
70         InvertVideoEnable *r, *g, *b, *a;
71         InvertVideoEffect *plugin;
72 };
73
74
75 class InvertVideoEffect : public PluginVClient
76 {
77 public:
78         InvertVideoEffect(PluginServer *server);
79         ~InvertVideoEffect();
80         PLUGIN_CLASS_MEMBERS(InvertVideoConfig)
81         int process_buffer(VFrame *frame,
82                 int64_t start_position,
83                 double frame_rate);
84         int is_realtime();
85         void save_data(KeyFrame *keyframe);
86         void read_data(KeyFrame *keyframe);
87         void update_gui();
88         int handle_opengl();
89 };
90
91
92
93
94
95 REGISTER_PLUGIN(InvertVideoEffect)
96
97
98
99
100
101
102
103 InvertVideoConfig::InvertVideoConfig()
104 {
105         r = 1;
106         g = 1;
107         b = 1;
108         a = 1;
109 }
110
111 void InvertVideoConfig::copy_from(InvertVideoConfig &src)
112 {
113         r = src.r;
114         g = src.g;
115         b = src.b;
116         a = src.a;
117 }
118
119 int InvertVideoConfig::equivalent(InvertVideoConfig &src)
120 {
121         return r == src.r &&
122                 g == src.g &&
123                 b == src.b &&
124                 a == src.a;
125 }
126
127 void InvertVideoConfig::interpolate(InvertVideoConfig &prev,
128         InvertVideoConfig &next,
129         long prev_frame,
130         long next_frame,
131         long current_frame)
132 {
133         r = prev.r;
134         g = prev.g;
135         b = prev.b;
136         a = prev.a;
137 }
138
139
140
141
142 InvertVideoEnable::InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text)
143  : BC_CheckBox(x, y, *output, text)
144 {
145         this->plugin = plugin;
146         this->output = output;
147 }
148 int InvertVideoEnable::handle_event()
149 {
150         *output = get_value();
151         plugin->send_configure_change();
152         return 1;
153 }
154
155
156
157
158
159 InvertVideoWindow::InvertVideoWindow(InvertVideoEffect *plugin)
160  : PluginClientWindow(plugin,
161         260,
162         130,
163         260,
164         130,
165         0)
166 {
167         this->plugin = plugin;
168 }
169
170 void InvertVideoWindow::create_objects()
171 {
172         int x = 10, y = 10;
173         add_subwindow(r = new InvertVideoEnable(plugin, &plugin->config.r, x, y, _("Invert R")));
174         y += 30;
175         add_subwindow(g = new InvertVideoEnable(plugin, &plugin->config.g, x, y, _("Invert G")));
176         y += 30;
177         add_subwindow(b = new InvertVideoEnable(plugin, &plugin->config.b, x, y, _("Invert B")));
178         y += 30;
179         add_subwindow(a = new InvertVideoEnable(plugin, &plugin->config.a, x, y, _("Invert A")));
180
181         show_window();
182         flush();
183 }
184
185
186
187
188
189
190
191
192
193
194 InvertVideoEffect::InvertVideoEffect(PluginServer *server)
195  : PluginVClient(server)
196 {
197
198 }
199 InvertVideoEffect::~InvertVideoEffect()
200 {
201
202 }
203
204 const char* InvertVideoEffect::plugin_title() { return N_("Invert Video"); }
205 int InvertVideoEffect::is_realtime() { return 1; }
206
207 NEW_WINDOW_MACRO(InvertVideoEffect, InvertVideoWindow)
208 LOAD_CONFIGURATION_MACRO(InvertVideoEffect, InvertVideoConfig)
209
210 void InvertVideoEffect::update_gui()
211 {
212         if(thread)
213         {
214                 thread->window->lock_window();
215                 load_configuration();
216                 ((InvertVideoWindow*)thread->window)->r->update(config.r);
217                 ((InvertVideoWindow*)thread->window)->g->update(config.g);
218                 ((InvertVideoWindow*)thread->window)->b->update(config.b);
219                 ((InvertVideoWindow*)thread->window)->a->update(config.a);
220                 thread->window->unlock_window();
221         }
222 }
223
224
225 void InvertVideoEffect::save_data(KeyFrame *keyframe)
226 {
227         FileXML output;
228         output.set_shared_output(keyframe->xbuf);
229         output.tag.set_title("INVERTVIDEO");
230         output.tag.set_property("R", config.r);
231         output.tag.set_property("G", config.g);
232         output.tag.set_property("B", config.b);
233         output.tag.set_property("A", config.a);
234         output.append_tag();
235         output.tag.set_title("/INVERTVIDEO");
236         output.append_tag();
237         output.append_newline();
238         output.terminate_string();
239 }
240
241 void InvertVideoEffect::read_data(KeyFrame *keyframe)
242 {
243         FileXML input;
244         input.set_shared_input(keyframe->xbuf);
245         while(!input.read_tag())
246         {
247                 if(input.tag.title_is("INVERTVIDEO"))
248                 {
249                         config.r = input.tag.get_property("R", config.r);
250                         config.g = input.tag.get_property("G", config.g);
251                         config.b = input.tag.get_property("B", config.b);
252                         config.a = input.tag.get_property("A", config.a);
253                 }
254         }
255 }
256
257
258 #define INVERT_MACRO(type, components, max) \
259 { \
260         for(int i = 0; i < frame->get_h(); i++) \
261         { \
262                 type *in_row = (type*)frame->get_rows()[i]; \
263                 type *out_row = (type*)frame->get_rows()[i]; \
264  \
265                 for(int j = 0; j < w; j++) \
266                 { \
267                         if(config.r) out_row[0] = max - in_row[0]; \
268                         if(config.g) out_row[1] = max - in_row[1]; \
269                         if(config.b) out_row[2] = max - in_row[2]; \
270                         if(components == 4) \
271                                 if(config.a) out_row[3] = max - in_row[3]; \
272  \
273                         in_row += components; \
274                         out_row += components; \
275                 } \
276         } \
277 }
278
279 int InvertVideoEffect::process_buffer(VFrame *frame,
280         int64_t start_position,
281         double frame_rate)
282 {
283         load_configuration();
284
285         read_frame(frame,
286                 0,
287                 start_position,
288                 frame_rate,
289                 get_use_opengl());
290
291
292         if(config.r || config.g || config.b || config.a)
293         {
294                 if(get_use_opengl())
295                 {
296                         run_opengl();
297                         return 0;
298                 }
299                 int w = frame->get_w();
300
301                 switch(frame->get_color_model())
302                 {
303                         case BC_RGB_FLOAT:
304                                 INVERT_MACRO(float, 3, 1.0)
305                                 break;
306                         case BC_RGB888:
307                         case BC_YUV888:
308                                 INVERT_MACRO(unsigned char, 3, 0xff)
309                                 break;
310                         case BC_RGBA_FLOAT:
311                                 INVERT_MACRO(float, 4, 1.0)
312                                 break;
313                         case BC_RGBA8888:
314                         case BC_YUVA8888:
315                                 INVERT_MACRO(unsigned char, 4, 0xff)
316                                 break;
317                         case BC_RGB161616:
318                         case BC_YUV161616:
319                                 INVERT_MACRO(uint16_t, 3, 0xffff)
320                                 break;
321                         case BC_RGBA16161616:
322                         case BC_YUVA16161616:
323                                 INVERT_MACRO(uint16_t, 4, 0xffff)
324                                 break;
325                 }
326         }
327
328         return 0;
329 }
330
331 int InvertVideoEffect::handle_opengl()
332 {
333 #ifdef HAVE_GL
334         static const char *invert_frag =
335                 "uniform sampler2D tex;\n"
336                 "uniform bool do_r;\n"
337                 "uniform bool do_g;\n"
338                 "uniform bool do_b;\n"
339                 "uniform bool do_a;\n"
340                 "void main()\n"
341                 "{\n"
342                 "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
343                 "       if(do_r) gl_FragColor.r = 1.0 - gl_FragColor.r;\n"
344                 "       if(do_g) gl_FragColor.g = 1.0 - gl_FragColor.g;\n"
345                 "       if(do_b) gl_FragColor.b = 1.0 - gl_FragColor.b;\n"
346                 "       if(do_a) gl_FragColor.a = 1.0 - gl_FragColor.a;\n"
347                 "}\n";
348
349         get_output()->to_texture();
350         get_output()->enable_opengl();
351
352         unsigned int frag_shader = VFrame::make_shader(0, invert_frag, 0);
353         glUseProgram(frag_shader);
354         glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
355         glUniform1i(glGetUniformLocation(frag_shader, "do_r"), config.r);
356         glUniform1i(glGetUniformLocation(frag_shader, "do_g"), config.g);
357         glUniform1i(glGetUniformLocation(frag_shader, "do_b"), config.b);
358         glUniform1i(glGetUniformLocation(frag_shader, "do_a"), config.a);
359
360
361         VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
362         get_output()->bind_texture(0);
363         get_output()->draw_texture();
364         glUseProgram(0);
365         get_output()->set_opengl_state(VFrame::SCREEN);
366 #endif
367         return 0;
368 }
369
370