• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files

hvirtual/plugins/motion/affine.C

Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #ifdef HAVE_GL
00006 #define GL_GLEXT_PROTOTYPES
00007 #include <GL/gl.h>
00008 #endif
00009 
00010 #include "affine.h"
00011 #include "clip.h"
00012 #include "vframe.h"
00013 
00014 
00015 #include <math.h>
00016 #include <stdint.h>
00017 #include <stdio.h>
00018 #include <string.h>
00019 
00020 AffineMatrix::AffineMatrix()
00021 {
00022         bzero(values, sizeof(values));
00023 }
00024 
00025 void AffineMatrix::identity()
00026 {
00027         bzero(values, sizeof(values));
00028         values[0][0] = 1;
00029         values[1][1] = 1;
00030         values[2][2] = 1;
00031 }
00032 
00033 void AffineMatrix::translate(double x, double y)
00034 {
00035         double g = values[2][0];
00036         double h = values[2][1];
00037         double i = values[2][2];
00038         values[0][0] += x * g;
00039         values[0][1] += x * h;
00040         values[0][2] += x * i;
00041         values[1][0] += y * g;
00042         values[1][1] += y * h;
00043         values[1][2] += y * i;
00044 }
00045 
00046 void AffineMatrix::scale(double x, double y)
00047 {
00048         values[0][0] *= x;
00049         values[0][1] *= x;
00050         values[0][2] *= x;
00051 
00052         values[1][0] *= y;
00053         values[1][1] *= y;
00054         values[1][2] *= y;
00055 }
00056 
00057 void AffineMatrix::multiply(AffineMatrix *dst)
00058 {
00059         int i, j;
00060         AffineMatrix tmp;
00061         double t1, t2, t3;
00062 
00063         for (i = 0; i < 3; i++)
00064     {
00065         t1 = values[i][0];
00066         t2 = values[i][1];
00067         t3 = values[i][2];
00068         for (j = 0; j < 3; j++)
00069                 {
00070                         tmp.values[i][j]  = t1 * dst->values[0][j];
00071                         tmp.values[i][j] += t2 * dst->values[1][j];
00072                         tmp.values[i][j] += t3 * dst->values[2][j];
00073                 }
00074     }
00075         dst->copy_from(&tmp);
00076 }
00077 
00078 double AffineMatrix::determinant()
00079 {
00080         double determinant;
00081 
00082         determinant  = 
00083         values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
00084         determinant -= 
00085         values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
00086         determinant += 
00087         values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
00088 
00089         return determinant;
00090 }
00091 
00092 void AffineMatrix::invert(AffineMatrix *dst)
00093 {
00094         double det_1;
00095 
00096         det_1 = determinant();
00097 
00098         if(det_1 == 0.0)
00099         return;
00100 
00101         det_1 = 1.0 / det_1;
00102 
00103         dst->values[0][0] =   
00104       (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
00105 
00106         dst->values[1][0] = 
00107       - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
00108 
00109         dst->values[2][0] =   
00110       (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
00111 
00112         dst->values[0][1] = 
00113       - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
00114 
00115         dst->values[1][1] = 
00116       (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
00117 
00118         dst->values[2][1] = 
00119       - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
00120 
00121         dst->values[0][2] =
00122       (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
00123 
00124         dst->values[1][2] = 
00125       - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
00126 
00127         dst->values[2][2] = 
00128       (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
00129 }
00130 
00131 void AffineMatrix::copy_from(AffineMatrix *src)
00132 {
00133         memcpy(&values[0][0], &src->values[0][0], sizeof(values));
00134 }
00135 
00136 void AffineMatrix::transform_point(float x, 
00137         float y, 
00138         float *newx, 
00139         float *newy)
00140 {
00141         double w;
00142 
00143         w = values[2][0] * x + values[2][1] * y + values[2][2];
00144 
00145         if (w == 0.0)
00146         w = 1.0;
00147         else
00148         w = 1.0 / w;
00149 
00150         *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
00151         *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
00152 }
00153 
00154 void AffineMatrix::dump()
00155 {
00156         printf("AffineMatrix::dump\n");
00157         printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
00158         printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
00159         printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
00160 }
00161 
00162 
00163 
00164 
00165 
00166 AffinePackage::AffinePackage()
00167  : LoadPackage()
00168 {
00169 }
00170 
00171 
00172 
00173 
00174 AffineUnit::AffineUnit(AffineEngine *server)
00175  : LoadClient(server)
00176 {
00177         this->server = server;
00178 }
00179 
00180 
00181 
00182 
00183 
00184 
00185 
00186 
00187 
00188 void AffineUnit::calculate_matrix(
00189         double in_x1,
00190         double in_y1,
00191         double in_x2,
00192         double in_y2,
00193         double out_x1,
00194         double out_y1,
00195         double out_x2,
00196         double out_y2,
00197         double out_x3,
00198         double out_y3,
00199         double out_x4,
00200         double out_y4,
00201         AffineMatrix *result)
00202 {
00203         AffineMatrix matrix;
00204         double scalex;
00205         double scaley;
00206 
00207         scalex = scaley = 1.0;
00208 
00209         if((in_x2 - in_x1) > 0)
00210         scalex = 1.0 / (double)(in_x2 - in_x1);
00211 
00212         if((in_y2 - in_y1) > 0)
00213         scaley = 1.0 / (double)(in_y2 - in_y1);
00214 
00215 /* Determine the perspective transform that maps from
00216  * the unit cube to the transformed coordinates
00217  */
00218     double dx1, dx2, dx3, dy1, dy2, dy3;
00219     double det1, det2;
00220 
00221     dx1 = out_x2 - out_x4;
00222     dx2 = out_x3 - out_x4;
00223     dx3 = out_x1 - out_x2 + out_x4 - out_x3;
00224 
00225     dy1 = out_y2 - out_y4;
00226     dy2 = out_y3 - out_y4;
00227     dy3 = out_y1 - out_y2 + out_y4 - out_y3;
00228 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
00229 // dx1,
00230 // dx2,
00231 // dx3,
00232 // dy1,
00233 // dy2,
00234 // dy3
00235 // );
00236 
00237 /*  Is the mapping affine?  */
00238     if((dx3 == 0.0) && (dy3 == 0.0))
00239     {
00240         matrix.values[0][0] = out_x2 - out_x1;
00241         matrix.values[0][1] = out_x4 - out_x2;
00242         matrix.values[0][2] = out_x1;
00243         matrix.values[1][0] = out_y2 - out_y1;
00244         matrix.values[1][1] = out_y4 - out_y2;
00245         matrix.values[1][2] = out_y1;
00246         matrix.values[2][0] = 0.0;
00247         matrix.values[2][1] = 0.0;
00248     }
00249     else
00250     {
00251         det1 = dx3 * dy2 - dy3 * dx2;
00252         det2 = dx1 * dy2 - dy1 * dx2;
00253         matrix.values[2][0] = det1 / det2;
00254         det1 = dx1 * dy3 - dy1 * dx3;
00255         det2 = dx1 * dy2 - dy1 * dx2;
00256         matrix.values[2][1] = det1 / det2;
00257 
00258         matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
00259         matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
00260         matrix.values[0][2] = out_x1;
00261 
00262         matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
00263         matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
00264         matrix.values[1][2] = out_y1;
00265     }
00266 
00267     matrix.values[2][2] = 1.0;
00268 
00269 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
00270 // matrix.dump();
00271 
00272         result->identity();
00273         result->translate(-in_x1, -in_y1);
00274         result->scale(scalex, scaley);
00275         matrix.multiply(result);
00276 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
00277 //                                { 0.0, 0.0896, 0.0 },
00278 //                                { -0.00126, 0.0, 1.0 } };
00279 // memcpy(&result->values[0][0], test, sizeof(test));
00280 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
00281 // result->dump();
00282 
00283 
00284 }
00285 
00286 float AffineUnit::transform_cubic(float dx,
00287                                float jm1,
00288                                float j,
00289                                float jp1,
00290                                float jp2)
00291 {
00292 /* Catmull-Rom - not bad */
00293         float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
00294                        ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
00295                        ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
00296 // printf("%f %f %f %f %f\n", 
00297 // result,
00298 // jm1,
00299 // j,
00300 // jp1,
00301 // jp2);
00302 
00303 
00304         return result;
00305 }
00306 
00307 
00308 void AffineUnit::process_package(LoadPackage *package)
00309 {
00310         AffinePackage *pkg = (AffinePackage*)package;
00311         int minx = server->x;
00312         int miny = server->y;
00313         int maxx = server->x + server->w - 1;
00314         int maxy = server->y + server->h - 1;
00315 
00316 // Calculate real coords
00317         float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
00318         if(server->mode == AffineEngine::STRETCH ||
00319                 server->mode == AffineEngine::PERSPECTIVE ||
00320                 server->mode == AffineEngine::ROTATE)
00321         {
00322                 out_x1 = (float)server->x + (float)server->x1 * server->w / 100;
00323                 out_y1 = (float)server->y + (float)server->y1 * server->h / 100;
00324                 out_x2 = (float)server->x + (float)server->x2 * server->w / 100;
00325                 out_y2 = (float)server->y + (float)server->y2 * server->h / 100;
00326                 out_x3 = (float)server->x + (float)server->x3 * server->w / 100;
00327                 out_y3 = (float)server->y + (float)server->y3 * server->h / 100;
00328                 out_x4 = (float)server->x + (float)server->x4 * server->w / 100;
00329                 out_y4 = (float)server->y + (float)server->y4 * server->h / 100;
00330         }
00331         else
00332         {
00333                 out_x1 = (float)server->x + (float)server->x1 * server->w / 100;
00334                 out_y1 = server->y;
00335                 out_x2 = out_x1 + server->w;
00336                 out_y2 = server->y;
00337                 out_x4 = (float)server->x + (float)server->x4 * server->w / 100;
00338                 out_y4 = server->y + server->h;
00339                 out_x3 = out_x4 + server->w;
00340                 out_y3 = server->y + server->h;
00341         }
00342 
00343 
00344 
00345 // Rotation with OpenGL uses a simple quad.
00346         if(server->mode == AffineEngine::ROTATE &&
00347                 server->use_opengl)
00348         {
00349 #ifdef HAVE_GL
00350                 server->output->to_texture();
00351                 server->output->enable_opengl();
00352                 server->output->init_screen();
00353                 server->output->bind_texture(0);
00354                 server->output->clear_pbuffer();
00355 
00356                 int texture_w = server->output->get_texture_w();
00357                 int texture_h = server->output->get_texture_h();
00358                 float output_h = server->output->get_h();
00359                 float in_x1 = (float)server->x / texture_w;
00360                 float in_x2 = (float)(server->x + server->w) / texture_w;
00361                 float in_y1 = (float)server->y / texture_h;
00362                 float in_y2 = (float)(server->y + server->h) / texture_h;
00363 
00364 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
00365 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
00366 
00367                 glBegin(GL_QUADS);
00368                 glNormal3f(0, 0, 1.0);
00369 
00370                 glTexCoord2f(in_x1, in_y1);
00371                 glVertex3f(out_x1, -output_h+out_y1, 0);
00372 
00373                 glTexCoord2f(in_x2, in_y1);
00374                 glVertex3f(out_x2, -output_h+out_y2, 0);
00375 
00376                 glTexCoord2f(in_x2, in_y2);
00377                 glVertex3f(out_x3, -output_h+out_y3, 0);
00378 
00379                 glTexCoord2f(in_x1, in_y2);
00380                 glVertex3f(out_x4, -output_h+out_y4, 0);
00381 
00382 
00383                 glEnd();
00384 
00385                 server->output->set_opengl_state(VFrame::SCREEN);
00386 #endif
00387         }
00388         else
00389         if(server->mode == AffineEngine::PERSPECTIVE ||
00390                 server->mode == AffineEngine::SHEER ||
00391                 server->mode == AffineEngine::ROTATE)
00392         {
00393                 AffineMatrix matrix;
00394                 float temp;
00395                 temp = out_x4;
00396                 out_x4 = out_x3;
00397                 out_x3 = temp;
00398                 temp = out_y4;
00399                 out_y4 = out_y3;
00400                 out_y3 = temp;
00401 
00402 
00403 
00404 
00405 
00406 
00407                 calculate_matrix(
00408                         server->x,
00409                         server->y,
00410                         server->x + server->w,
00411                         server->y + server->h,
00412                         out_x1,
00413                         out_y1,
00414                         out_x2,
00415                         out_y2,
00416                         out_x3,
00417                         out_y3,
00418                         out_x4,
00419                         out_y4,
00420                         &matrix);
00421 
00422 // printf("AffineUnit::process_package 10 %f %f %f %f %f %f %f %f\n", 
00423 // out_x1,
00424 // out_y1,
00425 // out_x2,
00426 // out_y2,
00427 // out_x3,
00428 // out_y3,
00429 // out_x4,
00430 // out_y4);
00431                 int interpolate = 1;
00432                 int reverse = !server->forward;
00433                 float tx, ty, tw;
00434                 float xinc, yinc, winc;
00435                 AffineMatrix m, im;
00436                 float ttx, tty;
00437                 int itx, ity;
00438                 int tx1, ty1, tx2, ty2;
00439 
00440                 if(reverse)
00441                 {
00442                         m.copy_from(&matrix);
00443                         m.invert(&im);
00444                         matrix.copy_from(&im);
00445                 }
00446                 else
00447                 {
00448                         matrix.invert(&m);
00449                 }
00450 
00451                 float dx1, dy1;
00452                 float dx2, dy2;
00453                 float dx3, dy3;
00454                 float dx4, dy4;
00455                 matrix.transform_point(server->x, server->y, &dx1, &dy1);
00456                 matrix.transform_point(server->x + server->w, server->y, &dx2, &dy2);
00457                 matrix.transform_point(server->x, server->y + server->h, &dx3, &dy3);
00458                 matrix.transform_point(server->x + server->w, server->y + server->h, &dx4, &dy4);
00459 
00460 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
00461 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
00462 //printf("AffineUnit::process_package 2 %d ty1=%d %d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
00463 
00464 
00465                 if(server->use_opengl)
00466                 {
00467 #ifdef HAVE_GL
00468                         static char *affine_frag =
00469                                 "uniform sampler2D tex;\n"
00470                                 "uniform mat3 affine_matrix;\n"
00471                                 "uniform vec2 texture_extents;\n"
00472                                 "uniform vec2 image_extents;\n"
00473                                 "uniform vec4 border_color;\n"
00474                                 "void main()\n"
00475                                 "{\n"
00476                                 "       vec2 outcoord = gl_TexCoord[0].st;\n"
00477                                 "       outcoord *= texture_extents;\n"
00478                                 "       mat3 coord_matrix = mat3(\n"
00479                                 "               outcoord.x, outcoord.y, 1.0, \n"
00480                                 "               outcoord.x, outcoord.y, 1.0, \n"
00481                                 "               outcoord.x, outcoord.y, 1.0);\n"
00482                                 "       mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
00483                                 "       vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
00484                                 "       incoord /= incoord_matrix[0][2];\n"
00485                                 "       incoord /= texture_extents;\n"
00486                                 "       if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
00487                                 "               gl_FragColor = border_color;\n"
00488                                 "       else\n"
00489                                 "               gl_FragColor = texture2D(tex, incoord);\n"
00490                                 "}\n";
00491 
00492                         float affine_matrix[9] = {
00493                                 m.values[0][0], m.values[1][0], m.values[2][0],
00494                                 m.values[0][1], m.values[1][1], m.values[2][1],
00495                                 m.values[0][2], m.values[1][2], m.values[2][2] 
00496                         };
00497 
00498 
00499                         server->output->to_texture();
00500                         server->output->enable_opengl();
00501                         unsigned int frag_shader = VFrame::make_shader(0,
00502                                         affine_frag,
00503                                         0);
00504                         if(frag_shader > 0)
00505                         {
00506                                 glUseProgram(frag_shader);
00507                                 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
00508                                 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"), 
00509                                         1,
00510                                         0,
00511                                         affine_matrix);
00512                                 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"), 
00513                                         (GLfloat)server->output->get_texture_w(),
00514                                         (GLfloat)server->output->get_texture_h());
00515                                 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"), 
00516                                         (GLfloat)server->output->get_w() / server->output->get_texture_w(),
00517                                         (GLfloat)server->output->get_h() / server->output->get_texture_h());
00518                                 float border_color[] = { 0, 0, 0, 0 };
00519                                 if(cmodel_is_yuv(server->output->get_color_model()))
00520                                 {
00521                                         border_color[1] = 0.5;
00522                                         border_color[2] = 0.5;
00523                                 }
00524                                 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"), 
00525                                         1,
00526                                         (GLfloat*)border_color);
00527                                 server->output->init_screen();
00528                                 server->output->bind_texture(0);
00529                                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
00530                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
00531                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
00532                                 server->output->draw_texture();
00533                                 glUseProgram(0);
00534                                 server->output->set_opengl_state(VFrame::SCREEN);
00535                         }
00536                         return;
00537 #endif
00538                 }
00539 
00540 
00541 
00542 
00543 
00544 
00545 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
00546 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
00547 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
00548 
00549         tx1 = ROUND(MIN4(dx1, dx2, dx3, dx4));
00550         ty1 = ROUND(MIN4(dy1, dy2, dy3, dy4));
00551 
00552         tx2 = ROUND(MAX4(dx1, dx2, dx3, dx4));
00553         ty2 = ROUND(MAX4(dy1, dy2, dy3, dy4));
00554 
00555                 CLAMP(ty1, pkg->y1, pkg->y2);
00556                 CLAMP(ty2, pkg->y1, pkg->y2);
00557 
00558                 xinc = m.values[0][0];
00559                 yinc = m.values[1][0];
00560                 winc = m.values[2][0];
00561 
00562 
00563 #define CUBIC_ROW(in_row, chroma_offset) \
00564         transform_cubic(dx, \
00565                 in_row[col1_offset] - chroma_offset, \
00566                 in_row[col2_offset] - chroma_offset, \
00567                 in_row[col3_offset] - chroma_offset, \
00568                 in_row[col4_offset] - chroma_offset)
00569 
00570 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
00571 { \
00572         type **in_rows = (type**)server->input->get_rows(); \
00573         float round_factor = 0.0; \
00574         if(sizeof(type) < 4) round_factor = 0.5; \
00575         for(int y = ty1; y < ty2; y++) \
00576         { \
00577                 type *out_row = (type*)server->output->get_rows()[y]; \
00578  \
00579                 if(!interpolate) \
00580                 { \
00581                 tx = xinc * (tx1 + 0.5) + m.values[0][1] * (y + 0.5) + m.values[0][2]; \
00582                 ty = yinc * (tx1 + 0.5) + m.values[1][1] * (y + 0.5) + m.values[1][2]; \
00583                 tw = winc * (tx1 + 0.5) + m.values[2][1] * (y + 0.5) + m.values[2][2]; \
00584                 } \
00585         else \
00586         { \
00587                 tx = xinc * tx1 + m.values[0][1] * y + m.values[0][2]; \
00588                 ty = yinc * tx1 + m.values[1][1] * y + m.values[1][2]; \
00589                 tw = winc * tx1 + m.values[2][1] * y + m.values[2][2]; \
00590         } \
00591  \
00592  \
00593                 out_row += tx1 * components; \
00594                 for(int x = tx1; x < tx2; x++) \
00595                 { \
00596 /* Normalize homogeneous coords */ \
00597                         if(tw == 0.0) \
00598                         { \
00599                                 ttx = 0.0; \
00600                                 tty = 0.0; \
00601                         } \
00602                         else \
00603                         if(tw != 1.0) \
00604                         { \
00605                                 ttx = tx / tw; \
00606                                 tty = ty / tw; \
00607                         } \
00608                         else \
00609                         { \
00610                                 ttx = tx; \
00611                                 tty = ty; \
00612                         } \
00613                         itx = (int)ttx; \
00614                         ity = (int)tty; \
00615  \
00616                         int row1 = ity - 1; \
00617                         int row2 = ity; \
00618                         int row3 = ity + 1; \
00619                         int row4 = ity + 2; \
00620                         CLAMP(row1, miny, maxy); \
00621                         CLAMP(row2, miny, maxy); \
00622                         CLAMP(row3, miny, maxy); \
00623                         CLAMP(row4, miny, maxy); \
00624  \
00625 /* Set destination pixels */ \
00626                         if(!interpolate && x >= server->x && x < server->x + server->w) \
00627                         { \
00628                                 if(itx >= server->x && itx < server->x + server->w && \
00629                                         ity >= server->y && ity < server->y + server->h) \
00630                                 { \
00631                                         type *src = in_rows[ity] + itx * components; \
00632                                         *out_row++ = *src++; \
00633                                         *out_row++ = *src++; \
00634                                         *out_row++ = *src++; \
00635                                         if(components == 4) *out_row++ = *src; \
00636                                 } \
00637                                 else \
00638 /* Fill with chroma */ \
00639                                 { \
00640                                         *out_row++ = 0; \
00641                                         *out_row++ = chroma_offset; \
00642                                         *out_row++ = chroma_offset; \
00643                                         if(components == 4) *out_row++ = 0; \
00644                                 } \
00645                         } \
00646                         else \
00647 /* Bicubic algorithm */ \
00648                         if(interpolate && x >= server->x && x < server->x + server->w) \
00649                         { \
00650                                 if ((itx + 2) >= server->x && (itx - 1) < server->x + server->w && \
00651                         (ity + 2) >= server->y && (ity - 1) < server->y + server->h) \
00652                 { \
00653                         float dx, dy; \
00654  \
00655 /* the fractional error */ \
00656                         dx = ttx - itx; \
00657                         dy = tty - ity; \
00658  \
00659 /* Row and column offsets in cubic block */ \
00660                                         int col1 = itx - 1; \
00661                                         int col2 = itx; \
00662                                         int col3 = itx + 1; \
00663                                         int col4 = itx + 2; \
00664                                         CLAMP(col1, minx, maxx); \
00665                                         CLAMP(col2, minx, maxx); \
00666                                         CLAMP(col3, minx, maxx); \
00667                                         CLAMP(col4, minx, maxx); \
00668                                         int col1_offset = col1 * components; \
00669                                         int col2_offset = col2 * components; \
00670                                         int col3_offset = col3 * components; \
00671                                         int col4_offset = col4 * components; \
00672                                         type *row1_ptr = in_rows[row1]; \
00673                                         type *row2_ptr = in_rows[row2]; \
00674                                         type *row3_ptr = in_rows[row3]; \
00675                                         type *row4_ptr = in_rows[row4]; \
00676                                         temp_type r, g, b, a; \
00677  \
00678                                         r = (temp_type)(transform_cubic(dy, \
00679                                  CUBIC_ROW(row1_ptr, 0x0), \
00680                                  CUBIC_ROW(row2_ptr, 0x0), \
00681                                  CUBIC_ROW(row3_ptr, 0x0), \
00682                                  CUBIC_ROW(row4_ptr, 0x0)) + \
00683                                                          round_factor); \
00684  \
00685                                         row1_ptr++; \
00686                                         row2_ptr++; \
00687                                         row3_ptr++; \
00688                                         row4_ptr++; \
00689                                         g = (temp_type)(transform_cubic(dy, \
00690                                  CUBIC_ROW(row1_ptr, chroma_offset), \
00691                                  CUBIC_ROW(row2_ptr, chroma_offset), \
00692                                  CUBIC_ROW(row3_ptr, chroma_offset), \
00693                                  CUBIC_ROW(row4_ptr, chroma_offset)) + \
00694                                                          round_factor); \
00695                                         g += chroma_offset; \
00696  \
00697                                         row1_ptr++; \
00698                                         row2_ptr++; \
00699                                         row3_ptr++; \
00700                                         row4_ptr++; \
00701                                         b = (temp_type)(transform_cubic(dy, \
00702                                  CUBIC_ROW(row1_ptr, chroma_offset), \
00703                                  CUBIC_ROW(row2_ptr, chroma_offset), \
00704                                  CUBIC_ROW(row3_ptr, chroma_offset), \
00705                                  CUBIC_ROW(row4_ptr, chroma_offset)) + \
00706                                                          round_factor); \
00707                                         b += chroma_offset; \
00708  \
00709                                         if(components == 4) \
00710                                         { \
00711                                                 row1_ptr++; \
00712                                                 row2_ptr++; \
00713                                                 row3_ptr++; \
00714                                                 row4_ptr++; \
00715                                                 a = (temp_type)(transform_cubic(dy, \
00716                                          CUBIC_ROW(row1_ptr, 0x0), \
00717                                          CUBIC_ROW(row2_ptr, 0x0), \
00718                                          CUBIC_ROW(row3_ptr, 0x0), \
00719                                          CUBIC_ROW(row4_ptr, 0x0)) +  \
00720                                                                  round_factor); \
00721                                         } \
00722  \
00723                                         if(sizeof(type) < 4) \
00724                                         { \
00725                                                 *out_row++ = CLIP(r, 0, max); \
00726                                                 *out_row++ = CLIP(g, 0, max); \
00727                                                 *out_row++ = CLIP(b, 0, max); \
00728                                                 if(components == 4) *out_row++ = CLIP(a, 0, max); \
00729                                         } \
00730                                         else \
00731                                         { \
00732                                                 *out_row++ = r; \
00733                                                 *out_row++ = g; \
00734                                                 *out_row++ = b; \
00735                                                 if(components == 4) *out_row++ = a; \
00736                                         } \
00737                 } \
00738                                 else \
00739 /* Fill with chroma */ \
00740                                 { \
00741                                         *out_row++ = 0; \
00742                                         *out_row++ = chroma_offset; \
00743                                         *out_row++ = chroma_offset; \
00744                                         if(components == 4) *out_row++ = 0; \
00745                                 } \
00746                         } \
00747                         else \
00748                         { \
00749                                 out_row += components; \
00750                         } \
00751  \
00752 /*  increment the transformed coordinates  */ \
00753                         tx += xinc; \
00754                         ty += yinc; \
00755                         tw += winc; \
00756                 } \
00757         } \
00758 }
00759 
00760 
00761 
00762 
00763                 switch(server->input->get_color_model())
00764                 {
00765                         case BC_RGB_FLOAT:
00766                                 TRANSFORM(3, float, float, 0x0, 1.0)
00767                                 break;
00768                         case BC_RGB888:
00769                                 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
00770                                 break;
00771                         case BC_RGBA_FLOAT:
00772                                 TRANSFORM(4, float, float, 0x0, 1.0)
00773                                 break;
00774                         case BC_RGBA8888:
00775                                 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
00776                                 break;
00777                         case BC_YUV888:
00778                                 TRANSFORM(3, unsigned char, int, 0x80, 0xff)
00779                                 break;
00780                         case BC_YUVA8888:
00781                                 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
00782                                 break;
00783                         case BC_RGB161616:
00784                                 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
00785                                 break;
00786                         case BC_RGBA16161616:
00787                                 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
00788                                 break;
00789                         case BC_YUV161616:
00790                                 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
00791                                 break;
00792                         case BC_YUVA16161616:
00793                                 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
00794                                 break;
00795                 }
00796 
00797         }
00798         else
00799         {
00800                 int min_x = server->x * AFFINE_OVERSAMPLE;
00801                 int min_y = server->y * AFFINE_OVERSAMPLE;
00802                 int max_x = server->x * AFFINE_OVERSAMPLE + server->w * AFFINE_OVERSAMPLE - 1;
00803                 int max_y = server->y * AFFINE_OVERSAMPLE + server->h * AFFINE_OVERSAMPLE - 1;
00804                 float top_w = out_x2 - out_x1;
00805                 float bottom_w = out_x3 - out_x4;
00806                 float left_h = out_y4 - out_y1;
00807                 float right_h = out_y3 - out_y2;
00808                 float out_w_diff = bottom_w - top_w;
00809                 float out_left_diff = out_x4 - out_x1;
00810                 float out_h_diff = right_h - left_h;
00811                 float out_top_diff = out_y2 - out_y1;
00812                 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
00813                 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
00814                 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
00815                 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
00816                 float max_v = MAX(distance1, distance3);
00817                 float max_h = MAX(distance2, distance4);
00818                 float max_dimension = MAX(max_v, max_h);
00819                 float min_dimension = MIN(server->h, server->w);
00820                 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
00821                 float x_f = server->x;
00822                 float y_f = server->y;
00823                 float h_f = server->h;
00824                 float w_f = server->w;
00825 
00826 
00827 
00828                 if(server->use_opengl)
00829                 {
00830                         return;
00831                 }
00832 
00833 
00834 
00835 // Projection
00836 #define DO_STRETCH(type, components) \
00837 { \
00838         type **in_rows = (type**)server->input->get_rows(); \
00839         type **out_rows = (type**)server->temp->get_rows(); \
00840  \
00841         for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
00842         { \
00843                 int i = (int)in_y; \
00844                 type *in_row = in_rows[i]; \
00845                 for(float in_x = x_f; in_x < w_f; in_x += step) \
00846                 { \
00847                         int j = (int)in_x; \
00848                         float in_x_fraction = (in_x - x_f) / w_f; \
00849                         float in_y_fraction = (in_y - y_f) / h_f; \
00850                         int out_x = (int)((out_x1 + \
00851                                 out_left_diff * in_y_fraction + \
00852                                 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) *  \
00853                                 AFFINE_OVERSAMPLE); \
00854                         int out_y = (int)((out_y1 +  \
00855                                 out_top_diff * in_x_fraction + \
00856                                 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
00857                                 AFFINE_OVERSAMPLE); \
00858                         CLAMP(out_x, min_x, max_x); \
00859                         CLAMP(out_y, min_y, max_y); \
00860                         type *dst = out_rows[out_y] + out_x * components; \
00861                         type *src = in_row + j * components; \
00862                         dst[0] = src[0]; \
00863                         dst[1] = src[1]; \
00864                         dst[2] = src[2]; \
00865                         if(components == 4) dst[3] = src[3]; \
00866                 } \
00867         } \
00868 }
00869 
00870                 switch(server->input->get_color_model())
00871                 {
00872                         case BC_RGB_FLOAT:
00873                                 DO_STRETCH(float, 3)
00874                                 break;
00875                         case BC_RGB888:
00876                                 DO_STRETCH(unsigned char, 3)
00877                                 break;
00878                         case BC_RGBA_FLOAT:
00879                                 DO_STRETCH(float, 4)
00880                                 break;
00881                         case BC_RGBA8888:
00882                                 DO_STRETCH(unsigned char, 4)
00883                                 break;
00884                         case BC_YUV888:
00885                                 DO_STRETCH(unsigned char, 3)
00886                                 break;
00887                         case BC_YUVA8888:
00888                                 DO_STRETCH(unsigned char, 4)
00889                                 break;
00890                         case BC_RGB161616:
00891                                 DO_STRETCH(uint16_t, 3)
00892                                 break;
00893                         case BC_RGBA16161616:
00894                                 DO_STRETCH(uint16_t, 4)
00895                                 break;
00896                         case BC_YUV161616:
00897                                 DO_STRETCH(uint16_t, 3)
00898                                 break;
00899                         case BC_YUVA16161616:
00900                                 DO_STRETCH(uint16_t, 4)
00901                                 break;
00902                 }
00903         }
00904 
00905 
00906 
00907 
00908 }
00909 
00910 
00911 
00912 
00913 
00914 
00915 AffineEngine::AffineEngine(int total_clients,
00916         int total_packages)
00917  : LoadServer(
00918 //1, 1 
00919 total_clients, total_packages 
00920 )
00921 {
00922         user_viewport = 0;
00923         user_pivot = 0;
00924         use_opengl = 0;
00925 }
00926 
00927 void AffineEngine::init_packages()
00928 {
00929         for(int i = 0; i < get_total_packages(); i++)
00930         {
00931                 AffinePackage *package = (AffinePackage*)get_package(i);
00932                 package->y1 = y + (h * i / get_total_packages());
00933                 package->y2 = y + (h * (i + 1) / get_total_packages());
00934         }
00935 }
00936 
00937 LoadClient* AffineEngine::new_client()
00938 {
00939         return new AffineUnit(this);
00940 }
00941 
00942 LoadPackage* AffineEngine::new_package()
00943 {
00944         return new AffinePackage;
00945 }
00946 
00947 void AffineEngine::process(VFrame *output,
00948         VFrame *input, 
00949         VFrame *temp,
00950         int mode,
00951         float x1, 
00952         float y1, 
00953         float x2, 
00954         float y2, 
00955         float x3, 
00956         float y3, 
00957         float x4, 
00958         float y4,
00959         int forward)
00960 {
00961         this->output = output;
00962         this->input = input;
00963         this->temp = temp;
00964         this->mode = mode;
00965         this->x1 = x1;
00966         this->y1 = y1;
00967         this->x2 = x2;
00968         this->y2 = y2;
00969         this->x3 = x3;
00970         this->y3 = y3;
00971         this->x4 = x4;
00972         this->y4 = y4;
00973         this->forward = forward;
00974 
00975 
00976         if(!user_viewport)
00977         {
00978                 x = 0;
00979                 y = 0;
00980                 w = input->get_w();
00981                 h = input->get_h();
00982         }
00983 
00984         if(use_opengl)
00985                 process_single();
00986         else
00987                 process_packages();
00988 }
00989 
00990 
00991 
00992 
00993 void AffineEngine::rotate(VFrame *output,
00994         VFrame *input, 
00995         float angle)
00996 {
00997         this->output = output;
00998         this->input = input;
00999         this->temp = 0;
01000         this->mode = ROTATE;
01001         this->forward = 1;
01002 
01003         if(!user_viewport)
01004         {
01005                 x = 0;
01006                 y = 0;
01007                 w = input->get_w();
01008                 h = input->get_h();
01009         }
01010 
01011         if(!user_pivot)
01012         {
01013                 pivot_x = x + w / 2;
01014                 pivot_y = y + h / 2;
01015         }
01016 
01017 // All subscripts are clockwise around the quadrangle
01018         angle = angle * 2 * M_PI / 360;
01019         double angle1 = atan((double)(pivot_y - y) / (double)(pivot_x -