1 #include "../motion/affine.h"
4 #include "perspective.h"
12 REGISTER_PLUGIN(PerspectiveMain)
16 PerspectiveConfig::PerspectiveConfig()
26 mode = AffineEngine::PERSPECTIVE;
33 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
45 forward == that.forward;
48 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
59 window_w = that.window_w;
60 window_h = that.window_h;
61 current_point = that.current_point;
62 forward = that.forward;
65 void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
66 PerspectiveConfig &next,
69 int64_t current_frame)
71 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
72 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
73 this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
74 this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
75 this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
76 this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
77 this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
78 this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
79 this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
80 this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
82 forward = prev.forward;
93 PLUGIN_THREAD_OBJECT(PerspectiveMain, PerspectiveThread, PerspectiveWindow)
97 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin, int x, int y)
98 : BC_Window(plugin->gui_string,
101 plugin->config.window_w,
102 plugin->config.window_h,
103 plugin->config.window_w,
104 plugin->config.window_h,
108 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
109 this->plugin = plugin;
112 PerspectiveWindow::~PerspectiveWindow()
116 int PerspectiveWindow::create_objects()
120 add_subwindow(canvas = new PerspectiveCanvas(plugin,
125 canvas->set_cursor(CROSS_CURSOR);
126 y += canvas->get_h() + 10;
127 add_subwindow(new BC_Title(x, y, _("Current X:")));
129 this->x = new PerspectiveCoord(this,
133 plugin->get_current_x(),
135 this->x->create_objects();
137 add_subwindow(new BC_Title(x, y, _("Y:")));
139 this->y = new PerspectiveCoord(this,
143 plugin->get_current_y(),
145 this->y->create_objects();
148 add_subwindow(new PerspectiveReset(plugin, x, y));
150 add_subwindow(mode_perspective = new PerspectiveMode(plugin,
153 AffineEngine::PERSPECTIVE,
156 add_subwindow(mode_sheer = new PerspectiveMode(plugin,
163 add_subwindow(mode_stretch = new PerspectiveMode(plugin,
166 AffineEngine::STRETCH,
171 add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
173 add_subwindow(forward = new PerspectiveDirection(plugin,
179 add_subwindow(reverse = new PerspectiveDirection(plugin,
190 WINDOW_CLOSE_EVENT(PerspectiveWindow)
192 int PerspectiveWindow::resize_event(int w, int h)
197 void PerspectiveWindow::update_canvas()
199 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
200 int x1, y1, x2, y2, x3, y3, x4, y4;
201 calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
203 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
212 canvas->set_color(BLACK);
215 for(int i = 0; i <= DIVISIONS; i++)
219 x1 + (x4 - x1) * i / DIVISIONS,
220 y1 + (y4 - y1) * i / DIVISIONS,
221 x2 + (x3 - x2) * i / DIVISIONS,
222 y2 + (y3 - y2) * i / DIVISIONS);
225 x1 + (x2 - x1) * i / DIVISIONS,
226 y1 + (y2 - y1) * i / DIVISIONS,
227 x4 + (x3 - x4) * i / DIVISIONS,
228 y4 + (y3 - y4) * i / DIVISIONS);
233 if(plugin->config.current_point == 0)
234 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
236 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
238 if(plugin->config.current_point == 1)
239 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
241 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
243 if(plugin->config.current_point == 2)
244 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
246 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
248 if(plugin->config.current_point == 3)
249 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
251 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
257 void PerspectiveWindow::update_mode()
259 mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
260 mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
261 mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
262 forward->update(plugin->config.forward);
263 reverse->update(!plugin->config.forward);
266 void PerspectiveWindow::update_coord()
268 x->update(plugin->get_current_x());
269 y->update(plugin->get_current_y());
272 void PerspectiveWindow::calculate_canvas_coords(int &x1,
281 int w = canvas->get_w() - 1;
282 int h = canvas->get_h() - 1;
283 if(plugin->config.mode == AffineEngine::PERSPECTIVE ||
284 plugin->config.mode == AffineEngine::STRETCH)
286 x1 = (int)(plugin->config.x1 * w / 100);
287 y1 = (int)(plugin->config.y1 * h / 100);
288 x2 = (int)(plugin->config.x2 * w / 100);
289 y2 = (int)(plugin->config.y2 * h / 100);
290 x3 = (int)(plugin->config.x3 * w / 100);
291 y3 = (int)(plugin->config.y3 * h / 100);
292 x4 = (int)(plugin->config.x4 * w / 100);
293 y4 = (int)(plugin->config.y4 * h / 100);
297 x1 = (int)(plugin->config.x1 * w) / 100;
301 x4 = (int)(plugin->config.x4 * w) / 100;
311 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
316 : BC_SubWindow(x, y, w, h, 0xffffff)
318 this->plugin = plugin;
319 state = PerspectiveCanvas::NONE;
325 int PerspectiveCanvas::button_press_event()
327 if(is_event_win() && cursor_inside())
330 int x1, y1, x2, y2, x3, y3, x4, y4;
331 int cursor_x = get_cursor_x();
332 int cursor_y = get_cursor_y();
333 plugin->thread->window->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
335 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
336 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
337 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
338 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
339 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n",
345 float min = distance1;
346 plugin->config.current_point = 0;
350 plugin->config.current_point = 1;
355 plugin->config.current_point = 2;
360 plugin->config.current_point = 3;
363 if(plugin->config.mode == AffineEngine::SHEER)
365 if(plugin->config.current_point == 1)
366 plugin->config.current_point = 0;
368 if(plugin->config.current_point == 2)
369 plugin->config.current_point = 3;
371 start_cursor_x = cursor_x;
372 start_cursor_y = cursor_y;
374 if(alt_down() || shift_down())
377 state = PerspectiveCanvas::DRAG_FULL;
379 state = PerspectiveCanvas::ZOOM;
381 // Get starting positions
382 start_x1 = plugin->config.x1;
383 start_y1 = plugin->config.y1;
384 start_x2 = plugin->config.x2;
385 start_y2 = plugin->config.y2;
386 start_x3 = plugin->config.x3;
387 start_y3 = plugin->config.y3;
388 start_x4 = plugin->config.x4;
389 start_y4 = plugin->config.y4;
393 state = PerspectiveCanvas::DRAG;
395 // Get starting positions
396 start_x1 = plugin->get_current_x();
397 start_y1 = plugin->get_current_y();
399 plugin->thread->window->update_coord();
400 plugin->thread->window->update_canvas();
407 int PerspectiveCanvas::button_release_event()
409 if(state != PerspectiveCanvas::NONE)
411 state = PerspectiveCanvas::NONE;
417 int PerspectiveCanvas::cursor_motion_event()
419 if(state != PerspectiveCanvas::NONE)
423 if(state == PerspectiveCanvas::DRAG)
425 plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
426 plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
429 if(state == PerspectiveCanvas::DRAG_FULL)
431 plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
432 plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
433 plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
434 plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
435 plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
436 plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
437 plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
438 plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
441 if(state == PerspectiveCanvas::ZOOM)
443 float center_x = (start_x1 +
447 float center_y = (start_y1 +
451 float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
452 plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
453 plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
454 plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
455 plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
456 plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
457 plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
458 plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
459 plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
461 plugin->thread->window->update_canvas();
462 plugin->thread->window->update_coord();
463 plugin->send_configure_change();
475 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
476 PerspectiveMain *plugin,
481 : BC_TumbleTextBox(gui, value, (float)0, (float)100, x, y, 100)
483 this->plugin = plugin;
487 int PerspectiveCoord::handle_event()
490 plugin->set_current_x(atof(get_text()));
492 plugin->set_current_y(atof(get_text()));
493 plugin->thread->window->update_canvas();
494 plugin->send_configure_change();
505 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin,
508 : BC_GenericButton(x, y, _("Reset"))
510 this->plugin = plugin;
512 int PerspectiveReset::handle_event()
514 plugin->config.x1 = 0;
515 plugin->config.y1 = 0;
516 plugin->config.x2 = 100;
517 plugin->config.y2 = 0;
518 plugin->config.x3 = 100;
519 plugin->config.y3 = 100;
520 plugin->config.x4 = 0;
521 plugin->config.y4 = 100;
522 plugin->thread->window->update_canvas();
523 plugin->thread->window->update_coord();
524 plugin->send_configure_change();
538 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin,
543 : BC_Radial(x, y, plugin->config.mode == value, text)
545 this->plugin = plugin;
548 int PerspectiveMode::handle_event()
550 plugin->config.mode = value;
551 plugin->thread->window->update_mode();
552 plugin->thread->window->update_canvas();
553 plugin->send_configure_change();
560 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin,
565 : BC_Radial(x, y, plugin->config.forward == value, text)
567 this->plugin = plugin;
570 int PerspectiveDirection::handle_event()
572 plugin->config.forward = value;
573 plugin->thread->window->update_mode();
574 plugin->send_configure_change();
589 PerspectiveMain::PerspectiveMain(PluginServer *server)
590 : PluginVClient(server)
592 PLUGIN_CONSTRUCTOR_MACRO
597 PerspectiveMain::~PerspectiveMain()
599 PLUGIN_DESTRUCTOR_MACRO
600 if(engine) delete engine;
601 if(temp) delete temp;
604 char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
605 int PerspectiveMain::is_realtime() { return 1; }
608 NEW_PICON_MACRO(PerspectiveMain)
610 SHOW_GUI_MACRO(PerspectiveMain, PerspectiveThread)
612 SET_STRING_MACRO(PerspectiveMain)
614 RAISE_WINDOW_MACRO(PerspectiveMain)
616 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
620 void PerspectiveMain::update_gui()
624 //printf("PerspectiveMain::update_gui 1\n");
625 thread->window->lock_window();
626 //printf("PerspectiveMain::update_gui 2\n");
627 load_configuration();
628 thread->window->update_coord();
629 thread->window->update_mode();
630 thread->window->update_canvas();
631 thread->window->unlock_window();
632 //printf("PerspectiveMain::update_gui 3\n");
637 int PerspectiveMain::load_defaults()
639 char directory[1024], string[1024];
640 // set the default directory
641 sprintf(directory, "%sperspective.rc", BCASTDIR);
644 defaults = new BC_Hash(directory);
647 config.x1 = defaults->get("X1", config.x1);
648 config.x2 = defaults->get("X2", config.x2);
649 config.x3 = defaults->get("X3", config.x3);
650 config.x4 = defaults->get("X4", config.x4);
651 config.y1 = defaults->get("Y1", config.y1);
652 config.y2 = defaults->get("Y2", config.y2);
653 config.y3 = defaults->get("Y3", config.y3);
654 config.y4 = defaults->get("Y4", config.y4);
656 config.mode = defaults->get("MODE", config.mode);
657 config.forward = defaults->get("FORWARD", config.forward);
658 config.window_w = defaults->get("WINDOW_W", config.window_w);
659 config.window_h = defaults->get("WINDOW_H", config.window_h);
664 int PerspectiveMain::save_defaults()
666 defaults->update("X1", config.x1);
667 defaults->update("X2", config.x2);
668 defaults->update("X3", config.x3);
669 defaults->update("X4", config.x4);
670 defaults->update("Y1", config.y1);
671 defaults->update("Y2", config.y2);
672 defaults->update("Y3", config.y3);
673 defaults->update("Y4", config.y4);
675 defaults->update("MODE", config.mode);
676 defaults->update("FORWARD", config.forward);
677 defaults->update("WINDOW_W", config.window_w);
678 defaults->update("WINDOW_H", config.window_h);
685 void PerspectiveMain::save_data(KeyFrame *keyframe)
689 // cause data to be stored directly in text
690 output.set_shared_string(keyframe->data, MESSAGESIZE);
691 output.tag.set_title("PERSPECTIVE");
693 output.tag.set_property("X1", config.x1);
694 output.tag.set_property("X2", config.x2);
695 output.tag.set_property("X3", config.x3);
696 output.tag.set_property("X4", config.x4);
697 output.tag.set_property("Y1", config.y1);
698 output.tag.set_property("Y2", config.y2);
699 output.tag.set_property("Y3", config.y3);
700 output.tag.set_property("Y4", config.y4);
702 output.tag.set_property("MODE", config.mode);
703 output.tag.set_property("FORWARD", config.forward);
704 output.tag.set_property("WINDOW_W", config.window_w);
705 output.tag.set_property("WINDOW_H", config.window_h);
707 output.terminate_string();
710 void PerspectiveMain::read_data(KeyFrame *keyframe)
714 input.set_shared_string(keyframe->data, strlen(keyframe->data));
720 result = input.read_tag();
724 if(input.tag.title_is("PERSPECTIVE"))
726 config.x1 = input.tag.get_property("X1", config.x1);
727 config.x2 = input.tag.get_property("X2", config.x2);
728 config.x3 = input.tag.get_property("X3", config.x3);
729 config.x4 = input.tag.get_property("X4", config.x4);
730 config.y1 = input.tag.get_property("Y1", config.y1);
731 config.y2 = input.tag.get_property("Y2", config.y2);
732 config.y3 = input.tag.get_property("Y3", config.y3);
733 config.y4 = input.tag.get_property("Y4", config.y4);
735 config.mode = input.tag.get_property("MODE", config.mode);
736 config.forward = input.tag.get_property("FORWARD", config.forward);
737 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
738 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
744 float PerspectiveMain::get_current_x()
746 switch(config.current_point)
763 float PerspectiveMain::get_current_y()
765 switch(config.current_point)
782 void PerspectiveMain::set_current_x(float value)
784 switch(config.current_point)
801 void PerspectiveMain::set_current_y(float value)
803 switch(config.current_point)
822 int PerspectiveMain::process_buffer(VFrame *frame,
823 int64_t start_position,
826 int need_reconfigure = load_configuration();
830 if( EQUIV(config.x1, 0) && EQUIV(config.y1, 0) &&
831 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
832 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
833 EQUIV(config.x4, 0) && EQUIV(config.y4, 100))
843 // Opengl does some funny business with stretching.
844 int use_opengl = get_use_opengl() &&
845 (config.mode == AffineEngine::PERSPECTIVE ||
846 config.mode == AffineEngine::SHEER);
853 if(!engine) engine = new AffineEngine(get_project_smp() + 1,
854 get_project_smp() + 1);
862 this->output = frame;
864 int w = frame->get_w();
865 int h = frame->get_h();
866 int color_model = frame->get_color_model();
869 config.mode == AffineEngine::STRETCH &&
870 (temp->get_w() != w * AFFINE_OVERSAMPLE ||
871 temp->get_h() != h * AFFINE_OVERSAMPLE))
878 (config.mode == AffineEngine::PERSPECTIVE ||
879 config.mode == AffineEngine::SHEER) &&
880 (temp->get_w() != w ||
887 if(config.mode == AffineEngine::STRETCH)
892 w * AFFINE_OVERSAMPLE,
893 h * AFFINE_OVERSAMPLE,
899 if(config.mode == AffineEngine::PERSPECTIVE ||
900 config.mode == AffineEngine::SHEER)
902 if(frame->get_rows()[0] == frame->get_rows()[0])
911 temp->copy_from(input);
914 output->clear_frame();
918 engine->process(output,
937 if(config.mode == AffineEngine::STRETCH)
939 #define RESAMPLE(type, components, chroma_offset) \
941 for(int i = 0; i < h; i++) \
943 type *out_row = (type*)output->get_rows()[i]; \
944 type *in_row1 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE]; \
945 type *in_row2 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE + 1]; \
946 for(int j = 0; j < w; j++) \
948 out_row[0] = (in_row1[0] + \
949 in_row1[components] + \
951 in_row2[components]) / \
952 AFFINE_OVERSAMPLE / \
954 out_row[1] = ((in_row1[1] + \
955 in_row1[components + 1] + \
957 in_row2[components + 1]) - \
959 AFFINE_OVERSAMPLE * \
960 AFFINE_OVERSAMPLE) / \
961 AFFINE_OVERSAMPLE / \
962 AFFINE_OVERSAMPLE + \
964 out_row[2] = ((in_row1[2] + \
965 in_row1[components + 2] + \
967 in_row2[components + 2]) - \
969 AFFINE_OVERSAMPLE * \
970 AFFINE_OVERSAMPLE) / \
971 AFFINE_OVERSAMPLE / \
972 AFFINE_OVERSAMPLE + \
974 if(components == 4) \
976 out_row[3] = (in_row1[3] + \
977 in_row1[components + 3] + \
979 in_row2[components + 3]) / \
980 AFFINE_OVERSAMPLE / \
983 out_row += components; \
984 in_row1 += components * AFFINE_OVERSAMPLE; \
985 in_row2 += components * AFFINE_OVERSAMPLE; \
990 switch(frame->get_color_model())
993 RESAMPLE(float, 3, 0)
996 RESAMPLE(unsigned char, 3, 0)
999 RESAMPLE(float, 4, 0)
1002 RESAMPLE(unsigned char, 4, 0)
1005 RESAMPLE(unsigned char, 3, 0x80)
1008 RESAMPLE(unsigned char, 4, 0x80)
1011 RESAMPLE(uint16_t, 3, 0)
1013 case BC_RGBA16161616:
1014 RESAMPLE(uint16_t, 4, 0)
1017 RESAMPLE(uint16_t, 3, 0x8000)
1019 case BC_YUVA16161616:
1020 RESAMPLE(uint16_t, 4, 0x8000)
1029 int PerspectiveMain::handle_opengl()
1032 engine->set_opengl(1);
1033 engine->process(get_output(),
1046 engine->set_opengl(0);