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