Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / driver / direct3d / driver_direct3d.cpp
blobf201455afb9846dceb46bac6581267cee74914d8
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Robert TIMM (rti) <mail@rtti.de>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // Copyright (C) 2014 Matthew LAGOE (Botanic) <cyberempires@gmail.com>
8 //
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Affero General Public License as
11 // published by the Free Software Foundation, either version 3 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Affero General Public License for more details.
19 // You should have received a copy of the GNU Affero General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stddirect3d.h"
24 // by default, we disable the windows menu keys (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
25 #define NL_DISABLE_MENU
27 #include <tchar.h>
29 #include "nel/3d/vertex_buffer.h"
30 #include "nel/3d/light.h"
31 #include "nel/3d/index_buffer.h"
32 #include "nel/misc/rect.h"
33 #include "nel/misc/dynloadlib.h"
34 #include "nel/3d/viewport.h"
35 #include "nel/3d/scissor.h"
36 #include "nel/3d/u_driver.h"
38 #include "driver_direct3d.h"
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 using namespace std;
45 using namespace NLMISC;
47 #define RASTERIZER D3DDEVTYPE_HAL
48 //#define RASTERIZER D3DDEVTYPE_REF
50 #define D3D_WINDOWED_STYLE (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX)
51 #define D3D_FULLSCREEN_STYLE (WS_POPUP)
53 // ***************************************************************************
55 // Try to allocate 16Mo by default of AGP Ram.
56 #define NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE (16384*1024)
58 // Initial volatile vertex buffer size
59 #define NL_VOLATILE_RAM_VB_SIZE 512*1024
60 #define NL_VOLATILE_AGP_VB_SIZE 128*1024
61 #define NL_VOLATILE_RAM_IB_SIZE 64*1024
62 #define NL_VOLATILE_AGP_IB_SIZE 1024
64 #define NL_VOLATILE_RAM_VB_MAXSIZE 512*1024
65 #define NL_VOLATILE_AGP_VB_MAXSIZE 2500*1024
66 #define NL_VOLATILE_RAM_IB_MAXSIZE 1024*1024
67 #define NL_VOLATILE_AGP_IB_MAXSIZE 256*1024
71 // ***************************************************************************
73 #ifndef NL_STATIC
75 HINSTANCE HInstDLL = NULL;
77 BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
79 HInstDLL = hinstDLL;
81 return true;
84 class CDriverD3DNelLibrary : public INelLibrary {
85 void onLibraryLoaded(bool firstTime) { }
86 void onLibraryUnloaded(bool lastTime) { }
88 NLMISC_DECL_PURE_LIB(CDriverD3DNelLibrary)
90 #endif /* #ifndef NL_STATIC */
92 // ***************************************************************************
94 namespace NL3D
97 // ***************************************************************************
99 // Version of the driver. Not the interface version!! Increment when implementation of the driver change.
100 const uint32 CDriverD3D::ReleaseVersion = 0xe;
104 // ***************************************************************************
106 #ifdef NL_STATIC
108 # pragma comment(lib, "d3dx9")
109 # pragma comment(lib, "d3d9")
110 # pragma comment(lib, "dinput8")
111 # pragma comment(lib, "dxguid")
113 IDriver* createD3DDriverInstance ()
115 return new CDriverD3D;
118 #else
120 #ifdef NL_COMP_MINGW
121 extern "C"
123 #endif
124 __declspec(dllexport) IDriver* NL3D_createIDriverInstance ()
126 return new CDriverD3D;
129 __declspec(dllexport) uint32 NL3D_interfaceVersion ()
131 return IDriver::InterfaceVersion;
133 #ifdef NL_COMP_MINGW
135 #endif
136 #endif
138 /*static*/ bool CDriverD3D::_CacheTest[CacheTest_Count] =
140 false, // CacheTest_CullMode = 0;
141 false, // CacheTest_RenderState = 1,
142 false, // CacheTest_TextureState = 2,
143 false, // CacheTest_TextureIndexMode = 3,
144 false, // CacheTest_TextureIndexUV = 4,
145 false, // CacheTest_Texture = 5,
146 false, // CacheTest_VertexProgram = 6,
147 false, // CacheTest_PixelShader = 7,
148 false, // CacheTest_VertexProgramConstant = 8,
149 false, // CacheTest_PixelShaderConstant = 9,
150 false, // CacheTest_SamplerState = 10,
151 false, // CacheTest_VertexBuffer = 11,
152 false, // CacheTest_IndexBuffer = 12,
153 false, // CacheTest_VertexDecl = 13,
154 false, // CacheTest_Matrix = 14,
155 false, // CacheTest_RenderTarget = 15,
156 false, // CacheTest_MaterialState = 16,
157 false // CacheTest_DepthRange = 17,
163 // ***************************************************************************
165 CDriverD3D::CDriverD3D()
167 _SwapBufferCounter = 0;
168 _CurrentOcclusionQuery = NULL;
169 _D3D = NULL;
170 _HWnd = NULL;
171 _DeviceInterface = NULL;
172 _DestroyWindow = false;
173 _CurrentMode.Width = 640;
174 _CurrentMode.Height = 480;
175 _WindowX = 0;
176 _WindowY = 0;
177 _FullScreen = false;
179 _ColorDepth = ColorDepth32;
181 _DefaultCursor = EmptyCursor;
183 _AlphaBlendedCursorSupported = false;
184 _AlphaBlendedCursorSupportRetrieved = false;
185 _CurrCol = CRGBA::White;
186 _CurrRot = 0;
187 _CurrHotSpotX = 0;
188 _CurrHotSpotY = 0;
189 _CursorScale = 1.f;
191 _UserViewMtx.identity();
192 _UserModelMtx.identity();
193 _PZBCameraPos = CVector::Null;
194 _CurrentMaterial = NULL;
195 _CurrentMaterialInfo = NULL;
196 _CurrentShader = NULL;
197 _BackBuffer = NULL;
198 _Maximized = false;
199 _HandlePossibleSizeChangeNextSize = false;
200 _WindowFocus = true;
201 _Interval = 1;
202 _AGPMemoryAllocated = 0;
203 _VRAMMemoryAllocated = 0;
204 _Rasterizer = RASTERIZER;
205 #ifdef NL_DISABLE_HARDWARE_VERTEX_PROGAM
206 _DisableHardwareVertexProgram = true;
207 #else // NL_DISABLE_HARDWARE_VERTEX_PROGAM
208 _DisableHardwareVertexProgram = false;
209 #endif // NL_DISABLE_HARDWARE_VERTEX_PROGAM
210 #ifdef NL_DISABLE_HARDWARE_PIXEL_PROGAM
211 _DisableHardwarePixelProgram = true;
212 #else // NL_DISABLE_HARDWARE_PIXEL_PROGAM
213 _DisableHardwarePixelProgram = false;
214 #endif // NL_DISABLE_HARDWARE_PIXEL_PROGAM
215 #ifdef NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP
216 _DisableHardwareVertexArrayAGP = true;
217 #else // NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP
218 _DisableHardwareVertexArrayAGP = false;
219 #endif // NL_DISABLE_HARDWARE_VERTEX_ARRAY_AGP
220 #ifdef NL_DISABLE_HARDWARE_INDEX_ARRAY_AGP
221 _DisableHardwareIndexArrayAGP = true;
222 #else // NL_DISABLE_HARDWARE_INDEX_ARRAY_AGP
223 _DisableHardwareIndexArrayAGP = false;
224 #endif // NL_DISABLE_HARDWARE_INDEX_ARRAY_AGP
225 #ifdef NL_DISABLE_HARDWARE_PIXEL_SHADER
226 _DisableHardwarePixelShader = true;
227 #else // NL_DISABLE_HARDWARE_PIXEL_SHADER
228 _DisableHardwarePixelShader = false;
229 #endif // NL_DISABLE_HARDWARE_PIXEL_SHADER
231 // Compute the Flag which say if one texture has been changed in CMaterial.
232 _MaterialAllTextureTouchedFlag= 0;
233 uint i;
234 for(i=0; i < IDRV_MAT_MAXTEXTURES; i++)
236 _MaterialAllTextureTouchedFlag|= IDRV_TOUCHED_TEX[i];
239 // Default adapter
240 _Adapter = 0xffffffff;
241 _ModifiedRenderState = NULL;
243 // Create a Direct 3d object
244 if ( NULL == (_D3D = Direct3DCreate9(D3D_SDK_VERSION)))
246 nlwarning ("Can't create the direct 3d 9 object.");
248 #ifdef NL_OS_WINDOWS
249 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);
250 if(val == IDOK)
252 openURL("http://www.microsoft.com/downloads/details.aspx?FamilyID=4b1f5d0c-5e44-4864-93cd-464ef59da050");
254 #endif
255 exit(EXIT_FAILURE);
258 _DepthRangeNear = 0.f;
259 _DepthRangeFar = 1.f;
260 // default for lightmap
261 _LightMapDynamicLightDirty= false;
262 _LightMapDynamicLightEnabled= false;
263 _CurrentMaterialSupportedShader= CMaterial::Normal;
264 // to avoid any problem if light0 never setuped, and ligthmap rendered
265 _UserLight0.setupDirectional(CRGBA::Black, CRGBA::White, CRGBA::White, CVector::K);
266 // All User Light are disabled by Default
267 for(i=0;i<MaxLight;i++)
268 _UserLightEnable[i]= false;
269 _CullMode = CCW;
270 _ScissorTouched = true;
271 _Scissor.X = -1;
272 _Scissor.Y = -1;
273 _Scissor.Width = -1;
274 _Scissor.Height = -1;
276 _CurStencilTest = false;
277 _CurStencilFunc = D3DCMP_ALWAYS;
278 _CurStencilRef = 0;
279 _CurStencilMask = std::numeric_limits<DWORD>::max();
280 _CurStencilOpFail = D3DSTENCILOP_KEEP;
281 _CurStencilOpZFail = D3DSTENCILOP_KEEP;
282 _CurStencilOpZPass = D3DSTENCILOP_KEEP;
283 _CurStencilWriteMask = std::numeric_limits<DWORD>::max();
286 for(uint k = 0; k < MaxTexture; ++k)
288 _CurrentUVRouting[k] = (uint8) k;
290 _VolatileVertexBufferRAM[0] = new CVolatileVertexBuffer;
291 _VolatileVertexBufferRAM[1] = new CVolatileVertexBuffer;
292 _VolatileVertexBufferAGP[0] = new CVolatileVertexBuffer;
293 _VolatileVertexBufferAGP[1] = new CVolatileVertexBuffer;
294 _VolatileIndexBuffer16RAM[0]= new CVolatileIndexBuffer;
295 _VolatileIndexBuffer16RAM[1]= new CVolatileIndexBuffer;
296 _VolatileIndexBuffer16AGP[0]= new CVolatileIndexBuffer;
297 _VolatileIndexBuffer16AGP[1]= new CVolatileIndexBuffer;
298 _VolatileIndexBuffer32RAM[0]= new CVolatileIndexBuffer;
299 _VolatileIndexBuffer32RAM[1]= new CVolatileIndexBuffer;
300 _VolatileIndexBuffer32AGP[0]= new CVolatileIndexBuffer;
301 _VolatileIndexBuffer32AGP[1]= new CVolatileIndexBuffer;
302 _MustRestoreLight = false;
303 _Lost = false;
304 _SceneBegun = false;
305 _MaxVertexIndex = 0;
306 _QuadIB = NULL;
307 _MaxNumPerStageConstantLighted = 0;
308 _MaxNumPerStageConstantUnlighted = 0;
309 D3DXMatrixIdentity(&_D3DMatrixIdentity);
310 _FogColor = 0xffffffff;
311 _CurrIndexBufferFormat = CIndexBuffer::IndicesUnknownFormat;
312 _IsGeforce = false;
313 _NonPowerOfTwoTexturesSupported = false;
314 _MaxAnisotropy = 0;
315 _AnisotropicMinSupported = false;
316 _AnisotropicMagSupported = false;
317 _AnisotropicMinCubeSupported = false;
318 _AnisotropicMagCubeSupported = false;
320 _FrustumLeft= -1.f;
321 _FrustumRight= 1.f;
322 _FrustumTop= 1.f;
323 _FrustumBottom= -1.f;
324 _FrustumZNear= -1.f;
325 _FrustumZFar= 1.f;
326 _FrustumPerspective= false;
327 _FogStart = 0;
328 _FogEnd = 1;
330 _SumTextureMemoryUsed = false;
333 _DesktopGammaRampValid = false;
336 // ***************************************************************************
338 CDriverD3D::~CDriverD3D()
340 release();
342 if(_D3D != NULL)
344 _D3D->Release();
345 _D3D = NULL;
347 delete _VolatileVertexBufferRAM[0];
348 delete _VolatileVertexBufferRAM[1];
349 delete _VolatileVertexBufferAGP[0];
350 delete _VolatileVertexBufferAGP[1];
351 delete _VolatileIndexBuffer16RAM[0];
352 delete _VolatileIndexBuffer16RAM[1];
353 delete _VolatileIndexBuffer16AGP[0];
354 delete _VolatileIndexBuffer16AGP[1];
355 delete _VolatileIndexBuffer32RAM[0];
356 delete _VolatileIndexBuffer32RAM[1];
357 delete _VolatileIndexBuffer32AGP[0];
358 delete _VolatileIndexBuffer32AGP[1];
361 // ***************************************************************************
363 void CDriverD3D::resetRenderVariables()
365 H_AUTO_D3D(CDriver3D_resetRenderVariables);
367 uint i;
368 for (i=0; i<MaxRenderState; i++)
370 if (_RenderStateCache[i].ValueSet)
372 // here, don't use 0xcccccccc, because it is a valid value for D3DRS_TFACTOR
373 touchRenderVariable (&(_RenderStateCache[i]));
377 for (i=0; i<MaxTexture; i++)
379 uint j;
380 for (j=0; j<MaxTextureState; j++)
382 if (_TextureStateCache[i][j].Value != 0xcccccccc)
384 touchRenderVariable (&(_TextureStateCache[i][j]));
385 _TextureStateCache[i][j].DeviceValue = 0xcccccccc;
389 for (i=0; i<MaxTexture; i++)
391 if (_TextureIndexStateCache[i].TexGenMode != 0xcccccccc)
392 touchRenderVariable (&(_TextureIndexStateCache[i]));
394 for (i=0; i<MaxTexture; i++)
396 if ((uintptr_t)(_TexturePtrStateCache[i].Texture) != 0xcccccccc)
398 touchRenderVariable (&(_TexturePtrStateCache[i]));
399 // reset texture because it may reference an old render target
400 CTexturePtrState &textureState = (CTexturePtrState &)(_TexturePtrStateCache[i]);
401 textureState.Texture = NULL;
404 for (i=0; i<MaxSampler; i++)
406 uint j;
407 for (j=0; j<MaxSamplerState; j++)
409 if (_SamplerStateCache[i][j].Value != 0xcccccccc)
410 touchRenderVariable (&(_SamplerStateCache[i][j]));
413 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_VIEW)]));
414 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_PROJECTION)]));
415 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE0)]));
416 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE1)]));
417 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE2)]));
418 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE3)]));
419 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE4)]));
420 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE5)]));
421 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE6)]));
422 touchRenderVariable (&(_MatrixCache[remapMatrixIndex (D3DTS_TEXTURE7)]));
425 // Vertices and indexes are not valid anymore
426 _VertexBufferCache.VertexBuffer = NULL;
427 _IndexBufferCache.IndexBuffer = NULL;
428 _VertexDeclCache.Decl = NULL;
430 touchRenderVariable (&(_VertexBufferCache));
431 touchRenderVariable (&(_IndexBufferCache));
432 touchRenderVariable (&(_VertexDeclCache));
434 for (i=0; i<MaxLight; i++)
436 if (*(uintptr_t*)(&(_LightCache[i].Light)) != 0xcccccccc)
438 _LightCache[i].EnabledTouched = true;
439 touchRenderVariable (&(_LightCache[i]));
443 // Vertices and indexes are not valid anymore
444 _VertexProgramCache.VertexProgram = NULL;
445 _VertexProgramCache.VP = NULL;
446 touchRenderVariable (&(_VertexProgramCache));
447 _PixelShaderCache.PixelShader = NULL;
448 touchRenderVariable (&(_PixelShaderCache));
449 touchRenderVariable(&_MaterialState);
451 for (i=0; i<MaxVertexProgramConstantState; i++)
453 touchRenderVariable (&(_VertexProgramConstantCache[i]));
455 for (i=0; i<MaxPixelShaderConstantState; i++)
457 touchRenderVariable (&(_PixelShaderConstantCache[i]));
459 setRenderTarget (NULL, 0, 0, 0, 0, 0, 0);
461 CVertexBuffer::TLocation vertexAgpLocation = _DisableHardwareVertexArrayAGP ? CVertexBuffer::RAMResident : CVertexBuffer::AGPResident;
462 CIndexBuffer::TLocation indexAgpLocation = _DisableHardwareIndexArrayAGP ? CIndexBuffer::RAMResident : CIndexBuffer::AGPResident;
464 // Init volatile vertex buffers
465 _VolatileVertexBufferRAM[0]->init (CVertexBuffer::RAMResident, _VolatileVertexBufferRAM[0]->Size, _VolatileVertexBufferRAM[0]->MaxSize, this);
466 _VolatileVertexBufferRAM[0]->reset ();
467 _VolatileVertexBufferRAM[1]->init (CVertexBuffer::RAMResident, _VolatileVertexBufferRAM[1]->Size, _VolatileVertexBufferRAM[1]->MaxSize, this);
468 _VolatileVertexBufferRAM[1]->reset ();
469 _VolatileVertexBufferAGP[0]->init (vertexAgpLocation, _VolatileVertexBufferAGP[0]->Size, _VolatileVertexBufferAGP[0]->MaxSize, this);
470 _VolatileVertexBufferAGP[0]->reset ();
471 _VolatileVertexBufferAGP[1]->init (vertexAgpLocation, _VolatileVertexBufferAGP[1]->Size, _VolatileVertexBufferAGP[1]->MaxSize, this);
472 _VolatileVertexBufferAGP[1]->reset ();
474 _VolatileIndexBuffer16RAM[0]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer16RAM[0]->Size, _VolatileIndexBuffer16RAM[0]->MaxSize, this, CIndexBuffer::Indices16);
475 _VolatileIndexBuffer16RAM[0]->reset ();
476 _VolatileIndexBuffer16RAM[1]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer16RAM[1]->Size, _VolatileIndexBuffer16RAM[1]->MaxSize, this, CIndexBuffer::Indices16);
477 _VolatileIndexBuffer16RAM[1]->reset ();
478 _VolatileIndexBuffer16AGP[0]->init (indexAgpLocation, _VolatileIndexBuffer16AGP[0]->Size, _VolatileIndexBuffer16AGP[0]->MaxSize, this, CIndexBuffer::Indices16);
479 _VolatileIndexBuffer16AGP[0]->reset ();
480 _VolatileIndexBuffer16AGP[1]->init (indexAgpLocation, _VolatileIndexBuffer16AGP[1]->Size, _VolatileIndexBuffer16AGP[1]->MaxSize, this, CIndexBuffer::Indices16);
481 _VolatileIndexBuffer16AGP[1]->reset ();
483 if (_MaxVertexIndex > 0xffff) // supports 32 bits ?
485 _VolatileIndexBuffer32RAM[0]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer32RAM[0]->Size, _VolatileIndexBuffer32RAM[0]->MaxSize, this, CIndexBuffer::Indices32);
486 _VolatileIndexBuffer32RAM[0]->reset ();
487 _VolatileIndexBuffer32RAM[1]->init (CIndexBuffer::RAMResident, _VolatileIndexBuffer32RAM[1]->Size, _VolatileIndexBuffer32RAM[1]->MaxSize, this, CIndexBuffer::Indices32);
488 _VolatileIndexBuffer32RAM[1]->reset ();
489 _VolatileIndexBuffer32AGP[0]->init (indexAgpLocation, _VolatileIndexBuffer32AGP[0]->Size, _VolatileIndexBuffer32AGP[0]->MaxSize, this, CIndexBuffer::Indices32);
490 _VolatileIndexBuffer32AGP[0]->reset ();
491 _VolatileIndexBuffer32AGP[1]->init (indexAgpLocation, _VolatileIndexBuffer32AGP[1]->Size, _VolatileIndexBuffer32AGP[1]->MaxSize, this, CIndexBuffer::Indices32);
492 _VolatileIndexBuffer32AGP[1]->reset ();
494 _ScissorTouched = true;
497 // ***************************************************************************
499 void CDriverD3D::initRenderVariables()
501 H_AUTO_D3D(CDriver3D_initRenderVariables);
502 uint i;
503 for (i=0; i<MaxRenderState; i++)
505 _RenderStateCache[i].StateID = (D3DRENDERSTATETYPE)i;
506 _RenderStateCache[i].ValueSet = false;
507 _RenderStateCache[i].Modified = false;
509 for (i=0; i<MaxTexture; i++)
511 uint j;
512 for (j=0; j<MaxTextureState; j++)
514 _TextureStateCache[i][j].StageID = i;
515 _TextureStateCache[i][j].StateID = (D3DTEXTURESTAGESTATETYPE)j;
516 _TextureStateCache[i][j].Value = 0xcccccccc;
517 _TextureStateCache[i][j].Modified = false;
520 for (i=0; i<MaxTexture; i++)
522 _TextureIndexStateCache[i].StageID = i;
523 _TextureIndexStateCache[i].TexGen = false;
524 _TextureIndexStateCache[i].TexGenMode = 0xcccccccc;
525 _TextureIndexStateCache[i].UVChannel = 0xcccccccc;
526 _TextureIndexStateCache[i].Modified = false;
528 for (i=0; i<MaxTexture; i++)
530 _TexturePtrStateCache[i].StageID = i;
531 *(uintptr_t*)&(_TexturePtrStateCache[i].Texture) = 0xcccccccc;
532 _TexturePtrStateCache[i].Modified = false;
534 for (i=0; i<MaxSampler; i++)
536 uint j;
537 for (j=0; j<MaxSamplerState; j++)
539 _SamplerStateCache[i][j].SamplerID = i;
540 _SamplerStateCache[i][j].StateID = (D3DSAMPLERSTATETYPE)j;
541 _SamplerStateCache[i][j].Value = 0xcccccccc;
542 _SamplerStateCache[i][j].Modified = false;
545 for (i=0; i<MaxMatrixState; i++)
547 _MatrixCache[i].TransformType = (D3DTRANSFORMSTATETYPE)((i>=MatrixStateRemap)?i-MatrixStateRemap+256:i);
548 memset (&(_MatrixCache[i].Matrix), 0xcc, sizeof(D3DXMATRIX));
549 _MatrixCache[i].Modified = false;
551 _VertexBufferCache.Modified = false;
552 _VertexBufferCache.VertexBuffer = NULL;
553 _IndexBufferCache.Modified = false;
554 _IndexBufferCache.IndexBuffer = NULL;
555 _VertexDeclCache.Modified = false;
556 _VertexDeclCache.Decl = NULL;
557 for (i=0; i<MaxLight; ++i)
559 _LightCache[i].LightIndex = uint8(i);
560 *(uintptr_t*)&(_LightCache[i].Light) = 0xcccccccc;
561 _LightCache[i].Modified = false;
563 _VertexProgramCache.Modified = false;
564 _VertexProgramCache.VertexProgram = NULL;
565 _PixelShaderCache.Modified = false;
566 _PixelShaderCache.PixelShader = NULL;
567 for (i=0; i<MaxVertexProgramConstantState; i++)
569 _VertexProgramConstantCache[i].StateID = i;
570 _VertexProgramConstantCache[i].Modified = false;
571 _VertexProgramConstantCache[i].ValueType = CVertexProgramConstantState::Undef;
573 for (i=0; i<MaxPixelShaderConstantState; i++)
575 _PixelShaderConstantCache[i].StateID = i;
576 _PixelShaderConstantCache[i].Modified = false;
577 _PixelShaderConstantCache[i].ValueType = CPixelShaderConstantState::Undef;
579 _RenderTarget.Modified = false;
582 // Set the render states cache to its default values
583 setRenderState (D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA|D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE);
584 setRenderState (D3DRS_CULLMODE, D3DCULL_CW);
585 setRenderState (D3DRS_FOGENABLE, FALSE);
587 // Stencil Buffer
588 //affreux
589 setRenderState (D3DRS_STENCILENABLE, _CurStencilTest);
590 setRenderState (D3DRS_STENCILFUNC, _CurStencilFunc);
591 setRenderState (D3DRS_STENCILREF, _CurStencilRef);
592 setRenderState (D3DRS_STENCILMASK, _CurStencilMask);
593 setRenderState (D3DRS_STENCILFAIL, _CurStencilOpFail);
594 setRenderState (D3DRS_STENCILZFAIL, _CurStencilOpZFail);
595 setRenderState (D3DRS_STENCILPASS, _CurStencilOpZPass);
596 setRenderState (D3DRS_STENCILWRITEMASK, _CurStencilWriteMask);
598 // Force normalize
599 _ForceNormalize = false;
600 _UseVertexColor = false;
602 // Material
603 _CurrentMaterial = NULL;
604 _CurrentMaterialInfo = NULL;
605 _CurrentShader = NULL;
607 // Shaders
608 initInternalShaders();
610 // Fog default values
611 _FogStart = 0;
612 _FogEnd = 1;
613 setRenderState (D3DRS_FOGSTART, *((DWORD*) (&_FogStart)));
614 setRenderState (D3DRS_FOGEND, *((DWORD*) (&_FogEnd)));
615 setRenderState (D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
617 // Alpha render states
618 setRenderState (D3DRS_ALPHATESTENABLE, FALSE);
619 setRenderState (D3DRS_ALPHAREF, 128);
620 setRenderState (D3DRS_ALPHAFUNC, D3DCMP_GREATER);
622 // Cull mode
623 _InvertCullMode = false;
624 _DoubleSided = false;
626 // Depth range
627 _DepthRangeNear = 0.f;
628 _DepthRangeFar = 1.f;
630 // Flush caches
631 updateRenderVariablesInternal();
634 // ***************************************************************************
636 #define NL_SRC_OPERATORS_COUNT 6
638 // ***************************************************************************
640 static const D3DTEXTURESTAGESTATETYPE SrcOperators[NL_SRC_OPERATORS_COUNT]=
642 D3DTSS_COLORARG0,
643 D3DTSS_COLORARG1,
644 D3DTSS_COLORARG2,
645 D3DTSS_ALPHAARG0,
646 D3DTSS_ALPHAARG1,
647 D3DTSS_ALPHAARG2,
650 // ***************************************************************************
652 void CDriverD3D::updateRenderVariables()
654 H_AUTO_D3D(CDriver3D_updateRenderVariables);
655 _CurrentMaterial = NULL;
656 _CurrentMaterialInfo = NULL;
658 updateRenderVariablesInternal();
661 // ***************************************************************************
663 inline void CDriverD3D::applyRenderVariable(CRenderVariable *currentRenderState)
665 switch (currentRenderState->Type)
667 case CRenderVariable::RenderState:
669 CRenderState *renderState = static_cast<CRenderState*>(currentRenderState);
670 _DeviceInterface->SetRenderState (renderState->StateID, renderState->Value);
672 break;
673 case CRenderVariable::TextureState:
675 CTextureState *textureState = static_cast<CTextureState*>(currentRenderState);
676 _DeviceInterface->SetTextureStageState (textureState->StageID, textureState->StateID, textureState->Value);
678 break;
679 case CRenderVariable::TextureIndexState:
681 CTextureIndexState *textureState = static_cast<CTextureIndexState*>(currentRenderState);
682 if (textureState->TexGen)
683 setTextureState (textureState->StageID, D3DTSS_TEXCOORDINDEX, textureState->TexGenMode);
684 else
685 setTextureState (textureState->StageID, D3DTSS_TEXCOORDINDEX, textureState->UVChannel);
687 break;
688 case CRenderVariable::TexturePtrState:
690 CTexturePtrState *textureState = static_cast<CTexturePtrState*>(currentRenderState);
691 _DeviceInterface->SetTexture (textureState->StageID, textureState->Texture);
693 break;
694 case CRenderVariable::VertexProgramPtrState:
696 CVertexProgramPtrState *vertexProgram = static_cast<CVertexProgramPtrState*>(currentRenderState);
697 _DeviceInterface->SetVertexShader(vertexProgram->VertexProgram);
699 break;
700 case CRenderVariable::PixelShaderPtrState:
702 CPixelShaderPtrState *pixelShader = static_cast<CPixelShaderPtrState*>(currentRenderState);
703 _DeviceInterface->SetPixelShader(pixelShader->PixelShader);
705 break;
706 case CRenderVariable::VertexProgramConstantState:
708 CVertexProgramConstantState *vertexProgramConstant = static_cast<CVertexProgramConstantState*>(currentRenderState);
709 switch (vertexProgramConstant->ValueType)
711 case CVertexProgramConstantState::Float:
712 _DeviceInterface->SetVertexShaderConstantF (vertexProgramConstant->StateID, (float*)vertexProgramConstant->Values, 1);
713 break;
714 case CVertexProgramConstantState::Int:
715 _DeviceInterface->SetVertexShaderConstantI (vertexProgramConstant->StateID, (int*)vertexProgramConstant->Values, 1);
716 break;
719 break;
720 case CRenderVariable::PixelShaderConstantState:
722 CPixelShaderConstantState *pixelShaderConstant = static_cast<CPixelShaderConstantState*>(currentRenderState);
723 switch (pixelShaderConstant->ValueType)
725 case CPixelShaderConstantState::Float:
726 _DeviceInterface->SetPixelShaderConstantF (pixelShaderConstant->StateID, (float*)pixelShaderConstant->Values, 1);
727 break;
728 case CPixelShaderConstantState::Int:
729 _DeviceInterface->SetPixelShaderConstantI (pixelShaderConstant->StateID, (int*)pixelShaderConstant->Values, 1);
730 break;
733 break;
734 case CRenderVariable::SamplerState:
736 CSamplerState *samplerState = static_cast<CSamplerState*>(currentRenderState);
737 _DeviceInterface->SetSamplerState (samplerState->SamplerID, samplerState->StateID, samplerState->Value);
739 break;
740 case CRenderVariable::MatrixState:
742 CMatrixState *renderMatrix = static_cast<CMatrixState*>(currentRenderState);
743 _DeviceInterface->SetTransform (renderMatrix->TransformType, &(renderMatrix->Matrix));
745 break;
746 case CRenderVariable::VBState:
748 CVBState *renderVB = static_cast<CVBState*>(currentRenderState);
749 if (renderVB->VertexBuffer)
751 _DeviceInterface->SetStreamSource (0, renderVB->VertexBuffer, renderVB->Offset, renderVB->Stride);
754 break;
755 case CRenderVariable::IBState:
757 CIBState *renderIB = static_cast<CIBState*>(currentRenderState);
758 if (renderIB->IndexBuffer)
760 _DeviceInterface->SetIndices (renderIB->IndexBuffer);
763 break;
764 case CRenderVariable::VertexDecl:
766 CVertexDeclState *renderVB = static_cast<CVertexDeclState*>(currentRenderState);
767 if (renderVB->Decl)
769 _DeviceInterface->SetVertexDeclaration (renderVB->Decl);
772 break;
773 case CRenderVariable::LightState:
775 CLightState *renderLight = static_cast<CLightState*>(currentRenderState);
777 // Enabel state modified ?
778 if (renderLight->EnabledTouched)
779 _DeviceInterface->LightEnable (renderLight->LightIndex, renderLight->Enabled);
781 // Light enabled ?
782 if (renderLight->Enabled)
784 if (renderLight->SettingsTouched)
786 // New position
787 renderLight->Light.Position.x -= _PZBCameraPos.x;
788 renderLight->Light.Position.y -= _PZBCameraPos.y;
789 renderLight->Light.Position.z -= _PZBCameraPos.z;
790 _DeviceInterface->SetLight (renderLight->LightIndex, &(renderLight->Light));
791 renderLight->SettingsTouched = false;
795 // Clean
796 renderLight->EnabledTouched = false;
798 break;
799 case CRenderVariable::RenderTargetState:
801 CRenderTargetState *renderTarget = static_cast<CRenderTargetState*>(currentRenderState);
802 _DeviceInterface->SetRenderTarget (0, renderTarget->Target);
803 setupViewport (_Viewport);
804 setupScissor (_Scissor);
806 break;
813 // ***************************************************************************
814 #ifdef NL_DEBUG
815 inline
816 #endif
817 void CDriverD3D::replaceArgumentAtStage(D3DTEXTURESTAGESTATETYPE state, DWORD stage, DWORD from, DWORD to)
819 if ((_TextureStateCache[stage][state].Value & D3DTA_SELECTMASK) == from)
821 setTextureState (stage, state, (_TextureStateCache[stage][state].Value&~D3DTA_SELECTMASK)|to);
825 // ***************************************************************************
826 // Replace a constant with diffuse color at the given stage
827 #ifdef NL_DEBUG
828 inline
829 #endif
830 void CDriverD3D::replaceAllRGBArgumentAtStage(uint stage, DWORD from, DWORD to, DWORD blendOpFrom)
832 replaceArgumentAtStage(D3DTSS_COLORARG1, stage, from, to);
833 if (_CurrentMaterialInfo->NumColorArg[stage] > 1)
835 replaceArgumentAtStage(D3DTSS_COLORARG2, stage, from, to);
836 if (_CurrentMaterialInfo->NumColorArg[stage] > 2)
838 replaceArgumentAtStage(D3DTSS_COLORARG0, stage, from, to);
842 // Operator is D3DTOP_BLENDDIFFUSEALPHA ?
843 if (_TextureStateCache[stage][D3DTSS_COLOROP].Value == blendOpFrom)
845 setTextureState (stage, D3DTSS_COLOROP, D3DTOP_LERP);
846 setTextureState (stage, D3DTSS_COLORARG0, to|D3DTA_ALPHAREPLICATE);
851 #ifdef NL_DEBUG
852 inline
853 #endif
854 void CDriverD3D::replaceAllAlphaArgumentAtStage(uint stage, DWORD from, DWORD to, DWORD blendOpFrom)
856 replaceArgumentAtStage(D3DTSS_ALPHAARG1, stage, from, to);
857 if (_CurrentMaterialInfo->NumAlphaArg[stage] > 1)
859 replaceArgumentAtStage(D3DTSS_ALPHAARG2, stage, from, to);
860 if (_CurrentMaterialInfo->NumAlphaArg[stage] > 2)
862 replaceArgumentAtStage(D3DTSS_ALPHAARG0, stage, from, to);
865 if (_TextureStateCache[stage][D3DTSS_ALPHAOP].Value == blendOpFrom)
867 setTextureState (stage, D3DTSS_ALPHAOP, D3DTOP_LERP);
868 setTextureState (stage, D3DTSS_ALPHAARG0, to);
872 #ifdef NL_DEBUG
873 inline
874 #endif
875 void CDriverD3D::replaceAllArgumentAtStage(uint stage, DWORD from, DWORD to, DWORD blendOpFrom)
877 if (_CurrentMaterialInfo->RGBPipe[stage])
879 replaceAllRGBArgumentAtStage(stage, from, to, blendOpFrom);
881 if (_CurrentMaterialInfo->AlphaPipe[stage])
883 replaceAllAlphaArgumentAtStage(stage, from, to, blendOpFrom);
887 // ***************************************************************************
888 // Replace all argument at relevant stages with the given value
889 #ifdef NL_DEBUG
890 inline
891 #endif
892 void CDriverD3D::replaceAllArgument(DWORD from, DWORD to, DWORD blendOpFrom)
894 const uint maxTexture = inlGetNumTextStages();
895 // Look for texture state
896 for (uint i=0; i<maxTexture; i++)
898 if (_CurrentMaterialInfo->ColorOp[i] == D3DTOP_DISABLE) break;
899 replaceAllArgumentAtStage(i, from, to, blendOpFrom);
903 // ***************************************************************************
904 #ifdef NL_DEBUG
905 inline
906 #endif
907 void CDriverD3D::setupConstantDiffuseColorFromLightedMaterial(D3DCOLOR color)
909 for(uint i=1;i<_MaxLight;++i)
910 enableLightInternal(uint8(i), false);
911 _LightMapDynamicLightDirty= true;
912 D3DMATERIAL9 d3dMat;
913 setColor(d3dMat.Diffuse, 0.f, 0.f, 0.f, (1.f / 255.f) * (color >> 24));
914 setColor(d3dMat.Ambient, 0.f, 0.f, 0.f, 0.f);
915 setColor(d3dMat.Specular, 0.f, 0.f, 0.f, 0.f);
916 setColor(d3dMat.Emissive, color);
917 setMaterialState(d3dMat);
918 setRenderState(D3DRS_LIGHTING, TRUE);
922 // ***************************************************************************
923 void CDriverD3D::updateRenderVariablesInternal()
925 H_AUTO_D3D(CDriver3D_updateRenderVariablesInternal);
926 nlassert (_DeviceInterface);
927 bool aliasDiffuseToSpecular = false;
928 bool enableVertexColorFlag = true;
929 if (_CurrentMaterialInfo && (_CurrentMaterialInfo->NeedsConstantForDiffuse || _CurrentMaterialInfo->MultipleConstantNoPixelShader)) /* The "unlighted without vertex color" trick */
931 // The material IS unlighted
932 // No pixel shader ?
933 if (_CurrentMaterialInfo->PixelShader)
936 * We have to set the pixel shader now, because we have to choose between normal pixel shader and pixel shader without vertex color */
937 // Must have two pixel shader
938 nlassert (_CurrentMaterialInfo->PixelShaderUnlightedNoVertexColor);
939 if (!_UseVertexColor && (_VertexProgramCache.VertexProgram == NULL))
941 setPixelShader (_CurrentMaterialInfo->PixelShaderUnlightedNoVertexColor);
943 else
945 setPixelShader (_CurrentMaterialInfo->PixelShader);
948 else
950 setPixelShader (NULL);
951 if (_CurrentMaterialInfo->NeedsConstantForDiffuse)
954 * We have to change all texture state setuped to D3DTA_DIFFUSE into D3DTA_TFACTOR
955 * if we use a vertex buffer with diffuse color vertex with an unlighted material and no vertex program */
956 if (_VertexProgramCache.VertexProgram)
958 // Diffuse should be output from vertex program
959 // So we can only emulate 1 per stage constant (it has already been setup in CDriverD3D::setupMaterial)
960 #ifdef NL_DEBUG
961 nlassert(!_CurrentMaterialInfo->MultipleConstantNoPixelShader);
962 #endif
964 else
966 if (!_UseVertexColor)
968 if (!_CurrentMaterialInfo->MultipleConstantNoPixelShader)
970 // Diffuse is used, but no other constant is used in the shader
971 // Max texture
972 replaceAllArgument(D3DTA_DIFFUSE, D3DTA_TFACTOR, D3DTOP_BLENDDIFFUSEALPHA);
973 setRenderState (D3DRS_TEXTUREFACTOR, _CurrentMaterialInfo->UnlightedColor);
975 else
977 #ifdef NL_DEBUG
978 nlassert(!_CurrentMaterialInfo->MultiplePerStageConstant); // Can't render this material on current hardware
979 #endif
980 //replaceAllArgumentAtStage(_CurrentMaterialInfo->ConstantIndex, D3DTA_TFACTOR, D3DTA_DIFFUSE, D3DTOP_BLENDFACTORALPHA);
981 setupConstantDiffuseColorFromLightedMaterial(_CurrentMaterialInfo->UnlightedColor);
984 else
986 if (_CurrentMaterialInfo->MultiplePerStageConstant)
988 // vertex color, 1st constant from CMaterial::getColor (already setuped in CDriverD3D::setupMaterial)
989 // 2nd constant from a stage constant
990 // Vertex color is aliased to the specular stream -> all references to D3DTA_DIFFUSE must be replaced with references to D3DTA_SPECULAR
991 replaceAllArgument(D3DTA_DIFFUSE, D3DTA_SPECULAR, 0xffffffff);
992 aliasDiffuseToSpecular = true;
993 replaceAllArgumentAtStage(_CurrentMaterialInfo->ConstantIndex2, D3DTA_TFACTOR, D3DTA_DIFFUSE, D3DTOP_BLENDFACTORALPHA);
994 setupConstantDiffuseColorFromLightedMaterial(NL_D3DCOLOR_RGBA(_CurrentMaterialInfo->Constant2)); // set 2nd per stage constant
995 #ifdef NL_DEBUG
996 nlassert(_VertexDeclCache.DeclAliasDiffuseToSpecular); // VB must not have specular used ... else this material can't render
997 #endif
998 // NB : currently this don't work with the GeForce2 (seems to be a driver bug). Fortunately, this case isn't encountered with Ryzom materials :)
999 // So it's provided for convenience.
1004 else
1006 nlassert(_CurrentMaterialInfo->MultipleConstantNoPixelShader);
1007 // If vertex color is used, alias it to specular
1009 if (_UseVertexColor)
1011 replaceAllArgument(D3DTA_DIFFUSE, D3DTA_SPECULAR, 0xffffffff);
1012 aliasDiffuseToSpecular = true; // VB must not have specular used ... else this material can't render
1015 // up to 2 constants with no pixel shaders
1016 // look for constant at other stages and replaces then with diffuse color
1017 // first constant color has already been set yet (in CD3DDriver::setupMaterial)
1018 replaceAllArgumentAtStage(_CurrentMaterialInfo->ConstantIndex2, D3DTA_TFACTOR, D3DTA_DIFFUSE, D3DTOP_BLENDFACTORALPHA);
1019 setupConstantDiffuseColorFromLightedMaterial(NL_D3DCOLOR_RGBA(_CurrentMaterialInfo->Constant2)); // set 2nd per stage constant
1023 else
1025 if (_CurrentMaterialInfo) enableVertexColorFlag = _CurrentMaterialInfo->VertexColorLighted;
1029 if (_NbNeLTextureStages == 3)
1031 // Fix (one more...) for Radeon 7xxx
1032 // Don't know why, but the lighting is broken when MULTIPLYADD is used as in the lightmap shader..
1033 // Correct behaviour with GeForce & Ref. rasterizer...
1034 // The fix is to disable the light contribution from dynamic lights
1035 if (_TextureStateCache[0][D3DTSS_COLOROP].Value == D3DTOP_MULTIPLYADD &&
1036 _TextureStateCache[0][D3DTSS_COLORARG0].Value == D3DTA_DIFFUSE
1039 _TextureStateCache[0][D3DTSS_COLOROP].Value = D3DTOP_MODULATE;
1040 touchRenderVariable(&_TextureStateCache[0][D3DTSS_COLOROP]);
1042 // fix for radeon 7xxx -> should enable vertex color only if really used in pixel pipe
1043 setEnableVertexColor(enableVertexColorFlag);
1045 setAliasDiffuseToSpecular(aliasDiffuseToSpecular);
1048 // Flush all the modified render states
1049 while (_ModifiedRenderState)
1051 // Current variable
1052 CRenderVariable *currentRenderState = _ModifiedRenderState;
1054 // It is clean now
1055 currentRenderState->Modified = false;
1057 // Unlinked
1058 _ModifiedRenderState = currentRenderState->NextModified;
1059 currentRenderState->apply(this);
1063 // 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.
1064 // Forcing to resetup material solves the prb.. (though D3DRS_LIGHTING is set to FALSE ...)
1065 // I only have the prb with GeForce. The behaviour doesn't exhibit when using the D3D debug dll.
1066 if (_IsGeforce)
1068 if (_RenderStateCache[D3DRS_LIGHTING].Value == FALSE && _VertexProgramCache.VertexProgram == NULL)
1070 _MaterialState.apply(this);
1078 // ***************************************************************************
1080 void D3DWndProc(CDriverD3D *driver, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1082 H_AUTO_D3D(D3DWndProc);
1084 // Check this message in parents
1086 if ((message == WM_SIZE) || (message == WM_EXITSIZEMOVE) || (message == WM_MOVE))
1088 if (driver != NULL)
1090 // *** Check the hwnd is the root parent of driver->_HWnd
1092 // hwnd must be a _HWnd parent
1093 bool sameWindow = hWnd == driver->_HWnd;
1094 bool rootWindow = false;
1095 HWND tmp = driver->_HWnd;
1096 while (tmp)
1098 if (tmp == hWnd)
1100 rootWindow = true;
1101 break;
1103 tmp = GetParent (tmp);
1106 // hwnd must be a top window
1107 rootWindow &= (GetParent (hWnd) == NULL);
1109 // This is a root parent, not _HWnd
1110 if (rootWindow)
1112 if (message == WM_SIZE)
1114 if( SIZE_MAXIMIZED == wParam)
1116 driver->_Maximized = true;
1117 if (sameWindow)
1118 driver->handlePossibleSizeChange();
1119 else
1120 driver->_HandlePossibleSizeChangeNextSize = true;
1122 else if( SIZE_RESTORED == wParam)
1124 if (driver->_Maximized)
1126 driver->_Maximized = false;
1127 if (sameWindow)
1128 driver->handlePossibleSizeChange();
1129 else
1130 driver->_HandlePossibleSizeChangeNextSize = true;
1134 else if(message == WM_EXITSIZEMOVE)
1136 if (driver != NULL)
1138 driver->handlePossibleSizeChange();
1141 else if(message == WM_MOVE)
1143 if (driver != NULL)
1145 RECT rect;
1146 GetWindowRect (hWnd, &rect);
1147 driver->_WindowX = rect.left;
1148 driver->_WindowY = rect.top;
1152 // This is the window itself
1153 else if (sameWindow)
1155 if (message == WM_SIZE)
1157 if (driver->_HandlePossibleSizeChangeNextSize)
1159 driver->handlePossibleSizeChange();
1160 driver->_HandlePossibleSizeChangeNextSize = false;
1168 if ((message == WM_SETFOCUS) || (message == WM_KILLFOCUS))
1170 if (driver != NULL)
1172 driver->_WindowFocus = (message == WM_SETFOCUS);
1176 if (driver && driver->_EventEmitter.getNumEmitters() > 0)
1178 CWinEventEmitter *we = NLMISC::safe_cast<CWinEventEmitter *>(driver->_EventEmitter.getEmitter(0));
1179 // Process the message by the emitter
1180 we->setHWnd(hWnd);
1181 we->processMessage (hWnd, message, wParam, lParam);
1185 // ***************************************************************************
1187 bool CDriverD3D::handlePossibleSizeChange()
1189 //DUMP_AUTO(handlePossibleSizeChange);
1190 H_AUTO_D3D(CDriver3D_handlePossibleSizeChange);
1191 // If windowed, check if the size as changed
1192 if (_CurrentMode.Windowed)
1194 RECT rect;
1195 GetClientRect (_HWnd, &rect);
1197 // Setup d3d resolution
1198 uint16 newWidth = uint16(rect.right-rect.left);
1199 uint16 newHeight = uint16(rect.bottom-rect.top);
1201 // Set the new mode. Only change the size, keep the last setDisplay/setMode settings
1202 GfxMode mode = _CurrentMode;
1203 mode.Width = newWidth;
1204 mode.Height = newHeight;
1206 if ( ( (mode.Width != _CurrentMode.Width) || (mode.Height != _CurrentMode.Height) ) &&
1207 ( mode.Width != 0 ) &&
1208 ( mode.Height != 0 ) )
1210 return reset (mode);
1213 return false;
1216 // ***************************************************************************
1218 static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1220 H_AUTO_D3D(WndProc);
1221 // Get the driver pointer..
1222 CDriverD3D *pDriver=(CDriverD3D*)GetWindowLongPtrW (hWnd, GWLP_USERDATA);
1223 if (pDriver != NULL)
1225 D3DWndProc (pDriver, hWnd, message, wParam, lParam);
1228 if (message == WM_SYSCOMMAND)
1230 switch (wParam)
1232 #ifdef NL_DISABLE_MENU
1233 // disable menu (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
1234 case SC_KEYMENU:
1235 #endif // NL_DISABLE_MENU
1237 // Screensaver Trying To Start?
1238 case SC_SCREENSAVE:
1240 // Monitor Trying To Enter Powersave?
1241 case SC_MONITORPOWER:
1243 // Prevent From Happening
1244 return 0;
1246 default:
1247 break;
1251 // ace: if we receive close, exit now or it'll assert after
1252 if(message == WM_CLOSE)
1254 if(pDriver && pDriver->ExitFunc)
1256 pDriver->ExitFunc();
1258 else
1260 #ifndef NL_DISABLE_MENU
1261 // if we don't disable menu, alt F4 make a direct exit else we discard the message
1262 exit(0);
1263 #endif // NL_DISABLE_MENU
1265 return 0;
1268 #ifdef WM_UNICHAR
1269 // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-unichar
1270 if (message == WM_UNICHAR)
1271 return (wParam == UNICODE_NOCHAR);
1272 #endif
1274 return DefWindowProcW(hWnd, message, wParam, lParam);
1277 // ***************************************************************************
1279 bool CDriverD3D::init (uintptr_t windowIcon, emptyProc exitFunc)
1281 H_AUTO_D3D(CDriver3D_init );
1283 ExitFunc = exitFunc;
1285 createCursors();
1287 _WindowClass = utf8ToWide("NLD3D" + toString(windowIcon));
1289 // Register a window class
1290 WNDCLASSW wc;
1292 memset(&wc,0,sizeof(wc));
1293 wc.style = 0; // CS_HREDRAW | CS_VREDRAW ;//| CS_DBLCLKS;
1294 wc.lpfnWndProc = (WNDPROC)WndProc;
1295 wc.cbClsExtra = 0;
1296 wc.cbWndExtra = 0;
1297 wc.hInstance = GetModuleHandleW(NULL);
1298 wc.hIcon = (HICON)windowIcon;
1299 wc.hCursor = _DefaultCursor;
1300 wc.hbrBackground = WHITE_BRUSH;
1301 wc.lpszClassName = _WindowClass.c_str();
1302 wc.lpszMenuName = NULL;
1303 if (!RegisterClassW(&wc))
1305 DWORD error = GetLastError();
1306 if (error != ERROR_CLASS_ALREADY_EXISTS)
1308 nlwarning("CDriverD3D::init: Can't register window class %s (error code %i)", _WindowClass.c_str(), (sint)error);
1309 _WindowClass.clear();
1310 return false;
1314 return true;
1317 // ***************************************************************************
1319 // From the SDK
1320 bool CDriverD3D::isDepthFormatOk(UINT adapter, D3DDEVTYPE rasterizer, D3DFORMAT DepthFormat,
1321 D3DFORMAT AdapterFormat,
1322 D3DFORMAT BackBufferFormat)
1324 H_AUTO_D3D(CDriverD3D_isDepthFormatOk);
1325 // Verify that the depth format exists
1326 HRESULT hr = _D3D->CheckDeviceFormat(adapter,
1327 rasterizer,
1328 AdapterFormat,
1329 D3DUSAGE_DEPTHSTENCIL,
1330 D3DRTYPE_SURFACE,
1331 DepthFormat);
1333 if(FAILED(hr)) return FALSE;
1335 // Verify that the depth format is compatible
1336 hr = _D3D->CheckDepthStencilMatch(adapter,
1337 (D3DDEVTYPE) rasterizer,
1338 AdapterFormat,
1339 BackBufferFormat,
1340 DepthFormat);
1342 return SUCCEEDED(hr);
1346 // ***************************************************************************
1348 const D3DFORMAT FinalPixelFormat[ITexture::UploadFormatCount][CDriverD3D::FinalPixelFormatChoice]=
1350 { D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // Auto
1351 { D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGBA8888
1352 { D3DFMT_A4R4G4B4, D3DFMT_A1R5G5B5, D3DFMT_A8R3G3B2, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGBA4444
1353 { D3DFMT_A1R5G5B5, D3DFMT_A4R4G4B4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGBA5551
1354 { D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGB888
1355 { D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // RGB565
1356 { D3DFMT_DXT1, D3DFMT_R3G3B2, D3DFMT_A1R5G5B5, D3DFMT_R5G6B5, D3DFMT_A8R8G8B8 }, // DXTC1
1357 { D3DFMT_DXT1, D3DFMT_R3G3B2, D3DFMT_A1R5G5B5, D3DFMT_R5G6B5, D3DFMT_A8R8G8B8 }, // DXTC1Alpha
1358 { D3DFMT_DXT3, D3DFMT_A4R4G4B4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // DXTC3
1359 { D3DFMT_DXT5, D3DFMT_A4R4G4B4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // DXTC5
1360 { D3DFMT_L8, D3DFMT_A8L8, D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_A8R8G8B8 }, // Luminance
1361 { D3DFMT_A8, D3DFMT_A8L8, D3DFMT_A8R3G3B2, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // Alpha
1362 { D3DFMT_A8L8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // AlphaLuminance
1363 { D3DFMT_V8U8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8 }, // DsDt
1366 // ***************************************************************************
1368 bool CDriverD3D::setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable)
1370 H_AUTO_D3D(CDriver3D_setDisplay);
1372 if (!mode.OffScreen)
1373 NLMISC::INelContext::getInstance().setWindowedApplication(true);
1375 if (!_D3D)
1376 return false;
1377 #ifndef NL_NO_ASM
1378 CFpuRestorer fpuRestorer;
1379 #endif
1380 // Release the driver if already setuped
1381 release ();
1383 // Should be initialized
1384 nlassert (!_WindowClass.empty());
1386 // Should be released
1387 nlassert (_DeviceInterface == NULL);
1388 nlassert (_HWnd == NULL);
1390 // memorize desktop gamma ramp
1391 HDC dc = CreateDCW (L"DISPLAY", NULL, NULL, NULL);
1392 if (dc)
1394 _DesktopGammaRampValid = GetDeviceGammaRamp (dc, _DesktopGammaRamp) != FALSE;
1395 // Release the DC
1396 ReleaseDC (NULL, dc);
1399 // Create a window
1400 _HWnd = wnd;
1402 // Reset window state
1403 _Maximized = false;
1404 _HandlePossibleSizeChangeNextSize = false;
1405 _WindowFocus = true;
1407 if (_HWnd)
1409 // We don't have to destroy this window
1410 _DestroyWindow = false;
1412 // Init Window Width and Height
1413 RECT clientRect;
1414 GetClientRect (_HWnd, &clientRect);
1415 _CurrentMode.OffScreen = false;
1416 _CurrentMode.Width = (uint16)(clientRect.right-clientRect.left);
1417 _CurrentMode.Height = (uint16)(clientRect.bottom-clientRect.top);
1418 _CurrentMode.Frequency = 0;
1419 _CurrentMode.Windowed = true;
1420 _CurrentMode.Depth = 32;
1422 else
1424 _CurrentMode = mode;
1426 // We have to destroy this window
1427 _DestroyWindow = true;
1429 // Window flags
1430 //ULONG WndFlags=(mode.Windowed?D3D_WINDOWED_STYLE:D3D_FULLSCREEN_STYLE)&~WS_VISIBLE;
1431 ULONG WndFlags;
1432 if(mode.Windowed)
1434 WndFlags = D3D_WINDOWED_STYLE;
1435 if(!resizeable)
1437 WndFlags &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);
1440 else
1442 WndFlags = D3D_FULLSCREEN_STYLE;
1443 findNearestFullscreenVideoMode();
1446 WndFlags &= ~WS_VISIBLE;
1448 // Window rect
1449 RECT WndRect;
1450 WndRect.left=0;
1451 WndRect.top=0;
1452 WndRect.right=_CurrentMode.Width;
1453 WndRect.bottom=_CurrentMode.Height;
1454 AdjustWindowRect(&WndRect,WndFlags,FALSE);
1456 // Create
1457 _HWnd = CreateWindowW(_WindowClass.c_str(), L"", WndFlags, CW_USEDEFAULT,CW_USEDEFAULT, WndRect.right-WndRect.left,WndRect.bottom-WndRect.top, NULL, NULL,
1458 GetModuleHandleW(NULL), NULL);
1459 if (!_HWnd)
1461 nlwarning ("CreateWindowW failed");
1462 release();
1463 return false;
1466 // Set the window long integer
1467 SetWindowLongPtrW (_HWnd, GWLP_USERDATA, (LONG_PTR)this);
1469 // Show the window
1470 if (show || !_CurrentMode.Windowed)
1471 showWindow(true);
1474 // Choose an adapter
1475 UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
1477 // Get adapter format
1478 D3DDISPLAYMODE adapterMode;
1479 if (_D3D->GetAdapterDisplayMode (adapter, &adapterMode) != D3D_OK)
1481 nlwarning ("GetAdapterDisplayMode failed");
1482 release();
1483 return false;
1486 // The following code is taken from the NVPerfHud user guide
1487 // Set default settings
1488 _Rasterizer = RASTERIZER;
1489 #ifdef NL_D3D_USE_NV_PERF_HUD
1490 // Look for 'NVIDIA NVPerfHUD' adapter
1491 // If it is present, override default settings
1492 for (UINT adapterIndex = 0; adapterIndex < _D3D->GetAdapterCount(); adapterIndex++)
1494 D3DADAPTER_IDENTIFIER9 identifier;
1495 HRESULT res = _D3D->GetAdapterIdentifier(adapterIndex, 0, &identifier);
1496 if (strstr(identifier.Description, "PerfHUD") != 0)
1498 adapter = adapterIndex;
1499 _Adapter = adapter;
1500 _Rasterizer = D3DDEVTYPE_REF;
1501 nlinfo("Using NVIDIA NVPerfHUD adapter");
1502 break;
1505 #endif
1507 // Create device options
1508 D3DPRESENT_PARAMETERS parameters;
1509 D3DFORMAT adapterFormat;
1510 if (!fillPresentParameter (parameters, adapterFormat, _CurrentMode, adapterMode))
1512 release();
1513 return false;
1516 #if WITH_PERFHUD
1517 // Look for 'NVIDIA PerfHUD' adapter
1518 // If it is present, override default settings
1519 for (UINT gAdapter=0;gAdapter<_D3D->GetAdapterCount();gAdapter++)
1521 D3DADAPTER_IDENTIFIER9 Identifier;
1522 HRESULT Res;
1523 Res = _D3D->GetAdapterIdentifier(gAdapter,0,&Identifier);
1525 if (strstr(Identifier.Description,"PerfHUD") != 0)
1527 nlinfo ("Setting up with PerfHUD");
1528 adapter=gAdapter;
1529 _Rasterizer=D3DDEVTYPE_REF;
1530 break;
1533 #endif /* WITH_PERFHUD */
1534 // Create the D3D device
1535 HRESULT result = _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE, &parameters, &_DeviceInterface);
1536 if (result != D3D_OK)
1538 nlwarning ("Can't create device hr:0x%x adap:0x%x rast:0x%x", result, adapter, _Rasterizer);
1540 // Create the D3D device without puredevice
1541 HRESULT result = _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &parameters, &_DeviceInterface);
1542 if (result != D3D_OK)
1544 nlwarning ("Can't create device without puredevice hr:0x%x adap:0x%x rast:0x%x", result, adapter, _Rasterizer);
1546 // Create the D3D device without puredevice and hardware
1547 HRESULT result = _D3D->CreateDevice (adapter, _Rasterizer, _HWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, &_DeviceInterface);
1548 if (result != D3D_OK)
1550 nlwarning ("Can't create device without puredevice and hardware hr:0x%x adap:0x%x rast:0x%x", result, adapter, _Rasterizer);
1551 release();
1552 return false;
1557 // Check some caps
1558 D3DCAPS9 caps;
1559 if (_DeviceInterface->GetDeviceCaps(&caps) == D3D_OK)
1561 _TextureCubeSupported = (caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0;
1562 _NbNeLTextureStages = (caps.MaxSimultaneousTextures<IDRV_MAT_MAXTEXTURES)?caps.MaxSimultaneousTextures:IDRV_MAT_MAXTEXTURES;
1563 _MADOperatorSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_MULTIPLYADD) != 0;
1564 _EMBMSupported = (caps.TextureOpCaps & D3DTOP_BUMPENVMAP) != 0;
1565 _PixelShaderVersion = caps.PixelShaderVersion;
1566 _CubbedMipMapSupported = (caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP) != 0;
1567 _MaxPrimitiveCount = caps.MaxPrimitiveCount;
1568 _MaxVertexIndex = caps.MaxVertexIndex;
1569 _IsGeforce = !(caps.DevCaps & D3DDEVCAPS_NPATCHES) && (caps.PixelShaderVersion >= D3DPS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(1, 4));
1570 _NonPowerOfTwoTexturesSupported = !(caps.TextureCaps & D3DPTEXTURECAPS_POW2) || (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
1571 _MaxAnisotropy = caps.MaxAnisotropy;
1572 _AnisotropicMinSupported = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
1573 _AnisotropicMagSupported = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
1574 _AnisotropicMinCubeSupported = (caps.CubeTextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
1575 _AnisotropicMagCubeSupported = (caps.CubeTextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
1577 else
1579 _TextureCubeSupported = false;
1580 _NbNeLTextureStages = 1;
1581 _MADOperatorSupported = false;
1582 _EMBMSupported = false;
1583 _CubbedMipMapSupported = false;
1584 _PixelShaderVersion = 0;
1585 _MaxPrimitiveCount = 0xffff;
1586 _MaxVertexIndex = 0xffff;
1587 _IsGeforce = false;
1588 _NonPowerOfTwoTexturesSupported = false;
1589 _MaxAnisotropy = 0;
1590 _AnisotropicMinSupported = false;
1591 _AnisotropicMagSupported = false;
1592 _AnisotropicMinCubeSupported = false;
1593 _AnisotropicMagCubeSupported = false;
1595 // If 16 bits vertices only, build a vb for quads rendering
1596 if (_MaxVertexIndex <= 0xffff)
1598 if (!buildQuadIndexBuffer()) return false;
1601 // test for occlusion query support
1602 IDirect3DQuery9 *dummyQuery = NULL;
1603 if (_DeviceInterface->CreateQuery(D3DQUERYTYPE_OCCLUSION, &dummyQuery) == D3DERR_NOTAVAILABLE)
1605 _OcclusionQuerySupported = false;
1607 else
1609 _OcclusionQuerySupported = true;
1610 if (dummyQuery) dummyQuery->Release();
1614 #ifdef NL_FORCE_TEXTURE_STAGE_COUNT
1615 _NbNeLTextureStages = min ((uint)NL_FORCE_TEXTURE_STAGE_COUNT, (uint)IDRV_MAT_MAXTEXTURES);
1616 #endif // NL_FORCE_TEXTURE_STAGE_COUNT
1618 _VertexProgram = !_DisableHardwareVertexProgram && ((caps.VertexShaderVersion&0xffff) >= 0x0100);
1619 _PixelProgramVersion = _DisableHardwareVertexProgram ? 0x0000 : caps.PixelShaderVersion & 0xffff;
1620 nldebug("Pixel Program Version: %i.%i", (uint32)((_PixelProgramVersion & 0xFF00) >> 8), (uint32)(_PixelProgramVersion & 0xFF));
1621 _PixelProgram = _PixelProgramVersion >= 0x0101;
1622 _MaxVerticesByVertexBufferHard = caps.MaxVertexIndex;
1623 _MaxLight = caps.MaxActiveLights;
1625 if(_MaxLight > 0xFF) _MaxLight = 3;
1627 if (_PixelProgram)
1629 _MaxNumPerStageConstantLighted = _NbNeLTextureStages;
1630 _MaxNumPerStageConstantUnlighted = _NbNeLTextureStages;
1632 else
1634 // emulation of per stage constant through diffuse
1635 _MaxNumPerStageConstantLighted = 1;
1636 _MaxNumPerStageConstantUnlighted = 2;
1639 if (_DisableHardwarePixelShader && _NbNeLTextureStages > 3) // yes, 3 is not a bug
1641 // 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)
1642 // Radeon with 3 stages cases : let the third stage to ensure availability of the EMBM feature
1643 // There is a special fix in CMaterial::isSupportedByDriver to force the number of stages to 2 for the radeons
1644 _NbNeLTextureStages = 2;
1647 // *** Check textures caps
1648 uint j;
1649 uint i;
1650 for (i=0; i<ITexture::UploadFormatCount; i++)
1652 // Default format : D3DFMT_A8R8G8B8
1653 _PreferedTextureFormat[i] = D3DFMT_A8R8G8B8;
1655 for (j=0; j<CDriverD3D::FinalPixelFormatChoice; j++)
1657 if (isTextureFormatOk(adapter, _Rasterizer, FinalPixelFormat[i][j], adapterFormat))
1658 break;
1661 // Set the prefered pixel format
1662 if (j<CDriverD3D::FinalPixelFormatChoice)
1663 _PreferedTextureFormat[i] = FinalPixelFormat[i][j];
1666 // Reset render state cache
1667 initRenderVariables();
1669 // *** Event init
1671 // Release old emitter
1672 while (_EventEmitter.getNumEmitters() != 0)
1674 _EventEmitter.removeEmitter(_EventEmitter.getEmitter(_EventEmitter.getNumEmitters() - 1));
1676 NLMISC::CWinEventEmitter *we = new NLMISC::CWinEventEmitter;
1678 // Setup the event emitter, and try to retrieve a direct input interface
1679 _EventEmitter.addEmitter(we, true /*must delete*/); // the main emitter
1681 // Init some variables
1682 _ForceDXTCCompression = false;
1683 _AnisotropicFilter = 0;
1684 _ForceTextureResizePower = 0;
1685 _FogEnabled = false;
1687 // No back buffer backuped for the moment
1688 _BackBuffer = NULL;
1690 // Reset profiling.
1691 _AllocatedTextureMemory= 0;
1692 _TextureUsed.clear();
1693 _PrimitiveProfileIn.reset();
1694 _PrimitiveProfileOut.reset();
1695 _NbSetupMaterialCall= 0;
1696 _NbSetupModelMatrixCall= 0;
1697 _VBHardProfiling= false;
1698 _CurVBHardLockCount= 0;
1699 _NumVBHardProfileFrame= 0;
1700 _IBProfiling= false;
1701 _CurIBLockCount= 0;
1702 _NumIBProfileFrame= 0;
1704 // try to allocate 16Mo by default of AGP Ram.
1705 initVertexBufferHard(NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE, 0);
1707 // If AGP is less than 16 mo, try to keep the max in proportion
1708 float maxAGPbufferSizeRatio = (float) _AGPMemoryAllocated / (float) NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE;
1710 // Init volatile vertex buffers
1711 _CurrentRenderPass = 0;
1712 _VolatileVertexBufferRAM[0]->init (CVertexBuffer::RAMResident, NL_VOLATILE_RAM_VB_SIZE, NL_VOLATILE_RAM_VB_MAXSIZE, this);
1713 _VolatileVertexBufferRAM[0]->reset ();
1714 _VolatileVertexBufferRAM[1]->init (CVertexBuffer::RAMResident, NL_VOLATILE_RAM_VB_SIZE, NL_VOLATILE_RAM_VB_MAXSIZE, this);
1715 _VolatileVertexBufferRAM[1]->reset ();
1716 _VolatileVertexBufferAGP[0]->init (CVertexBuffer::AGPResident, NL_VOLATILE_AGP_VB_SIZE, (uint) (NL_VOLATILE_AGP_VB_MAXSIZE * maxAGPbufferSizeRatio), this);
1717 _VolatileVertexBufferAGP[0]->reset ();
1718 _VolatileVertexBufferAGP[1]->init (CVertexBuffer::AGPResident, NL_VOLATILE_AGP_VB_SIZE, (uint) (NL_VOLATILE_AGP_VB_MAXSIZE * maxAGPbufferSizeRatio), this);
1719 _VolatileVertexBufferAGP[1]->reset ();
1721 _VolatileIndexBuffer16RAM[0]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices16);
1722 _VolatileIndexBuffer16RAM[0]->reset ();
1723 _VolatileIndexBuffer16RAM[1]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices16);
1724 _VolatileIndexBuffer16RAM[1]->reset ();
1725 _VolatileIndexBuffer16AGP[0]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices16);
1726 _VolatileIndexBuffer16AGP[0]->reset ();
1727 _VolatileIndexBuffer16AGP[1]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices16);
1728 _VolatileIndexBuffer16AGP[1]->reset ();
1729 // 32 bits indices supported
1730 if (_MaxVertexIndex > 0xffff)
1732 _VolatileIndexBuffer32RAM[0]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices32);
1733 _VolatileIndexBuffer32RAM[0]->reset ();
1734 _VolatileIndexBuffer32RAM[1]->init (CIndexBuffer::RAMResident, NL_VOLATILE_RAM_IB_SIZE, NL_VOLATILE_RAM_IB_MAXSIZE, this, CIndexBuffer::Indices32);
1735 _VolatileIndexBuffer32RAM[1]->reset ();
1736 _VolatileIndexBuffer32AGP[0]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices32);
1737 _VolatileIndexBuffer32AGP[0]->reset ();
1738 _VolatileIndexBuffer32AGP[1]->init (CIndexBuffer::AGPResident, NL_VOLATILE_AGP_IB_SIZE, (uint) (NL_VOLATILE_AGP_IB_MAXSIZE * maxAGPbufferSizeRatio), this, CIndexBuffer::Indices32);
1739 _VolatileIndexBuffer32AGP[1]->reset ();
1742 setupViewport (CViewport());
1746 // Begin now
1747 //nldebug("BeginScene");
1748 if (!beginScene()) return false;
1750 // Done
1751 return true;
1754 // ***************************************************************************
1755 extern uint indexCount;
1756 extern uint vertexCount;
1758 bool CDriverD3D::release()
1760 H_AUTO_D3D(CDriver3D_release);
1761 // Call IDriver::release() before, to destroy textures, shaders and VBs...
1762 IDriver::release();
1764 ItShaderDrvInfoPtrList itshd;
1765 while( (itshd = _ShaderDrvInfos.begin()) != _ShaderDrvInfos.end() )
1767 // NB: at IShader deletion, this->_MatDrvInfos is updated (entry deleted);
1768 delete *itshd;
1771 _SwapBufferCounter = 0;
1773 if (_QuadIB)
1775 _QuadIB->Release();
1776 _QuadIB = NULL;
1779 // delete queries
1780 while (!_OcclusionQueryList.empty())
1782 deleteOcclusionQuery(_OcclusionQueryList.front());
1785 // Back buffer ref
1786 if (_BackBuffer)
1787 _BackBuffer->Release();
1788 _BackBuffer = NULL;
1790 // Release all the vertex declaration
1791 std::list<CVertexDeclaration>::iterator ite = _VertexDeclarationList.begin();
1792 while (ite != _VertexDeclarationList.end())
1794 ite->VertexDecl->Release();
1795 ite++;
1797 _VertexDeclarationList.clear ();
1799 // Release pixel shaders
1800 _NormalPixelShaders[0].clear ();
1801 _NormalPixelShaders[1].clear ();
1803 if( _DeviceInterface != NULL)
1805 _DeviceInterface->Release();
1806 _DeviceInterface = NULL;
1809 if (_HWnd)
1811 releaseCursors();
1813 // make sure window icons are deleted
1814 std::vector<NLMISC::CBitmap> bitmaps;
1815 setWindowIcon(bitmaps);
1817 if (_DestroyWindow)
1818 DestroyWindow (_HWnd);
1819 _HWnd = NULL;
1823 nlassert (indexCount == 0);
1824 nlassert (vertexCount == 0);
1826 // restore desktop gamma ramp
1827 if (_DesktopGammaRampValid)
1829 HDC dc = CreateDCW (L"DISPLAY", NULL, NULL, NULL);
1830 if (dc)
1832 SetDeviceGammaRamp (dc, _DesktopGammaRamp);
1834 _DesktopGammaRampValid = false;
1836 return true;
1839 // ***************************************************************************
1841 emptyProc CDriverD3D::getWindowProc()
1843 return (emptyProc)D3DWndProc;
1846 // ***************************************************************************
1848 IDriver::TMessageBoxId CDriverD3D::systemMessageBox (const char* message, const char* title, TMessageBoxType type, TMessageBoxIcon icon)
1850 switch (::MessageBoxW(_HWnd, nlUtf8ToWide(message), nlUtf8ToWide(title), ((type == retryCancelType) ? MB_RETRYCANCEL :
1851 (type==yesNoCancelType)?MB_YESNOCANCEL:
1852 (type==okCancelType)?MB_OKCANCEL:
1853 (type==abortRetryIgnoreType)?MB_ABORTRETRYIGNORE:
1854 (type==yesNoType)?MB_YESNO|MB_ICONQUESTION:MB_OK)|
1856 ((icon==handIcon)?MB_ICONHAND:
1857 (icon==questionIcon)?MB_ICONQUESTION:
1858 (icon==exclamationIcon)?MB_ICONEXCLAMATION:
1859 (icon==asteriskIcon)?MB_ICONASTERISK:
1860 (icon==warningIcon)?MB_ICONWARNING:
1861 (icon==errorIcon)?MB_ICONERROR:
1862 (icon==informationIcon)?MB_ICONINFORMATION:
1863 (icon==stopIcon)?MB_ICONSTOP:0)))
1865 case IDOK:
1866 return okId;
1867 case IDCANCEL:
1868 return cancelId;
1869 case IDABORT:
1870 return abortId;
1871 case IDRETRY:
1872 return retryId;
1873 case IDIGNORE:
1874 return ignoreId;
1875 case IDYES:
1876 return yesId;
1877 case IDNO:
1878 return noId;
1880 return okId;
1883 // ***************************************************************************
1884 bool CDriverD3D::activate()
1886 return true;
1889 // ***************************************************************************
1890 bool CDriverD3D::isActive ()
1892 return (IsWindow(_HWnd) != 0);
1895 // ***************************************************************************
1896 nlWindow CDriverD3D::getDisplay()
1898 return _HWnd;
1901 // ***************************************************************************
1902 NLMISC::IEventEmitter *CDriverD3D::getEventEmitter()
1904 return &_EventEmitter;
1907 // ***************************************************************************
1908 void CDriverD3D::getWindowSize (uint32 &width, uint32 &height)
1910 H_AUTO_D3D(CDriverD3D_getWindowSize);
1911 width = _CurrentMode.Width;
1912 height = _CurrentMode.Height;
1915 // ***************************************************************************
1917 void CDriverD3D::getWindowPos (sint32 &x, sint32 &y)
1919 H_AUTO_D3D(CDriverD3D_getWindowPos);
1920 x = _WindowX;
1921 y = _WindowY;
1924 // ***************************************************************************
1925 uint32 CDriverD3D::getImplementationVersion () const
1927 H_AUTO_D3D(CDriverD3D_getImplementationVersion);
1928 return ReleaseVersion;
1931 // ***************************************************************************
1932 const char *CDriverD3D::getDriverInformation ()
1934 return "Directx 9 NeL Driver";
1937 // ***************************************************************************
1938 uint8 CDriverD3D::getBitPerPixel ()
1940 return _CurrentMode.Depth;
1943 // ***************************************************************************
1944 bool CDriverD3D::clear2D(CRGBA rgba)
1946 H_AUTO_D3D(CDriverD3D_clear2D);
1947 nlassert (_DeviceInterface);
1949 // Backup viewport
1950 CViewport oldViewport = _Viewport;
1951 setupViewport (CViewport());
1952 updateRenderVariables ();
1954 bool result = _DeviceInterface->Clear( 0, NULL, D3DCLEAR_TARGET, NL_D3DCOLOR_RGBA(rgba), 1.0f, 0 ) == D3D_OK;
1956 // Restore the old viewport
1957 setupViewport (oldViewport);
1958 return result;
1961 // ***************************************************************************
1963 bool CDriverD3D::clearZBuffer(float zval)
1965 H_AUTO_D3D(CDriverD3D_clearZBuffer);
1966 nlassert (_DeviceInterface);
1968 // Backup viewport
1969 CViewport oldViewport = _Viewport;
1970 setupViewport (CViewport());
1971 updateRenderVariables ();
1973 bool result = _DeviceInterface->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0,0,0,0), zval, 0 ) == D3D_OK;
1975 // Restore the old viewport
1976 setupViewport (oldViewport);
1978 // NVidia driver 56.72 needs to reset the vertex buffer after a clear Z
1979 touchRenderVariable (&_VertexBufferCache);
1981 return result;
1984 // ***************************************************************************
1986 bool CDriverD3D::clearStencilBuffer(float stencilval)
1988 H_AUTO_D3D(CDriverD3D_clearStencilBuffer);
1989 nlassert (_DeviceInterface);
1991 // Backup viewport
1992 CViewport oldViewport = _Viewport;
1993 setupViewport (CViewport());
1994 updateRenderVariables ();
1996 bool result = _DeviceInterface->Clear( 0, NULL, D3DCLEAR_STENCIL, D3DCOLOR_ARGB(0,0,0,0), 1.0f, (unsigned long)stencilval ) == D3D_OK;
1998 // Restore the old viewport
1999 setupViewport (oldViewport);
2001 return result;
2004 // ***************************************************************************
2006 void CDriverD3D::setColorMask (bool bRed, bool bGreen, bool bBlue, bool bAlpha)
2008 H_AUTO_D3D(CDriverD3D_setColorMask);
2009 setRenderState (D3DRS_COLORWRITEENABLE,
2010 (bAlpha?D3DCOLORWRITEENABLE_ALPHA:0)|
2011 (bRed?D3DCOLORWRITEENABLE_RED:0)|
2012 (bGreen?D3DCOLORWRITEENABLE_GREEN:0)|
2013 (bBlue?D3DCOLORWRITEENABLE_BLUE:0)
2020 // ***************************************************************************
2021 bool CDriverD3D::swapBuffers()
2023 //DUMP_AUTO(swapBuffers);
2024 H_AUTO_D3D(CDriverD3D_swapBuffers);
2025 nlassert (_DeviceInterface);
2027 ++ _SwapBufferCounter;
2028 // Swap & reset volatile buffers
2029 _CurrentRenderPass++;
2030 _VolatileVertexBufferRAM[_CurrentRenderPass&1]->reset ();
2031 _VolatileVertexBufferAGP[_CurrentRenderPass&1]->reset ();
2032 _VolatileIndexBuffer16RAM[_CurrentRenderPass&1]->reset ();
2033 _VolatileIndexBuffer16AGP[_CurrentRenderPass&1]->reset ();
2034 _VolatileIndexBuffer32RAM[_CurrentRenderPass&1]->reset ();
2035 _VolatileIndexBuffer32AGP[_CurrentRenderPass&1]->reset ();
2037 // todo hulud volatile
2038 //_DeviceInterface->SetStreamSource(0, _VolatileVertexBufferRAM[1]->VertexBuffer, 0, 12);
2040 // End now
2041 if (!endScene())
2043 nlstop;
2044 return false;
2047 HRESULT result = _DeviceInterface->Present( NULL, NULL, NULL, NULL);
2048 if (result != D3D_OK)
2050 // Device lost ?
2051 if (result == D3DERR_DEVICELOST)
2053 _Lost = true;
2054 // check if we can exit lost state
2055 if (_DeviceInterface->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
2057 // Reset the driver
2058 reset (_CurrentMode);
2063 // Check window size
2064 handlePossibleSizeChange ();
2066 // Reset the profiling counter.
2067 _PrimitiveProfileIn.reset();
2068 _PrimitiveProfileOut.reset();
2069 _NbSetupMaterialCall= 0;
2070 _NbSetupModelMatrixCall= 0;
2072 // Reset the texture set
2073 _TextureUsed.clear();
2075 // Reset vertex program
2076 setVertexProgram (NULL, NULL);
2077 // Reset pixel program
2078 setPixelShader (NULL);
2080 if (_VBHardProfiling)
2082 ++_NumVBHardProfileFrame;
2084 if (_IBProfiling)
2086 ++ _NumIBProfileFrame;
2089 // Begin now
2090 return beginScene();
2093 // ***************************************************************************
2095 void CDriverD3D::setPolygonMode (TPolygonMode mode)
2097 H_AUTO_D3D(CDriverD3D_setPolygonMode);
2098 IDriver::setPolygonMode (mode);
2100 setRenderState (D3DRS_FILLMODE, mode==Point?D3DFILL_POINT:mode==Line?D3DFILL_WIREFRAME:D3DFILL_SOLID);
2103 // ***************************************************************************
2105 bool CDriverD3D::isTextureFormatOk(UINT adapter, D3DDEVTYPE rasterizer, D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat)
2107 H_AUTO_D3D(CDriverD3D_isTextureFormatOk);
2108 HRESULT hr = _D3D->CheckDeviceFormat( adapter,
2109 rasterizer,
2110 AdapterFormat,
2112 D3DRTYPE_TEXTURE,
2113 TextureFormat);
2115 return SUCCEEDED( hr ) != FALSE;
2118 // ***************************************************************************
2120 void CDriverD3D::forceDXTCCompression(bool dxtcComp)
2122 H_AUTO_D3D(CDriverD3D_forceDXTCCompression);
2123 _ForceDXTCCompression = dxtcComp;
2126 // ***************************************************************************
2128 void CDriverD3D::setAnisotropicFilter(sint filter)
2130 H_AUTO_D3D(CDriverD3D_setAnisotropicFilter);
2132 // anisotropic filter not supported
2133 if (_MaxAnisotropy < 2) return;
2135 if (filter < 0 || filter > _MaxAnisotropy)
2137 _AnisotropicFilter = _MaxAnisotropy;
2139 else
2141 _AnisotropicFilter = filter;
2145 // ***************************************************************************
2147 uint CDriverD3D::getAnisotropicFilter() const
2149 H_AUTO_D3D(CDriverD3D_getAnisotropicFilter);
2151 return _AnisotropicFilter;
2154 // ***************************************************************************
2156 uint CDriverD3D::getAnisotropicFilterMaximum() const
2158 H_AUTO_D3D(CDriverD3D_getAnisotropicFilterMaximum);
2160 return _MaxAnisotropy;
2163 // ***************************************************************************
2165 void CDriverD3D::forceTextureResize(uint divisor)
2167 H_AUTO_D3D(CDriverD3D_forceTextureResize);
2168 clamp(divisor, 1U, 256U);
2170 // 16 -> 4.
2171 _ForceTextureResizePower= getPowerOf2(divisor);
2174 // ***************************************************************************
2176 bool CDriverD3D::fogEnabled()
2178 H_AUTO_D3D(CDriverD3D_fogEnabled);
2179 // Return _RenderStateCache[D3DRS_FOGENABLE].Value == TRUE;
2180 // Nico Patch : must return the _FogEnabled value here, because it MAY be
2181 // different of the one found in _RenderStateCache[D3DRS_FOGENABLE]
2182 // this happens for example when dest blend is one : the actual content of _RenderStateCache[D3DRS_FOGENABLE]
2183 // is then restored when current material alpha blending settings are modified, or when a new material is set.
2184 return _FogEnabled;
2187 // ***************************************************************************
2189 void CDriverD3D::enableFog(bool enable)
2191 H_AUTO_D3D(CDriverD3D_enableFog);
2192 _FogEnabled = enable;
2193 setRenderState (D3DRS_FOGENABLE, enable?TRUE:FALSE);
2196 // ***************************************************************************
2198 void CDriverD3D::setupFog(float start, float end, CRGBA color)
2200 H_AUTO_D3D(CDriverD3D_setupFog);
2201 // Remember fog start and end
2202 _FogStart = start;
2203 _FogEnd = end;
2204 _FogColor = NL_D3DCOLOR_RGBA(color);
2206 // Set the fog
2207 setRenderState (D3DRS_FOGCOLOR, _FogColor);
2208 setRenderState (D3DRS_FOGSTART, *((DWORD*) (&_FogStart)));
2209 setRenderState (D3DRS_FOGEND, *((DWORD*) (&_FogEnd)));
2212 // ***************************************************************************
2214 float CDriverD3D::getFogStart() const
2216 return _FogStart;
2219 // ***************************************************************************
2221 float CDriverD3D::getFogEnd() const
2223 return _FogEnd;
2226 // ***************************************************************************
2228 CRGBA CDriverD3D::getFogColor() const
2230 return D3DCOLOR_NL_RGBA(_RenderStateCache[D3DRS_FOGCOLOR].Value);
2233 // ***************************************************************************
2235 CVertexBuffer::TVertexColorType CDriverD3D::getVertexColorFormat() const
2237 return CVertexBuffer::TBGRA;
2240 // ***************************************************************************
2242 uint CDriverD3D::getNbTextureStages() const
2244 return _NbNeLTextureStages;
2247 // ***************************************************************************
2249 bool CDriverD3D::getModes(std::vector<GfxMode> &modes)
2251 H_AUTO_D3D(CDriverD3D_getModes);
2252 static const D3DFORMAT format[]=
2254 D3DFMT_A8R8G8B8,
2255 D3DFMT_X8R8G8B8,
2256 D3DFMT_R8G8B8,
2257 D3DFMT_A1R5G5B5,
2258 D3DFMT_R5G6B5,
2260 static const uint8 depth[]=
2268 uint f;
2269 for (f=0; f<sizeof(format)/sizeof(uint); f++)
2271 UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
2272 const uint count = _D3D->GetAdapterModeCount(adapter, format[f]);
2273 uint i;
2274 for (i=0; i<count; i++)
2276 D3DDISPLAYMODE mode;
2277 if (_D3D->EnumAdapterModes( adapter, format[f], i, &mode) == D3D_OK)
2279 GfxMode gfxMode;
2280 gfxMode.Windowed=false;
2281 gfxMode.Width=(uint16)mode.Width;
2282 gfxMode.Height=(uint16)mode.Height;
2283 gfxMode.Depth=depth[f];
2284 gfxMode.Frequency=(uint8)mode.RefreshRate;
2285 modes.push_back (gfxMode);
2289 return true;
2292 // ***************************************************************************
2293 bool CDriverD3D::getCurrentScreenMode(GfxMode &gfxMode)
2295 H_AUTO_D3D(CDriverD3D_getCurrentScreenMode);
2296 UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
2297 D3DDISPLAYMODE mode;
2298 _D3D->GetAdapterDisplayMode(adapter, &mode);
2299 gfxMode.Windowed = !_FullScreen;
2300 gfxMode.Width = (uint16)mode.Width;
2301 gfxMode.Height = (uint16)mode.Height;
2302 gfxMode.Depth = ((mode.Format==D3DFMT_A8R8G8B8)||(mode.Format==D3DFMT_X8R8G8B8))?32:16;
2303 gfxMode.Frequency = (uint8)mode.RefreshRate;
2305 return true;
2308 // ***************************************************************************
2309 void CDriverD3D::setWindowTitle(const ucstring &title)
2311 if (!SetWindowTextW(_HWnd, (WCHAR*)title.c_str()))
2313 nlwarning("SetWindowText failed: %s", formatErrorMessage(getLastError()).c_str());
2317 // ***************************************************************************
2318 void CDriverD3D::setWindowIcon(const std::vector<NLMISC::CBitmap> &bitmaps)
2320 if (!_HWnd)
2321 return;
2323 static HICON winIconBig = NULL;
2324 static HICON winIconSmall = NULL;
2326 if (winIconBig)
2328 DestroyIcon(winIconBig);
2329 winIconBig = NULL;
2332 if (winIconSmall)
2334 DestroyIcon(winIconSmall);
2335 winIconSmall = NULL;
2338 sint smallIndex = -1;
2339 uint smallWidth = GetSystemMetrics(SM_CXSMICON);
2340 uint smallHeight = GetSystemMetrics(SM_CYSMICON);
2342 sint bigIndex = -1;
2343 uint bigWidth = GetSystemMetrics(SM_CXICON);
2344 uint bigHeight = GetSystemMetrics(SM_CYICON);
2346 // find icons with the exact size
2347 for(uint i = 0; i < bitmaps.size(); ++i)
2349 if (smallIndex == -1 && bitmaps[i].getWidth() == smallWidth && bitmaps[i].getHeight() == smallHeight)
2350 smallIndex = i;
2352 if (bigIndex == -1 && bitmaps[i].getWidth() == bigWidth && bitmaps[i].getHeight() == bigHeight)
2353 bigIndex = i;
2356 // find icons with taller size (we will resize them)
2357 for(uint i = 0; i < bitmaps.size(); ++i)
2359 if (smallIndex == -1 && bitmaps[i].getWidth() >= smallWidth && bitmaps[i].getHeight() >= smallHeight)
2360 smallIndex = i;
2362 if (bigIndex == -1 && bitmaps[i].getWidth() >= bigWidth && bitmaps[i].getHeight() >= bigHeight)
2363 bigIndex = i;
2366 if (smallIndex > -1)
2367 convertBitmapToIcon(bitmaps[smallIndex], winIconSmall, smallWidth, smallHeight, 32);
2369 if (bigIndex > -1)
2370 convertBitmapToIcon(bitmaps[bigIndex], winIconBig, bigWidth, bigHeight, 32);
2372 if (winIconBig)
2374 SendMessageA(_HWnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)winIconSmall);
2375 SendMessageA(_HWnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)winIconBig);
2377 else
2379 SendMessageA(_HWnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)winIconSmall);
2380 SendMessageA(_HWnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)winIconSmall);
2384 // ***************************************************************************
2385 void CDriverD3D::setWindowPos(sint32 x, sint32 y)
2387 _WindowX = x;
2388 _WindowY = y;
2389 SetWindowPos(_HWnd, NULL, _WindowX, _WindowY, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
2392 // ***************************************************************************
2393 void CDriverD3D::showWindow(bool show)
2395 ShowWindow (_HWnd, show ? SW_SHOW:SW_HIDE);
2398 // ***************************************************************************
2400 uint CDriverD3D::getNumAdapter() const
2402 H_AUTO_D3D(CDriverD3D_getNumAdapter);
2403 if (_D3D)
2404 return _D3D->GetAdapterCount();
2405 else
2406 return 0;
2409 // ***************************************************************************
2411 bool CDriverD3D::getAdapter(uint adapter, IDriver::CAdapter &desc) const
2413 H_AUTO_D3D(CDriverD3D_getAdapter);
2414 if (_D3D)
2416 D3DADAPTER_IDENTIFIER9 identifier;
2417 UINT _adapter = (adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)adapter;
2418 if (_D3D->GetAdapterIdentifier(_adapter, 0, &identifier) == D3D_OK)
2420 desc.Description = identifier.Description;
2421 desc.DeviceId = identifier.DeviceId;
2422 desc.DeviceName = identifier.DeviceName;
2423 desc.Driver = identifier.Driver;
2424 desc.DriverVersion = (((sint64)identifier.DriverVersion.HighPart<<32))|(sint64)identifier.DriverVersion.LowPart;
2425 desc.Revision = identifier.Revision;
2426 desc.SubSysId = identifier.SubSysId;
2427 desc.VendorId = identifier.VendorId;
2428 desc.VideoMemory = _Adapter == _adapter ? getTotalVideoMemory():-1;
2429 return true;
2432 return false;
2435 // ***************************************************************************
2437 bool CDriverD3D::setAdapter(uint adapter)
2439 H_AUTO_D3D(CDriverD3D_setAdapter);
2440 if (_D3D)
2442 D3DDISPLAYMODE adapterMode;
2443 UINT _adapter = (adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)adapter;
2444 if (_D3D->GetAdapterDisplayMode (_adapter, &adapterMode) != D3D_OK)
2446 nlwarning ("CDriverD3D::setDisplay: GetAdapterDisplayMode failed");
2447 release();
2448 return false;
2450 _Adapter = adapter;
2451 return true;
2453 return false;
2456 // ***************************************************************************
2458 bool CDriverD3D::supportMADOperator() const
2460 H_AUTO_D3D(CDriverD3D_supportMADOperator);
2461 if (_DeviceInterface)
2463 return _MADOperatorSupported;
2465 return false; // don't know..
2468 // ***************************************************************************
2470 bool CDriverD3D::setMode (const GfxMode& mode)
2472 H_AUTO_D3D(CDriverD3D_setMode);
2474 // if fullscreen
2475 if(!mode.Windowed)
2477 // Must check if mode exist, else crash at reset() time
2478 std::vector<GfxMode> modes;
2479 if(getModes(modes))
2481 bool found= false;
2482 for(uint i=0;i<modes.size();i++)
2484 if( modes[i].Windowed==mode.Windowed &&
2485 modes[i].Width==mode.Width &&
2486 modes[i].Height==mode.Height &&
2487 modes[i].Depth==mode.Depth &&
2488 modes[i].Frequency==mode.Frequency )
2490 found= true;
2491 break;
2495 // found?
2496 if(!found)
2497 return false;
2499 else
2500 return false;
2503 // set the mode
2504 if( mode.Windowed )
2506 // Set windowed-mode style
2507 SetWindowLongW( _HWnd, GWL_STYLE, D3D_WINDOWED_STYLE|WS_VISIBLE);
2508 _FullScreen = false;
2510 else
2512 // Set fullscreen-mode style
2513 SetWindowLongW( _HWnd, GWL_STYLE, D3D_FULLSCREEN_STYLE|WS_VISIBLE);
2514 _FullScreen = true;
2517 SetWindowLongPtrW(_HWnd, GWLP_WNDPROC, GetWindowLongPtr(_HWnd, GWLP_WNDPROC));
2519 // Reset the driver
2520 if (reset (mode))
2522 // Reajust window
2523 if( _CurrentMode.Windowed )
2525 // Window rect
2526 RECT WndRect;
2527 WndRect.left=_WindowX;
2528 WndRect.top=_WindowY;
2529 WndRect.right=_WindowX+_CurrentMode.Width;
2530 WndRect.bottom=_WindowY+_CurrentMode.Height;
2531 AdjustWindowRect(&WndRect, GetWindowLongW (_HWnd, GWL_STYLE), FALSE);
2533 SetWindowPos( _HWnd, HWND_NOTOPMOST,
2534 std::max ((int)WndRect.left, 0), std::max ((int)WndRect.top, 0),
2535 ( WndRect.right - WndRect.left ),
2536 ( WndRect.bottom - WndRect.top ),
2537 SWP_NOMOVE | SWP_SHOWWINDOW );
2539 return true;
2541 return false;
2545 // ***************************************************************************
2546 void CDriverD3D::deleteIndexBuffer(CIBDrvInfosD3D *indexBuffer)
2548 if (!indexBuffer) return;
2549 CIndexBuffer *ib = indexBuffer->IndexBufferPtr;
2550 // If resident in RAM, content has not been lost
2551 if (ib->getLocation () != CIndexBuffer::RAMResident)
2553 // Realloc local memory
2554 ib->setLocation (CIndexBuffer::NotResident);
2555 delete indexBuffer;
2560 // ***************************************************************************
2561 bool CDriverD3D::reset (const GfxMode& mode)
2563 //DUMP_AUTO(reset);
2564 H_AUTO_D3D(CDriverD3D_reset);
2565 if (_DeviceInterface->TestCooperativeLevel() == D3DERR_DEVICELOST) return false;
2567 // Choose an adapter
2568 UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
2570 // Get adapter format
2571 D3DDISPLAYMODE adapterMode;
2572 if (_D3D->GetAdapterDisplayMode (adapter, &adapterMode) != D3D_OK)
2574 nlwarning ("CDriverD3D::reset: GetAdapterDisplayMode failed");
2575 release();
2576 return false;
2579 // Do the reset
2580 // Increment the IDriver reset counter
2582 D3DPRESENT_PARAMETERS parameters;
2583 D3DFORMAT adapterFormat;
2584 if (!fillPresentParameter (parameters, adapterFormat, mode, adapterMode))
2585 return false;
2587 // Current mode
2588 _CurrentMode = mode;
2589 _CurrentMaterial = NULL;
2590 _CurrentMaterialInfo = NULL;
2592 // Restore non managed vertex buffer in system memory
2593 ItVBDrvInfoPtrList iteVb = _VBDrvInfos.begin();
2594 while (iteVb != _VBDrvInfos.end())
2596 ItVBDrvInfoPtrList iteVbNext = iteVb;
2597 iteVbNext++;
2599 CVBDrvInfosD3D *vertexBuffer = static_cast<CVBDrvInfosD3D*>(*iteVb);
2600 CVertexBuffer *vb = vertexBuffer->VertexBufferPtr;
2602 // If resident in RAM, content has not been lost
2603 if (vb->getLocation () != CVertexBuffer::RAMResident)
2605 // Realloc local memory
2606 vb->setLocation (CVertexBuffer::NotResident); // If resident in RAM, content backuped by setLocation
2607 delete vertexBuffer;
2610 iteVb = iteVbNext;
2613 // Restore non managed index buffer in system memory
2614 ItIBDrvInfoPtrList iteIb = _IBDrvInfos.begin();
2615 while (iteIb != _IBDrvInfos.end())
2617 ItIBDrvInfoPtrList iteIbNext = iteIb;
2618 iteIbNext++;
2619 deleteIndexBuffer(static_cast<CIBDrvInfosD3D*>(*iteIb));
2620 iteIb = iteIbNext;
2622 deleteIndexBuffer(static_cast<CIBDrvInfosD3D*>((IIBDrvInfos *) _QuadIndexesAGP.DrvInfos));
2624 // Remove render targets
2625 ItTexDrvSharePtrList ite = _TexDrvShares.begin();
2626 while (ite != _TexDrvShares.end())
2628 ItTexDrvSharePtrList iteNext = ite;
2629 iteNext++;
2631 // Render target ?
2632 nlassert ((*ite)->DrvTexture != NULL);
2633 CTextureDrvInfosD3D *info = static_cast<CTextureDrvInfosD3D*>(static_cast<ITextureDrvInfos*>((*ite)->DrvTexture));
2634 if (info->RenderTarget)
2636 // Remove it
2637 delete *ite;
2639 ite = iteNext;
2642 // Free volatile buffers
2643 _VolatileVertexBufferRAM[0]->release ();
2644 _VolatileVertexBufferRAM[1]->release ();
2645 _VolatileVertexBufferAGP[0]->release ();
2646 _VolatileVertexBufferAGP[1]->release ();
2647 _VolatileIndexBuffer16RAM[0]->release ();
2648 _VolatileIndexBuffer16RAM[1]->release ();
2649 _VolatileIndexBuffer16AGP[0]->release ();
2650 _VolatileIndexBuffer16AGP[1]->release ();
2651 _VolatileIndexBuffer32RAM[0]->release ();
2652 _VolatileIndexBuffer32RAM[1]->release ();
2653 _VolatileIndexBuffer32AGP[0]->release ();
2654 _VolatileIndexBuffer32AGP[1]->release ();
2656 // Back buffer ref
2657 if (_BackBuffer)
2658 _BackBuffer->Release();
2659 _BackBuffer = NULL;
2661 // Invalidate all occlusion queries.
2662 // 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...
2663 for(TOcclusionQueryList::iterator it = _OcclusionQueryList.begin(); it != _OcclusionQueryList.end(); ++it)
2665 if ((*it)->Query)
2667 (*it)->WasLost = true;
2668 (*it)->Query->Release();
2669 (*it)->Query = NULL;
2673 // Release internal shaders
2674 //releaseInternalShaders();
2677 notifyAllShaderDrvOfLostDevice();
2681 /* Do not reset if reset will fail */
2682 _ResetCounter++;
2683 bool sceneBegun = hasSceneBegun();
2684 if (sceneBegun)
2686 //nldebug("EndScene");
2687 endScene();
2690 // delete all .fx caches
2691 for(TMatDrvInfoPtrList::iterator it = _MatDrvInfos.begin(); it != _MatDrvInfos.end(); ++it)
2693 CMaterialDrvInfosD3D *mi = NLMISC::safe_cast<CMaterialDrvInfosD3D *>(*it);
2694 if (mi->FXCache)
2696 mi->FXCache->reset();
2701 #ifndef NL_NO_ASM
2702 CFpuRestorer fpuRestorer; // fpu control word is changed by "Reset"
2703 #endif
2704 if (_Rasterizer!=D3DDEVTYPE_REF)
2706 HRESULT hr = _DeviceInterface->Reset (&parameters);
2707 if (hr != D3D_OK)
2709 nlwarning("CDriverD3D::reset: Reset on _DeviceInterface error 0x%x", hr);
2710 // tmp
2711 nlstopex(("CDriverD3D::reset: Reset on _DeviceInterface"));
2712 return false;
2717 _Lost = false;
2718 // BeginScene now
2719 if (sceneBegun)
2721 //nldebug("BeginScene");
2722 beginScene();
2725 notifyAllShaderDrvOfResetDevice();
2727 // Reset internal caches
2728 resetRenderVariables();
2730 // Init shaders
2731 //initInternalShaders();
2733 // reallocate occlusion queries
2734 for(TOcclusionQueryList::iterator it = _OcclusionQueryList.begin(); it != _OcclusionQueryList.end(); ++it)
2736 if (!(*it)->Query)
2738 _DeviceInterface->CreateQuery(D3DQUERYTYPE_OCCLUSION, &(*it)->Query);
2741 return true;
2744 // ***************************************************************************
2746 bool CDriverD3D::fillPresentParameter (D3DPRESENT_PARAMETERS &parameters, D3DFORMAT &adapterFormat, const GfxMode& mode, const D3DDISPLAYMODE &adapterMode)
2748 UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
2749 H_AUTO_D3D(CDriverD3D_fillPresentParameter);
2750 memset (&parameters, 0, sizeof(D3DPRESENT_PARAMETERS));
2751 parameters.BackBufferWidth = mode.Width;
2752 parameters.BackBufferHeight = mode.Height;
2753 parameters.BackBufferCount = 1;
2754 parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
2755 parameters.MultiSampleQuality = 0;
2756 parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
2757 parameters.hDeviceWindow = NULL;
2758 parameters.Windowed = mode.Windowed;
2759 parameters.EnableAutoDepthStencil = TRUE;
2760 parameters.FullScreen_RefreshRateInHz = mode.Windowed?0:mode.Frequency;
2761 switch (_Interval)
2763 case 0:
2764 parameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
2765 break;
2766 case 1:
2767 parameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
2768 break;
2769 case 2:
2770 parameters.PresentationInterval = D3DPRESENT_INTERVAL_TWO;
2771 break;
2772 case 3:
2773 parameters.PresentationInterval = D3DPRESENT_INTERVAL_THREE;
2774 break;
2775 default:
2776 parameters.PresentationInterval = D3DPRESENT_INTERVAL_FOUR;
2777 break;
2780 // Build a depth index
2781 const uint depthIndex = (mode.Depth==16)?0:(mode.Depth==24)?1:2;
2783 // Choose a back buffer format
2784 const uint numFormat = 4;
2785 D3DFORMAT backBufferFormats[3][numFormat]=
2787 {D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_X1R5G5B5, D3DFMT_A4R4G4B4},
2788 {D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8},
2789 {D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8},
2791 bool found = false;
2792 if (mode.Windowed)
2794 uint backBuffer;
2795 for (backBuffer=0; backBuffer<numFormat; backBuffer++)
2797 if (_D3D->CheckDeviceType(adapter, _Rasterizer, adapterMode.Format, backBufferFormats[depthIndex][backBuffer], TRUE) == D3D_OK)
2799 parameters.BackBufferFormat = backBufferFormats[depthIndex][backBuffer];
2800 adapterFormat = adapterMode.Format;
2801 found = true;
2802 break;
2806 else
2808 // Found a pair display and back buffer format
2809 uint backBuffer;
2810 for (backBuffer=0; backBuffer<numFormat; backBuffer++)
2812 uint display;
2813 for (display=0; display<numFormat; display++)
2815 if (_D3D->CheckDeviceType(adapter, _Rasterizer, backBufferFormats[depthIndex][display], backBufferFormats[depthIndex][display], FALSE) == D3D_OK)
2817 parameters.BackBufferFormat = backBufferFormats[depthIndex][backBuffer];
2818 adapterFormat = backBufferFormats[depthIndex][display];
2819 found = true;
2820 break;
2823 if (found)
2824 break;
2828 // Not found ?
2829 if (!found)
2831 nlwarning ("Can't create backbuffer");
2832 return false;
2835 // Choose a zbuffer format
2836 D3DFORMAT zbufferFormats[]=
2838 //uncomment to save zbuffer D3DFMT_D32F_LOCKABLE,
2839 //uncomment to save zbuffer D3DFMT_D16_LOCKABLE,
2840 /*D3DFMT_D32,
2841 D3DFMT_D24X8,*/
2842 D3DFMT_D24S8,
2843 D3DFMT_D24X4S4,
2844 D3DFMT_D24FS8,
2845 //D3DFMT_D16,
2848 const uint zbufferFormatCount = sizeof(zbufferFormats)/sizeof(D3DFORMAT);
2849 uint i;
2850 for (i=0; i<zbufferFormatCount; i++)
2852 if (isDepthFormatOk (adapter, _Rasterizer, zbufferFormats[i], adapterFormat, parameters.BackBufferFormat))
2853 break;
2856 if (i>=zbufferFormatCount)
2858 nlwarning ("Can't create zbuffer");
2859 return false;
2862 // Set the zbuffer format
2863 parameters.AutoDepthStencilFormat = zbufferFormats[i];
2865 if(mode.AntiAlias == -1)
2867 parameters.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
2869 else
2871 DWORD aa = 0;
2872 if(mode.AntiAlias == 0)
2874 if(SUCCEEDED(_D3D->CheckDeviceMultiSampleType(adapter, _Rasterizer, adapterFormat, mode.Windowed, D3DMULTISAMPLE_NONMASKABLE, &aa)))
2876 parameters.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE;
2877 parameters.MultiSampleQuality = aa - 1;
2878 nlinfo("Use AntiAlias with %d sample", aa);
2880 else
2882 nlwarning("No AntiAlias support found");
2885 else
2887 parameters.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE;
2888 parameters.MultiSampleQuality = mode.AntiAlias - 1;
2889 nlinfo("Use AntiAlias with %d sample", mode.AntiAlias);
2893 return true;
2896 // ***************************************************************************
2898 const char *CDriverD3D::getVideocardInformation ()
2900 H_AUTO_D3D(CDriverD3D_getVideocardInformation);
2901 static char name[1024];
2903 // if (!_DeviceInterface)
2904 // return "Direct3d isn't initialized";
2906 D3DADAPTER_IDENTIFIER9 identifier;
2907 UINT adapter = (_Adapter==0xffffffff)?D3DADAPTER_DEFAULT:(UINT)_Adapter;
2908 if (_D3D->GetAdapterIdentifier(adapter, 0, &identifier) == D3D_OK)
2910 uint64 version = ((uint64)identifier.DriverVersion.HighPart) << 32;
2911 version |= identifier.DriverVersion.LowPart;
2912 smprintf (name, 1024, "Direct3d / %s / %s / %s / driver version : %d.%d.%d.%d", identifier.Driver, identifier.Description, identifier.DeviceName,
2913 (uint16)((version>>48)&0xFFFF),(uint16)((version>>32)&0xFFFF),(uint16)((version>>16)&0xFFFF),(uint16)(version&0xffff));
2914 return name;
2916 else
2917 return "Can't get video card information";
2920 // ***************************************************************************
2922 sint CDriverD3D::getTotalVideoMemory () const
2924 H_AUTO_D3D(CDriverD3D_getTotalVideoMemory);
2926 // Can't use _DeviceInterface->GetAvailableTextureMem() because it's not reliable
2927 // Returns 4 GiB instead of 2 with my GPU
2928 return -1;
2931 // ***************************************************************************
2933 void CDriverD3D::getBuffer (CBitmap &bitmap)
2935 H_AUTO_D3D(CDriverD3D_getBuffer);
2936 NLMISC::CRect rect;
2937 rect.setWH (0, 0, _CurrentMode.Width, _CurrentMode.Height);
2938 getBufferPart (bitmap, rect);
2941 // ***************************************************************************
2943 void CDriverD3D::getBufferPart (CBitmap &bitmap, NLMISC::CRect &rect)
2945 H_AUTO_D3D(CDriverD3D_getBufferPart);
2946 if (_DeviceInterface)
2948 // Resize the bitmap
2949 const uint lineCount = rect.Height;
2950 const uint width = rect.Width;
2951 bitmap.resize (width, lineCount, CBitmap::RGBA);
2953 // Lock the back buffer
2954 IDirect3DSurface9 *surface;
2955 if (_DeviceInterface->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &surface) == D3D_OK)
2957 // Surface desc
2958 D3DSURFACE_DESC desc;
2959 if (surface->GetDesc(&desc) == D3D_OK)
2961 // 32 bits format supported
2962 if ((desc.Format == D3DFMT_R8G8B8) ||
2963 (desc.Format == D3DFMT_A8R8G8B8) ||
2964 (desc.Format == D3DFMT_X8R8G8B8) ||
2965 (desc.Format == D3DFMT_A8B8G8R8) ||
2966 (desc.Format == D3DFMT_X8B8G8R8))
2968 // Invert RGBA ?
2969 bool invertRGBA = (desc.Format == D3DFMT_R8G8B8) || (desc.Format == D3DFMT_A8R8G8B8) || (desc.Format == D3DFMT_X8R8G8B8);
2971 // Lock the surface
2972 D3DLOCKED_RECT lock;
2973 ::RECT winRect;
2974 winRect.left = rect.left();
2975 winRect.right = rect.right();
2976 winRect.top = rect.top();
2977 winRect.bottom = rect.bottom();
2978 if (surface->LockRect (&lock, &winRect, D3DLOCK_READONLY) == D3D_OK)
2980 // Line count
2981 uint8 *dest = &(bitmap.getPixels ()[0]);
2982 uint i;
2983 for (i=0; i<lineCount; i++)
2985 if (invertRGBA)
2986 copyRGBA2BGRA ((uint32*)dest+(i*width), (uint32*)((uint8*)lock.pBits+(i*lock.Pitch)), width);
2987 else
2988 memcpy (dest+(4*i*width), ((uint8*)lock.pBits)+(i*lock.Pitch), width*4);
2991 surface->UnlockRect ();
2996 surface->Release();
3001 // ***************************************************************************
3003 IDirect3DSurface9 * CDriverD3D::getSurfaceTexture(ITexture * text)
3005 if(!text)
3007 if(!_BackBuffer)
3009 updateRenderVariables ();
3010 _DeviceInterface->GetRenderTarget (0, &_BackBuffer);
3012 nlassert(_BackBuffer);
3013 return _BackBuffer;
3016 if(text->TextureDrvShare==NULL || text->TextureDrvShare->DrvTexture.getPtr()==NULL)
3018 text->setRenderTarget(true);
3019 setupTexture(*text);
3021 CTextureDrvInfosD3D* rdvInfosD3D = (NLMISC::safe_cast<CTextureDrvInfosD3D*>(text->TextureDrvShare->DrvTexture.getPtr()));
3023 IDirect3DTexture9 * texture = rdvInfosD3D->Texture2d;
3024 nlassert(texture);
3026 IDirect3DSurface9 * surface;
3027 HRESULT hr = texture->GetSurfaceLevel(0, &surface);
3028 nlassert(hr==D3D_OK);
3030 return surface;
3033 void CDriverD3D::getDirect3DRect(NLMISC::CRect &rect, RECT & d3dRect)
3035 d3dRect.left = rect.left();
3036 d3dRect.top = rect.top();
3037 d3dRect.right = rect.right();
3038 d3dRect.bottom = rect.bottom();
3040 uint32 w, h;
3041 getWindowSize(w, h);
3043 if(d3dRect.top>(sint32)h)
3044 d3dRect.top = h;
3046 if(d3dRect.right>(sint32)w)
3047 d3dRect.right = w;
3049 if(d3dRect.bottom<0)
3050 d3dRect.bottom = 0;
3052 if(d3dRect.left<0)
3053 d3dRect.left = 0;
3056 bool CDriverD3D::stretchRect(ITexture * srcText, NLMISC::CRect &srcRect, ITexture * destText, NLMISC::CRect &destRect)
3058 H_AUTO_D3D(CDriverD3D_stretchRect);
3059 if (_DeviceInterface)
3061 IDirect3DSurface9 * srcSurface = getSurfaceTexture(srcText);
3062 IDirect3DSurface9 * destSurface = getSurfaceTexture(destText);
3064 D3DTEXTUREFILTERTYPE filterType = D3DTEXF_LINEAR;
3066 RECT srcD3DRect;
3067 RECT destD3DRect;
3068 getDirect3DRect(srcRect, srcD3DRect);
3069 getDirect3DRect(destRect, destD3DRect);
3071 HRESULT hr = _DeviceInterface->StretchRect(srcSurface, &srcD3DRect, destSurface, &destD3DRect, filterType);
3073 srcSurface->Release();
3074 destSurface->Release();
3076 return (hr==D3D_OK);
3079 return false;
3082 // ***************************************************************************
3084 bool CDriverD3D::supportBloomEffect() const
3086 return supportVertexProgram(CVertexProgram::nelvp);
3089 // ***************************************************************************
3091 bool CDriverD3D::supportNonPowerOfTwoTextures() const
3093 return _NonPowerOfTwoTexturesSupported;
3096 // ***************************************************************************
3098 bool CDriverD3D::fillBuffer (NLMISC::CBitmap &bitmap)
3100 H_AUTO_D3D(CDriverD3D_fillBuffer);
3101 bool result = false;
3102 if (_DeviceInterface)
3104 // Resize the bitmap
3105 const uint lineCount = _CurrentMode.Height;
3106 const uint width = _CurrentMode.Width;
3107 if ((bitmap.getWidth() == width) && (bitmap.getHeight() == lineCount))
3109 // Lock the back buffer
3110 IDirect3DSurface9 *surface;
3111 if (_DeviceInterface->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &surface) == D3D_OK)
3113 // Surface desc
3114 D3DSURFACE_DESC desc;
3115 if (surface->GetDesc(&desc) == D3D_OK)
3117 // 32 bits format supported
3118 if ((desc.Format == D3DFMT_R8G8B8) ||
3119 (desc.Format == D3DFMT_A8R8G8B8) ||
3120 (desc.Format == D3DFMT_X8R8G8B8) ||
3121 (desc.Format == D3DFMT_A8B8G8R8) ||
3122 (desc.Format == D3DFMT_X8B8G8R8))
3124 // Invert RGBA ?
3125 bool invertRGBA = (desc.Format == D3DFMT_R8G8B8) || (desc.Format == D3DFMT_A8R8G8B8) || (desc.Format == D3DFMT_X8R8G8B8);
3127 // Lock the surface
3128 D3DLOCKED_RECT lock;
3129 ::RECT winRect;
3130 winRect.left = 0;
3131 winRect.right = width;
3132 winRect.top = 0;
3133 winRect.bottom = lineCount;
3134 if (surface->LockRect (&lock, &winRect, 0) == D3D_OK)
3136 // Line count
3137 uint8 *dest = &(bitmap.getPixels ()[0]);
3138 uint i;
3139 for (i=0; i<lineCount; i++)
3141 if (invertRGBA)
3142 copyRGBA2BGRA ((uint32*)((uint8*)lock.pBits+(i*lock.Pitch)), (uint32*)dest+(i*width), width);
3143 else
3144 memcpy (((uint8*)lock.pBits)+(i*lock.Pitch), dest+(4*i*width), width*4);
3147 surface->UnlockRect ();
3148 result = true;
3153 surface->Release();
3157 return result;
3160 // ***************************************************************************
3162 void CDriverD3D::setSwapVBLInterval(uint interval)
3164 H_AUTO_D3D(CDriverD3D_setSwapVBLInterval);
3165 if (_Interval != interval)
3167 _Interval = interval;
3169 // Must do a reset because the vsync parameter is choosed in the D3DPRESENT structure
3170 if (_DeviceInterface)
3171 reset (_CurrentMode);
3175 // ***************************************************************************
3177 uint CDriverD3D::getSwapVBLInterval()
3179 H_AUTO_D3D(CDriverD3D_getSwapVBLInterval);
3180 return _Interval;
3183 // ***************************************************************************
3184 void CDriverD3D::finish()
3186 // TODO : actually do not wait until everythin is rendered
3187 H_AUTO_D3D(CDriverD3D_finish);
3188 // Flush now
3189 //nldebug("EndScene");
3190 endScene();
3191 //nldebug("BeginScene");
3192 beginScene();
3195 // ***************************************************************************
3196 void CDriverD3D::flush()
3198 H_AUTO_D3D(CDriverD3D_finish);
3199 // Flush now
3200 //nldebug("EndScene");
3201 endScene();
3202 //nldebug("BeginScene");
3203 beginScene();
3206 // ***************************************************************************
3208 bool CDriverD3D::setMonitorColorProperties (const CMonitorColorProperties &properties)
3211 H_AUTO_D3D(CDriverD3D_setMonitorColorProperties);
3212 // The ramp
3213 D3DGAMMARAMP ramp;
3215 // For each composant
3216 uint c;
3217 for( c=0; c<3; c++ )
3219 WORD *table = (c==0)?ramp.red:(c==1)?ramp.green:ramp.blue;
3220 uint i;
3221 for( i=0; i<256; i++ )
3223 // Floating value
3224 float value = (float)i / 256;
3226 // Contrast
3227 value = (float) max (0.0f, (value-0.5f) * (float) pow (3.f, properties.Contrast[c]) + 0.5f );
3229 // Gamma
3230 value = (float) pow (value, (properties.Gamma[c]>0) ? 1 - 3 * properties.Gamma[c] / 4 : 1 - properties.Gamma[c] );
3232 // Luminosity
3233 value = value + properties.Luminosity[c] / 2.f;
3234 table[i] = min (65535, max (0, (int)(value * 65535)));
3238 // Set the ramp
3239 _DeviceInterface->SetGammaRamp (0, D3DSGR_NO_CALIBRATION, &ramp);
3240 return true;
3243 // TODO nico
3244 // It would be better to apply the gamma ramp only to the window and not to the whole desktop when playing in windowed mode.
3245 // This require to switch to D3D 9.0c which has a flag for that purpose in the 'Present' function.
3246 // Currently the SetGammaRamp only works in fullscreen mode, so we rely to the classic 'SetDeviceGammaRamp' instead.
3247 HDC dc = CreateDCW (L"DISPLAY", NULL, NULL, NULL);
3248 if (dc)
3250 // The ramp
3251 WORD ramp[256*3];
3253 // For each composant
3254 uint c;
3255 for( c=0; c<3; c++ )
3257 uint i;
3258 for( i=0; i<256; i++ )
3260 // Floating value
3261 float value = (float)i / 256;
3263 // Contrast
3264 value = (float) max (0.0f, (value-0.5f) * (float) pow (3.f, properties.Contrast[c]) + 0.5f );
3266 // Gamma
3267 value = (float) pow (value, (properties.Gamma[c]>0) ? 1 - 3 * properties.Gamma[c] / 4 : 1 - properties.Gamma[c] );
3269 // Luminosity
3270 value = value + properties.Luminosity[c] / 2.f;
3271 ramp[i+(c<<8)] = (WORD)min (65535, max (0, (int)(value * 65535)));
3275 // Set the ramp
3276 bool result = SetDeviceGammaRamp (dc, ramp) != FALSE;
3278 // Release the DC
3279 ReleaseDC (NULL, dc);
3281 // Returns result
3282 return result;
3284 else
3286 nlwarning ("(CDriverD3D::setMonitorColorProperties): can't create DC");
3287 return false;
3291 // ***************************************************************************
3293 // ****************************************************************************
3294 bool CDriverD3D::supportEMBM() const
3296 H_AUTO_D3D(CDriverD3D_supportEMBM);
3297 return _EMBMSupported;
3300 // ****************************************************************************
3301 bool CDriverD3D::isEMBMSupportedAtStage(uint stage) const
3303 H_AUTO_D3D(CDriverD3D_isEMBMSupportedAtStage);
3304 // we assume EMBM is supported at all stages except the last one
3305 return stage < _NbNeLTextureStages - 1;
3308 // ****************************************************************************
3309 void CDriverD3D::setEMBMMatrix(const uint stage, const float mat[4])
3311 H_AUTO_D3D(CDriverD3D_setEMBMMatrix);
3312 nlassert(stage < _NbNeLTextureStages - 1);
3313 SetTextureStageState(stage, D3DTSS_BUMPENVMAT00, (DWORD &) mat[0]);
3314 SetTextureStageState(stage, D3DTSS_BUMPENVMAT01, (DWORD &) mat[1]);
3315 SetTextureStageState(stage, D3DTSS_BUMPENVMAT10, (DWORD &) mat[2]);
3316 SetTextureStageState(stage, D3DTSS_BUMPENVMAT11, (DWORD &) mat[3]);
3319 // ***************************************************************************
3320 bool CDriverD3D::supportOcclusionQuery() const
3322 H_AUTO_D3D(CDriverD3D_supportOcclusionQuery);
3323 return _OcclusionQuerySupported;
3326 // ***************************************************************************
3327 IOcclusionQuery *CDriverD3D::createOcclusionQuery()
3329 H_AUTO_D3D(CDriverD3D_createOcclusionQuery);
3330 nlassert(_OcclusionQuerySupported);
3331 nlassert(_DeviceInterface);
3332 IDirect3DQuery9 *query;
3333 if (_DeviceInterface->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query) != D3D_OK) return NULL;
3334 COcclusionQueryD3D *oqd3d = new COcclusionQueryD3D;
3335 oqd3d->Driver = this;
3336 oqd3d->Query = query;
3337 oqd3d->VisibleCount = 0;
3338 oqd3d->OcclusionType = IOcclusionQuery::NotAvailable;
3339 oqd3d->QueryIssued = false;
3340 oqd3d->WasLost = false;
3341 _OcclusionQueryList.push_front(oqd3d);
3342 oqd3d->Iterator = _OcclusionQueryList.begin();
3343 return oqd3d;
3346 // ***************************************************************************
3347 void CDriverD3D::deleteOcclusionQuery(IOcclusionQuery *oq)
3349 H_AUTO_D3D(CDriverD3D_deleteOcclusionQuery);
3350 if (!oq) return;
3351 COcclusionQueryD3D *oqd3d = NLMISC::safe_cast<COcclusionQueryD3D *>(oq);
3352 nlassert((CDriverD3D *) oqd3d->Driver == this); // should come from the same driver
3353 oqd3d->Driver = NULL;
3354 if (oqd3d->Query)
3356 oqd3d->Query->Release();
3357 oqd3d->Query = NULL;
3359 _OcclusionQueryList.erase(oqd3d->Iterator);
3360 if (oqd3d == _CurrentOcclusionQuery)
3362 _CurrentOcclusionQuery = NULL;
3364 delete oqd3d;
3367 // ***************************************************************************
3368 void COcclusionQueryD3D::begin()
3370 H_AUTO_D3D(COcclusionQueryD3D_begin);
3371 if (!Query) return; // Lost device
3372 nlassert(Driver);
3373 nlassert(Driver->_CurrentOcclusionQuery == NULL); // only one query at a time
3374 Query->Issue(D3DISSUE_BEGIN);
3375 Driver->_CurrentOcclusionQuery = this;
3376 OcclusionType = NotAvailable;
3377 QueryIssued = false;
3378 WasLost = false;
3381 // ***************************************************************************
3382 void COcclusionQueryD3D::end()
3384 H_AUTO_D3D(COcclusionQueryD3D_end);
3385 if (!Query) return; // Lost device
3386 nlassert(Driver);
3387 nlassert(Driver->_CurrentOcclusionQuery == this); // only one query at a time
3388 if (!WasLost)
3390 Query->Issue(D3DISSUE_END);
3392 Driver->_CurrentOcclusionQuery = NULL;
3393 QueryIssued = true;
3396 // ***************************************************************************
3397 IOcclusionQuery::TOcclusionType COcclusionQueryD3D::getOcclusionType()
3399 if (!Query || WasLost) return QueryIssued ? Occluded : NotAvailable;
3400 H_AUTO_D3D(COcclusionQueryD3D_getOcclusionType);
3401 nlassert(Driver);
3402 nlassert(Query);
3403 nlassert(Driver->_CurrentOcclusionQuery != this); // can't query result between a begin/end pair!
3404 if (OcclusionType == NotAvailable)
3406 DWORD numPix;
3407 if (Query->GetData(&numPix, sizeof(DWORD), 0) == S_OK)
3409 OcclusionType = numPix != 0 ? NotOccluded : Occluded;
3410 VisibleCount = (uint) numPix;
3413 return OcclusionType;
3416 // ***************************************************************************
3417 uint COcclusionQueryD3D::getVisibleCount()
3419 if (!Query || WasLost) return 0;
3420 H_AUTO_D3D(COcclusionQueryD3D_getVisibleCount);
3421 nlassert(Driver);
3422 nlassert(Query);
3423 nlassert(Driver->_CurrentOcclusionQuery != this); // can't query result between a begin/end pair!
3424 if (getOcclusionType() == NotAvailable) return 0;
3425 return VisibleCount;
3428 // ***************************************************************************
3429 bool CDriverD3D::supportWaterShader() const
3431 H_AUTO_D3D(CDriverD3D_supportWaterShader);
3432 return _PixelShaderVersion >= D3DPS_VERSION(1, 1);
3435 // ***************************************************************************
3436 void CDriverD3D::setCullMode(TCullMode cullMode)
3438 H_AUTO_D3D(CDriver3D_cullMode);
3439 #ifdef NL_D3D_USE_RENDER_STATE_CACHE
3440 NL_D3D_CACHE_TEST(CacheTest_CullMode, cullMode != _CullMode)
3441 #endif
3443 if (_InvertCullMode)
3445 setRenderState(D3DRS_CULLMODE, _CullMode == CCW ? D3DCULL_CW : D3DCULL_CCW);
3447 else
3449 setRenderState(D3DRS_CULLMODE, _CullMode == CCW ? D3DCULL_CCW : D3DCULL_CW);
3451 _CullMode = cullMode;
3455 // ***************************************************************************
3456 IDriver::TCullMode CDriverD3D::getCullMode() const
3458 H_AUTO_D3D(CDriver3D_CDriverD3D);
3459 return _CullMode;
3462 // ***************************************************************************
3463 void CDriverD3D::enableStencilTest(bool enable)
3465 H_AUTO_D3D(CDriver3D_CDriverD3D);
3467 _CurStencilTest = enable;
3468 setRenderState(D3DRS_STENCILENABLE, enable?TRUE:FALSE);
3471 // ***************************************************************************
3472 bool CDriverD3D::isStencilTestEnabled() const
3474 H_AUTO_D3D(CDriver3D_CDriverD3D);
3475 return _CurStencilTest?TRUE:FALSE;
3478 // ***************************************************************************
3479 void CDriverD3D::stencilFunc(TStencilFunc stencilFunc, int ref, uint mask)
3481 H_AUTO_D3D(CDriver3D_CDriverD3D);
3483 switch(stencilFunc)
3485 case IDriver::never: _CurStencilFunc=D3DCMP_NEVER; break;
3486 case IDriver::less: _CurStencilFunc=D3DCMP_LESS; break;
3487 case IDriver::lessequal: _CurStencilFunc=D3DCMP_LESSEQUAL; break;
3488 case IDriver::equal: _CurStencilFunc=D3DCMP_EQUAL; break;
3489 case IDriver::notequal: _CurStencilFunc=D3DCMP_NOTEQUAL; break;
3490 case IDriver::greaterequal: _CurStencilFunc=D3DCMP_GREATEREQUAL; break;
3491 case IDriver::greater: _CurStencilFunc=D3DCMP_GREATER; break;
3492 case IDriver::always: _CurStencilFunc=D3DCMP_ALWAYS; break;
3493 default: nlstop;
3496 _CurStencilRef = (DWORD)ref;
3497 _CurStencilMask = (DWORD)mask;
3498 setRenderState(D3DRS_STENCILFUNC, _CurStencilFunc);
3499 setRenderState(D3DRS_STENCILREF, _CurStencilRef);
3500 setRenderState(D3DRS_STENCILMASK, _CurStencilMask);
3503 // ***************************************************************************
3504 void CDriverD3D::stencilOp(TStencilOp fail, TStencilOp zfail, TStencilOp zpass)
3506 H_AUTO_D3D(CDriver3D_CDriverD3D);
3508 switch(fail)
3510 case IDriver::keep: _CurStencilOpFail=D3DSTENCILOP_KEEP; break;
3511 case IDriver::zero: _CurStencilOpFail=D3DSTENCILOP_ZERO; break;
3512 case IDriver::replace: _CurStencilOpFail=D3DSTENCILOP_REPLACE; break;
3513 case IDriver::incr: _CurStencilOpFail=D3DSTENCILOP_INCR; break;
3514 case IDriver::decr: _CurStencilOpFail=D3DSTENCILOP_DECR; break;
3515 case IDriver::invert: _CurStencilOpFail=D3DSTENCILOP_INVERT; break;
3516 default: nlstop;
3519 switch(zfail)
3521 case IDriver::keep: _CurStencilOpZFail=D3DSTENCILOP_KEEP; break;
3522 case IDriver::zero: _CurStencilOpZFail=D3DSTENCILOP_ZERO; break;
3523 case IDriver::replace: _CurStencilOpZFail=D3DSTENCILOP_REPLACE; break;
3524 case IDriver::incr: _CurStencilOpZFail=D3DSTENCILOP_INCR; break;
3525 case IDriver::decr: _CurStencilOpZFail=D3DSTENCILOP_DECR; break;
3526 case IDriver::invert: _CurStencilOpZFail=D3DSTENCILOP_INVERT; break;
3527 default: nlstop;
3530 switch(zpass)
3532 case IDriver::keep: _CurStencilOpZPass=D3DSTENCILOP_KEEP; break;
3533 case IDriver::zero: _CurStencilOpZPass=D3DSTENCILOP_ZERO; break;
3534 case IDriver::replace: _CurStencilOpZPass=D3DSTENCILOP_REPLACE; break;
3535 case IDriver::incr: _CurStencilOpZPass=D3DSTENCILOP_INCR; break;
3536 case IDriver::decr: _CurStencilOpZPass=D3DSTENCILOP_DECR; break;
3537 case IDriver::invert: _CurStencilOpZPass=D3DSTENCILOP_INVERT; break;
3538 default: nlstop;
3541 setRenderState(D3DRS_STENCILFAIL, _CurStencilOpFail);
3542 setRenderState(D3DRS_STENCILZFAIL, _CurStencilOpZFail);
3543 setRenderState(D3DRS_STENCILPASS, _CurStencilOpZPass);
3546 // ***************************************************************************
3547 void CDriverD3D::stencilMask(uint mask)
3549 H_AUTO_D3D(CDriver3D_CDriverD3D);
3551 _CurStencilWriteMask = (DWORD)mask;
3552 setRenderState (D3DRS_STENCILWRITEMASK, _CurStencilWriteMask);
3555 // volatile bool preciseStateProfile = false;
3556 // ***************************************************************************
3557 void CDriverD3D::CRenderState::apply(CDriverD3D *driver)
3559 H_AUTO_D3D(CDriverD3D_CRenderState);
3560 /*if (!preciseStateProfile)
3562 driver->_DeviceInterface->SetRenderState (StateID, Value);
3565 else
3567 switch(StateID)
3569 case D3DRS_ZENABLE: { H_AUTO_D3D(D3DRS_ZENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3570 case D3DRS_FILLMODE: { H_AUTO_D3D(D3DRS_FILLMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3571 case D3DRS_SHADEMODE: { H_AUTO_D3D(D3DRS_SHADEMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3572 case D3DRS_ZWRITEENABLE: { H_AUTO_D3D(D3DRS_ZWRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3573 case D3DRS_ALPHATESTENABLE: { H_AUTO_D3D(D3DRS_ALPHATESTENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3574 case D3DRS_LASTPIXEL: { H_AUTO_D3D(D3DRS_LASTPIXEL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3575 case D3DRS_SRCBLEND: { H_AUTO_D3D(D3DRS_SRCBLEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3576 case D3DRS_DESTBLEND: { H_AUTO_D3D(D3DRS_DESTBLEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3577 case D3DRS_CULLMODE: { H_AUTO_D3D(D3DRS_CULLMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3578 case D3DRS_ZFUNC: { H_AUTO_D3D(D3DRS_ZFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3579 case D3DRS_ALPHAREF: { H_AUTO_D3D(D3DRS_ALPHAREF); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3580 case D3DRS_ALPHAFUNC: { H_AUTO_D3D(D3DRS_ALPHAFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3581 case D3DRS_DITHERENABLE: { H_AUTO_D3D(D3DRS_DITHERENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3582 case D3DRS_ALPHABLENDENABLE: { H_AUTO_D3D(D3DRS_ALPHABLENDENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3583 case D3DRS_FOGENABLE: { H_AUTO_D3D(D3DRS_FOGENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3584 case D3DRS_SPECULARENABLE: { H_AUTO_D3D(D3DRS_SPECULARENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3585 case D3DRS_FOGCOLOR: { H_AUTO_D3D(D3DRS_FOGCOLOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3586 case D3DRS_FOGTABLEMODE: { H_AUTO_D3D(D3DRS_FOGTABLEMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3587 case D3DRS_FOGSTART: { H_AUTO_D3D(D3DRS_FOGSTART); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3588 case D3DRS_FOGEND: { H_AUTO_D3D(D3DRS_FOGEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3589 case D3DRS_FOGDENSITY: { H_AUTO_D3D(D3DRS_FOGDENSITY); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3590 case D3DRS_RANGEFOGENABLE: { H_AUTO_D3D(D3DRS_RANGEFOGENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3591 case D3DRS_STENCILENABLE: { H_AUTO_D3D(D3DRS_STENCILENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3592 case D3DRS_STENCILFAIL: { H_AUTO_D3D(D3DRS_STENCILFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3593 case D3DRS_STENCILZFAIL: { H_AUTO_D3D(D3DRS_STENCILZFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3594 case D3DRS_STENCILPASS: { H_AUTO_D3D(D3DRS_STENCILPASS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3595 case D3DRS_STENCILFUNC: { H_AUTO_D3D(D3DRS_STENCILFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3596 case D3DRS_STENCILREF: { H_AUTO_D3D(D3DRS_STENCILREF); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3597 case D3DRS_STENCILMASK: { H_AUTO_D3D(D3DRS_STENCILMASK); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3598 case D3DRS_STENCILWRITEMASK: { H_AUTO_D3D(D3DRS_STENCILWRITEMASK); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3599 case D3DRS_TEXTUREFACTOR: { H_AUTO_D3D(D3DRS_TEXTUREFACTOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3600 case D3DRS_WRAP0: { H_AUTO_D3D(D3DRS_WRAP0); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3601 case D3DRS_WRAP1: { H_AUTO_D3D(D3DRS_WRAP1); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3602 case D3DRS_WRAP2: { H_AUTO_D3D(D3DRS_WRAP2); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3603 case D3DRS_WRAP3: { H_AUTO_D3D(D3DRS_WRAP3); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3604 case D3DRS_WRAP4: { H_AUTO_D3D(D3DRS_WRAP4); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3605 case D3DRS_WRAP5: { H_AUTO_D3D(D3DRS_WRAP5); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3606 case D3DRS_WRAP6: { H_AUTO_D3D(D3DRS_WRAP6); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3607 case D3DRS_WRAP7: { H_AUTO_D3D(D3DRS_WRAP7); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3608 case D3DRS_CLIPPING: { H_AUTO_D3D(D3DRS_CLIPPING); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3609 case D3DRS_LIGHTING: { H_AUTO_D3D(D3DRS_LIGHTING); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3610 case D3DRS_AMBIENT: { H_AUTO_D3D(D3DRS_AMBIENT); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3611 case D3DRS_FOGVERTEXMODE: { H_AUTO_D3D(D3DRS_FOGVERTEXMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3612 case D3DRS_COLORVERTEX: { H_AUTO_D3D(D3DRS_COLORVERTEX); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3613 case D3DRS_LOCALVIEWER: { H_AUTO_D3D(D3DRS_LOCALVIEWER); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3614 case D3DRS_NORMALIZENORMALS: { H_AUTO_D3D(D3DRS_NORMALIZENORMALS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3615 case D3DRS_DIFFUSEMATERIALSOURCE: { H_AUTO_D3D(D3DRS_DIFFUSEMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3616 case D3DRS_SPECULARMATERIALSOURCE: { H_AUTO_D3D(D3DRS_SPECULARMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3617 case D3DRS_AMBIENTMATERIALSOURCE: { H_AUTO_D3D(D3DRS_AMBIENTMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3618 case D3DRS_EMISSIVEMATERIALSOURCE: { H_AUTO_D3D(D3DRS_EMISSIVEMATERIALSOURCE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3619 case D3DRS_VERTEXBLEND: { H_AUTO_D3D(D3DRS_VERTEXBLEND); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3620 case D3DRS_CLIPPLANEENABLE: { H_AUTO_D3D(D3DRS_CLIPPLANEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3621 case D3DRS_POINTSIZE: { H_AUTO_D3D(D3DRS_POINTSIZE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3622 case D3DRS_POINTSIZE_MIN: { H_AUTO_D3D(D3DRS_POINTSIZE_MIN); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3623 case D3DRS_POINTSPRITEENABLE: { H_AUTO_D3D(D3DRS_POINTSPRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3624 case D3DRS_POINTSCALEENABLE: { H_AUTO_D3D(D3DRS_POINTSCALEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3625 case D3DRS_POINTSCALE_A: { H_AUTO_D3D(D3DRS_POINTSCALE_A); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3626 case D3DRS_POINTSCALE_B: { H_AUTO_D3D(D3DRS_POINTSCALE_B); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3627 case D3DRS_POINTSCALE_C: { H_AUTO_D3D(D3DRS_POINTSCALE_C); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3628 case D3DRS_MULTISAMPLEANTIALIAS: { H_AUTO_D3D(D3DRS_MULTISAMPLEANTIALIAS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3629 case D3DRS_MULTISAMPLEMASK: { H_AUTO_D3D(D3DRS_MULTISAMPLEMASK); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3630 case D3DRS_PATCHEDGESTYLE: { H_AUTO_D3D(D3DRS_PATCHEDGESTYLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3631 case D3DRS_DEBUGMONITORTOKEN: { H_AUTO_D3D(D3DRS_DEBUGMONITORTOKEN); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3632 case D3DRS_POINTSIZE_MAX: { H_AUTO_D3D(D3DRS_POINTSIZE_MAX); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3633 case D3DRS_INDEXEDVERTEXBLENDENABLE: { H_AUTO_D3D(D3DRS_INDEXEDVERTEXBLENDENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3634 case D3DRS_COLORWRITEENABLE: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3635 case D3DRS_TWEENFACTOR: { H_AUTO_D3D(D3DRS_TWEENFACTOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3636 case D3DRS_BLENDOP: { H_AUTO_D3D(D3DRS_BLENDOP); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3637 case D3DRS_POSITIONDEGREE: { H_AUTO_D3D(D3DRS_POSITIONDEGREE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3638 case D3DRS_NORMALDEGREE: { H_AUTO_D3D(D3DRS_NORMALDEGREE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3639 case D3DRS_SCISSORTESTENABLE: { H_AUTO_D3D(D3DRS_SCISSORTESTENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3640 case D3DRS_SLOPESCALEDEPTHBIAS: { H_AUTO_D3D(D3DRS_SLOPESCALEDEPTHBIAS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3641 case D3DRS_ANTIALIASEDLINEENABLE: { H_AUTO_D3D(D3DRS_ANTIALIASEDLINEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3642 case D3DRS_MINTESSELLATIONLEVEL: { H_AUTO_D3D(D3DRS_MINTESSELLATIONLEVEL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3643 case D3DRS_MAXTESSELLATIONLEVEL: { H_AUTO_D3D(D3DRS_MAXTESSELLATIONLEVEL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3644 case D3DRS_ADAPTIVETESS_X: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_X); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3645 case D3DRS_ADAPTIVETESS_Y: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_Y); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3646 case D3DRS_ADAPTIVETESS_Z: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_Z); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3647 case D3DRS_ADAPTIVETESS_W: { H_AUTO_D3D(D3DRS_ADAPTIVETESS_W); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3648 case D3DRS_ENABLEADAPTIVETESSELLATION: { H_AUTO_D3D(D3DRS_ENABLEADAPTIVETESSELLATION); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3649 case D3DRS_TWOSIDEDSTENCILMODE: { H_AUTO_D3D(D3DRS_TWOSIDEDSTENCILMODE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3650 case D3DRS_CCW_STENCILFAIL: { H_AUTO_D3D(D3DRS_CCW_STENCILFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3651 case D3DRS_CCW_STENCILZFAIL: { H_AUTO_D3D(D3DRS_CCW_STENCILZFAIL); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3652 case D3DRS_CCW_STENCILPASS: { H_AUTO_D3D(D3DRS_CCW_STENCILPASS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3653 case D3DRS_CCW_STENCILFUNC: { H_AUTO_D3D(D3DRS_CCW_STENCILFUNC); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3654 case D3DRS_COLORWRITEENABLE1: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE1); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3655 case D3DRS_COLORWRITEENABLE2: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE2); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3656 case D3DRS_COLORWRITEENABLE3: { H_AUTO_D3D(D3DRS_COLORWRITEENABLE3); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3657 case D3DRS_BLENDFACTOR: { H_AUTO_D3D(D3DRS_BLENDFACTOR); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3658 case D3DRS_SRGBWRITEENABLE: { H_AUTO_D3D(D3DRS_SRGBWRITEENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3659 case D3DRS_DEPTHBIAS: { H_AUTO_D3D(D3DRS_DEPTHBIAS); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3660 case D3DRS_WRAP8: { H_AUTO_D3D(D3DRS_WRAP8); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3661 case D3DRS_WRAP9: { H_AUTO_D3D(D3DRS_WRAP9); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3662 case D3DRS_WRAP10: { H_AUTO_D3D(D3DRS_WRAP10); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3663 case D3DRS_WRAP11: { H_AUTO_D3D(D3DRS_WRAP11); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3664 case D3DRS_WRAP12: { H_AUTO_D3D(D3DRS_WRAP12); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3665 case D3DRS_WRAP13: { H_AUTO_D3D(D3DRS_WRAP13); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3666 case D3DRS_WRAP14: { H_AUTO_D3D(D3DRS_WRAP14); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3667 case D3DRS_WRAP15: { H_AUTO_D3D(D3DRS_WRAP15); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3668 case D3DRS_SEPARATEALPHABLENDENABLE: { H_AUTO_D3D(D3DRS_SEPARATEALPHABLENDENABLE); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3669 case D3DRS_SRCBLENDALPHA: { H_AUTO_D3D(D3DRS_SRCBLENDALPHA); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3670 case D3DRS_DESTBLENDALPHA: { H_AUTO_D3D(D3DRS_DESTBLENDALPHA); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3671 case D3DRS_BLENDOPALPHA: { H_AUTO_D3D(D3DRS_BLENDOPALPHA); driver->_DeviceInterface->SetRenderState(StateID, Value); } break;
3678 // ***************************************************************************
3679 void CDriverD3D::CTextureState::apply(CDriverD3D *driver)
3681 H_AUTO_D3D(CDriverD3D_CTextureState);
3682 if (Value != DeviceValue)
3684 driver->_DeviceInterface->SetTextureStageState (StageID, StateID, Value);
3685 DeviceValue = Value;
3689 // ***************************************************************************
3690 void CDriverD3D::CTextureIndexState::apply(CDriverD3D *driver)
3692 H_AUTO_D3D(CDriverD3D_CTextureIndexState);
3693 if (TexGen)
3694 driver->setTextureState (StageID, D3DTSS_TEXCOORDINDEX, TexGenMode);
3695 else
3696 driver->setTextureState (StageID, D3DTSS_TEXCOORDINDEX, UVChannel);
3699 // ***************************************************************************
3700 void CDriverD3D::CTexturePtrState::apply(CDriverD3D *driver)
3702 H_AUTO_D3D(CDriverD3D_CTexturePtrState);
3703 driver->_DeviceInterface->SetTexture (StageID, Texture);
3706 // ***************************************************************************
3707 void CDriverD3D::CVertexProgramPtrState::apply(CDriverD3D *driver)
3709 H_AUTO_D3D(CDriverD3D_CVertexProgramPtrState);
3710 driver->_DeviceInterface->SetVertexShader(VertexProgram);
3713 // ***************************************************************************
3714 void CDriverD3D::CPixelShaderPtrState::apply(CDriverD3D *driver)
3716 H_AUTO_D3D(CDriverD3D_CPixelShaderPtrState);
3717 if (!driver->_PixelProgram) return;
3718 driver->_DeviceInterface->SetPixelShader(PixelShader);
3721 // ***************************************************************************
3722 void CDriverD3D::CVertexProgramConstantState::apply(CDriverD3D *driver)
3724 H_AUTO_D3D(CDriverD3D_CVertexProgramConstantState);
3725 switch (ValueType)
3727 case CVertexProgramConstantState::Float:
3728 driver->_DeviceInterface->SetVertexShaderConstantF (StateID, (float*)Values, 1);
3729 break;
3730 case CVertexProgramConstantState::Int:
3731 driver->_DeviceInterface->SetVertexShaderConstantI (StateID, (int*)Values, 1);
3732 break;
3736 // ***************************************************************************
3737 void CDriverD3D::CPixelShaderConstantState::apply(CDriverD3D *driver)
3739 H_AUTO_D3D(CDriverD3D_CPixelShaderConstantState);
3740 switch (ValueType)
3742 case CPixelShaderConstantState::Float:
3743 driver->_DeviceInterface->SetPixelShaderConstantF (StateID, (float*)Values, 1);
3744 break;
3745 case CPixelShaderConstantState::Int:
3746 driver->_DeviceInterface->SetPixelShaderConstantI (StateID, (int*)Values, 1);
3747 break;
3751 // ***************************************************************************
3752 void CDriverD3D::CSamplerState::apply(CDriverD3D *driver)
3754 H_AUTO_D3D(CDriverD3D_CSamplerState);
3755 driver->_DeviceInterface->SetSamplerState (SamplerID, StateID, Value);
3758 // ***************************************************************************
3759 void CDriverD3D::CMatrixState::apply(CDriverD3D *driver)
3761 H_AUTO_D3D(CDriverD3D_CMatrixState);
3762 driver->_DeviceInterface->SetTransform (TransformType, &Matrix);
3765 // ***************************************************************************
3766 void CDriverD3D::CVBState::apply(CDriverD3D *driver)
3768 H_AUTO_D3D(CDriverD3D_CVBState);
3769 if (VertexBuffer)
3771 driver->_DeviceInterface->SetStreamSource (0, VertexBuffer, Offset, Stride);
3772 // Fix for radeon 7xxx & bad vertex layout
3773 if (driver->inlGetNumTextStages() == 3) // If there are 3 stages this is a Radeon 7xxx
3775 if (ColorOffset != 0 && driver->_VertexDeclCache.EnableVertexColor)
3777 driver->_DeviceInterface->SetStreamSource (1, VertexBuffer, Offset + ColorOffset, Stride);
3779 else
3781 driver->_DeviceInterface->SetStreamSource (1, NULL, 0, 0);
3786 // ***************************************************************************
3787 void CDriverD3D::CIBState::apply(CDriverD3D *driver)
3789 H_AUTO_D3D(CDriverD3D_CIBState);
3790 if (IndexBuffer)
3792 driver->_DeviceInterface->SetIndices (IndexBuffer);
3796 // ***************************************************************************
3797 void CDriverD3D::CVertexDeclState::apply(CDriverD3D *driver)
3799 H_AUTO_D3D(CDriverD3D_CVertexDeclState);
3800 if (Decl)
3802 if (!EnableVertexColor && DeclAliasDiffuseToSpecular && driver->inlGetNumTextStages() == 3)
3804 // 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)
3805 nlassert(DeclNoDiffuse);
3806 driver->_DeviceInterface->SetVertexDeclaration (DeclNoDiffuse);
3808 else
3809 if (AliasDiffuseToSpecular)
3811 nlassert(DeclAliasDiffuseToSpecular);
3812 driver->_DeviceInterface->SetVertexDeclaration (DeclAliasDiffuseToSpecular);
3814 else
3816 nlassert(Decl);
3817 driver->_DeviceInterface->SetVertexDeclaration (Decl);
3822 // ***************************************************************************
3823 void CDriverD3D::CLightState::apply(CDriverD3D *driver)
3825 H_AUTO_D3D(CDriverD3D_CLightState);
3826 // Enable state modified ?
3828 H_AUTO_D3D(CDriverD3D_CLightStateEnabled);
3829 if (EnabledTouched)
3830 driver->_DeviceInterface->LightEnable (LightIndex, Enabled);
3833 H_AUTO_D3D(CDriverD3D_CLightStateSetup);
3834 // Light enabled ?
3835 if (Enabled)
3837 if (SettingsTouched)
3839 // New position
3840 Light.Position.x -= driver->_PZBCameraPos.x;
3841 Light.Position.y -= driver->_PZBCameraPos.y;
3842 Light.Position.z -= driver->_PZBCameraPos.z;
3843 driver->_DeviceInterface->SetLight (LightIndex, &Light);
3844 SettingsTouched = false;
3847 // Clean
3848 EnabledTouched = false;
3852 // ***************************************************************************
3853 void CDriverD3D::CRenderTargetState::apply(CDriverD3D *driver)
3855 H_AUTO_D3D(CDriverD3D_CRenderTargetState);
3856 nlassert(TargetOwned); // Can only apply once!
3857 driver->_DeviceInterface->SetRenderTarget(0, Target);
3858 driver->setupViewport(driver->_Viewport);
3859 driver->setupScissor(driver->_Scissor);
3860 if (TargetOwned)
3862 Target->Release();
3863 TargetOwned = false;
3867 // ***************************************************************************
3868 void CDriverD3D::CMaterialState::apply(CDriverD3D *driver)
3870 H_AUTO_D3D(CDriverD3D_CMaterialState);
3871 driver->_DeviceInterface->SetMaterial(&Current);
3874 // ***************************************************************************
3875 void CDriverD3D::beginDialogMode()
3877 if (_FullScreen && _HWnd)
3878 ShowWindow(_HWnd, SW_MINIMIZE);
3881 // ***************************************************************************
3882 void CDriverD3D::endDialogMode()
3884 if (_FullScreen && _HWnd)
3885 ShowWindow(_HWnd, SW_MAXIMIZE);
3888 bool CDriverD3D::clipRect(NLMISC::CRect &rect)
3890 // Clip the wanted rectangle with window.
3891 uint32 width, height;
3892 getWindowSize(width, height);
3894 sint32 xr=rect.right() ,yr=rect.bottom();
3896 clamp((sint32&)rect.X, (sint32)0, (sint32)width);
3897 clamp((sint32&)rect.Y, (sint32)0, (sint32)height);
3898 clamp((sint32&)xr, (sint32)rect.X, (sint32)width);
3899 clamp((sint32&)yr, (sint32)rect.Y, (sint32)height);
3900 rect.Width= xr-rect.X;
3901 rect.Height= yr-rect.Y;
3903 return rect.Width>0 && rect.Height>0;
3906 void CDriverD3D::getZBuffer(std::vector<float> &zbuffer)
3908 H_AUTO_D3D(CDriverD3D_getZBuffer);
3910 CRect rect(0, 0);
3911 getWindowSize(rect.Width, rect.Height);
3912 getZBufferPart(zbuffer, rect);
3915 void CDriverD3D::getZBufferPart (std::vector<float> &zbuffer, NLMISC::CRect &rect)
3917 zbuffer.clear();
3919 IDirect3DSurface9 *surface;
3920 if (SUCCEEDED(_DeviceInterface->GetDepthStencilSurface(&surface)))
3922 if (clipRect(rect))
3924 RECT winRect;
3925 winRect.left = rect.left();
3926 winRect.right = rect.right();
3927 winRect.top = rect.top();
3928 winRect.bottom = rect.bottom();
3930 // Lock the surface
3931 D3DLOCKED_RECT lock;
3932 if (SUCCEEDED(surface->LockRect (&lock, &winRect, D3DLOCK_READONLY)))
3934 zbuffer.resize(rect.Width*rect.Height);
3936 // Surface desc
3937 D3DSURFACE_DESC desc;
3938 if (SUCCEEDED(surface->GetDesc(&desc)))
3940 const uint8* pBits = (uint8*)lock.pBits;
3942 for(uint y=0; y<rect.Height; ++y)
3944 uint offset = y*rect.Width;
3945 uint end = offset + rect.Width;
3947 // 32 bits format supported
3948 if (desc.Format == D3DFMT_D32F_LOCKABLE)
3950 const float *src = (float*)(pBits + lock.Pitch * y);
3951 float *dst = &zbuffer[offset];
3952 memcpy(dst, src, rect.Width * sizeof(float));
3954 else if (desc.Format == D3DFMT_D24S8)
3956 uint32* pRow = (uint32*)(pBits + lock.Pitch * y);
3957 while(offset != end)
3959 uint32 value = *pRow++;
3960 zbuffer[offset++] = (float)value / (float)std::numeric_limits<uint32>::max();
3963 else if (desc.Format == D3DFMT_D16_LOCKABLE)
3965 uint16* pRow = (uint16*)(pBits + lock.Pitch * y);
3966 while(offset != end)
3968 uint16 value = *pRow++;
3969 zbuffer[offset++] = (float)value / (float)std::numeric_limits<uint16>::max();
3975 surface->UnlockRect ();
3979 surface->Release();
3984 void CDriverD3D::findNearestFullscreenVideoMode()
3986 if(_CurrentMode.Windowed)
3987 return;
3989 std::vector<GfxMode> modes;
3990 if(getModes(modes))
3992 sint32 nbPixels = _CurrentMode.Width * _CurrentMode.Height;
3993 sint32 minError = nbPixels;
3994 uint bestMode = (uint)modes.size();
3995 for(uint i=0; i < modes.size(); i++)
3997 if(!modes[i].Windowed)
3999 if(modes[i].Width==_CurrentMode.Width && modes[i].Height==_CurrentMode.Height)
4001 // ok we found the perfect mode
4002 return;
4004 sint32 currentPixels = modes[i].Width * modes[i].Height;
4005 sint32 currentError = abs(nbPixels - currentPixels);
4006 if(currentError < minError)
4008 minError = currentError;
4009 bestMode = i;
4013 if(bestMode != modes.size())
4015 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);
4016 _CurrentMode.Width = modes[bestMode].Width;
4017 _CurrentMode.Height = modes[bestMode].Height;
4021 bool CDriverD3D::copyTextToClipboard(const std::string &text)
4023 return _EventEmitter.copyTextToClipboard(text);
4026 bool CDriverD3D::pasteTextFromClipboard(std::string &text)
4028 return _EventEmitter.pasteTextFromClipboard(text);
4031 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)
4033 CBitmap src = bitmap;
4034 // resample bitmap if necessary
4035 if (src.getWidth() != iconWidth || src.getHeight() != iconHeight)
4037 src.resample(iconWidth, iconHeight);
4039 CBitmap colorBm;
4040 colorBm.resize(iconWidth, iconHeight, CBitmap::RGBA);
4041 const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]);
4042 const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight);
4043 CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]);
4044 static volatile uint8 alphaThreshold = 127;
4047 destColorPtr->modulateFromColor(*srcColorPtr, col);
4048 std::swap(destColorPtr->R, destColorPtr->B);
4049 ++ srcColorPtr;
4050 ++ destColorPtr;
4052 while (srcColorPtr != srcColorPtrLast);
4054 HBITMAP colorHbm = NULL;
4055 HBITMAP maskHbm = NULL;
4057 if (iconDepth == 16)
4059 std::vector<uint16> colorBm16(iconWidth * iconHeight);
4060 const CRGBA *src32 = (const CRGBA *) &colorBm.getPixels(0)[0];
4062 for (uint k = 0; k < colorBm16.size(); ++k)
4064 colorBm16[k] = ((uint16)(src32[k].R&0xf8)>>3) | ((uint16)(src32[k].G&0xfc)<<3) | ((uint16)(src32[k].B & 0xf8)<<8);
4067 colorHbm = CreateBitmap(iconWidth, iconHeight, 1, 16, &colorBm16[0]);
4068 std::vector<uint8> bitMask((iconWidth * iconHeight + 7) / 8, 0);
4070 for (uint k = 0;k < colorBm16.size(); ++k)
4072 if (src32[k].A <= 120)
4074 bitMask[k / 8] |= (0x80 >> (k & 7));
4078 maskHbm = CreateBitmap(iconWidth, iconHeight, 1, 1, &bitMask[0]);
4080 else
4082 colorHbm = CreateBitmap(iconWidth, iconHeight, 1, 32, &colorBm.getPixels(0)[0]);
4083 maskHbm = CreateBitmap(iconWidth, iconHeight, 1, 32, &colorBm.getPixels(0)[0]);
4086 ICONINFO iconInfo;
4087 iconInfo.fIcon = cursor ? FALSE:TRUE;
4088 iconInfo.xHotspot = (DWORD) hotSpotX;
4089 iconInfo.yHotspot = (DWORD) hotSpotY;
4090 iconInfo.hbmMask = maskHbm;
4091 iconInfo.hbmColor = colorHbm;
4093 if (colorHbm && maskHbm)
4095 icon = CreateIconIndirect(&iconInfo);
4099 if (colorHbm) DeleteObject(colorHbm);
4100 if (maskHbm) DeleteObject(maskHbm);
4102 return true;
4105 } // NL3D