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
25 #include "perspective.h"
27 #define PERSPECTIVE_WIDTH 400
28 #define PERSPECTIVE_HEIGHT 600
30 REGISTER_PLUGIN(PerspectiveMain)
33 PerspectiveConfig::PerspectiveConfig()
39 mode = AffineEngine::PERSPECTIVE;
40 smoothing = AffineEngine::AF_DEFAULT;
41 window_w = PERSPECTIVE_WIDTH;
42 window_h = PERSPECTIVE_HEIGHT;
49 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
61 smoothing == that.smoothing &&
62 forward == that.forward;
64 // view_x == that.view_x &&
65 // view_y == that.view_y &&
66 // view_zoom == that.view_zoom &&
69 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
71 x1 = that.x1; y1 = that.y1;
72 x2 = that.x2; y2 = that.y2;
73 x3 = that.x3; y3 = that.y3;
74 x4 = that.x4; y4 = that.y4;
76 smoothing = that.smoothing;
77 window_w = that.window_w;
78 window_h = that.window_h;
79 current_point = that.current_point;
80 forward = that.forward;
83 view_zoom = that.view_zoom;
86 void PerspectiveConfig::interpolate(PerspectiveConfig &prev, PerspectiveConfig &next,
87 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
89 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
90 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
91 this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
92 this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
93 this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
94 this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
95 this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
96 this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
97 this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
98 this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
100 smoothing = prev.smoothing;
101 forward = prev.forward;
102 view_x = prev.view_x;
103 view_y = prev.view_y;
104 view_zoom = prev.view_zoom;
108 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin)
109 : PluginClientWindow(plugin,
110 plugin->config.window_w, plugin->config.window_h,
111 plugin->config.window_w, plugin->config.window_h, 0)
113 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
114 this->plugin = plugin;
117 PerspectiveWindow::~PerspectiveWindow()
121 void PerspectiveWindow::create_objects()
125 add_subwindow(canvas = new PerspectiveCanvas(this,
126 x, y, get_w() - 20, get_h() - 290));
127 canvas->set_cursor(CROSS_CURSOR, 0, 0);
128 y += canvas->get_h() + 10;
129 add_subwindow(new BC_Title(x, y, _("Current X:")));
131 this->x = new PerspectiveCoord(this,
132 x, y, plugin->get_current_x(), 1);
133 this->x->create_objects();
135 add_subwindow(new BC_Title(x, y, _("Y:")));
137 this->y = new PerspectiveCoord(this,
138 x, y, plugin->get_current_y(), 0);
139 this->y->create_objects();
141 add_subwindow(mode_perspective = new PerspectiveMode(this,
142 x, y, AffineEngine::PERSPECTIVE, _("Perspective")));
144 add_subwindow(mode_sheer = new PerspectiveMode(this,
145 x, y, AffineEngine::SHEER, _("Sheer")));
147 add_subwindow(affine = new PerspectiveAffine(this, x, y));
148 affine->create_objects();
150 add_subwindow(mode_stretch = new PerspectiveMode(this,
151 x, y, AffineEngine::STRETCH, _("Stretch")));
153 add_subwindow(new PerspectiveReset(this, x, y));
158 add_subwindow(title = new BC_Title(x, y, _("Zoom view:")));
159 int x1 = x + title->get_w() + 10, w1 = get_w() - x1 - 10;
160 add_subwindow(zoom_view = new PerspectiveZoomView(this, x1, y, w1));
163 add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
165 add_subwindow(forward = new PerspectiveDirection(this,
166 x, y, 1, _("Forward")));
168 add_subwindow(reverse = new PerspectiveDirection(this,
169 x, y, 0, _("Reverse")));
171 add_subwindow(title = new BC_Title(x, y, _("Alt/Shift:")));
172 add_subwindow(new BC_Title(x+100, y, _("Button1 Action:")));
173 y += title->get_h() + 5;
174 add_subwindow(new BC_Title(x, y,
179 add_subwindow(new BC_Title(x+100, y,
180 _("Translate endpoint\n"
188 int PerspectiveWindow::resize_event(int w, int h)
193 PerspectiveZoomView::PerspectiveZoomView(PerspectiveWindow *gui,
195 : BC_FSlider(x, y, 0, w, w, -2., 2.,
196 log10(gui->plugin->config.view_zoom < 0.01 ?
197 0.01 : gui->plugin->config.view_zoom))
200 set_precision(0.001);
201 set_tooltip(_("Zoom"));
203 PerspectiveZoomView::~PerspectiveZoomView()
206 int PerspectiveZoomView::handle_event()
208 float value = get_value();
209 BC_FSlider::update(value);
210 PerspectiveMain *plugin = gui->plugin;
211 float view_zoom = plugin->config.view_zoom;
212 double new_zoom = pow(10.,value);
213 double scale = new_zoom / view_zoom;
214 plugin->config.view_zoom = new_zoom;
215 plugin->config.view_x *= scale;
216 plugin->config.view_y *= scale;
217 gui->update_canvas();
218 plugin->send_configure_change();
222 char *PerspectiveZoomView::get_caption()
224 double value = get_value();
225 int frac = value >= 0. ? 1 : value >= -1. ? 2 : 3;
226 double zoom = pow(10., value);
227 char *caption = BC_Slider::get_caption();
228 sprintf(caption, "%.*f", frac, zoom);
232 void PerspectiveZoomView::update(float zoom)
234 if( zoom < 0.01 ) zoom = 0.01;
235 float value = log10f(zoom);
236 BC_FSlider::update(value);
239 void PerspectiveWindow::update_canvas()
241 int cw = canvas->get_w(), ch = canvas->get_h();
242 canvas->clear_box(0, 0, cw, ch);
243 int x1, y1, x2, y2, x3, y3, x4, y4;
244 calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
245 float x0 = cw / 2.0f, y0 = ch / 2.0f;
246 float view_zoom = plugin->config.view_zoom;
247 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
248 x1 = (x1-x0) * view_zoom + view_x + x0;
249 y1 = (y1-y0) * view_zoom + view_y + y0;
250 x2 = (x2-x0) * view_zoom + view_x + x0;
251 y2 = (y2-y0) * view_zoom + view_y + y0;
252 x3 = (x3-x0) * view_zoom + view_x + x0;
253 y3 = (y3-y0) * view_zoom + view_y + y0;
254 x4 = (x4-x0) * view_zoom + view_x + x0;
255 y4 = (y4-y0) * view_zoom + view_y + y0;
257 canvas->set_color(RED);
258 int vx1 = x0 - x0 * view_zoom + view_x;
259 int vy1 = y0 - y0 * view_zoom + view_y;
260 int vx2 = vx1 + cw * view_zoom - 1;
261 int vy2 = vy1 + ch * view_zoom - 1;
262 canvas->draw_line(vx1, vy1, vx2, vy1);
263 canvas->draw_line(vx2, vy1, vx2, vy2);
264 canvas->draw_line(vx2, vy2, vx1, vy2);
265 canvas->draw_line(vx1, vy2, vx1, vy1);
267 //printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
268 // x1, y1, x2, y2, x3, y3, x4, y4);
270 canvas->set_color(WHITE);
273 for( int i=0; i<=DIVISIONS; ++i ) {
274 canvas->draw_line( // latitude
275 x1 + (x4 - x1) * i / DIVISIONS,
276 y1 + (y4 - y1) * i / DIVISIONS,
277 x2 + (x3 - x2) * i / DIVISIONS,
278 y2 + (y3 - y2) * i / DIVISIONS);
279 canvas->draw_line( // longitude
280 x1 + (x2 - x1) * i / DIVISIONS,
281 y1 + (y2 - y1) * i / DIVISIONS,
282 x4 + (x3 - x4) * i / DIVISIONS,
283 y4 + (y3 - y4) * i / DIVISIONS);
288 if(plugin->config.current_point == 0)
289 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
291 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
293 if(plugin->config.current_point == 1)
294 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
296 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
298 if(plugin->config.current_point == 2)
299 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
301 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
303 if(plugin->config.current_point == 3)
304 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
306 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
311 void PerspectiveWindow::update_mode()
313 mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
314 mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
315 mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
316 forward->update(plugin->config.forward);
317 reverse->update(!plugin->config.forward);
320 void PerspectiveWindow::update_coord()
322 x->update(plugin->get_current_x());
323 y->update(plugin->get_current_y());
326 void PerspectiveWindow::update_view_zoom()
328 zoom_view->update(plugin->config.view_zoom);
331 void PerspectiveWindow::reset_view()
333 plugin->config.view_x = plugin->config.view_y = 0;
334 zoom_view->update(plugin->config.view_zoom = 1);
336 plugin->send_configure_change();
339 void PerspectiveWindow::calculate_canvas_coords(
340 int &x1, int &y1, int &x2, int &y2,
341 int &x3, int &y3, int &x4, int &y4)
343 int w = canvas->get_w() - 1;
344 int h = canvas->get_h() - 1;
345 if( plugin->config.mode == AffineEngine::PERSPECTIVE ||
346 plugin->config.mode == AffineEngine::STRETCH ) {
347 x1 = (int)(plugin->config.x1 * w / 100);
348 y1 = (int)(plugin->config.y1 * h / 100);
349 x2 = (int)(plugin->config.x2 * w / 100);
350 y2 = (int)(plugin->config.y2 * h / 100);
351 x3 = (int)(plugin->config.x3 * w / 100);
352 y3 = (int)(plugin->config.y3 * h / 100);
353 x4 = (int)(plugin->config.x4 * w / 100);
354 y4 = (int)(plugin->config.y4 * h / 100);
357 x1 = (int)(plugin->config.x1 * w) / 100;
361 x4 = (int)(plugin->config.x4 * w) / 100;
369 PerspectiveCanvas::PerspectiveCanvas(PerspectiveWindow *gui,
370 int x, int y, int w, int h)
371 : BC_SubWindow(x, y, w, h, BLACK)
374 state = PerspectiveCanvas::NONE;
378 int PerspectiveCanvas::button_press_event()
380 if( is_event_win() && cursor_inside() ) {
382 int cx = get_cursor_x(), cy = get_cursor_y();
383 if( alt_down() && shift_down() ) {
384 state = PerspectiveCanvas::DRAG_VIEW;
385 start_x = cx; start_y = cy;
389 PerspectiveMain *plugin = gui->plugin;
390 int x1, y1, x2, y2, x3, y3, x4, y4;
391 gui->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
392 float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
393 float x0 = cw / 2, y0 = ch / 2;
394 float view_zoom = plugin->config.view_zoom;
395 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
396 int x = (cx-x0 - view_x) / view_zoom + x0;
397 int y = (cy-y0 - view_y) / view_zoom + y0;
398 float distance1 = DISTANCE(x, y, x1, y1);
399 float distance2 = DISTANCE(x, y, x2, y2);
400 float distance3 = DISTANCE(x, y, x3, y3);
401 float distance4 = DISTANCE(x, y, x4, y4);
402 float min = distance1;
403 plugin->config.current_point = 0;
404 if( distance2 < min ) {
406 plugin->config.current_point = 1;
408 if( distance3 < min ) {
410 plugin->config.current_point = 2;
412 if( distance4 < min ) {
414 plugin->config.current_point = 3;
417 if( plugin->config.mode == AffineEngine::SHEER ) {
418 if( plugin->config.current_point == 1 )
419 plugin->config.current_point = 0;
420 else if( plugin->config.current_point == 2 )
421 plugin->config.current_point = 3;
425 if( alt_down() || shift_down() ) {
427 PerspectiveCanvas::DRAG_FULL :
428 PerspectiveCanvas::ZOOM;
429 // Get starting positions
430 start_x1 = plugin->config.x1;
431 start_y1 = plugin->config.y1;
432 start_x2 = plugin->config.x2;
433 start_y2 = plugin->config.y2;
434 start_x3 = plugin->config.x3;
435 start_y3 = plugin->config.y3;
436 start_x4 = plugin->config.x4;
437 start_y4 = plugin->config.y4;
440 state = PerspectiveCanvas::DRAG;
441 // Get starting positions
442 start_x1 = plugin->get_current_x();
443 start_y1 = plugin->get_current_y();
446 gui->update_canvas();
453 int PerspectiveCanvas::button_release_event()
455 if( state == PerspectiveCanvas::NONE ) return 0;
456 state = PerspectiveCanvas::NONE;
460 int PerspectiveCanvas::cursor_motion_event()
462 if( state == PerspectiveCanvas::NONE ) return 0;
463 PerspectiveMain *plugin = gui->plugin;
464 int cx = get_cursor_x(), cy = get_cursor_y();
465 if( state != PerspectiveCanvas::DRAG_VIEW ) {
466 float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
467 float x0 = cw / 2, y0 = ch / 2;
468 float view_zoom = plugin->config.view_zoom;
469 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
470 int x = (cx-x0 - view_x) / view_zoom + x0;
471 int y = (cy-y0 - view_y) / view_zoom + y0;
472 int w1 = get_w() - 1, h1 = get_h() - 1;
475 case PerspectiveCanvas::DRAG:
476 plugin->set_current_x((float)(x - start_x) / w1 * 100 + start_x1);
477 plugin->set_current_y((float)(y - start_y) / h1 * 100 + start_y1);
479 case PerspectiveCanvas::DRAG_FULL:
480 plugin->config.x1 = ((float)(x - start_x) / w1 * 100 + start_x1);
481 plugin->config.y1 = ((float)(y - start_y) / h1 * 100 + start_y1);
482 plugin->config.x2 = ((float)(x - start_x) / w1 * 100 + start_x2);
483 plugin->config.y2 = ((float)(y - start_y) / h1 * 100 + start_y2);
484 plugin->config.x3 = ((float)(x - start_x) / w1 * 100 + start_x3);
485 plugin->config.y3 = ((float)(y - start_y) / h1 * 100 + start_y3);
486 plugin->config.x4 = ((float)(x - start_x) / w1 * 100 + start_x4);
487 plugin->config.y4 = ((float)(y - start_y) / h1 * 100 + start_y4);
489 case PerspectiveCanvas::ZOOM:
490 float center_x = (start_x1 + start_x2 + start_x3 + start_x4) / 4;
491 float center_y = (start_y1 + start_y2 + start_y3 + start_y4) / 4;
492 float zoom = (float)(get_cursor_y() - start_y + 640) / 640;
493 plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
494 plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
495 plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
496 plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
497 plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
498 plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
499 plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
500 plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
506 plugin->config.view_x += cx - start_x;
507 plugin->config.view_y += cy - start_y;
508 start_x = cx; start_y = cy;
510 gui->update_canvas();
511 plugin->send_configure_change();
516 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
517 int x, int y, float value, int is_x)
518 : BC_TumbleTextBox(gui, value, (float)-100, (float)200, x, y, 100)
524 int PerspectiveCoord::handle_event()
526 PerspectiveMain *plugin = gui->plugin;
527 float v = atof(get_text());
529 plugin->set_current_x(v);
531 plugin->set_current_y(v);
532 gui->update_canvas();
533 plugin->send_configure_change();
538 PerspectiveReset::PerspectiveReset(PerspectiveWindow *gui, int x, int y)
539 : BC_GenericButton(x, y, _("Reset"))
543 int PerspectiveReset::handle_event()
547 PerspectiveMain *plugin = gui->plugin;
548 plugin->config.x1 = 0; plugin->config.y1 = 0;
549 plugin->config.x2 = 100; plugin->config.y2 = 0;
550 plugin->config.x3 = 100; plugin->config.y3 = 100;
551 plugin->config.x4 = 0; plugin->config.y4 = 100;
552 gui->update_canvas();
554 plugin->send_configure_change();
559 PerspectiveMode::PerspectiveMode(PerspectiveWindow *gui,
560 int x, int y, int value, char *text)
561 : BC_Radial(x, y, gui->plugin->config.mode == value, text)
566 int PerspectiveMode::handle_event()
568 PerspectiveMain *plugin = gui->plugin;
569 plugin->config.mode = value;
571 gui->update_canvas();
572 plugin->send_configure_change();
577 PerspectiveDirection::PerspectiveDirection(PerspectiveWindow *gui,
578 int x, int y, int value, char *text)
579 : BC_Radial(x, y, gui->plugin->config.forward == value, text)
584 int PerspectiveDirection::handle_event()
586 PerspectiveMain *plugin = gui->plugin;
587 plugin->config.forward = value;
589 plugin->send_configure_change();
594 int PerspectiveAffineItem::handle_event()
596 ((PerspectiveAffine *)get_popup_menu())->update(id);
600 PerspectiveAffine::PerspectiveAffine(PerspectiveWindow *gui, int x, int y)
601 : BC_PopupMenu(x, y, 100, "", 1)
604 affine_modes[AffineEngine::AF_DEFAULT] = _("default");
605 affine_modes[AffineEngine::AF_NEAREST] = _("Nearest");
606 affine_modes[AffineEngine::AF_LINEAR] = _("Linear");
607 affine_modes[AffineEngine::AF_CUBIC] = _("Cubic");
610 PerspectiveAffine::~PerspectiveAffine()
612 int id = total_items();
614 remove_item(get_item(id));
615 for( int id=0; id<n_modes; ++id )
616 delete affine_items[id];
618 void PerspectiveAffine::affine_item(int id)
620 affine_items[id] = new PerspectiveAffineItem(affine_modes[id], id);
621 add_item(affine_items[id]);
624 void PerspectiveAffine::create_objects()
626 affine_item(AffineEngine::AF_DEFAULT);
627 affine_item(AffineEngine::AF_NEAREST);
628 affine_item(AffineEngine::AF_LINEAR);
629 affine_item(AffineEngine::AF_CUBIC);
630 PerspectiveMain *plugin = gui->plugin;
631 update(plugin->config.smoothing, 0);
634 void PerspectiveAffine::update(int mode, int send)
636 if( this->mode == mode ) return;
638 set_text(affine_modes[mode]);
639 PerspectiveMain *plugin = gui->plugin;
640 plugin->config.smoothing = mode;
641 if( send ) plugin->send_configure_change();
644 PerspectiveMain::PerspectiveMain(PluginServer *server)
645 : PluginVClient(server)
652 PerspectiveMain::~PerspectiveMain()
655 if(engine) delete engine;
656 if(temp) delete temp;
659 const char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
660 int PerspectiveMain::is_realtime() { return 1; }
663 NEW_WINDOW_MACRO(PerspectiveMain, PerspectiveWindow)
665 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
667 void PerspectiveMain::update_gui()
669 if( !thread ) return;
670 //printf("PerspectiveMain::update_gui 1\n");
671 thread->window->lock_window();
672 PerspectiveWindow *gui = (PerspectiveWindow*)thread->window;
673 //printf("PerspectiveMain::update_gui 2\n");
674 load_configuration();
677 gui->update_view_zoom();
678 gui->update_canvas();
679 thread->window->unlock_window();
680 //printf("PerspectiveMain::update_gui 3\n");
687 void PerspectiveMain::save_data(KeyFrame *keyframe)
691 // cause data to be stored directly in text
692 output.set_shared_output(keyframe->xbuf);
693 output.tag.set_title("PERSPECTIVE");
695 output.tag.set_property("X1", config.x1);
696 output.tag.set_property("X2", config.x2);
697 output.tag.set_property("X3", config.x3);
698 output.tag.set_property("X4", config.x4);
699 output.tag.set_property("Y1", config.y1);
700 output.tag.set_property("Y2", config.y2);
701 output.tag.set_property("Y3", config.y3);
702 output.tag.set_property("Y4", config.y4);
704 output.tag.set_property("MODE", config.mode);
705 output.tag.set_property("VIEW_X", config.view_x);
706 output.tag.set_property("VIEW_Y", config.view_y);
707 output.tag.set_property("VIEW_ZOOM", config.view_zoom);
708 output.tag.set_property("SMOOTHING", config.smoothing);
709 output.tag.set_property("FORWARD", config.forward);
710 output.tag.set_property("WINDOW_W", config.window_w);
711 output.tag.set_property("WINDOW_H", config.window_h);
713 output.tag.set_title("/PERSPECTIVE");
715 output.append_newline();
716 output.terminate_string();
719 void PerspectiveMain::read_data(KeyFrame *keyframe)
722 input.set_shared_input(keyframe->xbuf);
725 while(!(result = input.read_tag()) ) {
726 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.view_x = input.tag.get_property("VIEW_X", config.view_x);
738 config.view_y = input.tag.get_property("VIEW_Y", config.view_y);
739 config.view_zoom = input.tag.get_property("VIEW_ZOOM", config.view_zoom);
740 config.smoothing = input.tag.get_property("SMOOTHING", config.smoothing);
741 config.forward = input.tag.get_property("FORWARD", config.forward);
742 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
743 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
748 float PerspectiveMain::get_current_x()
750 switch( config.current_point ) {
751 case 0: return config.x1;
752 case 1: return config.x2;
753 case 2: return config.x3;
754 case 3: return config.x4;
759 float PerspectiveMain::get_current_y()
761 switch( config.current_point ) {
762 case 0: return config.y1;
763 case 1: return config.y2;
764 case 2: return config.y3;
765 case 3: return config.y4;
770 void PerspectiveMain::set_current_x(float value)
772 switch( config.current_point ) {
773 case 0: config.x1 = value; break;
774 case 1: config.x2 = value; break;
775 case 2: config.x3 = value; break;
776 case 3: config.x4 = value; break;
780 void PerspectiveMain::set_current_y(float value)
782 switch( config.current_point ) {
783 case 0: config.y1 = value; break;
784 case 1: config.y2 = value; break;
785 case 2: config.y3 = value; break;
786 case 3: config.y4 = value; break;
790 int PerspectiveMain::process_buffer(VFrame *frame,
791 int64_t start_position, double frame_rate)
793 /*int need_reconfigure =*/ load_configuration();
794 int smoothing = config.smoothing;
795 // default smoothing uses opengl if possible
796 int use_opengl = smoothing != AffineEngine::AF_DEFAULT ? 0 :
797 // Opengl does some funny business with stretching.
798 config.mode == AffineEngine::PERSPECTIVE ||
799 config.mode == AffineEngine::SHEER ? get_use_opengl() : 0;
801 read_frame(frame, 0, start_position, frame_rate, use_opengl);
805 if( EQUIV(config.x1, 0) && EQUIV(config.y1, 0) &&
806 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
807 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
808 EQUIV(config.x4, 0) && EQUIV(config.y4, 100) )
812 int cpus = get_project_smp() + 1;
813 engine = new AffineEngine(cpus, cpus);
815 engine->set_interpolation(smoothing);
821 this->output = frame;
823 int w = frame->get_w(), need_w = w;
824 int h = frame->get_h(), need_h = h;
825 int color_model = frame->get_color_model();
826 switch( config.mode ) {
827 case AffineEngine::STRETCH:
828 need_w *= AFFINE_OVERSAMPLE;
829 need_h *= AFFINE_OVERSAMPLE;
830 case AffineEngine::SHEER:
831 case AffineEngine::PERSPECTIVE:
833 if( temp->get_w() != need_w || temp->get_h() != need_h ||
834 temp->get_color_model() != color_model ) {
835 delete temp; temp = 0;
839 temp = new VFrame(need_w, need_h, color_model, 0);
842 switch( config.mode ) {
843 case AffineEngine::STRETCH:
846 case AffineEngine::PERSPECTIVE:
847 case AffineEngine::SHEER:
848 temp->copy_from(input);
850 output->clear_frame();
853 delete temp; temp = 0;
857 engine->process(output, input, temp, config.mode,
858 config.x1, config.y1, config.x2, config.y2,
859 config.x3, config.y3, config.x4, config.y4,
864 if( config.mode == AffineEngine::STRETCH ) {
866 #define RESAMPLE(tag, type, components, chroma_offset) \
868 int os = AFFINE_OVERSAMPLE, os2 = os*os; \
869 for( int i=0; i<h; ++i ) { \
870 type *out_row = (type*)output->get_rows()[i]; \
871 type *in_row1 = (type*)temp->get_rows()[i * os]; \
872 type *in_row2 = (type*)temp->get_rows()[i * os + 1]; \
873 for( int j=0; j<w; ++j ) { \
875 ( in_row1[0] + in_row1[components + 0] + \
876 in_row2[0] + in_row2[components + 0] ) / os2; \
878 ( in_row1[1] + in_row1[components + 1] + \
879 in_row2[1] + in_row2[components + 1] ) / os2; \
881 ( in_row1[2] + in_row1[components + 2] + \
882 in_row2[2] + in_row2[components + 2] ) / os2; \
883 if( components == 4 ) { \
885 ( in_row1[3] + in_row1[components + 3] + \
886 in_row2[3] + in_row2[components + 3] ) / os2; \
888 out_row += components; \
889 in_row1 += components * os; \
890 in_row2 += components * os; \
895 switch( frame->get_color_model() ) {
896 RESAMPLE( BC_RGB_FLOAT, float, 3, 0 );
897 RESAMPLE( BC_RGB888, unsigned char, 3, 0 );
898 RESAMPLE( BC_RGBA_FLOAT, float, 4, 0 );
899 RESAMPLE( BC_RGBA8888, unsigned char, 4, 0 );
900 RESAMPLE( BC_YUV888, unsigned char, 3, 0x80 );
901 RESAMPLE( BC_YUVA8888, unsigned char, 4, 0x80 );
902 RESAMPLE( BC_RGB161616, uint16_t, 3, 0 );
903 RESAMPLE( BC_RGBA16161616, uint16_t, 4, 0 );
904 RESAMPLE( BC_YUV161616, uint16_t, 3, 0x8000 );
905 RESAMPLE( BC_YUVA16161616, uint16_t, 4, 0x8000 );
913 int PerspectiveMain::handle_opengl()
916 engine->set_opengl(1);
917 engine->process(get_output(), get_output(), get_output(), config.mode,
918 config.x1, config.y1, config.x2, config.y2,
919 config.x3, config.y3, config.x4, config.y4,
921 engine->set_opengl(0);