r105: This commit was manufactured by cvs2svn to create tag
[cinelerra_cv/mob.git] / hvirtual / plugins / perspective / perspective.C
blob3f50b4e7be56374bd3d3d627e659170ce79ce5f1
1 #include "cursors.h"
2 #include "perspective.h"
4 #include <libintl.h>
5 #define _(String) gettext(String)
6 #define gettext_noop(String) String
7 #define N_(String) gettext_noop (String)
14 REGISTER_PLUGIN(PerspectiveMain)
18 PerspectiveConfig::PerspectiveConfig()
20         x1 = 0;
21         y1 = 0;
22         x2 = 100;
23         y2 = 0;
24         x3 = 100;
25         y3 = 100;
26         x4 = 0;
27         y4 = 100;
28         mode = PERSPECTIVE;
29         window_w = 400;
30         window_h = 450;
31         current_point = 0;
32         forward = 1;
35 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
37         return 
38                 EQUIV(x1, that.x1) &&
39                 EQUIV(y1, that.y1) &&
40                 EQUIV(x2, that.x2) &&
41                 EQUIV(y2, that.y2) &&
42                 EQUIV(x3, that.x3) &&
43                 EQUIV(y3, that.y3) &&
44                 EQUIV(x4, that.x4) &&
45                 EQUIV(y4, that.y4) &&
46                 mode == that.mode &&
47                 forward == that.forward;
50 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
52         x1 = that.x1;
53         y1 = that.y1;
54         x2 = that.x2;
55         y2 = that.y2;
56         x3 = that.x3;
57         y3 = that.y3;
58         x4 = that.x4;
59         y4 = that.y4;
60         mode = that.mode;
61         window_w = that.window_w;
62         window_h = that.window_h;
63         current_point = that.current_point;
64         forward = that.forward;
67 void PerspectiveConfig::interpolate(PerspectiveConfig &prev, 
68         PerspectiveConfig &next, 
69         int64_t prev_frame, 
70         int64_t next_frame, 
71         int64_t current_frame)
73         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
74         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
75         this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
76         this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
77         this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
78         this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
79         this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
80         this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
81         this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
82         this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
83         mode = prev.mode;
84         forward = prev.forward;
95 PLUGIN_THREAD_OBJECT(PerspectiveMain, PerspectiveThread, PerspectiveWindow)
99 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin, int x, int y)
100  : BC_Window(plugin->gui_string, 
101         x,
102         y,
103         plugin->config.window_w, 
104         plugin->config.window_h, 
105         plugin->config.window_w,
106         plugin->config.window_h,
107         0, 
108         1)
110 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
111         this->plugin = plugin; 
114 PerspectiveWindow::~PerspectiveWindow()
118 int PerspectiveWindow::create_objects()
120         int x = 10, y = 10;
122         add_subwindow(canvas = new PerspectiveCanvas(plugin, 
123                 x, 
124                 y, 
125                 get_w() - 20, 
126                 get_h() - 140));
127         canvas->set_cursor(CROSS_CURSOR);
128         y += canvas->get_h() + 10;
129         add_subwindow(new BC_Title(x, y, _("Current X:")));
130         x += 80;
131         this->x = new PerspectiveCoord(this, 
132                 plugin, 
133                 x, 
134                 y, 
135                 plugin->get_current_x(),
136                 1);
137         this->x->create_objects();
138         x += 140;
139         add_subwindow(new BC_Title(x, y, _("Y:")));
140         x += 20;
141         this->y = new PerspectiveCoord(this, 
142                 plugin, 
143                 x, 
144                 y, 
145                 plugin->get_current_y(),
146                 0);
147         this->y->create_objects();
148         y += 30;
149         x = 10;
150         add_subwindow(new PerspectiveReset(plugin, x, y));
151         x += 100;
152         add_subwindow(mode_perspective = new PerspectiveMode(plugin, 
153                 x, 
154                 y, 
155                 PerspectiveConfig::PERSPECTIVE,
156                 _("Perspective")));
157         x += 120;
158         add_subwindow(mode_sheer = new PerspectiveMode(plugin, 
159                 x, 
160                 y, 
161                 PerspectiveConfig::SHEER,
162                 _("Sheer")));
163         x = 110;
164         y += 30;
165         add_subwindow(mode_stretch = new PerspectiveMode(plugin, 
166                 x, 
167                 y, 
168                 PerspectiveConfig::STRETCH,
169                 _("Stretch")));
170         update_canvas();
171         y += 30;
172         x = 10;
173         add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
174         x += 170;
175         add_subwindow(forward = new PerspectiveDirection(plugin, 
176                 x, 
177                 y, 
178                 1,
179                 _("Forward")));
180         x += 100;
181         add_subwindow(reverse = new PerspectiveDirection(plugin, 
182                 x, 
183                 y, 
184                 0,
185                 _("Reverse")));
187         show_window();
188         flush();
189         return 0;
192 WINDOW_CLOSE_EVENT(PerspectiveWindow)
194 int PerspectiveWindow::resize_event(int w, int h)
196         return 1;
199 void PerspectiveWindow::update_canvas()
201         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
202         int x1, y1, x2, y2, x3, y3, x4, y4;
203         calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
205 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
206 // x1,
207 // y1,
208 // x2,
209 // y2,
210 // x3,
211 // y3,
212 // x4,
213 // y4);
214         canvas->set_color(BLACK);
216 #define DIVISIONS 10
217         for(int i = 0; i <= DIVISIONS; i++)
218         {
219 // latitude
220                 canvas->draw_line(
221                         x1 + (x4 - x1) * i / DIVISIONS,
222                         y1 + (y4 - y1) * i / DIVISIONS,
223                         x2 + (x3 - x2) * i / DIVISIONS,
224                         y2 + (y3 - y2) * i / DIVISIONS);
225 // longitude
226                 canvas->draw_line(
227                         x1 + (x2 - x1) * i / DIVISIONS,
228                         y1 + (y2 - y1) * i / DIVISIONS,
229                         x4 + (x3 - x4) * i / DIVISIONS,
230                         y4 + (y3 - y4) * i / DIVISIONS);
231         }
233 // Corners
234 #define RADIUS 5
235         if(plugin->config.current_point == 0)
236                 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
237         else
238                 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
240         if(plugin->config.current_point == 1)
241                 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
242         else
243                 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
245         if(plugin->config.current_point == 2)
246                 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
247         else
248                 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
250         if(plugin->config.current_point == 3)
251                 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
252         else
253                 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
255         canvas->flash();
256         canvas->flush();
259 void PerspectiveWindow::update_mode()
261         mode_perspective->update(plugin->config.mode == PerspectiveConfig::PERSPECTIVE);
262         mode_sheer->update(plugin->config.mode == PerspectiveConfig::SHEER);
263         mode_stretch->update(plugin->config.mode == PerspectiveConfig::STRETCH);
264         forward->update(plugin->config.forward);
265         reverse->update(!plugin->config.forward);
268 void PerspectiveWindow::update_coord()
270         x->update(plugin->get_current_x());
271         y->update(plugin->get_current_y());
274 void PerspectiveWindow::calculate_canvas_coords(int &x1, 
275         int &y1, 
276         int &x2, 
277         int &y2, 
278         int &x3, 
279         int &y3, 
280         int &x4, 
281         int &y4)
283         int w = canvas->get_w() - 1;
284         int h = canvas->get_h() - 1;
285         if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
286                 plugin->config.mode == PerspectiveConfig::STRETCH)
287         {
288                 x1 = (int)(plugin->config.x1 * w / 100);
289                 y1 = (int)(plugin->config.y1 * h / 100);
290                 x2 = (int)(plugin->config.x2 * w / 100);
291                 y2 = (int)(plugin->config.y2 * h / 100);
292                 x3 = (int)(plugin->config.x3 * w / 100);
293                 y3 = (int)(plugin->config.y3 * h / 100);
294                 x4 = (int)(plugin->config.x4 * w / 100);
295                 y4 = (int)(plugin->config.y4 * h / 100);
296         }
297         else
298         {
299                 x1 = (int)(plugin->config.x1 * w) / 100;
300                 y1 = 0;
301                 x2 = x1 + w;
302                 y2 = 0;
303                 x4 = (int)(plugin->config.x4 * w) / 100;
304                 y4 = h;
305                 x3 = x4 + w;
306                 y3 = h;
307         }
313 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin, 
314         int x, 
315         int y, 
316         int w,
317         int h)
318  : BC_SubWindow(x, y, w, h, 0xffffff)
320         this->plugin = plugin;
321         state = PerspectiveCanvas::NONE;
326 #define DISTANCE(x1, y1, x2, y2) \
327 (sqrt(((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1))))
329 int PerspectiveCanvas::button_press_event()
331         if(is_event_win() && cursor_inside())
332         {
333 // Set current point
334                 int x1, y1, x2, y2, x3, y3, x4, y4;
335                 int cursor_x = get_cursor_x();
336                 int cursor_y = get_cursor_y();
337                 plugin->thread->window->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
339                 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
340                 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
341                 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
342                 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
343 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n", 
344 // distance3,
345 // cursor_x,
346 // cursor_y,
347 // x3,
348 // y3);
349                 float min = distance1;
350                 plugin->config.current_point = 0;
351                 if(distance2 < min)
352                 {
353                         min = distance2;
354                         plugin->config.current_point = 1;
355                 }
356                 if(distance3 < min)
357                 {
358                         min = distance3;
359                         plugin->config.current_point = 2;
360                 }
361                 if(distance4 < min)
362                 {
363                         min = distance4;
364                         plugin->config.current_point = 3;
365                 }
367                 if(plugin->config.mode == PerspectiveConfig::SHEER)
368                 {
369                         if(plugin->config.current_point == 1)
370                                 plugin->config.current_point = 0;
371                         else
372                         if(plugin->config.current_point == 2)
373                                 plugin->config.current_point = 3;
374                 }
375                 start_cursor_x = cursor_x;
376                 start_cursor_y = cursor_y;
378                 if(alt_down() || shift_down())
379                 {
380                         if(alt_down())
381                                 state = PerspectiveCanvas::DRAG_FULL;
382                         else
383                                 state = PerspectiveCanvas::ZOOM;
385 // Get starting positions
386                         start_x1 = plugin->config.x1;
387                         start_y1 = plugin->config.y1;
388                         start_x2 = plugin->config.x2;
389                         start_y2 = plugin->config.y2;
390                         start_x3 = plugin->config.x3;
391                         start_y3 = plugin->config.y3;
392                         start_x4 = plugin->config.x4;
393                         start_y4 = plugin->config.y4;
394                 }
395                 else
396                 {
397                         state = PerspectiveCanvas::DRAG;
399 // Get starting positions
400                         start_x1 = plugin->get_current_x();
401                         start_y1 = plugin->get_current_y();
402                 }
403                 plugin->thread->window->update_coord();
404                 plugin->thread->window->update_canvas();
405                 return 1;
406         }
408         return 0;
411 int PerspectiveCanvas::button_release_event()
413         if(state != PerspectiveCanvas::NONE)
414         {
415                 state = PerspectiveCanvas::NONE;
416                 return 1;
417         }
418         return 0;
421 int PerspectiveCanvas::cursor_motion_event()
423         if(state != PerspectiveCanvas::NONE)
424         {
425                 int w = get_w() - 1;
426                 int h = get_h() - 1;
427                 if(state == PerspectiveCanvas::DRAG)
428                 {
429                         plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
430                         plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
431                 }
432                 else
433                 if(state == PerspectiveCanvas::DRAG_FULL)
434                 {
435                         plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
436                         plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
437                         plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
438                         plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
439                         plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
440                         plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
441                         plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
442                         plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
443                 }
444                 else
445                 if(state == PerspectiveCanvas::ZOOM)
446                 {
447                         float center_x = (start_x1 +
448                                 start_x2 +
449                                 start_x3 +
450                                 start_x4) / 4;
451                         float center_y = (start_y1 +
452                                 start_y2 +
453                                 start_y3 +
454                                 start_y4) / 4;
455                         float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
456                         plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
457                         plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
458                         plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
459                         plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
460                         plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
461                         plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
462                         plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
463                         plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
464                 }
465                 plugin->thread->window->update_canvas();
466                 plugin->thread->window->update_coord();
467                 plugin->send_configure_change();
468                 return 1;
469         }
471         return 0;
479 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
480         PerspectiveMain *plugin, 
481         int x, 
482         int y,
483         float value,
484         int is_x)
485  : BC_TumbleTextBox(gui, value, (float)0, (float)100, x, y, 100)
487         this->plugin = plugin;
488         this->is_x = is_x;
491 int PerspectiveCoord::handle_event()
493         if(is_x)
494                 plugin->set_current_x(atof(get_text()));
495         else
496                 plugin->set_current_y(atof(get_text()));
497         plugin->thread->window->update_canvas();
498         plugin->send_configure_change();
499         return 1;
509 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin, 
510         int x, 
511         int y)
512  : BC_GenericButton(x, y, _("Reset"))
514         this->plugin = plugin;
516 int PerspectiveReset::handle_event()
518         plugin->config.x1 = 0;
519         plugin->config.y1 = 0;
520         plugin->config.x2 = 100;
521         plugin->config.y2 = 0;
522         plugin->config.x3 = 100;
523         plugin->config.y3 = 100;
524         plugin->config.x4 = 0;
525         plugin->config.y4 = 100;
526         plugin->thread->window->update_canvas();
527         plugin->thread->window->update_coord();
528         plugin->send_configure_change();
529         return 1;
542 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin, 
543         int x, 
544         int y,
545         int value,
546         char *text)
547  : BC_Radial(x, y, plugin->config.mode == value, text)
549         this->plugin = plugin;
550         this->value = value;
552 int PerspectiveMode::handle_event()
554         plugin->config.mode = value;
555         plugin->thread->window->update_mode();
556         plugin->thread->window->update_canvas();
557         plugin->send_configure_change();
558         return 1;
564 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin, 
565         int x, 
566         int y,
567         int value,
568         char *text)
569  : BC_Radial(x, y, plugin->config.forward == value, text)
571         this->plugin = plugin;
572         this->value = value;
574 int PerspectiveDirection::handle_event()
576         plugin->config.forward = value;
577         plugin->thread->window->update_mode();
578         plugin->send_configure_change();
579         return 1;
593 PerspectiveMain::PerspectiveMain(PluginServer *server)
594  : PluginVClient(server)
596         PLUGIN_CONSTRUCTOR_MACRO
597         engine = 0;
598         temp = 0;
601 PerspectiveMain::~PerspectiveMain()
603         PLUGIN_DESTRUCTOR_MACRO
604         if(engine) delete engine;
605         if(temp) delete temp;
608 char* PerspectiveMain::plugin_title() { return _("Perspective"); }
609 int PerspectiveMain::is_realtime() { return 1; }
612 NEW_PICON_MACRO(PerspectiveMain)
614 SHOW_GUI_MACRO(PerspectiveMain, PerspectiveThread)
616 SET_STRING_MACRO(PerspectiveMain)
618 RAISE_WINDOW_MACRO(PerspectiveMain)
620 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
624 void PerspectiveMain::update_gui()
626         if(thread)
627         {
628 //printf("PerspectiveMain::update_gui 1\n");
629                 thread->window->lock_window();
630 //printf("PerspectiveMain::update_gui 2\n");
631                 load_configuration();
632                 thread->window->update_coord();
633                 thread->window->update_mode();
634                 thread->window->update_canvas();
635                 thread->window->unlock_window();
636 //printf("PerspectiveMain::update_gui 3\n");
637         }
641 int PerspectiveMain::load_defaults()
643         char directory[1024], string[1024];
644 // set the default directory
645         sprintf(directory, "%sperspective.rc", BCASTDIR);
647 // load the defaults
648         defaults = new Defaults(directory);
649         defaults->load();
651         config.x1 = defaults->get("X1", config.x1);
652         config.x2 = defaults->get("X2", config.x2);
653         config.x3 = defaults->get("X3", config.x3);
654         config.x4 = defaults->get("X4", config.x4);
655         config.y1 = defaults->get("Y1", config.y1);
656         config.y2 = defaults->get("Y2", config.y2);
657         config.y3 = defaults->get("Y3", config.y3);
658         config.y4 = defaults->get("Y4", config.y4);
660         config.mode = defaults->get("MODE", config.mode);
661         config.forward = defaults->get("FORWARD", config.forward);
662         config.window_w = defaults->get("WINDOW_W", config.window_w);
663         config.window_h = defaults->get("WINDOW_H", config.window_h);
664         return 0;
668 int PerspectiveMain::save_defaults()
670         defaults->update("X1", config.x1);
671         defaults->update("X2", config.x2);
672         defaults->update("X3", config.x3);
673         defaults->update("X4", config.x4);
674         defaults->update("Y1", config.y1);
675         defaults->update("Y2", config.y2);
676         defaults->update("Y3", config.y3);
677         defaults->update("Y4", config.y4);
679         defaults->update("MODE", config.mode);
680         defaults->update("FORWARD", config.forward);
681         defaults->update("WINDOW_W", config.window_w);
682         defaults->update("WINDOW_H", config.window_h);
683         defaults->save();
684         return 0;
689 void PerspectiveMain::save_data(KeyFrame *keyframe)
691         FileXML output;
693 // cause data to be stored directly in text
694         output.set_shared_string(keyframe->data, MESSAGESIZE);
695         output.tag.set_title("PERSPECTIVE");
697         output.tag.set_property("X1", config.x1);
698         output.tag.set_property("X2", config.x2);
699         output.tag.set_property("X3", config.x3);
700         output.tag.set_property("X4", config.x4);
701         output.tag.set_property("Y1", config.y1);
702         output.tag.set_property("Y2", config.y2);
703         output.tag.set_property("Y3", config.y3);
704         output.tag.set_property("Y4", config.y4);
706         output.tag.set_property("MODE", config.mode);
707         output.tag.set_property("FORWARD", config.forward);
708         output.tag.set_property("WINDOW_W", config.window_w);
709         output.tag.set_property("WINDOW_H", config.window_h);
710         output.append_tag();
711         output.terminate_string();
714 void PerspectiveMain::read_data(KeyFrame *keyframe)
716         FileXML input;
718         input.set_shared_string(keyframe->data, strlen(keyframe->data));
720         int result = 0;
722         while(!result)
723         {
724                 result = input.read_tag();
726                 if(!result)
727                 {
728                         if(input.tag.title_is("PERSPECTIVE"))
729                         {
730                                 config.x1 = input.tag.get_property("X1", config.x1);
731                                 config.x2 = input.tag.get_property("X2", config.x2);
732                                 config.x3 = input.tag.get_property("X3", config.x3);
733                                 config.x4 = input.tag.get_property("X4", config.x4);
734                                 config.y1 = input.tag.get_property("Y1", config.y1);
735                                 config.y2 = input.tag.get_property("Y2", config.y2);
736                                 config.y3 = input.tag.get_property("Y3", config.y3);
737                                 config.y4 = input.tag.get_property("Y4", config.y4);
739                                 config.mode = input.tag.get_property("MODE", config.mode);
740                                 config.forward = input.tag.get_property("FORWARD", config.forward);
741                                 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
742                                 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
743                         }
744                 }
745         }
748 float PerspectiveMain::get_current_x()
750         switch(config.current_point)
751         {
752                 case 0:
753                         return config.x1;
754                         break;
755                 case 1:
756                         return config.x2;
757                         break;
758                 case 2:
759                         return config.x3;
760                         break;
761                 case 3:
762                         return config.x4;
763                         break;
764         }
767 float PerspectiveMain::get_current_y()
769         switch(config.current_point)
770         {
771                 case 0:
772                         return config.y1;
773                         break;
774                 case 1:
775                         return config.y2;
776                         break;
777                 case 2:
778                         return config.y3;
779                         break;
780                 case 3:
781                         return config.y4;
782                         break;
783         }
786 void PerspectiveMain::set_current_x(float value)
788         switch(config.current_point)
789         {
790                 case 0:
791                         config.x1 = value;
792                         break;
793                 case 1:
794                         config.x2 = value;
795                         break;
796                 case 2:
797                         config.x3 = value;
798                         break;
799                 case 3:
800                         config.x4 = value;
801                         break;
802         }
805 void PerspectiveMain::set_current_y(float value)
807         switch(config.current_point)
808         {
809                 case 0:
810                         config.y1 = value;
811                         break;
812                 case 1:
813                         config.y2 = value;
814                         break;
815                 case 2:
816                         config.y3 = value;
817                         break;
818                 case 3:
819                         config.y4 = value;
820                         break;
821         }
826 int PerspectiveMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
828         int need_reconfigure = load_configuration();
831         if(!engine) engine = new PerspectiveEngine(this,
832                 get_project_smp() + 1,
833                 get_project_smp() + 1);
835         this->input = input_ptr;
836         this->output = output_ptr;
838         if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
839                 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
840                 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
841                 EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
842         {
843                 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
844                         output_ptr->copy_from(input_ptr);
845                 return 1;
846         }
848         int w = input_ptr->get_w();
849         int h = input_ptr->get_h();
850         int color_model = input_ptr->get_color_model();
852         if(temp && 
853                 config.mode == PerspectiveConfig::STRETCH &&
854                 (temp->get_w() != w * OVERSAMPLE ||
855                         temp->get_h() != h * OVERSAMPLE))
856         {
857                 delete temp;
858                 temp = 0;
859         }
860         else
861         if(temp &&
862                 (config.mode == PerspectiveConfig::PERSPECTIVE ||
863                 config.mode == PerspectiveConfig::SHEER) &&
864                 (temp->get_w() != w ||
865                         temp->get_h() != h))
866         {
867                 delete temp;
868                 temp = 0;
869         }
871         if(config.mode == PerspectiveConfig::STRETCH)
872         {
873                 if(!temp)
874                 {
875                         temp = new VFrame(0,
876                                         w * OVERSAMPLE,
877                                         h * OVERSAMPLE,
878                                         color_model);
879                 }
880                 temp->clear_frame();
881         }
883         if(config.mode == PerspectiveConfig::PERSPECTIVE ||
884                 config.mode == PerspectiveConfig::SHEER)
885         {
886                 if(input_ptr->get_rows()[0] == output_ptr->get_rows()[0])
887                 {
888                         if(!temp) 
889                         {
890                                 temp = new VFrame(0,
891                                         w,
892                                         h,
893                                         color_model);
894                         }
895                         temp->copy_from(input);
896                         input = temp;
897                 }
898                 output->clear_frame();
899         }
903         engine->process_packages();
908 // Resample
910         if(config.mode == PerspectiveConfig::STRETCH)
911         {
912 #define RESAMPLE(type, components, chroma_offset) \
913 { \
914         for(int i = 0; i < h; i++) \
915         { \
916                 type *out_row = (type*)output->get_rows()[i]; \
917                 type *in_row1 = (type*)temp->get_rows()[i * OVERSAMPLE]; \
918                 type *in_row2 = (type*)temp->get_rows()[i * OVERSAMPLE + 1]; \
919                 for(int j = 0; j < w; j++) \
920                 { \
921                         out_row[0] = (in_row1[0] +  \
922                                         in_row1[components] +  \
923                                         in_row2[0] +  \
924                                         in_row2[components]) /  \
925                                 OVERSAMPLE /  \
926                                 OVERSAMPLE; \
927                         out_row[1] = ((in_row1[1] +  \
928                                                 in_row1[components + 1] +  \
929                                                 in_row2[1] +  \
930                                                 in_row2[components + 1]) -  \
931                                         chroma_offset *  \
932                                         OVERSAMPLE *  \
933                                         OVERSAMPLE) /  \
934                                 OVERSAMPLE /  \
935                                 OVERSAMPLE + \
936                                 chroma_offset; \
937                         out_row[2] = ((in_row1[2] +  \
938                                                 in_row1[components + 2] +  \
939                                                 in_row2[2] +  \
940                                                 in_row2[components + 2]) -  \
941                                         chroma_offset *  \
942                                         OVERSAMPLE *  \
943                                         OVERSAMPLE) /  \
944                                 OVERSAMPLE /  \
945                                 OVERSAMPLE + \
946                                 chroma_offset; \
947                         if(components == 4) \
948                         { \
949                                 out_row[3] = (in_row1[3] +  \
950                                                 in_row1[components + 3] +  \
951                                                 in_row2[3] +  \
952                                                 in_row2[components + 3]) /  \
953                                         OVERSAMPLE /  \
954                                         OVERSAMPLE; \
955                         } \
956                         out_row += components; \
957                         in_row1 += components * OVERSAMPLE; \
958                         in_row2 += components * OVERSAMPLE; \
959                 } \
960         } \
963                 switch(input_ptr->get_color_model())
964                 {
965                         case BC_RGB888:
966                                 RESAMPLE(unsigned char, 3, 0)
967                                 break;
968                         case BC_RGBA8888:
969                                 RESAMPLE(unsigned char, 4, 0)
970                                 break;
971                         case BC_YUV888:
972                                 RESAMPLE(unsigned char, 3, 0x80)
973                                 break;
974                         case BC_YUVA8888:
975                                 RESAMPLE(unsigned char, 4, 0x80)
976                                 break;
977                         case BC_RGB161616:
978                                 RESAMPLE(uint16_t, 3, 0)
979                                 break;
980                         case BC_RGBA16161616:
981                                 RESAMPLE(uint16_t, 4, 0)
982                                 break;
983                         case BC_YUV161616:
984                                 RESAMPLE(uint16_t, 3, 0x8000)
985                                 break;
986                         case BC_YUVA16161616:
987                                 RESAMPLE(uint16_t, 4, 0x8000)
988                                 break;
989                 }
990         }
992         return 1;
1005 PerspectiveMatrix::PerspectiveMatrix()
1007         bzero(values, sizeof(values));
1010 void PerspectiveMatrix::identity()
1012         bzero(values, sizeof(values));
1013         values[0][0] = 1;
1014         values[1][1] = 1;
1015         values[2][2] = 1;
1018 void PerspectiveMatrix::translate(double x, double y)
1020         double g = values[2][0];
1021         double h = values[2][1];
1022         double i = values[2][2];
1023         values[0][0] += x * g;
1024         values[0][1] += x * h;
1025         values[0][2] += x * i;
1026         values[1][0] += y * g;
1027         values[1][1] += y * h;
1028         values[1][2] += y * i;
1031 void PerspectiveMatrix::scale(double x, double y)
1033         values[0][0] *= x;
1034         values[0][1] *= x;
1035         values[0][2] *= x;
1037         values[1][0] *= y;
1038         values[1][1] *= y;
1039         values[1][2] *= y;
1042 void PerspectiveMatrix::multiply(PerspectiveMatrix *dst)
1044         int i, j;
1045         PerspectiveMatrix tmp;
1046         double t1, t2, t3;
1048         for (i = 0; i < 3; i++)
1049     {
1050         t1 = values[i][0];
1051         t2 = values[i][1];
1052         t3 = values[i][2];
1053         for (j = 0; j < 3; j++)
1054                 {
1055                         tmp.values[i][j]  = t1 * dst->values[0][j];
1056                         tmp.values[i][j] += t2 * dst->values[1][j];
1057                         tmp.values[i][j] += t3 * dst->values[2][j];
1058                 }
1059     }
1060         dst->copy_from(&tmp);
1063 double PerspectiveMatrix::determinant()
1065         double determinant;
1067         determinant  = 
1068         values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
1069         determinant -= 
1070         values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
1071         determinant += 
1072         values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
1074         return determinant;
1077 void PerspectiveMatrix::invert(PerspectiveMatrix *dst)
1079         double det_1;
1081         det_1 = determinant();
1083         if(det_1 == 0.0)
1084         return;
1086         det_1 = 1.0 / det_1;
1088         dst->values[0][0] =   
1089       (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
1091         dst->values[1][0] = 
1092       - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
1094         dst->values[2][0] =   
1095       (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
1097         dst->values[0][1] = 
1098       - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
1100         dst->values[1][1] = 
1101       (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
1103         dst->values[2][1] = 
1104       - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
1106         dst->values[0][2] =
1107       (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
1109         dst->values[1][2] = 
1110       - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
1112         dst->values[2][2] = 
1113       (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
1116 void PerspectiveMatrix::copy_from(PerspectiveMatrix *src)
1118         memcpy(&values[0][0], &src->values[0][0], sizeof(values));
1121 void PerspectiveMatrix::transform_point(float x, 
1122         float y, 
1123         float *newx, 
1124         float *newy)
1126         double w;
1128         w = values[2][0] * x + values[2][1] * y + values[2][2];
1130         if (w == 0.0)
1131         w = 1.0;
1132         else
1133         w = 1.0 / w;
1135         *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
1136         *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
1139 void PerspectiveMatrix::dump()
1141         printf("PerspectiveMatrix::dump\n");
1142         printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
1143         printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
1144         printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
1151 PerspectivePackage::PerspectivePackage()
1152  : LoadPackage()
1159 PerspectiveUnit::PerspectiveUnit(PerspectiveEngine *server, 
1160         PerspectiveMain *plugin)
1161  : LoadClient(server)
1163         this->plugin = plugin;
1164         this->server = server;
1175 void PerspectiveUnit::calculate_matrix(
1176         double in_x1,
1177         double in_y1,
1178         double in_x2,
1179         double in_y2,
1180         double out_x1,
1181         double out_y1,
1182         double out_x2,
1183         double out_y2,
1184         double out_x3,
1185         double out_y3,
1186         double out_x4,
1187         double out_y4,
1188         PerspectiveMatrix *result)
1190         PerspectiveMatrix matrix;
1191         double scalex;
1192         double scaley;
1194         scalex = scaley = 1.0;
1196         if((in_x2 - in_x1) > 0)
1197         scalex = 1.0 / (double)(in_x2 - in_x1);
1199         if((in_y2 - in_y1) > 0)
1200         scaley = 1.0 / (double)(in_y2 - in_y1);
1202 /* Determine the perspective transform that maps from
1203  * the unit cube to the transformed coordinates
1204  */
1205     double dx1, dx2, dx3, dy1, dy2, dy3;
1206     double det1, det2;
1208     dx1 = out_x2 - out_x4;
1209     dx2 = out_x3 - out_x4;
1210     dx3 = out_x1 - out_x2 + out_x4 - out_x3;
1212     dy1 = out_y2 - out_y4;
1213     dy2 = out_y3 - out_y4;
1214     dy3 = out_y1 - out_y2 + out_y4 - out_y3;
1215 // printf("PerspectiveUnit::calculate_matrix %f %f %f %f %f %f\n",
1216 // dx1,
1217 // dx2,
1218 // dx3,
1219 // dy1,
1220 // dy2,
1221 // dy3
1222 // );
1224 /*  Is the mapping affine?  */
1225     if((dx3 == 0.0) && (dy3 == 0.0))
1226     {
1227         matrix.values[0][0] = out_x2 - out_x1;
1228         matrix.values[0][1] = out_x4 - out_x2;
1229         matrix.values[0][2] = out_x1;
1230         matrix.values[1][0] = out_y2 - out_y1;
1231         matrix.values[1][1] = out_y4 - out_y2;
1232         matrix.values[1][2] = out_y1;
1233         matrix.values[2][0] = 0.0;
1234         matrix.values[2][1] = 0.0;
1235     }
1236     else
1237     {
1238         det1 = dx3 * dy2 - dy3 * dx2;
1239         det2 = dx1 * dy2 - dy1 * dx2;
1240         matrix.values[2][0] = det1 / det2;
1241         det1 = dx1 * dy3 - dy1 * dx3;
1242         det2 = dx1 * dy2 - dy1 * dx2;
1243         matrix.values[2][1] = det1 / det2;
1245         matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
1246         matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
1247         matrix.values[0][2] = out_x1;
1249         matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
1250         matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
1251         matrix.values[1][2] = out_y1;
1252     }
1254     matrix.values[2][2] = 1.0;
1256 // printf("PerspectiveUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
1257 // matrix.dump();
1259         result->identity();
1260         result->translate(-in_x1, -in_y1);
1261         result->scale(scalex, scaley);
1262         matrix.multiply(result);
1263 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
1264 //                                { 0.0, 0.0896, 0.0 },
1265 //                                { -0.00126, 0.0, 1.0 } };
1266 // memcpy(&result->values[0][0], test, sizeof(test));
1267 // printf("PerspectiveUnit::calculate_matrix 4 %p\n", result);
1268 // result->dump();
1273 float PerspectiveUnit::transform_cubic(float dx,
1274                                float jm1,
1275                                float j,
1276                                float jp1,
1277                                float jp2)
1279 /* Catmull-Rom - not bad */
1280         float result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
1281                        ( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
1282                        ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
1284         return result;
1288 void PerspectiveUnit::process_package(LoadPackage *package)
1290         PerspectivePackage *pkg = (PerspectivePackage*)package;
1291         int w = plugin->input->get_w();
1292         int h = plugin->input->get_h();
1293         int maxw = w - 1;
1294         int maxh = h - 1;
1296 // Calculate real coords
1297         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
1298         if(plugin->config.mode == PerspectiveConfig::STRETCH ||
1299                 plugin->config.mode == PerspectiveConfig::PERSPECTIVE)
1300         {
1301                 out_x1 = (float)plugin->config.x1 * w / 100;
1302                 out_y1 = (float)plugin->config.y1 * h / 100;
1303                 out_x2 = (float)plugin->config.x2 * w / 100;
1304                 out_y2 = (float)plugin->config.y2 * h / 100;
1305                 out_x3 = (float)plugin->config.x3 * w / 100;
1306                 out_y3 = (float)plugin->config.y3 * h / 100;
1307                 out_x4 = (float)plugin->config.x4 * w / 100;
1308                 out_y4 = (float)plugin->config.y4 * h / 100;
1309         }
1310         else
1311         {
1312                 out_x1 = (float)plugin->config.x1 * w / 100;
1313                 out_y1 = 0;
1314                 out_x2 = out_x1 + w;
1315                 out_y2 = 0;
1316                 out_x4 = (float)plugin->config.x4 * w / 100;
1317                 out_y4 = h;
1318                 out_x3 = out_x4 + w;
1319                 out_y3 = h;
1320         }
1324         if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
1325                 plugin->config.mode == PerspectiveConfig::SHEER)
1326         {
1327                 PerspectiveMatrix matrix;
1328                 float temp;
1329                 temp = out_x4;
1330                 out_x4 = out_x3;
1331                 out_x3 = temp;
1332                 temp = out_y4;
1333                 out_y4 = out_y3;
1334                 out_y3 = temp;
1338 // printf("PerspectiveUnit::process_package 10 %f %f %f %f %f %f %f %f\n", 
1339 // out_x1,
1340 // out_y1,
1341 // out_x2,
1342 // out_y2,
1343 // out_x3,
1344 // out_y3,
1345 // out_x4,
1346 // out_y4);
1350                 calculate_matrix(
1351                         0,
1352                         0,
1353                         w,
1354                         h,
1355                         out_x1,
1356                         out_y1,
1357                         out_x2,
1358                         out_y2,
1359                         out_x3,
1360                         out_y3,
1361                         out_x4,
1362                         out_y4,
1363                         &matrix);
1365                 int interpolate = 1;
1366                 int reverse = !plugin->config.forward;
1367                 float tx, ty, tw;
1368                 float xinc, yinc, winc;
1369                 PerspectiveMatrix m, im;
1370                 float ttx, tty;
1371                 int itx, ity;
1372                 int tx1, ty1, tx2, ty2;
1374                 if(reverse)
1375                 {
1376                         m.copy_from(&matrix);
1377                         m.invert(&im);
1378                         matrix.copy_from(&im);
1379                 }
1380                 else
1381                 {
1382                         matrix.invert(&m);
1383                 }
1385                 float dx1, dy1;
1386                 float dx2, dy2;
1387                 float dx3, dy3;
1388                 float dx4, dy4;
1389                 matrix.transform_point(0, 0, &dx1, &dy1);
1390                 matrix.transform_point(w, 0, &dx2, &dy2);
1391                 matrix.transform_point(0, h, &dx3, &dy3);
1392                 matrix.transform_point(w, h, &dx4, &dy4);
1394 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
1395 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
1396 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
1397 #define CUBIC_ROW(in_row, chroma_offset) \
1398         transform_cubic(dx, \
1399                 in_row[col1_offset] - chroma_offset, \
1400                 in_row[col2_offset] - chroma_offset, \
1401                 in_row[col3_offset] - chroma_offset, \
1402                 in_row[col4_offset] - chroma_offset)
1404         tx1 = ROUND(MIN4(dx1, dx2, dx3, dx4));
1405         ty1 = ROUND(MIN4(dy1, dy2, dy3, dy4));
1407         tx2 = ROUND(MAX4(dx1, dx2, dx3, dx4));
1408         ty2 = ROUND(MAX4(dy1, dy2, dy3, dy4));
1410                 CLAMP(ty1, pkg->y1, pkg->y2);
1411                 CLAMP(ty2, pkg->y1, pkg->y2);
1413                 xinc = m.values[0][0];
1414                 yinc = m.values[1][0];
1415                 winc = m.values[2][0];
1416 //printf("PerspectiveUnit::process_package 1 %d %d %d %d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
1419 #define TRANSFORM(components, type, chroma_offset, max) \
1420 { \
1421         type **in_rows = (type**)plugin->input->get_rows(); \
1422         for(int y = ty1; y < ty2; y++) \
1423         { \
1424                 type *out_row = (type*)plugin->output->get_rows()[y]; \
1426                 if(!interpolate) \
1427                 { \
1428                 tx = xinc * (tx1 + 0.5) + m.values[0][1] * (y + 0.5) + m.values[0][2]; \
1429                 ty = yinc * (tx1 + 0.5) + m.values[1][1] * (y + 0.5) + m.values[1][2]; \
1430                 tw = winc * (tx1 + 0.5) + m.values[2][1] * (y + 0.5) + m.values[2][2]; \
1431                 } \
1432         else \
1433         { \
1434                 tx = xinc * tx1 + m.values[0][1] * y + m.values[0][2]; \
1435                 ty = yinc * tx1 + m.values[1][1] * y + m.values[1][2]; \
1436                 tw = winc * tx1 + m.values[2][1] * y + m.values[2][2]; \
1437         } \
1440                 out_row += tx1 * components; \
1441                 for(int x = tx1; x < tx2; x++) \
1442                 { \
1443 /* Normalize homogeneous coords */ \
1444                         if(tw == 0.0) \
1445                         { \
1446                                 ttx = 0.0; \
1447                                 tty = 0.0; \
1448                         } \
1449                         else \
1450                         if(tw != 1.0) \
1451                         { \
1452                                 ttx = tx / tw; \
1453                                 tty = ty / tw; \
1454                         } \
1455                         else \
1456                         { \
1457                                 ttx = tx; \
1458                                 tty = ty; \
1459                         } \
1460                         itx = (int)ttx; \
1461                         ity = (int)tty; \
1463 /* Set destination pixels */ \
1464                         if(!interpolate && x >= 0 && x < w) \
1465                         { \
1466                                 if(itx >= 0 && itx < w && \
1467                                         ity >= 0 && ity < h && \
1468                                         x >= 0 && x < w) \
1469                                 { \
1470                                         type *src = in_rows[ity] + itx * components; \
1471                                         *out_row++ = *src++; \
1472                                         *out_row++ = *src++; \
1473                                         *out_row++ = *src++; \
1474                                         if(components == 4) *out_row++ = *src; \
1475                                 } \
1476                                 else \
1477 /* Fill with chroma */ \
1478                                 { \
1479                                         *out_row++ = 0; \
1480                                         *out_row++ = chroma_offset; \
1481                                         *out_row++ = chroma_offset; \
1482                                         if(components == 4) *out_row++ = 0; \
1483                                 } \
1484                         } \
1485                         else \
1486 /* Bicubic algorithm */ \
1487                         if(interpolate && x >= 0 && x < w) \
1488                         { \
1489                                 if ((itx + 2) >= 0 && (itx - 1) < w && \
1490                         (ity + 2) >= 0 && (ity - 1) < h) \
1491                 { \
1492                         float dx, dy; \
1494 /* the fractional error */ \
1495                         dx = ttx - itx; \
1496                         dy = tty - ity; \
1498 /* Row and column offsets in cubic block */ \
1499                                         int col1 = itx - 1; \
1500                                         int col2 = itx; \
1501                                         int col3 = itx + 1; \
1502                                         int col4 = itx + 2; \
1503                                         int row1 = ity - 1; \
1504                                         int row2 = ity; \
1505                                         int row3 = ity + 1; \
1506                                         int row4 = ity + 2; \
1507                                         CLAMP(col1, 0, maxw); \
1508                                         CLAMP(col2, 0, maxw); \
1509                                         CLAMP(col3, 0, maxw); \
1510                                         CLAMP(col4, 0, maxw); \
1511                                         CLAMP(row1, 0, maxh); \
1512                                         CLAMP(row2, 0, maxh); \
1513                                         CLAMP(row3, 0, maxh); \
1514                                         CLAMP(row4, 0, maxh); \
1515                                         int col1_offset = col1 * components; \
1516                                         int col2_offset = col2 * components; \
1517                                         int col3_offset = col3 * components; \
1518                                         int col4_offset = col4 * components; \
1519                                         type *row1_ptr = in_rows[row1]; \
1520                                         type *row2_ptr = in_rows[row2]; \
1521                                         type *row3_ptr = in_rows[row3]; \
1522                                         type *row4_ptr = in_rows[row4]; \
1523                                         int r, g, b, a; \
1525                                         r = (int)(transform_cubic(dy, \
1526                                  CUBIC_ROW(row1_ptr, 0x0), \
1527                                  CUBIC_ROW(row2_ptr, 0x0), \
1528                                  CUBIC_ROW(row3_ptr, 0x0), \
1529                                  CUBIC_ROW(row4_ptr, 0x0)) +  \
1530                                                          0.5); \
1532                                         row1_ptr++; \
1533                                         row2_ptr++; \
1534                                         row3_ptr++; \
1535                                         row4_ptr++; \
1536                                         g = ROUND(transform_cubic(dy, \
1537                                  CUBIC_ROW(row1_ptr, chroma_offset), \
1538                                  CUBIC_ROW(row2_ptr, chroma_offset), \
1539                                  CUBIC_ROW(row3_ptr, chroma_offset), \
1540                                  CUBIC_ROW(row4_ptr, chroma_offset))); \
1541                                         g += chroma_offset; \
1543                                         row1_ptr++; \
1544                                         row2_ptr++; \
1545                                         row3_ptr++; \
1546                                         row4_ptr++; \
1547                                         b = ROUND(transform_cubic(dy, \
1548                                  CUBIC_ROW(row1_ptr, chroma_offset), \
1549                                  CUBIC_ROW(row2_ptr, chroma_offset), \
1550                                  CUBIC_ROW(row3_ptr, chroma_offset), \
1551                                  CUBIC_ROW(row4_ptr, chroma_offset))); \
1552                                         b += chroma_offset; \
1554                                         if(components == 4) \
1555                                         { \
1556                                                 row1_ptr++; \
1557                                                 row2_ptr++; \
1558                                                 row3_ptr++; \
1559                                                 row4_ptr++; \
1560                                                 a = (int)(transform_cubic(dy, \
1561                                          CUBIC_ROW(row1_ptr, 0x0), \
1562                                          CUBIC_ROW(row2_ptr, 0x0), \
1563                                          CUBIC_ROW(row3_ptr, 0x0), \
1564                                          CUBIC_ROW(row4_ptr, 0x0)) +  \
1565                                                                  0.5); \
1566                                         } \
1568                                         *out_row++ = CLIP(r, 0, max); \
1569                                         *out_row++ = CLIP(g, 0, max); \
1570                                         *out_row++ = CLIP(b, 0, max); \
1571                                         if(components == 4) *out_row++ = CLIP(a, 0, max); \
1572                 } \
1573                                 else \
1574 /* Fill with chroma */ \
1575                                 { \
1576                                         *out_row++ = 0; \
1577                                         *out_row++ = chroma_offset; \
1578                                         *out_row++ = chroma_offset; \
1579                                         if(components == 4) *out_row++ = 0; \
1580                                 } \
1581                         } \
1582                         else \
1583                         { \
1584                                 out_row += components; \
1585                         } \
1587 /*  increment the transformed coordinates  */ \
1588                         tx += xinc; \
1589                         ty += yinc; \
1590                         tw += winc; \
1591                 } \
1592         } \
1598                 switch(plugin->input->get_color_model())
1599                 {
1600                         case BC_RGB888:
1601                                 TRANSFORM(3, unsigned char, 0x0, 0xff)
1602                                 break;
1603                         case BC_RGBA8888:
1604                                 TRANSFORM(4, unsigned char, 0x0, 0xff)
1605                                 break;
1606                         case BC_YUV888:
1607                                 TRANSFORM(3, unsigned char, 0x80, 0xff)
1608                                 break;
1609                         case BC_YUVA8888:
1610                                 TRANSFORM(4, unsigned char, 0x80, 0xff)
1611                                 break;
1612                         case BC_RGB161616:
1613                                 TRANSFORM(3, uint16_t, 0x0, 0xffff)
1614                                 break;
1615                         case BC_RGBA16161616:
1616                                 TRANSFORM(4, uint16_t, 0x0, 0xffff)
1617                                 break;
1618                         case BC_YUV161616:
1619                                 TRANSFORM(3, uint16_t, 0x8000, 0xffff)
1620                                 break;
1621                         case BC_YUVA16161616:
1622                                 TRANSFORM(4, uint16_t, 0x8000, 0xffff)
1623                                 break;
1624                 }
1626 //printf("PerspectiveUnit::process_package 50\n");
1627         }
1628         else
1629         {
1630                 int max_x = w * OVERSAMPLE - 1;
1631                 int max_y = h * OVERSAMPLE - 1;
1632 //printf("PerspectiveUnit::process_package 50 %d %d\n", max_x, max_y);
1633                 float top_w = out_x2 - out_x1;
1634                 float bottom_w = out_x3 - out_x4;
1635                 float left_h = out_y4 - out_y1;
1636                 float right_h = out_y3 - out_y2;
1637                 float out_w_diff = bottom_w - top_w;
1638                 float out_left_diff = out_x4 - out_x1;
1639                 float out_h_diff = right_h - left_h;
1640                 float out_top_diff = out_y2 - out_y1;
1641                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1642                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1643                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1644                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1645                 float max_v = MAX(distance1, distance3);
1646                 float max_h = MAX(distance2, distance4);
1647                 float max_dimension = MAX(max_v, max_h);
1648                 float min_dimension = MIN(h, w);
1649                 float step = min_dimension / max_dimension / OVERSAMPLE;
1650                 float h_f = h;
1651                 float w_f = w;
1653 // Projection
1654 #define PERSPECTIVE(type, components) \
1655 { \
1656         type **in_rows = (type**)plugin->input->get_rows(); \
1657         type **out_rows = (type**)plugin->temp->get_rows(); \
1659         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1660         { \
1661                 int i = (int)in_y; \
1662                 type *in_row = in_rows[i]; \
1663                 for(float in_x = 0; in_x < w; in_x += step) \
1664                 { \
1665                         int j = (int)in_x; \
1666                         float in_x_fraction = in_x / w_f; \
1667                         float in_y_fraction = in_y / h_f; \
1668                         int out_x = (int)((out_x1 + \
1669                                 out_left_diff * in_y_fraction + \
1670                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
1671                                 OVERSAMPLE); \
1672                         int out_y = (int)((out_y1 +  \
1673                                 out_top_diff * in_x_fraction + \
1674                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1675                                 OVERSAMPLE); \
1676                         CLAMP(out_x, 0, max_x); \
1677                         CLAMP(out_y, 0, max_y); \
1678                         type *dst = out_rows[out_y] + out_x * components; \
1679                         type *src = in_row + j * components; \
1680                         dst[0] = src[0]; \
1681                         dst[1] = src[1]; \
1682                         dst[2] = src[2]; \
1683                         if(components == 4) dst[3] = src[3]; \
1684                 } \
1685         } \
1688                 switch(plugin->input->get_color_model())
1689                 {
1690                         case BC_RGB888:
1691                                 PERSPECTIVE(unsigned char, 3)
1692                                 break;
1693                         case BC_RGBA8888:
1694                                 PERSPECTIVE(unsigned char, 4)
1695                                 break;
1696                         case BC_YUV888:
1697                                 PERSPECTIVE(unsigned char, 3)
1698                                 break;
1699                         case BC_YUVA8888:
1700                                 PERSPECTIVE(unsigned char, 4)
1701                                 break;
1702                         case BC_RGB161616:
1703                                 PERSPECTIVE(uint16_t, 3)
1704                                 break;
1705                         case BC_RGBA16161616:
1706                                 PERSPECTIVE(uint16_t, 4)
1707                                 break;
1708                         case BC_YUV161616:
1709                                 PERSPECTIVE(uint16_t, 3)
1710                                 break;
1711                         case BC_YUVA16161616:
1712                                 PERSPECTIVE(uint16_t, 4)
1713                                 break;
1714                 }
1715         }
1727 PerspectiveEngine::PerspectiveEngine(PerspectiveMain *plugin, 
1728         int total_clients,
1729         int total_packages)
1730  : LoadServer(
1731 //1, 1 
1732 total_clients, total_packages 
1735         this->plugin = plugin;
1738 void PerspectiveEngine::init_packages()
1740         int package_h = (int)((float)plugin->output->get_h() / 
1741                         total_packages + 1);
1742         int y1 = 0;
1743         for(int i = 0; i < total_packages; i++)
1744         {
1745                 PerspectivePackage *package = (PerspectivePackage*)packages[i];
1746                 package->y1 = y1;
1747                 package->y2 = y1 + package_h;
1748                 package->y1 = MIN(plugin->output->get_h(), package->y1);
1749                 package->y2 = MIN(plugin->output->get_h(), package->y2);
1750                 y1 = package->y2;
1751         }
1754 LoadClient* PerspectiveEngine::new_client()
1756         return new PerspectiveUnit(this, plugin);
1759 LoadPackage* PerspectiveEngine::new_package()
1761         return new PerspectivePackage;