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 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 /* Get the source matrices */
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
);
213 pmx
= XFORMOBJ_pmx(pxo
);
216 /* Update accelerators and return complexity */
217 return XFORMOBJ_UpdateAccel(pxo
);
223 XFORMOBJ_iCombineXform(
227 IN BOOL bLeftMultiply
)
232 XFORMOBJ_vInit(&xo2
, &mx
);
233 XFORMOBJ_iSetXform(&xo2
, pxform
);
237 return XFORMOBJ_iCombine(pxo
, &xo2
, pxo1
);
241 return XFORMOBJ_iCombine(pxo
, pxo1
, &xo2
);
246 * A^-1 = adj(A) / det(AT)
247 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
252 OUT XFORMOBJ
*pxoDst
,
255 PMATRIX pmxDst
, pmxSrc
;
259 pmxDst
= XFORMOBJ_pmx(pxoDst
);
260 pmxSrc
= XFORMOBJ_pmx(pxoSrc
);
262 XFORMOBJ_iGetXform(pxoSrc
, (XFORML
*)&xformSrc
);
264 /* det = M11 * M22 - M12 * M21 */
265 MulSub(&foDet
, &pmxSrc
->efM11
, &pmxSrc
->efM22
, &pmxSrc
->efM12
, &pmxSrc
->efM21
);
267 if (FLOATOBJ_Equal0(&foDet
))
269 /* Determinant is 0! */
273 /* Calculate adj(A) / det(A) */
274 pmxDst
->efM11
= pmxSrc
->efM22
;
275 FLOATOBJ_Div(&pmxDst
->efM11
, &foDet
);
276 pmxDst
->efM22
= pmxSrc
->efM11
;
277 FLOATOBJ_Div(&pmxDst
->efM22
, &foDet
);
279 /* The other 2 are negative, negate foDet for that */
280 FLOATOBJ_Neg(&foDet
);
281 pmxDst
->efM12
= pmxSrc
->efM12
;
282 FLOATOBJ_Div(&pmxDst
->efM12
, &foDet
);
283 pmxDst
->efM21
= pmxSrc
->efM21
;
284 FLOATOBJ_Div(&pmxDst
->efM21
, &foDet
);
286 /* Calculate the inverted x shift: Dx' = -Dx * M11' - Dy * M21' */
287 pmxDst
->efDx
= pmxSrc
->efDx
;
288 FLOATOBJ_Neg(&pmxDst
->efDx
);
289 MulSub(&pmxDst
->efDx
, &pmxDst
->efDx
, &pmxDst
->efM11
, &pmxSrc
->efDy
, &pmxDst
->efM21
);
291 /* Calculate the inverted y shift: Dy' = -Dy * M22' - Dx * M12' */
292 pmxDst
->efDy
= pmxSrc
->efDy
;
293 FLOATOBJ_Neg(&pmxDst
->efDy
);
294 MulSub(&pmxDst
->efDy
, &pmxDst
->efDy
, &pmxDst
->efM22
, &pmxSrc
->efDx
, &pmxDst
->efM12
);
296 /* Update accelerators and return complexity */
297 return XFORMOBJ_UpdateAccel(pxoDst
);
303 XFORMOBJ_bXformFixPoints(
314 pmx
= XFORMOBJ_pmx(pxo
);
315 flAccel
= pmx
->flAccel
;
317 if ((flAccel
& (XFORM_SCALE
|XFORM_UNITY
)) == (XFORM_SCALE
|XFORM_UNITY
))
319 /* Identity transformation, nothing todo */
321 else if (flAccel
& XFORM_INTEGER
)
323 if (flAccel
& XFORM_UNITY
)
325 /* 1-scale integer transform */
326 LONG lM12
= FLOATOBJ_GetLong(&pmx
->efM12
);
327 LONG lM21
= FLOATOBJ_GetLong(&pmx
->efM21
);
332 LONG x
= pptIn
[i
].x
+ pptIn
[i
].y
* lM21
;
333 LONG y
= pptIn
[i
].y
+ pptIn
[i
].x
* lM12
;
339 else if (flAccel
& XFORM_SCALE
)
341 /* Diagonal integer transform */
342 LONG lM11
= FLOATOBJ_GetLong(&pmx
->efM11
);
343 LONG lM22
= FLOATOBJ_GetLong(&pmx
->efM22
);
348 pptOut
[i
].x
= pptIn
[i
].x
* lM11
;
349 pptOut
[i
].y
= pptIn
[i
].y
* lM22
;
355 /* Full integer transform */
356 LONG lM11
= FLOATOBJ_GetLong(&pmx
->efM11
);
357 LONG lM12
= FLOATOBJ_GetLong(&pmx
->efM12
);
358 LONG lM21
= FLOATOBJ_GetLong(&pmx
->efM21
);
359 LONG lM22
= FLOATOBJ_GetLong(&pmx
->efM22
);
365 x
= pptIn
[i
].x
* lM11
;
366 x
+= pptIn
[i
].y
* lM21
;
367 pptOut
[i
].y
= pptIn
[i
].y
* lM22
;
368 pptOut
[i
].y
+= pptIn
[i
].x
* lM12
;
374 else if (flAccel
& XFORM_UNITY
)
376 /* 1-scale transform */
381 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].y
);
383 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].x
);
384 pptOut
[i
].x
= pptIn
[i
].x
+ FLOATOBJ_GetLong(&fo1
);
385 pptOut
[i
].y
= pptIn
[i
].y
+ FLOATOBJ_GetLong(&fo2
);
389 else if (flAccel
& XFORM_SCALE
)
391 /* Diagonal float transform */
396 FLOATOBJ_MulLong(&fo1
, pptIn
[i
].x
);
397 pptOut
[i
].x
= FLOATOBJ_GetLong(&fo1
);
399 FLOATOBJ_MulLong(&fo2
, pptIn
[i
].y
);
400 pptOut
[i
].y
= FLOATOBJ_GetLong(&fo2
);
406 /* Full float transform */
410 MulAddLong(&fo1
, &pmx
->efM11
, pptIn
[i
].x
, &pmx
->efM21
, pptIn
[i
].y
);
411 MulAddLong(&fo2
, &pmx
->efM12
, pptIn
[i
].x
, &pmx
->efM22
, pptIn
[i
].y
);
412 pptOut
[i
].x
= FLOATOBJ_GetLong(&fo1
);
413 pptOut
[i
].y
= FLOATOBJ_GetLong(&fo2
);
418 if (!(pmx
->flAccel
& XFORM_NO_TRANSLATION
))
420 /* Translate points */
424 pptOut
[i
].x
+= pmx
->fxDx
;
425 pptOut
[i
].y
+= pmx
->fxDy
;
433 /** Public functions **********************************************************/
435 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
442 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
444 /* Check parameters */
451 pxform
->eM11
= FLOATOBJ_GetFloat(&pmx
->efM11
);
452 pxform
->eM12
= FLOATOBJ_GetFloat(&pmx
->efM12
);
453 pxform
->eM21
= FLOATOBJ_GetFloat(&pmx
->efM21
);
454 pxform
->eM22
= FLOATOBJ_GetFloat(&pmx
->efM22
);
455 pxform
->eDx
= FLOATOBJ_GetFloat(&pmx
->efDx
);
456 pxform
->eDy
= FLOATOBJ_GetFloat(&pmx
->efDy
);
458 /* Return complexity hint */
459 return HintFromAccel(pmx
->flAccel
);
463 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
466 XFORMOBJ_iGetFloatObjXform(
468 OUT FLOATOBJ_XFORM
*pxfo
)
470 PMATRIX pmx
= XFORMOBJ_pmx(pxo
);
472 /* Check parameters */
479 pxfo
->eM11
= pmx
->efM11
;
480 pxfo
->eM12
= pmx
->efM12
;
481 pxfo
->eM21
= pmx
->efM21
;
482 pxfo
->eM22
= pmx
->efM22
;
483 pxfo
->eDx
= pmx
->efDx
;
484 pxfo
->eDy
= pmx
->efDy
;
486 /* Return complexity hint */
487 return HintFromAccel(pmx
->flAccel
);
491 // www.osr.com/ddk/graphics/gdifncs_027b.htm
494 XFORMOBJ_bApplyXform(
506 /* Check parameters */
507 if (!pxo
|| !pvIn
|| !pvOut
|| cPoints
< 1)
512 /* Use inverse xform? */
513 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
)
515 XFORMOBJ_vInit(&xoInv
, &mx
);
516 if (XFORMOBJ_iInverse(&xoInv
, pxo
) == DDI_ERROR
)
523 /* Convert POINTL to POINTFIX? */
524 if (iMode
== XF_LTOFX
|| iMode
== XF_LTOL
|| iMode
== XF_INV_LTOL
)
527 for (i
= cPoints
- 1; i
>= 0; i
--)
529 pptl
[i
].x
= LONG2FIX(pptl
[i
].x
);
530 pptl
[i
].y
= LONG2FIX(pptl
[i
].y
);
534 /* Do the actual fixpoint transformation */
535 if (!XFORMOBJ_bXformFixPoints(pxo
, cPoints
, pvIn
, pvOut
))
540 /* Convert POINTFIX to POINTL? */
541 if (iMode
== XF_INV_FXTOL
|| iMode
== XF_INV_LTOL
|| iMode
== XF_LTOL
)
544 for (i
= cPoints
- 1; i
>= 0; i
--)
546 pptl
[i
].x
= FIX2LONG(pptl
[i
].x
);
547 pptl
[i
].y
= FIX2LONG(pptl
[i
].y
);