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