gdiplus: Add a stub for GdipSetLinePresetBlend.
[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 "objbase.h"
27
28 #include "gdiplus.h"
29 #include "gdiplus_private.h"
30
31 /* Multiplies two matrices of the form
32  *
33  * idx:0 idx:1     0
34  * idx:2 idx:3     0
35  * idx:4 idx:5     1
36  *
37  * and puts the output in out.
38  * */
39 static void matrix_multiply(GDIPCONST REAL * left, GDIPCONST REAL * right, REAL * out)
40 {
41     REAL temp[6];
42     int i, odd;
43
44     for(i = 0; i < 6; i++){
45         odd = i % 2;
46         temp[i] = left[i - odd] * right[odd] + left[i - odd + 1] * right[odd + 2] +
47                   (i >= 4 ? right[odd + 4] : 0.0);
48     }
49
50     memcpy(out, temp, 6 * sizeof(REAL));
51 }
52
53 GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22,
54     REAL dx, REAL dy, GpMatrix **matrix)
55 {
56     if(!matrix)
57         return InvalidParameter;
58
59     *matrix = GdipAlloc(sizeof(GpMatrix));
60     if(!*matrix)    return OutOfMemory;
61
62     /* first row */
63     (*matrix)->matrix[0] = m11;
64     (*matrix)->matrix[1] = m12;
65     /* second row */
66     (*matrix)->matrix[2] = m21;
67     (*matrix)->matrix[3] = m22;
68     /* third row */
69     (*matrix)->matrix[4] = dx;
70     (*matrix)->matrix[5] = dy;
71
72     return Ok;
73 }
74
75 GpStatus WINGDIPAPI GdipCreateMatrix3(GDIPCONST GpRectF *rect,
76     GDIPCONST GpPointF *pt, GpMatrix **matrix)
77 {
78     if(!matrix)
79         return InvalidParameter;
80
81     *matrix = GdipAlloc(sizeof(GpMatrix));
82     if(!*matrix)    return OutOfMemory;
83
84     memcpy((*matrix)->matrix, rect, 4 * sizeof(REAL));
85
86     (*matrix)->matrix[4] = pt->X;
87     (*matrix)->matrix[5] = pt->Y;
88
89     return Ok;
90 }
91
92 GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix *matrix, GpMatrix **clone)
93 {
94     if(!matrix || !clone)
95         return InvalidParameter;
96
97     *clone = GdipAlloc(sizeof(GpMatrix));
98     if(!*clone)    return OutOfMemory;
99
100     **clone = *matrix;
101
102     return Ok;
103 }
104
105 GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix)
106 {
107     if(!matrix)
108         return InvalidParameter;
109
110     *matrix = GdipAlloc(sizeof(GpMatrix));
111     if(!*matrix)    return OutOfMemory;
112
113     (*matrix)->matrix[0] = 1.0;
114     (*matrix)->matrix[1] = 0.0;
115     (*matrix)->matrix[2] = 0.0;
116     (*matrix)->matrix[3] = 1.0;
117     (*matrix)->matrix[4] = 0.0;
118     (*matrix)->matrix[5] = 0.0;
119
120     return Ok;
121 }
122
123 GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix)
124 {
125     if(!matrix)
126         return InvalidParameter;
127
128     GdipFree(matrix);
129
130     return Ok;
131 }
132
133 GpStatus WINGDIPAPI GdipGetMatrixElements(GDIPCONST GpMatrix *matrix,
134     REAL *out)
135 {
136     if(!matrix || !out)
137         return InvalidParameter;
138
139     memcpy(out, matrix->matrix, sizeof(matrix->matrix));
140
141     return Ok;
142 }
143
144 GpStatus WINGDIPAPI GdipMultiplyMatrix(GpMatrix *matrix, GpMatrix* matrix2,
145     GpMatrixOrder order)
146 {
147     if(!matrix || !matrix2)
148         return InvalidParameter;
149
150     if(order == MatrixOrderAppend)
151         matrix_multiply(matrix->matrix, matrix2->matrix, matrix->matrix);
152     else
153         matrix_multiply(matrix2->matrix, matrix->matrix, matrix->matrix);
154
155     return Ok;
156 }
157
158 GpStatus WINGDIPAPI GdipRotateMatrix(GpMatrix *matrix, REAL angle,
159     GpMatrixOrder order)
160 {
161     REAL cos_theta, sin_theta, rotate[6];
162
163     if(!matrix)
164         return InvalidParameter;
165
166     angle = deg2rad(angle);
167     cos_theta = cos(angle);
168     sin_theta = sin(angle);
169
170     rotate[0] = cos_theta;
171     rotate[1] = sin_theta;
172     rotate[2] = -sin_theta;
173     rotate[3] = cos_theta;
174     rotate[4] = 0.0;
175     rotate[5] = 0.0;
176
177     if(order == MatrixOrderAppend)
178         matrix_multiply(matrix->matrix, rotate, matrix->matrix);
179     else
180         matrix_multiply(rotate, matrix->matrix, matrix->matrix);
181
182     return Ok;
183 }
184
185 GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY,
186     GpMatrixOrder order)
187 {
188     REAL scale[6];
189
190     if(!matrix)
191         return InvalidParameter;
192
193     scale[0] = scaleX;
194     scale[1] = 0.0;
195     scale[2] = 0.0;
196     scale[3] = scaleY;
197     scale[4] = 0.0;
198     scale[5] = 0.0;
199
200     if(order == MatrixOrderAppend)
201         matrix_multiply(matrix->matrix, scale, matrix->matrix);
202     else
203         matrix_multiply(scale, matrix->matrix, matrix->matrix);
204
205     return Ok;
206 }
207
208 GpStatus WINGDIPAPI GdipSetMatrixElements(GpMatrix *matrix, REAL m11, REAL m12,
209     REAL m21, REAL m22, REAL dx, REAL dy)
210 {
211     if(!matrix)
212         return InvalidParameter;
213
214     matrix->matrix[0] = m11;
215     matrix->matrix[1] = m12;
216     matrix->matrix[2] = m21;
217     matrix->matrix[3] = m22;
218     matrix->matrix[4] = dx;
219     matrix->matrix[5] = dy;
220
221     return Ok;
222 }
223
224 GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts,
225                                               INT count)
226 {
227     REAL x, y;
228     INT i;
229
230     if(!matrix || !pts)
231         return InvalidParameter;
232
233     for(i = 0; i < count; i++)
234     {
235         x = pts[i].X;
236         y = pts[i].Y;
237
238         pts[i].X = x * matrix->matrix[0] + y * matrix->matrix[2] + matrix->matrix[4];
239         pts[i].Y = x * matrix->matrix[1] + y * matrix->matrix[3] + matrix->matrix[5];
240     }
241
242     return Ok;
243 }
244
245 GpStatus WINGDIPAPI GdipTranslateMatrix(GpMatrix *matrix, REAL offsetX,
246     REAL offsetY, GpMatrixOrder order)
247 {
248     REAL translate[6];
249
250     if(!matrix)
251         return InvalidParameter;
252
253     translate[0] = 1.0;
254     translate[1] = 0.0;
255     translate[2] = 0.0;
256     translate[3] = 1.0;
257     translate[4] = offsetX;
258     translate[5] = offsetY;
259
260     if(order == MatrixOrderAppend)
261         matrix_multiply(matrix->matrix, translate, matrix->matrix);
262     else
263         matrix_multiply(translate, matrix->matrix, matrix->matrix);
264
265     return Ok;
266 }