affine + perspective plugin rework, info popup tweaks
[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         AffineMatrix tmp;
77
78         for( int i=0; i<3; ++i ) {
79                 double t1 = values[i][0], t2 = values[i][1], t3 = values[i][2];
80                 for( int j=0; j<3; ++j ) {
81                         tmp.values[i][j]  = t1 * dst->values[0][j];
82                         tmp.values[i][j] += t2 * dst->values[1][j];
83                         tmp.values[i][j] += t3 * dst->values[2][j];
84                 }
85         }
86         dst->copy_from(&tmp);
87 }
88
89 double AffineMatrix::determinant()
90 {
91         double determinant;
92
93         determinant  =
94                 values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
95         determinant -=
96                 values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
97         determinant +=
98                 values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
99
100         return determinant;
101 }
102
103 void AffineMatrix::invert(AffineMatrix *dst)
104 {
105         double det_1;
106
107         det_1 = determinant();
108
109         if(det_1 == 0.0)
110         return;
111
112         det_1 = 1.0 / det_1;
113
114         dst->values[0][0] =
115                 (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
116
117         dst->values[1][0] =
118                 - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
119
120         dst->values[2][0] =
121                 (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
122
123         dst->values[0][1] =
124                 - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
125
126         dst->values[1][1] =
127                 (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
128
129         dst->values[2][1] =
130                 - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
131
132         dst->values[0][2] =
133                 (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
134
135         dst->values[1][2] =
136                 - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
137
138         dst->values[2][2] =
139                 (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
140 }
141
142 void AffineMatrix::copy_from(AffineMatrix *src)
143 {
144         memcpy(&values[0][0], &src->values[0][0], sizeof(values));
145 }
146
147 void AffineMatrix::transform_point(float x,
148         float y,
149         float *newx,
150         float *newy)
151 {
152         double w;
153
154         w = values[2][0] * x + values[2][1] * y + values[2][2];
155         w = !w ? 1 : 1/w;
156
157         *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
158         *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
159 }
160
161 void AffineMatrix::dump()
162 {
163         printf("AffineMatrix::dump\n");
164         printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
165         printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
166         printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
167 }
168
169
170
171
172
173 AffinePackage::AffinePackage()
174  : LoadPackage()
175 {
176 }
177
178
179
180
181 AffineUnit::AffineUnit(AffineEngine *server)
182  : LoadClient(server)
183 {
184         this->server = server;
185 }
186
187
188
189
190
191
192
193
194
195 void AffineUnit::calculate_matrix(
196         double in_x1, double in_y1, double in_x2, double in_y2,
197         double out_x1, double out_y1, double out_x2, double out_y2,
198         double out_x3, double out_y3, double out_x4, double out_y4,
199         AffineMatrix *result)
200 {
201         AffineMatrix matrix;
202         double scalex;
203         double scaley;
204
205         scalex = scaley = 1.0;
206
207         if( (in_x2 - in_x1) > 0 )
208                 scalex = 1.0 / (double)(in_x2 - in_x1);
209
210         if( (in_y2 - in_y1) > 0 )
211                 scaley = 1.0 / (double)(in_y2 - in_y1);
212
213 /* Determine the perspective transform that maps from
214  * the unit cube to the transformed coordinates
215  */
216         double dx1, dx2, dx3, dy1, dy2, dy3;
217         double det1, det2;
218
219         dx1 = out_x2 - out_x4;
220         dx2 = out_x3 - out_x4;
221         dx3 = out_x1 - out_x2 + out_x4 - out_x3;
222
223         dy1 = out_y2 - out_y4;
224         dy2 = out_y3 - out_y4;
225         dy3 = out_y1 - out_y2 + out_y4 - out_y3;
226 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
227 //  dx1, dx2, dx3, dy1, dy2, dy3 );
228
229 /*  Is the mapping affine?  */
230         if((dx3 == 0.0) && (dy3 == 0.0)) {
231                 matrix.values[0][0] = out_x2 - out_x1;
232                 matrix.values[0][1] = out_x4 - out_x2;
233                 matrix.values[0][2] = out_x1;
234                 matrix.values[1][0] = out_y2 - out_y1;
235                 matrix.values[1][1] = out_y4 - out_y2;
236                 matrix.values[1][2] = out_y1;
237                 matrix.values[2][0] = 0.0;
238                 matrix.values[2][1] = 0.0;
239         }
240         else {
241                 det1 = dx3 * dy2 - dy3 * dx2;
242                 det2 = dx1 * dy2 - dy1 * dx2;
243                 matrix.values[2][0] = det1 / det2;
244                 det1 = dx1 * dy3 - dy1 * dx3;
245                 det2 = dx1 * dy2 - dy1 * dx2;
246                 matrix.values[2][1] = det1 / det2;
247
248                 matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
249                 matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
250                 matrix.values[0][2] = out_x1;
251
252                 matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
253                 matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
254                 matrix.values[1][2] = out_y1;
255         }
256
257         matrix.values[2][2] = 1.0;
258
259 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
260 // matrix.dump();
261
262         result->identity();
263         result->translate(-in_x1, -in_y1);
264         result->scale(scalex, scaley);
265         matrix.multiply(result);
266 // double test[3][3] = 
267 // { { 0.0896, 0.0, 0.0 },  { 0.0, 0.0896, 0.0 },  { -0.00126, 0.0, 1.0 } };
268 // memcpy(&result->values[0][0], test, sizeof(test));
269 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
270 // result->dump();
271 }
272
273 static inline float transform_cubic(float dx,
274                 float p0, float p1, float p2, float p3)
275 {
276 /* Catmull-Rom - not bad */
277         float result = ((( (- p0 + 3*p1 - 3*p2 + p3) * dx +
278                          ( 2*p0 - 5*p1 + 4*p2 - p3 ) ) * dx +
279                          ( - p0 + p2 ) ) * dx + (p1 + p1) ) / 2;
280 // printf("%f %f %f %f %f\n", result, p0, p1, p2, p3);
281         return result;
282 }
283
284 static inline float transform_linear(float dx,
285                 float p1, float p2)
286 {
287         float result = p1 * (1-dx) + p2 * dx;
288         return result;
289 }
290
291
292 void AffineUnit::process_package(LoadPackage *package)
293 {
294         AffinePackage *pkg = (AffinePackage*)package;
295         int min_in_x = server->in_x;
296         int min_in_y = server->in_y;
297         int max_in_x = server->in_x + server->in_w - 1;
298         int max_in_y = server->in_y + server->in_h - 1;
299
300
301 // printf("AffineUnit::process_package %d %d %d %d %d\n",
302 // __LINE__,
303 // min_in_x,
304 // min_in_y,
305 // max_in_x,
306 // max_in_y);
307         int min_out_x = server->out_x;
308         //int min_out_y = server->out_y;
309         int max_out_x = server->out_x + server->out_w;
310         //int max_out_y = server->out_y + server->out_h;
311
312 // Amount to shift the input coordinates relative to the output coordinates
313 // To get the pivots to line up
314         int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
315         int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
316
317 // Calculate real coords
318         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
319         if( server->mode == AffineEngine::STRETCH ||
320             server->mode == AffineEngine::PERSPECTIVE ||
321             server->mode == AffineEngine::ROTATE ||
322             server->mode == AffineEngine::TRANSFORM ) {
323                 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
324                 out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
325                 out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
326                 out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
327                 out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
328                 out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
329                 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
330                 out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
331         }
332         else {
333                 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
334                 out_y1 = server->in_y;
335                 out_x2 = out_x1 + server->in_w;
336                 out_y2 = server->in_y;
337                 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
338                 out_y4 = server->in_y + server->in_h;
339                 out_x3 = out_x4 + server->in_w;
340                 out_y3 = server->in_y + server->in_h;
341         }
342
343
344
345 // Rotation with OpenGL uses a simple quad.
346         if( server->mode == AffineEngine::ROTATE &&
347             server->use_opengl ) {
348 #ifdef HAVE_GL
349                 out_x1 -= pivot_offset_x;  out_y1 -= pivot_offset_y;
350                 out_x2 -= pivot_offset_x;  out_y2 -= pivot_offset_y;
351                 out_x3 -= pivot_offset_x;  out_y3 -= pivot_offset_y;
352                 out_x4 -= pivot_offset_x;  out_y4 -= pivot_offset_y;
353
354                 server->output->to_texture();
355                 server->output->enable_opengl();
356                 server->output->init_screen();
357                 server->output->bind_texture(0);
358                 server->output->clear_pbuffer();
359
360                 int texture_w = server->output->get_texture_w();
361                 int texture_h = server->output->get_texture_h();
362                 float output_h = server->output->get_h();
363                 float in_x1 = (float)server->in_x / texture_w;
364                 float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
365                 float in_y1 = (float)server->in_y / texture_h;
366                 float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
367
368 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
369 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
370
371                 glBegin(GL_QUADS);
372                 glNormal3f(0, 0, 1.0);
373
374                 glTexCoord2f(in_x1, in_y1);
375                 glVertex3f(out_x1, -output_h+out_y1, 0);
376
377                 glTexCoord2f(in_x2, in_y1);
378                 glVertex3f(out_x2, -output_h+out_y2, 0);
379
380                 glTexCoord2f(in_x2, in_y2);
381                 glVertex3f(out_x3, -output_h+out_y3, 0);
382
383                 glTexCoord2f(in_x1, in_y2);
384                 glVertex3f(out_x4, -output_h+out_y4, 0);
385
386
387                 glEnd();
388
389                 server->output->set_opengl_state(VFrame::SCREEN);
390 #endif
391         }
392         else
393         if( server->mode == AffineEngine::PERSPECTIVE ||
394             server->mode == AffineEngine::SHEER ||
395             server->mode == AffineEngine::ROTATE ||
396             server->mode == AffineEngine::TRANSFORM ) {
397                 AffineMatrix matrix;
398                 float temp;
399 // swap points 3 & 4
400                 temp = out_x4;
401                 out_x4 = out_x3;
402                 out_x3 = temp;
403                 temp = out_y4;
404                 out_y4 = out_y3;
405                 out_y3 = temp;
406
407
408
409
410
411                 if( server->mode != AffineEngine::TRANSFORM ) {
412                         calculate_matrix( server->in_x, server->in_y,
413                                 server->in_x + server->in_w,
414                                 server->in_y + server->in_h,
415                                 out_x1, out_y1, out_x2, out_y2,
416                                 out_x3, out_y3, out_x4, out_y4,
417                                 &matrix);
418                 }
419                 else {
420                         matrix.copy_from(&server->matrix);
421                 }
422
423 //printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n", __LINE__,
424 // matrix.values[0][0], matrix.values[0][1], matrix.values[0][2],
425 // matrix.values[1][0], matrix.values[1][1], matrix.values[1][2],
426 // matrix.values[2][0], matrix.values[2][1], matrix.values[2][2]);
427                 int reverse = !server->forward;
428                 float tx, ty, tw;
429                 float xinc, yinc, winc;
430                 AffineMatrix m, im;
431                 float ttx = 0, tty = 0;
432                 int itx = 0, ity = 0;
433                 int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
434
435                 if(reverse) {
436                         m.copy_from(&matrix);
437                         m.invert(&im);
438                         matrix.copy_from(&im);
439                 }
440                 else {
441                         matrix.invert(&m);
442                 }
443
444                 float dx1 = 0, dy1 = 0;
445                 float dx2 = 0, dy2 = 0;
446                 float dx3 = 0, dy3 = 0;
447                 float dx4 = 0, dy4 = 0;
448                 matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
449                 matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
450                 matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
451                 matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
452
453 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
454 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
455 // printf("AffineUnit::process_package %d use_opengl=%d\n",
456 // __LINE__, server->use_opengl);
457
458                 if( server->use_opengl &&
459                     server->interpolation == AffineEngine::AF_DEFAULT ) {
460 #ifdef HAVE_GL
461                         static const char *affine_frag =
462                                 "uniform sampler2D tex;\n"
463                                 "uniform mat3 affine_matrix;\n"
464                                 "uniform vec2 texture_extents;\n"
465                                 "uniform vec2 image_extents;\n"
466                                 "uniform vec4 border_color;\n"
467                                 "void main()\n"
468                                 "{\n"
469                                 "       vec2 outcoord = gl_TexCoord[0].st;\n"
470                                 "       outcoord *= texture_extents;\n"
471                                 "       mat3 coord_matrix = mat3(\n"
472                                 "               outcoord.x, outcoord.y, 1.0, \n"
473                                 "               outcoord.x, outcoord.y, 1.0, \n"
474                                 "               outcoord.x, outcoord.y, 1.0);\n"
475                                 "       mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
476                                 "       vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
477                                 "       incoord /= incoord_matrix[0][2];\n"
478                                 "       incoord /= texture_extents;\n"
479                                 "       if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
480                                 "               gl_FragColor = border_color;\n"
481                                 "       else\n"
482                                 "               gl_FragColor = texture2D(tex, incoord);\n"
483                                 "}\n";
484
485                         float affine_matrix[9] = {
486                                 (float)m.values[0][0], (float)m.values[1][0], (float)m.values[2][0],
487                                 (float)m.values[0][1], (float)m.values[1][1], (float)m.values[2][1],
488                                 (float)m.values[0][2], (float)m.values[1][2], (float)m.values[2][2]
489                         };
490
491
492                         server->output->to_texture();
493                         server->output->enable_opengl();
494                         unsigned int frag_shader = VFrame::make_shader(0,
495                                         affine_frag,
496                                         0);
497                         if( frag_shader > 0 ) {
498                                 glUseProgram(frag_shader);
499                                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
500                                 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"),
501                                         1, 0, affine_matrix);
502                                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
503                                         (GLfloat)server->output->get_texture_w(),
504                                         (GLfloat)server->output->get_texture_h());
505                                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
506                                         (GLfloat)server->output->get_w() / server->output->get_texture_w(),
507                                         (GLfloat)server->output->get_h() / server->output->get_texture_h());
508                                 float border_color[] = { 0, 0, 0, 0 };
509                                 if(BC_CModels::is_yuv(server->output->get_color_model())) {
510                                         border_color[1] = 0.5;
511                                         border_color[2] = 0.5;
512                                 }
513                                 if(!BC_CModels::has_alpha(server->output->get_color_model())) {
514                                         border_color[3] = 1.0;
515                                 }
516
517                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
518                                         1, (GLfloat*)border_color);
519                                 server->output->init_screen();
520                                 server->output->bind_texture(0);
521                                 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
522                                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
523                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
524                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
525                                 server->output->draw_texture();
526                                 glUseProgram(0);
527                                 server->output->set_opengl_state(VFrame::SCREEN);
528                         }
529                         return;
530 #endif // HAVE_GL
531                 }
532
533 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
534 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
535 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
536
537         tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
538         ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
539
540         tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
541         ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
542
543         CLAMP(ty1, pkg->y1, pkg->y2);
544         CLAMP(ty2, pkg->y1, pkg->y2);
545         CLAMP(tx1, server->out_x, server->out_x + server->out_w);
546         CLAMP(tx2, server->out_x, server->out_x + server->out_w);
547
548
549         xinc = m.values[0][0];
550         yinc = m.values[1][0];
551         winc = m.values[2][0];
552
553 //printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n",
554 // tx1, ty1, tx2, ty2, out_x4, out_y4);
555 //printf("AffineUnit::process_package %d %d %d %d %d\n",
556 // __LINE__, min_in_x, max_in_x, min_in_y, max_in_y);
557
558 #define CUBIC_ROW(in_row, chroma_offset) ( !in_row ? 0 : transform_cubic(dx, \
559                 cp>=min_in_x && cp<max_in_x ? in_row[cp*comps]-chroma_offset : 0, \
560                 c0>=min_in_x && c0<max_in_x ? in_row[c0*comps]-chroma_offset : 0, \
561                 c1>=min_in_x && c1<max_in_x ? in_row[c1*comps]-chroma_offset : 0, \
562                 c2>=min_in_x && c2<max_in_x ? in_row[c2*comps]-chroma_offset : 0) )
563
564
565 #define DO_CUBIC(tag, components, type, temp_type, chroma_offset, max) \
566 case tag: { \
567     type **inp_rows = (type**)server->input->get_rows(); \
568     type **out_rows = (type**)server->output->get_rows(); \
569     float round_factor = sizeof(type) < 4 ? 0.5 : 0; \
570     int comps = components; \
571     for( int y=ty1; y<ty2; ++y ) { \
572         type *out_row = (type*)out_rows[y]; \
573  \
574         int x1 = tx1, x2 = tx2; \
575         if( x1 < min_out_x ) x1 = min_out_x; \
576         if( x2 > max_out_x ) x2 = max_out_x; \
577         tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
578             + pivot_offset_x * xinc; \
579         ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
580             + pivot_offset_x * yinc; \
581         tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
582             + pivot_offset_x * winc; \
583         type *out = out_row + x1 * comps; \
584         for( int x=x1; x<x2; ++x ) { \
585 /* Normalize homogeneous coords */ \
586             if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
587             else { ttx = tx / tw; tty = ty / tw; } \
588             itx = (int)ttx;  ity = (int)tty; \
589 /* the fractional error */ \
590             float dx = ttx - itx, dy = tty - ity; \
591             if( dx < 0 ) dx += 1; \
592             if( dy < 0 ) dy += 1; \
593 /* row/col index */ \
594             int cp = itx-1, c0 = itx+0, c1 = itx+1, c2 = itx+2; \
595             int rp = ity-1, r0 = ity+0, r1 = ity+1, r2 = ity+2; \
596             type *rpp, *r0p, *r1p, *r2p; \
597             rpp = rp>=min_in_y && rp<max_in_y ? inp_rows[rp] : 0; \
598             r0p = r0>=min_in_y && r0<max_in_y ? inp_rows[r0] : 0; \
599             r1p = r1>=min_in_y && r1<max_in_y ? inp_rows[r1] : 0; \
600             r2p = r2>=min_in_y && r2<max_in_y ? inp_rows[r2] : 0; \
601             temp_type r, g, b, a; \
602             r = (temp_type)(transform_cubic(dy, \
603                 CUBIC_ROW(rpp, 0x0), CUBIC_ROW(r0p, 0x0), \
604                 CUBIC_ROW(r1p, 0x0), CUBIC_ROW(r2p, 0x0)) \
605                 + round_factor); \
606             if(rpp) ++rpp;  if(r0p) ++r0p;  if(r1p) ++r1p;  if(r2p) ++r2p; \
607             g = (temp_type)(transform_cubic(dy, \
608                 CUBIC_ROW(rpp, chroma_offset), CUBIC_ROW(r0p, chroma_offset), \
609                 CUBIC_ROW(r1p, chroma_offset), CUBIC_ROW(r2p, chroma_offset)) \
610                 + round_factor) + chroma_offset; \
611             if(rpp) ++rpp;  if(r0p) ++r0p;  if(r1p) ++r1p;  if(r2p) ++r2p; \
612             b = (temp_type)(transform_cubic(dy, \
613                 CUBIC_ROW(rpp, chroma_offset), CUBIC_ROW(r0p, chroma_offset), \
614                 CUBIC_ROW(r1p, chroma_offset), CUBIC_ROW(r2p, chroma_offset)) \
615                 + round_factor) + chroma_offset; \
616             if( components == 4 ) { \
617                 if(rpp) ++rpp;  if(r0p) ++r0p;  if(r1p) ++r1p;  if(r2p) ++r2p; \
618                 a = (temp_type)(transform_cubic(dy, \
619                     CUBIC_ROW(rpp, 0x0), CUBIC_ROW(r0p, 0x0), \
620                     CUBIC_ROW(r1p, 0x0), CUBIC_ROW(r2p, 0x0)) \
621                     + round_factor); \
622             } \
623             if( sizeof(type) < 4 ) { \
624                 *out++ = CLIP(r, 0, max); \
625                 *out++ = CLIP(g, 0, max); \
626                 *out++ = CLIP(b, 0, max); \
627                 if( components == 4 ) *out++ = CLIP(a, 0, max); \
628             } \
629             else { \
630                 *out++ = r; \
631                 *out++ = g; \
632                 *out++ = b; \
633                 if( components == 4 ) *out++ = a; \
634             } \
635  \
636 /*  increment the transformed coordinates  */ \
637             tx += xinc;  ty += yinc;  tw += winc; \
638         } \
639     } \
640 } break
641
642 #define LINEAR_ROW(in_row, chroma_offset) ( !in_row ? 0 : transform_linear(dx, \
643                 c0>=min_in_x && c0<max_in_x ? in_row[c0*comps]-chroma_offset : 0, \
644                 c1>=min_in_x && c1<max_in_x ? in_row[c1*comps]-chroma_offset : 0) )
645
646 #define DO_LINEAR(tag, components, type, temp_type, chroma_offset, max) \
647 case tag: { \
648     type **inp_rows = (type**)server->input->get_rows(); \
649     type **out_rows = (type**)server->output->get_rows(); \
650     int comps = components; \
651     float round_factor = sizeof(type) < 4 ? 0.5 : 0; \
652     for( int y=ty1; y<ty2; ++y ) { \
653         type *out_row = (type*)out_rows[y]; \
654  \
655         int x1 = tx1, x2 = tx2; \
656         if( x1 < min_out_x ) x1 = min_out_x; \
657         if( x2 > max_out_x ) x2 = max_out_x; \
658         tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
659             + pivot_offset_x * xinc; \
660         ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
661             + pivot_offset_x * yinc; \
662         tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
663             + pivot_offset_x * winc; \
664         type *out = out_row + x1 * comps; \
665         for( int x=x1; x<x2; ++x ) { \
666 /* Normalize homogeneous coords */ \
667             if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
668             else { ttx = tx / tw; tty = ty / tw; } \
669             itx = (int)ttx;  ity = (int)tty; \
670 /* the fractional error */ \
671             float dx = ttx - itx, dy = tty - ity; \
672             if( dx < 0 ) dx += 1; \
673             if( dy < 0 ) dy += 1; \
674 /* row/col index */ \
675             int c0 = itx+0, c1 = itx+1; \
676             int r0 = ity+0, r1 = ity+1; \
677             type *r0p, *r1p; \
678             r0p = r0>=min_in_y && r0<max_in_y ? inp_rows[r0] : 0; \
679             r1p = r1>=min_in_y && r1<max_in_y ? inp_rows[r1] : 0; \
680             temp_type r, g, b, a; \
681             r = (temp_type)(transform_linear(dy, \
682                 LINEAR_ROW(r0p, 0x0), LINEAR_ROW(r1p, 0x0)) \
683                 + round_factor); \
684             if(r0p) ++r0p;  if(r1p) ++r1p; \
685             g = (temp_type)(transform_linear(dy, \
686                 LINEAR_ROW(r0p, chroma_offset), LINEAR_ROW(r1p, chroma_offset)) \
687                 + round_factor) + chroma_offset; \
688             if(r0p) ++r0p;  if(r1p) ++r1p; \
689             b = (temp_type)(transform_linear(dy, \
690                 LINEAR_ROW(r0p, chroma_offset), LINEAR_ROW(r1p, chroma_offset)) \
691                 + round_factor) + chroma_offset; \
692             if( components == 4 ) { \
693                 if(r0p) ++r0p;  if(r1p) ++r1p; \
694                 a = (temp_type)(transform_linear(dy, \
695                     LINEAR_ROW(r0p, 0x0), LINEAR_ROW(r1p, 0x0)) \
696                     + round_factor); \
697             } \
698             if( sizeof(type) < 4 ) { \
699                 *out++ = CLIP(r, 0, max); \
700                 *out++ = CLIP(g, 0, max); \
701                 *out++ = CLIP(b, 0, max); \
702                 if( components == 4 ) *out++ = CLIP(a, 0, max); \
703             } \
704             else { \
705                 *out++ = r; \
706                 *out++ = g; \
707                 *out++ = b; \
708                 if( components == 4 ) *out++ = a; \
709             } \
710  \
711 /*  increment the transformed coordinates  */ \
712             tx += xinc;  ty += yinc;  tw += winc; \
713         } \
714     } \
715 } break
716
717 #define DO_NEAREST(tag, components, type, temp_type, chroma_offset, max) \
718 case tag: { \
719     type **inp_rows = (type**)server->input->get_rows(); \
720     type **out_rows = (type**)server->output->get_rows(); \
721     for( int y=ty1; y<ty2; ++y ) { \
722         type *out_row = (type*)out_rows[y]; \
723  \
724         int x1 = tx1, x2 = tx2; \
725         if( x1 < min_out_x ) x1 = min_out_x; \
726         if( x2 > max_out_x ) x2 = max_out_x; \
727         tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
728             + pivot_offset_x * xinc; \
729         ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
730             + pivot_offset_x * yinc; \
731         tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
732             + pivot_offset_x * winc; \
733         type *out = out_row + x1 * components; \
734         for( int x=x1; x<x2; ++x ) { \
735 /* Normalize homogeneous coords */ \
736             if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
737             else { ttx = tx / tw; tty = ty / tw; } \
738             itx = (int)ttx;  ity = (int)tty; \
739 /* row/col index */ \
740             type *rp = ity>=min_in_y && ity<max_in_y ? inp_rows[ity] : 0; \
741             temp_type r, g, b, a; \
742             r = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
743             if(rp) ++rp; \
744             g = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
745             if(rp) ++rp; \
746             b = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
747             if( components == 4 ) { \
748                 if(rp) ++rp; \
749                 a = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
750             } \
751             *out++ = r;  *out++ = g;  *out++ = b; \
752             if( components == 4 ) *out++ = a; \
753  \
754 /*  increment the transformed coordinates  */ \
755             tx += xinc;  ty += yinc;  tw += winc; \
756         } \
757     } \
758 } break
759
760 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
761 // __LINE__, tx1, ty1, tx2, ty2);
762
763                 switch( server->interpolation ) {
764                 case AffineEngine::AF_NEAREST:
765                         switch( server->input->get_color_model() ) {
766                         DO_NEAREST( BC_RGB_FLOAT, 3, float, float, 0x0, 1.0);
767                         DO_NEAREST( BC_RGB888, 3, unsigned char, int, 0x0, 0xff);
768                         DO_NEAREST( BC_RGBA_FLOAT, 4, float, float, 0x0, 1.0);
769                         DO_NEAREST( BC_RGBA8888, 4, unsigned char, int, 0x0, 0xff);
770                         DO_NEAREST( BC_YUV888, 3, unsigned char, int, 0x80, 0xff);
771                         DO_NEAREST( BC_YUVA8888, 4, unsigned char, int, 0x80, 0xff);
772                         DO_NEAREST( BC_RGB161616, 3, uint16_t, int, 0x0, 0xffff);
773                         DO_NEAREST( BC_RGBA16161616, 4, uint16_t, int, 0x0, 0xffff);
774                         DO_NEAREST( BC_YUV161616, 3, uint16_t, int, 0x8000, 0xffff);
775                         DO_NEAREST( BC_YUVA16161616, 4, uint16_t, int, 0x8000, 0xffff);
776                         }
777                         break;
778                 case AffineEngine::AF_LINEAR:
779                         switch( server->input->get_color_model() ) {
780                         DO_LINEAR( BC_RGB_FLOAT, 3, float, float, 0x0, 1.0);
781                         DO_LINEAR( BC_RGB888, 3, unsigned char, int, 0x0, 0xff);
782                         DO_LINEAR( BC_RGBA_FLOAT, 4, float, float, 0x0, 1.0);
783                         DO_LINEAR( BC_RGBA8888, 4, unsigned char, int, 0x0, 0xff);
784                         DO_LINEAR( BC_YUV888, 3, unsigned char, int, 0x80, 0xff);
785                         DO_LINEAR( BC_YUVA8888, 4, unsigned char, int, 0x80, 0xff);
786                         DO_LINEAR( BC_RGB161616, 3, uint16_t, int, 0x0, 0xffff);
787                         DO_LINEAR( BC_RGBA16161616, 4, uint16_t, int, 0x0, 0xffff);
788                         DO_LINEAR( BC_YUV161616, 3, uint16_t, int, 0x8000, 0xffff);
789                         DO_LINEAR( BC_YUVA16161616, 4, uint16_t, int, 0x8000, 0xffff);
790                         }
791                         break;
792                 default:
793                 case AffineEngine::AF_CUBIC:
794                         switch( server->input->get_color_model() ) {
795                         DO_CUBIC( BC_RGB_FLOAT, 3, float, float, 0x0, 1.0);
796                         DO_CUBIC( BC_RGB888, 3, unsigned char, int, 0x0, 0xff);
797                         DO_CUBIC( BC_RGBA_FLOAT, 4, float, float, 0x0, 1.0);
798                         DO_CUBIC( BC_RGBA8888, 4, unsigned char, int, 0x0, 0xff);
799                         DO_CUBIC( BC_YUV888, 3, unsigned char, int, 0x80, 0xff);
800                         DO_CUBIC( BC_YUVA8888, 4, unsigned char, int, 0x80, 0xff);
801                         DO_CUBIC( BC_RGB161616, 3, uint16_t, int, 0x0, 0xffff);
802                         DO_CUBIC( BC_RGBA16161616, 4, uint16_t, int, 0x0, 0xffff);
803                         DO_CUBIC( BC_YUV161616, 3, uint16_t, int, 0x8000, 0xffff);
804                         DO_CUBIC( BC_YUVA16161616, 4, uint16_t, int, 0x8000, 0xffff);
805                         }
806                         break;
807                 }
808         }
809         else
810         {
811                 int min_x = server->in_x * AFFINE_OVERSAMPLE;
812                 int min_y = server->in_y * AFFINE_OVERSAMPLE;
813                 int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
814                 int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
815                 float top_w = out_x2 - out_x1;
816                 float bottom_w = out_x3 - out_x4;
817                 float left_h = out_y4 - out_y1;
818                 float right_h = out_y3 - out_y2;
819                 float out_w_diff = bottom_w - top_w;
820                 float out_left_diff = out_x4 - out_x1;
821                 float out_h_diff = right_h - left_h;
822                 float out_top_diff = out_y2 - out_y1;
823                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
824                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
825                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
826                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
827                 float max_v = MAX(distance1, distance3);
828                 float max_h = MAX(distance2, distance4);
829                 float max_dimension = MAX(max_v, max_h);
830                 float min_dimension = MIN(server->in_h, server->in_w);
831                 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
832                 float x_f = server->in_x;
833                 float y_f = server->in_y;
834                 float h_f = server->in_h;
835                 float w_f = server->in_w;
836
837                 if(server->use_opengl) {
838                         return;
839                 }
840
841 // Projection
842 #define DO_STRETCH(tag, type, components) \
843 case tag: { \
844         type **in_rows = (type**)server->input->get_rows(); \
845         type **out_rows = (type**)server->temp->get_rows(); \
846  \
847         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
848         { \
849                 int i = (int)in_y; \
850                 type *in_row = in_rows[i]; \
851                 for(float in_x = x_f; in_x < w_f; in_x += step) \
852                 { \
853                         int j = (int)in_x; \
854                         float in_x_fraction = (in_x - x_f) / w_f; \
855                         float in_y_fraction = (in_y - y_f) / h_f; \
856                         int out_x = (int)((out_x1 + \
857                                 out_left_diff * in_y_fraction + \
858                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
859                                 AFFINE_OVERSAMPLE); \
860                         int out_y = (int)((out_y1 +  \
861                                 out_top_diff * in_x_fraction + \
862                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
863                                 AFFINE_OVERSAMPLE); \
864                         CLAMP(out_x, min_x, max_x); \
865                         CLAMP(out_y, min_y, max_y); \
866                         type *dst = out_rows[out_y] + out_x * components; \
867                         type *src = in_row + j * components; \
868                         dst[0] = src[0]; \
869                         dst[1] = src[1]; \
870                         dst[2] = src[2]; \
871                         if(components == 4) dst[3] = src[3]; \
872                 } \
873         } \
874 } break
875
876                 switch( server->input->get_color_model() ) {
877                 DO_STRETCH( BC_RGB_FLOAT, float, 3 );
878                 DO_STRETCH( BC_RGB888, unsigned char, 3 );
879                 DO_STRETCH( BC_RGBA_FLOAT, float, 4 );
880                 DO_STRETCH( BC_RGBA8888, unsigned char, 4 );
881                 DO_STRETCH( BC_YUV888, unsigned char, 3 );
882                 DO_STRETCH( BC_YUVA8888, unsigned char, 4 );
883                 DO_STRETCH( BC_RGB161616, uint16_t, 3 );
884                 DO_STRETCH( BC_RGBA16161616, uint16_t, 4 );
885                 DO_STRETCH( BC_YUV161616, uint16_t, 3 );
886                 DO_STRETCH( BC_YUVA16161616, uint16_t, 4 );
887                 }
888         }
889 }
890
891
892 AffineEngine::AffineEngine(int total_clients, int total_packages)
893  : LoadServer(total_clients, total_packages) //(1, 1)
894 {
895         user_in_viewport = 0;
896         user_in_pivot = 0;
897         user_out_viewport = 0;
898         user_out_pivot = 0;
899         use_opengl = 0;
900         in_x = in_y = in_w = in_h = 0;
901         out_x = out_y = out_w = out_h = 0;
902         in_pivot_x = in_pivot_y = 0;
903         out_pivot_x = out_pivot_y = 0;
904         interpolation = AF_DEFAULT;
905         this->total_packages = total_packages;
906 }
907
908 void AffineEngine::init_packages()
909 {
910         int y1 = 0, npkgs = get_total_packages();
911         for( int i=0; i<npkgs; ) {
912                 AffinePackage *package = (AffinePackage*)get_package(i);
913                 int y2 = out_y + (out_h * ++i / npkgs);
914                 package->y1 = y1;  package->y2 = y2;  y1 = y2;
915         }
916 }
917
918 LoadClient* AffineEngine::new_client()
919 {
920         return new AffineUnit(this);
921 }
922
923 LoadPackage* AffineEngine::new_package()
924 {
925         return new AffinePackage;
926 }
927
928 void AffineEngine::process(VFrame *output, VFrame *input, VFrame *temp, int mode,
929         float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
930         int forward)
931 {
932
933
934 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
935 // __LINE__, x1, y1, x2, y2, x3, y3, x4, y4);
936 //
937 // printf("AffineEngine::process %d %d %d %d %d\n",
938 // __LINE__, in_x, in_y, in_w, in_h);
939 //
940 // printf("AffineEngine::process %d %d %d %d %d\n",
941 // __LINE__, out_x, out_y, out_w, out_h);
942 //
943 // printf("AffineEngine::process %d %d %d %d %d\n",
944 // __LINE__, in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
945 //
946 // printf("AffineEngine::process %d %d %d %d %d\n",
947 // __LINE__, user_in_pivot, user_out_pivot, user_in_viewport, user_out_viewport);
948
949         this->output = output;
950         this->input = input;
951         this->temp = temp;
952         this->mode = mode;
953         this->x1 = x1;  this->y1 = y1;
954         this->x2 = x2;  this->y2 = y2;
955         this->x3 = x3;  this->y3 = y3;
956         this->x4 = x4;  this->y4 = y4;
957         this->forward = forward;
958
959         if(!user_in_viewport) {
960                 in_x = 0;  in_y = 0;
961                 in_w = input->get_w();
962                 in_h = input->get_h();
963         }
964
965         if(!user_out_viewport) {
966                 out_x = 0;  out_y = 0;
967                 out_w = output->get_w();
968                 out_h = output->get_h();
969         }
970
971         if(use_opengl) {
972                 set_package_count(1);
973                 process_single();
974         }
975         else {
976                 set_package_count(total_packages);
977                 process_packages();
978         }
979 }
980
981
982
983
984 void AffineEngine::rotate(VFrame *output,
985         VFrame *input,
986         float angle)
987 {
988         this->output = output;
989         this->input = input;
990         this->temp = 0;
991         this->mode = ROTATE;
992         this->forward = 1;
993
994         if( !user_in_viewport ) {
995                 in_x = 0;  in_y = 0;
996                 in_w = input->get_w();
997                 in_h = input->get_h();
998 // DEBUG
999 // in_x = 4;
1000 // in_w = 2992;
1001 // in_y = 4;
1002 // in_h = 2992;
1003 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
1004         }
1005
1006         if( !user_in_pivot ) {
1007                 in_pivot_x = in_x + in_w / 2;
1008                 in_pivot_y = in_y + in_h / 2;
1009         }
1010
1011         if( !user_out_viewport ) {
1012                 out_x = 0;  out_y = 0;
1013                 out_w = output->get_w();
1014                 out_h = output->get_h();
1015         }
1016
1017         if( !user_out_pivot ) {
1018                 out_pivot_x = out_x + out_w / 2;
1019                 out_pivot_y = out_y + out_h / 2;
1020         }
1021
1022 // All subscripts are clockwise around the quadrangle
1023         angle = angle * 2 * M_PI / 360;
1024         double angle1 = atan((double)(in_pivot_y - in_y) / (double)(in_pivot_x - in_x)) + angle;
1025         double angle2 = atan((double)(in_x + in_w - in_pivot_x) / (double)(in_pivot_y - in_y)) + angle;
1026         double angle3 = atan((double)(in_y + in_h - in_pivot_y) / (double)(in_x + in_w - in_pivot_x)) + angle;
1027         double angle4 = atan((double)(in_pivot_x - in_x) / (double)(in_y + in_h - in_pivot_y)) + angle;
1028         double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
1029         double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
1030         double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
1031         double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
1032
1033         x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
1034         y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
1035         x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
1036         y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
1037         x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
1038         y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
1039         x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
1040         y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
1041
1042 // printf("AffineEngine::rotate angle=%f\n",
1043 // angle);
1044
1045 //
1046 // printf("     angle1=%f angle2=%f angle3=%f angle4=%f\n",
1047 // angle1 * 360 / 2 / M_PI,  angle2 * 360 / 2 / M_PI,
1048 // angle3 * 360 / 2 / M_PI,  angle4 * 360 / 2 / M_PI);
1049 //
1050 // printf("     radius1=%f radius2=%f radius3=%f radius4=%f\n",
1051 // radius1, radius2, radius3, radius4);
1052 //
1053 // printf("     x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
1054 // x1 * w / 100, y1 * h / 100,
1055 // x2 * w / 100, y2 * h / 100,
1056 // x3 * w / 100, y3 * h / 100,
1057 // x4 * w / 100, y4 * h / 100);
1058
1059         if(use_opengl) {
1060                 set_package_count(1);
1061                 process_single();
1062         }
1063         else {
1064                 set_package_count(total_packages);
1065                 process_packages();
1066         }
1067 }
1068
1069 void AffineEngine::set_matrix(AffineMatrix *matrix)
1070 {
1071         for( int i=0; i<3; ++i ) {
1072                 for( int j=0; j<3; ++j ) {
1073                         this->matrix.values[i][j] = matrix->values[i][j];
1074                 }
1075         }
1076 }
1077
1078 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
1079 {
1080         this->in_x = x;  this->in_y = y;
1081         this->in_w = w;  this->in_h = h;
1082         this->user_in_viewport = 1;
1083 }
1084
1085 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
1086 {
1087         this->out_x = x;  this->out_y = y;
1088         this->out_w = w;  this->out_h = h;
1089         this->user_out_viewport = 1;
1090 }
1091
1092 void AffineEngine::set_viewport(int x, int y, int w, int h)
1093 {
1094         set_in_viewport(x, y, w, h);
1095         set_out_viewport(x, y, w, h);
1096 }
1097
1098 void AffineEngine::set_opengl(int value)
1099 {
1100         this->use_opengl = value;
1101 }
1102
1103 void AffineEngine::set_in_pivot(int x, int y)
1104 {
1105         this->in_pivot_x = x;
1106         this->in_pivot_y = y;
1107         this->user_in_pivot = 1;
1108 }
1109
1110 void AffineEngine::set_out_pivot(int x, int y)
1111 {
1112         this->out_pivot_x = x;
1113         this->out_pivot_y = y;
1114         this->user_out_pivot = 1;
1115 }
1116
1117 void AffineEngine::set_pivot(int x, int y)
1118 {
1119         set_in_pivot(x, y);
1120         set_out_pivot(x, y);
1121 }
1122
1123 void AffineEngine::unset_pivot()
1124 {
1125         user_in_pivot = 0;
1126         user_out_pivot = 0;
1127 }
1128
1129 void AffineEngine::unset_viewport()
1130 {
1131         user_in_viewport = 0;
1132         user_out_viewport = 0;
1133 }
1134
1135
1136 void AffineEngine::set_interpolation(int type)
1137 {
1138         interpolation = type;
1139 }