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