affine + perspective plugin rework, info popup tweaks
authorGood Guy <good1.2guy@gmail.com>
Fri, 7 Jul 2017 18:00:08 +0000 (12:00 -0600)
committerGood Guy <good1.2guy@gmail.com>
Fri, 7 Jul 2017 18:00:08 +0000 (12:00 -0600)
cinelerra-5.1/cinelerra/affine.C
cinelerra-5.1/cinelerra/affine.h
cinelerra-5.1/cinelerra/assetedit.C
cinelerra-5.1/cinelerra/assetpopup.C
cinelerra-5.1/cinelerra/clipedit.C
cinelerra-5.1/plugins/perspective/perspective.C
cinelerra-5.1/plugins/perspective/perspective.h

index 09f81f2ed6b9542d4377f0e2a825423bb1ba160d..f5f90a7c8228c7ee8680a8576e61e2fd31b02953 100644 (file)
@@ -73,22 +73,16 @@ void AffineMatrix::scale(double x, double y)
 
 void AffineMatrix::multiply(AffineMatrix *dst)
 {
-       int i, j;
        AffineMatrix tmp;
-       double t1, t2, t3;
-
-       for (i = 0; i < 3; i++)
-    {
-       t1 = values[i][0];
-       t2 = values[i][1];
-       t3 = values[i][2];
-       for (j = 0; j < 3; j++)
-               {
+
+       for( int i=0; i<3; ++i ) {
+               double t1 = values[i][0], t2 = values[i][1], t3 = values[i][2];
+               for( int j=0; j<3; ++j ) {
                        tmp.values[i][j]  = t1 * dst->values[0][j];
                        tmp.values[i][j] += t2 * dst->values[1][j];
                        tmp.values[i][j] += t3 * dst->values[2][j];
                }
-    }
+       }
        dst->copy_from(&tmp);
 }
 
@@ -97,11 +91,11 @@ double AffineMatrix::determinant()
        double determinant;
 
        determinant  =
-        values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
+               values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
        determinant -=
-        values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
+               values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
        determinant +=
-        values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
+               values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
 
        return determinant;
 }
@@ -113,36 +107,36 @@ void AffineMatrix::invert(AffineMatrix *dst)
        det_1 = determinant();
 
        if(det_1 == 0.0)
-       return;
+       return;
 
        det_1 = 1.0 / det_1;
 
        dst->values[0][0] =
