The XFORM matrix in PlgBlt is calculated incorrectly

Alexander Almaleh sashoalm at gmail.com
Tue Dec 8 10:45:18 CST 2009


I'm talking about this code, from
http://source.winehq.org/source/dlls/gdi32/bitblt.c, in function PlgBlt :

577 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L577>
    rect[0].x <http://source.winehq.org/source/dlls/gdi32/ident?i=x> =
nXSrc;578 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L578>
    rect[0].y <http://source.winehq.org/source/dlls/gdi32/ident?i=y> =
nYSrc;579 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L579>
    rect[1].x <http://source.winehq.org/source/dlls/gdi32/ident?i=x> =
nXSrc + nWidth;580
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L580>
    rect[1].y <http://source.winehq.org/source/dlls/gdi32/ident?i=y> =
nYSrc;581 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L581>
    rect[2].x <http://source.winehq.org/source/dlls/gdi32/ident?i=x> =
nXSrc;582 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L582>
    rect[2].y <http://source.winehq.org/source/dlls/gdi32/ident?i=y> =
nYSrc + nHeight;583
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L583>
    */* calc XFORM matrix to transform hdcDest -> hdcSrc
(parallelogram to rectangle) */*584
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L584>
    */* determinant */*585
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L585>
    det = rect[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - rect[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - rect[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>);586
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L586>
587 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L587>
    if (fabs(det) < 1e-5)588
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L588>
    {589 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L589>
        SetGraphicsMode
<http://source.winehq.org/source/dlls/gdi32/ident?i=SetGraphicsMode>(hdcDest,oldgMode);590
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L590>
        return FALSE
<http://source.winehq.org/source/dlls/gdi32/ident?i=FALSE>;591
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L591>
    }592 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L592>
593 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L593>
    TRACE <http://source.winehq.org/source/dlls/gdi32/ident?i=TRACE>(*"hdcSrc=%p
%d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n"*,594
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L594>
        hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>, plg[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>, plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>, plg[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>, plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>, plg[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>);595
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L595>
596 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L596>
    */* X components */*597
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L597>
    xf.eM11 = (plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>)) / det;598
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L598>
    xf.eM21 = (rect[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x> - plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>) - rect[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x> - plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>) - rect[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x> - plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>)) / det;599
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L599>
    xf.eDx  = (rect[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x> - rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>) -600
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L600>
               rect[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x> - rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>) +601
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L601>
               rect[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x> - rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>)602
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L602>
               ) / det;603
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L603>
604 <http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L604>
    */* Y components */*605
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L605>
    xf.eM12 = (plg[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - plg[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*(rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - plg[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>)) / det;606
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L606>
    xf.eM22 = (plg[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - plg[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) - plg[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>)) / det;607
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L607>
    xf.eDy  = (rect[0].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) -608
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L608>
               rect[1].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[2].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>) +609
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L609>
               rect[2].x
<http://source.winehq.org/source/dlls/gdi32/ident?i=x>*(rect[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y> - rect[1].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>*plg[0].y
<http://source.winehq.org/source/dlls/gdi32/ident?i=y>)610
<http://source.winehq.org/source/dlls/gdi32/source/dlls/gdi32/bitblt.c#L610>
               ) / det;



I have a formula that so far seems to give always the correct matrix:

xf.eM11 = (FLOAT)
-(rect[1].y*plg[2].x+rect[0].y*(plg[1].x-plg[2].x)-rect[2].y*plg[1].x+plg[0].x*(rect[2].y-rect[1].y))
/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);
xf.eM12 = (FLOAT)
-(rect[1].y*(plg[2].y-plg[0].y)+rect[0].y*(plg[1].y-plg[2].y)+rect[2].y*(plg[0].y-plg[1].y))
/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);
xf.eM21 = (FLOAT)
(plg[0].x*(rect[2].x-rect[1].x)-plg[1].x*rect[2].x+plg[2].x*rect[1].x+(plg[1].x-plg[2].x)*rect[0].x)
/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);
xf.eM22 = (FLOAT)
((plg[0].y-plg[1].y)*rect[2].x+(plg[2].y-plg[0].y)*rect[1].x+(plg[1].y-plg[2].y)*rect[0].x)
/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);
xf.eDx = (FLOAT)
-(rect[0].y*(plg[2].x*rect[1].x-plg[1].x*rect[2].x)+plg[0].x*(rect[1].y*rect[2].x-rect[2].y*rect[1].x)+(rect[2].y*plg[1].x-rect[1].y*plg[2].x)*rect[0].x)
/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);
xf.eDy = (FLOAT)
(rect[0].y*(plg[1].y*rect[2].x-plg[2].y*rect[1].x)-rect[1].y*plg[0].y*rect[2].x+rect[2].y*plg[0].y*rect[1].x+(rect[1].y*plg[2].y-rect[2].y*plg[1].y)*rect[0].x)
/(rect[0].y*(rect[2].x-rect[1].x)-rect[1].y*rect[2].x+rect[2].y*rect[1].x+(rect[1].y-rect[2].y)*rect[0].x);


The rect and plg arrays must be of FLOAT points for the formula to work
well, like

struct
{
double x;
double y;
}

Otherwise sometimes the compiler will decide to divide integers.

I found out about the bug by converting the rect points using the XFORM
matrix, and checking that their the same as the plg points.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20091208/66a442b3/attachment.htm>


More information about the wine-devel mailing list