prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / affine.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #ifdef HAVE_GL
23 #define GL_GLEXT_PROTOTYPES
24 #include <GL/gl.h>
25 #endif
26
27 #include "affine.h"
28 #include "clip.h"
29 #include "vframe.h"
30
31
32 #include <math.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 AffineMatrix::AffineMatrix()
38 {
39         bzero(values, sizeof(values));
40 }
41
42 void AffineMatrix::identity()
43 {
44         bzero(values, sizeof(values));
45         values[0][0] = 1;
46         values[1][1] = 1;
47         values[2][2] = 1;
48 }
49
50 void AffineMatrix::translate(double x, double y)
51 {
52         double g = values[2][0];
53         double h = values[2][1];
54         double i = values[2][2];
55         values[0][0] += x * g;
56         values[0][1] += x * h;
57         values[0][2] += x * i;
58         values[1][0] += y * g;
59         values[1][1] += y * h;
60         values[1][2] += y * i;
61 }
62
63 void AffineMatrix::scale(double x, double y)
64 {
65         values[0][0] *= x;
66         values[0][1] *= x;
67         values[0][2] *= x;
68
69         values[1][0] *= y;
70         values[1][1] *= y;
71         values[1][2] *= y;
72 }
73
74 void AffineMatrix::multiply(AffineMatrix *dst)
75 {
76         int i, j;
77         AffineMatrix tmp;
78         double t1, t2, t3;
79
80         for (i = 0; i < 3; i++)
81     {
82         t1 = values[i][0];
83         t2 = values[i][1];
84         t3 = values[i][2];
85         for (j = 0; j < 3; j++)
86                 {
87                         tmp.values[i][j]  = t1 * dst->values[0][j];
88                         tmp.values[i][j] += t2 * dst->values[1][j];
89                         tmp.values[i][j] += t3 * dst->values[2][j];
90                 }
91     }
92         dst->copy_from(&tmp);
93 }
94
95 double AffineMatrix::determinant()
96 {
97         double determinant;
98
99         determinant  = 
100         values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
101         determinant -= 
102         values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
103         determinant += 
104         values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
105
106         return determinant;
107 }
108
109 void AffineMatrix::invert(AffineMatrix *dst)
110 {
111         double det_1;
112
113         det_1 = determinant();
114
115         if(det_1 == 0.0)
116         return;
117
118         det_1 = 1.0 / det_1;
119
120         dst->values[0][0] =   
121       (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
122
123         dst->values[1][0] = 
124       - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
125
126         dst->values[2][0] =   
127       (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
128
129         dst->values[0][1] = 
130       - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
131
132         dst->values[1][1] = 
133       (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
134
135         dst->values[2][1] = 
136       - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
137
138         dst->values[0][2] =
139       (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
140
141         dst->values[1][2] = 
142       - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
143
144         dst->values[2][2] = 
145       (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
146 }
147
148 void AffineMatrix::copy_from(AffineMatrix *src)
149 {
150         memcpy(&values[0][0], &src->values[0][0], sizeof(values));
151 }
152
153 void AffineMatrix::transform_point(float x, 
154         float y, 
155         float *newx, 
156         float *newy)
157 {
158         double w;
159
160         w = values[2][0] * x + values[2][1] * y + values[2][2];
161
162         if (w == 0.0)
163         w = 1.0;
164         else
165         w = 1.0 / w;
166
167         *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
168         *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
169 }
170
171 void AffineMatrix::dump()
172 {
173         printf("AffineMatrix::dump\n");
174         printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
175         printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
176         printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
177 }
178
179
180
181
182
183 AffinePackage::AffinePackage()
184  : LoadPackage()
185 {
186 }
187
188
189
190
191 AffineUnit::AffineUnit(AffineEngine *server)
192  : LoadClient(server)
193 {
194         this->server = server;
195 }
196
197
198
199
200
201
202
203
204
205 void AffineUnit::calculate_matrix(
206         double in_x1,
207         double in_y1,
208         double in_x2,
209         double in_y2,
210         double out_x1,
211         double out_y1,
212         double out_x2,
213         double out_y2,
214         double out_x3,
215         double out_y3,
216         double out_x4,
217         double out_y4,
218         AffineMatrix *result)
219 {
220         AffineMatrix matrix;
221         double scalex;
222         double scaley;
223
224         scalex = scaley = 1.0;
225
226         if((in_x2 - in_x1) > 0)
227         scalex = 1.0 / (double)(in_x2 - in_x1);
228
229         if((in_y2 - in_y1) > 0)
230         scaley = 1.0 / (double)(in_y2 - in_y1);
231
232 /* Determine the perspective transform that maps from
233  * the unit cube to the transformed coordinates
234  */
235     double dx1, dx2, dx3, dy1, dy2, dy3;
236     double det1, det2;
237
238     dx1 = out_x2 - out_x4;
239     dx2 = out_x3 - out_x4;
240     dx3 = out_x1 - out_x2 + out_x4 - out_x3;
241
242     dy1 = out_y2 - out_y4;
243     dy2 = out_y3 - out_y4;
244     dy3 = out_y1 - out_y2 + out_y4 - out_y3;
245 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
246 // dx1,
247 // dx2,
248 // dx3,
249 // dy1,
250 // dy2,
251 // dy3
252 // );
253
254 /*  Is the mapping affine?  */
255     if((dx3 == 0.0) && (dy3 == 0.0))
256     {
257         matrix.values[0][0] = out_x2 - out_x1;
258         matrix.values[0][1] = out_x4 - out_x2;
259         matrix.values[0][2] = out_x1;
260         matrix.values[1][0] = out_y2 - out_y1;
261         matrix.values[1][1] = out_y4 - out_y2;
262         matrix.values[1][2] = out_y1;
263         matrix.values[2][0] = 0.0;
264         matrix.values[2][1] = 0.0;
265     }
266     else
267     {
268         det1 = dx3 * dy2 - dy3 * dx2;
269         det2 = dx1 * dy2 - dy1 * dx2;
270         matrix.values[2][0] = det1 / det2;
271         det1 = dx1 * dy3 - dy1 * dx3;
272         det2 = dx1 * dy2 - dy1 * dx2;
273         matrix.values[2][1] = det1 / det2;
274
275         matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
276         matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
277         matrix.values[0][2] = out_x1;
278
279         matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
280         matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
281         matrix.values[1][2] = out_y1;
282     }
283
284     matrix.values[2][2] = 1.0;
285
286 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
287 // matrix.dump();
288
289         result->identity();
290         result->translate(-in_x1, -in_y1);
291         result->scale(scalex, scaley);
292         matrix.multiply(result);
293 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
294 //                                { 0.0, 0.0896, 0.0 },
295 //                                { -0.00126, 0.0, 1.0 } };
296 // memcpy(&result->values[0][0], test, sizeof(test));
297 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
298 // result->dump();
299
300
301 }
302
303 float AffineUnit::transform_cubic(float dx,
304                                float jm1,
305                                float j,
306                                float jp1,
307                                float jp2)
308 {
309 /* Catmull-Rom - not bad */
310         float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
311                        ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
312                        ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
313 // printf("%f %f %f %f %f\n", 
314 // result,
315 // jm1,
316 // j,
317 // jp1,
318 // jp2);
319
320
321         return result;
322 }
323
324
325 void AffineUnit::process_package(LoadPackage *package)
326 {
327         AffinePackage *pkg = (AffinePackage*)package;
328         int min_in_x = server->in_x;
329         int min_in_y = server->in_y;
330         int max_in_x = server->in_x + server->in_w - 1;
331         int max_in_y = server->in_y + server->in_h - 1;
332
333
334 // printf("AffineUnit::process_package %d %d %d %d %d\n", 
335 // __LINE__, 
336 // min_in_x,
337 // min_in_y,
338 // max_in_x,
339 // max_in_y);
340         int min_out_x = server->out_x;
341         //int min_out_y = server->out_y;
342         int max_out_x = server->out_x + server->out_w;
343         //int max_out_y = server->out_y + server->out_h;
344
345 // Amount to shift the input coordinates relative to the output coordinates
346 // To get the pivots to line up
347         int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
348         int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
349
350 // Calculate real coords
351         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
352         if(server->mode == AffineEngine::STRETCH ||
353                 server->mode == AffineEngine::PERSPECTIVE ||
354                 server->mode == AffineEngine::ROTATE ||
355                 server->mode == AffineEngine::TRANSFORM)
356         {
357                 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
358                 out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
359                 out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
360                 out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
361                 out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
362                 out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
363                 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
364                 out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
365         }
366         else
367         {
368                 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
369                 out_y1 = server->in_y;
370                 out_x2 = out_x1 + server->in_w;
371                 out_y2 = server->in_y;
372                 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
373                 out_y4 = server->in_y + server->in_h;
374                 out_x3 = out_x4 + server->in_w;
375                 out_y3 = server->in_y + server->in_h;
376         }
377
378
379
380 // Rotation with OpenGL uses a simple quad.
381         if(server->mode == AffineEngine::ROTATE &&
382                 server->use_opengl)
383         {
384 #ifdef HAVE_GL
385                 server->output->to_texture();
386                 server->output->enable_opengl();
387                 server->output->init_screen();
388                 server->output->bind_texture(0);
389                 server->output->clear_pbuffer();
390
391                 int texture_w = server->output->get_texture_w();
392                 int texture_h = server->output->get_texture_h();
393                 float output_h = server->output->get_h();
394                 float in_x1 = (float)server->in_x / texture_w;
395                 float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
396                 float in_y1 = (float)server->in_y / texture_h;
397                 float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
398
399 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
400 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
401
402                 glBegin(GL_QUADS);
403                 glNormal3f(0, 0, 1.0);
404
405                 glTexCoord2f(in_x1, in_y1);
406                 glVertex3f(out_x1, -output_h+out_y1, 0);
407
408                 glTexCoord2f(in_x2, in_y1);
409                 glVertex3f(out_x2, -output_h+out_y2, 0);
410
411                 glTexCoord2f(in_x2, in_y2);
412                 glVertex3f(out_x3, -output_h+out_y3, 0);
413
414                 glTexCoord2f(in_x1, in_y2);
415                 glVertex3f(out_x4, -output_h+out_y4, 0);
416
417
418                 glEnd();
419
420                 server->output->set_opengl_state(VFrame::SCREEN);
421 #endif
422         }
423         else
424         if(server->mode == AffineEngine::PERSPECTIVE ||
425                 server->mode == AffineEngine::SHEER ||
426                 server->mode == AffineEngine::ROTATE ||
427                 server->mode == AffineEngine::TRANSFORM)
428         {
429                 AffineMatrix matrix;
430                 float temp;
431 // swap points 3 & 4
432                 temp = out_x4;
433                 out_x4 = out_x3;
434                 out_x3 = temp;
435                 temp = out_y4;
436                 out_y4 = out_y3;
437                 out_y3 = temp;
438
439
440
441
442
443                 if(server->mode != AffineEngine::TRANSFORM)
444                 {
445                         calculate_matrix(
446                                 server->in_x,
447                                 server->in_y,
448                                 server->in_x + server->in_w,
449                                 server->in_y + server->in_h,
450                                 out_x1,
451                                 out_y1,
452                                 out_x2,
453                                 out_y2,
454                                 out_x3,
455                                 out_y3,
456                                 out_x4,
457                                 out_y4,
458                                 &matrix);
459                 }
460                 else
461                 {
462                         matrix.copy_from(&server->matrix);
463                 }
464
465 // printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n", 
466 // __LINE__,
467 // matrix.values[0][0],
468 // matrix.values[0][1],
469 // matrix.values[0][2],
470 // matrix.values[1][0],
471 // matrix.values[1][1],
472 // matrix.values[1][2],
473 // matrix.values[2][0],
474 // matrix.values[2][1],
475 // matrix.values[2][2]);
476                 int interpolate = 1;
477                 int reverse = !server->forward;
478                 float tx, ty, tw;
479                 float xinc, yinc, winc;
480                 AffineMatrix m, im;
481                 float ttx = 0, tty = 0;
482                 int itx = 0, ity = 0;
483                 int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
484
485                 if(reverse)
486                 {
487                         m.copy_from(&matrix);
488                         m.invert(&im);
489                         matrix.copy_from(&im);
490                 }
491                 else
492                 {
493                         matrix.invert(&m);
494                 }
495
496
497
498
499
500
501                 float dx1 = 0, dy1 = 0;
502                 float dx2 = 0, dy2 = 0;
503                 float dx3 = 0, dy3 = 0;
504                 float dx4 = 0, dy4 = 0;
505                 matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
506                 matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
507                 matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
508                 matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
509
510 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
511 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
512 // printf("AffineUnit::process_package %d use_opengl=%d\n",
513 // __LINE__, server->use_opengl);
514
515
516
517
518
519                 if(server->use_opengl)
520                 {
521 #ifdef HAVE_GL
522                         static const char *affine_frag =
523                                 "uniform sampler2D tex;\n"
524                                 "uniform mat3 affine_matrix;\n"
525                                 "uniform vec2 texture_extents;\n"
526                                 "uniform vec2 image_extents;\n"
527                                 "uniform vec4 border_color;\n"
528                                 "void main()\n"
529                                 "{\n"
530                                 "       vec2 outcoord = gl_TexCoord[0].st;\n"
531                                 "       outcoord *= texture_extents;\n"
532                                 "       mat3 coord_matrix = mat3(\n"
533                                 "               outcoord.x, outcoord.y, 1.0, \n"
534                                 "               outcoord.x, outcoord.y, 1.0, \n"
535                                 "               outcoord.x, outcoord.y, 1.0);\n"
536                                 "       mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
537                                 "       vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
538                                 "       incoord /= incoord_matrix[0][2];\n"
539                                 "       incoord /= texture_extents;\n"
540                                 "       if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
541                                 "               gl_FragColor = border_color;\n"
542                                 "       else\n"
543                                 "               gl_FragColor = texture2D(tex, incoord);\n"
544                                 "}\n";
545
546                         float affine_matrix[9] = {
547                                 (float)m.values[0][0], (float)m.values[1][0], (float)m.values[2][0],
548                                 (float)m.values[0][1], (float)m.values[1][1], (float)m.values[2][1],
549                                 (float)m.values[0][2], (float)m.values[1][2], (float)m.values[2][2] 
550                         };
551
552
553                         server->output->to_texture();
554                         server->output->enable_opengl();
555                         unsigned int frag_shader = VFrame::make_shader(0,
556                                         affine_frag,
557                                         0);
558                         if(frag_shader > 0)
559                         {
560                                 glUseProgram(frag_shader);
561                                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
562                                 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"), 
563                                         1,
564                                         0,
565                                         affine_matrix);
566                                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"), 
567                                         (GLfloat)server->output->get_texture_w(),
568                                         (GLfloat)server->output->get_texture_h());
569                                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"), 
570                                         (GLfloat)server->output->get_w() / server->output->get_texture_w(),
571                                         (GLfloat)server->output->get_h() / server->output->get_texture_h());
572                                 float border_color[] = { 0, 0, 0, 0 };
573                                 if(BC_CModels::is_yuv(server->output->get_color_model()))
574                                 {
575                                         border_color[1] = 0.5;
576                                         border_color[2] = 0.5;
577                                 }
578                                 if(!BC_CModels::has_alpha(server->output->get_color_model()))
579                                 {
580                                         border_color[3] = 1.0;
581                                 }
582
583                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"), 
584                                         1,
585                                         (GLfloat*)border_color);
586                                 server->output->init_screen();
587                                 server->output->bind_texture(0);
588                                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
589                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
590                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
591                                 server->output->draw_texture();
592                                 glUseProgram(0);
593                                 server->output->set_opengl_state(VFrame::SCREEN);
594                         }
595                         return;
596 #endif // HAVE_GL
597                 }
598
599
600
601
602
603
604 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
605 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
606 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
607
608         tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
609         ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
610
611         tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
612         ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
613
614                 CLAMP(ty1, pkg->y1, pkg->y2);
615                 CLAMP(ty2, pkg->y1, pkg->y2);
616                 CLAMP(tx1, server->out_x, server->out_x + server->out_w);
617                 CLAMP(tx2, server->out_x, server->out_x + server->out_w);
618
619
620                 xinc = m.values[0][0];
621                 yinc = m.values[1][0];
622                 winc = m.values[2][0];
623
624 //printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
625 //printf("AffineUnit::process_package %d %d %d %d %d\n", 
626 //__LINE__,
627 //min_in_x,
628 //max_in_x,
629 //min_in_y,
630 //max_in_y);
631
632 #define CUBIC_ROW(in_row, chroma_offset) \
633         transform_cubic(dx, \
634                 in_row[col1_offset] - chroma_offset, \
635                 in_row[col2_offset] - chroma_offset, \
636                 in_row[col3_offset] - chroma_offset, \
637                 in_row[col4_offset] - chroma_offset)
638
639
640 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
641 { \
642         type **in_rows = (type**)server->input->get_rows(); \
643         float round_factor = 0.0; \
644         if(sizeof(type) < 4) round_factor = 0.5; \
645         for(int y = ty1; y < ty2; y++) \
646         { \
647                 type *out_row = (type*)server->output->get_rows()[y]; \
648  \
649                 if(!interpolate) \
650                 { \
651                 tx = xinc * (tx1 + 0.5) + \
652                                 m.values[0][1] * (y + pivot_offset_y + 0.5) + \
653                                 m.values[0][2] + \
654                                 pivot_offset_x * xinc; \
655                 ty = yinc * (tx1 + 0.5) + \
656                                 m.values[1][1] * (y + pivot_offset_y + 0.5) + \
657                                 m.values[1][2] + \
658                                 pivot_offset_x * yinc; \
659                 tw = winc * (tx1 + 0.5) + \
660                                 m.values[2][1] * (y + pivot_offset_y + 0.5) + \
661                                 m.values[2][2] + \
662                                 pivot_offset_x * winc; \
663                 } \
664         else \
665         { \
666                 tx = xinc * tx1 + \
667                                 m.values[0][1] * (y + pivot_offset_y) + \
668                                 m.values[0][2] + \
669                                 pivot_offset_x * xinc; \
670                 ty = yinc * tx1 + \
671                                 m.values[1][1] * (y + pivot_offset_y) + \
672                                 m.values[1][2] + \
673                                 pivot_offset_x * yinc; \
674                 tw = winc * tx1 + \
675                                 m.values[2][1] * (y + pivot_offset_y) + \
676                                 m.values[2][2] + \
677                                 pivot_offset_x * winc; \
678         } \
679  \
680  \
681                 out_row += tx1 * components; \
682                 for(int x = tx1; x < tx2; x++) \
683                 { \
684 /* Normalize homogeneous coords */ \
685                         if(tw == 0.0) \
686                         { \
687                                 ttx = 0.0; \
688                                 tty = 0.0; \
689                         } \
690                         else \
691                         if(tw != 1.0) \
692                         { \
693                                 ttx = tx / tw; \
694                                 tty = ty / tw; \
695                         } \
696                         else \
697                         { \
698                                 ttx = tx; \
699                                 tty = ty; \
700                         } \
701                         itx = (int)ttx; \
702                         ity = (int)tty; \
703  \
704                         int row1 = ity - 1; \
705                         int row2 = ity; \
706                         int row3 = ity + 1; \
707                         int row4 = ity + 2; \
708                         CLAMP(row1, min_in_y, max_in_y); \
709                         CLAMP(row2, min_in_y, max_in_y); \
710                         CLAMP(row3, min_in_y, max_in_y); \
711                         CLAMP(row4, min_in_y, max_in_y); \
712  \
713 /* Set destination pixels if in clipping region */ \
714                         if(!interpolate && \
715                                 x >= min_out_x && \
716                                 x < max_out_x) \
717                         { \
718                                 if(itx >= min_in_x && \
719                                         itx <= max_in_x && \
720                                         ity >= min_in_y && \
721                                         ity <= max_in_y) \
722                                 { \
723                                         type *src = in_rows[ity] + itx * components; \
724                                         *out_row++ = *src++; \
725                                         *out_row++ = *src++; \
726                                         *out_row++ = *src++; \
727                                         if(components == 4) *out_row++ = *src; \
728                                 } \
729                                 else \
730 /* Fill with chroma */ \
731                                 { \
732                                         *out_row++ = 0; \
733                                         *out_row++ = chroma_offset; \
734                                         *out_row++ = chroma_offset; \
735                                         if(components == 4) *out_row++ = 0; \
736                                 } \
737                         } \
738                         else \
739 /* Bicubic algorithm */ \
740                         if(interpolate &&  \
741                                 x >= min_out_x &&  \
742                                 x < max_out_x) \
743                         { \
744 /* clipping region */ \
745                                 if ((itx + 2) >= min_in_x && \
746                                         (itx - 1) <= max_in_x && \
747                         (ity + 2) >= min_in_y && \
748                                         (ity - 1) <= max_in_y) \
749                 { \
750                         float dx, dy; \
751  \
752 /* the fractional error */ \
753                         dx = ttx - itx; \
754                         dy = tty - ity; \
755  \
756 /* Row and column offsets in cubic block */ \
757                                         int col1 = itx - 1; \
758                                         int col2 = itx; \
759                                         int col3 = itx + 1; \
760                                         int col4 = itx + 2; \
761                                         CLAMP(col1, min_in_x, max_in_x); \
762                                         CLAMP(col2, min_in_x, max_in_x); \
763                                         CLAMP(col3, min_in_x, max_in_x); \
764                                         CLAMP(col4, min_in_x, max_in_x); \
765                                         int col1_offset = col1 * components; \
766                                         int col2_offset = col2 * components; \
767                                         int col3_offset = col3 * components; \
768                                         int col4_offset = col4 * components; \
769  \
770                                         type *row1_ptr = in_rows[row1]; \
771                                         type *row2_ptr = in_rows[row2]; \
772                                         type *row3_ptr = in_rows[row3]; \
773                                         type *row4_ptr = in_rows[row4]; \
774                                         temp_type r, g, b, a; \
775  \
776                                         r = (temp_type)(transform_cubic(dy, \
777                         CUBIC_ROW(row1_ptr, 0x0), \
778                         CUBIC_ROW(row2_ptr, 0x0), \
779                         CUBIC_ROW(row3_ptr, 0x0), \
780                         CUBIC_ROW(row4_ptr, 0x0)) + \
781                                                 round_factor); \
782  \
783                                         row1_ptr++; \
784                                         row2_ptr++; \
785                                         row3_ptr++; \
786                                         row4_ptr++; \
787                                         g = (temp_type)(transform_cubic(dy, \
788                         CUBIC_ROW(row1_ptr, chroma_offset), \
789                         CUBIC_ROW(row2_ptr, chroma_offset), \
790                         CUBIC_ROW(row3_ptr, chroma_offset), \
791                         CUBIC_ROW(row4_ptr, chroma_offset)) + \
792                                                 round_factor); \
793                                         g += chroma_offset; \
794  \
795                                         row1_ptr++; \
796                                         row2_ptr++; \
797                                         row3_ptr++; \
798                                         row4_ptr++; \
799                                         b = (temp_type)(transform_cubic(dy, \
800                         CUBIC_ROW(row1_ptr, chroma_offset), \
801                         CUBIC_ROW(row2_ptr, chroma_offset), \
802                         CUBIC_ROW(row3_ptr, chroma_offset), \
803                         CUBIC_ROW(row4_ptr, chroma_offset)) + \
804                                                 round_factor); \
805                                         b += chroma_offset; \
806  \
807                                         if(components == 4) \
808                                         { \
809                                                 row1_ptr++; \
810                                                 row2_ptr++; \
811                                                 row3_ptr++; \
812                                                 row4_ptr++; \
813                                                 a = (temp_type)(transform_cubic(dy, \
814                                 CUBIC_ROW(row1_ptr, 0x0), \
815                                 CUBIC_ROW(row2_ptr, 0x0), \
816                                 CUBIC_ROW(row3_ptr, 0x0), \
817                                 CUBIC_ROW(row4_ptr, 0x0)) +  \
818                                                         round_factor); \
819                                         } \
820  \
821                                         if(sizeof(type) < 4) \
822                                         { \
823                                                 *out_row++ = CLIP(r, 0, max); \
824                                                 *out_row++ = CLIP(g, 0, max); \
825                                                 *out_row++ = CLIP(b, 0, max); \
826                                                 if(components == 4) *out_row++ = CLIP(a, 0, max); \
827                                         } \
828                                         else \
829                                         { \
830                                                 *out_row++ = r; \
831                                                 *out_row++ = g; \
832                                                 *out_row++ = b; \
833                                                 if(components == 4) *out_row++ = a; \
834                                         } \
835                 } \
836                                 else \
837 /* Fill with chroma */ \
838                                 { \
839                                         *out_row++ = 0; \
840                                         *out_row++ = chroma_offset; \
841                                         *out_row++ = chroma_offset; \
842                                         if(components == 4) *out_row++ = 0; \
843                                 } \
844                         } \
845                         else \
846                         { \
847                                 out_row += components; \
848                         } \
849  \
850 /*  increment the transformed coordinates  */ \
851                         tx += xinc; \
852                         ty += yinc; \
853                         tw += winc; \
854                 } \
855         } \
856 }
857
858
859
860
861 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
862 // __LINE__, tx1, ty1, tx2, ty2);
863                 switch(server->input->get_color_model())
864                 {
865                         case BC_RGB_FLOAT:
866                                 TRANSFORM(3, float, float, 0x0, 1.0)
867                                 break;
868                         case BC_RGB888:
869                                 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
870                                 break;
871                         case BC_RGBA_FLOAT:
872                                 TRANSFORM(4, float, float, 0x0, 1.0)
873                                 break;
874                         case BC_RGBA8888:
875                                 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
876                                 break;
877                         case BC_YUV888:
878 // DEBUG
879 //                              TRANSFORM(3, unsigned char, int, 0x80, 0xff)
880 {
881         
882         unsigned char **in_rows = (unsigned char**)server->input->get_rows();
883         float round_factor = 0.0;
884         if(sizeof(unsigned char) < 4) round_factor = 0.5;
885         for(int y = ty1; y < ty2; y++)
886         {
887                 unsigned char *out_row = (unsigned char*)server->output->get_rows()[y];
888
889                 if(!interpolate)
890                 {
891                 tx = xinc * (tx1 + 0.5) +
892                                 m.values[0][1] * (y + pivot_offset_y + 0.5) +
893                                 m.values[0][2] +
894                                 pivot_offset_x * xinc;
895                 ty = yinc * (tx1 + 0.5) +
896                                 m.values[1][1] * (y + pivot_offset_y + 0.5) +
897                                 m.values[1][2] +
898                                 pivot_offset_x * yinc;
899                 tw = winc * (tx1 + 0.5) +
900                                 m.values[2][1] * (y + pivot_offset_y + 0.5) +
901                                 m.values[2][2] +
902                                 pivot_offset_x * winc;
903                 }
904         else
905         {
906                 tx = xinc * tx1 +
907                                 m.values[0][1] * (y + pivot_offset_y) +
908                                 m.values[0][2] +
909                                 pivot_offset_x * xinc;
910                 ty = yinc * tx1 +
911                                 m.values[1][1] * (y + pivot_offset_y) +
912                                 m.values[1][2] +
913                                 pivot_offset_x * yinc;
914                 tw = winc * tx1 +
915                                 m.values[2][1] * (y + pivot_offset_y) +
916                                 m.values[2][2] +
917                                 pivot_offset_x * winc;
918         }
919
920
921                 out_row += tx1 * 3;
922                 for(int x = tx1; x < tx2; x++)
923                 {
924 /* Normalize homogeneous coords */
925                         if(tw == 0.0)
926                         {
927                                 ttx = 0.0;
928                                 tty = 0.0;
929                         }
930                         else
931                         if(tw != 1.0)
932                         {
933                                 ttx = tx / tw;
934                                 tty = ty / tw;
935                         }
936                         else
937                         {
938                                 ttx = tx;
939                                 tty = ty;
940                         }
941                         itx = (int)ttx;
942                         ity = (int)tty;
943
944                         int row1 = ity - 1;
945                         int row2 = ity;
946                         int row3 = ity + 1;
947                         int row4 = ity + 2;
948                         CLAMP(row1, min_in_y, max_in_y);
949                         CLAMP(row2, min_in_y, max_in_y);
950                         CLAMP(row3, min_in_y, max_in_y);
951                         CLAMP(row4, min_in_y, max_in_y);
952
953 /* Set destination pixels if in clipping region */
954                         if(!interpolate &&
955                                 x >= min_out_x &&
956                                 x < max_out_x)
957                         {
958                                 if(itx >= min_in_x &&
959                                         itx <= max_in_x &&
960                                         ity >= min_in_y &&
961                                         ity <= max_in_y)
962                                 {
963                                         unsigned char *src = in_rows[ity] + itx * 3;
964                                         *out_row++ = *src++;
965                                         *out_row++ = *src++;
966                                         *out_row++ = *src++;
967                                         if(3 == 4) *out_row++ = *src;
968                                 }
969                                 else
970 /* Fill with chroma */
971                                 {
972                                         *out_row++ = 0;
973                                         *out_row++ = 0x80;
974                                         *out_row++ = 0x80;
975                                         if(3 == 4) *out_row++ = 0;
976                                 }
977                         }
978                         else
979 /* Bicubic algorithm */
980                         if(interpolate && 
981                                 x >= min_out_x && 
982                                 x < max_out_x)
983                         {
984 /* clipping region */
985                                 if ((itx + 2) >= min_in_x &&
986                                         (itx - 1) <= max_in_x &&
987                         (ity + 2) >= min_in_y &&
988                                         (ity - 1) <= max_in_y)
989                 {
990                         float dx, dy;
991
992 /* the fractional error */
993                         dx = ttx - itx;
994                         dy = tty - ity;
995
996 /* Row and column offsets in cubic block */
997                                         int col1 = itx - 1;
998                                         int col2 = itx;
999                                         int col3 = itx + 1;
1000                                         int col4 = itx + 2;
1001                                         CLAMP(col1, min_in_x, max_in_x);
1002                                         CLAMP(col2, min_in_x, max_in_x);
1003                                         CLAMP(col3, min_in_x, max_in_x);
1004                                         CLAMP(col4, min_in_x, max_in_x);
1005                                         int col1_offset = col1 * 3;
1006                                         int col2_offset = col2 * 3;
1007                                         int col3_offset = col3 * 3;
1008                                         int col4_offset = col4 * 3;
1009
1010                                         unsigned char *row1_ptr = in_rows[row1];
1011                                         unsigned char *row2_ptr = in_rows[row2];
1012                                         unsigned char *row3_ptr = in_rows[row3];
1013                                         unsigned char *row4_ptr = in_rows[row4];
1014                                         int r, g, b, a;
1015
1016                                         r = (int)(transform_cubic(dy,
1017                         CUBIC_ROW(row1_ptr, 0x0),
1018                         CUBIC_ROW(row2_ptr, 0x0),
1019                         CUBIC_ROW(row3_ptr, 0x0),
1020                         CUBIC_ROW(row4_ptr, 0x0)) +
1021                                                 round_factor);
1022
1023                                         row1_ptr++;
1024                                         row2_ptr++;
1025                                         row3_ptr++;
1026                                         row4_ptr++;
1027                                         g = (int)(transform_cubic(dy,
1028                         CUBIC_ROW(row1_ptr, 0x80),
1029                         CUBIC_ROW(row2_ptr, 0x80),
1030                         CUBIC_ROW(row3_ptr, 0x80),
1031                         CUBIC_ROW(row4_ptr, 0x80)) +
1032                                                 round_factor);
1033                                         g += 0x80;
1034
1035                                         row1_ptr++;
1036                                         row2_ptr++;
1037                                         row3_ptr++;
1038                                         row4_ptr++;
1039                                         b = (int)(transform_cubic(dy,
1040                         CUBIC_ROW(row1_ptr, 0x80),
1041                         CUBIC_ROW(row2_ptr, 0x80),
1042                         CUBIC_ROW(row3_ptr, 0x80),
1043                         CUBIC_ROW(row4_ptr, 0x80)) +
1044                                                 round_factor);
1045                                         b += 0x80;
1046
1047                                         if(3 == 4)
1048                                         {
1049                                                 row1_ptr++;
1050                                                 row2_ptr++;
1051                                                 row3_ptr++;
1052                                                 row4_ptr++;
1053                                                 a = (int)(transform_cubic(dy,
1054                                 CUBIC_ROW(row1_ptr, 0x0),
1055                                 CUBIC_ROW(row2_ptr, 0x0),
1056                                 CUBIC_ROW(row3_ptr, 0x0),
1057                                 CUBIC_ROW(row4_ptr, 0x0)) + 
1058                                                         round_factor);
1059                                         }
1060
1061                                         if(sizeof(unsigned char) < 4)
1062                                         {
1063                                                 *out_row++ = CLIP(r, 0, 0xff);
1064                                                 *out_row++ = CLIP(g, 0, 0xff);
1065                                                 *out_row++ = CLIP(b, 0, 0xff);
1066                                                 if(3 == 4) *out_row++ = CLIP(a, 0, 0xff);
1067                                         }
1068                                         else
1069                                         {
1070                                                 *out_row++ = r;
1071                                                 *out_row++ = g;
1072                                                 *out_row++ = b;
1073                                                 if(3 == 4) *out_row++ = a;
1074                                         }
1075                 }
1076                                 else
1077 /* Fill with chroma */
1078                                 {
1079                                         *out_row++ = 0;
1080                                         *out_row++ = 0x80;
1081                                         *out_row++ = 0x80;
1082                                         if(3 == 4) *out_row++ = 0;
1083                                 }
1084                         }
1085                         else
1086                         {
1087                                 out_row += 3;
1088                         }
1089
1090 /*  increment the transformed coordinates  */
1091                         tx += xinc;
1092                         ty += yinc;
1093                         tw += winc;
1094                 }
1095         }
1096 }
1097
1098                                 break;
1099                         case BC_YUVA8888:
1100                                 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
1101                                 break;
1102                         case BC_RGB161616:
1103                                 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
1104                                 break;
1105                         case BC_RGBA16161616:
1106                                 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
1107                                 break;
1108                         case BC_YUV161616:
1109                                 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
1110                                 break;
1111                         case BC_YUVA16161616:
1112                                 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
1113                                 break;
1114                 }
1115
1116         }
1117         else
1118         {
1119                 int min_x = server->in_x * AFFINE_OVERSAMPLE;
1120                 int min_y = server->in_y * AFFINE_OVERSAMPLE;
1121                 int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
1122                 int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
1123                 float top_w = out_x2 - out_x1;
1124                 float bottom_w = out_x3 - out_x4;
1125                 float left_h = out_y4 - out_y1;
1126                 float right_h = out_y3 - out_y2;
1127                 float out_w_diff = bottom_w - top_w;
1128                 float out_left_diff = out_x4 - out_x1;
1129                 float out_h_diff = right_h - left_h;
1130                 float out_top_diff = out_y2 - out_y1;
1131                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1132                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1133                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1134                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1135                 float max_v = MAX(distance1, distance3);
1136                 float max_h = MAX(distance2, distance4);
1137                 float max_dimension = MAX(max_v, max_h);
1138                 float min_dimension = MIN(server->in_h, server->in_w);
1139                 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
1140                 float x_f = server->in_x;
1141                 float y_f = server->in_y;
1142                 float h_f = server->in_h;
1143                 float w_f = server->in_w;
1144
1145
1146
1147                 if(server->use_opengl)
1148                 {
1149                         return;
1150                 }
1151
1152
1153
1154 // Projection
1155 #define DO_STRETCH(type, components) \
1156 { \
1157         type **in_rows = (type**)server->input->get_rows(); \
1158         type **out_rows = (type**)server->temp->get_rows(); \
1159  \
1160         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1161         { \
1162                 int i = (int)in_y; \
1163                 type *in_row = in_rows[i]; \
1164                 for(float in_x = x_f; in_x < w_f; in_x += step) \
1165                 { \
1166                         int j = (int)in_x; \
1167                         float in_x_fraction = (in_x - x_f) / w_f; \
1168                         float in_y_fraction = (in_y - y_f) / h_f; \
1169                         int out_x = (int)((out_x1 + \
1170                                 out_left_diff * in_y_fraction + \
1171                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
1172                                 AFFINE_OVERSAMPLE); \
1173                         int out_y = (int)((out_y1 +  \
1174                                 out_top_diff * in_x_fraction + \
1175                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1176                                 AFFINE_OVERSAMPLE); \
1177                         CLAMP(out_x, min_x, max_x); \
1178                         CLAMP(out_y, min_y, max_y); \
1179                         type *dst = out_rows[out_y] + out_x * components; \
1180                         type *src = in_row + j * components; \
1181                         dst[0] = src[0]; \
1182                         dst[1] = src[1]; \
1183                         dst[2] = src[2]; \
1184                         if(components == 4) dst[3] = src[3]; \
1185                 } \
1186         } \
1187 }
1188
1189                 switch(server->input->get_color_model())
1190                 {
1191                         case BC_RGB_FLOAT:
1192                                 DO_STRETCH(float, 3)
1193                                 break;
1194                         case BC_RGB888:
1195                                 DO_STRETCH(unsigned char, 3)
1196                                 break;
1197                         case BC_RGBA_FLOAT:
1198                                 DO_STRETCH(float, 4)
1199                                 break;
1200                         case BC_RGBA8888:
1201                                 DO_STRETCH(unsigned char, 4)
1202                                 break;
1203                         case BC_YUV888:
1204                                 DO_STRETCH(unsigned char, 3)
1205                                 break;
1206                         case BC_YUVA8888:
1207                                 DO_STRETCH(unsigned char, 4)
1208                                 break;
1209                         case BC_RGB161616:
1210                                 DO_STRETCH(uint16_t, 3)
1211                                 break;
1212                         case BC_RGBA16161616:
1213                                 DO_STRETCH(uint16_t, 4)
1214                                 break;
1215                         case BC_YUV161616:
1216                                 DO_STRETCH(uint16_t, 3)
1217                                 break;
1218                         case BC_YUVA16161616:
1219                                 DO_STRETCH(uint16_t, 4)
1220                                 break;
1221                 }
1222         }
1223
1224
1225
1226
1227 }
1228
1229
1230
1231
1232
1233
1234 AffineEngine::AffineEngine(int total_clients,
1235         int total_packages)
1236  : LoadServer(
1237 //1, 1 
1238 total_clients, total_packages 
1239 )
1240 {
1241         user_in_viewport = 0;
1242         user_in_pivot = 0;
1243         user_out_viewport = 0;
1244         user_out_pivot = 0;
1245         use_opengl = 0;
1246         in_x = in_y = in_w = in_h = 0;
1247         out_x = out_y = out_w = out_h = 0;
1248         in_pivot_x = in_pivot_y = 0;
1249         out_pivot_x = out_pivot_y = 0;
1250         this->total_packages = total_packages;
1251 }
1252
1253 void AffineEngine::init_packages()
1254 {
1255         for(int i = 0; i < get_total_packages(); i++)
1256         {
1257                 AffinePackage *package = (AffinePackage*)get_package(i);
1258                 package->y1 = out_y + (out_h * i / get_total_packages());
1259                 package->y2 = out_y + (out_h * (i + 1) / get_total_packages());
1260         }
1261 }
1262
1263 LoadClient* AffineEngine::new_client()
1264 {
1265         return new AffineUnit(this);
1266 }
1267
1268 LoadPackage* AffineEngine::new_package()
1269 {
1270         return new AffinePackage;
1271 }
1272
1273 void AffineEngine::process(VFrame *output,
1274         VFrame *input, 
1275         VFrame *temp,
1276         int mode,
1277         float x1, 
1278         float y1, 
1279         float x2, 
1280         float y2, 
1281         float x3, 
1282         float y3, 
1283         float x4, 
1284         float y4,
1285         int forward)
1286 {
1287
1288
1289 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
1290 // __LINE__,
1291 // x1, 
1292 // y1, 
1293 // x2, 
1294 // y2, 
1295 // x3, 
1296 // y3, 
1297 // x4, 
1298 // y4);
1299 // 
1300 // printf("AffineEngine::process %d %d %d %d %d\n", 
1301 // __LINE__,
1302 // in_x, in_y, in_w, in_h);
1303 // 
1304 // printf("AffineEngine::process %d %d %d %d %d\n", 
1305 // __LINE__,
1306 // out_x, out_y, out_w, out_h);
1307 // 
1308 // printf("AffineEngine::process %d %d %d %d %d\n", 
1309 // __LINE__,
1310 // in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
1311 // 
1312 // printf("AffineEngine::process %d %d %d %d %d\n", 
1313 // __LINE__,
1314 // user_in_pivot,
1315 // user_out_pivot,
1316 // user_in_viewport,
1317 // user_out_viewport);
1318
1319         this->output = output;
1320         this->input = input;
1321         this->temp = temp;
1322         this->mode = mode;
1323         this->x1 = x1;
1324         this->y1 = y1;
1325         this->x2 = x2;
1326         this->y2 = y2;
1327         this->x3 = x3;
1328         this->y3 = y3;
1329         this->x4 = x4;
1330         this->y4 = y4;
1331         this->forward = forward;
1332
1333
1334         if(!user_in_viewport)
1335         {
1336                 in_x = 0;
1337                 in_y = 0;
1338                 in_w = input->get_w();
1339                 in_h = input->get_h();
1340         }
1341
1342         if(!user_out_viewport)
1343         {
1344                 out_x = 0;
1345                 out_y = 0;
1346                 out_w = output->get_w();
1347                 out_h = output->get_h();
1348         }
1349
1350         if(use_opengl)
1351         {
1352                 set_package_count(1);
1353                 process_single();
1354         }
1355         else
1356         {
1357                 set_package_count(total_packages);
1358                 process_packages();
1359         }
1360 }
1361
1362
1363
1364
1365 void AffineEngine::rotate(VFrame *output,
1366         VFrame *input, 
1367         float angle)
1368 {
1369         this->output = output;
1370         this->input = input;
1371         this->temp = 0;
1372         this->mode = ROTATE;
1373         this->forward = 1;
1374
1375         if(!user_in_viewport)
1376         {
1377                 in_x = 0;
1378                 in_y = 0;
1379                 in_w = input->get_w();
1380                 in_h = input->get_h();
1381 // DEBUG
1382 // in_x = 4;
1383 // in_w = 2992;
1384 // in_y = 4;
1385 // in_h = 2992;
1386 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
1387         }
1388
1389         if(!user_in_pivot)
1390         {
1391                 in_pivot_x = in_x + in_w / 2;
1392                 in_pivot_y = in_y + in_h / 2;
1393         }
1394
1395         if(!user_out_viewport)
1396         {
1397                 out_x = 0;
1398                 out_y = 0;
1399                 out_w = output->get_w();
1400                 out_h = output->get_h();
1401         }
1402
1403         if(!user_out_pivot)
1404         {
1405                 out_pivot_x = out_x + out_w / 2;
1406                 out_pivot_y = out_y + out_h / 2;
1407         }
1408
1409 // All subscripts are clockwise around the quadrangle
1410         angle = angle * 2 * M_PI / 360;
1411         double angle1 = atan((double)(in_pivot_y - in_y) / (double)(in_pivot_x - in_x)) + angle;
1412         double angle2 = atan((double)(in_x + in_w - in_pivot_x) / (double)(in_pivot_y - in_y)) + angle;
1413         double angle3 = atan((double)(in_y + in_h - in_pivot_y) / (double)(in_x + in_w - in_pivot_x)) + angle;
1414         double angle4 = atan((double)(in_pivot_x - in_x) / (double)(in_y + in_h - in_pivot_y)) + angle;
1415         double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
1416         double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
1417         double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
1418         double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
1419
1420         x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
1421         y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
1422         x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
1423         y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
1424         x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
1425         y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
1426         x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
1427         y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
1428
1429 // printf("AffineEngine::rotate angle=%f\n",
1430 // angle);
1431
1432 // 
1433 // printf("     angle1=%f angle2=%f angle3=%f angle4=%f\n",
1434 // angle1 * 360 / 2 / M_PI, 
1435 // angle2 * 360 / 2 / M_PI, 
1436 // angle3 * 360 / 2 / M_PI, 
1437 // angle4 * 360 / 2 / M_PI);
1438 // 
1439 // printf("     radius1=%f radius2=%f radius3=%f radius4=%f\n",
1440 // radius1,
1441 // radius2,
1442 // radius3,
1443 // radius4);
1444 // 
1445 // printf("     x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
1446 // x1 * w / 100, 
1447 // y1 * h / 100, 
1448 // x2 * w / 100, 
1449 // y2 * h / 100, 
1450 // x3 * w / 100, 
1451 // y3 * h / 100, 
1452 // x4 * w / 100, 
1453 // y4 * h / 100);
1454
1455         if(use_opengl)
1456         {
1457                 set_package_count(1);
1458                 process_single();
1459         }
1460         else
1461         {
1462                 set_package_count(total_packages);
1463                 process_packages();
1464         }
1465 }
1466
1467 void AffineEngine::set_matrix(AffineMatrix *matrix)
1468 {
1469         for(int i = 0; i < 3; i++)
1470         {
1471                 for(int j = 0; j < 3; j++)
1472                 {
1473                         this->matrix.values[i][j] = matrix->values[i][j];
1474                 }
1475         }
1476 }
1477
1478 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
1479 {
1480         this->in_x = x;
1481         this->in_y = y;
1482         this->in_w = w;
1483         this->in_h = h;
1484         this->user_in_viewport = 1;
1485 }
1486
1487 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
1488 {
1489         this->out_x = x;
1490         this->out_y = y;
1491         this->out_w = w;
1492         this->out_h = h;
1493         this->user_out_viewport = 1;
1494 }
1495
1496 void AffineEngine::set_opengl(int value)
1497 {
1498         this->use_opengl = value;
1499 }
1500
1501 void AffineEngine::set_in_pivot(int x, int y)
1502 {
1503         this->in_pivot_x = x;
1504         this->in_pivot_y = y;
1505         this->user_in_pivot = 1;
1506 }
1507
1508 void AffineEngine::set_out_pivot(int x, int y)
1509 {
1510         this->out_pivot_x = x;
1511         this->out_pivot_y = y;
1512         this->user_out_pivot = 1;
1513 }
1514
1515 void AffineEngine::unset_pivot()
1516 {
1517         user_in_pivot = 0;
1518         user_out_pivot = 0;
1519 }
1520
1521 void AffineEngine::unset_viewport()
1522 {
1523         user_in_viewport = 0;
1524         user_out_viewport = 0;
1525 }
1526
1527