crypt32: Introduce function to encode an array of items as a set.
[wine] / dlls / gdiplus / matrix.c
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include <math.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25
26 #include "gdiplus.h"
27 #include "gdiplus_private.h"
28
29 /* Multiplies two matrices of the form
30  *
31  * idx:0 idx:1     0
32  * idx:2 idx:3     0
33  * idx:4 idx:5     1
34  *
35  * and puts the output in out.
36  * */
37 static void matrix_multiply(GDIPCONST REAL * left, GDIPCONST REAL * right, REAL * out)
38 {
39     REAL temp[6];
40     int i, odd;
41
42     for(i = 0; i < 6; i++){
43         odd = i % 2;
44         temp[i] = left[i - odd] * right[odd] + left[i - odd + 1] * right[odd + 2] +
45                   (i >= 4 ? right[odd + 4] : 0.0);
46     }
47
48     memcpy(out, temp, 6 * sizeof(REAL));
49 }
50
51 GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22,
52     REAL dx, REAL dy, GpMatrix **matrix)
53 {
54     if(!matrix)
55         return InvalidParameter;
56
57     *matrix = GdipAlloc(sizeof(GpMatrix));
58     if(!*matrix)    return OutOfMemory;
59
60     /* first row */
61     (*matrix)->matrix[0] = m11;
62     (*matrix)->matrix[1] = m12;
63     /* second row */
64     (*matrix)->matrix[2] = m21;
65     (*matrix)->matrix[3] = m22;
66     /* third row */
67     (*matrix)->matrix[4] = dx;
68     (*matrix)->matrix[5] = dy;
69
70     return Ok;
71 }
72
73 GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix)
74 {
75     if(!matrix)
76         return InvalidParameter;
77
78     *matrix = GdipAlloc(sizeof(GpMatrix));
79     if(!*matrix)    return OutOfMemory;
80
81     (*matrix)->matrix[0] = 1.0;
82     (*matrix)->matrix[1] = 0.0;
83     (*matrix)->matrix[2] = 0.0;
84     (*matrix)->matrix[3] = 1.0;
85     (*matrix)->matrix[4] = 0.0;
86     (*matrix)->matrix[5] = 0.0;
87
88     return Ok;
89 }
90
91 GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix)
92 {
93     if(!matrix)
94         return InvalidParameter;
95
96     GdipFree(matrix);
97
98     return Ok;
99 }
100
101 GpStatus WINGDIPAPI GdipMultiplyMatrix(GpMatrix *matrix, GpMatrix* matrix2,
102     GpMatrixOrder order)
103 {
104     if(!matrix || !matrix2)
105         return InvalidParameter;
106
107     if(order == MatrixOrderAppend)
108         matrix_multiply(matrix->matrix, matrix2->matrix, matrix->matrix);
109     else
110         matrix_multiply(matrix2->matrix, matrix->matrix, matrix->matrix);
111
112     return Ok;
113 }
114
115 GpStatus WINGDIPAPI GdipRotateMatrix(GpMatrix *matrix, REAL angle,
116     GpMatrixOrder order)
117 {
118     REAL cos_theta, sin_theta, rotate[6];
119
120     if(!matrix)
121         return InvalidParameter;
122
123     angle = deg2rad(angle);
124     cos_theta = cos(angle);
125     sin_theta = sin(angle);
126
127     rotate[0] = cos_theta;
128     rotate[1] = sin_theta;
129     rotate[2] = -sin_theta;
130     rotate[3] = cos_theta;
131     rotate[4] = 0.0;
132     rotate[5] = 0.0;
133
134     if(order == MatrixOrderAppend)
135         matrix_multiply(matrix->matrix, rotate, matrix->matrix);
136     else
137         matrix_multiply(rotate, matrix->matrix, matrix->matrix);
138
139     return Ok;
140 }
141
142 GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY,
143     GpMatrixOrder order)
144 {
145     REAL scale[6];
146
147     if(!matrix)
148         return InvalidParameter;
149
150     scale[0] = scaleX;
151     scale[1] = 0.0;
152     scale[2] = 0.0;
153     scale[3] = scaleY;
154     scale[4] = 0.0;
155     scale[5] = 0.0;
156
157     if(order == MatrixOrderAppend)
158         matrix_multiply(matrix->matrix, scale, matrix->matrix);
159     else
160         matrix_multiply(scale, matrix->matrix, matrix->matrix);
161
162     return Ok;
163 }
164
165 GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts,
166                                               INT count)
167 {
168     REAL x, y;
169     INT i;
170
171     if(!matrix || !pts)
172         return InvalidParameter;
173
174     for(i = 0; i < count; i++)
175     {
176         x = pts[i].X;
177         y = pts[i].Y;
178
179         pts[i].X = x * matrix->matrix[0] + y * matrix->matrix[2] + matrix->matrix[4];
180         pts[i].Y = x * matrix->matrix[1] + y * matrix->matrix[3] + matrix->matrix[5];
181     }
182
183     return Ok;
184 }
185
186 GpStatus WINGDIPAPI GdipTranslateMatrix(GpMatrix *matrix, REAL offsetX,
187     REAL offsetY, GpMatrixOrder order)
188 {
189     REAL translate[6];
190
191     if(!matrix)
192         return InvalidParameter;
193
194     translate[0] = 1.0;
195     translate[1] = 0.0;
196     translate[2] = 0.0;
197     translate[3] = 1.0;
198     translate[4] = offsetX;
199     translate[5] = offsetY;
200
201     if(order == MatrixOrderAppend)
202         matrix_multiply(matrix->matrix, translate, matrix->matrix);
203     else
204         matrix_multiply(translate, matrix->matrix, matrix->matrix);
205
206     return Ok;
207 }