add auto zoombar/status color, fix 3 batchrender boobies, rotate plugin tweaks, add...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / shiftinterlace / shiftinterlace.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 "shiftinterlace.h"
23
24
25
26
27
28 PluginClient* new_plugin(PluginServer *server)
29 {
30         return new ShiftInterlaceMain(server);
31 }
32
33
34
35
36 ShiftInterlaceConfig::ShiftInterlaceConfig()
37 {
38         reset();
39 }
40
41 void ShiftInterlaceConfig::reset()
42 {
43         odd_offset = 0;
44         even_offset = 0;
45 }
46
47
48 int ShiftInterlaceConfig::equivalent(ShiftInterlaceConfig &that)
49 {
50         return (odd_offset == that.odd_offset &&
51                 even_offset == that.even_offset);
52 }
53
54 void ShiftInterlaceConfig::copy_from(ShiftInterlaceConfig &that)
55 {
56         odd_offset = that.odd_offset;
57         even_offset = that.even_offset;
58 }
59
60 void ShiftInterlaceConfig::interpolate(ShiftInterlaceConfig &prev,
61                 ShiftInterlaceConfig &next,
62                 long prev_frame,
63                 long next_frame,
64                 long current_frame)
65 {
66         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
67         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
68
69         this->odd_offset = (int)(prev.odd_offset * prev_scale + next.odd_offset * next_scale);
70         this->even_offset = (int)(prev.even_offset * prev_scale + next.even_offset * next_scale);
71 }
72
73
74
75
76
77
78 ShiftInterlaceWindow::ShiftInterlaceWindow(ShiftInterlaceMain *plugin)
79  : PluginClientWindow(plugin,
80         310,
81         110,
82         310,
83         110,
84         0)
85 {
86         this->plugin = plugin;
87 }
88
89
90 void ShiftInterlaceWindow::create_objects()
91 {
92         int x = 10, y = 10;
93         int margin = 30;
94
95         add_subwindow(new BC_Title(x, y, _("Odd offset:")));
96         add_subwindow(odd_offset = new ShiftInterlaceOdd(plugin, x + 90, y));
97         y += margin;
98         add_subwindow(new BC_Title(x, y, _("Even offset:")));
99         add_subwindow(even_offset = new ShiftInterlaceEven(plugin, x + 90, y));
100         y += 40;
101         add_subwindow(reset = new ShiftInterlaceReset(plugin, this, x, y));
102         show_window();
103         flush();
104 }
105
106 // for Reset button
107 void ShiftInterlaceWindow::update()
108 {
109         odd_offset->update(plugin->config.odd_offset);
110         even_offset->update(plugin->config.even_offset);
111 }
112
113
114
115 ShiftInterlaceOdd::ShiftInterlaceOdd(ShiftInterlaceMain *plugin, int x, int y)
116  : BC_ISlider(x,
117         y,
118         0,
119         200,
120         200,
121         -100,
122         100,
123         plugin->config.odd_offset)
124 {
125         this->plugin = plugin;
126 }
127 int ShiftInterlaceOdd::handle_event()
128 {
129         plugin->config.odd_offset = get_value();
130         plugin->send_configure_change();
131         return 1;
132 }
133
134
135
136
137 ShiftInterlaceEven::ShiftInterlaceEven(ShiftInterlaceMain *plugin, int x, int y)
138  : BC_ISlider(x,
139         y,
140         0,
141         200,
142         200,
143         -100,
144         100,
145         plugin->config.even_offset)
146 {
147         this->plugin = plugin;
148 }
149
150
151 int ShiftInterlaceEven::handle_event()
152 {
153         plugin->config.even_offset = get_value();
154         plugin->send_configure_change();
155         return 1;
156 }
157
158
159
160
161 ShiftInterlaceReset::ShiftInterlaceReset(ShiftInterlaceMain *plugin, ShiftInterlaceWindow *gui, int x, int y)
162  : BC_GenericButton(x, y, _("Reset"))
163 {
164         this->plugin = plugin;
165         this->gui = gui;
166 }
167 ShiftInterlaceReset::~ShiftInterlaceReset()
168 {
169 }
170 int ShiftInterlaceReset::handle_event()
171 {
172         plugin->config.reset();
173         gui->update();
174         plugin->send_configure_change();
175         return 1;
176 }
177
178
179
180
181
182
183
184
185
186
187 ShiftInterlaceMain::ShiftInterlaceMain(PluginServer *server)
188  : PluginVClient(server)
189 {
190
191 }
192
193 ShiftInterlaceMain::~ShiftInterlaceMain()
194 {
195
196 }
197
198
199 const char* ShiftInterlaceMain::plugin_title() { return N_("ShiftInterlace"); }
200 int ShiftInterlaceMain::is_realtime() { return 1; }
201
202
203
204
205
206 LOAD_CONFIGURATION_MACRO(ShiftInterlaceMain, ShiftInterlaceConfig)
207
208 NEW_WINDOW_MACRO(ShiftInterlaceMain, ShiftInterlaceWindow)
209
210
211
212 void ShiftInterlaceMain::save_data(KeyFrame *keyframe)
213 {
214         FileXML output;
215
216 // cause data to be stored directly in text
217         output.set_shared_output(keyframe->xbuf);
218         output.tag.set_title("SHIFTINTERLACE");
219         output.tag.set_property("ODD_OFFSET", config.odd_offset);
220         output.tag.set_property("EVEN_OFFSET", config.even_offset);
221         output.append_tag();
222         output.tag.set_title("/SHIFTINTERLACE");
223         output.append_tag();
224         output.append_newline();
225         output.terminate_string();
226 // data is now in *text
227 }
228
229 void ShiftInterlaceMain::read_data(KeyFrame *keyframe)
230 {
231         FileXML input;
232
233         input.set_shared_input(keyframe->xbuf);
234
235         int result = 0;
236
237         while(!result)
238         {
239                 result = input.read_tag();
240
241                 if(!result)
242                 {
243                         if(input.tag.title_is("SHIFTINTERLACE"))
244                         {
245                                 config.odd_offset = input.tag.get_property("ODD_OFFSET", config.odd_offset);
246                                 config.even_offset = input.tag.get_property("EVEN_OFFSET", config.even_offset);
247                         }
248                 }
249         }
250 }
251
252 void ShiftInterlaceMain::update_gui()
253 {
254         if(thread)
255         {
256                 load_configuration();
257                 thread->window->lock_window();
258                 ((ShiftInterlaceWindow*)thread->window)->odd_offset->update(config.odd_offset);
259                 ((ShiftInterlaceWindow*)thread->window)->even_offset->update(config.even_offset);
260                 thread->window->unlock_window();
261         }
262 }
263
264
265 #define SHIFT_ROW_MACRO(components, type, chroma_offset) \
266 { \
267         type *input_row = (type*)input_frame->get_rows()[row]; \
268         type *output_row = (type*)output_frame->get_rows()[row]; \
269  \
270         if(offset < 0) \
271         { \
272                 int i, j; \
273                 for(i = 0, j = -offset;  \
274                         j < w;  \
275                         i++, j++) \
276                 { \
277                         output_row[i * components + 0] = input_row[j * components + 0]; \
278                         output_row[i * components + 1] = input_row[j * components + 1]; \
279                         output_row[i * components + 2] = input_row[j * components + 2]; \
280                         if(components == 4) output_row[i * components + 3] = input_row[j * components + 3]; \
281                 } \
282  \
283                 for( ; i < w; i++) \
284                 { \
285                         output_row[i * components + 0] = 0; \
286                         output_row[i * components + 1] = chroma_offset; \
287                         output_row[i * components + 2] = chroma_offset; \
288                         if(components == 4) output_row[i * components + 3] = 0; \
289                 } \
290         } \
291         else \
292         { \
293                 int i, j; \
294                 for(i = w - offset - 1, j = w - 1; \
295                         j >= offset; \
296                         i--, \
297                         j--) \
298                 { \
299                         output_row[j * components + 0] = input_row[i * components + 0]; \
300                         output_row[j * components + 1] = input_row[i * components + 1]; \
301                         output_row[j * components + 2] = input_row[i * components + 2]; \
302                         if(components == 4) output_row[j * components + 3] = input_row[i * components + 3]; \
303                 } \
304  \
305                 for( ; j >= 0; j--) \
306                 { \
307                         output_row[j * components + 0] = 0; \
308                         output_row[j * components + 1] = chroma_offset; \
309                         output_row[j * components + 2] = chroma_offset; \
310                         if(components == 4) output_row[j * components + 3] = 0; \
311                 } \
312         } \
313 }
314
315
316 void ShiftInterlaceMain::shift_row(VFrame *input_frame,
317         VFrame *output_frame,
318         int offset,
319         int row)
320 {
321         int w = input_frame->get_w();
322         switch(input_frame->get_color_model())
323         {
324                 case BC_RGB888:
325                         SHIFT_ROW_MACRO(3, unsigned char, 0x0)
326                         break;
327                 case BC_RGB_FLOAT:
328                         SHIFT_ROW_MACRO(3, float, 0x0)
329                         break;
330                 case BC_YUV888:
331                         SHIFT_ROW_MACRO(3, unsigned char, 0x80)
332                         break;
333                 case BC_RGBA_FLOAT:
334                         SHIFT_ROW_MACRO(4, float, 0x0)
335                         break;
336                 case BC_RGBA8888:
337                         SHIFT_ROW_MACRO(4, unsigned char, 0x0)
338                         break;
339                 case BC_YUVA8888:
340                         SHIFT_ROW_MACRO(4, unsigned char, 0x80)
341                         break;
342                 case BC_RGB161616:
343                         SHIFT_ROW_MACRO(3, uint16_t, 0x0)
344                         break;
345                 case BC_YUV161616:
346                         SHIFT_ROW_MACRO(3, uint16_t, 0x8000)
347                         break;
348                 case BC_RGBA16161616:
349                         SHIFT_ROW_MACRO(4, uint16_t, 0x0)
350                         break;
351                 case BC_YUVA16161616:
352                         SHIFT_ROW_MACRO(4, uint16_t, 0x8000)
353                         break;
354         }
355 }
356
357 int ShiftInterlaceMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
358 {
359         load_configuration();
360
361         int h = input_ptr->get_h();
362         for(int i = 0; i < h; i++)
363         {
364                 if(i % 2)
365                         shift_row(input_ptr, output_ptr, config.even_offset, i);
366                 else
367                         shift_row(input_ptr, output_ptr, config.odd_offset, i);
368         }
369
370         return 0;
371 }
372
373