4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 * 2023. Derivative by Flip plugin.
27 #include "bccmodels.h"
31 #include "mirrorwindow.h"
39 REGISTER_PLUGIN(MirrorMain)
46 MirrorConfig::MirrorConfig()
48 reset(RESET_DEFAULT_SETTINGS);
51 void MirrorConfig::reset(int clear)
54 case RESET_REFLECTION_CENTER_X :
55 reflection_center_x = 50.00;
56 mirror_horizontal = 1;
57 mirror_swaphorizontal = 0;
59 case RESET_REFLECTION_CENTER_Y :
60 reflection_center_y = 50.00;
62 mirror_swapvertical = 0;
65 case RESET_DEFAULT_SETTINGS :
67 mirror_horizontal = 1;
68 mirror_swaphorizontal = 0;
70 mirror_swapvertical = 0;
71 reflection_center_enable = 0;
72 reflection_center_x = 50.00;
73 reflection_center_y = 50.00;
78 void MirrorConfig::copy_from(MirrorConfig &that)
80 mirror_horizontal = that.mirror_horizontal;
81 mirror_swaphorizontal = that.mirror_swaphorizontal;
82 mirror_vertical = that.mirror_vertical;
83 mirror_swapvertical = that.mirror_swapvertical;
84 reflection_center_enable = that.reflection_center_enable;
85 reflection_center_x = that.reflection_center_x;
86 reflection_center_y = that.reflection_center_y;
89 int MirrorConfig::equivalent(MirrorConfig &that)
91 return EQUIV(mirror_horizontal, that.mirror_horizontal) &&
92 EQUIV(mirror_swaphorizontal, that.mirror_swaphorizontal) &&
93 EQUIV(mirror_vertical, that.mirror_vertical) &&
94 EQUIV(mirror_swapvertical, that.mirror_swapvertical) &&
95 EQUIV(reflection_center_enable, that.reflection_center_enable) &&
96 EQUIV(reflection_center_x, that.reflection_center_x) &&
97 EQUIV(reflection_center_y, that.reflection_center_y);
100 void MirrorConfig::interpolate(MirrorConfig &prev,
104 int64_t current_frame)
106 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
107 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
109 this->mirror_horizontal = prev.mirror_horizontal;
110 this->mirror_swaphorizontal = prev.mirror_swaphorizontal;
111 this->mirror_vertical = prev.mirror_vertical;
112 this->mirror_swapvertical = prev.mirror_swapvertical;
113 this->reflection_center_enable = prev.reflection_center_enable;
114 this->reflection_center_x = prev.reflection_center_x * prev_scale + next.reflection_center_x * next_scale;
115 this->reflection_center_y = prev.reflection_center_y * prev_scale + next.reflection_center_y * next_scale;
127 MirrorMain::MirrorMain(PluginServer *server)
128 : PluginVClient(server)
133 MirrorMain::~MirrorMain()
138 const char* MirrorMain::plugin_title() { return N_("Mirror"); }
139 int MirrorMain::is_realtime() { return 1; }
142 #define SWAPCOPY_PIXELS(components, in, out) \
147 if(components == 4) \
154 #define MIRROR_MACRO(type, components) \
156 type **input_rows, **output_rows; \
157 type *input_row, *output_row; \
158 input_rows = ((type**)frame->get_rows()); \
159 output_rows = ((type**)frame->get_rows()); \
161 if (!config.reflection_center_enable) \
163 /* HORIZONTAL ONLY */ \
164 if(config.mirror_horizontal && !config.mirror_vertical && !config.mirror_swaphorizontal) \
166 for(i = 0; i < h; i++) \
168 input_row = input_rows[i]; \
169 output_row = output_rows[i] + (w - 1) * components; \
170 for(k = 0; k < w / 2; k++) \
172 SWAPCOPY_PIXELS(components, output_row, input_row); \
173 input_row += components; \
174 output_row -= components; \
178 /* HORIZONTAL SWAP ONLY */ \
179 else if(config.mirror_horizontal && !config.mirror_vertical && config.mirror_swaphorizontal) \
181 for(i = 0; i < h; i++) \
183 input_row = input_rows[i]; \
184 output_row = output_rows[i] + (w - 1) * components; \
185 for(k = 0; k < w / 2; k++) \
187 SWAPCOPY_PIXELS(components, input_row, output_row); \
188 input_row += components; \
189 output_row -= components; \
193 /* VERTICAL ONLY */ \
194 else if(config.mirror_vertical && !config.mirror_horizontal && !config.mirror_swapvertical) \
196 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
198 input_row = input_rows[i]; \
199 output_row = output_rows[j]; \
200 for(k = 0; k < w; k++) \
202 SWAPCOPY_PIXELS(components, output_row, input_row); \
203 output_row += components; \
204 input_row += components; \
208 /* VERTICAL SWAP ONLY */ \
209 else if(config.mirror_vertical && !config.mirror_horizontal && config.mirror_swapvertical) \
211 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
213 input_row = input_rows[i]; \
214 output_row = output_rows[j]; \
215 for(k = 0; k < w; k++) \
217 SWAPCOPY_PIXELS(components, input_row, output_row); \
218 output_row += components; \
219 input_row += components; \
223 /* HORIZONTAL and VERTICAL */ \
224 else if(config.mirror_horizontal && config.mirror_vertical && !config.mirror_swaphorizontal && !config.mirror_swapvertical) \
226 /* HORIZONTAL ONLY */ \
227 for(i = 0; i < h; i++) \
229 input_row = input_rows[i]; \
230 output_row = output_rows[i] + (w - 1) * components; \
231 for(k = 0; k < w / 2; k++) \
233 SWAPCOPY_PIXELS(components, output_row, input_row); \
234 input_row += components; \
235 output_row -= components; \
238 /* VERTICAL ONLY */ \
239 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
241 input_row = input_rows[i]; \
242 output_row = output_rows[j]; \
243 for(k = 0; k < w; k++) \
245 SWAPCOPY_PIXELS(components, output_row, input_row); \
246 output_row += components; \
247 input_row += components; \
251 /* HORIZONTAL with SWAP and VERTICAL with SWAP */ \
252 else if(config.mirror_horizontal && config.mirror_vertical && config.mirror_swaphorizontal && config.mirror_swapvertical) \
254 /* HORIZONTAL SWAP ONLY */ \
255 for(i = 0; i < h; i++) \
257 input_row = input_rows[i]; \
258 output_row = output_rows[i] + (w - 1) * components; \
259 for(k = 0; k < w / 2; k++) \
261 SWAPCOPY_PIXELS(components, input_row, output_row); \
262 input_row += components; \
263 output_row -= components; \
266 /* VERTICAL SWAP ONLY */ \
267 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
269 input_row = input_rows[i]; \
270 output_row = output_rows[j]; \
271 for(k = 0; k < w; k++) \
273 SWAPCOPY_PIXELS(components, input_row, output_row); \
274 output_row += components; \
275 input_row += components; \
279 /* HORIZONTAL with SWAP and VERTICAL ONLY */ \
280 else if(config.mirror_horizontal && config.mirror_vertical && config.mirror_swaphorizontal && !config.mirror_swapvertical) \
282 /* HORIZONTAL SWAP ONLY */ \
283 for(i = 0; i < h; i++) \
285 input_row = input_rows[i]; \
286 output_row = output_rows[i] + (w - 1) * components; \
287 for(k = 0; k < w / 2; k++) \
289 SWAPCOPY_PIXELS(components, input_row, output_row); \
290 input_row += components; \
291 output_row -= components; \
294 /* VERTICAL ONLY */ \
295 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
297 input_row = input_rows[i]; \
298 output_row = output_rows[j]; \
299 for(k = 0; k < w; k++) \
301 SWAPCOPY_PIXELS(components, output_row, input_row); \
302 output_row += components; \
303 input_row += components; \
307 /* HORIZONTAL ONLY and VERTICAL with SWAP */ \
308 else if(config.mirror_horizontal && config.mirror_vertical && !config.mirror_swaphorizontal && config.mirror_swapvertical) \
310 /* HORIZONTAL ONLY */ \
311 for(i = 0; i < h; i++) \
313 input_row = input_rows[i]; \
314 output_row = output_rows[i] + (w - 1) * components; \
315 for(k = 0; k < w / 2; k++) \
317 SWAPCOPY_PIXELS(components, output_row, input_row); \
318 input_row += components; \
319 output_row -= components; \
322 /* VERTICAL SWAP ONLY */ \
323 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
325 input_row = input_rows[i]; \
326 output_row = output_rows[j]; \
327 for(k = 0; k < w; k++) \
329 SWAPCOPY_PIXELS(components, input_row, output_row); \
330 output_row += components; \
331 input_row += components; \
337 else if(config.reflection_center_enable) \
339 if(config.mirror_vertical) \
341 int y_pixel = (int)round(config.reflection_center_y / 100.00 * h); \
342 if(config.reflection_center_y < 50.00) \
344 int valueY_source = y_pixel + 1; \
345 int valueY_destination = y_pixel - 1; \
346 for(int i = 0; i < y_pixel; i++) \
348 input_row = input_rows[valueY_source]; \
349 output_row = output_rows[valueY_destination]; \
350 for(k = 0; k < w; k++) \
352 SWAPCOPY_PIXELS(components, output_row, input_row); \
353 output_row += components; \
354 input_row += components; \
356 valueY_source += 1; \
357 valueY_destination -= 1; \
360 else if(config.reflection_center_y > 50.00) \
362 int valueY_source = y_pixel - 1; \
363 int valueY_destination = y_pixel + 1; \
364 for(int i = 0; i < (h - y_pixel - 1); i++) \
366 input_row = input_rows[valueY_source]; \
367 output_row = output_rows[valueY_destination]; \
368 for(k = 0; k < w; k++) \
370 SWAPCOPY_PIXELS(components, output_row, input_row); \
371 output_row += components; \
372 input_row += components; \
374 valueY_source -= 1; \
375 valueY_destination += 1; \
378 else /* Y_PERCENT == 50.00 */ \
380 for(i = 0, j = h - 1; i < h / 2; i++, j--) \
382 input_row = input_rows[i]; \
383 output_row = output_rows[j]; \
384 for(k = 0; k < w; k++) \
386 SWAPCOPY_PIXELS(components, output_row, input_row); \
387 output_row += components; \
388 input_row += components; \
394 if(config.mirror_horizontal) \
396 int x_pixel = (int)round(config.reflection_center_x / 100.00 * w); \
397 if(config.reflection_center_x < 50.00) \
399 int valueX_source = x_pixel + 1; \
400 int valueX_destination = x_pixel - 1; \
401 for(i = 0; i < h; i++) \
403 input_row = input_rows[i] + valueX_source * components; \
404 output_row = output_rows[i] + valueX_destination * components; \
405 for(k = 0; k < x_pixel; k++) \
407 SWAPCOPY_PIXELS(components, output_row, input_row); \
408 output_row -= components; \
409 input_row += components; \
413 else if(config.reflection_center_x > 50.00) \
415 int valueX_source = x_pixel - 1; \
416 int valueX_destination = x_pixel + 1; \
417 for(i = 0; i < h; i++) \
419 input_row = input_rows[i] + valueX_source * components; \
420 output_row = output_rows[i] + valueX_destination * components; \
421 for(k = 0; k < (w - x_pixel - 1); k++) \
423 SWAPCOPY_PIXELS(components, output_row, input_row); \
424 output_row += components; \
425 input_row -= components; \
429 else /* X_PERCENT == 50.00 */ \
431 for(i = 0; i < h; i++) \
433 input_row = input_rows[i]; \
434 output_row = output_rows[i] + (w - 1) * components; \
435 for(k = 0; k < w / 2; k++) \
437 SWAPCOPY_PIXELS(components, output_row, input_row); \
438 input_row += components; \
439 output_row -= components; \
447 int MirrorMain::process_buffer(VFrame *frame,
448 int64_t start_position,
452 int w = frame->get_w();
453 int h = frame->get_h();
454 int colormodel = frame->get_color_model();
456 load_configuration();
458 // THIS CODE WAS FOR the FLIP Plugin!!!
462 get_source_position(),
468 if(config.mirror_vertical || config.mirror_horizontal)
480 if(config.mirror_vertical || config.mirror_horizontal)
486 MIRROR_MACRO(unsigned char, 3);
489 MIRROR_MACRO(float, 3);
493 MIRROR_MACRO(uint16_t, 3);
497 MIRROR_MACRO(unsigned char, 4);
500 MIRROR_MACRO(float, 4);
502 case BC_RGBA16161616:
503 case BC_YUVA16161616:
504 MIRROR_MACRO(uint16_t, 4);
512 NEW_WINDOW_MACRO(MirrorMain, MirrorWindow)
513 LOAD_CONFIGURATION_MACRO(MirrorMain, MirrorConfig)
515 void MirrorMain::update_gui()
519 load_configuration();
520 thread->window->lock_window();
521 ((MirrorWindow*)thread->window)->mirror_horizontal->update((int)config.mirror_horizontal);
522 ((MirrorWindow*)thread->window)->mirror_swaphorizontal->update((int)config.mirror_swaphorizontal);
523 ((MirrorWindow*)thread->window)->mirror_vertical->update((int)config.mirror_vertical);
524 ((MirrorWindow*)thread->window)->mirror_swapvertical->update((int)config.mirror_swapvertical);
525 ((MirrorWindow*)thread->window)->reflection_center_enable->update(config.reflection_center_enable);
526 ((MirrorWindow*)thread->window)->reflection_center_x_text->update(config.reflection_center_x);
527 ((MirrorWindow*)thread->window)->reflection_center_x_slider->update(config.reflection_center_x);
528 ((MirrorWindow*)thread->window)->reflection_center_y_text->update(config.reflection_center_y);
529 ((MirrorWindow*)thread->window)->reflection_center_y_slider->update(config.reflection_center_y);
530 // Needed to update Enable-Disable GUI when "Show controls" is pressed.
531 ((MirrorWindow*)thread->window)->update_reflection_center_enable();
532 thread->window->unlock_window();
536 void MirrorMain::save_data(KeyFrame *keyframe)
540 // cause data to be stored directly in text
541 output.set_shared_output(keyframe->xbuf);
544 output.tag.set_title("MIRROR");
545 output.tag.set_property("HORIZONTAL", config.mirror_horizontal);
546 output.tag.set_property("SWAP_HORIZONTAL", config.mirror_swaphorizontal);
547 output.tag.set_property("VERTICAL", config.mirror_vertical);
548 output.tag.set_property("SWAP_VERTICAL", config.mirror_swapvertical);
549 output.tag.set_property("REFLECTION_CENTER_ENABLE", config.reflection_center_enable);
550 output.tag.set_property("REFLECTION_CENTER_X", config.reflection_center_x);
551 output.tag.set_property("REFLECTION_CENTER_Y", config.reflection_center_y);
553 output.tag.set_title("/MIRROR");
555 output.append_newline();
556 output.terminate_string();
557 // data is now in *text
560 void MirrorMain::read_data(KeyFrame *keyframe)
564 input.set_shared_input(keyframe->xbuf);
567 config.mirror_vertical = config.mirror_horizontal = 0;
568 config.mirror_swapvertical = config.mirror_swaphorizontal = 0;
572 result = input.read_tag();
576 if(input.tag.title_is("MIRROR"))
578 config.mirror_horizontal = input.tag.get_property("HORIZONTAL", config.mirror_horizontal);
579 config.mirror_swaphorizontal = input.tag.get_property("SWAP_HORIZONTAL", config.mirror_swaphorizontal);
580 config.mirror_vertical = input.tag.get_property("VERTICAL", config.mirror_vertical);
581 config.mirror_swapvertical = input.tag.get_property("SWAP_VERTICAL", config.mirror_swapvertical);
582 config.reflection_center_enable = input.tag.get_property("REFLECTION_CENTER_ENABLE", config.reflection_center_enable);
583 config.reflection_center_x = input.tag.get_property("REFLECTION_CENTER_X", config.reflection_center_x);
584 config.reflection_center_y = input.tag.get_property("REFLECTION_CENTER_Y", config.reflection_center_y);
591 int MirrorMain::handle_opengl()
594 // FIXIT. When?! ... THIS CODE WAS FOR the FLIP Plugin!!!
596 get_output()->to_texture();
597 get_output()->enable_opengl();
598 get_output()->init_screen();
599 get_output()->bind_texture(0);
601 if(config.mirror_vertical && !config.mirror_horizontal)
603 get_output()->draw_texture(0,
605 get_output()->get_w(),
606 get_output()->get_h(),
608 get_output()->get_h(),
609 get_output()->get_w(),
613 if(config.mirror_horizontal && !config.mirror_vertical)
615 get_output()->draw_texture(0,
617 get_output()->get_w(),
618 get_output()->get_h(),
619 get_output()->get_w(),
622 get_output()->get_h());
625 if(config.mirror_vertical && config.mirror_horizontal)
627 get_output()->draw_texture(0,
629 get_output()->get_w(),
630 get_output()->get_h(),
631 get_output()->get_w(),
632 get_output()->get_h(),
637 get_output()->set_opengl_state(VFrame::SCREEN);