khanat-opennel-code/code/nel/src/3d/driver/direct3d/driver_direct3d_matrix.cpp

444 lines
12 KiB
C++
Raw Normal View History

2010-05-06 00:08:41 +00:00
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stddirect3d.h"
#include "nel/3d/vertex_buffer.h"
#include "nel/3d/light.h"
#include "nel/3d/index_buffer.h"
#include "nel/misc/rect.h"
#include "nel/misc/di_event_emitter.h"
#include "nel/misc/mouse_device.h"
#include "nel/3d/viewport.h"
#include "nel/3d/scissor.h"
#include "nel/3d/u_driver.h"
#include "driver_direct3d.h"
using namespace std;
using namespace NLMISC;
namespace NL3D
{
// ***************************************************************************
void CDriverD3D::updateMatrices ()
{
H_AUTO_D3D(CDriver3D_updateMatrices );
// Update view model matrix
D3DXMatrixMultiply (&_D3DModelView, &(_MatrixCache[remapMatrixIndex (D3DTS_WORLD)].Matrix), &(_MatrixCache[remapMatrixIndex (D3DTS_VIEW)].Matrix));
// Update view model projection matrix
_D3DModelViewProjection = _D3DModelView;
D3DXMatrixMultiply (&_D3DModelViewProjection, &_D3DModelViewProjection, &(_MatrixCache[remapMatrixIndex (D3DTS_PROJECTION)].Matrix));
// Update the inverted view model matrix
D3DXMatrixInverse (&_D3DInvModelView, NULL, &_D3DModelView);
// Update the normalize state
setRenderState (D3DRS_NORMALIZENORMALS, (_UserViewMtx.hasScalePart() || _UserModelMtx.hasScalePart() || _ForceNormalize)?TRUE:FALSE);
}
// ***************************************************************************
void CDriverD3D::updateProjectionMatrix ()
{
H_AUTO_D3D(CDriver3D_updateProjectionMatrix );
float left = _FrustumLeft;
float right = _FrustumRight;
float top = _FrustumTop;
float bottom = _FrustumBottom;
if (_RenderTarget.Texture)
swap (bottom, top);
// Get the render target size
uint32 clientWidth;
uint32 clientHeight;
getRenderTargetSize (clientWidth, clientHeight);
// In D3D, the center of the first screen pixel is [0.0,0.0]. Is NeL it is [0.5,0.5]
const float addW = (right-left)/(2*(_Viewport.getWidth() * (float)clientWidth));
const float addH = (bottom-top)/(2*(_Viewport.getHeight() * (float)clientHeight));
left += addW;
right += addW;
top += addH;
bottom += addH;
D3DXMATRIX projection;
if (_FrustumPerspective)
{
D3DXMatrixPerspectiveOffCenterLH (&projection, left, right, bottom, top, _FrustumZNear, _FrustumZFar);
}
else
{
D3DXMatrixOrthoOffCenterLH (&projection, left, right, bottom, top, _FrustumZNear, _FrustumZFar);
}
setMatrix (D3DTS_PROJECTION, projection);
// Backup znear and zfar for zbias setup
_OODeltaZ = 1 / (_FrustumZFar - _FrustumZNear);
updateMatrices ();
}
// ***************************************************************************
void CDriverD3D::setFrustum(float left, float right, float bottom, float top, float znear, float zfar, bool perspective)
{
H_AUTO_D3D(CDriverD3D_setFrustum)
_FrustumLeft = left;
_FrustumRight = right;
_FrustumTop = top;
_FrustumBottom = bottom;
_FrustumZNear = znear;
_FrustumZFar = zfar;
_FrustumPerspective = perspective;
updateProjectionMatrix ();
}
// ***************************************************************************
void CDriverD3D::setFrustumMatrix(CMatrix &frustumMatrix)
{
H_AUTO_D3D(CDriverD3D_setFrustum)
frustumMatrix.transpose();
setMatrix (D3DTS_PROJECTION, D3DXMATRIX(frustumMatrix.get()));
}
// ***************************************************************************
CMatrix CDriverD3D::getFrustumMatrix()
{
H_AUTO_D3D(CDriverD3D_getFrustum)
CMatrix frustumMatrix;
frustumMatrix.set((float *)_MatrixCache[D3DTS_PROJECTION].Matrix.m);
frustumMatrix.transpose();
return frustumMatrix;
}
// ***************************************************************************
void CDriverD3D::setupViewMatrix(const CMatrix& mtx)
{
H_AUTO_D3D(CDriverD3D_setupViewMatrix)
// Remember the view matrix
_UserViewMtx= mtx;
_PZBCameraPos= CVector::Null;
// Set the driver matrix
D3DXMATRIX view;
NL_D3D_MATRIX (view, mtx);
// Pass to directx matrix basis
swap (view._12, view._13);
swap (view._22, view._23);
swap (view._32, view._33);
swap (view._42, view._43);
setMatrix (D3DTS_VIEW, view);
// Set the spacular matrix
CMatrix specularTex;
specularTex = mtx;
specularTex.setPos(CVector(0.0f,0.0f,0.0f));
specularTex.invert();
NL_D3D_MATRIX (_D3DSpecularWorldTex, specularTex);
updateMatrices ();
}
// ***************************************************************************
void CDriverD3D::setupViewMatrixEx(const CMatrix& mtx, const CVector &cameraPos)
{
H_AUTO_D3D(CDriverD3D_setupViewMatrixEx)
// Remeber the view matrix
_UserViewMtx= mtx;
_PZBCameraPos= cameraPos;
// Set the driver matrix
D3DXMATRIX view;
NL_D3D_MATRIX (view, mtx);
// Pass to directx matrix basis
swap (view._12, view._13);
swap (view._22, view._23);
swap (view._32, view._33);
swap (view._42, view._43);
// Reset the viewMtx position.
view._41 = 0;
view._42 = 0;
view._43 = 0;
setMatrix (D3DTS_VIEW, view);
// Set the spacular matrix
CMatrix specularTex;
specularTex = mtx;
NL_D3D_MATRIX (_D3DSpecularWorldTex, specularTex);
swap (_D3DSpecularWorldTex._12, _D3DSpecularWorldTex._13);
swap (_D3DSpecularWorldTex._22, _D3DSpecularWorldTex._23);
swap (_D3DSpecularWorldTex._32, _D3DSpecularWorldTex._33);
swap (_D3DSpecularWorldTex._42, _D3DSpecularWorldTex._43);
_D3DSpecularWorldTex._41 = 0;
_D3DSpecularWorldTex._42 = 0;
_D3DSpecularWorldTex._43 = 0;
D3DXMatrixInverse ( &_D3DSpecularWorldTex, NULL, &_D3DSpecularWorldTex);
swap (_D3DSpecularWorldTex._12, _D3DSpecularWorldTex._13);
swap (_D3DSpecularWorldTex._22, _D3DSpecularWorldTex._23);
swap (_D3DSpecularWorldTex._32, _D3DSpecularWorldTex._33);
swap (_D3DSpecularWorldTex._42, _D3DSpecularWorldTex._43);
updateMatrices ();
}
// ***************************************************************************
void CDriverD3D::setupModelMatrix(const CMatrix& mtx)
{
H_AUTO_D3D(CDriverD3D_setupModelMatrix)
// Stats
_NbSetupModelMatrixCall++;
// Remeber the model matrix
_UserModelMtx= mtx;
D3DXMATRIX world;
NL_D3D_MATRIX (world, mtx);
// Remove from position the camera position
world._41 -= _PZBCameraPos.x;
world._42 -= _PZBCameraPos.y;
world._43 -= _PZBCameraPos.z;
setMatrix (D3DTS_WORLD, world);
updateMatrices ();
}
// ***************************************************************************
CMatrix CDriverD3D::getViewMatrix() const
{
H_AUTO_D3D(CDriverD3D_getViewMatrix)
return _UserViewMtx;
}
// ***************************************************************************
void CDriverD3D::forceNormalize(bool normalize)
{
H_AUTO_D3D(CDriverD3D_forceNormalize)
_ForceNormalize = normalize;
updateMatrices ();
}
// ***************************************************************************
bool CDriverD3D::isForceNormalize() const
{
H_AUTO_D3D(CDriverD3D_isForceNormalize)
return _RenderStateCache[D3DRS_NORMALIZENORMALS].Value != FALSE;
}
// ***************************************************************************
void CDriverD3D::setupScissor (const class CScissor& scissor)
{
H_AUTO_D3D(CDriverD3D_setupScissor )
if (!_ScissorTouched &&
_Scissor.X == scissor.X &&
_Scissor.Y == scissor.Y &&
_Scissor.Width == scissor.Width &&
_Scissor.Height == scissor.Height
) return;
nlassert (_DeviceInterface);
// Get viewport
_ScissorTouched = false;
float x= scissor.X;
float width= scissor.Width;
float height= scissor.Height;
if(x==0 && x==0 && width==1 && height==1)
{
setRenderState (D3DRS_SCISSORTESTENABLE, FALSE);
}
else
{
float y= scissor.Y;
if (_HWnd)
{
// Get the render target size
uint32 clientWidth;
uint32 clientHeight;
getRenderTargetSize (clientWidth, clientHeight);
// Setup d3d scissor
RECT rect;
rect.left=(int)floor((float)clientWidth * x + 0.5f);
clamp (rect.left, 0, (int)clientWidth);
if (_RenderTarget.Texture)
rect.top=(int)floor((float)clientHeight* y + 0.5f);
else
rect.top=(int)floor((float)clientHeight* (1-y-height) + 0.5f);
clamp (rect.top, 0, (int)clientHeight);
rect.right=(int)floor((float)clientWidth * (x+width) + 0.5f );
clamp (rect.right, 0, (int)clientWidth);
if (_RenderTarget.Texture)
rect.bottom=(int)floor((float)clientHeight* (y+height) + 0.5f);
else
rect.bottom=(int)floor((float)clientHeight* (1-y) + 0.5f);
clamp (rect.bottom, 0, (int)clientHeight);
{
H_AUTO_D3D(CDriverD3D_setupScissorDevice )
_DeviceInterface->SetScissorRect (&rect);
}
setRenderState (D3DRS_SCISSORTESTENABLE, TRUE);
}
}
// Backup the scissor
_Scissor = scissor;
}
// ***************************************************************************
void CDriverD3D::setupViewport (const class CViewport& viewport)
{
H_AUTO_D3D(CDriverD3D_setupViewport )
if (_HWnd == NULL)
return;
// Get the render target size
uint32 clientWidth;
uint32 clientHeight;
getRenderTargetSize (clientWidth, clientHeight);
// Get viewport
float x;
float y;
float width;
float height;
viewport.getValues (x, y, width, height);
// Get integer values
int ix=(int)((float)clientWidth*x);
clamp (ix, 0, (int)clientWidth);
int iy;
if (_RenderTarget.Texture)
iy=(int)((float)clientHeight*y);
else
iy=(int)((float)clientHeight*(1.f-(y+height)));
clamp (iy, 0, (int)clientHeight);
int iwidth=(int)((float)clientWidth*width);
clamp (iwidth, 0, (int)clientWidth-ix);
int iheight=(int)((float)clientHeight*height);
clamp (iheight, 0, (int)clientHeight-iy);
// Setup D3D viewport
_D3DViewport.X = ix;
_D3DViewport.Y = iy;
_D3DViewport.Width = iwidth;
_D3DViewport.Height = iheight;
_D3DViewport.MinZ = _DepthRangeNear;
_D3DViewport.MaxZ = _DepthRangeFar;
_DeviceInterface->SetViewport (&_D3DViewport);
// Backup the viewport
_Viewport = viewport;
updateProjectionMatrix ();
}
// ***************************************************************************
void CDriverD3D::setDepthRange(float znear, float zfar)
{
H_AUTO_D3D(CDriverD3D_setDepthRange)
nlassert(znear != zfar);
if (_HWnd == NULL)
return;
#ifdef NL_D3D_USE_RENDER_STATE_CACHE
NL_D3D_CACHE_TEST(CacheTest_DepthRange, znear != _DepthRangeNear || zfar != _DepthRangeFar)
#endif
{
_DepthRangeNear = znear;
_DepthRangeFar = zfar;
_D3DViewport.MinZ = _DepthRangeNear;
_D3DViewport.MaxZ = _DepthRangeFar;
_DeviceInterface->SetViewport (&_D3DViewport);
}
}
// ***************************************************************************
void CDriverD3D::getDepthRange(float &znear, float &zfar) const
{
H_AUTO_D3D(CDriverD3D_getDepthRange)
znear = _DepthRangeNear;
zfar = _DepthRangeFar;
}
// ***************************************************************************
void CDriverD3D::getViewport(CViewport &viewport)
{
H_AUTO_D3D(CDriverD3D_getViewport)
viewport = _Viewport;
}
// ***************************************************************************
} // NL3D