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