r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / plugins / perspective / perspective.C
blob2ad0b993f17210383a5824e702e701923d453e95
1 #include "cursors.h"
2 #include "language.h"
3 #include "perspective.h"
11 REGISTER_PLUGIN(PerspectiveMain)
15 PerspectiveConfig::PerspectiveConfig()
17         x1 = 0;
18         y1 = 0;
19         x2 = 100;
20         y2 = 0;
21         x3 = 100;
22         y3 = 100;
23         x4 = 0;
24         y4 = 100;
25         mode = PERSPECTIVE;
26         window_w = 400;
27         window_h = 450;
28         current_point = 0;
29         forward = 1;
32 int PerspectiveConfig::equivalent(PerspectiveConfig &that)
34         return 
35                 EQUIV(x1, that.x1) &&
36                 EQUIV(y1, that.y1) &&
37                 EQUIV(x2, that.x2) &&
38                 EQUIV(y2, that.y2) &&
39                 EQUIV(x3, that.x3) &&
40                 EQUIV(y3, that.y3) &&
41                 EQUIV(x4, that.x4) &&
42                 EQUIV(y4, that.y4) &&
43                 mode == that.mode &&
44                 forward == that.forward;
47 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
49         x1 = that.x1;
50         y1 = that.y1;
51         x2 = that.x2;
52         y2 = that.y2;
53         x3 = that.x3;
54         y3 = that.y3;
55         x4 = that.x4;
56         y4 = that.y4;
57         mode = that.mode;
58         window_w = that.window_w;
59         window_h = that.window_h;
60         current_point = that.current_point;
61         forward = that.forward;
64 void PerspectiveConfig::interpolate(PerspectiveConfig &prev, 
65         PerspectiveConfig &next, 
66         int64_t prev_frame, 
67         int64_t next_frame, 
68         int64_t current_frame)
70         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
71         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
72         this->x1 = prev.x1 * prev_scale + next.x1 * next_scale;
73         this->y1 = prev.y1 * prev_scale + next.y1 * next_scale;
74         this->x2 = prev.x2 * prev_scale + next.x2 * next_scale;
75         this->y2 = prev.y2 * prev_scale + next.y2 * next_scale;
76         this->x3 = prev.x3 * prev_scale + next.x3 * next_scale;
77         this->y3 = prev.y3 * prev_scale + next.y3 * next_scale;
78         this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
79         this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
80         mode = prev.mode;
81         forward = prev.forward;
92 PLUGIN_THREAD_OBJECT(PerspectiveMain, PerspectiveThread, PerspectiveWindow)
96 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin, int x, int y)
97  : BC_Window(plugin->gui_string, 
98         x,
99         y,
100         plugin->config.window_w, 
101         plugin->config.window_h, 
102         plugin->config.window_w,
103         plugin->config.window_h,
104         0, 
105         1)
107 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
108         this->plugin = plugin; 
111 PerspectiveWindow::~PerspectiveWindow()
115 int PerspectiveWindow::create_objects()
117         int x = 10, y = 10;
119         add_subwindow(canvas = new PerspectiveCanvas(plugin, 
120                 x, 
121                 y, 
122                 get_w() - 20, 
123                 get_h() - 140));
124         canvas->set_cursor(CROSS_CURSOR);
125         y += canvas->get_h() + 10;
126         add_subwindow(new BC_Title(x, y, _("Current X:")));
127         x += 80;
128         this->x = new PerspectiveCoord(this, 
129                 plugin, 
130                 x, 
131                 y, 
132                 plugin->get_current_x(),
133                 1);
134         this->x->create_objects();
135         x += 140;
136         add_subwindow(new BC_Title(x, y, _("Y:")));
137         x += 20;
138         this->y = new PerspectiveCoord(this, 
139                 plugin, 
140                 x, 
141                 y, 
142                 plugin->get_current_y(),
143                 0);
144         this->y->create_objects();
145         y += 30;
146         x = 10;
147         add_subwindow(new PerspectiveReset(plugin, x, y));
148         x += 100;
149         add_subwindow(mode_perspective = new PerspectiveMode(plugin, 
150                 x, 
151                 y, 
152                 PerspectiveConfig::PERSPECTIVE,
153                 _("Perspective")));
154         x += 120;
155         add_subwindow(mode_sheer = new PerspectiveMode(plugin, 
156                 x, 
157                 y, 
158                 PerspectiveConfig::SHEER,
159                 _("Sheer")));
160         x = 110;
161         y += 30;
162         add_subwindow(mode_stretch = new PerspectiveMode(plugin, 
163                 x, 
164                 y, 
165                 PerspectiveConfig::STRETCH,
166                 _("Stretch")));
167         update_canvas();
168         y += 30;
169         x = 10;
170         add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
171         x += 170;
172         add_subwindow(forward = new PerspectiveDirection(plugin, 
173                 x, 
174                 y, 
175                 1,
176                 _("Forward")));
177         x += 100;
178         add_subwindow(reverse = new PerspectiveDirection(plugin, 
179                 x, 
180                 y, 
181                 0,
182                 _("Reverse")));
184         show_window();
185         flush();
186         return 0;
189 WINDOW_CLOSE_EVENT(PerspectiveWindow)
191 int PerspectiveWindow::resize_event(int w, int h)
193         return 1;
196 void PerspectiveWindow::update_canvas()
198         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
199         int x1, y1, x2, y2, x3, y3, x4, y4;
200         calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
202 // printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
203 // x1,
204 // y1,
205 // x2,
206 // y2,
207 // x3,
208 // y3,
209 // x4,
210 // y4);
211         canvas->set_color(BLACK);
213 #define DIVISIONS 10
214         for(int i = 0; i <= DIVISIONS; i++)
215         {
216 // latitude
217                 canvas->draw_line(
218                         x1 + (x4 - x1) * i / DIVISIONS,
219                         y1 + (y4 - y1) * i / DIVISIONS,
220                         x2 + (x3 - x2) * i / DIVISIONS,
221                         y2 + (y3 - y2) * i / DIVISIONS);
222 // longitude
223                 canvas->draw_line(
224                         x1 + (x2 - x1) * i / DIVISIONS,
225                         y1 + (y2 - y1) * i / DIVISIONS,
226                         x4 + (x3 - x4) * i / DIVISIONS,
227                         y4 + (y3 - y4) * i / DIVISIONS);
228         }
230 // Corners
231 #define RADIUS 5
232         if(plugin->config.current_point == 0)
233                 canvas->draw_disc(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
234         else
235                 canvas->draw_circle(x1 - RADIUS, y1 - RADIUS, RADIUS * 2, RADIUS * 2);
237         if(plugin->config.current_point == 1)
238                 canvas->draw_disc(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
239         else
240                 canvas->draw_circle(x2 - RADIUS, y2 - RADIUS, RADIUS * 2, RADIUS * 2);
242         if(plugin->config.current_point == 2)
243                 canvas->draw_disc(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
244         else
245                 canvas->draw_circle(x3 - RADIUS, y3 - RADIUS, RADIUS * 2, RADIUS * 2);
247         if(plugin->config.current_point == 3)
248                 canvas->draw_disc(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
249         else
250                 canvas->draw_circle(x4 - RADIUS, y4 - RADIUS, RADIUS * 2, RADIUS * 2);
252         canvas->flash();
253         canvas->flush();
256 void PerspectiveWindow::update_mode()
258         mode_perspective->update(plugin->config.mode == PerspectiveConfig::PERSPECTIVE);
259         mode_sheer->update(plugin->config.mode == PerspectiveConfig::SHEER);
260         mode_stretch->update(plugin->config.mode == PerspectiveConfig::STRETCH);
261         forward->update(plugin->config.forward);
262         reverse->update(!plugin->config.forward);
265 void PerspectiveWindow::update_coord()
267         x->update(plugin->get_current_x());
268         y->update(plugin->get_current_y());
271 void PerspectiveWindow::calculate_canvas_coords(int &x1, 
272         int &y1, 
273         int &x2, 
274         int &y2, 
275         int &x3, 
276         int &y3, 
277         int &x4, 
278         int &y4)
280         int w = canvas->get_w() - 1;
281         int h = canvas->get_h() - 1;
282         if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
283                 plugin->config.mode == PerspectiveConfig::STRETCH)
284         {
285                 x1 = (int)(plugin->config.x1 * w / 100);
286                 y1 = (int)(plugin->config.y1 * h / 100);
287                 x2 = (int)(plugin->config.x2 * w / 100);
288                 y2 = (int)(plugin->config.y2 * h / 100);
289                 x3 = (int)(plugin->config.x3 * w / 100);
290                 y3 = (int)(plugin->config.y3 * h / 100);
291                 x4 = (int)(plugin->config.x4 * w / 100);
292                 y4 = (int)(plugin->config.y4 * h / 100);
293         }
294         else
295         {
296                 x1 = (int)(plugin->config.x1 * w) / 100;
297                 y1 = 0;
298                 x2 = x1 + w;
299                 y2 = 0;
300                 x4 = (int)(plugin->config.x4 * w) / 100;
301                 y4 = h;
302                 x3 = x4 + w;
303                 y3 = h;
304         }
310 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin, 
311         int x, 
312         int y, 
313         int w,
314         int h)
315  : BC_SubWindow(x, y, w, h, 0xffffff)
317         this->plugin = plugin;
318         state = PerspectiveCanvas::NONE;
323 #define DISTANCE(x1, y1, x2, y2) \
324 (sqrt(((x2) - (x1)) * ((x2) - (x1)) + ((y2) - (y1)) * ((y2) - (y1))))
326 int PerspectiveCanvas::button_press_event()
328         if(is_event_win() && cursor_inside())
329         {
330 // Set current point
331                 int x1, y1, x2, y2, x3, y3, x4, y4;
332                 int cursor_x = get_cursor_x();
333                 int cursor_y = get_cursor_y();
334                 plugin->thread->window->calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
336                 float distance1 = DISTANCE(cursor_x, cursor_y, x1, y1);
337                 float distance2 = DISTANCE(cursor_x, cursor_y, x2, y2);
338                 float distance3 = DISTANCE(cursor_x, cursor_y, x3, y3);
339                 float distance4 = DISTANCE(cursor_x, cursor_y, x4, y4);
340 // printf("PerspectiveCanvas::button_press_event %f %d %d %d %d\n", 
341 // distance3,
342 // cursor_x,
343 // cursor_y,
344 // x3,
345 // y3);
346                 float min = distance1;
347                 plugin->config.current_point = 0;
348                 if(distance2 < min)
349                 {
350                         min = distance2;
351                         plugin->config.current_point = 1;
352                 }
353                 if(distance3 < min)
354                 {
355                         min = distance3;
356                         plugin->config.current_point = 2;
357                 }
358                 if(distance4 < min)
359                 {
360                         min = distance4;
361                         plugin->config.current_point = 3;
362                 }
364                 if(plugin->config.mode == PerspectiveConfig::SHEER)
365                 {
366                         if(plugin->config.current_point == 1)
367                                 plugin->config.current_point = 0;
368                         else
369                         if(plugin->config.current_point == 2)
370                                 plugin->config.current_point = 3;
371                 }
372                 start_cursor_x = cursor_x;
373                 start_cursor_y = cursor_y;
375                 if(alt_down() || shift_down())
376                 {
377                         if(alt_down())
378                                 state = PerspectiveCanvas::DRAG_FULL;
379                         else
380                                 state = PerspectiveCanvas::ZOOM;
382 // Get starting positions
383                         start_x1 = plugin->config.x1;
384                         start_y1 = plugin->config.y1;
385                         start_x2 = plugin->config.x2;
386                         start_y2 = plugin->config.y2;
387                         start_x3 = plugin->config.x3;
388                         start_y3 = plugin->config.y3;
389                         start_x4 = plugin->config.x4;
390                         start_y4 = plugin->config.y4;
391                 }
392                 else
393                 {
394                         state = PerspectiveCanvas::DRAG;
396 // Get starting positions
397                         start_x1 = plugin->get_current_x();
398                         start_y1 = plugin->get_current_y();
399                 }
400                 plugin->thread->window->update_coord();
401                 plugin->thread->window->update_canvas();
402                 return 1;
403         }
405         return 0;
408 int PerspectiveCanvas::button_release_event()
410         if(state != PerspectiveCanvas::NONE)
411         {
412                 state = PerspectiveCanvas::NONE;
413                 return 1;
414         }
415         return 0;
418 int PerspectiveCanvas::cursor_motion_event()
420         if(state != PerspectiveCanvas::NONE)
421         {
422                 int w = get_w() - 1;
423                 int h = get_h() - 1;
424                 if(state == PerspectiveCanvas::DRAG)
425                 {
426                         plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
427                         plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
428                 }
429                 else
430                 if(state == PerspectiveCanvas::DRAG_FULL)
431                 {
432                         plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
433                         plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
434                         plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
435                         plugin->config.y2 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y2);
436                         plugin->config.x3 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x3);
437                         plugin->config.y3 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y3);
438                         plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
439                         plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
440                 }
441                 else
442                 if(state == PerspectiveCanvas::ZOOM)
443                 {
444                         float center_x = (start_x1 +
445                                 start_x2 +
446                                 start_x3 +
447                                 start_x4) / 4;
448                         float center_y = (start_y1 +
449                                 start_y2 +
450                                 start_y3 +
451                                 start_y4) / 4;
452                         float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
453                         plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
454                         plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
455                         plugin->config.x2 = center_x + (start_x2 - center_x) * zoom;
456                         plugin->config.y2 = center_y + (start_y2 - center_y) * zoom;
457                         plugin->config.x3 = center_x + (start_x3 - center_x) * zoom;
458                         plugin->config.y3 = center_y + (start_y3 - center_y) * zoom;
459                         plugin->config.x4 = center_x + (start_x4 - center_x) * zoom;
460                         plugin->config.y4 = center_y + (start_y4 - center_y) * zoom;
461                 }
462                 plugin->thread->window->update_canvas();
463                 plugin->thread->window->update_coord();
464                 plugin->send_configure_change();
465                 return 1;
466         }
468         return 0;
476 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
477         PerspectiveMain *plugin, 
478         int x, 
479         int y,
480         float value,
481         int is_x)
482  : BC_TumbleTextBox(gui, value, (float)0, (float)100, x, y, 100)
484         this->plugin = plugin;
485         this->is_x = is_x;
488 int PerspectiveCoord::handle_event()
490         if(is_x)
491                 plugin->set_current_x(atof(get_text()));
492         else
493                 plugin->set_current_y(atof(get_text()));
494         plugin->thread->window->update_canvas();
495         plugin->send_configure_change();
496         return 1;
506 PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin, 
507         int x, 
508         int y)
509  : BC_GenericButton(x, y, _("Reset"))
511         this->plugin = plugin;
513 int PerspectiveReset::handle_event()
515         plugin->config.x1 = 0;
516         plugin->config.y1 = 0;
517         plugin->config.x2 = 100;
518         plugin->config.y2 = 0;
519         plugin->config.x3 = 100;
520         plugin->config.y3 = 100;
521         plugin->config.x4 = 0;
522         plugin->config.y4 = 100;
523         plugin->thread->window->update_canvas();
524         plugin->thread->window->update_coord();
525         plugin->send_configure_change();
526         return 1;
539 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin, 
540         int x, 
541         int y,
542         int value,
543         char *text)
544  : BC_Radial(x, y, plugin->config.mode == value, text)
546         this->plugin = plugin;
547         this->value = value;
549 int PerspectiveMode::handle_event()
551         plugin->config.mode = value;
552         plugin->thread->window->update_mode();
553         plugin->thread->window->update_canvas();
554         plugin->send_configure_change();
555         return 1;
561 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin, 
562         int x, 
563         int y,
564         int value,
565         char *text)
566  : BC_Radial(x, y, plugin->config.forward == value, text)
568         this->plugin = plugin;
569         this->value = value;
571 int PerspectiveDirection::handle_event()
573         plugin->config.forward = value;
574         plugin->thread->window->update_mode();
575         plugin->send_configure_change();
576         return 1;
590 PerspectiveMain::PerspectiveMain(PluginServer *server)
591  : PluginVClient(server)
593         PLUGIN_CONSTRUCTOR_MACRO
594         engine = 0;
595         temp = 0;
598 PerspectiveMain::~PerspectiveMain()
600         PLUGIN_DESTRUCTOR_MACRO
601         if(engine) delete engine;
602         if(temp) delete temp;
605 char* PerspectiveMain::plugin_title() { return N_("Perspective"); }
606 int PerspectiveMain::is_realtime() { return 1; }
609 NEW_PICON_MACRO(PerspectiveMain)
611 SHOW_GUI_MACRO(PerspectiveMain, PerspectiveThread)
613 SET_STRING_MACRO(PerspectiveMain)
615 RAISE_WINDOW_MACRO(PerspectiveMain)
617 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
621 void PerspectiveMain::update_gui()
623         if(thread)
624         {
625 //printf("PerspectiveMain::update_gui 1\n");
626                 thread->window->lock_window();
627 //printf("PerspectiveMain::update_gui 2\n");
628                 load_configuration();
629                 thread->window->update_coord();
630                 thread->window->update_mode();
631                 thread->window->update_canvas();
632                 thread->window->unlock_window();
633 //printf("PerspectiveMain::update_gui 3\n");
634         }
638 int PerspectiveMain::load_defaults()
640         char directory[1024], string[1024];
641 // set the default directory
642         sprintf(directory, "%sperspective.rc", BCASTDIR);
644 // load the defaults
645         defaults = new Defaults(directory);
646         defaults->load();
648         config.x1 = defaults->get("X1", config.x1);
649         config.x2 = defaults->get("X2", config.x2);
650         config.x3 = defaults->get("X3", config.x3);
651         config.x4 = defaults->get("X4", config.x4);
652         config.y1 = defaults->get("Y1", config.y1);
653         config.y2 = defaults->get("Y2", config.y2);
654         config.y3 = defaults->get("Y3", config.y3);
655         config.y4 = defaults->get("Y4", config.y4);
657         config.mode = defaults->get("MODE", config.mode);
658         config.forward = defaults->get("FORWARD", config.forward);
659         config.window_w = defaults->get("WINDOW_W", config.window_w);
660         config.window_h = defaults->get("WINDOW_H", config.window_h);
661         return 0;
665 int PerspectiveMain::save_defaults()
667         defaults->update("X1", config.x1);
668         defaults->update("X2", config.x2);
669         defaults->update("X3", config.x3);
670         defaults->update("X4", config.x4);
671         defaults->update("Y1", config.y1);
672         defaults->update("Y2", config.y2);
673         defaults->update("Y3", config.y3);
674         defaults->update("Y4", config.y4);
676         defaults->update("MODE", config.mode);
677         defaults->update("FORWARD", config.forward);
678         defaults->update("WINDOW_W", config.window_w);
679         defaults->update("WINDOW_H", config.window_h);
680         defaults->save();
681         return 0;
686 void PerspectiveMain::save_data(KeyFrame *keyframe)
688         FileXML output;
690 // cause data to be stored directly in text
691         output.set_shared_string(keyframe->data, MESSAGESIZE);
692         output.tag.set_title("PERSPECTIVE");
694         output.tag.set_property("X1", config.x1);
695         output.tag.set_property("X2", config.x2);
696         output.tag.set_property("X3", config.x3);
697         output.tag.set_property("X4", config.x4);
698         output.tag.set_property("Y1", config.y1);
699         output.tag.set_property("Y2", config.y2);
700         output.tag.set_property("Y3", config.y3);
701         output.tag.set_property("Y4", config.y4);
703         output.tag.set_property("MODE", config.mode);
704         output.tag.set_property("FORWARD", config.forward);
705         output.tag.set_property("WINDOW_W", config.window_w);
706         output.tag.set_property("WINDOW_H", config.window_h);
707         output.append_tag();
708         output.terminate_string();
711 void PerspectiveMain::read_data(KeyFrame *keyframe)
713         FileXML input;
715         input.set_shared_string(keyframe->data, strlen(keyframe->data));
717         int result = 0;
719         while(!result)
720         {
721                 result = input.read_tag();
723                 if(!result)
724                 {
725                         if(input.tag.title_is("PERSPECTIVE"))
726                         {
727                                 config.x1 = input.tag.get_property("X1", config.x1);
728                                 config.x2 = input.tag.get_property("X2", config.x2);
729                                 config.x3 = input.tag.get_property("X3", config.x3);
730                                 config.x4 = input.tag.get_property("X4", config.x4);
731                                 config.y1 = input.tag.get_property("Y1", config.y1);
732                                 config.y2 = input.tag.get_property("Y2", config.y2);
733                                 config.y3 = input.tag.get_property("Y3", config.y3);
734                                 config.y4 = input.tag.get_property("Y4", config.y4);
736                                 config.mode = input.tag.get_property("MODE", config.mode);
737                                 config.forward = input.tag.get_property("FORWARD", config.forward);
738                                 config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
739                                 config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
740                         }
741                 }
742         }
745 float PerspectiveMain::get_current_x()
747         switch(config.current_point)
748         {
749                 case 0:
750                         return config.x1;
751                         break;
752                 case 1:
753                         return config.x2;
754                         break;
755                 case 2:
756                         return config.x3;
757                         break;
758                 case 3:
759                         return config.x4;
760                         break;
761         }
764 float PerspectiveMain::get_current_y()
766         switch(config.current_point)
767         {
768                 case 0:
769                         return config.y1;
770                         break;
771                 case 1:
772                         return config.y2;
773                         break;
774                 case 2:
775                         return config.y3;
776                         break;
777                 case 3:
778                         return config.y4;
779                         break;
780         }
783 void PerspectiveMain::set_current_x(float value)
785         switch(config.current_point)
786         {
787                 case 0:
788                         config.x1 = value;
789                         break;
790                 case 1:
791                         config.x2 = value;
792                         break;
793                 case 2:
794                         config.x3 = value;
795                         break;
796                 case 3:
797                         config.x4 = value;
798                         break;
799         }
802 void PerspectiveMain::set_current_y(float value)
804         switch(config.current_point)
805         {
806                 case 0:
807                         config.y1 = value;
808                         break;
809                 case 1:
810                         config.y2 = value;
811                         break;
812                 case 2:
813                         config.y3 = value;
814                         break;
815                 case 3:
816                         config.y4 = value;
817                         break;
818         }
823 int PerspectiveMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
825         int need_reconfigure = load_configuration();
828         if(!engine) engine = new PerspectiveEngine(this,
829                 get_project_smp() + 1,
830                 get_project_smp() + 1);
832         this->input = input_ptr;
833         this->output = output_ptr;
835         if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
836                 EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
837                 EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
838                 EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
839         {
840                 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
841                         output_ptr->copy_from(input_ptr);
842                 return 1;
843         }
845         int w = input_ptr->get_w();
846         int h = input_ptr->get_h();
847         int color_model = input_ptr->get_color_model();
849         if(temp && 
850                 config.mode == PerspectiveConfig::STRETCH &&
851                 (temp->get_w() != w * OVERSAMPLE ||
852                         temp->get_h() != h * OVERSAMPLE))
853         {
854                 delete temp;
855                 temp = 0;
856         }
857         else
858         if(temp &&
859                 (config.mode == PerspectiveConfig::PERSPECTIVE ||
860                 config.mode == PerspectiveConfig::SHEER) &&
861                 (temp->get_w() != w ||
862                         temp->get_h() != h))
863         {
864                 delete temp;
865                 temp = 0;
866         }
868         if(config.mode == PerspectiveConfig::STRETCH)
869         {
870                 if(!temp)
871                 {
872                         temp = new VFrame(0,
873                                         w * OVERSAMPLE,
874                                         h * OVERSAMPLE,
875                                         color_model);
876                 }
877                 temp->clear_frame();
878         }
880         if(config.mode == PerspectiveConfig::PERSPECTIVE ||
881                 config.mode == PerspectiveConfig::SHEER)
882         {
883                 if(input_ptr->get_rows()[0] == output_ptr->get_rows()[0])
884                 {
885                         if(!temp) 
886                         {
887                                 temp = new VFrame(0,
888                                         w,
889                                         h,
890                                         color_model);
891                         }
892                         temp->copy_from(input);
893                         input = temp;
894                 }
895                 output->clear_frame();
896         }
900         engine->process_packages();
905 // Resample
907         if(config.mode == PerspectiveConfig::STRETCH)
908         {
909 #define RESAMPLE(type, components, chroma_offset) \
910 { \
911         for(int i = 0; i < h; i++) \
912         { \
913                 type *out_row = (type*)output->get_rows()[i]; \
914                 type *in_row1 = (type*)temp->get_rows()[i * OVERSAMPLE]; \
915                 type *in_row2 = (type*)temp->get_rows()[i * OVERSAMPLE + 1]; \
916                 for(int j = 0; j < w; j++) \
917                 { \
918                         out_row[0] = (in_row1[0] +  \
919                                         in_row1[components] +  \
920                                         in_row2[0] +  \
921                                         in_row2[components]) /  \
922                                 OVERSAMPLE /  \
923                                 OVERSAMPLE; \
924                         out_row[1] = ((in_row1[1] +  \
925                                                 in_row1[components + 1] +  \
926                                                 in_row2[1] +  \
927                                                 in_row2[components + 1]) -  \
928                                         chroma_offset *  \
929                                         OVERSAMPLE *  \
930                                         OVERSAMPLE) /  \
931                                 OVERSAMPLE /  \
932                                 OVERSAMPLE + \
933                                 chroma_offset; \
934                         out_row[2] = ((in_row1[2] +  \
935                                                 in_row1[components + 2] +  \
936                                                 in_row2[2] +  \
937                                                 in_row2[components + 2]) -  \
938                                         chroma_offset *  \
939                                         OVERSAMPLE *  \
940                                         OVERSAMPLE) /  \
941                                 OVERSAMPLE /  \
942                                 OVERSAMPLE + \
943                                 chroma_offset; \
944                         if(components == 4) \
945                         { \
946                                 out_row[3] = (in_row1[3] +  \
947                                                 in_row1[components + 3] +  \
948                                                 in_row2[3] +  \
949                                                 in_row2[components + 3]) /  \
950                                         OVERSAMPLE /  \
951                                         OVERSAMPLE; \
952                         } \
953                         out_row += components; \
954                         in_row1 += components * OVERSAMPLE; \
955                         in_row2 += components * OVERSAMPLE; \
956                 } \
957         } \
960                 switch(input_ptr->get_color_model())
961                 {
962                         case BC_RGB_FLOAT:
963                                 RESAMPLE(float, 3, 0)
964                                 break;
965                         case BC_RGB888:
966                                 RESAMPLE(unsigned char, 3, 0)
967                                 break;
968                         case BC_RGBA_FLOAT:
969                                 RESAMPLE(float, 4, 0)
970                                 break;
971                         case BC_RGBA8888:
972                                 RESAMPLE(unsigned char, 4, 0)
973                                 break;
974                         case BC_YUV888:
975                                 RESAMPLE(unsigned char, 3, 0x80)
976                                 break;
977                         case BC_YUVA8888:
978                                 RESAMPLE(unsigned char, 4, 0x80)
979                                 break;
980                         case BC_RGB161616:
981                                 RESAMPLE(uint16_t, 3, 0)
982                                 break;
983                         case BC_RGBA16161616:
984                                 RESAMPLE(uint16_t, 4, 0)
985                                 break;
986                         case BC_YUV161616:
987                                 RESAMPLE(uint16_t, 3, 0x8000)
988                                 break;
989                         case BC_YUVA16161616:
990                                 RESAMPLE(uint16_t, 4, 0x8000)
991                                 break;
992                 }
993         }
995         return 1;
1008 PerspectiveMatrix::PerspectiveMatrix()
1010         bzero(values, sizeof(values));
1013 void PerspectiveMatrix::identity()
1015         bzero(values, sizeof(values));
1016         values[0][0] = 1;
1017         values[1][1] = 1;
1018         values[2][2] = 1;
1021 void PerspectiveMatrix::translate(double x, double y)
1023         double g = values[2][0];
1024         double h = values[2][1];
1025         double i = values[2][2];
1026         values[0][0] += x * g;
1027         values[0][1] += x * h;
1028         values[0][2] += x * i;
1029         values[1][0] += y * g;
1030         values[1][1] += y * h;
1031         values[1][2] += y * i;
1034 void PerspectiveMatrix::scale(double x, double y)
1036         values[0][0] *= x;
1037         values[0][1] *= x;
1038         values[0][2] *= x;
1040         values[1][0] *= y;
1041         values[1][1] *= y;
1042         values[1][2] *= y;
1045 void PerspectiveMatrix::multiply(PerspectiveMatrix *dst)
1047         int i, j;
1048         PerspectiveMatrix tmp;
1049         double t1, t2, t3;
1051         for (i = 0; i < 3; i++)
1052     {
1053         t1 = values[i][0];
1054         t2 = values[i][1];
1055         t3 = values[i][2];
1056         for (j = 0; j < 3; j++)
1057                 {
1058                         tmp.values[i][j]  = t1 * dst->values[0][j];
1059                         tmp.values[i][j] += t2 * dst->values[1][j];
1060                         tmp.values[i][j] += t3 * dst->values[2][j];
1061                 }
1062     }
1063         dst->copy_from(&tmp);
1066 double PerspectiveMatrix::determinant()
1068         double determinant;
1070         determinant  = 
1071         values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
1072         determinant -= 
1073         values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
1074         determinant += 
1075         values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
1077         return determinant;
1080 void PerspectiveMatrix::invert(PerspectiveMatrix *dst)
1082         double det_1;
1084         det_1 = determinant();
1086         if(det_1 == 0.0)
1087         return;
1089         det_1 = 1.0 / det_1;
1091         dst->values[0][0] =   
1092       (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
1094         dst->values[1][0] = 
1095       - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
1097         dst->values[2][0] =   
1098       (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
1100         dst->values[0][1] = 
1101       - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
1103         dst->values[1][1] = 
1104       (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
1106         dst->values[2][1] = 
1107       - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
1109         dst->values[0][2] =
1110       (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
1112         dst->values[1][2] = 
1113       - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
1115         dst->values[2][2] = 
1116       (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
1119 void PerspectiveMatrix::copy_from(PerspectiveMatrix *src)
1121         memcpy(&values[0][0], &src->values[0][0], sizeof(values));
1124 void PerspectiveMatrix::transform_point(float x, 
1125         float y, 
1126         float *newx, 
1127         float *newy)
1129         double w;
1131         w = values[2][0] * x + values[2][1] * y + values[2][2];
1133         if (w == 0.0)
1134         w = 1.0;
1135         else
1136         w = 1.0 / w;
1138         *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
1139         *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
1142 void PerspectiveMatrix::dump()
1144         printf("PerspectiveMatrix::dump\n");
1145         printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
1146         printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
1147         printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
1154 PerspectivePackage::PerspectivePackage()
1155  : LoadPackage()
1162 PerspectiveUnit::PerspectiveUnit(PerspectiveEngine *server, 
1163         PerspectiveMain *plugin)
1164  : LoadClient(server)
1166         this->plugin = plugin;
1167         this->server = server;
1178 void PerspectiveUnit::calculate_matrix(
1179         double in_x1,
1180         double in_y1,
1181         double in_x2,
1182         double in_y2,
1183         double out_x1,
1184         double out_y1,
1185         double out_x2,
1186         double out_y2,
1187         double out_x3,
1188         double out_y3,
1189         double out_x4,
1190         double out_y4,
1191         PerspectiveMatrix *result)
1193         PerspectiveMatrix matrix;
1194         double scalex;
1195         double scaley;
1197         scalex = scaley = 1.0;
1199         if((in_x2 - in_x1) > 0)
1200         scalex = 1.0 / (double)(in_x2 - in_x1);
1202         if((in_y2 - in_y1) > 0)
1203         scaley = 1.0 / (double)(in_y2 - in_y1);
1205 /* Determine the perspective transform that maps from
1206  * the unit cube to the transformed coordinates
1207  */
1208     double dx1, dx2, dx3, dy1, dy2, dy3;
1209     double det1, det2;
1211     dx1 = out_x2 - out_x4;
1212     dx2 = out_x3 - out_x4;
1213     dx3 = out_x1 - out_x2 + out_x4 - out_x3;
1215     dy1 = out_y2 - out_y4;
1216     dy2 = out_y3 - out_y4;
1217     dy3 = out_y1 - out_y2 + out_y4 - out_y3;
1218 // printf("PerspectiveUnit::calculate_matrix %f %f %f %f %f %f\n",
1219 // dx1,
1220 // dx2,
1221 // dx3,
1222 // dy1,
1223 // dy2,
1224 // dy3
1225 // );
1227 /*  Is the mapping affine?  */
1228     if((dx3 == 0.0) && (dy3 == 0.0))
1229     {
1230         matrix.values[0][0] = out_x2 - out_x1;
1231         matrix.values[0][1] = out_x4 - out_x2;
1232         matrix.values[0][2] = out_x1;
1233         matrix.values[1][0] = out_y2 - out_y1;
1234         matrix.values[1][1] = out_y4 - out_y2;
1235         matrix.values[1][2] = out_y1;
1236         matrix.values[2][0] = 0.0;
1237         matrix.values[2][1] = 0.0;
1238     }
1239     else
1240     {
1241         det1 = dx3 * dy2 - dy3 * dx2;
1242         det2 = dx1 * dy2 - dy1 * dx2;
1243         matrix.values[2][0] = det1 / det2;
1244         det1 = dx1 * dy3 - dy1 * dx3;
1245         det2 = dx1 * dy2 - dy1 * dx2;
1246         matrix.values[2][1] = det1 / det2;
1248         matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
1249         matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
1250         matrix.values[0][2] = out_x1;
1252         matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
1253         matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
1254         matrix.values[1][2] = out_y1;
1255     }
1257     matrix.values[2][2] = 1.0;
1259 // printf("PerspectiveUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
1260 // matrix.dump();
1262         result->identity();
1263         result->translate(-in_x1, -in_y1);
1264         result->scale(scalex, scaley);
1265         matrix.multiply(result);
1266 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
1267 //                                { 0.0, 0.0896, 0.0 },
1268 //                                { -0.00126, 0.0, 1.0 } };
1269 // memcpy(&result->values[0][0], test, sizeof(test));
1270 // printf("PerspectiveUnit::calculate_matrix 4 %p\n", result);
1271 // result->dump();
1276 float PerspectiveUnit::transform_cubic(float dx,
1277                                float jm1,
1278                                float j,
1279                                float jp1,
1280                                float jp2)
1282 /* Catmull-Rom - not bad */
1283         float result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
1284                        ( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
1285                        ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
1287         return result;
1291 void PerspectiveUnit::process_package(LoadPackage *package)
1293         PerspectivePackage *pkg = (PerspectivePackage*)package;
1294         int w = plugin->input->get_w();
1295         int h = plugin->input->get_h();
1296         int maxw = w - 1;
1297         int maxh = h - 1;
1299 // Calculate real coords
1300         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
1301         if(plugin->config.mode == PerspectiveConfig::STRETCH ||
1302                 plugin->config.mode == PerspectiveConfig::PERSPECTIVE)
1303         {
1304                 out_x1 = (float)plugin->config.x1 * w / 100;
1305                 out_y1 = (float)plugin->config.y1 * h / 100;
1306                 out_x2 = (float)plugin->config.x2 * w / 100;
1307                 out_y2 = (float)plugin->config.y2 * h / 100;
1308                 out_x3 = (float)plugin->config.x3 * w / 100;
1309                 out_y3 = (float)plugin->config.y3 * h / 100;
1310                 out_x4 = (float)plugin->config.x4 * w / 100;
1311                 out_y4 = (float)plugin->config.y4 * h / 100;
1312         }
1313         else
1314         {
1315                 out_x1 = (float)plugin->config.x1 * w / 100;
1316                 out_y1 = 0;
1317                 out_x2 = out_x1 + w;
1318                 out_y2 = 0;
1319                 out_x4 = (float)plugin->config.x4 * w / 100;
1320                 out_y4 = h;
1321                 out_x3 = out_x4 + w;
1322                 out_y3 = h;
1323         }
1327         if(plugin->config.mode == PerspectiveConfig::PERSPECTIVE ||
1328                 plugin->config.mode == PerspectiveConfig::SHEER)
1329         {
1330                 PerspectiveMatrix matrix;
1331                 float temp;
1332                 temp = out_x4;
1333                 out_x4 = out_x3;
1334                 out_x3 = temp;
1335                 temp = out_y4;
1336                 out_y4 = out_y3;
1337                 out_y3 = temp;
1341 // printf("PerspectiveUnit::process_package 10 %f %f %f %f %f %f %f %f\n", 
1342 // out_x1,
1343 // out_y1,
1344 // out_x2,
1345 // out_y2,
1346 // out_x3,
1347 // out_y3,
1348 // out_x4,
1349 // out_y4);
1353                 calculate_matrix(
1354                         0,
1355                         0,
1356                         w,
1357                         h,
1358                         out_x1,
1359                         out_y1,
1360                         out_x2,
1361                         out_y2,
1362                         out_x3,
1363                         out_y3,
1364                         out_x4,
1365                         out_y4,
1366                         &matrix);
1368                 int interpolate = 1;
1369                 int reverse = !plugin->config.forward;
1370                 float tx, ty, tw;
1371                 float xinc, yinc, winc;
1372                 PerspectiveMatrix m, im;
1373                 float ttx, tty;
1374                 int itx, ity;
1375                 int tx1, ty1, tx2, ty2;
1377                 if(reverse)
1378                 {
1379                         m.copy_from(&matrix);
1380                         m.invert(&im);
1381                         matrix.copy_from(&im);
1382                 }
1383                 else
1384                 {
1385                         matrix.invert(&m);
1386                 }
1388                 float dx1, dy1;
1389                 float dx2, dy2;
1390                 float dx3, dy3;
1391                 float dx4, dy4;
1392                 matrix.transform_point(0, 0, &dx1, &dy1);
1393                 matrix.transform_point(w, 0, &dx2, &dy2);
1394                 matrix.transform_point(0, h, &dx3, &dy3);
1395                 matrix.transform_point(w, h, &dx4, &dy4);
1397 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
1398 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
1399 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
1400 #define CUBIC_ROW(in_row, chroma_offset) \
1401         transform_cubic(dx, \
1402                 in_row[col1_offset] - chroma_offset, \
1403                 in_row[col2_offset] - chroma_offset, \
1404                 in_row[col3_offset] - chroma_offset, \
1405                 in_row[col4_offset] - chroma_offset)
1407         tx1 = ROUND(MIN4(dx1, dx2, dx3, dx4));
1408         ty1 = ROUND(MIN4(dy1, dy2, dy3, dy4));
1410         tx2 = ROUND(MAX4(dx1, dx2, dx3, dx4));
1411         ty2 = ROUND(MAX4(dy1, dy2, dy3, dy4));
1413                 CLAMP(ty1, pkg->y1, pkg->y2);
1414                 CLAMP(ty2, pkg->y1, pkg->y2);
1416                 xinc = m.values[0][0];
1417                 yinc = m.values[1][0];
1418                 winc = m.values[2][0];
1419 //printf("PerspectiveUnit::process_package 1 %d %d %d %d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
1422 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
1423 { \
1424         type **in_rows = (type**)plugin->input->get_rows(); \
1425         float round_factor = 0.0; \
1426         if(sizeof(type) < 4) round_factor = 0.5; \
1427         for(int y = ty1; y < ty2; y++) \
1428         { \
1429                 type *out_row = (type*)plugin->output->get_rows()[y]; \
1431                 if(!interpolate) \
1432                 { \
1433                 tx = xinc * (tx1 + 0.5) + m.values[0][1] * (y + 0.5) + m.values[0][2]; \
1434                 ty = yinc * (tx1 + 0.5) + m.values[1][1] * (y + 0.5) + m.values[1][2]; \
1435                 tw = winc * (tx1 + 0.5) + m.values[2][1] * (y + 0.5) + m.values[2][2]; \
1436                 } \
1437         else \
1438         { \
1439                 tx = xinc * tx1 + m.values[0][1] * y + m.values[0][2]; \
1440                 ty = yinc * tx1 + m.values[1][1] * y + m.values[1][2]; \
1441                 tw = winc * tx1 + m.values[2][1] * y + m.values[2][2]; \
1442         } \
1445                 out_row += tx1 * components; \
1446                 for(int x = tx1; x < tx2; x++) \
1447                 { \
1448 /* Normalize homogeneous coords */ \
1449                         if(tw == 0.0) \
1450                         { \
1451                                 ttx = 0.0; \
1452                                 tty = 0.0; \
1453                         } \
1454                         else \
1455                         if(tw != 1.0) \
1456                         { \
1457                                 ttx = tx / tw; \
1458                                 tty = ty / tw; \
1459                         } \
1460                         else \
1461                         { \
1462                                 ttx = tx; \
1463                                 tty = ty; \
1464                         } \
1465                         itx = (int)ttx; \
1466                         ity = (int)tty; \
1468 /* Set destination pixels */ \
1469                         if(!interpolate && x >= 0 && x < w) \
1470                         { \
1471                                 if(itx >= 0 && itx < w && \
1472                                         ity >= 0 && ity < h && \
1473                                         x >= 0 && x < w) \
1474                                 { \
1475                                         type *src = in_rows[ity] + itx * components; \
1476                                         *out_row++ = *src++; \
1477                                         *out_row++ = *src++; \
1478                                         *out_row++ = *src++; \
1479                                         if(components == 4) *out_row++ = *src; \
1480                                 } \
1481                                 else \
1482 /* Fill with chroma */ \
1483                                 { \
1484                                         *out_row++ = 0; \
1485                                         *out_row++ = chroma_offset; \
1486                                         *out_row++ = chroma_offset; \
1487                                         if(components == 4) *out_row++ = 0; \
1488                                 } \
1489                         } \
1490                         else \
1491 /* Bicubic algorithm */ \
1492                         if(interpolate && x >= 0 && x < w) \
1493                         { \
1494                                 if ((itx + 2) >= 0 && (itx - 1) < w && \
1495                         (ity + 2) >= 0 && (ity - 1) < h) \
1496                 { \
1497                         float dx, dy; \
1499 /* the fractional error */ \
1500                         dx = ttx - itx; \
1501                         dy = tty - ity; \
1503 /* Row and column offsets in cubic block */ \
1504                                         int col1 = itx - 1; \
1505                                         int col2 = itx; \
1506                                         int col3 = itx + 1; \
1507                                         int col4 = itx + 2; \
1508                                         int row1 = ity - 1; \
1509                                         int row2 = ity; \
1510                                         int row3 = ity + 1; \
1511                                         int row4 = ity + 2; \
1512                                         CLAMP(col1, 0, maxw); \
1513                                         CLAMP(col2, 0, maxw); \
1514                                         CLAMP(col3, 0, maxw); \
1515                                         CLAMP(col4, 0, maxw); \
1516                                         CLAMP(row1, 0, maxh); \
1517                                         CLAMP(row2, 0, maxh); \
1518                                         CLAMP(row3, 0, maxh); \
1519                                         CLAMP(row4, 0, maxh); \
1520                                         int col1_offset = col1 * components; \
1521                                         int col2_offset = col2 * components; \
1522                                         int col3_offset = col3 * components; \
1523                                         int col4_offset = col4 * components; \
1524                                         type *row1_ptr = in_rows[row1]; \
1525                                         type *row2_ptr = in_rows[row2]; \
1526                                         type *row3_ptr = in_rows[row3]; \
1527                                         type *row4_ptr = in_rows[row4]; \
1528                                         temp_type r, g, b, a; \
1530                                         r = (temp_type)(transform_cubic(dy, \
1531                                  CUBIC_ROW(row1_ptr, 0x0), \
1532                                  CUBIC_ROW(row2_ptr, 0x0), \
1533                                  CUBIC_ROW(row3_ptr, 0x0), \
1534                                  CUBIC_ROW(row4_ptr, 0x0)) + \
1535                                                          round_factor); \
1537                                         row1_ptr++; \
1538                                         row2_ptr++; \
1539                                         row3_ptr++; \
1540                                         row4_ptr++; \
1541                                         g = (temp_type)(transform_cubic(dy, \
1542                                  CUBIC_ROW(row1_ptr, chroma_offset), \
1543                                  CUBIC_ROW(row2_ptr, chroma_offset), \
1544                                  CUBIC_ROW(row3_ptr, chroma_offset), \
1545                                  CUBIC_ROW(row4_ptr, chroma_offset)) + \
1546                                                          round_factor); \
1547                                         g += chroma_offset; \
1549                                         row1_ptr++; \
1550                                         row2_ptr++; \
1551                                         row3_ptr++; \
1552                                         row4_ptr++; \
1553                                         b = (temp_type)(transform_cubic(dy, \
1554                                  CUBIC_ROW(row1_ptr, chroma_offset), \
1555                                  CUBIC_ROW(row2_ptr, chroma_offset), \
1556                                  CUBIC_ROW(row3_ptr, chroma_offset), \
1557                                  CUBIC_ROW(row4_ptr, chroma_offset)) + \
1558                                                          round_factor); \
1559                                         b += chroma_offset; \
1561                                         if(components == 4) \
1562                                         { \
1563                                                 row1_ptr++; \
1564                                                 row2_ptr++; \
1565                                                 row3_ptr++; \
1566                                                 row4_ptr++; \
1567                                                 a = (temp_type)(transform_cubic(dy, \
1568                                          CUBIC_ROW(row1_ptr, 0x0), \
1569                                          CUBIC_ROW(row2_ptr, 0x0), \
1570                                          CUBIC_ROW(row3_ptr, 0x0), \
1571                                          CUBIC_ROW(row4_ptr, 0x0)) +  \
1572                                                                  round_factor); \
1573                                         } \
1575                                         if(sizeof(type) < 4) \
1576                                         { \
1577                                                 *out_row++ = CLIP(r, 0, max); \
1578                                                 *out_row++ = CLIP(g, 0, max); \
1579                                                 *out_row++ = CLIP(b, 0, max); \
1580                                                 if(components == 4) *out_row++ = CLIP(a, 0, max); \
1581                                         } \
1582                                         else \
1583                                         { \
1584                                                 *out_row++ = r; \
1585                                                 *out_row++ = g; \
1586                                                 *out_row++ = b; \
1587                                                 if(components == 4) *out_row++ = a; \
1588                                         } \
1589                 } \
1590                                 else \
1591 /* Fill with chroma */ \
1592                                 { \
1593                                         *out_row++ = 0; \
1594                                         *out_row++ = chroma_offset; \
1595                                         *out_row++ = chroma_offset; \
1596                                         if(components == 4) *out_row++ = 0; \
1597                                 } \
1598                         } \
1599                         else \
1600                         { \
1601                                 out_row += components; \
1602                         } \
1604 /*  increment the transformed coordinates  */ \
1605                         tx += xinc; \
1606                         ty += yinc; \
1607                         tw += winc; \
1608                 } \
1609         } \
1615                 switch(plugin->input->get_color_model())
1616                 {
1617                         case BC_RGB_FLOAT:
1618                                 TRANSFORM(3, float, float, 0x0, 1)
1619                                 break;
1620                         case BC_RGB888:
1621                                 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
1622                                 break;
1623                         case BC_RGBA_FLOAT:
1624                                 TRANSFORM(4, float, float, 0x0, 1)
1625                                 break;
1626                         case BC_RGBA8888:
1627                                 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
1628                                 break;
1629                         case BC_YUV888:
1630                                 TRANSFORM(3, unsigned char, int, 0x80, 0xff)
1631                                 break;
1632                         case BC_YUVA8888:
1633                                 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
1634                                 break;
1635                         case BC_RGB161616:
1636                                 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
1637                                 break;
1638                         case BC_RGBA16161616:
1639                                 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
1640                                 break;
1641                         case BC_YUV161616:
1642                                 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
1643                                 break;
1644                         case BC_YUVA16161616:
1645                                 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
1646                                 break;
1647                 }
1649 //printf("PerspectiveUnit::process_package 50\n");
1650         }
1651         else
1652         {
1653                 int max_x = w * OVERSAMPLE - 1;
1654                 int max_y = h * OVERSAMPLE - 1;
1655 //printf("PerspectiveUnit::process_package 50 %d %d\n", max_x, max_y);
1656                 float top_w = out_x2 - out_x1;
1657                 float bottom_w = out_x3 - out_x4;
1658                 float left_h = out_y4 - out_y1;
1659                 float right_h = out_y3 - out_y2;
1660                 float out_w_diff = bottom_w - top_w;
1661                 float out_left_diff = out_x4 - out_x1;
1662                 float out_h_diff = right_h - left_h;
1663                 float out_top_diff = out_y2 - out_y1;
1664                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1665                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1666                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1667                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1668                 float max_v = MAX(distance1, distance3);
1669                 float max_h = MAX(distance2, distance4);
1670                 float max_dimension = MAX(max_v, max_h);
1671                 float min_dimension = MIN(h, w);
1672                 float step = min_dimension / max_dimension / OVERSAMPLE;
1673                 float h_f = h;
1674                 float w_f = w;
1676 // Projection
1677 #define PERSPECTIVE(type, components) \
1678 { \
1679         type **in_rows = (type**)plugin->input->get_rows(); \
1680         type **out_rows = (type**)plugin->temp->get_rows(); \
1682         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1683         { \
1684                 int i = (int)in_y; \
1685                 type *in_row = in_rows[i]; \
1686                 for(float in_x = 0; in_x < w; in_x += step) \
1687                 { \
1688                         int j = (int)in_x; \
1689                         float in_x_fraction = in_x / w_f; \
1690                         float in_y_fraction = in_y / h_f; \
1691                         int out_x = (int)((out_x1 + \
1692                                 out_left_diff * in_y_fraction + \
1693                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
1694                                 OVERSAMPLE); \
1695                         int out_y = (int)((out_y1 +  \
1696                                 out_top_diff * in_x_fraction + \
1697                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1698                                 OVERSAMPLE); \
1699                         CLAMP(out_x, 0, max_x); \
1700                         CLAMP(out_y, 0, max_y); \
1701                         type *dst = out_rows[out_y] + out_x * components; \
1702                         type *src = in_row + j * components; \
1703                         dst[0] = src[0]; \
1704                         dst[1] = src[1]; \
1705                         dst[2] = src[2]; \
1706                         if(components == 4) dst[3] = src[3]; \
1707                 } \
1708         } \
1711                 switch(plugin->input->get_color_model())
1712                 {
1713                         case BC_RGB_FLOAT:
1714                                 PERSPECTIVE(float, 3)
1715                                 break;
1716                         case BC_RGB888:
1717                                 PERSPECTIVE(unsigned char, 3)
1718                                 break;
1719                         case BC_RGBA_FLOAT:
1720                                 PERSPECTIVE(float, 4)
1721                                 break;
1722                         case BC_RGBA8888:
1723                                 PERSPECTIVE(unsigned char, 4)
1724                                 break;
1725                         case BC_YUV888:
1726                                 PERSPECTIVE(unsigned char, 3)
1727                                 break;
1728                         case BC_YUVA8888:
1729                                 PERSPECTIVE(unsigned char, 4)
1730                                 break;
1731                         case BC_RGB161616:
1732                                 PERSPECTIVE(uint16_t, 3)
1733                                 break;
1734                         case BC_RGBA16161616:
1735                                 PERSPECTIVE(uint16_t, 4)
1736                                 break;
1737                         case BC_YUV161616:
1738                                 PERSPECTIVE(uint16_t, 3)
1739                                 break;
1740                         case BC_YUVA16161616:
1741                                 PERSPECTIVE(uint16_t, 4)
1742                                 break;
1743                 }
1744         }
1756 PerspectiveEngine::PerspectiveEngine(PerspectiveMain *plugin, 
1757         int total_clients,
1758         int total_packages)
1759  : LoadServer(
1760 //1, 1 
1761 total_clients, total_packages 
1764         this->plugin = plugin;
1767 void PerspectiveEngine::init_packages()
1769         int package_h = (int)((float)plugin->output->get_h() / 
1770                         total_packages + 1);
1771         int y1 = 0;
1772         for(int i = 0; i < total_packages; i++)
1773         {
1774                 PerspectivePackage *package = (PerspectivePackage*)packages[i];
1775                 package->y1 = y1;
1776                 package->y2 = y1 + package_h;
1777                 package->y1 = MIN(plugin->output->get_h(), package->y1);
1778                 package->y2 = MIN(plugin->output->get_h(), package->y2);
1779                 y1 = package->y2;
1780         }
1783 LoadClient* PerspectiveEngine::new_client()
1785         return new PerspectiveUnit(this, plugin);
1788 LoadPackage* PerspectiveEngine::new_package()
1790         return new PerspectivePackage;