2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/xformobj.c
5 * PURPOSE: XFORMOBJ API
6 * PROGRAMMER: Timo Kreuzer
9 /** Includes ******************************************************************/
15 #define DOES_VALUE_OVERFLOW_LONG(x) \
16 (((__int64)((long)(x))) != (x))
18 /** Inline helper functions ***************************************************/
21 * Inline helper to calculate pfo1 * pfo2 + pfo3 * pfo4
35 FLOATOBJ_Mul(pfoDest
, pfo2
);
37 FLOATOBJ_Mul(&foTmp
, pfo4
);
38 FLOATOBJ_Add(pfoDest
, &foTmp
);
42 * Inline helper to calculate pfo1 * l2 + pfo3 * l4
56 FLOATOBJ_MulLong(pfoDest
, l2
);
58 FLOATOBJ_MulLong(&foTmp
, l4
);
59 FLOATOBJ_Add(pfoDest
, &foTmp
);
63 * Inline helper to calculate pfo1 * pfo2 - pfo3 * pfo4
77 FLOATOBJ_Mul(pfoDest
, pfo2
);
79 FLOATOBJ_Mul(&foTmp
, pfo4
);
80 FLOATOBJ_Sub(pfoDest
, &foTmp
);
84 * Inline helper to get the complexity hint from flAccel
88 HintFromAccel(ULONG flAccel
)
90 switch (flAccel
& (XFORM_SCALE
|XFORM_UNITY
|XFORM_NO_TRANSLATION
))
92 case (XFORM_SCALE
|XFORM_UNITY
|XFORM_NO_TRANSLATION
):
94 case (XFORM_SCALE
|XFORM_UNITY
):
103 /** Internal functions ********************************************************/
107 XFORMOBJ_UpdateAccel(
110 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
112 /* Copy Dx and Dy to FIX format */
113 pmx
->fxDx
= FLOATOBJ_GetFix(&pmx
->efDx
);
114 pmx
->fxDy
= FLOATOBJ_GetFix(&pmx
->efDy
);
118 if (FLOATOBJ_Equal0(&pmx
->efDx
) &&
119 FLOATOBJ_Equal0(&pmx
->efDy
))
121 pmx
->flAccel
|= XFORM_NO_TRANSLATION
;
124 if (FLOATOBJ_Equal0(&pmx
->efM12
) &&
125 FLOATOBJ_Equal0(&pmx
->efM21
))
127 pmx
->flAccel
|= XFORM_SCALE
;
130 if (FLOATOBJ_Equal1(&pmx
->efM11
) &&
131 FLOATOBJ_Equal1(&pmx
->efM22
))
133 pmx
->flAccel
|= XFORM_UNITY
;
136 if (FLOATOBJ_IsLong(&pmx
->efM11
) && FLOATOBJ_IsLong(&pmx
->efM12
) &&
137 FLOATOBJ_IsLong(&pmx
->efM21
) && FLOATOBJ_IsLong(&pmx
->efM22
))
139 pmx
->flAccel
|= XFORM_INTEGER
;
142 return HintFromAccel(pmx
->flAccel
);
150 IN
const XFORML
*pxform
)
152 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
154 /* Check parameters */
155 if (!pxo
|| !pxform
) return DDI_ERROR
;
157 /* Check if the xform is valid */
158 if ((pxform
->eM11
== 0) || (pxform
->eM22
== 0)) return DDI_ERROR
;
161 FLOATOBJ_SetFloat(&pmx
->efM11
, pxform
->eM11
);
162 FLOATOBJ_SetFloat(&pmx
->efM12
, pxform
->eM12
);
163 FLOATOBJ_SetFloat(&pmx
->efM21
, pxform
->eM21
);
164 FLOATOBJ_SetFloat(&pmx
->efM22
, pxform
->eM22
);
165 FLOATOBJ_SetFloat(&pmx
->efDx
, pxform
->eDx
);
166 FLOATOBJ_SetFloat(&pmx
->efDy
, pxform
->eDy
);
168 /* Update accelerators and return complexity */
169 return XFORMOBJ_UpdateAccel(pxo
);
174 * Multiplies pxo1 with pxo2 and stores the result in pxo.
175 * returns complexity hint
188 PMATRIX pmx
, pmx1
, pmx2
;
190 /* Get the source matrices */
191 pmx1
= XFORMOBJ_pmx(pxo1
);
192 pmx2
= XFORMOBJ_pmx(pxo2
);
194 /* Do a 3 x 3 matrix multiplication with mx as destinantion */
195 MulAdd(&mx
.efM11
, &pmx1
->efM11
, &pmx2
->efM11
, &pmx1
->efM12
, &pmx2
->efM21
);
196 MulAdd(&mx
.efM12
, &pmx1
->efM11
, &pmx2
->efM12
, &pmx1
->efM12
, &pmx2
->efM22
);
197 MulAdd(&mx
.efM21
, &pmx1
->efM21
, &pmx2
->efM11
, &pmx1
->efM22
, &pmx2
->efM21
);
198 MulAdd(&mx
.efM22
, &pmx1
->efM21
, &pmx2
->efM12
, &pmx1
->efM22
, &pmx2
->efM22
);
199 MulAdd(&mx
.efDx
, &pmx1
->efDx
, &pmx2
->efM11
, &pmx1
->efDy
, &pmx2
->efM21
);
200 FLOATOBJ_Add(&mx
.efDx
, &pmx2
->efDx
);
201 MulAdd(&mx
.efDy
, &pmx1
->efDx
, &pmx2
->efM12
, &pmx1
->efDy
, &pmx2
->efM22
);
202 FLOATOBJ_Add(&mx
.efDy
, &pmx2
->efDy
);
205 pmx
= XFORMOBJ_pmx(pxo
);
208 /* Update accelerators and return complexity */
209 return XFORMOBJ_UpdateAccel(pxo
);
215 XFORMOBJ_iCombineXform(
219 IN BOOL bLeftMultiply
)
224 XFORMOBJ_vInit(&xo2
, &mx
);
225 XFORMOBJ_iSetXform(&xo2
, pxform
);
229 return XFORMOBJ_iCombine(pxo
, &xo2
, pxo1
);
233 return XFORMOBJ_iCombine(pxo
, pxo1
, &xo2
);
238 * A^-1 = adj(A) / det(AT)
239 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
244 OUT XFORMOBJ
*pxoDst
,
247 PMATRIX pmxDst
, pmxSrc
;
251 pmxDst
= XFORMOBJ_pmx(pxoDst
);
252 pmxSrc
= XFORMOBJ_pmx(pxoSrc
);
254 XFORMOBJ_iGetXform(pxoSrc
, (XFORML
*)&xformSrc
);
256 /* det = M11 * M22 - M12 * M21 */
257 MulSub(&foDet
, &pmxSrc
->efM11
, &pmxSrc
->efM22
, &pmxSrc
->efM12
, &pmxSrc
->efM21
);
259 if (FLOATOBJ_Equal0(&foDet
))
261 /* Determinant is 0! */
265 /* Calculate adj(A) / det(A) */
266 pmxDst
->efM11
= pmxSrc
->efM22
;
267 FLOATOBJ_Div(&pmxDst
->efM11
, &foDet
);
268 pmxDst
->efM22
= pmxSrc
->efM11
;
269 FLOATOBJ_Div(&pmxDst
->efM22
, &foDet
);
271 /* The other 2 are negative, negate foDet for that */
272 FLOATOBJ_Neg(&foDet
);
273 pmxDst
->efM12
= pmxSrc
->efM12
;
274 FLOATOBJ_Div(&pmxDst
->efM12
, &foDet
);
275 pmxDst
->efM21
= pmxSrc
->efM21
;
276 FLOATOBJ_Div(&pmxDst
->efM21
, &foDet
);
278 /* Calculate the inverted x shift: Dx' = -Dx * M11' - Dy * M21' */
279 pmxDst
->efDx
= pmxSrc
->efDx
;
280 FLOATOBJ_Neg(&pmxDst
->efDx
);
281 MulSub(&pmxDst
->efDx
, &pmxDst
->efDx
, &pmxDst
->efM11
, &pmxSrc
->efDy
, &pmxDst
->efM21
);
283 /* Calculate the inverted y shift: Dy' = -Dy * M22' - Dx * M12' */
284 pmxDst
->efDy
= pmxSrc
->efDy
;
285 FLOATOBJ_Neg(&pmxDst
->efDy
);
286 MulSub(&pmxDst
->efDy
, &pmxDst
->efDy
, &pmxDst
->efM22
, &pmxSrc
->efDx
, &pmxDst
->efM12
);
288 /* Update accelerators and return complexity */
289 return XFORMOBJ_UpdateAccel(pxoDst
);
294 * \brief Transforms fix-point coordinates in an array of POINTL structures using
295 * the transformation matrix from the XFORMOBJ.
297 * \param pxo - Pointer to the XFORMOBJ
299 * \param cPoints - Number of coordinates to transform
301 * \param pptIn - Pointer to an array of POINTL structures containing the
302 * source coordinates.
304 * \param pptOut - Pointer to an array of POINTL structures, receiving the
305 * transformed coordinates. Can be the same as pptIn.
307 * \return TRUE if the operation was successful, FALSE if any of the calculations
308 * caused an integer overflow.
310 * \note If the function returns FALSE, it might still have written to the
311 * output buffer. If pptIn and pptOut are equal, the source coordinates
312 * might have been partly overwritten!
317 XFORMOBJ_bXformFixPoints(
320 _In_reads_(cPoints
) PPOINTL pptIn
,
321 _Out_writes_(cPoints
) PPOINTL pptOut
)
327 LONG lM11
, lM12
, lM21
, lM22
, lTemp
;
328 register LONGLONG llx
, lly
;
330 pmx
= XFORMOBJ_pmx(pxo
);
331 flAccel
= pmx
->flAccel
;
333 if ((flAccel
& (XFORM_SCALE
|XFORM_UNITY
)) == (XFORM_SCALE
|XFORM_UNITY
))
335 /* Identity transformation */
336 RtlCopyMemory(pptOut
, pptIn
, cPoints
* sizeof(POINTL
));
338 else if (flAccel
& XFORM_INTEGER
)
340 if (flAccel
& XFORM_UNITY
)
342 /* 1-scale integer transform, get the off-diagonal elements */
343 if (!FLOATOBJ_bConvertToLong(&pmx
->efM12
, &lM12
) ||
344 !FLOATOBJ_bConvertToLong(&pmx
->efM21
, &lM21
))
353 /* Calculate x in 64 bit and check for overflow */
354 llx
= Int32x32To64(pptIn
[i
].y
, lM21
) + pptIn
[i
].x
;
355 if (DOES_VALUE_OVERFLOW_LONG(llx
))
360 /* Calculate y in 64 bit and check for overflow */
361 lly
= Int32x32To64(pptIn
[i
].x
, lM12
) + pptIn
[i
].y
;
362 if (DOES_VALUE_OVERFLOW_LONG(lly
))
367 /* Write back the results */
368 pptOut
[i
].x
= (LONG
)llx
;
369 pptOut
[i
].y
= (LONG
)lly
;
373 else if (flAccel
& XFORM_SCALE
)
375 /* Diagonal integer transform, get the diagonal elements */
376 if (!FLOATOBJ_bConvertToLong(&pmx
->efM11
, &lM11
) ||
377 !FLOATOBJ_bConvertToLong(&pmx
->efM22
, &lM22
))
386 /* Calculate x in 64 bit and check for overflow */
387 llx
= Int32x32To64(pptIn
[i
].x
, lM11
);
388 if (DOES_VALUE_OVERFLOW_LONG(llx
))
393 /* Calculate y in 64 bit and check for overflow */
394 lly
= Int32x32To64(pptIn
[i
].y
, lM22
);
395 if (DOES_VALUE_OVERFLOW_LONG(lly
))
400 /* Write back the results */
401 pptOut
[i
].x
= (LONG
)llx
;
402 pptOut
[i
].y
= (LONG
)lly
;
408 /* Full integer transform */
409 if (!FLOATOBJ_bConvertToLong(&pmx
->efM11
, &lM11
) ||
410 !FLOATOBJ_bConvertToLong(&pmx
->efM12
, &lM12
) ||
411 !FLOATOBJ_bConvertToLong(&pmx
->efM21
, &lM21
) ||
412 !FLOATOBJ_bConvertToLong(&pmx
->efM22
, &lM22
))
421 /* Calculate x in 64 bit and check for overflow */
422 llx
= Int32x32To64(pptIn
[i
].x
, lM11
);
423 llx
+= Int32x32To64(pptIn
[i
].y
, lM21
);
424 if (DOES_VALUE_OVERFLOW_LONG(llx
))
429 /* Calculate y in 64 bit and check for overflow */
430 lly
= Int32x32To64(pptIn
[i
].y
, lM22
);
431 lly
+= Int32x32To64(pptIn
[i
].x
, lM12
);
432 if (DOES_VALUE_OVERFLOW_LONG(lly
))
437 /* Write back the results */
438 pptOut
[i
].x
= (LONG
)llx
;
439 pptOut
[i
].y
= (LONG
)lly
;
444 else if (flAccel
& XFORM_UNITY
)
446 /* 1-scale transform */
450 /* Calculate x in 64 bit and check for overflow */
452 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].y
);
453 if (!FLOATOBJ_bConvertToLong(&fo1
, &lTemp
))
457 llx
= (LONGLONG
)pptIn
[i
].x
+ lTemp
;
458 if (DOES_VALUE_OVERFLOW_LONG(llx
))
463 /* Calculate y in 64 bit and check for overflow */
465 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].x
);
466 if (!FLOATOBJ_bConvertToLong(&fo2
, &lTemp
))
470 lly
= (LONGLONG
)pptIn
[i
].y
+ lTemp
;
471 if (DOES_VALUE_OVERFLOW_LONG(lly
))
476 /* Write back the results */
477 pptOut
[i
].x
= (LONG
)llx
;
478 pptOut
[i
].y
= (LONG
)lly
;
482 else if (flAccel
& XFORM_SCALE
)
484 /* Diagonal float transform */
489 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].x
);
490 if (!FLOATOBJ_bConvertToLong(&fo1
, &pptOut
[i
].x
))
496 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].y
);
497 if (!FLOATOBJ_bConvertToLong(&fo2
, &pptOut
[i
].y
))
506 /* Full float transform */
510 /* Calculate x as FLOATOBJ */
511 MulAddLong(&fo1
, &pmx
->efM11
, pptIn
[i
].x
, &pmx
->efM21
, pptIn
[i
].y
);
513 /* Calculate y as FLOATOBJ */
514 MulAddLong(&fo2
, &pmx
->efM12
, pptIn
[i
].x
, &pmx
->efM22
, pptIn
[i
].y
);
516 if (!FLOATOBJ_bConvertToLong(&fo1
, &pptOut
[i
].x
))
521 if (!FLOATOBJ_bConvertToLong(&fo2
, &pptOut
[i
].y
))
529 if (!(pmx
->flAccel
& XFORM_NO_TRANSLATION
))
531 /* Translate points */
535 llx
= (LONGLONG
)pptOut
[i
].x
+ pmx
->fxDx
;
536 if (DOES_VALUE_OVERFLOW_LONG(llx
))
540 pptOut
[i
].x
= (LONG
)llx
;
542 lly
= (LONGLONG
)pptOut
[i
].y
+ pmx
->fxDy
;
543 if (DOES_VALUE_OVERFLOW_LONG(lly
))
547 pptOut
[i
].y
= (LONG
)lly
;
555 /** Public functions **********************************************************/
557 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
564 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
566 /* Check parameters */
573 pxform
->eM11
= FLOATOBJ_GetFloat(&pmx
->efM11
);
574 pxform
->eM12
= FLOATOBJ_GetFloat(&pmx
->efM12
);
575 pxform
->eM21
= FLOATOBJ_GetFloat(&pmx
->efM21
);
576 pxform
->eM22
= FLOATOBJ_GetFloat(&pmx
->efM22
);
577 pxform
->eDx
= FLOATOBJ_GetFloat(&pmx
->efDx
);
578 pxform
->eDy
= FLOATOBJ_GetFloat(&pmx
->efDy
);
580 /* Return complexity hint */
581 return HintFromAccel(pmx
->flAccel
);
585 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
588 XFORMOBJ_iGetFloatObjXform(
590 OUT FLOATOBJ_XFORM
*pxfo
)
592 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
594 /* Check parameters */
601 pxfo
->eM11
= pmx
->efM11
;
602 pxfo
->eM12
= pmx
->efM12
;
603 pxfo
->eM21
= pmx
->efM21
;
604 pxfo
->eM22
= pmx
->efM22
;
605 pxfo
->eDx
= pmx
->efDx
;
606 pxfo
->eDy
= pmx
->efDy
;
608 /* Return complexity hint */
609 return HintFromAccel(pmx
->flAccel
);
613 // www.osr.com/ddk/graphics/gdifncs_027b.htm
616 XFORMOBJ_bApplyXform(
625 PPOINTL pptlIn
, pptlOut
;
628 /* Check parameters */
629 if (!pxo
|| !pvIn
|| !pvOut
|| cPoints
< 1)
634 /* Use inverse xform? */
635 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
)
637 XFORMOBJ_vInit(&xoInv
, &mx
);
638 if (XFORMOBJ_iInverse(&xoInv
, pxo
) == DDI_ERROR
)
645 /* Convert POINTL to POINTFIX? */
646 if (iMode
== XF_LTOFX
|| iMode
== XF_LTOL
|| iMode
== XF_INV_LTOL
)
650 for (i
= cPoints
- 1; i
>= 0; i
--)
652 pptlOut
[i
].x
= LONG2FIX(pptlIn
[i
].x
);
653 pptlOut
[i
].y
= LONG2FIX(pptlIn
[i
].y
);
656 /* The input is in the out buffer now! */
660 /* Do the actual fixpoint transformation */
661 if (!XFORMOBJ_bXformFixPoints(pxo
, cPoints
, pvIn
, pvOut
))
666 /* Convert POINTFIX to POINTL? */
667 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
|| iMode
== XF_LTOL
)
670 for (i
= cPoints
- 1; i
>= 0; i
--)
672 pptlOut
[i
].x
= FIX2LONG(pptlOut
[i
].x
);
673 pptlOut
[i
].y
= FIX2LONG(pptlOut
[i
].y
);