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
37 AffineMatrix::AffineMatrix()
39 bzero(values, sizeof(values));
42 void AffineMatrix::identity()
44 bzero(values, sizeof(values));
50 void AffineMatrix::translate(double x, double y)
52 double g = values[2][0];
53 double h = values[2][1];
54 double i = values[2][2];
55 values[0][0] += x * g;
56 values[0][1] += x * h;
57 values[0][2] += x * i;
58 values[1][0] += y * g;
59 values[1][1] += y * h;
60 values[1][2] += y * i;
63 void AffineMatrix::scale(double x, double y)
74 void AffineMatrix::multiply(AffineMatrix *dst)
80 for (i = 0; i < 3; i++)
85 for (j = 0; j < 3; j++)
87 tmp.values[i][j] = t1 * dst->values[0][j];
88 tmp.values[i][j] += t2 * dst->values[1][j];
89 tmp.values[i][j] += t3 * dst->values[2][j];
95 double AffineMatrix::determinant()
100 values[0][0] * (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
102 values[1][0] * (values[0][1] * values[2][2] - values[0][2] * values[2][1]);
104 values[2][0] * (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
109 void AffineMatrix::invert(AffineMatrix *dst)
113 det_1 = determinant();
121 (values[1][1] * values[2][2] - values[1][2] * values[2][1]) * det_1;
124 - (values[1][0] * values[2][2] - values[1][2] * values[2][0]) * det_1;
127 (values[1][0] * values[2][1] - values[1][1] * values[2][0]) * det_1;
130 - (values[0][1] * values[2][2] - values[0][2] * values[2][1] ) * det_1;
133 (values[0][0] * values[2][2] - values[0][2] * values[2][0]) * det_1;
136 - (values[0][0] * values[2][1] - values[0][1] * values[2][0]) * det_1;
139 (values[0][1] * values[1][2] - values[0][2] * values[1][1]) * det_1;
142 - (values[0][0] * values[1][2] - values[0][2] * values[1][0]) * det_1;
145 (values[0][0] * values[1][1] - values[0][1] * values[1][0]) * det_1;
148 void AffineMatrix::copy_from(AffineMatrix *src)
150 memcpy(&values[0][0], &src->values[0][0], sizeof(values));
153 void AffineMatrix::transform_point(float x,
160 w = values[2][0] * x + values[2][1] * y + values[2][2];
167 *newx = (values[0][0] * x + values[0][1] * y + values[0][2]) * w;
168 *newy = (values[1][0] * x + values[1][1] * y + values[1][2]) * w;
171 void AffineMatrix::dump()
173 printf("AffineMatrix::dump\n");
174 printf("%f %f %f\n", values[0][0], values[0][1], values[0][2]);
175 printf("%f %f %f\n", values[1][0], values[1][1], values[1][2]);
176 printf("%f %f %f\n", values[2][0], values[2][1], values[2][2]);
183 AffinePackage::AffinePackage()
191 AffineUnit::AffineUnit(AffineEngine *server)
194 this->server = server;
205 void AffineUnit::calculate_matrix(
218 AffineMatrix *result)
224 scalex = scaley = 1.0;
226 if((in_x2 - in_x1) > 0)
227 scalex = 1.0 / (double)(in_x2 - in_x1);
229 if((in_y2 - in_y1) > 0)
230 scaley = 1.0 / (double)(in_y2 - in_y1);
232 /* Determine the perspective transform that maps from
233 * the unit cube to the transformed coordinates
235 double dx1, dx2, dx3, dy1, dy2, dy3;
238 dx1 = out_x2 - out_x4;
239 dx2 = out_x3 - out_x4;
240 dx3 = out_x1 - out_x2 + out_x4 - out_x3;
242 dy1 = out_y2 - out_y4;
243 dy2 = out_y3 - out_y4;
244 dy3 = out_y1 - out_y2 + out_y4 - out_y3;
245 // printf("AffineUnit::calculate_matrix %f %f %f %f %f %f\n",
254 /* Is the mapping affine? */
255 if((dx3 == 0.0) && (dy3 == 0.0))
257 matrix.values[0][0] = out_x2 - out_x1;
258 matrix.values[0][1] = out_x4 - out_x2;
259 matrix.values[0][2] = out_x1;
260 matrix.values[1][0] = out_y2 - out_y1;
261 matrix.values[1][1] = out_y4 - out_y2;
262 matrix.values[1][2] = out_y1;
263 matrix.values[2][0] = 0.0;
264 matrix.values[2][1] = 0.0;
268 det1 = dx3 * dy2 - dy3 * dx2;
269 det2 = dx1 * dy2 - dy1 * dx2;
270 matrix.values[2][0] = det1 / det2;
271 det1 = dx1 * dy3 - dy1 * dx3;
272 det2 = dx1 * dy2 - dy1 * dx2;
273 matrix.values[2][1] = det1 / det2;
275 matrix.values[0][0] = out_x2 - out_x1 + matrix.values[2][0] * out_x2;
276 matrix.values[0][1] = out_x3 - out_x1 + matrix.values[2][1] * out_x3;
277 matrix.values[0][2] = out_x1;
279 matrix.values[1][0] = out_y2 - out_y1 + matrix.values[2][0] * out_y2;
280 matrix.values[1][1] = out_y3 - out_y1 + matrix.values[2][1] * out_y3;
281 matrix.values[1][2] = out_y1;
284 matrix.values[2][2] = 1.0;
286 // printf("AffineUnit::calculate_matrix 1 %f %f\n", dx3, dy3);
290 result->translate(-in_x1, -in_y1);
291 result->scale(scalex, scaley);
292 matrix.multiply(result);
293 // double test[3][3] = { { 0.0896, 0.0, 0.0 },
294 // { 0.0, 0.0896, 0.0 },
295 // { -0.00126, 0.0, 1.0 } };
296 // memcpy(&result->values[0][0], test, sizeof(test));
297 // printf("AffineUnit::calculate_matrix 4 %p\n", result);
303 static inline float transform_cubic(float dx,
304 float jm1, float j, float jp1, float jp2)
306 /* Catmull-Rom - not bad */
307 float result = ((( ( - jm1 + 3.0 * j - 3.0 * jp1 + jp2 ) * dx +
308 ( 2.0 * jm1 - 5.0 * j + 4.0 * jp1 - jp2 ) ) * dx +
309 ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
310 // printf("%f %f %f %f %f\n", result, jm1, j, jp1, jp2);
315 void AffineUnit::process_package(LoadPackage *package)
317 AffinePackage *pkg = (AffinePackage*)package;
318 int min_in_x = server->in_x;
319 int min_in_y = server->in_y;
320 int max_in_x = server->in_x + server->in_w - 1;
321 int max_in_y = server->in_y + server->in_h - 1;
324 // printf("AffineUnit::process_package %d %d %d %d %d\n",
330 int min_out_x = server->out_x;
331 //int min_out_y = server->out_y;
332 int max_out_x = server->out_x + server->out_w;
333 //int max_out_y = server->out_y + server->out_h;
335 // Amount to shift the input coordinates relative to the output coordinates
336 // To get the pivots to line up
337 int pivot_offset_x = server->in_pivot_x - server->out_pivot_x;
338 int pivot_offset_y = server->in_pivot_y - server->out_pivot_y;
340 // Calculate real coords
341 float out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4;
342 if(server->mode == AffineEngine::STRETCH ||
343 server->mode == AffineEngine::PERSPECTIVE ||
344 server->mode == AffineEngine::ROTATE ||
345 server->mode == AffineEngine::TRANSFORM)
347 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
348 out_y1 = (float)server->in_y + (float)server->y1 * server->in_h / 100;
349 out_x2 = (float)server->in_x + (float)server->x2 * server->in_w / 100;
350 out_y2 = (float)server->in_y + (float)server->y2 * server->in_h / 100;
351 out_x3 = (float)server->in_x + (float)server->x3 * server->in_w / 100;
352 out_y3 = (float)server->in_y + (float)server->y3 * server->in_h / 100;
353 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
354 out_y4 = (float)server->in_y + (float)server->y4 * server->in_h / 100;
358 out_x1 = (float)server->in_x + (float)server->x1 * server->in_w / 100;
359 out_y1 = server->in_y;
360 out_x2 = out_x1 + server->in_w;
361 out_y2 = server->in_y;
362 out_x4 = (float)server->in_x + (float)server->x4 * server->in_w / 100;
363 out_y4 = server->in_y + server->in_h;
364 out_x3 = out_x4 + server->in_w;
365 out_y3 = server->in_y + server->in_h;
370 // Rotation with OpenGL uses a simple quad.
371 if(server->mode == AffineEngine::ROTATE &&
375 out_x1 -= pivot_offset_x; out_y1 -= pivot_offset_y;
376 out_x2 -= pivot_offset_x; out_y2 -= pivot_offset_y;
377 out_x3 -= pivot_offset_x; out_y3 -= pivot_offset_y;
378 out_x4 -= pivot_offset_x; out_y4 -= pivot_offset_y;
380 server->output->to_texture();
381 server->output->enable_opengl();
382 server->output->init_screen();
383 server->output->bind_texture(0);
384 server->output->clear_pbuffer();
386 int texture_w = server->output->get_texture_w();
387 int texture_h = server->output->get_texture_h();
388 float output_h = server->output->get_h();
389 float in_x1 = (float)server->in_x / texture_w;
390 float in_x2 = (float)(server->in_x + server->in_w) / texture_w;
391 float in_y1 = (float)server->in_y / texture_h;
392 float in_y2 = (float)(server->in_y + server->in_h) / texture_h;
394 // printf("%f %f %f %f\n%f,%f %f,%f %f,%f %f,%f\n", in_x1, in_y1, in_x2, in_y2,
395 // out_x1, out_y1, out_x2, out_y2, out_x3, out_y3, out_x4, out_y4);
398 glNormal3f(0, 0, 1.0);
400 glTexCoord2f(in_x1, in_y1);
401 glVertex3f(out_x1, -output_h+out_y1, 0);
403 glTexCoord2f(in_x2, in_y1);
404 glVertex3f(out_x2, -output_h+out_y2, 0);
406 glTexCoord2f(in_x2, in_y2);
407 glVertex3f(out_x3, -output_h+out_y3, 0);
409 glTexCoord2f(in_x1, in_y2);
410 glVertex3f(out_x4, -output_h+out_y4, 0);
415 server->output->set_opengl_state(VFrame::SCREEN);
419 if(server->mode == AffineEngine::PERSPECTIVE ||
420 server->mode == AffineEngine::SHEER ||
421 server->mode == AffineEngine::ROTATE ||
422 server->mode == AffineEngine::TRANSFORM)
438 if(server->mode != AffineEngine::TRANSFORM)
443 server->in_x + server->in_w,
444 server->in_y + server->in_h,
457 matrix.copy_from(&server->matrix);
460 // printf("AffineUnit::process_package %d\n%f %f %f\n%f %f %f\n%f %f %f\n",
462 // matrix.values[0][0],
463 // matrix.values[0][1],
464 // matrix.values[0][2],
465 // matrix.values[1][0],
466 // matrix.values[1][1],
467 // matrix.values[1][2],
468 // matrix.values[2][0],
469 // matrix.values[2][1],
470 // matrix.values[2][2]);
472 int reverse = !server->forward;
474 float xinc, yinc, winc;
476 float ttx = 0, tty = 0;
477 int itx = 0, ity = 0;
478 int tx1 = 0, ty1 = 0, tx2 = 0, ty2 = 0;
482 m.copy_from(&matrix);
484 matrix.copy_from(&im);
496 float dx1 = 0, dy1 = 0;
497 float dx2 = 0, dy2 = 0;
498 float dx3 = 0, dy3 = 0;
499 float dx4 = 0, dy4 = 0;
500 matrix.transform_point(server->in_x, server->in_y, &dx1, &dy1);
501 matrix.transform_point(server->in_x + server->in_w, server->in_y, &dx2, &dy2);
502 matrix.transform_point(server->in_x, server->in_y + server->in_h, &dx3, &dy3);
503 matrix.transform_point(server->in_x + server->in_w, server->in_y + server->in_h, &dx4, &dy4);
505 //printf("AffineUnit::process_package 1 y1=%d y2=%d\n", pkg->y1, pkg->y2);
506 //printf("AffineUnit::process_package 1 %f %f %f %f\n", dy1, dy2, dy3, dy4);
507 // printf("AffineUnit::process_package %d use_opengl=%d\n",
508 // __LINE__, server->use_opengl);
514 if(server->use_opengl)
517 static const char *affine_frag =
518 "uniform sampler2D tex;\n"
519 "uniform mat3 affine_matrix;\n"
520 "uniform vec2 texture_extents;\n"
521 "uniform vec2 image_extents;\n"
522 "uniform vec4 border_color;\n"
525 " vec2 outcoord = gl_TexCoord[0].st;\n"
526 " outcoord *= texture_extents;\n"
527 " mat3 coord_matrix = mat3(\n"
528 " outcoord.x, outcoord.y, 1.0, \n"
529 " outcoord.x, outcoord.y, 1.0, \n"
530 " outcoord.x, outcoord.y, 1.0);\n"
531 " mat3 incoord_matrix = affine_matrix * coord_matrix;\n"
532 " vec2 incoord = vec2(incoord_matrix[0][0], incoord_matrix[0][1]);\n"
533 " incoord /= incoord_matrix[0][2];\n"
534 " incoord /= texture_extents;\n"
535 " if(incoord.x > image_extents.x || incoord.y > image_extents.y)\n"
536 " gl_FragColor = border_color;\n"
538 " gl_FragColor = texture2D(tex, incoord);\n"
541 float affine_matrix[9] = {
542 (float)m.values[0][0], (float)m.values[1][0], (float)m.values[2][0],
543 (float)m.values[0][1], (float)m.values[1][1], (float)m.values[2][1],
544 (float)m.values[0][2], (float)m.values[1][2], (float)m.values[2][2]
548 server->output->to_texture();
549 server->output->enable_opengl();
550 unsigned int frag_shader = VFrame::make_shader(0,
555 glUseProgram(frag_shader);
556 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
557 glUniformMatrix3fv(glGetUniformLocation(frag_shader, "affine_matrix"),
561 glUniform2f(glGetUniformLocation(frag_shader, "texture_extents"),
562 (GLfloat)server->output->get_texture_w(),
563 (GLfloat)server->output->get_texture_h());
564 glUniform2f(glGetUniformLocation(frag_shader, "image_extents"),
565 (GLfloat)server->output->get_w() / server->output->get_texture_w(),
566 (GLfloat)server->output->get_h() / server->output->get_texture_h());
567 float border_color[] = { 0, 0, 0, 0 };
568 if(BC_CModels::is_yuv(server->output->get_color_model()))
570 border_color[1] = 0.5;
571 border_color[2] = 0.5;
573 if(!BC_CModels::has_alpha(server->output->get_color_model()))
575 border_color[3] = 1.0;
578 glUniform4fv(glGetUniformLocation(frag_shader, "border_color"),
580 (GLfloat*)border_color);
581 server->output->init_screen();
582 server->output->bind_texture(0);
583 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
584 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
585 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
586 server->output->draw_texture();
588 server->output->set_opengl_state(VFrame::SCREEN);
599 #define ROUND(x) ((int)((x > 0) ? (x) + 0.5 : (x) - 0.5))
600 #define MIN4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
601 #define MAX4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
603 tx1 = ROUND(MIN4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
604 ty1 = ROUND(MIN4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
606 tx2 = ROUND(MAX4(dx1 - pivot_offset_x, dx2 - pivot_offset_x, dx3 - pivot_offset_x, dx4 - pivot_offset_x));
607 ty2 = ROUND(MAX4(dy1 - pivot_offset_y, dy2 - pivot_offset_y, dy3 - pivot_offset_y, dy4 - pivot_offset_y));
609 CLAMP(ty1, pkg->y1, pkg->y2);
610 CLAMP(ty2, pkg->y1, pkg->y2);
611 CLAMP(tx1, server->out_x, server->out_x + server->out_w);
612 CLAMP(tx2, server->out_x, server->out_x + server->out_w);
615 xinc = m.values[0][0];
616 yinc = m.values[1][0];
617 winc = m.values[2][0];
619 //printf("AffineUnit::process_package 2 tx1=%d ty1=%d tx2=%d ty2=%d %f %f\n", tx1, ty1, tx2, ty2, out_x4, out_y4);
620 //printf("AffineUnit::process_package %d %d %d %d %d\n",
627 #define CUBIC_ROW(in_row, chroma_offset) \
628 transform_cubic(dx, \
629 in_row[col1_offset] - chroma_offset, \
630 in_row[col2_offset] - chroma_offset, \
631 in_row[col3_offset] - chroma_offset, \
632 in_row[col4_offset] - chroma_offset)
635 #define TRANSFORM(components, type, temp_type, chroma_offset, max) \
637 type **in_rows = (type**)server->input->get_rows(); \
638 float round_factor = 0.0; \
639 if(sizeof(type) < 4) round_factor = 0.5; \
640 for(int y = ty1; y < ty2; y++) \
642 type *out_row = (type*)server->output->get_rows()[y]; \
646 tx = xinc * (tx1 + 0.5) + \
647 m.values[0][1] * (y + pivot_offset_y + 0.5) + \
649 pivot_offset_x * xinc; \
650 ty = yinc * (tx1 + 0.5) + \
651 m.values[1][1] * (y + pivot_offset_y + 0.5) + \
653 pivot_offset_x * yinc; \
654 tw = winc * (tx1 + 0.5) + \
655 m.values[2][1] * (y + pivot_offset_y + 0.5) + \
657 pivot_offset_x * winc; \
662 m.values[0][1] * (y + pivot_offset_y) + \
664 pivot_offset_x * xinc; \
666 m.values[1][1] * (y + pivot_offset_y) + \
668 pivot_offset_x * yinc; \
670 m.values[2][1] * (y + pivot_offset_y) + \
672 pivot_offset_x * winc; \
676 out_row += tx1 * components; \
677 for(int x = tx1; x < tx2; x++) \
679 /* Normalize homogeneous coords */ \
699 int row1 = ity - 1; \
701 int row3 = ity + 1; \
702 int row4 = ity + 2; \
703 CLAMP(row1, min_in_y, max_in_y); \
704 CLAMP(row2, min_in_y, max_in_y); \
705 CLAMP(row3, min_in_y, max_in_y); \
706 CLAMP(row4, min_in_y, max_in_y); \
708 /* Set destination pixels if in clipping region */ \
713 if(itx >= min_in_x && \
718 type *src = in_rows[ity] + itx * components; \
719 *out_row++ = *src++; \
720 *out_row++ = *src++; \
721 *out_row++ = *src++; \
722 if(components == 4) *out_row++ = *src; \
725 /* Fill with chroma */ \
728 *out_row++ = chroma_offset; \
729 *out_row++ = chroma_offset; \
730 if(components == 4) *out_row++ = 0; \
734 /* Bicubic algorithm */ \
739 /* clipping region */ \
740 if ((itx + 2) >= min_in_x && \
741 (itx - 1) <= max_in_x && \
742 (ity + 2) >= min_in_y && \
743 (ity - 1) <= max_in_y) \
747 /* the fractional error */ \
751 /* Row and column offsets in cubic block */ \
752 int col1 = itx - 1; \
754 int col3 = itx + 1; \
755 int col4 = itx + 2; \
756 CLAMP(col1, min_in_x, max_in_x); \
757 CLAMP(col2, min_in_x, max_in_x); \
758 CLAMP(col3, min_in_x, max_in_x); \
759 CLAMP(col4, min_in_x, max_in_x); \
760 int col1_offset = col1 * components; \
761 int col2_offset = col2 * components; \
762 int col3_offset = col3 * components; \
763 int col4_offset = col4 * components; \
765 type *row1_ptr = in_rows[row1]; \
766 type *row2_ptr = in_rows[row2]; \
767 type *row3_ptr = in_rows[row3]; \
768 type *row4_ptr = in_rows[row4]; \
769 temp_type r, g, b, a; \
771 r = (temp_type)(transform_cubic(dy, \
772 CUBIC_ROW(row1_ptr, 0x0), \
773 CUBIC_ROW(row2_ptr, 0x0), \
774 CUBIC_ROW(row3_ptr, 0x0), \
775 CUBIC_ROW(row4_ptr, 0x0)) + \
782 g = (temp_type)(transform_cubic(dy, \
783 CUBIC_ROW(row1_ptr, chroma_offset), \
784 CUBIC_ROW(row2_ptr, chroma_offset), \
785 CUBIC_ROW(row3_ptr, chroma_offset), \
786 CUBIC_ROW(row4_ptr, chroma_offset)) + \
788 g += chroma_offset; \
794 b = (temp_type)(transform_cubic(dy, \
795 CUBIC_ROW(row1_ptr, chroma_offset), \
796 CUBIC_ROW(row2_ptr, chroma_offset), \
797 CUBIC_ROW(row3_ptr, chroma_offset), \
798 CUBIC_ROW(row4_ptr, chroma_offset)) + \
800 b += chroma_offset; \
802 if(components == 4) \
808 a = (temp_type)(transform_cubic(dy, \
809 CUBIC_ROW(row1_ptr, 0x0), \
810 CUBIC_ROW(row2_ptr, 0x0), \
811 CUBIC_ROW(row3_ptr, 0x0), \
812 CUBIC_ROW(row4_ptr, 0x0)) + \
816 if(sizeof(type) < 4) \
818 *out_row++ = CLIP(r, 0, max); \
819 *out_row++ = CLIP(g, 0, max); \
820 *out_row++ = CLIP(b, 0, max); \
821 if(components == 4) *out_row++ = CLIP(a, 0, max); \
828 if(components == 4) *out_row++ = a; \
832 /* Fill with chroma */ \
835 *out_row++ = chroma_offset; \
836 *out_row++ = chroma_offset; \
837 if(components == 4) *out_row++ = 0; \
842 out_row += components; \
845 /* increment the transformed coordinates */ \
856 // printf("AffineUnit::process_package %d tx1=%d ty1=%d tx2=%d ty2=%d\n",
857 // __LINE__, tx1, ty1, tx2, ty2);
858 switch(server->input->get_color_model())
861 TRANSFORM(3, float, float, 0x0, 1.0)
864 TRANSFORM(3, unsigned char, int, 0x0, 0xff)
867 TRANSFORM(4, float, float, 0x0, 1.0)
870 TRANSFORM(4, unsigned char, int, 0x0, 0xff)
874 // TRANSFORM(3, unsigned char, int, 0x80, 0xff)
877 unsigned char **in_rows = (unsigned char**)server->input->get_rows();
878 float round_factor = 0.0;
879 if(sizeof(unsigned char) < 4) round_factor = 0.5;
881 for(int y = ty1; y < ty2; y++)
883 //printf("AffineUnit::process_package %d y=%d tx1=%d tx2=%d ty1=%d ty2=%d\n",
884 //__LINE__, y, tx1, tx2, ty1, ty2);
885 unsigned char *out_row = (unsigned char*)server->output->get_rows()[y];
889 tx = xinc * (tx1 + 0.5) +
890 m.values[0][1] * (y + pivot_offset_y + 0.5) +
892 pivot_offset_x * xinc;
893 ty = yinc * (tx1 + 0.5) +
894 m.values[1][1] * (y + pivot_offset_y + 0.5) +
896 pivot_offset_x * yinc;
897 tw = winc * (tx1 + 0.5) +
898 m.values[2][1] * (y + pivot_offset_y + 0.5) +
900 pivot_offset_x * winc;
905 m.values[0][1] * (y + pivot_offset_y) +
907 pivot_offset_x * xinc;
909 m.values[1][1] * (y + pivot_offset_y) +
911 pivot_offset_x * yinc;
913 m.values[2][1] * (y + pivot_offset_y) +
915 pivot_offset_x * winc;
920 for(int x = tx1; x < tx2; x++)
922 /* Normalize homogeneous coords */
946 CLAMP(row1, min_in_y, max_in_y);
947 CLAMP(row2, min_in_y, max_in_y);
948 CLAMP(row3, min_in_y, max_in_y);
949 CLAMP(row4, min_in_y, max_in_y);
951 /* Set destination pixels if in clipping region */
956 if(itx >= min_in_x &&
961 unsigned char *src = in_rows[ity] + itx * 3;
965 if(3 == 4) *out_row++ = *src;
968 /* Fill with chroma */
973 if(3 == 4) *out_row++ = 0;
977 /* Bicubic algorithm */
982 /* clipping region */
983 if ((itx + 2) >= min_in_x &&
984 (itx - 1) <= max_in_x &&
985 (ity + 2) >= min_in_y &&
986 (ity - 1) <= max_in_y)
990 /* the fractional error */
994 /* Row and column offsets in cubic block */
999 CLAMP(col1, min_in_x, max_in_x);
1000 CLAMP(col2, min_in_x, max_in_x);
1001 CLAMP(col3, min_in_x, max_in_x);
1002 CLAMP(col4, min_in_x, max_in_x);
1003 int col1_offset = col1 * 3;
1004 int col2_offset = col2 * 3;
1005 int col3_offset = col3 * 3;
1006 int col4_offset = col4 * 3;
1008 unsigned char *row1_ptr = in_rows[row1];
1009 unsigned char *row2_ptr = in_rows[row2];
1010 unsigned char *row3_ptr = in_rows[row3];
1011 unsigned char *row4_ptr = in_rows[row4];
1014 r = (int)(transform_cubic(dy,
1015 CUBIC_ROW(row1_ptr, 0x0),
1016 CUBIC_ROW(row2_ptr, 0x0),
1017 CUBIC_ROW(row3_ptr, 0x0),
1018 CUBIC_ROW(row4_ptr, 0x0)) +
1025 g = (int)(transform_cubic(dy,
1026 CUBIC_ROW(row1_ptr, 0x80),
1027 CUBIC_ROW(row2_ptr, 0x80),
1028 CUBIC_ROW(row3_ptr, 0x80),
1029 CUBIC_ROW(row4_ptr, 0x80)) +
1037 b = (int)(transform_cubic(dy,
1038 CUBIC_ROW(row1_ptr, 0x80),
1039 CUBIC_ROW(row2_ptr, 0x80),
1040 CUBIC_ROW(row3_ptr, 0x80),
1041 CUBIC_ROW(row4_ptr, 0x80)) +
1051 a = (int)(transform_cubic(dy,
1052 CUBIC_ROW(row1_ptr, 0x0),
1053 CUBIC_ROW(row2_ptr, 0x0),
1054 CUBIC_ROW(row3_ptr, 0x0),
1055 CUBIC_ROW(row4_ptr, 0x0)) +
1059 if(sizeof(unsigned char) < 4)
1061 *out_row++ = CLIP(r, 0, 0xff);
1062 *out_row++ = CLIP(g, 0, 0xff);
1063 *out_row++ = CLIP(b, 0, 0xff);
1064 if(3 == 4) *out_row++ = CLIP(a, 0, 0xff);
1071 if(3 == 4) *out_row++ = a;
1075 /* Fill with chroma */
1080 if(3 == 4) *out_row++ = 0;
1088 /* increment the transformed coordinates */
1098 TRANSFORM(4, unsigned char, int, 0x80, 0xff)
1101 TRANSFORM(3, uint16_t, int, 0x0, 0xffff)
1103 case BC_RGBA16161616:
1104 TRANSFORM(4, uint16_t, int, 0x0, 0xffff)
1107 TRANSFORM(3, uint16_t, int, 0x8000, 0xffff)
1109 case BC_YUVA16161616:
1110 TRANSFORM(4, uint16_t, int, 0x8000, 0xffff)
1117 int min_x = server->in_x * AFFINE_OVERSAMPLE;
1118 int min_y = server->in_y * AFFINE_OVERSAMPLE;
1119 int max_x = server->in_x * AFFINE_OVERSAMPLE + server->in_w * AFFINE_OVERSAMPLE - 1;
1120 int max_y = server->in_y * AFFINE_OVERSAMPLE + server->in_h * AFFINE_OVERSAMPLE - 1;
1121 float top_w = out_x2 - out_x1;
1122 float bottom_w = out_x3 - out_x4;
1123 float left_h = out_y4 - out_y1;
1124 float right_h = out_y3 - out_y2;
1125 float out_w_diff = bottom_w - top_w;
1126 float out_left_diff = out_x4 - out_x1;
1127 float out_h_diff = right_h - left_h;
1128 float out_top_diff = out_y2 - out_y1;
1129 float distance1 = DISTANCE(out_x1, out_y1, out_x2, out_y2);
1130 float distance2 = DISTANCE(out_x2, out_y2, out_x3, out_y3);
1131 float distance3 = DISTANCE(out_x3, out_y3, out_x4, out_y4);
1132 float distance4 = DISTANCE(out_x4, out_y4, out_x1, out_y1);
1133 float max_v = MAX(distance1, distance3);
1134 float max_h = MAX(distance2, distance4);
1135 float max_dimension = MAX(max_v, max_h);
1136 float min_dimension = MIN(server->in_h, server->in_w);
1137 float step = min_dimension / max_dimension / AFFINE_OVERSAMPLE;
1138 float x_f = server->in_x;
1139 float y_f = server->in_y;
1140 float h_f = server->in_h;
1141 float w_f = server->in_w;
1145 if(server->use_opengl)
1153 #define DO_STRETCH(type, components) \
1155 type **in_rows = (type**)server->input->get_rows(); \
1156 type **out_rows = (type**)server->temp->get_rows(); \
1158 for(float in_y = pkg->y1; in_y < pkg->y2; in_y += step) \
1160 int i = (int)in_y; \
1161 type *in_row = in_rows[i]; \
1162 for(float in_x = x_f; in_x < w_f; in_x += step) \
1164 int j = (int)in_x; \
1165 float in_x_fraction = (in_x - x_f) / w_f; \
1166 float in_y_fraction = (in_y - y_f) / h_f; \
1167 int out_x = (int)((out_x1 + \
1168 out_left_diff * in_y_fraction + \
1169 (top_w + out_w_diff * in_y_fraction) * in_x_fraction) * \
1170 AFFINE_OVERSAMPLE); \
1171 int out_y = (int)((out_y1 + \
1172 out_top_diff * in_x_fraction + \
1173 (left_h + out_h_diff * in_x_fraction) * in_y_fraction) * \
1174 AFFINE_OVERSAMPLE); \
1175 CLAMP(out_x, min_x, max_x); \
1176 CLAMP(out_y, min_y, max_y); \
1177 type *dst = out_rows[out_y] + out_x * components; \
1178 type *src = in_row + j * components; \
1182 if(components == 4) dst[3] = src[3]; \
1187 switch(server->input->get_color_model())
1190 DO_STRETCH(float, 3)
1193 DO_STRETCH(unsigned char, 3)
1196 DO_STRETCH(float, 4)
1199 DO_STRETCH(unsigned char, 4)
1202 DO_STRETCH(unsigned char, 3)
1205 DO_STRETCH(unsigned char, 4)
1208 DO_STRETCH(uint16_t, 3)
1210 case BC_RGBA16161616:
1211 DO_STRETCH(uint16_t, 4)
1214 DO_STRETCH(uint16_t, 3)
1216 case BC_YUVA16161616:
1217 DO_STRETCH(uint16_t, 4)
1232 AffineEngine::AffineEngine(int total_clients,
1236 total_clients, total_packages
1239 user_in_viewport = 0;
1241 user_out_viewport = 0;
1244 in_x = in_y = in_w = in_h = 0;
1245 out_x = out_y = out_w = out_h = 0;
1246 in_pivot_x = in_pivot_y = 0;
1247 out_pivot_x = out_pivot_y = 0;
1248 this->total_packages = total_packages;
1251 void AffineEngine::init_packages()
1253 for(int i = 0; i < get_total_packages(); i++)
1255 AffinePackage *package = (AffinePackage*)get_package(i);
1256 package->y1 = out_y + (out_h * i / get_total_packages());
1257 package->y2 = out_y + (out_h * (i + 1) / get_total_packages());
1261 LoadClient* AffineEngine::new_client()
1263 return new AffineUnit(this);
1266 LoadPackage* AffineEngine::new_package()
1268 return new AffinePackage;
1271 void AffineEngine::process(VFrame *output,
1287 // printf("AffineEngine::process %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
1298 // printf("AffineEngine::process %d %d %d %d %d\n",
1300 // in_x, in_y, in_w, in_h);
1302 // printf("AffineEngine::process %d %d %d %d %d\n",
1304 // out_x, out_y, out_w, out_h);
1306 // printf("AffineEngine::process %d %d %d %d %d\n",
1308 // in_pivot_x, in_pivot_y, out_pivot_x, out_pivot_y);
1310 // printf("AffineEngine::process %d %d %d %d %d\n",
1314 // user_in_viewport,
1315 // user_out_viewport);
1317 this->output = output;
1318 this->input = input;
1329 this->forward = forward;
1332 if(!user_in_viewport)
1336 in_w = input->get_w();
1337 in_h = input->get_h();
1340 if(!user_out_viewport)
1344 out_w = output->get_w();
1345 out_h = output->get_h();
1350 set_package_count(1);
1355 set_package_count(total_packages);
1363 void AffineEngine::rotate(VFrame *output,
1367 this->output = output;
1368 this->input = input;
1370 this->mode = ROTATE;
1373 if(!user_in_viewport)
1377 in_w = input->get_w();
1378 in_h = input->get_h();
1384 // printf("AffineEngine::rotate %d %d %d %d %d\n", __LINE__, in_x, in_w, in_y, in_h);
1389 in_pivot_x = in_x + in_w / 2;
1390 in_pivot_y = in_y + in_h / 2;
1393 if(!user_out_viewport)
1397 out_w = output->get_w();
1398 out_h = output->get_h();
1403 out_pivot_x = out_x + out_w / 2;
1404 out_pivot_y = out_y + out_h / 2;
1407 // All subscripts are clockwise around the quadrangle
1408 angle = angle * 2 * M_PI / 360;
1409 double angle1 = atan((double)(in_pivot_y - in_y) / (double)(in_pivot_x - in_x)) + angle;
1410 double angle2 = atan((double)(in_x + in_w - in_pivot_x) / (double)(in_pivot_y - in_y)) + angle;
1411 double angle3 = atan((double)(in_y + in_h - in_pivot_y) / (double)(in_x + in_w - in_pivot_x)) + angle;
1412 double angle4 = atan((double)(in_pivot_x - in_x) / (double)(in_y + in_h - in_pivot_y)) + angle;
1413 double radius1 = DISTANCE(in_x, in_y, in_pivot_x, in_pivot_y);
1414 double radius2 = DISTANCE(in_x + in_w, in_y, in_pivot_x, in_pivot_y);
1415 double radius3 = DISTANCE(in_x + in_w, in_y + in_h, in_pivot_x, in_pivot_y);
1416 double radius4 = DISTANCE(in_x, in_y + in_h, in_pivot_x, in_pivot_y);
1418 x1 = ((in_pivot_x - in_x) - cos(angle1) * radius1) * 100 / in_w;
1419 y1 = ((in_pivot_y - in_y) - sin(angle1) * radius1) * 100 / in_h;
1420 x2 = ((in_pivot_x - in_x) + sin(angle2) * radius2) * 100 / in_w;
1421 y2 = ((in_pivot_y - in_y) - cos(angle2) * radius2) * 100 / in_h;
1422 x3 = ((in_pivot_x - in_x) + cos(angle3) * radius3) * 100 / in_w;
1423 y3 = ((in_pivot_y - in_y) + sin(angle3) * radius3) * 100 / in_h;
1424 x4 = ((in_pivot_x - in_x) - sin(angle4) * radius4) * 100 / in_w;
1425 y4 = ((in_pivot_y - in_y) + cos(angle4) * radius4) * 100 / in_h;
1427 // printf("AffineEngine::rotate angle=%f\n",
1431 // printf(" angle1=%f angle2=%f angle3=%f angle4=%f\n",
1432 // angle1 * 360 / 2 / M_PI,
1433 // angle2 * 360 / 2 / M_PI,
1434 // angle3 * 360 / 2 / M_PI,
1435 // angle4 * 360 / 2 / M_PI);
1437 // printf(" radius1=%f radius2=%f radius3=%f radius4=%f\n",
1443 // printf(" x1=%f y1=%f x2=%f y2=%f x3=%f y3=%f x4=%f y4=%f\n",
1455 set_package_count(1);
1460 set_package_count(total_packages);
1465 void AffineEngine::set_matrix(AffineMatrix *matrix)
1467 for(int i = 0; i < 3; i++)
1469 for(int j = 0; j < 3; j++)
1471 this->matrix.values[i][j] = matrix->values[i][j];
1476 void AffineEngine::set_in_viewport(int x, int y, int w, int h)
1482 this->user_in_viewport = 1;
1485 void AffineEngine::set_out_viewport(int x, int y, int w, int h)
1491 this->user_out_viewport = 1;
1494 void AffineEngine::set_viewport(int x, int y, int w, int h)
1496 set_in_viewport(x, y, w, h);
1497 set_out_viewport(x, y, w, h);
1500 void AffineEngine::set_opengl(int value)
1502 this->use_opengl = value;
1505 void AffineEngine::set_in_pivot(int x, int y)
1507 this->in_pivot_x = x;
1508 this->in_pivot_y = y;
1509 this->user_in_pivot = 1;
1512 void AffineEngine::set_out_pivot(int x, int y)
1514 this->out_pivot_x = x;
1515 this->out_pivot_y = y;
1516 this->user_out_pivot = 1;
1519 void AffineEngine::set_pivot(int x, int y)
1522 set_out_pivot(x, y);
1525 void AffineEngine::unset_pivot()
1531 void AffineEngine::unset_viewport()
1533 user_in_viewport = 0;
1534 user_out_viewport = 0;