4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #define GL_GLEXT_PROTOTYPES
38 AffineMatrix::AffineMatrix()
40 bzero(values, sizeof(values));
43 void AffineMatrix::identity()
45 bzero(values, sizeof(values));
51 void AffineMatrix::translate(double x, double y)
53 double g = values[2][0];
54 double h = values[2][1];
55 double i = values[2][2];
56 values[0][0] += x * g;
57 values[0][1] += x * h;
58 values[0][2] += x * i;
59 values[1][0] += y * g;
60 values[1][1] += y * h;
61 values[1][2] += y * i;
64 void AffineMatrix::scale(double x, double y)
75 void AffineMatrix::multiply(AffineMatrix *dst)
79 for( int i=0; i<3; ++i ) {
80 double t1 = values[i][0], t2 = values[i][1], t3 = values[i][2];
81 for( int j=0; j<3; ++j ) {
82 tmp.values[i][j] = t1 * dst->values[0][j];
83 tmp.values[i][j] += t2 * dst->values[1][j];
84 tmp.values[i][j] += t3 * dst->values[2][j];
90 double AffineMatrix::determinant()
95 values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
97 values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
99 values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
104 void AffineMatrix::invert(AffineMatrix *dst)
108 det_1 = determinant();
116 (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
119 - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
122 (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
125 - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
128 (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
131 - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
134 (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
137 - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
140 (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
143 void AffineMatrix::copy_from(AffineMatrix *src)
145 memcpy(&values[0][0], &src->values[0][0], sizeof(values));
148 void AffineMatrix::transform_point(float x,
155 w = values[2][0] * x + values[2][1] * y + values[2][2];
158 *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
159 *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
162 void AffineMatrix::dump()
164 printf("AffineMatrix::dump\n");
165 printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
166 printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
167 printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
174 AffinePackage::AffinePackage()
182 AffineUnit::AffineUnit(AffineEngine *server)
185 this->server = server;
196 void AffineUnit::calculate_matrix(
197 double in_x1, double in_y1, double in_x2, double in_y2,
198 double out_x1, double out_y1, double out_x2, double out_y2,
199 double out_x3, double out_y3, double out_x4, double out_y4,
200 AffineMatrix *result)
206 scalex = scaley = 1.0;
208 if( (in_x2 - in_x1) > 0 )
209 scalex = 1.0 / (double)(in_x2 - in_x1);
211 if( (in_y2 - in_y1) > 0 )
212 scaley = 1.0 / (double)(in_y2 - in_y1);
214 /* Determine the perspective transform that maps from
215 * the unit cube to the transformed coordinates
217 double dx1, dx2, dx3, dy1, dy2, dy3;
220 dx1 = out_x2 - out_x4;
221 dx2 = out_x3 - out_x4;
222 dx3 = out_x1 - out_x2 + out_x4 - out_x3;
224 dy1 = out_y2 - out_y4;
225 dy2 = out_y3 - out_y4;
226 dy3 = out_y1 - out_y2 + out_y4 - out_y3;
227 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
228 // dx1, dx2, dx3, dy1, dy2, dy3 );
230 /* Is the mapping affine? */
231 if((dx3 == 0.0) && (dy3 == 0.0)) {
232 matrix.values[0][0] = out_x2 - out_x1;
233 matrix.values[0][1] = out_x4 - out_x2;
234 matrix.values[0][2] = out_x1;
235 matrix.values[1][0] = out_y2 - out_y1;
236 matrix.values[1][1] = out_y4 - out_y2;
237 matrix.values[1][2] = out_y1;
238 matrix.values[2][0] = 0.0;
239 matrix.values[2][1] = 0.0;
242 det1 = dx3 * dy2 - dy3 * dx2;
243 det2 = dx1 * dy2 - dy1 * dx2;
244 matrix.values[2][0] = det1 / det2;
245 det1 = dx1 * dy3 - dy1 * dx3;
246 det2 = dx1 * dy2 - dy1 * dx2;
247 matrix.values[2][1] = det1 / det2;
249 matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
250 matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
251 matrix.values[0][2] = out_x1;
253 matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
254 matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
255 matrix.values[1][2] = out_y1;
258 matrix.values[2][2] = 1.0;
260 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
264 result->translate(-in_x1, -in_y1);
265 result->scale(scalex, scaley);
266 matrix.multiply(result);
267 // double test[3][3] =
268 // { { 0.0896, 0.0, 0.0 }, { 0.0, 0.0896, 0.0 }, { -0.00126, 0.0, 1.0 } };
269 // memcpy(&result->values[0][0], test, sizeof(test));
270 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
274 static inline float transform_cubic(float dx,
275 float p0, float p1, float p2, float p3)
277 /* Catmull-Rom - not bad */
278 float result = ((( (- p0 + 3*p1 - 3*p2 + p3) * dx +
279 ( 2*p0 - 5*p1 + 4*p2 - p3 ) ) * dx +
280 ( - p0 + p2 ) ) * dx + (p1 + p1) ) / 2;
281 // printf("%f %f %f %f %f\n", result, p0, p1, p2, p3);
285 static inline float transform_linear(float dx,
288 float result = p1 * (1-dx) + p2 * dx;
293 void AffineUnit::process_package(LoadPackage *package)
295 AffinePackage *pkg = (AffinePackage*)package;
296 int min_in_x = server->in_x;
297 int min_in_y = server->in_y;
298 int max_in_x = server->in_x + server->in_w - 1;
299 int max_in_y = server->in_y + server->in_h - 1;
302 // printf("AffineUnit::process_package %d %d %d %d %d\n",
308 int min_out_x = server->out_x;
309 //int min_out_y = server->out_y;
310 int max_out_x = server->out_x + server->out_w;
311 //int max_out_y = server->out_y + server->out_h;
313 // Amount to shift the input coordinates relative to the output coordinates
314 // To get the pivots to line up
315 int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
316 int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
318 // Calculate real coords
319 float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
320 if( server->mode == AffineEngine::STRETCH ||
321 server->mode == AffineEngine::PERSPECTIVE ||
322 server->mode == AffineEngine::ROTATE ||
323 server->mode == AffineEngine::TRANSFORM ) {
324 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
325 out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
326 out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
327 out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
328 out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
329 out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
330 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
331 out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
334 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
335 out_y1 = server->in_y;
336 out_x2 = out_x1 + server->in_w;
337 out_y2 = server->in_y;
338 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
339 out_y4 = server->in_y + server->in_h;
340 out_x3 = out_x4 + server->in_w;
341 out_y3 = server->in_y + server->in_h;
346 // Rotation with OpenGL uses a simple quad.
347 if( server->mode == AffineEngine::ROTATE &&
348 server->use_opengl ) {
350 out_x1 -= pivot_offset_x; out_y1 -= pivot_offset_y;
351 out_x2 -= pivot_offset_x; out_y2 -= pivot_offset_y;
352 out_x3 -= pivot_offset_x; out_y3 -= pivot_offset_y;
353 out_x4 -= pivot_offset_x; out_y4 -= pivot_offset_y;
355 server->output->to_texture();
356 server->output->enable_opengl();
357 server->output->init_screen();
358 server->output->bind_texture(0);
359 server->output->clear_pbuffer();
361 int texture_w = server->output->get_texture_w();
362 int texture_h = server->output->get_texture_h();
363 float output_h = server->output->get_h();
364 float in_x1 = (float)server->in_x / texture_w;
365 float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
366 float in_y1 = (float)server->in_y / texture_h;
367 float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
369 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
370 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
373 glNormal3f(0, 0, 1.0);
375 glTexCoord2f(in_x1, in_y1);
376 glVertex3f(out_x1, -output_h+out_y1, 0);
378 glTexCoord2f(in_x2, in_y1);
379 glVertex3f(out_x2, -output_h+out_y2, 0);
381 glTexCoord2f(in_x2, in_y2);
382 glVertex3f(out_x3, -output_h+out_y3, 0);
384 glTexCoord2f(in_x1, in_y2);
385 glVertex3f(out_x4, -output_h+out_y4, 0);
390 server->output->set_opengl_state(VFrame::SCREEN);
394 if( server->mode == AffineEngine::PERSPECTIVE ||
395 server->mode == AffineEngine::SHEER ||
396 server->mode == AffineEngine::ROTATE ||
397 server->mode == AffineEngine::TRANSFORM ) {
412 if( server->mode != AffineEngine::TRANSFORM ) {
413 calculate_matrix( server->in_x, server->in_y,
414 server->in_x + server->in_w,
415 server->in_y + server->in_h,
416 out_x1, out_y1, out_x2, out_y2,
417 out_x3, out_y3, out_x4, out_y4,
421 matrix.copy_from(&server->matrix);
424 //printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n", __LINE__,
425 // matrix.values[0][0], matrix.values[0][1], matrix.values[0][2],
426 // matrix.values[1][0], matrix.values[1][1], matrix.values[1][2],
427 // matrix.values[2][0], matrix.values[2][1], matrix.values[2][2]);
428 int reverse = !server->forward;
430 float xinc, yinc, winc;
432 float ttx = 0, tty = 0;
433 int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
436 m.copy_from(&matrix);
438 matrix.copy_from(&im);
444 float dx1 = 0, dy1 = 0;
445 float dx2 = 0, dy2 = 0;
446 float dx3 = 0, dy3 = 0;
447 float dx4 = 0, dy4 = 0;
448 matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
449 matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
450 matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
451 matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
453 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
454 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
455 // printf("AffineUnit::process_package %d use_opengl=%d\n",
456 // __LINE__, server->use_opengl);
458 if( server->use_opengl &&
459 server->interpolation == AffineEngine::AF_DEFAULT ) {
461 static const char *affine_frag =
462 "uniform sampler2D tex;\n"
463 "uniform mat3 affine_matrix;\n"
464 "uniform vec2 texture_extents;\n"
465 "uniform vec2 image_extents;\n"
466 "uniform vec4 border_color;\n"
469 " vec2 outcoord = gl_TexCoord[0].st;\n"
470 " outcoord *= texture_extents;\n"
471 " mat3 coord_matrix = mat3(\n"
472 " outcoord.x, outcoord.y, 1.0, \n"
473 " outcoord.x, outcoord.y, 1.0, \n"
474 " outcoord.x, outcoord.y, 1.0);\n"
475 " mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
476 " vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
477 " incoord /= incoord_matrix[0][2];\n"
478 " incoord /= texture_extents;\n"
479 " if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
480 " gl_FragColor = border_color;\n"
482 " gl_FragColor = texture2D(tex, incoord);\n"
485 float affine_matrix[9] = {
486 (float)m.values[0][0], (float)m.values[1][0], (float)m.values[2][0],
487 (float)m.values[0][1], (float)m.values[1][1], (float)m.values[2][1],
488 (float)m.values[0][2], (float)m.values[1][2], (float)m.values[2][2]
492 server->output->to_texture();
493 server->output->enable_opengl();
494 unsigned int frag_shader = VFrame::make_shader(0,
497 if( frag_shader > 0 ) {
498 glUseProgram(frag_shader);
499 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
500 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"),
501 1, 0, affine_matrix);
502 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
503 (GLfloat)server->output->get_texture_w(),
504 (GLfloat)server->output->get_texture_h());
505 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
506 (GLfloat)server->output->get_w() / server->output->get_texture_w(),
507 (GLfloat)server->output->get_h() / server->output->get_texture_h());
508 float border_color[] = { 0, 0, 0, 0 };
509 if(BC_CModels::is_yuv(server->output->get_color_model())) {
510 border_color[1] = 0.5;
511 border_color[2] = 0.5;
513 if(!BC_CModels::has_alpha(server->output->get_color_model())) {
514 border_color[3] = 1.0;
517 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
518 1, (GLfloat*)border_color);
519 server->output->init_screen();
520 server->output->bind_texture(0);
521 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
522 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
523 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
524 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
525 server->output->draw_texture();
527 server->output->set_opengl_state(VFrame::SCREEN);
533 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
534 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
535 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
537 tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
538 ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
540 tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
541 ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
543 CLAMP(ty1, pkg->y1, pkg->y2);
544 CLAMP(ty2, pkg->y1, pkg->y2);
545 CLAMP(tx1, server->out_x, server->out_x + server->out_w);
546 CLAMP(tx2, server->out_x, server->out_x + server->out_w);
549 xinc = m.values[0][0];
550 yinc = m.values[1][0];
551 winc = m.values[2][0];
553 //printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n",
554 // tx1, ty1, tx2, ty2, out_x4, out_y4);
555 //printf("AffineUnit::process_package %d %d %d %d %d\n",
556 // __LINE__, min_in_x, max_in_x, min_in_y, max_in_y);
558 #define DO_INTERP(tag, interp, components, type, temp_type, chroma, max) \
560 type **inp_rows = (type**)server->input->get_rows(); \
561 type **out_rows = (type**)server->output->get_rows(); \
562 float round_factor = sizeof(type) < 4 ? 0.5 : 0; \
563 INTERP_SETUP(inp_rows, max, min_in_x,min_in_y, max_in_x,max_in_y); \
565 for( int y=ty1; y<ty2; ++y ) { \
566 type *out_row = (type*)out_rows[y]; \
567 int x1 = tx1, x2 = tx2; \
568 if( x1 < min_out_x ) x1 = min_out_x; \
569 if( x2 > max_out_x ) x2 = max_out_x; \
570 tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
571 + pivot_offset_x * xinc; \
572 ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
573 + pivot_offset_x * yinc; \
574 tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
575 + pivot_offset_x * winc; \
576 type *out = out_row + x1 * components; \
578 for( int x=x1; x<x2; ++x ) { \
579 /* Normalize homogeneous coords */ \
580 if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
581 else { ttx = tx / tw; tty = ty / tw; } \
582 interp##_SETUP(type, components, ttx, tty); \
583 *out++ = ((temp_type)interp##_interp(0, 0) + round_factor); \
585 *out++ = ((temp_type)interp##_interp(chroma, chroma) + round_factor); \
587 *out++ = ((temp_type)interp##_interp(chroma, chroma) + round_factor); \
588 if( components == 4 ) { \
590 *out++ = ((temp_type)interp##_interp(0, 0) + round_factor); \
593 /* increment the transformed coordinates */ \
594 tx += xinc; ty += yinc; tw += winc; \
599 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
600 // __LINE__, tx1, ty1, tx2, ty2);
602 switch( server->interpolation ) {
603 case AffineEngine::AF_NEAREST:
604 switch( server->input->get_color_model() ) {
605 DO_INTERP( BC_RGB_FLOAT, nearest, 3, float, float, 0x0, 1.0);
606 DO_INTERP( BC_RGB888, nearest, 3, unsigned char, int, 0x0, 0xff);
607 DO_INTERP( BC_RGBA_FLOAT, nearest, 4, float, float, 0x0, 1.0);
608 DO_INTERP( BC_RGBA8888, nearest, 4, unsigned char, int, 0x0, 0xff);
609 DO_INTERP( BC_YUV888, nearest, 3, unsigned char, int, 0x80, 0xff);
610 DO_INTERP( BC_YUVA8888, nearest, 4, unsigned char, int, 0x80, 0xff);
611 DO_INTERP( BC_RGB161616, nearest, 3, uint16_t, int, 0x0, 0xffff);
612 DO_INTERP( BC_RGBA16161616, nearest, 4, uint16_t, int, 0x0, 0xffff);
613 DO_INTERP( BC_YUV161616, nearest, 3, uint16_t, int, 0x8000, 0xffff);
614 DO_INTERP( BC_YUVA16161616, nearest, 4, uint16_t, int, 0x8000, 0xffff);
617 case AffineEngine::AF_LINEAR:
618 switch( server->input->get_color_model() ) {
619 DO_INTERP( BC_RGB_FLOAT, bi_linear, 3, float, float, 0x0, 1.0);
620 DO_INTERP( BC_RGB888, bi_linear, 3, unsigned char, int, 0x0, 0xff);
621 DO_INTERP( BC_RGBA_FLOAT, bi_linear, 4, float, float, 0x0, 1.0);
622 DO_INTERP( BC_RGBA8888, bi_linear, 4, unsigned char, int, 0x0, 0xff);
623 DO_INTERP( BC_YUV888, bi_linear, 3, unsigned char, int, 0x80, 0xff);
624 DO_INTERP( BC_YUVA8888, bi_linear, 4, unsigned char, int, 0x80, 0xff);
625 DO_INTERP( BC_RGB161616, bi_linear, 3, uint16_t, int, 0x0, 0xffff);
626 DO_INTERP( BC_RGBA16161616, bi_linear, 4, uint16_t, int, 0x0, 0xffff);
627 DO_INTERP( BC_YUV161616, bi_linear, 3, uint16_t, int, 0x8000, 0xffff);
628 DO_INTERP( BC_YUVA16161616, bi_linear, 4, uint16_t, int, 0x8000, 0xffff);
632 case AffineEngine::AF_CUBIC:
633 switch( server->input->get_color_model() ) {
634 DO_INTERP( BC_RGB_FLOAT, bi_cubic, 3, float, float, 0x0, 1.0);
635 DO_INTERP( BC_RGB888, bi_cubic, 3, unsigned char, int, 0x0, 0xff);
636 DO_INTERP( BC_RGBA_FLOAT, bi_cubic, 4, float, float, 0x0, 1.0);
637 DO_INTERP( BC_RGBA8888, bi_cubic, 4, unsigned char, int, 0x0, 0xff);
638 DO_INTERP( BC_YUV888, bi_cubic, 3, unsigned char, int, 0x80, 0xff);
639 DO_INTERP( BC_YUVA8888, bi_cubic, 4, unsigned char, int, 0x80, 0xff);
640 DO_INTERP( BC_RGB161616, bi_cubic, 3, uint16_t, int, 0x0, 0xffff);
641 DO_INTERP( BC_RGBA16161616, bi_cubic, 4, uint16_t, int, 0x0, 0xffff);
642 DO_INTERP( BC_YUV161616, bi_cubic, 3, uint16_t, int, 0x8000, 0xffff);
643 DO_INTERP( BC_YUVA16161616, bi_cubic, 4, uint16_t, int, 0x8000, 0xffff);
650 int min_x = server->in_x * AFFINE_OVERSAMPLE;
651 int min_y = server->in_y * AFFINE_OVERSAMPLE;
652 int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
653 int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
654 float top_w = out_x2 - out_x1;
655 float bottom_w = out_x3 - out_x4;
656 float left_h = out_y4 - out_y1;
657 float right_h = out_y3 - out_y2;
658 float out_w_diff = bottom_w - top_w;
659 float out_left_diff = out_x4 - out_x1;
660 float out_h_diff = right_h - left_h;
661 float out_top_diff = out_y2 - out_y1;
662 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
663 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
664 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
665 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
666 float max_v = MAX(distance1, distance3);
667 float max_h = MAX(distance2, distance4);
668 float max_dimension = MAX(max_v, max_h);
669 float min_dimension = MIN(server->in_h, server->in_w);
670 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
671 float x_f = server->in_x;
672 float y_f = server->in_y;
673 float h_f = server->in_h;
674 float w_f = server->in_w;
676 if(server->use_opengl) {
681 #define DO_STRETCH(tag, type, components) \
683 type **in_rows = (type**)server->input->get_rows(); \
684 type **out_rows = (type**)server->temp->get_rows(); \
686 for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
689 type *in_row = in_rows[i]; \
690 for(float in_x = x_f; in_x < w_f; in_x += step) \
693 float in_x_fraction = (in_x - x_f) / w_f; \
694 float in_y_fraction = (in_y - y_f) / h_f; \
695 int out_x = (int)((out_x1 + \
696 out_left_diff * in_y_fraction + \
697 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) * \
698 AFFINE_OVERSAMPLE); \
699 int out_y = (int)((out_y1 + \
700 out_top_diff * in_x_fraction + \
701 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
702 AFFINE_OVERSAMPLE); \
703 CLAMP(out_x, min_x, max_x); \
704 CLAMP(out_y, min_y, max_y); \
705 type *dst = out_rows[out_y] + out_x * components; \
706 type *src = in_row + j * components; \
710 if(components == 4) dst[3] = src[3]; \
715 switch( server->input->get_color_model() ) {
716 DO_STRETCH( BC_RGB_FLOAT, float, 3 );
717 DO_STRETCH( BC_RGB888, unsigned char, 3 );
718 DO_STRETCH( BC_RGBA_FLOAT, float, 4 );
719 DO_STRETCH( BC_RGBA8888, unsigned char, 4 );
720 DO_STRETCH( BC_YUV888, unsigned char, 3 );
721 DO_STRETCH( BC_YUVA8888, unsigned char, 4 );
722 DO_STRETCH( BC_RGB161616, uint16_t, 3 );
723 DO_STRETCH( BC_RGBA16161616, uint16_t, 4 );
724 DO_STRETCH( BC_YUV161616, uint16_t, 3 );
725 DO_STRETCH( BC_YUVA16161616, uint16_t, 4 );
731 AffineEngine::AffineEngine(int total_clients, int total_packages)
732 : LoadServer(total_clients, total_packages) //(1, 1)
734 user_in_viewport = 0;
736 user_out_viewport = 0;
739 in_x = in_y = in_w = in_h = 0;
740 out_x = out_y = out_w = out_h = 0;
741 in_pivot_x = in_pivot_y = 0;
742 out_pivot_x = out_pivot_y = 0;
743 interpolation = AF_DEFAULT;
744 this->total_packages = total_packages;
747 void AffineEngine::init_packages()
749 int y1 = 0, npkgs = get_total_packages();
750 for( int i=0; i<npkgs; ) {
751 AffinePackage *package = (AffinePackage*)get_package(i);
752 int y2 = out_y + (out_h * ++i / npkgs);
753 package->y1 = y1; package->y2 = y2; y1 = y2;
757 LoadClient* AffineEngine::new_client()
759 return new AffineUnit(this);
762 LoadPackage* AffineEngine::new_package()
764 return new AffinePackage;
767 void AffineEngine::process(VFrame *output, VFrame *input, VFrame *temp, int mode,
768 float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
773 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
774 // __LINE__, x1, y1, x2, y2, x3, y3, x4, y4);
776 // printf("AffineEngine::process %d %d %d %d %d\n",
777 // __LINE__, in_x, in_y, in_w, in_h);
779 // printf("AffineEngine::process %d %d %d %d %d\n",
780 // __LINE__, out_x, out_y, out_w, out_h);
782 // printf("AffineEngine::process %d %d %d %d %d\n",
783 // __LINE__, in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
785 // printf("AffineEngine::process %d %d %d %d %d\n",
786 // __LINE__, user_in_pivot, user_out_pivot, user_in_viewport, user_out_viewport);
788 this->output = output;
792 this->x1 = x1; this->y1 = y1;
793 this->x2 = x2; this->y2 = y2;
794 this->x3 = x3; this->y3 = y3;
795 this->x4 = x4; this->y4 = y4;
796 this->forward = forward;
798 if(!user_in_viewport) {
800 in_w = input->get_w();
801 in_h = input->get_h();
804 if(!user_out_viewport) {
805 out_x = 0; out_y = 0;
806 out_w = output->get_w();
807 out_h = output->get_h();
811 set_package_count(1);
815 set_package_count(total_packages);
823 void AffineEngine::rotate(VFrame *output,
827 this->output = output;
833 if( !user_in_viewport ) {
835 in_w = input->get_w();
836 in_h = input->get_h();
842 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
845 if( !user_in_pivot ) {
846 in_pivot_x = in_x + in_w / 2;
847 in_pivot_y = in_y + in_h / 2;
850 if( !user_out_viewport ) {
851 out_x = 0; out_y = 0;
852 out_w = output->get_w();
853 out_h = output->get_h();
856 if( !user_out_pivot ) {
857 out_pivot_x = out_x + out_w / 2;
858 out_pivot_y = out_y + out_h / 2;
861 // All subscripts are clockwise around the quadrangle
862 angle = angle * 2 * M_PI / 360;
863 double angle1 = atan((double)(in_pivot_y - in_y) / (double)(in_pivot_x - in_x)) + angle;
864 double angle2 = atan((double)(in_x + in_w - in_pivot_x) / (double)(in_pivot_y - in_y)) + angle;
865 double angle3 = atan((double)(in_y + in_h - in_pivot_y) / (double)(in_x + in_w - in_pivot_x)) + angle;
866 double angle4 = atan((double)(in_pivot_x - in_x) / (double)(in_y + in_h - in_pivot_y)) + angle;
867 double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
868 double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
869 double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
870 double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
872 x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
873 y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
874 x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
875 y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
876 x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
877 y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
878 x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
879 y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
881 // printf("AffineEngine::rotate angle=%f\n",
885 // printf(" angle1=%f angle2=%f angle3=%f angle4=%f\n",
886 // angle1 * 360 / 2 / M_PI, angle2 * 360 / 2 / M_PI,
887 // angle3 * 360 / 2 / M_PI, angle4 * 360 / 2 / M_PI);
889 // printf(" radius1=%f radius2=%f radius3=%f radius4=%f\n",
890 // radius1, radius2, radius3, radius4);
892 // printf(" x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
893 // x1 * w / 100, y1 * h / 100,
894 // x2 * w / 100, y2 * h / 100,
895 // x3 * w / 100, y3 * h / 100,
896 // x4 * w / 100, y4 * h / 100);
899 set_package_count(1);
903 set_package_count(total_packages);
908 void AffineEngine::set_matrix(AffineMatrix *matrix)
910 for( int i=0; i<3; ++i ) {
911 for( int j=0; j<3; ++j ) {
912 this->matrix.values[i][j] = matrix->values[i][j];
917 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
919 this->in_x = x; this->in_y = y;
920 this->in_w = w; this->in_h = h;
921 this->user_in_viewport = 1;
924 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
926 this->out_x = x; this->out_y = y;
927 this->out_w = w; this->out_h = h;
928 this->user_out_viewport = 1;
931 void AffineEngine::set_viewport(int x, int y, int w, int h)
933 set_in_viewport(x, y, w, h);
934 set_out_viewport(x, y, w, h);
937 void AffineEngine::set_opengl(int value)
939 this->use_opengl = value;
942 void AffineEngine::set_in_pivot(int x, int y)
944 this->in_pivot_x = x;
945 this->in_pivot_y = y;
946 this->user_in_pivot = 1;
949 void AffineEngine::set_out_pivot(int x, int y)
951 this->out_pivot_x = x;
952 this->out_pivot_y = y;
953 this->user_out_pivot = 1;
956 void AffineEngine::set_pivot(int x, int y)
962 void AffineEngine::unset_pivot()
968 void AffineEngine::unset_viewport()
970 user_in_viewport = 0;
971 user_out_viewport = 0;
975 void AffineEngine::set_interpolation(int type)
977 interpolation = type;