fix mask vframe setup, add unshared vframe constructor
[goodguy/history.git] / cinelerra-5.1 / plugins / perspective / perspective.C
index 26a2e774ebc1eba55a4cc9f25e98151808450d64..a9e2adf3bb676fe4aca0d7fbb0a8e77fef4da23f 100644 (file)
@@ -2,21 +2,21 @@
 /*
  * CINELERRA
  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
+ *
  */
 
 #include "affine.h"
 #include "language.h"
 #include "perspective.h"
 
-
-
-
-
-
+#define PERSPECTIVE_WIDTH 400
+#define PERSPECTIVE_HEIGHT 600
 
 REGISTER_PLUGIN(PerspectiveMain)
 
 
-
 PerspectiveConfig::PerspectiveConfig()
 {
-       x1 = 0;
-       y1 = 0;
-       x2 = 100;
-       y2 = 0;
-       x3 = 100;
-       y3 = 100;
-       x4 = 0;
-       y4 = 100;
+       x1 = 0;    y1 = 0;
+       x2 = 100;  y2 = 0;
+       x3 = 100;  y3 = 100;
+       x4 = 0;    y4 = 100;
        mode = AffineEngine::PERSPECTIVE;
-       window_w = 400;
-       window_h = 450;
+       smoothing = AffineEngine::AF_DEFAULT;
+       window_w = PERSPECTIVE_WIDTH;
+       window_h = PERSPECTIVE_HEIGHT;
        current_point = 0;
        forward = 1;
+       view_x = view_y = 0;
+       view_zoom = 1;
 }
 
 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
 {
-       return 
+       return
                EQUIV(x1, that.x1) &&
                EQUIV(y1, that.y1) &&
                EQUIV(x2, that.x2) &&
@@ -63,31 +58,33 @@ int PerspectiveConfig::equivalent(PerspectiveConfig &that)
                EQUIV(x4, that.x4) &&
                EQUIV(y4, that.y4) &&
                mode == that.mode &&
+               smoothing == that.smoothing &&
                forward == that.forward;
+// not tracking:
+//             view_x == that.view_x &&
+//             view_y == that.view_y &&
+//             view_zoom == that.view_zoom &&
 }
 
 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
 {
-       x1 = that.x1;
-       y1 = that.y1;
-       x2 = that.x2;
-       y2 = that.y2;
-       x3 = that.x3;
-       y3 = that.y3;
-       x4 = that.x4;
-       y4 = that.y4;
+       x1 = that.x1;  y1 = that.y1;
+       x2 = that.x2;  y2 = that.y2;
+       x3 = that.x3;  y3 = that.y3;
+       x4 = that.x4;  y4 = that.y4;
        mode = that.mode;
+       smoothing = that.smoothing;
        window_w = that.window_w;
        window_h = that.window_h;
        current_point = that.current_point;
        forward = that.forward;
+       view_x = that.view_x;
+       view_y = that.view_y;
+       view_zoom = that.view_zoom;
 }
 
-void PerspectiveConfig::interpolate(PerspectiveConfig &prev, 
-       PerspectiveConfig &next, 
-       int64_t prev_frame, 
-       int64_t next_frame, 
-       int64_t current_frame)
+void PerspectiveConfig::interpolate(PerspectiveConfig &prev, PerspectiveConfig &next,
+       int64_t prev_frame, int64_t next_frame, int64_t current_frame)
 {
        double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
        double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
@@ -100,31 +97,21 @@ void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
        this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
        this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
        mode = prev.mode;
+       smoothing = prev.smoothing;
        forward = prev.forward;
+       view_x = prev.view_x;
+       view_y = prev.view_y;
+       view_zoom = prev.view_zoom;
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin)
  : PluginClientWindow(plugin,
-       plugin->config.window_w, 
-       plugin->config.window_h, 
-       plugin->config.window_w,
-       plugin->config.window_h,
-       0)
+       plugin->config.window_w, plugin->config.window_h,
+       plugin->config.window_w, plugin->config.window_h, 0)
 {
 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
-       this->plugin = plugin; 
+       this->plugin = plugin;
 }
 
 PerspectiveWindow::~PerspectiveWindow()
