--- /dev/null
+
+/*
+ * 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 "cursors.h"
+#include "language.h"
+#include "perspective.h"
+
+
+
+
+
+
+
+REGISTER_PLUGIN(PerspectiveMain)
+
+
+
+PerspectiveConfig::PerspectiveConfig()
+{
+ 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;
+ current_point = 0;
+ forward = 1;
+}
+
+int PerspectiveConfig::equivalent(PerspectiveConfig &that)
+{
+ return
+ EQUIV(x1, that.x1) &&
+ EQUIV(y1, that.y1) &&
+ EQUIV(x2, that.x2) &&
+ EQUIV(y2, that.y2) &&
+ EQUIV(x3, that.x3) &&
+ EQUIV(y3, that.y3) &&
+ EQUIV(x4, that.x4) &&
+ EQUIV(y4, that.y4) &&
+ mode == that.mode &&
+ forward == that.forward;
+}
+
+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;
+ mode = that.mode;
+ window_w = that.window_w;
+ window_h = that.window_h;
+ current_point = that.current_point;
+ forward = that.forward;
+}
+
+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);
+ this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
+ this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
+ this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
+ this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
+ this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
+ this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
+ this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
+ this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
+ mode = prev.mode;
+ forward = prev.forward;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin)
+ : PluginClientWindow(plugin,
+ 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;
+}
+
+PerspectiveWindow::~PerspectiveWindow()
+{
+}
+
+void PerspectiveWindow::create_objects()
+{
+ int x = 10, y = 10;
+
+ add_subwindow(canvas = new PerspectiveCanvas(plugin,
+ x,
+ y,
+ get_w() - 20,
+ get_h() - 140));
+ 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->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->create_objects();
+ y += 30;
+ x = 10;
+ add_subwindow(new PerspectiveReset(plugin, x, y));
+ x += 100;
+ add_subwindow(mode_perspective = new PerspectiveMode(plugin,
+ x,
+ y,
+ AffineEngine::PERSPECTIVE,
+ _("Perspective")));
+ 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")));
+ update_canvas();
+ 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")));
+ x += 100;
+ add_subwindow(reverse = new PerspectiveDirection(plugin,
+ x,
+ y,
+ 0,
+ _("Reverse")));
+
+ show_window();
+}
+
+
+
+int PerspectiveWindow::resize_event(int w, int h)
+{
+ return 1;
+}
+
+void PerspectiveWindow::update_canvas()
+{
+ canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
+ 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);
+// Draw divisions
+ canvas->set_color(WHITE);
+
+#define DIVISIONS 10
+ for(int i = 0; i <= DIVISIONS; i++)
+ {
+// latitude
+ canvas->draw_line(
+ x1 + (x4 - x1) * i / DIVISIONS,
+ y1 + (y4 - y1) * i / DIVISIONS,
+ x2 + (x3 - x2) * i / DIVISIONS,
+ y2 + (y3 - y2) * i / DIVISIONS);
+// longitude
+ canvas->draw_line(
+ x1 + (x2 - x1) * i / DIVISIONS,
+ y1 + (y2 - y1) * i / DIVISIONS,
+ x4 + (x3 - x4) * i / DIVISIONS,
+ y4 + (y3 - y4) * i / DIVISIONS);
+ }
+
+// Corners
+#define RADIUS 5
+ if(plugin->config.current_point == 0)
+ canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
+ else
+ canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
+
+ if(plugin->config.current_point == 1)
+ canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
+ else
+ canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
+
+ if(plugin->config.current_point == 2)
+ canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
+ else
+ canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
+
+ if(plugin->config.current_point == 3)
+ canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
+ else
+ canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
+
+ canvas->flash();
+}
+
+void PerspectiveWindow::update_mode()
+{
+ mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
+ mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
+ mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
+ forward->update(plugin->config.forward);
+ reverse->update(!plugin->config.forward);
+}
+
+void PerspectiveWindow::update_coord()
+{
+ x->update(plugin->get_current_x());
+ 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)
+{
+ int w = canvas->get_w() - 1;
+ int h = canvas->get_h() - 1;
+ 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);
+ y2 = (int)(plugin->config.y2 * h / 100);
+ x3 = (int)(plugin->config.x3 * w / 100);
+ y3 = (int)(plugin->config.y3 * h / 100);
+ x4 = (int)(plugin->config.x4 * w / 100);
+ y4 = (int)(plugin->config.y4 * h / 100);
+ }
+ else
+ {
+ x1 = (int)(plugin->config.x1 * w) / 100;
+ y1 = 0;
+ x2 = x1 + w;
+ y2 = 0;
+ x4 = (int)(plugin->config.x4 * w) / 100;
+ y4 = h;
+ x3 = x4 + w;
+ y3 = h;
+ }
+}
+
+
+
+
+PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
+ int x,
+ int y,
+ int w,
+ int h)
+ : BC_SubWindow(x, y, w, h, BLACK)
+{
+ this->plugin = plugin;
+ state = PerspectiveCanvas::NONE;
+}
+
+
+
+
+int PerspectiveCanvas::button_press_event()
+{
+ if(is_event_win() && cursor_inside())
+ {
+// Set current point
+ 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);
+ float min = distance1;
+ plugin->config.current_point = 0;
+ if(distance2 < min)
+ {
+ min = distance2;
+ plugin->config.current_point = 1;
+ }
+ if(distance3 < min)
+ {
+ min = distance3;
+ plugin->config.current_point = 2;
+ }
+ if(distance4 < min)
+ {
+ min = distance4;
+ plugin->config.current_point = 3;
+ }
+
+ if(plugin->config.mode == AffineEngine::SHEER)
+ {
+ if(plugin->config.current_point == 1)
+ plugin->config.current_point = 0;
+ 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;
+
+// Get starting positions
+ start_x1 = plugin->config.x1;
+ start_y1 = plugin->config.y1;
+ start_x2 = plugin->config.x2;
+ start_y2 = plugin->config.y2;
+ start_x3 = plugin->config.x3;
+ start_y3 = plugin->config.y3;
+ start_x4 = plugin->config.x4;
+ start_y4 = plugin->config.y4;
+ }
+ 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();
+ return 1;
+ }
+
+ return 0;
+}
+
+int PerspectiveCanvas::button_release_event()
+{
+ if(state != PerspectiveCanvas::NONE)
+ {
+ state = PerspectiveCanvas::NONE;
+ return 1;
+ }
+ return 0;
+}
+
+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;
+ 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;
+ plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
+ plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
+ 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;
+ }
+ ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
+ ((PerspectiveWindow*)plugin->thread->window)->update_coord();
+ plugin->send_configure_change();
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
+ PerspectiveMain *plugin,
+ int x,
+ int y,
+ float value,
+ int is_x)
+ : BC_TumbleTextBox(gui, value, (float)-100, (float)200, x, y, 100)
+{
+ this->plugin = plugin;
+ this->is_x = is_x;
+}
+
+int PerspectiveCoord::handle_event()
+{
+ if(is_x)
+ plugin->set_current_x(atof(get_text()));
+ else
+ plugin->set_current_y(atof(get_text()));
+ ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+
+
+
+PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin,
+ int x,
+ int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+ this->plugin = plugin;
+}
+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();
+ 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)
+{
+ this->plugin = plugin;
+ this->value = value;
+}
+int PerspectiveMode::handle_event()
+{
+ plugin->config.mode = value;
+ ((PerspectiveWindow*)plugin->thread->window)->update_mode();
+ ((PerspectiveWindow*)plugin->thread->window)->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)
+{
+ this->plugin = plugin;
+ this->value = value;
+}
+int PerspectiveDirection::handle_event()
+{
+ plugin->config.forward = value;
+ ((PerspectiveWindow*)plugin->thread->window)->update_mode();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+PerspectiveMain::PerspectiveMain(PluginServer *server)
+ : PluginVClient(server)
+{
+
+ engine = 0;
+ temp = 0;
+}
+
+PerspectiveMain::~PerspectiveMain()
+{
+
+ if(engine) delete engine;
+ if(temp) delete temp;
+}
+
+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)
+ {
+//printf("PerspectiveMain::update_gui 1\n");
+ thread->window->lock_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();
+//printf("PerspectiveMain::update_gui 3\n");
+ }
+}
+
+
+
+
+
+void PerspectiveMain::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+
+// cause data to be stored directly in text
+ output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+ output.tag.set_title("PERSPECTIVE");
+
+ output.tag.set_property("X1", config.x1);
+ output.tag.set_property("X2", config.x2);
+ output.tag.set_property("X3", config.x3);
+ output.tag.set_property("X4", config.x4);
+ output.tag.set_property("Y1", config.y1);
+ output.tag.set_property("Y2", config.y2);
+ output.tag.set_property("Y3", config.y3);
+ output.tag.set_property("Y4", config.y4);
+
+ output.tag.set_property("MODE", config.mode);
+ 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);
+ output.append_tag();
+ output.tag.set_title("/PERSPECTIVE");
+ output.append_tag();
+ output.append_newline();
+ output.terminate_string();
+}
+
+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);
+ }
+ }
+ }
+}
+
+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;
+ }
+ 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;
+ }
+ 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;
+ }
+}
+
+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;
+ }
+}
+
+
+
+int PerspectiveMain::process_buffer(VFrame *frame,
+ int64_t start_position,
+ double frame_rate)
+{
+ /*int need_reconfigure =*/ load_configuration();
+
+// 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());
+ return 1;
+ }
+
+// 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)
+ return run_opengl();
+
+
+
+ this->input = frame;
+ this->output = frame;
+
+ int w = frame->get_w();
+ int h = frame->get_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);
+ }
+ temp->copy_from(input);
+ input = temp;
+ }
+ output->clear_frame();
+ }
+
+
+ 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;
+ }
+ }
+
+ return 1;
+}
+
+
+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,
+ config.forward);
+ engine->set_opengl(0);
+ return 0;
+#endif
+}
+
+
+
+
+
+