remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / plugins / translate / translate.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 "clip.h"
23 #include "filexml.h"
24 #include "language.h"
25 #include "translate.h"
26 #include "translatewin.h"
27
28 #include <string.h>
29
30
31
32
33 REGISTER_PLUGIN(TranslateMain)
34
35 TranslateConfig::TranslateConfig()
36 {
37         in_x = 0;
38         in_y = 0;
39         in_w = 720;
40         in_h = 480;
41         out_x = 0;
42         out_y = 0;
43         out_w = 720;
44         out_h = 480;
45 }
46
47 int TranslateConfig::equivalent(TranslateConfig &that)
48 {
49         return EQUIV(in_x, that.in_x) &&
50                 EQUIV(in_y, that.in_y) &&
51                 EQUIV(in_w, that.in_w) &&
52                 EQUIV(in_h, that.in_h) &&
53                 EQUIV(out_x, that.out_x) &&
54                 EQUIV(out_y, that.out_y) &&
55                 EQUIV(out_w, that.out_w) &&
56                 EQUIV(out_h, that.out_h);
57 }
58
59 void TranslateConfig::copy_from(TranslateConfig &that)
60 {
61         in_x = that.in_x;
62         in_y = that.in_y;
63         in_w = that.in_w;
64         in_h = that.in_h;
65         out_x = that.out_x;
66         out_y = that.out_y;
67         out_w = that.out_w;
68         out_h = that.out_h;
69 }
70
71 void TranslateConfig::interpolate(TranslateConfig &prev,
72         TranslateConfig &next,
73         int64_t prev_frame,
74         int64_t next_frame,
75         int64_t current_frame)
76 {
77         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
78         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
79
80         this->in_x = prev.in_x * prev_scale + next.in_x * next_scale;
81         this->in_y = prev.in_y * prev_scale + next.in_y * next_scale;
82         this->in_w = prev.in_w * prev_scale + next.in_w * next_scale;
83         this->in_h = prev.in_h * prev_scale + next.in_h * next_scale;
84         this->out_x = prev.out_x * prev_scale + next.out_x * next_scale;
85         this->out_y = prev.out_y * prev_scale + next.out_y * next_scale;
86         this->out_w = prev.out_w * prev_scale + next.out_w * next_scale;
87         this->out_h = prev.out_h * prev_scale + next.out_h * next_scale;
88 }
89
90
91
92
93
94
95
96
97 TranslateMain::TranslateMain(PluginServer *server)
98  : PluginVClient(server)
99 {
100         temp_frame = 0;
101         overlayer = 0;
102
103 }
104
105 TranslateMain::~TranslateMain()
106 {
107
108
109         if(temp_frame) delete temp_frame;
110         temp_frame = 0;
111         if(overlayer) delete overlayer;
112         overlayer = 0;
113 }
114
115 const char* TranslateMain::plugin_title() { return _("Translate"); }
116 int TranslateMain::is_realtime() { return 1; }
117
118
119
120 LOAD_CONFIGURATION_MACRO(TranslateMain, TranslateConfig)
121
122 void TranslateMain::save_data(KeyFrame *keyframe)
123 {
124         FileXML output;
125
126 // cause data to be stored directly in text
127         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
128
129 // Store data
130         output.tag.set_title("TRANSLATE");
131         output.tag.set_property("IN_X", config.in_x);
132         output.tag.set_property("IN_Y", config.in_y);
133         output.tag.set_property("IN_W", config.in_w);
134         output.tag.set_property("IN_H", config.in_h);
135         output.tag.set_property("OUT_X", config.out_x);
136         output.tag.set_property("OUT_Y", config.out_y);
137         output.tag.set_property("OUT_W", config.out_w);
138         output.tag.set_property("OUT_H", config.out_h);
139         output.append_tag();
140         output.tag.set_title("/TRANSLATE");
141         output.append_tag();
142         output.append_newline();
143         output.terminate_string();
144 // data is now in *text
145 }
146
147 void TranslateMain::read_data(KeyFrame *keyframe)
148 {
149         FileXML input;
150
151         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
152
153         int result = 0;
154
155         while(!result)
156         {
157                 result = input.read_tag();
158
159                 if(!result)
160                 {
161                         if(input.tag.title_is("TRANSLATE"))
162                         {
163                                 config.in_x = input.tag.get_property("IN_X", config.in_x);
164                                 config.in_y = input.tag.get_property("IN_Y", config.in_y);
165                                 config.in_w = input.tag.get_property("IN_W", config.in_w);
166                                 config.in_h = input.tag.get_property("IN_H", config.in_h);
167                                 config.out_x =  input.tag.get_property("OUT_X", config.out_x);
168                                 config.out_y =  input.tag.get_property("OUT_Y", config.out_y);
169                                 config.out_w =  input.tag.get_property("OUT_W", config.out_w);
170                                 config.out_h =  input.tag.get_property("OUT_H", config.out_h);
171                         }
172                 }
173         }
174 }
175
176
177 #define EPSILON 0.001
178
179 int TranslateMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
180 {
181         VFrame *input = input_ptr;
182         VFrame *output = output_ptr;
183
184         load_configuration();
185
186 //printf("TranslateMain::process_realtime 1 %p\n", input);
187         if( input->get_rows()[0] == output->get_rows()[0] ) {
188                 if( temp_frame && (
189                     temp_frame->get_w() != input_ptr->get_w() ||
190                     temp_frame->get_h() != input_ptr->get_h() ||
191                     temp_frame->get_color_model() != input_ptr->get_color_model() ) ) {
192                         delete temp_frame;
193                         temp_frame = 0;
194                 }
195                 if(!temp_frame)
196                         temp_frame = new VFrame(0,
197                                 -1,
198                                 input_ptr->get_w(),
199                                 input_ptr->get_h(),
200                                 input->get_color_model(),
201                                 -1);
202                 temp_frame->copy_from(input);
203                 input = temp_frame;
204         }
205 //printf("TranslateMain::process_realtime 2 %p\n", input);
206
207
208         if(!overlayer)
209         {
210                 overlayer = new OverlayFrame(smp + 1);
211         }
212
213         output->clear_frame();
214
215         if( config.in_w < EPSILON ) return 1;
216         if( config.in_h < EPSILON ) return 1;
217         if( config.out_w < EPSILON ) return 1;
218         if( config.out_h < EPSILON ) return 1;
219
220         float ix1 = config.in_x, ox1 = config.out_x;
221         float ix2 = ix1 + config.in_w;
222
223         if( ix1 < 0 ) {
224                 ox1 -= ix1;
225                 ix2 = config.in_w;
226                 ix1 = 0;
227         }
228
229         if(ix2 > output->get_w())
230                 ix2 = output->get_w();
231
232         float iy1 = config.in_y, oy1 = config.out_y;
233         float iy2 = iy1 + config.in_h;
234
235         if( iy1 < 0 ) {
236                 oy1 -= iy1;
237                 iy2 = config.in_h;
238                 iy1 = 0;
239         }
240
241         if( iy2 > output->get_h() )
242                 iy2 = output->get_h();
243
244         float cx = config.out_w / config.in_w;
245         float cy = config.out_h / config.in_h;
246
247         float ox2 = ox1 + (ix2 - ix1) * cx;
248         float oy2 = oy1 + (iy2 - iy1) * cy;
249
250         if( ox1 < 0 ) {
251                 ix1 += -ox1 / cx;
252                 ox1 = 0;
253         }
254         if( oy1 < 0 ) {
255                 iy1 += -oy1 / cy;
256                 oy1 = 0;
257         }
258         if( ox2 > output->get_w() ) {
259                 ix2 -= (ox2 - output->get_w()) / cx;
260                 ox2 = output->get_w();
261         }
262         if( oy2 > output->get_h() ) {
263                 iy2 -= (oy2 - output->get_h()) / cy;
264                 oy2 = output->get_h();
265         }
266
267         if( ix1 >= ix2 ) return 1;
268         if( iy1 >= iy2 ) return 1;
269         if( ox1 >= ox2 ) return 1;
270         if( oy1 >= oy2 ) return 1;
271
272         overlayer->overlay(output, input,
273                 ix1, iy1, ix2, iy2,
274                 ox1, oy1, ox2, oy2,
275                 1, TRANSFER_REPLACE,
276                 get_interpolation_type());
277         return 0;
278 }
279
280 NEW_WINDOW_MACRO(TranslateMain, TranslateWin)
281
282 void TranslateMain::update_gui()
283 {
284         if( !thread ) return;
285         if( !load_configuration() ) return;
286
287         TranslateWin *window = (TranslateWin*)thread->window;
288         window->lock_window();
289         window->in_x->update(config.in_x);
290         window->in_y->update(config.in_y);
291         window->in_w->update(config.in_w);
292         window->in_h->update(config.in_h);
293         window->out_x->update(config.out_x);
294         window->out_y->update(config.out_y);
295         window->out_w->update(config.out_w);
296         window->out_h->update(config.out_h);
297         window->unlock_window();
298 }