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), 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;
133 add_subwindow(title = new BC_Title(x1, y, _("Current: ")));
134 x1 += title->get_w() + xs10;
135 char string[BCSTRLEN];
136 sprintf(string, "%d", plugin->config.current_point+1);
137 add_subwindow(curr_point = new BC_Title(x1, y, string));
139 add_subwindow(title = new BC_Title(x1, y, _("X:")));
140 x1 += title->get_w() + xs10;
141 this->x = new PerspectiveCoord(this,
142 x1, y, plugin->get_current_x(), 1);
143 this->x->create_objects();
144 x1 += this->x->get_w() + xs20;
145 add_subwindow(new BC_Title(x1, y, _("Y:")));
146 x1 += title->get_w() + xs10;
147 this->y = new PerspectiveCoord(this,
148 x1, y, plugin->get_current_y(), 0);
149 this->y->create_objects();
151 add_subwindow(mode_perspective = new PerspectiveMode(this,
152 x, y, AffineEngine::PERSPECTIVE, _("Perspective")));
154 add_subwindow(mode_sheer = new PerspectiveMode(this,
155 x, y, AffineEngine::SHEER, _("Sheer")));
157 add_subwindow(affine = new PerspectiveAffine(this, x, y));
158 affine->create_objects();
160 add_subwindow(mode_stretch = new PerspectiveMode(this,
161 x, y, AffineEngine::STRETCH, _("Stretch")));
163 add_subwindow(new PerspectiveReset(this, x, y));
167 add_subwindow(title = new BC_Title(x, y, _("Zoom view:")));
168 x1 = x + title->get_w() + xs10;
169 int w1 = get_w() - x1 - xs10;
170 add_subwindow(zoom_view = new PerspectiveZoomView(this, x1, y, w1));
173 add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
175 add_subwindow(forward = new PerspectiveDirection(this,
176 x, y, 1, _("Forward")));
178 add_subwindow(reverse = new PerspectiveDirection(this,
179 x, y, 0, _("Reverse")));
181 add_subwindow(title = new BC_Title(x, y, _("Alt/Shift:")));
182 add_subwindow(new BC_Title(x+xs100, y, _("Button1 Action:")));
183 y += title->get_h() + ys5;
184 add_subwindow(new BC_Title(x, y,
189 add_subwindow(new BC_Title(x+xs100, y,
190 _("Translate endpoint\n"
198 int PerspectiveWindow::resize_event(int w, int h)
203 PerspectiveZoomView::PerspectiveZoomView(PerspectiveWindow *gui,
205 : BC_FSlider(x, y, 0, w, w, -2., 2.,
206 log10(gui->plugin->config.view_zoom < 0.01 ?
207 0.01 : gui->plugin->config.view_zoom))
210 set_precision(0.001);
211 set_tooltip(_("Zoom"));
213 PerspectiveZoomView::~PerspectiveZoomView()
216 int PerspectiveZoomView::handle_event()
218 float value = get_value();
219 BC_FSlider::update(value);
220 PerspectiveMain *plugin = gui->plugin;
221 float view_zoom = plugin->config.view_zoom;
222 double new_zoom = pow(10.,value);
223 double scale = new_zoom / view_zoom;
224 plugin->config.view_zoom = new_zoom;
225 plugin->config.view_x *= scale;
226 plugin->config.view_y *= scale;
227 gui->update_canvas();
228 plugin->send_configure_change();
232 char *PerspectiveZoomView::get_caption()
234 double value = get_value();
235 int frac = value >= 0. ? 1 : value >= -1. ? 2 : 3;
236 double zoom = pow(10., value);
237 char *caption = BC_Slider::get_caption();
238 sprintf(caption, "%.*f", frac, zoom);
242 void PerspectiveZoomView::update(float zoom)
244 if( zoom < 0.01 ) zoom = 0.01;
245 float value = log10f(zoom);
246 BC_FSlider::update(value);
249 void PerspectiveWindow::update_canvas()
251 int cw = canvas->get_w(), ch = canvas->get_h();
252 canvas->clear_box(0, 0, cw, ch);
253 int x1, y1, x2, y2, x3, y3, x4, y4;
254 calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
255 float x0 = cw / 2.0f, y0 = ch / 2.0f;
256 float view_zoom = plugin->config.view_zoom;
257 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
258 x1 = (x1-x0) * view_zoom + view_x + x0;
259 y1 = (y1-y0) * view_zoom + view_y + y0;
260 x2 = (x2-x0) * view_zoom + view_x + x0;
261 y2 = (y2-y0) * view_zoom + view_y + y0;
262 x3 = (x3-x0) * view_zoom + view_x + x0;
263 y3 = (y3-y0) * view_zoom + view_y + y0;
264 x4 = (x4-x0) * view_zoom + view_x + x0;
265 y4 = (y4-y0) * view_zoom + view_y + y0;
267 canvas->set_color(RED);
268 int vx1 = x0 - x0 * view_zoom + view_x;
269 int vy1 = y0 - y0 * view_zoom + view_y;
270 int vx2 = vx1 + cw * view_zoom - 1;
271 int vy2 = vy1 + ch * view_zoom - 1;
272 canvas->draw_line(vx1, vy1, vx2, vy1);
273 canvas->draw_line(vx2, vy1, vx2, vy2);
274 canvas->draw_line(vx2, vy2, vx1, vy2);
275 canvas->draw_line(vx1, vy2, vx1, vy1);
277 canvas->set_color(YELLOW);
278 canvas->draw_text(x1, y1,"1");
279 canvas->draw_text(x2, y2,"2");
280 canvas->draw_text(x3, y3,"3");
281 canvas->draw_text(x4, y4,"4");
283 //printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
284 // x1, y1, x2, y2, x3, y3, x4, y4);
286 canvas->set_color(WHITE);
289 for( int i=0; i<=DIVISIONS; ++i ) {
290 canvas->draw_line( // latitude
291 x1 + (x4 - x1) * i / DIVISIONS,
292 y1 + (y4 - y1) * i / DIVISIONS,
293 x2 + (x3 - x2) * i / DIVISIONS,
294 y2 + (y3 - y2) * i / DIVISIONS);
295 canvas->draw_line( // longitude
296 x1 + (x2 - x1) * i / DIVISIONS,
297 y1 + (y2 - y1) * i / DIVISIONS,
298 x4 + (x3 - x4) * i / DIVISIONS,
299 y4 + (y3 - y4) * i / DIVISIONS);
304 if(plugin->config.current_point == 0)
305 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
307 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
309 if(plugin->config.current_point == 1)
310 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
312 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
314 if(plugin->config.current_point == 2)
315 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
317 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
319 if(plugin->config.current_point == 3)
320 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
322 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
327 void PerspectiveWindow::update_mode()
329 mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
330 mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
331 mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
332 forward->update(plugin->config.forward);
333 reverse->update(!plugin->config.forward);
336 void PerspectiveWindow::update_coord()
338 char string[BCSTRLEN];
339 sprintf(string, "%d", plugin->config.current_point+1);
340 curr_point->update(string);
341 x->update(plugin->get_current_x());
342 y->update(plugin->get_current_y());
345 void PerspectiveWindow::update_view_zoom()
347 zoom_view->update(plugin->config.view_zoom);
350 void PerspectiveWindow::reset_view()
352 plugin->config.view_x = plugin->config.view_y = 0;
353 zoom_view->update(plugin->config.view_zoom = 1);
355 plugin->send_configure_change();
358 void PerspectiveWindow::calculate_canvas_coords(
359 int &x1, int &y1, int &x2, int &y2,
360 int &x3, int &y3, int &x4, int &y4)
362 int w = canvas->get_w() - 1;
363 int h = canvas->get_h() - 1;
364 if( plugin->config.mode == AffineEngine::PERSPECTIVE ||
365 plugin->config.mode == AffineEngine::STRETCH ) {
366 x1 = (int)(plugin->config.x1 * w / 100);
367 y1 = (int)(plugin->config.y1 * h / 100);
368 x2 = (int)(plugin->config.x2 * w / 100);
369 y2 = (int)(plugin->config.y2 * h / 100);
370 x3 = (int)(plugin->config.x3 * w / 100);
371 y3 = (int)(plugin->config.y3 * h / 100);
372 x4 = (int)(plugin->config.x4 * w / 100);
373 y4 = (int)(plugin->config.y4 * h / 100);
376 x1 = (int)(plugin->config.x1 * w) / 100;
380 x4 = (int)(plugin->config.x4 * w) / 100;
388 PerspectiveCanvas::PerspectiveCanvas(PerspectiveWindow *gui,
389 int x, int y, int w, int h)
390 : BC_SubWindow(x, y, w, h, BLACK)
393 state = PerspectiveCanvas::NONE;
397 int PerspectiveCanvas::button_press_event()
399 if( is_event_win() && cursor_inside() ) {
401 int cx = get_cursor_x(), cy = get_cursor_y();
402 if( alt_down() && shift_down() ) {
403 state = PerspectiveCanvas::DRAG_VIEW;
404 start_x = cx; start_y = cy;
408 PerspectiveMain *plugin = gui->plugin;
409 int x1, y1, x2, y2, x3, y3, x4, y4;
410 gui->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
411 float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
412 float x0 = cw / 2, y0 = ch / 2;
413 float view_zoom = plugin->config.view_zoom;
414 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
415 int x = (cx-x0 - view_x) / view_zoom + x0;
416 int y = (cy-y0 - view_y) / view_zoom + y0;
417 float distance1 = DISTANCE(x, y, x1, y1);
418 float distance2 = DISTANCE(x, y, x2, y2);
419 float distance3 = DISTANCE(x, y, x3, y3);
420 float distance4 = DISTANCE(x, y, x4, y4);
421 float min = distance1;
422 plugin->config.current_point = 0;
423 if( distance2 < min ) {
425 plugin->config.current_point = 1;
427 if( distance3 < min ) {
429 plugin->config.current_point = 2;
431 if( distance4 < min ) {
433 plugin->config.current_point = 3;
436 if( plugin->config.mode == AffineEngine::SHEER ) {
437 if( plugin->config.current_point == 1 )
438 plugin->config.current_point = 0;
439 else if( plugin->config.current_point == 2 )
440 plugin->config.current_point = 3;
444 if( alt_down() || shift_down() ) {
446 PerspectiveCanvas::DRAG_FULL :
447 PerspectiveCanvas::ZOOM;
448 // Get starting positions
449 start_x1 = plugin->config.x1;
450 start_y1 = plugin->config.y1;
451 start_x2 = plugin->config.x2;
452 start_y2 = plugin->config.y2;
453 start_x3 = plugin->config.x3;
454 start_y3 = plugin->config.y3;
455 start_x4 = plugin->config.x4;
456 start_y4 = plugin->config.y4;
459 state = PerspectiveCanvas::DRAG;
460 // Get starting positions
461 start_x1 = plugin->get_current_x();
462 start_y1 = plugin->get_current_y();
465 gui->update_canvas();
472 int PerspectiveCanvas::button_release_event()
474 if( state == PerspectiveCanvas::NONE ) return 0;
475 state = PerspectiveCanvas::NONE;
479 int PerspectiveCanvas::cursor_motion_event()
481 if( state == PerspectiveCanvas::NONE ) return 0;
482 PerspectiveMain *plugin = gui->plugin;
483 int cx = get_cursor_x(), cy = get_cursor_y();
484 if( state != PerspectiveCanvas::DRAG_VIEW ) {
485 float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
486 float x0 = cw / 2, y0 = ch / 2;
487 float view_zoom = plugin->config.view_zoom;
488 float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
489 int x = (cx-x0 - view_x) / view_zoom + x0;
490 int y = (cy-y0 - view_y) / view_zoom + y0;
491 int w1 = get_w() - 1, h1 = get_h() - 1;
494 case PerspectiveCanvas::DRAG:
495 plugin->set_current_x((float)(x - start_x) / w1 * 100 + start_x1);
496 plugin->set_current_y((float)(y - start_y) / h1 * 100 + start_y1);
498 case PerspectiveCanvas::DRAG_FULL:
499 plugin->config.x1 = ((float)(x - start_x) / w1 * 100 + start_x1);
500 plugin->config.y1 = ((float)(y - start_y) / h1 * 100 + start_y1);
501 plugin->config.x2 = ((float)(x - start_x) / w1 * 100 + start_x2);
502 plugin->config.y2 = ((float)(y - start_y) / h1 * 100 + start_y2);
503 plugin->config.x3 = ((float)(x - start_x) / w1 * 100 + start_x3);
504 plugin->config.y3 = ((float)(y - start_y) / h1 * 100 + start_y3);
505 plugin->config.x4 = ((float)(x - start_x) / w1 * 100 + start_x4);
506 plugin->config.y4 = ((float)(y - start_y) / h1 * 100 + start_y4);
508 case PerspectiveCanvas::ZOOM:
509 float center_x = (start_x1 + start_x2 + start_x3 + start_x4) / 4;
510 float center_y = (start_y1 + start_y2 + start_y3 + start_y4) / 4;
511 float zoom = (float)(get_cursor_y() - start_y + 640) / 640;
512 plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
513 plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
514 plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
515 plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
516 plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
517 plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
518 plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
519 plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
525 plugin->config.view_x += cx - start_x;
526 plugin->config.view_y += cy - start_y;
527 start_x = cx; start_y = cy;
529 gui->update_canvas();
530 plugin->send_configure_change();
535 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
536 int x, int y, float value, int is_x)
537 : BC_TumbleTextBox(gui, value, -100.f, 200.f, x, y, xS(70))
544 int PerspectiveCoord::handle_event()
546 PerspectiveMain *plugin = gui->plugin;
547 float v = atof(get_text());
549 plugin->set_current_x(v);
551 plugin->set_current_y(v);
552 gui->update_canvas();
553 plugin->send_configure_change();
558 PerspectiveReset::PerspectiveReset(PerspectiveWindow *gui, int x, int y)
559 : BC_GenericButton(x, y, _("Reset"))
563 int PerspectiveReset::handle_event()
567 PerspectiveMain *plugin = gui->plugin;
568 plugin->config.x1 = 0; plugin->config.y1 = 0;
569 plugin->config.x2 = 100; plugin->config.y2 = 0;
570 plugin->config.x3 = 100; plugin->config.y3 = 100;
571 plugin->config.x4 = 0; plugin->config.y4 = 100;
572 gui->update_canvas();
574 plugin->send_configure_change();
579 PerspectiveMode::PerspectiveMode(PerspectiveWindow *gui,
580 int x, int y, int value, char *text)
581 : BC_Radial(x, y, gui->plugin->config.mode == value, text)
586 int PerspectiveMode::handle_event()
588 PerspectiveMain *plugin = gui->plugin;
589 plugin->config.mode = value;
591 gui->update_canvas();
592 plugin->send_configure_change();
597 PerspectiveDirection::PerspectiveDirection(PerspectiveWindow *gui,
598 int x, int y, int value, char *text)
599 : BC_Radial(x, y, gui->plugin->config.forward == value, text)
604 int PerspectiveDirection::handle_event()
606 PerspectiveMain *plugin = gui->plugin;
607 plugin->config.forward = value;
609 plugin->send_configure_change();
614 int PerspectiveAffineItem::handle_event()
616 ((PerspectiveAffine *)get_popup_menu())->update(id);
620 PerspectiveAffine::PerspectiveAffine(PerspectiveWindow *gui, int x, int y)
621 : BC_PopupMenu(x, y, xS(100), "", 1)
624 affine_modes[AffineEngine::AF_DEFAULT] = _("default");
625 affine_modes[AffineEngine::AF_NEAREST] = _("Nearest");
626 affine_modes[AffineEngine::AF_LINEAR] = _("Linear");
627 affine_modes[AffineEngine::AF_CUBIC] = _("Cubic");
630 PerspectiveAffine::~PerspectiveAffine()
632 int id = total_items();
634 remove_item(get_item(id));
635 for( int id=0; id<n_modes; ++id )
636 delete affine_items[id];
638 void PerspectiveAffine::affine_item(int id)
640 affine_items[id] = new PerspectiveAffineItem(affine_modes[id], id);
641 add_item(affine_items[id]);
644 void PerspectiveAffine::create_objects()
646 affine_item(AffineEngine::AF_DEFAULT);
647 affine_item(AffineEngine::AF_NEAREST);
648 affine_item(AffineEngine::AF_LINEAR);
649 affine_item(AffineEngine::AF_CUBIC);
650 PerspectiveMain *plugin = gui->plugin;
651 update(plugin->config.smoothing, 0);
654 void PerspectiveAffine::update(int mode, int send)
656 if( this->mode == mode ) return;
658 set_text(affine_modes[mode]);
659 PerspectiveMain *plugin = gui->plugin;
660 plugin->config.smoothing = mode;
661 if( send ) plugin->send_configure_change();
664 PerspectiveMain::PerspectiveMain(PluginServer *server)
665 : PluginVClient(server)
672 PerspectiveMain::~PerspectiveMain()
675 if(engine) delete engine;
676 if(temp) delete temp;
679 const char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
680 int PerspectiveMain::is_realtime() { return 1; }
683 NEW_WINDOW_MACRO(PerspectiveMain, PerspectiveWindow)
685 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
687 void PerspectiveMain::update_gui()
689 if( !thread ) return;
690 //printf("PerspectiveMain::update_gui 1\n");
691 thread->window->lock_window();
692 PerspectiveWindow *gui = (PerspectiveWindow*)thread->window;
693 //printf("PerspectiveMain::update_gui 2\n");
694 load_configuration();
697 gui->update_view_zoom();
698 gui->update_canvas();
699 thread->window->unlock_window();
700 //printf("PerspectiveMain::update_gui 3\n");
707 void PerspectiveMain::save_data(KeyFrame *keyframe)
711 // cause data to be stored directly in text
712 output.set_shared_output(keyframe->xbuf);
713 output.tag.set_title("PERSPECTIVE");
715 output.tag.set_property("X1", config.x1);
716 output.tag.set_property("X2", config.x2);
717 output.tag.set_property("X3", config.x3);
718 output.tag.set_property("X4", config.x4);
719 output.tag.set_property("Y1", config.y1);
720 output.tag.set_property("Y2", config.y2);
721 output.tag.set_property("Y3", config.y3);
722 output.tag.set_property("Y4", config.y4);
724 output.tag.set_property("MODE", config.mode);
725 output.tag.set_property("VIEW_X", config.view_x);
726 output.tag.set_property("VIEW_Y", config.view_y);
727 output.tag.set_property("VIEW_ZOOM", config.view_zoom);
728 output.tag.set_property("SMOOTHING", config.smoothing);
729 output.tag.set_property("FORWARD", config.forward);
730 output.tag.set_property("WINDOW_W", config.window_w);
731 output.tag.set_property("WINDOW_H", config.window_h);
733 output.tag.set_title("/PERSPECTIVE");
735 output.append_newline();
736 output.terminate_string();
739 void PerspectiveMain::read_data(KeyFrame *keyframe)
742 input.set_shared_input(keyframe->xbuf);
745 while(!(result = input.read_tag()) ) {
746 if(input.tag.title_is("PERSPECTIVE")) {
747 config.x1 = input.tag.get_property("X1", config.x1);
748 config.x2 = input.tag.get_property("X2", config.x2);
749 config.x3 = input.tag.get_property("X3", config.x3);
750 config.x4 = input.tag.get_property("X4", config.x4);
751 config.y1 = input.tag.get_property("Y1", config.y1);
752 config.y2 = input.tag.get_property("Y2", config.y2);
753 config.y3 = input.tag.get_property("Y3", config.y3);
754 config.y4 = input.tag.get_property("Y4", config.y4);
756 config.mode = input.tag.get_property("MODE", config.mode);
757 config.view_x = input.tag.get_property("VIEW_X", config.view_x);
758 config.view_y = input.tag.get_property("VIEW_Y", config.view_y);
759 config.view_zoom = input.tag.get_property("VIEW_ZOOM", config.view_zoom);
760 config.smoothing = input.tag.get_property("SMOOTHING", config.smoothing);
761 config.forward = input.tag.get_property("FORWARD", config.forward);
762 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
763 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
768 float PerspectiveMain::get_current_x()
770 switch( config.current_point ) {
771 case 0: return config.x1;
772 case 1: return config.x2;
773 case 2: return config.x3;
774 case 3: return config.x4;
779 float PerspectiveMain::get_current_y()
781 switch( config.current_point ) {
782 case 0: return config.y1;
783 case 1: return config.y2;
784 case 2: return config.y3;
785 case 3: return config.y4;
790 void PerspectiveMain::set_current_x(float value)
792 switch( config.current_point ) {
793 case 0: config.x1 = value; break;
794 case 1: config.x2 = value; break;
795 case 2: config.x3 = value; break;
796 case 3: config.x4 = value; break;
800 void PerspectiveMain::set_current_y(float value)
802 switch( config.current_point ) {
803 case 0: config.y1 = value; break;
804 case 1: config.y2 = value; break;
805 case 2: config.y3 = value; break;
806 case 3: config.y4 = value; break;
810 int PerspectiveMain::process_buffer(VFrame *frame,
811 int64_t start_position, double frame_rate)
813 /*int need_reconfigure =*/ load_configuration();
814 int smoothing = config.smoothing;
815 // default smoothing uses opengl if possible
816 int use_opengl = smoothing != AffineEngine::AF_DEFAULT ? 0 :
817 // Opengl does some funny business with stretching.
818 config.mode == AffineEngine::PERSPECTIVE ||
819 config.mode == AffineEngine::SHEER ? get_use_opengl() : 0;
821 read_frame(frame, 0, start_position, frame_rate, use_opengl);
825 if( EQUIV(config.x1, 0) && EQUIV(config.y1, 0) &&
826 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
827 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
828 EQUIV(config.x4, 0) && EQUIV(config.y4, 100) )
830 if( config.mode == AffineEngine::PERSPECTIVE &&
831 ( (EQUIV(config.x1, config.x2) && EQUIV(config.x3, config.x4)) ||
832 (EQUIV(config.y1, config.y3) && EQUIV(config.y2, config.y4)) ) ) {
833 frame->clear_frame();
838 int cpus = get_project_smp() + 1;
839 engine = new AffineEngine(cpus, cpus);
841 engine->set_interpolation(smoothing);
847 this->output = frame;
849 int w = frame->get_w(), need_w = w;
850 int h = frame->get_h(), need_h = h;
851 int color_model = frame->get_color_model();
852 switch( config.mode ) {
853 case AffineEngine::STRETCH:
854 need_w *= AFFINE_OVERSAMPLE;
855 need_h *= AFFINE_OVERSAMPLE;
856 case AffineEngine::SHEER:
857 case AffineEngine::PERSPECTIVE:
859 if( temp->get_w() != need_w || temp->get_h() != need_h ||
860 temp->get_color_model() != color_model ) {
861 delete temp; temp = 0;
865 temp = new VFrame(need_w, need_h, color_model, 0);
868 switch( config.mode ) {
869 case AffineEngine::STRETCH:
872 case AffineEngine::PERSPECTIVE:
873 case AffineEngine::SHEER:
874 temp->copy_from(input);
876 output->clear_frame();
879 delete temp; temp = 0;
883 engine->process(output, input, temp, config.mode,
884 config.x1, config.y1, config.x2, config.y2,
885 config.x3, config.y3, config.x4, config.y4,
890 if( config.mode == AffineEngine::STRETCH ) {
892 #define RESAMPLE(tag, type, components, chroma_offset) \
894 int os = AFFINE_OVERSAMPLE, os2 = os*os; \
895 for( int i=0; i<h; ++i ) { \
896 type *out_row = (type*)output->get_rows()[i]; \
897 type *in_row1 = (type*)temp->get_rows()[i * os]; \
898 type *in_row2 = (type*)temp->get_rows()[i * os + 1]; \
899 for( int j=0; j<w; ++j ) { \
901 ( in_row1[0] + in_row1[components + 0] + \
902 in_row2[0] + in_row2[components + 0] ) / os2; \
904 ( in_row1[1] + in_row1[components + 1] + \
905 in_row2[1] + in_row2[components + 1] ) / os2; \
907 ( in_row1[2] + in_row1[components + 2] + \
908 in_row2[2] + in_row2[components + 2] ) / os2; \
909 if( components == 4 ) { \
911 ( in_row1[3] + in_row1[components + 3] + \
912 in_row2[3] + in_row2[components + 3] ) / os2; \
914 out_row += components; \
915 in_row1 += components * os; \
916 in_row2 += components * os; \
921 switch( frame->get_color_model() ) {
922 RESAMPLE( BC_RGB_FLOAT, float, 3, 0 );
923 RESAMPLE( BC_RGB888, unsigned char, 3, 0 );
924 RESAMPLE( BC_RGBA_FLOAT, float, 4, 0 );
925 RESAMPLE( BC_RGBA8888, unsigned char, 4, 0 );
926 RESAMPLE( BC_YUV888, unsigned char, 3, 0x80 );
927 RESAMPLE( BC_YUVA8888, unsigned char, 4, 0x80 );
928 RESAMPLE( BC_RGB161616, uint16_t, 3, 0 );
929 RESAMPLE( BC_RGBA16161616, uint16_t, 4, 0 );
930 RESAMPLE( BC_YUV161616, uint16_t, 3, 0x8000 );
931 RESAMPLE( BC_YUVA16161616, uint16_t, 4, 0x8000 );
939 int PerspectiveMain::handle_opengl()
942 engine->set_opengl(1);
943 engine->process(get_output(), get_output(), get_output(), config.mode,
944 config.x1, config.y1, config.x2, config.y2,
945 config.x3, config.y3, config.x4, config.y4,
947 engine->set_opengl(0);