2 #include "perspective.h"
5 #define _(String) gettext(String)
6 #define gettext_noop(String) String
7 #define N_(String) gettext_noop (String)
14 REGISTER_PLUGIN(PerspectiveMain)
18 PerspectiveConfig::PerspectiveConfig()
35 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
47 forward == that.forward;
50 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
61 window_w = that.window_w;
62 window_h = that.window_h;
63 current_point = that.current_point;
64 forward = that.forward;
67 void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
68 PerspectiveConfig &next,
71 int64_t current_frame)
73 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
74 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
75 this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
76 this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
77 this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
78 this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
79 this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
80 this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
81 this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
82 this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
84 forward = prev.forward;
95 PLUGIN_THREAD_OBJECT(PerspectiveMain, PerspectiveThread, PerspectiveWindow)
99 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin, int x, int y)
100 : BC_Window(plugin->gui_string,
103 plugin->config.window_w,
104 plugin->config.window_h,
105 plugin->config.window_w,
106 plugin->config.window_h,
110 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
111 this->plugin = plugin;
114 PerspectiveWindow::~PerspectiveWindow()
118 int PerspectiveWindow::create_objects()
122 add_subwindow(canvas = new PerspectiveCanvas(plugin,
127 canvas->set_cursor(CROSS_CURSOR);
128 y += canvas->get_h() + 10;
129 add_subwindow(new BC_Title(x, y, _("Current X:")));
131 this->x = new PerspectiveCoord(this,
135 plugin->get_current_x(),
137 this->x->create_objects();
139 add_subwindow(new BC_Title(x, y, _("Y:")));
141 this->y = new PerspectiveCoord(this,
145 plugin->get_current_y(),
147 this->y->create_objects();
150 add_subwindow(new PerspectiveReset(plugin, x, y));
152 add_subwindow(mode_perspective = new PerspectiveMode(plugin,
155 PerspectiveConfig::PERSPECTIVE,
158 add_subwindow(mode_sheer = new PerspectiveMode(plugin,
161 PerspectiveConfig::SHEER,
165 add_subwindow(mode_stretch = new PerspectiveMode(plugin,
168 PerspectiveConfig::STRETCH,
173 add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
175 add_subwindow(forward = new PerspectiveDirection(plugin,
181 add_subwindow(reverse = new PerspectiveDirection(plugin,
192 WINDOW_CLOSE_EVENT(PerspectiveWindow)
194 int PerspectiveWindow::resize_event(int w, int h)
199 void PerspectiveWindow::update_canvas()
201 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
202 int x1, y1, x2, y2, x3, y3, x4, y4;
203 calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
205 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
214 canvas->set_color(BLACK);
217 for(int i = 0; i <= DIVISIONS; i++)
221 x1 + (x4 - x1) * i / DIVISIONS,
222 y1 + (y4 - y1) * i / DIVISIONS,
223 x2 + (x3 - x2) * i / DIVISIONS,
224 y2 + (y3 - y2) * i / DIVISIONS);
227 x1 + (x2 - x1) * i / DIVISIONS,
228 y1 + (y2 - y1) * i / DIVISIONS,
229 x4 + (x3 - x4) * i / DIVISIONS,
230 y4 + (y3 - y4) * i / DIVISIONS);
235 if(plugin->config.current_point == 0)
236 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
238 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
240 if(plugin->config.current_point == 1)
241 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
243 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
245 if(plugin->config.current_point == 2)
246 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
248 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
250 if(plugin->config.current_point == 3)
251 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
253 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
259 void PerspectiveWindow::update_mode()
261 mode_perspective->update(plugin->config.mode == PerspectiveConfig::PERSPECTIVE);
262 mode_sheer->update(plugin->config.mode == PerspectiveConfig::SHEER);
263 mode_stretch->update(plugin->config.mode == PerspectiveConfig::STRETCH);
264 forward->update(plugin->config.forward);
265 reverse->update(!plugin->config.forward);
268 void PerspectiveWindow::update_coord()
270 x->update(plugin->get_current_x());
271 y->update(plugin->get_current_y());
274 void PerspectiveWindow::calculate_canvas_coords(int &x1,
283 int w = canvas->get_w() - 1;
284 int h = canvas->get_h() - 1;
285 if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
286 plugin->config.mode == PerspectiveConfig::STRETCH)
288 x1 = (int)(plugin->config.x1 * w / 100);
289 y1 = (int)(plugin->config.y1 * h / 100);
290 x2 = (int)(plugin->config.x2 * w / 100);
291 y2 = (int)(plugin->config.y2 * h / 100);
292 x3 = (int)(plugin->config.x3 * w / 100);
293 y3 = (int)(plugin->config.y3 * h / 100);
294 x4 = (int)(plugin->config.x4 * w / 100);
295 y4 = (int)(plugin->config.y4 * h / 100);
299 x1 = (int)(plugin->config.x1 * w) / 100;
303 x4 = (int)(plugin->config.x4 * w) / 100;
313 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
318 : BC_SubWindow(x, y, w, h, 0xffffff)
320 this->plugin = plugin;
321 state = PerspectiveCanvas::NONE;
326 #define DISTANCE(x1, y1, x2, y2) \
327 (sqrt(((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1))))
329 int PerspectiveCanvas::button_press_event()
331 if(is_event_win() && cursor_inside())
334 int x1, y1, x2, y2, x3, y3, x4, y4;
335 int cursor_x = get_cursor_x();
336 int cursor_y = get_cursor_y();
337 plugin->thread->window->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
339 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
340 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
341 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
342 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
343 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n",
349 float min = distance1;
350 plugin->config.current_point = 0;
354 plugin->config.current_point = 1;
359 plugin->config.current_point = 2;
364 plugin->config.current_point = 3;
367 if(plugin->config.mode == PerspectiveConfig::SHEER)
369 if(plugin->config.current_point == 1)
370 plugin->config.current_point = 0;
372 if(plugin->config.current_point == 2)
373 plugin->config.current_point = 3;
375 start_cursor_x = cursor_x;
376 start_cursor_y = cursor_y;
378 if(alt_down() || shift_down())
381 state = PerspectiveCanvas::DRAG_FULL;
383 state = PerspectiveCanvas::ZOOM;
385 // Get starting positions
386 start_x1 = plugin->config.x1;
387 start_y1 = plugin->config.y1;
388 start_x2 = plugin->config.x2;
389 start_y2 = plugin->config.y2;
390 start_x3 = plugin->config.x3;
391 start_y3 = plugin->config.y3;
392 start_x4 = plugin->config.x4;
393 start_y4 = plugin->config.y4;
397 state = PerspectiveCanvas::DRAG;
399 // Get starting positions
400 start_x1 = plugin->get_current_x();
401 start_y1 = plugin->get_current_y();
403 plugin->thread->window->update_coord();
404 plugin->thread->window->update_canvas();
411 int PerspectiveCanvas::button_release_event()
413 if(state != PerspectiveCanvas::NONE)
415 state = PerspectiveCanvas::NONE;
421 int PerspectiveCanvas::cursor_motion_event()
423 if(state != PerspectiveCanvas::NONE)
427 if(state == PerspectiveCanvas::DRAG)
429 plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
430 plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
433 if(state == PerspectiveCanvas::DRAG_FULL)
435 plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
436 plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
437 plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
438 plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
439 plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
440 plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
441 plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
442 plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
445 if(state == PerspectiveCanvas::ZOOM)
447 float center_x = (start_x1 +
451 float center_y = (start_y1 +
455 float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
456 plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
457 plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
458 plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
459 plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
460 plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
461 plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
462 plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
463 plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
465 plugin->thread->window->update_canvas();
466 plugin->thread->window->update_coord();
467 plugin->send_configure_change();
479 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
480 PerspectiveMain *plugin,
485 : BC_TumbleTextBox(gui, value, (float)0, (float)100, x, y, 100)
487 this->plugin = plugin;
491 int PerspectiveCoord::handle_event()
494 plugin->set_current_x(atof(get_text()));
496 plugin->set_current_y(atof(get_text()));
497 plugin->thread->window->update_canvas();
498 plugin->send_configure_change();
509 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin,
512 : BC_GenericButton(x, y, _("Reset"))
514 this->plugin = plugin;
516 int PerspectiveReset::handle_event()
518 plugin->config.x1 = 0;
519 plugin->config.y1 = 0;
520 plugin->config.x2 = 100;
521 plugin->config.y2 = 0;
522 plugin->config.x3 = 100;
523 plugin->config.y3 = 100;
524 plugin->config.x4 = 0;
525 plugin->config.y4 = 100;
526 plugin->thread->window->update_canvas();
527 plugin->thread->window->update_coord();
528 plugin->send_configure_change();
542 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin,
547 : BC_Radial(x, y, plugin->config.mode == value, text)
549 this->plugin = plugin;
552 int PerspectiveMode::handle_event()
554 plugin->config.mode = value;
555 plugin->thread->window->update_mode();
556 plugin->thread->window->update_canvas();
557 plugin->send_configure_change();
564 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin,
569 : BC_Radial(x, y, plugin->config.forward == value, text)
571 this->plugin = plugin;
574 int PerspectiveDirection::handle_event()
576 plugin->config.forward = value;
577 plugin->thread->window->update_mode();
578 plugin->send_configure_change();
593 PerspectiveMain::PerspectiveMain(PluginServer *server)
594 : PluginVClient(server)
596 PLUGIN_CONSTRUCTOR_MACRO
601 PerspectiveMain::~PerspectiveMain()
603 PLUGIN_DESTRUCTOR_MACRO
604 if(engine) delete engine;
605 if(temp) delete temp;
608 char* PerspectiveMain::plugin_title() { return _("Perspective"); }
609 int PerspectiveMain::is_realtime() { return 1; }
612 NEW_PICON_MACRO(PerspectiveMain)
614 SHOW_GUI_MACRO(PerspectiveMain, PerspectiveThread)
616 SET_STRING_MACRO(PerspectiveMain)
618 RAISE_WINDOW_MACRO(PerspectiveMain)
620 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
624 void PerspectiveMain::update_gui()
628 //printf("PerspectiveMain::update_gui 1\n");
629 thread->window->lock_window();
630 //printf("PerspectiveMain::update_gui 2\n");
631 load_configuration();
632 thread->window->update_coord();
633 thread->window->update_mode();
634 thread->window->update_canvas();
635 thread->window->unlock_window();
636 //printf("PerspectiveMain::update_gui 3\n");
641 int PerspectiveMain::load_defaults()
643 char directory[1024], string[1024];
644 // set the default directory
645 sprintf(directory, "%sperspective.rc", BCASTDIR);
648 defaults = new Defaults(directory);
651 config.x1 = defaults->get("X1", config.x1);
652 config.x2 = defaults->get("X2", config.x2);
653 config.x3 = defaults->get("X3", config.x3);
654 config.x4 = defaults->get("X4", config.x4);
655 config.y1 = defaults->get("Y1", config.y1);
656 config.y2 = defaults->get("Y2", config.y2);
657 config.y3 = defaults->get("Y3", config.y3);
658 config.y4 = defaults->get("Y4", config.y4);
660 config.mode = defaults->get("MODE", config.mode);
661 config.forward = defaults->get("FORWARD", config.forward);
662 config.window_w = defaults->get("WINDOW_W", config.window_w);
663 config.window_h = defaults->get("WINDOW_H", config.window_h);
668 int PerspectiveMain::save_defaults()
670 defaults->update("X1", config.x1);
671 defaults->update("X2", config.x2);
672 defaults->update("X3", config.x3);
673 defaults->update("X4", config.x4);
674 defaults->update("Y1", config.y1);
675 defaults->update("Y2", config.y2);
676 defaults->update("Y3", config.y3);
677 defaults->update("Y4", config.y4);
679 defaults->update("MODE", config.mode);
680 defaults->update("FORWARD", config.forward);
681 defaults->update("WINDOW_W", config.window_w);
682 defaults->update("WINDOW_H", config.window_h);
689 void PerspectiveMain::save_data(KeyFrame *keyframe)
693 // cause data to be stored directly in text
694 output.set_shared_string(keyframe->data, MESSAGESIZE);
695 output.tag.set_title("PERSPECTIVE");
697 output.tag.set_property("X1", config.x1);
698 output.tag.set_property("X2", config.x2);
699 output.tag.set_property("X3", config.x3);
700 output.tag.set_property("X4", config.x4);
701 output.tag.set_property("Y1", config.y1);
702 output.tag.set_property("Y2", config.y2);
703 output.tag.set_property("Y3", config.y3);
704 output.tag.set_property("Y4", config.y4);
706 output.tag.set_property("MODE", config.mode);
707 output.tag.set_property("FORWARD", config.forward);
708 output.tag.set_property("WINDOW_W", config.window_w);
709 output.tag.set_property("WINDOW_H", config.window_h);
711 output.terminate_string();
714 void PerspectiveMain::read_data(KeyFrame *keyframe)
718 input.set_shared_string(keyframe->data, strlen(keyframe->data));
724 result = input.read_tag();
728 if(input.tag.title_is("PERSPECTIVE"))
730 config.x1 = input.tag.get_property("X1", config.x1);
731 config.x2 = input.tag.get_property("X2", config.x2);
732 config.x3 = input.tag.get_property("X3", config.x3);
733 config.x4 = input.tag.get_property("X4", config.x4);
734 config.y1 = input.tag.get_property("Y1", config.y1);
735 config.y2 = input.tag.get_property("Y2", config.y2);
736 config.y3 = input.tag.get_property("Y3", config.y3);
737 config.y4 = input.tag.get_property("Y4", config.y4);
739 config.mode = input.tag.get_property("MODE", config.mode);
740 config.forward = input.tag.get_property("FORWARD", config.forward);
741 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
742 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
748 float PerspectiveMain::get_current_x()
750 switch(config.current_point)
767 float PerspectiveMain::get_current_y()
769 switch(config.current_point)
786 void PerspectiveMain::set_current_x(float value)
788 switch(config.current_point)
805 void PerspectiveMain::set_current_y(float value)
807 switch(config.current_point)
826 int PerspectiveMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
828 int need_reconfigure = load_configuration();
831 if(!engine) engine = new PerspectiveEngine(this,
832 get_project_smp() + 1,
833 get_project_smp() + 1);
835 this->input = input_ptr;
836 this->output = output_ptr;
838 if( EQUIV(config.x1, 0) && EQUIV(config.y1, 0) &&
839 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
840 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
841 EQUIV(config.x4, 0) && EQUIV(config.y4, 100))
843 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
844 output_ptr->copy_from(input_ptr);
848 int w = input_ptr->get_w();
849 int h = input_ptr->get_h();
850 int color_model = input_ptr->get_color_model();
853 config.mode == PerspectiveConfig::STRETCH &&
854 (temp->get_w() != w * OVERSAMPLE ||
855 temp->get_h() != h * OVERSAMPLE))
862 (config.mode == PerspectiveConfig::PERSPECTIVE ||
863 config.mode == PerspectiveConfig::SHEER) &&
864 (temp->get_w() != w ||
871 if(config.mode == PerspectiveConfig::STRETCH)
883 if(config.mode == PerspectiveConfig::PERSPECTIVE ||
884 config.mode == PerspectiveConfig::SHEER)
886 if(input_ptr->get_rows()[0] == output_ptr->get_rows()[0])
895 temp->copy_from(input);
898 output->clear_frame();
903 engine->process_packages();
910 if(config.mode == PerspectiveConfig::STRETCH)
912 #define RESAMPLE(type, components, chroma_offset) \
914 for(int i = 0; i < h; i++) \
916 type *out_row = (type*)output->get_rows()[i]; \
917 type *in_row1 = (type*)temp->get_rows()[i * OVERSAMPLE]; \
918 type *in_row2 = (type*)temp->get_rows()[i * OVERSAMPLE + 1]; \
919 for(int j = 0; j < w; j++) \
921 out_row[0] = (in_row1[0] + \
922 in_row1[components] + \
924 in_row2[components]) / \
927 out_row[1] = ((in_row1[1] + \
928 in_row1[components + 1] + \
930 in_row2[components + 1]) - \
937 out_row[2] = ((in_row1[2] + \
938 in_row1[components + 2] + \
940 in_row2[components + 2]) - \
947 if(components == 4) \
949 out_row[3] = (in_row1[3] + \
950 in_row1[components + 3] + \
952 in_row2[components + 3]) / \
956 out_row += components; \
957 in_row1 += components * OVERSAMPLE; \
958 in_row2 += components * OVERSAMPLE; \
963 switch(input_ptr->get_color_model())
966 RESAMPLE(unsigned char, 3, 0)
969 RESAMPLE(unsigned char, 4, 0)
972 RESAMPLE(unsigned char, 3, 0x80)
975 RESAMPLE(unsigned char, 4, 0x80)
978 RESAMPLE(uint16_t, 3, 0)
980 case BC_RGBA16161616:
981 RESAMPLE(uint16_t, 4, 0)
984 RESAMPLE(uint16_t, 3, 0x8000)
986 case BC_YUVA16161616:
987 RESAMPLE(uint16_t, 4, 0x8000)
1005 PerspectiveMatrix::PerspectiveMatrix()
1007 bzero(values, sizeof(values));
1010 void PerspectiveMatrix::identity()
1012 bzero(values, sizeof(values));
1018 void PerspectiveMatrix::translate(double x, double y)
1020 double g = values[2][0];
1021 double h = values[2][1];
1022 double i = values[2][2];
1023 values[0][0] += x * g;
1024 values[0][1] += x * h;
1025 values[0][2] += x * i;
1026 values[1][0] += y * g;
1027 values[1][1] += y * h;
1028 values[1][2] += y * i;
1031 void PerspectiveMatrix::scale(double x, double y)
1042 void PerspectiveMatrix::multiply(PerspectiveMatrix *dst)
1045 PerspectiveMatrix tmp;
1048 for (i = 0; i < 3; i++)
1053 for (j = 0; j < 3; j++)
1055 tmp.values[i][j] = t1 * dst->values[0][j];
1056 tmp.values[i][j] += t2 * dst->values[1][j];
1057 tmp.values[i][j] += t3 * dst->values[2][j];
1060 dst->copy_from(&tmp);
1063 double PerspectiveMatrix::determinant()
1068 values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
1070 values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
1072 values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
1077 void PerspectiveMatrix::invert(PerspectiveMatrix *dst)
1081 det_1 = determinant();
1086 det_1 = 1.0 / det_1;
1089 (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
1092 - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
1095 (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
1098 - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
1101 (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
1104 - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
1107 (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
1110 - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
1113 (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
1116 void PerspectiveMatrix::copy_from(PerspectiveMatrix *src)
1118 memcpy(&values[0][0], &src->values[0][0], sizeof(values));
1121 void PerspectiveMatrix::transform_point(float x,
1128 w = values[2][0] * x + values[2][1] * y + values[2][2];
1135 *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
1136 *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
1139 void PerspectiveMatrix::dump()
1141 printf("PerspectiveMatrix::dump\n");
1142 printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
1143 printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
1144 printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
1151 PerspectivePackage::PerspectivePackage()
1159 PerspectiveUnit::PerspectiveUnit(PerspectiveEngine *server,
1160 PerspectiveMain *plugin)
1161 : LoadClient(server)
1163 this->plugin = plugin;
1164 this->server = server;
1175 void PerspectiveUnit::calculate_matrix(
1188 PerspectiveMatrix *result)
1190 PerspectiveMatrix matrix;
1194 scalex = scaley = 1.0;
1196 if((in_x2 - in_x1) > 0)
1197 scalex = 1.0 / (double)(in_x2 - in_x1);
1199 if((in_y2 - in_y1) > 0)
1200 scaley = 1.0 / (double)(in_y2 - in_y1);
1202 /* Determine the perspective transform that maps from
1203 * the unit cube to the transformed coordinates
1205 double dx1, dx2, dx3, dy1, dy2, dy3;
1208 dx1 = out_x2 - out_x4;
1209 dx2 = out_x3 - out_x4;
1210 dx3 = out_x1 - out_x2 + out_x4 - out_x3;
1212 dy1 = out_y2 - out_y4;
1213 dy2 = out_y3 - out_y4;
1214 dy3 = out_y1 - out_y2 + out_y4 - out_y3;
1215 // printf("PerspectiveUnit::calculate_matrix %f %f %f %f %f %f\n",
1224 /* Is the mapping affine? */
1225 if((dx3 == 0.0) && (dy3 == 0.0))
1227 matrix.values[0][0] = out_x2 - out_x1;
1228 matrix.values[0][1] = out_x4 - out_x2;
1229 matrix.values[0][2] = out_x1;
1230 matrix.values[1][0] = out_y2 - out_y1;
1231 matrix.values[1][1] = out_y4 - out_y2;
1232 matrix.values[1][2] = out_y1;
1233 matrix.values[2][0] = 0.0;
1234 matrix.values[2][1] = 0.0;
1238 det1 = dx3 * dy2 - dy3 * dx2;
1239 det2 = dx1 * dy2 - dy1 * dx2;
1240 matrix.values[2][0] = det1 / det2;
1241 det1 = dx1 * dy3 - dy1 * dx3;
1242 det2 = dx1 * dy2 - dy1 * dx2;
1243 matrix.values[2][1] = det1 / det2;
1245 matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
1246 matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
1247 matrix.values[0][2] = out_x1;
1249 matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
1250 matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
1251 matrix.values[1][2] = out_y1;
1254 matrix.values[2][2] = 1.0;
1256 // printf("PerspectiveUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
1260 result->translate(-in_x1, -in_y1);
1261 result->scale(scalex, scaley);
1262 matrix.multiply(result);
1263 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
1264 // { 0.0, 0.0896, 0.0 },
1265 // { -0.00126, 0.0, 1.0 } };
1266 // memcpy(&result->values[0][0], test, sizeof(test));
1267 // printf("PerspectiveUnit::calculate_matrix 4 %p\n", result);
1273 float PerspectiveUnit::transform_cubic(float dx,
1279 /* Catmull-Rom - not bad */
1280 float result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
1281 ( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
1282 ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
1288 void PerspectiveUnit::process_package(LoadPackage *package)
1290 PerspectivePackage *pkg = (PerspectivePackage*)package;
1291 int w = plugin->input->get_w();
1292 int h = plugin->input->get_h();
1296 // Calculate real coords
1297 float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
1298 if(plugin->config.mode == PerspectiveConfig::STRETCH ||
1299 plugin->config.mode == PerspectiveConfig::PERSPECTIVE)
1301 out_x1 = (float)plugin->config.x1 * w / 100;
1302 out_y1 = (float)plugin->config.y1 * h / 100;
1303 out_x2 = (float)plugin->config.x2 * w / 100;
1304 out_y2 = (float)plugin->config.y2 * h / 100;
1305 out_x3 = (float)plugin->config.x3 * w / 100;
1306 out_y3 = (float)plugin->config.y3 * h / 100;
1307 out_x4 = (float)plugin->config.x4 * w / 100;
1308 out_y4 = (float)plugin->config.y4 * h / 100;
1312 out_x1 = (float)plugin->config.x1 * w / 100;
1314 out_x2 = out_x1 + w;
1316 out_x4 = (float)plugin->config.x4 * w / 100;
1318 out_x3 = out_x4 + w;
1324 if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
1325 plugin->config.mode == PerspectiveConfig::SHEER)
1327 PerspectiveMatrix matrix;
1338 // printf("PerspectiveUnit::process_package 10 %f %f %f %f %f %f %f %f\n",
1365 int interpolate = 1;
1366 int reverse = !plugin->config.forward;
1368 float xinc, yinc, winc;
1369 PerspectiveMatrix m, im;
1372 int tx1, ty1, tx2, ty2;
1376 m.copy_from(&matrix);
1378 matrix.copy_from(&im);
1389 matrix.transform_point(0, 0, &dx1, &dy1);
1390 matrix.transform_point(w, 0, &dx2, &dy2);
1391 matrix.transform_point(0, h, &dx3, &dy3);
1392 matrix.transform_point(w, h, &dx4, &dy4);
1394 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
1395 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
1396 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
1397 #define CUBIC_ROW(in_row, chroma_offset) \
1398 transform_cubic(dx, \
1399 in_row[col1_offset] - chroma_offset, \
1400 in_row[col2_offset] - chroma_offset, \
1401 in_row[col3_offset] - chroma_offset, \
1402 in_row[col4_offset] - chroma_offset)
1404 tx1 = ROUND(MIN4(dx1, dx2, dx3, dx4));
1405 ty1 = ROUND(MIN4(dy1, dy2, dy3, dy4));
1407 tx2 = ROUND(MAX4(dx1, dx2, dx3, dx4));
1408 ty2 = ROUND(MAX4(dy1, dy2, dy3, dy4));
1410 CLAMP(ty1, pkg->y1, pkg->y2);
1411 CLAMP(ty2, pkg->y1, pkg->y2);
1413 xinc = m.values[0][0];
1414 yinc = m.values[1][0];
1415 winc = m.values[2][0];
1416 //printf("PerspectiveUnit::process_package 1 %d %d %d %d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
1419 #define TRANSFORM(components, type, chroma_offset, max) \
1421 type **in_rows = (type**)plugin->input->get_rows(); \
1422 for(int y = ty1; y < ty2; y++) \
1424 type *out_row = (type*)plugin->output->get_rows()[y]; \
1428 tx = xinc * (tx1 + 0.5) + m.values[0][1] * (y + 0.5) + m.values[0][2]; \
1429 ty = yinc * (tx1 + 0.5) + m.values[1][1] * (y + 0.5) + m.values[1][2]; \
1430 tw = winc * (tx1 + 0.5) + m.values[2][1] * (y + 0.5) + m.values[2][2]; \
1434 tx = xinc * tx1 + m.values[0][1] * y + m.values[0][2]; \
1435 ty = yinc * tx1 + m.values[1][1] * y + m.values[1][2]; \
1436 tw = winc * tx1 + m.values[2][1] * y + m.values[2][2]; \
1440 out_row += tx1 * components; \
1441 for(int x = tx1; x < tx2; x++) \
1443 /* Normalize homogeneous coords */ \
1463 /* Set destination pixels */ \
1464 if(!interpolate && x >= 0 && x < w) \
1466 if(itx >= 0 && itx < w && \
1467 ity >= 0 && ity < h && \
1470 type *src = in_rows[ity] + itx * components; \
1471 *out_row++ = *src++; \
1472 *out_row++ = *src++; \
1473 *out_row++ = *src++; \
1474 if(components == 4) *out_row++ = *src; \
1477 /* Fill with chroma */ \
1480 *out_row++ = chroma_offset; \
1481 *out_row++ = chroma_offset; \
1482 if(components == 4) *out_row++ = 0; \
1486 /* Bicubic algorithm */ \
1487 if(interpolate && x >= 0 && x < w) \
1489 if ((itx + 2) >= 0 && (itx - 1) < w && \
1490 (ity + 2) >= 0 && (ity - 1) < h) \
1494 /* the fractional error */ \
1498 /* Row and column offsets in cubic block */ \
1499 int col1 = itx - 1; \
1501 int col3 = itx + 1; \
1502 int col4 = itx + 2; \
1503 int row1 = ity - 1; \
1505 int row3 = ity + 1; \
1506 int row4 = ity + 2; \
1507 CLAMP(col1, 0, maxw); \
1508 CLAMP(col2, 0, maxw); \
1509 CLAMP(col3, 0, maxw); \
1510 CLAMP(col4, 0, maxw); \
1511 CLAMP(row1, 0, maxh); \
1512 CLAMP(row2, 0, maxh); \
1513 CLAMP(row3, 0, maxh); \
1514 CLAMP(row4, 0, maxh); \
1515 int col1_offset = col1 * components; \
1516 int col2_offset = col2 * components; \
1517 int col3_offset = col3 * components; \
1518 int col4_offset = col4 * components; \
1519 type *row1_ptr = in_rows[row1]; \
1520 type *row2_ptr = in_rows[row2]; \
1521 type *row3_ptr = in_rows[row3]; \
1522 type *row4_ptr = in_rows[row4]; \
1525 r = (int)(transform_cubic(dy, \
1526 CUBIC_ROW(row1_ptr, 0x0), \
1527 CUBIC_ROW(row2_ptr, 0x0), \
1528 CUBIC_ROW(row3_ptr, 0x0), \
1529 CUBIC_ROW(row4_ptr, 0x0)) + \
1536 g = ROUND(transform_cubic(dy, \
1537 CUBIC_ROW(row1_ptr, chroma_offset), \
1538 CUBIC_ROW(row2_ptr, chroma_offset), \
1539 CUBIC_ROW(row3_ptr, chroma_offset), \
1540 CUBIC_ROW(row4_ptr, chroma_offset))); \
1541 g += chroma_offset; \
1547 b = ROUND(transform_cubic(dy, \
1548 CUBIC_ROW(row1_ptr, chroma_offset), \
1549 CUBIC_ROW(row2_ptr, chroma_offset), \
1550 CUBIC_ROW(row3_ptr, chroma_offset), \
1551 CUBIC_ROW(row4_ptr, chroma_offset))); \
1552 b += chroma_offset; \
1554 if(components == 4) \
1560 a = (int)(transform_cubic(dy, \
1561 CUBIC_ROW(row1_ptr, 0x0), \
1562 CUBIC_ROW(row2_ptr, 0x0), \
1563 CUBIC_ROW(row3_ptr, 0x0), \
1564 CUBIC_ROW(row4_ptr, 0x0)) + \
1568 *out_row++ = CLIP(r, 0, max); \
1569 *out_row++ = CLIP(g, 0, max); \
1570 *out_row++ = CLIP(b, 0, max); \
1571 if(components == 4) *out_row++ = CLIP(a, 0, max); \
1574 /* Fill with chroma */ \
1577 *out_row++ = chroma_offset; \
1578 *out_row++ = chroma_offset; \
1579 if(components == 4) *out_row++ = 0; \
1584 out_row += components; \
1587 /* increment the transformed coordinates */ \
1598 switch(plugin->input->get_color_model())
1601 TRANSFORM(3, unsigned char, 0x0, 0xff)
1604 TRANSFORM(4, unsigned char, 0x0, 0xff)
1607 TRANSFORM(3, unsigned char, 0x80, 0xff)
1610 TRANSFORM(4, unsigned char, 0x80, 0xff)
1613 TRANSFORM(3, uint16_t, 0x0, 0xffff)
1615 case BC_RGBA16161616:
1616 TRANSFORM(4, uint16_t, 0x0, 0xffff)
1619 TRANSFORM(3, uint16_t, 0x8000, 0xffff)
1621 case BC_YUVA16161616:
1622 TRANSFORM(4, uint16_t, 0x8000, 0xffff)
1626 //printf("PerspectiveUnit::process_package 50\n");
1630 int max_x = w * OVERSAMPLE - 1;
1631 int max_y = h * OVERSAMPLE - 1;
1632 //printf("PerspectiveUnit::process_package 50 %d %d\n", max_x, max_y);
1633 float top_w = out_x2 - out_x1;
1634 float bottom_w = out_x3 - out_x4;
1635 float left_h = out_y4 - out_y1;
1636 float right_h = out_y3 - out_y2;
1637 float out_w_diff = bottom_w - top_w;
1638 float out_left_diff = out_x4 - out_x1;
1639 float out_h_diff = right_h - left_h;
1640 float out_top_diff = out_y2 - out_y1;
1641 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1642 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1643 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1644 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1645 float max_v = MAX(distance1, distance3);
1646 float max_h = MAX(distance2, distance4);
1647 float max_dimension = MAX(max_v, max_h);
1648 float min_dimension = MIN(h, w);
1649 float step = min_dimension / max_dimension / OVERSAMPLE;
1654 #define PERSPECTIVE(type, components) \
1656 type **in_rows = (type**)plugin->input->get_rows(); \
1657 type **out_rows = (type**)plugin->temp->get_rows(); \
1659 for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1661 int i = (int)in_y; \
1662 type *in_row = in_rows[i]; \
1663 for(float in_x = 0; in_x < w; in_x += step) \
1665 int j = (int)in_x; \
1666 float in_x_fraction = in_x / w_f; \
1667 float in_y_fraction = in_y / h_f; \
1668 int out_x = (int)((out_x1 + \
1669 out_left_diff * in_y_fraction + \
1670 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) * \
1672 int out_y = (int)((out_y1 + \
1673 out_top_diff * in_x_fraction + \
1674 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1676 CLAMP(out_x, 0, max_x); \
1677 CLAMP(out_y, 0, max_y); \
1678 type *dst = out_rows[out_y] + out_x * components; \
1679 type *src = in_row + j * components; \
1683 if(components == 4) dst[3] = src[3]; \
1688 switch(plugin->input->get_color_model())
1691 PERSPECTIVE(unsigned char, 3)
1694 PERSPECTIVE(unsigned char, 4)
1697 PERSPECTIVE(unsigned char, 3)
1700 PERSPECTIVE(unsigned char, 4)
1703 PERSPECTIVE(uint16_t, 3)
1705 case BC_RGBA16161616:
1706 PERSPECTIVE(uint16_t, 4)
1709 PERSPECTIVE(uint16_t, 3)
1711 case BC_YUVA16161616:
1712 PERSPECTIVE(uint16_t, 4)
1727 PerspectiveEngine::PerspectiveEngine(PerspectiveMain *plugin,
1732 total_clients, total_packages
1735 this->plugin = plugin;
1738 void PerspectiveEngine::init_packages()
1740 int package_h = (int)((float)plugin->output->get_h() /
1741 total_packages + 1);
1743 for(int i = 0; i < total_packages; i++)
1745 PerspectivePackage *package = (PerspectivePackage*)packages[i];
1747 package->y2 = y1 + package_h;
1748 package->y1 = MIN(plugin->output->get_h(), package->y1);
1749 package->y2 = MIN(plugin->output->get_h(), package->y2);
1754 LoadClient* PerspectiveEngine::new_client()
1756 return new PerspectiveUnit(this, plugin);
1759 LoadPackage* PerspectiveEngine::new_package()
1761 return new PerspectivePackage;