merge hv v6, rework trace methods
[goodguy/history.git] / cinelerra-5.1 / 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 static inline float transform_cubic(float dx,
304                 float jm1, float j, float jp1, float jp2)
305 {
306 /* Catmull-Rom - not bad */
307         float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
308                        ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
309                        ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
310 // printf("%f %f %f %f %f\n", result, jm1, j, jp1, jp2);
311         return result;
312 }
313
314
315 void AffineUnit::process_package(LoadPackage *package)
316 {
317         AffinePackage *pkg = (AffinePackage*)package;
318         int min_in_x = server->in_x;
319         int min_in_y = server->in_y;
320         int max_in_x = server->in_x + server->in_w - 1;
321         int max_in_y = server->in_y + server->in_h - 1;
322
323
324 // printf("AffineUnit::process_package %d %d %d %d %d\n",
325 // __LINE__,
326 // min_in_x,
327 // min_in_y,
328 // max_in_x,
329 // max_in_y);
330         int min_out_x = server->out_x;
331         //int min_out_y = server->out_y;
332         int max_out_x = server->out_x + server->out_w;
333         //int max_out_y = server->out_y + server->out_h;
334
335 // Amount to shift the input coordinates relative to the output coordinates
336 // To get the pivots to line up
337         int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
338         int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
339
340 // Calculate real coords
341         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
342         if(server->mode == AffineEngine::STRETCH ||
343                 server->mode == AffineEngine::PERSPECTIVE ||
344                 server->mode == AffineEngine::ROTATE ||
345                 server->mode == AffineEngine::TRANSFORM)
346         {
347                 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
348                 out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
349                 out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
350                 out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
351                 out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
352                 out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
353                 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
354                 out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
355         }
356         else
357         {
358                 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
359                 out_y1 = server->in_y;
360                 out_x2 = out_x1 + server->in_w;
361                 out_y2 = server->in_y;
362                 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
363                 out_y4 = server->in_y + server->in_h;
364                 out_x3 = out_x4 + server->in_w;
365                 out_y3 = server->in_y + server->in_h;
366         }
367
368
369
370 // Rotation with OpenGL uses a simple quad.
371         if(server->mode == AffineEngine::ROTATE &&
372                 server->use_opengl)
373         {
374 #ifdef HAVE_GL
375                 server->output->to_texture();
376                 server->output->enable_opengl();
377                 server->output->init_screen();
378                 server->output->bind_texture(0);
379                 server->output->clear_pbuffer();
380
381                 int texture_w = server->output->get_texture_w();
382                 int texture_h = server->output->get_texture_h();
383                 float output_h = server->output->get_h();
384                 float in_x1 = (float)server->in_x / texture_w;
385                 float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
386                 float in_y1 = (float)server->in_y / texture_h;
387                 float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
388
389 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
390 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
391
392                 glBegin(GL_QUADS);
393                 glNormal3f(0, 0, 1.0);
394
395                 glTexCoord2f(in_x1, in_y1);
396                 glVertex3f(out_x1, -output_h+out_y1, 0);
397
398                 glTexCoord2f(in_x2, in_y1);
399                 glVertex3f(out_x2, -output_h+out_y2, 0);
400
401                 glTexCoord2f(in_x2, in_y2);
402                 glVertex3f(out_x3, -output_h+out_y3, 0);
403
404                 glTexCoord2f(in_x1, in_y2);
405                 glVertex3f(out_x4, -output_h+out_y4, 0);
406
407
408                 glEnd();
409
410                 server->output->set_opengl_state(VFrame::SCREEN);
411 #endif
412         }
413         else
414         if(server->mode == AffineEngine::PERSPECTIVE ||
415                 server->mode == AffineEngine::SHEER ||
416                 server->mode == AffineEngine::ROTATE ||
417                 server->mode == AffineEngine::TRANSFORM)
418         {
419                 AffineMatrix matrix;
420                 float temp;
421 // swap points 3 & 4
422                 temp = out_x4;
423                 out_x4 = out_x3;
424                 out_x3 = temp;
425                 temp = out_y4;
426                 out_y4 = out_y3;
427                 out_y3 = temp;
428
429
430
431
432
433                 if(server->mode != AffineEngine::TRANSFORM)
434                 {
435                         calculate_matrix(
436                                 server->in_x,
437                                 server->in_y,
438                                 server->in_x + server->in_w,
439                                 server->in_y + server->in_h,
440                                 out_x1,
441                                 out_y1,
442                                 out_x2,
443                                 out_y2,
444                                 out_x3,
445                                 out_y3,
446                                 out_x4,
447                                 out_y4,
448                                 &matrix);
449                 }
450                 else
451                 {
452                         matrix.copy_from(&server->matrix);
453                 }
454
455 // printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n",
456 // __LINE__,
457 // matrix.values[0][0],
458 // matrix.values[0][1],
459 // matrix.values[0][2],
460 // matrix.values[1][0],
461 // matrix.values[1][1],
462 // matrix.values[1][2],
463 // matrix.values[2][0],
464 // matrix.values[2][1],
465 // matrix.values[2][2]);
466                 int interpolate = 1;
467                 int reverse = !server->forward;
468                 float tx, ty, tw;
469                 float xinc, yinc, winc;
470                 AffineMatrix m, im;
471                 float ttx = 0, tty = 0;
472                 int itx = 0, ity = 0;
473                 int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
474
475                 if(reverse)
476                 {
477                         m.copy_from(&matrix);
478                         m.invert(&im);
479                         matrix.copy_from(&im);
480                 }
481                 else
482                 {
483                         matrix.invert(&m);
484                 }
485
486
487
488
489
490
491                 float dx1 = 0, dy1 = 0;
492                 float dx2 = 0, dy2 = 0;
493                 float dx3 = 0, dy3 = 0;
494                 float dx4 = 0, dy4 = 0;
495                 matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
496                 matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
497                 matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
498                 matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
499
500 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
501 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
502 // printf("AffineUnit::process_package %d use_opengl=%d\n",
503 // __LINE__, server->use_opengl);
504
505
506
507
508
509                 if(server->use_opengl)
510                 {
511 #ifdef HAVE_GL
512                         static const char *affine_frag =
513                                 "uniform sampler2D tex;\n"
514                                 "uniform mat3 affine_matrix;\n"
515                                 "uniform vec2 texture_extents;\n"
516                                 "uniform vec2 image_extents;\n"
517                                 "uniform vec4 border_color;\n"
518                                 "void main()\n"
519                                 "{\n"
520                                 "       vec2 outcoord = gl_TexCoord[0].st;\n"
521                                 "       outcoord *= texture_extents;\n"
522                                 "       mat3 coord_matrix = mat3(\n"
523                                 "               outcoord.x, outcoord.y, 1.0, \n"
524                                 "               outcoord.x, outcoord.y, 1.0, \n"
525                                 "               outcoord.x, outcoord.y, 1.0);\n"
526                                 "       mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
527                                 "       vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
528                                 "       incoord /= incoord_matrix[0][2];\n"
529                                 "       incoord /= texture_extents;\n"
530                                 "       if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
531                                 "               gl_FragColor = border_color;\n"
532                                 "       else\n"
533                                 "               gl_FragColor = texture2D(tex, incoord);\n"
534                                 "}\n";
535
536                         float affine_matrix[9] = {
537                                 (float)m.values[0][0], (float)m.values[1][0], (float)m.values[2][0],
538                                 (float)m.values[0][1], (float)m.values[1][1], (float)m.values[2][1],
539                                 (float)m.values[0][2], (float)m.values[1][2], (float)m.values[2][2]
540                         };
541
542
543                         server->output->to_texture();
544                         server->output->enable_opengl();
545                         unsigned int frag_shader = VFrame::make_shader(0,
546                                         affine_frag,
547                                         0);
548                         if(frag_shader > 0)
549                         {
550                                 glUseProgram(frag_shader);
551                                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
552                                 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"),
553                                         1,
554                                         0,
555                                         affine_matrix);
556                                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
557                                         (GLfloat)server->output->get_texture_w(),
558                                         (GLfloat)server->output->get_texture_h());
559                                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
560                                         (GLfloat)server->output->get_w() / server->output->get_texture_w(),
561                                         (GLfloat)server->output->get_h() / server->output->get_texture_h());
562                                 float border_color[] = { 0, 0, 0, 0 };
563                                 if(BC_CModels::is_yuv(server->output->get_color_model()))
564                                 {
565                                         border_color[1] = 0.5;
566                                         border_color[2] = 0.5;
567                                 }
568                                 if(!BC_CModels::has_alpha(server->output->get_color_model()))
569                                 {
570                                         border_color[3] = 1.0;
571                                 }
572
573                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
574                                         1,
575                                         (GLfloat*)border_color);
576                                 server->output->init_screen();
577                                 server->output->bind_texture(0);
578                                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
579                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
580                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
581                                 server->output->draw_texture();
582                                 glUseProgram(0);
583                                 server->output->set_opengl_state(VFrame::SCREEN);
584                         }
585                         return;
586 #endif // HAVE_GL
587                 }
588
589
590
591
592
593
594 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
595 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
596 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
597
598         tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
599         ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
600
601         tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
602         ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
603
604                 CLAMP(ty1, pkg->y1, pkg->y2);
605                 CLAMP(ty2, pkg->y1, pkg->y2);
606                 CLAMP(tx1, server->out_x, server->out_x + server->out_w);
607                 CLAMP(tx2, server->out_x, server->out_x + server->out_w);
608
609
610                 xinc = m.values[0][0];
611                 yinc = m.values[1][0];
612                 winc = m.values[2][0];
613
614 //printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
615 //printf("AffineUnit::process_package %d %d %d %d %d\n",
616 //__LINE__,
617 //min_in_x,
618 //max_in_x,
619 //min_in_y,
620 //max_in_y);
621
622 #define CUBIC_ROW(in_row, chroma_offset) \
623         transform_cubic(dx, \
624                 in_row[col1_offset] - chroma_offset, \
625                 in_row[col2_offset] - chroma_offset, \
626                 in_row[col3_offset] - chroma_offset, \
627                 in_row[col4_offset] - chroma_offset)
628
629
630 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
631 { \
632         type **in_rows = (type**)server->input->get_rows(); \
633         float round_factor = 0.0; \
634         if(sizeof(type) < 4) round_factor = 0.5; \
635         for(int y = ty1; y < ty2; y++) \
636         { \
637                 type *out_row = (type*)server->output->get_rows()[y]; \
638  \
639                 if(!interpolate) \
640                 { \
641                 tx = xinc * (tx1 + 0.5) + \
642                                 m.values[0][1] * (y + pivot_offset_y + 0.5) + \
643                                 m.values[0][2] + \
644                                 pivot_offset_x * xinc; \
645                 ty = yinc * (tx1 + 0.5) + \
646                                 m.values[1][1] * (y + pivot_offset_y + 0.5) + \
647                                 m.values[1][2] + \
648                                 pivot_offset_x * yinc; \
649                 tw = winc * (tx1 + 0.5) + \
650                                 m.values[2][1] * (y + pivot_offset_y + 0.5) + \
651                                 m.values[2][2] + \
652                                 pivot_offset_x * winc; \
653                 } \
654         else \
655         { \
656                 tx = xinc * tx1 + \
657                                 m.values[0][1] * (y + pivot_offset_y) + \
658                                 m.values[0][2] + \
659                                 pivot_offset_x * xinc; \
660                 ty = yinc * tx1 + \
661                                 m.values[1][1] * (y + pivot_offset_y) + \
662                                 m.values[1][2] + \
663                                 pivot_offset_x * yinc; \
664                 tw = winc * tx1 + \
665                                 m.values[2][1] * (y + pivot_offset_y) + \
666                                 m.values[2][2] + \
667                                 pivot_offset_x * winc; \
668         } \
669  \
670  \
671                 out_row += tx1 * components; \
672                 for(int x = tx1; x < tx2; x++) \
673                 { \
674 /* Normalize homogeneous coords */ \
675                         if(tw == 0.0) \
676                         { \
677                                 ttx = 0.0; \
678                                 tty = 0.0; \
679                         } \
680                         else \
681                         if(tw != 1.0) \
682                         { \
683                                 ttx = tx / tw; \
684                                 tty = ty / tw; \
685                         } \
686                         else \
687                         { \
688                                 ttx = tx; \
689                                 tty = ty; \
690                         } \
691                         itx = (int)ttx; \
692                         ity = (int)tty; \
693  \
694                         int row1 = ity - 1; \
695                         int row2 = ity; \
696                         int row3 = ity + 1; \
697                         int row4 = ity + 2; \
698                         CLAMP(row1, min_in_y, max_in_y); \
699                         CLAMP(row2, min_in_y, max_in_y); \
700                         CLAMP(row3, min_in_y, max_in_y); \
701                         CLAMP(row4, min_in_y, max_in_y); \
702  \
703 /* Set destination pixels if in clipping region */ \
704                         if(!interpolate && \
705                                 x >= min_out_x && \
706                                 x < max_out_x) \
707                         { \
708                                 if(itx >= min_in_x && \
709                                         itx <= max_in_x && \
710                                         ity >= min_in_y && \
711                                         ity <= max_in_y) \
712                                 { \
713                                         type *src = in_rows[ity] + itx * components; \
714                                         *out_row++ = *src++; \
715                                         *out_row++ = *src++; \
716                                         *out_row++ = *src++; \
717                                         if(components == 4) *out_row++ = *src; \
718                                 } \
719                                 else \
720 /* Fill with chroma */ \
721                                 { \
722                                         *out_row++ = 0; \
723                                         *out_row++ = chroma_offset; \
724                                         *out_row++ = chroma_offset; \
725                                         if(components == 4) *out_row++ = 0; \
726                                 } \
727                         } \
728                         else \
729 /* Bicubic algorithm */ \
730                         if(interpolate &&  \
731                                 x >= min_out_x &&  \
732                                 x < max_out_x) \
733                         { \
734 /* clipping region */ \
735                                 if ((itx + 2) >= min_in_x && \
736                                         (itx - 1) <= max_in_x && \
737                         (ity + 2) >= min_in_y && \
738                                         (ity - 1) <= max_in_y) \
739                 { \
740                         float dx, dy; \
741  \
742 /* the fractional error */ \
743                         dx = ttx - itx; \
744                         dy = tty - ity; \
745  \
746 /* Row and column offsets in cubic block */ \
747                                         int col1 = itx - 1; \
748                                         int col2 = itx; \
749                                         int col3 = itx + 1; \
750                                         int col4 = itx + 2; \
751                                         CLAMP(col1, min_in_x, max_in_x); \
752                                         CLAMP(col2, min_in_x, max_in_x); \
753                                         CLAMP(col3, min_in_x, max_in_x); \
754                                         CLAMP(col4, min_in_x, max_in_x); \
755                                         int col1_offset = col1 * components; \
756                                         int col2_offset = col2 * components; \
757                                         int col3_offset = col3 * components; \
758                                         int col4_offset = col4 * components; \
759  \
760                                         type *row1_ptr = in_rows[row1]; \
761                                         type *row2_ptr = in_rows[row2]; \
762                                         type *row3_ptr = in_rows[row3]; \
763                                         type *row4_ptr = in_rows[row4]; \
764                                         temp_type r, g, b, a; \
765  \
766                                         r = (temp_type)(transform_cubic(dy, \
767                         CUBIC_ROW(row1_ptr, 0x0), \
768                         CUBIC_ROW(row2_ptr, 0x0), \
769                         CUBIC_ROW(row3_ptr, 0x0), \
770                         CUBIC_ROW(row4_ptr, 0x0)) + \
771                                                 round_factor); \
772  \
773                                         row1_ptr++; \
774                                         row2_ptr++; \
775                                         row3_ptr++; \
776                                         row4_ptr++; \
777                                         g = (temp_type)(transform_cubic(dy, \
778                         CUBIC_ROW(row1_ptr, chroma_offset), \
779                         CUBIC_ROW(row2_ptr, chroma_offset), \
780                         CUBIC_ROW(row3_ptr, chroma_offset), \
781                         CUBIC_ROW(row4_ptr, chroma_offset)) + \
782                                                 round_factor); \
783                                         g += chroma_offset; \
784  \
785                                         row1_ptr++; \
786                                         row2_ptr++; \
787                                         row3_ptr++; \
788                                         row4_ptr++; \
789                                         b = (temp_type)(transform_cubic(dy, \
790                         CUBIC_ROW(row1_ptr, chroma_offset), \
791                         CUBIC_ROW(row2_ptr, chroma_offset), \
792                         CUBIC_ROW(row3_ptr, chroma_offset), \
793                         CUBIC_ROW(row4_ptr, chroma_offset)) + \
794                                                 round_factor); \
795                                         b += chroma_offset; \
796  \
797                                         if(components == 4) \
798                                         { \
799                                                 row1_ptr++; \
800                                                 row2_ptr++; \
801                                                 row3_ptr++; \
802                                                 row4_ptr++; \
803                                                 a = (temp_type)(transform_cubic(dy, \
804                                 CUBIC_ROW(row1_ptr, 0x0), \
805                                 CUBIC_ROW(row2_ptr, 0x0), \
806                                 CUBIC_ROW(row3_ptr, 0x0), \
807                                 CUBIC_ROW(row4_ptr, 0x0)) +  \
808                                                         round_factor); \
809                                         } \
810  \
811                                         if(sizeof(type) < 4) \
812                                         { \
813                                                 *out_row++ = CLIP(r, 0, max); \
814                                                 *out_row++ = CLIP(g, 0, max); \
815                                                 *out_row++ = CLIP(b, 0, max); \
816                                                 if(components == 4) *out_row++ = CLIP(a, 0, max); \
817                                         } \
818                                         else \
819                                         { \
820                                                 *out_row++ = r; \
821                                                 *out_row++ = g; \
822                                                 *out_row++ = b; \
823                                                 if(components == 4) *out_row++ = a; \
824                                         } \
825                 } \
826                                 else \
827 /* Fill with chroma */ \
828                                 { \
829                                         *out_row++ = 0; \
830                                         *out_row++ = chroma_offset; \
831                                         *out_row++ = chroma_offset; \
832                                         if(components == 4) *out_row++ = 0; \
833                                 } \
834                         } \
835                         else \
836                         { \
837                                 out_row += components; \
838                         } \
839  \
840 /*  increment the transformed coordinates  */ \
841                         tx += xinc; \
842                         ty += yinc; \
843                         tw += winc; \
844                 } \
845         } \
846 }
847
848
849
850
851 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
852 // __LINE__, tx1, ty1, tx2, ty2);
853                 switch(server->input->get_color_model())
854                 {
855                         case BC_RGB_FLOAT:
856                                 TRANSFORM(3, float, float, 0x0, 1.0)
857                                 break;
858                         case BC_RGB888:
859                                 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
860                                 break;
861                         case BC_RGBA_FLOAT:
862                                 TRANSFORM(4, float, float, 0x0, 1.0)
863                                 break;
864                         case BC_RGBA8888:
865                                 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
866                                 break;
867                         case BC_YUV888:
868 // DEBUG
869 //                              TRANSFORM(3, unsigned char, int, 0x80, 0xff)
870 {
871
872         unsigned char **in_rows = (unsigned char**)server->input->get_rows();
873         float round_factor = 0.0;
874         if(sizeof(unsigned char) < 4) round_factor = 0.5;
875
876         for(int y = ty1; y < ty2; y++)
877         {
878 //printf("AffineUnit::process_package %d y=%d tx1=%d tx2=%d ty1=%d ty2=%d\n", 
879 //__LINE__, y, tx1, tx2, ty1, ty2);
880                 unsigned char *out_row = (unsigned char*)server->output->get_rows()[y];
881
882                 if(!interpolate)
883                 {
884                 tx = xinc * (tx1 + 0.5) +
885                                 m.values[0][1] * (y + pivot_offset_y + 0.5) +
886                                 m.values[0][2] +
887                                 pivot_offset_x * xinc;
888                 ty = yinc * (tx1 + 0.5) +
889                                 m.values[1][1] * (y + pivot_offset_y + 0.5) +
890                                 m.values[1][2] +
891                                 pivot_offset_x * yinc;
892                 tw = winc * (tx1 + 0.5) +
893                                 m.values[2][1] * (y + pivot_offset_y + 0.5) +
894                                 m.values[2][2] +
895                                 pivot_offset_x * winc;
896                 }
897         else
898         {
899                 tx = xinc * tx1 +
900                                 m.values[0][1] * (y + pivot_offset_y) +
901                                 m.values[0][2] +
902                                 pivot_offset_x * xinc;
903                 ty = yinc * tx1 +
904                                 m.values[1][1] * (y + pivot_offset_y) +
905                                 m.values[1][2] +
906                                 pivot_offset_x * yinc;
907                 tw = winc * tx1 +
908                                 m.values[2][1] * (y + pivot_offset_y) +
909                                 m.values[2][2] +
910                                 pivot_offset_x * winc;
911         }
912
913
914                 out_row += tx1 * 3;
915                 for(int x = tx1; x < tx2; x++)
916                 {
917 /* Normalize homogeneous coords */
918                         if(tw == 0.0)
919                         {
920                                 ttx = 0.0;
921                                 tty = 0.0;
922                         }
923                         else
924                         if(tw != 1.0)
925                         {
926                                 ttx = tx / tw;
927                                 tty = ty / tw;
928                         }
929                         else
930                         {
931                                 ttx = tx;
932                                 tty = ty;
933                         }
934                         itx = (int)ttx;
935                         ity = (int)tty;
936
937                         int row1 = ity - 1;
938                         int row2 = ity;
939                         int row3 = ity + 1;
940                         int row4 = ity + 2;
941                         CLAMP(row1, min_in_y, max_in_y);
942                         CLAMP(row2, min_in_y, max_in_y);
943                         CLAMP(row3, min_in_y, max_in_y);
944                         CLAMP(row4, min_in_y, max_in_y);
945
946 /* Set destination pixels if in clipping region */
947                         if(!interpolate &&
948                                 x >= min_out_x &&
949                                 x < max_out_x)
950                         {
951                                 if(itx >= min_in_x &&
952                                         itx <= max_in_x &&
953                                         ity >= min_in_y &&
954                                         ity <= max_in_y)
955                                 {
956                                         unsigned char *src = in_rows[ity] + itx * 3;
957                                         *out_row++ = *src++;
958                                         *out_row++ = *src++;
959                                         *out_row++ = *src++;
960                                         if(3 == 4) *out_row++ = *src;
961                                 }
962                                 else
963 /* Fill with chroma */
964                                 {
965                                         *out_row++ = 0;
966                                         *out_row++ = 0x80;
967                                         *out_row++ = 0x80;
968                                         if(3 == 4) *out_row++ = 0;
969                                 }
970                         }
971                         else
972 /* Bicubic algorithm */
973                         if(interpolate &&
974                                 x >= min_out_x &&
975                                 x < max_out_x)
976                         {
977 /* clipping region */
978                                 if ((itx + 2) >= min_in_x &&
979                                         (itx - 1) <= max_in_x &&
980                         (ity + 2) >= min_in_y &&
981                                         (ity - 1) <= max_in_y)
982                 {
983                         float dx, dy;
984
985 /* the fractional error */
986                         dx = ttx - itx;
987                         dy = tty - ity;
988
989 /* Row and column offsets in cubic block */
990                                         int col1 = itx - 1;
991                                         int col2 = itx;
992                                         int col3 = itx + 1;
993                                         int col4 = itx + 2;
994                                         CLAMP(col1, min_in_x, max_in_x);
995                                         CLAMP(col2, min_in_x, max_in_x);
996                                         CLAMP(col3, min_in_x, max_in_x);
997                                         CLAMP(col4, min_in_x, max_in_x);
998                                         int col1_offset = col1 * 3;
999                                         int col2_offset = col2 * 3;
1000                                         int col3_offset = col3 * 3;
1001                                         int col4_offset = col4 * 3;
1002
1003                                         unsigned char *row1_ptr = in_rows[row1];
1004                                         unsigned char *row2_ptr = in_rows[row2];
1005                                         unsigned char *row3_ptr = in_rows[row3];
1006                                         unsigned char *row4_ptr = in_rows[row4];
1007                                         int r, g, b, a;
1008
1009                                         r = (int)(transform_cubic(dy,
1010                         CUBIC_ROW(row1_ptr, 0x0),
1011                         CUBIC_ROW(row2_ptr, 0x0),
1012                         CUBIC_ROW(row3_ptr, 0x0),
1013                         CUBIC_ROW(row4_ptr, 0x0)) +
1014                                                 round_factor);
1015
1016                                         row1_ptr++;
1017                                         row2_ptr++;
1018                                         row3_ptr++;
1019                                         row4_ptr++;
1020                                         g = (int)(transform_cubic(dy,
1021                         CUBIC_ROW(row1_ptr, 0x80),
1022                         CUBIC_ROW(row2_ptr, 0x80),
1023                         CUBIC_ROW(row3_ptr, 0x80),
1024                         CUBIC_ROW(row4_ptr, 0x80)) +
1025                                                 round_factor);
1026                                         g += 0x80;
1027
1028                                         row1_ptr++;
1029                                         row2_ptr++;
1030                                         row3_ptr++;
1031                                         row4_ptr++;
1032                                         b = (int)(transform_cubic(dy,
1033                         CUBIC_ROW(row1_ptr, 0x80),
1034                         CUBIC_ROW(row2_ptr, 0x80),
1035                         CUBIC_ROW(row3_ptr, 0x80),
1036                         CUBIC_ROW(row4_ptr, 0x80)) +
1037                                                 round_factor);
1038                                         b += 0x80;
1039
1040                                         if(3 == 4)
1041                                         {
1042                                                 row1_ptr++;
1043                                                 row2_ptr++;
1044                                                 row3_ptr++;
1045                                                 row4_ptr++;
1046                                                 a = (int)(transform_cubic(dy,
1047                                 CUBIC_ROW(row1_ptr, 0x0),
1048                                 CUBIC_ROW(row2_ptr, 0x0),
1049                                 CUBIC_ROW(row3_ptr, 0x0),
1050                                 CUBIC_ROW(row4_ptr, 0x0)) +
1051                                                         round_factor);
1052                                         }
1053
1054                                         if(sizeof(unsigned char) < 4)
1055                                         {
1056                                                 *out_row++ = CLIP(r, 0, 0xff);
1057                                                 *out_row++ = CLIP(g, 0, 0xff);
1058                                                 *out_row++ = CLIP(b, 0, 0xff);
1059                                                 if(3 == 4) *out_row++ = CLIP(a, 0, 0xff);
1060                                         }
1061                                         else
1062                                         {
1063                                                 *out_row++ = r;
1064                                                 *out_row++ = g;
1065                                                 *out_row++ = b;
1066                                                 if(3 == 4) *out_row++ = a;
1067                                         }
1068                 }
1069                                 else
1070 /* Fill with chroma */
1071                                 {
1072                                         *out_row++ = 0;
1073                                         *out_row++ = 0x80;
1074                                         *out_row++ = 0x80;
1075                                         if(3 == 4) *out_row++ = 0;
1076                                 }
1077                         }
1078                         else
1079                         {
1080                                 out_row += 3;
1081                         }
1082
1083 /*  increment the transformed coordinates  */
1084                         tx += xinc;
1085                         ty += yinc;
1086                         tw += winc;
1087                 }
1088         }
1089 }
1090
1091                                 break;
1092                         case BC_YUVA8888:
1093                                 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
1094                                 break;
1095                         case BC_RGB161616:
1096                                 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
1097                                 break;
1098                         case BC_RGBA16161616:
1099                                 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
1100                                 break;
1101                         case BC_YUV161616:
1102                                 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
1103                                 break;
1104                         case BC_YUVA16161616:
1105                                 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
1106                                 break;
1107                 }
1108
1109         }
1110         else
1111         {
1112                 int min_x = server->in_x * AFFINE_OVERSAMPLE;
1113                 int min_y = server->in_y * AFFINE_OVERSAMPLE;
1114                 int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
1115                 int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
1116                 float top_w = out_x2 - out_x1;
1117                 float bottom_w = out_x3 - out_x4;
1118                 float left_h = out_y4 - out_y1;
1119                 float right_h = out_y3 - out_y2;
1120                 float out_w_diff = bottom_w - top_w;
1121                 float out_left_diff = out_x4 - out_x1;
1122                 float out_h_diff = right_h - left_h;
1123                 float out_top_diff = out_y2 - out_y1;
1124                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1125                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1126                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1127                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1128                 float max_v = MAX(distance1, distance3);
1129                 float max_h = MAX(distance2, distance4);
1130                 float max_dimension = MAX(max_v, max_h);
1131                 float min_dimension = MIN(server->in_h, server->in_w);
1132                 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
1133                 float x_f = server->in_x;
1134                 float y_f = server->in_y;
1135                 float h_f = server->in_h;
1136                 float w_f = server->in_w;
1137
1138
1139
1140                 if(server->use_opengl)
1141                 {
1142                         return;
1143                 }
1144
1145
1146
1147 // Projection
1148 #define DO_STRETCH(type, components) \
1149 { \
1150         type **in_rows = (type**)server->input->get_rows(); \
1151         type **out_rows = (type**)server->temp->get_rows(); \
1152  \
1153         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1154         { \
1155                 int i = (int)in_y; \
1156                 type *in_row = in_rows[i]; \
1157                 for(float in_x = x_f; in_x < w_f; in_x += step) \
1158                 { \
1159                         int j = (int)in_x; \
1160                         float in_x_fraction = (in_x - x_f) / w_f; \
1161                         float in_y_fraction = (in_y - y_f) / h_f; \
1162                         int out_x = (int)((out_x1 + \
1163                                 out_left_diff * in_y_fraction + \
1164                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
1165                                 AFFINE_OVERSAMPLE); \
1166                         int out_y = (int)((out_y1 +  \
1167                                 out_top_diff * in_x_fraction + \
1168                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1169                                 AFFINE_OVERSAMPLE); \
1170                         CLAMP(out_x, min_x, max_x); \
1171                         CLAMP(out_y, min_y, max_y); \
1172                         type *dst = out_rows[out_y] + out_x * components; \
1173                         type *src = in_row + j * components; \
1174                         dst[0] = src[0]; \
1175                         dst[1] = src[1]; \
1176                         dst[2] = src[2]; \
1177                         if(components == 4) dst[3] = src[3]; \
1178                 } \
1179         } \
1180 }
1181
1182                 switch(server->input->get_color_model())
1183                 {
1184                         case BC_RGB_FLOAT:
1185                                 DO_STRETCH(float, 3)
1186                                 break;
1187                         case BC_RGB888:
1188                                 DO_STRETCH(unsigned char, 3)
1189                                 break;
1190                         case BC_RGBA_FLOAT:
1191                                 DO_STRETCH(float, 4)
1192                                 break;
1193                         case BC_RGBA8888:
1194                                 DO_STRETCH(unsigned char, 4)
1195                                 break;
1196                         case BC_YUV888:
1197                                 DO_STRETCH(unsigned char, 3)
1198                                 break;
1199                         case BC_YUVA8888:
1200                                 DO_STRETCH(unsigned char, 4)
1201                                 break;
1202                         case BC_RGB161616:
1203                                 DO_STRETCH(uint16_t, 3)
1204                                 break;
1205                         case BC_RGBA16161616:
1206                                 DO_STRETCH(uint16_t, 4)
1207                                 break;
1208                         case BC_YUV161616:
1209                                 DO_STRETCH(uint16_t, 3)
1210                                 break;
1211                         case BC_YUVA16161616:
1212                                 DO_STRETCH(uint16_t, 4)
1213                                 break;
1214                 }
1215         }
1216
1217
1218
1219
1220 }
1221
1222
1223
1224
1225
1226
1227 AffineEngine::AffineEngine(int total_clients,
1228         int total_packages)
1229  : LoadServer(
1230 //1, 1
1231 total_clients, total_packages
1232 )
1233 {
1234         user_in_viewport = 0;
1235         user_in_pivot = 0;
1236         user_out_viewport = 0;
1237         user_out_pivot = 0;
1238         use_opengl = 0;
1239         in_x = in_y = in_w = in_h = 0;
1240         out_x = out_y = out_w = out_h = 0;
1241         in_pivot_x = in_pivot_y = 0;
1242         out_pivot_x = out_pivot_y = 0;
1243         this->total_packages = total_packages;
1244 }
1245
1246 void AffineEngine::init_packages()
1247 {
1248         for(int i = 0; i < get_total_packages(); i++)
1249         {
1250                 AffinePackage *package = (AffinePackage*)get_package(i);
1251                 package->y1 = out_y + (out_h * i / get_total_packages());
1252                 package->y2 = out_y + (out_h * (i + 1) / get_total_packages());
1253         }
1254 }
1255
1256 LoadClient* AffineEngine::new_client()
1257 {
1258         return new AffineUnit(this);
1259 }
1260
1261 LoadPackage* AffineEngine::new_package()
1262 {
1263         return new AffinePackage;
1264 }
1265
1266 void AffineEngine::process(VFrame *output,
1267         VFrame *input,
1268         VFrame *temp,
1269         int mode,
1270         float x1,
1271         float y1,
1272         float x2,
1273         float y2,
1274         float x3,
1275         float y3,
1276         float x4,
1277         float y4,
1278         int forward)
1279 {
1280
1281
1282 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
1283 // __LINE__,
1284 // x1,
1285 // y1,
1286 // x2,
1287 // y2,
1288 // x3,
1289 // y3,
1290 // x4,
1291 // y4);
1292 //
1293 // printf("AffineEngine::process %d %d %d %d %d\n",
1294 // __LINE__,
1295 // in_x, in_y, in_w, in_h);
1296 //
1297 // printf("AffineEngine::process %d %d %d %d %d\n",
1298 // __LINE__,
1299 // out_x, out_y, out_w, out_h);
1300 //
1301 // printf("AffineEngine::process %d %d %d %d %d\n",
1302 // __LINE__,
1303 // in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
1304 //
1305 // printf("AffineEngine::process %d %d %d %d %d\n",
1306 // __LINE__,
1307 // user_in_pivot,
1308 // user_out_pivot,
1309 // user_in_viewport,
1310 // user_out_viewport);
1311
1312         this->output = output;
1313         this->input = input;
1314         this->temp = temp;
1315         this->mode = mode;
1316         this->x1 = x1;
1317         this->y1 = y1;
1318         this->x2 = x2;
1319         this->y2 = y2;
1320         this->x3 = x3;
1321         this->y3 = y3;
1322         this->x4 = x4;
1323         this->y4 = y4;
1324         this->forward = forward;
1325
1326
1327         if(!user_in_viewport)
1328         {
1329                 in_x = 0;
1330                 in_y = 0;
1331                 in_w = input->get_w();
1332                 in_h = input->get_h();
1333         }
1334
1335         if(!user_out_viewport)
1336         {
1337                 out_x = 0;
1338                 out_y = 0;
1339                 out_w = output->get_w();
1340                 out_h = output->get_h();
1341         }
1342
1343         if(use_opengl)
1344         {
1345                 set_package_count(1);
1346                 process_single();
1347         }
1348         else
1349         {
1350                 set_package_count(total_packages);
1351                 process_packages();
1352         }
1353 }
1354
1355
1356
1357
1358 void AffineEngine::rotate(VFrame *output,
1359         VFrame *input,
1360         float angle)
1361 {
1362         this->output = output;
1363         this->input = input;
1364         this->temp = 0;
1365         this->mode = ROTATE;
1366         this->forward = 1;
1367
1368         if(!user_in_viewport)
1369         {
1370                 in_x = 0;
1371                 in_y = 0;
1372                 in_w = input->get_w();
1373                 in_h = input->get_h();
1374 // DEBUG
1375 // in_x = 4;
1376 // in_w = 2992;
1377 // in_y = 4;
1378 // in_h = 2992;
1379 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
1380         }
1381
1382         if(!user_in_pivot)
1383         {
1384                 in_pivot_x = in_x + in_w / 2;
1385                 in_pivot_y = in_y + in_h / 2;
1386         }
1387
1388         if(!user_out_viewport)
1389         {
1390                 out_x = 0;
1391                 out_y = 0;
1392                 out_w = output->get_w();
1393                 out_h = output->get_h();
1394         }
1395
1396         if(!user_out_pivot)
1397         {
1398                 out_pivot_x = out_x + out_w / 2;
1399                 out_pivot_y = out_y + out_h / 2;
1400         }
1401
1402 // All subscripts are clockwise around the quadrangle
1403         angle = angle * 2 * M_PI / 360;
1404         double angle1 = atan((double)(in_pivot_y - in_y) / (double)(in_pivot_x - in_x)) + angle;
1405         double angle2 = atan((double)(in_x + in_w - in_pivot_x) / (double)(in_pivot_y - in_y)) + angle;
1406         double angle3 = atan((double)(in_y + in_h - in_pivot_y) / (double)(in_x + in_w - in_pivot_x)) + angle;
1407         double angle4 = atan((double)(in_pivot_x - in_x) / (double)(in_y + in_h - in_pivot_y)) + angle;
1408         double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
1409         double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
1410         double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
1411         double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
1412
1413         x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
1414         y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
1415         x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
1416         y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
1417         x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
1418         y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
1419         x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
1420         y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
1421
1422 // printf("AffineEngine::rotate angle=%f\n",
1423 // angle);
1424
1425 //
1426 // printf("     angle1=%f angle2=%f angle3=%f angle4=%f\n",
1427 // angle1 * 360 / 2 / M_PI,
1428 // angle2 * 360 / 2 / M_PI,
1429 // angle3 * 360 / 2 / M_PI,
1430 // angle4 * 360 / 2 / M_PI);
1431 //
1432 // printf("     radius1=%f radius2=%f radius3=%f radius4=%f\n",
1433 // radius1,
1434 // radius2,
1435 // radius3,
1436 // radius4);
1437 //
1438 // printf("     x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
1439 // x1 * w / 100,
1440 // y1 * h / 100,
1441 // x2 * w / 100,
1442 // y2 * h / 100,
1443 // x3 * w / 100,
1444 // y3 * h / 100,
1445 // x4 * w / 100,
1446 // y4 * h / 100);
1447
1448         if(use_opengl)
1449         {
1450                 set_package_count(1);
1451                 process_single();
1452         }
1453         else
1454         {
1455                 set_package_count(total_packages);
1456                 process_packages();
1457         }
1458 }
1459
1460 void AffineEngine::set_matrix(AffineMatrix *matrix)
1461 {
1462         for(int i = 0; i < 3; i++)
1463         {
1464                 for(int j = 0; j < 3; j++)
1465                 {
1466                         this->matrix.values[i][j] = matrix->values[i][j];
1467                 }
1468         }
1469 }
1470
1471 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
1472 {
1473         this->in_x = x;
1474         this->in_y = y;
1475         this->in_w = w;
1476         this->in_h = h;
1477         this->user_in_viewport = 1;
1478 }
1479
1480 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
1481 {
1482         this->out_x = x;
1483         this->out_y = y;
1484         this->out_w = w;
1485         this->out_h = h;
1486         this->user_out_viewport = 1;
1487 }
1488
1489 void AffineEngine::set_viewport(int x, int y, int w, int h)
1490 {
1491         set_in_viewport(x, y, w, h);
1492         set_out_viewport(x, y, w, h);
1493 }
1494
1495 void AffineEngine::set_opengl(int value)
1496 {
1497         this->use_opengl = value;
1498 }
1499
1500 void AffineEngine::set_in_pivot(int x, int y)
1501 {
1502         this->in_pivot_x = x;
1503         this->in_pivot_y = y;
1504         this->user_in_pivot = 1;
1505 }
1506
1507 void AffineEngine::set_out_pivot(int x, int y)
1508 {
1509         this->out_pivot_x = x;
1510         this->out_pivot_y = y;
1511         this->user_out_pivot = 1;
1512 }
1513
1514 void AffineEngine::set_pivot(int x, int y)
1515 {
1516         set_in_pivot(x, y);
1517         set_out_pivot(x, y);
1518 }
1519
1520 void AffineEngine::unset_pivot()
1521 {
1522         user_in_pivot = 0;
1523         user_out_pivot = 0;
1524 }
1525
1526 void AffineEngine::unset_viewport()
1527 {
1528         user_in_viewport = 0;
1529         user_out_viewport = 0;
1530 }
1531
1532