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, nothing to do */
337 else if (flAccel
& XFORM_INTEGER
)
339 if (flAccel
& XFORM_UNITY
)
341 /* 1-scale integer transform, get the off-diagonal elements */
342 if (!FLOATOBJ_bConvertToLong(&pmx
->efM12
, &lM12
) ||
343 !FLOATOBJ_bConvertToLong(&pmx
->efM21
, &lM21
))
352 /* Calculate x in 64 bit and check for overflow */
353 llx
= Int32x32To64(pptIn
[i
].y
, lM21
) + pptIn
[i
].x
;
354 if (DOES_VALUE_OVERFLOW_LONG(llx
))
359 /* Calculate y in 64 bit and check for overflow */
360 lly
= Int32x32To64(pptIn
[i
].x
, lM12
) + pptIn
[i
].y
;
361 if (DOES_VALUE_OVERFLOW_LONG(lly
))
366 /* Write back the results */
367 pptOut
[i
].x
= (LONG
)llx
;
368 pptOut
[i
].y
= (LONG
)lly
;
372 else if (flAccel
& XFORM_SCALE
)
374 /* Diagonal integer transform, get the diagonal elements */
375 if (!FLOATOBJ_bConvertToLong(&pmx
->efM11
, &lM11
) ||
376 !FLOATOBJ_bConvertToLong(&pmx
->efM22
, &lM22
))
385 /* Calculate x in 64 bit and check for overflow */
386 llx
= Int32x32To64(pptIn
[i
].x
, lM11
);
387 if (DOES_VALUE_OVERFLOW_LONG(llx
))
392 /* Calculate y in 64 bit and check for overflow */
393 lly
= Int32x32To64(pptIn
[i
].y
, lM22
);
394 if (DOES_VALUE_OVERFLOW_LONG(lly
))
399 /* Write back the results */
400 pptOut
[i
].x
= (LONG
)llx
;
401 pptOut
[i
].y
= (LONG
)lly
;
407 /* Full integer transform */
408 if (!FLOATOBJ_bConvertToLong(&pmx
->efM11
, &lM11
) ||
409 !FLOATOBJ_bConvertToLong(&pmx
->efM12
, &lM12
) ||
410 !FLOATOBJ_bConvertToLong(&pmx
->efM21
, &lM21
) ||
411 !FLOATOBJ_bConvertToLong(&pmx
->efM22
, &lM22
))
420 /* Calculate x in 64 bit and check for overflow */
421 llx
= Int32x32To64(pptIn
[i
].x
, lM11
);
422 llx
+= Int32x32To64(pptIn
[i
].y
, lM21
);
423 if (DOES_VALUE_OVERFLOW_LONG(llx
))
428 /* Calculate y in 64 bit and check for overflow */
429 lly
= Int32x32To64(pptIn
[i
].y
, lM22
);
430 lly
+= Int32x32To64(pptIn
[i
].x
, lM12
);
431 if (DOES_VALUE_OVERFLOW_LONG(lly
))
436 /* Write back the results */
437 pptOut
[i
].x
= (LONG
)llx
;
438 pptOut
[i
].y
= (LONG
)lly
;
443 else if (flAccel
& XFORM_UNITY
)
445 /* 1-scale transform */
449 /* Calculate x in 64 bit and check for overflow */
451 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].y
);
452 if (!FLOATOBJ_bConvertToLong(&fo1
, &lTemp
))
456 llx
= (LONGLONG
)pptIn
[i
].x
+ lTemp
;
457 if (DOES_VALUE_OVERFLOW_LONG(llx
))
462 /* Calculate y in 64 bit and check for overflow */
464 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].x
);
465 if (!FLOATOBJ_bConvertToLong(&fo2
, &lTemp
))
469 lly
= (LONGLONG
)pptIn
[i
].y
+ lTemp
;
470 if (DOES_VALUE_OVERFLOW_LONG(lly
))
475 /* Write back the results */
476 pptOut
[i
].x
= (LONG
)llx
;
477 pptOut
[i
].y
= (LONG
)lly
;
481 else if (flAccel
& XFORM_SCALE
)
483 /* Diagonal float transform */
488 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].x
);
489 if (!FLOATOBJ_bConvertToLong(&fo1
, &pptOut
[i
].x
))
495 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].y
);
496 if (!FLOATOBJ_bConvertToLong(&fo2
, &pptOut
[i
].y
))
505 /* Full float transform */
509 /* Calculate x as FLOATOBJ */
510 MulAddLong(&fo1
, &pmx
->efM11
, pptIn
[i
].x
, &pmx
->efM21
, pptIn
[i
].y
);
512 /* Calculate y as FLOATOBJ */
513 MulAddLong(&fo2
, &pmx
->efM12
, pptIn
[i
].x
, &pmx
->efM22
, pptIn
[i
].y
);
515 if (!FLOATOBJ_bConvertToLong(&fo1
, &pptOut
[i
].x
))
520 if (!FLOATOBJ_bConvertToLong(&fo2
, &pptOut
[i
].y
))
528 if (!(pmx
->flAccel
& XFORM_NO_TRANSLATION
))
530 /* Translate points */
534 llx
= (LONGLONG
)pptOut
[i
].x
+ pmx
->fxDx
;
535 if (DOES_VALUE_OVERFLOW_LONG(llx
))
539 pptOut
[i
].x
= (LONG
)llx
;
541 lly
= (LONGLONG
)pptOut
[i
].y
+ pmx
->fxDy
;
542 if (DOES_VALUE_OVERFLOW_LONG(lly
))
546 pptOut
[i
].y
= (LONG
)lly
;
554 /** Public functions **********************************************************/
556 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
563 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
565 /* Check parameters */
572 pxform
->eM11
= FLOATOBJ_GetFloat(&pmx
->efM11
);
573 pxform
->eM12
= FLOATOBJ_GetFloat(&pmx
->efM12
);
574 pxform
->eM21
= FLOATOBJ_GetFloat(&pmx
->efM21
);
575 pxform
->eM22
= FLOATOBJ_GetFloat(&pmx
->efM22
);
576 pxform
->eDx
= FLOATOBJ_GetFloat(&pmx
->efDx
);
577 pxform
->eDy
= FLOATOBJ_GetFloat(&pmx
->efDy
);
579 /* Return complexity hint */
580 return HintFromAccel(pmx
->flAccel
);
584 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
587 XFORMOBJ_iGetFloatObjXform(
589 OUT FLOATOBJ_XFORM
*pxfo
)
591 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
593 /* Check parameters */
600 pxfo
->eM11
= pmx
->efM11
;
601 pxfo
->eM12
= pmx
->efM12
;
602 pxfo
->eM21
= pmx
->efM21
;
603 pxfo
->eM22
= pmx
->efM22
;
604 pxfo
->eDx
= pmx
->efDx
;
605 pxfo
->eDy
= pmx
->efDy
;
607 /* Return complexity hint */
608 return HintFromAccel(pmx
->flAccel
);
612 // www.osr.com/ddk/graphics/gdifncs_027b.htm
615 XFORMOBJ_bApplyXform(
624 PPOINTL pptlIn
, pptlOut
;
627 /* Check parameters */
628 if (!pxo
|| !pvIn
|| !pvOut
|| cPoints
< 1)
633 /* Use inverse xform? */
634 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
)
636 XFORMOBJ_vInit(&xoInv
, &mx
);
637 if (XFORMOBJ_iInverse(&xoInv
, pxo
) == DDI_ERROR
)
644 /* Convert POINTL to POINTFIX? */
645 if (iMode
== XF_LTOFX
|| iMode
== XF_LTOL
|| iMode
== XF_INV_LTOL
)
649 for (i
= cPoints
- 1; i
>= 0; i
--)
651 pptlOut
[i
].x
= LONG2FIX(pptlIn
[i
].x
);
652 pptlOut
[i
].y
= LONG2FIX(pptlIn
[i
].y
);
655 /* The input is in the out buffer now! */
659 /* Do the actual fixpoint transformation */
660 if (!XFORMOBJ_bXformFixPoints(pxo
, cPoints
, pvIn
, pvOut
))
665 /* Convert POINTFIX to POINTL? */
666 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
|| iMode
== XF_LTOL
)
669 for (i
= cPoints
- 1; i
>= 0; i
--)
671 pptlOut
[i
].x
= FIX2LONG(pptlOut
[i
].x
);
672 pptlOut
[i
].y
= FIX2LONG(pptlOut
[i
].y
);