Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / perspective / perspective.C
blob76b9f9222ee3575e80aaeb9fd560dab6b090058f
1 #include "../motion/affine.h"
2 #include "cursors.h"
3 #include "language.h"
4 #include "perspective.h"
12 REGISTER_PLUGIN(PerspectiveMain)
16 PerspectiveConfig::PerspectiveConfig()
18         x1 = 0;
19         y1 = 0;
20         x2 = 100;
21         y2 = 0;
22         x3 = 100;
23         y3 = 100;
24         x4 = 0;
25         y4 = 100;
26         mode = AffineEngine::PERSPECTIVE;
27         window_w = 400;
28         window_h = 450;
29         current_point = 0;
30         forward = 1;
33 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
35         return 
36                 EQUIV(x1, that.x1) &&
37                 EQUIV(y1, that.y1) &&
38                 EQUIV(x2, that.x2) &&
39                 EQUIV(y2, that.y2) &&
40                 EQUIV(x3, that.x3) &&
41                 EQUIV(y3, that.y3) &&
42                 EQUIV(x4, that.x4) &&
43                 EQUIV(y4, that.y4) &&
44                 mode == that.mode &&
45                 forward == that.forward;
48 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
50         x1 = that.x1;
51         y1 = that.y1;
52         x2 = that.x2;
53         y2 = that.y2;
54         x3 = that.x3;
55         y3 = that.y3;
56         x4 = that.x4;
57         y4 = that.y4;
58         mode = that.mode;
59         window_w = that.window_w;
60         window_h = that.window_h;
61         current_point = that.current_point;
62         forward = that.forward;
65 void PerspectiveConfig::interpolate(PerspectiveConfig &prev, 
66         PerspectiveConfig &next, 
67         int64_t prev_frame, 
68         int64_t next_frame, 
69         int64_t current_frame)
71         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
72         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
73         this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
74         this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
75         this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
76         this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
77         this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
78         this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
79         this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
80         this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
81         mode = prev.mode;
82         forward = prev.forward;
93 PLUGIN_THREAD_OBJECT(PerspectiveMain, PerspectiveThread, PerspectiveWindow)
97 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin, int x, int y)
98  : BC_Window(plugin->gui_string, 
99         x,
100         y,
101         plugin->config.window_w, 
102         plugin->config.window_h, 
103         plugin->config.window_w,
104         plugin->config.window_h,
105         0, 
106         1)
108 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
109         this->plugin = plugin; 
112 PerspectiveWindow::~PerspectiveWindow()
116 int PerspectiveWindow::create_objects()
118         int x = 10, y = 10;
120         add_subwindow(canvas = new PerspectiveCanvas(plugin, 
121                 x, 
122                 y, 
123                 get_w() - 20, 
124                 get_h() - 140));
125         canvas->set_cursor(CROSS_CURSOR);
126         y += canvas->get_h() + 10;
127         add_subwindow(new BC_Title(x, y, _("Current X:")));
128         x += 80;
129         this->x = new PerspectiveCoord(this, 
130                 plugin, 
131                 x, 
132                 y, 
133                 plugin->get_current_x(),
134                 1);
135         this->x->create_objects();
136         x += 140;
137         add_subwindow(new BC_Title(x, y, _("Y:")));
138         x += 20;
139         this->y = new PerspectiveCoord(this, 
140                 plugin, 
141                 x, 
142                 y, 
143                 plugin->get_current_y(),
144                 0);
145         this->y->create_objects();
146         y += 30;
147         x = 10;
148         add_subwindow(new PerspectiveReset(plugin, x, y));
149         x += 100;
150         add_subwindow(mode_perspective = new PerspectiveMode(plugin, 
151                 x, 
152                 y, 
153                 AffineEngine::PERSPECTIVE,
154                 _("Perspective")));
155         x += 120;
156         add_subwindow(mode_sheer = new PerspectiveMode(plugin, 
157                 x, 
158                 y, 
159                 AffineEngine::SHEER,
160                 _("Sheer")));
161         x = 110;
162         y += 30;
163         add_subwindow(mode_stretch = new PerspectiveMode(plugin, 
164                 x, 
165                 y, 
166                 AffineEngine::STRETCH,
167                 _("Stretch")));
168         update_canvas();
169         y += 30;
170         x = 10;
171         add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
172         x += 170;
173         add_subwindow(forward = new PerspectiveDirection(plugin, 
174                 x, 
175                 y, 
176                 1,
177                 _("Forward")));
178         x += 100;
179         add_subwindow(reverse = new PerspectiveDirection(plugin, 
180                 x, 
181                 y, 
182                 0,
183                 _("Reverse")));
185         show_window();
186         flush();
187         return 0;
190 WINDOW_CLOSE_EVENT(PerspectiveWindow)
192 int PerspectiveWindow::resize_event(int w, int h)
194         return 1;
197 void PerspectiveWindow::update_canvas()
199         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
200         int x1, y1, x2, y2, x3, y3, x4, y4;
201         calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
203 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
204 // x1,
205 // y1,
206 // x2,
207 // y2,
208 // x3,
209 // y3,
210 // x4,
211 // y4);
212         canvas->set_color(BLACK);
214 #define DIVISIONS 10
215         for(int i = 0; i <= DIVISIONS; i++)
216         {
217 // latitude
218                 canvas->draw_line(
219                         x1 + (x4 - x1) * i / DIVISIONS,
220                         y1 + (y4 - y1) * i / DIVISIONS,
221                         x2 + (x3 - x2) * i / DIVISIONS,
222                         y2 + (y3 - y2) * i / DIVISIONS);
223 // longitude
224                 canvas->draw_line(
225                         x1 + (x2 - x1) * i / DIVISIONS,
226                         y1 + (y2 - y1) * i / DIVISIONS,
227                         x4 + (x3 - x4) * i / DIVISIONS,
228                         y4 + (y3 - y4) * i / DIVISIONS);
229         }
231 // Corners
232 #define RADIUS 5
233         if(plugin->config.current_point == 0)
234                 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
235         else
236                 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
238         if(plugin->config.current_point == 1)
239                 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
240         else
241                 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
243         if(plugin->config.current_point == 2)
244                 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
245         else
246                 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
248         if(plugin->config.current_point == 3)
249                 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
250         else
251                 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
253         canvas->flash();
254         canvas->flush();
257 void PerspectiveWindow::update_mode()
259         mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
260         mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
261         mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
262         forward->update(plugin->config.forward);
263         reverse->update(!plugin->config.forward);
266 void PerspectiveWindow::update_coord()
268         x->update(plugin->get_current_x());
269         y->update(plugin->get_current_y());
272 void PerspectiveWindow::calculate_canvas_coords(int &x1, 
273         int &y1, 
274         int &x2, 
275         int &y2, 
276         int &x3, 
277         int &y3, 
278         int &x4, 
279         int &y4)
281         int w = canvas->get_w() - 1;
282         int h = canvas->get_h() - 1;
283         if(plugin->config.mode == AffineEngine::PERSPECTIVE ||
284                 plugin->config.mode == AffineEngine::STRETCH)
285         {
286                 x1 = (int)(plugin->config.x1 * w / 100);
287                 y1 = (int)(plugin->config.y1 * h / 100);
288                 x2 = (int)(plugin->config.x2 * w / 100);
289                 y2 = (int)(plugin->config.y2 * h / 100);
290                 x3 = (int)(plugin->config.x3 * w / 100);
291                 y3 = (int)(plugin->config.y3 * h / 100);
292                 x4 = (int)(plugin->config.x4 * w / 100);
293                 y4 = (int)(plugin->config.y4 * h / 100);
294         }
295         else
296         {
297                 x1 = (int)(plugin->config.x1 * w) / 100;
298                 y1 = 0;
299                 x2 = x1 + w;
300                 y2 = 0;
301                 x4 = (int)(plugin->config.x4 * w) / 100;
302                 y4 = h;
303                 x3 = x4 + w;
304                 y3 = h;
305         }
311 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin, 
312         int x, 
313         int y, 
314         int w,
315         int h)
316  : BC_SubWindow(x, y, w, h, 0xffffff)
318         this->plugin = plugin;
319         state = PerspectiveCanvas::NONE;
325 int PerspectiveCanvas::button_press_event()
327         if(is_event_win() && cursor_inside())
328         {
329 // Set current point
330                 int x1, y1, x2, y2, x3, y3, x4, y4;
331                 int cursor_x = get_cursor_x();
332                 int cursor_y = get_cursor_y();
333                 plugin->thread->window->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
335                 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
336                 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
337                 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
338                 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
339 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n", 
340 // distance3,
341 // cursor_x,
342 // cursor_y,
343 // x3,
344 // y3);
345                 float min = distance1;
346                 plugin->config.current_point = 0;
347                 if(distance2 < min)
348                 {
349                         min = distance2;
350                         plugin->config.current_point = 1;
351                 }
352                 if(distance3 < min)
353                 {
354                         min = distance3;
355                         plugin->config.current_point = 2;
356                 }
357                 if(distance4 < min)
358                 {
359                         min = distance4;
360                         plugin->config.current_point = 3;
361                 }
363                 if(plugin->config.mode == AffineEngine::SHEER)
364                 {
365                         if(plugin->config.current_point == 1)
366                                 plugin->config.current_point = 0;
367                         else
368                         if(plugin->config.current_point == 2)
369                                 plugin->config.current_point = 3;
370                 }
371                 start_cursor_x = cursor_x;
372                 start_cursor_y = cursor_y;
374                 if(alt_down() || shift_down())
375                 {
376                         if(alt_down())
377                                 state = PerspectiveCanvas::DRAG_FULL;
378                         else
379                                 state = PerspectiveCanvas::ZOOM;
381 // Get starting positions
382                         start_x1 = plugin->config.x1;
383                         start_y1 = plugin->config.y1;
384                         start_x2 = plugin->config.x2;
385                         start_y2 = plugin->config.y2;
386                         start_x3 = plugin->config.x3;
387                         start_y3 = plugin->config.y3;
388                         start_x4 = plugin->config.x4;
389                         start_y4 = plugin->config.y4;
390                 }
391                 else
392                 {
393                         state = PerspectiveCanvas::DRAG;
395 // Get starting positions
396                         start_x1 = plugin->get_current_x();
397                         start_y1 = plugin->get_current_y();
398                 }
399                 plugin->thread->window->update_coord();
400                 plugin->thread->window->update_canvas();
401                 return 1;
402         }
404         return 0;
407 int PerspectiveCanvas::button_release_event()
409         if(state != PerspectiveCanvas::NONE)
410         {
411                 state = PerspectiveCanvas::NONE;
412                 return 1;
413         }
414         return 0;
417 int PerspectiveCanvas::cursor_motion_event()
419         if(state != PerspectiveCanvas::NONE)
420         {
421                 int w = get_w() - 1;
422                 int h = get_h() - 1;
423                 if(state == PerspectiveCanvas::DRAG)
424                 {
425                         plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
426                         plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
427                 }
428                 else
429                 if(state == PerspectiveCanvas::DRAG_FULL)
430                 {
431                         plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
432                         plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
433                         plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
434                         plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
435                         plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
436                         plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
437                         plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
438                         plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
439                 }
440                 else
441                 if(state == PerspectiveCanvas::ZOOM)
442                 {
443                         float center_x = (start_x1 +
444                                 start_x2 +
445                                 start_x3 +
446                                 start_x4) / 4;
447                         float center_y = (start_y1 +
448                                 start_y2 +
449                                 start_y3 +
450                                 start_y4) / 4;
451                         float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
452                         plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
453                         plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
454                         plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
455                         plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
456                         plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
457                         plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
458                         plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
459                         plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
460                 }
461                 plugin->thread->window->update_canvas();
462                 plugin->thread->window->update_coord();
463                 plugin->send_configure_change();
464                 return 1;
465         }
467         return 0;
475 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
476         PerspectiveMain *plugin, 
477         int x, 
478         int y,
479         float value,
480         int is_x)
481  : BC_TumbleTextBox(gui, value, (float)0, (float)100, x, y, 100)
483         this->plugin = plugin;
484         this->is_x = is_x;
487 int PerspectiveCoord::handle_event()
489         if(is_x)
490                 plugin->set_current_x(atof(get_text()));
491         else
492                 plugin->set_current_y(atof(get_text()));
493         plugin->thread->window->update_canvas();
494         plugin->send_configure_change();
495         return 1;
505 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin, 
506         int x, 
507         int y)
508  : BC_GenericButton(x, y, _("Reset"))
510         this->plugin = plugin;
512 int PerspectiveReset::handle_event()
514         plugin->config.x1 = 0;
515         plugin->config.y1 = 0;
516         plugin->config.x2 = 100;
517         plugin->config.y2 = 0;
518         plugin->config.x3 = 100;
519         plugin->config.y3 = 100;
520         plugin->config.x4 = 0;
521         plugin->config.y4 = 100;
522         plugin->thread->window->update_canvas();
523         plugin->thread->window->update_coord();
524         plugin->send_configure_change();
525         return 1;
538 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin, 
539         int x, 
540         int y,
541         int value,
542         char *text)
543  : BC_Radial(x, y, plugin->config.mode == value, text)
545         this->plugin = plugin;
546         this->value = value;
548 int PerspectiveMode::handle_event()
550         plugin->config.mode = value;
551         plugin->thread->window->update_mode();
552         plugin->thread->window->update_canvas();
553         plugin->send_configure_change();
554         return 1;
560 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin, 
561         int x, 
562         int y,
563         int value,
564         char *text)
565  : BC_Radial(x, y, plugin->config.forward == value, text)
567         this->plugin = plugin;
568         this->value = value;
570 int PerspectiveDirection::handle_event()
572         plugin->config.forward = value;
573         plugin->thread->window->update_mode();
574         plugin->send_configure_change();
575         return 1;
589 PerspectiveMain::PerspectiveMain(PluginServer *server)
590  : PluginVClient(server)
592         PLUGIN_CONSTRUCTOR_MACRO
593         engine = 0;
594         temp = 0;
597 PerspectiveMain::~PerspectiveMain()
599         PLUGIN_DESTRUCTOR_MACRO
600         if(engine) delete engine;
601         if(temp) delete temp;
604 char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
605 int PerspectiveMain::is_realtime() { return 1; }
608 NEW_PICON_MACRO(PerspectiveMain)
610 SHOW_GUI_MACRO(PerspectiveMain, PerspectiveThread)
612 SET_STRING_MACRO(PerspectiveMain)
614 RAISE_WINDOW_MACRO(PerspectiveMain)
616 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
620 void PerspectiveMain::update_gui()
622         if(thread)
623         {
624 //printf("PerspectiveMain::update_gui 1\n");
625                 thread->window->lock_window();
626 //printf("PerspectiveMain::update_gui 2\n");
627                 load_configuration();
628                 thread->window->update_coord();
629                 thread->window->update_mode();
630                 thread->window->update_canvas();
631                 thread->window->unlock_window();
632 //printf("PerspectiveMain::update_gui 3\n");
633         }
637 int PerspectiveMain::load_defaults()
639         char directory[1024], string[1024];
640 // set the default directory
641         sprintf(directory, "%sperspective.rc", BCASTDIR);
643 // load the defaults
644         defaults = new BC_Hash(directory);
645         defaults->load();
647         config.x1 = defaults->get("X1", config.x1);
648         config.x2 = defaults->get("X2", config.x2);
649         config.x3 = defaults->get("X3", config.x3);
650         config.x4 = defaults->get("X4", config.x4);
651         config.y1 = defaults->get("Y1", config.y1);
652         config.y2 = defaults->get("Y2", config.y2);
653         config.y3 = defaults->get("Y3", config.y3);
654         config.y4 = defaults->get("Y4", config.y4);
656         config.mode = defaults->get("MODE", config.mode);
657         config.forward = defaults->get("FORWARD", config.forward);
658         config.window_w = defaults->get("WINDOW_W", config.window_w);
659         config.window_h = defaults->get("WINDOW_H", config.window_h);
660         return 0;
664 int PerspectiveMain::save_defaults()
666         defaults->update("X1", config.x1);
667         defaults->update("X2", config.x2);
668         defaults->update("X3", config.x3);
669         defaults->update("X4", config.x4);
670         defaults->update("Y1", config.y1);
671         defaults->update("Y2", config.y2);
672         defaults->update("Y3", config.y3);
673         defaults->update("Y4", config.y4);
675         defaults->update("MODE", config.mode);
676         defaults->update("FORWARD", config.forward);
677         defaults->update("WINDOW_W", config.window_w);
678         defaults->update("WINDOW_H", config.window_h);
679         defaults->save();
680         return 0;
685 void PerspectiveMain::save_data(KeyFrame *keyframe)
687         FileXML output;
689 // cause data to be stored directly in text
690         output.set_shared_string(keyframe->data, MESSAGESIZE);
691         output.tag.set_title("PERSPECTIVE");
693         output.tag.set_property("X1", config.x1);
694         output.tag.set_property("X2", config.x2);
695         output.tag.set_property("X3", config.x3);
696         output.tag.set_property("X4", config.x4);
697         output.tag.set_property("Y1", config.y1);
698         output.tag.set_property("Y2", config.y2);
699         output.tag.set_property("Y3", config.y3);
700         output.tag.set_property("Y4", config.y4);
702         output.tag.set_property("MODE", config.mode);
703         output.tag.set_property("FORWARD", config.forward);
704         output.tag.set_property("WINDOW_W", config.window_w);
705         output.tag.set_property("WINDOW_H", config.window_h);
706         output.append_tag();
707         output.terminate_string();
710 void PerspectiveMain::read_data(KeyFrame *keyframe)
712         FileXML input;
714         input.set_shared_string(keyframe->data, strlen(keyframe->data));
716         int result = 0;
718         while(!result)
719         {
720                 result = input.read_tag();
722                 if(!result)
723                 {
724                         if(input.tag.title_is("PERSPECTIVE"))
725                         {
726                                 config.x1 = input.tag.get_property("X1", config.x1);
727                                 config.x2 = input.tag.get_property("X2", config.x2);
728                                 config.x3 = input.tag.get_property("X3", config.x3);
729                                 config.x4 = input.tag.get_property("X4", config.x4);
730                                 config.y1 = input.tag.get_property("Y1", config.y1);
731                                 config.y2 = input.tag.get_property("Y2", config.y2);
732                                 config.y3 = input.tag.get_property("Y3", config.y3);
733                                 config.y4 = input.tag.get_property("Y4", config.y4);
735                                 config.mode = input.tag.get_property("MODE", config.mode);
736                                 config.forward = input.tag.get_property("FORWARD", config.forward);
737                                 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
738                                 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
739                         }
740                 }
741         }
744 float PerspectiveMain::get_current_x()
746         switch(config.current_point)
747         {
748                 case 0:
749                         return config.x1;
750                         break;
751                 case 1:
752                         return config.x2;
753                         break;
754                 case 2:
755                         return config.x3;
756                         break;
757                 case 3:
758                         return config.x4;
759                         break;
760         }
763 float PerspectiveMain::get_current_y()
765         switch(config.current_point)
766         {
767                 case 0:
768                         return config.y1;
769                         break;
770                 case 1:
771                         return config.y2;
772                         break;
773                 case 2:
774                         return config.y3;
775                         break;
776                 case 3:
777                         return config.y4;
778                         break;
779         }
782 void PerspectiveMain::set_current_x(float value)
784         switch(config.current_point)
785         {
786                 case 0:
787                         config.x1 = value;
788                         break;
789                 case 1:
790                         config.x2 = value;
791                         break;
792                 case 2:
793                         config.x3 = value;
794                         break;
795                 case 3:
796                         config.x4 = value;
797                         break;
798         }
801 void PerspectiveMain::set_current_y(float value)
803         switch(config.current_point)
804         {
805                 case 0:
806                         config.y1 = value;
807                         break;
808                 case 1:
809                         config.y2 = value;
810                         break;
811                 case 2:
812                         config.y3 = value;
813                         break;
814                 case 3:
815                         config.y4 = value;
816                         break;
817         }
822 int PerspectiveMain::process_buffer(VFrame *frame,
823         int64_t start_position,
824         double frame_rate)
826         int need_reconfigure = load_configuration();
829 // Do nothing
830         if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
831                 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
832                 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
833                 EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
834         {
835                 read_frame(frame, 
836                         0, 
837                         start_position, 
838                         frame_rate,
839                         get_use_opengl());
840                 return 1;
841         }
843 // Opengl does some funny business with stretching.
844         int use_opengl = get_use_opengl() &&
845                 (config.mode == AffineEngine::PERSPECTIVE || 
846                 config.mode == AffineEngine::SHEER);
847         read_frame(frame, 
848                 0, 
849                 start_position, 
850                 frame_rate,
851                 use_opengl);
853         if(!engine) engine = new AffineEngine(get_project_smp() + 1,
854                 get_project_smp() + 1);
856         if(use_opengl)
857                 return run_opengl();
861         this->input = frame;
862         this->output = frame;
864         int w = frame->get_w();
865         int h = frame->get_h();
866         int color_model = frame->get_color_model();
868         if(temp && 
869                 config.mode == AffineEngine::STRETCH &&
870                 (temp->get_w() != w * AFFINE_OVERSAMPLE ||
871                         temp->get_h() != h * AFFINE_OVERSAMPLE))
872         {
873                 delete temp;
874                 temp = 0;
875         }
876         else
877         if(temp &&
878                 (config.mode == AffineEngine::PERSPECTIVE ||
879                 config.mode == AffineEngine::SHEER) &&
880                 (temp->get_w() != w ||
881                         temp->get_h() != h))
882         {
883                 delete temp;
884                 temp = 0;
885         }
887         if(config.mode == AffineEngine::STRETCH)
888         {
889                 if(!temp)
890                 {
891                         temp = new VFrame(0,
892                                         w * AFFINE_OVERSAMPLE,
893                                         h * AFFINE_OVERSAMPLE,
894                                         color_model);
895                 }
896                 temp->clear_frame();
897         }
899         if(config.mode == AffineEngine::PERSPECTIVE ||
900                 config.mode == AffineEngine::SHEER)
901         {
902                 if(frame->get_rows()[0] == frame->get_rows()[0])
903                 {
904                         if(!temp) 
905                         {
906                                 temp = new VFrame(0,
907                                         w,
908                                         h,
909                                         color_model);
910                         }
911                         temp->copy_from(input);
912                         input = temp;
913                 }
914                 output->clear_frame();
915         }
918         engine->process(output,
919                 input,
920                 temp, 
921                 config.mode,
922                 config.x1,
923                 config.y1,
924                 config.x2,
925                 config.y2,
926                 config.x3,
927                 config.y3,
928                 config.x4,
929                 config.y4,
930                 config.forward);
935 // Resample
937         if(config.mode == AffineEngine::STRETCH)
938         {
939 #define RESAMPLE(type, components, chroma_offset) \
940 { \
941         for(int i = 0; i < h; i++) \
942         { \
943                 type *out_row = (type*)output->get_rows()[i]; \
944                 type *in_row1 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE]; \
945                 type *in_row2 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE + 1]; \
946                 for(int j = 0; j < w; j++) \
947                 { \
948                         out_row[0] = (in_row1[0] +  \
949                                         in_row1[components] +  \
950                                         in_row2[0] +  \
951                                         in_row2[components]) /  \
952                                 AFFINE_OVERSAMPLE /  \
953                                 AFFINE_OVERSAMPLE; \
954                         out_row[1] = ((in_row1[1] +  \
955                                                 in_row1[components + 1] +  \
956                                                 in_row2[1] +  \
957                                                 in_row2[components + 1]) -  \
958                                         chroma_offset *  \
959                                         AFFINE_OVERSAMPLE *  \
960                                         AFFINE_OVERSAMPLE) /  \
961                                 AFFINE_OVERSAMPLE /  \
962                                 AFFINE_OVERSAMPLE + \
963                                 chroma_offset; \
964                         out_row[2] = ((in_row1[2] +  \
965                                                 in_row1[components + 2] +  \
966                                                 in_row2[2] +  \
967                                                 in_row2[components + 2]) -  \
968                                         chroma_offset *  \
969                                         AFFINE_OVERSAMPLE *  \
970                                         AFFINE_OVERSAMPLE) /  \
971                                 AFFINE_OVERSAMPLE /  \
972                                 AFFINE_OVERSAMPLE + \
973                                 chroma_offset; \
974                         if(components == 4) \
975                         { \
976                                 out_row[3] = (in_row1[3] +  \
977                                                 in_row1[components + 3] +  \
978                                                 in_row2[3] +  \
979                                                 in_row2[components + 3]) /  \
980                                         AFFINE_OVERSAMPLE /  \
981                                         AFFINE_OVERSAMPLE; \
982                         } \
983                         out_row += components; \
984                         in_row1 += components * AFFINE_OVERSAMPLE; \
985                         in_row2 += components * AFFINE_OVERSAMPLE; \
986                 } \
987         } \
990                 switch(frame->get_color_model())
991                 {
992                         case BC_RGB_FLOAT:
993                                 RESAMPLE(float, 3, 0)
994                                 break;
995                         case BC_RGB888:
996                                 RESAMPLE(unsigned char, 3, 0)
997                                 break;
998                         case BC_RGBA_FLOAT:
999                                 RESAMPLE(float, 4, 0)
1000                                 break;
1001                         case BC_RGBA8888:
1002                                 RESAMPLE(unsigned char, 4, 0)
1003                                 break;
1004                         case BC_YUV888:
1005                                 RESAMPLE(unsigned char, 3, 0x80)
1006                                 break;
1007                         case BC_YUVA8888:
1008                                 RESAMPLE(unsigned char, 4, 0x80)
1009                                 break;
1010                         case BC_RGB161616:
1011                                 RESAMPLE(uint16_t, 3, 0)
1012                                 break;
1013                         case BC_RGBA16161616:
1014                                 RESAMPLE(uint16_t, 4, 0)
1015                                 break;
1016                         case BC_YUV161616:
1017                                 RESAMPLE(uint16_t, 3, 0x8000)
1018                                 break;
1019                         case BC_YUVA16161616:
1020                                 RESAMPLE(uint16_t, 4, 0x8000)
1021                                 break;
1022                 }
1023         }
1025         return 1;
1029 int PerspectiveMain::handle_opengl()
1031 #ifdef HAVE_GL
1032         engine->set_opengl(1);
1033         engine->process(get_output(),
1034                 get_output(),
1035                 get_output(), 
1036                 config.mode,
1037                 config.x1,
1038                 config.y1,
1039                 config.x2,
1040                 config.y2,
1041                 config.x3,
1042                 config.y3,
1043                 config.x4,
1044                 config.y4,
1045                 config.forward);
1046         engine->set_opengl(0);
1047         return 0;
1048 #endif