mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-16 14:28:43 +00:00
4041 lines
128 KiB
C++
4041 lines
128 KiB
C++
// 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"
|
|
|
|
// by default, we disable the windows menu keys (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
|
|
#define NL_DISABLE_MENU
|
|
|
|
#include <tchar.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/misc/dynloadlib.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;
|
|
|
|
#define RASTERIZER D3DDEVTYPE_HAL
|
|
//#define RASTERIZER D3DDEVTYPE_REF
|
|
|
|
#define D3D_WINDOWED_STYLE (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX)
|
|
#define D3D_FULLSCREEN_STYLE (WS_POPUP)
|
|
|
|
// ***************************************************************************
|
|
|
|
// Try to allocate 16Mo by default of AGP Ram.
|
|
#define NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE (16384*1024)
|
|
|
|
// Initial volatile vertex buffer size
|
|
#define NL_VOLATILE_RAM_VB_SIZE 512*1024
|
|
#define NL_VOLATILE_AGP_VB_SIZE 128*1024
|
|
#define NL_VOLATILE_RAM_IB_SIZE 64*1024
|
|
#define NL_VOLATILE_AGP_IB_SIZE 1024
|
|
//
|
|
#define NL_VOLATILE_RAM_VB_MAXSIZE 512*1024
|
|
#define NL_VOLATILE_AGP_VB_MAXSIZE 2500*1024
|
|
#define NL_VOLATILE_RAM_IB_MAXSIZE 1024*1024
|
|
#define NL_VOLATILE_AGP_IB_MAXSIZE 256*1024
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
#ifndef NL_STATIC
|
|
|
|
HINSTANCE HInstDLL = NULL;
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
|
|
{
|
|
HInstDLL = hinstDLL;
|
|
|
|
return true;
|
|
}
|
|
|
|
class CDriverD3DNelLibrary : public INelLibrary {
|
|
void onLibraryLoaded(bool firstTime) { }
|
|
void onLibraryUnloaded(bool lastTime) { }
|
|
};
|
|
NLMISC_DECL_PURE_LIB(CDriverD3DNelLibrary)
|
|
|
|
#endif /* #ifndef NL_STATIC */
|
|
|
|
// ***************************************************************************
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
// ***************************************************************************
|
|
|
|
// Version of the driver. Not the interface version!! Increment when implementation of the driver change.
|
|
const uint32 CDriverD3D::ReleaseVersion = 0xe;
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
#ifdef NL_STATIC
|
|
|
|
# pragma comment(lib, "d3dx9")
|
|
# pragma comment(lib, "d3d9")
|
|
# pragma comment(lib, "dinput8")
|
|
# pragma comment(lib, "dxguid")
|
|
|
|
IDriver* createD3DDriverInstance ()
|
|
{
|
|
return new CDriverD3D;
|
|
}
|
|
|
|
#else
|
|
|
|
__declspec(dllexport) IDriver* NL3D_createIDriverInstance ()
|
|
{
|
|
return new CDriverD3D;
|
|
}
|
|
|
|
__declspec(dllexport) uint32 NL3D_interfaceVersion ()
|
|
{
|
|
return IDriver::InterfaceVersion;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*static*/ bool CDriverD3D::_CacheTest[CacheTest_Count] =
|
|
{
|
|
false, // CacheTest_CullMode = 0;
|
|
false, // CacheTest_RenderState = 1,
|
|
false, // CacheTest_TextureState = 2,
|
|
false, // CacheTest_TextureIndexMode = 3,
|
|
false, // CacheTest_TextureIndexUV = 4,
|
|
false, // CacheTest_Texture = 5,
|
|
false, // CacheTest_VertexProgram = 6,
|
|
false, // CacheTest_PixelShader = 7,
|
|
false, // CacheTest_VertexProgramConstant = 8,
|
|
false, // CacheTest_PixelShaderConstant = 9,
|
|
false, // CacheTest_SamplerState = 10,
|
|
false, // CacheTest_VertexBuffer = 11,
|
|
false, // CacheTest_IndexBuffer = 12,
|
|
false, // CacheTest_VertexDecl = 13,
|
|
false, // CacheTest_Matrix = 14,
|
|
false, // CacheTest_RenderTarget = 15,
|
|
false, // CacheTest_MaterialState = 16,
|
|
false // CacheTest_DepthRange = 17,
|
|
};
|
|
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
CDriverD3D::CDriverD3D()
|
|
{
|
|
_SwapBufferCounter = 0;
|
|
_CurrentOcclusionQuery = NULL;
|
|
_D3D = NULL;
|
|
_HWnd = NULL;
|
|
_DeviceInterface = NULL;
|
|
_DestroyWindow = false;
|
|
_CurrentMode.Width = 640;
|
|
_CurrentMode.Height = 480;
|
|
_WindowX = 0;
|
|
_WindowY = 0;
|
|
_FullScreen = false;
|
|
|
|
_ColorDepth = ColorDepth32;
|
|
|
|
_DefaultCursor = EmptyCursor;
|
|
|
|
_AlphaBlendedCursorSupported = false;
|
|
_AlphaBlendedCursorSupportRetrieved = false;
|
|
_CurrCol = CRGBA::White;
|
|
_CurrRot = 0;
|
|
_CurrHotSpotX = 0;
|
|
_CurrHotSpotY = 0;
|
|
_CursorScale = 1.f;
|
|
|
|
_UserViewMtx.identity();
|
|
_UserModelMtx.identity();
|
|
_PZBCameraPos = CVector::Null;
|
|
_CurrentMaterial = NULL;
|
|
_CurrentMaterialInfo = NULL;
|
|
_CurrentShader = NULL;
|
|
_BackBuffer = NULL;
|
|
_Maximized = false;
|
|
_HandlePossibleSizeChangeNextSize = false;
|
|
_Interval = 1;
|
|
_AGPMemoryAllocated = 0;
|
|
_VRAMMemoryAllocated = 0;
|
|
_Rasterizer = RASTERIZER;
|
|
#ifdef NL_DISABLE_HARDWARE_VERTEX_PROGAM
|
|
_DisableHardwareVertexProgram = true;
|
|
#else // NL_DISABLE_HARDWARE_VERTEX_PROGAM
|
|
_DisableHardwareVertexProgram = false;
|
|
#endif // NL_DISABLE_HARDWARE_VERTEX_PROGAM
|
|
#ifdef NL_DISABLE_HARDWARE_PIXEL_PROGAM
|
|
_DisableHardwarePixelProgram = true;
|
|
#else // NL_DISABLE_HARDWARE_PIXEL_PROGAM
|
|
_DisableHardwarePixelProgram = false;
|
|
#endif // NL_DISABLE_HARDWARE_PIXEL_PROGAM
|
|
#ifdef NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP
|
|
_DisableHardwareVertexArrayAGP = true;
|
|
#else // NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP
|
|
_DisableHardwareVertexArrayAGP = false;
|
|
#endif // NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP
|
|
#ifdef NL_DISABLE_HARDWARE_INDEX_ARRAY_AGP
|
|
_DisableHardwareIndexArrayAGP = true;
|
|
#else // NL_DISABLE_HARDWARE_INDEX_ARRAY_AGP
|
|
_DisableHardwareIndexArrayAGP = false;
|
|
#endif // NL_DISABLE_HARDWARE_INDEX_ARRAY_AGP
|
|
#ifdef NL_DISABLE_HARDWARE_PIXEL_SHADER
|
|
_DisableHardwarePixelShader = true;
|
|
#else // NL_DISABLE_HARDWARE_PIXEL_SHADER
|
|
_DisableHardwarePixelShader = false;
|
|
#endif // NL_DISABLE_HARDWARE_PIXEL_SHADER
|
|
|
|
// Compute the Flag which say if one texture has been changed in CMaterial.
|
|
_MaterialAllTextureTouchedFlag= 0;
|
|
uint i;
|
|
for(i=0; i < IDRV_MAT_MAXTEXTURES; i++)
|
|
{
|
|
_MaterialAllTextureTouchedFlag|= IDRV_TOUCHED_TEX[i];
|
|
}
|
|
|
|
// Default adapter
|
|
_Adapter = 0xffffffff;
|
|
_ModifiedRenderState = NULL;
|
|
|
|
// Create a Direct 3d object
|
|
if ( NULL == (_D3D = Direct3DCreate9(D3D_SDK_VERSION)))
|
|
{
|
|
nlwarning ("Can't create the direct 3d 9 object.");
|
|
|
|
#ifdef NL_OS_WINDOWS
|
|
sint val = MessageBoxA(NULL, "Your DirectX version is too old. You need to install the latest one.\r\n\r\nPressing OK will quit the game and automatically open your browser to download the latest version of DirectX.\r\nPress Cancel will just quit the game.\r\n", "Mtp Target Error", MB_OKCANCEL);
|
|
if(val == IDOK)
|
|
{
|
|
openURL("http://www.microsoft.com/downloads/details.aspx?FamilyID=4b1f5d0c-5e44-4864-93cd-464ef59da050");
|
|
}
|
|
#endif
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
_DepthRangeNear = 0.f;
|
|
_DepthRangeFar = 1.f;
|
|
// default for lightmap
|
|
_LightMapDynamicLightDirty= false;
|
|
_LightMapDynamicLightEnabled= false;
|
|
_CurrentMaterialSupportedShader= CMaterial::Normal;
|
|
// to avoid any problem if light0 never setuped, and ligthmap rendered
|
|
_UserLight0.setupDirectional(CRGBA::Black, CRGBA::White, CRGBA::White, CVector::K);
|
|
// All User Light are disabled by Default
|
|
for(i=0;i<MaxLight;i++)
|
|
_UserLightEnable[i]= false;
|
|
_CullMode = CCW;
|
|
_ScissorTouched = true;
|
|
_Scissor.X = -1;
|
|
_Scissor.Y = -1;
|
|
_Scissor.Width = -1;
|
|
_Scissor.Height = -1;
|
|
|
|
_CurStencilTest = false;
|
|
_CurStencilFunc = D3DCMP_ALWAYS;
|
|
_CurStencilRef = 0;
|
|
_CurStencilMask = std::numeric_limits<DWORD>::max();
|
|
_CurStencilOpFail = D3DSTENCILOP_KEEP;
|
|
_CurStencilOpZFail = D3DSTENCILOP_KEEP;
|
|
_CurStencilOpZPass = D3DSTENCILOP_KEEP;
|
|
_CurStencilWriteMask = std::numeric_limits<DWORD>::max();
|
|
|
|
|
|
for(uint k = 0; k < MaxTexture; ++k)
|
|
{
|
|
_CurrentUVRouting[k] = (uint8) k;
|
|
}
|
|
_VolatileVertexBufferRAM[0] = new CVolatileVertexBuffer;
|
|
_VolatileVertexBufferRAM[1] = new CVolatileVertexBuffer;
|
|
_VolatileVertexBufferAGP[0] = new CVolatileVertexBuffer;
|
|
_VolatileVertexBufferAGP[1] = new CVolatileVertexBuffer;
|
|
_VolatileIndexBuffer16RAM[0]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer16RAM[1]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer16AGP[0]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer16AGP[1]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer32RAM[0]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer32RAM[1]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer32AGP[0]= new CVolatileIndexBuffer;
|
|
_VolatileIndexBuffer32AGP[1]= new CVolatileIndexBuffer;
|
|
_MustRestoreLight = false;
|
|
_Lost = false;
|
|
_SceneBegun = false;
|
|
_MaxVertexIndex = 0;
|
|
_QuadIB = NULL;
|
|
_MaxNumPerStageConstantLighted = 0;
|
|
_MaxNumPerStageConstantUnlighted = 0;
|
|
D3DXMatrixIdentity(&_D3DMatrixIdentity);
|
|
_FogColor = 0xffffffff;
|
|
_CurrIndexBufferFormat = CIndexBuffer::IndicesUnknownFormat;
|
|
_IsGeforce = false;
|
|
_NonPowerOfTwoTexturesSupported = false;
|
|
_MaxAnisotropy = 0;
|
|
_AnisotropicMinSupported = false;
|
|
_AnisotropicMagSupported = false;
|
|
_AnisotropicMinCubeSupported = false;
|
|
_AnisotropicMagCubeSupported = false;
|
|
|
|
_FrustumLeft= -1.f;
|
|
_FrustumRight= 1.f;
|
|
_FrustumTop= 1.f;
|
|
_FrustumBottom= -1.f;
|
|
_FrustumZNear= -1.f;
|
|
_FrustumZFar= 1.f;
|
|
_FrustumPerspective= false;
|
|
_FogStart = 0;
|
|
_FogEnd = 1;
|
|
|
|
_SumTextureMemoryUsed = false;
|
|
|
|
|
|
_DesktopGammaRampValid = false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
CDriverD3D::~CDriverD3D()
|
|
{
|
|
release();
|
|
|
|
if(_D3D != NULL)
|
|
{
|
|
_D3D->Release();
|
|
_D3D = NULL;
|
|
}
|
|
delete _VolatileVertexBufferRAM[0];
|
|
delete _VolatileVertexBufferRAM[1];
|
|
delete _VolatileVertexBufferAGP[0];
|
|
delete _VolatileVertexBufferAGP[1];
|
|
delete _VolatileIndexBuffer16RAM[0];
|
|
delete _VolatileIndexBuffer16RAM[1];
|
|
delete _VolatileIndexBuffer16AGP[0];
|
|
delete _VolatileIndexBuffer16AGP[1];
|
|
delete _VolatileIndexBuffer32RAM[0];
|
|
delete _VolatileIndexBuffer32RAM[1];
|
|
delete _VolatileIndexBuffer32AGP[0];
|
|
delete _VolatileIndexBuffer32AGP[1];
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::resetRenderVariables()
|
|
{
|
|
H_AUTO_D3D(CDriver3D_resetRenderVariables);
|
|
|
|
uint i;
|
|
for (i=0; i<MaxRenderState; i++)
|
|
{
|
|
if (_RenderStateCache[i].ValueSet)
|
|
{
|
|
// here, don't use 0xcccccccc, because it is a valid value for D3DRS_TFACTOR
|
|
touchRenderVariable (&(_RenderStateCache[i]));
|
|
}
|
|
}
|
|
|
|
for (i=0; i<MaxTexture; i++)
|
|
{
|
|
uint j;
|
|
for (j=0; j<MaxTextureState; j++)
|
|
{
|
|
if (_TextureStateCache[i][j].Value != 0xcccccccc)
|
|
{
|
|
touchRenderVariable (&(_TextureStateCache[i][j]));
|
|
_TextureStateCache[i][j].DeviceValue = 0xcccccccc;
|
|
}
|
|
}
|
|
}
|
|
for (i=0; i<MaxTexture; i++)
|
|
{
|
|
if (_TextureIndexStateCache[i].TexGenMode != 0xcccccccc)
|
|
touchRenderVariable (&(_TextureIndexStateCache[i]));
|
|
}
|
|
for (i=0; i<MaxTexture; i++)
|
|
{
|
|
if ((uint32)(_TexturePtrStateCache[i].Texture) != 0xcccccccc)
|
|
{
|
|
touchRenderVariable (&(_TexturePtrStateCache[i]));
|
|
// reset texture because it may reference an old render target
|
|
CTexturePtrState &textureState = (CTexturePtrState &)(_TexturePtrStateCache[i]);
|
|
textureState.Texture = NULL;
|
|
}
|
|
}
|
|
for (i=0; i<MaxSampler; i++)
|
|
{
|
|
uint j;
|
|
for (j=0; j<MaxSamplerState; j++)
|
|
{
|
|
if (_SamplerStateCache[i][j].Value != 0xcccccccc)
|
|
touchRenderVariable (&(_SamplerStateCache[i][j]));
|
|
}
|
|
}
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_VIEW)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_PROJECTION)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE0)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE1)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE2)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE3)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE4)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE5)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE6)]));
|
|
touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE7)]));
|
|
|
|
|
|
// Vertices and indexes are not valid anymore
|
|
_VertexBufferCache.VertexBuffer = NULL;
|
|
_IndexBufferCache.IndexBuffer = NULL;
|
|
_VertexDeclCache.Decl = NULL;
|
|
|
|
touchRenderVariable (&(_VertexBufferCache));
|
|
touchRenderVariable (&(_IndexBufferCache));
|
|
touchRenderVariable (&(_VertexDeclCache));
|
|
|
|
for (i=0; i<MaxLight; i++)
|
|
{
|
|
if (*(uint32*)(&(_LightCache[i].Light)) != 0xcccccccc)
|
|
{
|
|
_LightCache[i].EnabledTouched = true;
|
|
touchRenderVariable (&(_LightCache[i]));
|
|
}
|
|
}
|
|
|
|
// Vertices and indexes are not valid anymore
|
|
_VertexProgramCache.VertexProgram = NULL;
|
|
_VertexProgramCache.VP = NULL;
|
|
touchRenderVariable (&(_VertexProgramCache));
|
|
_PixelShaderCache.PixelShader = NULL;
|
|
touchRenderVariable (&(_PixelShaderCache));
|
|
touchRenderVariable(&_MaterialState);
|
|
|
|
for (i=0; i<MaxVertexProgramConstantState; i++)
|
|
{
|
|
touchRenderVariable (&(_VertexProgramConstantCache[i]));
|
|
}
|
|
for (i=0; i<MaxPixelShaderConstantState; i++)
|
|
{
|
|
touchRenderVariable (&(_PixelShaderConstantCache[i]));
|
|
}
|
|
setRenderTarget (NULL, 0, 0, 0, 0, 0, 0);
|
|
|
|
CVertexBuffer::TLocation vertexAgpLocation = _DisableHardwareVertexArrayAGP ? CVertexBuffer::RAMResident : CVertexBuffer::AGPResident;
|
|
CIndexBuffer::TLocation indexAgpLocation = _DisableHardwareIndexArrayAGP ? CIndexBuffer::RAMResident : CIndexBuffer::AGPResident;
|
|
|
|
// Init volatile vertex buffers
|
|
_VolatileVertexBufferRAM[0]->init (CVertexBuffer::RAMResident, _VolatileVertexBufferRAM[0]->Size, _VolatileVertexBufferRAM[0]->MaxSize, this);
|
|
_VolatileVertexBufferRAM[0]->reset ();
|
|
_VolatileVertexBufferRAM[1]->init (CVertexBuffer::RAMResident, _VolatileVertexBufferRAM[1]->Size, _VolatileVertexBufferRAM[1]->MaxSize, this);
|
|
_VolatileVertexBufferRAM[1]->reset ();
|
|
_VolatileVertexBufferAGP[0]->init (vertexAgpLocation, _VolatileVertexBufferAGP[0]->Size, _VolatileVertexBufferAGP[0]->MaxSize, this);
|
|
_VolatileVertexBufferAGP[0]->reset ();
|
|
_VolatileVertexBufferAGP[1]->init (vertexAgpLocation, _VolatileVertexBufferAGP[1]->Size, _VolatileVertexBufferAGP[1]->MaxSize, this);
|
|
_VolatileVertexBufferAGP[1]->reset ();
|
|
//
|
|
_VolatileIndexBuffer16RAM[0]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer16RAM[0]->Size, _VolatileIndexBuffer16RAM[0]->MaxSize, this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16RAM[0]->reset ();
|
|
_VolatileIndexBuffer16RAM[1]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer16RAM[1]->Size, _VolatileIndexBuffer16RAM[1]->MaxSize, this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16RAM[1]->reset ();
|
|
_VolatileIndexBuffer16AGP[0]->init (indexAgpLocation, _VolatileIndexBuffer16AGP[0]->Size, _VolatileIndexBuffer16AGP[0]->MaxSize, this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16AGP[0]->reset ();
|
|
_VolatileIndexBuffer16AGP[1]->init (indexAgpLocation, _VolatileIndexBuffer16AGP[1]->Size, _VolatileIndexBuffer16AGP[1]->MaxSize, this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16AGP[1]->reset ();
|
|
//
|
|
if (_MaxVertexIndex > 0xffff) // supports 32 bits ?
|
|
{
|
|
_VolatileIndexBuffer32RAM[0]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer32RAM[0]->Size, _VolatileIndexBuffer32RAM[0]->MaxSize, this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32RAM[0]->reset ();
|
|
_VolatileIndexBuffer32RAM[1]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer32RAM[1]->Size, _VolatileIndexBuffer32RAM[1]->MaxSize, this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32RAM[1]->reset ();
|
|
_VolatileIndexBuffer32AGP[0]->init (indexAgpLocation, _VolatileIndexBuffer32AGP[0]->Size, _VolatileIndexBuffer32AGP[0]->MaxSize, this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32AGP[0]->reset ();
|
|
_VolatileIndexBuffer32AGP[1]->init (indexAgpLocation, _VolatileIndexBuffer32AGP[1]->Size, _VolatileIndexBuffer32AGP[1]->MaxSize, this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32AGP[1]->reset ();
|
|
}
|
|
_ScissorTouched = true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::initRenderVariables()
|
|
{
|
|
H_AUTO_D3D(CDriver3D_initRenderVariables);
|
|
uint i;
|
|
for (i=0; i<MaxRenderState; i++)
|
|
{
|
|
_RenderStateCache[i].StateID = (D3DRENDERSTATETYPE)i;
|
|
_RenderStateCache[i].ValueSet = false;
|
|
_RenderStateCache[i].Modified = false;
|
|
}
|
|
for (i=0; i<MaxTexture; i++)
|
|
{
|
|
uint j;
|
|
for (j=0; j<MaxTextureState; j++)
|
|
{
|
|
_TextureStateCache[i][j].StageID = i;
|
|
_TextureStateCache[i][j].StateID = (D3DTEXTURESTAGESTATETYPE)j;
|
|
_TextureStateCache[i][j].Value = 0xcccccccc;
|
|
_TextureStateCache[i][j].Modified = false;
|
|
}
|
|
}
|
|
for (i=0; i<MaxTexture; i++)
|
|
{
|
|
_TextureIndexStateCache[i].StageID = i;
|
|
_TextureIndexStateCache[i].TexGen = false;
|
|
_TextureIndexStateCache[i].TexGenMode = 0xcccccccc;
|
|
_TextureIndexStateCache[i].UVChannel = 0xcccccccc;
|
|
_TextureIndexStateCache[i].Modified = false;
|
|
}
|
|
for (i=0; i<MaxTexture; i++)
|
|
{
|
|
_TexturePtrStateCache[i].StageID = i;
|
|
*(uint32*)&(_TexturePtrStateCache[i].Texture) = 0xcccccccc;
|
|
_TexturePtrStateCache[i].Modified = false;
|
|
}
|
|
for (i=0; i<MaxSampler; i++)
|
|
{
|
|
uint j;
|
|
for (j=0; j<MaxSamplerState; j++)
|
|
{
|
|
_SamplerStateCache[i][j].SamplerID = i;
|
|
_SamplerStateCache[i][j].StateID = (D3DSAMPLERSTATETYPE)j;
|
|
_SamplerStateCache[i][j].Value = 0xcccccccc;
|
|
_SamplerStateCache[i][j].Modified = false;
|
|
}
|
|
}
|
|
for (i=0; i<MaxMatrixState; i++)
|
|
{
|
|
_MatrixCache[i].TransformType = (D3DTRANSFORMSTATETYPE)((i>=MatrixStateRemap)?i-MatrixStateRemap+256:i);
|
|
memset (&(_MatrixCache[i].Matrix), 0xcc, sizeof(D3DXMATRIX));
|
|
_MatrixCache[i].Modified = false;
|
|
}
|
|
_VertexBufferCache.Modified = false;
|
|
_VertexBufferCache.VertexBuffer = NULL;
|
|
_IndexBufferCache.Modified = false;
|
|
_IndexBufferCache.IndexBuffer = NULL;
|
|
_VertexDeclCache.Modified = false;
|
|
_VertexDeclCache.Decl = NULL;
|
|
for (i=0; i<MaxLight; ++i)
|
|
{
|
|
_LightCache[i].LightIndex = uint8(i);
|
|
*(uint32*)&(_LightCache[i].Light) = 0xcccccccc;
|
|
_LightCache[i].Modified = false;
|
|
}
|
|
_VertexProgramCache.Modified = false;
|
|
_VertexProgramCache.VertexProgram = NULL;
|
|
_PixelShaderCache.Modified = false;
|
|
_PixelShaderCache.PixelShader = NULL;
|
|
for (i=0; i<MaxVertexProgramConstantState; i++)
|
|
{
|
|
_VertexProgramConstantCache[i].StateID = i;
|
|
_VertexProgramConstantCache[i].Modified = false;
|
|
_VertexProgramConstantCache[i].ValueType = CVertexProgramConstantState::Undef;
|
|
}
|
|
for (i=0; i<MaxPixelShaderConstantState; i++)
|
|
{
|
|
_PixelShaderConstantCache[i].StateID = i;
|
|
_PixelShaderConstantCache[i].Modified = false;
|
|
_PixelShaderConstantCache[i].ValueType = CPixelShaderConstantState::Undef;
|
|
}
|
|
_RenderTarget.Modified = false;
|
|
|
|
|
|
// Set the render states cache to its default values
|
|
setRenderState (D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA|D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE);
|
|
setRenderState (D3DRS_CULLMODE, D3DCULL_CW);
|
|
setRenderState (D3DRS_FOGENABLE, FALSE);
|
|
|
|
// Stencil Buffer
|
|
//affreux
|
|
setRenderState (D3DRS_STENCILENABLE, _CurStencilTest);
|
|
setRenderState (D3DRS_STENCILFUNC, _CurStencilFunc);
|
|
setRenderState (D3DRS_STENCILREF, _CurStencilRef);
|
|
setRenderState (D3DRS_STENCILMASK, _CurStencilMask);
|
|
setRenderState (D3DRS_STENCILFAIL, _CurStencilOpFail);
|
|
setRenderState (D3DRS_STENCILZFAIL, _CurStencilOpZFail);
|
|
setRenderState (D3DRS_STENCILPASS, _CurStencilOpZPass);
|
|
setRenderState (D3DRS_STENCILWRITEMASK, _CurStencilWriteMask);
|
|
|
|
// Force normalize
|
|
_ForceNormalize = false;
|
|
_UseVertexColor = false;
|
|
|
|
// Material
|
|
_CurrentMaterial = NULL;
|
|
_CurrentMaterialInfo = NULL;
|
|
_CurrentShader = NULL;
|
|
|
|
// Shaders
|
|
initInternalShaders();
|
|
|
|
// Fog default values
|
|
_FogStart = 0;
|
|
_FogEnd = 1;
|
|
setRenderState (D3DRS_FOGSTART, *((DWORD*) (&_FogStart)));
|
|
setRenderState (D3DRS_FOGEND, *((DWORD*) (&_FogEnd)));
|
|
setRenderState (D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
|
|
|
|
// Alpha render states
|
|
setRenderState (D3DRS_ALPHATESTENABLE, FALSE);
|
|
setRenderState (D3DRS_ALPHAREF, 128);
|
|
setRenderState (D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
|
|
|
// Cull mode
|
|
_InvertCullMode = false;
|
|
_DoubleSided = false;
|
|
|
|
// Depth range
|
|
_DepthRangeNear = 0.f;
|
|
_DepthRangeFar = 1.f;
|
|
|
|
// Flush caches
|
|
updateRenderVariablesInternal();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
#define NL_SRC_OPERATORS_COUNT 6
|
|
|
|
// ***************************************************************************
|
|
|
|
static const D3DTEXTURESTAGESTATETYPE SrcOperators[NL_SRC_OPERATORS_COUNT]=
|
|
{
|
|
D3DTSS_COLORARG0,
|
|
D3DTSS_COLORARG1,
|
|
D3DTSS_COLORARG2,
|
|
D3DTSS_ALPHAARG0,
|
|
D3DTSS_ALPHAARG1,
|
|
D3DTSS_ALPHAARG2,
|
|
};
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::updateRenderVariables()
|
|
{
|
|
H_AUTO_D3D(CDriver3D_updateRenderVariables);
|
|
_CurrentMaterial = NULL;
|
|
_CurrentMaterialInfo = NULL;
|
|
|
|
updateRenderVariablesInternal();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
/*
|
|
inline void CDriverD3D::applyRenderVariable(CRenderVariable *currentRenderState)
|
|
{
|
|
switch (currentRenderState->Type)
|
|
{
|
|
case CRenderVariable::RenderState:
|
|
{
|
|
CRenderState *renderState = static_cast<CRenderState*>(currentRenderState);
|
|
_DeviceInterface->SetRenderState (renderState->StateID, renderState->Value);
|
|
}
|
|
break;
|
|
case CRenderVariable::TextureState:
|
|
{
|
|
CTextureState *textureState = static_cast<CTextureState*>(currentRenderState);
|
|
_DeviceInterface->SetTextureStageState (textureState->StageID, textureState->StateID, textureState->Value);
|
|
}
|
|
break;
|
|
case CRenderVariable::TextureIndexState:
|
|
{
|
|
CTextureIndexState *textureState = static_cast<CTextureIndexState*>(currentRenderState);
|
|
if (textureState->TexGen)
|
|
setTextureState (textureState->StageID, D3DTSS_TEXCOORDINDEX, textureState->TexGenMode);
|
|
else
|
|
setTextureState (textureState->StageID, D3DTSS_TEXCOORDINDEX, textureState->UVChannel);
|
|
}
|
|
break;
|
|
case CRenderVariable::TexturePtrState:
|
|
{
|
|
CTexturePtrState *textureState = static_cast<CTexturePtrState*>(currentRenderState);
|
|
_DeviceInterface->SetTexture (textureState->StageID, textureState->Texture);
|
|
}
|
|
break;
|
|
case CRenderVariable::VertexProgramPtrState:
|
|
{
|
|
CVertexProgramPtrState *vertexProgram = static_cast<CVertexProgramPtrState*>(currentRenderState);
|
|
_DeviceInterface->SetVertexShader(vertexProgram->VertexProgram);
|
|
}
|
|
break;
|
|
case CRenderVariable::PixelShaderPtrState:
|
|
{
|
|
CPixelShaderPtrState *pixelShader = static_cast<CPixelShaderPtrState*>(currentRenderState);
|
|
_DeviceInterface->SetPixelShader(pixelShader->PixelShader);
|
|
}
|
|
break;
|
|
case CRenderVariable::VertexProgramConstantState:
|
|
{
|
|
CVertexProgramConstantState *vertexProgramConstant = static_cast<CVertexProgramConstantState*>(currentRenderState);
|
|
switch (vertexProgramConstant->ValueType)
|
|
{
|
|
case CVertexProgramConstantState::Float:
|
|
_DeviceInterface->SetVertexShaderConstantF (vertexProgramConstant->StateID, (float*)vertexProgramConstant->Values, 1);
|
|
break;
|
|
case CVertexProgramConstantState::Int:
|
|
_DeviceInterface->SetVertexShaderConstantI (vertexProgramConstant->StateID, (int*)vertexProgramConstant->Values, 1);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case CRenderVariable::PixelShaderConstantState:
|
|
{
|
|
CPixelShaderConstantState *pixelShaderConstant = static_cast<CPixelShaderConstantState*>(currentRenderState);
|
|
switch (pixelShaderConstant->ValueType)
|
|
{
|
|
case CPixelShaderConstantState::Float:
|
|
_DeviceInterface->SetPixelShaderConstantF (pixelShaderConstant->StateID, (float*)pixelShaderConstant->Values, 1);
|
|
break;
|
|
case CPixelShaderConstantState::Int:
|
|
_DeviceInterface->SetPixelShaderConstantI (pixelShaderConstant->StateID, (int*)pixelShaderConstant->Values, 1);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case CRenderVariable::SamplerState:
|
|
{
|
|
CSamplerState *samplerState = static_cast<CSamplerState*>(currentRenderState);
|
|
_DeviceInterface->SetSamplerState (samplerState->SamplerID, samplerState->StateID, samplerState->Value);
|
|
}
|
|
break;
|
|
case CRenderVariable::MatrixState:
|
|
{
|
|
CMatrixState *renderMatrix = static_cast<CMatrixState*>(currentRenderState);
|
|
_DeviceInterface->SetTransform (renderMatrix->TransformType, &(renderMatrix->Matrix));
|
|
}
|
|
break;
|
|
case CRenderVariable::VBState:
|
|
{
|
|
CVBState *renderVB = static_cast<CVBState*>(currentRenderState);
|
|
if (renderVB->VertexBuffer)
|
|
{
|
|
_DeviceInterface->SetStreamSource (0, renderVB->VertexBuffer, renderVB->Offset, renderVB->Stride);
|
|
}
|
|
}
|
|
break;
|
|
case CRenderVariable::IBState:
|
|
{
|
|
CIBState *renderIB = static_cast<CIBState*>(currentRenderState);
|
|
if (renderIB->IndexBuffer)
|
|
{
|
|
_DeviceInterface->SetIndices (renderIB->IndexBuffer);
|
|
}
|
|
}
|
|
break;
|
|
case CRenderVariable::VertexDecl:
|
|
{
|
|
CVertexDeclState *renderVB = static_cast<CVertexDeclState*>(currentRenderState);
|
|
if (renderVB->Decl)
|
|
{
|
|
_DeviceInterface->SetVertexDeclaration (renderVB->Decl);
|
|
}
|
|
}
|
|
break;
|
|
case CRenderVariable::LightState:
|
|
{
|
|
CLightState *renderLight = static_cast<CLightState*>(currentRenderState);
|
|
|
|
// Enabel state modified ?
|
|
if (renderLight->EnabledTouched)
|
|
_DeviceInterface->LightEnable (renderLight->LightIndex, renderLight->Enabled);
|
|
|
|
// Light enabled ?
|
|
if (renderLight->Enabled)
|
|
{
|
|
if (renderLight->SettingsTouched)
|
|
{
|
|
// New position
|
|
renderLight->Light.Position.x -= _PZBCameraPos.x;
|
|
renderLight->Light.Position.y -= _PZBCameraPos.y;
|
|
renderLight->Light.Position.z -= _PZBCameraPos.z;
|
|
_DeviceInterface->SetLight (renderLight->LightIndex, &(renderLight->Light));
|
|
renderLight->SettingsTouched = false;
|
|
}
|
|
}
|
|
|
|
// Clean
|
|
renderLight->EnabledTouched = false;
|
|
}
|
|
break;
|
|
case CRenderVariable::RenderTargetState:
|
|
{
|
|
CRenderTargetState *renderTarget = static_cast<CRenderTargetState*>(currentRenderState);
|
|
_DeviceInterface->SetRenderTarget (0, renderTarget->Target);
|
|
setupViewport (_Viewport);
|
|
setupScissor (_Scissor);
|
|
}
|
|
break;
|
|
}
|
|
}*/
|
|
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
#ifdef NL_DEBUG
|
|
inline
|
|
#endif
|
|
void CDriverD3D::replaceArgumentAtStage(D3DTEXTURESTAGESTATETYPE state, DWORD stage, DWORD from, DWORD to)
|
|
{
|
|
if ((_TextureStateCache[stage][state].Value & D3DTA_SELECTMASK) == from)
|
|
{
|
|
setTextureState (stage, state, (_TextureStateCache[stage][state].Value&~D3DTA_SELECTMASK)|to);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Replace a constant with diffuse color at the given stage
|
|
#ifdef NL_DEBUG
|
|
inline
|
|
#endif
|
|
void CDriverD3D::replaceAllRGBArgumentAtStage(uint stage, DWORD from, DWORD to, DWORD blendOpFrom)
|
|
{
|
|
replaceArgumentAtStage(D3DTSS_COLORARG1, stage, from, to);
|
|
if (_CurrentMaterialInfo->NumColorArg[stage] > 1)
|
|
{
|
|
replaceArgumentAtStage(D3DTSS_COLORARG2, stage, from, to);
|
|
if (_CurrentMaterialInfo->NumColorArg[stage] > 2)
|
|
{
|
|
replaceArgumentAtStage(D3DTSS_COLORARG0, stage, from, to);
|
|
}
|
|
}
|
|
//
|
|
// Operator is D3DTOP_BLENDDIFFUSEALPHA ?
|
|
if (_TextureStateCache[stage][D3DTSS_COLOROP].Value == blendOpFrom)
|
|
{
|
|
setTextureState (stage, D3DTSS_COLOROP, D3DTOP_LERP);
|
|
setTextureState (stage, D3DTSS_COLORARG0, to|D3DTA_ALPHAREPLICATE);
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef NL_DEBUG
|
|
inline
|
|
#endif
|
|
void CDriverD3D::replaceAllAlphaArgumentAtStage(uint stage, DWORD from, DWORD to, DWORD blendOpFrom)
|
|
{
|
|
replaceArgumentAtStage(D3DTSS_ALPHAARG1, stage, from, to);
|
|
if (_CurrentMaterialInfo->NumAlphaArg[stage] > 1)
|
|
{
|
|
replaceArgumentAtStage(D3DTSS_ALPHAARG2, stage, from, to);
|
|
if (_CurrentMaterialInfo->NumAlphaArg[stage] > 2)
|
|
{
|
|
replaceArgumentAtStage(D3DTSS_ALPHAARG0, stage, from, to);
|
|
}
|
|
}
|
|
if (_TextureStateCache[stage][D3DTSS_ALPHAOP].Value == blendOpFrom)
|
|
{
|
|
setTextureState (stage, D3DTSS_ALPHAOP, D3DTOP_LERP);
|
|
setTextureState (stage, D3DTSS_ALPHAARG0, to);
|
|
}
|
|
}
|
|
|
|
#ifdef NL_DEBUG
|
|
inline
|
|
#endif
|
|
void CDriverD3D::replaceAllArgumentAtStage(uint stage, DWORD from, DWORD to, DWORD blendOpFrom)
|
|
{
|
|
if (_CurrentMaterialInfo->RGBPipe[stage])
|
|
{
|
|
replaceAllRGBArgumentAtStage(stage, from, to, blendOpFrom);
|
|
}
|
|
if (_CurrentMaterialInfo->AlphaPipe[stage])
|
|
{
|
|
replaceAllAlphaArgumentAtStage(stage, from, to, blendOpFrom);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Replace all argument at relevant stages with the given value
|
|
#ifdef NL_DEBUG
|
|
inline
|
|
#endif
|
|
void CDriverD3D::replaceAllArgument(DWORD from, DWORD to, DWORD blendOpFrom)
|
|
{
|
|
const uint maxTexture = inlGetNumTextStages();
|
|
// Look for texture state
|
|
for (uint i=0; i<maxTexture; i++)
|
|
{
|
|
if (_CurrentMaterialInfo->ColorOp[i] == D3DTOP_DISABLE) break;
|
|
replaceAllArgumentAtStage(i, from, to, blendOpFrom);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
#ifdef NL_DEBUG
|
|
inline
|
|
#endif
|
|
void CDriverD3D::setupConstantDiffuseColorFromLightedMaterial(D3DCOLOR color)
|
|
{
|
|
for(uint i=1;i<_MaxLight;++i)
|
|
enableLightInternal(uint8(i), false);
|
|
_LightMapDynamicLightDirty= true;
|
|
D3DMATERIAL9 d3dMat;
|
|
setColor(d3dMat.Diffuse, 0.f, 0.f, 0.f, (1.f / 255.f) * (color >> 24));
|
|
setColor(d3dMat.Ambient, 0.f, 0.f, 0.f, 0.f);
|
|
setColor(d3dMat.Specular, 0.f, 0.f, 0.f, 0.f);
|
|
setColor(d3dMat.Emissive, color);
|
|
setMaterialState(d3dMat);
|
|
setRenderState(D3DRS_LIGHTING, TRUE);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::updateRenderVariablesInternal()
|
|
{
|
|
H_AUTO_D3D(CDriver3D_updateRenderVariablesInternal);
|
|
nlassert (_DeviceInterface);
|
|
bool aliasDiffuseToSpecular = false;
|
|
bool enableVertexColorFlag = true;
|
|
if (_CurrentMaterialInfo && (_CurrentMaterialInfo->NeedsConstantForDiffuse || _CurrentMaterialInfo->MultipleConstantNoPixelShader)) /* The "unlighted without vertex color" trick */
|
|
{
|
|
// The material IS unlighted
|
|
// No pixel shader ?
|
|
if (_CurrentMaterialInfo->PixelShader)
|
|
{
|
|
/*
|
|
* We have to set the pixel shader now, because we have to choose between normal pixel shader and pixel shader without vertex color */
|
|
// Must have two pixel shader
|
|
nlassert (_CurrentMaterialInfo->PixelShaderUnlightedNoVertexColor);
|
|
if (!_UseVertexColor && (_VertexProgramCache.VertexProgram == NULL))
|
|
{
|
|
setPixelShader (_CurrentMaterialInfo->PixelShaderUnlightedNoVertexColor);
|
|
}
|
|
else
|
|
{
|
|
setPixelShader (_CurrentMaterialInfo->PixelShader);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setPixelShader (NULL);
|
|
if (_CurrentMaterialInfo->NeedsConstantForDiffuse)
|
|
{
|
|
/*
|
|
* We have to change all texture state setuped to D3DTA_DIFFUSE into D3DTA_TFACTOR
|
|
* if we use a vertex buffer with diffuse color vertex with an unlighted material and no vertex program */
|
|
if (_VertexProgramCache.VertexProgram)
|
|
{
|
|
// Diffuse should be output from vertex program
|
|
// So we can only emulate 1 per stage constant (it has already been setup in CDriverD3D::setupMaterial)
|
|
#ifdef NL_DEBUG
|
|
nlassert(!_CurrentMaterialInfo->MultipleConstantNoPixelShader);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (!_UseVertexColor)
|
|
{
|
|
if (!_CurrentMaterialInfo->MultipleConstantNoPixelShader)
|
|
{
|
|
// Diffuse is used, but no other constant is used in the shader
|
|
// Max texture
|
|
replaceAllArgument(D3DTA_DIFFUSE, D3DTA_TFACTOR, D3DTOP_BLENDDIFFUSEALPHA);
|
|
setRenderState (D3DRS_TEXTUREFACTOR, _CurrentMaterialInfo->UnlightedColor);
|
|
}
|
|
else
|
|
{
|
|
#ifdef NL_DEBUG
|
|
nlassert(!_CurrentMaterialInfo->MultiplePerStageConstant); // Can't render this material on current hardware
|
|
#endif
|
|
//replaceAllArgumentAtStage(_CurrentMaterialInfo->ConstantIndex, D3DTA_TFACTOR, D3DTA_DIFFUSE, D3DTOP_BLENDFACTORALPHA);
|
|
setupConstantDiffuseColorFromLightedMaterial(_CurrentMaterialInfo->UnlightedColor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_CurrentMaterialInfo->MultiplePerStageConstant)
|
|
{
|
|
// vertex color, 1st constant from CMaterial::getColor (already setuped in CDriverD3D::setupMaterial)
|
|
// 2nd constant from a stage constant
|
|
// Vertex color is aliased to the specular stream -> all references to D3DTA_DIFFUSE must be replaced with references to D3DTA_SPECULAR
|
|
replaceAllArgument(D3DTA_DIFFUSE, D3DTA_SPECULAR, 0xffffffff);
|
|
aliasDiffuseToSpecular = true;
|
|
replaceAllArgumentAtStage(_CurrentMaterialInfo->ConstantIndex2, D3DTA_TFACTOR, D3DTA_DIFFUSE, D3DTOP_BLENDFACTORALPHA);
|
|
setupConstantDiffuseColorFromLightedMaterial(NL_D3DCOLOR_RGBA(_CurrentMaterialInfo->Constant2)); // set 2nd per stage constant
|
|
#ifdef NL_DEBUG
|
|
nlassert(_VertexDeclCache.DeclAliasDiffuseToSpecular); // VB must not have specular used ... else this material can't render
|
|
#endif
|
|
// NB : currently this don't work with the GeForce2 (seems to be a driver bug). Fortunately, this case isn't encountered with Ryzom materials :)
|
|
// So it's provided for convenience.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlassert(_CurrentMaterialInfo->MultipleConstantNoPixelShader);
|
|
// If vertex color is used, alias it to specular
|
|
/*
|
|
if (_UseVertexColor)
|
|
{
|
|
replaceAllArgument(D3DTA_DIFFUSE, D3DTA_SPECULAR, 0xffffffff);
|
|
aliasDiffuseToSpecular = true; // VB must not have specular used ... else this material can't render
|
|
}
|
|
*/
|
|
// up to 2 constants with no pixel shaders
|
|
// look for constant at other stages and replaces then with diffuse color
|
|
// first constant color has already been set yet (in CD3DDriver::setupMaterial)
|
|
replaceAllArgumentAtStage(_CurrentMaterialInfo->ConstantIndex2, D3DTA_TFACTOR, D3DTA_DIFFUSE, D3DTOP_BLENDFACTORALPHA);
|
|
setupConstantDiffuseColorFromLightedMaterial(NL_D3DCOLOR_RGBA(_CurrentMaterialInfo->Constant2)); // set 2nd per stage constant
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_CurrentMaterialInfo) enableVertexColorFlag = _CurrentMaterialInfo->VertexColorLighted;
|
|
}
|
|
|
|
|
|
if (_NbNeLTextureStages == 3)
|
|
{
|
|
// Fix (one more...) for Radeon 7xxx
|
|
// Don't know why, but the lighting is broken when MULTIPLYADD is used as in the lightmap shader..
|
|
// Correct behaviour with GeForce & Ref. rasterizer...
|
|
// The fix is to disable the light contribution from dynamic lights
|
|
if (_TextureStateCache[0][D3DTSS_COLOROP].Value == D3DTOP_MULTIPLYADD &&
|
|
_TextureStateCache[0][D3DTSS_COLORARG0].Value == D3DTA_DIFFUSE
|
|
)
|
|
{
|
|
_TextureStateCache[0][D3DTSS_COLOROP].Value = D3DTOP_MODULATE;
|
|
touchRenderVariable(&_TextureStateCache[0][D3DTSS_COLOROP]);
|
|
}
|
|
// fix for radeon 7xxx -> should enable vertex color only if really used in pixel pipe
|
|
setEnableVertexColor(enableVertexColorFlag);
|
|
}
|
|
setAliasDiffuseToSpecular(aliasDiffuseToSpecular);
|
|
|
|
|
|
// Flush all the modified render states
|
|
while (_ModifiedRenderState)
|
|
{
|
|
// Current variable
|
|
CRenderVariable *currentRenderState = _ModifiedRenderState;
|
|
|
|
// It is clean now
|
|
currentRenderState->Modified = false;
|
|
|
|
// Unlinked
|
|
_ModifiedRenderState = currentRenderState->NextModified;
|
|
currentRenderState->apply(this);
|
|
}
|
|
|
|
|
|
// Maybe it is a driver bug : in some situation with GeForce, I got vertex color set to (0, 0, 0, 0) with unlighted vertices and vertex color.
|
|
// Forcing to resetup material solves the prb.. (though D3DRS_LIGHTING is set to FALSE ...)
|
|
// I only have the prb with GeForce. The behaviour doesn't exhibit when using the D3D debug dll.
|
|
if (_IsGeforce)
|
|
{
|
|
if (_RenderStateCache[D3DRS_LIGHTING].Value == FALSE && _VertexProgramCache.VertexProgram == NULL)
|
|
{
|
|
_MaterialState.apply(this);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
static void D3DWndProc(CDriverD3D *driver, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
H_AUTO_D3D(D3DWndProc);
|
|
|
|
// Check this message in parents
|
|
|
|
if ((message == WM_SIZE) || (message == WM_EXITSIZEMOVE) || (message == WM_MOVE))
|
|
{
|
|
if (driver != NULL)
|
|
{
|
|
// *** Check the hwnd is the root parent of driver->_HWnd
|
|
|
|
// hwnd must be a _HWnd parent
|
|
bool sameWindow = hWnd == driver->_HWnd;
|
|
bool rootWindow = false;
|
|
HWND tmp = driver->_HWnd;
|
|
while (tmp)
|
|
{
|
|
if (tmp == hWnd)
|
|
{
|
|
rootWindow = true;
|
|
break;
|
|
}
|
|
tmp = GetParent (tmp);
|
|
}
|
|
|
|
// hwnd must be a top window
|
|
rootWindow &= (GetParent (hWnd) == NULL);
|
|
|
|
// This is a root parent, not _HWnd
|
|
if (rootWindow)
|
|
{
|
|
if (message == WM_SIZE)
|
|
{
|
|
if( SIZE_MAXIMIZED == wParam)
|
|
{
|
|
driver->_Maximized = true;
|
|
if (sameWindow)
|
|
driver->handlePossibleSizeChange();
|
|
else
|
|
driver->_HandlePossibleSizeChangeNextSize = true;
|
|
}
|
|
else if( SIZE_RESTORED == wParam)
|
|
{
|
|
if (driver->_Maximized)
|
|
{
|
|
driver->_Maximized = false;
|
|
if (sameWindow)
|
|
driver->handlePossibleSizeChange();
|
|
else
|
|
driver->_HandlePossibleSizeChangeNextSize = true;
|
|
}
|
|
}
|
|
}
|
|
else if(message == WM_EXITSIZEMOVE)
|
|
{
|
|
if (driver != NULL)
|
|
{
|
|
driver->handlePossibleSizeChange();
|
|
}
|
|
}
|
|
else if(message == WM_MOVE)
|
|
{
|
|
if (driver != NULL)
|
|
{
|
|
RECT rect;
|
|
GetWindowRect (hWnd, &rect);
|
|
driver->_WindowX = rect.left;
|
|
driver->_WindowY = rect.top;
|
|
}
|
|
}
|
|
}
|
|
// This is the window itself
|
|
else if (sameWindow)
|
|
{
|
|
if (message == WM_SIZE)
|
|
{
|
|
if (driver->_HandlePossibleSizeChangeNextSize)
|
|
{
|
|
driver->handlePossibleSizeChange();
|
|
driver->_HandlePossibleSizeChangeNextSize = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (driver->_EventEmitter.getNumEmitters() > 0)
|
|
{
|
|
CWinEventEmitter *we = NLMISC::safe_cast<CWinEventEmitter *>(driver->_EventEmitter.getEmitter(0));
|
|
// Process the message by the emitter
|
|
we->setHWnd(hWnd);
|
|
we->processMessage (hWnd, message, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::handlePossibleSizeChange()
|
|
{
|
|
//DUMP_AUTO(handlePossibleSizeChange);
|
|
H_AUTO_D3D(CDriver3D_handlePossibleSizeChange);
|
|
// If windowed, check if the size as changed
|
|
if (_CurrentMode.Windowed)
|
|
{
|
|
RECT rect;
|
|
GetClientRect (_HWnd, &rect);
|
|
|
|
// Setup d3d resolution
|
|
uint16 newWidth = uint16(rect.right-rect.left);
|
|
uint16 newHeight = uint16(rect.bottom-rect.top);
|
|
|
|
// Set the new mode. Only change the size, keep the last setDisplay/setMode settings
|
|
GfxMode mode = _CurrentMode;
|
|
mode.Width = newWidth;
|
|
mode.Height = newHeight;
|
|
|
|
if ( ( (mode.Width != _CurrentMode.Width) || (mode.Height != _CurrentMode.Height) ) &&
|
|
( mode.Width != 0 ) &&
|
|
( mode.Height != 0 ) )
|
|
{
|
|
return reset (mode);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
H_AUTO_D3D(WndProc);
|
|
// Get the driver pointer..
|
|
CDriverD3D *pDriver=(CDriverD3D*)GetWindowLongPtrW (hWnd, GWLP_USERDATA);
|
|
if (pDriver != NULL)
|
|
{
|
|
D3DWndProc (pDriver, hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
#ifdef NL_DISABLE_MENU
|
|
// disable menu (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
|
|
if(message == WM_SYSCOMMAND && wParam == SC_KEYMENU)
|
|
return 0;
|
|
#endif // NL_DISABLE_MENU
|
|
|
|
// ace: if we receive close, exit now or it'll assert after
|
|
if(message == WM_CLOSE)
|
|
{
|
|
if(pDriver && pDriver->ExitFunc)
|
|
{
|
|
pDriver->ExitFunc();
|
|
}
|
|
else
|
|
{
|
|
#ifndef NL_DISABLE_MENU
|
|
// if we don't disable menu, alt F4 make a direct exit else we discard the message
|
|
exit(0);
|
|
#endif // NL_DISABLE_MENU
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return DefWindowProcW(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::init (uint windowIcon, emptyProc exitFunc)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_init );
|
|
|
|
ExitFunc = exitFunc;
|
|
|
|
createCursors();
|
|
|
|
// Register a window class
|
|
WNDCLASSW wc;
|
|
|
|
memset(&wc,0,sizeof(wc));
|
|
wc.style = 0; // CS_HREDRAW | CS_VREDRAW ;//| CS_DBLCLKS;
|
|
wc.lpfnWndProc = (WNDPROC)WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = GetModuleHandleW(NULL);
|
|
wc.hIcon = (HICON)windowIcon;
|
|
wc.hCursor = _DefaultCursor;
|
|
wc.hbrBackground = WHITE_BRUSH;
|
|
_WindowClass = "NLD3D" + toString(windowIcon);
|
|
ucstring us = _WindowClass;
|
|
wc.lpszClassName = (LPCWSTR)us.c_str();
|
|
wc.lpszMenuName = NULL;
|
|
if (!RegisterClassW(&wc))
|
|
{
|
|
DWORD error = GetLastError();
|
|
if (error != ERROR_CLASS_ALREADY_EXISTS)
|
|
{
|
|
nlwarning("CDriverD3D::init: Can't register window class %s (error code %i)", _WindowClass.c_str(), (sint)error);
|
|
_WindowClass = "";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
// From the SDK
|
|
bool CDriverD3D::isDepthFormatOk(UINT adapter, D3DDEVTYPE rasterizer, D3DFORMAT DepthFormat,
|
|
D3DFORMAT AdapterFormat,
|
|
D3DFORMAT BackBufferFormat)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_isDepthFormatOk);
|
|
// Verify that the depth format exists
|
|
HRESULT hr = _D3D->CheckDeviceFormat(adapter,
|
|
rasterizer,
|
|
AdapterFormat,
|
|
D3DUSAGE_DEPTHSTENCIL,
|
|
D3DRTYPE_SURFACE,
|
|
DepthFormat);
|
|
|
|
if(FAILED(hr)) return FALSE;
|
|
|
|
// Verify that the depth format is compatible
|
|
hr = _D3D->CheckDepthStencilMatch(adapter,
|
|
(D3DDEVTYPE) rasterizer,
|
|
AdapterFormat,
|
|
BackBufferFormat,
|
|
DepthFormat);
|
|
|
|
return SUCCEEDED(hr);
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const D3DFORMAT FinalPixelFormat[ITexture::UploadFormatCount][CDriverD3D::FinalPixelFormatChoice]=
|
|
{
|
|
{ D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // Auto
|
|
{ D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGBA8888
|
|
{ D3DFMT_A4R4G4B4, D3DFMT_A1R5G5B5, D3DFMT_A8R3G3B2, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGBA4444
|
|
{ D3DFMT_A1R5G5B5, D3DFMT_A4R4G4B4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGBA5551
|
|
{ D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGB888
|
|
{ D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGB565
|
|
{ D3DFMT_DXT1, D3DFMT_R3G3B2, D3DFMT_A1R5G5B5, D3DFMT_R5G6B5, D3DFMT_A8R8G8B8 }, // DXTC1
|
|
{ D3DFMT_DXT1, D3DFMT_R3G3B2, D3DFMT_A1R5G5B5, D3DFMT_R5G6B5, D3DFMT_A8R8G8B8 }, // DXTC1Alpha
|
|
{ D3DFMT_DXT3, D3DFMT_A4R4G4B4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // DXTC3
|
|
{ D3DFMT_DXT5, D3DFMT_A4R4G4B4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // DXTC5
|
|
{ D3DFMT_L8, D3DFMT_A8L8, D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_A8R8G8B8 }, // Luminance
|
|
{ D3DFMT_A8, D3DFMT_A8L8, D3DFMT_A8R3G3B2, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // Alpha
|
|
{ D3DFMT_A8L8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // AlphaLuminance
|
|
{ D3DFMT_V8U8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // DsDt
|
|
};
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable) throw(EBadDisplay)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_setDisplay);
|
|
if (!_D3D)
|
|
return false;
|
|
#ifndef NL_NO_ASM
|
|
CFpuRestorer fpuRestorer;
|
|
#endif
|
|
// Release the driver if already setuped
|
|
release ();
|
|
|
|
// Should be initialized
|
|
nlassert (!_WindowClass.empty());
|
|
|
|
// Should be released
|
|
nlassert (_DeviceInterface == NULL);
|
|
nlassert (_HWnd == NULL);
|
|
|
|
// memorize desktop gamma ramp
|
|
HDC dc = CreateDCW (L"DISPLAY", NULL, NULL, NULL);
|
|
if (dc)
|
|
{
|
|
_DesktopGammaRampValid = GetDeviceGammaRamp (dc, _DesktopGammaRamp) != FALSE;
|
|
// Release the DC
|
|
ReleaseDC (NULL, dc);
|
|
}
|
|
|
|
// Create a window
|
|
_HWnd = wnd;
|
|
|
|
// Reset window state
|
|
_Maximized = false;
|
|
_HandlePossibleSizeChangeNextSize = false;
|
|
|
|
if (_HWnd)
|
|
{
|
|
// We don't have to destroy this window
|
|
_DestroyWindow = false;
|
|
|
|
// Init Window Width and Height
|
|
RECT clientRect;
|
|
GetClientRect (_HWnd, &clientRect);
|
|
_CurrentMode.OffScreen = false;
|
|
_CurrentMode.Width = (uint16)(clientRect.right-clientRect.left);
|
|
_CurrentMode.Height = (uint16)(clientRect.bottom-clientRect.top);
|
|
_CurrentMode.Frequency = 0;
|
|
_CurrentMode.Windowed = true;
|
|
_CurrentMode.Depth = 32;
|
|
}
|
|
else
|
|
{
|
|
_CurrentMode = mode;
|
|
|
|
// We have to destroy this window
|
|
_DestroyWindow = true;
|
|
|
|
// Window flags
|
|
//ULONG WndFlags=(mode.Windowed?D3D_WINDOWED_STYLE:D3D_FULLSCREEN_STYLE)&~WS_VISIBLE;
|
|
ULONG WndFlags;
|
|
if(mode.Windowed)
|
|
{
|
|
WndFlags = D3D_WINDOWED_STYLE;
|
|
if(!resizeable)
|
|
{
|
|
WndFlags &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WndFlags = D3D_FULLSCREEN_STYLE;
|
|
findNearestFullscreenVideoMode();
|
|
}
|
|
|
|
WndFlags &= ~WS_VISIBLE;
|
|
|
|
// Window rect
|
|
RECT WndRect;
|
|
WndRect.left=0;
|
|
WndRect.top=0;
|
|
WndRect.right=_CurrentMode.Width;
|
|
WndRect.bottom=_CurrentMode.Height;
|
|
AdjustWindowRect(&WndRect,WndFlags,FALSE);
|
|
|
|
// Create
|
|
ucstring ustr(_WindowClass);
|
|
_HWnd = CreateWindowW((LPCWSTR)ustr.c_str(), L"", WndFlags, CW_USEDEFAULT,CW_USEDEFAULT, WndRect.right-WndRect.left,WndRect.bottom-WndRect.top, NULL, NULL,
|
|
GetModuleHandleW(NULL), NULL);
|
|
if (!_HWnd)
|
|
{
|
|
nlwarning ("CreateWindowW failed");
|
|
release();
|
|
return false;
|
|
}
|
|
|
|
// Set the window long integer
|
|
SetWindowLongPtrW (_HWnd, GWLP_USERDATA, (LONG_PTR)this);
|
|
|
|
// Show the window
|
|
if (show || !_CurrentMode.Windowed)
|
|
showWindow(true);
|
|
}
|
|
|
|
// Choose an adapter
|
|
UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
|
|
|
|
// Get adapter format
|
|
D3DDISPLAYMODE adapterMode;
|
|
if (_D3D->GetAdapterDisplayMode (adapter, &adapterMode) != D3D_OK)
|
|
{
|
|
nlwarning ("GetAdapterDisplayMode failed");
|
|
release();
|
|
return false;
|
|
}
|
|
|
|
// The following code is taken from the NVPerfHud user guide
|
|
// Set default settings
|
|
_Rasterizer = RASTERIZER;
|
|
#ifdef NL_D3D_USE_NV_PERF_HUD
|
|
// Look for 'NVIDIA NVPerfHUD' adapter
|
|
// If it is present, override default settings
|
|
for (UINT adapterIndex = 0; adapterIndex < _D3D->GetAdapterCount(); adapterIndex++)
|
|
{
|
|
D3DADAPTER_IDENTIFIER9 identifier;
|
|
HRESULT res = _D3D->GetAdapterIdentifier(adapterIndex, 0, &identifier);
|
|
if (strstr(identifier.Description, "PerfHUD") != 0)
|
|
{
|
|
adapter = adapterIndex;
|
|
_Adapter = adapter;
|
|
_Rasterizer = D3DDEVTYPE_REF;
|
|
nlinfo("Using NVIDIA NVPerfHUD adapter");
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Create device options
|
|
D3DPRESENT_PARAMETERS parameters;
|
|
D3DFORMAT adapterFormat;
|
|
if (!fillPresentParameter (parameters, adapterFormat, _CurrentMode, adapterMode))
|
|
{
|
|
release();
|
|
return false;
|
|
}
|
|
|
|
#if WITH_PERFHUD
|
|
// Look for 'NVIDIA PerfHUD' adapter
|
|
// If it is present, override default settings
|
|
for (UINT gAdapter=0;gAdapter<_D3D->GetAdapterCount();gAdapter++)
|
|
{
|
|
D3DADAPTER_IDENTIFIER9 Identifier;
|
|
HRESULT Res;
|
|
Res = _D3D->GetAdapterIdentifier(gAdapter,0,&Identifier);
|
|
|
|
if (strstr(Identifier.Description,"PerfHUD") != 0)
|
|
{
|
|
nlinfo ("Setting up with PerfHUD");
|
|
adapter=gAdapter;
|
|
_Rasterizer=D3DDEVTYPE_REF;
|
|
break;
|
|
}
|
|
}
|
|
#endif WITH_PERFHUD
|
|
// Create the D3D device
|
|
HRESULT result = _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE, ¶meters, &_DeviceInterface);
|
|
if (result != D3D_OK)
|
|
{
|
|
nlwarning ("Can't create device hr:0x%x adap:0x%x rast:0x%x", result, adapter, _Rasterizer);
|
|
|
|
// Create the D3D device without puredevice
|
|
HRESULT result = _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, ¶meters, &_DeviceInterface);
|
|
if (result != D3D_OK)
|
|
{
|
|
nlwarning ("Can't create device without puredevice hr:0x%x adap:0x%x rast:0x%x", result, adapter, _Rasterizer);
|
|
|
|
// Create the D3D device without puredevice and hardware
|
|
HRESULT result = _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶meters, &_DeviceInterface);
|
|
if (result != D3D_OK)
|
|
{
|
|
nlwarning ("Can't create device without puredevice and hardware hr:0x%x adap:0x%x rast:0x%x", result, adapter, _Rasterizer);
|
|
release();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶meters, &_DeviceInterface);
|
|
|
|
// Check some caps
|
|
D3DCAPS9 caps;
|
|
if (_DeviceInterface->GetDeviceCaps(&caps) == D3D_OK)
|
|
{
|
|
_TextureCubeSupported = (caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0;
|
|
_NbNeLTextureStages = (caps.MaxSimultaneousTextures<IDRV_MAT_MAXTEXTURES)?caps.MaxSimultaneousTextures:IDRV_MAT_MAXTEXTURES;
|
|
_MADOperatorSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_MULTIPLYADD) != 0;
|
|
_EMBMSupported = (caps.TextureOpCaps & D3DTOP_BUMPENVMAP) != 0;
|
|
_PixelShaderVersion = caps.PixelShaderVersion;
|
|
_CubbedMipMapSupported = (caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP) != 0;
|
|
_MaxPrimitiveCount = caps.MaxPrimitiveCount;
|
|
_MaxVertexIndex = caps.MaxVertexIndex;
|
|
_IsGeforce = !(caps.DevCaps & D3DDEVCAPS_NPATCHES) && (caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(1, 4));
|
|
_NonPowerOfTwoTexturesSupported = !(caps.TextureCaps & D3DPTEXTURECAPS_POW2) || (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
|
|
_MaxAnisotropy = caps.MaxAnisotropy;
|
|
_AnisotropicMinSupported = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
|
|
_AnisotropicMagSupported = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
|
|
_AnisotropicMinCubeSupported = (caps.CubeTextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
|
|
_AnisotropicMagCubeSupported = (caps.CubeTextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
|
|
}
|
|
else
|
|
{
|
|
_TextureCubeSupported = false;
|
|
_NbNeLTextureStages = 1;
|
|
_MADOperatorSupported = false;
|
|
_EMBMSupported = false;
|
|
_CubbedMipMapSupported = false;
|
|
_PixelShaderVersion = 0;
|
|
_MaxPrimitiveCount = 0xffff;
|
|
_MaxVertexIndex = 0xffff;
|
|
_IsGeforce = false;
|
|
_NonPowerOfTwoTexturesSupported = false;
|
|
_MaxAnisotropy = 0;
|
|
_AnisotropicMinSupported = false;
|
|
_AnisotropicMagSupported = false;
|
|
_AnisotropicMinCubeSupported = false;
|
|
_AnisotropicMagCubeSupported = false;
|
|
}
|
|
// If 16 bits vertices only, build a vb for quads rendering
|
|
if (_MaxVertexIndex <= 0xffff)
|
|
{
|
|
if (!buildQuadIndexBuffer()) return false;
|
|
}
|
|
|
|
// test for occlusion query support
|
|
IDirect3DQuery9 *dummyQuery = NULL;
|
|
if (_DeviceInterface->CreateQuery(D3DQUERYTYPE_OCCLUSION, &dummyQuery) == D3DERR_NOTAVAILABLE)
|
|
{
|
|
_OcclusionQuerySupported = false;
|
|
}
|
|
else
|
|
{
|
|
_OcclusionQuerySupported = true;
|
|
if (dummyQuery) dummyQuery->Release();
|
|
}
|
|
|
|
|
|
#ifdef NL_FORCE_TEXTURE_STAGE_COUNT
|
|
_NbNeLTextureStages = min ((uint)NL_FORCE_TEXTURE_STAGE_COUNT, (uint)IDRV_MAT_MAXTEXTURES);
|
|
#endif // NL_FORCE_TEXTURE_STAGE_COUNT
|
|
|
|
_VertexProgram = !_DisableHardwareVertexProgram && ((caps.VertexShaderVersion&0xffff) >= 0x0100);
|
|
_PixelProgramVersion = _DisableHardwareVertexProgram ? 0x0000 : caps.PixelShaderVersion & 0xffff;
|
|
nldebug("Pixel Program Version: %i.%i", (uint32)((_PixelProgramVersion & 0xFF00) >> 8), (uint32)(_PixelProgramVersion & 0xFF));
|
|
_PixelProgram = _PixelProgramVersion >= 0x0101;
|
|
_MaxVerticesByVertexBufferHard = caps.MaxVertexIndex;
|
|
_MaxLight = caps.MaxActiveLights;
|
|
|
|
if(_MaxLight > 0xFF) _MaxLight = 3;
|
|
|
|
if (_PixelProgram)
|
|
{
|
|
_MaxNumPerStageConstantLighted = _NbNeLTextureStages;
|
|
_MaxNumPerStageConstantUnlighted = _NbNeLTextureStages;
|
|
}
|
|
else
|
|
{
|
|
// emulation of per stage constant through diffuse
|
|
_MaxNumPerStageConstantLighted = 1;
|
|
_MaxNumPerStageConstantUnlighted = 2;
|
|
}
|
|
|
|
if (_DisableHardwarePixelShader && _NbNeLTextureStages > 3) // yes, 3 is not a bug
|
|
{
|
|
// If pixel shader are disabled, then can't emulate the texEnvColor feature with more than 2 stages. (only 2 constant available by using material emissive in addition to the texture factor)
|
|
// Radeon with 3 stages cases : let the third stage to ensure availability of the EMBM feature
|
|
// There is a special fix in CMaterial::isSupportedByDriver to force the number of stages to 2 for the radeons
|
|
_NbNeLTextureStages = 2;
|
|
}
|
|
|
|
// *** Check textures caps
|
|
uint j;
|
|
uint i;
|
|
for (i=0; i<ITexture::UploadFormatCount; i++)
|
|
{
|
|
// Default format : D3DFMT_A8R8G8B8
|
|
_PreferedTextureFormat[i] = D3DFMT_A8R8G8B8;
|
|
|
|
for (j=0; j<CDriverD3D::FinalPixelFormatChoice; j++)
|
|
{
|
|
if (isTextureFormatOk(adapter, _Rasterizer, FinalPixelFormat[i][j], adapterFormat))
|
|
break;
|
|
}
|
|
|
|
// Set the prefered pixel format
|
|
if (j<CDriverD3D::FinalPixelFormatChoice)
|
|
_PreferedTextureFormat[i] = FinalPixelFormat[i][j];
|
|
}
|
|
|
|
// Reset render state cache
|
|
initRenderVariables();
|
|
|
|
// *** Event init
|
|
|
|
// Release old emitter
|
|
while (_EventEmitter.getNumEmitters() != 0)
|
|
{
|
|
_EventEmitter.removeEmitter(_EventEmitter.getEmitter(_EventEmitter.getNumEmitters() - 1));
|
|
}
|
|
NLMISC::CWinEventEmitter *we = new NLMISC::CWinEventEmitter;
|
|
|
|
// Setup the event emitter, and try to retrieve a direct input interface
|
|
_EventEmitter.addEmitter(we, true /*must delete*/); // the main emitter
|
|
|
|
// Try to get direct input
|
|
try
|
|
{
|
|
NLMISC::CDIEventEmitter *diee = NLMISC::CDIEventEmitter::create(GetModuleHandle(NULL), _HWnd, we);
|
|
if (diee)
|
|
{
|
|
_EventEmitter.addEmitter(diee, true);
|
|
}
|
|
}
|
|
catch(const EDirectInput &e)
|
|
{
|
|
nlinfo(e.what());
|
|
}
|
|
|
|
// Init some variables
|
|
_ForceDXTCCompression = false;
|
|
_AnisotropicFilter = 0;
|
|
_ForceTextureResizePower = 0;
|
|
_FogEnabled = false;
|
|
|
|
// No back buffer backuped for the moment
|
|
_BackBuffer = NULL;
|
|
|
|
// Reset profiling.
|
|
_AllocatedTextureMemory= 0;
|
|
_TextureUsed.clear();
|
|
_PrimitiveProfileIn.reset();
|
|
_PrimitiveProfileOut.reset();
|
|
_NbSetupMaterialCall= 0;
|
|
_NbSetupModelMatrixCall= 0;
|
|
_VBHardProfiling= false;
|
|
_CurVBHardLockCount= 0;
|
|
_NumVBHardProfileFrame= 0;
|
|
_IBProfiling= false;
|
|
_CurIBLockCount= 0;
|
|
_NumIBProfileFrame= 0;
|
|
|
|
// try to allocate 16Mo by default of AGP Ram.
|
|
initVertexBufferHard(NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE, 0);
|
|
|
|
// If AGP is less than 16 mo, try to keep the max in proportion
|
|
float maxAGPbufferSizeRatio = (float) _AGPMemoryAllocated / (float) NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE;
|
|
|
|
// Init volatile vertex buffers
|
|
_CurrentRenderPass = 0;
|
|
_VolatileVertexBufferRAM[0]->init (CVertexBuffer::RAMResident, NL_VOLATILE_RAM_VB_SIZE, NL_VOLATILE_RAM_VB_MAXSIZE, this);
|
|
_VolatileVertexBufferRAM[0]->reset ();
|
|
_VolatileVertexBufferRAM[1]->init (CVertexBuffer::RAMResident, NL_VOLATILE_RAM_VB_SIZE, NL_VOLATILE_RAM_VB_MAXSIZE, this);
|
|
_VolatileVertexBufferRAM[1]->reset ();
|
|
_VolatileVertexBufferAGP[0]->init (CVertexBuffer::AGPResident, NL_VOLATILE_AGP_VB_SIZE, (uint) (NL_VOLATILE_AGP_VB_MAXSIZE * maxAGPbufferSizeRatio), this);
|
|
_VolatileVertexBufferAGP[0]->reset ();
|
|
_VolatileVertexBufferAGP[1]->init (CVertexBuffer::AGPResident, NL_VOLATILE_AGP_VB_SIZE, (uint) (NL_VOLATILE_AGP_VB_MAXSIZE * maxAGPbufferSizeRatio), this);
|
|
_VolatileVertexBufferAGP[1]->reset ();
|
|
//
|
|
_VolatileIndexBuffer16RAM[0]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16RAM[0]->reset ();
|
|
_VolatileIndexBuffer16RAM[1]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16RAM[1]->reset ();
|
|
_VolatileIndexBuffer16AGP[0]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16AGP[0]->reset ();
|
|
_VolatileIndexBuffer16AGP[1]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices16);
|
|
_VolatileIndexBuffer16AGP[1]->reset ();
|
|
// 32 bits indices supported
|
|
if (_MaxVertexIndex > 0xffff)
|
|
{
|
|
_VolatileIndexBuffer32RAM[0]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32RAM[0]->reset ();
|
|
_VolatileIndexBuffer32RAM[1]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32RAM[1]->reset ();
|
|
_VolatileIndexBuffer32AGP[0]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32AGP[0]->reset ();
|
|
_VolatileIndexBuffer32AGP[1]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices32);
|
|
_VolatileIndexBuffer32AGP[1]->reset ();
|
|
}
|
|
//
|
|
setupViewport (CViewport());
|
|
|
|
|
|
|
|
// Begin now
|
|
//nldebug("BeginScene");
|
|
if (!beginScene()) return false;
|
|
|
|
// Done
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
extern uint indexCount;
|
|
extern uint vertexCount;
|
|
|
|
bool CDriverD3D::release()
|
|
{
|
|
H_AUTO_D3D(CDriver3D_release);
|
|
// Call IDriver::release() before, to destroy textures, shaders and VBs...
|
|
IDriver::release();
|
|
|
|
ItShaderDrvInfoPtrList itshd;
|
|
while( (itshd = _ShaderDrvInfos.begin()) != _ShaderDrvInfos.end() )
|
|
{
|
|
// NB: at IShader deletion, this->_MatDrvInfos is updated (entry deleted);
|
|
delete *itshd;
|
|
}
|
|
|
|
_SwapBufferCounter = 0;
|
|
|
|
if (_QuadIB)
|
|
{
|
|
_QuadIB->Release();
|
|
_QuadIB = NULL;
|
|
}
|
|
|
|
// delete queries
|
|
while (!_OcclusionQueryList.empty())
|
|
{
|
|
deleteOcclusionQuery(_OcclusionQueryList.front());
|
|
}
|
|
|
|
// Back buffer ref
|
|
if (_BackBuffer)
|
|
_BackBuffer->Release();
|
|
_BackBuffer = NULL;
|
|
|
|
// Release all the vertex declaration
|
|
std::list<CVertexDeclaration>::iterator ite = _VertexDeclarationList.begin();
|
|
while (ite != _VertexDeclarationList.end())
|
|
{
|
|
ite->VertexDecl->Release();
|
|
ite++;
|
|
}
|
|
_VertexDeclarationList.clear ();
|
|
|
|
// Release pixel shaders
|
|
_NormalPixelShaders[0].clear ();
|
|
_NormalPixelShaders[1].clear ();
|
|
|
|
if( _DeviceInterface != NULL)
|
|
{
|
|
_DeviceInterface->Release();
|
|
_DeviceInterface = NULL;
|
|
}
|
|
|
|
if (_HWnd)
|
|
{
|
|
releaseCursors();
|
|
|
|
// make sure window icons are deleted
|
|
std::vector<NLMISC::CBitmap> bitmaps;
|
|
setWindowIcon(bitmaps);
|
|
|
|
if (_DestroyWindow)
|
|
DestroyWindow (_HWnd);
|
|
_HWnd = NULL;
|
|
}
|
|
|
|
|
|
nlassert (indexCount == 0);
|
|
nlassert (vertexCount == 0);
|
|
|
|
// restore desktop gamma ramp
|
|
if (_DesktopGammaRampValid)
|
|
{
|
|
HDC dc = CreateDCW (L"DISPLAY", NULL, NULL, NULL);
|
|
if (dc)
|
|
{
|
|
SetDeviceGammaRamp (dc, _DesktopGammaRamp);
|
|
}
|
|
_DesktopGammaRampValid = false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// ***************************************************************************
|
|
|
|
emptyProc CDriverD3D::getWindowProc()
|
|
{
|
|
return (emptyProc)D3DWndProc;
|
|
};
|
|
|
|
// ***************************************************************************
|
|
|
|
IDriver::TMessageBoxId CDriverD3D::systemMessageBox (const char* message, const char* title, TMessageBoxType type, TMessageBoxIcon icon)
|
|
{
|
|
switch (::MessageBox (_HWnd, message, title, ((type==retryCancelType)?MB_RETRYCANCEL:
|
|
(type==yesNoCancelType)?MB_YESNOCANCEL:
|
|
(type==okCancelType)?MB_OKCANCEL:
|
|
(type==abortRetryIgnoreType)?MB_ABORTRETRYIGNORE:
|
|
(type==yesNoType)?MB_YESNO|MB_ICONQUESTION:MB_OK)|
|
|
|
|
((icon==handIcon)?MB_ICONHAND:
|
|
(icon==questionIcon)?MB_ICONQUESTION:
|
|
(icon==exclamationIcon)?MB_ICONEXCLAMATION:
|
|
(icon==asteriskIcon)?MB_ICONASTERISK:
|
|
(icon==warningIcon)?MB_ICONWARNING:
|
|
(icon==errorIcon)?MB_ICONERROR:
|
|
(icon==informationIcon)?MB_ICONINFORMATION:
|
|
(icon==stopIcon)?MB_ICONSTOP:0)))
|
|
{
|
|
case IDOK:
|
|
return okId;
|
|
case IDCANCEL:
|
|
return cancelId;
|
|
case IDABORT:
|
|
return abortId;
|
|
case IDRETRY:
|
|
return retryId;
|
|
case IDIGNORE:
|
|
return ignoreId;
|
|
case IDYES:
|
|
return yesId;
|
|
case IDNO:
|
|
return noId;
|
|
}
|
|
return okId;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::activate()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::isActive ()
|
|
{
|
|
return (IsWindow(_HWnd) != 0);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
nlWindow CDriverD3D::getDisplay()
|
|
{
|
|
return _HWnd;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
NLMISC::IEventEmitter *CDriverD3D::getEventEmitter()
|
|
{
|
|
return &_EventEmitter;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::getWindowSize (uint32 &width, uint32 &height)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getWindowSize);
|
|
width = _CurrentMode.Width;
|
|
height = _CurrentMode.Height;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::getWindowPos (sint32 &x, sint32 &y)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getWindowPos);
|
|
x = _WindowX;
|
|
y = _WindowY;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
uint32 CDriverD3D::getImplementationVersion () const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getImplementationVersion);
|
|
return ReleaseVersion;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
const char *CDriverD3D::getDriverInformation ()
|
|
{
|
|
return "Directx 9 NeL Driver";
|
|
}
|
|
|
|
// ***************************************************************************
|
|
uint8 CDriverD3D::getBitPerPixel ()
|
|
{
|
|
return _CurrentMode.Depth;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::clear2D(CRGBA rgba)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_clear2D);
|
|
nlassert (_DeviceInterface);
|
|
|
|
// Backup viewport
|
|
CViewport oldViewport = _Viewport;
|
|
setupViewport (CViewport());
|
|
updateRenderVariables ();
|
|
|
|
bool result = _DeviceInterface->Clear( 0, NULL, D3DCLEAR_TARGET, NL_D3DCOLOR_RGBA(rgba), 1.0f, 0 ) == D3D_OK;
|
|
|
|
// Restaure the old viewport
|
|
setupViewport (oldViewport);
|
|
return result;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::clearZBuffer(float zval)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_clearZBuffer);
|
|
nlassert (_DeviceInterface);
|
|
|
|
// Backup viewport
|
|
CViewport oldViewport = _Viewport;
|
|
setupViewport (CViewport());
|
|
updateRenderVariables ();
|
|
|
|
bool result = _DeviceInterface->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,0,0,0), zval, 0 ) == D3D_OK;
|
|
|
|
// Restaure the old viewport
|
|
setupViewport (oldViewport);
|
|
|
|
// NVidia driver 56.72 needs to reset the vertex buffer after a clear Z
|
|
touchRenderVariable (&_VertexBufferCache);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::clearStencilBuffer(float stencilval)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_clearStencilBuffer);
|
|
nlassert (_DeviceInterface);
|
|
|
|
// Backup viewport
|
|
CViewport oldViewport = _Viewport;
|
|
setupViewport (CViewport());
|
|
updateRenderVariables ();
|
|
|
|
bool result = _DeviceInterface->Clear( 0, NULL, D3DCLEAR_STENCIL, D3DCOLOR_ARGB(0,0,0,0), 1.0f, (unsigned long)stencilval ) == D3D_OK;
|
|
|
|
// Restaure the old viewport
|
|
setupViewport (oldViewport);
|
|
|
|
return result;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::setColorMask (bool bRed, bool bGreen, bool bBlue, bool bAlpha)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setColorMask);
|
|
setRenderState (D3DRS_COLORWRITEENABLE,
|
|
(bAlpha?D3DCOLORWRITEENABLE_ALPHA:0)|
|
|
(bRed?D3DCOLORWRITEENABLE_RED:0)|
|
|
(bGreen?D3DCOLORWRITEENABLE_GREEN:0)|
|
|
(bBlue?D3DCOLORWRITEENABLE_BLUE:0)
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::swapBuffers()
|
|
{
|
|
//DUMP_AUTO(swapBuffers);
|
|
H_AUTO_D3D(CDriverD3D_swapBuffers);
|
|
nlassert (_DeviceInterface);
|
|
|
|
++ _SwapBufferCounter;
|
|
// Swap & reset volatile buffers
|
|
_CurrentRenderPass++;
|
|
_VolatileVertexBufferRAM[_CurrentRenderPass&1]->reset ();
|
|
_VolatileVertexBufferAGP[_CurrentRenderPass&1]->reset ();
|
|
_VolatileIndexBuffer16RAM[_CurrentRenderPass&1]->reset ();
|
|
_VolatileIndexBuffer16AGP[_CurrentRenderPass&1]->reset ();
|
|
_VolatileIndexBuffer32RAM[_CurrentRenderPass&1]->reset ();
|
|
_VolatileIndexBuffer32AGP[_CurrentRenderPass&1]->reset ();
|
|
|
|
// todo hulud volatile
|
|
//_DeviceInterface->SetStreamSource(0, _VolatileVertexBufferRAM[1]->VertexBuffer, 0, 12);
|
|
|
|
// Is direct input running ?
|
|
if (_EventEmitter.getNumEmitters() > 1)
|
|
{
|
|
// flush direct input messages if any
|
|
NLMISC::safe_cast<NLMISC::CDIEventEmitter *>(_EventEmitter.getEmitter(1))->poll();
|
|
}
|
|
|
|
// End now
|
|
if (!endScene())
|
|
{
|
|
nlstop;
|
|
return false;
|
|
}
|
|
|
|
HRESULT result = _DeviceInterface->Present( NULL, NULL, NULL, NULL);
|
|
if (result != D3D_OK)
|
|
{
|
|
// Device lost ?
|
|
if (result == D3DERR_DEVICELOST)
|
|
{
|
|
_Lost = true;
|
|
// check if we can exit lost state
|
|
if (_DeviceInterface->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
|
|
{
|
|
// Reset the driver
|
|
reset (_CurrentMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check window size
|
|
handlePossibleSizeChange ();
|
|
|
|
// Reset the profiling counter.
|
|
_PrimitiveProfileIn.reset();
|
|
_PrimitiveProfileOut.reset();
|
|
_NbSetupMaterialCall= 0;
|
|
_NbSetupModelMatrixCall= 0;
|
|
|
|
// Reset the texture set
|
|
_TextureUsed.clear();
|
|
|
|
// Reset vertex program
|
|
setVertexProgram (NULL, NULL);
|
|
// Reset pixel program
|
|
setPixelShader (NULL);
|
|
|
|
if (_VBHardProfiling)
|
|
{
|
|
++_NumVBHardProfileFrame;
|
|
}
|
|
if (_IBProfiling)
|
|
{
|
|
++ _NumIBProfileFrame;
|
|
}
|
|
|
|
// Begin now
|
|
return beginScene();
|
|
};
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::setPolygonMode (TPolygonMode mode)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setPolygonMode);
|
|
IDriver::setPolygonMode (mode);
|
|
|
|
setRenderState (D3DRS_FILLMODE, mode==Point?D3DFILL_POINT:mode==Line?D3DFILL_WIREFRAME:D3DFILL_SOLID);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::isTextureFormatOk(UINT adapter, D3DDEVTYPE rasterizer, D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_isTextureFormatOk);
|
|
HRESULT hr = _D3D->CheckDeviceFormat( adapter,
|
|
rasterizer,
|
|
AdapterFormat,
|
|
0,
|
|
D3DRTYPE_TEXTURE,
|
|
TextureFormat);
|
|
|
|
return SUCCEEDED( hr ) != FALSE;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::forceDXTCCompression(bool dxtcComp)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_forceDXTCCompression);
|
|
_ForceDXTCCompression = dxtcComp;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::setAnisotropicFilter(sint filter)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setAnisotropicFilter);
|
|
|
|
// anisotropic filter not supported
|
|
if (_MaxAnisotropy < 2) return;
|
|
|
|
if (filter < 0 || filter > _MaxAnisotropy)
|
|
{
|
|
_AnisotropicFilter = _MaxAnisotropy;
|
|
}
|
|
else
|
|
{
|
|
_AnisotropicFilter = filter;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::forceTextureResize(uint divisor)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_forceTextureResize);
|
|
clamp(divisor, 1U, 256U);
|
|
|
|
// 16 -> 4.
|
|
_ForceTextureResizePower= getPowerOf2(divisor);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::fogEnabled()
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_fogEnabled);
|
|
// Return _RenderStateCache[D3DRS_FOGENABLE].Value == TRUE;
|
|
// Nico Patch : must return the _FogEnabled value here, because it MAY be
|
|
// different of the one found in _RenderStateCache[D3DRS_FOGENABLE]
|
|
// this happens for example when dest blend is one : the actual content of _RenderStateCache[D3DRS_FOGENABLE]
|
|
// is then restored when current material alpha blending settings are modified, or when a new material is set.
|
|
return _FogEnabled;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::enableFog(bool enable)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_enableFog);
|
|
_FogEnabled = enable;
|
|
setRenderState (D3DRS_FOGENABLE, enable?TRUE:FALSE);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::setupFog(float start, float end, CRGBA color)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setupFog);
|
|
// Remember fog start and end
|
|
_FogStart = start;
|
|
_FogEnd = end;
|
|
_FogColor = NL_D3DCOLOR_RGBA(color);
|
|
|
|
// Set the fog
|
|
setRenderState (D3DRS_FOGCOLOR, _FogColor);
|
|
setRenderState (D3DRS_FOGSTART, *((DWORD*) (&_FogStart)));
|
|
setRenderState (D3DRS_FOGEND, *((DWORD*) (&_FogEnd)));
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
float CDriverD3D::getFogStart() const
|
|
{
|
|
return _FogStart;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
float CDriverD3D::getFogEnd() const
|
|
{
|
|
return _FogEnd;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
CRGBA CDriverD3D::getFogColor() const
|
|
{
|
|
return D3DCOLOR_NL_RGBA(_RenderStateCache[D3DRS_FOGCOLOR].Value);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
CVertexBuffer::TVertexColorType CDriverD3D::getVertexColorFormat() const
|
|
{
|
|
return CVertexBuffer::TBGRA;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
uint CDriverD3D::getNbTextureStages() const
|
|
{
|
|
return _NbNeLTextureStages;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::getModes(std::vector<GfxMode> &modes)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getModes);
|
|
static const D3DFORMAT format[]=
|
|
{
|
|
D3DFMT_A8R8G8B8,
|
|
D3DFMT_X8R8G8B8,
|
|
D3DFMT_R8G8B8,
|
|
D3DFMT_A1R5G5B5,
|
|
D3DFMT_R5G6B5,
|
|
};
|
|
static const uint8 depth[]=
|
|
{
|
|
32,
|
|
32,
|
|
24,
|
|
16,
|
|
16,
|
|
};
|
|
uint f;
|
|
for (f=0; f<sizeof(format)/sizeof(uint); f++)
|
|
{
|
|
UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
|
|
const uint count = _D3D->GetAdapterModeCount(adapter, format[f]);
|
|
uint i;
|
|
for (i=0; i<count; i++)
|
|
{
|
|
D3DDISPLAYMODE mode;
|
|
if (_D3D->EnumAdapterModes( adapter, format[f], i, &mode) == D3D_OK)
|
|
{
|
|
GfxMode gfxMode;
|
|
gfxMode.Windowed=false;
|
|
gfxMode.Width=(uint16)mode.Width;
|
|
gfxMode.Height=(uint16)mode.Height;
|
|
gfxMode.Depth=depth[f];
|
|
gfxMode.Frequency=(uint8)mode.RefreshRate;
|
|
modes.push_back (gfxMode);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::getCurrentScreenMode(GfxMode &gfxMode)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getCurrentScreenMode);
|
|
UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
|
|
D3DDISPLAYMODE mode;
|
|
_D3D->GetAdapterDisplayMode(adapter, &mode);
|
|
gfxMode.Windowed = !_FullScreen;
|
|
gfxMode.Width = (uint16)mode.Width;
|
|
gfxMode.Height = (uint16)mode.Height;
|
|
gfxMode.Depth = ((mode.Format==D3DFMT_A8R8G8B8)||(mode.Format==D3DFMT_X8R8G8B8))?32:16;
|
|
gfxMode.Frequency = (uint8)mode.RefreshRate;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::setWindowTitle(const ucstring &title)
|
|
{
|
|
SetWindowTextW(_HWnd,(WCHAR*)title.c_str());
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::setWindowIcon(const std::vector<NLMISC::CBitmap> &bitmaps)
|
|
{
|
|
if (!_HWnd)
|
|
return;
|
|
|
|
static HICON winIconBig = NULL;
|
|
static HICON winIconSmall = NULL;
|
|
|
|
if (winIconBig)
|
|
{
|
|
DestroyIcon(winIconBig);
|
|
winIconBig = NULL;
|
|
}
|
|
|
|
if (winIconSmall)
|
|
{
|
|
DestroyIcon(winIconSmall);
|
|
winIconSmall = NULL;
|
|
}
|
|
|
|
sint smallIndex = -1;
|
|
uint smallWidth = GetSystemMetrics(SM_CXSMICON);
|
|
uint smallHeight = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
sint bigIndex = -1;
|
|
uint bigWidth = GetSystemMetrics(SM_CXICON);
|
|
uint bigHeight = GetSystemMetrics(SM_CYICON);
|
|
|
|
// find icons with the exact size
|
|
for(uint i = 0; i < bitmaps.size(); ++i)
|
|
{
|
|
if (smallIndex == -1 && bitmaps[i].getWidth() == smallWidth && bitmaps[i].getHeight() == smallHeight)
|
|
smallIndex = i;
|
|
|
|
if (bigIndex == -1 && bitmaps[i].getWidth() == bigWidth && bitmaps[i].getHeight() == bigHeight)
|
|
bigIndex = i;
|
|
}
|
|
|
|
// find icons with taller size (we will resize them)
|
|
for(uint i = 0; i < bitmaps.size(); ++i)
|
|
{
|
|
if (smallIndex == -1 && bitmaps[i].getWidth() >= smallWidth && bitmaps[i].getHeight() >= smallHeight)
|
|
smallIndex = i;
|
|
|
|
if (bigIndex == -1 && bitmaps[i].getWidth() >= bigWidth && bitmaps[i].getHeight() >= bigHeight)
|
|
bigIndex = i;
|
|
}
|
|
|
|
if (smallIndex > -1)
|
|
convertBitmapToIcon(bitmaps[smallIndex], winIconSmall, smallWidth, smallHeight, 32);
|
|
|
|
if (bigIndex > -1)
|
|
convertBitmapToIcon(bitmaps[bigIndex], winIconBig, bigWidth, bigHeight, 32);
|
|
|
|
if (winIconBig)
|
|
{
|
|
SendMessage(_HWnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)winIconSmall);
|
|
SendMessage(_HWnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)winIconBig);
|
|
}
|
|
else
|
|
{
|
|
SendMessage(_HWnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)winIconSmall);
|
|
SendMessage(_HWnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)winIconSmall);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::setWindowPos(sint32 x, sint32 y)
|
|
{
|
|
_WindowX = x;
|
|
_WindowY = y;
|
|
SetWindowPos(_HWnd, NULL, _WindowX, _WindowY, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::showWindow(bool show)
|
|
{
|
|
ShowWindow (_HWnd, show ? SW_SHOW:SW_HIDE);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
uint CDriverD3D::getNumAdapter() const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getNumAdapter);
|
|
if (_D3D)
|
|
return _D3D->GetAdapterCount();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::getAdapter(uint adapter, IDriver::CAdapter &desc) const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getAdapter);
|
|
if (_D3D)
|
|
{
|
|
D3DADAPTER_IDENTIFIER9 identifier;
|
|
UINT _adapter = (adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)adapter;
|
|
if (_D3D->GetAdapterIdentifier(_adapter, 0, &identifier) == D3D_OK)
|
|
{
|
|
desc.Description = identifier.Description;
|
|
desc.DeviceId = identifier.DeviceId;
|
|
desc.DeviceName = identifier.DeviceName;
|
|
desc.Driver = identifier.Driver;
|
|
desc.DriverVersion = (((sint64)identifier.DriverVersion.HighPart<<32))|(sint64)identifier.DriverVersion.LowPart;
|
|
desc.Revision = identifier.Revision;
|
|
desc.SubSysId = identifier.SubSysId;
|
|
desc.VendorId = identifier.VendorId;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::setAdapter(uint adapter)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setAdapter);
|
|
if (_D3D)
|
|
{
|
|
D3DDISPLAYMODE adapterMode;
|
|
UINT _adapter = (adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)adapter;
|
|
if (_D3D->GetAdapterDisplayMode (_adapter, &adapterMode) != D3D_OK)
|
|
{
|
|
nlwarning ("CDriverD3D::setDisplay: GetAdapterDisplayMode failed");
|
|
release();
|
|
return false;
|
|
}
|
|
_Adapter = adapter;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::supportMADOperator() const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_supportMADOperator);
|
|
if (_DeviceInterface)
|
|
{
|
|
return _MADOperatorSupported;
|
|
}
|
|
return false; // don't know..
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::setMode (const GfxMode& mode)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setMode);
|
|
|
|
// if fullscreen
|
|
if(!mode.Windowed)
|
|
{
|
|
// Must check if mode exist, else crash at reset() time
|
|
std::vector<GfxMode> modes;
|
|
if(getModes(modes))
|
|
{
|
|
bool found= false;
|
|
for(uint i=0;i<modes.size();i++)
|
|
{
|
|
if( modes[i].Windowed==mode.Windowed &&
|
|
modes[i].Width==mode.Width &&
|
|
modes[i].Height==mode.Height &&
|
|
modes[i].Depth==mode.Depth &&
|
|
modes[i].Frequency==mode.Frequency )
|
|
{
|
|
found= true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// found?
|
|
if(!found)
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// set the mode
|
|
if( mode.Windowed )
|
|
{
|
|
// Set windowed-mode style
|
|
SetWindowLongW( _HWnd, GWL_STYLE, D3D_WINDOWED_STYLE|WS_VISIBLE);
|
|
_FullScreen = false;
|
|
}
|
|
else
|
|
{
|
|
// Set fullscreen-mode style
|
|
SetWindowLongW( _HWnd, GWL_STYLE, D3D_FULLSCREEN_STYLE|WS_VISIBLE);
|
|
_FullScreen = true;
|
|
}
|
|
|
|
SetWindowLongPtrW(_HWnd, GWLP_WNDPROC, GetWindowLongPtr(_HWnd, GWLP_WNDPROC));
|
|
|
|
// Reset the driver
|
|
if (reset (mode))
|
|
{
|
|
// Reajust window
|
|
if( _CurrentMode.Windowed )
|
|
{
|
|
// Window rect
|
|
RECT WndRect;
|
|
WndRect.left=_WindowX;
|
|
WndRect.top=_WindowY;
|
|
WndRect.right=_WindowX+_CurrentMode.Width;
|
|
WndRect.bottom=_WindowY+_CurrentMode.Height;
|
|
AdjustWindowRect(&WndRect, GetWindowLongW (_HWnd, GWL_STYLE), FALSE);
|
|
|
|
SetWindowPos( _HWnd, HWND_NOTOPMOST,
|
|
std::max ((int)WndRect.left, 0), std::max ((int)WndRect.top, 0),
|
|
( WndRect.right - WndRect.left ),
|
|
( WndRect.bottom - WndRect.top ),
|
|
SWP_NOMOVE | SWP_SHOWWINDOW );
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::deleteIndexBuffer(CIBDrvInfosD3D *indexBuffer)
|
|
{
|
|
if (!indexBuffer) return;
|
|
CIndexBuffer *ib = indexBuffer->IndexBufferPtr;
|
|
// If resident in RAM, content has not been lost
|
|
if (ib->getLocation () != CIndexBuffer::RAMResident)
|
|
{
|
|
// Realloc local memory
|
|
ib->setLocation (CIndexBuffer::NotResident);
|
|
delete indexBuffer;
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::reset (const GfxMode& mode)
|
|
{
|
|
//DUMP_AUTO(reset);
|
|
H_AUTO_D3D(CDriverD3D_reset);
|
|
if (_DeviceInterface->TestCooperativeLevel() == D3DERR_DEVICELOST) return false;
|
|
|
|
// Choose an adapter
|
|
UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
|
|
|
|
// Get adapter format
|
|
D3DDISPLAYMODE adapterMode;
|
|
if (_D3D->GetAdapterDisplayMode (adapter, &adapterMode) != D3D_OK)
|
|
{
|
|
nlwarning ("CDriverD3D::reset: GetAdapterDisplayMode failed");
|
|
release();
|
|
return false;
|
|
}
|
|
|
|
// Do the reset
|
|
// Increment the IDriver reset counter
|
|
|
|
D3DPRESENT_PARAMETERS parameters;
|
|
D3DFORMAT adapterFormat;
|
|
if (!fillPresentParameter (parameters, adapterFormat, mode, adapterMode))
|
|
return false;
|
|
|
|
// Current mode
|
|
_CurrentMode = mode;
|
|
_CurrentMaterial = NULL;
|
|
_CurrentMaterialInfo = NULL;
|
|
|
|
// Restaure non managed vertex buffer in system memory
|
|
ItVBDrvInfoPtrList iteVb = _VBDrvInfos.begin();
|
|
while (iteVb != _VBDrvInfos.end())
|
|
{
|
|
ItVBDrvInfoPtrList iteVbNext = iteVb;
|
|
iteVbNext++;
|
|
|
|
CVBDrvInfosD3D *vertexBuffer = static_cast<CVBDrvInfosD3D*>(*iteVb);
|
|
CVertexBuffer *vb = vertexBuffer->VertexBufferPtr;
|
|
|
|
// If resident in RAM, content has not been lost
|
|
if (vb->getLocation () != CVertexBuffer::RAMResident)
|
|
{
|
|
// Realloc local memory
|
|
vb->setLocation (CVertexBuffer::NotResident); // If resident in RAM, content backuped by setLocation
|
|
delete vertexBuffer;
|
|
}
|
|
|
|
iteVb = iteVbNext;
|
|
}
|
|
|
|
// Restore non managed index buffer in system memory
|
|
ItIBDrvInfoPtrList iteIb = _IBDrvInfos.begin();
|
|
while (iteIb != _IBDrvInfos.end())
|
|
{
|
|
ItIBDrvInfoPtrList iteIbNext = iteIb;
|
|
iteIbNext++;
|
|
deleteIndexBuffer(static_cast<CIBDrvInfosD3D*>(*iteIb));
|
|
iteIb = iteIbNext;
|
|
}
|
|
deleteIndexBuffer(static_cast<CIBDrvInfosD3D*>((IIBDrvInfos *) _QuadIndexesAGP.DrvInfos));
|
|
|
|
// Remove render targets
|
|
ItTexDrvSharePtrList ite = _TexDrvShares.begin();
|
|
while (ite != _TexDrvShares.end())
|
|
{
|
|
ItTexDrvSharePtrList iteNext = ite;
|
|
iteNext++;
|
|
|
|
// Render target ?
|
|
nlassert ((*ite)->DrvTexture != NULL);
|
|
CTextureDrvInfosD3D *info = static_cast<CTextureDrvInfosD3D*>(static_cast<ITextureDrvInfos*>((*ite)->DrvTexture));
|
|
if (info->RenderTarget)
|
|
{
|
|
// Remove it
|
|
delete *ite;
|
|
}
|
|
ite = iteNext;
|
|
}
|
|
|
|
// Free volatile buffers
|
|
_VolatileVertexBufferRAM[0]->release ();
|
|
_VolatileVertexBufferRAM[1]->release ();
|
|
_VolatileVertexBufferAGP[0]->release ();
|
|
_VolatileVertexBufferAGP[1]->release ();
|
|
_VolatileIndexBuffer16RAM[0]->release ();
|
|
_VolatileIndexBuffer16RAM[1]->release ();
|
|
_VolatileIndexBuffer16AGP[0]->release ();
|
|
_VolatileIndexBuffer16AGP[1]->release ();
|
|
_VolatileIndexBuffer32RAM[0]->release ();
|
|
_VolatileIndexBuffer32RAM[1]->release ();
|
|
_VolatileIndexBuffer32AGP[0]->release ();
|
|
_VolatileIndexBuffer32AGP[1]->release ();
|
|
|
|
// Back buffer ref
|
|
if (_BackBuffer)
|
|
_BackBuffer->Release();
|
|
_BackBuffer = NULL;
|
|
|
|
// Invalidate all occlusion queries.
|
|
// TODO nico : for now, even if a result has been retrieved successfully by the query, the query is put in the lost state. See if its worth improving...
|
|
for(TOcclusionQueryList::iterator it = _OcclusionQueryList.begin(); it != _OcclusionQueryList.end(); ++it)
|
|
{
|
|
if ((*it)->Query)
|
|
{
|
|
(*it)->WasLost = true;
|
|
(*it)->Query->Release();
|
|
(*it)->Query = NULL;
|
|
}
|
|
}
|
|
|
|
// Release internal shaders
|
|
//releaseInternalShaders();
|
|
|
|
|
|
notifyAllShaderDrvOfLostDevice();
|
|
|
|
|
|
|
|
/* Do not reset if reset will fail */
|
|
_ResetCounter++;
|
|
bool sceneBegun = hasSceneBegun();
|
|
if (sceneBegun)
|
|
{
|
|
//nldebug("EndScene");
|
|
endScene();
|
|
}
|
|
|
|
// delete all .fx caches
|
|
for(TMatDrvInfoPtrList::iterator it = _MatDrvInfos.begin(); it != _MatDrvInfos.end(); ++it)
|
|
{
|
|
CMaterialDrvInfosD3D *mi = NLMISC::safe_cast<CMaterialDrvInfosD3D *>(*it);
|
|
if (mi->FXCache)
|
|
{
|
|
mi->FXCache->reset();
|
|
}
|
|
}
|
|
|
|
{
|
|
#ifndef NL_NO_ASM
|
|
CFpuRestorer fpuRestorer; // fpu control word is changed by "Reset"
|
|
#endif
|
|
if (_Rasterizer!=D3DDEVTYPE_REF) {
|
|
HRESULT hr = _DeviceInterface->Reset (¶meters);
|
|
if (hr != D3D_OK)
|
|
{
|
|
nlwarning("CDriverD3D::reset: Reset on _DeviceInterface error 0x%x", hr);
|
|
// tmp
|
|
nlstopex(("CDriverD3D::reset: Reset on _DeviceInterface"));
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Lost = false;
|
|
// BeginScene now
|
|
if (sceneBegun)
|
|
{
|
|
//nldebug("BeginScene");
|
|
beginScene();
|
|
}
|
|
|
|
notifyAllShaderDrvOfResetDevice();
|
|
|
|
// Reset internal caches
|
|
resetRenderVariables();
|
|
|
|
// Init shaders
|
|
//initInternalShaders();
|
|
|
|
// reallocate occlusion queries
|
|
for(TOcclusionQueryList::iterator it = _OcclusionQueryList.begin(); it != _OcclusionQueryList.end(); ++it)
|
|
{
|
|
if (!(*it)->Query)
|
|
{
|
|
_DeviceInterface->CreateQuery(D3DQUERYTYPE_OCCLUSION, &(*it)->Query);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::fillPresentParameter (D3DPRESENT_PARAMETERS ¶meters, D3DFORMAT &adapterFormat, const GfxMode& mode, const D3DDISPLAYMODE &adapterMode)
|
|
{
|
|
UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
|
|
H_AUTO_D3D(CDriverD3D_fillPresentParameter);
|
|
memset (¶meters, 0, sizeof(D3DPRESENT_PARAMETERS));
|
|
parameters.BackBufferWidth = mode.Width;
|
|
parameters.BackBufferHeight = mode.Height;
|
|
parameters.BackBufferCount = 1;
|
|
parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
|
|
parameters.MultiSampleQuality = 0;
|
|
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
parameters.hDeviceWindow = NULL;
|
|
parameters.Windowed = mode.Windowed;
|
|
parameters.EnableAutoDepthStencil = TRUE;
|
|
parameters.FullScreen_RefreshRateInHz = mode.Windowed?0:mode.Frequency;
|
|
switch (_Interval)
|
|
{
|
|
case 0:
|
|
parameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
break;
|
|
case 1:
|
|
parameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
|
break;
|
|
case 2:
|
|
parameters.PresentationInterval = D3DPRESENT_INTERVAL_TWO;
|
|
break;
|
|
case 3:
|
|
parameters.PresentationInterval = D3DPRESENT_INTERVAL_THREE;
|
|
break;
|
|
default:
|
|
parameters.PresentationInterval = D3DPRESENT_INTERVAL_FOUR;
|
|
break;
|
|
}
|
|
|
|
// Build a depth index
|
|
const uint depthIndex = (mode.Depth==16)?0:(mode.Depth==24)?1:2;
|
|
|
|
// Choose a back buffer format
|
|
const uint numFormat = 4;
|
|
D3DFORMAT backBufferFormats[3][numFormat]=
|
|
{
|
|
{D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_X1R5G5B5, D3DFMT_A4R4G4B4},
|
|
{D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8},
|
|
{D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8},
|
|
};
|
|
bool found = false;
|
|
if (mode.Windowed)
|
|
{
|
|
uint backBuffer;
|
|
for (backBuffer=0; backBuffer<numFormat; backBuffer++)
|
|
{
|
|
if (_D3D->CheckDeviceType(adapter, _Rasterizer, adapterMode.Format, backBufferFormats[depthIndex][backBuffer], TRUE) == D3D_OK)
|
|
{
|
|
parameters.BackBufferFormat = backBufferFormats[depthIndex][backBuffer];
|
|
adapterFormat = adapterMode.Format;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Found a pair display and back buffer format
|
|
uint backBuffer;
|
|
for (backBuffer=0; backBuffer<numFormat; backBuffer++)
|
|
{
|
|
uint display;
|
|
for (display=0; display<numFormat; display++)
|
|
{
|
|
if (_D3D->CheckDeviceType(adapter, _Rasterizer, backBufferFormats[depthIndex][display], backBufferFormats[depthIndex][display], FALSE) == D3D_OK)
|
|
{
|
|
parameters.BackBufferFormat = backBufferFormats[depthIndex][backBuffer];
|
|
adapterFormat = backBufferFormats[depthIndex][display];
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Not found ?
|
|
if (!found)
|
|
{
|
|
nlwarning ("Can't create backbuffer");
|
|
return false;
|
|
}
|
|
|
|
// Choose a zbuffer format
|
|
D3DFORMAT zbufferFormats[]=
|
|
{
|
|
//uncomment to save zbuffer D3DFMT_D32F_LOCKABLE,
|
|
//uncomment to save zbuffer D3DFMT_D16_LOCKABLE,
|
|
/*D3DFMT_D32,
|
|
D3DFMT_D24X8,*/
|
|
D3DFMT_D24S8,
|
|
D3DFMT_D24X4S4,
|
|
D3DFMT_D24FS8,
|
|
//D3DFMT_D16,
|
|
};
|
|
|
|
const uint zbufferFormatCount = sizeof(zbufferFormats)/sizeof(D3DFORMAT);
|
|
uint i;
|
|
for (i=0; i<zbufferFormatCount; i++)
|
|
{
|
|
if (isDepthFormatOk (adapter, _Rasterizer, zbufferFormats[i], adapterFormat, parameters.BackBufferFormat))
|
|
break;
|
|
}
|
|
|
|
if (i>=zbufferFormatCount)
|
|
{
|
|
nlwarning ("Can't create zbuffer");
|
|
return false;
|
|
}
|
|
|
|
// Set the zbuffer format
|
|
parameters.AutoDepthStencilFormat = zbufferFormats[i];
|
|
|
|
if(mode.AntiAlias == -1)
|
|
{
|
|
parameters.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
|
|
}
|
|
else
|
|
{
|
|
DWORD aa = 0;
|
|
if(mode.AntiAlias == 0)
|
|
{
|
|
if(SUCCEEDED(_D3D->CheckDeviceMultiSampleType(adapter, _Rasterizer, adapterFormat, mode.Windowed, D3DMULTISAMPLE_NONMASKABLE, &aa)))
|
|
{
|
|
parameters.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE;
|
|
parameters.MultiSampleQuality = aa - 1;
|
|
nlinfo("Use AntiAlias with %d sample", aa);
|
|
}
|
|
else
|
|
{
|
|
nlwarning("No AntiAlias support found");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
parameters.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE;
|
|
parameters.MultiSampleQuality = mode.AntiAlias - 1;
|
|
nlinfo("Use AntiAlias with %d sample", mode.AntiAlias);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const char *CDriverD3D::getVideocardInformation ()
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getVideocardInformation);
|
|
static char name[1024];
|
|
|
|
// if (!_DeviceInterface)
|
|
// return "Direct3d isn't initialized";
|
|
|
|
D3DADAPTER_IDENTIFIER9 identifier;
|
|
UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
|
|
if (_D3D->GetAdapterIdentifier(adapter, 0, &identifier) == D3D_OK)
|
|
{
|
|
uint64 version = ((uint64)identifier.DriverVersion.HighPart) << 32;
|
|
version |= identifier.DriverVersion.LowPart;
|
|
smprintf (name, 1024, "Direct3d / %s / %s / %s / driver version : %d.%d.%d.%d", identifier.Driver, identifier.Description, identifier.DeviceName,
|
|
(uint16)((version>>48)&0xFFFF),(uint16)((version>>32)&0xFFFF),(uint16)((version>>16)&0xFFFF),(uint16)(version&0xffff));
|
|
return name;
|
|
}
|
|
else
|
|
return "Can't get video card information";
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::getBuffer (CBitmap &bitmap)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getBuffer);
|
|
NLMISC::CRect rect;
|
|
rect.setWH (0, 0, _CurrentMode.Width, _CurrentMode.Height);
|
|
getBufferPart (bitmap, rect);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::getBufferPart (CBitmap &bitmap, NLMISC::CRect &rect)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getBufferPart);
|
|
if (_DeviceInterface)
|
|
{
|
|
// Resize the bitmap
|
|
const uint lineCount = rect.Height;
|
|
const uint width = rect.Width;
|
|
bitmap.resize (width, lineCount, CBitmap::RGBA);
|
|
|
|
// Lock the back buffer
|
|
IDirect3DSurface9 *surface;
|
|
if (_DeviceInterface->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &surface) == D3D_OK)
|
|
{
|
|
// Surface desc
|
|
D3DSURFACE_DESC desc;
|
|
if (surface->GetDesc(&desc) == D3D_OK)
|
|
{
|
|
// 32 bits format supported
|
|
if ((desc.Format == D3DFMT_R8G8B8) ||
|
|
(desc.Format == D3DFMT_A8R8G8B8) ||
|
|
(desc.Format == D3DFMT_X8R8G8B8) ||
|
|
(desc.Format == D3DFMT_A8B8G8R8) ||
|
|
(desc.Format == D3DFMT_X8B8G8R8))
|
|
{
|
|
// Invert RGBA ?
|
|
bool invertRGBA = (desc.Format == D3DFMT_R8G8B8) || (desc.Format == D3DFMT_A8R8G8B8) || (desc.Format == D3DFMT_X8R8G8B8);
|
|
|
|
// Lock the surface
|
|
D3DLOCKED_RECT lock;
|
|
::RECT winRect;
|
|
winRect.left = rect.left();
|
|
winRect.right = rect.right();
|
|
winRect.top = rect.top();
|
|
winRect.bottom = rect.bottom();
|
|
if (surface->LockRect (&lock, &winRect, D3DLOCK_READONLY) == D3D_OK)
|
|
{
|
|
// Line count
|
|
uint8 *dest = &(bitmap.getPixels ()[0]);
|
|
uint i;
|
|
for (i=0; i<lineCount; i++)
|
|
{
|
|
if (invertRGBA)
|
|
copyRGBA2BGRA ((uint32*)dest+(i*width), (uint32*)((uint8*)lock.pBits+(i*lock.Pitch)), width);
|
|
else
|
|
memcpy (dest+(4*i*width), ((uint8*)lock.pBits)+(i*lock.Pitch), width*4);
|
|
}
|
|
|
|
surface->UnlockRect ();
|
|
}
|
|
}
|
|
}
|
|
|
|
surface->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
IDirect3DSurface9 * CDriverD3D::getSurfaceTexture(ITexture * text)
|
|
{
|
|
if(!text)
|
|
{
|
|
if(!_BackBuffer)
|
|
{
|
|
updateRenderVariables ();
|
|
_DeviceInterface->GetRenderTarget (0, &_BackBuffer);
|
|
}
|
|
nlassert(_BackBuffer);
|
|
return _BackBuffer;
|
|
}
|
|
|
|
if(text->TextureDrvShare==NULL || text->TextureDrvShare->DrvTexture.getPtr()==NULL)
|
|
{
|
|
text->setRenderTarget(true);
|
|
setupTexture(*text);
|
|
}
|
|
CTextureDrvInfosD3D* rdvInfosD3D = (NLMISC::safe_cast<CTextureDrvInfosD3D*>(text->TextureDrvShare->DrvTexture.getPtr()));
|
|
|
|
IDirect3DTexture9 * texture = rdvInfosD3D->Texture2d;
|
|
nlassert(texture);
|
|
|
|
IDirect3DSurface9 * surface;
|
|
HRESULT hr = texture->GetSurfaceLevel(0, &surface);
|
|
nlassert(hr==D3D_OK);
|
|
|
|
return surface;
|
|
}
|
|
|
|
void CDriverD3D::getDirect3DRect(NLMISC::CRect &rect, RECT & d3dRect)
|
|
{
|
|
d3dRect.left = rect.left();
|
|
d3dRect.top = rect.top();
|
|
d3dRect.right = rect.right();
|
|
d3dRect.bottom = rect.bottom();
|
|
|
|
uint32 w, h;
|
|
getWindowSize(w, h);
|
|
|
|
if(d3dRect.top>(sint32)h)
|
|
d3dRect.top = h;
|
|
|
|
if(d3dRect.right>(sint32)w)
|
|
d3dRect.right = w;
|
|
|
|
if(d3dRect.bottom<0)
|
|
d3dRect.bottom = 0;
|
|
|
|
if(d3dRect.left<0)
|
|
d3dRect.left = 0;
|
|
}
|
|
|
|
bool CDriverD3D::stretchRect(ITexture * srcText, NLMISC::CRect &srcRect, ITexture * destText, NLMISC::CRect &destRect)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_stretchRect);
|
|
if (_DeviceInterface)
|
|
{
|
|
IDirect3DSurface9 * srcSurface = getSurfaceTexture(srcText);
|
|
IDirect3DSurface9 * destSurface = getSurfaceTexture(destText);
|
|
|
|
D3DTEXTUREFILTERTYPE filterType = D3DTEXF_LINEAR;
|
|
|
|
RECT srcD3DRect;
|
|
RECT destD3DRect;
|
|
getDirect3DRect(srcRect, srcD3DRect);
|
|
getDirect3DRect(destRect, destD3DRect);
|
|
|
|
HRESULT hr = _DeviceInterface->StretchRect(srcSurface, &srcD3DRect, destSurface, &destD3DRect, filterType);
|
|
|
|
srcSurface->Release();
|
|
destSurface->Release();
|
|
|
|
return (hr==D3D_OK);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::supportBloomEffect() const
|
|
{
|
|
return supportVertexProgram(CVertexProgram::nelvp);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::supportNonPowerOfTwoTextures() const
|
|
{
|
|
return _NonPowerOfTwoTexturesSupported;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::fillBuffer (NLMISC::CBitmap &bitmap)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_fillBuffer);
|
|
bool result = false;
|
|
if (_DeviceInterface)
|
|
{
|
|
// Resize the bitmap
|
|
const uint lineCount = _CurrentMode.Height;
|
|
const uint width = _CurrentMode.Width;
|
|
if ((bitmap.getWidth() == width) && (bitmap.getHeight() == lineCount))
|
|
{
|
|
// Lock the back buffer
|
|
IDirect3DSurface9 *surface;
|
|
if (_DeviceInterface->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &surface) == D3D_OK)
|
|
{
|
|
// Surface desc
|
|
D3DSURFACE_DESC desc;
|
|
if (surface->GetDesc(&desc) == D3D_OK)
|
|
{
|
|
// 32 bits format supported
|
|
if ((desc.Format == D3DFMT_R8G8B8) ||
|
|
(desc.Format == D3DFMT_A8R8G8B8) ||
|
|
(desc.Format == D3DFMT_X8R8G8B8) ||
|
|
(desc.Format == D3DFMT_A8B8G8R8) ||
|
|
(desc.Format == D3DFMT_X8B8G8R8))
|
|
{
|
|
// Invert RGBA ?
|
|
bool invertRGBA = (desc.Format == D3DFMT_R8G8B8) || (desc.Format == D3DFMT_A8R8G8B8) || (desc.Format == D3DFMT_X8R8G8B8);
|
|
|
|
// Lock the surface
|
|
D3DLOCKED_RECT lock;
|
|
::RECT winRect;
|
|
winRect.left = 0;
|
|
winRect.right = width;
|
|
winRect.top = 0;
|
|
winRect.bottom = lineCount;
|
|
if (surface->LockRect (&lock, &winRect, 0) == D3D_OK)
|
|
{
|
|
// Line count
|
|
uint8 *dest = &(bitmap.getPixels ()[0]);
|
|
uint i;
|
|
for (i=0; i<lineCount; i++)
|
|
{
|
|
if (invertRGBA)
|
|
copyRGBA2BGRA ((uint32*)((uint8*)lock.pBits+(i*lock.Pitch)), (uint32*)dest+(i*width), width);
|
|
else
|
|
memcpy (((uint8*)lock.pBits)+(i*lock.Pitch), dest+(4*i*width), width*4);
|
|
}
|
|
|
|
surface->UnlockRect ();
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
surface->Release();
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverD3D::setSwapVBLInterval(uint interval)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setSwapVBLInterval);
|
|
if (_Interval != interval)
|
|
{
|
|
_Interval = interval;
|
|
|
|
// Must do a reset because the vsync parameter is choosed in the D3DPRESENT structure
|
|
if (_DeviceInterface)
|
|
reset (_CurrentMode);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
uint CDriverD3D::getSwapVBLInterval()
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getSwapVBLInterval);
|
|
return _Interval;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::finish()
|
|
{
|
|
// TODO : actually do not wait until everythin is rendered
|
|
H_AUTO_D3D(CDriverD3D_finish);
|
|
// Flush now
|
|
//nldebug("EndScene");
|
|
endScene();
|
|
//nldebug("BeginScene");
|
|
beginScene();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::flush()
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_finish);
|
|
// Flush now
|
|
//nldebug("EndScene");
|
|
endScene();
|
|
//nldebug("BeginScene");
|
|
beginScene();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CDriverD3D::setMonitorColorProperties (const CMonitorColorProperties &properties)
|
|
{
|
|
/*
|
|
H_AUTO_D3D(CDriverD3D_setMonitorColorProperties);
|
|
// The ramp
|
|
D3DGAMMARAMP ramp;
|
|
|
|
// For each composant
|
|
uint c;
|
|
for( c=0; c<3; c++ )
|
|
{
|
|
WORD *table = (c==0)?ramp.red:(c==1)?ramp.green:ramp.blue;
|
|
uint i;
|
|
for( i=0; i<256; i++ )
|
|
{
|
|
// Floating value
|
|
float value = (float)i / 256;
|
|
|
|
// Contrast
|
|
value = (float) max (0.0f, (value-0.5f) * (float) pow (3.f, properties.Contrast[c]) + 0.5f );
|
|
|
|
// Gamma
|
|
value = (float) pow (value, (properties.Gamma[c]>0) ? 1 - 3 * properties.Gamma[c] / 4 : 1 - properties.Gamma[c] );
|
|
|
|
// Luminosity
|
|
value = value + properties.Luminosity[c] / 2.f;
|
|
table[i] = min (65535, max (0, (int)(value * 65535)));
|
|
}
|
|
}
|
|
|
|
// Set the ramp
|
|
_DeviceInterface->SetGammaRamp (0, D3DSGR_NO_CALIBRATION, &ramp);
|
|
return true;
|
|
*/
|
|
|
|
// TODO nico
|
|
// It would be better to apply the gamma ramp only to the window and not to the whole desktop when playing in windowed mode.
|
|
// This require to switch to D3D 9.0c which has a flag for that purpose in the 'Present' function.
|
|
// Currently the SetGammaRamp only works in fullscreen mode, so we rely to the classic 'SetDeviceGammaRamp' instead.
|
|
HDC dc = CreateDCW (L"DISPLAY", NULL, NULL, NULL);
|
|
if (dc)
|
|
{
|
|
// The ramp
|
|
WORD ramp[256*3];
|
|
|
|
// For each composant
|
|
uint c;
|
|
for( c=0; c<3; c++ )
|
|
{
|
|
uint i;
|
|
for( i=0; i<256; i++ )
|
|
{
|
|
// Floating value
|
|
float value = (float)i / 256;
|
|
|
|
// Contrast
|
|
value = (float) max (0.0f, (value-0.5f) * (float) pow (3.f, properties.Contrast[c]) + 0.5f );
|
|
|
|
// Gamma
|
|
value = (float) pow (value, (properties.Gamma[c]>0) ? 1 - 3 * properties.Gamma[c] / 4 : 1 - properties.Gamma[c] );
|
|
|
|
// Luminosity
|
|
value = value + properties.Luminosity[c] / 2.f;
|
|
ramp[i+(c<<8)] = (WORD)min (65535, max (0, (int)(value * 65535)));
|
|
}
|
|
}
|
|
|
|
// Set the ramp
|
|
bool result = SetDeviceGammaRamp (dc, ramp) != FALSE;
|
|
|
|
// Release the DC
|
|
ReleaseDC (NULL, dc);
|
|
|
|
// Returns result
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
nlwarning ("(CDriverD3D::setMonitorColorProperties): can't create DC");
|
|
return false;
|
|
}
|
|
|
|
}
|
|
// ***************************************************************************
|
|
|
|
// ****************************************************************************
|
|
bool CDriverD3D::supportEMBM() const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_supportEMBM);
|
|
return _EMBMSupported;
|
|
}
|
|
|
|
// ****************************************************************************
|
|
bool CDriverD3D::isEMBMSupportedAtStage(uint stage) const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_isEMBMSupportedAtStage);
|
|
// we assume EMBM is supported at all stages except the last one
|
|
return stage < _NbNeLTextureStages - 1;
|
|
}
|
|
|
|
// ****************************************************************************
|
|
void CDriverD3D::setEMBMMatrix(const uint stage, const float mat[4])
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_setEMBMMatrix);
|
|
nlassert(stage < _NbNeLTextureStages - 1);
|
|
SetTextureStageState(stage, D3DTSS_BUMPENVMAT00, (DWORD &) mat[0]);
|
|
SetTextureStageState(stage, D3DTSS_BUMPENVMAT01, (DWORD &) mat[1]);
|
|
SetTextureStageState(stage, D3DTSS_BUMPENVMAT10, (DWORD &) mat[2]);
|
|
SetTextureStageState(stage, D3DTSS_BUMPENVMAT11, (DWORD &) mat[3]);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::supportOcclusionQuery() const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_supportOcclusionQuery);
|
|
return _OcclusionQuerySupported;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
IOcclusionQuery *CDriverD3D::createOcclusionQuery()
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_createOcclusionQuery);
|
|
nlassert(_OcclusionQuerySupported);
|
|
nlassert(_DeviceInterface);
|
|
IDirect3DQuery9 *query;
|
|
if (_DeviceInterface->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query) != D3D_OK) return NULL;
|
|
COcclusionQueryD3D *oqd3d = new COcclusionQueryD3D;
|
|
oqd3d->Driver = this;
|
|
oqd3d->Query = query;
|
|
oqd3d->VisibleCount = 0;
|
|
oqd3d->OcclusionType = IOcclusionQuery::NotAvailable;
|
|
oqd3d->QueryIssued = false;
|
|
oqd3d->WasLost = false;
|
|
_OcclusionQueryList.push_front(oqd3d);
|
|
oqd3d->Iterator = _OcclusionQueryList.begin();
|
|
return oqd3d;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::deleteOcclusionQuery(IOcclusionQuery *oq)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_deleteOcclusionQuery);
|
|
if (!oq) return;
|
|
COcclusionQueryD3D *oqd3d = NLMISC::safe_cast<COcclusionQueryD3D *>(oq);
|
|
nlassert((CDriverD3D *) oqd3d->Driver == this); // should come from the same driver
|
|
oqd3d->Driver = NULL;
|
|
if (oqd3d->Query)
|
|
{
|
|
oqd3d->Query->Release();
|
|
oqd3d->Query = NULL;
|
|
}
|
|
_OcclusionQueryList.erase(oqd3d->Iterator);
|
|
if (oqd3d == _CurrentOcclusionQuery)
|
|
{
|
|
_CurrentOcclusionQuery = NULL;
|
|
}
|
|
delete oqd3d;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void COcclusionQueryD3D::begin()
|
|
{
|
|
H_AUTO_D3D(COcclusionQueryD3D_begin);
|
|
if (!Query) return; // Lost device
|
|
nlassert(Driver);
|
|
nlassert(Driver->_CurrentOcclusionQuery == NULL); // only one query at a time
|
|
Query->Issue(D3DISSUE_BEGIN);
|
|
Driver->_CurrentOcclusionQuery = this;
|
|
OcclusionType = NotAvailable;
|
|
QueryIssued = false;
|
|
WasLost = false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void COcclusionQueryD3D::end()
|
|
{
|
|
H_AUTO_D3D(COcclusionQueryD3D_end);
|
|
if (!Query) return; // Lost device
|
|
nlassert(Driver);
|
|
nlassert(Driver->_CurrentOcclusionQuery == this); // only one query at a time
|
|
if (!WasLost)
|
|
{
|
|
Query->Issue(D3DISSUE_END);
|
|
}
|
|
Driver->_CurrentOcclusionQuery = NULL;
|
|
QueryIssued = true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
IOcclusionQuery::TOcclusionType COcclusionQueryD3D::getOcclusionType()
|
|
{
|
|
if (!Query || WasLost) return QueryIssued ? Occluded : NotAvailable;
|
|
H_AUTO_D3D(COcclusionQueryD3D_getOcclusionType);
|
|
nlassert(Driver);
|
|
nlassert(Query);
|
|
nlassert(Driver->_CurrentOcclusionQuery != this); // can't query result between a begin/end pair!
|
|
if (OcclusionType == NotAvailable)
|
|
{
|
|
DWORD numPix;
|
|
if (Query->GetData(&numPix, sizeof(DWORD), 0) == S_OK)
|
|
{
|
|
OcclusionType = numPix != 0 ? NotOccluded : Occluded;
|
|
VisibleCount = (uint) numPix;
|
|
}
|
|
}
|
|
return OcclusionType;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
uint COcclusionQueryD3D::getVisibleCount()
|
|
{
|
|
if (!Query || WasLost) return 0;
|
|
H_AUTO_D3D(COcclusionQueryD3D_getVisibleCount);
|
|
nlassert(Driver);
|
|
nlassert(Query);
|
|
nlassert(Driver->_CurrentOcclusionQuery != this); // can't query result between a begin/end pair!
|
|
if (getOcclusionType() == NotAvailable) return 0;
|
|
return VisibleCount;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::supportWaterShader() const
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_supportWaterShader);
|
|
return _PixelShaderVersion >= D3DPS_VERSION(1, 1);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::setCullMode(TCullMode cullMode)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_cullMode);
|
|
#ifdef NL_D3D_USE_RENDER_STATE_CACHE
|
|
NL_D3D_CACHE_TEST(CacheTest_CullMode, cullMode != _CullMode)
|
|
#endif
|
|
{
|
|
if (_InvertCullMode)
|
|
{
|
|
setRenderState(D3DRS_CULLMODE, _CullMode == CCW ? D3DCULL_CW : D3DCULL_CCW);
|
|
}
|
|
else
|
|
{
|
|
setRenderState(D3DRS_CULLMODE, _CullMode == CCW ? D3DCULL_CCW : D3DCULL_CW);
|
|
}
|
|
_CullMode = cullMode;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
IDriver::TCullMode CDriverD3D::getCullMode() const
|
|
{
|
|
H_AUTO_D3D(CDriver3D_CDriverD3D);
|
|
return _CullMode;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::enableStencilTest(bool enable)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_CDriverD3D);
|
|
|
|
_CurStencilTest = enable;
|
|
setRenderState(D3DRS_STENCILENABLE, enable?TRUE:FALSE);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CDriverD3D::isStencilTestEnabled() const
|
|
{
|
|
H_AUTO_D3D(CDriver3D_CDriverD3D);
|
|
return _CurStencilTest?TRUE:FALSE;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::stencilFunc(TStencilFunc stencilFunc, int ref, uint mask)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_CDriverD3D);
|
|
|
|
switch(stencilFunc)
|
|
{
|
|
case IDriver::never: _CurStencilFunc=D3DCMP_NEVER; break;
|
|
case IDriver::less: _CurStencilFunc=D3DCMP_LESS; break;
|
|
case IDriver::lessequal: _CurStencilFunc=D3DCMP_LESSEQUAL; break;
|
|
case IDriver::equal: _CurStencilFunc=D3DCMP_EQUAL; break;
|
|
case IDriver::notequal: _CurStencilFunc=D3DCMP_NOTEQUAL; break;
|
|
case IDriver::greaterequal: _CurStencilFunc=D3DCMP_GREATEREQUAL; break;
|
|
case IDriver::greater: _CurStencilFunc=D3DCMP_GREATER; break;
|
|
case IDriver::always: _CurStencilFunc=D3DCMP_ALWAYS; break;
|
|
default: nlstop;
|
|
}
|
|
|
|
_CurStencilRef = (DWORD)ref;
|
|
_CurStencilMask = (DWORD)mask;
|
|
setRenderState(D3DRS_STENCILFUNC, _CurStencilFunc);
|
|
setRenderState(D3DRS_STENCILREF, _CurStencilRef);
|
|
setRenderState(D3DRS_STENCILMASK, _CurStencilMask);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::stencilOp(TStencilOp fail, TStencilOp zfail, TStencilOp zpass)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_CDriverD3D);
|
|
|
|
switch(fail)
|
|
{
|
|
case IDriver::keep: _CurStencilOpFail=D3DSTENCILOP_KEEP; break;
|
|
case IDriver::zero: _CurStencilOpFail=D3DSTENCILOP_ZERO; break;
|
|
case IDriver::replace: _CurStencilOpFail=D3DSTENCILOP_REPLACE; break;
|
|
case IDriver::incr: _CurStencilOpFail=D3DSTENCILOP_INCR; break;
|
|
case IDriver::decr: _CurStencilOpFail=D3DSTENCILOP_DECR; break;
|
|
case IDriver::invert: _CurStencilOpFail=D3DSTENCILOP_INVERT; break;
|
|
default: nlstop;
|
|
}
|
|
|
|
switch(zfail)
|
|
{
|
|
case IDriver::keep: _CurStencilOpZFail=D3DSTENCILOP_KEEP; break;
|
|
case IDriver::zero: _CurStencilOpZFail=D3DSTENCILOP_ZERO; break;
|
|
case IDriver::replace: _CurStencilOpZFail=D3DSTENCILOP_REPLACE; break;
|
|
case IDriver::incr: _CurStencilOpZFail=D3DSTENCILOP_INCR; break;
|
|
case IDriver::decr: _CurStencilOpZFail=D3DSTENCILOP_DECR; break;
|
|
case IDriver::invert: _CurStencilOpZFail=D3DSTENCILOP_INVERT; break;
|
|
default: nlstop;
|
|
}
|
|
|
|
switch(zpass)
|
|
{
|
|
case IDriver::keep: _CurStencilOpZPass=D3DSTENCILOP_KEEP; break;
|
|
case IDriver::zero: _CurStencilOpZPass=D3DSTENCILOP_ZERO; break;
|
|
case IDriver::replace: _CurStencilOpZPass=D3DSTENCILOP_REPLACE; break;
|
|
case IDriver::incr: _CurStencilOpZPass=D3DSTENCILOP_INCR; break;
|
|
case IDriver::decr: _CurStencilOpZPass=D3DSTENCILOP_DECR; break;
|
|
case IDriver::invert: _CurStencilOpZPass=D3DSTENCILOP_INVERT; break;
|
|
default: nlstop;
|
|
}
|
|
|
|
setRenderState(D3DRS_STENCILFAIL, _CurStencilOpFail);
|
|
setRenderState(D3DRS_STENCILZFAIL, _CurStencilOpZFail);
|
|
setRenderState(D3DRS_STENCILPASS, _CurStencilOpZPass);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::stencilMask(uint mask)
|
|
{
|
|
H_AUTO_D3D(CDriver3D_CDriverD3D);
|
|
|
|
_CurStencilWriteMask = (DWORD)mask;
|
|
setRenderState (D3DRS_STENCILWRITEMASK, _CurStencilWriteMask);
|
|
}
|
|
|
|
// volatile bool preciseStateProfile = false;
|
|
// ***************************************************************************
|
|
void CDriverD3D::CRenderState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CRenderState);
|
|
/*if (!preciseStateProfile)
|
|
{*/
|
|
driver->_DeviceInterface->SetRenderState (StateID, Value);
|
|
/*
|
|
}
|
|
else
|
|
{
|
|
switch(StateID)
|
|
{
|
|
case D3DRS_ZENABLE: { H_AUTO_D3D(D3DRS_ZENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FILLMODE: { H_AUTO_D3D(D3DRS_FILLMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SHADEMODE: { H_AUTO_D3D(D3DRS_SHADEMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ZWRITEENABLE: { H_AUTO_D3D(D3DRS_ZWRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ALPHATESTENABLE: { H_AUTO_D3D(D3DRS_ALPHATESTENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_LASTPIXEL: { H_AUTO_D3D(D3DRS_LASTPIXEL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SRCBLEND: { H_AUTO_D3D(D3DRS_SRCBLEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_DESTBLEND: { H_AUTO_D3D(D3DRS_DESTBLEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CULLMODE: { H_AUTO_D3D(D3DRS_CULLMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ZFUNC: { H_AUTO_D3D(D3DRS_ZFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ALPHAREF: { H_AUTO_D3D(D3DRS_ALPHAREF); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ALPHAFUNC: { H_AUTO_D3D(D3DRS_ALPHAFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_DITHERENABLE: { H_AUTO_D3D(D3DRS_DITHERENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ALPHABLENDENABLE: { H_AUTO_D3D(D3DRS_ALPHABLENDENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGENABLE: { H_AUTO_D3D(D3DRS_FOGENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SPECULARENABLE: { H_AUTO_D3D(D3DRS_SPECULARENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGCOLOR: { H_AUTO_D3D(D3DRS_FOGCOLOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGTABLEMODE: { H_AUTO_D3D(D3DRS_FOGTABLEMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGSTART: { H_AUTO_D3D(D3DRS_FOGSTART); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGEND: { H_AUTO_D3D(D3DRS_FOGEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGDENSITY: { H_AUTO_D3D(D3DRS_FOGDENSITY); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_RANGEFOGENABLE: { H_AUTO_D3D(D3DRS_RANGEFOGENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILENABLE: { H_AUTO_D3D(D3DRS_STENCILENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILFAIL: { H_AUTO_D3D(D3DRS_STENCILFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILZFAIL: { H_AUTO_D3D(D3DRS_STENCILZFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILPASS: { H_AUTO_D3D(D3DRS_STENCILPASS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILFUNC: { H_AUTO_D3D(D3DRS_STENCILFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILREF: { H_AUTO_D3D(D3DRS_STENCILREF); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILMASK: { H_AUTO_D3D(D3DRS_STENCILMASK); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_STENCILWRITEMASK: { H_AUTO_D3D(D3DRS_STENCILWRITEMASK); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_TEXTUREFACTOR: { H_AUTO_D3D(D3DRS_TEXTUREFACTOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP0: { H_AUTO_D3D(D3DRS_WRAP0); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP1: { H_AUTO_D3D(D3DRS_WRAP1); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP2: { H_AUTO_D3D(D3DRS_WRAP2); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP3: { H_AUTO_D3D(D3DRS_WRAP3); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP4: { H_AUTO_D3D(D3DRS_WRAP4); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP5: { H_AUTO_D3D(D3DRS_WRAP5); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP6: { H_AUTO_D3D(D3DRS_WRAP6); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP7: { H_AUTO_D3D(D3DRS_WRAP7); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CLIPPING: { H_AUTO_D3D(D3DRS_CLIPPING); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_LIGHTING: { H_AUTO_D3D(D3DRS_LIGHTING); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_AMBIENT: { H_AUTO_D3D(D3DRS_AMBIENT); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_FOGVERTEXMODE: { H_AUTO_D3D(D3DRS_FOGVERTEXMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_COLORVERTEX: { H_AUTO_D3D(D3DRS_COLORVERTEX); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_LOCALVIEWER: { H_AUTO_D3D(D3DRS_LOCALVIEWER); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_NORMALIZENORMALS: { H_AUTO_D3D(D3DRS_NORMALIZENORMALS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_DIFFUSEMATERIALSOURCE: { H_AUTO_D3D(D3DRS_DIFFUSEMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SPECULARMATERIALSOURCE: { H_AUTO_D3D(D3DRS_SPECULARMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_AMBIENTMATERIALSOURCE: { H_AUTO_D3D(D3DRS_AMBIENTMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_EMISSIVEMATERIALSOURCE: { H_AUTO_D3D(D3DRS_EMISSIVEMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_VERTEXBLEND: { H_AUTO_D3D(D3DRS_VERTEXBLEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CLIPPLANEENABLE: { H_AUTO_D3D(D3DRS_CLIPPLANEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSIZE: { H_AUTO_D3D(D3DRS_POINTSIZE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSIZE_MIN: { H_AUTO_D3D(D3DRS_POINTSIZE_MIN); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSPRITEENABLE: { H_AUTO_D3D(D3DRS_POINTSPRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSCALEENABLE: { H_AUTO_D3D(D3DRS_POINTSCALEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSCALE_A: { H_AUTO_D3D(D3DRS_POINTSCALE_A); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSCALE_B: { H_AUTO_D3D(D3DRS_POINTSCALE_B); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSCALE_C: { H_AUTO_D3D(D3DRS_POINTSCALE_C); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_MULTISAMPLEANTIALIAS: { H_AUTO_D3D(D3DRS_MULTISAMPLEANTIALIAS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_MULTISAMPLEMASK: { H_AUTO_D3D(D3DRS_MULTISAMPLEMASK); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_PATCHEDGESTYLE: { H_AUTO_D3D(D3DRS_PATCHEDGESTYLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_DEBUGMONITORTOKEN: { H_AUTO_D3D(D3DRS_DEBUGMONITORTOKEN); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POINTSIZE_MAX: { H_AUTO_D3D(D3DRS_POINTSIZE_MAX); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_INDEXEDVERTEXBLENDENABLE: { H_AUTO_D3D(D3DRS_INDEXEDVERTEXBLENDENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_COLORWRITEENABLE: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_TWEENFACTOR: { H_AUTO_D3D(D3DRS_TWEENFACTOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_BLENDOP: { H_AUTO_D3D(D3DRS_BLENDOP); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_POSITIONDEGREE: { H_AUTO_D3D(D3DRS_POSITIONDEGREE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_NORMALDEGREE: { H_AUTO_D3D(D3DRS_NORMALDEGREE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SCISSORTESTENABLE: { H_AUTO_D3D(D3DRS_SCISSORTESTENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SLOPESCALEDEPTHBIAS: { H_AUTO_D3D(D3DRS_SLOPESCALEDEPTHBIAS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ANTIALIASEDLINEENABLE: { H_AUTO_D3D(D3DRS_ANTIALIASEDLINEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_MINTESSELLATIONLEVEL: { H_AUTO_D3D(D3DRS_MINTESSELLATIONLEVEL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_MAXTESSELLATIONLEVEL: { H_AUTO_D3D(D3DRS_MAXTESSELLATIONLEVEL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ADAPTIVETESS_X: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_X); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ADAPTIVETESS_Y: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_Y); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ADAPTIVETESS_Z: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_Z); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ADAPTIVETESS_W: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_W); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_ENABLEADAPTIVETESSELLATION: { H_AUTO_D3D(D3DRS_ENABLEADAPTIVETESSELLATION); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_TWOSIDEDSTENCILMODE: { H_AUTO_D3D(D3DRS_TWOSIDEDSTENCILMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CCW_STENCILFAIL: { H_AUTO_D3D(D3DRS_CCW_STENCILFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CCW_STENCILZFAIL: { H_AUTO_D3D(D3DRS_CCW_STENCILZFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CCW_STENCILPASS: { H_AUTO_D3D(D3DRS_CCW_STENCILPASS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_CCW_STENCILFUNC: { H_AUTO_D3D(D3DRS_CCW_STENCILFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_COLORWRITEENABLE1: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE1); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_COLORWRITEENABLE2: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE2); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_COLORWRITEENABLE3: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE3); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_BLENDFACTOR: { H_AUTO_D3D(D3DRS_BLENDFACTOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SRGBWRITEENABLE: { H_AUTO_D3D(D3DRS_SRGBWRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_DEPTHBIAS: { H_AUTO_D3D(D3DRS_DEPTHBIAS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP8: { H_AUTO_D3D(D3DRS_WRAP8); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP9: { H_AUTO_D3D(D3DRS_WRAP9); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP10: { H_AUTO_D3D(D3DRS_WRAP10); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP11: { H_AUTO_D3D(D3DRS_WRAP11); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP12: { H_AUTO_D3D(D3DRS_WRAP12); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP13: { H_AUTO_D3D(D3DRS_WRAP13); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP14: { H_AUTO_D3D(D3DRS_WRAP14); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_WRAP15: { H_AUTO_D3D(D3DRS_WRAP15); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SEPARATEALPHABLENDENABLE: { H_AUTO_D3D(D3DRS_SEPARATEALPHABLENDENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_SRCBLENDALPHA: { H_AUTO_D3D(D3DRS_SRCBLENDALPHA); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_DESTBLENDALPHA: { H_AUTO_D3D(D3DRS_DESTBLENDALPHA); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
case D3DRS_BLENDOPALPHA: { H_AUTO_D3D(D3DRS_BLENDOPALPHA); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CTextureState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CTextureState);
|
|
if (Value != DeviceValue)
|
|
{
|
|
driver->_DeviceInterface->SetTextureStageState (StageID, StateID, Value);
|
|
DeviceValue = Value;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CTextureIndexState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CTextureIndexState);
|
|
if (TexGen)
|
|
driver->setTextureState (StageID, D3DTSS_TEXCOORDINDEX, TexGenMode);
|
|
else
|
|
driver->setTextureState (StageID, D3DTSS_TEXCOORDINDEX, UVChannel);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CTexturePtrState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CTexturePtrState);
|
|
driver->_DeviceInterface->SetTexture (StageID, Texture);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CVertexProgramPtrState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CVertexProgramPtrState);
|
|
driver->_DeviceInterface->SetVertexShader(VertexProgram);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CPixelShaderPtrState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CPixelShaderPtrState);
|
|
if (!driver->_PixelProgram) return;
|
|
driver->_DeviceInterface->SetPixelShader(PixelShader);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CVertexProgramConstantState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CVertexProgramConstantState);
|
|
switch (ValueType)
|
|
{
|
|
case CVertexProgramConstantState::Float:
|
|
driver->_DeviceInterface->SetVertexShaderConstantF (StateID, (float*)Values, 1);
|
|
break;
|
|
case CVertexProgramConstantState::Int:
|
|
driver->_DeviceInterface->SetVertexShaderConstantI (StateID, (int*)Values, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CPixelShaderConstantState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CPixelShaderConstantState);
|
|
switch (ValueType)
|
|
{
|
|
case CPixelShaderConstantState::Float:
|
|
driver->_DeviceInterface->SetPixelShaderConstantF (StateID, (float*)Values, 1);
|
|
break;
|
|
case CPixelShaderConstantState::Int:
|
|
driver->_DeviceInterface->SetPixelShaderConstantI (StateID, (int*)Values, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CSamplerState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CSamplerState);
|
|
driver->_DeviceInterface->SetSamplerState (SamplerID, StateID, Value);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CMatrixState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CMatrixState);
|
|
driver->_DeviceInterface->SetTransform (TransformType, &Matrix);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CVBState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CVBState);
|
|
if (VertexBuffer)
|
|
{
|
|
driver->_DeviceInterface->SetStreamSource (0, VertexBuffer, Offset, Stride);
|
|
// Fix for radeon 7xxx & bad vertex layout
|
|
if (driver->inlGetNumTextStages() == 3) // If there are 3 stages this is a Radeon 7xxx
|
|
{
|
|
if (ColorOffset != 0 && driver->_VertexDeclCache.EnableVertexColor)
|
|
{
|
|
driver->_DeviceInterface->SetStreamSource (1, VertexBuffer, Offset + ColorOffset, Stride);
|
|
}
|
|
else
|
|
{
|
|
driver->_DeviceInterface->SetStreamSource (1, NULL, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// ***************************************************************************
|
|
void CDriverD3D::CIBState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CIBState);
|
|
if (IndexBuffer)
|
|
{
|
|
driver->_DeviceInterface->SetIndices (IndexBuffer);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CVertexDeclState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CVertexDeclState);
|
|
if (Decl)
|
|
{
|
|
if (!EnableVertexColor && DeclAliasDiffuseToSpecular && driver->inlGetNumTextStages() == 3)
|
|
{
|
|
// Fix for radeon 7xxx -> if vertex color is not used it should not be present in the vertex declaration (example : lighted material + vertex color but, no vertexColorLighted)
|
|
nlassert(DeclNoDiffuse);
|
|
driver->_DeviceInterface->SetVertexDeclaration (DeclNoDiffuse);
|
|
}
|
|
else
|
|
if (AliasDiffuseToSpecular)
|
|
{
|
|
nlassert(DeclAliasDiffuseToSpecular);
|
|
driver->_DeviceInterface->SetVertexDeclaration (DeclAliasDiffuseToSpecular);
|
|
}
|
|
else
|
|
{
|
|
nlassert(Decl);
|
|
driver->_DeviceInterface->SetVertexDeclaration (Decl);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CLightState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CLightState);
|
|
// Enable state modified ?
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CLightStateEnabled);
|
|
if (EnabledTouched)
|
|
driver->_DeviceInterface->LightEnable (LightIndex, Enabled);
|
|
}
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CLightStateSetup);
|
|
// Light enabled ?
|
|
if (Enabled)
|
|
{
|
|
if (SettingsTouched)
|
|
{
|
|
// New position
|
|
Light.Position.x -= driver->_PZBCameraPos.x;
|
|
Light.Position.y -= driver->_PZBCameraPos.y;
|
|
Light.Position.z -= driver->_PZBCameraPos.z;
|
|
driver->_DeviceInterface->SetLight (LightIndex, &Light);
|
|
SettingsTouched = false;
|
|
}
|
|
}
|
|
// Clean
|
|
EnabledTouched = false;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CRenderTargetState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CRenderTargetState);
|
|
driver->_DeviceInterface->SetRenderTarget (0, Target);
|
|
driver->setupViewport(driver->_Viewport);
|
|
driver->setupScissor(driver->_Scissor);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::CMaterialState::apply(CDriverD3D *driver)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_CMaterialState);
|
|
driver->_DeviceInterface->SetMaterial(&Current);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::beginDialogMode()
|
|
{
|
|
if (_FullScreen && _HWnd)
|
|
ShowWindow(_HWnd, SW_MINIMIZE);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverD3D::endDialogMode()
|
|
{
|
|
if (_FullScreen && _HWnd)
|
|
ShowWindow(_HWnd, SW_MAXIMIZE);
|
|
}
|
|
|
|
bool CDriverD3D::clipRect(NLMISC::CRect &rect)
|
|
{
|
|
// Clip the wanted rectangle with window.
|
|
uint32 width, height;
|
|
getWindowSize(width, height);
|
|
|
|
sint32 xr=rect.right() ,yr=rect.bottom();
|
|
|
|
clamp((sint32&)rect.X, (sint32)0, (sint32)width);
|
|
clamp((sint32&)rect.Y, (sint32)0, (sint32)height);
|
|
clamp((sint32&)xr, (sint32)rect.X, (sint32)width);
|
|
clamp((sint32&)yr, (sint32)rect.Y, (sint32)height);
|
|
rect.Width= xr-rect.X;
|
|
rect.Height= yr-rect.Y;
|
|
|
|
return rect.Width>0 && rect.Height>0;
|
|
}
|
|
|
|
void CDriverD3D::getZBuffer(std::vector<float> &zbuffer)
|
|
{
|
|
H_AUTO_D3D(CDriverD3D_getZBuffer);
|
|
|
|
CRect rect(0, 0);
|
|
getWindowSize(rect.Width, rect.Height);
|
|
getZBufferPart(zbuffer, rect);
|
|
}
|
|
|
|
void CDriverD3D::getZBufferPart (std::vector<float> &zbuffer, NLMISC::CRect &rect)
|
|
{
|
|
zbuffer.clear();
|
|
|
|
IDirect3DSurface9 *surface;
|
|
if (SUCCEEDED(_DeviceInterface->GetDepthStencilSurface(&surface)))
|
|
{
|
|
if (clipRect(rect))
|
|
{
|
|
RECT winRect;
|
|
winRect.left = rect.left();
|
|
winRect.right = rect.right();
|
|
winRect.top = rect.top();
|
|
winRect.bottom = rect.bottom();
|
|
|
|
// Lock the surface
|
|
D3DLOCKED_RECT lock;
|
|
if (SUCCEEDED(surface->LockRect (&lock, &winRect, D3DLOCK_READONLY)))
|
|
{
|
|
zbuffer.resize(rect.Width*rect.Height);
|
|
|
|
// Surface desc
|
|
D3DSURFACE_DESC desc;
|
|
if (SUCCEEDED(surface->GetDesc(&desc)))
|
|
{
|
|
const uint8* pBits = (uint8*)lock.pBits;
|
|
|
|
for(uint y=0; y<rect.Height; ++y)
|
|
{
|
|
uint offset = y*rect.Width;
|
|
uint end = offset + rect.Width;
|
|
|
|
// 32 bits format supported
|
|
if (desc.Format == D3DFMT_D32F_LOCKABLE)
|
|
{
|
|
const float *src = (float*)(pBits + lock.Pitch * y);
|
|
float *dst = &zbuffer[offset];
|
|
memcpy(dst, src, rect.Width * sizeof(float));
|
|
}
|
|
else if (desc.Format == D3DFMT_D24S8)
|
|
{
|
|
uint32* pRow = (uint32*)(pBits + lock.Pitch * y);
|
|
while(offset != end)
|
|
{
|
|
uint32 value = *pRow++;
|
|
zbuffer[offset++] = (float)value / (float)std::numeric_limits<uint32>::max();
|
|
}
|
|
}
|
|
else if (desc.Format == D3DFMT_D16_LOCKABLE)
|
|
{
|
|
uint16* pRow = (uint16*)(pBits + lock.Pitch * y);
|
|
while(offset != end)
|
|
{
|
|
uint16 value = *pRow++;
|
|
zbuffer[offset++] = (float)value / (float)std::numeric_limits<uint16>::max();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
surface->UnlockRect ();
|
|
}
|
|
}
|
|
|
|
surface->Release();
|
|
}
|
|
}
|
|
|
|
|
|
void CDriverD3D::findNearestFullscreenVideoMode()
|
|
{
|
|
if(_CurrentMode.Windowed)
|
|
return;
|
|
|
|
std::vector<GfxMode> modes;
|
|
if(getModes(modes))
|
|
{
|
|
sint32 nbPixels = _CurrentMode.Width * _CurrentMode.Height;
|
|
sint32 minError = nbPixels;
|
|
uint bestMode = (uint)modes.size();
|
|
for(uint i=0; i < modes.size(); i++)
|
|
{
|
|
if(!modes[i].Windowed)
|
|
{
|
|
if(modes[i].Width==_CurrentMode.Width && modes[i].Height==_CurrentMode.Height)
|
|
{
|
|
// ok we found the perfect mode
|
|
return;
|
|
}
|
|
sint32 currentPixels = modes[i].Width * modes[i].Height;
|
|
sint32 currentError = abs(nbPixels - currentPixels);
|
|
if(currentError < minError)
|
|
{
|
|
minError = currentError;
|
|
bestMode = i;
|
|
}
|
|
}
|
|
}
|
|
if(bestMode != modes.size())
|
|
{
|
|
nlwarning("The video mode %dx%d doesn't exist, use the nearest mode %dx%d", _CurrentMode.Width, _CurrentMode.Height, modes[bestMode].Width, modes[bestMode].Height);
|
|
_CurrentMode.Width = modes[bestMode].Width;
|
|
_CurrentMode.Height = modes[bestMode].Height;
|
|
}
|
|
}
|
|
}
|
|
bool CDriverD3D::copyTextToClipboard(const ucstring &text)
|
|
{
|
|
return _EventEmitter.copyTextToClipboard(text);
|
|
}
|
|
|
|
bool CDriverD3D::pasteTextFromClipboard(ucstring &text)
|
|
{
|
|
return _EventEmitter.pasteTextFromClipboard(text);
|
|
}
|
|
|
|
bool CDriverD3D::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, HICON &icon, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY, bool cursor)
|
|
{
|
|
CBitmap src = bitmap;
|
|
// resample bitmap if necessary
|
|
if (src.getWidth() != iconWidth || src.getHeight() != iconHeight)
|
|
{
|
|
src.resample(iconWidth, iconHeight);
|
|
}
|
|
CBitmap colorBm;
|
|
colorBm.resize(iconWidth, iconHeight, CBitmap::RGBA);
|
|
const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]);
|
|
const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight);
|
|
CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]);
|
|
static volatile uint8 alphaThreshold = 127;
|
|
do
|
|
{
|
|
destColorPtr->modulateFromColor(*srcColorPtr, col);
|
|
std::swap(destColorPtr->R, destColorPtr->B);
|
|
++ srcColorPtr;
|
|
++ destColorPtr;
|
|
}
|
|
while (srcColorPtr != srcColorPtrLast);
|
|
//
|
|
HBITMAP colorHbm = NULL;
|
|
HBITMAP maskHbm = NULL;
|
|
//
|
|
if (iconDepth == 16)
|
|
{
|
|
std::vector<uint16> colorBm16(iconWidth * iconHeight);
|
|
const CRGBA *src32 = (const CRGBA *) &colorBm.getPixels(0)[0];
|
|
|
|
for (uint k = 0; k < colorBm16.size(); ++k)
|
|
{
|
|
colorBm16[k] = ((uint16)(src32[k].R&0xf8)>>3) | ((uint16)(src32[k].G&0xfc)<<3) | ((uint16)(src32[k].B & 0xf8)<<8);
|
|
}
|
|
|
|
colorHbm = CreateBitmap(iconWidth, iconHeight, 1, 16, &colorBm16[0]);
|
|
std::vector<uint8> bitMask((iconWidth * iconHeight + 7) / 8, 0);
|
|
|
|
for (uint k = 0;k < colorBm16.size(); ++k)
|
|
{
|
|
if (src32[k].A <= 120)
|
|
{
|
|
bitMask[k / 8] |= (0x80 >> (k & 7));
|
|
}
|
|
}
|
|
|
|
maskHbm = CreateBitmap(iconWidth, iconHeight, 1, 1, &bitMask[0]);
|
|
}
|
|
else
|
|
{
|
|
colorHbm = CreateBitmap(iconWidth, iconHeight, 1, 32, &colorBm.getPixels(0)[0]);
|
|
maskHbm = CreateBitmap(iconWidth, iconHeight, 1, 32, &colorBm.getPixels(0)[0]);
|
|
}
|
|
|
|
ICONINFO iconInfo;
|
|
iconInfo.fIcon = cursor ? FALSE:TRUE;
|
|
iconInfo.xHotspot = (DWORD) hotSpotX;
|
|
iconInfo.yHotspot = (DWORD) hotSpotY;
|
|
iconInfo.hbmMask = maskHbm;
|
|
iconInfo.hbmColor = colorHbm;
|
|
|
|
if (colorHbm && maskHbm)
|
|
{
|
|
icon = CreateIconIndirect(&iconInfo);
|
|
}
|
|
|
|
//
|
|
if (colorHbm) DeleteObject(colorHbm);
|
|
if (maskHbm) DeleteObject(maskHbm);
|
|
|
|
return true;
|
|
}
|
|
|
|
} // NL3D
|