[SYSSETUP]
[reactos.git] / win32ss / gdi / ntgdi / xformobj.c
1 /*
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
7 */
8
9 /** Includes ******************************************************************/
10
11 #include <win32k.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 C_ASSERT(sizeof(FIX) == sizeof(LONG));
16 #define FIX2LONG(x) ((x) >> 4)
17 #define LONG2FIX(x) ((x) << 4)
18
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
25
26 /** Inline helper functions ***************************************************/
27
28 /*
29 * Inline helper to calculate pfo1 * pfo2 + pfo3 * pfo4
30 */
31 FORCEINLINE
32 VOID
33 MulAdd(
34 PFLOATOBJ pfoDest,
35 PFLOATOBJ pfo1,
36 PFLOATOBJ pfo2,
37 PFLOATOBJ pfo3,
38 PFLOATOBJ pfo4)
39 {
40 FLOATOBJ foTmp;
41
42 *pfoDest = *pfo1;
43 FLOATOBJ_Mul(pfoDest, pfo2);
44 foTmp = *pfo3;
45 FLOATOBJ_Mul(&foTmp, pfo4);
46 FLOATOBJ_Add(pfoDest, &foTmp);
47 }
48
49 /*
50 * Inline helper to calculate pfo1 * l2 + pfo3 * l4
51 */
52 FORCEINLINE
53 VOID
54 MulAddLong(
55 PFLOATOBJ pfoDest,
56 PFLOATOBJ pfo1,
57 LONG l2,
58 PFLOATOBJ pfo3,
59 LONG l4)
60 {
61 FLOATOBJ foTmp;
62
63 *pfoDest = *pfo1;
64 FLOATOBJ_MulLong(pfoDest, l2);
65 foTmp = *pfo3;
66 FLOATOBJ_MulLong(&foTmp, l4);
67 FLOATOBJ_Add(pfoDest, &foTmp);
68 }
69
70 /*
71 * Inline helper to calculate pfo1 * pfo2 - pfo3 * pfo4
72 */
73 FORCEINLINE
74 VOID
75 MulSub(
76 PFLOATOBJ pfoDest,
77 PFLOATOBJ pfo1,
78 PFLOATOBJ pfo2,
79 PFLOATOBJ pfo3,
80 PFLOATOBJ pfo4)
81 {
82 FLOATOBJ foTmp;
83
84 *pfoDest = *pfo1;
85 FLOATOBJ_Mul(pfoDest, pfo2);
86 foTmp = *pfo3;
87 FLOATOBJ_Mul(&foTmp, pfo4);
88 FLOATOBJ_Sub(pfoDest, &foTmp);
89 }
90
91 /*
92 * Inline helper to get the complexity hint from flAccel
93 */
94 FORCEINLINE
95 ULONG
96 HintFromAccel(ULONG flAccel)
97 {
98 switch (flAccel & (XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION))
99 {
100 case (XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION):
101 return GX_IDENTITY;
102 case (XFORM_SCALE|XFORM_UNITY):
103 return GX_OFFSET;
104 case XFORM_SCALE:
105 return GX_SCALE;
106 default:
107 return GX_GENERAL;
108 }
109 }
110
111 /** Internal functions ********************************************************/
112
113 ULONG
114 NTAPI
115 XFORMOBJ_UpdateAccel(
116 IN XFORMOBJ *pxo)
117 {
118 PMATRIX pmx = XFORMOBJ_pmx(pxo);
119
120 /* Copy Dx and Dy to FIX format */
121 pmx->fxDx = FLOATOBJ_GetFix(&pmx->efDx);
122 pmx->fxDy = FLOATOBJ_GetFix(&pmx->efDy);
123
124 pmx->flAccel = 0;
125
126 if (FLOATOBJ_Equal0(&pmx->efDx) &&
127 FLOATOBJ_Equal0(&pmx->efDy))
128 {
129 pmx->flAccel |= XFORM_NO_TRANSLATION;
130 }
131
132 if (FLOATOBJ_Equal0(&pmx->efM12) &&
133 FLOATOBJ_Equal0(&pmx->efM21))
134 {
135 pmx->flAccel |= XFORM_SCALE;
136 }
137
138 if (FLOATOBJ_Equal1(&pmx->efM11) &&
139 FLOATOBJ_Equal1(&pmx->efM22))
140 {
141 pmx->flAccel |= XFORM_UNITY;
142 }
143
144 if (FLOATOBJ_IsLong(&pmx->efM11) && FLOATOBJ_IsLong(&pmx->efM12) &&
145 FLOATOBJ_IsLong(&pmx->efM21) && FLOATOBJ_IsLong(&pmx->efM22))
146 {
147 pmx->flAccel |= XFORM_INTEGER;
148 }
149
150 return HintFromAccel(pmx->flAccel);
151 }
152
153
154 ULONG
155 NTAPI
156 XFORMOBJ_iSetXform(
157 OUT XFORMOBJ *pxo,
158 IN const XFORML *pxform)
159 {
160 PMATRIX pmx = XFORMOBJ_pmx(pxo);
161
162 /* Check parameters */
163 if (!pxo || !pxform) return DDI_ERROR;
164
165 /* Check if the xform is valid */
166 if ((pxform->eM11 == 0) || (pxform->eM22 == 0)) return DDI_ERROR;
167
168 /* Copy members */
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);
175
176 /* Update accelerators and return complexity */
177 return XFORMOBJ_UpdateAccel(pxo);
178 }
179
180
181 /*
182 * Multiplies pxo1 with pxo2 and stores the result in pxo.
183 * returns complexity hint
184 * | efM11 efM12 0 |
185 * | efM21 efM22 0 |
186 * | efDx efDy 1 |
187 */
188 ULONG
189 NTAPI
190 XFORMOBJ_iCombine(
191 IN XFORMOBJ *pxo,
192 IN XFORMOBJ *pxo1,
193 IN XFORMOBJ *pxo2)
194 {
195 MATRIX mx;
196 PMATRIX pmx, pmx1, pmx2;
197
198 /* Get the source matrices */
199 pmx1 = XFORMOBJ_pmx(pxo1);
200 pmx2 = XFORMOBJ_pmx(pxo2);
201
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);
211
212 /* Copy back */
213 pmx = XFORMOBJ_pmx(pxo);
214 *pmx = mx;
215
216 /* Update accelerators and return complexity */
217 return XFORMOBJ_UpdateAccel(pxo);
218 }
219
220
221 ULONG
222 NTAPI
223 XFORMOBJ_iCombineXform(
224 IN XFORMOBJ *pxo,
225 IN XFORMOBJ *pxo1,
226 IN XFORML *pxform,
227 IN BOOL bLeftMultiply)
228 {
229 MATRIX mx;
230 XFORMOBJ xo2;
231
232 XFORMOBJ_vInit(&xo2, &mx);
233 XFORMOBJ_iSetXform(&xo2, pxform);
234
235 if (bLeftMultiply)
236 {
237 return XFORMOBJ_iCombine(pxo, &xo2, pxo1);
238 }
239 else
240 {
241 return XFORMOBJ_iCombine(pxo, pxo1, &xo2);
242 }
243 }
244
245 /*
246 * A^-1 = adj(A) / det(AT)
247 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11)
248 */
249 ULONG
250 NTAPI
251 XFORMOBJ_iInverse(
252 OUT XFORMOBJ *pxoDst,
253 IN XFORMOBJ *pxoSrc)
254 {
255 PMATRIX pmxDst, pmxSrc;
256 FLOATOBJ foDet;
257 XFORM xformSrc;
258
259 pmxDst = XFORMOBJ_pmx(pxoDst);
260 pmxSrc = XFORMOBJ_pmx(pxoSrc);
261
262 XFORMOBJ_iGetXform(pxoSrc, (XFORML*)&xformSrc);
263
264 /* det = M11 * M22 - M12 * M21 */
265 MulSub(&foDet, &pmxSrc->efM11, &pmxSrc->efM22, &pmxSrc->efM12, &pmxSrc->efM21);
266
267 if (FLOATOBJ_Equal0(&foDet))
268 {
269 /* Determinant is 0! */
270 return DDI_ERROR;
271 }
272
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);
278
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);
285
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);
290
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);
295
296 /* Update accelerators and return complexity */
297 return XFORMOBJ_UpdateAccel(pxoDst);
298 }
299
300
301 BOOL
302 NTAPI
303 XFORMOBJ_bXformFixPoints(
304 IN XFORMOBJ *pxo,
305 IN ULONG cPoints,
306 IN PPOINTL pptIn,
307 OUT PPOINTL pptOut)
308 {
309 PMATRIX pmx;
310 INT i;
311 FLOATOBJ fo1, fo2;
312 FLONG flAccel;
313
314 pmx = XFORMOBJ_pmx(pxo);
315 flAccel = pmx->flAccel;
316
317 if ((flAccel & (XFORM_SCALE|XFORM_UNITY)) == (XFORM_SCALE|XFORM_UNITY))
318 {
319 /* Identity transformation, nothing todo */
320 }
321 else if (flAccel & XFORM_INTEGER)
322 {
323 if (flAccel & XFORM_UNITY)
324 {
325 /* 1-scale integer transform */
326 LONG lM12 = FLOATOBJ_GetLong(&pmx->efM12);
327 LONG lM21 = FLOATOBJ_GetLong(&pmx->efM21);
328
329 i = cPoints - 1;
330 do
331 {
332 LONG x = pptIn[i].x + pptIn[i].y * lM21;
333 LONG y = pptIn[i].y + pptIn[i].x * lM12;
334 pptOut[i].y = y;
335 pptOut[i].x = x;
336 }
337 while (--i >= 0);
338 }
339 else if (flAccel & XFORM_SCALE)
340 {
341 /* Diagonal integer transform */
342 LONG lM11 = FLOATOBJ_GetLong(&pmx->efM11);
343 LONG lM22 = FLOATOBJ_GetLong(&pmx->efM22);
344
345 i = cPoints - 1;
346 do
347 {
348 pptOut[i].x = pptIn[i].x * lM11;
349 pptOut[i].y = pptIn[i].y * lM22;
350 }
351 while (--i >= 0);
352 }
353 else
354 {
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);
360
361 i = cPoints - 1;
362 do
363 {
364 LONG x;
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;
369 pptOut[i].x = x;
370 }
371 while (--i >= 0);
372 }
373 }
374 else if (flAccel & XFORM_UNITY)
375 {
376 /* 1-scale transform */
377 i = cPoints - 1;
378 do
379 {
380 fo1 = pmx->efM21;
381 FLOATOBJ_MulLong(&fo1, pptIn[i].y);
382 fo2 = pmx->efM12;
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);
386 }
387 while (--i >= 0);
388 }
389 else if (flAccel & XFORM_SCALE)
390 {
391 /* Diagonal float transform */
392 i = cPoints - 1;
393 do
394 {
395 fo1 = pmx->efM11;
396 FLOATOBJ_MulLong(&fo1, pptIn[i].x);
397 pptOut[i].x = FLOATOBJ_GetLong(&fo1);
398 fo2 = pmx->efM22;
399 FLOATOBJ_MulLong(&fo2, pptIn[i].y);
400 pptOut[i].y = FLOATOBJ_GetLong(&fo2);
401 }
402 while (--i >= 0);
403 }
404 else
405 {
406 /* Full float transform */
407 i = cPoints - 1;
408 do
409 {
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);
414 }
415 while (--i >= 0);
416 }
417
418 if (!(pmx->flAccel & XFORM_NO_TRANSLATION))
419 {
420 /* Translate points */
421 i = cPoints - 1;
422 do
423 {
424 pptOut[i].x += pmx->fxDx;
425 pptOut[i].y += pmx->fxDy;
426 }
427 while (--i >= 0);
428 }
429
430 return TRUE;
431 }
432
433 /** Public functions **********************************************************/
434
435 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm
436 ULONG
437 APIENTRY
438 XFORMOBJ_iGetXform(
439 IN XFORMOBJ *pxo,
440 OUT XFORML *pxform)
441 {
442 PMATRIX pmx = XFORMOBJ_pmx(pxo);
443
444 /* Check parameters */
445 if (!pxo || !pxform)
446 {
447 return DDI_ERROR;
448 }
449
450 /* Copy members */
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);
457
458 /* Return complexity hint */
459 return HintFromAccel(pmx->flAccel);
460 }
461
462
463 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm
464 ULONG
465 APIENTRY
466 XFORMOBJ_iGetFloatObjXform(
467 IN XFORMOBJ *pxo,
468 OUT FLOATOBJ_XFORM *pxfo)
469 {
470 PMATRIX pmx = XFORMOBJ_pmx(pxo);
471
472 /* Check parameters */
473 if (!pxo || !pxfo)
474 {
475 return DDI_ERROR;
476 }
477
478 /* Copy members */
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;
485
486 /* Return complexity hint */
487 return HintFromAccel(pmx->flAccel);
488 }
489
490
491 // www.osr.com/ddk/graphics/gdifncs_027b.htm
492 BOOL
493 APIENTRY
494 XFORMOBJ_bApplyXform(
495 IN XFORMOBJ *pxo,
496 IN ULONG iMode,
497 IN ULONG cPoints,
498 IN PVOID pvIn,
499 OUT PVOID pvOut)
500 {
501 MATRIX mx;
502 XFORMOBJ xoInv;
503 POINTL *pptl;
504 INT i;
505
506 /* Check parameters */
507 if (!pxo || !pvIn || !pvOut || cPoints < 1)
508 {
509 return FALSE;
510 }
511
512 /* Use inverse xform? */
513 if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL)
514 {
515 XFORMOBJ_vInit(&xoInv, &mx);
516 if (XFORMOBJ_iInverse(&xoInv, pxo) == DDI_ERROR)
517 {
518 return FALSE;
519 }
520 pxo = &xoInv;
521 }
522
523 /* Convert POINTL to POINTFIX? */
524 if (iMode == XF_LTOFX || iMode == XF_LTOL || iMode == XF_INV_LTOL)
525 {
526 pptl = pvIn;
527 for (i = cPoints - 1; i >= 0; i--)
528 {
529 pptl[i].x = LONG2FIX(pptl[i].x);
530 pptl[i].y = LONG2FIX(pptl[i].y);
531 }
532 }
533
534 /* Do the actual fixpoint transformation */
535 if (!XFORMOBJ_bXformFixPoints(pxo, cPoints, pvIn, pvOut))
536 {
537 return FALSE;
538 }
539
540 /* Convert POINTFIX to POINTL? */
541 if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL || iMode == XF_LTOL)
542 {
543 pptl = pvOut;
544 for (i = cPoints - 1; i >= 0; i--)
545 {
546 pptl[i].x = FIX2LONG(pptl[i].x);
547 pptl[i].y = FIX2LONG(pptl[i].y);
548 }
549 }
550
551 return TRUE;
552 }
553
554 /* EOF */