initial commit
[goodguy/history.git] / cinelerra-5.0 / 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 N_("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.terminate_string();
674 }
675
676 void PerspectiveMain::read_data(KeyFrame *keyframe)
677 {
678         FileXML input;
679
680         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
681
682         int result = 0;
683
684         while(!result)
685         {
686                 result = input.read_tag();
687
688                 if(!result)
689                 {
690                         if(input.tag.title_is("PERSPECTIVE"))
691                         {
692                                 config.x1 = input.tag.get_property("X1", config.x1);
693                                 config.x2 = input.tag.get_property("X2", config.x2);
694                                 config.x3 = input.tag.get_property("X3", config.x3);
695                                 config.x4 = input.tag.get_property("X4", config.x4);
696                                 config.y1 = input.tag.get_property("Y1", config.y1);
697                                 config.y2 = input.tag.get_property("Y2", config.y2);
698                                 config.y3 = input.tag.get_property("Y3", config.y3);
699                                 config.y4 = input.tag.get_property("Y4", config.y4);
700
701                                 config.mode = input.tag.get_property("MODE", config.mode);
702                                 config.forward = input.tag.get_property("FORWARD", config.forward);
703                                 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
704                                 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
705                         }
706                 }
707         }
708 }
709
710 float PerspectiveMain::get_current_x()
711 {
712         switch(config.current_point)
713         {
714                 case 0:
715                         return config.x1;
716                         break;
717                 case 1:
718                         return config.x2;
719                         break;
720                 case 2:
721                         return config.x3;
722                         break;
723                 case 3:
724                         return config.x4;
725                         break;
726         }
727         return 0;
728 }
729
730 float PerspectiveMain::get_current_y()
731 {
732         switch(config.current_point)
733         {
734                 case 0:
735                         return config.y1;
736                         break;
737                 case 1:
738                         return config.y2;
739                         break;
740                 case 2:
741                         return config.y3;
742                         break;
743                 case 3:
744                         return config.y4;
745                         break;
746         }
747         return 0;
748 }
749
750 void PerspectiveMain::set_current_x(float value)
751 {
752         switch(config.current_point)
753         {
754                 case 0:
755                         config.x1 = value;
756                         break;
757                 case 1:
758                         config.x2 = value;
759                         break;
760                 case 2:
761                         config.x3 = value;
762                         break;
763                 case 3:
764                         config.x4 = value;
765                         break;
766         }
767 }
768
769 void PerspectiveMain::set_current_y(float value)
770 {
771         switch(config.current_point)
772         {
773                 case 0:
774                         config.y1 = value;
775                         break;
776                 case 1:
777                         config.y2 = value;
778                         break;
779                 case 2:
780                         config.y3 = value;
781                         break;
782                 case 3:
783                         config.y4 = value;
784                         break;
785         }
786 }
787
788
789
790 int PerspectiveMain::process_buffer(VFrame *frame,
791         int64_t start_position,
792         double frame_rate)
793 {
794         /*int need_reconfigure =*/ load_configuration();
795
796 // Do nothing
797         if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
798                 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
799                 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
800                 EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
801         {
802                 read_frame(frame, 
803                         0, 
804                         start_position, 
805                         frame_rate,
806                         get_use_opengl());
807                 return 1;
808         }
809
810 // Opengl does some funny business with stretching.
811         int use_opengl = get_use_opengl() &&
812                 (config.mode == AffineEngine::PERSPECTIVE || 
813                 config.mode == AffineEngine::SHEER);
814         read_frame(frame, 
815                 0, 
816                 start_position, 
817                 frame_rate,
818                 use_opengl);
819
820         if(!engine) engine = new AffineEngine(get_project_smp() + 1,
821                 get_project_smp() + 1);
822
823         if(use_opengl)
824                 return run_opengl();
825
826
827
828         this->input = frame;
829         this->output = frame;
830
831         int w = frame->get_w();
832         int h = frame->get_h();
833         int color_model = frame->get_color_model();
834
835         if(temp && 
836                 config.mode == AffineEngine::STRETCH &&
837                 (temp->get_w() != w * AFFINE_OVERSAMPLE ||
838                         temp->get_h() != h * AFFINE_OVERSAMPLE))
839         {
840                 delete temp;
841                 temp = 0;
842         }
843         else
844         if(temp &&
845                 (config.mode == AffineEngine::PERSPECTIVE ||
846                 config.mode == AffineEngine::SHEER) &&
847                 (temp->get_w() != w ||
848                         temp->get_h() != h))
849         {
850                 delete temp;
851                 temp = 0;
852         }
853
854         if(config.mode == AffineEngine::STRETCH)
855         {
856                 if(!temp)
857                 {
858                         temp = new VFrame(0,
859                                         -1,
860                                         w * AFFINE_OVERSAMPLE,
861                                         h * AFFINE_OVERSAMPLE,
862                                         color_model,
863                                         -1);
864                 }
865                 temp->clear_frame();
866         }
867
868         if(config.mode == AffineEngine::PERSPECTIVE ||
869                 config.mode == AffineEngine::SHEER)
870         {
871                 if(frame->get_rows()[0] == frame->get_rows()[0])
872                 {
873                         if(!temp) 
874                         {
875                                 temp = new VFrame(0,
876                                         -1,
877                                         w,
878                                         h,
879                                         color_model,
880                                         -1);
881                         }
882                         temp->copy_from(input);
883                         input = temp;
884                 }
885                 output->clear_frame();
886         }
887
888
889         engine->process(output,
890                 input,
891                 temp, 
892                 config.mode,
893                 config.x1,
894                 config.y1,
895                 config.x2,
896                 config.y2,
897                 config.x3,
898                 config.y3,
899                 config.x4,
900                 config.y4,
901                 config.forward);
902
903
904
905
906 // Resample
907
908         if(config.mode == AffineEngine::STRETCH)
909         {
910 #define RESAMPLE(type, components, chroma_offset) \
911 { \
912         for(int i = 0; i < h; i++) \
913         { \
914                 type *out_row = (type*)output->get_rows()[i]; \
915                 type *in_row1 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE]; \
916                 type *in_row2 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE + 1]; \
917                 for(int j = 0; j < w; j++) \
918                 { \
919                         out_row[0] = (in_row1[0] +  \
920                                         in_row1[components] +  \
921                                         in_row2[0] +  \
922                                         in_row2[components]) /  \
923                                 AFFINE_OVERSAMPLE /  \
924                                 AFFINE_OVERSAMPLE; \
925                         out_row[1] = ((in_row1[1] +  \
926                                                 in_row1[components + 1] +  \
927                                                 in_row2[1] +  \
928                                                 in_row2[components + 1]) -  \
929                                         chroma_offset *  \
930                                         AFFINE_OVERSAMPLE *  \
931                                         AFFINE_OVERSAMPLE) /  \
932                                 AFFINE_OVERSAMPLE /  \
933                                 AFFINE_OVERSAMPLE + \
934                                 chroma_offset; \
935                         out_row[2] = ((in_row1[2] +  \
936                                                 in_row1[components + 2] +  \
937                                                 in_row2[2] +  \
938                                                 in_row2[components + 2]) -  \
939                                         chroma_offset *  \
940                                         AFFINE_OVERSAMPLE *  \
941                                         AFFINE_OVERSAMPLE) /  \
942                                 AFFINE_OVERSAMPLE /  \
943                                 AFFINE_OVERSAMPLE + \
944                                 chroma_offset; \
945                         if(components == 4) \
946                         { \
947                                 out_row[3] = (in_row1[3] +  \
948                                                 in_row1[components + 3] +  \
949                                                 in_row2[3] +  \
950                                                 in_row2[components + 3]) /  \
951                                         AFFINE_OVERSAMPLE /  \
952                                         AFFINE_OVERSAMPLE; \
953                         } \
954                         out_row += components; \
955                         in_row1 += components * AFFINE_OVERSAMPLE; \
956                         in_row2 += components * AFFINE_OVERSAMPLE; \
957                 } \
958         } \
959 }
960
961                 switch(frame->get_color_model())
962                 {
963                         case BC_RGB_FLOAT:
964                                 RESAMPLE(float, 3, 0)
965                                 break;
966                         case BC_RGB888:
967                                 RESAMPLE(unsigned char, 3, 0)
968                                 break;
969                         case BC_RGBA_FLOAT:
970                                 RESAMPLE(float, 4, 0)
971                                 break;
972                         case BC_RGBA8888:
973                                 RESAMPLE(unsigned char, 4, 0)
974                                 break;
975                         case BC_YUV888:
976                                 RESAMPLE(unsigned char, 3, 0x80)
977                                 break;
978                         case BC_YUVA8888:
979                                 RESAMPLE(unsigned char, 4, 0x80)
980                                 break;
981                         case BC_RGB161616:
982                                 RESAMPLE(uint16_t, 3, 0)
983                                 break;
984                         case BC_RGBA16161616:
985                                 RESAMPLE(uint16_t, 4, 0)
986                                 break;
987                         case BC_YUV161616:
988                                 RESAMPLE(uint16_t, 3, 0x8000)
989                                 break;
990                         case BC_YUVA16161616:
991                                 RESAMPLE(uint16_t, 4, 0x8000)
992                                 break;
993                 }
994         }
995
996         return 1;
997 }
998
999
1000 int PerspectiveMain::handle_opengl()
1001 {
1002 #ifdef HAVE_GL
1003         engine->set_opengl(1);
1004         engine->process(get_output(),
1005                 get_output(),
1006                 get_output(), 
1007                 config.mode,
1008                 config.x1,
1009                 config.y1,
1010                 config.x2,
1011                 config.y2,
1012                 config.x3,
1013                 config.y3,
1014                 config.x4,
1015                 config.y4,
1016                 config.forward);
1017         engine->set_opengl(0);
1018         return 0;
1019 #endif
1020 }
1021
1022
1023
1024
1025
1026