/* * Copyright (C) 2007 Google (Evan Stade) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "objbase.h" #include "gdiplus.h" #include "gdiplus_private.h" /* Multiplies two matrices of the form * * idx:0 idx:1 0 * idx:2 idx:3 0 * idx:4 idx:5 1 * * and puts the output in out. * */ static void matrix_multiply(GDIPCONST REAL * left, GDIPCONST REAL * right, REAL * out) { REAL temp[6]; int i, odd; for(i = 0; i < 6; i++){ odd = i % 2; temp[i] = left[i - odd] * right[odd] + left[i - odd + 1] * right[odd + 2] + (i >= 4 ? right[odd + 4] : 0.0); } memcpy(out, temp, 6 * sizeof(REAL)); } GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy, GpMatrix **matrix) { if(!matrix) return InvalidParameter; *matrix = GdipAlloc(sizeof(GpMatrix)); if(!*matrix) return OutOfMemory; /* first row */ (*matrix)->matrix[0] = m11; (*matrix)->matrix[1] = m12; /* second row */ (*matrix)->matrix[2] = m21; (*matrix)->matrix[3] = m22; /* third row */ (*matrix)->matrix[4] = dx; (*matrix)->matrix[5] = dy; return Ok; } GpStatus WINGDIPAPI GdipCreateMatrix3(GDIPCONST GpRectF *rect, GDIPCONST GpPointF *pt, GpMatrix **matrix) { if(!matrix) return InvalidParameter; *matrix = GdipAlloc(sizeof(GpMatrix)); if(!*matrix) return OutOfMemory; memcpy((*matrix)->matrix, rect, 4 * sizeof(REAL)); (*matrix)->matrix[4] = pt->X; (*matrix)->matrix[5] = pt->Y; return Ok; } GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix *matrix, GpMatrix **clone) { if(!matrix || !clone) return InvalidParameter; *clone = GdipAlloc(sizeof(GpMatrix)); if(!*clone) return OutOfMemory; memcpy(*clone, matrix, sizeof(GpMatrix)); return Ok; } GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix) { if(!matrix) return InvalidParameter; *matrix = GdipAlloc(sizeof(GpMatrix)); if(!*matrix) return OutOfMemory; (*matrix)->matrix[0] = 1.0; (*matrix)->matrix[1] = 0.0; (*matrix)->matrix[2] = 0.0; (*matrix)->matrix[3] = 1.0; (*matrix)->matrix[4] = 0.0; (*matrix)->matrix[5] = 0.0; return Ok; } GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix) { if(!matrix) return InvalidParameter; GdipFree(matrix); return Ok; } GpStatus WINGDIPAPI GdipGetMatrixElements(GDIPCONST GpMatrix *matrix, REAL *out) { if(!matrix || !out) return InvalidParameter; memcpy(out, matrix->matrix, sizeof(matrix->matrix)); return Ok; } GpStatus WINGDIPAPI GdipMultiplyMatrix(GpMatrix *matrix, GpMatrix* matrix2, GpMatrixOrder order) { if(!matrix || !matrix2) return InvalidParameter; if(order == MatrixOrderAppend) matrix_multiply(matrix->matrix, matrix2->matrix, matrix->matrix); else matrix_multiply(matrix2->matrix, matrix->matrix, matrix->matrix); return Ok; } GpStatus WINGDIPAPI GdipRotateMatrix(GpMatrix *matrix, REAL angle, GpMatrixOrder order) { REAL cos_theta, sin_theta, rotate[6]; if(!matrix) return InvalidParameter; angle = deg2rad(angle); cos_theta = cos(angle); sin_theta = sin(angle); rotate[0] = cos_theta; rotate[1] = sin_theta; rotate[2] = -sin_theta; rotate[3] = cos_theta; rotate[4] = 0.0; rotate[5] = 0.0; if(order == MatrixOrderAppend) matrix_multiply(matrix->matrix, rotate, matrix->matrix); else matrix_multiply(rotate, matrix->matrix, matrix->matrix); return Ok; } GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY, GpMatrixOrder order) { REAL scale[6]; if(!matrix) return InvalidParameter; scale[0] = scaleX; scale[1] = 0.0; scale[2] = 0.0; scale[3] = scaleY; scale[4] = 0.0; scale[5] = 0.0; if(order == MatrixOrderAppend) matrix_multiply(matrix->matrix, scale, matrix->matrix); else matrix_multiply(scale, matrix->matrix, matrix->matrix); return Ok; } GpStatus WINGDIPAPI GdipSetMatrixElements(GpMatrix *matrix, REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy) { if(!matrix) return InvalidParameter; matrix->matrix[0] = m11; matrix->matrix[1] = m12; matrix->matrix[2] = m21; matrix->matrix[3] = m22; matrix->matrix[4] = dx; matrix->matrix[5] = dy; return Ok; } GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts, INT count) { REAL x, y; INT i; if(!matrix || !pts) return InvalidParameter; for(i = 0; i < count; i++) { x = pts[i].X; y = pts[i].Y; pts[i].X = x * matrix->matrix[0] + y * matrix->matrix[2] + matrix->matrix[4]; pts[i].Y = x * matrix->matrix[1] + y * matrix->matrix[3] + matrix->matrix[5]; } return Ok; } GpStatus WINGDIPAPI GdipTranslateMatrix(GpMatrix *matrix, REAL offsetX, REAL offsetY, GpMatrixOrder order) { REAL translate[6]; if(!matrix) return InvalidParameter; translate[0] = 1.0; translate[1] = 0.0; translate[2] = 0.0; translate[3] = 1.0; translate[4] = offsetX; translate[5] = offsetY; if(order == MatrixOrderAppend) matrix_multiply(matrix->matrix, translate, matrix->matrix); else matrix_multiply(translate, matrix->matrix, matrix->matrix); return Ok; }