add layout_scale preference, scaling cleanup, rework init bc_resources, init tip_info...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / reroute / reroute.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2007 Hermann Vosseler
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 "keyframe.h"
28 #include "language.h"
29 #include "overlayframe.h"
30 #include "pluginvclient.h"
31 #include "vframe.h"
32
33 #include <string.h>
34 #include <stdint.h>
35
36
37 class Reroute;
38 class RerouteWindow;
39
40
41 class RerouteConfig
42 {
43 public:
44         RerouteConfig();
45
46
47
48         static const char* operation_to_text(int operation);
49         int operation;
50         enum
51         {
52                 REPLACE,
53                 REPLACE_COMPONENTS,
54                 REPLACE_ALPHA
55         };
56
57         static const char* output_to_text(int output_track);
58         int output_track;
59         enum
60         {
61                 TOP,
62                 BOTTOM
63         };
64 };
65
66
67
68
69
70
71 class RerouteOperation : public BC_PopupMenu
72 {
73 public:
74         RerouteOperation(Reroute *plugin,
75                 int x,
76                 int y);
77         void create_objects();
78         int handle_event();
79         Reroute *plugin;
80 };
81
82 class RerouteOutput : public BC_PopupMenu
83 {
84 public:
85         RerouteOutput(Reroute *plugin,
86                 int x,
87                 int y);
88         void create_objects();
89         int handle_event();
90         Reroute *plugin;
91 };
92
93
94 class RerouteWindow : public PluginClientWindow
95 {
96 public:
97         RerouteWindow(Reroute *plugin);
98         ~RerouteWindow();
99
100         void create_objects();
101
102         Reroute *plugin;
103         RerouteOperation *operation;
104         RerouteOutput *output;
105 };
106
107
108
109
110
111 class Reroute : public PluginVClient
112 {
113 public:
114         Reroute(PluginServer *server);
115         ~Reroute();
116
117
118         PLUGIN_CLASS_MEMBERS(RerouteConfig);
119
120         int process_buffer(VFrame **frame, int64_t start_position, double frame_rate);
121         int is_realtime();
122         int is_multichannel();
123         void save_data(KeyFrame *keyframe);
124         void read_data(KeyFrame *keyframe);
125         void update_gui();
126
127         int output_track;
128         int input_track;
129 };
130
131
132
133
134
135
136
137
138
139
140
141
142 RerouteConfig::RerouteConfig()
143 {
144         operation = RerouteConfig::REPLACE;
145         output_track = RerouteConfig::TOP;
146 }
147
148
149 const char* RerouteConfig::operation_to_text(int operation)
150 {
151         switch(operation)
152         {
153                 case RerouteConfig::REPLACE:                    return _("replace Target");
154                 case RerouteConfig::REPLACE_COMPONENTS: return _("Components only");
155                 case RerouteConfig::REPLACE_ALPHA:      return _("Alpha replace");
156         }
157         return "";
158 }
159
160 const char* RerouteConfig::output_to_text(int output_track)
161 {
162         switch(output_track)
163         {
164                 case RerouteConfig::TOP:    return _("Top");
165                 case RerouteConfig::BOTTOM: return _("Bottom");
166         }
167         return "";
168 }
169
170
171
172
173
174
175
176
177
178 RerouteWindow::RerouteWindow(Reroute *plugin)
179  : PluginClientWindow(plugin, xS(300), yS(70), 0, 0, 1)
180 {
181         this->plugin = plugin;
182 }
183
184 RerouteWindow::~RerouteWindow()
185 {
186 }
187
188 void RerouteWindow::create_objects()
189 {
190         int xs5 = xS(5), xs10 = xS(10);
191         int ys10 = yS(10), ys30 = yS(30);
192         int x = xs10, y = ys10;
193
194         BC_Title *title;
195         add_subwindow(title = new BC_Title(x, y, _("Target track:")));
196
197         int col2 = title->get_w() + xs5;
198         add_subwindow(output = new RerouteOutput(plugin,
199                 x + col2,
200                 y));
201         output->create_objects();
202
203         y += ys30;
204         add_subwindow(title = new BC_Title(x, y, _("Operation:")));
205         add_subwindow(operation = new RerouteOperation(plugin,
206                 x + col2,
207                 y));
208         operation->create_objects();
209
210         show_window();
211         flush();
212 }
213
214
215
216
217
218
219
220
221 RerouteOperation::RerouteOperation(Reroute *plugin,
222         int x,
223         int y)
224  : BC_PopupMenu(x,
225         y,
226         xS(180),
227         RerouteConfig::operation_to_text(plugin->config.operation),
228         1)
229 {
230         this->plugin = plugin;
231 }
232
233 void RerouteOperation::create_objects()
234 {
235         add_item(new BC_MenuItem(
236                 RerouteConfig::operation_to_text(
237                         RerouteConfig::REPLACE)));
238         add_item(new BC_MenuItem(
239                 RerouteConfig::operation_to_text(
240                         RerouteConfig::REPLACE_COMPONENTS)));
241         add_item(new BC_MenuItem(
242                 RerouteConfig::operation_to_text(
243                         RerouteConfig::REPLACE_ALPHA)));
244 }
245
246 int RerouteOperation::handle_event()
247 {
248         char *text = get_text();
249
250         if(!strcmp(text,
251                 RerouteConfig::operation_to_text(
252                         RerouteConfig::REPLACE)))
253                 plugin->config.operation = RerouteConfig::REPLACE;
254         else
255         if(!strcmp(text,
256                 RerouteConfig::operation_to_text(
257                         RerouteConfig::REPLACE_COMPONENTS)))
258                 plugin->config.operation = RerouteConfig::REPLACE_COMPONENTS;
259         else
260         if(!strcmp(text,
261                 RerouteConfig::operation_to_text(
262                         RerouteConfig::REPLACE_ALPHA)))
263                 plugin->config.operation = RerouteConfig::REPLACE_ALPHA;
264
265         plugin->send_configure_change();
266         return 1;
267 }
268
269
270 RerouteOutput::RerouteOutput(Reroute *plugin,
271         int x,
272         int y)
273  : BC_PopupMenu(x,
274         y,
275         xS(100),
276         RerouteConfig::output_to_text(plugin->config.output_track),
277         1)
278 {
279         this->plugin = plugin;
280 }
281
282 void RerouteOutput::create_objects()
283 {
284         add_item(new BC_MenuItem(
285                 RerouteConfig::output_to_text(
286                         RerouteConfig::TOP)));
287         add_item(new BC_MenuItem(
288                 RerouteConfig::output_to_text(
289                         RerouteConfig::BOTTOM)));
290 }
291
292 int RerouteOutput::handle_event()
293 {
294         char *text = get_text();
295
296         if(!strcmp(text,
297                 RerouteConfig::output_to_text(
298                         RerouteConfig::TOP)))
299                 plugin->config.output_track = RerouteConfig::TOP;
300         else
301         if(!strcmp(text,
302                 RerouteConfig::output_to_text(
303                         RerouteConfig::BOTTOM)))
304                 plugin->config.output_track = RerouteConfig::BOTTOM;
305
306         plugin->send_configure_change();
307         return 1;
308 }
309
310
311
312
313
314 /***** Register Plugin ***********************************/
315
316
317 REGISTER_PLUGIN(Reroute)
318
319
320
321
322
323
324
325 Reroute::Reroute(PluginServer *server)
326  : PluginVClient(server)
327 {
328 }
329
330
331 Reroute::~Reroute()
332 {
333 }
334
335
336
337 /*
338  *  Main operation
339  *
340  *****************************************/
341 template<class TYPE, int COMPONENTS>
342 struct px_type
343 {
344         static inline
345         void transfer(VFrame*, VFrame*, bool, bool) ;
346 };
347
348 template<class TYPE, int COMPONENTS>
349 void px_type<TYPE,COMPONENTS>::transfer(VFrame *source, VFrame *target, bool do_components, bool do_alpha)
350 //partially overwrite target data buffer
351 {
352         int w = target->get_w();
353         int h = source->get_h();
354         do_alpha = do_alpha && (COMPONENTS > 3);  // only possible if we have alpha
355
356         for(int i = 0; i < h; i++)
357         {
358                 TYPE *inpx  = (TYPE*)source->get_rows()[i];
359                 TYPE *outpx = (TYPE*)target->get_rows()[i];
360
361                 for(int j = 0; j < w; j++)
362                 {
363                         if(do_components)
364                         {
365                                 outpx[0] = inpx[0];
366                                 outpx[1] = inpx[1];
367                                 outpx[2] = inpx[2];
368                         }
369                         if(do_alpha)
370                                 outpx[3] = inpx[3];
371
372                         inpx += COMPONENTS;
373                         outpx += COMPONENTS;
374                 }
375         }
376 }
377
378
379
380 int Reroute::process_buffer(VFrame **frame,
381         int64_t start_position,
382         double frame_rate)
383 {
384         load_configuration();
385
386         bool do_components = true, do_alpha = true;
387         switch(config.operation)
388         {
389                 case RerouteConfig::REPLACE:            break;
390                 case RerouteConfig::REPLACE_ALPHA:      do_components = false; break;
391                 case RerouteConfig::REPLACE_COMPONENTS: do_alpha = false; break;
392         }
393
394         if(config.output_track == RerouteConfig::TOP)
395         {
396                 input_track  = get_total_buffers() - 1;
397                 output_track = 0;
398         }
399         else
400         {
401                 input_track  = 0;
402                 output_track = get_total_buffers() - 1;
403         }
404
405
406         // output buffers for source and target track
407         VFrame *source = frame[input_track];
408         VFrame *target = frame[output_track];
409
410         // input track always passed through unaltered
411         read_frame(source,
412                 input_track,
413                 start_position,
414                 frame_rate,
415                 false );  // no OpenGL support
416
417          // no real operation necessary
418         //  unless applied to multiple tracks....
419         if(get_total_buffers() <= 1)
420                 return 0;
421
422         if(config.operation == RerouteConfig::REPLACE)
423         {
424                 target->copy_from(source);
425                 return 0;
426         }
427
428
429         // prepare data for output track
430         // (to be overidden partially)
431         read_frame(target,
432                 output_track,
433                 start_position,
434                 frame_rate,
435                 0);
436
437         switch(source->get_color_model())
438         {
439                 case BC_RGB_FLOAT:
440                         px_type<float,3>::transfer(source,target, do_components,do_alpha);
441                         break;
442                 case BC_RGBA_FLOAT:
443                         px_type<float,4>::transfer(source,target, do_components,do_alpha);
444                         break;
445                 case BC_RGB888:
446                 case BC_YUV888:
447                         px_type<unsigned char,3>::transfer(source,target, do_components,do_alpha);
448                         break;
449                 case BC_RGBA8888:
450                 case BC_YUVA8888:
451                         px_type<unsigned char,4>::transfer(source,target, do_components,do_alpha);
452                         break;
453                 case BC_RGB161616:
454                 case BC_YUV161616:
455                         px_type<uint16_t,3>::transfer(source,target, do_components,do_alpha);
456                         break;
457                 case BC_RGBA16161616:
458                 case BC_YUVA16161616:
459                         px_type<uint16_t,4>::transfer(source,target, do_components,do_alpha);
460                         break;
461         }
462
463         return 0;
464 }
465
466
467
468
469
470
471
472
473 const char* Reroute::plugin_title() { return N_("Reroute"); }
474 int Reroute::is_realtime()              { return 1; }
475 int Reroute::is_multichannel()  { return 1; }
476
477
478
479
480
481 NEW_WINDOW_MACRO(Reroute,RerouteWindow)
482
483 int Reroute::load_configuration()
484 {
485         KeyFrame *prev_keyframe;
486         prev_keyframe = get_prev_keyframe(get_source_position());
487         read_data(prev_keyframe);
488         return 0;
489 }
490
491
492 void Reroute::save_data(KeyFrame *keyframe)
493 {
494         FileXML output;
495
496 // write configuration data as XML text
497         output.set_shared_output(keyframe->xbuf);
498         output.tag.set_title("REROUTE");
499         output.tag.set_property("OPERATION", config.operation);
500         output.tag.set_property("OUTPUT_TRACK", config.output_track);
501         output.append_tag();
502         output.tag.set_title("/REROUTE");
503         output.append_tag();
504         output.terminate_string();
505 }
506
507 void Reroute::read_data(KeyFrame *keyframe)
508 {
509         FileXML input;
510         input.set_shared_input(keyframe->xbuf);
511
512         while(!input.read_tag())
513         {
514                 if(input.tag.title_is("REROUTE"))
515                 {
516                         config.operation = input.tag.get_property("OPERATION", config.operation);
517                         config.output_track = input.tag.get_property("OUTPUT_TRACK", config.output_track);
518                 }
519         }
520 }
521
522 void Reroute::update_gui()
523 {
524         if(thread)
525         {
526                 RerouteWindow *window = (RerouteWindow *)thread->window;
527                 window->lock_window("Reroute::update_gui");
528                 window->operation->set_text(RerouteConfig::operation_to_text(config.operation));
529                 window->output->set_text(RerouteConfig::output_to_text(config.output_track));
530                 window->unlock_window();
531         }
532 }