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::set_matrix(
149 double in_x1, double in_y1, double in_x2, double in_y2,
150 double out_x1, double out_y1, double out_x2, double out_y2,
151 double out_x3, double out_y3, double out_x4, double out_y4)
153 double scalex = in_x2 > in_x1 ? 1./(in_x2 - in_x1) : 1.0;
154 double scaley = in_y2 > in_y1 ? 1./(in_y2 - in_y1) : 1.0;
155 double dx1 = out_x2 - out_x4, dx2 = out_x3 - out_x4;
156 double dx3 = out_x1 - out_x2 + out_x4 - out_x3;
158 double dy1 = out_y2 - out_y4, dy2 = out_y3 - out_y4;
159 double dy3 = out_y1 - out_y2 + out_y4 - out_y3;
160 double det = dx1 * dy2 - dy1 * dx2;
161 if( !det ) { identity(); return; }
164 m.values[2][0] = (dx3 * dy2 - dy3 * dx2) / det;
165 m.values[2][1] = (dx1 * dy3 - dy1 * dx3) / det;
166 m.values[0][0] = out_x2 - out_x1 + m.values[2][0] * out_x2;
167 m.values[0][1] = out_x3 - out_x1 + m.values[2][1] * out_x3;
168 m.values[0][2] = out_x1;
169 m.values[1][0] = out_y2 - out_y1 + m.values[2][0] * out_y2;
170 m.values[1][1] = out_y3 - out_y1 + m.values[2][1] * out_y3;
171 m.values[1][2] = out_y1;
172 m.values[2][2] = 1.0;
175 translate(-in_x1, -in_y1);
176 scale(scalex, scaley);
180 void AffineMatrix::transform_point(float x,
187 w = values[2][0] * x + values[2][1] * y + values[2][2];
190 *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
191 *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
194 void AffineMatrix::dump()
196 printf("AffineMatrix::dump\n");
197 printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
198 printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
199 printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
206 AffinePackage::AffinePackage()
214 AffineUnit::AffineUnit(AffineEngine *server)
217 this->server = server;
221 static inline float transform_cubic(float dx,
222 float p0, float p1, float p2, float p3)
224 /* Catmull-Rom - not bad */
225 float result = ((( (- p0 + 3*p1 - 3*p2 + p3) * dx +
226 ( 2*p0 - 5*p1 + 4*p2 - p3 ) ) * dx +
227 ( - p0 + p2 ) ) * dx + (p1 + p1) ) / 2;
228 // printf("%f %f %f %f %f\n", result, p0, p1, p2, p3);
232 static inline float transform_linear(float dx,
235 float result = p1 * (1-dx) + p2 * dx;
240 void AffineUnit::process_package(LoadPackage *package)
242 AffinePackage *pkg = (AffinePackage*)package;
243 int min_in_x = server->in_x;
244 int min_in_y = server->in_y;
245 int max_in_x = server->in_x + server->in_w;
246 int max_in_y = server->in_y + server->in_h;
249 // printf("AffineUnit::process_package %d %d %d %d %d\n",
255 int min_out_x = server->out_x;
256 //int min_out_y = server->out_y;
257 int max_out_x = server->out_x + server->out_w;
258 //int max_out_y = server->out_y + server->out_h;
260 // Amount to shift the input coordinates relative to the output coordinates
261 // To get the pivots to line up
262 int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
263 int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
265 // Calculate real coords
266 float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
267 if( server->mode == AffineEngine::STRETCH ||
268 server->mode == AffineEngine::PERSPECTIVE ||
269 server->mode == AffineEngine::ROTATE ||
270 server->mode == AffineEngine::TRANSFORM ) {
271 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
272 out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
273 out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
274 out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
275 out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
276 out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
277 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
278 out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
281 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
282 out_y1 = server->in_y;
283 out_x2 = out_x1 + server->in_w;
284 out_y2 = server->in_y;
285 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
286 out_y4 = server->in_y + server->in_h;
287 out_x3 = out_x4 + server->in_w;
288 out_y3 = server->in_y + server->in_h;
293 // Rotation with OpenGL uses a simple quad.
294 if( server->mode == AffineEngine::ROTATE &&
295 server->use_opengl ) {
297 out_x1 -= pivot_offset_x; out_y1 -= pivot_offset_y;
298 out_x2 -= pivot_offset_x; out_y2 -= pivot_offset_y;
299 out_x3 -= pivot_offset_x; out_y3 -= pivot_offset_y;
300 out_x4 -= pivot_offset_x; out_y4 -= pivot_offset_y;
302 server->output->to_texture();
303 server->output->enable_opengl();
304 server->output->init_screen();
305 server->output->bind_texture(0);
306 server->output->clear_pbuffer();
308 int texture_w = server->output->get_texture_w();
309 int texture_h = server->output->get_texture_h();
310 float output_h = server->output->get_h();
311 float in_x1 = (float)server->in_x / texture_w;
312 float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
313 float in_y1 = (float)server->in_y / texture_h;
314 float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
316 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
317 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
320 glNormal3f(0, 0, 1.0);
322 glTexCoord2f(in_x1, in_y1);
323 glVertex3f(out_x1, -output_h+out_y1, 0);
325 glTexCoord2f(in_x2, in_y1);
326 glVertex3f(out_x2, -output_h+out_y2, 0);
328 glTexCoord2f(in_x2, in_y2);
329 glVertex3f(out_x3, -output_h+out_y3, 0);
331 glTexCoord2f(in_x1, in_y2);
332 glVertex3f(out_x4, -output_h+out_y4, 0);
337 server->output->set_opengl_state(VFrame::SCREEN);
341 if( server->mode == AffineEngine::PERSPECTIVE ||
342 server->mode == AffineEngine::SHEER ||
343 server->mode == AffineEngine::ROTATE ||
344 server->mode == AffineEngine::TRANSFORM ) {
359 if( server->mode != AffineEngine::TRANSFORM ) {
360 matrix.set_matrix(server->in_x, server->in_y,
361 server->in_x + server->in_w,
362 server->in_y + server->in_h,
363 out_x1, out_y1, out_x2, out_y2,
364 out_x3, out_y3, out_x4, out_y4);
367 matrix.copy_from(&server->matrix);
370 //printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n", __LINE__,
371 // matrix.values[0][0], matrix.values[0][1], matrix.values[0][2],
372 // matrix.values[1][0], matrix.values[1][1], matrix.values[1][2],
373 // matrix.values[2][0], matrix.values[2][1], matrix.values[2][2]);
374 int reverse = !server->forward;
376 float xinc, yinc, winc;
378 float ttx = 0, tty = 0;
379 int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
382 m.copy_from(&matrix);
384 matrix.copy_from(&im);
390 float dx1 = 0, dy1 = 0;
391 float dx2 = 0, dy2 = 0;
392 float dx3 = 0, dy3 = 0;
393 float dx4 = 0, dy4 = 0;
394 matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
395 matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
396 matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
397 matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
399 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
400 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
401 // printf("AffineUnit::process_package %d use_opengl=%d\n",
402 // __LINE__, server->use_opengl);
404 if( server->use_opengl &&
405 server->interpolation == AffineEngine::AF_DEFAULT ) {
407 static const char *affine_frag =
408 "uniform sampler2D tex;\n"
409 "uniform mat3 affine_matrix;\n"
410 "uniform vec2 texture_extents;\n"
411 "uniform vec2 image_extents;\n"
412 "uniform vec4 border_color;\n"
415 " vec2 outcoord = gl_TexCoord[0].st;\n"
416 " outcoord *= texture_extents;\n"
417 " mat3 coord_matrix = mat3(\n"
418 " outcoord.x, outcoord.y, 1.0, \n"
419 " outcoord.x, outcoord.y, 1.0, \n"
420 " outcoord.x, outcoord.y, 1.0);\n"
421 " mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
422 " vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
423 " incoord /= incoord_matrix[0][2];\n"
424 " incoord /= texture_extents;\n"
425 " if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
426 " gl_FragColor = border_color;\n"
428 " gl_FragColor = texture2D(tex, incoord);\n"
431 float affine_matrix[9] = {
432 (float)m.values[0][0], (float)m.values[1][0], (float)m.values[2][0],
433 (float)m.values[0][1], (float)m.values[1][1], (float)m.values[2][1],
434 (float)m.values[0][2], (float)m.values[1][2], (float)m.values[2][2]
438 server->output->to_texture();
439 server->output->enable_opengl();
440 unsigned int frag_shader = VFrame::make_shader(0, affine_frag, 0);
441 if( frag_shader > 0 ) {
442 glUseProgram(frag_shader);
443 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
444 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"),
445 1, 0, affine_matrix);
446 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
447 (GLfloat)server->output->get_texture_w(),
448 (GLfloat)server->output->get_texture_h());
449 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
450 (GLfloat)server->output->get_w() / server->output->get_texture_w(),
451 (GLfloat)server->output->get_h() / server->output->get_texture_h());
452 float border_color[] = { 0, 0, 0, 0 };
453 if(BC_CModels::is_yuv(server->output->get_color_model())) {
454 border_color[1] = 0.5;
455 border_color[2] = 0.5;
457 if(!BC_CModels::has_alpha(server->output->get_color_model())) {
458 border_color[3] = 1.0;
461 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
462 1, (GLfloat*)border_color);
463 server->output->init_screen();
464 server->output->bind_texture(0);
465 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
466 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
467 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
469 server->output->draw_texture();
471 server->output->set_opengl_state(VFrame::SCREEN);
477 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
478 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
479 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
481 tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
482 ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
484 tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
485 ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
487 CLAMP(ty1, pkg->y1, pkg->y2);
488 CLAMP(ty2, pkg->y1, pkg->y2);
489 CLAMP(tx1, server->out_x, server->out_x + server->out_w);
490 CLAMP(tx2, server->out_x, server->out_x + server->out_w);
493 xinc = m.values[0][0];
494 yinc = m.values[1][0];
495 winc = m.values[2][0];
497 //printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n",
498 // tx1, ty1, tx2, ty2, out_x4, out_y4);
499 //printf("AffineUnit::process_package %d %d %d %d %d\n",
500 // __LINE__, min_in_x, max_in_x, min_in_y, max_in_y);
502 #define DO_INTERP(tag, interp, components, type, temp_type, chroma, max) \
504 type **inp_rows = (type**)server->input->get_rows(); \
505 type **out_rows = (type**)server->output->get_rows(); \
506 float round_factor = sizeof(type) < 4 ? 0.5 : 0; \
507 INTERP_SETUP(inp_rows, max, min_in_x,min_in_y, max_in_x,max_in_y); \
509 for( int y=ty1; y<ty2; ++y ) { \
510 type *out_row = (type*)out_rows[y]; \
511 int x1 = tx1, x2 = tx2; \
512 if( x1 < min_out_x ) x1 = min_out_x; \
513 if( x2 > max_out_x ) x2 = max_out_x; \
514 tx = xinc * x1 + m.values[0][1] * (y + pivot_offset_y) + m.values[0][2] \
515 + pivot_offset_x * xinc; \
516 ty = yinc * x1 + m.values[1][1] * (y + pivot_offset_y) + m.values[1][2] \
517 + pivot_offset_x * yinc; \
518 tw = winc * x1 + m.values[2][1] * (y + pivot_offset_y) + m.values[2][2] \
519 + pivot_offset_x * winc; \
520 type *out = out_row + x1 * components; \
522 for( int x=x1; x<x2; ++x ) { \
523 /* Normalize homogeneous coords */ \
524 if( tw == 0.0 ) { ttx = 0.0; tty = 0.0; } \
525 else { ttx = tx / tw; tty = ty / tw; } \
526 interp##_SETUP(type, components, ttx, tty); \
527 *out++ = ((temp_type)interp##_interp(0, 0) + round_factor); \
529 *out++ = ((temp_type)interp##_interp(chroma, chroma) + round_factor); \
531 *out++ = ((temp_type)interp##_interp(chroma, chroma) + round_factor); \
532 if( components == 4 ) { \
534 *out++ = ((temp_type)interp##_interp(0, 0) + round_factor); \
537 /* increment the transformed coordinates */ \
538 tx += xinc; ty += yinc; tw += winc; \
543 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
544 // __LINE__, tx1, ty1, tx2, ty2);
546 switch( server->interpolation ) {
547 case AffineEngine::AF_NEAREST:
548 switch( server->input->get_color_model() ) {
549 DO_INTERP( BC_RGB_FLOAT, nearest, 3, float, float, 0x0, 1.0);
550 DO_INTERP( BC_RGB888, nearest, 3, unsigned char, int, 0x0, 0xff);
551 DO_INTERP( BC_RGBA_FLOAT, nearest, 4, float, float, 0x0, 1.0);
552 DO_INTERP( BC_RGBA8888, nearest, 4, unsigned char, int, 0x0, 0xff);
553 DO_INTERP( BC_YUV888, nearest, 3, unsigned char, int, 0x80, 0xff);
554 DO_INTERP( BC_YUVA8888, nearest, 4, unsigned char, int, 0x80, 0xff);
555 DO_INTERP( BC_RGB161616, nearest, 3, uint16_t, int, 0x0, 0xffff);
556 DO_INTERP( BC_RGBA16161616, nearest, 4, uint16_t, int, 0x0, 0xffff);
557 DO_INTERP( BC_YUV161616, nearest, 3, uint16_t, int, 0x8000, 0xffff);
558 DO_INTERP( BC_YUVA16161616, nearest, 4, uint16_t, int, 0x8000, 0xffff);
561 case AffineEngine::AF_LINEAR:
562 switch( server->input->get_color_model() ) {
563 DO_INTERP( BC_RGB_FLOAT, bi_linear, 3, float, float, 0x0, 1.0);
564 DO_INTERP( BC_RGB888, bi_linear, 3, unsigned char, int, 0x0, 0xff);
565 DO_INTERP( BC_RGBA_FLOAT, bi_linear, 4, float, float, 0x0, 1.0);
566 DO_INTERP( BC_RGBA8888, bi_linear, 4, unsigned char, int, 0x0, 0xff);
567 DO_INTERP( BC_YUV888, bi_linear, 3, unsigned char, int, 0x80, 0xff);
568 DO_INTERP( BC_YUVA8888, bi_linear, 4, unsigned char, int, 0x80, 0xff);
569 DO_INTERP( BC_RGB161616, bi_linear, 3, uint16_t, int, 0x0, 0xffff);
570 DO_INTERP( BC_RGBA16161616, bi_linear, 4, uint16_t, int, 0x0, 0xffff);
571 DO_INTERP( BC_YUV161616, bi_linear, 3, uint16_t, int, 0x8000, 0xffff);
572 DO_INTERP( BC_YUVA16161616, bi_linear, 4, uint16_t, int, 0x8000, 0xffff);
576 case AffineEngine::AF_CUBIC:
577 switch( server->input->get_color_model() ) {
578 DO_INTERP( BC_RGB_FLOAT, bi_cubic, 3, float, float, 0x0, 1.0);
579 DO_INTERP( BC_RGB888, bi_cubic, 3, unsigned char, int, 0x0, 0xff);
580 DO_INTERP( BC_RGBA_FLOAT, bi_cubic, 4, float, float, 0x0, 1.0);
581 DO_INTERP( BC_RGBA8888, bi_cubic, 4, unsigned char, int, 0x0, 0xff);
582 DO_INTERP( BC_YUV888, bi_cubic, 3, unsigned char, int, 0x80, 0xff);
583 DO_INTERP( BC_YUVA8888, bi_cubic, 4, unsigned char, int, 0x80, 0xff);
584 DO_INTERP( BC_RGB161616, bi_cubic, 3, uint16_t, int, 0x0, 0xffff);
585 DO_INTERP( BC_RGBA16161616, bi_cubic, 4, uint16_t, int, 0x0, 0xffff);
586 DO_INTERP( BC_YUV161616, bi_cubic, 3, uint16_t, int, 0x8000, 0xffff);
587 DO_INTERP( BC_YUVA16161616, bi_cubic, 4, uint16_t, int, 0x8000, 0xffff);
594 int min_x = server->in_x * AFFINE_OVERSAMPLE;
595 int min_y = server->in_y * AFFINE_OVERSAMPLE;
596 int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
597 int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
598 float top_w = out_x2 - out_x1;
599 float bottom_w = out_x3 - out_x4;
600 float left_h = out_y4 - out_y1;
601 float right_h = out_y3 - out_y2;
602 float out_w_diff = bottom_w - top_w;
603 float out_left_diff = out_x4 - out_x1;
604 float out_h_diff = right_h - left_h;
605 float out_top_diff = out_y2 - out_y1;
606 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
607 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
608 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
609 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
610 float max_v = MAX(distance1, distance3);
611 float max_h = MAX(distance2, distance4);
612 float max_dimension = MAX(max_v, max_h);
613 float min_dimension = MIN(server->in_h, server->in_w);
614 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
615 float x_f = server->in_x;
616 float y_f = server->in_y;
617 float h_f = server->in_h;
618 float w_f = server->in_w;
620 if(server->use_opengl) {
625 #define DO_STRETCH(tag, type, components) \
627 type **in_rows = (type**)server->input->get_rows(); \
628 type **out_rows = (type**)server->temp->get_rows(); \
630 for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
633 type *in_row = in_rows[i]; \
634 for(float in_x = x_f; in_x < w_f; in_x += step) \
637 float in_x_fraction = (in_x - x_f) / w_f; \
638 float in_y_fraction = (in_y - y_f) / h_f; \
639 int out_x = (int)((out_x1 + \
640 out_left_diff * in_y_fraction + \
641 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) * \
642 AFFINE_OVERSAMPLE); \
643 int out_y = (int)((out_y1 + \
644 out_top_diff * in_x_fraction + \
645 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
646 AFFINE_OVERSAMPLE); \
647 CLAMP(out_x, min_x, max_x); \
648 CLAMP(out_y, min_y, max_y); \
649 type *dst = out_rows[out_y] + out_x * components; \
650 type *src = in_row + j * components; \
654 if(components == 4) dst[3] = src[3]; \
659 switch( server->input->get_color_model() ) {
660 DO_STRETCH( BC_RGB_FLOAT, float, 3 );
661 DO_STRETCH( BC_RGB888, unsigned char, 3 );
662 DO_STRETCH( BC_RGBA_FLOAT, float, 4 );
663 DO_STRETCH( BC_RGBA8888, unsigned char, 4 );
664 DO_STRETCH( BC_YUV888, unsigned char, 3 );
665 DO_STRETCH( BC_YUVA8888, unsigned char, 4 );
666 DO_STRETCH( BC_RGB161616, uint16_t, 3 );
667 DO_STRETCH( BC_RGBA16161616, uint16_t, 4 );
668 DO_STRETCH( BC_YUV161616, uint16_t, 3 );
669 DO_STRETCH( BC_YUVA16161616, uint16_t, 4 );
675 AffineEngine::AffineEngine(int total_clients, int total_packages)
676 : LoadServer(total_clients, total_packages) //(1, 1)
678 user_in_viewport = 0;
680 user_out_viewport = 0;
683 in_x = in_y = in_w = in_h = 0;
684 out_x = out_y = out_w = out_h = 0;
685 in_pivot_x = in_pivot_y = 0;
686 out_pivot_x = out_pivot_y = 0;
687 interpolation = AF_DEFAULT;
688 this->total_packages = total_packages;
691 void AffineEngine::init_packages()
693 int y1 = out_y, npkgs = get_total_packages();
694 for( int i=0; i<npkgs; ) {
695 AffinePackage *package = (AffinePackage*)get_package(i);
696 int y2 = out_y + (out_h * ++i / npkgs);
697 package->y1 = y1; package->y2 = y2; y1 = y2;
701 LoadClient* AffineEngine::new_client()
703 return new AffineUnit(this);
706 LoadPackage* AffineEngine::new_package()
708 return new AffinePackage;
711 void AffineEngine::process(VFrame *output, VFrame *input, VFrame *temp, int mode,
712 float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
717 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
718 // __LINE__, x1, y1, x2, y2, x3, y3, x4, y4);
720 // printf("AffineEngine::process %d %d %d %d %d\n",
721 // __LINE__, in_x, in_y, in_w, in_h);
723 // printf("AffineEngine::process %d %d %d %d %d\n",
724 // __LINE__, out_x, out_y, out_w, out_h);
726 // printf("AffineEngine::process %d %d %d %d %d\n",
727 // __LINE__, in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
729 // printf("AffineEngine::process %d %d %d %d %d\n",
730 // __LINE__, user_in_pivot, user_out_pivot, user_in_viewport, user_out_viewport);
732 this->output = output;
736 this->x1 = x1; this->y1 = y1;
737 this->x2 = x2; this->y2 = y2;
738 this->x3 = x3; this->y3 = y3;
739 this->x4 = x4; this->y4 = y4;
740 this->forward = forward;
742 if(!user_in_viewport) {
744 in_w = input->get_w();
745 in_h = input->get_h();
748 if(!user_out_viewport) {
749 out_x = 0; out_y = 0;
750 out_w = output->get_w();
751 out_h = output->get_h();
755 set_package_count(1);
759 set_package_count(total_packages);
764 void AffineEngine::set_matrix(
765 double in_x1, double in_y1, double in_x2, double in_y2,
766 double out_x1, double out_y1, double out_x2, double out_y2,
767 double out_x3, double out_y3, double out_x4, double out_y4)
769 matrix.set_matrix(in_x1, in_y1, in_x2, in_y2,
770 out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
774 void AffineEngine::rotate(VFrame *output,
778 this->output = output;
784 if( !user_in_viewport ) {
786 in_w = input->get_w();
787 in_h = input->get_h();
793 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
796 if( !user_in_pivot ) {
797 in_pivot_x = in_x + in_w / 2;
798 in_pivot_y = in_y + in_h / 2;
801 if( !user_out_viewport ) {
802 out_x = 0; out_y = 0;
803 out_w = output->get_w();
804 out_h = output->get_h();
807 if( !user_out_pivot ) {
808 out_pivot_x = out_x + out_w / 2;
809 out_pivot_y = out_y + out_h / 2;
812 // All subscripts are clockwise around the quadrangle
813 angle = angle * 2 * M_PI / 360;
814 double angle1 = atan2((double)(in_pivot_y - in_y), (double)(in_pivot_x - in_x)) + angle;
815 double angle2 = atan2((double)(in_x + in_w - in_pivot_x), (double)(in_pivot_y - in_y)) + angle;
816 double angle3 = atan2((double)(in_y + in_h - in_pivot_y), (double)(in_x + in_w - in_pivot_x)) + angle;
817 double angle4 = atan2((double)(in_pivot_x - in_x), (double)(in_y + in_h - in_pivot_y)) + angle;
818 double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
819 double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
820 double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
821 double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
823 x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
824 y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
825 x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
826 y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
827 x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
828 y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
829 x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
830 y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
832 // printf("AffineEngine::rotate angle=%f\n",
836 // printf(" angle1=%f angle2=%f angle3=%f angle4=%f\n",
837 // angle1 * 360 / 2 / M_PI, angle2 * 360 / 2 / M_PI,
838 // angle3 * 360 / 2 / M_PI, angle4 * 360 / 2 / M_PI);
840 // printf(" radius1=%f radius2=%f radius3=%f radius4=%f\n",
841 // radius1, radius2, radius3, radius4);
843 // printf(" x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
844 // x1 * w / 100, y1 * h / 100,
845 // x2 * w / 100, y2 * h / 100,
846 // x3 * w / 100, y3 * h / 100,
847 // x4 * w / 100, y4 * h / 100);
850 set_package_count(1);
854 set_package_count(total_packages);
859 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
861 this->in_x = x; this->in_y = y;
862 this->in_w = w; this->in_h = h;
863 this->user_in_viewport = 1;
866 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
868 this->out_x = x; this->out_y = y;
869 this->out_w = w; this->out_h = h;
870 this->user_out_viewport = 1;
873 void AffineEngine::set_viewport(int x, int y, int w, int h)
875 set_in_viewport(x, y, w, h);
876 set_out_viewport(x, y, w, h);
879 void AffineEngine::set_opengl(int value)
881 this->use_opengl = value;
884 void AffineEngine::set_in_pivot(int x, int y)
886 this->in_pivot_x = x;
887 this->in_pivot_y = y;
888 this->user_in_pivot = 1;
891 void AffineEngine::set_out_pivot(int x, int y)
893 this->out_pivot_x = x;
894 this->out_pivot_y = y;
895 this->user_out_pivot = 1;
898 void AffineEngine::set_pivot(int x, int y)
904 void AffineEngine::unset_pivot()
910 void AffineEngine::unset_viewport()
912 user_in_viewport = 0;
913 user_out_viewport = 0;
917 void AffineEngine::set_interpolation(int type)
919 interpolation = type;