~akirad/cinecutie/trunk

« back to all changes in this revision

Viewing changes to plugins/perspective/perspective.C

  • Committer: Paolo Rampino
  • Date: 2010-02-17 19:46:21 UTC
  • Revision ID: git-v1:c39ff77ffa6ae08441c12e7d7f54e3897ddde7f1
Initial Merge

Show diffs side-by-side

added added

removed removed

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