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 xS(400)
28 #define PERSPECTIVE_HEIGHT yS(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()
123 int xs10 = xS(10), xs20 = xS(20), xs80 = xS(80), xs100 = xS(100), xs120 = xS(120);
124 int ys5 = yS(5), ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
125 int x = xs10, y = ys10;
127 add_subwindow(canvas = new PerspectiveCanvas(this,
128 x, y, get_w() - xs20, get_h() - yS(290)));
129 canvas->set_cursor(CROSS_CURSOR, 0, 0);
130 y += canvas->get_h() + ys10;
131 add_subwindow(new BC_Title(x, y, _("Current X:")));
133 this->x = new PerspectiveCoord(this,
134 x, y, plugin->get_current_x(), 1);
135 this->x->create_objects();
137 add_subwindow(new BC_Title(x, y, _("Y:")));
139 this->y = new PerspectiveCoord(this,
140 x, y, plugin->get_current_y(), 0);
141 this->y->create_objects();
143 add_subwindow(mode_perspective = new PerspectiveMode(this,
144 x, y, AffineEngine::PERSPECTIVE, _("Perspective")));
146 add_subwindow(mode_sheer = new PerspectiveMode(this,
147 x, y, AffineEngine::SHEER, _("Sheer")));
149 add_subwindow(affine = new PerspectiveAffine(this, x, y));
150 affine->create_objects();
152 add_subwindow(mode_stretch = new PerspectiveMode(this,
153 x, y, AffineEngine::STRETCH, _("Stretch")));
155 add_subwindow(new PerspectiveReset(this, x, y));
160 add_subwindow(title = new BC_Title(x, y, _("Zoom view:")));
161 int x1 = x + title->get_w() + xs10, w1 = get_w() - x1 - xs10;
162 add_subwindow(zoom_view = new PerspectiveZoomView(this, x1, y, w1));
165 add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
167 add_subwindow(forward = new PerspectiveDirection(this,
168 x, y, 1, _("Forward")));
170 add_subwindow(reverse = new PerspectiveDirection(this,
171 x, y, 0, _("Reverse")));
173 add_subwindow(title = new BC_Title(x, y, _("Alt/Shift:")));
174 add_subwindow(new BC_Title(x+xs100, y, _("Button1 Action:")));
175 y += title->get_h() + ys5;
176 add_subwindow(new BC_Title(x, y,
181 add_subwindow(new BC_Title(x+xs100, y,
182 _("Translate endpoint\n"
190 int PerspectiveWindow::resize_event(int w, int h)
195 PerspectiveZoomView::PerspectiveZoomView(PerspectiveWindow *gui,
197 : BC_FSlider(x, y, 0, w, w, -2., 2.,
198 log10(gui->plugin->config.view_zoom < 0.01 ?
199 0.01 : gui->plugin->config.view_zoom))
202 set_precision(0.001);
203 set_tooltip(_("Zoom"));
205 PerspectiveZoomView::~PerspectiveZoomView()
208 int PerspectiveZoomView::handle_event()
210 float value = get_value();
211 BC_FSlider::update(value);
212 PerspectiveMain *plugin = gui->plugin;
213 float view_zoom = plugin->config.view_zoom;
214 double new_zoom = pow(10.,value);
215 double scale = new_zoom / view_zoom;
216 plugin->config.view_zoom = new_zoom;
217 plugin->config.view_x *= scale;
218 plugin->config.view_y *= scale;
219 gui->update_canvas();
220 plugin->send_configure_change();
224 char *PerspectiveZoomView::get_caption()
226 double value = get_value();
227 int frac = value >= 0. ? 1 : value >= -1. ? 2 : 3;
228 double zoom = pow(10., value);
229 char *caption = BC_Slider::get_caption();
230 sprintf(caption, "%.*f", frac, zoom);
234 void PerspectiveZoomView::update(float zoom)
236 if( zoom < 0.01 ) zoom = 0.01;
237 float value = log10f(zoom);
238 BC_FSlider::update(value);
241 void PerspectiveWindow::update_canvas()
243 int cw = canvas->get_w(), ch = canvas->get_h();
244 canvas->clear_box(0, 0, cw, ch);
245 int x1, y1, x2, y2, x3, y3, x4, y4;
246 calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
247 float x0 = cw / 2.0f, y0 = ch / 2.0f;
248 float view_zoom = plugin->config.view_zoom;
249 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
250 x1 = (x1-x0) * view_zoom + view_x + x0;
251 y1 = (y1-y0) * view_zoom + view_y + y0;
252 x2 = (x2-x0) * view_zoom + view_x + x0;
253 y2 = (y2-y0) * view_zoom + view_y + y0;
254 x3 = (x3-x0) * view_zoom + view_x + x0;
255 y3 = (y3-y0) * view_zoom + view_y + y0;
256 x4 = (x4-x0) * view_zoom + view_x + x0;
257 y4 = (y4-y0) * view_zoom + view_y + y0;
259 canvas->set_color(RED);
260 int vx1 = x0 - x0 * view_zoom + view_x;
261 int vy1 = y0 - y0 * view_zoom + view_y;
262 int vx2 = vx1 + cw * view_zoom - 1;
263 int vy2 = vy1 + ch * view_zoom - 1;
264 canvas->draw_line(vx1, vy1, vx2, vy1);
265 canvas->draw_line(vx2, vy1, vx2, vy2);
266 canvas->draw_line(vx2, vy2, vx1, vy2);
267 canvas->draw_line(vx1, vy2, vx1, vy1);
269 //printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
270 // x1, y1, x2, y2, x3, y3, x4, y4);
272 canvas->set_color(WHITE);
275 for( int i=0; i<=DIVISIONS; ++i ) {
276 canvas->draw_line( // latitude
277 x1 + (x4 - x1) * i / DIVISIONS,
278 y1 + (y4 - y1) * i / DIVISIONS,
279 x2 + (x3 - x2) * i / DIVISIONS,
280 y2 + (y3 - y2) * i / DIVISIONS);
281 canvas->draw_line( // longitude
282 x1 + (x2 - x1) * i / DIVISIONS,
283 y1 + (y2 - y1) * i / DIVISIONS,
284 x4 + (x3 - x4) * i / DIVISIONS,
285 y4 + (y3 - y4) * i / DIVISIONS);
290 if(plugin->config.current_point == 0)
291 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
293 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
295 if(plugin->config.current_point == 1)
296 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
298 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
300 if(plugin->config.current_point == 2)
301 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
303 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
305 if(plugin->config.current_point == 3)
306 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
308 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
313 void PerspectiveWindow::update_mode()
315 mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
316 mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
317 mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
318 forward->update(plugin->config.forward);
319 reverse->update(!plugin->config.forward);
322 void PerspectiveWindow::update_coord()
324 x->update(plugin->get_current_x());
325 y->update(plugin->get_current_y());
328 void PerspectiveWindow::update_view_zoom()
330 zoom_view->update(plugin->config.view_zoom);
333 void PerspectiveWindow::reset_view()
335 plugin->config.view_x = plugin->config.view_y = 0;
336 zoom_view->update(plugin->config.view_zoom = 1);
338 plugin->send_configure_change();
341 void PerspectiveWindow::calculate_canvas_coords(
342 int &x1, int &y1, int &x2, int &y2,
343 int &x3, int &y3, int &x4, int &y4)
345 int w = canvas->get_w() - 1;
346 int h = canvas->get_h() - 1;
347 if( plugin->config.mode == AffineEngine::PERSPECTIVE ||
348 plugin->config.mode == AffineEngine::STRETCH ) {
349 x1 = (int)(plugin->config.x1 * w / 100);
350 y1 = (int)(plugin->config.y1 * h / 100);
351 x2 = (int)(plugin->config.x2 * w / 100);
352 y2 = (int)(plugin->config.y2 * h / 100);
353 x3 = (int)(plugin->config.x3 * w / 100);
354 y3 = (int)(plugin->config.y3 * h / 100);
355 x4 = (int)(plugin->config.x4 * w / 100);
356 y4 = (int)(plugin->config.y4 * h / 100);
359 x1 = (int)(plugin->config.x1 * w) / 100;
363 x4 = (int)(plugin->config.x4 * w) / 100;
371 PerspectiveCanvas::PerspectiveCanvas(PerspectiveWindow *gui,
372 int x, int y, int w, int h)
373 : BC_SubWindow(x, y, w, h, BLACK)
376 state = PerspectiveCanvas::NONE;
380 int PerspectiveCanvas::button_press_event()
382 if( is_event_win() && cursor_inside() ) {
384 int cx = get_cursor_x(), cy = get_cursor_y();
385 if( alt_down() && shift_down() ) {
386 state = PerspectiveCanvas::DRAG_VIEW;
387 start_x = cx; start_y = cy;
391 PerspectiveMain *plugin = gui->plugin;
392 int x1, y1, x2, y2, x3, y3, x4, y4;
393 gui->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
394 float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
395 float x0 = cw / 2, y0 = ch / 2;
396 float view_zoom = plugin->config.view_zoom;
397 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
398 int x = (cx-x0 - view_x) / view_zoom + x0;
399 int y = (cy-y0 - view_y) / view_zoom + y0;
400 float distance1 = DISTANCE(x, y, x1, y1);
401 float distance2 = DISTANCE(x, y, x2, y2);
402 float distance3 = DISTANCE(x, y, x3, y3);
403 float distance4 = DISTANCE(x, y, x4, y4);
404 float min = distance1;
405 plugin->config.current_point = 0;
406 if( distance2 < min ) {
408 plugin->config.current_point = 1;
410 if( distance3 < min ) {
412 plugin->config.current_point = 2;
414 if( distance4 < min ) {
416 plugin->config.current_point = 3;
419 if( plugin->config.mode == AffineEngine::SHEER ) {
420 if( plugin->config.current_point == 1 )
421 plugin->config.current_point = 0;
422 else if( plugin->config.current_point == 2 )
423 plugin->config.current_point = 3;
427 if( alt_down() || shift_down() ) {
429 PerspectiveCanvas::DRAG_FULL :
430 PerspectiveCanvas::ZOOM;
431 // Get starting positions
432 start_x1 = plugin->config.x1;
433 start_y1 = plugin->config.y1;
434 start_x2 = plugin->config.x2;
435 start_y2 = plugin->config.y2;
436 start_x3 = plugin->config.x3;
437 start_y3 = plugin->config.y3;
438 start_x4 = plugin->config.x4;
439 start_y4 = plugin->config.y4;
442 state = PerspectiveCanvas::DRAG;
443 // Get starting positions
444 start_x1 = plugin->get_current_x();
445 start_y1 = plugin->get_current_y();
448 gui->update_canvas();
455 int PerspectiveCanvas::button_release_event()
457 if( state == PerspectiveCanvas::NONE ) return 0;
458 state = PerspectiveCanvas::NONE;
462 int PerspectiveCanvas::cursor_motion_event()
464 if( state == PerspectiveCanvas::NONE ) return 0;
465 PerspectiveMain *plugin = gui->plugin;
466 int cx = get_cursor_x(), cy = get_cursor_y();
467 if( state != PerspectiveCanvas::DRAG_VIEW ) {
468 float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
469 float x0 = cw / 2, y0 = ch / 2;
470 float view_zoom = plugin->config.view_zoom;
471 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
472 int x = (cx-x0 - view_x) / view_zoom + x0;
473 int y = (cy-y0 - view_y) / view_zoom + y0;
474 int w1 = get_w() - 1, h1 = get_h() - 1;
477 case PerspectiveCanvas::DRAG:
478 plugin->set_current_x((float)(x - start_x) / w1 * 100 + start_x1);
479 plugin->set_current_y((float)(y - start_y) / h1 * 100 + start_y1);
481 case PerspectiveCanvas::DRAG_FULL:
482 plugin->config.x1 = ((float)(x - start_x) / w1 * 100 + start_x1);
483 plugin->config.y1 = ((float)(y - start_y) / h1 * 100 + start_y1);
484 plugin->config.x2 = ((float)(x - start_x) / w1 * 100 + start_x2);
485 plugin->config.y2 = ((float)(y - start_y) / h1 * 100 + start_y2);
486 plugin->config.x3 = ((float)(x - start_x) / w1 * 100 + start_x3);
487 plugin->config.y3 = ((float)(y - start_y) / h1 * 100 + start_y3);
488 plugin->config.x4 = ((float)(x - start_x) / w1 * 100 + start_x4);
489 plugin->config.y4 = ((float)(y - start_y) / h1 * 100 + start_y4);
491 case PerspectiveCanvas::ZOOM:
492 float center_x = (start_x1 + start_x2 + start_x3 + start_x4) / 4;
493 float center_y = (start_y1 + start_y2 + start_y3 + start_y4) / 4;
494 float zoom = (float)(get_cursor_y() - start_y + 640) / 640;
495 plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
496 plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
497 plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
498 plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
499 plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
500 plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
501 plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
502 plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
508 plugin->config.view_x += cx - start_x;
509 plugin->config.view_y += cy - start_y;
510 start_x = cx; start_y = cy;
512 gui->update_canvas();
513 plugin->send_configure_change();
518 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
519 int x, int y, float value, int is_x)
520 : BC_TumbleTextBox(gui, value, -100.f, 200.f, x, y, xS(70))
527 int PerspectiveCoord::handle_event()
529 PerspectiveMain *plugin = gui->plugin;
530 float v = atof(get_text());
532 plugin->set_current_x(v);
534 plugin->set_current_y(v);
535 gui->update_canvas();
536 plugin->send_configure_change();
541 PerspectiveReset::PerspectiveReset(PerspectiveWindow *gui, int x, int y)
542 : BC_GenericButton(x, y, _("Reset"))
546 int PerspectiveReset::handle_event()
550 PerspectiveMain *plugin = gui->plugin;
551 plugin->config.x1 = 0; plugin->config.y1 = 0;
552 plugin->config.x2 = 100; plugin->config.y2 = 0;
553 plugin->config.x3 = 100; plugin->config.y3 = 100;
554 plugin->config.x4 = 0; plugin->config.y4 = 100;
555 gui->update_canvas();
557 plugin->send_configure_change();
562 PerspectiveMode::PerspectiveMode(PerspectiveWindow *gui,
563 int x, int y, int value, char *text)
564 : BC_Radial(x, y, gui->plugin->config.mode == value, text)
569 int PerspectiveMode::handle_event()
571 PerspectiveMain *plugin = gui->plugin;
572 plugin->config.mode = value;
574 gui->update_canvas();
575 plugin->send_configure_change();
580 PerspectiveDirection::PerspectiveDirection(PerspectiveWindow *gui,
581 int x, int y, int value, char *text)
582 : BC_Radial(x, y, gui->plugin->config.forward == value, text)
587 int PerspectiveDirection::handle_event()
589 PerspectiveMain *plugin = gui->plugin;
590 plugin->config.forward = value;
592 plugin->send_configure_change();
597 int PerspectiveAffineItem::handle_event()
599 ((PerspectiveAffine *)get_popup_menu())->update(id);
603 PerspectiveAffine::PerspectiveAffine(PerspectiveWindow *gui, int x, int y)
604 : BC_PopupMenu(x, y, xS(100), "", 1)
607 affine_modes[AffineEngine::AF_DEFAULT] = _("default");
608 affine_modes[AffineEngine::AF_NEAREST] = _("Nearest");
609 affine_modes[AffineEngine::AF_LINEAR] = _("Linear");
610 affine_modes[AffineEngine::AF_CUBIC] = _("Cubic");
613 PerspectiveAffine::~PerspectiveAffine()
615 int id = total_items();
617 remove_item(get_item(id));
618 for( int id=0; id<n_modes; ++id )
619 delete affine_items[id];
621 void PerspectiveAffine::affine_item(int id)
623 affine_items[id] = new PerspectiveAffineItem(affine_modes[id], id);
624 add_item(affine_items[id]);
627 void PerspectiveAffine::create_objects()
629 affine_item(AffineEngine::AF_DEFAULT);
630 affine_item(AffineEngine::AF_NEAREST);
631 affine_item(AffineEngine::AF_LINEAR);
632 affine_item(AffineEngine::AF_CUBIC);
633 PerspectiveMain *plugin = gui->plugin;
634 update(plugin->config.smoothing, 0);
637 void PerspectiveAffine::update(int mode, int send)
639 if( this->mode == mode ) return;
641 set_text(affine_modes[mode]);
642 PerspectiveMain *plugin = gui->plugin;
643 plugin->config.smoothing = mode;
644 if( send ) plugin->send_configure_change();
647 PerspectiveMain::PerspectiveMain(PluginServer *server)
648 : PluginVClient(server)
655 PerspectiveMain::~PerspectiveMain()
658 if(engine) delete engine;
659 if(temp) delete temp;
662 const char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
663 int PerspectiveMain::is_realtime() { return 1; }
666 NEW_WINDOW_MACRO(PerspectiveMain, PerspectiveWindow)
668 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
670 void PerspectiveMain::update_gui()
672 if( !thread ) return;
673 //printf("PerspectiveMain::update_gui 1\n");
674 thread->window->lock_window();
675 PerspectiveWindow *gui = (PerspectiveWindow*)thread->window;
676 //printf("PerspectiveMain::update_gui 2\n");
677 load_configuration();
680 gui->update_view_zoom();
681 gui->update_canvas();
682 thread->window->unlock_window();
683 //printf("PerspectiveMain::update_gui 3\n");
690 void PerspectiveMain::save_data(KeyFrame *keyframe)
694 // cause data to be stored directly in text
695 output.set_shared_output(keyframe->xbuf);
696 output.tag.set_title("PERSPECTIVE");
698 output.tag.set_property("X1", config.x1);
699 output.tag.set_property("X2", config.x2);
700 output.tag.set_property("X3", config.x3);
701 output.tag.set_property("X4", config.x4);
702 output.tag.set_property("Y1", config.y1);
703 output.tag.set_property("Y2", config.y2);
704 output.tag.set_property("Y3", config.y3);
705 output.tag.set_property("Y4", config.y4);
707 output.tag.set_property("MODE", config.mode);
708 output.tag.set_property("VIEW_X", config.view_x);
709 output.tag.set_property("VIEW_Y", config.view_y);
710 output.tag.set_property("VIEW_ZOOM", config.view_zoom);
711 output.tag.set_property("SMOOTHING", config.smoothing);
712 output.tag.set_property("FORWARD", config.forward);
713 output.tag.set_property("WINDOW_W", config.window_w);
714 output.tag.set_property("WINDOW_H", config.window_h);
716 output.tag.set_title("/PERSPECTIVE");
718 output.append_newline();
719 output.terminate_string();
722 void PerspectiveMain::read_data(KeyFrame *keyframe)
725 input.set_shared_input(keyframe->xbuf);
728 while(!(result = input.read_tag()) ) {
729 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.view_x = input.tag.get_property("VIEW_X", config.view_x);
741 config.view_y = input.tag.get_property("VIEW_Y", config.view_y);
742 config.view_zoom = input.tag.get_property("VIEW_ZOOM", config.view_zoom);
743 config.smoothing = input.tag.get_property("SMOOTHING", config.smoothing);
744 config.forward = input.tag.get_property("FORWARD", config.forward);
745 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
746 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
751 float PerspectiveMain::get_current_x()
753 switch( config.current_point ) {
754 case 0: return config.x1;
755 case 1: return config.x2;
756 case 2: return config.x3;
757 case 3: return config.x4;
762 float PerspectiveMain::get_current_y()
764 switch( config.current_point ) {
765 case 0: return config.y1;
766 case 1: return config.y2;
767 case 2: return config.y3;
768 case 3: return config.y4;
773 void PerspectiveMain::set_current_x(float value)
775 switch( config.current_point ) {
776 case 0: config.x1 = value; break;
777 case 1: config.x2 = value; break;
778 case 2: config.x3 = value; break;
779 case 3: config.x4 = value; break;
783 void PerspectiveMain::set_current_y(float value)
785 switch( config.current_point ) {
786 case 0: config.y1 = value; break;
787 case 1: config.y2 = value; break;
788 case 2: config.y3 = value; break;
789 case 3: config.y4 = value; break;
793 int PerspectiveMain::process_buffer(VFrame *frame,
794 int64_t start_position, double frame_rate)
796 /*int need_reconfigure =*/ load_configuration();
797 int smoothing = config.smoothing;
798 // default smoothing uses opengl if possible
799 int use_opengl = smoothing != AffineEngine::AF_DEFAULT ? 0 :
800 // Opengl does some funny business with stretching.
801 config.mode == AffineEngine::PERSPECTIVE ||
802 config.mode == AffineEngine::SHEER ? get_use_opengl() : 0;
804 read_frame(frame, 0, start_position, frame_rate, use_opengl);
808 if( EQUIV(config.x1, 0) && EQUIV(config.y1, 0) &&
809 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
810 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
811 EQUIV(config.x4, 0) && EQUIV(config.y4, 100) )
815 int cpus = get_project_smp() + 1;
816 engine = new AffineEngine(cpus, cpus);
818 engine->set_interpolation(smoothing);
824 this->output = frame;
826 int w = frame->get_w(), need_w = w;
827 int h = frame->get_h(), need_h = h;
828 int color_model = frame->get_color_model();
829 switch( config.mode ) {
830 case AffineEngine::STRETCH:
831 need_w *= AFFINE_OVERSAMPLE;
832 need_h *= AFFINE_OVERSAMPLE;
833 case AffineEngine::SHEER:
834 case AffineEngine::PERSPECTIVE:
836 if( temp->get_w() != need_w || temp->get_h() != need_h ||
837 temp->get_color_model() != color_model ) {
838 delete temp; temp = 0;
842 temp = new VFrame(need_w, need_h, color_model, 0);
845 switch( config.mode ) {
846 case AffineEngine::STRETCH:
849 case AffineEngine::PERSPECTIVE:
850 case AffineEngine::SHEER:
851 temp->copy_from(input);
853 output->clear_frame();
856 delete temp; temp = 0;
860 engine->process(output, input, temp, config.mode,
861 config.x1, config.y1, config.x2, config.y2,
862 config.x3, config.y3, config.x4, config.y4,
867 if( config.mode == AffineEngine::STRETCH ) {
869 #define RESAMPLE(tag, type, components, chroma_offset) \
871 int os = AFFINE_OVERSAMPLE, os2 = os*os; \
872 for( int i=0; i<h; ++i ) { \
873 type *out_row = (type*)output->get_rows()[i]; \
874 type *in_row1 = (type*)temp->get_rows()[i * os]; \
875 type *in_row2 = (type*)temp->get_rows()[i * os + 1]; \
876 for( int j=0; j<w; ++j ) { \
878 ( in_row1[0] + in_row1[components + 0] + \
879 in_row2[0] + in_row2[components + 0] ) / os2; \
881 ( in_row1[1] + in_row1[components + 1] + \
882 in_row2[1] + in_row2[components + 1] ) / os2; \
884 ( in_row1[2] + in_row1[components + 2] + \
885 in_row2[2] + in_row2[components + 2] ) / os2; \
886 if( components == 4 ) { \
888 ( in_row1[3] + in_row1[components + 3] + \
889 in_row2[3] + in_row2[components + 3] ) / os2; \
891 out_row += components; \
892 in_row1 += components * os; \
893 in_row2 += components * os; \
898 switch( frame->get_color_model() ) {
899 RESAMPLE( BC_RGB_FLOAT, float, 3, 0 );
900 RESAMPLE( BC_RGB888, unsigned char, 3, 0 );
901 RESAMPLE( BC_RGBA_FLOAT, float, 4, 0 );
902 RESAMPLE( BC_RGBA8888, unsigned char, 4, 0 );
903 RESAMPLE( BC_YUV888, unsigned char, 3, 0x80 );
904 RESAMPLE( BC_YUVA8888, unsigned char, 4, 0x80 );
905 RESAMPLE( BC_RGB161616, uint16_t, 3, 0 );
906 RESAMPLE( BC_RGBA16161616, uint16_t, 4, 0 );
907 RESAMPLE( BC_YUV161616, uint16_t, 3, 0x8000 );
908 RESAMPLE( BC_YUVA16161616, uint16_t, 4, 0x8000 );
916 int PerspectiveMain::handle_opengl()
919 engine->set_opengl(1);
920 engine->process(get_output(), get_output(), get_output(), config.mode,
921 config.x1, config.y1, config.x2, config.y2,
922 config.x3, config.y3, config.x4, config.y4,
924 engine->set_opengl(0);