@@ -135,110 +122,161 @@ void PerspectiveWindow::create_objects()
 {
        int x = 10, y = 10;
 
-       add_subwindow(canvas = new PerspectiveCanvas(plugin, 
-               x, 
-               y, 
-               get_w() - 20, 
-               get_h() - 140));
+       add_subwindow(canvas = new PerspectiveCanvas(this,
+               x, y, get_w() - 20, get_h() - 290));
        canvas->set_cursor(CROSS_CURSOR, 0, 0);
        y += canvas->get_h() + 10;
        add_subwindow(new BC_Title(x, y, _("Current X:")));
        x += 80;
-       this->x = new PerspectiveCoord(this, 
-               plugin, 
-               x, 
-               y, 
-               plugin->get_current_x(),
-               1);
+       this->x = new PerspectiveCoord(this,
+               x, y, plugin->get_current_x(), 1);
        this->x->create_objects();
        x += 140;
        add_subwindow(new BC_Title(x, y, _("Y:")));
        x += 20;
-       this->y = new PerspectiveCoord(this, 
-               plugin, 
-               x, 
-               y, 
-               plugin->get_current_y(),
-               0);
+       this->y = new PerspectiveCoord(this,
+               x, y, plugin->get_current_y(), 0);
        this->y->create_objects();
-       y += 30;
-       x = 10;
-       add_subwindow(new PerspectiveReset(plugin, x, y));
+       x = 10;   y += 30;
+       add_subwindow(mode_perspective = new PerspectiveMode(this,
+               x, y, AffineEngine::PERSPECTIVE, _("Perspective")));
+       x += 120;
+       add_subwindow(mode_sheer = new PerspectiveMode(this,
+               x, y, AffineEngine::SHEER, _("Sheer")));
        x += 100;
-       add_subwindow(mode_perspective = new PerspectiveMode(plugin, 
-               x, 
-               y, 
-               AffineEngine::PERSPECTIVE,
-               _("Perspective")));
+       add_subwindow(affine = new PerspectiveAffine(this, x, y));
+       affine->create_objects();
+       x = 10;  y += 30;
+       add_subwindow(mode_stretch = new PerspectiveMode(this,
+               x, y, AffineEngine::STRETCH, _("Stretch")));
        x += 120;
-       add_subwindow(mode_sheer = new PerspectiveMode(plugin, 
-               x, 
-               y, 
-               AffineEngine::SHEER,
-               _("Sheer")));
-       x = 110;
-       y += 30;
-       add_subwindow(mode_stretch = new PerspectiveMode(plugin, 
-               x, 
-               y, 
-               AffineEngine::STRETCH,
-               _("Stretch")));
+       add_subwindow(new PerspectiveReset(this, x, y));
        update_canvas();
+
+       x = 10;   y += 30;
+       BC_Title *title;
+       add_subwindow(title = new BC_Title(x, y, _("Zoom view:")));
+       int x1 = x + title->get_w() + 10, w1 = get_w() - x1 - 10;
+       add_subwindow(zoom_view = new PerspectiveZoomView(this, x1, y, w1));
        y += 30;
-       x = 10;
+
        add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
        x += 170;
-       add_subwindow(forward = new PerspectiveDirection(plugin, 
-               x, 
-               y, 
-               1,
-               _("Forward")));
+       add_subwindow(forward = new PerspectiveDirection(this,
+               x, y, 1, _("Forward")));
        x += 100;
-       add_subwindow(reverse = new PerspectiveDirection(plugin, 
-               x, 
-               y, 
-               0,
-               _("Reverse")));
-
+       add_subwindow(reverse = new PerspectiveDirection(this,
+               x, y, 0, _("Reverse")));
+       x = 10;  y += 40;
+       add_subwindow(title = new BC_Title(x, y, _("Alt/Shift:")));
+       add_subwindow(new BC_Title(x+100, y, _("Button1 Action:")));
+       y += title->get_h() + 5;
+       add_subwindow(new BC_Title(x, y,
+               "  0 / 0\n"
+               "  0 / 1\n"
+               "  1 / 0\n"
+               "  1 / 1"));
+       add_subwindow(new BC_Title(x+100, y,
+             _("Translate endpoint\n"
+               "Zoom image\n"
+               "Translate image\n"
+               "Translate view")));
        show_window();
 }
 
 
-
 int PerspectiveWindow::resize_event(int w, int h)
 {
        return 1;
 }
 
