3 #include "perspective.h"
11 REGISTER_PLUGIN(PerspectiveMain)
15 PerspectiveConfig::PerspectiveConfig()
32 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
44 forward == that.forward;
47 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
58 window_w = that.window_w;
59 window_h = that.window_h;
60 current_point = that.current_point;
61 forward = that.forward;
64 void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
65 PerspectiveConfig &next,
68 int64_t current_frame)
70 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
71 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
72 this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
73 this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
74 this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
75 this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
76 this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
77 this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
78 this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
79 this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
81 forward = prev.forward;
92 PLUGIN_THREAD_OBJECT(PerspectiveMain, PerspectiveThread, PerspectiveWindow)
96 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin, int x, int y)
97 : BC_Window(plugin->gui_string,
100 plugin->config.window_w,
101 plugin->config.window_h,
102 plugin->config.window_w,
103 plugin->config.window_h,
107 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
108 this->plugin = plugin;
111 PerspectiveWindow::~PerspectiveWindow()
115 int PerspectiveWindow::create_objects()
119 add_subwindow(canvas = new PerspectiveCanvas(plugin,
124 canvas->set_cursor(CROSS_CURSOR);
125 y += canvas->get_h() + 10;
126 add_subwindow(new BC_Title(x, y, _("Current X:")));
128 this->x = new PerspectiveCoord(this,
132 plugin->get_current_x(),
134 this->x->create_objects();
136 add_subwindow(new BC_Title(x, y, _("Y:")));
138 this->y = new PerspectiveCoord(this,
142 plugin->get_current_y(),
144 this->y->create_objects();
147 add_subwindow(new PerspectiveReset(plugin, x, y));
149 add_subwindow(mode_perspective = new PerspectiveMode(plugin,
152 PerspectiveConfig::PERSPECTIVE,
155 add_subwindow(mode_sheer = new PerspectiveMode(plugin,
158 PerspectiveConfig::SHEER,
162 add_subwindow(mode_stretch = new PerspectiveMode(plugin,
165 PerspectiveConfig::STRETCH,
170 add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
172 add_subwindow(forward = new PerspectiveDirection(plugin,
178 add_subwindow(reverse = new PerspectiveDirection(plugin,
189 WINDOW_CLOSE_EVENT(PerspectiveWindow)
191 int PerspectiveWindow::resize_event(int w, int h)
196 void PerspectiveWindow::update_canvas()
198 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
199 int x1, y1, x2, y2, x3, y3, x4, y4;
200 calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
202 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
211 canvas->set_color(BLACK);
214 for(int i = 0; i <= DIVISIONS; i++)
218 x1 + (x4 - x1) * i / DIVISIONS,
219 y1 + (y4 - y1) * i / DIVISIONS,
220 x2 + (x3 - x2) * i / DIVISIONS,
221 y2 + (y3 - y2) * i / DIVISIONS);
224 x1 + (x2 - x1) * i / DIVISIONS,
225 y1 + (y2 - y1) * i / DIVISIONS,
226 x4 + (x3 - x4) * i / DIVISIONS,
227 y4 + (y3 - y4) * i / DIVISIONS);
232 if(plugin->config.current_point == 0)
233 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
235 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
237 if(plugin->config.current_point == 1)
238 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
240 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
242 if(plugin->config.current_point == 2)
243 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
245 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
247 if(plugin->config.current_point == 3)
248 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
250 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
256 void PerspectiveWindow::update_mode()
258 mode_perspective->update(plugin->config.mode == PerspectiveConfig::PERSPECTIVE);
259 mode_sheer->update(plugin->config.mode == PerspectiveConfig::SHEER);
260 mode_stretch->update(plugin->config.mode == PerspectiveConfig::STRETCH);
261 forward->update(plugin->config.forward);
262 reverse->update(!plugin->config.forward);
265 void PerspectiveWindow::update_coord()
267 x->update(plugin->get_current_x());
268 y->update(plugin->get_current_y());
271 void PerspectiveWindow::calculate_canvas_coords(int &x1,
280 int w = canvas->get_w() - 1;
281 int h = canvas->get_h() - 1;
282 if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
283 plugin->config.mode == PerspectiveConfig::STRETCH)
285 x1 = (int)(plugin->config.x1 * w / 100);
286 y1 = (int)(plugin->config.y1 * h / 100);
287 x2 = (int)(plugin->config.x2 * w / 100);
288 y2 = (int)(plugin->config.y2 * h / 100);
289 x3 = (int)(plugin->config.x3 * w / 100);
290 y3 = (int)(plugin->config.y3 * h / 100);
291 x4 = (int)(plugin->config.x4 * w / 100);
292 y4 = (int)(plugin->config.y4 * h / 100);
296 x1 = (int)(plugin->config.x1 * w) / 100;
300 x4 = (int)(plugin->config.x4 * w) / 100;
310 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
315 : BC_SubWindow(x, y, w, h, 0xffffff)
317 this->plugin = plugin;
318 state = PerspectiveCanvas::NONE;
323 #define DISTANCE(x1, y1, x2, y2) \
324 (sqrt(((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1))))
326 int PerspectiveCanvas::button_press_event()
328 if(is_event_win() && cursor_inside())
331 int x1, y1, x2, y2, x3, y3, x4, y4;
332 int cursor_x = get_cursor_x();
333 int cursor_y = get_cursor_y();
334 plugin->thread->window->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
336 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
337 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
338 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
339 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
340 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n",
346 float min = distance1;
347 plugin->config.current_point = 0;
351 plugin->config.current_point = 1;
356 plugin->config.current_point = 2;
361 plugin->config.current_point = 3;
364 if(plugin->config.mode == PerspectiveConfig::SHEER)
366 if(plugin->config.current_point == 1)
367 plugin->config.current_point = 0;
369 if(plugin->config.current_point == 2)
370 plugin->config.current_point = 3;
372 start_cursor_x = cursor_x;
373 start_cursor_y = cursor_y;
375 if(alt_down() || shift_down())
378 state = PerspectiveCanvas::DRAG_FULL;
380 state = PerspectiveCanvas::ZOOM;
382 // Get starting positions
383 start_x1 = plugin->config.x1;
384 start_y1 = plugin->config.y1;
385 start_x2 = plugin->config.x2;
386 start_y2 = plugin->config.y2;
387 start_x3 = plugin->config.x3;
388 start_y3 = plugin->config.y3;
389 start_x4 = plugin->config.x4;
390 start_y4 = plugin->config.y4;
394 state = PerspectiveCanvas::DRAG;
396 // Get starting positions
397 start_x1 = plugin->get_current_x();
398 start_y1 = plugin->get_current_y();
400 plugin->thread->window->update_coord();
401 plugin->thread->window->update_canvas();
408 int PerspectiveCanvas::button_release_event()
410 if(state != PerspectiveCanvas::NONE)
412 state = PerspectiveCanvas::NONE;
418 int PerspectiveCanvas::cursor_motion_event()
420 if(state != PerspectiveCanvas::NONE)
424 if(state == PerspectiveCanvas::DRAG)
426 plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
427 plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
430 if(state == PerspectiveCanvas::DRAG_FULL)
432 plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
433 plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
434 plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
435 plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
436 plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
437 plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
438 plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
439 plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
442 if(state == PerspectiveCanvas::ZOOM)
444 float center_x = (start_x1 +
448 float center_y = (start_y1 +
452 float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
453 plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
454 plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
455 plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
456 plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
457 plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
458 plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
459 plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
460 plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
462 plugin->thread->window->update_canvas();
463 plugin->thread->window->update_coord();
464 plugin->send_configure_change();
476 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
477 PerspectiveMain *plugin,
482 : BC_TumbleTextBox(gui, value, (float)0, (float)100, x, y, 100)
484 this->plugin = plugin;
488 int PerspectiveCoord::handle_event()
491 plugin->set_current_x(atof(get_text()));
493 plugin->set_current_y(atof(get_text()));
494 plugin->thread->window->update_canvas();
495 plugin->send_configure_change();
506 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin,
509 : BC_GenericButton(x, y, _("Reset"))
511 this->plugin = plugin;
513 int PerspectiveReset::handle_event()
515 plugin->config.x1 = 0;
516 plugin->config.y1 = 0;
517 plugin->config.x2 = 100;
518 plugin->config.y2 = 0;
519 plugin->config.x3 = 100;
520 plugin->config.y3 = 100;
521 plugin->config.x4 = 0;
522 plugin->config.y4 = 100;
523 plugin->thread->window->update_canvas();
524 plugin->thread->window->update_coord();
525 plugin->send_configure_change();
539 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin,
544 : BC_Radial(x, y, plugin->config.mode == value, text)
546 this->plugin = plugin;
549 int PerspectiveMode::handle_event()
551 plugin->config.mode = value;
552 plugin->thread->window->update_mode();
553 plugin->thread->window->update_canvas();
554 plugin->send_configure_change();
561 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin,
566 : BC_Radial(x, y, plugin->config.forward == value, text)
568 this->plugin = plugin;
571 int PerspectiveDirection::handle_event()
573 plugin->config.forward = value;
574 plugin->thread->window->update_mode();
575 plugin->send_configure_change();
590 PerspectiveMain::PerspectiveMain(PluginServer *server)
591 : PluginVClient(server)
593 PLUGIN_CONSTRUCTOR_MACRO
598 PerspectiveMain::~PerspectiveMain()
600 PLUGIN_DESTRUCTOR_MACRO
601 if(engine) delete engine;
602 if(temp) delete temp;
605 char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
606 int PerspectiveMain::is_realtime() { return 1; }
609 NEW_PICON_MACRO(PerspectiveMain)
611 SHOW_GUI_MACRO(PerspectiveMain, PerspectiveThread)
613 SET_STRING_MACRO(PerspectiveMain)
615 RAISE_WINDOW_MACRO(PerspectiveMain)
617 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
621 void PerspectiveMain::update_gui()
625 //printf("PerspectiveMain::update_gui 1\n");
626 thread->window->lock_window();
627 //printf("PerspectiveMain::update_gui 2\n");
628 load_configuration();
629 thread->window->update_coord();
630 thread->window->update_mode();
631 thread->window->update_canvas();
632 thread->window->unlock_window();
633 //printf("PerspectiveMain::update_gui 3\n");
638 int PerspectiveMain::load_defaults()
640 char directory[1024], string[1024];
641 // set the default directory
642 sprintf(directory, "%sperspective.rc", BCASTDIR);
645 defaults = new Defaults(directory);
648 config.x1 = defaults->get("X1", config.x1);
649 config.x2 = defaults->get("X2", config.x2);
650 config.x3 = defaults->get("X3", config.x3);
651 config.x4 = defaults->get("X4", config.x4);
652 config.y1 = defaults->get("Y1", config.y1);
653 config.y2 = defaults->get("Y2", config.y2);
654 config.y3 = defaults->get("Y3", config.y3);
655 config.y4 = defaults->get("Y4", config.y4);
657 config.mode = defaults->get("MODE", config.mode);
658 config.forward = defaults->get("FORWARD", config.forward);
659 config.window_w = defaults->get("WINDOW_W", config.window_w);
660 config.window_h = defaults->get("WINDOW_H", config.window_h);
665 int PerspectiveMain::save_defaults()
667 defaults->update("X1", config.x1);
668 defaults->update("X2", config.x2);
669 defaults->update("X3", config.x3);
670 defaults->update("X4", config.x4);
671 defaults->update("Y1", config.y1);
672 defaults->update("Y2", config.y2);
673 defaults->update("Y3", config.y3);
674 defaults->update("Y4", config.y4);
676 defaults->update("MODE", config.mode);
677 defaults->update("FORWARD", config.forward);
678 defaults->update("WINDOW_W", config.window_w);
679 defaults->update("WINDOW_H", config.window_h);
686 void PerspectiveMain::save_data(KeyFrame *keyframe)
690 // cause data to be stored directly in text
691 output.set_shared_string(keyframe->data, MESSAGESIZE);
692 output.tag.set_title("PERSPECTIVE");
694 output.tag.set_property("X1", config.x1);
695 output.tag.set_property("X2", config.x2);
696 output.tag.set_property("X3", config.x3);
697 output.tag.set_property("X4", config.x4);
698 output.tag.set_property("Y1", config.y1);
699 output.tag.set_property("Y2", config.y2);
700 output.tag.set_property("Y3", config.y3);
701 output.tag.set_property("Y4", config.y4);
703 output.tag.set_property("MODE", config.mode);
704 output.tag.set_property("FORWARD", config.forward);
705 output.tag.set_property("WINDOW_W", config.window_w);
706 output.tag.set_property("WINDOW_H", config.window_h);
708 output.terminate_string();
711 void PerspectiveMain::read_data(KeyFrame *keyframe)
715 input.set_shared_string(keyframe->data, strlen(keyframe->data));
721 result = input.read_tag();
725 if(input.tag.title_is("PERSPECTIVE"))
727 config.x1 = input.tag.get_property("X1", config.x1);
728 config.x2 = input.tag.get_property("X2", config.x2);
729 config.x3 = input.tag.get_property("X3", config.x3);
730 config.x4 = input.tag.get_property("X4", config.x4);
731 config.y1 = input.tag.get_property("Y1", config.y1);
732 config.y2 = input.tag.get_property("Y2", config.y2);
733 config.y3 = input.tag.get_property("Y3", config.y3);
734 config.y4 = input.tag.get_property("Y4", config.y4);
736 config.mode = input.tag.get_property("MODE", config.mode);
737 config.forward = input.tag.get_property("FORWARD", config.forward);
738 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
739 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
745 float PerspectiveMain::get_current_x()
747 switch(config.current_point)
764 float PerspectiveMain::get_current_y()
766 switch(config.current_point)
783 void PerspectiveMain::set_current_x(float value)
785 switch(config.current_point)
802 void PerspectiveMain::set_current_y(float value)
804 switch(config.current_point)
823 int PerspectiveMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
825 int need_reconfigure = load_configuration();
828 if(!engine) engine = new PerspectiveEngine(this,
829 get_project_smp() + 1,
830 get_project_smp() + 1);
832 this->input = input_ptr;
833 this->output = output_ptr;
835 if( EQUIV(config.x1, 0) && EQUIV(config.y1, 0) &&
836 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
837 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
838 EQUIV(config.x4, 0) && EQUIV(config.y4, 100))
840 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
841 output_ptr->copy_from(input_ptr);
845 int w = input_ptr->get_w();
846 int h = input_ptr->get_h();
847 int color_model = input_ptr->get_color_model();
850 config.mode == PerspectiveConfig::STRETCH &&
851 (temp->get_w() != w * OVERSAMPLE ||
852 temp->get_h() != h * OVERSAMPLE))
859 (config.mode == PerspectiveConfig::PERSPECTIVE ||
860 config.mode == PerspectiveConfig::SHEER) &&
861 (temp->get_w() != w ||
868 if(config.mode == PerspectiveConfig::STRETCH)
880 if(config.mode == PerspectiveConfig::PERSPECTIVE ||
881 config.mode == PerspectiveConfig::SHEER)
883 if(input_ptr->get_rows()[0] == output_ptr->get_rows()[0])
892 temp->copy_from(input);
895 output->clear_frame();
900 engine->process_packages();
907 if(config.mode == PerspectiveConfig::STRETCH)
909 #define RESAMPLE(type, components, chroma_offset) \
911 for(int i = 0; i < h; i++) \
913 type *out_row = (type*)output->get_rows()[i]; \
914 type *in_row1 = (type*)temp->get_rows()[i * OVERSAMPLE]; \
915 type *in_row2 = (type*)temp->get_rows()[i * OVERSAMPLE + 1]; \
916 for(int j = 0; j < w; j++) \
918 out_row[0] = (in_row1[0] + \
919 in_row1[components] + \
921 in_row2[components]) / \
924 out_row[1] = ((in_row1[1] + \
925 in_row1[components + 1] + \
927 in_row2[components + 1]) - \
934 out_row[2] = ((in_row1[2] + \
935 in_row1[components + 2] + \
937 in_row2[components + 2]) - \
944 if(components == 4) \
946 out_row[3] = (in_row1[3] + \
947 in_row1[components + 3] + \
949 in_row2[components + 3]) / \
953 out_row += components; \
954 in_row1 += components * OVERSAMPLE; \
955 in_row2 += components * OVERSAMPLE; \
960 switch(input_ptr->get_color_model())
963 RESAMPLE(float, 3, 0)
966 RESAMPLE(unsigned char, 3, 0)
969 RESAMPLE(float, 4, 0)
972 RESAMPLE(unsigned char, 4, 0)
975 RESAMPLE(unsigned char, 3, 0x80)
978 RESAMPLE(unsigned char, 4, 0x80)
981 RESAMPLE(uint16_t, 3, 0)
983 case BC_RGBA16161616:
984 RESAMPLE(uint16_t, 4, 0)
987 RESAMPLE(uint16_t, 3, 0x8000)
989 case BC_YUVA16161616:
990 RESAMPLE(uint16_t, 4, 0x8000)
1008 PerspectiveMatrix::PerspectiveMatrix()
1010 bzero(values, sizeof(values));
1013 void PerspectiveMatrix::identity()
1015 bzero(values, sizeof(values));
1021 void PerspectiveMatrix::translate(double x, double y)
1023 double g = values[2][0];
1024 double h = values[2][1];
1025 double i = values[2][2];
1026 values[0][0] += x * g;
1027 values[0][1] += x * h;
1028 values[0][2] += x * i;
1029 values[1][0] += y * g;
1030 values[1][1] += y * h;
1031 values[1][2] += y * i;
1034 void PerspectiveMatrix::scale(double x, double y)
1045 void PerspectiveMatrix::multiply(PerspectiveMatrix *dst)
1048 PerspectiveMatrix tmp;
1051 for (i = 0; i < 3; i++)
1056 for (j = 0; j < 3; j++)
1058 tmp.values[i][j] = t1 * dst->values[0][j];
1059 tmp.values[i][j] += t2 * dst->values[1][j];
1060 tmp.values[i][j] += t3 * dst->values[2][j];
1063 dst->copy_from(&tmp);
1066 double PerspectiveMatrix::determinant()
1071 values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
1073 values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
1075 values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
1080 void PerspectiveMatrix::invert(PerspectiveMatrix *dst)
1084 det_1 = determinant();
1089 det_1 = 1.0 / det_1;
1092 (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
1095 - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
1098 (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
1101 - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
1104 (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
1107 - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
1110 (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
1113 - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
1116 (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
1119 void PerspectiveMatrix::copy_from(PerspectiveMatrix *src)
1121 memcpy(&values[0][0], &src->values[0][0], sizeof(values));
1124 void PerspectiveMatrix::transform_point(float x,
1131 w = values[2][0] * x + values[2][1] * y + values[2][2];
1138 *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
1139 *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
1142 void PerspectiveMatrix::dump()
1144 printf("PerspectiveMatrix::dump\n");
1145 printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
1146 printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
1147 printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
1154 PerspectivePackage::PerspectivePackage()
1162 PerspectiveUnit::PerspectiveUnit(PerspectiveEngine *server,
1163 PerspectiveMain *plugin)
1164 : LoadClient(server)
1166 this->plugin = plugin;
1167 this->server = server;
1178 void PerspectiveUnit::calculate_matrix(
1191 PerspectiveMatrix *result)
1193 PerspectiveMatrix matrix;
1197 scalex = scaley = 1.0;
1199 if((in_x2 - in_x1) > 0)
1200 scalex = 1.0 / (double)(in_x2 - in_x1);
1202 if((in_y2 - in_y1) > 0)
1203 scaley = 1.0 / (double)(in_y2 - in_y1);
1205 /* Determine the perspective transform that maps from
1206 * the unit cube to the transformed coordinates
1208 double dx1, dx2, dx3, dy1, dy2, dy3;
1211 dx1 = out_x2 - out_x4;
1212 dx2 = out_x3 - out_x4;
1213 dx3 = out_x1 - out_x2 + out_x4 - out_x3;
1215 dy1 = out_y2 - out_y4;
1216 dy2 = out_y3 - out_y4;
1217 dy3 = out_y1 - out_y2 + out_y4 - out_y3;
1218 // printf("PerspectiveUnit::calculate_matrix %f %f %f %f %f %f\n",
1227 /* Is the mapping affine? */
1228 if((dx3 == 0.0) && (dy3 == 0.0))
1230 matrix.values[0][0] = out_x2 - out_x1;
1231 matrix.values[0][1] = out_x4 - out_x2;
1232 matrix.values[0][2] = out_x1;
1233 matrix.values[1][0] = out_y2 - out_y1;
1234 matrix.values[1][1] = out_y4 - out_y2;
1235 matrix.values[1][2] = out_y1;
1236 matrix.values[2][0] = 0.0;
1237 matrix.values[2][1] = 0.0;
1241 det1 = dx3 * dy2 - dy3 * dx2;
1242 det2 = dx1 * dy2 - dy1 * dx2;
1243 matrix.values[2][0] = det1 / det2;
1244 det1 = dx1 * dy3 - dy1 * dx3;
1245 det2 = dx1 * dy2 - dy1 * dx2;
1246 matrix.values[2][1] = det1 / det2;
1248 matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
1249 matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
1250 matrix.values[0][2] = out_x1;
1252 matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
1253 matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
1254 matrix.values[1][2] = out_y1;
1257 matrix.values[2][2] = 1.0;
1259 // printf("PerspectiveUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
1263 result->translate(-in_x1, -in_y1);
1264 result->scale(scalex, scaley);
1265 matrix.multiply(result);
1266 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
1267 // { 0.0, 0.0896, 0.0 },
1268 // { -0.00126, 0.0, 1.0 } };
1269 // memcpy(&result->values[0][0], test, sizeof(test));
1270 // printf("PerspectiveUnit::calculate_matrix 4 %p\n", result);
1276 float PerspectiveUnit::transform_cubic(float dx,
1282 /* Catmull-Rom - not bad */
1283 float result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
1284 ( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
1285 ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
1291 void PerspectiveUnit::process_package(LoadPackage *package)
1293 PerspectivePackage *pkg = (PerspectivePackage*)package;
1294 int w = plugin->input->get_w();
1295 int h = plugin->input->get_h();
1299 // Calculate real coords
1300 float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
1301 if(plugin->config.mode == PerspectiveConfig::STRETCH ||
1302 plugin->config.mode == PerspectiveConfig::PERSPECTIVE)
1304 out_x1 = (float)plugin->config.x1 * w / 100;
1305 out_y1 = (float)plugin->config.y1 * h / 100;
1306 out_x2 = (float)plugin->config.x2 * w / 100;
1307 out_y2 = (float)plugin->config.y2 * h / 100;
1308 out_x3 = (float)plugin->config.x3 * w / 100;
1309 out_y3 = (float)plugin->config.y3 * h / 100;
1310 out_x4 = (float)plugin->config.x4 * w / 100;
1311 out_y4 = (float)plugin->config.y4 * h / 100;
1315 out_x1 = (float)plugin->config.x1 * w / 100;
1317 out_x2 = out_x1 + w;
1319 out_x4 = (float)plugin->config.x4 * w / 100;
1321 out_x3 = out_x4 + w;
1327 if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
1328 plugin->config.mode == PerspectiveConfig::SHEER)
1330 PerspectiveMatrix matrix;
1341 // printf("PerspectiveUnit::process_package 10 %f %f %f %f %f %f %f %f\n",
1368 int interpolate = 1;
1369 int reverse = !plugin->config.forward;
1371 float xinc, yinc, winc;
1372 PerspectiveMatrix m, im;
1375 int tx1, ty1, tx2, ty2;
1379 m.copy_from(&matrix);
1381 matrix.copy_from(&im);
1392 matrix.transform_point(0, 0, &dx1, &dy1);
1393 matrix.transform_point(w, 0, &dx2, &dy2);
1394 matrix.transform_point(0, h, &dx3, &dy3);
1395 matrix.transform_point(w, h, &dx4, &dy4);
1397 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
1398 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
1399 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
1400 #define CUBIC_ROW(in_row, chroma_offset) \
1401 transform_cubic(dx, \
1402 in_row[col1_offset] - chroma_offset, \
1403 in_row[col2_offset] - chroma_offset, \
1404 in_row[col3_offset] - chroma_offset, \
1405 in_row[col4_offset] - chroma_offset)
1407 tx1 = ROUND(MIN4(dx1, dx2, dx3, dx4));
1408 ty1 = ROUND(MIN4(dy1, dy2, dy3, dy4));
1410 tx2 = ROUND(MAX4(dx1, dx2, dx3, dx4));
1411 ty2 = ROUND(MAX4(dy1, dy2, dy3, dy4));
1413 CLAMP(ty1, pkg->y1, pkg->y2);
1414 CLAMP(ty2, pkg->y1, pkg->y2);
1416 xinc = m.values[0][0];
1417 yinc = m.values[1][0];
1418 winc = m.values[2][0];
1419 //printf("PerspectiveUnit::process_package 1 %d %d %d %d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
1422 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
1424 type **in_rows = (type**)plugin->input->get_rows(); \
1425 float round_factor = 0.0; \
1426 if(sizeof(type) < 4) round_factor = 0.5; \
1427 for(int y = ty1; y < ty2; y++) \
1429 type *out_row = (type*)plugin->output->get_rows()[y]; \
1433 tx = xinc * (tx1 + 0.5) + m.values[0][1] * (y + 0.5) + m.values[0][2]; \
1434 ty = yinc * (tx1 + 0.5) + m.values[1][1] * (y + 0.5) + m.values[1][2]; \
1435 tw = winc * (tx1 + 0.5) + m.values[2][1] * (y + 0.5) + m.values[2][2]; \
1439 tx = xinc * tx1 + m.values[0][1] * y + m.values[0][2]; \
1440 ty = yinc * tx1 + m.values[1][1] * y + m.values[1][2]; \
1441 tw = winc * tx1 + m.values[2][1] * y + m.values[2][2]; \
1445 out_row += tx1 * components; \
1446 for(int x = tx1; x < tx2; x++) \
1448 /* Normalize homogeneous coords */ \
1468 /* Set destination pixels */ \
1469 if(!interpolate && x >= 0 && x < w) \
1471 if(itx >= 0 && itx < w && \
1472 ity >= 0 && ity < h && \
1475 type *src = in_rows[ity] + itx * components; \
1476 *out_row++ = *src++; \
1477 *out_row++ = *src++; \
1478 *out_row++ = *src++; \
1479 if(components == 4) *out_row++ = *src; \
1482 /* Fill with chroma */ \
1485 *out_row++ = chroma_offset; \
1486 *out_row++ = chroma_offset; \
1487 if(components == 4) *out_row++ = 0; \
1491 /* Bicubic algorithm */ \
1492 if(interpolate && x >= 0 && x < w) \
1494 if ((itx + 2) >= 0 && (itx - 1) < w && \
1495 (ity + 2) >= 0 && (ity - 1) < h) \
1499 /* the fractional error */ \
1503 /* Row and column offsets in cubic block */ \
1504 int col1 = itx - 1; \
1506 int col3 = itx + 1; \
1507 int col4 = itx + 2; \
1508 int row1 = ity - 1; \
1510 int row3 = ity + 1; \
1511 int row4 = ity + 2; \
1512 CLAMP(col1, 0, maxw); \
1513 CLAMP(col2, 0, maxw); \
1514 CLAMP(col3, 0, maxw); \
1515 CLAMP(col4, 0, maxw); \
1516 CLAMP(row1, 0, maxh); \
1517 CLAMP(row2, 0, maxh); \
1518 CLAMP(row3, 0, maxh); \
1519 CLAMP(row4, 0, maxh); \
1520 int col1_offset = col1 * components; \
1521 int col2_offset = col2 * components; \
1522 int col3_offset = col3 * components; \
1523 int col4_offset = col4 * components; \
1524 type *row1_ptr = in_rows[row1]; \
1525 type *row2_ptr = in_rows[row2]; \
1526 type *row3_ptr = in_rows[row3]; \
1527 type *row4_ptr = in_rows[row4]; \
1528 temp_type r, g, b, a; \
1530 r = (temp_type)(transform_cubic(dy, \
1531 CUBIC_ROW(row1_ptr, 0x0), \
1532 CUBIC_ROW(row2_ptr, 0x0), \
1533 CUBIC_ROW(row3_ptr, 0x0), \
1534 CUBIC_ROW(row4_ptr, 0x0)) + \
1541 g = (temp_type)(transform_cubic(dy, \
1542 CUBIC_ROW(row1_ptr, chroma_offset), \
1543 CUBIC_ROW(row2_ptr, chroma_offset), \
1544 CUBIC_ROW(row3_ptr, chroma_offset), \
1545 CUBIC_ROW(row4_ptr, chroma_offset)) + \
1547 g += chroma_offset; \
1553 b = (temp_type)(transform_cubic(dy, \
1554 CUBIC_ROW(row1_ptr, chroma_offset), \
1555 CUBIC_ROW(row2_ptr, chroma_offset), \
1556 CUBIC_ROW(row3_ptr, chroma_offset), \
1557 CUBIC_ROW(row4_ptr, chroma_offset)) + \
1559 b += chroma_offset; \
1561 if(components == 4) \
1567 a = (temp_type)(transform_cubic(dy, \
1568 CUBIC_ROW(row1_ptr, 0x0), \
1569 CUBIC_ROW(row2_ptr, 0x0), \
1570 CUBIC_ROW(row3_ptr, 0x0), \
1571 CUBIC_ROW(row4_ptr, 0x0)) + \
1575 if(sizeof(type) < 4) \
1577 *out_row++ = CLIP(r, 0, max); \
1578 *out_row++ = CLIP(g, 0, max); \
1579 *out_row++ = CLIP(b, 0, max); \
1580 if(components == 4) *out_row++ = CLIP(a, 0, max); \
1587 if(components == 4) *out_row++ = a; \
1591 /* Fill with chroma */ \
1594 *out_row++ = chroma_offset; \
1595 *out_row++ = chroma_offset; \
1596 if(components == 4) *out_row++ = 0; \
1601 out_row += components; \
1604 /* increment the transformed coordinates */ \
1615 switch(plugin->input->get_color_model())
1618 TRANSFORM(3, float, float, 0x0, 1)
1621 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
1624 TRANSFORM(4, float, float, 0x0, 1)
1627 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
1630 TRANSFORM(3, unsigned char, int, 0x80, 0xff)
1633 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
1636 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
1638 case BC_RGBA16161616:
1639 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
1642 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
1644 case BC_YUVA16161616:
1645 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
1649 //printf("PerspectiveUnit::process_package 50\n");
1653 int max_x = w * OVERSAMPLE - 1;
1654 int max_y = h * OVERSAMPLE - 1;
1655 //printf("PerspectiveUnit::process_package 50 %d %d\n", max_x, max_y);
1656 float top_w = out_x2 - out_x1;
1657 float bottom_w = out_x3 - out_x4;
1658 float left_h = out_y4 - out_y1;
1659 float right_h = out_y3 - out_y2;
1660 float out_w_diff = bottom_w - top_w;
1661 float out_left_diff = out_x4 - out_x1;
1662 float out_h_diff = right_h - left_h;
1663 float out_top_diff = out_y2 - out_y1;
1664 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1665 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1666 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1667 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1668 float max_v = MAX(distance1, distance3);
1669 float max_h = MAX(distance2, distance4);
1670 float max_dimension = MAX(max_v, max_h);
1671 float min_dimension = MIN(h, w);
1672 float step = min_dimension / max_dimension / OVERSAMPLE;
1677 #define PERSPECTIVE(type, components) \
1679 type **in_rows = (type**)plugin->input->get_rows(); \
1680 type **out_rows = (type**)plugin->temp->get_rows(); \
1682 for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1684 int i = (int)in_y; \
1685 type *in_row = in_rows[i]; \
1686 for(float in_x = 0; in_x < w; in_x += step) \
1688 int j = (int)in_x; \
1689 float in_x_fraction = in_x / w_f; \
1690 float in_y_fraction = in_y / h_f; \
1691 int out_x = (int)((out_x1 + \
1692 out_left_diff * in_y_fraction + \
1693 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) * \
1695 int out_y = (int)((out_y1 + \
1696 out_top_diff * in_x_fraction + \
1697 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1699 CLAMP(out_x, 0, max_x); \
1700 CLAMP(out_y, 0, max_y); \
1701 type *dst = out_rows[out_y] + out_x * components; \
1702 type *src = in_row + j * components; \
1706 if(components == 4) dst[3] = src[3]; \
1711 switch(plugin->input->get_color_model())
1714 PERSPECTIVE(float, 3)
1717 PERSPECTIVE(unsigned char, 3)
1720 PERSPECTIVE(float, 4)
1723 PERSPECTIVE(unsigned char, 4)
1726 PERSPECTIVE(unsigned char, 3)
1729 PERSPECTIVE(unsigned char, 4)
1732 PERSPECTIVE(uint16_t, 3)
1734 case BC_RGBA16161616:
1735 PERSPECTIVE(uint16_t, 4)
1738 PERSPECTIVE(uint16_t, 3)
1740 case BC_YUVA16161616:
1741 PERSPECTIVE(uint16_t, 4)
1756 PerspectiveEngine::PerspectiveEngine(PerspectiveMain *plugin,
1761 total_clients, total_packages
1764 this->plugin = plugin;
1767 void PerspectiveEngine::init_packages()
1769 int package_h = (int)((float)plugin->output->get_h() /
1770 total_packages + 1);
1772 for(int i = 0; i < total_packages; i++)
1774 PerspectivePackage *package = (PerspectivePackage*)packages[i];
1776 package->y2 = y1 + package_h;
1777 package->y1 = MIN(plugin->output->get_h(), package->y1);
1778 package->y2 = MIN(plugin->output->get_h(), package->y2);
1783 LoadClient* PerspectiveEngine::new_client()
1785 return new PerspectiveUnit(this, plugin);
1788 LoadPackage* PerspectiveEngine::new_package()
1790 return new PerspectivePackage;