📄 zfxd3d_misc.cpp
字号:
// File: ZFXD3D_misc.cpp
#include "math.h" // sqrt function
#include "ZFX.h" // return values and stuff
#include "ZFXD3D.h" // class definition
#include "d3dx9.h" // shader compiler
extern bool g_bLF;
/*-----------------------------------------------------------*/
/* ZFXD3D class implementation *
/*-----------------------------------------------------------*/
/**
* Set mode for projection and view for given Stage.
* -> IN: ZFXENGINEMODE - mode perspective, ortho or 2D
* int - stage, not needed for 2D mode
*/
HRESULT ZFXD3D::SetMode(ZFXENGINEMODE Mode, int nStage) {
D3DVIEWPORT9 d3dVP;
if (!m_bRunning) return E_FAIL;
if ((nStage > 3) || (nStage < 0)) nStage=0;
if (m_Mode != Mode)
m_Mode = Mode;
// we change fundamentals settings so fush all content
m_pVertexMan->ForcedFlushAll();
m_nStage = nStage;
// set viewport
d3dVP.X = m_VP[nStage].X;
d3dVP.Y = m_VP[nStage].Y;
d3dVP.Width = m_VP[nStage].Width;
d3dVP.Height = m_VP[nStage].Height;
d3dVP.MinZ = 0.0f;
d3dVP.MaxZ = 1.0f;
// if 2D mode set orthogonal projection and view
if (Mode==EMD_TWOD) {
if (FAILED(m_pDevice->SetViewport(&d3dVP)))
return ZFX_FAIL;
if (!m_bUseShaders) {
if (FAILED(m_pDevice->SetTransform(D3DTS_PROJECTION, &m_mProj2D)))
return ZFX_FAIL;
if (FAILED(m_pDevice->SetTransform(D3DTS_VIEW, &m_mView2D)))
return ZFX_FAIL;
}
}
// perspective or orthogonal projection
else {
if (FAILED(m_pDevice->SetViewport(&d3dVP)))
return ZFX_FAIL;
if (!m_bUseShaders) {
if (FAILED(m_pDevice->SetTransform(D3DTS_VIEW, &m_mView3D)))
return ZFX_FAIL;
if (m_Mode == EMD_PERSPECTIVE) {
if (FAILED(m_pDevice->SetTransform(D3DTS_PROJECTION,
&m_mProjP[nStage])))
return ZFX_FAIL;
}
else { // EMD_ORTHOGONAL
if (FAILED(m_pDevice->SetTransform(D3DTS_PROJECTION,
&m_mProjO[nStage])))
return ZFX_FAIL;
}
}
CalcViewProjMatrix();
CalcWorldViewProjMatrix();
}
return ZFX_OK;
} // SetMode
/*----------------------------------------------------------------*/
/**
* Calculate perspective and orthogonal projection matrix for given
* stage using given values. Thi will not activate any settings.
* -> IN: float - field of view (horizontal)
* ZFXVIEWPORT - viewport dimensions or NULL for screen dimensions
* int - which stage to set (4 possible)
*/
HRESULT ZFXD3D::InitStage(float fFOV, ZFXVIEWPORT *pView, int nStage) {
float fAspect;
bool bOwnRect=false;
if (!pView) {
ZFXVIEWPORT vpOwn = { 0, 0, m_dwWidth, m_dwHeight};
memcpy(&m_VP[nStage], &vpOwn, sizeof(RECT));
}
else
memcpy(&m_VP[nStage], pView, sizeof(RECT));
if ( (nStage>3) || (nStage<0) ) nStage=0;
fAspect = ((float)(m_VP[nStage].Height)) / (m_VP[nStage].Width);
// PERSPECTIVE PROJEKTION MATRIX
if (FAILED(this->CalcPerspProjMatrix(fFOV, fAspect, &m_mProjP[nStage])))
return ZFX_FAIL;
// ORTHOGONAL PROJECTION MATRIX
memset(&m_mProjO[nStage], 0, sizeof(float)*16);
m_mProjO[nStage]._11 = 2.0f/m_VP[nStage].Width;
m_mProjO[nStage]._22 = 2.0f/m_VP[nStage].Height;
m_mProjO[nStage]._33 = 1.0f/(m_fFar-m_fNear);
m_mProjO[nStage]._43 = m_fNear/(m_fNear-m_fFar);
m_mProjO[nStage]._44 = 1.0f;
return ZFX_OK;
} // InitStage
/*----------------------------------------------------------------*/
/**
* Recalculate view-projection combo matrix each time one of them
* is changing to maintain integrity.
*/
void ZFXD3D::CalcViewProjMatrix(void) {
ZFXMatrix *pA;
ZFXMatrix *pB;
// 2D, perspective or orthogonal mode
if (m_Mode == EMD_TWOD) {
pA = (ZFXMatrix*)&m_mProj2D;
pB = (ZFXMatrix*)&m_mView2D;
}
else {
pB = (ZFXMatrix*)&m_mView3D;
if (m_Mode == EMD_PERSPECTIVE)
pA = (ZFXMatrix*)&(m_mProjP[m_nStage]);
else
pA = (ZFXMatrix*)&(m_mProjO[m_nStage]);
}
ZFXMatrix *pM = (ZFXMatrix*)&m_mViewProj;
(*pM) = (*pB) * (*pA);
} // CalcViewProjMatrix
/*----------------------------------------------------------------*/
void ZFXD3D::CalcOrthoProjMatrix(float l, float r, float b, float t,
float fN, float fF, int nStage) {
float x = 2.0f / (r-l);
float y = 2.0f / (t-b);
float z = 2.0f / (fF-fN);
float tx = -(r+l) / (r-l);
float ty = -(t+b) / (t-b);
float tz = -(fF+fN) / (fF-fN);
memset(&m_mProjO[nStage], 0, sizeof(D3DMATRIX));
m_mProjO[nStage]._11 = x;
m_mProjO[nStage]._22 = y;
m_mProjO[nStage]._33 = z;
m_mProjO[nStage]._44 = 1.0f;
m_mProjO[nStage]._41 = tx;
m_mProjO[nStage]._42 = ty;
m_mProjO[nStage]._43 = tz;
} // CalcOrthoProjMatrix
/*----------------------------------------------------------------*/
/**
* Calculate a combo matrix for world, view and projection.
*/
void ZFXD3D::CalcWorldViewProjMatrix(void) {
ZFXMatrix *pProj;
ZFXMatrix *pView;
ZFXMatrix *pWorld;
pWorld = (ZFXMatrix*)&m_mWorld;
// 2D, perspective or orthogonal mode
if (m_Mode == EMD_TWOD) {
pProj = (ZFXMatrix*)&m_mProj2D;
pView = (ZFXMatrix*)&m_mView2D;
}
else {
pView = (ZFXMatrix*)&m_mView3D;
if (m_Mode == EMD_PERSPECTIVE)
pProj = (ZFXMatrix*)&(m_mProjP[m_nStage]);
else
pProj = (ZFXMatrix*)&(m_mProjO[m_nStage]);
}
ZFXMatrix *pCombo = (ZFXMatrix*)&m_mWorldViewProj;
(*pCombo) = ((*pWorld) * (*pView)) * (*pProj);
} // CalcWorldViewProjMatrix
/*----------------------------------------------------------------*/
/**
* Calculate perspective 3D projection matrix.
* -> IN: float - field of horizontal view
* float - aspect ration (viewport height / width)
* D3DMATRIX - adress to store result
*/
HRESULT ZFXD3D::CalcPerspProjMatrix(float fFOV, float fAspect, D3DMATRIX *m) {
if(fabs(m_fFar - m_fNear) < 0.01f)
return ZFX_FAIL;
float sinFOV2 = sinf(fFOV/2);
if(fabs(sinFOV2) < 0.01f)
return ZFX_FAIL;
float cosFOV2 = cosf(fFOV/2);
float w = fAspect * (cosFOV2 / sinFOV2);
float h = 1.0f * (cosFOV2 / sinFOV2);
float Q = m_fFar / (m_fFar - m_fNear);
memset(m, 0, sizeof(D3DMATRIX));
(*m)._11 = w;
(*m)._22 = h;
(*m)._33 = Q;
(*m)._34 = 1.0f;
(*m)._43 = -Q*m_fNear;
return ZFX_OK;
} // CalcPerspProjMatrix
/*----------------------------------------------------------------*/
/**
* Set camera as viewmatrix.
* -> IN: float* - 4 float building camera's right vector
* float* - 4 float building camera's up vector
* float* - 4 float building camera's direction vector
* float* - 4 float building camera's pos vector
*/
HRESULT ZFXD3D::SetView3D(const ZFXVector &vcRight,
const ZFXVector &vcUp,
const ZFXVector &vcDir,
const ZFXVector &vcPos) {
if (!m_bRunning) return E_FAIL;
m_mView3D._14 = m_mView3D._21 = m_mView3D._34 = 0.0f;
m_mView3D._44 = 1.0f;
m_mView3D._11 = vcRight.x;
m_mView3D._21 = vcRight.y;
m_mView3D._31 = vcRight.z;
m_mView3D._41 = - (vcRight*vcPos);
m_mView3D._12 = vcUp.x;
m_mView3D._22 = vcUp.y;
m_mView3D._32 = vcUp.z;
m_mView3D._42 = - (vcUp*vcPos);
m_mView3D._13 = vcDir.x;
m_mView3D._23 = vcDir.y;
m_mView3D._33 = vcDir.z;
m_mView3D._43 = - (vcDir*vcPos);
if (!m_bUseShaders) {
// activate viewmatrix for D3D
if (FAILED(m_pDevice->SetTransform(D3DTS_VIEW, &m_mView3D)))
return ZFX_FAIL;
}
// view changed so recalculate combomatrix
CalcViewProjMatrix();
CalcWorldViewProjMatrix();
return ZFX_OK;
}
/*----------------------------------------------------------------*/
/**
* Calculates look at matrix for given point and calls SetView3D
* to active the look at matrix.
* -> IN: float* - 3 floats building camera's psoition vector
* float* - 3 floats building lookat point vector
* float* - 3 floats building world up vector at cam pos
*/
HRESULT ZFXD3D::SetViewLookAt(const ZFXVector &vcPos,
const ZFXVector &vcPoint,
const ZFXVector &vcWorldUp) {
ZFXVector vcDir, vcTemp, vcUp;
vcDir = vcPoint - vcPos;
vcDir.Normalize();
// calculate up vector
float fDot = vcWorldUp * vcDir;
vcTemp = vcDir * fDot;
vcUp = vcWorldUp - vcTemp;
float fL = vcUp.GetLength();
// if length too small take normal y axis as up vector
if (fL < 1e-6f) {
ZFXVector vcY;
vcY.Set(0.0f, 1.0f, 0.0f);
vcTemp = vcDir * vcDir.y;
vcUp = vcY - vcTemp;
fL = vcUp.GetLength();
// if still too small take z axis as up vector
if (fL < 1e-6f) {
vcY.Set(0.0f, 0.0f, 1.0f);
vcTemp = vcDir * vcDir.z;
vcUp = vcY - vcTemp;
// if still too small we are lost
fL = vcUp.GetLength();
if(fL < 1e-6f) return ZFX_FAIL;
}
}
vcUp /= fL;
// build right vector using cross product
ZFXVector vcRight;
vcRight.Cross(vcUp, vcDir);
// build final matrix and set for device
return SetView3D(vcRight, vcUp, vcDir, vcPos);
} // SetViewLookAt
/*----------------------------------------------------------------*/
/**
* Set Clipping Planes and take care of other values that need
* to be changed then.
*/
void ZFXD3D::SetClippingPlanes(float fNear, float fFar) {
m_fNear = fNear;
m_fFar = fFar;
if (m_fNear <= 0.0f)
m_fNear = 0.01f;
if (m_fFar <= 1.0f)
m_fFar = 1.00f;
if (m_fNear >= m_fFar) {
m_fNear = m_fFar;
m_fFar = m_fNear + 1.0f;
}
// change 2D projection and view
Prepare2D();
// change orthogonal projection
float Q = 1.0f / (m_fFar-m_fNear);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -