You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
543 lines
17 KiB
543 lines
17 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: xformobj.hxx *
|
|
* *
|
|
* User objects for transforms. *
|
|
* *
|
|
* Created: 13-Sep-1990 14:45:27 *
|
|
* Author: Wendy Wu [wendywu] *
|
|
* *
|
|
* Copyright (c) 1990-1999 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
// These constants are used in the XFORMOBJ constructor.
|
|
|
|
#define COORD_METAFILE 1
|
|
#define COORD_WORLD 2
|
|
#define COORD_PAGE 3
|
|
#define COORD_DEVICE 4
|
|
|
|
#define WORLD_TO_DEVICE ((COORD_WORLD << 8) + COORD_DEVICE)
|
|
#define DEVICE_TO_WORLD ((COORD_DEVICE << 8) + COORD_WORLD)
|
|
|
|
// The exponents of all the coefficients for the various transforms must be
|
|
// within the following ranges:
|
|
//
|
|
// Metafile --
|
|
// |--> -47 <= e <= 48
|
|
// World --
|
|
// |--> -47 <= e <= 48
|
|
// Page --
|
|
// |--> -31 <= e <= 31
|
|
// Device --
|
|
//
|
|
// This will guarantee us a METAFILE_TO_DEVICE transform with
|
|
//
|
|
// -126 <= exponents <= 127
|
|
//
|
|
// for all the coefficients. The ranges are set so that transform coefficients
|
|
// can fit nicely in the IEEE single precision floating point format which has
|
|
// 8-bit exponent field that can hold values from -126 to 127. Note that when
|
|
// the transforms have reached the limits the calculations of inverse transforms
|
|
// might cause overflow.
|
|
|
|
// The max and min values for metafile and world transforms.
|
|
|
|
#define MAX_METAFILE_XFORM_EXP 52
|
|
#define MIN_METAFILE_XFORM_EXP -43
|
|
#define MAX_WORLD_XFORM_EXP MAX_METAFILE_XFORM_EXP
|
|
#define MIN_WORLD_XFORM_EXP MIN_METAFILE_XFORM_EXP
|
|
|
|
#define MAX_METAFILE_XFORM 1024*1024*1024*1024*1024*4 // 2^52
|
|
#define MIN_METAFILE_XFORM 1/(1024*1024*1024*1024*8) // 2^(-43)
|
|
#define MAX_WORLD_XFORM MAX_METAFILE_XFORM
|
|
#define MIN_WORLD_XFORM MIN_METAFILE_XFORM
|
|
|
|
// flag values for matrix.flAccel
|
|
|
|
#define XFORM_SCALE 1 // off-diagonal are 0
|
|
#define XFORM_UNITY 2 // diagonal are 1s, off-diagonal are 0
|
|
// will be set only if XFORM_SCALE is set
|
|
#define XFORM_Y_NEG 4 // M22 is negative. Will be set only if
|
|
// XFORM_SCALE|XFORM_UNITY are set
|
|
#define XFORM_FORMAT_LTOFX 8 // transform from LONG to FIX format
|
|
#define XFORM_FORMAT_FXTOL 16 // transform from FIX to LONG format
|
|
#define XFORM_FORMAT_LTOL 32 // transform from LONG to LONG format
|
|
#define XFORM_NO_TRANSLATION 64 // no translations
|
|
|
|
// These constants are used in the XFORMOBJ constructor.
|
|
|
|
#define IDENTITY 1
|
|
|
|
#define DONT_COMPUTE_FLAGS 0
|
|
#define COMPUTE_FLAGS 1
|
|
#define XFORM_FORMAT (XFORM_FORMAT_LTOFX|XFORM_FORMAT_FXTOL|XFORM_FORMAT_LTOL)
|
|
|
|
|
|
#define BLTOFXOK(x) (((x) < 0x07FFFFFF) && ((x) > -0x07FFFFFF))
|
|
|
|
extern "C" {
|
|
BOOL bCvtPts(PMATRIX pmx, PPOINTL pSrc, PPOINTL pDest, SIZE_T cPts);
|
|
BOOL bCvtPts1(PMATRIX pmx, PPOINTL pptl, SIZE_T cPts);
|
|
BOOL bCvtVts(PMATRIX pmx, PVECTORL pSrc, PVECTORL pDest, SIZE_T cPts);
|
|
BOOL bCvtVts_FlToFl(PMATRIX pmx, PVECTORFL pSrc, PVECTORFL pDest, SIZE_T cPts);
|
|
};
|
|
|
|
extern MATRIX gmxIdentity_LToFx;
|
|
extern MATRIX gmxIdentity_LToL;
|
|
extern MATRIX gmxIdentity_FxToL;
|
|
|
|
VOID vConvertXformToMatrix(CONST XFORML *pxf, PMATRIX pmx);
|
|
|
|
#if DBG
|
|
extern int giXformLevel;
|
|
#define XFORMPRINT(l,s,a) {if (giXformLevel >= l) DbgPrint(s,a);}
|
|
#else
|
|
#define XFORMPRINT(l,s,a)
|
|
#endif
|
|
|
|
/******************************Class***************************************\
|
|
* class EXFORMOBJ *
|
|
* *
|
|
* User object that lets clients interact with transforms. *
|
|
* *
|
|
* History: *
|
|
* 12-Nov-1990 -by- Wendy Wu [wendywu] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
class EXFORMOBJ
|
|
{
|
|
public:
|
|
MATRIX *pmx; // pointer to the matrix
|
|
ULONG ulMode;
|
|
BOOL bMirrored;
|
|
|
|
public:
|
|
|
|
// Constructor
|
|
|
|
EXFORMOBJ() { pmx = (PMATRIX)NULL;
|
|
bMirrored = FALSE;
|
|
}
|
|
|
|
// Constructor - Make the given matrix a transform.
|
|
|
|
EXFORMOBJ(MATRIX& mx) { pmx = &mx;
|
|
bMirrored = FALSE;
|
|
}
|
|
|
|
// Initialize the the xform
|
|
|
|
VOID vInit(MATRIX *pmx_, FLONG fl = DONT_COMPUTE_FLAGS)
|
|
{
|
|
pmx = pmx_;
|
|
|
|
if (fl & COMPUTE_FLAGS) // compute accelerator flags
|
|
{
|
|
vComputeAccelFlags(fl & XFORM_FORMAT);
|
|
}
|
|
else if (fl & XFORM_FORMAT)
|
|
{
|
|
pmx->flAccel = fl;
|
|
}
|
|
}
|
|
|
|
// Constructor - Make a transform object given the pointer to the matrix.
|
|
|
|
EXFORMOBJ(MATRIX *pmx_, FLONG fl)
|
|
{
|
|
pmx = pmx_;
|
|
bMirrored = FALSE;
|
|
|
|
if (fl & COMPUTE_FLAGS) // compute accelerator flags
|
|
{
|
|
vComputeAccelFlags(fl & XFORM_FORMAT);
|
|
}
|
|
else if (fl & XFORM_FORMAT)
|
|
{
|
|
pmx->flAccel = fl;
|
|
}
|
|
}
|
|
|
|
// Constructor - Get a transform matrix based on the request type. The only
|
|
// legitimate type for now is IDENTITY.
|
|
|
|
EXFORMOBJ(ULONG iXform, ULONG iFormat = XFORM_FORMAT_LTOFX);
|
|
|
|
#ifdef _DCOBJ_
|
|
// Constructor - Get a transform from a DC.
|
|
|
|
EXFORMOBJ(XDCOBJ& dco, ULONG iXform) {vQuickInit(dco,iXform);}
|
|
|
|
VOID vQuickInit(XDCOBJ& dco, ULONG iXform)
|
|
{
|
|
ulMode = (ULONG)dco.pdc->iGraphicsMode();
|
|
bMirrored = MIRRORED_DC(dco.pdc);
|
|
|
|
if (!dco.pdc->bDirtyXform() && (iXform == WORLD_TO_DEVICE))
|
|
{
|
|
pmx = &dco.pdc->mxWorldToDevice();
|
|
}
|
|
else
|
|
{
|
|
vInit(dco,iXform);
|
|
}
|
|
}
|
|
|
|
VOID vInit(XDCOBJ &dco, ULONG iXform);
|
|
VOID vInitPageToDevice(XDCOBJ &dco, PMATRIX pmx_);
|
|
#endif
|
|
|
|
// vComputeWtoDAccelFlags - Compute accelerator flags for the world
|
|
// to device xform.
|
|
|
|
VOID vComputeWtoDAccelFlags()
|
|
{
|
|
pmx->flAccel = XFORM_FORMAT_LTOFX; // clear the flag
|
|
|
|
// set translation flag
|
|
|
|
if ((pmx->fxDx == 0) && (pmx->fxDy == 0))
|
|
pmx->flAccel |= XFORM_NO_TRANSLATION;
|
|
|
|
if (pmx->efM12.bIsZero() && pmx->efM21.bIsZero())
|
|
{
|
|
// off diagonal elements are zeros
|
|
|
|
pmx->flAccel |= XFORM_SCALE;
|
|
|
|
if (pmx->efM11.bIs16() && pmx->efM22.bIs16())
|
|
pmx->flAccel |= XFORM_UNITY;
|
|
}
|
|
}
|
|
|
|
// Destructor - Don't need to free anything.
|
|
|
|
~EXFORMOBJ() {}
|
|
|
|
// bValid - Validator.
|
|
|
|
BOOL bValid() { return(pmx != (PMATRIX)NULL); }
|
|
|
|
// vComputeAccelFlags - Compute accelerator flags for a given transform matrix.
|
|
|
|
VOID vComputeAccelFlags(FLONG flFormat = XFORM_FORMAT_LTOFX);
|
|
|
|
// efM11 - Get/set coefficients of the given matrix.
|
|
|
|
EFLOAT& efM11() {return(pmx->efM11);}
|
|
EFLOAT& efM22() {return(pmx->efM22);}
|
|
EFLOAT& efM12() {return(pmx->efM12);}
|
|
EFLOAT& efM21() {return(pmx->efM21);}
|
|
FIX fxDx() {return(pmx->fxDx);}
|
|
FIX fxDy() {return(pmx->fxDy);}
|
|
|
|
VOID vSetElementsLToL (
|
|
EFLOAT ef11,
|
|
EFLOAT ef12,
|
|
EFLOAT ef21,
|
|
EFLOAT ef22
|
|
)
|
|
{
|
|
pmx->efM11 = ef11;
|
|
pmx->efM12 = ef12;
|
|
pmx->efM21 = ef21;
|
|
pmx->efM22 = ef22;
|
|
}
|
|
|
|
VOID vSetElementsLToFx (
|
|
FLOATL l_e11,
|
|
FLOATL l_e12,
|
|
FLOATL l_e21,
|
|
FLOATL l_e22
|
|
)
|
|
{
|
|
pmx->efM11 = l_e11;
|
|
pmx->efM12 = l_e12;
|
|
pmx->efM21 = l_e21;
|
|
pmx->efM22 = l_e22;
|
|
|
|
// Elements in a transform of LTOFX format must be scaled by 16.
|
|
|
|
pmx->efM11.vTimes16();
|
|
pmx->efM12.vTimes16();
|
|
pmx->efM21.vTimes16();
|
|
pmx->efM22.vTimes16();
|
|
}
|
|
|
|
// flAccel - Get the accelerator flag of a given matrix.
|
|
|
|
FLONG flAccel() { return(pmx->flAccel); }
|
|
FLONG flAccel(FLONG fl) { return(pmx->flAccel = fl); }
|
|
|
|
// bEqual - See if two transforms are identical.
|
|
|
|
BOOL bEqual(EXFORMOBJ& xo);
|
|
|
|
// bEqualExceptTranslations - See if two transforms are identical in M11, M12,
|
|
// M21, and M22.
|
|
|
|
BOOL bEqualExceptTranslations(PMATRIX pmx_);
|
|
BOOL bEqualExceptTranslations(EXFORMOBJ& xo)
|
|
{
|
|
return(bEqualExceptTranslations(xo.pmx));
|
|
}
|
|
|
|
// bScale -- See if a the off-diangonal elements of a transform are 0.
|
|
|
|
BOOL bScale() { return(pmx->flAccel & XFORM_SCALE); }
|
|
|
|
// bRotation -- See if there is rotation.
|
|
|
|
BOOL bRotation() { return(!bScale()); }
|
|
|
|
// bRotationOrMirroring -- See if there is a rotation or mirroring (negative
|
|
// diagonal element(s) with 0 off-diagonal elements)
|
|
|
|
BOOL bRotationOrMirroring() { return (bRotation() ||
|
|
(
|
|
!bMirrored &&
|
|
((pmx->efM11.bIsNegative()) || (pmx->efM22.bIsNegative()))
|
|
)); }
|
|
|
|
// bNoTranslation -- See if a transform has translation components.
|
|
|
|
BOOL bNoTranslation() { return(pmx->flAccel & XFORM_NO_TRANSLATION); }
|
|
|
|
// bIdentity - See if a given transform is an identity transform.
|
|
|
|
BOOL bIdentity()
|
|
{
|
|
return((pmx->flAccel &
|
|
(XFORM_SCALE | XFORM_UNITY | XFORM_NO_TRANSLATION)) ==
|
|
(XFORM_SCALE | XFORM_UNITY | XFORM_NO_TRANSLATION));
|
|
}
|
|
|
|
// bTranslationsOnly - no rotations and scaling, translations may possibly
|
|
// be zero
|
|
|
|
BOOL bTranslationsOnly () { return (pmx->flAccel & XFORM_UNITY); }
|
|
|
|
// bConformal -- Does the transform preserve angles?
|
|
// looks at the 2 X 2 transform only
|
|
|
|
BOOL bConformal()
|
|
{
|
|
EFLOAT ef;
|
|
|
|
ef = pmx->efM21;
|
|
ef.vNegate();
|
|
return (pmx->efM11 == pmx->efM22 && pmx->efM12 == ef);
|
|
}
|
|
|
|
// bXform - Apply the transform to various objects. Return FALSE on
|
|
// overflow.
|
|
|
|
// Transform a list of points.
|
|
|
|
BOOL bXform(PPOINTL pptlSrc,PPOINTL pptlDst,SIZE_T cPts);
|
|
BOOL bXform(PPOINTL pSrc, PPOINTFIX pDest, SIZE_T cPts);
|
|
BOOL bXform(PPOINTFIX pSrc, PPOINTL pDest, SIZE_T cPts);
|
|
BOOL bXformRound(PPOINTL pSrc, PPOINTFIX pDest, SIZE_T cPts);
|
|
|
|
// Transform a list of points in place.
|
|
|
|
BOOL bXform(PPOINTL pptl, SIZE_T cPts)
|
|
{
|
|
return(bIdentity() || bCvtPts1(pmx, pptl, cPts));
|
|
}
|
|
|
|
BOOL bXform(EPOINTL& eptl)
|
|
{
|
|
return(bXform((PPOINTL) &eptl, 1));
|
|
}
|
|
|
|
BOOL bXform(ERECTL& ercl)
|
|
{
|
|
BOOL bRet;
|
|
|
|
bRet = bXform((PPOINTL) &ercl, 2);
|
|
// If it a mirrored DC then shift the rect one pixel to the right
|
|
// This will give the effect of including the right edge of the rect and exclude the left edge.
|
|
if (bMirrored) {
|
|
++ercl.left;
|
|
++ercl.right;
|
|
}
|
|
return (bRet);
|
|
}
|
|
|
|
// Transform a list of vectors.
|
|
|
|
BOOL bXform(PVECTORFL pvtflSrc, PVECTORFL pvtflDst,SIZE_T cVts);
|
|
BOOL bXform(PVECTORL pSrc, PVECTORFX pDest, SIZE_T cVts);
|
|
BOOL bXform(PVECTORL pSrc, PVECTORL pDest, SIZE_T cVts);
|
|
BOOL bXform(PVECTORFX pSrc, PVECTORL pDest, SIZE_T cVts);
|
|
BOOL bXformRound(PVECTORL pSrc, PVECTORFX pDest, SIZE_T cVts);
|
|
|
|
// Transform a list of vectors in place.
|
|
|
|
BOOL bXform(PVECTORFL pvtfl, SIZE_T cVts)
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
|
|
if (!bTranslationsOnly())
|
|
bReturn = bXform(pvtfl, pvtfl, cVts);
|
|
|
|
return(bReturn);
|
|
}
|
|
|
|
BOOL bXform(EVECTORFL& evtfl)
|
|
{
|
|
return(bXform((PVECTORFL) &evtfl, 1));
|
|
}
|
|
|
|
BOOL bXform(EVECTORL& evtl)
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
|
|
if (!bTranslationsOnly())
|
|
bReturn = bXform((PVECTORL)&evtl, (PVECTORL)&evtl, 1);
|
|
|
|
return(bReturn);
|
|
}
|
|
|
|
// bMultiply - Multiply two XFORMs together and store the result in the
|
|
// XFORMOBJ.
|
|
|
|
BOOL bMultiply(PMATRIX pmxLeft, PMATRIX pmxRight,
|
|
FLONG fl = DONT_COMPUTE_FLAGS);
|
|
BOOL bMultiply(EXFORMOBJ& exoLeft, EXFORMOBJ& exoRight,
|
|
FLONG fl = DONT_COMPUTE_FLAGS)
|
|
{
|
|
return(bMultiply(exoLeft.pmx, exoRight.pmx, fl));
|
|
}
|
|
|
|
// bMultToWorld - Multiply the world transform with a given matrix. The
|
|
// result is stored in the passed in matrix. This is so
|
|
// that the resultant matrix can be range-checked later on
|
|
// before the WORLD_TO_PAGE xform is changed.
|
|
// The order of the multiplication is based on imode.
|
|
// If imode == MWT_LEFTMULTIPLY, the given matrix is applied
|
|
// to the left of the multiplication. It's applied to the
|
|
// right otherwise.
|
|
|
|
BOOL bMultToWorld(MATRIX *pmx_, ULONG imode)
|
|
{
|
|
MATRIX mx = *pmx_;
|
|
EXFORMOBJ xo(pmx_, DONT_COMPUTE_FLAGS);
|
|
|
|
if (imode == MWT_LEFTMULTIPLY)
|
|
return(xo.bMultiply(&mx, pmx));
|
|
else
|
|
return(xo.bMultiply(pmx, &mx));
|
|
}
|
|
|
|
// vRemoveTranslation - Remove the translation coefficients from a matrix.
|
|
|
|
VOID vRemoveTranslation();
|
|
|
|
// vGetCoefficient - Get the coefficients of a transform matrix. This is
|
|
// used to convert our internal matrix structure into
|
|
// the GDI/DDI transform format.
|
|
|
|
VOID vGetCoefficient(PFLOATOBJ_XFORM pxf);
|
|
|
|
// vGetCoefficient - Get the coefficients of a transform matrix. This is
|
|
// used to convert our internal matrix structure into
|
|
// the GDI/DDI transform format.
|
|
|
|
VOID vGetCoefficient(XFORML *pxf);
|
|
|
|
// vGetCoefficient - Get the coefficients of a transform matrix. This is
|
|
// used to convert our internal matrix structure into
|
|
// the IFI transform format.
|
|
|
|
VOID vGetCoefficient(PFD_XFORM pxf);
|
|
|
|
// vSetScaling - Set the scaling factors for a given matrix.
|
|
|
|
VOID vSetScaling(EFLOAT efM11, EFLOAT efM22,
|
|
FLONG fl = DONT_COMPUTE_FLAGS)
|
|
{
|
|
ASSERTGDI(pmx->efM12.bIsZero(), "vSetScaling error: M12 not zero");
|
|
ASSERTGDI(pmx->efM21.bIsZero(), "vSetScaling error: M21 not zero");
|
|
|
|
pmx->efM11 = efM11;
|
|
pmx->efM22 = efM22;
|
|
|
|
if (fl & COMPUTE_FLAGS)
|
|
vComputeAccelFlags(fl & XFORM_FORMAT);
|
|
}
|
|
|
|
// vSetTranslations - Set the translations for a given matrix.
|
|
|
|
VOID vSetTranslations(EFLOAT efDx, EFLOAT efDy)
|
|
{
|
|
FIX fxDx, fxDy;
|
|
|
|
pmx->efDx = efDx;
|
|
pmx->efDy = efDy;
|
|
|
|
#if DBG
|
|
if (!efDx.bEfToL(fxDx))
|
|
WARNING("vSetTranslations:dx overflowed\n");
|
|
if (!efDy.bEfToL(fxDy))
|
|
WARNING("vSetTranslations:dy overflowed\n");
|
|
#else
|
|
efDx.bEfToL(fxDx);
|
|
efDy.bEfToL(fxDy);
|
|
#endif
|
|
pmx->fxDx = fxDx;
|
|
pmx->fxDy = fxDy;
|
|
|
|
if ((fxDx == 0) && (fxDy == 0))
|
|
pmx->flAccel |= XFORM_NO_TRANSLATION;
|
|
else
|
|
pmx->flAccel &= ~(XFORM_NO_TRANSLATION);
|
|
}
|
|
|
|
// vSet - Set the coefficients for a given matrix.
|
|
// This is used to set WorldToPage transform.
|
|
|
|
VOID vSet(MATRIX *pmx_, FLONG fl = DONT_COMPUTE_FLAGS)
|
|
{
|
|
*pmx = *pmx_;
|
|
|
|
if (fl & COMPUTE_FLAGS)
|
|
vComputeAccelFlags(fl & XFORM_FORMAT);
|
|
}
|
|
|
|
// vCopy -- Copy a transform obj to another.
|
|
|
|
VOID vCopy(EXFORMOBJ& xoSrc);
|
|
|
|
// vOrder -- Order a rectangle based on the PAGE_TO_DEVICE transform.
|
|
// The rectangle will be well ordered after the PAGE_TO_DEVICE
|
|
// transform is applied.
|
|
|
|
VOID vOrder(RECTL &rcl);
|
|
|
|
// bInverse -- Calculate the inverse of a passed in xform/matrix and store
|
|
// the result in the XFORMOBJ. The source and destination
|
|
// matrices CANNOT be the same one.
|
|
|
|
BOOL bInverse(MATRIX& mxSrc);
|
|
BOOL bInverse(EXFORMOBJ& xo) { return(bInverse(*(xo.pmx))); }
|
|
|
|
|
|
|
|
// bComputeUnits -- Calculates a simplified transform for vectors parallel
|
|
// to the given angle.
|
|
|
|
BOOL bComputeUnits(LONG lAngle,POINTFL *ppte,EFLOAT *pefWD,EFLOAT *pefDW);
|
|
|
|
// fxFastX -- Does a quick scaling transform on x.
|
|
|
|
FIX fxFastX(LONG ll) {return((FIX) lCvt(pmx->efM11,ll) + pmx->fxDx);}
|
|
|
|
// fxFastY -- Does a quick scaling transform on y.
|
|
|
|
FIX fxFastY(LONG ll) {return((FIX) lCvt(pmx->efM22,ll) + pmx->fxDy);}
|
|
};
|
|
|
|
typedef EXFORMOBJ *PEXFORMOBJ;
|