+PerspectiveZoomView::PerspectiveZoomView(PerspectiveWindow *gui,
+       int x, int y, int w)
+ : BC_FSlider(x, y, 0, w, w, -2., 2.,
+       log10(gui->plugin->config.view_zoom < 0.01 ?
+               0.01 : gui->plugin->config.view_zoom))
+{
+       this->gui = gui;
+       set_precision(0.001);
+       set_tooltip(_("Zoom"));
+}
+PerspectiveZoomView::~PerspectiveZoomView()
+{
+}
+int PerspectiveZoomView::handle_event()
+{
+       float value = get_value();
+       BC_FSlider::update(value);
+       PerspectiveMain *plugin = gui->plugin;
+       float view_zoom = plugin->config.view_zoom;
+       double new_zoom = pow(10.,value);
+       double scale = new_zoom / view_zoom;
+       plugin->config.view_zoom = new_zoom;
+       plugin->config.view_x *= scale;
+       plugin->config.view_y *= scale;
+       gui->update_canvas();
+       plugin->send_configure_change();
+       return 1;
+}
+
+char *PerspectiveZoomView::get_caption()
+{
+       double value = get_value();
+       int frac = value >= 0. ? 1 : value >= -1. ? 2 : 3;
+       double zoom = pow(10., value);
+       char *caption = BC_Slider::get_caption();
+       sprintf(caption, "%.*f", frac, zoom);
+       return caption;
+}
+
+void PerspectiveZoomView::update(float zoom)
+{
+       if( zoom < 0.01 ) zoom = 0.01;
+       float value = log10f(zoom);
+       BC_FSlider::update(value);
+}
+
 void PerspectiveWindow::update_canvas()
 {
-       canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
+       int cw = canvas->get_w(), ch = canvas->get_h();
+       canvas->clear_box(0, 0, cw, ch);
        int x1, y1, x2, y2, x3, y3, x4, y4;
        calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
-
-// printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
-// x1,
-// y1,
-// x2,
-// y2,
-// x3,
-// y3,
-// x4,
-// y4);
+       float x0 = cw / 2.0f, y0 = ch / 2.0f;
+       float view_zoom = plugin->config.view_zoom;
+       float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
+       x1 = (x1-x0) * view_zoom + view_x + x0;
+       y1 = (y1-y0) * view_zoom + view_y + y0;
+       x2 = (x2-x0) * view_zoom + view_x + x0;
+       y2 = (y2-y0) * view_zoom + view_y + y0;
+       x3 = (x3-x0) * view_zoom + view_x + x0;
+       y3 = (y3-y0) * view_zoom + view_y + y0;
+       x4 = (x4-x0) * view_zoom + view_x + x0;
+       y4 = (y4-y0) * view_zoom + view_y + y0;
+
+       canvas->set_color(RED);
+       int vx1 = x0 - x0 * view_zoom + view_x;
+       int vy1 = y0 - y0 * view_zoom + view_y;
+       int vx2 = vx1 + cw * view_zoom - 1;
+       int vy2 = vy1 + ch * view_zoom - 1;
+       canvas->draw_line(vx1, vy1, vx2, vy1);
+       canvas->draw_line(vx2, vy1, vx2, vy2);
+       canvas->draw_line(vx2, vy2, vx1, vy2);
+       canvas->draw_line(vx1, vy2, vx1, vy1);
+
+//printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
+// x1, y1, x2, y2, x3, y3, x4, y4);
 // Draw divisions
        canvas->set_color(WHITE);
 
 #define DIVISIONS 10
-       for(int i = 0; i <= DIVISIONS; i++)
-       {
-// latitude
-               canvas->draw_line(
+       for( int i=0; i<=DIVISIONS; ++i ) {
+               canvas->draw_line( // latitude
                        x1 + (x4 - x1) * i / DIVISIONS,
                        y1 + (y4 - y1) * i / DIVISIONS,
                        x2 + (x3 - x2) * i / DIVISIONS,
                        y2 + (y3 - y2) * i / DIVISIONS);
-// longitude
-               canvas->draw_line(
+               canvas->draw_line( // longitude
                        x1 + (x2 - x1) * i / DIVISIONS,
                        y1 + (y2 - y1) * i / DIVISIONS,
                        x4 + (x3 - x4) * i / DIVISIONS,
@@ -285,20 +323,27 @@ void PerspectiveWindow::update_coord()
        y->update(plugin->get_current_y());
 }
 
-void PerspectiveWindow::calculate_canvas_coords(int &x1, 
-       int &y1, 
-       int &x2, 
-       int &y2, 
-       int &x3, 
-       int &y3, 
-       int &x4, 
-       int &y4)
+void PerspectiveWindow::update_view_zoom()
+{
+       zoom_view->update(plugin->config.view_zoom);
+}
+
+void PerspectiveWindow::reset_view()
+{
+       plugin->config.view_x = plugin->config.view_y = 0;
+       zoom_view->update(plugin->config.view_zoom = 1);
+       update_canvas();
+       plugin->send_configure_change();
+}
+
+void PerspectiveWindow::calculate_canvas_coords(
+       int &x1, int &y1, int &x2, int &y2,
+       int &x3, int &y3, int &x4, int &y4)
 {
        int w = canvas->get_w() - 1;
        int h = canvas->get_h() - 1;
-       if(plugin->config.mode == AffineEngine::PERSPECTIVE ||
-               plugin->config.mode == AffineEngine::STRETCH)
-       {
+       if( plugin->config.mode == AffineEngine::PERSPECTIVE ||
+           plugin->config.mode == AffineEngine::STRETCH ) {
                x1 = (int)(plugin->config.x1 * w / 100);
                y1 = (int)(plugin->config.y1 * h / 100);
                x2 = (int)(plugin->config.x2 * w / 100);
@@ -308,8 +353,7 @@ void PerspectiveWindow::calculate_canvas_coords(int &x1,
                x4 = (int)(plugin->config.x4 * w / 100);
                y4 = (int)(plugin->config.y4 * h / 100);
        }
-       else
-       {
+       else {
                x1 = (int)(plugin->config.x1 * w) / 100;
                y1 = 0;
                x2 = x1 + w;
@@ -322,78 +366,66 @@ void PerspectiveWindow::calculate_canvas_coords(int &x1,
 }
 
 
-
-
-PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin, 
-       int x, 
-       int y, 
-       int w,
-       int h)
+PerspectiveCanvas::PerspectiveCanvas(PerspectiveWindow *gui,
+       int x, int y, int w, int h)
  : BC_SubWindow(x, y, w, h, BLACK)
 {
-       this->plugin = plugin;
+       this->gui = gui;
        state = PerspectiveCanvas::NONE;
 }
 
 
-
-
 int PerspectiveCanvas::button_press_event()
 {
-       if(is_event_win() && cursor_inside())
-       {
+       if( is_event_win() && cursor_inside() ) {
 // Set current point
+               int cx = get_cursor_x(), cy = get_cursor_y();
+               if( alt_down() && shift_down() ) {
+                       state = PerspectiveCanvas::DRAG_VIEW;
+                       start_x = cx;  start_y = cy;
+                       return 1;
+               }
+
+               PerspectiveMain *plugin = gui->plugin;
                int x1, y1, x2, y2, x3, y3, x4, y4;
-               int cursor_x = get_cursor_x();
-               int cursor_y = get_cursor_y();
-               ((PerspectiveWindow*)plugin->thread->window)->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
-
-               float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
-               float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
-               float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
-               float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
-// printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n", 
-// distance3,
-// cursor_x,
-// cursor_y,
-// x3,
-// y3);
+               gui->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
+               float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
+               float x0 = cw / 2, y0 = ch / 2;
+               float view_zoom = plugin->config.view_zoom;
+               float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
+               int x = (cx-x0 - view_x) / view_zoom + x0;
+               int y = (cy-y0 - view_y) / view_zoom + y0;
+               float distance1 = DISTANCE(x, y, x1, y1);
+               float distance2 = DISTANCE(x, y, x2, y2);
+               float distance3 = DISTANCE(x, y, x3, y3);
+               float distance4 = DISTANCE(x, y, x4, y4);
                float min = distance1;
                plugin->config.current_point = 0;
-               if(distance2 < min)
-               {
+               if( distance2 < min ) {
                        min = distance2;
                        plugin->config.current_point = 1;
                }
-               if(distance3 < min)
-               {
+               if( distance3 < min ) {
                        min = distance3;
                        plugin->config.current_point = 2;
                }
-               if(distance4 < min)
-               {
+               if( distance4 < min ) {
                        min = distance4;
                        plugin->config.current_point = 3;
                }
 
-               if(plugin->config.mode == AffineEngine::SHEER)
-               {
-                       if(plugin->config.current_point == 1)
+               if( plugin->config.mode == AffineEngine::SHEER ) {
+                       if( plugin->config.current_point == 1 )
                                plugin->config.current_point = 0;
-                       else
-                       if(plugin->config.current_point == 2)
+                       else if( plugin->config.current_point == 2 )
                                plugin->config.current_point = 3;
                }
-               start_cursor_x = cursor_x;
-               start_cursor_y = cursor_y;
-
-               if(alt_down() || shift_down())
-               {
-                       if(alt_down())
-                               state = PerspectiveCanvas::DRAG_FULL;
-                       else
-                               state = PerspectiveCanvas::ZOOM;
-
+               start_x = x;
+               start_y = y;
+               if( alt_down() || shift_down() ) {
+                       state =  alt_down() ?
+                               PerspectiveCanvas::DRAG_FULL :
+                               PerspectiveCanvas::ZOOM;
 // Get starting positions
                        start_x1 = plugin->config.x1;
                        start_y1 = plugin->config.y1;
@@ -404,16 +436,14 @@ int PerspectiveCanvas::button_press_event()
                        start_x4 = plugin->config.x4;
                        start_y4 = plugin->config.y4;
                }
-               else
-               {
+               else {
                        state = PerspectiveCanvas::DRAG;
-
 // Get starting positions
                        start_x1 = plugin->get_current_x();
                        start_y1 = plugin->get_current_y();
                }
-               ((PerspectiveWindow*)plugin->thread->window)->update_coord();
-               ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
+               gui->update_coord();
+               gui->update_canvas();
                return 1;
        }
 
@@ -422,49 +452,44 @@ int PerspectiveCanvas::button_press_event()
 
 int PerspectiveCanvas::button_release_event()
 {
-       if(state != PerspectiveCanvas::NONE)
-       {
-               state = PerspectiveCanvas::NONE;
-               return 1;
-       }
-       return 0;
+       if( state == PerspectiveCanvas::NONE ) return 0;
+       state = PerspectiveCanvas::NONE;
+       return 1;
 }
 
 int PerspectiveCanvas::cursor_motion_event()
 {
-       if(state != PerspectiveCanvas::NONE)
-       {
-               int w = get_w() - 1;
-               int h = get_h() - 1;
-               if(state == PerspectiveCanvas::DRAG)
-               {
-                       plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
-                       plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
-               }
-               else
-               if(state == PerspectiveCanvas::DRAG_FULL)
-               {
-                       plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
-                       plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
-                       plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
-                       plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
-                       plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
-                       plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
-                       plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
-                       plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
-               }
-               else
-               if(state == PerspectiveCanvas::ZOOM)
-               {
-                       float center_x = (start_x1 +
-                               start_x2 +
-                               start_x3 +
-                               start_x4) / 4;
-                       float center_y = (start_y1 +
-                               start_y2 +
-                               start_y3 +
-                               start_y4) / 4;
-                       float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
+       if( state == PerspectiveCanvas::NONE ) return 0;
+       PerspectiveMain *plugin = gui->plugin;
+       int cx = get_cursor_x(), cy = get_cursor_y();
+       if( state != PerspectiveCanvas::DRAG_VIEW ) {
+               float cw = gui->canvas->get_w(), ch = gui->canvas->get_h();
+               float x0 = cw / 2, y0 = ch / 2;
+               float view_zoom = plugin->config.view_zoom;
+               float view_x = plugin->config.view_x, view_y = plugin->config.view_y;
+               int x = (cx-x0 - view_x) / view_zoom + x0;
+               int y = (cy-y0 - view_y) / view_zoom + y0;
+               int w1 = get_w() - 1, h1 = get_h() - 1;
+
+               switch( state ) {
+               case PerspectiveCanvas::DRAG:
+                       plugin->set_current_x((float)(x - start_x) / w1 * 100 + start_x1);
+                       plugin->set_current_y((float)(y - start_y) / h1 * 100 + start_y1);
+                       break;
+               case PerspectiveCanvas::DRAG_FULL:
+                       plugin->config.x1 = ((float)(x - start_x) / w1 * 100 + start_x1);
+                       plugin->config.y1 = ((float)(y - start_y) / h1 * 100 + start_y1);
+                       plugin->config.x2 = ((float)(x - start_x) / w1 * 100 + start_x2);
+                       plugin->config.y2 = ((float)(y - start_y) / h1 * 100 + start_y2);
+                       plugin->config.x3 = ((float)(x - start_x) / w1 * 100 + start_x3);
+                       plugin->config.y3 = ((float)(y - start_y) / h1 * 100 + start_y3);
+                       plugin->config.x4 = ((float)(x - start_x) / w1 * 100 + start_x4);
+                       plugin->config.y4 = ((float)(y - start_y) / h1 * 100 + start_y4);
+                       break;
+               case PerspectiveCanvas::ZOOM:
+                       float center_x = (start_x1 + start_x2 + start_x3 + start_x4) / 4;
+                       float center_y = (start_y1 + start_y2 + start_y3 + start_y4) / 4;
+                       float zoom = (float)(get_cursor_y() - start_y + 640) / 640;
                        plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
                        plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
                        plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
@@ -473,146 +498,160 @@ int PerspectiveCanvas::cursor_motion_event()
                        plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
                        plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
                        plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
+                       break;
                }
-               ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
-               ((PerspectiveWindow*)plugin->thread->window)->update_coord();
-               plugin->send_configure_change();
-               return 1;
+               gui->update_coord();
        }
-
-       return 0;
+       else {
+               plugin->config.view_x += cx - start_x;
+               plugin->config.view_y += cy - start_y;
+               start_x = cx;  start_y = cy;
+       }
+       gui->update_canvas();
+       plugin->send_configure_change();
+       return 1;
 }
 
 
-
-
-
-
 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
-       PerspectiveMain *plugin, 
-       int x, 
-       int y,
-       float value,
-       int is_x)
+       int x, int y, float value, int is_x)
  : BC_TumbleTextBox(gui, value, (float)-100, (float)200, x, y, 100)
 {
-       this->plugin = plugin;
+       this->gui = gui;
        this->is_x = is_x;
 }
 
 int PerspectiveCoord::handle_event()
 {
-       if(is_x)
-               plugin->set_current_x(atof(get_text()));
+       PerspectiveMain *plugin = gui->plugin;
+       float v = atof(get_text());
+       if( is_x )
+               plugin->set_current_x(v);
        else
-               plugin->set_current_y(atof(get_text()));
-       ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
+               plugin->set_current_y(v);
+       gui->update_canvas();
        plugin->send_configure_change();
        return 1;
 }
 
 
-
-
-
-
-
-
-PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin, 
-       int x, 
-       int y)
+PerspectiveReset::PerspectiveReset(PerspectiveWindow *gui, int x, int y)
  : BC_GenericButton(x, y, _("Reset"))
 {
-       this->plugin = plugin;
+       this->gui = gui;
 }
 int PerspectiveReset::handle_event()
 {
-       plugin->config.x1 = 0;
-       plugin->config.y1 = 0;
-       plugin->config.x2 = 100;
-       plugin->config.y2 = 0;
-       plugin->config.x3 = 100;
-       plugin->config.y3 = 100;
-       plugin->config.x4 = 0;
-       plugin->config.y4 = 100;
-       ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
-       ((PerspectiveWindow*)plugin->thread->window)->update_coord();
+       gui->reset_view();
+
+       PerspectiveMain *plugin = gui->plugin;
+       plugin->config.x1 = 0;    plugin->config.y1 = 0;
+       plugin->config.x2 = 100;  plugin->config.y2 = 0;
+       plugin->config.x3 = 100;  plugin->config.y3 = 100;
+       plugin->config.x4 = 0;    plugin->config.y4 = 100;
+       gui->update_canvas();
+       gui->update_coord();
        plugin->send_configure_change();
        return 1;
 }
 
 
-
-
-
-
-
-
-
-
-
-PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin, 
-       int x, 
-       int y,
-       int value,
-       char *text)
- : BC_Radial(x, y, plugin->config.mode == value, text)
+PerspectiveMode::PerspectiveMode(PerspectiveWindow *gui,
+       int x, int y, int value, char *text)
+ : BC_Radial(x, y, gui->plugin->config.mode == value, text)
 {
-       this->plugin = plugin;
+       this->gui = gui;
        this->value = value;
 }
 int PerspectiveMode::handle_event()
 {
+       PerspectiveMain *plugin = gui->plugin;
        plugin->config.mode = value;
-       ((PerspectiveWindow*)plugin->thread->window)->update_mode();
-       ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
+       gui->update_mode();
+       gui->update_canvas();
        plugin->send_configure_change();
        return 1;
 }
 
 
-
-
-PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin, 
-       int x, 
-       int y,
-       int value,
-       char *text)
- : BC_Radial(x, y, plugin->config.forward == value, text)
+PerspectiveDirection::PerspectiveDirection(PerspectiveWindow *gui,
+       int x, int y, int value, char *text)
+ : BC_Radial(x, y, gui->plugin->config.forward == value, text)
 {
-       this->plugin = plugin;
+       this->gui = gui;
        this->value = value;
 }
 int PerspectiveDirection::handle_event()
 {
+       PerspectiveMain *plugin = gui->plugin;
        plugin->config.forward = value;
-       ((PerspectiveWindow*)plugin->thread->window)->update_mode();
+       gui->update_mode();
        plugin->send_configure_change();
        return 1;
 }
 
 
+int PerspectiveAffineItem::handle_event()
+{
+       ((PerspectiveAffine *)get_popup_menu())->update(id);
+       return 1;
+}
 
+PerspectiveAffine::PerspectiveAffine(PerspectiveWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, 100, "", 1)
+{
+       this->gui = gui;
+       affine_modes[AffineEngine::AF_DEFAULT]     = _("default");
+       affine_modes[AffineEngine::AF_NEAREST]     = _("Nearest");
+       affine_modes[AffineEngine::AF_LINEAR]      = _("Linear");
+       affine_modes[AffineEngine::AF_CUBIC]       = _("Cubic");
+       mode = -1;
+}
+PerspectiveAffine::~PerspectiveAffine()
+{
+       int id = total_items();
+       while( --id >= 0 )
+               remove_item(get_item(id));
+       for( int id=0; id<n_modes; ++id )
+               delete affine_items[id];
+}
+void PerspectiveAffine::affine_item(int id)
+{
+       affine_items[id] = new PerspectiveAffineItem(affine_modes[id], id);
+       add_item(affine_items[id]);
+}
 
+void PerspectiveAffine::create_objects()
+{
+       affine_item(AffineEngine::AF_DEFAULT);
+       affine_item(AffineEngine::AF_NEAREST);
+       affine_item(AffineEngine::AF_LINEAR);
+       affine_item(AffineEngine::AF_CUBIC);
+       PerspectiveMain *plugin = gui->plugin;
+       update(plugin->config.smoothing, 0);
+}
 
-
-
-
-
-
-
+void PerspectiveAffine::update(int mode, int send)
+{
+       if( this->mode == mode ) return;
+       this->mode = mode;
+       set_text(affine_modes[mode]);
+       PerspectiveMain *plugin = gui->plugin;
+       plugin->config.smoothing = mode;
+       if( send ) plugin->send_configure_change();
+}
 
 PerspectiveMain::PerspectiveMain(PluginServer *server)
  : PluginVClient(server)
 {
-       
+
        engine = 0;
        temp = 0;
 }
 
 PerspectiveMain::~PerspectiveMain()
 {
-       
+
        if(engine) delete engine;
        if(temp) delete temp;
 }
@@ -621,27 +660,24 @@ const char* PerspectiveMain::plugin_title() { return _("Perspective"); }
 int PerspectiveMain::is_realtime() { return 1; }
 
 
-
 NEW_WINDOW_MACRO(PerspectiveMain, PerspectiveWindow)
 
 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
 
-
-
 void PerspectiveMain::update_gui()
 {
-       if(thread)
-       {
+       if( !thread ) return;
 //printf("PerspectiveMain::update_gui 1\n");
-               thread->window->lock_window();
+       thread->window->lock_window();
+       PerspectiveWindow *gui = (PerspectiveWindow*)thread->window;
 //printf("PerspectiveMain::update_gui 2\n");
-               load_configuration();
-               ((PerspectiveWindow*)thread->window)->update_coord();
-               ((PerspectiveWindow*)thread->window)->update_mode();
-               ((PerspectiveWindow*)thread->window)->update_canvas();
-               thread->window->unlock_window();
+       load_configuration();
+       gui->update_coord();
+       gui->update_mode();
+       gui->update_view_zoom();
+       gui->update_canvas();
+       thread->window->unlock_window();
 //printf("PerspectiveMain::update_gui 3\n");
-       }
 }
 
 
@@ -666,6 +702,10 @@ void PerspectiveMain::save_data(KeyFrame *keyframe)
        output.tag.set_property("Y4", config.y4);
 
        output.tag.set_property("MODE", config.mode);
+       output.tag.set_property("VIEW_X", config.view_x);
+       output.tag.set_property("VIEW_Y", config.view_y);
+       output.tag.set_property("VIEW_ZOOM", config.view_zoom);
+       output.tag.set_property("SMOOTHING", config.smoothing);
        output.tag.set_property("FORWARD", config.forward);
        output.tag.set_property("WINDOW_W", config.window_w);
        output.tag.set_property("WINDOW_H", config.window_h);
@@ -679,324 +719,194 @@ void PerspectiveMain::save_data(KeyFrame *keyframe)
 void PerspectiveMain::read_data(KeyFrame *keyframe)
 {
        FileXML input;
-
        input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
        int result = 0;
 
-       while(!result)
-       {
-               result = input.read_tag();
-
-               if(!result)
-               {
-                       if(input.tag.title_is("PERSPECTIVE"))
-                       {
-                               config.x1 = input.tag.get_property("X1", config.x1);
-                               config.x2 = input.tag.get_property("X2", config.x2);
-                               config.x3 = input.tag.get_property("X3", config.x3);
-                               config.x4 = input.tag.get_property("X4", config.x4);
-                               config.y1 = input.tag.get_property("Y1", config.y1);
-                               config.y2 = input.tag.get_property("Y2", config.y2);
-                               config.y3 = input.tag.get_property("Y3", config.y3);
-                               config.y4 = input.tag.get_property("Y4", config.y4);
-
-                               config.mode = input.tag.get_property("MODE", config.mode);
-                               config.forward = input.tag.get_property("FORWARD", config.forward);
-                               config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
-                               config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
-                       }
+       while(!(result = input.read_tag()) ) {
+               if(input.tag.title_is("PERSPECTIVE")) {
+                       config.x1 = input.tag.get_property("X1", config.x1);
+                       config.x2 = input.tag.get_property("X2", config.x2);
+                       config.x3 = input.tag.get_property("X3", config.x3);
+                       config.x4 = input.tag.get_property("X4", config.x4);
+                       config.y1 = input.tag.get_property("Y1", config.y1);
+                       config.y2 = input.tag.get_property("Y2", config.y2);
+                       config.y3 = input.tag.get_property("Y3", config.y3);
+                       config.y4 = input.tag.get_property("Y4", config.y4);
+
+                       config.mode = input.tag.get_property("MODE", config.mode);
+                       config.view_x = input.tag.get_property("VIEW_X", config.view_x);
+                       config.view_y = input.tag.get_property("VIEW_Y", config.view_y);
+                       config.view_zoom = input.tag.get_property("VIEW_ZOOM", config.view_zoom);
+                       config.smoothing = input.tag.get_property("SMOOTHING", config.smoothing);
+                       config.forward = input.tag.get_property("FORWARD", config.forward);
+                       config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
+                       config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
                }
        }
 }
 
 float PerspectiveMain::get_current_x()
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       return config.x1;
-                       break;
-               case 1:
-                       return config.x2;
-                       break;
-               case 2:
-                       return config.x3;
-                       break;
-               case 3:
-                       return config.x4;
-                       break;
+       switch( config.current_point ) {
+       case 0: return config.x1;
+       case 1: return config.x2;
+       case 2: return config.x3;
+       case 3: return config.x4;
        }
        return 0;
 }
 
 float PerspectiveMain::get_current_y()
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       return config.y1;
-                       break;
-               case 1:
-                       return config.y2;
-                       break;
-               case 2:
-                       return config.y3;
-                       break;
-               case 3:
-                       return config.y4;
-                       break;
+       switch( config.current_point ) {
+       case 0: return config.y1;
+       case 1: return config.y2;
+       case 2: return config.y3;
+       case 3: return config.y4;
        }
        return 0;
 }
 
 void PerspectiveMain::set_current_x(float value)
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       config.x1 = value;
-                       break;
-               case 1:
-                       config.x2 = value;
-                       break;
-               case 2:
-                       config.x3 = value;
-                       break;
-               case 3:
-                       config.x4 = value;
-                       break;
+       switch( config.current_point ) {
+       case 0: config.x1 = value; break;
+       case 1: config.x2 = value; break;
+       case 2: config.x3 = value; break;
+       case 3: config.x4 = value; break;
        }
 }
 
 void PerspectiveMain::set_current_y(float value)
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       config.y1 = value;
-                       break;
-               case 1:
-                       config.y2 = value;
-                       break;
-               case 2:
-                       config.y3 = value;
-                       break;
-               case 3:
-                       config.y4 = value;
-                       break;
+       switch( config.current_point ) {
+       case 0: config.y1 = value; break;
+       case 1: config.y2 = value; break;
+       case 2: config.y3 = value; break;
+       case 3: config.y4 = value; break;
        }
 }
 
-
-
 int PerspectiveMain::process_buffer(VFrame *frame,
-       int64_t start_position,
-       double frame_rate)
+       int64_t start_position, double frame_rate)
 {
        /*int need_reconfigure =*/ load_configuration();
+       int smoothing = config.smoothing;
+// default smoothing uses opengl if possible
+       int use_opengl = smoothing != AffineEngine::AF_DEFAULT ? 0 :
+// Opengl does some funny business with stretching.
+               config.mode == AffineEngine::PERSPECTIVE ||
+               config.mode == AffineEngine::SHEER ? get_use_opengl() : 0;
+
+       read_frame(frame, 0, start_position, frame_rate, use_opengl);
 
 // Do nothing
+
        if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
-               EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
-               EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
-               EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
-       {
-               read_frame(frame, 
-                       0, 
-                       start_position, 
-                       frame_rate,
-                       get_use_opengl());
+           EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
+           EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
+           EQUIV(config.x4, 0)   && EQUIV(config.y4, 100) )
                return 1;
+
+       if( !engine ) {
+               int cpus = get_project_smp() + 1;
+               engine = new AffineEngine(cpus, cpus);
        }
+       engine->set_interpolation(smoothing);
 
-// Opengl does some funny business with stretching.
-       int use_opengl = get_use_opengl() &&
-               (config.mode == AffineEngine::PERSPECTIVE || 
-               config.mode == AffineEngine::SHEER);
-       read_frame(frame, 
-               0, 
-               start_position, 
-               frame_rate,
-               use_opengl);
-
-       if(!engine) engine = new AffineEngine(get_project_smp() + 1,
-               get_project_smp() + 1);
-
-       if(use_opengl)
+       if( use_opengl )
                return run_opengl();
 
-
-
        this->input = frame;
        this->output = frame;
 
-       int w = frame->get_w();
-       int h = frame->get_h();
+       int w = frame->get_w(), need_w = w;
+       int h = frame->get_h(), need_h = h;
        int color_model = frame->get_color_model();
-
-       if(temp && 
-               config.mode == AffineEngine::STRETCH &&
-               (temp->get_w() != w * AFFINE_OVERSAMPLE ||
-                       temp->get_h() != h * AFFINE_OVERSAMPLE))
-       {
-               delete temp;
-               temp = 0;
-       }
-       else
-       if(temp &&
-               (config.mode == AffineEngine::PERSPECTIVE ||
-               config.mode == AffineEngine::SHEER) &&
-               (temp->get_w() != w ||
-                       temp->get_h() != h))
-       {
-               delete temp;
-               temp = 0;
-       }
-
-       if(config.mode == AffineEngine::STRETCH)
-       {
-               if(!temp)
-               {
-                       temp = new VFrame(0,
-                                       -1,
-                                       w * AFFINE_OVERSAMPLE,
-                                       h * AFFINE_OVERSAMPLE,
-                                       color_model,
-                                       -1);
-               }
-               temp->clear_frame();
-       }
-
-       if(config.mode == AffineEngine::PERSPECTIVE ||
-               config.mode == AffineEngine::SHEER)
-       {
-               if(frame->get_rows()[0] == frame->get_rows()[0])
-               {
-                       if(!temp) 
-                       {
-                               temp = new VFrame(0,
-                                       -1,
-                                       w,
-                                       h,
-                                       color_model,
-                                       -1);
+       switch( config.mode ) {
+       case AffineEngine::STRETCH:
+               need_w *= AFFINE_OVERSAMPLE;
+               need_h *= AFFINE_OVERSAMPLE;
+       case AffineEngine::SHEER:
+       case AffineEngine::PERSPECTIVE:
+               if( temp ) {
+                       if( temp->get_w() != need_w || temp->get_h() != need_h ||
+                           temp->get_color_model() != color_model ) {
+                               delete temp;  temp = 0;
                        }
-                       temp->copy_from(input);
-                       input = temp;
                }
+               if( !temp )
+                       temp = new VFrame(need_w, need_h, color_model, 0);
+               break;
+       }
+       switch( config.mode ) {
+       case AffineEngine::STRETCH:
+               temp->clear_frame();
+               break;
+       case AffineEngine::PERSPECTIVE:
+       case AffineEngine::SHEER:
+               temp->copy_from(input);
+               input = temp;
                output->clear_frame();
+               break;
+       default:
+               delete temp;  temp = 0;
+               break;
        }
 
-
-       engine->process(output,
-               input,
-               temp, 
-               config.mode,
-               config.x1,
-               config.y1,
-               config.x2,
-               config.y2,
-               config.x3,
-               config.y3,
-               config.x4,
-               config.y4,
+       engine->process(output, input, temp, config.mode,
+               config.x1, config.y1, config.x2, config.y2,
+               config.x3, config.y3, config.x4, config.y4,
                config.forward);
 
-
-
-
 // Resample
 
-       if(config.mode == AffineEngine::STRETCH)
-       {
-#define RESAMPLE(type, components, chroma_offset) \
-{ \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *out_row = (type*)output->get_rows()[i]; \
-               type *in_row1 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE]; \
-               type *in_row2 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE + 1]; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       out_row[0] = (in_row1[0] +  \
-                                       in_row1[components] +  \
-                                       in_row2[0] +  \
-                                       in_row2[components]) /  \
-                               AFFINE_OVERSAMPLE /  \
-                               AFFINE_OVERSAMPLE; \
-                       out_row[1] = ((in_row1[1] +  \
-                                               in_row1[components + 1] +  \
-                                               in_row2[1] +  \
-                                               in_row2[components + 1]) -  \
-                                       chroma_offset *  \
-                                       AFFINE_OVERSAMPLE *  \
-                                       AFFINE_OVERSAMPLE) /  \
-                               AFFINE_OVERSAMPLE /  \
-                               AFFINE_OVERSAMPLE + \
-                               chroma_offset; \
-                       out_row[2] = ((in_row1[2] +  \
-                                               in_row1[components + 2] +  \
-                                               in_row2[2] +  \
-                                               in_row2[components + 2]) -  \
-                                       chroma_offset *  \
-                                       AFFINE_OVERSAMPLE *  \
-                                       AFFINE_OVERSAMPLE) /  \
-                               AFFINE_OVERSAMPLE /  \
-                               AFFINE_OVERSAMPLE + \
-                               chroma_offset; \
-                       if(components == 4) \
-                       { \
-                               out_row[3] = (in_row1[3] +  \
-                                               in_row1[components + 3] +  \
-                                               in_row2[3] +  \
-                                               in_row2[components + 3]) /  \
-                                       AFFINE_OVERSAMPLE /  \
-                                       AFFINE_OVERSAMPLE; \
-                       } \
-                       out_row += components; \
-                       in_row1 += components * AFFINE_OVERSAMPLE; \
-                       in_row2 += components * AFFINE_OVERSAMPLE; \
-               } \
-       } \
-}
-
-               switch(frame->get_color_model())
-               {
-                       case BC_RGB_FLOAT:
-                               RESAMPLE(float, 3, 0)
-                               break;
-                       case BC_RGB888:
-                               RESAMPLE(unsigned char, 3, 0)
-                               break;
-                       case BC_RGBA_FLOAT:
-                               RESAMPLE(float, 4, 0)
-                               break;
-                       case BC_RGBA8888:
-                               RESAMPLE(unsigned char, 4, 0)
-                               break;
-                       case BC_YUV888:
-                               RESAMPLE(unsigned char, 3, 0x80)
-                               break;
-                       case BC_YUVA8888:
-                               RESAMPLE(unsigned char, 4, 0x80)
-                               break;
-                       case BC_RGB161616:
-                               RESAMPLE(uint16_t, 3, 0)
-                               break;
-                       case BC_RGBA16161616:
-                               RESAMPLE(uint16_t, 4, 0)
-                               break;
-                       case BC_YUV161616:
-                               RESAMPLE(uint16_t, 3, 0x8000)
-                               break;
-                       case BC_YUVA16161616:
-                               RESAMPLE(uint16_t, 4, 0x8000)
-                               break;
+       if( config.mode == AffineEngine::STRETCH ) {
+
+#define RESAMPLE(tag, type, components, chroma_offset) \
+case tag: { \
+    int os = AFFINE_OVERSAMPLE, os2 = os*os; \
+    for( int i=0; i<h; ++i ) { \
+        type *out_row = (type*)output->get_rows()[i]; \
+        type *in_row1 = (type*)temp->get_rows()[i * os]; \
+        type *in_row2 = (type*)temp->get_rows()[i * os + 1]; \
+        for( int j=0; j<w; ++j ) { \
+            out_row[0] = \
+                ( in_row1[0] + in_row1[components + 0] +  \
+                  in_row2[0] + in_row2[components + 0] ) / os2; \
+            out_row[1] = \
+                ( in_row1[1] + in_row1[components + 1] + \
+                  in_row2[1] + in_row2[components + 1] ) / os2; \
+            out_row[2] = \
+                ( in_row1[2] + in_row1[components + 2] + \
+                  in_row2[2] + in_row2[components + 2] ) / os2; \
+            if( components == 4 ) { \
+                out_row[3] = \
+                   ( in_row1[3] + in_row1[components + 3] +  \
+                      in_row2[3] + in_row2[components + 3] ) / os2; \
+            } \
+            out_row += components; \
+            in_row1 += components * os; \
+            in_row2 += components * os; \
+        } \
+    } \
+} break
+
+               switch( frame->get_color_model() ) {
+               RESAMPLE( BC_RGB_FLOAT, float, 3, 0 );
+               RESAMPLE( BC_RGB888, unsigned char, 3, 0 );
+               RESAMPLE( BC_RGBA_FLOAT, float, 4, 0 );
+               RESAMPLE( BC_RGBA8888, unsigned char, 4, 0 );
+               RESAMPLE( BC_YUV888, unsigned char, 3, 0x80 );
+               RESAMPLE( BC_YUVA8888, unsigned char, 4, 0x80 );
+               RESAMPLE( BC_RGB161616, uint16_t, 3, 0 );
+               RESAMPLE( BC_RGBA16161616, uint16_t, 4, 0 );
+               RESAMPLE( BC_YUV161616, uint16_t, 3, 0x8000 );
+               RESAMPLE( BC_YUVA16161616, uint16_t, 4, 0x8000 );
                }
        }
 
-       return 1;
+       return 0;
 }
 
 
@@ -1004,26 +914,12 @@ int PerspectiveMain::handle_opengl()
 {
 #ifdef HAVE_GL
        engine->set_opengl(1);
-       engine->process(get_output(),
-               get_output(),
-               get_output(), 
-               config.mode,
-               config.x1,
-               config.y1,
-               config.x2,
-               config.y2,
-               config.x3,
-               config.y3,
-               config.x4,
-               config.y4,
+       engine->process(get_output(), get_output(), get_output(), config.mode,
+               config.x1, config.y1, config.x2, config.y2,
+               config.x3, config.y3, config.x4, config.y4,
                config.forward);
        engine->set_opengl(0);
-       return 0;
 #endif
+       return 0;
 }
 
-
-
-
-
-