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