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
9 /** Includes ******************************************************************/
15 C_ASSERT(sizeof(FIX
) == sizeof(LONG
));
16 #define FIX2LONG(x) ((x) >> 4)
17 #define LONG2FIX(x) ((x) << 4)
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
26 /** Inline helper functions ***************************************************/
29 * Inline helper to calculate pfo1 * pfo2 + pfo3 * pfo4
43 FLOATOBJ_Mul(pfoDest
, pfo2
);
45 FLOATOBJ_Mul(&foTmp
, pfo4
);
46 FLOATOBJ_Add(pfoDest
, &foTmp
);
50 * Inline helper to calculate pfo1 * l2 + pfo3 * l4
64 FLOATOBJ_MulLong(pfoDest
, l2
);
66 FLOATOBJ_MulLong(&foTmp
, l4
);
67 FLOATOBJ_Add(pfoDest
, &foTmp
);
71 * Inline helper to calculate pfo1 * pfo2 - pfo3 * pfo4
85 FLOATOBJ_Mul(pfoDest
, pfo2
);
87 FLOATOBJ_Mul(&foTmp
, pfo4
);
88 FLOATOBJ_Sub(pfoDest
, &foTmp
);
92 * Inline helper to get the complexity hint from flAccel
96 HintFromAccel(ULONG flAccel
)
98 switch (flAccel
& (XFORM_SCALE
|XFORM_UNITY
|XFORM_NO_TRANSLATION
))
100 case (XFORM_SCALE
|XFORM_UNITY
|XFORM_NO_TRANSLATION
):
102 case (XFORM_SCALE
|XFORM_UNITY
):
111 /** Internal functions ********************************************************/
115 XFORMOBJ_UpdateAccel(
118 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
120 /* Copy Dx and Dy to FIX format */
121 pmx
->fxDx
= FLOATOBJ_GetFix(&pmx
->efDx
);
122 pmx
->fxDy
= FLOATOBJ_GetFix(&pmx
->efDy
);
126 if (FLOATOBJ_Equal0(&pmx
->efDx
) &&
127 FLOATOBJ_Equal0(&pmx
->efDy
))
129 pmx
->flAccel
|= XFORM_NO_TRANSLATION
;
132 if (FLOATOBJ_Equal0(&pmx
->efM12
) &&
133 FLOATOBJ_Equal0(&pmx
->efM21
))
135 pmx
->flAccel
|= XFORM_SCALE
;
138 if (FLOATOBJ_Equal1(&pmx
->efM11
) &&
139 FLOATOBJ_Equal1(&pmx
->efM22
))
141 pmx
->flAccel
|= XFORM_UNITY
;
144 if (FLOATOBJ_IsLong(&pmx
->efM11
) && FLOATOBJ_IsLong(&pmx
->efM12
) &&
145 FLOATOBJ_IsLong(&pmx
->efM21
) && FLOATOBJ_IsLong(&pmx
->efM22
))
147 pmx
->flAccel
|= XFORM_INTEGER
;
150 return HintFromAccel(pmx
->flAccel
);
158 IN
const XFORML
*pxform
)
160 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
162 /* Check parameters */
163 if (!pxo
|| !pxform
) return DDI_ERROR
;
165 /* Check if the xform is valid */
166 if ((pxform
->eM11
== 0) || (pxform
->eM22
== 0)) return DDI_ERROR
;
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
);
176 /* Update accelerators and return complexity */
177 return XFORMOBJ_UpdateAccel(pxo
);
182 * Multiplies pxo1 with pxo2 and stores the result in pxo.
183 * returns complexity hint
196 PMATRIX pmx
, pmx1
, pmx2
;
198 pmx
= XFORMOBJ_pmx(pxo
);
199 pmx1
=XFORMOBJ_pmx(pxo1
);
200 pmx2
= XFORMOBJ_pmx(pxo2
);
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
);
215 /* Update accelerators and return complexity */
216 return XFORMOBJ_UpdateAccel(pxo
);
222 XFORMOBJ_iCombineXform(
226 IN BOOL bLeftMultiply
)
231 XFORMOBJ_vInit(&xo2
, &mx
);
232 XFORMOBJ_iSetXform(&xo2
, pxform
);
236 return XFORMOBJ_iCombine(pxo
, &xo2
, pxo1
);
240 return XFORMOBJ_iCombine(pxo
, pxo1
, &xo2
);
245 * A^-1 = adj(A) / det(AT)
246 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
251 OUT XFORMOBJ
*pxoDst
,
254 PMATRIX pmxDst
, pmxSrc
;
263 pmxDst
= XFORMOBJ_pmx(pxoDst
);
264 pmxSrc
= XFORMOBJ_pmx(pxoSrc
);
266 XFORMOBJ_iGetXform(pxoSrc
, (XFORML
*)&xformSrc
);
268 /* det = M11 * M22 - M12 * M21 */
269 MulSub(&foDet
, &pmxSrc
->efM11
, &pmxSrc
->efM22
, &pmxSrc
->efM12
, &pmxSrc
->efM21
);
271 if (FLOATOBJ_Equal0(&foDet
))
273 /* Determinant is 0! */
277 eDet
.Long
= FLOATOBJ_GetFloat(&foDet
);
279 /* Calculate adj(A) / det(A) */
280 pmxDst
->efM11
= pmxSrc
->efM22
;
281 FLOATOBJ_Div(&pmxDst
->efM11
, &foDet
);
282 pmxDst
->efM22
= pmxSrc
->efM11
;
283 FLOATOBJ_Div(&pmxDst
->efM22
, &foDet
);
285 /* The other 2 are negative, negate foDet for that */
286 FLOATOBJ_Neg(&foDet
);
287 pmxDst
->efM12
= pmxSrc
->efM12
;
288 FLOATOBJ_Div(&pmxDst
->efM12
, &foDet
);
289 pmxDst
->efM21
= pmxSrc
->efM21
;
290 FLOATOBJ_Div(&pmxDst
->efM21
, &foDet
);
292 /* Calculate the inverted x shift: Dx' = -Dx * M11' - Dy * M21' */
293 pmxDst
->efDx
= pmxSrc
->efDx
;
294 FLOATOBJ_Neg(&pmxDst
->efDx
);
295 MulSub(&pmxDst
->efDx
, &pmxDst
->efDx
, &pmxDst
->efM11
, &pmxSrc
->efDy
, &pmxDst
->efM21
);
297 /* Calculate the inverted y shift: Dy' = -Dy * M22' - Dx * M12' */
298 pmxDst
->efDy
= pmxSrc
->efDy
;
299 FLOATOBJ_Neg(&pmxDst
->efDy
);
300 MulSub(&pmxDst
->efDy
, &pmxDst
->efDy
, &pmxDst
->efM22
, &pmxSrc
->efDx
, &pmxDst
->efM12
);
302 /* Update accelerators and return complexity */
303 return XFORMOBJ_UpdateAccel(pxoDst
);
309 XFORMOBJ_bXformFixPoints(
320 pmx
= XFORMOBJ_pmx(pxo
);
321 flAccel
= pmx
->flAccel
;
323 if ((flAccel
& (XFORM_SCALE
|XFORM_UNITY
)) == (XFORM_SCALE
|XFORM_UNITY
))
325 /* Identity transformation, nothing todo */
327 else if (flAccel
& XFORM_INTEGER
)
329 if (flAccel
& XFORM_UNITY
)
331 /* 1-scale integer transform */
335 LONG x
= pptIn
[i
].x
+ pptIn
[i
].y
* FLOATOBJ_GetLong(&pmx
->efM21
);
336 LONG y
= pptIn
[i
].y
+ pptIn
[i
].x
* FLOATOBJ_GetLong(&pmx
->efM12
);
342 else if (flAccel
& XFORM_SCALE
)
344 /* Diagonal integer transform */
348 pptOut
[i
].x
= pptIn
[i
].x
* FLOATOBJ_GetLong(&pmx
->efM11
);
349 pptOut
[i
].y
= pptIn
[i
].y
* FLOATOBJ_GetLong(&pmx
->efM22
);
355 /* Full integer transform */
360 x
= pptIn
[i
].x
* FLOATOBJ_GetLong(&pmx
->efM11
);
361 x
+= pptIn
[i
].y
* FLOATOBJ_GetLong(&pmx
->efM21
);
362 pptOut
[i
].y
= pptIn
[i
].y
* FLOATOBJ_GetLong(&pmx
->efM22
);
363 pptOut
[i
].y
+= pptIn
[i
].x
* FLOATOBJ_GetLong(&pmx
->efM12
);
369 else if (flAccel
& XFORM_UNITY
)
371 /* 1-scale transform */
376 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].y
);
378 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].x
);
379 pptOut
[i
].x
= pptIn
[i
].x
+ FLOATOBJ_GetLong(&fo1
);
380 pptOut
[i
].y
= pptIn
[i
].y
+ FLOATOBJ_GetLong(&fo2
);
384 else if (flAccel
& XFORM_SCALE
)
386 /* Diagonal float transform */
391 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].x
);
392 pptOut
[i
].x
= FLOATOBJ_GetLong(&fo1
);
394 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].y
);
395 pptOut
[i
].y
= FLOATOBJ_GetLong(&fo2
);
401 /* Full float transform */
405 MulAddLong(&fo1
, &pmx
->efM11
, pptIn
[i
].x
, &pmx
->efM21
, pptIn
[i
].y
);
406 MulAddLong(&fo2
, &pmx
->efM12
, pptIn
[i
].x
, &pmx
->efM22
, pptIn
[i
].y
);
407 pptOut
[i
].x
= FLOATOBJ_GetLong(&fo1
);
408 pptOut
[i
].y
= FLOATOBJ_GetLong(&fo2
);
413 if (!(pmx
->flAccel
& XFORM_NO_TRANSLATION
))
415 /* Translate points */
419 pptOut
[i
].x
+= pmx
->fxDx
;
420 pptOut
[i
].y
+= pmx
->fxDy
;
428 /** Public functions **********************************************************/
430 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
437 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
439 /* Check parameters */
446 pxform
->eM11
= FLOATOBJ_GetFloat(&pmx
->efM11
);
447 pxform
->eM12
= FLOATOBJ_GetFloat(&pmx
->efM12
);
448 pxform
->eM21
= FLOATOBJ_GetFloat(&pmx
->efM21
);
449 pxform
->eM22
= FLOATOBJ_GetFloat(&pmx
->efM22
);
450 pxform
->eDx
= FLOATOBJ_GetFloat(&pmx
->efDx
);
451 pxform
->eDy
= FLOATOBJ_GetFloat(&pmx
->efDy
);
453 /* Return complexity hint */
454 return HintFromAccel(pmx
->flAccel
);
458 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
461 XFORMOBJ_iGetFloatObjXform(
463 OUT FLOATOBJ_XFORM
*pxfo
)
465 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
467 /* Check parameters */
474 pxfo
->eM11
= pmx
->efM11
;
475 pxfo
->eM12
= pmx
->efM12
;
476 pxfo
->eM21
= pmx
->efM21
;
477 pxfo
->eM22
= pmx
->efM22
;
478 pxfo
->eDx
= pmx
->efDx
;
479 pxfo
->eDy
= pmx
->efDy
;
481 /* Return complexity hint */
482 return HintFromAccel(pmx
->flAccel
);
486 // www.osr.com/ddk/graphics/gdifncs_027b.htm
489 XFORMOBJ_bApplyXform(
501 /* Check parameters */
502 if (!pxo
|| !pvIn
|| !pvOut
|| cPoints
< 1)
507 /* Use inverse xform? */
508 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
)
510 XFORMOBJ_vInit(&xoInv
, &mx
);
511 if (XFORMOBJ_iInverse(&xoInv
, pxo
) == DDI_ERROR
)
518 /* Convert POINTL to POINTFIX? */
519 if (iMode
== XF_LTOFX
|| iMode
== XF_LTOL
|| iMode
== XF_INV_LTOL
)
522 for (i
= cPoints
- 1; i
>= 0; i
--)
524 pptl
[i
].x
= LONG2FIX(pptl
[i
].x
);
525 pptl
[i
].y
= LONG2FIX(pptl
[i
].y
);
529 /* Do the actual fixpoint transformation */
530 if (!XFORMOBJ_bXformFixPoints(pxo
, cPoints
, pvIn
, pvOut
))
535 /* Convert POINTFIX to POINTL? */
536 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
|| iMode
== XF_LTOL
)
539 for (i
= cPoints
- 1; i
>= 0; i
--)
541 pptl
[i
].x
= FIX2LONG(pptl
[i
].x
);
542 pptl
[i
].y
= FIX2LONG(pptl
[i
].y
);