[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / xformobj.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/xformobj.c
5 * PURPOSE: XFORMOBJ api
6 * PROGRAMMER: Timo Kreuzer
7 */
8
9 /** Includes ******************************************************************/
10
11 #include <win32k.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 C_ASSERT(sizeof(FIX) == sizeof(LONG));
16 #define FIX2LONG(x) ((x) >> 4)
17 #define LONG2FIX(x) ((x) << 4)
18
19 #define FLOATOBJ_Equal _FLOATOBJ_Equal
20 #define FLOATOBJ_GetLong _FLOATOBJ_GetLong
21 #define FLOATOBJ_GetFix _FLOATOBJ_GetFix
22 #define FLOATOBJ_IsLong _FLOATOBJ_IsLong
23 #define FLOATOBJ_Equal0 _FLOATOBJ_Equal0
24 #define FLOATOBJ_Equal1 _FLOATOBJ_Equal1
25
26 /** Inline helper functions ***************************************************/
27
28 /*
29 * Inline helper to calculate pfo1 * pfo2 + pfo3 * pfo4
30 */
31 FORCEINLINE
32 VOID
33 MulAdd(
34 PFLOATOBJ pfoDest,
35 PFLOATOBJ pfo1,
36 PFLOATOBJ pfo2,
37 PFLOATOBJ pfo3,
38 PFLOATOBJ pfo4)
39 {
40 FLOATOBJ foTmp;
41
42 *pfoDest = *pfo1;
43 FLOATOBJ_Mul(pfoDest, pfo2);
44 foTmp = *pfo3;
45 FLOATOBJ_Mul(&foTmp, pfo4);
46 FLOATOBJ_Add(pfoDest, &foTmp);
47 }
48
49 /*
50 * Inline helper to calculate pfo1 * l2 + pfo3 * l4
51 */
52 FORCEINLINE
53 VOID
54 MulAddLong(
55 PFLOATOBJ pfoDest,
56 PFLOATOBJ pfo1,
57 LONG l2,
58 PFLOATOBJ pfo3,
59 LONG l4)
60 {
61 FLOATOBJ foTmp;
62
63 *pfoDest = *pfo1;
64 FLOATOBJ_MulLong(pfoDest, l2);
65 foTmp = *pfo3;
66 FLOATOBJ_MulLong(&foTmp, l4);
67 FLOATOBJ_Add(pfoDest, &foTmp);
68 }
69
70 /*
71 * Inline helper to calculate pfo1 * pfo2 - pfo3 * pfo4
72 */
73 FORCEINLINE
74 VOID
75 MulSub(
76 PFLOATOBJ pfoDest,
77 PFLOATOBJ pfo1,
78 PFLOATOBJ pfo2,
79 PFLOATOBJ pfo3,
80 PFLOATOBJ pfo4)
81 {
82 FLOATOBJ foTmp;
83
84 *pfoDest = *pfo1;
85 FLOATOBJ_Mul(pfoDest, pfo2);
86 foTmp = *pfo3;
87 FLOATOBJ_Mul(&foTmp, pfo4);
88 FLOATOBJ_Sub(pfoDest, &foTmp);
89 }
90
91 /*
92 * Inline helper to get the complexity hint from flAccel
93 */
94 FORCEINLINE
95 ULONG
96 HintFromAccel(ULONG flAccel)
97 {
98 switch (flAccel & (MX_NOTRANSLATE | MX_IDENTITYSCALE | MX_SCALE))
99 {
100 case (MX_SCALE | MX_IDENTITYSCALE | MX_NOTRANSLATE):
101 return GX_IDENTITY;
102 case (MX_SCALE | MX_IDENTITYSCALE):
103 return GX_OFFSET;
104 case MX_SCALE:
105 return GX_SCALE;
106 default:
107 return GX_GENERAL;
108 }
109 }
110
111 /** Internal functions ********************************************************/
112
113 ULONG
114 INTERNAL_CALL
115 XFORMOBJ_UpdateAccel(
116 IN XFORMOBJ *pxo)
117 {
118 PMATRIX pmx = (PMATRIX)pxo;
119
120 /* Copy Dx and Dy to FIX format */
121 pmx->fxDx = FLOATOBJ_GetFix(&pmx->efDx);
122 pmx->fxDy = FLOATOBJ_GetFix(&pmx->efDy);
123
124 pmx->flAccel = 0;
125
126 if (FLOATOBJ_Equal0(&pmx->efDx) &&
127 FLOATOBJ_Equal0(&pmx->efDy))
128 {
129 pmx->flAccel |= MX_NOTRANSLATE;
130 }
131
132 if (FLOATOBJ_Equal0(&pmx->efM12) &&
133 FLOATOBJ_Equal0(&pmx->efM21))
134 {
135 pmx->flAccel |= MX_SCALE;
136 }
137
138 if (FLOATOBJ_Equal1(&pmx->efM11) &&
139 FLOATOBJ_Equal1(&pmx->efM22))
140 {
141 pmx->flAccel |= MX_IDENTITYSCALE;
142 }
143
144 if (FLOATOBJ_IsLong(&pmx->efM11) && FLOATOBJ_IsLong(&pmx->efM12) &&
145 FLOATOBJ_IsLong(&pmx->efM21) && FLOATOBJ_IsLong(&pmx->efM22))
146 {
147 pmx->flAccel |= MX_INTEGER;
148 }
149
150 return HintFromAccel(pmx->flAccel);
151 }
152
153
154 ULONG
155 INTERNAL_CALL
156 XFORMOBJ_iSetXform(
157 OUT XFORMOBJ *pxo,
158 IN XFORML * pxform)
159 {
160 PMATRIX pmx = (PMATRIX)pxo;
161
162 /* Check parameters */
163 if (!pxo || !pxform)
164 {
165 return DDI_ERROR;
166 }
167
168 /* Copy members */
169 FLOATOBJ_SetFloat(&pmx->efM11, pxform->eM11);
170 FLOATOBJ_SetFloat(&pmx->efM12, pxform->eM12);
171 FLOATOBJ_SetFloat(&pmx->efM21, pxform->eM21);
172 FLOATOBJ_SetFloat(&pmx->efM22, pxform->eM22);
173 FLOATOBJ_SetFloat(&pmx->efDx, pxform->eDx);
174 FLOATOBJ_SetFloat(&pmx->efDy, pxform->eDy);
175
176 /* Update accelerators and return complexity */
177 return XFORMOBJ_UpdateAccel(pxo);
178 }
179
180
181 /*
182 * Multiplies pxo1 with pxo2 and stores the result in pxo.
183 * returns complexity hint
184 * | efM11 efM12 0 |
185 * | efM21 efM22 0 |
186 * | efDx efDy 1 |
187 */
188 ULONG
189 INTERNAL_CALL
190 XFORMOBJ_iCombine(
191 IN XFORMOBJ *pxo,
192 IN XFORMOBJ *pxo1,
193 IN XFORMOBJ *pxo2)
194 {
195 MATRIX mx;
196 PMATRIX pmx, pmx1, pmx2;
197
198 pmx = (PMATRIX)pxo;
199 pmx1 = (PMATRIX)pxo1;
200 pmx2 = (PMATRIX)pxo2;
201
202 /* Do a 3 x 3 matrix multiplication with mx as destinantion */
203 MulAdd(&mx.efM11, &pmx1->efM11, &pmx2->efM11, &pmx1->efM12, &pmx2->efM21);
204 MulAdd(&mx.efM12, &pmx1->efM11, &pmx2->efM12, &pmx1->efM12, &pmx2->efM22);
205 MulAdd(&mx.efM21, &pmx1->efM21, &pmx2->efM11, &pmx1->efM22, &pmx2->efM21);
206 MulAdd(&mx.efM22, &pmx1->efM21, &pmx2->efM12, &pmx1->efM22, &pmx2->efM22);
207 MulAdd(&mx.efDx, &pmx1->efDx, &pmx2->efM11, &pmx1->efDy, &pmx2->efM21);
208 FLOATOBJ_Add(&mx.efDx, &pmx2->efDx);
209 MulAdd(&mx.efDy, &pmx1->efDx, &pmx2->efM12, &pmx1->efDy, &pmx2->efM22);
210 FLOATOBJ_Add(&mx.efDy, &pmx2->efDy);
211
212 /* Copy back */
213 *pmx = mx;
214
215 /* Update accelerators and return complexity */
216 return XFORMOBJ_UpdateAccel(pxo);
217 }
218
219
220 ULONG
221 INTERNAL_CALL
222 XFORMOBJ_iCombineXform(
223 IN XFORMOBJ *pxo,
224 IN XFORMOBJ *pxo1,
225 IN XFORML *pxform,
226 IN BOOL bLeftMultiply)
227 {
228 MATRIX mx;
229 XFORMOBJ *pxo2 = (XFORMOBJ*)&mx;
230
231 XFORMOBJ_iSetXform(pxo2, pxform);
232
233 if (bLeftMultiply)
234 {
235 return XFORMOBJ_iCombine(pxo, pxo2, pxo1);
236 }
237 else
238 {
239 return XFORMOBJ_iCombine(pxo, pxo1, pxo2);
240 }
241 }
242
243 /*
244 * A^-1 = adj(A) / det(AT)
245 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
246 */
247 ULONG
248 INTERNAL_CALL
249 XFORMOBJ_Inverse(
250 OUT XFORMOBJ *pxoDst,
251 IN XFORMOBJ *pxoSrc)
252 {
253 PMATRIX pmxDst, pmxSrc;
254 FLOATOBJ foDet;
255
256 pmxDst = (PMATRIX)pxoDst;
257 pmxSrc = (PMATRIX)pxoSrc;
258
259 /* det = M11 * M22 - M12 * M21 */
260 MulSub(&foDet, &pmxSrc->efM11, &pmxSrc->efM22, &pmxSrc->efM12, &pmxSrc->efM21);
261
262 if (FLOATOBJ_Equal0(&foDet))
263 {
264 /* Determinant is 0! */
265 return DDI_ERROR;
266 }
267
268 /* Calculate adj(A) / det(A) */
269 pmxDst->efM11 = pmxSrc->efM22;
270 FLOATOBJ_Div(&pmxDst->efM11, &foDet);
271 pmxDst->efM22 = pmxSrc->efM11;
272 FLOATOBJ_Div(&pmxDst->efM22, &foDet);
273
274 /* The other 2 are negative, negate foDet for that */
275 FLOATOBJ_Neg(&foDet);
276 pmxDst->efM12 = pmxSrc->efM21;
277 FLOATOBJ_Div(&pmxDst->efM12, &foDet);
278 pmxDst->efM21 = pmxSrc->efM12;
279 FLOATOBJ_Div(&pmxDst->efM22, &foDet);
280
281 /* Update accelerators and return complexity */
282 return XFORMOBJ_UpdateAccel(pxoDst);
283 }
284
285
286 BOOL
287 INTERNAL_CALL
288 XFORMOBJ_bXformFixPoints(
289 IN XFORMOBJ *pxo,
290 IN ULONG cPoints,
291 IN PPOINTL pptIn,
292 OUT PPOINTL pptOut)
293 {
294 PMATRIX pmx;
295 INT i;
296 FLOATOBJ fo1, fo2;
297 FLONG flAccel;
298
299 pmx = (PMATRIX)pxo;
300 flAccel = pmx->flAccel & (MX_INTEGER|MX_SCALE|MX_IDENTITYSCALE);
301
302 switch (flAccel)
303 {
304 case (MX_SCALE | MX_IDENTITYSCALE):
305 case (MX_SCALE | MX_IDENTITYSCALE | MX_INTEGER):
306 /* Identity transformation, nothing todo */
307 break;
308
309 case (MX_IDENTITYSCALE | MX_INTEGER):
310 /* 1-scale integer transform */
311 i = cPoints - 1;
312 do
313 {
314 LONG x = pptIn[i].x + pptIn[i].y * FLOATOBJ_GetLong(&pmx->efM21);
315 LONG y = pptIn[i].y + pptIn[i].x * FLOATOBJ_GetLong(&pmx->efM12);
316 pptOut[i].y = y;
317 pptOut[i].x = x;
318 }
319 while (--i >= 0);
320 break;
321
322 case (MX_SCALE | MX_INTEGER):
323 /* Diagonal integer transform */
324 i = cPoints - 1;
325 do
326 {
327 pptOut[i].x = pptIn[i].x * FLOATOBJ_GetLong(&pmx->efM11);
328 pptOut[i].y = pptIn[i].y * FLOATOBJ_GetLong(&pmx->efM22);
329 }
330 while (--i >= 0);
331 break;
332
333 case (MX_INTEGER):
334 /* Full integer transform */
335 i = cPoints - 1;
336 do
337 {
338 LONG x;
339 x = pptIn[i].x * FLOATOBJ_GetLong(&pmx->efM11);
340 x += pptIn[i].y * FLOATOBJ_GetLong(&pmx->efM21);
341 pptOut[i].y = pptIn[i].y * FLOATOBJ_GetLong(&pmx->efM22);
342 pptOut[i].y += pptIn[i].x * FLOATOBJ_GetLong(&pmx->efM12);
343 pptOut[i].x = x;
344 }
345 while (--i >= 0);
346 break;
347
348 case (MX_IDENTITYSCALE):
349 /* 1-scale transform */
350 i = cPoints - 1;
351 do
352 {
353 fo1 = pmx->efM21;
354 FLOATOBJ_MulLong(&fo1, pptIn[i].y);
355 fo2 = pmx->efM12;
356 FLOATOBJ_MulLong(&fo2, pptIn[i].x);
357 pptOut[i].x = pptIn[i].x + FLOATOBJ_GetLong(&fo1);
358 pptOut[i].y = pptIn[i].y + FLOATOBJ_GetLong(&fo2);
359 }
360 while (--i >= 0);
361 break;
362
363 case (MX_SCALE):
364 /* Diagonal float transform */
365 i = cPoints - 1;
366 do
367 {
368 fo1 = pmx->efM11;
369 FLOATOBJ_MulLong(&fo1, pptIn[i].x);
370 pptOut[i].x = FLOATOBJ_GetLong(&fo1);
371 fo2 = pmx->efM22;
372 FLOATOBJ_MulLong(&fo2, pptIn[i].y);
373 pptOut[i].y = FLOATOBJ_GetLong(&fo2);
374 }
375 while (--i >= 0);
376 break;
377
378 default:
379 /* Full float transform */
380 i = cPoints - 1;
381 do
382 {
383 MulAddLong(&fo1, &pmx->efM11, pptIn[i].x, &pmx->efM21, pptIn[i].y);
384 MulAddLong(&fo2, &pmx->efM12, pptIn[i].x, &pmx->efM22, pptIn[i].y);
385 pptOut[i].x = FLOATOBJ_GetLong(&fo1);
386 pptOut[i].y = FLOATOBJ_GetLong(&fo2);
387 }
388 while (--i >= 0);
389 break;
390 }
391
392 if (!(pmx->flAccel & MX_NOTRANSLATE))
393 {
394 /* Translate points */
395 i = cPoints - 1;
396 do
397 {
398 // DPRINT1("Translating Points (%d,%d)->(%d,%d)\n", pptOut[i].x, pptOut[i].y, pptOut[i].x + pmx->fxDx, pptOut[i].y + pmx->fxDy);
399 pptOut[i].x += pmx->fxDx;
400 pptOut[i].y += pmx->fxDy;
401 }
402 while (--i >= 0);
403 }
404
405 return TRUE;
406 }
407
408 /** Public functions **********************************************************/
409
410 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
411 ULONG
412 APIENTRY
413 XFORMOBJ_iGetXform(
414 IN XFORMOBJ *pxo,
415 OUT XFORML *pxform)
416 {
417 PMATRIX pmx = (PMATRIX)pxo;
418
419 /* Check parameters */
420 if (!pxo || !pxform)
421 {
422 return DDI_ERROR;
423 }
424
425 /* Copy members */
426 pxform->eM11 = FLOATOBJ_GetFloat(&pmx->efM11);
427 pxform->eM12 = FLOATOBJ_GetFloat(&pmx->efM12);
428 pxform->eM21 = FLOATOBJ_GetFloat(&pmx->efM21);
429 pxform->eM22 = FLOATOBJ_GetFloat(&pmx->efM22);
430 pxform->eDx = FLOATOBJ_GetFloat(&pmx->efDx);
431 pxform->eDy = FLOATOBJ_GetFloat(&pmx->efDy);
432
433 /* Return complexity hint */
434 return HintFromAccel(pmx->flAccel);
435 }
436
437
438 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
439 ULONG
440 APIENTRY
441 XFORMOBJ_iGetFloatObjXform(
442 IN XFORMOBJ *pxo,
443 OUT FLOATOBJ_XFORM *pxfo)
444 {
445 PMATRIX pmx = (PMATRIX)pxo;
446
447 /* Check parameters */
448 if (!pxo || !pxfo)
449 {
450 return DDI_ERROR;
451 }
452
453 /* Copy members */
454 pxfo->eM11 = pmx->efM11;
455 pxfo->eM12 = pmx->efM12;
456 pxfo->eM21 = pmx->efM21;
457 pxfo->eM22 = pmx->efM22;
458 pxfo->eDx = pmx->efDx;
459 pxfo->eDy = pmx->efDy;
460
461 /* Return complexity hint */
462 return HintFromAccel(pmx->flAccel);
463 }
464
465
466 // www.osr.com/ddk/graphics/gdifncs_027b.htm
467 BOOL
468 APIENTRY
469 XFORMOBJ_bApplyXform(
470 IN XFORMOBJ *pxo,
471 IN ULONG iMode,
472 IN ULONG cPoints,
473 IN PVOID pvIn,
474 OUT PVOID pvOut)
475 {
476 MATRIX mx;
477 POINTL *pptl;
478 INT i;
479
480 /* Check parameters */
481 if (!pxo || !pvIn || !pvOut || cPoints < 1)
482 {
483 return FALSE;
484 }
485
486 /* Use inverse xform? */
487 if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL)
488 {
489 ULONG ret;
490 ret = XFORMOBJ_Inverse((XFORMOBJ*)&mx, pxo);
491 if (ret == DDI_ERROR)
492 {
493 return FALSE;
494 }
495 pxo = (XFORMOBJ*)&mx;
496 }
497
498 /* Convert POINTL to POINTFIX? */
499 if (iMode == XF_LTOFX || iMode == XF_LTOL || iMode == XF_INV_LTOL)
500 {
501 pptl = pvIn;
502 for (i = cPoints - 1; i >= 0; i--)
503 {
504 pptl[i].x = LONG2FIX(pptl[i].x);
505 pptl[i].y = LONG2FIX(pptl[i].y);
506 }
507 }
508
509 /* Do the actual fixpoint transformation */
510 if (!XFORMOBJ_bXformFixPoints(pxo, cPoints, pvIn, pvOut))
511 {
512 return FALSE;
513 }
514
515 /* Convert POINTFIX to POINTL? */
516 if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL || iMode == XF_LTOL)
517 {
518 pptl = pvOut;
519 for (i = cPoints - 1; i >= 0; i--)
520 {
521 pptl[i].x = FIX2LONG(pptl[i].x);
522 pptl[i].y = FIX2LONG(pptl[i].y);
523 }
524 }
525
526 return TRUE;
527 }
528
529 /* EOF */