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.
401 lines
16 KiB
401 lines
16 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: helxfrm.c
|
|
* Content: Direct3D front-end transform and process vertices
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#include "light.h"
|
|
|
|
void MatrixProduct2(D3DMATRIXI *result, D3DMATRIXI *a, D3DMATRIXI *b);
|
|
|
|
D3DFE_PVFUNCS GeometryFuncsGuaranteed; // Our implementation
|
|
|
|
//---------------------------------------------------------------------
|
|
void CheckWorldViewMatrix(LPD3DFE_PROCESSVERTICES pv)
|
|
{
|
|
D3DMATRIXI *m = &pv->mWV;
|
|
D3DMATRIXI res;
|
|
res._11 = m->_11*m->_11 + m->_12*m->_12 + m->_13*m->_13;
|
|
res._12 = m->_11*m->_21 + m->_12*m->_22 + m->_13*m->_23;
|
|
res._13 = m->_11*m->_31 + m->_12*m->_32 + m->_13*m->_33;
|
|
|
|
res._21 = m->_21*m->_11 + m->_22*m->_12 + m->_23*m->_13;
|
|
res._22 = m->_21*m->_21 + m->_22*m->_22 + m->_23*m->_23;
|
|
res._23 = m->_21*m->_31 + m->_22*m->_32 + m->_23*m->_33;
|
|
|
|
res._31 = m->_31*m->_11 + m->_32*m->_12 + m->_33*m->_13;
|
|
res._32 = m->_31*m->_21 + m->_32*m->_22 + m->_33*m->_23;
|
|
res._33 = m->_31*m->_31 + m->_32*m->_32 + m->_33*m->_33;
|
|
|
|
const D3DVALUE eps = 0.0001f;
|
|
if (m->_14 == 0.0f &&
|
|
m->_24 == 0.0f &&
|
|
m->_34 == 0.0f &&
|
|
m->_44 == 1.0f &&
|
|
ABSF(res._12) < eps &&
|
|
ABSF(res._13) < eps &&
|
|
ABSF(res._21) < eps &&
|
|
ABSF(res._23) < eps &&
|
|
ABSF(res._31) < eps &&
|
|
ABSF(res._32) < eps &&
|
|
ABSF(1.0f - res._11) < eps &&
|
|
ABSF(1.0f - res._22) < eps &&
|
|
ABSF(1.0f - res._33) < eps)
|
|
{
|
|
pv->dwDeviceFlags |= D3DDEV_MODELSPACELIGHTING;
|
|
}
|
|
else
|
|
{
|
|
pv->dwDeviceFlags &= ~D3DDEV_MODELSPACELIGHTING;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void setIdentity(D3DMATRIXI * m)
|
|
{
|
|
m->_11 = D3DVAL(1.0); m->_12 = D3DVAL(0.0); m->_13 = D3DVAL(0.0); m->_14 = D3DVAL(0.0);
|
|
m->_21 = D3DVAL(0.0); m->_22 = D3DVAL(1.0); m->_23 = D3DVAL(0.0); m->_24 = D3DVAL(0.0);
|
|
m->_31 = D3DVAL(0.0); m->_32 = D3DVAL(0.0); m->_33 = D3DVAL(1.0); m->_34 = D3DVAL(0.0);
|
|
m->_41 = D3DVAL(0.0); m->_42 = D3DVAL(0.0); m->_43 = D3DVAL(0.0); m->_44 = D3DVAL(1.0);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
/*
|
|
* Combine all matrices.
|
|
*/
|
|
const DWORD __VPC_DIRTY = D3DFE_VIEWMATRIX_DIRTY |
|
|
D3DFE_PROJMATRIX_DIRTY;
|
|
|
|
void updateTransform(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
D3DFE_VIEWPORTCACHE& VPORT = lpDevI->vcache;
|
|
D3DFE_TRANSFORM& TRANSFORM = lpDevI->transform;
|
|
if (lpDevI->dwFEFlags & D3DFE_PROJMATRIX_DIRTY)
|
|
{
|
|
// We modify the projection matrix to make the clipping rules to be
|
|
// 0 < x,y,z < w
|
|
TRANSFORM.mPC._11 = (TRANSFORM.proj._11 + TRANSFORM.proj._14) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._12 = (TRANSFORM.proj._12 + TRANSFORM.proj._14) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._13 = TRANSFORM.proj._13;
|
|
TRANSFORM.mPC._14 = TRANSFORM.proj._14;
|
|
TRANSFORM.mPC._21 = (TRANSFORM.proj._21 + TRANSFORM.proj._24) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._22 = (TRANSFORM.proj._22 + TRANSFORM.proj._24) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._23 = TRANSFORM.proj._23;
|
|
TRANSFORM.mPC._24 = TRANSFORM.proj._24;
|
|
TRANSFORM.mPC._31 = (TRANSFORM.proj._31 + TRANSFORM.proj._34) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._32 = (TRANSFORM.proj._32 + TRANSFORM.proj._34) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._33 = TRANSFORM.proj._33;
|
|
TRANSFORM.mPC._34 = TRANSFORM.proj._34;
|
|
TRANSFORM.mPC._41 = (TRANSFORM.proj._41 + TRANSFORM.proj._44) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._42 = (TRANSFORM.proj._42 + TRANSFORM.proj._44) * D3DVAL(0.5);
|
|
TRANSFORM.mPC._43 = TRANSFORM.proj._43;
|
|
TRANSFORM.mPC._44 = TRANSFORM.proj._44;
|
|
}
|
|
if (lpDevI->dwFEFlags & (D3DFE_VIEWMATRIX_DIRTY |
|
|
D3DFE_PROJMATRIX_DIRTY))
|
|
{ // Update Mview*Mproj*Mclip
|
|
MatrixProduct(&TRANSFORM.mVPC, &TRANSFORM.view, &TRANSFORM.mPC);
|
|
lpDevI->dwFEFlags |= D3DFE_CLIPMATRIX_DIRTY | D3DFE_CLIPPLANES_DIRTY;
|
|
}
|
|
|
|
MatrixProduct(&lpDevI->mCTM, &TRANSFORM.world[0], &TRANSFORM.mVPC);
|
|
|
|
// Set dirty bit for world*view matrix (needed for fog and lighting)
|
|
if (lpDevI->dwFEFlags & (D3DFE_VIEWMATRIX_DIRTY |
|
|
D3DFE_WORLDMATRIX_DIRTY |
|
|
D3DFE_WORLDMATRIX1_DIRTY |
|
|
D3DFE_WORLDMATRIX2_DIRTY |
|
|
D3DFE_WORLDMATRIX3_DIRTY))
|
|
{
|
|
lpDevI->dwFEFlags |= D3DFE_WORLDVIEWMATRIX_DIRTY |
|
|
D3DFE_INVWORLDVIEWMATRIX_DIRTY |
|
|
D3DFE_NEEDCHECKWORLDVIEWVMATRIX;
|
|
}
|
|
|
|
if (lpDevI->dwFEFlags & (__VPC_DIRTY |
|
|
D3DFE_WORLDMATRIX1_DIRTY |
|
|
D3DFE_WORLDMATRIX2_DIRTY |
|
|
D3DFE_WORLDMATRIX3_DIRTY))
|
|
{
|
|
if (lpDevI->dwFEFlags & (__VPC_DIRTY | D3DFE_WORLDMATRIX1_DIRTY))
|
|
{
|
|
MatrixProduct(&lpDevI->mCTM2[0], &TRANSFORM.world[1], &TRANSFORM.mVPC);
|
|
}
|
|
if (lpDevI->dwFEFlags & (__VPC_DIRTY | D3DFE_WORLDMATRIX2_DIRTY))
|
|
{
|
|
MatrixProduct(&lpDevI->mCTM2[1], &TRANSFORM.world[2], &TRANSFORM.mVPC);
|
|
}
|
|
if (lpDevI->dwFEFlags & (__VPC_DIRTY | D3DFE_WORLDMATRIX3_DIRTY))
|
|
{
|
|
MatrixProduct(&lpDevI->mCTM2[2], &TRANSFORM.world[3], &TRANSFORM.mVPC);
|
|
}
|
|
}
|
|
|
|
// All matrices are set up
|
|
lpDevI->dwFEFlags &= ~D3DFE_TRANSFORM_DIRTY;
|
|
|
|
// Set dirty bit for lighting
|
|
lpDevI->dwFEFlags |= D3DFE_NEED_TRANSFORM_LIGHTS |
|
|
D3DFE_FRUSTUMPLANES_DIRTY;
|
|
|
|
lpDevI->dwDeviceFlags |= D3DDEV_TRANSFORMDIRTY;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#define MATRIX_PRODUCT(res, a, b) \
|
|
res->_11 = a->_11*b->_11 + a->_12*b->_21 + a->_13*b->_31 + a->_14*b->_41; \
|
|
res->_12 = a->_11*b->_12 + a->_12*b->_22 + a->_13*b->_32 + a->_14*b->_42; \
|
|
res->_13 = a->_11*b->_13 + a->_12*b->_23 + a->_13*b->_33 + a->_14*b->_43; \
|
|
res->_14 = a->_11*b->_14 + a->_12*b->_24 + a->_13*b->_34 + a->_14*b->_44; \
|
|
\
|
|
res->_21 = a->_21*b->_11 + a->_22*b->_21 + a->_23*b->_31 + a->_24*b->_41; \
|
|
res->_22 = a->_21*b->_12 + a->_22*b->_22 + a->_23*b->_32 + a->_24*b->_42; \
|
|
res->_23 = a->_21*b->_13 + a->_22*b->_23 + a->_23*b->_33 + a->_24*b->_43; \
|
|
res->_24 = a->_21*b->_14 + a->_22*b->_24 + a->_23*b->_34 + a->_24*b->_44; \
|
|
\
|
|
res->_31 = a->_31*b->_11 + a->_32*b->_21 + a->_33*b->_31 + a->_34*b->_41; \
|
|
res->_32 = a->_31*b->_12 + a->_32*b->_22 + a->_33*b->_32 + a->_34*b->_42; \
|
|
res->_33 = a->_31*b->_13 + a->_32*b->_23 + a->_33*b->_33 + a->_34*b->_43; \
|
|
res->_34 = a->_31*b->_14 + a->_32*b->_24 + a->_33*b->_34 + a->_34*b->_44; \
|
|
\
|
|
res->_41 = a->_41*b->_11 + a->_42*b->_21 + a->_43*b->_31 + a->_44*b->_41; \
|
|
res->_42 = a->_41*b->_12 + a->_42*b->_22 + a->_43*b->_32 + a->_44*b->_42; \
|
|
res->_43 = a->_41*b->_13 + a->_42*b->_23 + a->_43*b->_33 + a->_44*b->_43; \
|
|
res->_44 = a->_41*b->_14 + a->_42*b->_24 + a->_43*b->_34 + a->_44*b->_44;
|
|
//---------------------------------------------------------------------
|
|
// result = a*b.
|
|
// "result" pointer could be equal to "a" or "b"
|
|
//
|
|
void MatrixProduct(D3DMATRIXI *result, D3DMATRIXI *a, D3DMATRIXI *b)
|
|
{
|
|
if (result == a || result == b)
|
|
{
|
|
MatrixProduct2(result, a, b);
|
|
return;
|
|
}
|
|
MATRIX_PRODUCT(result, a, b);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// result = a*b
|
|
// result is the same as a or b
|
|
//
|
|
void MatrixProduct2(D3DMATRIXI *result, D3DMATRIXI *a, D3DMATRIXI *b)
|
|
{
|
|
D3DMATRIX res;
|
|
MATRIX_PRODUCT((&res), a, b);
|
|
*(D3DMATRIX*)result = res;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
#ifdef DEBUG_PIPELINE
|
|
|
|
extern DWORD g_DebugFlags;
|
|
|
|
#endif
|
|
//
|
|
// DoUpdateState should be called for every DrawPrimitive call in the slow path,
|
|
// because it sets some internal pipeline flags. These flags are persistent for the
|
|
// fast path
|
|
//
|
|
void DoUpdateState(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
// only set up lights if something has changed
|
|
if (lpDevI->dwFEFlags & D3DFE_LIGHTS_DIRTY)
|
|
{
|
|
LPDIRECT3DLIGHTI lpD3DLightI;
|
|
lpD3DLightI = (LPDIRECT3DLIGHTI)LIST_FIRST(&lpDevI->m_ActiveLights);
|
|
lpDevI->lighting.activeLights = NULL;
|
|
|
|
// Set lights in the device
|
|
while (lpD3DLightI)
|
|
{
|
|
if (lpD3DLightI->m_LightI.flags & D3DLIGHTI_DIRTY)
|
|
lpD3DLightI->SetInternalData();
|
|
lpD3DLightI->m_LightI.next = lpDevI->lighting.activeLights;
|
|
lpDevI->lighting.activeLights = &lpD3DLightI->m_LightI;
|
|
lpD3DLightI = (LPDIRECT3DLIGHTI)LIST_NEXT(lpD3DLightI, m_List);
|
|
}
|
|
}
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_LIGHTING &&
|
|
lpDevI->dwVIDOut & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR))
|
|
{
|
|
lpDevI->dwFlags |= D3DPV_LIGHTING;
|
|
}
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_FOG && lpDevI->dwVIDOut & D3DFVF_SPECULAR)
|
|
{
|
|
lpDevI->dwFlags |= D3DPV_FOG;
|
|
}
|
|
|
|
if (lpDevI->dwFEFlags & D3DFE_VERTEXBLEND_DIRTY)
|
|
{
|
|
lpDevI->dwNumVerBlends = min(lpDevI->rstates[D3DRENDERSTATE_VERTEXBLEND],
|
|
((lpDevI->dwVIDIn & D3DFVF_POSITION_MASK) >> 1) - 2);
|
|
lpDevI->dwFEFlags &= ~D3DFE_VERTEXBLEND_DIRTY;
|
|
// Lighting is done in the camera space when there is vertex blending
|
|
if (lpDevI->dwNumVerBlends)
|
|
{
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)
|
|
{
|
|
lpDevI->dwDeviceFlags &= ~(D3DDEV_MODELSPACELIGHTING | D3DFE_NEEDCHECKWORLDVIEWVMATRIX);
|
|
// We have to transform lights to the camera space
|
|
lpDevI->dwFEFlags |= D3DFE_NEED_TRANSFORM_LIGHTS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(lpDevI->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING))
|
|
lpDevI->dwFEFlags |= D3DFE_NEEDCHECKWORLDVIEWVMATRIX;
|
|
}
|
|
}
|
|
|
|
if (lpDevI->dwFEFlags & D3DFE_TRANSFORM_DIRTY)
|
|
{
|
|
updateTransform(lpDevI);
|
|
}
|
|
// We need World-View matrix for lighting, fog and when texture coordinates
|
|
// are taken from the vertex data in the camera space
|
|
if (lpDevI->dwFEFlags & D3DFE_WORLDVIEWMATRIX_DIRTY &&
|
|
(lpDevI->dwFlags & (D3DPV_LIGHTING | D3DPV_FOG) ||
|
|
lpDevI->dwDeviceFlags & (D3DDEV_NORMALINCAMERASPACE | D3DDEV_POSITIONINCAMERASPACE)))
|
|
{
|
|
MatrixProduct(&lpDevI->mWV, &lpDevI->transform.world[0],
|
|
&lpDevI->transform.view);
|
|
for (DWORD i=0; i < lpDevI->dwNumVerBlends; i++)
|
|
{
|
|
MatrixProduct(&lpDevI->mWV2[i], &lpDevI->transform.world[i+1],
|
|
&lpDevI->transform.view);
|
|
}
|
|
lpDevI->dwFEFlags &= ~D3DFE_WORLDVIEWMATRIX_DIRTY;
|
|
}
|
|
// Detect where to do lighting: in model or eye space
|
|
if (lpDevI->dwFEFlags & D3DFE_NEEDCHECKWORLDVIEWVMATRIX &&
|
|
lpDevI->dwFlags & D3DPV_LIGHTING)
|
|
{
|
|
// We try to do lighting in the model space if
|
|
// 1. we do not have to normalize normals
|
|
// 2. we do not need to do vertex blending
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_MODELSPACELIGHTING;
|
|
if (lpDevI->dwNumVerBlends == 0 &&
|
|
!(lpDevI->dwDeviceFlags & D3DDEV_NORMALIZENORMALS))
|
|
{
|
|
#ifdef DEBUG_PIPELINE
|
|
if (!(g_DebugFlags & __DEBUG_MODELSPACE))
|
|
#endif
|
|
{
|
|
CheckWorldViewMatrix(lpDevI);
|
|
lpDevI->dwFEFlags &= ~D3DFE_NEEDCHECKWORLDVIEWVMATRIX;
|
|
}
|
|
}
|
|
// If D3DDEV_MODELSPACELIGHTING has been changed we need to re-transform lights
|
|
lpDevI->dwFEFlags |= D3DFE_NEED_TRANSFORM_LIGHTS;
|
|
}
|
|
|
|
// Updating inverse World-View matrix
|
|
if (lpDevI->dwFEFlags & D3DFE_INVWORLDVIEWMATRIX_DIRTY &&
|
|
((lpDevI->dwFlags & D3DPV_LIGHTING && !(lpDevI->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)) ||
|
|
lpDevI->dwDeviceFlags & D3DDEV_NORMALINCAMERASPACE))
|
|
{
|
|
Inverse4x4((D3DMATRIX*)&lpDevI->mWV, (D3DMATRIX*)&lpDevI->mWVI);
|
|
for (DWORD i=0; i < lpDevI->dwNumVerBlends; i++)
|
|
{
|
|
Inverse4x4((D3DMATRIX*)&lpDevI->mWV2[i], (D3DMATRIX*)&lpDevI->mWVI2[i]);
|
|
}
|
|
lpDevI->dwFEFlags &= ~D3DFE_INVWORLDVIEWMATRIX_DIRTY;
|
|
}
|
|
|
|
// Update clipping planes if there are any
|
|
if (lpDevI->dwFEFlags & D3DFE_CLIPPLANES_DIRTY)
|
|
{
|
|
if (lpDevI->dwFEFlags & D3DFE_CLIPMATRIX_DIRTY)
|
|
{
|
|
// View and projection matrix are inversed separately, because it
|
|
// is possible that combined matrix cannot be inverted. This could happend
|
|
// when the view matrix has huge _43 value (> 10^7). Floating point precision
|
|
// is not enough in this case
|
|
D3DMATRIXI mPCInverse;
|
|
if (Inverse4x4((D3DMATRIX*)&lpDevI->transform.mPC, (D3DMATRIX*)&mPCInverse))
|
|
{
|
|
D3D_ERR("Cannot invert projection matrix");
|
|
setIdentity((D3DMATRIXI*)&mPCInverse);
|
|
}
|
|
D3DMATRIXI mViewInverse;
|
|
if (Inverse4x4((D3DMATRIX*)&lpDevI->transform.view, (D3DMATRIX*)&mViewInverse))
|
|
{
|
|
D3D_ERR("Cannot invert view matrix");
|
|
setIdentity((D3DMATRIXI*)&mViewInverse);
|
|
}
|
|
MatrixProduct(&lpDevI->transform.mVPCI, &mPCInverse, &mViewInverse);
|
|
lpDevI->dwFEFlags &= ~D3DFE_CLIPMATRIX_DIRTY;
|
|
}
|
|
DWORD dwMaxUserClipPlanes = 0;
|
|
DWORD dwPlanes = lpDevI->rstates[D3DRENDERSTATE_CLIPPLANEENABLE];
|
|
for (DWORD i=0; i < __MAXUSERCLIPPLANES; i++)
|
|
{
|
|
if (dwPlanes & (1 << i))
|
|
{
|
|
VecMatMul4HT(&lpDevI->transform.userClipPlane[i],
|
|
(D3DMATRIX*)&lpDevI->transform.mVPCI,
|
|
&lpDevI->userClipPlane[dwMaxUserClipPlanes]);
|
|
dwMaxUserClipPlanes++;
|
|
}
|
|
}
|
|
lpDevI->dwMaxUserClipPlanes = dwMaxUserClipPlanes;
|
|
lpDevI->dwFEFlags &= ~D3DFE_CLIPPLANES_DIRTY;
|
|
}
|
|
|
|
if (lpDevI->dwFEFlags & (D3DFE_NEED_TRANSFORM_LIGHTS |
|
|
D3DFE_LIGHTS_DIRTY |
|
|
D3DFE_MATERIAL_DIRTY))
|
|
{
|
|
D3DFE_UpdateLights(lpDevI);
|
|
// Set a flag for PSGP
|
|
lpDevI->dwDeviceFlags |= D3DDEV_LIGHTSDIRTY;
|
|
}
|
|
|
|
// In case if COLORVERTEX is TRUE, the vertexAlpha could be overriden
|
|
// by vertex alpha
|
|
lpDevI->lighting.alpha = (DWORD)lpDevI->lighting.materialAlpha;
|
|
lpDevI->lighting.alphaSpecular = (DWORD)lpDevI->lighting.materialAlphaS;
|
|
|
|
if (!(lpDevI->dwVIDOut & D3DFVF_DIFFUSE))
|
|
lpDevI->dwFlags |= D3DPV_DONOTCOPYDIFFUSE;
|
|
if (!(lpDevI->dwVIDOut & D3DFVF_SPECULAR))
|
|
lpDevI->dwFlags |= D3DPV_DONOTCOPYSPECULAR;
|
|
|
|
// This is a hint that only the inPosition pointer needs to be updated
|
|
// for speed reasons.
|
|
if (((lpDevI->dwVIDIn & ( D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_NORMAL)) == 0) &&
|
|
(lpDevI->nTexCoord == 0))
|
|
lpDevI->dwFlags |= D3DPV_TRANSFORMONLY;
|
|
|
|
if (lpDevI->nOutTexCoord == 0)
|
|
lpDevI->dwFlags |= D3DPV_DONOTCOPYTEXTURE;
|
|
|
|
SetInterpolationFlags(lpDevI);
|
|
|
|
lpDevI->dwFEFlags &= ~D3DFE_FRONTEND_DIRTY;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Convert extents from floating point to integer.
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "D3DFE_ConvertExtent"
|
|
|
|
void D3DFE_ConvertExtent(LPDIRECT3DDEVICEI lpDevI, LPD3DRECTV from, LPD3DRECT to)
|
|
{
|
|
to->x1 = FTOI(from->x1) - 1;
|
|
to->y1 = FTOI(from->y1) - 1;
|
|
to->x2 = FTOI(from->x2) + 1;
|
|
to->y2 = FTOI(from->y2) + 1;
|
|
if (to->x1 < lpDevI->vcache.minXi)
|
|
to->x1 = lpDevI->vcache.minXi;
|
|
if (to->y1 < lpDevI->vcache.minYi)
|
|
to->y1 = lpDevI->vcache.minYi;
|
|
if (to->x2 > lpDevI->vcache.maxXi)
|
|
to->x2 = lpDevI->vcache.maxXi;
|
|
if (to->y2 > lpDevI->vcache.maxYi)
|
|
to->y2 = lpDevI->vcache.maxYi;
|
|
}
|
|
|