Credit Andrew for build mods and cineform format
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / swapchannels / swapchannels.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 "language.h"
27 #include "swapchannels.h"
28 #include "vframe.h"
29
30
31
32 #include <stdint.h>
33 #include <string.h>
34
35
36
37
38
39
40 REGISTER_PLUGIN(SwapMain)
41
42
43
44
45
46
47
48
49 SwapConfig::SwapConfig()
50 {
51         reset_Config();
52 }
53
54 void SwapConfig::reset_Config()
55 {
56         red = RED_SRC;
57         green = GREEN_SRC;
58         blue = BLUE_SRC;
59         alpha = ALPHA_SRC;
60 }
61
62
63 int SwapConfig::equivalent(SwapConfig &that)
64 {
65         return (red == that.red &&
66                 green == that.green &&
67                 blue == that.blue &&
68                 alpha == that.alpha);
69 }
70
71 void SwapConfig::copy_from(SwapConfig &that)
72 {
73         red = that.red;
74         green = that.green;
75         blue = that.blue;
76         alpha = that.alpha;
77 }
78
79
80
81
82
83
84
85
86 SwapWindow::SwapWindow(SwapMain *plugin)
87  : PluginClientWindow(plugin,
88         xS(250),
89         yS(200),
90         xS(250),
91         yS(200),
92         0)
93 {
94         this->plugin = plugin;
95 }
96
97 SwapWindow::~SwapWindow()
98 {
99 }
100
101
102 void SwapWindow::create_objects()
103 {
104         int xs10 = xS(10), xs30 = xS(30), xs160 = xS(160);
105         int ys5 = yS(5), ys10 = yS(10), ys40 = yS(40);
106         int x = xs10, y = ys10;
107         int margin = xs30;
108
109         add_subwindow(new BC_Title(x, y, _("Swap channels")));
110         y += margin;
111         add_subwindow(new BC_Title(x + xs160, y + ys5, _("-> Red")));
112         add_subwindow(red = new SwapMenu(plugin, &(plugin->config.red), x, y));
113         red->create_objects();
114         y += margin;
115         add_subwindow(new BC_Title(x + xs160, y + ys5, _("-> Green")));
116         add_subwindow(green = new SwapMenu(plugin, &(plugin->config.green), x, y));
117         green->create_objects();
118         y += margin;
119         add_subwindow(new BC_Title(x + xs160, y + ys5, _("-> Blue")));
120         add_subwindow(blue = new SwapMenu(plugin, &(plugin->config.blue), x, y));
121         blue->create_objects();
122         y += margin;
123         add_subwindow(new BC_Title(x + xs160, y + ys5, _("-> Alpha")));
124         add_subwindow(alpha = new SwapMenu(plugin, &(plugin->config.alpha), x, y));
125         alpha->create_objects();
126
127         y += ys40;
128         add_subwindow(reset = new SwapReset(plugin, this, x, y));
129
130         show_window();
131         flush();
132 }
133
134
135
136
137
138
139
140
141 SwapMenu::SwapMenu(SwapMain *client, int *output, int x, int y)
142  : BC_PopupMenu(x, y, xS(150), client->output_to_text(*output))
143 {
144         this->client = client;
145         this->output = output;
146 }
147
148 int SwapMenu::handle_event()
149 {
150         client->send_configure_change();
151         return 1;
152 }
153
154 void SwapMenu::create_objects()
155 {
156         add_item(new SwapItem(this, client->output_to_text(RED_SRC)));
157         add_item(new SwapItem(this, client->output_to_text(GREEN_SRC)));
158         add_item(new SwapItem(this, client->output_to_text(BLUE_SRC)));
159         add_item(new SwapItem(this, client->output_to_text(ALPHA_SRC)));
160         add_item(new SwapItem(this, client->output_to_text(NO_SRC)));
161         add_item(new SwapItem(this, client->output_to_text(MAX_SRC)));
162 }
163
164
165
166
167 SwapItem::SwapItem(SwapMenu *menu, const char *title)
168  : BC_MenuItem(title)
169 {
170         this->menu = menu;
171 }
172
173 int SwapItem::handle_event()
174 {
175         menu->set_text(get_text());
176         *(menu->output) = menu->client->text_to_output(get_text());
177         menu->handle_event();
178         return 1;
179 }
180
181
182
183 SwapReset::SwapReset(SwapMain *plugin, SwapWindow *gui, int x, int y)
184  : BC_GenericButton(x, y, _("Reset"))
185 {
186         this->plugin = plugin;
187         this->gui = gui;
188 }
189 SwapReset::~SwapReset()
190 {
191 }
192 int SwapReset::handle_event()
193 {
194         plugin->config.reset_Config();
195         plugin->send_configure_change();
196         plugin->update_gui();
197         return 1;
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 SwapMain::SwapMain(PluginServer *server)
216  : PluginVClient(server)
217 {
218         reset();
219
220 }
221
222 SwapMain::~SwapMain()
223 {
224
225
226 //      if(temp) delete temp;
227 }
228
229 void SwapMain::reset()
230 {
231         temp = 0;
232 }
233
234
235 const char* SwapMain::plugin_title() { return N_("Swap channels"); }
236 int SwapMain::is_synthesis() { return 1; }
237 int SwapMain::is_realtime()  { return 1; }
238
239 NEW_WINDOW_MACRO(SwapMain, SwapWindow)
240
241
242 void SwapMain::save_data(KeyFrame *keyframe)
243 {
244         FileXML output;
245
246 // cause data to be stored directly in text
247         output.set_shared_output(keyframe->xbuf);
248         output.tag.set_title("SWAPCHANNELS");
249         output.tag.set_property("RED", config.red);
250         output.tag.set_property("GREEN", config.green);
251         output.tag.set_property("BLUE", config.blue);
252         output.tag.set_property("ALPHA", config.alpha);
253         output.append_tag();
254         output.tag.set_title("/SWAPCHANNELS");
255         output.append_tag();
256         output.append_newline();
257         output.terminate_string();
258 // data is now in *text
259 }
260
261 void SwapMain::read_data(KeyFrame *keyframe)
262 {
263         FileXML input;
264
265         input.set_shared_input(keyframe->xbuf);
266
267         int result = 0;
268
269         while(!result)
270         {
271                 result = input.read_tag();
272
273                 if(!result)
274                 {
275                         if(input.tag.title_is("SWAPCHANNELS"))
276                         {
277                                 config.red = input.tag.get_property("RED", config.red);
278                                 config.green = input.tag.get_property("GREEN", config.green);
279                                 config.blue = input.tag.get_property("BLUE", config.blue);
280                                 config.alpha = input.tag.get_property("ALPHA", config.alpha);
281                         }
282                 }
283         }
284 }
285
286 void SwapMain::update_gui()
287 {
288         if(thread)
289         {
290                 load_configuration();
291                 thread->window->lock_window();
292                 ((SwapWindow*)thread->window)->red->set_text(output_to_text(config.red));
293                 ((SwapWindow*)thread->window)->green->set_text(output_to_text(config.green));
294                 ((SwapWindow*)thread->window)->blue->set_text(output_to_text(config.blue));
295                 ((SwapWindow*)thread->window)->alpha->set_text(output_to_text(config.alpha));
296                 thread->window->unlock_window();
297         }
298 }
299
300
301 int SwapMain::load_configuration()
302 {
303         KeyFrame *prev_keyframe;
304         prev_keyframe = get_prev_keyframe(get_source_position());
305
306         read_data(prev_keyframe);
307         return 1;
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 #define MAXMINSRC(src, min, max) \
334         (src == MAX_SRC ? max : min)
335
336 #define SWAP_CHANNELS(type, min, max, components) \
337 { \
338         int h = frame->get_h(); \
339         int w = frame->get_w(); \
340         int red = config.red; \
341         int green = config.green; \
342         int blue = config.blue; \
343         int alpha = config.alpha; \
344  \
345         if(components == 3) \
346         { \
347                 if(red == ALPHA_SRC) red = MAX_SRC; \
348                 if(green == ALPHA_SRC) green = MAX_SRC; \
349                 if(blue == ALPHA_SRC) blue = MAX_SRC; \
350         } \
351  \
352  \
353         for(int i = 0; i < h; i++) \
354         { \
355                 type *inrow = (type*)frame->get_rows()[i]; \
356                 type *outrow = (type*)temp->get_rows()[i]; \
357  \
358                 for(int j = 0; j < w; j++) \
359                 { \
360                         if(red < 4) \
361                                 *outrow++ = *(inrow + red); \
362                         else \
363                                 *outrow++ = MAXMINSRC(red, 0, max); \
364  \
365                         if(green < 4) \
366                                 *outrow++ = *(inrow + green); \
367                         else \
368                                 *outrow++ = MAXMINSRC(green, min, max); \
369  \
370                         if(blue < 4) \
371                                 *outrow++ = *(inrow + blue); \
372                         else \
373                                 *outrow++ = MAXMINSRC(blue, min, max); \
374  \
375                         if(components == 4) \
376                         { \
377                                 if(alpha < 4) \
378                                         *outrow++ = *(inrow + alpha); \
379                                 else \
380                                         *outrow++ = MAXMINSRC(alpha, 0, max); \
381                         } \
382  \
383                         inrow += components; \
384                 } \
385         } \
386  \
387         frame->copy_from(temp); \
388 }
389
390
391
392 int SwapMain::process_buffer(VFrame *frame,
393         int64_t start_position,
394         double frame_rate)
395 {
396         load_configuration();
397
398         read_frame(frame,
399                 0,
400                 start_position,
401                 frame_rate,
402                 get_use_opengl());
403
404
405 // Use hardware
406         if(get_use_opengl())
407         {
408                 run_opengl();
409                 return 0;
410         }
411
412
413         temp = new_temp(frame->get_w(),
414                 frame->get_h(),
415                 frame->get_color_model());
416
417         switch(frame->get_color_model())
418         {
419                 case BC_RGB_FLOAT:
420                         SWAP_CHANNELS(float, 0, 1, 3);
421                         break;
422                 case BC_RGBA_FLOAT:
423                         SWAP_CHANNELS(float, 0, 1, 4);
424                         break;
425                 case BC_RGB888:
426                         SWAP_CHANNELS(unsigned char, 0, 0xff, 3);
427                         break;
428                 case BC_YUV888:
429                         SWAP_CHANNELS(unsigned char, 0x80, 0xff, 3);
430                         break;
431                 case BC_RGBA8888:
432                         SWAP_CHANNELS(unsigned char, 0, 0xff, 4);
433                         break;
434                 case BC_YUVA8888:
435                         SWAP_CHANNELS(unsigned char, 0x80, 0xff, 4);
436                         break;
437         }
438
439
440         return 0;
441 }
442
443
444 const char* SwapMain::output_to_text(int value)
445 {
446         switch(value)
447         {
448                 case RED_SRC:
449                         return _("Red");
450                         break;
451                 case GREEN_SRC:
452                         return _("Green");
453                         break;
454                 case BLUE_SRC:
455                         return _("Blue");
456                         break;
457                 case ALPHA_SRC:
458                         return _("Alpha");
459                         break;
460                 case NO_SRC:
461                         return "0%";
462                         break;
463                 case MAX_SRC:
464                         return "100%";
465                         break;
466                 default:
467                         return "";
468                         break;
469         }
470 }
471
472 int SwapMain::text_to_output(const char *text)
473 {
474         if(!strcmp(text, _("Red"))) return RED_SRC;
475         if(!strcmp(text, _("Green"))) return GREEN_SRC;
476         if(!strcmp(text, _("Blue"))) return BLUE_SRC;
477         if(!strcmp(text, _("Alpha"))) return ALPHA_SRC;
478         if(!strcmp(text, "0%")) return NO_SRC;
479         if(!strcmp(text, "100%")) return MAX_SRC;
480         return 0;
481 }
482
483 int SwapMain::handle_opengl()
484 {
485 #ifdef HAVE_GL
486
487         char output_frag[BCTEXTLEN];
488         sprintf(output_frag,
489                 "uniform sampler2D tex;\n"
490                 "uniform float chroma_offset;\n"
491                 "void main()\n"
492                 "{\n"
493                 "       vec4 in_color = texture2D(tex, gl_TexCoord[0].st);\n"
494                 "       vec4 out_color;\n");
495
496 #define COLOR_SWITCH(config, variable) \
497         strcat(output_frag, "   out_color." variable " = "); \
498         switch(config) \
499         { \
500                 case RED_SRC: strcat(output_frag, "in_color.r;\n"); break; \
501                 case GREEN_SRC: strcat(output_frag, "in_color.g;\n"); break; \
502                 case BLUE_SRC: strcat(output_frag, "in_color.b;\n"); break; \
503                 case ALPHA_SRC: strcat(output_frag, "in_color.a;\n"); break; \
504                 case NO_SRC: strcat(output_frag, "chroma_offset;\n"); break; \
505                 case MAX_SRC: strcat(output_frag, "1.0;\n"); break; \
506         }
507
508
509         COLOR_SWITCH(config.red, "r");
510         COLOR_SWITCH(config.green, "g");
511         COLOR_SWITCH(config.blue, "b");
512         COLOR_SWITCH(config.alpha, "a");
513
514         strcat(output_frag,
515                 "       gl_FragColor = out_color;\n"
516                 "}\n");
517
518         get_output()->to_texture();
519         get_output()->enable_opengl();
520         get_output()->init_screen();
521         get_output()->clear_pbuffer();
522         get_output()->bind_texture(0);
523
524         unsigned int shader = VFrame::make_shader(0, output_frag, 0);
525         if( shader > 0 ) {
526                 glUseProgram(shader);
527                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
528                 glUniform1f(glGetUniformLocation(shader, "chroma_offset"),
529                         BC_CModels::is_yuv(get_output()->get_color_model()) ? 0.5 : 0.0);
530         }
531
532         get_output()->draw_texture();
533         glUseProgram(0);
534         get_output()->set_opengl_state(VFrame::SCREEN);
535 #endif
536         return 0;
537 }
538
539
540