factored libaffine out of motion
[cinelerra_cv/ct.git] / plugins / libaffine / affine.C
blob5007a564ddebeaf5970ec6ff81611e28548d0ae5
1 #if defined(HAVE_CONFIG_H)
2 #include "config.h"
3 #endif
5 #ifdef HAVE_GL
6 #define GL_GLEXT_PROTOTYPES
7 #include <GL/gl.h>
8 #endif
10 #include "affine.h"
11 #include "clip.h"
12 #include "vframe.h"
15 #include <math.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <string.h>
20 AffineMatrix::AffineMatrix()
22         bzero(values, sizeof(values));
25 void AffineMatrix::identity()
27         bzero(values, sizeof(values));
28         values[0][0] = 1;
29         values[1][1] = 1;
30         values[2][2] = 1;
33 void AffineMatrix::translate(double x, double y)
35         double g = values[2][0];
36         double h = values[2][1];
37         double i = values[2][2];
38         values[0][0] += x * g;
39         values[0][1] += x * h;
40         values[0][2] += x * i;
41         values[1][0] += y * g;
42         values[1][1] += y * h;
43         values[1][2] += y * i;
46 void AffineMatrix::scale(double x, double y)
48         values[0][0] *= x;
49         values[0][1] *= x;
50         values[0][2] *= x;
52         values[1][0] *= y;
53         values[1][1] *= y;
54         values[1][2] *= y;
57 void AffineMatrix::multiply(AffineMatrix *dst)
59         int i, j;
60         AffineMatrix tmp;
61         double t1, t2, t3;
63         for (i = 0; i < 3; i++)
64     {
65         t1 = values[i][0];
66         t2 = values[i][1];
67         t3 = values[i][2];
68         for (j = 0; j < 3; j++)
69                 {
70                         tmp.values[i][j]  = t1 * dst->values[0][j];
71                         tmp.values[i][j] += t2 * dst->values[1][j];
72                         tmp.values[i][j] += t3 * dst->values[2][j];
73                 }
74     }
75         dst->copy_from(&tmp);
78 double AffineMatrix::determinant()
80         double determinant;
82         determinant  = 
83         values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
84         determinant -= 
85         values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
86         determinant += 
87         values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
89         return determinant;
92 void AffineMatrix::invert(AffineMatrix *dst)
94         double det_1;
96         det_1 = determinant();
98         if(det_1 == 0.0)
99         return;
101         det_1 = 1.0 / det_1;
103         dst->values[0][0] =   
104       (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
106         dst->values[1][0] = 
107       - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
109         dst->values[2][0] =   
110       (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
112         dst->values[0][1] = 
113       - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
115         dst->values[1][1] = 
116       (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
118         dst->values[2][1] = 
119       - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
121         dst->values[0][2] =
122       (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
124         dst->values[1][2] = 
125       - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
127         dst->values[2][2] = 
128       (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
131 void AffineMatrix::copy_from(AffineMatrix *src)
133         memcpy(&values[0][0], &src->values[0][0], sizeof(values));
136 void AffineMatrix::transform_point(float x, 
137         float y, 
138         float *newx, 
139         float *newy)
141         double w;
143         w = values[2][0] * x + values[2][1] * y + values[2][2];
145         if (w == 0.0)
146         w = 1.0;
147         else
148         w = 1.0 / w;
150         *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
151         *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
154 void AffineMatrix::dump()
156         printf("AffineMatrix::dump\n");
157         printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
158         printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
159         printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
166 AffinePackage::AffinePackage()
167  : LoadPackage()
174 AffineUnit::AffineUnit(AffineEngine *server)
175  : LoadClient(server)
177         this->server = server;
188 void AffineUnit::calculate_matrix(
189         double in_x1,
190         double in_y1,
191         double in_x2,
192         double in_y2,
193         double out_x1,
194         double out_y1,
195         double out_x2,
196         double out_y2,
197         double out_x3,
198         double out_y3,
199         double out_x4,
200         double out_y4,
201         AffineMatrix *result)
203         AffineMatrix matrix;
204         double scalex;
205         double scaley;
207         scalex = scaley = 1.0;
209         if((in_x2 - in_x1) > 0)
210         scalex = 1.0 / (double)(in_x2 - in_x1);
212         if((in_y2 - in_y1) > 0)
213         scaley = 1.0 / (double)(in_y2 - in_y1);
215 /* Determine the perspective transform that maps from
216  * the unit cube to the transformed coordinates
217  */
218     double dx1, dx2, dx3, dy1, dy2, dy3;
219     double det1, det2;
221     dx1 = out_x2 - out_x4;
222     dx2 = out_x3 - out_x4;
223     dx3 = out_x1 - out_x2 + out_x4 - out_x3;
225     dy1 = out_y2 - out_y4;
226     dy2 = out_y3 - out_y4;
227     dy3 = out_y1 - out_y2 + out_y4 - out_y3;
228 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
229 // dx1,
230 // dx2,
231 // dx3,
232 // dy1,
233 // dy2,
234 // dy3
235 // );
237 /*  Is the mapping affine?  */
238     if((dx3 == 0.0) && (dy3 == 0.0))
239     {
240         matrix.values[0][0] = out_x2 - out_x1;
241         matrix.values[0][1] = out_x4 - out_x2;
242         matrix.values[0][2] = out_x1;
243         matrix.values[1][0] = out_y2 - out_y1;
244         matrix.values[1][1] = out_y4 - out_y2;
245         matrix.values[1][2] = out_y1;
246         matrix.values[2][0] = 0.0;
247         matrix.values[2][1] = 0.0;
248     }
249     else
250     {
251         det1 = dx3 * dy2 - dy3 * dx2;
252         det2 = dx1 * dy2 - dy1 * dx2;
253         matrix.values[2][0] = det1 / det2;
254         det1 = dx1 * dy3 - dy1 * dx3;
255         det2 = dx1 * dy2 - dy1 * dx2;
256         matrix.values[2][1] = det1 / det2;
258         matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
259         matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
260         matrix.values[0][2] = out_x1;
262         matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
263         matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
264         matrix.values[1][2] = out_y1;
265     }
267     matrix.values[2][2] = 1.0;
269 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
270 // matrix.dump();
272         result->identity();
273         result->translate(-in_x1, -in_y1);
274         result->scale(scalex, scaley);
275         matrix.multiply(result);
276 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
277 //                                { 0.0, 0.0896, 0.0 },
278 //                                { -0.00126, 0.0, 1.0 } };
279 // memcpy(&result->values[0][0], test, sizeof(test));
280 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
281 // result->dump();
286 float AffineUnit::transform_cubic(float dx,
287                                float jm1,
288                                float j,
289                                float jp1,
290                                float jp2)
292 /* Catmull-Rom - not bad */
293         float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
294                        ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
295                        ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
296 // printf("%f %f %f %f %f\n", 
297 // result,
298 // jm1,
299 // j,
300 // jp1,
301 // jp2);
304         return result;
308 void AffineUnit::process_package(LoadPackage *package)
310         AffinePackage *pkg = (AffinePackage*)package;
311         int minx = server->x;
312         int miny = server->y;
313         int maxx = server->x + server->w - 1;
314         int maxy = server->y + server->h - 1;
316 // Calculate real coords
317         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
318         if(server->mode == AffineEngine::STRETCH ||
319                 server->mode == AffineEngine::PERSPECTIVE ||
320                 server->mode == AffineEngine::ROTATE)
321         {
322                 out_x1 = (float)server->x + (float)server->x1 * server->w / 100;
323                 out_y1 = (float)server->y + (float)server->y1 * server->h / 100;
324                 out_x2 = (float)server->x + (float)server->x2 * server->w / 100;
325                 out_y2 = (float)server->y + (float)server->y2 * server->h / 100;
326                 out_x3 = (float)server->x + (float)server->x3 * server->w / 100;
327                 out_y3 = (float)server->y + (float)server->y3 * server->h / 100;
328                 out_x4 = (float)server->x + (float)server->x4 * server->w / 100;
329                 out_y4 = (float)server->y + (float)server->y4 * server->h / 100;
330         }
331         else
332         {
333                 out_x1 = (float)server->x + (float)server->x1 * server->w / 100;
334                 out_y1 = server->y;
335                 out_x2 = out_x1 + server->w;
336                 out_y2 = server->y;
337                 out_x4 = (float)server->x + (float)server->x4 * server->w / 100;
338                 out_y4 = server->y + server->h;
339                 out_x3 = out_x4 + server->w;
340                 out_y3 = server->y + server->h;
341         }
345 // Rotation with OpenGL uses a simple quad.
346         if(server->mode == AffineEngine::ROTATE &&
347                 server->use_opengl)
348         {
349 #ifdef HAVE_GL
350                 server->output->to_texture();
351                 server->output->enable_opengl();
352                 server->output->init_screen();
353                 server->output->bind_texture(0);
354                 server->output->clear_pbuffer();
356                 int texture_w = server->output->get_texture_w();
357                 int texture_h = server->output->get_texture_h();
358                 float output_h = server->output->get_h();
359                 float in_x1 = (float)server->x / texture_w;
360                 float in_x2 = (float)(server->x + server->w) / texture_w;
361                 float in_y1 = (float)server->y / texture_h;
362                 float in_y2 = (float)(server->y + server->h) / texture_h;
364 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
365 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
367                 glBegin(GL_QUADS);
368                 glNormal3f(0, 0, 1.0);
370                 glTexCoord2f(in_x1, in_y1);
371                 glVertex3f(out_x1, -output_h+out_y1, 0);
373                 glTexCoord2f(in_x2, in_y1);
374                 glVertex3f(out_x2, -output_h+out_y2, 0);
376                 glTexCoord2f(in_x2, in_y2);
377                 glVertex3f(out_x3, -output_h+out_y3, 0);
379                 glTexCoord2f(in_x1, in_y2);
380                 glVertex3f(out_x4, -output_h+out_y4, 0);
383                 glEnd();
385                 server->output->set_opengl_state(VFrame::SCREEN);
386 #endif
387         }
388         else
389         if(server->mode == AffineEngine::PERSPECTIVE ||
390                 server->mode == AffineEngine::SHEER ||
391                 server->mode == AffineEngine::ROTATE)
392         {
393                 AffineMatrix matrix;
394                 float temp;
395                 temp = out_x4;
396                 out_x4 = out_x3;
397                 out_x3 = temp;
398                 temp = out_y4;
399                 out_y4 = out_y3;
400                 out_y3 = temp;
407                 calculate_matrix(
408                         server->x,
409                         server->y,
410                         server->x + server->w,
411                         server->y + server->h,
412                         out_x1,
413                         out_y1,
414                         out_x2,
415                         out_y2,
416                         out_x3,
417                         out_y3,
418                         out_x4,
419                         out_y4,
420                         &matrix);
422 // printf("AffineUnit::process_package 10 %f %f %f %f %f %f %f %f\n", 
423 // out_x1,
424 // out_y1,
425 // out_x2,
426 // out_y2,
427 // out_x3,
428 // out_y3,
429 // out_x4,
430 // out_y4);
431                 int interpolate = 1;
432                 int reverse = !server->forward;
433                 float tx, ty, tw;
434                 float xinc, yinc, winc;
435                 AffineMatrix m, im;
436                 float ttx, tty;
437                 int itx, ity;
438                 int tx1, ty1, tx2, ty2;
440                 if(reverse)
441                 {
442                         m.copy_from(&matrix);
443                         m.invert(&im);
444                         matrix.copy_from(&im);
445                 }
446                 else
447                 {
448                         matrix.invert(&m);
449                 }
451                 float dx1, dy1;
452                 float dx2, dy2;
453                 float dx3, dy3;
454                 float dx4, dy4;
455                 matrix.transform_point(server->x, server->y, &dx1, &dy1);
456                 matrix.transform_point(server->x + server->w, server->y, &dx2, &dy2);
457                 matrix.transform_point(server->x, server->y + server->h, &dx3, &dy3);
458                 matrix.transform_point(server->x + server->w, server->y + server->h, &dx4, &dy4);
460 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
461 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
462 //printf("AffineUnit::process_package 2 %d ty1=%d %d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
465                 if(server->use_opengl)
466                 {
467 #ifdef HAVE_GL
468                         static char *affine_frag =
469                                 "uniform sampler2D tex;\n"
470                                 "uniform mat3 affine_matrix;\n"
471                                 "uniform vec2 texture_extents;\n"
472                                 "uniform vec2 image_extents;\n"
473                                 "uniform vec4 border_color;\n"
474                                 "void main()\n"
475                                 "{\n"
476                                 "       vec2 outcoord = gl_TexCoord[0].st;\n"
477                                 "       outcoord *= texture_extents;\n"
478                                 "       mat3 coord_matrix = mat3(\n"
479                                 "               outcoord.x, outcoord.y, 1.0, \n"
480                                 "               outcoord.x, outcoord.y, 1.0, \n"
481                                 "               outcoord.x, outcoord.y, 1.0);\n"
482                                 "       mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
483                                 "       vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
484                                 "       incoord /= incoord_matrix[0][2];\n"
485                                 "       incoord /= texture_extents;\n"
486                                 "       if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
487                                 "               gl_FragColor = border_color;\n"
488                                 "       else\n"
489                                 "               gl_FragColor = texture2D(tex, incoord);\n"
490                                 "}\n";
492                         float affine_matrix[9] = {
493                                 m.values[0][0], m.values[1][0], m.values[2][0],
494                                 m.values[0][1], m.values[1][1], m.values[2][1],
495                                 m.values[0][2], m.values[1][2], m.values[2][2] 
496                         };
499                         server->output->to_texture();
500                         server->output->enable_opengl();
501                         unsigned int frag_shader = VFrame::make_shader(0,
502                                         affine_frag,
503                                         0);
504                         if(frag_shader > 0)
505                         {
506                                 glUseProgram(frag_shader);
507                                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
508                                 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"), 
509                                         1,
510                                         0,
511                                         affine_matrix);
512                                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"), 
513                                         (GLfloat)server->output->get_texture_w(),
514                                         (GLfloat)server->output->get_texture_h());
515                                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"), 
516                                         (GLfloat)server->output->get_w() / server->output->get_texture_w(),
517                                         (GLfloat)server->output->get_h() / server->output->get_texture_h());
518                                 float border_color[] = { 0, 0, 0, 0 };
519                                 if(cmodel_is_yuv(server->output->get_color_model()))
520                                 {
521                                         border_color[1] = 0.5;
522                                         border_color[2] = 0.5;
523                                 }
524                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"), 
525                                         1,
526                                         (GLfloat*)border_color);
527                                 server->output->init_screen();
528                                 server->output->bind_texture(0);
529                                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
530                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
531                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
532                                 server->output->draw_texture();
533                                 glUseProgram(0);
534                                 server->output->set_opengl_state(VFrame::SCREEN);
535                         }
536                         return;
537 #endif
538                 }
545 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
546 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
547 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
549         tx1 = ROUND(MIN4(dx1, dx2, dx3, dx4));
550         ty1 = ROUND(MIN4(dy1, dy2, dy3, dy4));
552         tx2 = ROUND(MAX4(dx1, dx2, dx3, dx4));
553         ty2 = ROUND(MAX4(dy1, dy2, dy3, dy4));
555                 CLAMP(ty1, pkg->y1, pkg->y2);
556                 CLAMP(ty2, pkg->y1, pkg->y2);
558                 xinc = m.values[0][0];
559                 yinc = m.values[1][0];
560                 winc = m.values[2][0];
563 #define CUBIC_ROW(in_row, chroma_offset) \
564         transform_cubic(dx, \
565                 in_row[col1_offset] - chroma_offset, \
566                 in_row[col2_offset] - chroma_offset, \
567                 in_row[col3_offset] - chroma_offset, \
568                 in_row[col4_offset] - chroma_offset)
570 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
571 { \
572         type **in_rows = (type**)server->input->get_rows(); \
573         float round_factor = 0.0; \
574         if(sizeof(type) < 4) round_factor = 0.5; \
575         for(int y = ty1; y < ty2; y++) \
576         { \
577                 type *out_row = (type*)server->output->get_rows()[y]; \
579                 if(!interpolate) \
580                 { \
581                 tx = xinc * (tx1 + 0.5) + m.values[0][1] * (y + 0.5) + m.values[0][2]; \
582                 ty = yinc * (tx1 + 0.5) + m.values[1][1] * (y + 0.5) + m.values[1][2]; \
583                 tw = winc * (tx1 + 0.5) + m.values[2][1] * (y + 0.5) + m.values[2][2]; \
584                 } \
585         else \
586         { \
587                 tx = xinc * tx1 + m.values[0][1] * y + m.values[0][2]; \
588                 ty = yinc * tx1 + m.values[1][1] * y + m.values[1][2]; \
589                 tw = winc * tx1 + m.values[2][1] * y + m.values[2][2]; \
590         } \
593                 out_row += tx1 * components; \
594                 for(int x = tx1; x < tx2; x++) \
595                 { \
596 /* Normalize homogeneous coords */ \
597                         if(tw == 0.0) \
598                         { \
599                                 ttx = 0.0; \
600                                 tty = 0.0; \
601                         } \
602                         else \
603                         if(tw != 1.0) \
604                         { \
605                                 ttx = tx / tw; \
606                                 tty = ty / tw; \
607                         } \
608                         else \
609                         { \
610                                 ttx = tx; \
611                                 tty = ty; \
612                         } \
613                         itx = (int)ttx; \
614                         ity = (int)tty; \
616                         int row1 = ity - 1; \
617                         int row2 = ity; \
618                         int row3 = ity + 1; \
619                         int row4 = ity + 2; \
620                         CLAMP(row1, miny, maxy); \
621                         CLAMP(row2, miny, maxy); \
622                         CLAMP(row3, miny, maxy); \
623                         CLAMP(row4, miny, maxy); \
625 /* Set destination pixels */ \
626                         if(!interpolate && x >= server->x && x < server->x + server->w) \
627                         { \
628                                 if(itx >= server->x && itx < server->x + server->w && \
629                                         ity >= server->y && ity < server->y + server->h) \
630                                 { \
631                                         type *src = in_rows[ity] + itx * components; \
632                                         *out_row++ = *src++; \
633                                         *out_row++ = *src++; \
634                                         *out_row++ = *src++; \
635                                         if(components == 4) *out_row++ = *src; \
636                                 } \
637                                 else \
638 /* Fill with chroma */ \
639                                 { \
640                                         *out_row++ = 0; \
641                                         *out_row++ = chroma_offset; \
642                                         *out_row++ = chroma_offset; \
643                                         if(components == 4) *out_row++ = 0; \
644                                 } \
645                         } \
646                         else \
647 /* Bicubic algorithm */ \
648                         if(interpolate && x >= server->x && x < server->x + server->w) \
649                         { \
650                                 if ((itx + 2) >= server->x && (itx - 1) < server->x + server->w && \
651                         (ity + 2) >= server->y && (ity - 1) < server->y + server->h) \
652                 { \
653                         float dx, dy; \
655 /* the fractional error */ \
656                         dx = ttx - itx; \
657                         dy = tty - ity; \
659 /* Row and column offsets in cubic block */ \
660                                         int col1 = itx - 1; \
661                                         int col2 = itx; \
662                                         int col3 = itx + 1; \
663                                         int col4 = itx + 2; \
664                                         CLAMP(col1, minx, maxx); \
665                                         CLAMP(col2, minx, maxx); \
666                                         CLAMP(col3, minx, maxx); \
667                                         CLAMP(col4, minx, maxx); \
668                                         int col1_offset = col1 * components; \
669                                         int col2_offset = col2 * components; \
670                                         int col3_offset = col3 * components; \
671                                         int col4_offset = col4 * components; \
672                                         type *row1_ptr = in_rows[row1]; \
673                                         type *row2_ptr = in_rows[row2]; \
674                                         type *row3_ptr = in_rows[row3]; \
675                                         type *row4_ptr = in_rows[row4]; \
676                                         temp_type r, g, b, a; \
678                                         r = (temp_type)(transform_cubic(dy, \
679                                  CUBIC_ROW(row1_ptr, 0x0), \
680                                  CUBIC_ROW(row2_ptr, 0x0), \
681                                  CUBIC_ROW(row3_ptr, 0x0), \
682                                  CUBIC_ROW(row4_ptr, 0x0)) + \
683                                                          round_factor); \
685                                         row1_ptr++; \
686                                         row2_ptr++; \
687                                         row3_ptr++; \
688                                         row4_ptr++; \
689                                         g = (temp_type)(transform_cubic(dy, \
690                                  CUBIC_ROW(row1_ptr, chroma_offset), \
691                                  CUBIC_ROW(row2_ptr, chroma_offset), \
692                                  CUBIC_ROW(row3_ptr, chroma_offset), \
693                                  CUBIC_ROW(row4_ptr, chroma_offset)) + \
694                                                          round_factor); \
695                                         g += chroma_offset; \
697                                         row1_ptr++; \
698                                         row2_ptr++; \
699                                         row3_ptr++; \
700                                         row4_ptr++; \
701                                         b = (temp_type)(transform_cubic(dy, \
702                                  CUBIC_ROW(row1_ptr, chroma_offset), \
703                                  CUBIC_ROW(row2_ptr, chroma_offset), \
704                                  CUBIC_ROW(row3_ptr, chroma_offset), \
705                                  CUBIC_ROW(row4_ptr, chroma_offset)) + \
706                                                          round_factor); \
707                                         b += chroma_offset; \
709                                         if(components == 4) \
710                                         { \
711                                                 row1_ptr++; \
712                                                 row2_ptr++; \
713                                                 row3_ptr++; \
714                                                 row4_ptr++; \
715                                                 a = (temp_type)(transform_cubic(dy, \
716                                          CUBIC_ROW(row1_ptr, 0x0), \
717                                          CUBIC_ROW(row2_ptr, 0x0), \
718                                          CUBIC_ROW(row3_ptr, 0x0), \
719                                          CUBIC_ROW(row4_ptr, 0x0)) +  \
720                                                                  round_factor); \
721                                         } \
723                                         if(sizeof(type) < 4) \
724                                         { \
725                                                 *out_row++ = CLIP(r, 0, max); \
726                                                 *out_row++ = CLIP(g, 0, max); \
727                                                 *out_row++ = CLIP(b, 0, max); \
728                                                 if(components == 4) *out_row++ = CLIP(a, 0, max); \
729                                         } \
730                                         else \
731                                         { \
732                                                 *out_row++ = r; \
733                                                 *out_row++ = g; \
734                                                 *out_row++ = b; \
735                                                 if(components == 4) *out_row++ = a; \
736                                         } \
737                 } \
738                                 else \
739 /* Fill with chroma */ \
740                                 { \
741                                         *out_row++ = 0; \
742                                         *out_row++ = chroma_offset; \
743                                         *out_row++ = chroma_offset; \
744                                         if(components == 4) *out_row++ = 0; \
745                                 } \
746                         } \
747                         else \
748                         { \
749                                 out_row += components; \
750                         } \
752 /*  increment the transformed coordinates  */ \
753                         tx += xinc; \
754                         ty += yinc; \
755                         tw += winc; \
756                 } \
757         } \
763                 switch(server->input->get_color_model())
764                 {
765                         case BC_RGB_FLOAT:
766                                 TRANSFORM(3, float, float, 0x0, 1.0)
767                                 break;
768                         case BC_RGB888:
769                                 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
770                                 break;
771                         case BC_RGBA_FLOAT:
772                                 TRANSFORM(4, float, float, 0x0, 1.0)
773                                 break;
774                         case BC_RGBA8888:
775                                 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
776                                 break;
777                         case BC_YUV888:
778                                 TRANSFORM(3, unsigned char, int, 0x80, 0xff)
779                                 break;
780                         case BC_YUVA8888:
781                                 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
782                                 break;
783                         case BC_RGB161616:
784                                 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
785                                 break;
786                         case BC_RGBA16161616:
787                                 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
788                                 break;
789                         case BC_YUV161616:
790                                 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
791                                 break;
792                         case BC_YUVA16161616:
793                                 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
794                                 break;
795                 }
797         }
798         else
799         {
800                 int min_x = server->x * AFFINE_OVERSAMPLE;
801                 int min_y = server->y * AFFINE_OVERSAMPLE;
802                 int max_x = server->x * AFFINE_OVERSAMPLE + server->w * AFFINE_OVERSAMPLE - 1;
803                 int max_y = server->y * AFFINE_OVERSAMPLE + server->h * AFFINE_OVERSAMPLE - 1;
804                 float top_w = out_x2 - out_x1;
805                 float bottom_w = out_x3 - out_x4;
806                 float left_h = out_y4 - out_y1;
807                 float right_h = out_y3 - out_y2;
808                 float out_w_diff = bottom_w - top_w;
809                 float out_left_diff = out_x4 - out_x1;
810                 float out_h_diff = right_h - left_h;
811                 float out_top_diff = out_y2 - out_y1;
812                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
813                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
814                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
815                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
816                 float max_v = MAX(distance1, distance3);
817                 float max_h = MAX(distance2, distance4);
818                 float max_dimension = MAX(max_v, max_h);
819                 float min_dimension = MIN(server->h, server->w);
820                 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
821                 float x_f = server->x;
822                 float y_f = server->y;
823                 float h_f = server->h;
824                 float w_f = server->w;
828                 if(server->use_opengl)
829                 {
830                         return;
831                 }
835 // Projection
836 #define DO_STRETCH(type, components) \
837 { \
838         type **in_rows = (type**)server->input->get_rows(); \
839         type **out_rows = (type**)server->temp->get_rows(); \
841         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
842         { \
843                 int i = (int)in_y; \
844                 type *in_row = in_rows[i]; \
845                 for(float in_x = x_f; in_x < w_f; in_x += step) \
846                 { \
847                         int j = (int)in_x; \
848                         float in_x_fraction = (in_x - x_f) / w_f; \
849                         float in_y_fraction = (in_y - y_f) / h_f; \
850                         int out_x = (int)((out_x1 + \
851                                 out_left_diff * in_y_fraction + \
852                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
853                                 AFFINE_OVERSAMPLE); \
854                         int out_y = (int)((out_y1 +  \
855                                 out_top_diff * in_x_fraction + \
856                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
857                                 AFFINE_OVERSAMPLE); \
858                         CLAMP(out_x, min_x, max_x); \
859                         CLAMP(out_y, min_y, max_y); \
860                         type *dst = out_rows[out_y] + out_x * components; \
861                         type *src = in_row + j * components; \
862                         dst[0] = src[0]; \
863                         dst[1] = src[1]; \
864                         dst[2] = src[2]; \
865                         if(components == 4) dst[3] = src[3]; \
866                 } \
867         } \
870                 switch(server->input->get_color_model())
871                 {
872                         case BC_RGB_FLOAT:
873                                 DO_STRETCH(float, 3)
874                                 break;
875                         case BC_RGB888:
876                                 DO_STRETCH(unsigned char, 3)
877                                 break;
878                         case BC_RGBA_FLOAT:
879                                 DO_STRETCH(float, 4)
880                                 break;
881                         case BC_RGBA8888:
882                                 DO_STRETCH(unsigned char, 4)
883                                 break;
884                         case BC_YUV888:
885                                 DO_STRETCH(unsigned char, 3)
886                                 break;
887                         case BC_YUVA8888:
888                                 DO_STRETCH(unsigned char, 4)
889                                 break;
890                         case BC_RGB161616:
891                                 DO_STRETCH(uint16_t, 3)
892                                 break;
893                         case BC_RGBA16161616:
894                                 DO_STRETCH(uint16_t, 4)
895                                 break;
896                         case BC_YUV161616:
897                                 DO_STRETCH(uint16_t, 3)
898                                 break;
899                         case BC_YUVA16161616:
900                                 DO_STRETCH(uint16_t, 4)
901                                 break;
902                 }
903         }
915 AffineEngine::AffineEngine(int total_clients,
916         int total_packages)
917  : LoadServer(
918 //1, 1 
919 total_clients, total_packages 
922         user_viewport = 0;
923         user_pivot = 0;
924         use_opengl = 0;
927 void AffineEngine::init_packages()
929         for(int i = 0; i < get_total_packages(); i++)
930         {
931                 AffinePackage *package = (AffinePackage*)get_package(i);
932                 package->y1 = y + (h * i / get_total_packages());
933                 package->y2 = y + (h * (i + 1) / get_total_packages());
934         }
937 LoadClient* AffineEngine::new_client()
939         return new AffineUnit(this);
942 LoadPackage* AffineEngine::new_package()
944         return new AffinePackage;
947 void AffineEngine::process(VFrame *output,
948         VFrame *input, 
949         VFrame *temp,
950         int mode,
951         float x1, 
952         float y1, 
953         float x2, 
954         float y2, 
955         float x3, 
956         float y3, 
957         float x4, 
958         float y4,
959         int forward)
961         this->output = output;
962         this->input = input;
963         this->temp = temp;
964         this->mode = mode;
965         this->x1 = x1;
966         this->y1 = y1;
967         this->x2 = x2;
968         this->y2 = y2;
969         this->x3 = x3;
970         this->y3 = y3;
971         this->x4 = x4;
972         this->y4 = y4;
973         this->forward = forward;
976         if(!user_viewport)
977         {
978                 x = 0;
979                 y = 0;
980                 w = input->get_w();
981                 h = input->get_h();
982         }
984         if(use_opengl)
985                 process_single();
986         else
987                 process_packages();
993 void AffineEngine::rotate(VFrame *output,
994         VFrame *input, 
995         float angle)
997         this->output = output;
998         this->input = input;
999         this->temp = 0;
1000         this->mode = ROTATE;
1001         this->forward = 1;
1003         if(!user_viewport)
1004         {
1005                 x = 0;
1006                 y = 0;
1007                 w = input->get_w();
1008                 h = input->get_h();
1009         }
1011         if(!user_pivot)
1012         {
1013                 pivot_x = x + w / 2;
1014                 pivot_y = y + h / 2;
1015         }
1017 // All subscripts are clockwise around the quadrangle
1018         angle = angle * 2 * M_PI / 360;
1019         double angle1 = atan((double)(pivot_y - y) / (double)(pivot_x - x)) + angle;
1020         double angle2 = atan((double)(x + w - pivot_x) / (double)(pivot_y - y)) + angle;
1021         double angle3 = atan((double)(y + h - pivot_y) / (double)(x + w - pivot_x)) + angle;
1022         double angle4 = atan((double)(pivot_x - x) / (double)(y + h - pivot_y)) + angle;
1023         double radius1 = DISTANCE(x, y, pivot_x, pivot_y);
1024         double radius2 = DISTANCE(x + w, y, pivot_x, pivot_y);
1025         double radius3 = DISTANCE(x + w, y + h, pivot_x, pivot_y);
1026         double radius4 = DISTANCE(x, y + h, pivot_x, pivot_y);
1028         x1 = ((pivot_x - x) - cos(angle1) * radius1) * 100 / w;
1029         y1 = ((pivot_y - y) - sin(angle1) * radius1) * 100 / h;
1030         x2 = ((pivot_x - x) + sin(angle2) * radius2) * 100 / w;
1031         y2 = ((pivot_y - y) - cos(angle2) * radius2) * 100 / h;
1032         x3 = ((pivot_x - x) + cos(angle3) * radius3) * 100 / w;
1033         y3 = ((pivot_y - y) + sin(angle3) * radius3) * 100 / h;
1034         x4 = ((pivot_x - x) - sin(angle4) * radius4) * 100 / w;
1035         y4 = ((pivot_y - y) + cos(angle4) * radius4) * 100 / h;
1037 // printf("AffineEngine::rotate x=%d y=%d w=%d h=%d pivot_x=%d pivot_y=%d angle=%f\n",
1038 // x, y, w, h, 
1039 // pivot_x, 
1040 // pivot_y,
1041 // angle * 360 / 2 / M_PI);
1042 // 
1043 // printf("     angle1=%f angle2=%f angle3=%f angle4=%f\n",
1044 // angle1 * 360 / 2 / M_PI, 
1045 // angle2 * 360 / 2 / M_PI, 
1046 // angle3 * 360 / 2 / M_PI, 
1047 // angle4 * 360 / 2 / M_PI);
1048 // 
1049 // printf("     radius1=%f radius2=%f radius3=%f radius4=%f\n",
1050 // radius1,
1051 // radius2,
1052 // radius3,
1053 // radius4);
1054 // 
1055 // printf("     x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
1056 // x1 * w / 100, 
1057 // y1 * h / 100, 
1058 // x2 * w / 100, 
1059 // y2 * h / 100, 
1060 // x3 * w / 100, 
1061 // y3 * h / 100, 
1062 // x4 * w / 100, 
1063 // y4 * h / 100);
1065         if(use_opengl)
1066                 process_single();
1067         else
1068                 process_packages();
1069 //      process_packages();
1072 void AffineEngine::set_viewport(int x, int y, int w, int h)
1074         this->x = x;
1075         this->y = y;
1076         this->w = w;
1077         this->h = h;
1078         user_viewport = 1;
1081 void AffineEngine::set_opengl(int value)
1083         this->use_opengl = value;
1086 void AffineEngine::set_pivot(int x, int y)
1088         this->pivot_x = x;
1089         this->pivot_y = y;
1090         this->user_pivot = 1;
1093 void AffineEngine::unset_pivot()
1095         user_pivot = 0;
1098 void AffineEngine::unset_viewport()
1100         user_viewport = 0;