Leaked source code of windows server 2003
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
16 KiB

/***************************************************************************\
*
* File: Matrix.cpp
*
* Description:
* Matrix.cpp implements common Matrix and Vector operations.
*
*
* History:
* 3/25/2000: JStall: Created
*
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
*
\***************************************************************************/
#include "stdafx.h"
#include "Base.h"
#include "Matrix.h"
#include "Rect.h"
/***************************************************************************\
*****************************************************************************
*
* class Vector3
*
*****************************************************************************
\***************************************************************************/
#if DBG
//------------------------------------------------------------------------------
void
Vector3::Dump() const
{
Trace(" | %6.2f, %6.2f, %6.2f |\n", m_rgfl[0], m_rgfl[1], m_rgfl[2]);
}
#endif // DBG
/***************************************************************************\
*****************************************************************************
*
* class Matrix3
*
*****************************************************************************
\***************************************************************************/
/*
//
// Standard multiplication of A by the current Matrix. This can be used
// as a template to be optimized for different cases.
//
Vector3 rgvT0 = m_rgv[0];
Vector3 rgvT1 = m_rgv[1];
Vector3 rgvT2 = m_rgv[2];
m_rgv[0].Set(A[0][0] * rgvT0[0] + A[0][1] * rgvT1[0] + A[0][2] * rgvT2[0],
A[0][0] * rgvT0[1] + A[0][1] * rgvT1[1] + A[0][2] * rgvT2[1],
A[0][0] * rgvT0[2] + A[0][1] * rgvT1[2] + A[0][2] * rgvT2[2]);
m_rgv[1].Set(A[1][0] * rgvT0[0] + A[1][1] * rgvT1[0] + A[1][2] * rgvT2[0],
A[1][0] * rgvT0[1] + A[1][1] * rgvT1[1] + A[1][2] * rgvT2[1],
A[1][0] * rgvT0[2] + A[1][1] * rgvT1[2] + A[1][2] * rgvT2[2]);
m_rgv[2].Set(A[2][0] * rgvT0[0] + A[2][1] * rgvT1[0] + A[2][2] * rgvT2[0],
A[2][0] * rgvT0[1] + A[2][1] * rgvT1[1] + A[2][2] * rgvT2[1],
A[2][0] * rgvT0[2] + A[2][1] * rgvT1[2] + A[2][2] * rgvT2[2]);
*/
/***************************************************************************\
*
* Matrix3::ApplyLeft
*
* ApplyLeft() left-multiples the given GDI matrix to the current matrix and
* stores the result in the current matrix.
*
* mCurrent = pxfLeft * mCurrent
*
\***************************************************************************/
void
Matrix3::ApplyLeft(
IN const XFORM * pxfLeft) // GDI matrix to left-multiply
{
const XFORM * pxf = pxfLeft;
Vector3 rgvT0 = m_rgv[0];
Vector3 rgvT1 = m_rgv[1];
Vector3 rgvT2 = m_rgv[2];
m_rgv[0].Set(pxf->eM11 * rgvT0[0] + pxf->eM12 * rgvT1[0],
pxf->eM11 * rgvT0[1] + pxf->eM12 * rgvT1[1],
pxf->eM11 * rgvT0[2] + pxf->eM12 * rgvT1[2]);
m_rgv[1].Set(pxf->eM21 * rgvT0[0] + pxf->eM22 * rgvT1[0],
pxf->eM21 * rgvT0[1] + pxf->eM22 * rgvT1[1],
pxf->eM21 * rgvT0[2] + pxf->eM22 * rgvT1[2]);
m_rgv[2].Set(pxf->eDx * rgvT0[0] + pxf->eDy * rgvT1[0] + rgvT2[0],
pxf->eDx * rgvT0[1] + pxf->eDy * rgvT1[1] + rgvT2[1],
pxf->eDx * rgvT0[2] + pxf->eDy * rgvT1[2] + rgvT2[2]);
m_fIdentity = FALSE;
m_fOnlyTranslate = FALSE;
}
/***************************************************************************\
*
* Matrix3::ApplyLeft
*
* ApplyLeft() left-multiples the given matrix to the current matrix and
* stores the result in the current matrix.
*
* mCurrent = mLeft * mCurrent
*
\***************************************************************************/
void
Matrix3::ApplyLeft(
IN const Matrix3 & mLeft) // Matrix to left-multiply
{
if (mLeft.m_fIdentity) {
return;
}
if (m_fOnlyTranslate && mLeft.m_fOnlyTranslate) {
m_rgv[2].Set(0, m_rgv[2][0] + mLeft.m_rgv[2][0]);
m_rgv[2].Set(1, m_rgv[2][1] + mLeft.m_rgv[2][1]);
m_fIdentity = FALSE;
return;
}
const Vector3 & A0 = mLeft.m_rgv[0];
const Vector3 & A1 = mLeft.m_rgv[1];
const Vector3 & A2 = mLeft.m_rgv[2];
Vector3 B0 = m_rgv[0];
Vector3 B1 = m_rgv[1];
Vector3 B2 = m_rgv[2];
m_rgv[0].Set(A0[0] * B0[0] + A0[1] * B1[0] + A0[2] * B2[0],
A0[0] * B0[1] + A0[1] * B1[1] + A0[2] * B2[1],
A0[0] * B0[2] + A0[1] * B1[2] + A0[2] * B2[2]);
m_rgv[1].Set(A1[0] * B0[0] + A1[1] * B1[0] + A1[2] * B2[0],
A1[0] * B0[1] + A1[1] * B1[1] + A1[2] * B2[1],
A1[0] * B0[2] + A1[1] * B1[2] + A1[2] * B2[2]);
m_rgv[2].Set(A2[0] * B0[0] + A2[1] * B1[0] + A2[2] * B2[0],
A2[0] * B0[1] + A2[1] * B1[1] + A2[2] * B2[1],
A2[0] * B0[2] + A2[1] * B1[2] + A2[2] * B2[2]);
m_fIdentity = FALSE;
m_fOnlyTranslate = FALSE;
}
/***************************************************************************\
*
* Matrix3::ApplyRight
*
* ApplyRight() right-multiples the given matrix to the current matrix and
* stores the result in the current matrix.
*
* mCurrent = mCurrent * mRight
*
\***************************************************************************/
void
Matrix3::ApplyRight(
IN const Matrix3 & mRight) // Matrix to right-multiply
{
if (mRight.m_fIdentity) {
return;
}
if (m_fOnlyTranslate && mRight.m_fOnlyTranslate) {
m_rgv[2].Set(0, m_rgv[2][0] + mRight.m_rgv[2][0]);
m_rgv[2].Set(1, m_rgv[2][1] + mRight.m_rgv[2][1]);
m_fIdentity = FALSE;
return;
}
Vector3 A0 = m_rgv[0];
Vector3 A1 = m_rgv[1];
Vector3 A2 = m_rgv[2];
const Vector3 & B0 = mRight.m_rgv[0];
const Vector3 & B1 = mRight.m_rgv[1];
const Vector3 & B2 = mRight.m_rgv[2];
m_rgv[0].Set(A0[0] * B0[0] + A0[1] * B1[0] + A0[2] * B2[0],
A0[0] * B0[1] + A0[1] * B1[1] + A0[2] * B2[1],
A0[0] * B0[2] + A0[1] * B1[2] + A0[2] * B2[2]);
m_rgv[1].Set(A1[0] * B0[0] + A1[1] * B1[0] + A1[2] * B2[0],
A1[0] * B0[1] + A1[1] * B1[1] + A1[2] * B2[1],
A1[0] * B0[2] + A1[1] * B1[2] + A1[2] * B2[2]);
m_rgv[2].Set(A2[0] * B0[0] + A2[1] * B1[0] + A2[2] * B2[0],
A2[0] * B0[1] + A2[1] * B1[1] + A2[2] * B2[1],
A2[0] * B0[2] + A2[1] * B1[2] + A2[2] * B2[2]);
m_fIdentity = FALSE;
m_fOnlyTranslate = FALSE;
}
/***************************************************************************\
*
* Matrix3::ApplyRight
*
* ApplyRight() right-multiples the given matrix to the current matrix and
* stores the result in the current matrix.
*
\***************************************************************************/
void
Matrix3::Get(
OUT XFORM * pxf // GDI matrix to receive information
) const
{
pxf->eM11 = m_rgv[0][0];
pxf->eM12 = m_rgv[0][1];
pxf->eM21 = m_rgv[1][0];
pxf->eM22 = m_rgv[1][1];
pxf->eDx = m_rgv[2][0];
pxf->eDy = m_rgv[2][1];
}
/***************************************************************************\
*
* Matrix3::Execute
*
* Execute() applies to given matrix on the collection of points,
* transforming each appropriately.
*
\***************************************************************************/
void
Matrix3::Execute(
IN OUT POINT * rgpt, // Points to apply matrix on
IN int cPoints) const // Number of points
{
if (m_fIdentity) {
return;
}
POINT ptT, ptN;
POINT * pptCur = rgpt;
if (m_fOnlyTranslate) {
//
// Only have translated so far, so can just offset the points without
// going through an entire transformation.
//
while (cPoints-- > 0) {
ptT = *pptCur;
ptN.x = ptT.x + (int) m_rgv[2][0];
ptN.y = ptT.y + (int) m_rgv[2][1];
*pptCur++ = ptN;
}
} else {
while (cPoints-- > 0) {
ptT = *pptCur;
ptN.x = (int) (ptT.x * m_rgv[0][0] + ptT.y * m_rgv[1][0] + m_rgv[2][0] + 0.5f);
ptN.y = (int) (ptT.x * m_rgv[0][1] + ptT.y * m_rgv[1][1] + m_rgv[2][1] + 0.5f);
*pptCur++ = ptN;
}
}
}
/***************************************************************************\
*
* Matrix3::ComputeBounds
*
* ComputeBounds() computes the bounding box that will contain the given
* transformed rectangle.
*
\***************************************************************************/
void
Matrix3::ComputeBounds(
OUT RECT * prcBounds, // The bound of the transformation
IN const RECT * prcLogical, // The logical rectangle to transform
IN EHintBounds hb // Hinting for border pixels
) const
{
if (m_fIdentity) {
AssertMsg(InlineIsRectNormalized(prcLogical), "Ensure normalized rect");
*prcBounds = *prcLogical;
return;
}
if (m_fOnlyTranslate) {
//
// Only have translated, so the bounding
//
AssertMsg(InlineIsRectNormalized(prcLogical), "Ensure normalized rect");
*prcBounds = *prcLogical;
InlineOffsetRect(prcBounds, (int) m_rgv[2][0], (int) m_rgv[2][1]);
return;
}
POINT rgpt[4];
rgpt[0].x = prcLogical->left;
rgpt[0].y = prcLogical->top;
rgpt[1].x = prcLogical->right;
rgpt[1].y = prcLogical->top;
rgpt[2].x = prcLogical->right;
rgpt[2].y = prcLogical->bottom;
rgpt[3].x = prcLogical->left;
rgpt[3].y = prcLogical->bottom;
Execute(rgpt, _countof(rgpt));
prcBounds->left = min(min(rgpt[0].x, rgpt[1].x), min(rgpt[2].x, rgpt[3].x));
prcBounds->top = min(min(rgpt[0].y, rgpt[1].y), min(rgpt[2].y, rgpt[3].y));
prcBounds->right = max(max(rgpt[0].x, rgpt[1].x), max(rgpt[2].x, rgpt[3].x));
prcBounds->bottom = max(max(rgpt[0].y, rgpt[1].y), max(rgpt[2].y, rgpt[3].y));
if (hb == hbOutside) {
//
// Just converted from int to float back to int, so we may have rounding
// errors. To compensate, need to inflate the given rectangle so that
// it overlaps these errors.
//
InlineInflateRect(prcBounds, 1, 1);
}
}
/***************************************************************************\
*
* Matrix3::ComputeRgn
*
* ComputeRgn() builds a region for the quadrilateral generated by applying
* this matrix to the given rectangle.
*
\***************************************************************************/
int
Matrix3::ComputeRgn(
IN HRGN hrgnDest,
IN const RECT * prcLogical,
IN SIZE sizeOffsetPxl
) const
{
AssertMsg(hrgnDest != NULL, "Must specify a valid (real) region");
if (m_fIdentity || m_fOnlyTranslate){
AssertMsg(InlineIsRectNormalized(prcLogical), "Ensure normalized rect");
RECT rcBounds = *prcLogical;
InlineOffsetRect(&rcBounds,
((int) m_rgv[2][0]) + sizeOffsetPxl.cx,
((int) m_rgv[2][1]) + sizeOffsetPxl.cy);
BOOL fSuccess = SetRectRgn(hrgnDest, rcBounds.left, rcBounds.top, rcBounds.right, rcBounds.bottom);
return fSuccess ? SIMPLEREGION : ERROR;
}
POINT rgpt[4];
rgpt[0].x = prcLogical->left;
rgpt[0].y = prcLogical->top;
rgpt[1].x = prcLogical->right;
rgpt[1].y = prcLogical->top;
rgpt[2].x = prcLogical->right;
rgpt[2].y = prcLogical->bottom;
rgpt[3].x = prcLogical->left;
rgpt[3].y = prcLogical->bottom;
Execute(rgpt, _countof(rgpt));
HRGN hrgnTemp = CreatePolygonRgn(rgpt, _countof(rgpt), WINDING);
if (hrgnTemp == NULL) {
return ERROR;
}
int nResult;
nResult = OffsetRgn(hrgnTemp, sizeOffsetPxl.cx, sizeOffsetPxl.cy);
AssertMsg((nResult == SIMPLEREGION) || (nResult == COMPLEXREGION),
"Just successfully created region should be either simple or complex");
nResult = CombineRgn(hrgnDest, hrgnTemp, NULL, RGN_COPY);
DeleteObject(hrgnTemp);
return nResult;
}
/***************************************************************************\
*
* Matrix3::SetIdentity
*
* SetIdentity() resets the matrix to the identity matrix.
*
\***************************************************************************/
void
Matrix3::SetIdentity()
{
m_rgv[0].Set(1.0f, 0.0f, 0.0f);
m_rgv[1].Set(0.0f, 1.0f, 0.0f);
m_rgv[2].Set(0.0f, 0.0f, 1.0f);
m_fIdentity = TRUE;
m_fOnlyTranslate = TRUE;
}
/***************************************************************************\
*
* Matrix3::Rotate
*
* Rotate() rotates the matrix by the specified angle. The specific
* orientation of clockwise or counterclockwise depends on how the matrix
* is being applied. For MM_TEXT, this is clockwise.
*
\***************************************************************************/
void
Matrix3::Rotate(
IN float flRotationRad) // Rotation angle in radians
{
float flCos = (float) cos(flRotationRad);
float flSin = (float) sin(flRotationRad);
float flSinN = - flSin;
Vector3 rgvT0 = m_rgv[0];
Vector3 rgvT1 = m_rgv[1];
Vector3 rgvT2 = m_rgv[2];
m_rgv[0].Set(flCos * rgvT0[0] + flSin * rgvT1[0],
flCos * rgvT0[1] + flSin * rgvT1[1],
flCos * rgvT0[2] + flSin * rgvT1[2]);
m_rgv[1].Set(flSinN * rgvT0[0] + flCos * rgvT1[0],
flSinN * rgvT0[1] + flCos * rgvT1[1],
flSinN * rgvT0[2] + flCos * rgvT1[2]);
m_fIdentity = FALSE;
m_fOnlyTranslate = FALSE;
}
/***************************************************************************\
*
* Matrix3::Translate
*
* Translate() offsets the matrix.
*
\***************************************************************************/
void
Matrix3::Translate(
IN float flOffsetX, // Horizontal offset
IN float flOffsetY) // Vertical offset
{
if (m_fOnlyTranslate) {
AssertMsg(fabs(m_rgv[2][2] - 1.0f) < 0.00001f, "Should still be 1.0f");
m_rgv[2].Set(m_rgv[2][0] + flOffsetX,
m_rgv[2][1] + flOffsetY,
1.0f);
m_fIdentity = FALSE;
return;
}
Vector3 rgvT0 = m_rgv[0];
Vector3 rgvT1 = m_rgv[1];
Vector3 rgvT2 = m_rgv[2];
m_rgv[2].Set(flOffsetX * rgvT0[0] + flOffsetY * rgvT1[0] + rgvT2[0],
flOffsetX * rgvT0[1] + flOffsetY * rgvT1[1] + rgvT2[1],
flOffsetX * rgvT0[2] + flOffsetY * rgvT1[2] + rgvT2[2]);
m_fIdentity = FALSE;
}
/***************************************************************************\
*
* Matrix3::Scale
*
* Scale() scales the matrix.
*
\***************************************************************************/
void
Matrix3::Scale(
IN float flScaleX, // Horizontal scaling
IN float flScaleY) // Vertical scaling
{
Vector3 rgvT0 = m_rgv[0];
Vector3 rgvT1 = m_rgv[1];
Vector3 rgvT2 = m_rgv[2];
m_rgv[0].Set(flScaleX * rgvT0[0],
flScaleX * rgvT0[1],
flScaleX * rgvT0[2]);
m_rgv[1].Set(flScaleY * rgvT1[0],
flScaleY * rgvT1[1],
flScaleY * rgvT1[2]);
m_fIdentity = FALSE;
m_fOnlyTranslate = FALSE;
}
#if DBG
//------------------------------------------------------------------------------
void
Matrix3::Dump() const
{
m_rgv[0].Dump();
m_rgv[1].Dump();
m_rgv[2].Dump();
}
#endif // DBG