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
);
153 FLOATOBJ ef1
, ef2
, efTemp
;
155 /* Check parameters */
156 if (!pxo
|| !pxform
) return DDI_ERROR
;
158 /* Check if the xform is valid */
159 /* M11 * M22 - M12 * M21 != 0 */
160 FLOATOBJ_SetFloat(&ef1
, pxform
->eM11
);
161 FLOATOBJ_SetFloat(&efTemp
, pxform
->eM22
);
162 FLOATOBJ_Mul(&ef1
, &efTemp
);
163 FLOATOBJ_SetFloat(&ef2
, pxform
->eM12
);
164 FLOATOBJ_SetFloat(&efTemp
, pxform
->eM21
);
165 FLOATOBJ_Mul(&ef2
, &efTemp
);
166 if (FLOATOBJ_Equal(&ef1
, &ef2
))
170 FLOATOBJ_SetFloat(&pmx
->efM11
, pxform
->eM11
);
171 FLOATOBJ_SetFloat(&pmx
->efM12
, pxform
->eM12
);
172 FLOATOBJ_SetFloat(&pmx
->efM21
, pxform
->eM21
);
173 FLOATOBJ_SetFloat(&pmx
->efM22
, pxform
->eM22
);
174 FLOATOBJ_SetFloat(&pmx
->efDx
, pxform
->eDx
);
175 FLOATOBJ_SetFloat(&pmx
->efDy
, pxform
->eDy
);
177 /* Update accelerators and return complexity */
178 return XFORMOBJ_UpdateAccel(pxo
);
183 * Multiplies pxo1 with pxo2 and stores the result in pxo.
184 * returns complexity hint
197 PMATRIX pmx
, pmx1
, pmx2
;
199 /* Get the source matrices */
200 pmx1
= XFORMOBJ_pmx(pxo1
);
201 pmx2
= XFORMOBJ_pmx(pxo2
);
203 /* Do a 3 x 3 matrix multiplication with mx as destinantion */
204 MulAdd(&mx
.efM11
, &pmx1
->efM11
, &pmx2
->efM11
, &pmx1
->efM12
, &pmx2
->efM21
);
205 MulAdd(&mx
.efM12
, &pmx1
->efM11
, &pmx2
->efM12
, &pmx1
->efM12
, &pmx2
->efM22
);
206 MulAdd(&mx
.efM21
, &pmx1
->efM21
, &pmx2
->efM11
, &pmx1
->efM22
, &pmx2
->efM21
);
207 MulAdd(&mx
.efM22
, &pmx1
->efM21
, &pmx2
->efM12
, &pmx1
->efM22
, &pmx2
->efM22
);
208 MulAdd(&mx
.efDx
, &pmx1
->efDx
, &pmx2
->efM11
, &pmx1
->efDy
, &pmx2
->efM21
);
209 FLOATOBJ_Add(&mx
.efDx
, &pmx2
->efDx
);
210 MulAdd(&mx
.efDy
, &pmx1
->efDx
, &pmx2
->efM12
, &pmx1
->efDy
, &pmx2
->efM22
);
211 FLOATOBJ_Add(&mx
.efDy
, &pmx2
->efDy
);
214 pmx
= XFORMOBJ_pmx(pxo
);
217 /* Update accelerators and return complexity */
218 return XFORMOBJ_UpdateAccel(pxo
);
224 XFORMOBJ_iCombineXform(
228 IN BOOL bLeftMultiply
)
233 XFORMOBJ_vInit(&xo2
, &mx
);
234 XFORMOBJ_iSetXform(&xo2
, pxform
);
238 return XFORMOBJ_iCombine(pxo
, &xo2
, pxo1
);
242 return XFORMOBJ_iCombine(pxo
, pxo1
, &xo2
);
247 * A^-1 = adj(A) / det(AT)
248 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
253 OUT XFORMOBJ
*pxoDst
,
256 PMATRIX pmxDst
, pmxSrc
;
260 pmxDst
= XFORMOBJ_pmx(pxoDst
);
261 pmxSrc
= XFORMOBJ_pmx(pxoSrc
);
263 XFORMOBJ_iGetXform(pxoSrc
, (XFORML
*)&xformSrc
);
265 /* det = M11 * M22 - M12 * M21 */
266 MulSub(&foDet
, &pmxSrc
->efM11
, &pmxSrc
->efM22
, &pmxSrc
->efM12
, &pmxSrc
->efM21
);
268 if (FLOATOBJ_Equal0(&foDet
))
270 /* Determinant is 0! */
274 /* Calculate adj(A) / det(A) */
275 pmxDst
->efM11
= pmxSrc
->efM22
;
276 FLOATOBJ_Div(&pmxDst
->efM11
, &foDet
);
277 pmxDst
->efM22
= pmxSrc
->efM11
;
278 FLOATOBJ_Div(&pmxDst
->efM22
, &foDet
);
280 /* The other 2 are negative, negate foDet for that */
281 FLOATOBJ_Neg(&foDet
);
282 pmxDst
->efM12
= pmxSrc
->efM12
;
283 FLOATOBJ_Div(&pmxDst
->efM12
, &foDet
);
284 pmxDst
->efM21
= pmxSrc
->efM21
;
285 FLOATOBJ_Div(&pmxDst
->efM21
, &foDet
);
287 /* Calculate the inverted x shift: Dx' = -Dx * M11' - Dy * M21' */
288 pmxDst
->efDx
= pmxSrc
->efDx
;
289 FLOATOBJ_Neg(&pmxDst
->efDx
);
290 MulSub(&pmxDst
->efDx
, &pmxDst
->efDx
, &pmxDst
->efM11
, &pmxSrc
->efDy
, &pmxDst
->efM21
);
292 /* Calculate the inverted y shift: Dy' = -Dy * M22' - Dx * M12' */
293 pmxDst
->efDy
= pmxSrc
->efDy
;
294 FLOATOBJ_Neg(&pmxDst
->efDy
);
295 MulSub(&pmxDst
->efDy
, &pmxDst
->efDy
, &pmxDst
->efM22
, &pmxSrc
->efDx
, &pmxDst
->efM12
);
297 /* Update accelerators and return complexity */
298 return XFORMOBJ_UpdateAccel(pxoDst
);
303 * \brief Transforms fix-point coordinates in an array of POINTL structures using
304 * the transformation matrix from the XFORMOBJ.
306 * \param pxo - Pointer to the XFORMOBJ
308 * \param cPoints - Number of coordinates to transform
310 * \param pptIn - Pointer to an array of POINTL structures containing the
311 * source coordinates.
313 * \param pptOut - Pointer to an array of POINTL structures, receiving the
314 * transformed coordinates. Can be the same as pptIn.
316 * \return TRUE if the operation was successful, FALSE if any of the calculations
317 * caused an integer overflow.
319 * \note If the function returns FALSE, it might still have written to the
320 * output buffer. If pptIn and pptOut are equal, the source coordinates
321 * might have been partly overwritten!
326 XFORMOBJ_bXformFixPoints(
329 _In_reads_(cPoints
) PPOINTL pptIn
,
330 _Out_writes_(cPoints
) PPOINTL pptOut
)
336 LONG lM11
, lM12
, lM21
, lM22
, lTemp
;
337 register LONGLONG llx
, lly
;
339 pmx
= XFORMOBJ_pmx(pxo
);
340 flAccel
= pmx
->flAccel
;
342 if ((flAccel
& (XFORM_SCALE
|XFORM_UNITY
)) == (XFORM_SCALE
|XFORM_UNITY
))
344 /* Identity transformation */
345 RtlCopyMemory(pptOut
, pptIn
, cPoints
* sizeof(POINTL
));
347 else if (flAccel
& XFORM_INTEGER
)
349 if (flAccel
& XFORM_UNITY
)
351 /* 1-scale integer transform, get the off-diagonal elements */
352 if (!FLOATOBJ_bConvertToLong(&pmx
->efM12
, &lM12
) ||
353 !FLOATOBJ_bConvertToLong(&pmx
->efM21
, &lM21
))
362 /* Calculate x in 64 bit and check for overflow */
363 llx
= Int32x32To64(pptIn
[i
].y
, lM21
) + pptIn
[i
].x
;
364 if (DOES_VALUE_OVERFLOW_LONG(llx
))
369 /* Calculate y in 64 bit and check for overflow */
370 lly
= Int32x32To64(pptIn
[i
].x
, lM12
) + pptIn
[i
].y
;
371 if (DOES_VALUE_OVERFLOW_LONG(lly
))
376 /* Write back the results */
377 pptOut
[i
].x
= (LONG
)llx
;
378 pptOut
[i
].y
= (LONG
)lly
;
382 else if (flAccel
& XFORM_SCALE
)
384 /* Diagonal integer transform, get the diagonal elements */
385 if (!FLOATOBJ_bConvertToLong(&pmx
->efM11
, &lM11
) ||
386 !FLOATOBJ_bConvertToLong(&pmx
->efM22
, &lM22
))
395 /* Calculate x in 64 bit and check for overflow */
396 llx
= Int32x32To64(pptIn
[i
].x
, lM11
);
397 if (DOES_VALUE_OVERFLOW_LONG(llx
))
402 /* Calculate y in 64 bit and check for overflow */
403 lly
= Int32x32To64(pptIn
[i
].y
, lM22
);
404 if (DOES_VALUE_OVERFLOW_LONG(lly
))
409 /* Write back the results */
410 pptOut
[i
].x
= (LONG
)llx
;
411 pptOut
[i
].y
= (LONG
)lly
;
417 /* Full integer transform */
418 if (!FLOATOBJ_bConvertToLong(&pmx
->efM11
, &lM11
) ||
419 !FLOATOBJ_bConvertToLong(&pmx
->efM12
, &lM12
) ||
420 !FLOATOBJ_bConvertToLong(&pmx
->efM21
, &lM21
) ||
421 !FLOATOBJ_bConvertToLong(&pmx
->efM22
, &lM22
))
430 /* Calculate x in 64 bit and check for overflow */
431 llx
= Int32x32To64(pptIn
[i
].x
, lM11
);
432 llx
+= Int32x32To64(pptIn
[i
].y
, lM21
);
433 if (DOES_VALUE_OVERFLOW_LONG(llx
))
438 /* Calculate y in 64 bit and check for overflow */
439 lly
= Int32x32To64(pptIn
[i
].y
, lM22
);
440 lly
+= Int32x32To64(pptIn
[i
].x
, lM12
);
441 if (DOES_VALUE_OVERFLOW_LONG(lly
))
446 /* Write back the results */
447 pptOut
[i
].x
= (LONG
)llx
;
448 pptOut
[i
].y
= (LONG
)lly
;
453 else if (flAccel
& XFORM_UNITY
)
455 /* 1-scale transform */
459 /* Calculate x in 64 bit and check for overflow */
461 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].y
);
462 if (!FLOATOBJ_bConvertToLong(&fo1
, &lTemp
))
466 llx
= (LONGLONG
)pptIn
[i
].x
+ lTemp
;
467 if (DOES_VALUE_OVERFLOW_LONG(llx
))
472 /* Calculate y in 64 bit and check for overflow */
474 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].x
);
475 if (!FLOATOBJ_bConvertToLong(&fo2
, &lTemp
))
479 lly
= (LONGLONG
)pptIn
[i
].y
+ lTemp
;
480 if (DOES_VALUE_OVERFLOW_LONG(lly
))
485 /* Write back the results */
486 pptOut
[i
].x
= (LONG
)llx
;
487 pptOut
[i
].y
= (LONG
)lly
;
491 else if (flAccel
& XFORM_SCALE
)
493 /* Diagonal float transform */
498 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].x
);
499 if (!FLOATOBJ_bConvertToLong(&fo1
, &pptOut
[i
].x
))
505 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].y
);
506 if (!FLOATOBJ_bConvertToLong(&fo2
, &pptOut
[i
].y
))
515 /* Full float transform */
519 /* Calculate x as FLOATOBJ */
520 MulAddLong(&fo1
, &pmx
->efM11
, pptIn
[i
].x
, &pmx
->efM21
, pptIn
[i
].y
);
522 /* Calculate y as FLOATOBJ */
523 MulAddLong(&fo2
, &pmx
->efM12
, pptIn
[i
].x
, &pmx
->efM22
, pptIn
[i
].y
);
525 if (!FLOATOBJ_bConvertToLong(&fo1
, &pptOut
[i
].x
))
530 if (!FLOATOBJ_bConvertToLong(&fo2
, &pptOut
[i
].y
))
538 if (!(pmx
->flAccel
& XFORM_NO_TRANSLATION
))
540 /* Translate points */
544 llx
= (LONGLONG
)pptOut
[i
].x
+ pmx
->fxDx
;
545 if (DOES_VALUE_OVERFLOW_LONG(llx
))
549 pptOut
[i
].x
= (LONG
)llx
;
551 lly
= (LONGLONG
)pptOut
[i
].y
+ pmx
->fxDy
;
552 if (DOES_VALUE_OVERFLOW_LONG(lly
))
556 pptOut
[i
].y
= (LONG
)lly
;
564 /** Public functions **********************************************************/
566 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
573 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
575 /* Check parameters */
582 pxform
->eM11
= FLOATOBJ_GetFloat(&pmx
->efM11
);
583 pxform
->eM12
= FLOATOBJ_GetFloat(&pmx
->efM12
);
584 pxform
->eM21
= FLOATOBJ_GetFloat(&pmx
->efM21
);
585 pxform
->eM22
= FLOATOBJ_GetFloat(&pmx
->efM22
);
586 pxform
->eDx
= FLOATOBJ_GetFloat(&pmx
->efDx
);
587 pxform
->eDy
= FLOATOBJ_GetFloat(&pmx
->efDy
);
589 /* Return complexity hint */
590 return HintFromAccel(pmx
->flAccel
);
594 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
597 XFORMOBJ_iGetFloatObjXform(
599 OUT FLOATOBJ_XFORM
*pxfo
)
601 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
603 /* Check parameters */
610 pxfo
->eM11
= pmx
->efM11
;
611 pxfo
->eM12
= pmx
->efM12
;
612 pxfo
->eM21
= pmx
->efM21
;
613 pxfo
->eM22
= pmx
->efM22
;
614 pxfo
->eDx
= pmx
->efDx
;
615 pxfo
->eDy
= pmx
->efDy
;
617 /* Return complexity hint */
618 return HintFromAccel(pmx
->flAccel
);
622 // www.osr.com/ddk/graphics/gdifncs_027b.htm
625 XFORMOBJ_bApplyXform(
634 PPOINTL pptlIn
, pptlOut
;
637 /* Check parameters */
638 if (!pxo
|| !pvIn
|| !pvOut
|| cPoints
< 1)
643 /* Use inverse xform? */
644 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
)
646 XFORMOBJ_vInit(&xoInv
, &mx
);
647 if (XFORMOBJ_iInverse(&xoInv
, pxo
) == DDI_ERROR
)
654 /* Convert POINTL to POINTFIX? */
655 if (iMode
== XF_LTOFX
|| iMode
== XF_LTOL
|| iMode
== XF_INV_LTOL
)
659 for (i
= cPoints
- 1; i
>= 0; i
--)
661 pptlOut
[i
].x
= LONG2FIX(pptlIn
[i
].x
);
662 pptlOut
[i
].y
= LONG2FIX(pptlIn
[i
].y
);
665 /* The input is in the out buffer now! */
669 /* Do the actual fixpoint transformation */
670 if (!XFORMOBJ_bXformFixPoints(pxo
, cPoints
, pvIn
, pvOut
))
675 /* Convert POINTFIX to POINTL? */
676 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
|| iMode
== XF_LTOL
)
679 for (i
= cPoints
- 1; i
>= 0; i
--)
681 pptlOut
[i
].x
= FIX2LONG(pptlOut
[i
].x
);
682 pptlOut
[i
].y
= FIX2LONG(pptlOut
[i
].y
);