-      (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
+               (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
 
        dst->values[1][0] =
-      - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
+               - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
 
        dst->values[2][0] =
-      (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
+               (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
 
        dst->values[0][1] =
-      - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
+               - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
 
        dst->values[1][1] =
-      (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
+               (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
 
        dst->values[2][1] =
-      - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
+               - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
 
        dst->values[0][2] =
-      (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
+               (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
 
        dst->values[1][2] =
-      - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
+               - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
 
        dst->values[2][2] =
-      (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
+               (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
 }
 
 void AffineMatrix::copy_from(AffineMatrix *src)
@@ -158,11 +152,7 @@ void AffineMatrix::transform_point(float x,
        double w;
 
        w = values[2][0] * x + values[2][1] * y + values[2][2];
-
-       if (w == 0.0)
-       w = 1.0;
-       else
-       w = 1.0 / w;
+       w = !w ? 1 : 1/w;
 
        *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
        *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
@@ -203,18 +193,9 @@ AffineUnit::AffineUnit(AffineEngine *server)
 
 
 void AffineUnit::calculate_matrix(
-       double in_x1,
-       double in_y1,
-       double in_x2,
-       double in_y2,
-       double out_x1,
-       double out_y1,
-       double out_x2,
-       double out_y2,
-       double out_x3,
-       double out_y3,
-       double out_x4,
-       double out_y4,
+       double in_x1, double in_y1, double in_x2, double in_y2,
+       double out_x1, double out_y1, double out_x2, double out_y2,
+       double out_x3, double out_y3, double out_x4, double out_y4,
        AffineMatrix *result)
 {
        AffineMatrix matrix;
@@ -223,65 +204,57 @@ void AffineUnit::calculate_matrix(
 
        scalex = scaley = 1.0;
 
-       if((in_x2 - in_x1) > 0)
-       scalex = 1.0 / (double)(in_x2 - in_x1);
+       if( (in_x2 - in_x1) > 0 )
+               scalex = 1.0 / (double)(in_x2 - in_x1);
 
-       if((in_y2 - in_y1) > 0)
-       scaley = 1.0 / (double)(in_y2 - in_y1);
+       if( (in_y2 - in_y1) > 0 )
+               scaley = 1.0 / (double)(in_y2 - in_y1);
 
 /* Determine the perspective transform that maps from
  * the unit cube to the transformed coordinates
  */
-    double dx1, dx2, dx3, dy1, dy2, dy3;
-    double det1, det2;
+       double dx1, dx2, dx3, dy1, dy2, dy3;
+       double det1, det2;
 
-    dx1 = out_x2 - out_x4;
-    dx2 = out_x3 - out_x4;
-    dx3 = out_x1 - out_x2 + out_x4 - out_x3;
+       dx1 = out_x2 - out_x4;
+       dx2 = out_x3 - out_x4;
+       dx3 = out_x1 - out_x2 + out_x4 - out_x3;
 
-    dy1 = out_y2 - out_y4;
-    dy2 = out_y3 - out_y4;
-    dy3 = out_y1 - out_y2 + out_y4 - out_y3;
+       dy1 = out_y2 - out_y4;
+       dy2 = out_y3 - out_y4;
+       dy3 = out_y1 - out_y2 + out_y4 - out_y3;
 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
-// dx1,
-// dx2,
-// dx3,
-// dy1,
-// dy2,
-// dy3
-// );
+//  dx1, dx2, dx3, dy1, dy2, dy3 );
 
 /*  Is the mapping affine?  */
-    if((dx3 == 0.0) && (dy3 == 0.0))
-    {
-        matrix.values[0][0] = out_x2 - out_x1;
-        matrix.values[0][1] = out_x4 - out_x2;
-        matrix.values[0][2] = out_x1;
-        matrix.values[1][0] = out_y2 - out_y1;
-        matrix.values[1][1] = out_y4 - out_y2;
-        matrix.values[1][2] = out_y1;
-        matrix.values[2][0] = 0.0;
-        matrix.values[2][1] = 0.0;
-    }
-    else
-    {
-        det1 = dx3 * dy2 - dy3 * dx2;
-        det2 = dx1 * dy2 - dy1 * dx2;
-        matrix.values[2][0] = det1 / det2;
-        det1 = dx1 * dy3 - dy1 * dx3;
-        det2 = dx1 * dy2 - dy1 * dx2;
-        matrix.values[2][1] = det1 / det2;
-
-        matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
-        matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
-        matrix.values[0][2] = out_x1;
-
-        matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
-        matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
-        matrix.values[1][2] = out_y1;
-    }
-
-    matrix.values[2][2] = 1.0;
+       if((dx3 == 0.0) && (dy3 == 0.0)) {
+               matrix.values[0][0] = out_x2 - out_x1;
+               matrix.values[0][1] = out_x4 - out_x2;
+               matrix.values[0][2] = out_x1;
+               matrix.values[1][0] = out_y2 - out_y1;
+               matrix.values[1][1] = out_y4 - out_y2;
+               matrix.values[1][2] = out_y1;
+               matrix.values[2][0] = 0.0;
+               matrix.values[2][1] = 0.0;
+       }
+       else {
+               det1 = dx3 * dy2 - dy3 * dx2;
+               det2 = dx1 * dy2 - dy1 * dx2;
+               matrix.values[2][0] = det1 / det2;
+               det1 = dx1 * dy3 - dy1 * dx3;
+               det2 = dx1 * dy2 - dy1 * dx2;
+               matrix.values[2][1] = det1 / det2;
+
+               matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
+               matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
+               matrix.values[0][2] = out_x1;
+
+               matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
+               matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
+               matrix.values[1][2] = out_y1;
+       }
+
+       matrix.values[2][2] = 1.0;
 
 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
 // matrix.dump();
@@ -290,25 +263,29 @@ void AffineUnit::calculate_matrix(
        result->translate(-in_x1, -in_y1);
        result->scale(scalex, scaley);
        matrix.multiply(result);
-// double test[3][3] = { { 0.0896, 0.0, 0.0 },
-//                               { 0.0, 0.0896, 0.0 },
-//                               { -0.00126, 0.0, 1.0 } };
+// double test[3][3] = 
+// { { 0.0896, 0.0, 0.0 },  { 0.0, 0.0896, 0.0 },  { -0.00126, 0.0, 1.0 } };
 // memcpy(&result->values[0][0], test, sizeof(test));
 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
 // result->dump();
-
-
 }
 
 static inline float transform_cubic(float dx,
-               float jm1, float j, float jp1, float jp2)
+               float p0, float p1, float p2, float p3)
 {
 /* Catmull-Rom - not bad */
-       float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
-                      ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
-                      ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
-// printf("%f %f %f %f %f\n", result, jm1, j, jp1, jp2);
-       return result;
+       float result = ((( (- p0 + 3*p1 - 3*p2 + p3) * dx +
+                        ( 2*p0 - 5*p1 + 4*p2 - p3 ) ) * dx +
+                        ( - p0 + p2 ) ) * dx + (p1 + p1) ) / 2;
+// printf("%f %f %f %f %f\n", result, p0, p1, p2, p3);
+       return result;
+}
+
+static inline float transform_linear(float dx,
+               float p1, float p2)
+{
+       float result = p1 * (1-dx) + p2 * dx;
+       return result;
 }
 
 
@@ -339,11 +316,10 @@ void AffineUnit::process_package(LoadPackage *package)
 
 // Calculate real coords
        float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
-       if(server->mode == AffineEngine::STRETCH ||
-               server->mode == AffineEngine::PERSPECTIVE ||
-               server->mode == AffineEngine::ROTATE ||
-               server->mode == AffineEngine::TRANSFORM)
-       {
+       if( server->mode == AffineEngine::STRETCH ||
+           server->mode == AffineEngine::PERSPECTIVE ||
+           server->mode == AffineEngine::ROTATE ||
+           server->mode == AffineEngine::TRANSFORM ) {
                out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
                out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
                out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
@@ -353,8 +329,7 @@ void AffineUnit::process_package(LoadPackage *package)
                out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
                out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
        }
-       else
-       {
+       else {
                out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
                out_y1 = server->in_y;
                out_x2 = out_x1 + server->in_w;
@@ -368,9 +343,8 @@ void AffineUnit::process_package(LoadPackage *package)
 
 
 // Rotation with OpenGL uses a simple quad.
-       if(server->mode == AffineEngine::ROTATE &&
-               server->use_opengl)
-       {
+       if( server->mode == AffineEngine::ROTATE &&
+           server->use_opengl ) {
 #ifdef HAVE_GL
                out_x1 -= pivot_offset_x;  out_y1 -= pivot_offset_y;
                out_x2 -= pivot_offset_x;  out_y2 -= pivot_offset_y;
@@ -416,11 +390,10 @@ void AffineUnit::process_package(LoadPackage *package)
 #endif
        }
        else
-       if(server->mode == AffineEngine::PERSPECTIVE ||
-               server->mode == AffineEngine::SHEER ||
-               server->mode == AffineEngine::ROTATE ||
-               server->mode == AffineEngine::TRANSFORM)
-       {
+       if( server->mode == AffineEngine::PERSPECTIVE ||
+           server->mode == AffineEngine::SHEER ||
+           server->mode == AffineEngine::ROTATE ||
+           server->mode == AffineEngine::TRANSFORM ) {
                AffineMatrix matrix;
                float temp;
 // swap points 3 & 4
@@ -435,40 +408,22 @@ void AffineUnit::process_package(LoadPackage *package)
 
 
 
-               if(server->mode != AffineEngine::TRANSFORM)
-               {
-                       calculate_matrix(
-                               server->in_x,
-                               server->in_y,
+               if( server->mode != AffineEngine::TRANSFORM ) {
+                       calculate_matrix( server->in_x, server->in_y,
                                server->in_x + server->in_w,
                                server->in_y + server->in_h,
-                               out_x1,
-                               out_y1,
-                               out_x2,
-                               out_y2,
-                               out_x3,
-                               out_y3,
-                               out_x4,
-                               out_y4,
+                               out_x1, out_y1, out_x2, out_y2,
+                               out_x3, out_y3, out_x4, out_y4,
                                &matrix);
                }
-               else
-               {
+               else {
                        matrix.copy_from(&server->matrix);
                }
 
-// printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n",
-// __LINE__,
-// matrix.values[0][0],
-// matrix.values[0][1],
-// matrix.values[0][2],
-// matrix.values[1][0],
-// matrix.values[1][1],
-// matrix.values[1][2],
-// matrix.values[2][0],
-// matrix.values[2][1],
-// matrix.values[2][2]);
-               int interpolate = 1;
+//printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n", __LINE__,
+// matrix.values[0][0], matrix.values[0][1], matrix.values[0][2],
+// matrix.values[1][0], matrix.values[1][1], matrix.values[1][2],
+// matrix.values[2][0], matrix.values[2][1], matrix.values[2][2]);
                int reverse = !server->forward;
                float tx, ty, tw;
                float xinc, yinc, winc;
@@ -477,22 +432,15 @@ void AffineUnit::process_package(LoadPackage *package)
                int itx = 0, ity = 0;
                int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
 
-               if(reverse)
-               {
+               if(reverse) {
                        m.copy_from(&matrix);
                        m.invert(&im);
                        matrix.copy_from(&im);
                }
-               else
-               {
+               else {
                        matrix.invert(&m);
                }
 
-
-
-
-
-
                float dx1 = 0, dy1 = 0;
                float dx2 = 0, dy2 = 0;
                float dx3 = 0, dy3 = 0;
@@ -507,12 +455,8 @@ void AffineUnit::process_package(LoadPackage *package)
 // printf("AffineUnit::process_package %d use_opengl=%d\n",
 // __LINE__, server->use_opengl);
 
-
-
-
-
-               if(server->use_opengl)
-               {
+               if( server->use_opengl &&
+                   server->interpolation == AffineEngine::AF_DEFAULT ) {
 #ifdef HAVE_GL
                        static const char *affine_frag =
                                "uniform sampler2D tex;\n"
@@ -550,14 +494,11 @@ void AffineUnit::process_package(LoadPackage *package)
                        unsigned int frag_shader = VFrame::make_shader(0,
                                        affine_frag,
                                        0);
-                       if(frag_shader > 0)
-                       {
+                       if( frag_shader > 0 ) {
                                glUseProgram(frag_shader);
                                glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
                                glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"),
-                                       1,
-                                       0,
-                                       affine_matrix);
+                                       1, 0, affine_matrix);
                                glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
                                        (GLfloat)server->output->get_texture_w(),
                                        (GLfloat)server->output->get_texture_h());
@@ -565,21 +506,19 @@ void AffineUnit::process_package(LoadPackage *package)
                                        (GLfloat)server->output->get_w() / server->output->get_texture_w(),
                                        (GLfloat)server->output->get_h() / server->output->get_texture_h());
                                float border_color[] = { 0, 0, 0, 0 };
-                               if(BC_CModels::is_yuv(server->output->get_color_model()))
-                               {
+                               if(BC_CModels::is_yuv(server->output->get_color_model())) {
                                        border_color[1] = 0.5;
                                        border_color[2] = 0.5;
                                }
-                               if(!BC_CModels::has_alpha(server->output->get_color_model()))
-                               {
+                               if(!BC_CModels::has_alpha(server->output->get_color_model())) {
                                        border_color[3] = 1.0;
                                }
 
                                glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
-                                       1,
-                                       (GLfloat*)border_color);
+                                       1, (GLfloat*)border_color);
                                server->output->init_screen();
                                server->output->bind_texture(0);
+                               glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
                                glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
                                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
                                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
@@ -591,527 +530,282 @@ void AffineUnit::process_package(LoadPackage *package)
 #endif // HAVE_GL
                }
 
-
-
-
-
-
 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
 
-       tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
-       ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
+       tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
+       ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
 
-       tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
-       ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
+       tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
+       ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
 
-               CLAMP(ty1, pkg->y1, pkg->y2);
-               CLAMP(ty2, pkg->y1, pkg->y2);
-               CLAMP(tx1, server->out_x, server->out_x + server->out_w);
-               CLAMP(tx2, server->out_x, server->out_x + server->out_w);
+       CLAMP(ty1, pkg->y1, pkg->y2);
+       CLAMP(ty2, pkg->y1, pkg->y2);
+       CLAMP(tx1, server->out_x, server->out_x + server->out_w);
+       CLAMP(tx2, server->out_x, server->out_x + server->out_w);
 
 
-               xinc = m.values[0][0];
-               yinc = m.values[1][0];
-               winc = m.values[2][0];
+       xinc = m.values[0][0];
+       yinc = m.values[1][0];
+       winc = m.values[2][0];
 
-//printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
+//printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n",
+// tx1, ty1, tx2, ty2, out_x4, out_y4);
 //printf("AffineUnit::process_package %d %d %d %d %d\n",
-//__LINE__,
-//min_in_x,
-//max_in_x,
-//min_in_y,
-//max_in_y);
-
-#define CUBIC_ROW(in_row, chroma_offset) \
-       transform_cubic(dx, \
-               in_row[col1_offset] - chroma_offset, \
-               in_row[col2_offset] - chroma_offset, \
-               in_row[col3_offset] - chroma_offset, \
-               in_row[col4_offset] - chroma_offset)
-
-
-#define TRANSFORM(components, type, temp_type, chroma_offset, max) \
-{ \
-       type **in_rows = (type**)server->input->get_rows(); \
-       float round_factor = 0.0; \
-       if(sizeof(type) < 4) round_factor = 0.5; \
-       for(int y = ty1; y < ty2; y++) \
-       { \
-               type *out_row = (type*)server->output->get_rows()[y]; \
+// __LINE__, min_in_x, max_in_x, min_in_y, max_in_y);
+
+#define CUBIC_ROW(in_row, chroma_offset) ( !in_row ? 0 : transform_cubic(dx, \
+               cp>=min_in_x && cp<max_in_x ? in_row[cp*comps]-chroma_offset : 0, \
+               c0>=min_in_x && c0<max_in_x ? in_row[c0*comps]-chroma_offset : 0, \
+               c1>=min_in_x && c1<max_in_x ? in_row[c1*comps]-chroma_offset : 0, \
+               c2>=min_in_x && c2<max_in_x ? in_row[c2*comps]-chroma_offset : 0) )
+
+
+#define DO_CUBIC(tag, components, type, temp_type, chroma_offset, max) \
+case tag: { \
+    type **inp_rows = (type**)server->input->get_rows(); \
+    type **out_rows = (type**)server->output->get_rows(); \
+    float round_factor = sizeof(type) < 4 ? 0.5 : 0; \
+    int comps = components; \
+    for( int y=ty1; y<ty2; ++y ) { \
+        type *out_row = (type*)out_rows[y]; \
  \
-               if(!interpolate) \
-               { \
-               tx = xinc * (tx1 + 0.5) + \
-                               m.values[0][1] * (y + pivot_offset_y + 0.5) + \
-                               m.values[0][2] + \
-                               pivot_offset_x * xinc; \
-               ty = yinc * (tx1 + 0.5) + \
-                               m.values[1][1] * (y + pivot_offset_y + 0.5) + \
-                               m.values[1][2] + \
-                               pivot_offset_x * yinc; \
-               tw = winc * (tx1 + 0.5) + \
-                               m.values[2][1] * (y + pivot_offset_y + 0.5) + \
-                               m.values[2][2] + \
-                               pivot_offset_x * winc; \
-               } \
-       else \
-        { \
-               tx = xinc * tx1 + \
-                               m.values[0][1] * (y + pivot_offset_y) + \
-                               m.values[0][2] + \
-                               pivot_offset_x * xinc; \
-               ty = yinc * tx1 + \
-                               m.values[1][1] * (y + pivot_offset_y) + \
-                               m.values[1][2] + \
-                               pivot_offset_x * yinc; \
-               tw = winc * tx1 + \
-                               m.values[2][1] * (y + pivot_offset_y) + \
-                               m.values[2][2] + \
-                               pivot_offset_x * winc; \
-        } \
- \
- \
-               out_row += tx1 * components; \
-               for(int x = tx1; x < tx2; x++) \
-               { \
+        int x1 = tx1, x2 = tx2; \
+        if( x1 < min_out_x ) x1 = min_out_x; \
+        if( x2 > max_out_x ) x2 = max_out_x; \
+        tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
+            + pivot_offset_x * xinc; \
+        ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
+            + pivot_offset_x * yinc; \
+        tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
+            + pivot_offset_x * winc; \
+        type *out = out_row + x1 * comps; \
+        for( int x=x1; x<x2; ++x ) { \
 /* Normalize homogeneous coords */ \
-                       if(tw == 0.0) \
-                       { \
-                               ttx = 0.0; \
-                               tty = 0.0; \
-                       } \
-                       else \
-                       if(tw != 1.0) \
-                       { \
-                               ttx = tx / tw; \
-                               tty = ty / tw; \
-                       } \
-                       else \
-                       { \
-                               ttx = tx; \
-                               tty = ty; \
-                       } \
-                       itx = (int)ttx; \
-                       ity = (int)tty; \
- \
-                       int row1 = ity - 1; \
-                       int row2 = ity; \
-                       int row3 = ity + 1; \
-                       int row4 = ity + 2; \
-                       CLAMP(row1, min_in_y, max_in_y); \
-                       CLAMP(row2, min_in_y, max_in_y); \
-                       CLAMP(row3, min_in_y, max_in_y); \
-                       CLAMP(row4, min_in_y, max_in_y); \
- \
-/* Set destination pixels if in clipping region */ \
-                       if(!interpolate && \
-                               x >= min_out_x && \
-                               x < max_out_x) \
-                       { \
-                               if(itx >= min_in_x && \
-                                       itx <= max_in_x && \
-                                       ity >= min_in_y && \
-                                       ity <= max_in_y) \
-                               { \
-                                       type *src = in_rows[ity] + itx * components; \
-                                       *out_row++ = *src++; \
-                                       *out_row++ = *src++; \
-                                       *out_row++ = *src++; \
-                                       if(components == 4) *out_row++ = *src; \
-                               } \
-                               else \
-/* Fill with chroma */ \
-                               { \
-                                       *out_row++ = 0; \
-                                       *out_row++ = chroma_offset; \
-                                       *out_row++ = chroma_offset; \
-                                       if(components == 4) *out_row++ = 0; \
-                               } \
-                       } \
-                       else \
-/* Bicubic algorithm */ \
-                       if(interpolate &&  \
-                               x >= min_out_x &&  \
-                               x < max_out_x) \
-                       { \
-/* clipping region */ \
-                               if ((itx + 2) >= min_in_x && \
-                                       (itx - 1) <= max_in_x && \
-                       (ity + 2) >= min_in_y && \
-                                       (ity - 1) <= max_in_y) \
-                { \
-                       float dx, dy; \
- \
+            if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
+            else { ttx = tx / tw; tty = ty / tw; } \
+            itx = (int)ttx;  ity = (int)tty; \
 /* the fractional error */ \
-                       dx = ttx - itx; \
-                       dy = tty - ity; \
- \
-/* Row and column offsets in cubic block */ \
-                                       int col1 = itx - 1; \
-                                       int col2 = itx; \
-                                       int col3 = itx + 1; \
-                                       int col4 = itx + 2; \
-                                       CLAMP(col1, min_in_x, max_in_x); \
-                                       CLAMP(col2, min_in_x, max_in_x); \
-                                       CLAMP(col3, min_in_x, max_in_x); \
-                                       CLAMP(col4, min_in_x, max_in_x); \
-                                       int col1_offset = col1 * components; \
-                                       int col2_offset = col2 * components; \
-                                       int col3_offset = col3 * components; \
-                                       int col4_offset = col4 * components; \
+            float dx = ttx - itx, dy = tty - ity; \
+            if( dx < 0 ) dx += 1; \
+            if( dy < 0 ) dy += 1; \
+/* row/col index */ \
+            int cp = itx-1, c0 = itx+0, c1 = itx+1, c2 = itx+2; \
+            int rp = ity-1, r0 = ity+0, r1 = ity+1, r2 = ity+2; \
+            type *rpp, *r0p, *r1p, *r2p; \
+            rpp = rp>=min_in_y && rp<max_in_y ? inp_rows[rp] : 0; \
+            r0p = r0>=min_in_y && r0<max_in_y ? inp_rows[r0] : 0; \
+            r1p = r1>=min_in_y && r1<max_in_y ? inp_rows[r1] : 0; \
+            r2p = r2>=min_in_y && r2<max_in_y ? inp_rows[r2] : 0; \
+            temp_type r, g, b, a; \
+            r = (temp_type)(transform_cubic(dy, \
+                CUBIC_ROW(rpp, 0x0), CUBIC_ROW(r0p, 0x0), \
+                CUBIC_ROW(r1p, 0x0), CUBIC_ROW(r2p, 0x0)) \
+                + round_factor); \
+            if(rpp) ++rpp;  if(r0p) ++r0p;  if(r1p) ++r1p;  if(r2p) ++r2p; \
+            g = (temp_type)(transform_cubic(dy, \
+                CUBIC_ROW(rpp, chroma_offset), CUBIC_ROW(r0p, chroma_offset), \
+                CUBIC_ROW(r1p, chroma_offset), CUBIC_ROW(r2p, chroma_offset)) \
+                + round_factor) + chroma_offset; \
+            if(rpp) ++rpp;  if(r0p) ++r0p;  if(r1p) ++r1p;  if(r2p) ++r2p; \
+            b = (temp_type)(transform_cubic(dy, \
+                CUBIC_ROW(rpp, chroma_offset), CUBIC_ROW(r0p, chroma_offset), \
+                CUBIC_ROW(r1p, chroma_offset), CUBIC_ROW(r2p, chroma_offset)) \
+                + round_factor) + chroma_offset; \
+            if( components == 4 ) { \
+                if(rpp) ++rpp;  if(r0p) ++r0p;  if(r1p) ++r1p;  if(r2p) ++r2p; \
+                a = (temp_type)(transform_cubic(dy, \
+                    CUBIC_ROW(rpp, 0x0), CUBIC_ROW(r0p, 0x0), \
+                    CUBIC_ROW(r1p, 0x0), CUBIC_ROW(r2p, 0x0)) \
+                    + round_factor); \
+            } \
+            if( sizeof(type) < 4 ) { \
+                *out++ = CLIP(r, 0, max); \
+                *out++ = CLIP(g, 0, max); \
+                *out++ = CLIP(b, 0, max); \
+                if( components == 4 ) *out++ = CLIP(a, 0, max); \
+            } \
+            else { \
+                *out++ = r; \
+                *out++ = g; \
+                *out++ = b; \
+                if( components == 4 ) *out++ = a; \
+            } \
  \
-                                       type *row1_ptr = in_rows[row1]; \
-                                       type *row2_ptr = in_rows[row2]; \
-                                       type *row3_ptr = in_rows[row3]; \
-                                       type *row4_ptr = in_rows[row4]; \
-                                       temp_type r, g, b, a; \
- \
-                                       r = (temp_type)(transform_cubic(dy, \
-                       CUBIC_ROW(row1_ptr, 0x0), \
-                       CUBIC_ROW(row2_ptr, 0x0), \
-                       CUBIC_ROW(row3_ptr, 0x0), \
-                       CUBIC_ROW(row4_ptr, 0x0)) + \
-                                               round_factor); \
- \
-                                       row1_ptr++; \
-                                       row2_ptr++; \
-                                       row3_ptr++; \
-                                       row4_ptr++; \
-                                       g = (temp_type)(transform_cubic(dy, \
-                       CUBIC_ROW(row1_ptr, chroma_offset), \
-                       CUBIC_ROW(row2_ptr, chroma_offset), \
-                       CUBIC_ROW(row3_ptr, chroma_offset), \
-                       CUBIC_ROW(row4_ptr, chroma_offset)) + \
-                                               round_factor); \
-                                       g += chroma_offset; \
+/*  increment the transformed coordinates  */ \
+            tx += xinc;  ty += yinc;  tw += winc; \
+        } \
+    } \
+} break
+
+#define LINEAR_ROW(in_row, chroma_offset) ( !in_row ? 0 : transform_linear(dx, \
+               c0>=min_in_x && c0<max_in_x ? in_row[c0*comps]-chroma_offset : 0, \
+               c1>=min_in_x && c1<max_in_x ? in_row[c1*comps]-chroma_offset : 0) )
+
+#define DO_LINEAR(tag, components, type, temp_type, chroma_offset, max) \
+case tag: { \
+    type **inp_rows = (type**)server->input->get_rows(); \
+    type **out_rows = (type**)server->output->get_rows(); \
+    int comps = components; \
+    float round_factor = sizeof(type) < 4 ? 0.5 : 0; \
+    for( int y=ty1; y<ty2; ++y ) { \
+        type *out_row = (type*)out_rows[y]; \
  \
-                                       row1_ptr++; \
-                                       row2_ptr++; \
-                                       row3_ptr++; \
-                                       row4_ptr++; \
-                                       b = (temp_type)(transform_cubic(dy, \
-                       CUBIC_ROW(row1_ptr, chroma_offset), \
-                       CUBIC_ROW(row2_ptr, chroma_offset), \
-                       CUBIC_ROW(row3_ptr, chroma_offset), \
-                       CUBIC_ROW(row4_ptr, chroma_offset)) + \
-                                               round_factor); \
-                                       b += chroma_offset; \
+        int x1 = tx1, x2 = tx2; \
+        if( x1 < min_out_x ) x1 = min_out_x; \
+        if( x2 > max_out_x ) x2 = max_out_x; \
+        tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
+            + pivot_offset_x * xinc; \
+        ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
+            + pivot_offset_x * yinc; \
+        tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
+            + pivot_offset_x * winc; \
+        type *out = out_row + x1 * comps; \
+        for( int x=x1; x<x2; ++x ) { \
+/* Normalize homogeneous coords */ \
+            if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
+            else { ttx = tx / tw; tty = ty / tw; } \
+            itx = (int)ttx;  ity = (int)tty; \
+/* the fractional error */ \
+            float dx = ttx - itx, dy = tty - ity; \
+            if( dx < 0 ) dx += 1; \
+            if( dy < 0 ) dy += 1; \
+/* row/col index */ \
+            int c0 = itx+0, c1 = itx+1; \
+            int r0 = ity+0, r1 = ity+1; \
+            type *r0p, *r1p; \
+            r0p = r0>=min_in_y && r0<max_in_y ? inp_rows[r0] : 0; \
+            r1p = r1>=min_in_y && r1<max_in_y ? inp_rows[r1] : 0; \
+            temp_type r, g, b, a; \
+            r = (temp_type)(transform_linear(dy, \
+                LINEAR_ROW(r0p, 0x0), LINEAR_ROW(r1p, 0x0)) \
+                + round_factor); \
+            if(r0p) ++r0p;  if(r1p) ++r1p; \
+            g = (temp_type)(transform_linear(dy, \
+                LINEAR_ROW(r0p, chroma_offset), LINEAR_ROW(r1p, chroma_offset)) \
+                + round_factor) + chroma_offset; \
+            if(r0p) ++r0p;  if(r1p) ++r1p; \
+            b = (temp_type)(transform_linear(dy, \
+                LINEAR_ROW(r0p, chroma_offset), LINEAR_ROW(r1p, chroma_offset)) \
+                + round_factor) + chroma_offset; \
+            if( components == 4 ) { \
+                if(r0p) ++r0p;  if(r1p) ++r1p; \
+                a = (temp_type)(transform_linear(dy, \
+                    LINEAR_ROW(r0p, 0x0), LINEAR_ROW(r1p, 0x0)) \
+                    + round_factor); \
+            } \
+            if( sizeof(type) < 4 ) { \
+                *out++ = CLIP(r, 0, max); \
+                *out++ = CLIP(g, 0, max); \
+                *out++ = CLIP(b, 0, max); \
+                if( components == 4 ) *out++ = CLIP(a, 0, max); \
+            } \
+            else { \
+                *out++ = r; \
+                *out++ = g; \
+                *out++ = b; \
+                if( components == 4 ) *out++ = a; \
+            } \
  \
-                                       if(components == 4) \
-                                       { \
-                                               row1_ptr++; \
-                                               row2_ptr++; \
-                                               row3_ptr++; \
-                                               row4_ptr++; \
-                                               a = (temp_type)(transform_cubic(dy, \
-                               CUBIC_ROW(row1_ptr, 0x0), \
-                               CUBIC_ROW(row2_ptr, 0x0), \
-                               CUBIC_ROW(row3_ptr, 0x0), \
-                               CUBIC_ROW(row4_ptr, 0x0)) +  \
-                                                       round_factor); \
-                                       } \
+/*  increment the transformed coordinates  */ \
+            tx += xinc;  ty += yinc;  tw += winc; \
+        } \
+    } \
+} break
+
+#define DO_NEAREST(tag, components, type, temp_type, chroma_offset, max) \
+case tag: { \
+    type **inp_rows = (type**)server->input->get_rows(); \
+    type **out_rows = (type**)server->output->get_rows(); \
+    for( int y=ty1; y<ty2; ++y ) { \
+        type *out_row = (type*)out_rows[y]; \
  \
-                                       if(sizeof(type) < 4) \
-                                       { \
-                                               *out_row++ = CLIP(r, 0, max); \
-                                               *out_row++ = CLIP(g, 0, max); \
-                                               *out_row++ = CLIP(b, 0, max); \
-                                               if(components == 4) *out_row++ = CLIP(a, 0, max); \
-                                       } \
-                                       else \
-                                       { \
-                                               *out_row++ = r; \
-                                               *out_row++ = g; \
-                                               *out_row++ = b; \
-                                               if(components == 4) *out_row++ = a; \
-                                       } \
-                } \
-                               else \
-/* Fill with chroma */ \
-                               { \
-                                       *out_row++ = 0; \
-                                       *out_row++ = chroma_offset; \
-                                       *out_row++ = chroma_offset; \
-                                       if(components == 4) *out_row++ = 0; \
-                               } \
-                       } \
-                       else \
-                       { \
-                               out_row += components; \
-                       } \
+        int x1 = tx1, x2 = tx2; \
+        if( x1 < min_out_x ) x1 = min_out_x; \
+        if( x2 > max_out_x ) x2 = max_out_x; \
+        tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
+            + pivot_offset_x * xinc; \
+        ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
+            + pivot_offset_x * yinc; \
+        tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
+            + pivot_offset_x * winc; \
+        type *out = out_row + x1 * components; \
+        for( int x=x1; x<x2; ++x ) { \
+/* Normalize homogeneous coords */ \
+            if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
+            else { ttx = tx / tw; tty = ty / tw; } \
+            itx = (int)ttx;  ity = (int)tty; \
+/* row/col index */ \
+            type *rp = ity>=min_in_y && ity<max_in_y ? inp_rows[ity] : 0; \
+            temp_type r, g, b, a; \
+            r = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
+            if(rp) ++rp; \
+            g = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
+            if(rp) ++rp; \
+            b = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
+            if( components == 4 ) { \
+                if(rp) ++rp; \
+                a = (temp_type)( rp && itx>=min_in_x && itx<max_in_x ? rp[itx*components] : 0 ); \
+            } \
+            *out++ = r;  *out++ = g;  *out++ = b; \
+            if( components == 4 ) *out++ = a; \
  \
 /*  increment the transformed coordinates  */ \
-                       tx += xinc; \
-                       ty += yinc; \
-                       tw += winc; \
-               } \
-       } \
-}
-
-
-
+            tx += xinc;  ty += yinc;  tw += winc; \
+        } \
+    } \
+} break
 
 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
 // __LINE__, tx1, ty1, tx2, ty2);
-               switch(server->input->get_color_model())
-               {
-                       case BC_RGB_FLOAT:
-                               TRANSFORM(3, float, float, 0x0, 1.0)
-                               break;
-                       case BC_RGB888:
-                               TRANSFORM(3, unsigned char, int, 0x0, 0xff)
-                               break;
-                       case BC_RGBA_FLOAT:
-                               TRANSFORM(4, float, float, 0x0, 1.0)
-                               break;
-                       case BC_RGBA8888:
-                               TRANSFORM(4, unsigned char, int, 0x0, 0xff)
-                               break;
-                       case BC_YUV888:
-// DEBUG
-//                             TRANSFORM(3, unsigned char, int, 0x80, 0xff)
-{
 
-       unsigned char **in_rows = (unsigned char**)server->input->get_rows();
-       float round_factor = 0.0;
-       if(sizeof(unsigned char) < 4) round_factor = 0.5;
-
-       for(int y = ty1; y < ty2; y++)
-       {
-//printf("AffineUnit::process_package %d y=%d tx1=%d tx2=%d ty1=%d ty2=%d\n",
-//__LINE__, y, tx1, tx2, ty1, ty2);
-               unsigned char *out_row = (unsigned char*)server->output->get_rows()[y];
-
-               if(!interpolate)
-               {
-               tx = xinc * (tx1 + 0.5) +
-                               m.values[0][1] * (y + pivot_offset_y + 0.5) +
-                               m.values[0][2] +
-                               pivot_offset_x * xinc;
-               ty = yinc * (tx1 + 0.5) +
-                               m.values[1][1] * (y + pivot_offset_y + 0.5) +
-                               m.values[1][2] +
-                               pivot_offset_x * yinc;
-               tw = winc * (tx1 + 0.5) +
-                               m.values[2][1] * (y + pivot_offset_y + 0.5) +
-                               m.values[2][2] +
-                               pivot_offset_x * winc;
-               }
-       else
-        {
-               tx = xinc * tx1 +
-                               m.values[0][1] * (y + pivot_offset_y) +
-                               m.values[0][2] +
-                               pivot_offset_x * xinc;
-               ty = yinc * tx1 +
-                               m.values[1][1] * (y + pivot_offset_y) +
-                               m.values[1][2] +
-                               pivot_offset_x * yinc;
-               tw = winc * tx1 +
-                               m.values[2][1] * (y + pivot_offset_y) +
-                               m.values[2][2] +
-                               pivot_offset_x * winc;
-        }
-
-
-               out_row += tx1 * 3;
-               for(int x = tx1; x < tx2; x++)
-               {
-/* Normalize homogeneous coords */
-                       if(tw == 0.0)
-                       {
-                               ttx = 0.0;
-                               tty = 0.0;
+               switch( server->interpolation ) {
+               case AffineEngine::AF_NEAREST:
+                       switch( server->input->get_color_model() ) {
+                       DO_NEAREST( BC_RGB_FLOAT, 3, float, float, 0x0, 1.0);
+                       DO_NEAREST( BC_RGB888, 3, unsigned char, int, 0x0, 0xff);
+                       DO_NEAREST( BC_RGBA_FLOAT, 4, float, float, 0x0, 1.0);
+                       DO_NEAREST( BC_RGBA8888, 4, unsigned char, int, 0x0, 0xff);
+                       DO_NEAREST( BC_YUV888, 3, unsigned char, int, 0x80, 0xff);
+                       DO_NEAREST( BC_YUVA8888, 4, unsigned char, int, 0x80, 0xff);
+                       DO_NEAREST( BC_RGB161616, 3, uint16_t, int, 0x0, 0xffff);
+                       DO_NEAREST( BC_RGBA16161616, 4, uint16_t, int, 0x0, 0xffff);
+                       DO_NEAREST( BC_YUV161616, 3, uint16_t, int, 0x8000, 0xffff);
+                       DO_NEAREST( BC_YUVA16161616, 4, uint16_t, int, 0x8000, 0xffff);
                        }
-                       else
-                       if(tw != 1.0)
-                       {
-                               ttx = tx / tw;
-                               tty = ty / tw;
+                       break;
+               case AffineEngine::AF_LINEAR:
+                       switch( server->input->get_color_model() ) {
+                       DO_LINEAR( BC_RGB_FLOAT, 3, float, float, 0x0, 1.0);
+                       DO_LINEAR( BC_RGB888, 3, unsigned char, int, 0x0, 0xff);
+                       DO_LINEAR( BC_RGBA_FLOAT, 4, float, float, 0x0, 1.0);
+                       DO_LINEAR( BC_RGBA8888, 4, unsigned char, int, 0x0, 0xff);
+                       DO_LINEAR( BC_YUV888, 3, unsigned char, int, 0x80, 0xff);
+                       DO_LINEAR( BC_YUVA8888, 4, unsigned char, int, 0x80, 0xff);
+                       DO_LINEAR( BC_RGB161616, 3, uint16_t, int, 0x0, 0xffff);
+                       DO_LINEAR( BC_RGBA16161616, 4, uint16_t, int, 0x0, 0xffff);
+                       DO_LINEAR( BC_YUV161616, 3, uint16_t, int, 0x8000, 0xffff);
+                       DO_LINEAR( BC_YUVA16161616, 4, uint16_t, int, 0x8000, 0xffff);
                        }
-                       else
-                       {
-                               ttx = tx;
-                               tty = ty;
+                       break;
+               default:
+               case AffineEngine::AF_CUBIC:
+                       switch( server->input->get_color_model() ) {
+                       DO_CUBIC( BC_RGB_FLOAT, 3, float, float, 0x0, 1.0);
+                       DO_CUBIC( BC_RGB888, 3, unsigned char, int, 0x0, 0xff);
+                       DO_CUBIC( BC_RGBA_FLOAT, 4, float, float, 0x0, 1.0);
+                       DO_CUBIC( BC_RGBA8888, 4, unsigned char, int, 0x0, 0xff);
+                       DO_CUBIC( BC_YUV888, 3, unsigned char, int, 0x80, 0xff);
+                       DO_CUBIC( BC_YUVA8888, 4, unsigned char, int, 0x80, 0xff);
+                       DO_CUBIC( BC_RGB161616, 3, uint16_t, int, 0x0, 0xffff);
+                       DO_CUBIC( BC_RGBA16161616, 4, uint16_t, int, 0x0, 0xffff);
+                       DO_CUBIC( BC_YUV161616, 3, uint16_t, int, 0x8000, 0xffff);
+                       DO_CUBIC( BC_YUVA16161616, 4, uint16_t, int, 0x8000, 0xffff);
                        }
-                       itx = (int)ttx;
-                       ity = (int)tty;
-
-                       int row1 = ity - 1;
-                       int row2 = ity;
-                       int row3 = ity + 1;
-                       int row4 = ity + 2;
-                       CLAMP(row1, min_in_y, max_in_y);
-                       CLAMP(row2, min_in_y, max_in_y);
-                       CLAMP(row3, min_in_y, max_in_y);
-                       CLAMP(row4, min_in_y, max_in_y);
-
-/* Set destination pixels if in clipping region */
-                       if(!interpolate &&
-                               x >= min_out_x &&
-                               x < max_out_x)
-                       {
-                               if(itx >= min_in_x &&
-                                       itx <= max_in_x &&
-                                       ity >= min_in_y &&
-                                       ity <= max_in_y)
-                               {
-                                       unsigned char *src = in_rows[ity] + itx * 3;
-                                       *out_row++ = *src++;
-                                       *out_row++ = *src++;
-                                       *out_row++ = *src++;
-                                       if(3 == 4) *out_row++ = *src;
-                               }
-                               else
-/* Fill with chroma */
-                               {
-                                       *out_row++ = 0;
-                                       *out_row++ = 0x80;
-                                       *out_row++ = 0x80;
-                                       if(3 == 4) *out_row++ = 0;
-                               }
-                       }
-                       else
-/* Bicubic algorithm */
-                       if(interpolate &&
-                               x >= min_out_x &&
-                               x < max_out_x)
-                       {
-/* clipping region */
-                               if ((itx + 2) >= min_in_x &&
-                                       (itx - 1) <= max_in_x &&
-                       (ity + 2) >= min_in_y &&
-                                       (ity - 1) <= max_in_y)
-                {
-                       float dx, dy;
-
-/* the fractional error */
-                       dx = ttx - itx;
-                       dy = tty - ity;
-
-/* Row and column offsets in cubic block */
-                                       int col1 = itx - 1;
-                                       int col2 = itx;
-                                       int col3 = itx + 1;
-                                       int col4 = itx + 2;
-                                       CLAMP(col1, min_in_x, max_in_x);
-                                       CLAMP(col2, min_in_x, max_in_x);
-                                       CLAMP(col3, min_in_x, max_in_x);
-                                       CLAMP(col4, min_in_x, max_in_x);
-                                       int col1_offset = col1 * 3;
-                                       int col2_offset = col2 * 3;
-                                       int col3_offset = col3 * 3;
-                                       int col4_offset = col4 * 3;
-
-                                       unsigned char *row1_ptr = in_rows[row1];
-                                       unsigned char *row2_ptr = in_rows[row2];
-                                       unsigned char *row3_ptr = in_rows[row3];
-                                       unsigned char *row4_ptr = in_rows[row4];
-                                       int r, g, b, a;
-
-                                       r = (int)(transform_cubic(dy,
-                       CUBIC_ROW(row1_ptr, 0x0),
-                       CUBIC_ROW(row2_ptr, 0x0),
-                       CUBIC_ROW(row3_ptr, 0x0),
-                       CUBIC_ROW(row4_ptr, 0x0)) +
-                                               round_factor);
-
-                                       row1_ptr++;
-                                       row2_ptr++;
-                                       row3_ptr++;
-                                       row4_ptr++;
-                                       g = (int)(transform_cubic(dy,
-                       CUBIC_ROW(row1_ptr, 0x80),
-                       CUBIC_ROW(row2_ptr, 0x80),
-                       CUBIC_ROW(row3_ptr, 0x80),
-                       CUBIC_ROW(row4_ptr, 0x80)) +
-                                               round_factor);
-                                       g += 0x80;
-
-                                       row1_ptr++;
-                                       row2_ptr++;
-                                       row3_ptr++;
-                                       row4_ptr++;
-                                       b = (int)(transform_cubic(dy,
-                       CUBIC_ROW(row1_ptr, 0x80),
-                       CUBIC_ROW(row2_ptr, 0x80),
-                       CUBIC_ROW(row3_ptr, 0x80),
-                       CUBIC_ROW(row4_ptr, 0x80)) +
-                                               round_factor);
-                                       b += 0x80;
-
-                                       if(3 == 4)
-                                       {
-                                               row1_ptr++;
-                                               row2_ptr++;
-                                               row3_ptr++;
-                                               row4_ptr++;
-                                               a = (int)(transform_cubic(dy,
-                               CUBIC_ROW(row1_ptr, 0x0),
-                               CUBIC_ROW(row2_ptr, 0x0),
-                               CUBIC_ROW(row3_ptr, 0x0),
-                               CUBIC_ROW(row4_ptr, 0x0)) +
-                                                       round_factor);
-                                       }
-
-                                       if(sizeof(unsigned char) < 4)
-                                       {
-                                               *out_row++ = CLIP(r, 0, 0xff);
-                                               *out_row++ = CLIP(g, 0, 0xff);
-                                               *out_row++ = CLIP(b, 0, 0xff);
-                                               if(3 == 4) *out_row++ = CLIP(a, 0, 0xff);
-                                       }
-                                       else
-                                       {
-                                               *out_row++ = r;
-                                               *out_row++ = g;
-                                               *out_row++ = b;
-                                               if(3 == 4) *out_row++ = a;
-                                       }
-                }
-                               else
-/* Fill with chroma */
-                               {
-                                       *out_row++ = 0;
-                                       *out_row++ = 0x80;
-                                       *out_row++ = 0x80;
-                                       if(3 == 4) *out_row++ = 0;
-                               }
-                       }
-                       else
-                       {
-                               out_row += 3;
-                       }
-
-/*  increment the transformed coordinates  */
-                       tx += xinc;
-                       ty += yinc;
-                       tw += winc;
+                       break;
                }
        }
-}
-
-                               break;
-                       case BC_YUVA8888:
-                               TRANSFORM(4, unsigned char, int, 0x80, 0xff)
-                               break;
-                       case BC_RGB161616:
-                               TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
-                               break;
-                       case BC_RGBA16161616:
-                               TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
-                               break;
-                       case BC_YUV161616:
-                               TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
-                               break;
-                       case BC_YUVA16161616:
-                               TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
-                               break;
-               }
-
-       }
        else
        {
                int min_x = server->in_x * AFFINE_OVERSAMPLE;
@@ -1140,18 +834,13 @@ void AffineUnit::process_package(LoadPackage *package)
                float h_f = server->in_h;
                float w_f = server->in_w;
 
-
-
-               if(server->use_opengl)
-               {
+               if(server->use_opengl) {
                        return;
                }
 
-
-
 // Projection
-#define DO_STRETCH(type, components) \
-{ \
+#define DO_STRETCH(tag, type, components) \
+case tag: { \
        type **in_rows = (type**)server->input->get_rows(); \
        type **out_rows = (type**)server->temp->get_rows(); \
  \
@@ -1182,59 +871,26 @@ void AffineUnit::process_package(LoadPackage *package)
                        if(components == 4) dst[3] = src[3]; \
                } \
        } \
-}
-
-               switch(server->input->get_color_model())
-               {
-                       case BC_RGB_FLOAT:
-                               DO_STRETCH(float, 3)
-                               break;
-                       case BC_RGB888:
-                               DO_STRETCH(unsigned char, 3)
-                               break;
-                       case BC_RGBA_FLOAT:
-                               DO_STRETCH(float, 4)
-                               break;
-                       case BC_RGBA8888:
-                               DO_STRETCH(unsigned char, 4)
-                               break;
-                       case BC_YUV888:
-                               DO_STRETCH(unsigned char, 3)
-                               break;
-                       case BC_YUVA8888:
-                               DO_STRETCH(unsigned char, 4)
-                               break;
-                       case BC_RGB161616:
-                               DO_STRETCH(uint16_t, 3)
-                               break;
-                       case BC_RGBA16161616:
-                               DO_STRETCH(uint16_t, 4)
-                               break;
-                       case BC_YUV161616:
-                               DO_STRETCH(uint16_t, 3)
-                               break;
-                       case BC_YUVA16161616:
-                               DO_STRETCH(uint16_t, 4)
-                               break;
+} break
+
+               switch( server->input->get_color_model() ) {
+               DO_STRETCH( BC_RGB_FLOAT, float, 3 );
+               DO_STRETCH( BC_RGB888, unsigned char, 3 );
+               DO_STRETCH( BC_RGBA_FLOAT, float, 4 );
+               DO_STRETCH( BC_RGBA8888, unsigned char, 4 );
+               DO_STRETCH( BC_YUV888, unsigned char, 3 );
+               DO_STRETCH( BC_YUVA8888, unsigned char, 4 );
+               DO_STRETCH( BC_RGB161616, uint16_t, 3 );
+               DO_STRETCH( BC_RGBA16161616, uint16_t, 4 );
+               DO_STRETCH( BC_YUV161616, uint16_t, 3 );
+               DO_STRETCH( BC_YUVA16161616, uint16_t, 4 );
                }
        }
-
-
-
-
 }
 
 
-
-
-
-
-AffineEngine::AffineEngine(int total_clients,
-       int total_packages)
- : LoadServer(
-//1, 1
-total_clients, total_packages
-)
+AffineEngine::AffineEngine(int total_clients, int total_packages)
+ : LoadServer(total_clients, total_packages) //(1, 1)
 {
        user_in_viewport = 0;
        user_in_pivot = 0;
@@ -1245,16 +901,17 @@ total_clients, total_packages
        out_x = out_y = out_w = out_h = 0;
        in_pivot_x = in_pivot_y = 0;
        out_pivot_x = out_pivot_y = 0;
+       interpolation = AF_DEFAULT;
        this->total_packages = total_packages;
 }
 
 void AffineEngine::init_packages()
 {
-       for(int i = 0; i < get_total_packages(); i++)
-       {
+       int y1 = 0, npkgs = get_total_packages();
+       for( int i=0; i<npkgs; ) {
                AffinePackage *package = (AffinePackage*)get_package(i);
-               package->y1 = out_y + (out_h * i / get_total_packages());
-               package->y2 = out_y + (out_h * (i + 1) / get_total_packages());
+               int y2 = out_y + (out_h * ++i / npkgs);
+               package->y1 = y1;  package->y2 = y2;  y1 = y2;
        }
 }
 
@@ -1268,90 +925,54 @@ LoadPackage* AffineEngine::new_package()
        return new AffinePackage;
 }
 
-void AffineEngine::process(VFrame *output,
-       VFrame *input,
-       VFrame *temp,
-       int mode,
-       float x1,
-       float y1,
-       float x2,
-       float y2,
-       float x3,
-       float y3,
-       float x4,
-       float y4,
+void AffineEngine::process(VFrame *output, VFrame *input, VFrame *temp, int mode,
+       float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
        int forward)
 {
 
 
 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
-// __LINE__,
-// x1,
-// y1,
-// x2,
-// y2,
-// x3,
-// y3,
-// x4,
-// y4);
+// __LINE__, x1, y1, x2, y2, x3, y3, x4, y4);
 //
 // printf("AffineEngine::process %d %d %d %d %d\n",
-// __LINE__,
-// in_x, in_y, in_w, in_h);
+// __LINE__, in_x, in_y, in_w, in_h);
 //
 // printf("AffineEngine::process %d %d %d %d %d\n",
-// __LINE__,
-// out_x, out_y, out_w, out_h);
+// __LINE__, out_x, out_y, out_w, out_h);
 //
 // printf("AffineEngine::process %d %d %d %d %d\n",
-// __LINE__,
-// in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
+// __LINE__, in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
 //
 // printf("AffineEngine::process %d %d %d %d %d\n",
-// __LINE__,
-// user_in_pivot,
-// user_out_pivot,
-// user_in_viewport,
-// user_out_viewport);
+// __LINE__, user_in_pivot, user_out_pivot, user_in_viewport, user_out_viewport);
 
        this->output = output;
        this->input = input;
        this->temp = temp;
        this->mode = mode;
-       this->x1 = x1;
-       this->y1 = y1;
-       this->x2 = x2;
-       this->y2 = y2;
-       this->x3 = x3;
-       this->y3 = y3;
-       this->x4 = x4;
-       this->y4 = y4;
+       this->x1 = x1;  this->y1 = y1;
+       this->x2 = x2;  this->y2 = y2;
+       this->x3 = x3;  this->y3 = y3;
+       this->x4 = x4;  this->y4 = y4;
        this->forward = forward;
 
-
-       if(!user_in_viewport)
-       {
-               in_x = 0;
-               in_y = 0;
+       if(!user_in_viewport) {
+               in_x = 0;  in_y = 0;
                in_w = input->get_w();
                in_h = input->get_h();
        }
 
-       if(!user_out_viewport)
-       {
-               out_x = 0;
-               out_y = 0;
+       if(!user_out_viewport) {
+               out_x = 0;  out_y = 0;
                out_w = output->get_w();
                out_h = output->get_h();
        }
 
-       if(use_opengl)
-       {
+       if(use_opengl) {
                set_package_count(1);
                process_single();
        }
-       else
-       {
+       else {
                set_package_count(total_packages);
                process_packages();
        }
@@ -1370,10 +991,8 @@ void AffineEngine::rotate(VFrame *output,
        this->mode = ROTATE;
        this->forward = 1;
 
-       if(!user_in_viewport)
-       {
-               in_x = 0;
-               in_y = 0;
+       if( !user_in_viewport ) {
+               in_x = 0;  in_y = 0;
                in_w = input->get_w();
                in_h = input->get_h();
 // DEBUG
@@ -1384,22 +1003,18 @@ void AffineEngine::rotate(VFrame *output,
 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
        }
 
-       if(!user_in_pivot)
-       {
+       if( !user_in_pivot ) {
                in_pivot_x = in_x + in_w / 2;
                in_pivot_y = in_y + in_h / 2;
        }
 
-       if(!user_out_viewport)
-       {
-               out_x = 0;
-               out_y = 0;
+       if( !user_out_viewport ) {
+               out_x = 0;  out_y = 0;
                out_w = output->get_w();
                out_h = output->get_h();
        }
 
-       if(!user_out_pivot)
-       {
+       if( !user_out_pivot ) {
                out_pivot_x = out_x + out_w / 2;
                out_pivot_y = out_y + out_h / 2;
        }
@@ -1429,34 +1044,23 @@ void AffineEngine::rotate(VFrame *output,
 
 //
 // printf("    angle1=%f angle2=%f angle3=%f angle4=%f\n",
-// angle1 * 360 / 2 / M_PI,
-// angle2 * 360 / 2 / M_PI,
-// angle3 * 360 / 2 / M_PI,
-// angle4 * 360 / 2 / M_PI);
+// angle1 * 360 / 2 / M_PI,  angle2 * 360 / 2 / M_PI,
+// angle3 * 360 / 2 / M_PI,  angle4 * 360 / 2 / M_PI);
 //
 // printf("    radius1=%f radius2=%f radius3=%f radius4=%f\n",
-// radius1,
-// radius2,
-// radius3,
-// radius4);
+// radius1, radius2, radius3, radius4);
 //
 // printf("    x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
-// x1 * w / 100,
-// y1 * h / 100,
-// x2 * w / 100,
-// y2 * h / 100,
-// x3 * w / 100,
-// y3 * h / 100,
-// x4 * w / 100,
-// y4 * h / 100);
-
-       if(use_opengl)
-       {
+// x1 * w / 100, y1 * h / 100,
+// x2 * w / 100, y2 * h / 100,
+// x3 * w / 100, y3 * h / 100,
+// x4 * w / 100, y4 * h / 100);
+
+       if(use_opengl) {
                set_package_count(1);
                process_single();
        }
-       else
-       {
+       else {
                set_package_count(total_packages);
                process_packages();
        }
@@ -1464,10 +1068,8 @@ void AffineEngine::rotate(VFrame *output,
 
 void AffineEngine::set_matrix(AffineMatrix *matrix)
 {
-       for(int i = 0; i < 3; i++)
-       {
-               for(int j = 0; j < 3; j++)
-               {
+       for( int i=0; i<3; ++i ) {
+               for( int j=0; j<3; ++j ) {
                        this->matrix.values[i][j] = matrix->values[i][j];
                }
        }
@@ -1475,19 +1077,15 @@ void AffineEngine::set_matrix(AffineMatrix *matrix)
 
 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
 {
-       this->in_x = x;
-       this->in_y = y;
-       this->in_w = w;
-       this->in_h = h;
+       this->in_x = x;  this->in_y = y;
+       this->in_w = w;  this->in_h = h;
        this->user_in_viewport = 1;
 }
 
 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
 {
-       this->out_x = x;
-       this->out_y = y;
-       this->out_w = w;
-       this->out_h = h;
+       this->out_x = x;  this->out_y = y;
+       this->out_w = w;  this->out_h = h;
        this->user_out_viewport = 1;
 }
 
@@ -1535,3 +1133,7 @@ void AffineEngine::unset_viewport()
 }
 
 
+void AffineEngine::set_interpolation(int type)
+{
+       interpolation = type;
+}
index d03f6cd872fd97c33ae67761327045883a8d1690..339c8cbb5c1b931e304a0be656df2b20b9e26bc6 100644 (file)
@@ -86,24 +86,13 @@ public:
 
 // Range of coords is 0 to 100 for coordinates in the image.
 // The coordinate locations are clockwise around the image.
-       void process(VFrame *output,
-               VFrame *input,
-               VFrame *temp,
-               int mode,
-               float x1,
-               float y1,
-               float x2,
-               float y2,
-               float x3,
-               float y3,
-               float x4,
-               float y4,
+       void process(VFrame *output, VFrame *input, VFrame *temp, int mode,
+               float x1, float y1, float x2, float y2,
+               float x3, float y3, float x4, float y4,
                int forward);
 // Do rotation with the affine/perspective transform.
 // This removes some of the extremely faint artifacts in the trig rotation.
-       void rotate(VFrame *output,
-               VFrame *input,
-               float angle);
+       void rotate(VFrame *output, VFrame *input, float angle);
        void set_matrix(AffineMatrix *matrix);
 // Set the viewport to transform.  The transform is based on the input viewport.
 // The output viewport clips the transformed output.
@@ -127,6 +116,8 @@ public:
 // Never used
        void unset_pivot();
        void unset_viewport();
+// default: AF_CUBIC
+       void set_interpolation(int type);
 // To use OpenGL for the processing, set to 1
        void set_opengl(int value);
        void init_packages();
@@ -136,8 +127,7 @@ public:
 
        VFrame *input, *output, *temp;
        int mode;
-       enum
-       {
+       enum {
                PERSPECTIVE,
                SHEER,
                STRETCH,
@@ -145,6 +135,14 @@ public:
 // multiply directly by a matrix.
                TRANSFORM
        };
+       int interpolation;
+       enum {
+               AF_DEFAULT,
+               AF_NEAREST,
+               AF_LINEAR,
+               AF_CUBIC,
+               AF_MODES
+       };
 
 // arbitrary matrix
        AffineMatrix matrix;
index 3eee273f20ea946e090df7228b71958e4d522b66..8383351374405efe1d19696d5f5fa7f6d92d2eeb 100644 (file)
@@ -78,11 +78,7 @@ AssetEdit::~AssetEdit()
 
 void AssetEdit::edit_asset(Indexable *indexable)
 {
-       if(this->indexable)
-       {
-               close_window();
-       }
-
+       close_window();
        this->indexable = indexable;
        this->indexable->add_user();
 
index 12a51429690bf93d5d192d23c89efb5865f25dff..f85b05c08c2983bdfb737ab865e8e942121fb07e 100644 (file)
@@ -147,17 +147,8 @@ int AssetPopupInfo::handle_event()
 {
        if(mwindow->session->drag_assets->total)
        {
-               if(mwindow->awindow->asset_edit->running() &&
-                       mwindow->awindow->asset_edit->window)
-               {
-                       mwindow->awindow->asset_edit->window->raise_window();
-                       mwindow->awindow->asset_edit->window->flush();
-               }
-               else
-               {
-                       mwindow->awindow->asset_edit->edit_asset(
-                               mwindow->session->drag_assets->values[0]);
-               }
+               mwindow->awindow->asset_edit->edit_asset(
+                       mwindow->session->drag_assets->values[0]);
        }
        else
        if(mwindow->session->drag_clips->total)
index 3e956e745808273a4239d835fa3548cc7accca14..e30656737b0269820c19bcba4a2481aa51db62f4 100644 (file)
@@ -127,6 +127,7 @@ BC_Window* ClipEdit::new_gui()
 
 void ClipEdit::edit_clip(EDL *clip)
 {
+       close_window();
 // Allow more than one window so we don't have to delete the clip in handle_event
        if(!this->clip)
        {
index e270bc8c86627df86c5ea3e37a014a9a8dc2b59b..6e2c7f9758503a162de8eccfa951dfa8cdebad2c 100644 (file)
@@ -36,15 +36,12 @@ REGISTER_PLUGIN(PerspectiveMain)
 
 PerspectiveConfig::PerspectiveConfig()
 {
-       x1 = 0;
-       y1 = 0;
-       x2 = 100;
-       y2 = 0;
-       x3 = 100;
-       y3 = 100;
-       x4 = 0;
-       y4 = 100;
+       x1 = 0;    y1 = 0;
+       x2 = 100;  y2 = 0;
+       x3 = 100;  y3 = 100;
+       x4 = 0;    y4 = 100;
        mode = AffineEngine::PERSPECTIVE;
+       smoothing = AffineEngine::AF_DEFAULT;
        window_w = 400;
        window_h = 450;
        current_point = 0;
@@ -63,31 +60,26 @@ int PerspectiveConfig::equivalent(PerspectiveConfig &that)
                EQUIV(x4, that.x4) &&
                EQUIV(y4, that.y4) &&
                mode == that.mode &&
+               smoothing == that.smoothing &&
                forward == that.forward;
 }
 
 void PerspectiveConfig::copy_from(PerspectiveConfig &that)
 {
-       x1 = that.x1;
-       y1 = that.y1;
-       x2 = that.x2;
-       y2 = that.y2;
-       x3 = that.x3;
-       y3 = that.y3;
-       x4 = that.x4;
-       y4 = that.y4;
+       x1 = that.x1;  y1 = that.y1;
+       x2 = that.x2;  y2 = that.y2;
+       x3 = that.x3;  y3 = that.y3;
+       x4 = that.x4;  y4 = that.y4;
        mode = that.mode;
+       smoothing = that.smoothing;
        window_w = that.window_w;
        window_h = that.window_h;
        current_point = that.current_point;
        forward = that.forward;
 }
 
-void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
-       PerspectiveConfig &next,
-       int64_t prev_frame,
-       int64_t next_frame,
-       int64_t current_frame)
+void PerspectiveConfig::interpolate(PerspectiveConfig &prev, PerspectiveConfig &next,
+       int64_t prev_frame, int64_t next_frame, int64_t current_frame)
 {
        double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
        double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
@@ -100,28 +92,15 @@ void PerspectiveConfig::interpolate(PerspectiveConfig &prev,
        this->x4 = prev.x4 * prev_scale + next.x4 * next_scale;
        this->y4 = prev.y4 * prev_scale + next.y4 * next_scale;
        mode = prev.mode;
+       smoothing = prev.smoothing;
        forward = prev.forward;
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
 PerspectiveWindow::PerspectiveWindow(PerspectiveMain *plugin)
  : PluginClientWindow(plugin,
-       plugin->config.window_w,
-       plugin->config.window_h,
-       plugin->config.window_w,
-       plugin->config.window_h,
-       0)
+       plugin->config.window_w, plugin->config.window_h,
+       plugin->config.window_w, plugin->config.window_h, 0)
 {
 //printf("PerspectiveWindow::PerspectiveWindow 1 %d %d\n", plugin->config.window_w, plugin->config.window_h);
        this->plugin = plugin;
@@ -136,69 +115,43 @@ void PerspectiveWindow::create_objects()
        int x = 10, y = 10;
 
        add_subwindow(canvas = new PerspectiveCanvas(plugin,
-               x,
-               y,
-               get_w() - 20,
-               get_h() - 140));
+               x, y, get_w() - 20, get_h() - 140));
        canvas->set_cursor(CROSS_CURSOR, 0, 0);
        y += canvas->get_h() + 10;
        add_subwindow(new BC_Title(x, y, _("Current X:")));
        x += 80;
        this->x = new PerspectiveCoord(this,
-               plugin,
-               x,
-               y,
-               plugin->get_current_x(),
-               1);
+               plugin, x, y, plugin->get_current_x(), 1);
        this->x->create_objects();
        x += 140;
        add_subwindow(new BC_Title(x, y, _("Y:")));
        x += 20;
        this->y = new PerspectiveCoord(this,
-               plugin,
-               x,
-               y,
-               plugin->get_current_y(),
-               0);
+               plugin, x, y, plugin->get_current_y(), 0);
        this->y->create_objects();
-       y += 30;
-       x = 10;
-       add_subwindow(new PerspectiveReset(plugin, x, y));
-       x += 100;
+       x = 10;   y += 30;
        add_subwindow(mode_perspective = new PerspectiveMode(plugin,
-               x,
-               y,
-               AffineEngine::PERSPECTIVE,
-               _("Perspective")));
+               x, y, AffineEngine::PERSPECTIVE, _("Perspective")));
        x += 120;
        add_subwindow(mode_sheer = new PerspectiveMode(plugin,
-               x,
-               y,
-               AffineEngine::SHEER,
-               _("Sheer")));
-       x = 110;
-       y += 30;
+               x, y, AffineEngine::SHEER, _("Sheer")));
+       x += 100;
+       add_subwindow(affine = new PerspectiveAffine(this, x, y));
+       affine->create_objects();
+       x = 10;  y += 30;
        add_subwindow(mode_stretch = new PerspectiveMode(plugin,
-               x,
-               y,
-               AffineEngine::STRETCH,
-               _("Stretch")));
+               x, y, AffineEngine::STRETCH, _("Stretch")));
+       x += 120;
+       add_subwindow(new PerspectiveReset(plugin, x, y));
        update_canvas();
-       y += 30;
-       x = 10;
+       x = 10;   y += 30;
        add_subwindow(new BC_Title(x, y, _("Perspective direction:")));
        x += 170;
        add_subwindow(forward = new PerspectiveDirection(plugin,
-               x,
-               y,
-               1,
-               _("Forward")));
+               x, y, 1, _("Forward")));
        x += 100;
        add_subwindow(reverse = new PerspectiveDirection(plugin,
-               x,
-               y,
-               0,
-               _("Reverse")));
+               x, y, 0, _("Reverse")));
 
        show_window();
 }
@@ -216,29 +169,19 @@ void PerspectiveWindow::update_canvas()
        int x1, y1, x2, y2, x3, y3, x4, y4;
        calculate_canvas_coords(x1, y1, x2, y2, x3, y3, x4, y4);
 
-// printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
-// x1,
-// y1,
-// x2,
-// y2,
-// x3,
-// y3,
-// x4,
-// y4);
+//printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
+// x1, y1, x2, y2, x3, y3, x4, y4);
 // Draw divisions
        canvas->set_color(WHITE);
 
 #define DIVISIONS 10
-       for(int i = 0; i <= DIVISIONS; i++)
-       {
-// latitude
-               canvas->draw_line(
+       for( int i=0; i<=DIVISIONS; ++i ) {
+               canvas->draw_line( // latitude
                        x1 + (x4 - x1) * i / DIVISIONS,
                        y1 + (y4 - y1) * i / DIVISIONS,
                        x2 + (x3 - x2) * i / DIVISIONS,
                        y2 + (y3 - y2) * i / DIVISIONS);
-// longitude
-               canvas->draw_line(
+               canvas->draw_line( // longitude
                        x1 + (x2 - x1) * i / DIVISIONS,
                        y1 + (y2 - y1) * i / DIVISIONS,
                        x4 + (x3 - x4) * i / DIVISIONS,
@@ -285,20 +228,14 @@ void PerspectiveWindow::update_coord()
        y->update(plugin->get_current_y());
 }
 
-void PerspectiveWindow::calculate_canvas_coords(int &x1,
-       int &y1,
-       int &x2,
-       int &y2,
-       int &x3,
-       int &y3,
-       int &x4,
-       int &y4)
+void PerspectiveWindow::calculate_canvas_coords(
+       int &x1, int &y1, int &x2, int &y2,
+       int &x3, int &y3, int &x4, int &y4)
 {
        int w = canvas->get_w() - 1;
        int h = canvas->get_h() - 1;
-       if(plugin->config.mode == AffineEngine::PERSPECTIVE ||
-               plugin->config.mode == AffineEngine::STRETCH)
-       {
+       if( plugin->config.mode == AffineEngine::PERSPECTIVE ||
+           plugin->config.mode == AffineEngine::STRETCH ) {
                x1 = (int)(plugin->config.x1 * w / 100);
                y1 = (int)(plugin->config.y1 * h / 100);
                x2 = (int)(plugin->config.x2 * w / 100);
@@ -308,8 +245,7 @@ void PerspectiveWindow::calculate_canvas_coords(int &x1,
                x4 = (int)(plugin->config.x4 * w / 100);
                y4 = (int)(plugin->config.y4 * h / 100);
        }
-       else
-       {
+       else {
                x1 = (int)(plugin->config.x1 * w) / 100;
                y1 = 0;
                x2 = x1 + w;
@@ -322,13 +258,8 @@ void PerspectiveWindow::calculate_canvas_coords(int &x1,
 }
 
 
-
-
 PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
-       int x,
-       int y,
-       int w,
-       int h)
+       int x, int y, int w, int h)
  : BC_SubWindow(x, y, w, h, BLACK)
 {
        this->plugin = plugin;
@@ -336,12 +267,9 @@ PerspectiveCanvas::PerspectiveCanvas(PerspectiveMain *plugin,
 }
 
 
-
-
 int PerspectiveCanvas::button_press_event()
 {
-       if(is_event_win() && cursor_inside())
-       {
+       if( is_event_win() && cursor_inside() ) {
 // Set current point
                int x1, y1, x2, y2, x3, y3, x4, y4;
                int cursor_x = get_cursor_x();
@@ -360,40 +288,32 @@ int PerspectiveCanvas::button_press_event()
 // y3);
                float min = distance1;
                plugin->config.current_point = 0;
-               if(distance2 < min)
-               {
+               if( distance2 < min ) {
                        min = distance2;
                        plugin->config.current_point = 1;
                }
-               if(distance3 < min)
-               {
+               if( distance3 < min ) {
                        min = distance3;
                        plugin->config.current_point = 2;
                }
-               if(distance4 < min)
-               {
+               if( distance4 < min ) {
                        min = distance4;
                        plugin->config.current_point = 3;
                }
 
-               if(plugin->config.mode == AffineEngine::SHEER)
-               {
-                       if(plugin->config.current_point == 1)
+               if( plugin->config.mode == AffineEngine::SHEER ) {
+                       if( plugin->config.current_point == 1 )
                                plugin->config.current_point = 0;
-                       else
-                       if(plugin->config.current_point == 2)
+                       else if( plugin->config.current_point == 2 )
                                plugin->config.current_point = 3;
                }
                start_cursor_x = cursor_x;
                start_cursor_y = cursor_y;
 
-               if(alt_down() || shift_down())
-               {
-                       if(alt_down())
-                               state = PerspectiveCanvas::DRAG_FULL;
-                       else
-                               state = PerspectiveCanvas::ZOOM;
-
+               if( alt_down() || shift_down() ) {
+                       state =  alt_down() ?
+                               PerspectiveCanvas::DRAG_FULL :
+                               PerspectiveCanvas::ZOOM;
 // Get starting positions
                        start_x1 = plugin->config.x1;
                        start_y1 = plugin->config.y1;
@@ -404,10 +324,8 @@ int PerspectiveCanvas::button_press_event()
                        start_x4 = plugin->config.x4;
                        start_y4 = plugin->config.y4;
                }
-               else
-               {
+               else {
                        state = PerspectiveCanvas::DRAG;
-
 // Get starting positions
                        start_x1 = plugin->get_current_x();
                        start_y1 = plugin->get_current_y();
@@ -422,8 +340,7 @@ int PerspectiveCanvas::button_press_event()
 
 int PerspectiveCanvas::button_release_event()
 {
-       if(state != PerspectiveCanvas::NONE)
-       {
+       if( state != PerspectiveCanvas::NONE ) {
                state = PerspectiveCanvas::NONE;
                return 1;
        }
@@ -432,18 +349,14 @@ int PerspectiveCanvas::button_release_event()
 
 int PerspectiveCanvas::cursor_motion_event()
 {
-       if(state != PerspectiveCanvas::NONE)
-       {
+       if( state != PerspectiveCanvas::NONE ) {
                int w = get_w() - 1;
                int h = get_h() - 1;
-               if(state == PerspectiveCanvas::DRAG)
-               {
+               if( state == PerspectiveCanvas::DRAG ) {
                        plugin->set_current_x((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
                        plugin->set_current_y((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
                }
-               else
-               if(state == PerspectiveCanvas::DRAG_FULL)
-               {
+               else if( state == PerspectiveCanvas::DRAG_FULL ) {
                        plugin->config.x1 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x1);
                        plugin->config.y1 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y1);
                        plugin->config.x2 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x2);
@@ -453,17 +366,9 @@ int PerspectiveCanvas::cursor_motion_event()
                        plugin->config.x4 = ((float)(get_cursor_x() - start_cursor_x) / w * 100 + start_x4);
                        plugin->config.y4 = ((float)(get_cursor_y() - start_cursor_y) / h * 100 + start_y4);
                }
-               else
-               if(state == PerspectiveCanvas::ZOOM)
-               {
-                       float center_x = (start_x1 +
-                               start_x2 +
-                               start_x3 +
-                               start_x4) / 4;
-                       float center_y = (start_y1 +
-                               start_y2 +
-                               start_y3 +
-                               start_y4) / 4;
+               else if( state == PerspectiveCanvas::ZOOM ) {
+                       float center_x = (start_x1 + start_x2 + start_x3 + start_x4) / 4;
+                       float center_y = (start_y1 + start_y2 + start_y3 + start_y4) / 4;
                        float zoom = (float)(get_cursor_y() - start_cursor_y + 640) / 640;
                        plugin->config.x1 = center_x + (start_x1 - center_x) * zoom;
                        plugin->config.y1 = center_y + (start_y1 - center_y) * zoom;
@@ -484,16 +389,8 @@ int PerspectiveCanvas::cursor_motion_event()
 }
 
 
-
-
-
-
 PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
-       PerspectiveMain *plugin,
-       int x,
-       int y,
-       float value,
-       int is_x)
+       PerspectiveMain *plugin, int x, int y, float value, int is_x)
  : BC_TumbleTextBox(gui, value, (float)-100, (float)200, x, y, 100)
 {
        this->plugin = plugin;
@@ -502,39 +399,28 @@ PerspectiveCoord::PerspectiveCoord(PerspectiveWindow *gui,
 
 int PerspectiveCoord::handle_event()
 {
-       if(is_x)
-               plugin->set_current_x(atof(get_text()));
+       float v = atof(get_text());
+       if( is_x )
+               plugin->set_current_x(v);
        else
-               plugin->set_current_y(atof(get_text()));
+               plugin->set_current_y(v);
        ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
        plugin->send_configure_change();
        return 1;
 }
 
 
-
-
-
-
-
-
-PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin,
-       int x,
-       int y)
+PerspectiveReset::PerspectiveReset(PerspectiveMain *plugin, int x, int y)
  : BC_GenericButton(x, y, _("Reset"))
 {
        this->plugin = plugin;
 }
 int PerspectiveReset::handle_event()
 {
-       plugin->config.x1 = 0;
-       plugin->config.y1 = 0;
-       plugin->config.x2 = 100;
-       plugin->config.y2 = 0;
-       plugin->config.x3 = 100;
-       plugin->config.y3 = 100;
-       plugin->config.x4 = 0;
-       plugin->config.y4 = 100;
+       plugin->config.x1 = 0;    plugin->config.y1 = 0;
+       plugin->config.x2 = 100;  plugin->config.y2 = 0;
+       plugin->config.x3 = 100;  plugin->config.y3 = 100;
+       plugin->config.x4 = 0;    plugin->config.y4 = 100;
        ((PerspectiveWindow*)plugin->thread->window)->update_canvas();
        ((PerspectiveWindow*)plugin->thread->window)->update_coord();
        plugin->send_configure_change();
@@ -542,20 +428,8 @@ int PerspectiveReset::handle_event()
 }
 
 
-
-
-
-
-
-
-
-
-
 PerspectiveMode::PerspectiveMode(PerspectiveMain *plugin,
-       int x,
-       int y,
-       int value,
-       char *text)
+       int x, int y, int value, char *text)
  : BC_Radial(x, y, plugin->config.mode == value, text)
 {
        this->plugin = plugin;
@@ -571,8 +445,6 @@ int PerspectiveMode::handle_event()
 }
 
 
-
-
 PerspectiveDirection::PerspectiveDirection(PerspectiveMain *plugin,
        int x,
        int y,
@@ -592,15 +464,53 @@ int PerspectiveDirection::handle_event()
 }
 
 
+int PerspectiveAffineItem::handle_event()
+{
+       ((PerspectiveAffine *)get_popup_menu())->update(id);
+       return 1;
+}
 
+PerspectiveAffine::PerspectiveAffine(PerspectiveWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, 100, "", 1)
+{
+       this->gui = gui;
+       affine_modes[AffineEngine::AF_DEFAULT]     = _("default");
+       affine_modes[AffineEngine::AF_NEAREST]     = _("Nearest");
+       affine_modes[AffineEngine::AF_LINEAR]      = _("Linear");
+       affine_modes[AffineEngine::AF_CUBIC]       = _("Cubic");
+       mode = -1;
+}
+PerspectiveAffine::~PerspectiveAffine()
+{
+       int id = total_items();
+       while( --id >= 0 )
+               remove_item(get_item(id));
+       for( int id=0; id<n_modes; ++id )
+               delete affine_items[id];
+}
+void PerspectiveAffine::affine_item(int id)
+{
+       affine_items[id] = new PerspectiveAffineItem(affine_modes[id], id);
+       add_item(affine_items[id]);
+}
 
+void PerspectiveAffine::create_objects()
+{
+       affine_item(AffineEngine::AF_DEFAULT);
+       affine_item(AffineEngine::AF_NEAREST);
+       affine_item(AffineEngine::AF_LINEAR);
+       affine_item(AffineEngine::AF_CUBIC);
+       update(gui->plugin->config.smoothing, 0);
+}
 
-
-
-
-
-
-
+void PerspectiveAffine::update(int mode, int send)
+{
+       if( this->mode == mode ) return;
+       this->mode = mode;
+       set_text(affine_modes[mode]);
+       gui->plugin->config.smoothing = mode;
+       if( send ) gui->plugin->send_configure_change();
+}
 
 PerspectiveMain::PerspectiveMain(PluginServer *server)
  : PluginVClient(server)
@@ -621,27 +531,23 @@ const char* PerspectiveMain::plugin_title() { return _("Perspective"); }
 int PerspectiveMain::is_realtime() { return 1; }
 
 
-
 NEW_WINDOW_MACRO(PerspectiveMain, PerspectiveWindow)
 
 LOAD_CONFIGURATION_MACRO(PerspectiveMain, PerspectiveConfig)
 
-
-
 void PerspectiveMain::update_gui()
 {
-       if(thread)
-       {
+       if( !thread ) return;
 //printf("PerspectiveMain::update_gui 1\n");
-               thread->window->lock_window();
+       thread->window->lock_window();
+       PerspectiveWindow *gui = (PerspectiveWindow*)thread->window;
 //printf("PerspectiveMain::update_gui 2\n");
-               load_configuration();
-               ((PerspectiveWindow*)thread->window)->update_coord();
-               ((PerspectiveWindow*)thread->window)->update_mode();
-               ((PerspectiveWindow*)thread->window)->update_canvas();
-               thread->window->unlock_window();
+       load_configuration();
+       gui->update_coord();
+       gui->update_mode();
+       gui->update_canvas();
+       thread->window->unlock_window();
 //printf("PerspectiveMain::update_gui 3\n");
-       }
 }
 
 
@@ -666,6 +572,7 @@ void PerspectiveMain::save_data(KeyFrame *keyframe)
        output.tag.set_property("Y4", config.y4);
 
        output.tag.set_property("MODE", config.mode);
+       output.tag.set_property("SMOOTHING", config.smoothing);
        output.tag.set_property("FORWARD", config.forward);
        output.tag.set_property("WINDOW_W", config.window_w);
        output.tag.set_property("WINDOW_H", config.window_h);
@@ -679,320 +586,187 @@ void PerspectiveMain::save_data(KeyFrame *keyframe)
 void PerspectiveMain::read_data(KeyFrame *keyframe)
 {
        FileXML input;
-
        input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
        int result = 0;
 
-       while(!result)
-       {
-               result = input.read_tag();
-
-               if(!result)
-               {
-                       if(input.tag.title_is("PERSPECTIVE"))
-                       {
-                               config.x1 = input.tag.get_property("X1", config.x1);
-                               config.x2 = input.tag.get_property("X2", config.x2);
-                               config.x3 = input.tag.get_property("X3", config.x3);
-                               config.x4 = input.tag.get_property("X4", config.x4);
-                               config.y1 = input.tag.get_property("Y1", config.y1);
-                               config.y2 = input.tag.get_property("Y2", config.y2);
-                               config.y3 = input.tag.get_property("Y3", config.y3);
-                               config.y4 = input.tag.get_property("Y4", config.y4);
-
-                               config.mode = input.tag.get_property("MODE", config.mode);
-                               config.forward = input.tag.get_property("FORWARD", config.forward);
-                               config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
-                               config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
-                       }
+       while(!(result = input.read_tag()) ) {
+               if(input.tag.title_is("PERSPECTIVE")) {
+                       config.x1 = input.tag.get_property("X1", config.x1);
+                       config.x2 = input.tag.get_property("X2", config.x2);
+                       config.x3 = input.tag.get_property("X3", config.x3);
+                       config.x4 = input.tag.get_property("X4", config.x4);
+                       config.y1 = input.tag.get_property("Y1", config.y1);
+                       config.y2 = input.tag.get_property("Y2", config.y2);
+                       config.y3 = input.tag.get_property("Y3", config.y3);
+                       config.y4 = input.tag.get_property("Y4", config.y4);
+
+                       config.mode = input.tag.get_property("MODE", config.mode);
+                       config.smoothing = input.tag.get_property("SMOOTHING", config.smoothing);
+                       config.forward = input.tag.get_property("FORWARD", config.forward);
+                       config.window_w = input.tag.get_property("WINDOW_W", config.window_w);
+                       config.window_h = input.tag.get_property("WINDOW_H", config.window_h);
                }
        }
 }
 
 float PerspectiveMain::get_current_x()
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       return config.x1;
-                       break;
-               case 1:
-                       return config.x2;
-                       break;
-               case 2:
-                       return config.x3;
-                       break;
-               case 3:
-                       return config.x4;
-                       break;
+       switch( config.current_point ) {
+       case 0: return config.x1;
+       case 1: return config.x2;
+       case 2: return config.x3;
+       case 3: return config.x4;
        }
        return 0;
 }
 
 float PerspectiveMain::get_current_y()
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       return config.y1;
-                       break;
-               case 1:
-                       return config.y2;
-                       break;
-               case 2:
-                       return config.y3;
-                       break;
-               case 3:
-                       return config.y4;
-                       break;
+       switch( config.current_point ) {
+       case 0: return config.y1;
+       case 1: return config.y2;
+       case 2: return config.y3;
+       case 3: return config.y4;
        }
        return 0;
 }
 
 void PerspectiveMain::set_current_x(float value)
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       config.x1 = value;
-                       break;
-               case 1:
-                       config.x2 = value;
-                       break;
-               case 2:
-                       config.x3 = value;
-                       break;
-               case 3:
-                       config.x4 = value;
-                       break;
+       switch( config.current_point ) {
+       case 0: config.x1 = value; break;
+       case 1: config.x2 = value; break;
+       case 2: config.x3 = value; break;
+       case 3: config.x4 = value; break;
        }
 }
 
 void PerspectiveMain::set_current_y(float value)
 {
-       switch(config.current_point)
-       {
-               case 0:
-                       config.y1 = value;
-                       break;
-               case 1:
-                       config.y2 = value;
-                       break;
-               case 2:
-                       config.y3 = value;
-                       break;
-               case 3:
-                       config.y4 = value;
-                       break;
+       switch( config.current_point ) {
+       case 0: config.y1 = value; break;
+       case 1: config.y2 = value; break;
+       case 2: config.y3 = value; break;
+       case 3: config.y4 = value; break;
        }
 }
 
-
-
 int PerspectiveMain::process_buffer(VFrame *frame,
-       int64_t start_position,
-       double frame_rate)
+       int64_t start_position, double frame_rate)
 {
        /*int need_reconfigure =*/ load_configuration();
+       int smoothing = config.smoothing;
+// default smoothing uses opengl if possible
+       int use_opengl = smoothing != AffineEngine::AF_DEFAULT ? 0 :
+// Opengl does some funny business with stretching.
+               config.mode == AffineEngine::PERSPECTIVE ||
+                config.mode == AffineEngine::SHEER ? get_use_opengl() : 0;
+
+       read_frame(frame, 0, start_position, frame_rate, use_opengl);
 
 // Do nothing
+
        if( EQUIV(config.x1, 0)   && EQUIV(config.y1, 0) &&
-               EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
-               EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
-               EQUIV(config.x4, 0)   && EQUIV(config.y4, 100))
-       {
-               read_frame(frame,
-                       0,
-                       start_position,
-                       frame_rate,
-                       get_use_opengl());
+           EQUIV(config.x2, 100) && EQUIV(config.y2, 0) &&
+           EQUIV(config.x3, 100) && EQUIV(config.y3, 100) &&
+           EQUIV(config.x4, 0)   && EQUIV(config.y4, 100) )
                return 1;
+
+       if( !engine ) {
+               int cpus = get_project_smp() + 1;
+               engine = new AffineEngine(cpus, cpus);
        }
+       engine->set_interpolation(smoothing);
 
-// Opengl does some funny business with stretching.
-       int use_opengl = get_use_opengl() &&
-               (config.mode == AffineEngine::PERSPECTIVE ||
-               config.mode == AffineEngine::SHEER);
-       read_frame(frame,
-               0,
-               start_position,
-               frame_rate,
-               use_opengl);
-
-       if(!engine) engine = new AffineEngine(get_project_smp() + 1,
-               get_project_smp() + 1);
-
-       if(use_opengl)
+       if( use_opengl )
                return run_opengl();
 
-
-
        this->input = frame;
        this->output = frame;
 
-       int w = frame->get_w();
-       int h = frame->get_h();
+       int w = frame->get_w(), need_w = w;
+       int h = frame->get_h(), need_h = h;
        int color_model = frame->get_color_model();
-
-       if(temp &&
-               config.mode == AffineEngine::STRETCH &&
-               (temp->get_w() != w * AFFINE_OVERSAMPLE ||
-                       temp->get_h() != h * AFFINE_OVERSAMPLE))
-       {
-               delete temp;
-               temp = 0;
-       }
-       else
-       if(temp &&
-               (config.mode == AffineEngine::PERSPECTIVE ||
-               config.mode == AffineEngine::SHEER) &&
-               (temp->get_w() != w ||
-                       temp->get_h() != h))
-       {
-               delete temp;
-               temp = 0;
-       }
-
-       if(config.mode == AffineEngine::STRETCH)
-       {
-               if(!temp)
-               {
-                       temp = new VFrame(0,
-                                       -1,
-                                       w * AFFINE_OVERSAMPLE,
-                                       h * AFFINE_OVERSAMPLE,
-                                       color_model,
-                                       -1);
-               }
-               temp->clear_frame();
-       }
-
-       if(config.mode == AffineEngine::PERSPECTIVE ||
-               config.mode == AffineEngine::SHEER)
-       {
-               if(frame->get_rows()[0] == frame->get_rows()[0])
-               {
-                       if(!temp)
-                       {
-                               temp = new VFrame(0,
-                                       -1,
-                                       w,
-                                       h,
-                                       color_model,
-                                       -1);
+       switch( config.mode ) {
+       case AffineEngine::STRETCH:
+               need_w *= AFFINE_OVERSAMPLE;
+               need_h *= AFFINE_OVERSAMPLE;
+       case AffineEngine::SHEER:
+       case AffineEngine::PERSPECTIVE:
+               if( temp ) {
+                       if( temp->get_w() != need_w || temp->get_h() != need_h ||
+                           temp->get_color_model() != color_model ) {
+                               delete temp;  temp = 0;
                        }
-                       temp->copy_from(input);
-                       input = temp;
                }
+               if( !temp )
+                       temp = new VFrame(need_w, need_h, color_model);
+               break;
+       }
+       switch( config.mode ) {
+       case AffineEngine::STRETCH:
+               temp->clear_frame();
+               break;
+       case AffineEngine::PERSPECTIVE:
+       case AffineEngine::SHEER:
+               temp->copy_from(input);
+               input = temp;
                output->clear_frame();
+               break;
+       default:
+               delete temp;  temp = 0;
+               break;
        }
 
-
-       engine->process(output,
-               input,
-               temp,
-               config.mode,
-               config.x1,
-               config.y1,
-               config.x2,
-               config.y2,
-               config.x3,
-               config.y3,
-               config.x4,
-               config.y4,
+       engine->process(output, input, temp, config.mode,
+               config.x1, config.y1, config.x2, config.y2,
+               config.x3, config.y3, config.x4, config.y4,
                config.forward);
 
-
-
-
 // Resample
 
-       if(config.mode == AffineEngine::STRETCH)
-       {
-#define RESAMPLE(type, components, chroma_offset) \
-{ \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *out_row = (type*)output->get_rows()[i]; \
-               type *in_row1 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE]; \
-               type *in_row2 = (type*)temp->get_rows()[i * AFFINE_OVERSAMPLE + 1]; \
-               for(int j = 0; j < w; j++) \
-               { \
-                       out_row[0] = (in_row1[0] +  \
-                                       in_row1[components] +  \
-                                       in_row2[0] +  \
-                                       in_row2[components]) /  \
-                               AFFINE_OVERSAMPLE /  \
-                               AFFINE_OVERSAMPLE; \
-                       out_row[1] = ((in_row1[1] +  \
-                                               in_row1[components + 1] +  \
-                                               in_row2[1] +  \
-                                               in_row2[components + 1]) -  \
-                                       chroma_offset *  \
-                                       AFFINE_OVERSAMPLE *  \
-                                       AFFINE_OVERSAMPLE) /  \
-                               AFFINE_OVERSAMPLE /  \
-                               AFFINE_OVERSAMPLE + \
-                               chroma_offset; \
-                       out_row[2] = ((in_row1[2] +  \
-                                               in_row1[components + 2] +  \
-                                               in_row2[2] +  \
-                                               in_row2[components + 2]) -  \
-                                       chroma_offset *  \
-                                       AFFINE_OVERSAMPLE *  \
-                                       AFFINE_OVERSAMPLE) /  \
-                               AFFINE_OVERSAMPLE /  \
-                               AFFINE_OVERSAMPLE + \
-                               chroma_offset; \
-                       if(components == 4) \
-                       { \
-                               out_row[3] = (in_row1[3] +  \
-                                               in_row1[components + 3] +  \
-                                               in_row2[3] +  \
-                                               in_row2[components + 3]) /  \
-                                       AFFINE_OVERSAMPLE /  \
-                                       AFFINE_OVERSAMPLE; \
-                       } \
-                       out_row += components; \
-                       in_row1 += components * AFFINE_OVERSAMPLE; \
-                       in_row2 += components * AFFINE_OVERSAMPLE; \
-               } \
-       } \
-}
-
-               switch(frame->get_color_model())
-               {
-                       case BC_RGB_FLOAT:
-                               RESAMPLE(float, 3, 0)
-                               break;
-                       case BC_RGB888:
-                               RESAMPLE(unsigned char, 3, 0)
-                               break;
-                       case BC_RGBA_FLOAT:
-                               RESAMPLE(float, 4, 0)
-                               break;
-                       case BC_RGBA8888:
-                               RESAMPLE(unsigned char, 4, 0)
-                               break;
-                       case BC_YUV888:
-                               RESAMPLE(unsigned char, 3, 0x80)
-                               break;
-                       case BC_YUVA8888:
-                               RESAMPLE(unsigned char, 4, 0x80)
-                               break;
-                       case BC_RGB161616:
-                               RESAMPLE(uint16_t, 3, 0)
-                               break;
-                       case BC_RGBA16161616:
-                               RESAMPLE(uint16_t, 4, 0)
-                               break;
-                       case BC_YUV161616:
-                               RESAMPLE(uint16_t, 3, 0x8000)
-                               break;
-                       case BC_YUVA16161616:
-                               RESAMPLE(uint16_t, 4, 0x8000)
-                               break;
+       if( config.mode == AffineEngine::STRETCH ) {
+
+#define RESAMPLE(tag, type, components, chroma_offset) \
+case tag: { \
+    int os = AFFINE_OVERSAMPLE, os2 = os*os; \
+    for( int i=0; i<h; ++i ) { \
+        type *out_row = (type*)output->get_rows()[i]; \
+        type *in_row1 = (type*)temp->get_rows()[i * os]; \
+        type *in_row2 = (type*)temp->get_rows()[i * os + 1]; \
+        for( int j=0; j<w; ++j ) { \
+            out_row[0] = \
+                ( in_row1[0] + in_row1[components + 0] +  \
+                  in_row2[0] + in_row2[components + 0] ) / os2; \
+            out_row[1] = \
+                ( in_row1[1] + in_row1[components + 1] + \
+                  in_row2[1] + in_row2[components + 1] ) / os2; \
+            out_row[2] = \
+                ( in_row1[2] + in_row1[components + 2] + \
+                  in_row2[2] + in_row2[components + 2] ) / os2; \
+            if( components == 4 ) { \
+                out_row[3] = \
+                   ( in_row1[3] + in_row1[components + 3] +  \
+                      in_row2[3] + in_row2[components + 3] ) / os2; \
+            } \
+            out_row += components; \
+            in_row1 += components * os; \
+            in_row2 += components * os; \
+        } \
+    } \
+} break
+
+               switch( frame->get_color_model() ) {
+               RESAMPLE( BC_RGB_FLOAT, float, 3, 0 );
+               RESAMPLE( BC_RGB888, unsigned char, 3, 0 );
+               RESAMPLE( BC_RGBA_FLOAT, float, 4, 0 );
+               RESAMPLE( BC_RGBA8888, unsigned char, 4, 0 );
+               RESAMPLE( BC_YUV888, unsigned char, 3, 0x80 );
+               RESAMPLE( BC_YUVA8888, unsigned char, 4, 0x80 );
+               RESAMPLE( BC_RGB161616, uint16_t, 3, 0 );
+               RESAMPLE( BC_RGBA16161616, uint16_t, 4, 0 );
+               RESAMPLE( BC_YUV161616, uint16_t, 3, 0x8000 );
+               RESAMPLE( BC_YUVA16161616, uint16_t, 4, 0x8000 );
                }
        }
 
@@ -1004,26 +778,12 @@ int PerspectiveMain::handle_opengl()
 {
 #ifdef HAVE_GL
        engine->set_opengl(1);
-       engine->process(get_output(),
-               get_output(),
-               get_output(),
-               config.mode,
-               config.x1,
-               config.y1,
-               config.x2,
-               config.y2,
-               config.x3,
-               config.y3,
-               config.x4,
-               config.y4,
+       engine->process(get_output(), get_output(), get_output(), config.mode,
+               config.x1, config.y1, config.x2, config.y2,
+               config.x3, config.y3, config.x4, config.y4,
                config.forward);
        engine->set_opengl(0);
        return 0;
 #endif
 }
 
-
-
-
-
-
index a4643d886da2818f7642f9621fe38a98f3c81c63..18e54584990bc1c50af3df8becbab0a84014b29c 100644 (file)
 #include "pluginvclient.h"
 #include "vframe.h"
 
-class PerspectiveMain;
-class PerspectiveWindow;
-
-
 
+class PerspectiveConfig;
+class PerspectiveCanvas;
+class PerspectiveCoord;
+class PerspectiveReset;
+class PerspectiveMode;
+class PerspectiveDirection;
+class PerspectiveAffine;
+class PerspectiveAffineItem;
+class PerspectiveWindow;
+class PerspectiveMain;
 
 class PerspectiveConfig
 {
@@ -45,14 +51,11 @@ public:
 
        int equivalent(PerspectiveConfig &that);
        void copy_from(PerspectiveConfig &that);
-       void interpolate(PerspectiveConfig &prev,
-               PerspectiveConfig &next,
-               int64_t prev_frame,
-               int64_t next_frame,
-               int64_t current_frame);
+       void interpolate(PerspectiveConfig &prev, PerspectiveConfig &next,
+               int64_t prev_frame, int64_t next_frame, int64_t current_frame);
 
        float x1, y1, x2, y2, x3, y3, x4, y4;
-       int mode;
+       int mode, smoothing;
        int window_w, window_h;
        int current_point;
        int forward;
@@ -64,22 +67,13 @@ class PerspectiveCanvas : public BC_SubWindow
 {
 public:
        PerspectiveCanvas(PerspectiveMain *plugin,
-               int x,
-               int y,
-               int w,
-               int h);
+               int x, int y, int w, int h);
        int button_press_event();
        int button_release_event();
        int cursor_motion_event();
-       int state;
 
-       enum
-       {
-               NONE,
-               DRAG,
-               DRAG_FULL,
-               ZOOM
-       };
+       int state;
+       enum { NONE, DRAG, DRAG_FULL, ZOOM };
 
        int start_cursor_x, start_cursor_y;
        float start_x1, start_y1;
@@ -94,10 +88,7 @@ class PerspectiveCoord : public BC_TumbleTextBox
 public:
        PerspectiveCoord(PerspectiveWindow *gui,
                PerspectiveMain *plugin,
-               int x,
-               int y,
-               float value,
-               int is_x);
+               int x, int y, float value, int is_x);
        int handle_event();
        PerspectiveMain *plugin;
        int is_x;
@@ -107,8 +98,7 @@ class PerspectiveReset : public BC_GenericButton
 {
 public:
        PerspectiveReset(PerspectiveMain *plugin,
-               int x,
-               int y);
+               int x, int y);
        int handle_event();
        PerspectiveMain *plugin;
 };
@@ -117,10 +107,7 @@ class PerspectiveMode : public BC_Radial
 {
 public:
        PerspectiveMode(PerspectiveMain *plugin,
-               int x,
-               int y,
-               int value,
-               char *text);
+               int x, int y, int value, char *text);
        int handle_event();
        PerspectiveMain *plugin;
        int value;
@@ -130,15 +117,42 @@ class PerspectiveDirection : public BC_Radial
 {
 public:
        PerspectiveDirection(PerspectiveMain *plugin,
-               int x,
-               int y,
-               int value,
-               char *text);
+               int x, int y, int value, char *text);
        int handle_event();
        PerspectiveMain *plugin;
        int value;
 };
 
+class PerspectiveAffine : public BC_PopupMenu
+{
+       static const int n_modes = AffineEngine::AF_MODES;
+       const char *affine_modes[n_modes];
+       PerspectiveAffineItem *affine_items[n_modes];
+public:
+       PerspectiveAffine(PerspectiveWindow *gui, int x, int y);
+       ~PerspectiveAffine();
+
+       void create_objects();
+       void update(int mode, int send=1);
+       void affine_item(int id);
+
+       PerspectiveWindow *gui;
+       int mode;
+};
+
+class PerspectiveAffineItem : public BC_MenuItem
+{
+public:
+       PerspectiveAffineItem(const char *txt, int id)
+       : BC_MenuItem(txt) { this->id = id; }
+
+       int handle_event();
+       PerspectiveWindow *gui;
+       int id;
+};
+
+
+
 class PerspectiveWindow : public PluginClientWindow
 {
 public:
@@ -150,28 +164,20 @@ public:
        void update_canvas();
        void update_mode();
        void update_coord();
-       void calculate_canvas_coords(int &x1,
-               int &y1,
-               int &x2,
-               int &y2,
-               int &x3,
-               int &y3,
-               int &x4,
-               int &y4);
+       void calculate_canvas_coords(
+               int &x1, int &y1, int &x2, int &y2,
+               int &x3, int &y3, int &x4, int &y4);
 
        PerspectiveCanvas *canvas;
        PerspectiveCoord *x, *y;
        PerspectiveReset *reset;
        PerspectiveMode *mode_perspective, *mode_sheer, *mode_stretch;
+       PerspectiveAffine *affine;
        PerspectiveMain *plugin;
        PerspectiveDirection *forward, *reverse;
 };
 
 
-
-
-
-
 class PerspectiveMain : public PluginVClient
 {
 public:
@@ -199,13 +205,3 @@ public:
 };
 
 
-
-
-
-
-
-
-
-
-
-