e270bc8c86627df86c5ea3e37a014a9a8dc2b59b
[goodguy/history.git] / cinelerra-5.1 / plugins / perspective / perspective.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "affine.h"
23 #include "cursors.h"
24 #include "language.h"
25 #include "perspective.h"
26
27
28
29
30
31
32
33 REGISTER_PLUGIN(PerspectiveMain)
34
35
36
37 PerspectiveConfig::PerspectiveConfig()
38 {
39         x1 = 0;
40         y1 = 0;
41         x2 = 100;
42         y2 = 0;
43         x3 = 100;
44         y3 = 100;
45         x4 = 0;
46         y4 = 100;
47         mode = AffineEngine::PERSPECTIVE;
48         window_w = 400;
49         window_h = 450;
50         current_point = 0;
51         forward = 1;
52 }
53
54 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
55 {
56         return
57                 EQUIV(x1, that.x1) &&
58                 EQUIV(y1, that.y1) &&
59                 EQUIV(x2, that.x2) &&
60                 EQUIV(y2, that.y2) &&
61                 EQUIV(x3, that.x3) &&
62                 EQUIV(y3, that.y3) &&
63                 EQUIV(x4, that.x4) &&
64                 EQUIV(y4, that.y4) &&
65                 mode == that.mode &&
66                 forward == that.forward;
67 }
68
69 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
70 {
71         x1 = that.x1;
72         y1 = that.y1;
73         x2 = that.x2;
74         y2 = that.y2;
75         x3 = that.x3;
76         y3 = that.y3;
77         x4 = that.x4;
78         y4 = that.y4;
79         mode = that.mode;
80         window_w = that.window_w;
81         window_h = that.window_h;
82         current_point = that.current_point;
83         forward = that.forward;
84 }
85
86 void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
87         PerspectiveConfig &next,
88         int64_t prev_frame,
89         int64_t next_frame,
90         int64_t current_frame)
91 {
92         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
93         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
94         this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
95         this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
96         this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
97         this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
98         this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
99         this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
100         this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
101         this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
102         mode = prev.mode;
103         forward = prev.forward;
104 }
105
106
107
108
109
110
111
112
113
114
115
116
117
118 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin)
119  : PluginClientWindow(plugin,
120         plugin->config.window_w,
121         plugin->config.window_h,
122         plugin->config.window_w,
123         plugin->config.window_h,
124         0)
125 {
126 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
127         this->plugin = plugin;
128 }
129
130 PerspectiveWindow::~PerspectiveWindow()
131 {
132 }
133
134 void PerspectiveWindow::create_objects()
135 {
136         int x = 10, y = 10;
137
138         add_subwindow(canvas = new PerspectiveCanvas(plugin,
139                 x,
140                 y,
141                 get_w() - 20,
142                 get_h() - 140));
143         canvas->set_cursor(CROSS_CURSOR, 0, 0);
144         y += canvas->get_h() + 10;
145         add_subwindow(new BC_Title(x, y, _("Current X:")));
146         x += 80;
147         this->x = new PerspectiveCoord(this,
148                 plugin,
149                 x,
150                 y,
151                 plugin->get_current_x(),
152                 1);
153         this->x->create_objects();
154         x += 140;
155         add_subwindow(new BC_Title(x, y, _("Y:")));
156         x += 20;
157         this->y = new PerspectiveCoord(this,
158                 plugin,
159                 x,
160                 y,
161                 plugin->get_current_y(),
162                 0);
163         this->y->create_objects();
164         y += 30;
165         x = 10;
166         add_subwindow(new PerspectiveReset(plugin, x, y));
167         x += 100;
168         add_subwindow(mode_perspective = new PerspectiveMode(plugin,
169                 x,
170                 y,
171                 AffineEngine::PERSPECTIVE,
172                 _("Perspective")));
173         x += 120;
174         add_subwindow(mode_sheer = new PerspectiveMode(plugin,
175                 x,
176                 y,
177                 AffineEngine::SHEER,
178                 _("Sheer")));
179         x = 110;
180         y += 30;
181         add_subwindow(mode_stretch = new PerspectiveMode(plugin,
182                 x,
183                 y,
184                 AffineEngine::STRETCH,
185                 _("Stretch")));
186         update_canvas();
187         y += 30;
188         x = 10;
189         add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
190         x += 170;
191         add_subwindow(forward = new PerspectiveDirection(plugin,
192                 x,
193                 y,
194                 1,
195                 _("Forward")));
196         x += 100;
197         add_subwindow(reverse = new PerspectiveDirection(plugin,
198                 x,
199                 y,
200                 0,
201                 _("Reverse")));
202
203         show_window();
204 }
205
206
207
208 int PerspectiveWindow::resize_event(int w, int h)
209 {
210         return 1;
211 }
212
213 void PerspectiveWindow::update_canvas()
214 {
215         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
216         int x1, y1, x2, y2, x3, y3, x4, y4;
217         calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
218
219 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
220 // x1,
221 // y1,
222 // x2,
223 // y2,
224 // x3,
225 // y3,
226 // x4,
227 // y4);
228 // Draw divisions
229         canvas->set_color(WHITE);
230
231 #define DIVISIONS 10
232         for(int i = 0; i <= DIVISIONS; i++)
233         {
234 // latitude
235                 canvas->draw_line(
236                         x1 + (x4 - x1) * i / DIVISIONS,
237                         y1 + (y4 - y1) * i / DIVISIONS,
238                         x2 + (x3 - x2) * i / DIVISIONS,
239                         y2 + (y3 - y2) * i / DIVISIONS);
240 // longitude
241                 canvas->draw_line(
242                         x1 + (x2 - x1) * i / DIVISIONS,
243                         y1 + (y2 - y1) * i / DIVISIONS,
244                         x4 + (x3 - x4) * i / DIVISIONS,
245                         y4 + (y3 - y4) * i / DIVISIONS);
246         }
247
248 // Corners
249 #define RADIUS 5
250         if(plugin->config.current_point == 0)
251                 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
252         else
253                 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
254
255         if(plugin->config.current_point == 1)
256                 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
257         else
258                 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
259
260         if(plugin->config.current_point == 2)
261                 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
262         else
263                 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
264
265         if(plugin->config.current_point == 3)
266                 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
267         else
268                 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
269
270         canvas->flash();
271 }
272
273 void PerspectiveWindow::update_mode()
274 {
275         mode_perspective->update(plugin->config.mode == AffineEngine::PERSPECTIVE);
276         mode_sheer->update(plugin->config.mode == AffineEngine::SHEER);
277         mode_stretch->update(plugin->config.mode == AffineEngine::STRETCH);
278         forward->update(plugin->config.forward);
279         reverse->update(!plugin->config.forward);
280 }
281
282 void PerspectiveWindow::update_coord()
283 {
284         x->update(plugin->get_current_x());
285         y->update(plugin->get_current_y());
286 }
287
288 void PerspectiveWindow::calculate_canvas_coords(int &x1,
289         int &y1,
290         int &x2,
291         int &y2,
292         int &x3,
293         int &y3,
294         int &x4,
295         int &y4)
296 {
297         int w = canvas->get_w() - 1;
298         int h = canvas->get_h() - 1;
299         if(plugin->config.mode == AffineEngine::PERSPECTIVE ||
300                 plugin->config.mode == AffineEngine::STRETCH)
301         {
302                 x1 = (int)(plugin->config.x1 * w / 100);
303                 y1 = (int)(plugin->config.y1 * h / 100);
304                 x2 = (int)(plugin->config.x2 * w / 100);
305                 y2 = (int)(plugin->config.y2 * h / 100);
306                 x3 = (int)(plugin->config.x3 * w / 100);
307                 y3 = (int)(plugin->config.y3 * h / 100);
308                 x4 = (int)(plugin->config.x4 * w / 100);
309                 y4 = (int)(plugin->config.y4 * h / 100);
310         }
311         else
312         {
313                 x1 = (int)(plugin->config.x1 * w) / 100;
314                 y1 = 0;
315                 x2 = x1 + w;
316                 y2 = 0;
317                 x4 = (int)(plugin->config.x4 * w) / 100;
318                 y4 = h;
319                 x3 = x4 + w;
320                 y3 = h;
321         }
322 }
323
324
325
326
327 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
328         int x,
329         int y,
330         int w,
331         int h)
332  : BC_SubWindow(x, y, w, h, BLACK)
333 {
334         this->plugin = plugin;
335         state = PerspectiveCanvas::NONE;
336 }
337
338
339
340
341 int PerspectiveCanvas::button_press_event()
342 {
343         if(is_event_win() && cursor_inside())
344         {
345 // Set current point
346                 int x1, y1, x2, y2, x3, y3, x4, y4;
347                 int cursor_x = get_cursor_x();
348                 int cursor_y = get_cursor_y();
349                 ((PerspectiveWindow*)plugin->thread->window)->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
350
351                 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
352                 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
353                 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
354                 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
355 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n",
356 // distance3,
357 // cursor_x,
358 // cursor_y,
359 // x3,
360 // y3);
361                 float min = distance1;
362                 plugin->config.current_point = 0;
363                 if(distance2 < min)
364                 {
365                         min = distance2;
366                         plugin->config.current_point = 1;
367                 }
368                 if(distance3 < min)
369                 {
370                         min = distance3;
371                         plugin->config.current_point = 2;
372                 }
373                 if(distance4 < min)
374                 {
375                         min = distance4;
376                         plugin->config.current_point = 3;
377                 }
378
379                 if(plugin->config.mode == AffineEngine::SHEER)
380                 {
381                         if(plugin->config.current_point == 1)
382                                 plugin->config.current_point = 0;
383                         else
384                         if(plugin->config.current_point == 2)
385                                 plugin->config.current_point = 3;
386                 }
387                 start_cursor_x = cursor_x;
388                 start_cursor_y = cursor_y;
389
390                 if(alt_down() || shift_down())
391                 {
392                         if(alt_down())
393                                 state = PerspectiveCanvas::DRAG_FULL;
394                         else
395                                 state = PerspectiveCanvas::ZOOM;
396
397 // Get starting positions
398                         start_x1 = plugin->config.x1;
399                         start_y1 = plugin->config.y1;
400                         start_x2 = plugin->config.x2;
401                         start_y2 = plugin->config.y2;
402                         start_x3 = plugin->config.x3;
403                         start_y3 = plugin->config.y3;
404                         start_x4 = plugin->config.x4;
405                         start_y4 = plugin->config.y4;
406                 }
407                 else
408                 {
409                         state = PerspectiveCanvas::DRAG;
410
411 // Get starting positions
412                         start_x1 = plugin->get_current_x();
413                         start_y1 = plugin->get_current_y();
414                 }
415                 ((PerspectiveWindow*)plugin->thread->window)->update_coord();
416                 ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
417                 return 1;
418         }
419
420         return 0;
421 }
422
423 int PerspectiveCanvas::button_release_event()
424 {
425         if(state != PerspectiveCanvas::NONE)
426         {
427                 state = PerspectiveCanvas::NONE;
428                 return 1;
429         }
430         return 0;
431 }
432
433 int PerspectiveCanvas::cursor_motion_event()
434 {
435         if(state != PerspectiveCanvas::NONE)
436         {
437                 int w = get_w() - 1;
438                 int h = get_h() - 1;
439                 if(state == PerspectiveCanvas::DRAG)
440                 {
441                         plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
442                         plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
443                 }
444                 else
445                 if(state == PerspectiveCanvas::DRAG_FULL)
446                 {
447                         plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
448                         plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
449                         plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
450                         plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
451                         plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
452                         plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
453                         plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
454                         plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
455                 }
456                 else
457                 if(state == PerspectiveCanvas::ZOOM)
458                 {
459                         float center_x = (start_x1 +
460                                 start_x2 +
461                                 start_x3 +
462                                 start_x4) / 4;
463                         float center_y = (start_y1 +
464                                 start_y2 +
465                                 start_y3 +
466                                 start_y4) / 4;
467                         float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
468                         plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
469                         plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
470                         plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
471                         plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
472                         plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
473                         plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
474                         plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
475                         plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
476                 }
477                 ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
478                 ((PerspectiveWindow*)plugin->thread->window)->update_coord();
479                 plugin->send_configure_change();
480                 return 1;
481         }
482
483         return 0;
484 }
485
486
487
488
489
490
491 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
492         PerspectiveMain *plugin,
493         int x,
494         int y,
495         float value,
496         int is_x)
497  : BC_TumbleTextBox(gui, value, (float)-100, (float)200, x, y, 100)
498 {
499         this->plugin = plugin;
500         this->is_x = is_x;
501 }
502
503 int PerspectiveCoord::handle_event()
504 {
505         if(is_x)
506                 plugin->set_current_x(atof(get_text()));
507         else
508                 plugin->set_current_y(atof(get_text()));
509         ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
510         plugin->send_configure_change();
511         return 1;
512 }
513
514
515
516
517
518
519
520
521 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin,
522         int x,
523         int y)
524  : BC_GenericButton(x, y, _("Reset"))
525 {
526         this->plugin = plugin;
527 }
528 int PerspectiveReset::handle_event()
529 {
530         plugin->config.x1 = 0;
531         plugin->config.y1 = 0;
532         plugin->config.x2 = 100;
533         plugin->config.y2 = 0;
534         plugin->config.x3 = 100;
535         plugin->config.y3 = 100;
536         plugin->config.x4 = 0;
537         plugin->config.y4 = 100;
538         ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
539         ((PerspectiveWindow*)plugin->thread->window)->update_coord();
540         plugin->send_configure_change();
541         return 1;
542 }
543
544
545
546
547
548
549
550
551
552
553
554 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin,
555         int x,
556         int y,
557         int value,
558         char *text)
559  : BC_Radial(x, y, plugin->config.mode == value, text)
560 {
561         this->plugin = plugin;
562         this->value = value;
563 }
564 int PerspectiveMode::handle_event()
565 {
566         plugin->config.mode = value;
567         ((PerspectiveWindow*)plugin->thread->window)->update_mode();
568         ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
569         plugin->send_configure_change();
570         return 1;
571 }
572
573
574
575
576 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin,
577         int x,
578         int y,
579         int value,
580         char *text)
581  : BC_Radial(x, y, plugin->config.forward == value, text)
582 {
583         this->plugin = plugin;
584         this->value = value;
585 }
586 int PerspectiveDirection::handle_event()
587 {
588         plugin->config.forward = value;
589         ((PerspectiveWindow*)plugin->thread->window)->update_mode();
590         plugin->send_configure_change();
591         return 1;
592 }
593
594
595
596
597
598
599
600
601
602
603
604
605 PerspectiveMain::PerspectiveMain(PluginServer *server)
606  : PluginVClient(server)
607 {
608
609         engine = 0;
610         temp = 0;
611 }
612
613 PerspectiveMain::~PerspectiveMain()
614 {
615
616         if(engine) delete engine;
617         if(temp) delete temp;
618 }
619
620 const char* PerspectiveMain::plugin_title() { return _("Perspective"); }
621 int PerspectiveMain::is_realtime() { return 1; }
622
623
624
625 NEW_WINDOW_MACRO(PerspectiveMain, PerspectiveWindow)
626
627 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
628
629
630
631 void PerspectiveMain::update_gui()
632 {
633         if(thread)
634         {
635 //printf("PerspectiveMain::update_gui 1\n");
636                 thread->window->lock_window();
637 //printf("PerspectiveMain::update_gui 2\n");
638                 load_configuration();
639                 ((PerspectiveWindow*)thread->window)->update_coord();
640                 ((PerspectiveWindow*)thread->window)->update_mode();
641                 ((PerspectiveWindow*)thread->window)->update_canvas();
642                 thread->window->unlock_window();
643 //printf("PerspectiveMain::update_gui 3\n");
644         }
645 }
646
647
648
649
650
651 void PerspectiveMain::save_data(KeyFrame *keyframe)
652 {
653         FileXML output;
654
655 // cause data to be stored directly in text
656         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
657         output.tag.set_title("PERSPECTIVE");
658
659         output.tag.set_property("X1", config.x1);
660         output.tag.set_property("X2", config.x2);
661         output.tag.set_property("X3", config.x3);
662         output.tag.set_property("X4", config.x4);
663         output.tag.set_property("Y1", config.y1);
664         output.tag.set_property("Y2", config.y2);
665         output.tag.set_property("Y3", config.y3);
666         output.tag.set_property("Y4", config.y4);
667
668         output.tag.set_property("MODE", config.mode);
669         output.tag.set_property("FORWARD", config.forward);
670         output.tag.set_property("WINDOW_W", config.window_w);
671         output.tag.set_property("WINDOW_H", config.window_h);
672         output.append_tag();
673         output.tag.set_title("/PERSPECTIVE");
674         output.append_tag();
675         output.append_newline();
676         output.terminate_string();
677 }
678
679 void PerspectiveMain::read_data(KeyFrame *keyframe)
680 {
681         FileXML input;
682
683         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
684
685         int result = 0;
686
687         while(!result)
688         {
689                 result = input.read_tag();
690
691                 if(!result)
692                 {
693                         if(input.tag.title_is("PERSPECTIVE"))
694                         {
695                                 config.x1 = input.tag.get_property("X1", config.x1);
696                                 config.x2 = input.tag.get_property("X2", config.x2);
697                                 config.x3 = input.tag.get_property("X3", config.x3);
698                                 config.x4 = input.tag.get_property("X4", config.x4);
699                                 config.y1 = input.tag.get_property("Y1", config.y1);
700                                 config.y2 = input.tag.get_property("Y2", config.y2);
701                                 config.y3 = input.tag.get_property("Y3", config.y3);
702                                 config.y4 = input.tag.get_property("Y4", config.y4);
703
704                                 config.mode = input.tag.get_property("MODE", config.mode);
705                                 config.forward = input.tag.get_property("FORWARD", config.forward);
706                                 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
707                                 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
708                         }
709                 }
710         }
711 }
712
713 float PerspectiveMain::get_current_x()
714 {
715         switch(config.current_point)
716         {
717                 case 0:
718                         return config.x1;
719                         break;
720                 case 1:
721                         return config.x2;
722                         break;
723                 case 2:
724                         return config.x3;
725                         break;
726                 case 3:
727                         return config.x4;
728                         break;
729         }
730         return 0;
731 }
732
733 float PerspectiveMain::get_current_y()
734 {
735         switch(config.current_point)
736         {
737                 case 0:
738                         return config.y1;
739                         break;
740                 case 1:
741                         return config.y2;
742                         break;
743                 case 2:
744                         return config.y3;
745                         break;
746                 case 3:
747                         return config.y4;
748                         break;
749         }
750         return 0;
751 }
752
753 void PerspectiveMain::set_current_x(float value)
754 {
755         switch(config.current_point)
756         {
757                 case 0:
758                         config.x1 = value;
759                         break;
760                 case 1:
761                         config.x2 = value;
762                         break;
763                 case 2:
764                         config.x3 = value;
765                         break;
766                 case 3:
767                         config.x4 = value;
768                         break;
769         }
770 }
771
772 void PerspectiveMain::set_current_y(float value)
773 {
774         switch(config.current_point)
775         {
776                 case 0:
777                         config.y1 = value;
778                         break;
779                 case 1:
780                         config.y2 = value;
781                         break;
782                 case 2:
783                         config.y3 = value;
784                         break;
785                 case 3:
786                         config.y4 = value;
787                         break;
788         }
789 }
790
791
792
793 int PerspectiveMain::process_buffer(VFrame *frame,
794         int64_t start_position,
795         double frame_rate)
796 {
797         /*int need_reconfigure =*/ load_configuration();
798
799 // Do nothing
800         if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
801                 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
802                 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
803                 EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
804         {
805                 read_frame(frame,
806                         0,
807                         start_position,
808                         frame_rate,
809                         get_use_opengl());
810                 return 1;
811         }
812
813 // Opengl does some funny business with stretching.
814         int use_opengl = get_use_opengl() &&
815                 (config.mode == AffineEngine::PERSPECTIVE ||
816                 config.mode == AffineEngine::SHEER);
817         read_frame(frame,
818                 0,
819                 start_position,
820                 frame_rate,
821                 use_opengl);
822
823         if(!engine) engine = new AffineEngine(get_project_smp() + 1,
824                 get_project_smp() + 1);
825
826         if(use_opengl)
827                 return run_opengl();
828
829
830
831         this->input = frame;
832         this->output = frame;
833
834         int w = frame->get_w();
835         int h = frame->get_h();
836         int color_model = frame->get_color_model();
837
838         if(temp &&
839                 config.mode == AffineEngine::STRETCH &&
840                 (temp->get_w() != w * AFFINE_OVERSAMPLE ||
841                         temp->get_h() != h * AFFINE_OVERSAMPLE))
842         {
843                 delete temp;
844                 temp = 0;
845         }
846         else
847         if(temp &&
848                 (config.mode == AffineEngine::PERSPECTIVE ||
849                 config.mode == AffineEngine::SHEER) &&
850                 (temp->get_w() != w ||
851                         temp->get_h() != h))
852         {
853                 delete temp;
854                 temp = 0;
855         }
856
857         if(config.mode == AffineEngine::STRETCH)
858         {
859                 if(!temp)
860                 {
861                         temp = new VFrame(0,
862                                         -1,
863                                         w * AFFINE_OVERSAMPLE,
864                                         h * AFFINE_OVERSAMPLE,
865                                         color_model,
866                                         -1);
867                 }
868                 temp->clear_frame();
869         }
870
871         if(config.mode == AffineEngine::PERSPECTIVE ||
872                 config.mode == AffineEngine::SHEER)
873         {
874                 if(frame->get_rows()[0] == frame->get_rows()[0])
875                 {
876                         if(!temp)
877                         {
878                                 temp = new VFrame(0,
879                                         -1,
880                                         w,
881                                         h,
882                                         color_model,
883                                         -1);
884                         }
885                         temp->copy_from(input);
886                         input = temp;
887                 }
888                 output->clear_frame();
889         }
890
891
892         engine->process(output,
893                 input,
894                 temp,
895                 config.mode,
896                 config.x1,
897                 config.y1,
898                 config.x2,
899                 config.y2,
900                 config.x3,
901                 config.y3,
902                 config.x4,
903                 config.y4,
904                 config.forward);
905
906
907
908
909 // Resample
910
911         if(config.mode == AffineEngine::STRETCH)
912         {
913 #define RESAMPLE(type, components, chroma_offset) \
914 { \
915         for(int i = 0; i < h; i++) \
916         { \
917                 type *out_row = (type*)output->get_rows()[i]; \
918                 type *in_row1 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE]; \
919                 type *in_row2 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE + 1]; \
920                 for(int j = 0; j < w; j++) \
921                 { \
922                         out_row[0] = (in_row1[0] +  \
923                                         in_row1[components] +  \
924                                         in_row2[0] +  \
925                                         in_row2[components]) /  \
926                                 AFFINE_OVERSAMPLE /  \
927                                 AFFINE_OVERSAMPLE; \
928                         out_row[1] = ((in_row1[1] +  \
929                                                 in_row1[components + 1] +  \
930                                                 in_row2[1] +  \
931                                                 in_row2[components + 1]) -  \
932                                         chroma_offset *  \
933                                         AFFINE_OVERSAMPLE *  \
934                                         AFFINE_OVERSAMPLE) /  \
935                                 AFFINE_OVERSAMPLE /  \
936                                 AFFINE_OVERSAMPLE + \
937                                 chroma_offset; \
938                         out_row[2] = ((in_row1[2] +  \
939                                                 in_row1[components + 2] +  \
940                                                 in_row2[2] +  \
941                                                 in_row2[components + 2]) -  \
942                                         chroma_offset *  \
943                                         AFFINE_OVERSAMPLE *  \
944                                         AFFINE_OVERSAMPLE) /  \
945                                 AFFINE_OVERSAMPLE /  \
946                                 AFFINE_OVERSAMPLE + \
947                                 chroma_offset; \
948                         if(components == 4) \
949                         { \
950                                 out_row[3] = (in_row1[3] +  \
951                                                 in_row1[components + 3] +  \
952                                                 in_row2[3] +  \
953                                                 in_row2[components + 3]) /  \
954                                         AFFINE_OVERSAMPLE /  \
955                                         AFFINE_OVERSAMPLE; \
956                         } \
957                         out_row += components; \
958                         in_row1 += components * AFFINE_OVERSAMPLE; \
959                         in_row2 += components * AFFINE_OVERSAMPLE; \
960                 } \
961         } \
962 }
963
964                 switch(frame->get_color_model())
965                 {
966                         case BC_RGB_FLOAT:
967                                 RESAMPLE(float, 3, 0)
968                                 break;
969                         case BC_RGB888:
970                                 RESAMPLE(unsigned char, 3, 0)
971                                 break;
972                         case BC_RGBA_FLOAT:
973                                 RESAMPLE(float, 4, 0)
974                                 break;
975                         case BC_RGBA8888:
976                                 RESAMPLE(unsigned char, 4, 0)
977                                 break;
978                         case BC_YUV888:
979                                 RESAMPLE(unsigned char, 3, 0x80)
980                                 break;
981                         case BC_YUVA8888:
982                                 RESAMPLE(unsigned char, 4, 0x80)
983                                 break;
984                         case BC_RGB161616:
985                                 RESAMPLE(uint16_t, 3, 0)
986                                 break;
987                         case BC_RGBA16161616:
988                                 RESAMPLE(uint16_t, 4, 0)
989                                 break;
990                         case BC_YUV161616:
991                                 RESAMPLE(uint16_t, 3, 0x8000)
992                                 break;
993                         case BC_YUVA16161616:
994                                 RESAMPLE(uint16_t, 4, 0x8000)
995                                 break;
996                 }
997         }
998
999         return 1;
1000 }
1001
1002
1003 int PerspectiveMain::handle_opengl()
1004 {
1005 #ifdef HAVE_GL
1006         engine->set_opengl(1);
1007         engine->process(get_output(),
1008                 get_output(),
1009                 get_output(),
1010                 config.mode,
1011                 config.x1,
1012                 config.y1,
1013                 config.x2,
1014                 config.y2,
1015                 config.x3,
1016                 config.y3,
1017                 config.x4,
1018                 config.y4,
1019                 config.forward);
1020         engine->set_opengl(0);
1021         return 0;
1022 #endif
1023 }
1024
1025
1026
1027
1028
1029