aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D9Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CD3D9Driver.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CD3D9Driver.cpp3633
1 files changed, 3633 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D9Driver.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D9Driver.cpp
new file mode 100644
index 0000000..7404894
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D9Driver.cpp
@@ -0,0 +1,3633 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#define _IRR_DONT_DO_MEMORY_DEBUGGING_HERE
6#include "CD3D9Driver.h"
7
8#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
9
10#include "os.h"
11#include "S3DVertex.h"
12#include "CD3D9Texture.h"
13#include "CD3D9MaterialRenderer.h"
14#include "CD3D9ShaderMaterialRenderer.h"
15#include "CD3D9NormalMapRenderer.h"
16#include "CD3D9ParallaxMapRenderer.h"
17#include "CD3D9HLSLMaterialRenderer.h"
18#include "CD3D9CgMaterialRenderer.h"
19#include "SIrrCreationParameters.h"
20
21namespace irr
22{
23namespace video
24{
25
26namespace
27{
28 inline DWORD F2DW( FLOAT f ) { return *((DWORD*)&f); }
29}
30
31//! constructor
32CD3D9Driver::CD3D9Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io)
33 : CNullDriver(io, params.WindowSize), CurrentRenderMode(ERM_NONE),
34 ResetRenderStates(true), Transformation3DChanged(false),
35 D3DLibrary(0), pID3D(0), pID3DDevice(0), PrevRenderTarget(0),
36 WindowId(0), SceneSourceRect(0),
37 LastVertexType((video::E_VERTEX_TYPE)-1), VendorID(0),
38 MaxTextureUnits(0), MaxUserClipPlanes(0), MaxMRTs(1), NumSetMRTs(1),
39 MaxLightDistance(0.f), LastSetLight(-1),
40 ColorFormat(ECF_A8R8G8B8), DeviceLost(false),
41 DriverWasReset(true), OcclusionQuerySupport(false),
42 AlphaToCoverageSupport(false), Params(params)
43{
44 #ifdef _DEBUG
45 setDebugName("CD3D9Driver");
46 #endif
47
48 printVersion();
49
50 for (u32 i=0; i<MATERIAL_MAX_TEXTURES; ++i)
51 {
52 CurrentTexture[i] = 0;
53 LastTextureMipMapsAvailable[i] = false;
54 }
55 MaxLightDistance = sqrtf(FLT_MAX);
56 // create sphere map matrix
57
58 SphereMapMatrixD3D9._11 = 0.5f; SphereMapMatrixD3D9._12 = 0.0f;
59 SphereMapMatrixD3D9._13 = 0.0f; SphereMapMatrixD3D9._14 = 0.0f;
60 SphereMapMatrixD3D9._21 = 0.0f; SphereMapMatrixD3D9._22 =-0.5f;
61 SphereMapMatrixD3D9._23 = 0.0f; SphereMapMatrixD3D9._24 = 0.0f;
62 SphereMapMatrixD3D9._31 = 0.0f; SphereMapMatrixD3D9._32 = 0.0f;
63 SphereMapMatrixD3D9._33 = 1.0f; SphereMapMatrixD3D9._34 = 0.0f;
64 SphereMapMatrixD3D9._41 = 0.5f; SphereMapMatrixD3D9._42 = 0.5f;
65 SphereMapMatrixD3D9._43 = 0.0f; SphereMapMatrixD3D9._44 = 1.0f;
66
67 core::matrix4 mat;
68 UnitMatrixD3D9 = *(D3DMATRIX*)((void*)mat.pointer());
69
70 #ifdef _IRR_COMPILE_WITH_CG_
71 CgContext = 0;
72 #endif
73
74 // init direct 3d is done in the factory function
75}
76
77
78//! destructor
79CD3D9Driver::~CD3D9Driver()
80{
81 deleteMaterialRenders();
82 deleteAllTextures();
83 removeAllOcclusionQueries();
84 removeAllHardwareBuffers();
85 for (u32 i=0; i<DepthBuffers.size(); ++i)
86 {
87 DepthBuffers[i]->drop();
88 }
89 DepthBuffers.clear();
90
91 // drop d3d9
92
93 if (pID3DDevice)
94 pID3DDevice->Release();
95
96 if (pID3D)
97 pID3D->Release();
98
99 #ifdef _IRR_COMPILE_WITH_CG_
100 cgD3D9SetDevice(0);
101
102 if(CgContext)
103 {
104 cgDestroyContext(CgContext);
105 }
106 #endif
107}
108
109
110void CD3D9Driver::createMaterialRenderers()
111{
112 // create D3D9 material renderers
113
114 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_SOLID(pID3DDevice, this));
115 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_SOLID_2_LAYER(pID3DDevice, this));
116
117 // add the same renderer for all lightmap types
118
119 CD3D9MaterialRenderer_LIGHTMAP* lmr = new CD3D9MaterialRenderer_LIGHTMAP(pID3DDevice, this);
120 addMaterialRenderer(lmr); // for EMT_LIGHTMAP:
121 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD:
122 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2:
123 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4:
124 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING:
125 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2:
126 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4:
127 lmr->drop();
128
129 // add remaining fixed function pipeline material renderers
130
131 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_DETAIL_MAP(pID3DDevice, this));
132 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_SPHERE_MAP(pID3DDevice, this));
133 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_REFLECTION_2_LAYER(pID3DDevice, this));
134 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR(pID3DDevice, this));
135 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(pID3DDevice, this));
136 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(pID3DDevice, this));
137 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(pID3DDevice, this));
138 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(pID3DDevice, this));
139
140 // add normal map renderers
141
142 s32 tmp = 0;
143 video::IMaterialRenderer* renderer = 0;
144
145 renderer = new CD3D9NormalMapRenderer(pID3DDevice, this, tmp,
146 MaterialRenderers[EMT_SOLID].Renderer);
147 renderer->drop();
148
149 renderer = new CD3D9NormalMapRenderer(pID3DDevice, this, tmp,
150 MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer);
151 renderer->drop();
152
153 renderer = new CD3D9NormalMapRenderer(pID3DDevice, this, tmp,
154 MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer);
155 renderer->drop();
156
157 // add parallax map renderers
158
159 renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp,
160 MaterialRenderers[EMT_SOLID].Renderer);
161 renderer->drop();
162
163 renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp,
164 MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer);
165 renderer->drop();
166
167 renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp,
168 MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer);
169 renderer->drop();
170
171 // add basic 1 texture blending
172 addAndDropMaterialRenderer(new CD3D9MaterialRenderer_ONETEXTURE_BLEND(pID3DDevice, this));
173}
174
175
176//! initialises the Direct3D API
177bool CD3D9Driver::initDriver(HWND hwnd, bool pureSoftware)
178{
179 if (!pID3D)
180 {
181 D3DLibrary = LoadLibrary( __TEXT("d3d9.dll") );
182
183 if (!D3DLibrary)
184 {
185 os::Printer::log("Error, could not load d3d9.dll.", ELL_ERROR);
186 return false;
187 }
188
189 typedef IDirect3D9 * (__stdcall *D3DCREATETYPE)(UINT);
190 D3DCREATETYPE d3dCreate = (D3DCREATETYPE) GetProcAddress(D3DLibrary, "Direct3DCreate9");
191
192 if (!d3dCreate)
193 {
194 os::Printer::log("Error, could not get proc adress of Direct3DCreate9.", ELL_ERROR);
195 return false;
196 }
197
198 //just like pID3D = Direct3DCreate9(D3D_SDK_VERSION);
199 pID3D = (*d3dCreate)(D3D_SDK_VERSION);
200
201 if (!pID3D)
202 {
203 os::Printer::log("Error initializing D3D.", ELL_ERROR);
204 return false;
205 }
206 }
207
208 // print device information
209 D3DADAPTER_IDENTIFIER9 dai;
210 if (!FAILED(pID3D->GetAdapterIdentifier(Params.DisplayAdapter, 0, &dai)))
211 {
212 char tmp[512];
213
214 s32 Product = HIWORD(dai.DriverVersion.HighPart);
215 s32 Version = LOWORD(dai.DriverVersion.HighPart);
216 s32 SubVersion = HIWORD(dai.DriverVersion.LowPart);
217 s32 Build = LOWORD(dai.DriverVersion.LowPart);
218
219 sprintf(tmp, "%s %s %d.%d.%d.%d", dai.Description, dai.Driver, Product, Version,
220 SubVersion, Build);
221 os::Printer::log(tmp, ELL_INFORMATION);
222
223 // Assign vendor name based on vendor id.
224 VendorID= static_cast<u16>(dai.VendorId);
225 switch(dai.VendorId)
226 {
227 case 0x1002 : VendorName = "ATI Technologies Inc."; break;
228 case 0x10DE : VendorName = "NVIDIA Corporation"; break;
229 case 0x102B : VendorName = "Matrox Electronic Systems Ltd."; break;
230 case 0x121A : VendorName = "3dfx Interactive Inc"; break;
231 case 0x5333 : VendorName = "S3 Graphics Co., Ltd."; break;
232 case 0x8086 : VendorName = "Intel Corporation"; break;
233 default: VendorName = "Unknown VendorId: ";VendorName += (u32)dai.VendorId; break;
234 }
235 }
236
237 D3DDISPLAYMODE d3ddm;
238 if (FAILED(pID3D->GetAdapterDisplayMode(Params.DisplayAdapter, &d3ddm)))
239 {
240 os::Printer::log("Error: Could not get Adapter Display mode.", ELL_ERROR);
241 return false;
242 }
243
244 ZeroMemory(&present, sizeof(present));
245
246 present.BackBufferCount = 1;
247 present.EnableAutoDepthStencil = TRUE;
248 if (Params.Vsync)
249 present.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
250 else
251 present.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
252
253 if (Params.Fullscreen)
254 {
255 present.BackBufferWidth = Params.WindowSize.Width;
256 present.BackBufferHeight = Params.WindowSize.Height;
257 // request 32bit mode if user specified 32 bit, added by Thomas Stuefe
258 if (Params.Bits == 32)
259 present.BackBufferFormat = D3DFMT_X8R8G8B8;
260 else
261 present.BackBufferFormat = D3DFMT_R5G6B5;
262 present.SwapEffect = D3DSWAPEFFECT_FLIP;
263 present.Windowed = FALSE;
264 present.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
265 }
266 else
267 {
268 present.BackBufferFormat = d3ddm.Format;
269 present.SwapEffect = D3DSWAPEFFECT_DISCARD;
270 present.Windowed = TRUE;
271 }
272
273 UINT adapter = Params.DisplayAdapter;
274 D3DDEVTYPE devtype = D3DDEVTYPE_HAL;
275 #ifndef _IRR_D3D_NO_SHADER_DEBUGGING
276 devtype = D3DDEVTYPE_REF;
277 #elif defined(_IRR_USE_NVIDIA_PERFHUD_)
278 for (UINT adapter_i = 0; adapter_i < pID3D->GetAdapterCount(); ++adapter_i)
279 {
280 D3DADAPTER_IDENTIFIER9 identifier;
281 pID3D->GetAdapterIdentifier(adapter_i,0,&identifier);
282 if (strstr(identifier.Description,"PerfHUD") != 0)
283 {
284 adapter = adapter_i;
285 devtype = D3DDEVTYPE_REF;
286 break;
287 }
288 }
289 #endif
290
291 // enable anti alias if possible and desired
292 if (Params.AntiAlias > 0)
293 {
294 if (Params.AntiAlias > 32)
295 Params.AntiAlias = 32;
296
297 DWORD qualityLevels = 0;
298
299 while(Params.AntiAlias > 0)
300 {
301 if(SUCCEEDED(pID3D->CheckDeviceMultiSampleType(adapter,
302 devtype, present.BackBufferFormat, !Params.Fullscreen,
303 (D3DMULTISAMPLE_TYPE)Params.AntiAlias, &qualityLevels)))
304 {
305 present.MultiSampleType = (D3DMULTISAMPLE_TYPE)Params.AntiAlias;
306 present.MultiSampleQuality = qualityLevels-1;
307 present.SwapEffect = D3DSWAPEFFECT_DISCARD;
308 break;
309 }
310 --Params.AntiAlias;
311 }
312
313 if (Params.AntiAlias==0)
314 {
315 os::Printer::log("Anti aliasing disabled because hardware/driver lacks necessary caps.", ELL_WARNING);
316 }
317 }
318
319 // check stencil buffer compatibility
320 if (Params.Stencilbuffer)
321 {
322 present.AutoDepthStencilFormat = D3DFMT_D24S8;
323 if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype,
324 present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
325 D3DRTYPE_SURFACE, present.AutoDepthStencilFormat)))
326 {
327 present.AutoDepthStencilFormat = D3DFMT_D24X4S4;
328 if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype,
329 present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
330 D3DRTYPE_SURFACE, present.AutoDepthStencilFormat)))
331 {
332 present.AutoDepthStencilFormat = D3DFMT_D15S1;
333 if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype,
334 present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
335 D3DRTYPE_SURFACE, present.AutoDepthStencilFormat)))
336 {
337 os::Printer::log("Device does not support stencilbuffer, disabling stencil buffer.", ELL_WARNING);
338 Params.Stencilbuffer = false;
339 }
340 }
341 }
342 else
343 if(FAILED(pID3D->CheckDepthStencilMatch(adapter, devtype,
344 present.BackBufferFormat, present.BackBufferFormat, present.AutoDepthStencilFormat)))
345 {
346 os::Printer::log("Depth-stencil format is not compatible with display format, disabling stencil buffer.", ELL_WARNING);
347 Params.Stencilbuffer = false;
348 }
349 }
350 // do not use else here to cope with flag change in previous block
351 if (!Params.Stencilbuffer)
352 {
353 present.AutoDepthStencilFormat = D3DFMT_D32;
354 if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype,
355 present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
356 D3DRTYPE_SURFACE, present.AutoDepthStencilFormat)))
357 {
358 present.AutoDepthStencilFormat = D3DFMT_D24X8;
359 if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype,
360 present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
361 D3DRTYPE_SURFACE, present.AutoDepthStencilFormat)))
362 {
363 present.AutoDepthStencilFormat = D3DFMT_D16;
364 if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype,
365 present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL,
366 D3DRTYPE_SURFACE, present.AutoDepthStencilFormat)))
367 {
368 os::Printer::log("Device does not support required depth buffer.", ELL_WARNING);
369 return false;
370 }
371 }
372 }
373 }
374
375 // create device
376
377 DWORD fpuPrecision = Params.HighPrecisionFPU ? D3DCREATE_FPU_PRESERVE : 0;
378 DWORD multithreaded = Params.DriverMultithreaded ? D3DCREATE_MULTITHREADED : 0;
379 if (pureSoftware)
380 {
381 if (FAILED(pID3D->CreateDevice(Params.DisplayAdapter, D3DDEVTYPE_REF, hwnd,
382 fpuPrecision | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice)))
383 os::Printer::log("Was not able to create Direct3D9 software device.", ELL_ERROR);
384 }
385 else
386 {
387 HRESULT hr = pID3D->CreateDevice(adapter, devtype, hwnd,
388 fpuPrecision | multithreaded | D3DCREATE_HARDWARE_VERTEXPROCESSING, &present, &pID3DDevice);
389
390 if(FAILED(hr))
391 hr = pID3D->CreateDevice(adapter, devtype, hwnd,
392 fpuPrecision | multithreaded | D3DCREATE_MIXED_VERTEXPROCESSING , &present, &pID3DDevice);
393
394 if(FAILED(hr))
395 hr = pID3D->CreateDevice(adapter, devtype, hwnd,
396 fpuPrecision | multithreaded | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice);
397
398 if (FAILED(hr))
399 os::Printer::log("Was not able to create Direct3D9 device.", ELL_ERROR);
400 }
401
402 if (!pID3DDevice)
403 {
404 os::Printer::log("Was not able to create DIRECT3D9 device.", ELL_ERROR);
405 return false;
406 }
407
408 // get caps
409 pID3DDevice->GetDeviceCaps(&Caps);
410
411 os::Printer::log("Currently available Video Memory (kB)", core::stringc(pID3DDevice->GetAvailableTextureMem()/1024).c_str());
412
413 // disable stencilbuffer if necessary
414 if (Params.Stencilbuffer &&
415 (!(Caps.StencilCaps & D3DSTENCILCAPS_DECRSAT) ||
416 !(Caps.StencilCaps & D3DSTENCILCAPS_INCRSAT) ||
417 !(Caps.StencilCaps & D3DSTENCILCAPS_KEEP)))
418 {
419 os::Printer::log("Device not able to use stencil buffer, disabling stencil buffer.", ELL_WARNING);
420 Params.Stencilbuffer = false;
421 }
422
423 // set default vertex shader
424 setVertexShader(EVT_STANDARD);
425
426 // set fog mode
427 setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);
428
429 // set exposed data
430 ExposedData.D3D9.D3D9 = pID3D;
431 ExposedData.D3D9.D3DDev9 = pID3DDevice;
432 ExposedData.D3D9.HWnd = hwnd;
433
434 ResetRenderStates = true;
435
436 // create materials
437 createMaterialRenderers();
438
439 MaxTextureUnits = core::min_((u32)Caps.MaxSimultaneousTextures, MATERIAL_MAX_TEXTURES);
440 MaxUserClipPlanes = (u32)Caps.MaxUserClipPlanes;
441 MaxMRTs = (s32)Caps.NumSimultaneousRTs;
442 OcclusionQuerySupport=(pID3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL) == S_OK);
443
444 if (VendorID==0x10DE)//NVidia
445 AlphaToCoverageSupport = (pID3D->CheckDeviceFormat(adapter, D3DDEVTYPE_HAL,
446 D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE,
447 (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK);
448 else if (VendorID==0x1002)//ATI
449 AlphaToCoverageSupport = true; // TODO: Check unknown
450#if 0
451 AlphaToCoverageSupport = (pID3D->CheckDeviceFormat(adapter, D3DDEVTYPE_HAL,
452 D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE,
453 (D3DFORMAT)MAKEFOURCC('A','2','M','1')) == S_OK);
454#endif
455
456 DriverAttributes->setAttribute("MaxTextures", (s32)MaxTextureUnits);
457 DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Caps.MaxSimultaneousTextures);
458 DriverAttributes->setAttribute("MaxLights", (s32)Caps.MaxActiveLights);
459 DriverAttributes->setAttribute("MaxAnisotropy", (s32)Caps.MaxAnisotropy);
460 DriverAttributes->setAttribute("MaxUserClipPlanes", (s32)Caps.MaxUserClipPlanes);
461 DriverAttributes->setAttribute("MaxMultipleRenderTargets", (s32)Caps.NumSimultaneousRTs);
462 DriverAttributes->setAttribute("MaxIndices", (s32)Caps.MaxVertexIndex);
463 DriverAttributes->setAttribute("MaxTextureSize", (s32)core::min_(Caps.MaxTextureHeight,Caps.MaxTextureWidth));
464 DriverAttributes->setAttribute("MaxTextureLODBias", 16);
465 DriverAttributes->setAttribute("Version", 901);
466 DriverAttributes->setAttribute("ShaderLanguageVersion", (s32)(((0x00ff00 & Caps.VertexShaderVersion)>>8)*100 + (Caps.VertexShaderVersion&0xff)));
467 DriverAttributes->setAttribute("AntiAlias", Params.AntiAlias);
468
469 // set the renderstates
470 setRenderStates3DMode();
471
472 // store the screen's depth buffer
473 DepthBuffers.push_back(new SDepthSurface());
474 if (SUCCEEDED(pID3DDevice->GetDepthStencilSurface(&(DepthBuffers[0]->Surface))))
475 {
476 D3DSURFACE_DESC desc;
477 DepthBuffers[0]->Surface->GetDesc(&desc);
478 DepthBuffers[0]->Size.set(desc.Width, desc.Height);
479 }
480 else
481 {
482 os::Printer::log("Was not able to get main depth buffer.", ELL_ERROR);
483 return false;
484 }
485
486 D3DColorFormat = D3DFMT_A8R8G8B8;
487 IDirect3DSurface9* bb=0;
488 if (SUCCEEDED(pID3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &bb)))
489 {
490 D3DSURFACE_DESC desc;
491 bb->GetDesc(&desc);
492 D3DColorFormat = desc.Format;
493
494 if (D3DColorFormat == D3DFMT_X8R8G8B8)
495 D3DColorFormat = D3DFMT_A8R8G8B8;
496
497 bb->Release();
498 }
499 ColorFormat = getColorFormatFromD3DFormat(D3DColorFormat);
500
501 #ifdef _IRR_COMPILE_WITH_CG_
502 CgContext = cgCreateContext();
503 cgD3D9SetDevice(pID3DDevice);
504 #endif
505
506 // so far so good.
507 return true;
508}
509
510
511//! applications must call this method before performing any rendering. returns false if failed.
512bool CD3D9Driver::beginScene(bool backBuffer, bool zBuffer, SColor color,
513 const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
514{
515 CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect);
516 WindowId = (HWND)videoData.D3D9.HWnd;
517 SceneSourceRect = sourceRect;
518
519 if (!pID3DDevice)
520 return false;
521
522 HRESULT hr;
523 if (DeviceLost)
524 {
525 if (FAILED(hr = pID3DDevice->TestCooperativeLevel()))
526 {
527 if (hr == D3DERR_DEVICELOST)
528 {
529 Sleep(100);
530 hr = pID3DDevice->TestCooperativeLevel();
531 if (hr == D3DERR_DEVICELOST)
532 return false;
533 }
534
535 if ((hr == D3DERR_DEVICENOTRESET) && !reset())
536 return false;
537 }
538 }
539
540 DWORD flags = 0;
541
542 if (backBuffer)
543 flags |= D3DCLEAR_TARGET;
544
545 if (zBuffer)
546 flags |= D3DCLEAR_ZBUFFER;
547
548 if (Params.Stencilbuffer)
549 flags |= D3DCLEAR_STENCIL;
550
551 if (flags)
552 {
553 hr = pID3DDevice->Clear( 0, NULL, flags, color.color, 1.0, 0);
554 if (FAILED(hr))
555 os::Printer::log("DIRECT3D9 clear failed.", ELL_WARNING);
556 }
557
558 hr = pID3DDevice->BeginScene();
559 if (FAILED(hr))
560 {
561 os::Printer::log("DIRECT3D9 begin scene failed.", ELL_WARNING);
562 return false;
563 }
564
565 return true;
566}
567
568
569//! applications must call this method after performing any rendering. returns false if failed.
570bool CD3D9Driver::endScene()
571{
572 CNullDriver::endScene();
573 DriverWasReset=false;
574
575 HRESULT hr = pID3DDevice->EndScene();
576 if (FAILED(hr))
577 {
578 os::Printer::log("DIRECT3D9 end scene failed.", ELL_WARNING);
579 return false;
580 }
581
582 RECT* srcRct = 0;
583 RECT sourceRectData;
584 if ( SceneSourceRect )
585 {
586 srcRct = &sourceRectData;
587 sourceRectData.left = SceneSourceRect->UpperLeftCorner.X;
588 sourceRectData.top = SceneSourceRect->UpperLeftCorner.Y;
589 sourceRectData.right = SceneSourceRect->LowerRightCorner.X;
590 sourceRectData.bottom = SceneSourceRect->LowerRightCorner.Y;
591 }
592
593 IDirect3DSwapChain9* swChain;
594 hr = pID3DDevice->GetSwapChain(0, &swChain);
595 DWORD flags = (Params.HandleSRGB && (Caps.Caps3&D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION))?D3DPRESENT_LINEAR_CONTENT:0;
596 hr = swChain->Present(srcRct, NULL, WindowId, NULL, flags);
597 swChain->Release();
598
599 if (SUCCEEDED(hr))
600 return true;
601
602 if (hr == D3DERR_DEVICELOST)
603 {
604 DeviceLost = true;
605 os::Printer::log("Present failed", "DIRECT3D9 device lost.", ELL_WARNING);
606 }
607#ifdef D3DERR_DEVICEREMOVED
608 else if (hr == D3DERR_DEVICEREMOVED)
609 {
610 os::Printer::log("Present failed", "Device removed.", ELL_WARNING);
611 }
612#endif
613 else if (hr == D3DERR_INVALIDCALL)
614 {
615 os::Printer::log("Present failed", "Invalid Call", ELL_WARNING);
616 }
617 else
618 os::Printer::log("DIRECT3D9 present failed.", ELL_WARNING);
619 return false;
620}
621
622
623//! queries the features of the driver, returns true if feature is available
624bool CD3D9Driver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
625{
626 if (!FeatureEnabled[feature])
627 return false;
628
629 switch (feature)
630 {
631 case EVDF_MULTITEXTURE:
632 case EVDF_BILINEAR_FILTER:
633 return true;
634 case EVDF_RENDER_TO_TARGET:
635 return Caps.NumSimultaneousRTs > 0;
636 case EVDF_HARDWARE_TL:
637 return (Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0;
638 case EVDF_MIP_MAP:
639 return (Caps.TextureCaps & D3DPTEXTURECAPS_MIPMAP) != 0;
640 case EVDF_MIP_MAP_AUTO_UPDATE:
641 // always return false because a lot of drivers claim they do
642 // this but actually don't do this at all.
643 return false; //(Caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0;
644 case EVDF_STENCIL_BUFFER:
645 return Params.Stencilbuffer && Caps.StencilCaps;
646 case EVDF_VERTEX_SHADER_1_1:
647 return Caps.VertexShaderVersion >= D3DVS_VERSION(1,1);
648 case EVDF_VERTEX_SHADER_2_0:
649 return Caps.VertexShaderVersion >= D3DVS_VERSION(2,0);
650 case EVDF_VERTEX_SHADER_3_0:
651 return Caps.VertexShaderVersion >= D3DVS_VERSION(3,0);
652 case EVDF_PIXEL_SHADER_1_1:
653 return Caps.PixelShaderVersion >= D3DPS_VERSION(1,1);
654 case EVDF_PIXEL_SHADER_1_2:
655 return Caps.PixelShaderVersion >= D3DPS_VERSION(1,2);
656 case EVDF_PIXEL_SHADER_1_3:
657 return Caps.PixelShaderVersion >= D3DPS_VERSION(1,3);
658 case EVDF_PIXEL_SHADER_1_4:
659 return Caps.PixelShaderVersion >= D3DPS_VERSION(1,4);
660 case EVDF_PIXEL_SHADER_2_0:
661 return Caps.PixelShaderVersion >= D3DPS_VERSION(2,0);
662 case EVDF_PIXEL_SHADER_3_0:
663 return Caps.PixelShaderVersion >= D3DPS_VERSION(3,0);
664 case EVDF_HLSL:
665 return Caps.VertexShaderVersion >= D3DVS_VERSION(1,1);
666 case EVDF_TEXTURE_NSQUARE:
667 return (Caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) == 0;
668 case EVDF_TEXTURE_NPOT:
669 return (Caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0;
670 case EVDF_COLOR_MASK:
671 return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0;
672 case EVDF_MULTIPLE_RENDER_TARGETS:
673 return Caps.NumSimultaneousRTs > 1;
674 case EVDF_MRT_COLOR_MASK:
675 return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_INDEPENDENTWRITEMASKS) != 0;
676 case EVDF_MRT_BLEND:
677 return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) != 0;
678 case EVDF_OCCLUSION_QUERY:
679 return OcclusionQuerySupport;
680 case EVDF_POLYGON_OFFSET:
681 return (Caps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS|D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) != 0;
682 case EVDF_BLEND_OPERATIONS:
683 case EVDF_TEXTURE_MATRIX:
684#ifdef _IRR_COMPILE_WITH_CG_
685 // available iff. define is present
686 case EVDF_CG:
687#endif
688 return true;
689 default:
690 return false;
691 };
692}
693
694
695//! sets transformation
696void CD3D9Driver::setTransform(E_TRANSFORMATION_STATE state,
697 const core::matrix4& mat)
698{
699 Transformation3DChanged = true;
700
701 switch(state)
702 {
703 case ETS_VIEW:
704 pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)mat.pointer()));
705 break;
706 case ETS_WORLD:
707 pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer()));
708 break;
709 case ETS_PROJECTION:
710 pID3DDevice->SetTransform( D3DTS_PROJECTION, (D3DMATRIX*)((void*)mat.pointer()));
711 break;
712 case ETS_COUNT:
713 return;
714 default:
715 if (state-ETS_TEXTURE_0 < MATERIAL_MAX_TEXTURES)
716 {
717 if (mat.isIdentity())
718 pID3DDevice->SetTextureStageState( state - ETS_TEXTURE_0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
719 else
720 {
721 pID3DDevice->SetTextureStageState( state - ETS_TEXTURE_0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
722 pID3DDevice->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+ ( state - ETS_TEXTURE_0 )),
723 (D3DMATRIX*)((void*)mat.pointer()));
724 }
725 }
726 break;
727 }
728
729 Matrices[state] = mat;
730}
731
732
733//! sets the current Texture
734bool CD3D9Driver::setActiveTexture(u32 stage, const video::ITexture* texture)
735{
736 if (CurrentTexture[stage] == texture)
737 return true;
738
739 if (texture && texture->getDriverType() != EDT_DIRECT3D9)
740 {
741 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
742 return false;
743 }
744
745 CurrentTexture[stage] = texture;
746
747 if (!texture)
748 {
749 pID3DDevice->SetTexture(stage, 0);
750 pID3DDevice->SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
751 }
752 else
753 {
754 pID3DDevice->SetTexture(stage, ((const CD3D9Texture*)texture)->getDX9Texture());
755 }
756 return true;
757}
758
759
760//! sets a material
761void CD3D9Driver::setMaterial(const SMaterial& material)
762{
763 Material = material;
764 OverrideMaterial.apply(Material);
765
766 for (u32 i=0; i<MaxTextureUnits; ++i)
767 {
768 setActiveTexture(i, Material.getTexture(i));
769 setTransform((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ),
770 material.getTextureMatrix(i));
771 }
772}
773
774
775//! returns a device dependent texture from a software surface (IImage)
776video::ITexture* CD3D9Driver::createDeviceDependentTexture(IImage* surface,const io::path& name, void* mipmapData)
777{
778 return new CD3D9Texture(surface, this, TextureCreationFlags, name, mipmapData);
779}
780
781
782//! Enables or disables a texture creation flag.
783void CD3D9Driver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag,
784 bool enabled)
785{
786 if (flag == video::ETCF_CREATE_MIP_MAPS && !queryFeature(EVDF_MIP_MAP))
787 enabled = false;
788
789 CNullDriver::setTextureCreationFlag(flag, enabled);
790}
791
792
793//! sets a render target
794bool CD3D9Driver::setRenderTarget(video::ITexture* texture,
795 bool clearBackBuffer, bool clearZBuffer, SColor color)
796{
797 // check for right driver type
798
799 if (texture && texture->getDriverType() != EDT_DIRECT3D9)
800 {
801 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
802 return false;
803 }
804
805 // check for valid render target
806
807 if (texture && !texture->isRenderTarget())
808 {
809 os::Printer::log("Fatal Error: Tried to set a non render target texture as render target.", ELL_ERROR);
810 return false;
811 }
812
813 CD3D9Texture* tex = static_cast<CD3D9Texture*>(texture);
814
815 // check if we should set the previous RT back
816
817 bool ret = true;
818
819 for(u32 i = 1; i < NumSetMRTs; i++)
820 {
821 // First texture handled elsewhere
822 pID3DDevice->SetRenderTarget(i, NULL);
823 }
824 if (tex == 0)
825 {
826 if (PrevRenderTarget)
827 {
828 if (FAILED(pID3DDevice->SetRenderTarget(0, PrevRenderTarget)))
829 {
830 os::Printer::log("Error: Could not set back to previous render target.", ELL_ERROR);
831 ret = false;
832 }
833 if (FAILED(pID3DDevice->SetDepthStencilSurface(DepthBuffers[0]->Surface)))
834 {
835 os::Printer::log("Error: Could not set main depth buffer.", ELL_ERROR);
836 }
837
838 CurrentRendertargetSize = core::dimension2d<u32>(0,0);
839 PrevRenderTarget->Release();
840 PrevRenderTarget = 0;
841 }
842 }
843 else
844 {
845 // we want to set a new target. so do this.
846
847 // store previous target
848
849 if (!PrevRenderTarget)
850 {
851 if (FAILED(pID3DDevice->GetRenderTarget(0, &PrevRenderTarget)))
852 {
853 os::Printer::log("Could not get previous render target.", ELL_ERROR);
854 return false;
855 }
856 }
857
858 // set new render target
859
860 if (FAILED(pID3DDevice->SetRenderTarget(0, tex->getRenderTargetSurface())))
861 {
862 os::Printer::log("Error: Could not set render target.", ELL_ERROR);
863 return false;
864 }
865 CurrentRendertargetSize = tex->getSize();
866
867 if (FAILED(pID3DDevice->SetDepthStencilSurface(tex->DepthSurface->Surface)))
868 {
869 os::Printer::log("Error: Could not set new depth buffer.", ELL_ERROR);
870 }
871 }
872 Transformation3DChanged=true;
873
874 if (clearBackBuffer || clearZBuffer)
875 {
876 DWORD flags = 0;
877
878 if (clearBackBuffer)
879 flags |= D3DCLEAR_TARGET;
880
881 if (clearZBuffer)
882 flags |= D3DCLEAR_ZBUFFER;
883
884 pID3DDevice->Clear(0, NULL, flags, color.color, 1.0f, 0);
885 }
886
887 return ret;
888}
889
890
891//! Sets multiple render targets
892bool CD3D9Driver::setRenderTarget(const core::array<video::IRenderTarget>& targets,
893 bool clearBackBuffer, bool clearZBuffer, SColor color)
894{
895 if (targets.size()==0)
896 return setRenderTarget(0, clearBackBuffer, clearZBuffer, color);
897
898 u32 maxMultipleRTTs = core::min_(MaxMRTs, targets.size());
899
900 for (u32 i = 0; i < maxMultipleRTTs; ++i)
901 {
902 if (targets[i].TargetType != ERT_RENDER_TEXTURE || !targets[i].RenderTexture)
903 {
904 maxMultipleRTTs = i;
905 os::Printer::log("Missing texture for MRT.", ELL_WARNING);
906 break;
907 }
908
909 // check for right driver type
910
911 if (targets[i].RenderTexture->getDriverType() != EDT_DIRECT3D9)
912 {
913 maxMultipleRTTs = i;
914 os::Printer::log("Tried to set a texture not owned by this driver.", ELL_WARNING);
915 break;
916 }
917
918 // check for valid render target
919
920 if (!targets[i].RenderTexture->isRenderTarget())
921 {
922 maxMultipleRTTs = i;
923 os::Printer::log("Tried to set a non render target texture as render target.", ELL_WARNING);
924 break;
925 }
926
927 // check for valid size
928
929 if (targets[0].RenderTexture->getSize() != targets[i].RenderTexture->getSize())
930 {
931 maxMultipleRTTs = i;
932 os::Printer::log("Render target texture has wrong size.", ELL_WARNING);
933 break;
934 }
935 }
936 if (maxMultipleRTTs==0)
937 {
938 os::Printer::log("Fatal Error: No valid MRT found.", ELL_ERROR);
939 return false;
940 }
941
942 CD3D9Texture* tex = static_cast<CD3D9Texture*>(targets[0].RenderTexture);
943
944 // check if we should set the previous RT back
945
946 bool ret = true;
947
948 // we want to set a new target. so do this.
949 // store previous target
950
951 if (!PrevRenderTarget)
952 {
953 if (FAILED(pID3DDevice->GetRenderTarget(0, &PrevRenderTarget)))
954 {
955 os::Printer::log("Could not get previous render target.", ELL_ERROR);
956 return false;
957 }
958 }
959
960 // set new render target
961
962 // In d3d9 we have at most 4 MRTs, so the following is enough
963 D3DRENDERSTATETYPE colorWrite[4]={D3DRS_COLORWRITEENABLE, D3DRS_COLORWRITEENABLE1, D3DRS_COLORWRITEENABLE2, D3DRS_COLORWRITEENABLE3};
964 for (u32 i = 0; i < maxMultipleRTTs; ++i)
965 {
966 if (FAILED(pID3DDevice->SetRenderTarget(i, static_cast<CD3D9Texture*>(targets[i].RenderTexture)->getRenderTargetSurface())))
967 {
968 os::Printer::log("Error: Could not set render target.", ELL_ERROR);
969 return false;
970 }
971 if (i<4 && (i==0 || queryFeature(EVDF_MRT_COLOR_MASK)))
972 {
973 const DWORD flag =
974 ((targets[i].ColorMask & ECP_RED)?D3DCOLORWRITEENABLE_RED:0) |
975 ((targets[i].ColorMask & ECP_GREEN)?D3DCOLORWRITEENABLE_GREEN:0) |
976 ((targets[i].ColorMask & ECP_BLUE)?D3DCOLORWRITEENABLE_BLUE:0) |
977 ((targets[i].ColorMask & ECP_ALPHA)?D3DCOLORWRITEENABLE_ALPHA:0);
978 pID3DDevice->SetRenderState(colorWrite[i], flag);
979 }
980 }
981 for(u32 i = maxMultipleRTTs; i < NumSetMRTs; i++)
982 {
983 pID3DDevice->SetRenderTarget(i, NULL);
984 }
985 NumSetMRTs=maxMultipleRTTs;
986
987 CurrentRendertargetSize = tex->getSize();
988
989 if (FAILED(pID3DDevice->SetDepthStencilSurface(tex->DepthSurface->Surface)))
990 {
991 os::Printer::log("Error: Could not set new depth buffer.", ELL_ERROR);
992 }
993
994 if (clearBackBuffer || clearZBuffer)
995 {
996 DWORD flags = 0;
997
998 if (clearBackBuffer)
999 flags |= D3DCLEAR_TARGET;
1000
1001 if (clearZBuffer)
1002 flags |= D3DCLEAR_ZBUFFER;
1003
1004 pID3DDevice->Clear(0, NULL, flags, color.color, 1.0f, 0);
1005 }
1006
1007 return ret;
1008}
1009
1010
1011//! sets a viewport
1012void CD3D9Driver::setViewPort(const core::rect<s32>& area)
1013{
1014 core::rect<s32> vp = area;
1015 core::rect<s32> rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);
1016 vp.clipAgainst(rendert);
1017 if (vp.getHeight()>0 && vp.getWidth()>0)
1018 {
1019 D3DVIEWPORT9 viewPort;
1020 viewPort.X = vp.UpperLeftCorner.X;
1021 viewPort.Y = vp.UpperLeftCorner.Y;
1022 viewPort.Width = vp.getWidth();
1023 viewPort.Height = vp.getHeight();
1024 viewPort.MinZ = 0.0f;
1025 viewPort.MaxZ = 1.0f;
1026
1027 HRESULT hr = pID3DDevice->SetViewport(&viewPort);
1028 if (FAILED(hr))
1029 os::Printer::log("Failed setting the viewport.", ELL_WARNING);
1030 else
1031 ViewPort = vp;
1032 }
1033}
1034
1035
1036//! gets the area of the current viewport
1037const core::rect<s32>& CD3D9Driver::getViewPort() const
1038{
1039 return ViewPort;
1040}
1041
1042
1043bool CD3D9Driver::updateVertexHardwareBuffer(SHWBufferLink_d3d9 *hwBuffer)
1044{
1045 if (!hwBuffer)
1046 return false;
1047
1048 const scene::IMeshBuffer* mb = hwBuffer->MeshBuffer;
1049 const void* vertices=mb->getVertices();
1050 const u32 vertexCount=mb->getVertexCount();
1051 const E_VERTEX_TYPE vType=mb->getVertexType();
1052 const u32 vertexSize = getVertexPitchFromType(vType);
1053 const u32 bufSize = vertexSize * vertexCount;
1054
1055 if (!hwBuffer->vertexBuffer || (bufSize > hwBuffer->vertexBufferSize))
1056 {
1057 if (hwBuffer->vertexBuffer)
1058 {
1059 hwBuffer->vertexBuffer->Release();
1060 hwBuffer->vertexBuffer=0;
1061 }
1062
1063 DWORD FVF;
1064 // Get the vertex sizes and cvf
1065 switch (vType)
1066 {
1067 case EVT_STANDARD:
1068 FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
1069 break;
1070 case EVT_2TCOORDS:
1071 FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX2;
1072 break;
1073 case EVT_TANGENTS:
1074 FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX3;
1075 break;
1076 default:
1077 return false;
1078 }
1079
1080 DWORD flags = D3DUSAGE_WRITEONLY; // SIO2: Default to D3DUSAGE_WRITEONLY
1081 if (hwBuffer->Mapped_Vertex != scene::EHM_STATIC)
1082 flags |= D3DUSAGE_DYNAMIC;
1083
1084 if (FAILED(pID3DDevice->CreateVertexBuffer(bufSize, flags, FVF, D3DPOOL_DEFAULT, &hwBuffer->vertexBuffer, NULL)))
1085 return false;
1086 hwBuffer->vertexBufferSize = bufSize;
1087
1088 flags = 0; // SIO2: Reset flags before Lock
1089 if (hwBuffer->Mapped_Vertex != scene::EHM_STATIC)
1090 flags = D3DLOCK_DISCARD;
1091
1092 void* lockedBuffer = 0;
1093 hwBuffer->vertexBuffer->Lock(0, bufSize, (void**)&lockedBuffer, flags);
1094 memcpy(lockedBuffer, vertices, bufSize);
1095 hwBuffer->vertexBuffer->Unlock();
1096 }
1097 else
1098 {
1099 void* lockedBuffer = 0;
1100 hwBuffer->vertexBuffer->Lock(0, bufSize, (void**)&lockedBuffer, D3DLOCK_DISCARD);
1101 memcpy(lockedBuffer, vertices, bufSize);
1102 hwBuffer->vertexBuffer->Unlock();
1103 }
1104
1105 return true;
1106}
1107
1108
1109bool CD3D9Driver::updateIndexHardwareBuffer(SHWBufferLink_d3d9 *hwBuffer)
1110{
1111 if (!hwBuffer)
1112 return false;
1113
1114 const scene::IMeshBuffer* mb = hwBuffer->MeshBuffer;
1115 const u16* indices=mb->getIndices();
1116 const u32 indexCount=mb->getIndexCount();
1117 u32 indexSize = 2;
1118 D3DFORMAT indexType=D3DFMT_UNKNOWN;
1119 switch (mb->getIndexType())
1120 {
1121 case EIT_16BIT:
1122 {
1123 indexType=D3DFMT_INDEX16;
1124 indexSize = 2;
1125 break;
1126 }
1127 case EIT_32BIT:
1128 {
1129 indexType=D3DFMT_INDEX32;
1130 indexSize = 4;
1131 break;
1132 }
1133 }
1134
1135 const u32 bufSize = indexSize * indexCount;
1136 if (!hwBuffer->indexBuffer || (bufSize > hwBuffer->indexBufferSize))
1137 {
1138 if (hwBuffer->indexBuffer)
1139 {
1140 hwBuffer->indexBuffer->Release();
1141 hwBuffer->indexBuffer=0;
1142 }
1143
1144 DWORD flags = D3DUSAGE_WRITEONLY; // SIO2: Default to D3DUSAGE_WRITEONLY
1145 if (hwBuffer->Mapped_Index != scene::EHM_STATIC)
1146 flags |= D3DUSAGE_DYNAMIC; // SIO2: Add DYNAMIC flag for dynamic buffer data
1147
1148 if (FAILED(pID3DDevice->CreateIndexBuffer(bufSize, flags, indexType, D3DPOOL_DEFAULT, &hwBuffer->indexBuffer, NULL)))
1149 return false;
1150
1151 flags = 0; // SIO2: Reset flags before Lock
1152 if (hwBuffer->Mapped_Index != scene::EHM_STATIC)
1153 flags = D3DLOCK_DISCARD;
1154
1155 void* lockedBuffer = 0;
1156 if (FAILED(hwBuffer->indexBuffer->Lock( 0, 0, (void**)&lockedBuffer, flags)))
1157 return false;
1158
1159 memcpy(lockedBuffer, indices, bufSize);
1160 hwBuffer->indexBuffer->Unlock();
1161
1162 hwBuffer->indexBufferSize = bufSize;
1163 }
1164 else
1165 {
1166 void* lockedBuffer = 0;
1167 if( SUCCEEDED(hwBuffer->indexBuffer->Lock( 0, 0, (void**)&lockedBuffer, D3DLOCK_DISCARD)))
1168 {
1169 memcpy(lockedBuffer, indices, bufSize);
1170 hwBuffer->indexBuffer->Unlock();
1171 }
1172 }
1173
1174 return true;
1175}
1176
1177
1178//! updates hardware buffer if needed
1179bool CD3D9Driver::updateHardwareBuffer(SHWBufferLink *hwBuffer)
1180{
1181 if (!hwBuffer)
1182 return false;
1183
1184 if (hwBuffer->Mapped_Vertex!=scene::EHM_NEVER)
1185 {
1186 if (hwBuffer->ChangedID_Vertex != hwBuffer->MeshBuffer->getChangedID_Vertex()
1187 || !((SHWBufferLink_d3d9*)hwBuffer)->vertexBuffer)
1188 {
1189 hwBuffer->ChangedID_Vertex = hwBuffer->MeshBuffer->getChangedID_Vertex();
1190
1191 if (!updateVertexHardwareBuffer((SHWBufferLink_d3d9*)hwBuffer))
1192 return false;
1193 }
1194 }
1195
1196 if (hwBuffer->Mapped_Index!=scene::EHM_NEVER)
1197 {
1198 if (hwBuffer->ChangedID_Index != hwBuffer->MeshBuffer->getChangedID_Index()
1199 || !((SHWBufferLink_d3d9*)hwBuffer)->indexBuffer)
1200 {
1201 hwBuffer->ChangedID_Index = hwBuffer->MeshBuffer->getChangedID_Index();
1202
1203 if (!updateIndexHardwareBuffer((SHWBufferLink_d3d9*)hwBuffer))
1204 return false;
1205 }
1206 }
1207
1208 return true;
1209}
1210
1211
1212//! Create hardware buffer from meshbuffer
1213CD3D9Driver::SHWBufferLink *CD3D9Driver::createHardwareBuffer(const scene::IMeshBuffer* mb)
1214{
1215 // Looks like d3d does not support only partial buffering, so refuse
1216 // in any case of NEVER
1217 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER || mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
1218 return 0;
1219
1220 SHWBufferLink_d3d9 *hwBuffer=new SHWBufferLink_d3d9(mb);
1221
1222 //add to map
1223 HWBufferMap.insert(hwBuffer->MeshBuffer, hwBuffer);
1224
1225 hwBuffer->ChangedID_Vertex=hwBuffer->MeshBuffer->getChangedID_Vertex();
1226 hwBuffer->ChangedID_Index=hwBuffer->MeshBuffer->getChangedID_Index();
1227 hwBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex();
1228 hwBuffer->Mapped_Index=mb->getHardwareMappingHint_Index();
1229 hwBuffer->LastUsed=0;
1230 hwBuffer->vertexBuffer=0;
1231 hwBuffer->indexBuffer=0;
1232 hwBuffer->vertexBufferSize=0;
1233 hwBuffer->indexBufferSize=0;
1234
1235 if (!updateHardwareBuffer(hwBuffer))
1236 {
1237 deleteHardwareBuffer(hwBuffer);
1238 return 0;
1239 }
1240
1241 return hwBuffer;
1242}
1243
1244
1245void CD3D9Driver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer)
1246{
1247 if (!_HWBuffer)
1248 return;
1249
1250 SHWBufferLink_d3d9 *HWBuffer=(SHWBufferLink_d3d9*)_HWBuffer;
1251 if (HWBuffer->indexBuffer)
1252 {
1253 HWBuffer->indexBuffer->Release();
1254 HWBuffer->indexBuffer = 0;
1255 }
1256
1257 if (HWBuffer->vertexBuffer)
1258 {
1259 HWBuffer->vertexBuffer->Release();
1260 HWBuffer->vertexBuffer = 0;
1261 }
1262
1263 CNullDriver::deleteHardwareBuffer(_HWBuffer);
1264}
1265
1266
1267//! Draw hardware buffer
1268void CD3D9Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)
1269{
1270 if (!_HWBuffer)
1271 return;
1272
1273 SHWBufferLink_d3d9 *HWBuffer=(SHWBufferLink_d3d9*)_HWBuffer;
1274
1275 updateHardwareBuffer(HWBuffer); //check if update is needed
1276
1277 HWBuffer->LastUsed=0;//reset count
1278
1279 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
1280 const E_VERTEX_TYPE vType = mb->getVertexType();
1281 const u32 stride = getVertexPitchFromType(vType);
1282 const void* vPtr = mb->getVertices();
1283 const void* iPtr = mb->getIndices();
1284 if (HWBuffer->vertexBuffer)
1285 {
1286 pID3DDevice->SetStreamSource(0, HWBuffer->vertexBuffer, 0, stride);
1287 vPtr=0;
1288 }
1289 if (HWBuffer->indexBuffer)
1290 {
1291 pID3DDevice->SetIndices(HWBuffer->indexBuffer);
1292 iPtr=0;
1293 }
1294
1295 drawVertexPrimitiveList(vPtr, mb->getVertexCount(), iPtr, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType());
1296
1297 if (HWBuffer->vertexBuffer)
1298 pID3DDevice->SetStreamSource(0, 0, 0, 0);
1299 if (HWBuffer->indexBuffer)
1300 pID3DDevice->SetIndices(0);
1301}
1302
1303
1304//! Create occlusion query.
1305/** Use node for identification and mesh for occlusion test. */
1306void CD3D9Driver::addOcclusionQuery(scene::ISceneNode* node,
1307 const scene::IMesh* mesh)
1308{
1309 if (!queryFeature(EVDF_OCCLUSION_QUERY))
1310 return;
1311 CNullDriver::addOcclusionQuery(node, mesh);
1312 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1313 if ((index != -1) && (OcclusionQueries[index].PID == 0))
1314 pID3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, reinterpret_cast<IDirect3DQuery9**>(&OcclusionQueries[index].PID));
1315}
1316
1317
1318//! Remove occlusion query.
1319void CD3D9Driver::removeOcclusionQuery(scene::ISceneNode* node)
1320{
1321 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1322 if (index != -1)
1323 {
1324 if (OcclusionQueries[index].PID != 0)
1325 reinterpret_cast<IDirect3DQuery9*>(OcclusionQueries[index].PID)->Release();
1326 CNullDriver::removeOcclusionQuery(node);
1327 }
1328}
1329
1330
1331//! Run occlusion query. Draws mesh stored in query.
1332/** If the mesh shall not be rendered visible, use
1333overrideMaterial to disable the color and depth buffer. */
1334void CD3D9Driver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
1335{
1336 if (!node)
1337 return;
1338
1339 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1340 if (index != -1)
1341 {
1342 if (OcclusionQueries[index].PID)
1343 reinterpret_cast<IDirect3DQuery9*>(OcclusionQueries[index].PID)->Issue(D3DISSUE_BEGIN);
1344 CNullDriver::runOcclusionQuery(node,visible);
1345 if (OcclusionQueries[index].PID)
1346 reinterpret_cast<IDirect3DQuery9*>(OcclusionQueries[index].PID)->Issue(D3DISSUE_END);
1347 }
1348}
1349
1350
1351//! Update occlusion query. Retrieves results from GPU.
1352/** If the query shall not block, set the flag to false.
1353Update might not occur in this case, though */
1354void CD3D9Driver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
1355{
1356 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1357 if (index != -1)
1358 {
1359 // not yet started
1360 if (OcclusionQueries[index].Run==u32(~0))
1361 return;
1362 bool available = block?true:false;
1363 int tmp=0;
1364 if (!block)
1365 available=(reinterpret_cast<IDirect3DQuery9*>(OcclusionQueries[index].PID)->GetData(&tmp, sizeof(DWORD), 0)==S_OK);
1366 else
1367 {
1368 do
1369 {
1370 HRESULT hr = reinterpret_cast<IDirect3DQuery9*>(OcclusionQueries[index].PID)->GetData(&tmp, sizeof(DWORD), D3DGETDATA_FLUSH);
1371 available = (hr == S_OK);
1372 if (hr!=S_FALSE)
1373 break;
1374 } while (!available);
1375 }
1376 if (available)
1377 OcclusionQueries[index].Result = tmp;
1378 }
1379}
1380
1381
1382//! Return query result.
1383/** Return value is the number of visible pixels/fragments.
1384The value is a safe approximation, i.e. can be larger than the
1385actual value of pixels. */
1386u32 CD3D9Driver::getOcclusionQueryResult(scene::ISceneNode* node) const
1387{
1388 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1389 if (index != -1)
1390 return OcclusionQueries[index].Result;
1391 else
1392 return ~0;
1393}
1394
1395
1396//! draws a vertex primitive list
1397void CD3D9Driver::drawVertexPrimitiveList(const void* vertices,
1398 u32 vertexCount, const void* indexList, u32 primitiveCount,
1399 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
1400 E_INDEX_TYPE iType)
1401{
1402 if (!checkPrimitiveCount(primitiveCount))
1403 return;
1404
1405 CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType,iType);
1406
1407 if (!vertexCount || !primitiveCount)
1408 return;
1409
1410 draw2D3DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount,
1411 vType, pType, iType, true);
1412}
1413
1414
1415//! draws a vertex primitive list
1416void CD3D9Driver::draw2DVertexPrimitiveList(const void* vertices,
1417 u32 vertexCount, const void* indexList, u32 primitiveCount,
1418 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
1419 E_INDEX_TYPE iType)
1420{
1421 if (!checkPrimitiveCount(primitiveCount))
1422 return;
1423
1424 CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType,iType);
1425
1426 if (!vertexCount || !primitiveCount)
1427 return;
1428
1429 draw2D3DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount,
1430 vType, pType, iType, false);
1431}
1432
1433
1434void CD3D9Driver::draw2D3DVertexPrimitiveList(const void* vertices,
1435 u32 vertexCount, const void* indexList, u32 primitiveCount,
1436 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
1437 E_INDEX_TYPE iType, bool is3D)
1438{
1439 setVertexShader(vType);
1440
1441 const u32 stride = getVertexPitchFromType(vType);
1442
1443 D3DFORMAT indexType=D3DFMT_UNKNOWN;
1444 switch (iType)
1445 {
1446 case (EIT_16BIT):
1447 {
1448 indexType=D3DFMT_INDEX16;
1449 break;
1450 }
1451 case (EIT_32BIT):
1452 {
1453 indexType=D3DFMT_INDEX32;
1454 break;
1455 }
1456 }
1457
1458 if (is3D)
1459 {
1460 if (!setRenderStates3DMode())
1461 return;
1462 }
1463 else
1464 {
1465 if (Material.MaterialType==EMT_ONETEXTURE_BLEND)
1466 {
1467 E_BLEND_FACTOR srcFact;
1468 E_BLEND_FACTOR dstFact;
1469 E_MODULATE_FUNC modulo;
1470 u32 alphaSource;
1471 unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam);
1472 setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0);
1473 }
1474 else
1475 setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL);
1476 }
1477
1478 switch (pType)
1479 {
1480 case scene::EPT_POINT_SPRITES:
1481 case scene::EPT_POINTS:
1482 {
1483 f32 tmp=Material.Thickness/getScreenSize().Height;
1484 if (pType==scene::EPT_POINT_SPRITES)
1485 pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
1486 pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
1487 pID3DDevice->SetRenderState(D3DRS_POINTSIZE, F2DW(tmp));
1488 tmp=1.0f;
1489 pID3DDevice->SetRenderState(D3DRS_POINTSCALE_A, F2DW(tmp));
1490 pID3DDevice->SetRenderState(D3DRS_POINTSCALE_B, F2DW(tmp));
1491 pID3DDevice->SetRenderState(D3DRS_POINTSIZE_MIN, F2DW(tmp));
1492 tmp=0.0f;
1493 pID3DDevice->SetRenderState(D3DRS_POINTSCALE_C, F2DW(tmp));
1494
1495 if (!vertices)
1496 {
1497 pID3DDevice->DrawIndexedPrimitive(D3DPT_POINTLIST, 0, 0, vertexCount, 0, primitiveCount);
1498 }
1499 else
1500 {
1501 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_POINTLIST, 0, vertexCount,
1502 primitiveCount, indexList, indexType, vertices, stride);
1503 }
1504
1505 pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
1506 if (pType==scene::EPT_POINT_SPRITES)
1507 pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
1508 }
1509 break;
1510 case scene::EPT_LINE_STRIP:
1511 if(!vertices)
1512 pID3DDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, 0, vertexCount, 0, primitiveCount);
1513 else
1514 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount,
1515 primitiveCount, indexList, indexType, vertices, stride);
1516 break;
1517 case scene::EPT_LINE_LOOP:
1518 if(!vertices)
1519 {
1520 // TODO: Implement proper hardware support for this primitive type.
1521 // (No looping occurs currently because this would require a way to
1522 // draw the hardware buffer with a custom set of indices. We may even
1523 // need to create a new mini index buffer specifically for this
1524 // primitive type.)
1525 pID3DDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, vertexCount, 0, primitiveCount);
1526 }
1527 else
1528 {
1529 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount,
1530 primitiveCount - 1, indexList, indexType, vertices, stride);
1531
1532 u16 tmpIndices[] = {primitiveCount - 1, 0};
1533
1534 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, vertexCount,
1535 1, tmpIndices, indexType, vertices, stride);
1536 }
1537 break;
1538 case scene::EPT_LINES:
1539 if(!vertices)
1540 pID3DDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, vertexCount, 0, primitiveCount);
1541 else
1542 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, vertexCount,
1543 primitiveCount, indexList, indexType, vertices, stride);
1544 break;
1545 case scene::EPT_TRIANGLE_STRIP:
1546 if(!vertices)
1547 pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, vertexCount, 0, primitiveCount);
1548 else
1549 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLESTRIP, 0, vertexCount, primitiveCount,
1550 indexList, indexType, vertices, stride);
1551 break;
1552 case scene::EPT_TRIANGLE_FAN:
1553 if(!vertices)
1554 pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, 0, 0, vertexCount, 0, primitiveCount);
1555 else
1556 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLEFAN, 0, vertexCount, primitiveCount,
1557 indexList, indexType, vertices, stride);
1558 break;
1559 case scene::EPT_TRIANGLES:
1560 if(!vertices)
1561 {
1562 pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vertexCount, 0, primitiveCount);
1563 }
1564 else
1565 {
1566 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, vertexCount,
1567 primitiveCount, indexList, indexType, vertices, stride);
1568 }
1569 break;
1570 }
1571}
1572
1573
1574void CD3D9Driver::draw2DImage(const video::ITexture* texture,
1575 const core::rect<s32>& destRect,
1576 const core::rect<s32>& sourceRect,
1577 const core::rect<s32>* clipRect,
1578 const video::SColor* const colors,
1579 bool useAlphaChannelOfTexture)
1580{
1581 if(!texture)
1582 return;
1583
1584 const core::dimension2d<u32>& ss = texture->getOriginalSize();
1585 core::rect<f32> tcoords;
1586 tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width;
1587 tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height;
1588 tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width;
1589 tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height;
1590
1591 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1592
1593 const video::SColor temp[4] =
1594 {
1595 0xFFFFFFFF,
1596 0xFFFFFFFF,
1597 0xFFFFFFFF,
1598 0xFFFFFFFF
1599 };
1600
1601 const video::SColor* const useColor = colors ? colors : temp;
1602
1603 S3DVertex vtx[4]; // clock wise
1604 vtx[0] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f,
1605 0.0f, 0.0f, 0.0f, useColor[0],
1606 tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
1607 vtx[1] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f,
1608 0.0f, 0.0f, 0.0f, useColor[3],
1609 tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
1610 vtx[2] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f,
1611 0.0f, 0.0f, 0.0f, useColor[2],
1612 tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
1613 vtx[3] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f,
1614 0.0f, 0.0f, 0.0f, useColor[1],
1615 tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
1616
1617 s16 indices[6] = {0,1,2,0,2,3};
1618
1619 setActiveTexture(0, const_cast<video::ITexture*>(texture));
1620
1621 setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 ||
1622 useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255,
1623 true, useAlphaChannelOfTexture);
1624
1625 setVertexShader(EVT_STANDARD);
1626
1627 if (clipRect)
1628 {
1629 pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
1630 RECT scissor;
1631 scissor.left = clipRect->UpperLeftCorner.X;
1632 scissor.top = clipRect->UpperLeftCorner.Y;
1633 scissor.right = clipRect->LowerRightCorner.X;
1634 scissor.bottom = clipRect->LowerRightCorner.Y;
1635 pID3DDevice->SetScissorRect(&scissor);
1636 }
1637
1638 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
1639 D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex));
1640
1641 if (clipRect)
1642 pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
1643}
1644
1645
1646void CD3D9Driver::draw2DImageBatch(const video::ITexture* texture,
1647 const core::array<core::position2d<s32> >& positions,
1648 const core::array<core::rect<s32> >& sourceRects,
1649 const core::rect<s32>* clipRect,
1650 SColor color,
1651 bool useAlphaChannelOfTexture)
1652{
1653 if (!texture)
1654 return;
1655
1656 if (!setActiveTexture(0, const_cast<video::ITexture*>(texture)))
1657 return;
1658
1659 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
1660
1661 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
1662
1663 core::array<S3DVertex> vtx(drawCount * 4);
1664 core::array<u16> indices(drawCount * 6);
1665
1666 for(u32 i = 0;i < drawCount;i++)
1667 {
1668 core::position2d<s32> targetPos = positions[i];
1669 core::position2d<s32> sourcePos = sourceRects[i].UpperLeftCorner;
1670 // This needs to be signed as it may go negative.
1671 core::dimension2d<s32> sourceSize(sourceRects[i].getSize());
1672
1673 if (clipRect)
1674 {
1675 if (targetPos.X < clipRect->UpperLeftCorner.X)
1676 {
1677 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
1678 if (sourceSize.Width <= 0)
1679 continue;
1680
1681 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
1682 targetPos.X = clipRect->UpperLeftCorner.X;
1683 }
1684
1685 if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X)
1686 {
1687 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
1688 if (sourceSize.Width <= 0)
1689 continue;
1690 }
1691
1692 if (targetPos.Y < clipRect->UpperLeftCorner.Y)
1693 {
1694 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
1695 if (sourceSize.Height <= 0)
1696 continue;
1697
1698 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
1699 targetPos.Y = clipRect->UpperLeftCorner.Y;
1700 }
1701
1702 if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y)
1703 {
1704 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
1705 if (sourceSize.Height <= 0)
1706 continue;
1707 }
1708 }
1709
1710 // clip these coordinates
1711
1712 if (targetPos.X<0)
1713 {
1714 sourceSize.Width += targetPos.X;
1715 if (sourceSize.Width <= 0)
1716 continue;
1717
1718 sourcePos.X -= targetPos.X;
1719 targetPos.X = 0;
1720 }
1721
1722 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1723
1724 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
1725 {
1726 sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
1727 if (sourceSize.Width <= 0)
1728 continue;
1729 }
1730
1731 if (targetPos.Y<0)
1732 {
1733 sourceSize.Height += targetPos.Y;
1734 if (sourceSize.Height <= 0)
1735 continue;
1736
1737 sourcePos.Y -= targetPos.Y;
1738 targetPos.Y = 0;
1739 }
1740
1741 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
1742 {
1743 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
1744 if (sourceSize.Height <= 0)
1745 continue;
1746 }
1747
1748 // ok, we've clipped everything.
1749 // now draw it.
1750
1751 core::rect<f32> tcoords;
1752 tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ;
1753 tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height;
1754 tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width);
1755 tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height);
1756
1757 const core::rect<s32> poss(targetPos, sourceSize);
1758
1759 vtx.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
1760 0.0f, 0.0f, 0.0f, color,
1761 tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y));
1762 vtx.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
1763 0.0f, 0.0f, 0.0f, color,
1764 tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y));
1765 vtx.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
1766 0.0f, 0.0f, 0.0f, color,
1767 tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y));
1768 vtx.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
1769 0.0f, 0.0f, 0.0f, color,
1770 tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y));
1771
1772 const u32 curPos = vtx.size()-4;
1773 indices.push_back(0+curPos);
1774 indices.push_back(1+curPos);
1775 indices.push_back(2+curPos);
1776
1777 indices.push_back(0+curPos);
1778 indices.push_back(2+curPos);
1779 indices.push_back(3+curPos);
1780 }
1781
1782 if (vtx.size())
1783 {
1784 setVertexShader(EVT_STANDARD);
1785
1786 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, vtx.size(), indices.size() / 3, indices.pointer(),
1787 D3DFMT_INDEX16,vtx.pointer(), sizeof(S3DVertex));
1788 }
1789}
1790
1791
1792//! draws a 2d image, using a color and the alpha channel of the texture if
1793//! desired. The image is drawn at pos and clipped against clipRect (if != 0).
1794void CD3D9Driver::draw2DImage(const video::ITexture* texture,
1795 const core::position2d<s32>& pos,
1796 const core::rect<s32>& sourceRect,
1797 const core::rect<s32>* clipRect, SColor color,
1798 bool useAlphaChannelOfTexture)
1799{
1800 if (!texture)
1801 return;
1802
1803 if (!sourceRect.isValid())
1804 return;
1805
1806 if (!setActiveTexture(0, const_cast<video::ITexture*>(texture)))
1807 return;
1808
1809 core::position2d<s32> targetPos = pos;
1810 core::position2d<s32> sourcePos = sourceRect.UpperLeftCorner;
1811 // This needs to be signed as it may go negative.
1812 core::dimension2d<s32> sourceSize(sourceRect.getSize());
1813
1814 if (clipRect)
1815 {
1816 if (targetPos.X < clipRect->UpperLeftCorner.X)
1817 {
1818 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
1819 if (sourceSize.Width <= 0)
1820 return;
1821
1822 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
1823 targetPos.X = clipRect->UpperLeftCorner.X;
1824 }
1825
1826 if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X)
1827 {
1828 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
1829 if (sourceSize.Width <= 0)
1830 return;
1831 }
1832
1833 if (targetPos.Y < clipRect->UpperLeftCorner.Y)
1834 {
1835 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
1836 if (sourceSize.Height <= 0)
1837 return;
1838
1839 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
1840 targetPos.Y = clipRect->UpperLeftCorner.Y;
1841 }
1842
1843 if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y)
1844 {
1845 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
1846 if (sourceSize.Height <= 0)
1847 return;
1848 }
1849 }
1850
1851 // clip these coordinates
1852
1853 if (targetPos.X<0)
1854 {
1855 sourceSize.Width += targetPos.X;
1856 if (sourceSize.Width <= 0)
1857 return;
1858
1859 sourcePos.X -= targetPos.X;
1860 targetPos.X = 0;
1861 }
1862
1863 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1864
1865 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
1866 {
1867 sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
1868 if (sourceSize.Width <= 0)
1869 return;
1870 }
1871
1872 if (targetPos.Y<0)
1873 {
1874 sourceSize.Height += targetPos.Y;
1875 if (sourceSize.Height <= 0)
1876 return;
1877
1878 sourcePos.Y -= targetPos.Y;
1879 targetPos.Y = 0;
1880 }
1881
1882 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
1883 {
1884 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
1885 if (sourceSize.Height <= 0)
1886 return;
1887 }
1888
1889 // ok, we've clipped everything.
1890 // now draw it.
1891
1892 core::rect<f32> tcoords;
1893 tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ;
1894 tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height;
1895 tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width);
1896 tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height);
1897
1898 const core::rect<s32> poss(targetPos, sourceSize);
1899
1900 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
1901
1902 S3DVertex vtx[4];
1903 vtx[0] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
1904 0.0f, 0.0f, 0.0f, color,
1905 tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
1906 vtx[1] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f,
1907 0.0f, 0.0f, 0.0f, color,
1908 tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
1909 vtx[2] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
1910 0.0f, 0.0f, 0.0f, color,
1911 tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
1912 vtx[3] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f,
1913 0.0f, 0.0f, 0.0f, color,
1914 tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
1915
1916 s16 indices[6] = {0,1,2,0,2,3};
1917
1918 setVertexShader(EVT_STANDARD);
1919
1920 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
1921 D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex));
1922}
1923
1924
1925//!Draws a 2d rectangle with a gradient.
1926void CD3D9Driver::draw2DRectangle(const core::rect<s32>& position,
1927 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
1928 const core::rect<s32>* clip)
1929{
1930 core::rect<s32> pos(position);
1931
1932 if (clip)
1933 pos.clipAgainst(*clip);
1934
1935 if (!pos.isValid())
1936 return;
1937
1938 S3DVertex vtx[4];
1939 vtx[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f,
1940 0.0f, 0.0f, 0.0f, colorLeftUp, 0.0f, 0.0f);
1941 vtx[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f,
1942 0.0f, 0.0f, 0.0f, colorRightUp, 0.0f, 1.0f);
1943 vtx[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f,
1944 0.0f, 0.0f, 0.0f, colorRightDown, 1.0f, 0.0f);
1945 vtx[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f,
1946 0.0f, 0.0f, 0.0f, colorLeftDown, 1.0f, 1.0f);
1947
1948 s16 indices[6] = {0,1,2,0,2,3};
1949
1950 setRenderStates2DMode(
1951 colorLeftUp.getAlpha() < 255 ||
1952 colorRightUp.getAlpha() < 255 ||
1953 colorLeftDown.getAlpha() < 255 ||
1954 colorRightDown.getAlpha() < 255, false, false);
1955
1956 setActiveTexture(0,0);
1957
1958 setVertexShader(EVT_STANDARD);
1959
1960 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
1961 D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex));
1962}
1963
1964
1965//! Draws a 2d line.
1966void CD3D9Driver::draw2DLine(const core::position2d<s32>& start,
1967 const core::position2d<s32>& end,
1968 SColor color)
1969{
1970 if (start==end)
1971 drawPixel(start.X, start.Y, color);
1972 else
1973 {
1974 // thanks to Vash TheStampede who sent in his implementation
1975 S3DVertex vtx[2];
1976 vtx[0] = S3DVertex((f32)start.X+0.375f, (f32)start.Y+0.375f, 0.0f,
1977 0.0f, 0.0f, 0.0f, // normal
1978 color, 0.0f, 0.0f); // texture
1979
1980 vtx[1] = S3DVertex((f32)end.X+0.375f, (f32)end.Y+0.375f, 0.0f,
1981 0.0f, 0.0f, 0.0f,
1982 color, 0.0f, 0.0f);
1983
1984 setRenderStates2DMode(color.getAlpha() < 255, false, false);
1985 setActiveTexture(0,0);
1986
1987 setVertexShader(EVT_STANDARD);
1988
1989 pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1,
1990 &vtx[0], sizeof(S3DVertex) );
1991 }
1992}
1993
1994
1995//! Draws a pixel
1996void CD3D9Driver::drawPixel(u32 x, u32 y, const SColor & color)
1997{
1998 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1999 if(x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)
2000 return;
2001
2002 setRenderStates2DMode(color.getAlpha() < 255, false, false);
2003 setActiveTexture(0,0);
2004
2005 setVertexShader(EVT_STANDARD);
2006
2007 S3DVertex vertex((f32)x+0.375f, (f32)y+0.375f, 0.f, 0.f, 0.f, 0.f, color, 0.f, 0.f);
2008
2009 pID3DDevice->DrawPrimitiveUP(D3DPT_POINTLIST, 1, &vertex, sizeof(vertex));
2010}
2011
2012
2013//! sets right vertex shader
2014void CD3D9Driver::setVertexShader(E_VERTEX_TYPE newType)
2015{
2016 if (newType != LastVertexType)
2017 {
2018 LastVertexType = newType;
2019 HRESULT hr = 0;
2020
2021 switch(newType)
2022 {
2023 case EVT_STANDARD:
2024 hr = pID3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1);
2025 break;
2026 case EVT_2TCOORDS:
2027 hr = pID3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX2);
2028 break;
2029 case EVT_TANGENTS:
2030 hr = pID3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX3 |
2031 D3DFVF_TEXCOORDSIZE2(0) | // real texture coord
2032 D3DFVF_TEXCOORDSIZE3(1) | // misuse texture coord 2 for tangent
2033 D3DFVF_TEXCOORDSIZE3(2) // misuse texture coord 3 for binormal
2034 );
2035 break;
2036 }
2037
2038 if (FAILED(hr))
2039 {
2040 os::Printer::log("Could not set vertex Shader.", ELL_ERROR);
2041 return;
2042 }
2043 }
2044}
2045
2046
2047//! sets the needed renderstates
2048bool CD3D9Driver::setRenderStates3DMode()
2049{
2050 if (!pID3DDevice)
2051 return false;
2052
2053 if (CurrentRenderMode != ERM_3D)
2054 {
2055 // switch back the matrices
2056 pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)&Matrices[ETS_VIEW]));
2057 pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)&Matrices[ETS_WORLD]));
2058 pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)&Matrices[ETS_PROJECTION]));
2059
2060 pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
2061 pID3DDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
2062
2063 ResetRenderStates = true;
2064 }
2065
2066 if (ResetRenderStates || LastMaterial != Material)
2067 {
2068 // unset old material
2069
2070 if (CurrentRenderMode == ERM_3D &&
2071 LastMaterial.MaterialType != Material.MaterialType &&
2072 LastMaterial.MaterialType >= 0 && LastMaterial.MaterialType < (s32)MaterialRenderers.size())
2073 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
2074
2075 // set new material.
2076
2077 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
2078 MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(
2079 Material, LastMaterial, ResetRenderStates, this);
2080 }
2081
2082 bool shaderOK = true;
2083 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
2084 shaderOK = MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, LastVertexType);
2085
2086 LastMaterial = Material;
2087
2088 ResetRenderStates = false;
2089
2090 CurrentRenderMode = ERM_3D;
2091
2092 return shaderOK;
2093}
2094
2095
2096//! Map Irrlicht texture wrap mode to native values
2097D3DTEXTUREADDRESS CD3D9Driver::getTextureWrapMode(const u8 clamp)
2098{
2099 switch (clamp)
2100 {
2101 case ETC_REPEAT:
2102 if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP)
2103 return D3DTADDRESS_WRAP;
2104 case ETC_CLAMP:
2105 case ETC_CLAMP_TO_EDGE:
2106 if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_CLAMP)
2107 return D3DTADDRESS_CLAMP;
2108 case ETC_MIRROR:
2109 if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRROR)
2110 return D3DTADDRESS_MIRROR;
2111 case ETC_CLAMP_TO_BORDER:
2112 if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_BORDER)
2113 return D3DTADDRESS_BORDER;
2114 else
2115 return D3DTADDRESS_CLAMP;
2116 case ETC_MIRROR_CLAMP:
2117 case ETC_MIRROR_CLAMP_TO_EDGE:
2118 case ETC_MIRROR_CLAMP_TO_BORDER:
2119 if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRRORONCE)
2120 return D3DTADDRESS_MIRRORONCE;
2121 else
2122 return D3DTADDRESS_CLAMP;
2123 default:
2124 return D3DTADDRESS_WRAP;
2125 }
2126}
2127
2128
2129//! Can be called by an IMaterialRenderer to make its work easier.
2130void CD3D9Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial,
2131 bool resetAllRenderstates)
2132{
2133 // This needs only to be updated onresets
2134 if (Params.HandleSRGB && resetAllRenderstates)
2135 pID3DDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, TRUE);
2136
2137 if (resetAllRenderstates ||
2138 lastmaterial.AmbientColor != material.AmbientColor ||
2139 lastmaterial.DiffuseColor != material.DiffuseColor ||
2140 lastmaterial.SpecularColor != material.SpecularColor ||
2141 lastmaterial.EmissiveColor != material.EmissiveColor ||
2142 lastmaterial.Shininess != material.Shininess)
2143 {
2144 D3DMATERIAL9 mat;
2145 mat.Diffuse = colorToD3D(material.DiffuseColor);
2146 mat.Ambient = colorToD3D(material.AmbientColor);
2147 mat.Specular = colorToD3D(material.SpecularColor);
2148 mat.Emissive = colorToD3D(material.EmissiveColor);
2149 mat.Power = material.Shininess;
2150 pID3DDevice->SetMaterial(&mat);
2151 }
2152
2153 if (lastmaterial.ColorMaterial != material.ColorMaterial)
2154 {
2155 pID3DDevice->SetRenderState(D3DRS_COLORVERTEX, (material.ColorMaterial != ECM_NONE));
2156 pID3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE,
2157 ((material.ColorMaterial == ECM_DIFFUSE)||
2158 (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT))?D3DMCS_COLOR1:D3DMCS_MATERIAL);
2159 pID3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE,
2160 ((material.ColorMaterial == ECM_AMBIENT)||
2161 (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT))?D3DMCS_COLOR1:D3DMCS_MATERIAL);
2162 pID3DDevice->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE,
2163 (material.ColorMaterial == ECM_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
2164 pID3DDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE,
2165 (material.ColorMaterial == ECM_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
2166 }
2167
2168 // fillmode
2169 if (resetAllRenderstates || lastmaterial.Wireframe != material.Wireframe || lastmaterial.PointCloud != material.PointCloud)
2170 {
2171 if (material.Wireframe)
2172 pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
2173 else
2174 if (material.PointCloud)
2175 pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT);
2176 else
2177 pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
2178 }
2179
2180 // shademode
2181
2182 if (resetAllRenderstates || lastmaterial.GouraudShading != material.GouraudShading)
2183 {
2184 if (material.GouraudShading)
2185 pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
2186 else
2187 pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
2188 }
2189
2190 // lighting
2191
2192 if (resetAllRenderstates || lastmaterial.Lighting != material.Lighting)
2193 {
2194 if (material.Lighting)
2195 pID3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
2196 else
2197 pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
2198 }
2199
2200 // zbuffer
2201
2202 if (resetAllRenderstates || lastmaterial.ZBuffer != material.ZBuffer)
2203 {
2204 switch (material.ZBuffer)
2205 {
2206 case ECFN_NEVER:
2207 pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
2208 break;
2209 case ECFN_LESSEQUAL:
2210 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2211 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
2212 break;
2213 case ECFN_EQUAL:
2214 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2215 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
2216 break;
2217 case ECFN_LESS:
2218 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2219 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
2220 break;
2221 case ECFN_NOTEQUAL:
2222 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2223 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL);
2224 break;
2225 case ECFN_GREATEREQUAL:
2226 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2227 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL);
2228 break;
2229 case ECFN_GREATER:
2230 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2231 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER);
2232 break;
2233 case ECFN_ALWAYS:
2234 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2235 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
2236 break;
2237 }
2238 }
2239
2240 // zwrite
2241// if (resetAllRenderstates || (lastmaterial.ZWriteEnable != material.ZWriteEnable))
2242 {
2243 if ( material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent()))
2244 pID3DDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE);
2245 else
2246 pID3DDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE);
2247 }
2248
2249 // back face culling
2250
2251 if (resetAllRenderstates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling))
2252 {
2253// if (material.FrontfaceCulling && material.BackfaceCulling)
2254// pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW|D3DCULL_CCW);
2255// else
2256 if (material.FrontfaceCulling)
2257 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
2258 else
2259 if (material.BackfaceCulling)
2260 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
2261 else
2262 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
2263 }
2264
2265 // fog
2266 if (resetAllRenderstates || lastmaterial.FogEnable != material.FogEnable)
2267 {
2268 pID3DDevice->SetRenderState(D3DRS_FOGENABLE, material.FogEnable);
2269 }
2270
2271 // specular highlights
2272 if (resetAllRenderstates || !core::equals(lastmaterial.Shininess,material.Shininess))
2273 {
2274 const bool enable = (material.Shininess!=0.0f);
2275 pID3DDevice->SetRenderState(D3DRS_SPECULARENABLE, enable);
2276 pID3DDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
2277 }
2278
2279 // normalization
2280 if (resetAllRenderstates || lastmaterial.NormalizeNormals != material.NormalizeNormals)
2281 {
2282 pID3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, material.NormalizeNormals);
2283 }
2284
2285 // Color Mask
2286 if (queryFeature(EVDF_COLOR_MASK) &&
2287 (resetAllRenderstates || lastmaterial.ColorMask != material.ColorMask))
2288 {
2289 const DWORD flag =
2290 ((material.ColorMask & ECP_RED)?D3DCOLORWRITEENABLE_RED:0) |
2291 ((material.ColorMask & ECP_GREEN)?D3DCOLORWRITEENABLE_GREEN:0) |
2292 ((material.ColorMask & ECP_BLUE)?D3DCOLORWRITEENABLE_BLUE:0) |
2293 ((material.ColorMask & ECP_ALPHA)?D3DCOLORWRITEENABLE_ALPHA:0);
2294 pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, flag);
2295 }
2296
2297 if (queryFeature(EVDF_BLEND_OPERATIONS) &&
2298 (resetAllRenderstates|| lastmaterial.BlendOperation != material.BlendOperation))
2299 {
2300 if (material.BlendOperation==EBO_NONE)
2301 pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2302 else
2303 {
2304 pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
2305 switch (material.BlendOperation)
2306 {
2307 case EBO_SUBTRACT:
2308 pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2309 break;
2310 case EBO_REVSUBTRACT:
2311 pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
2312 break;
2313 case EBO_MIN:
2314 case EBO_MIN_FACTOR:
2315 case EBO_MIN_ALPHA:
2316 pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN);
2317 break;
2318 case EBO_MAX:
2319 case EBO_MAX_FACTOR:
2320 case EBO_MAX_ALPHA:
2321 pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MAX);
2322 break;
2323 default:
2324 pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
2325 break;
2326 }
2327 }
2328 }
2329
2330 // Polygon offset
2331 if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderstates ||
2332 lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection ||
2333 lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor))
2334 {
2335 if (material.PolygonOffsetFactor)
2336 {
2337 if (material.PolygonOffsetDirection==EPO_BACK)
2338 {
2339 pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(1.f));
2340 pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)material.PolygonOffsetFactor));
2341 }
2342 else
2343 {
2344 pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(-1.f));
2345 pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)-material.PolygonOffsetFactor));
2346 }
2347 }
2348 else
2349 {
2350 pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
2351 pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
2352 }
2353 }
2354
2355 // Anti Aliasing
2356 if (resetAllRenderstates || lastmaterial.AntiAliasing != material.AntiAliasing)
2357 {
2358 if (AlphaToCoverageSupport && (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE))
2359 {
2360 if (VendorID==0x10DE)//NVidia
2361 pID3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y, MAKEFOURCC('A','T','O','C'));
2362 // SSAA could give better results on NVidia cards
2363 else if (VendorID==0x1002)//ATI
2364 pID3DDevice->SetRenderState(D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','1'));
2365 }
2366 else if (AlphaToCoverageSupport && (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE))
2367 {
2368 if (VendorID==0x10DE)
2369 pID3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y, D3DFMT_UNKNOWN);
2370 else if (VendorID==0x1002)
2371 pID3DDevice->SetRenderState(D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','0'));
2372 }
2373
2374 // enable antialiasing
2375 if (Params.AntiAlias)
2376 {
2377 if (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))
2378 pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
2379 else if (lastmaterial.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))
2380 pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, FALSE);
2381 if (material.AntiAliasing & (EAAM_LINE_SMOOTH))
2382 pID3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, TRUE);
2383 else if (lastmaterial.AntiAliasing & (EAAM_LINE_SMOOTH))
2384 pID3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, FALSE);
2385 }
2386 }
2387
2388 // thickness
2389 if (resetAllRenderstates || lastmaterial.Thickness != material.Thickness)
2390 {
2391 pID3DDevice->SetRenderState(D3DRS_POINTSIZE, F2DW(material.Thickness));
2392 }
2393
2394 // texture address mode
2395 for (u32 st=0; st<MaxTextureUnits; ++st)
2396 {
2397 if (resetAllRenderstates && Params.HandleSRGB)
2398 pID3DDevice->SetSamplerState(st, D3DSAMP_SRGBTEXTURE, TRUE);
2399
2400 if (resetAllRenderstates || lastmaterial.TextureLayer[st].LODBias != material.TextureLayer[st].LODBias)
2401 {
2402 const float tmp = material.TextureLayer[st].LODBias * 0.125f;
2403 pID3DDevice->SetSamplerState(st, D3DSAMP_MIPMAPLODBIAS, F2DW(tmp));
2404 }
2405
2406 if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapU != material.TextureLayer[st].TextureWrapU)
2407 pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSU, getTextureWrapMode(material.TextureLayer[st].TextureWrapU));
2408 // If separate UV not supported reuse U for V
2409 if (!(Caps.TextureAddressCaps & D3DPTADDRESSCAPS_INDEPENDENTUV))
2410 pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSV, getTextureWrapMode(material.TextureLayer[st].TextureWrapU));
2411 else if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapV != material.TextureLayer[st].TextureWrapV)
2412 pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSV, getTextureWrapMode(material.TextureLayer[st].TextureWrapV));
2413
2414 // Bilinear, trilinear, and anisotropic filter
2415 if (resetAllRenderstates ||
2416 lastmaterial.TextureLayer[st].BilinearFilter != material.TextureLayer[st].BilinearFilter ||
2417 lastmaterial.TextureLayer[st].TrilinearFilter != material.TextureLayer[st].TrilinearFilter ||
2418 lastmaterial.TextureLayer[st].AnisotropicFilter != material.TextureLayer[st].AnisotropicFilter ||
2419 lastmaterial.UseMipMaps != material.UseMipMaps)
2420 {
2421 if (material.TextureLayer[st].BilinearFilter || material.TextureLayer[st].TrilinearFilter || material.TextureLayer[st].AnisotropicFilter)
2422 {
2423 D3DTEXTUREFILTERTYPE tftMag = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) &&
2424 material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR;
2425 D3DTEXTUREFILTERTYPE tftMin = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) &&
2426 material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR;
2427 D3DTEXTUREFILTERTYPE tftMip = material.UseMipMaps? (material.TextureLayer[st].TrilinearFilter ? D3DTEXF_LINEAR : D3DTEXF_POINT) : D3DTEXF_NONE;
2428
2429 if (tftMag==D3DTEXF_ANISOTROPIC || tftMin == D3DTEXF_ANISOTROPIC)
2430 pID3DDevice->SetSamplerState(st, D3DSAMP_MAXANISOTROPY, core::min_((DWORD)material.TextureLayer[st].AnisotropicFilter, Caps.MaxAnisotropy));
2431 pID3DDevice->SetSamplerState(st, D3DSAMP_MAGFILTER, tftMag);
2432 pID3DDevice->SetSamplerState(st, D3DSAMP_MINFILTER, tftMin);
2433 pID3DDevice->SetSamplerState(st, D3DSAMP_MIPFILTER, tftMip);
2434 }
2435 else
2436 {
2437 pID3DDevice->SetSamplerState(st, D3DSAMP_MINFILTER, D3DTEXF_POINT);
2438 pID3DDevice->SetSamplerState(st, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
2439 pID3DDevice->SetSamplerState(st, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
2440 }
2441 }
2442 }
2443}
2444
2445
2446//! sets the needed renderstates
2447void CD3D9Driver::setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisible)
2448{
2449 if ((CurrentRenderMode != ERM_SHADOW_VOLUME_ZFAIL &&
2450 CurrentRenderMode != ERM_SHADOW_VOLUME_ZPASS) ||
2451 Transformation3DChanged)
2452 {
2453 // unset last 3d material
2454 if (CurrentRenderMode == ERM_3D &&
2455 static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
2456 {
2457 MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial();
2458 ResetRenderStates = true;
2459 }
2460 // switch back the matrices
2461 pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)&Matrices[ETS_VIEW]));
2462 pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)&Matrices[ETS_WORLD]));
2463 pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)&Matrices[ETS_PROJECTION]));
2464
2465 Transformation3DChanged = false;
2466
2467 setActiveTexture(0,0);
2468 setActiveTexture(1,0);
2469 setActiveTexture(2,0);
2470 setActiveTexture(3,0);
2471
2472 pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
2473
2474 pID3DDevice->SetFVF(D3DFVF_XYZ);
2475 LastVertexType = (video::E_VERTEX_TYPE)(-1);
2476
2477 pID3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
2478 pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
2479 pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
2480 //pID3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
2481 //pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
2482
2483 pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
2484 pID3DDevice->SetRenderState(D3DRS_STENCILREF, 0x0);
2485 pID3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);
2486 pID3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);
2487
2488 pID3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
2489 pID3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
2490 pID3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
2491
2492 pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2493 pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
2494
2495 //if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY)))
2496 // pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
2497 if ((debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY))
2498 pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
2499 }
2500
2501 if (CurrentRenderMode != ERM_SHADOW_VOLUME_ZPASS && !zfail)
2502 {
2503 // USE THE ZPASS METHOD
2504 pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
2505 pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
2506 //pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR); // does not matter, will be set later
2507 }
2508 else
2509 if (CurrentRenderMode != ERM_SHADOW_VOLUME_ZFAIL && zfail)
2510 {
2511 // USE THE ZFAIL METHOD
2512 pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
2513 //pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR); // does not matter, will be set later
2514 pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
2515 }
2516
2517 CurrentRenderMode = zfail ? ERM_SHADOW_VOLUME_ZFAIL : ERM_SHADOW_VOLUME_ZPASS;
2518}
2519
2520
2521//! sets the needed renderstates
2522void CD3D9Driver::setRenderStatesStencilFillMode(bool alpha)
2523{
2524 if (CurrentRenderMode != ERM_STENCIL_FILL || Transformation3DChanged)
2525 {
2526 core::matrix4 mat;
2527 pID3DDevice->SetTransform(D3DTS_VIEW, &UnitMatrixD3D9);
2528 pID3DDevice->SetTransform(D3DTS_WORLD, &UnitMatrixD3D9);
2529 pID3DDevice->SetTransform(D3DTS_PROJECTION, &UnitMatrixD3D9);
2530
2531 pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
2532 pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
2533 pID3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
2534
2535 pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
2536
2537 pID3DDevice->SetRenderState(D3DRS_STENCILREF, 0x1);
2538 pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL);
2539 //pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL);
2540 pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
2541 pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
2542 pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
2543 pID3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);
2544 pID3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);
2545
2546 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
2547
2548 Transformation3DChanged = false;
2549
2550 pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
2551 pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
2552 pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
2553 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
2554 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
2555 if (alpha)
2556 {
2557 pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
2558 pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
2559 pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
2560 }
2561 else
2562 {
2563 pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2564 }
2565 }
2566
2567 CurrentRenderMode = ERM_STENCIL_FILL;
2568}
2569
2570
2571//! Enable the 2d override material
2572void CD3D9Driver::enableMaterial2D(bool enable)
2573{
2574 if (!enable)
2575 CurrentRenderMode = ERM_NONE;
2576 CNullDriver::enableMaterial2D(enable);
2577}
2578
2579
2580//! sets the needed renderstates
2581void CD3D9Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)
2582{
2583 if (!pID3DDevice)
2584 return;
2585
2586 if (CurrentRenderMode != ERM_2D || Transformation3DChanged)
2587 {
2588 // unset last 3d material
2589 if (CurrentRenderMode == ERM_3D)
2590 {
2591 if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
2592 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
2593 }
2594 if (!OverrideMaterial2DEnabled)
2595 {
2596 setBasicRenderStates(InitMaterial2D, LastMaterial, true);
2597 LastMaterial=InitMaterial2D;
2598
2599 // fix everything that is wrongly set by InitMaterial2D default
2600 pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
2601
2602 pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
2603 }
2604 core::matrix4 m;
2605// this fixes some problems with pixel exact rendering, but also breaks nice texturing
2606// moreover, it would have to be tested in each call, as the texture flag can change each time
2607// if (!texture)
2608// m.setTranslation(core::vector3df(0.5f,0.5f,0));
2609 pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)m.pointer()));
2610
2611 // adjust the view such that pixel center aligns with texels
2612 // Otherwise, subpixel artifacts will occur
2613 m.setTranslation(core::vector3df(-0.5f,-0.5f,0));
2614 pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)m.pointer()));
2615
2616 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
2617 m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0, 1.0);
2618 m.setTranslation(core::vector3df(-1,1,0));
2619 pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)m.pointer()));
2620
2621 // 2d elements are clipped in software
2622 pID3DDevice->SetRenderState(D3DRS_CLIPPING, FALSE);
2623
2624 Transformation3DChanged = false;
2625 }
2626 if (OverrideMaterial2DEnabled)
2627 {
2628 OverrideMaterial2D.Lighting=false;
2629 setBasicRenderStates(OverrideMaterial2D, LastMaterial, false);
2630 LastMaterial = OverrideMaterial2D;
2631 }
2632
2633 // no alphaChannel without texture
2634 alphaChannel &= texture;
2635
2636 if (alpha || alphaChannel)
2637 {
2638 pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
2639 pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
2640 pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
2641 }
2642 else
2643 pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2644 pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
2645 pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
2646 pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
2647 if (texture)
2648 {
2649 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);
2650 // Due to the transformation change, the previous line would call a reset each frame
2651 // but we can safely reset the variable as it was false before
2652 Transformation3DChanged=false;
2653 }
2654 if (alphaChannel)
2655 {
2656 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
2657
2658 if (alpha)
2659 {
2660 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
2661 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
2662 }
2663 else
2664 {
2665 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
2666 }
2667 }
2668 else
2669 {
2670 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
2671 if (alpha)
2672 {
2673 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
2674 }
2675 else
2676 {
2677 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
2678 pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
2679 }
2680 }
2681
2682 CurrentRenderMode = ERM_2D;
2683}
2684
2685
2686//! deletes all dynamic lights there are
2687void CD3D9Driver::deleteAllDynamicLights()
2688{
2689 for (s32 i=0; i<LastSetLight+1; ++i)
2690 pID3DDevice->LightEnable(i, false);
2691
2692 LastSetLight = -1;
2693
2694 CNullDriver::deleteAllDynamicLights();
2695}
2696
2697
2698//! adds a dynamic light
2699s32 CD3D9Driver::addDynamicLight(const SLight& dl)
2700{
2701 CNullDriver::addDynamicLight(dl);
2702
2703 D3DLIGHT9 light;
2704
2705 switch (dl.Type)
2706 {
2707 case ELT_POINT:
2708 light.Type = D3DLIGHT_POINT;
2709 break;
2710 case ELT_SPOT:
2711 light.Type = D3DLIGHT_SPOT;
2712 break;
2713 case ELT_DIRECTIONAL:
2714 light.Type = D3DLIGHT_DIRECTIONAL;
2715 break;
2716 }
2717
2718 light.Position = *(D3DVECTOR*)((void*)(&dl.Position));
2719 light.Direction = *(D3DVECTOR*)((void*)(&dl.Direction));
2720
2721 light.Range = core::min_(dl.Radius, MaxLightDistance);
2722 light.Falloff = dl.Falloff;
2723
2724 light.Diffuse = *(D3DCOLORVALUE*)((void*)(&dl.DiffuseColor));
2725 light.Specular = *(D3DCOLORVALUE*)((void*)(&dl.SpecularColor));
2726 light.Ambient = *(D3DCOLORVALUE*)((void*)(&dl.AmbientColor));
2727
2728 light.Attenuation0 = dl.Attenuation.X;
2729 light.Attenuation1 = dl.Attenuation.Y;
2730 light.Attenuation2 = dl.Attenuation.Z;
2731
2732 light.Theta = dl.InnerCone * 2.0f * core::DEGTORAD;
2733 light.Phi = dl.OuterCone * 2.0f * core::DEGTORAD;
2734
2735 ++LastSetLight;
2736
2737 if(D3D_OK == pID3DDevice->SetLight(LastSetLight, &light))
2738 {
2739 // I don't care if this succeeds
2740 (void)pID3DDevice->LightEnable(LastSetLight, true);
2741 return LastSetLight;
2742 }
2743
2744 return -1;
2745}
2746
2747//! Turns a dynamic light on or off
2748//! \param lightIndex: the index returned by addDynamicLight
2749//! \param turnOn: true to turn the light on, false to turn it off
2750void CD3D9Driver::turnLightOn(s32 lightIndex, bool turnOn)
2751{
2752 if(lightIndex < 0 || lightIndex > LastSetLight)
2753 return;
2754
2755 (void)pID3DDevice->LightEnable(lightIndex, turnOn);
2756}
2757
2758
2759//! returns the maximal amount of dynamic lights the device can handle
2760u32 CD3D9Driver::getMaximalDynamicLightAmount() const
2761{
2762 return Caps.MaxActiveLights;
2763}
2764
2765
2766//! Sets the dynamic ambient light color. The default color is
2767//! (0,0,0,0) which means it is dark.
2768//! \param color: New color of the ambient light.
2769void CD3D9Driver::setAmbientLight(const SColorf& color)
2770{
2771 if (!pID3DDevice)
2772 return;
2773
2774 AmbientLight = color;
2775 D3DCOLOR col = color.toSColor().color;
2776 pID3DDevice->SetRenderState(D3DRS_AMBIENT, col);
2777}
2778
2779
2780//! \return Returns the name of the video driver. Example: In case of the DIRECT3D9
2781//! driver, it would return "Direct3D9.0".
2782const wchar_t* CD3D9Driver::getName() const
2783{
2784 return L"Direct3D 9.0";
2785}
2786
2787
2788//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
2789//! this: First, draw all geometry. Then use this method, to draw the shadow
2790//! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow.
2791void CD3D9Driver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
2792{
2793 if (!Params.Stencilbuffer)
2794 return;
2795
2796 setRenderStatesStencilShadowMode(zfail, debugDataVisible);
2797
2798 const u32 count = triangles.size();
2799 if (!count)
2800 return;
2801
2802 if (!zfail)
2803 {
2804 // ZPASS Method
2805
2806 // Draw front-side of shadow volume in stencil only
2807 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
2808 pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
2809 pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df));
2810
2811 // Now reverse cull order so front sides of shadow volume are written.
2812 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
2813 pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR);
2814 pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df));
2815 }
2816 else
2817 {
2818 // ZFAIL Method
2819
2820 // Draw front-side of shadow volume in stencil only
2821 pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
2822 pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR);
2823 pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df));
2824
2825 // Now reverse cull order so front sides of shadow volume are written.
2826 pID3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW);
2827 pID3DDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR);
2828 pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df));
2829 }
2830}
2831
2832
2833//! Fills the stencil shadow with color. After the shadow volume has been drawn
2834//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
2835//! to draw the color of the shadow.
2836void CD3D9Driver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge,
2837 video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge)
2838{
2839 if (!Params.Stencilbuffer)
2840 return;
2841
2842 S3DVertex vtx[4];
2843 vtx[0] = S3DVertex(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, leftUpEdge, 0.0f, 0.0f);
2844 vtx[1] = S3DVertex(1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, rightUpEdge, 0.0f, 1.0f);
2845 vtx[2] = S3DVertex(-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, leftDownEdge, 1.0f, 0.0f);
2846 vtx[3] = S3DVertex(-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, rightDownEdge, 1.0f, 1.0f);
2847
2848 s16 indices[6] = {0,1,2,1,3,2};
2849
2850 setRenderStatesStencilFillMode(
2851 leftUpEdge.getAlpha() < 255 ||
2852 rightUpEdge.getAlpha() < 255 ||
2853 leftDownEdge.getAlpha() < 255 ||
2854 rightDownEdge.getAlpha() < 255);
2855
2856 setActiveTexture(0,0);
2857
2858 setVertexShader(EVT_STANDARD);
2859
2860 pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
2861 D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex));
2862
2863 if (clearStencilBuffer)
2864 pID3DDevice->Clear( 0, NULL, D3DCLEAR_STENCIL,0, 1.0, 0);
2865}
2866
2867
2868//! Returns the maximum amount of primitives (mostly vertices) which
2869//! the device is able to render with one drawIndexedTriangleList
2870//! call.
2871u32 CD3D9Driver::getMaximalPrimitiveCount() const
2872{
2873 return Caps.MaxPrimitiveCount;
2874}
2875
2876
2877//! Sets the fog mode.
2878void CD3D9Driver::setFog(SColor color, E_FOG_TYPE fogType, f32 start,
2879 f32 end, f32 density, bool pixelFog, bool rangeFog)
2880{
2881 CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog);
2882
2883 if (!pID3DDevice)
2884 return;
2885
2886 pID3DDevice->SetRenderState(D3DRS_FOGCOLOR, color.color);
2887
2888 pID3DDevice->SetRenderState(
2889 pixelFog ? D3DRS_FOGTABLEMODE : D3DRS_FOGVERTEXMODE,
2890 (fogType==EFT_FOG_LINEAR)? D3DFOG_LINEAR : (fogType==EFT_FOG_EXP)?D3DFOG_EXP:D3DFOG_EXP2);
2891
2892 if (fogType==EFT_FOG_LINEAR)
2893 {
2894 pID3DDevice->SetRenderState(D3DRS_FOGSTART, F2DW(start));
2895 pID3DDevice->SetRenderState(D3DRS_FOGEND, F2DW(end));
2896 }
2897 else
2898 pID3DDevice->SetRenderState(D3DRS_FOGDENSITY, F2DW(density));
2899
2900 if(!pixelFog)
2901 pID3DDevice->SetRenderState(D3DRS_RANGEFOGENABLE, rangeFog);
2902}
2903
2904
2905//! Draws a 3d line.
2906void CD3D9Driver::draw3DLine(const core::vector3df& start,
2907 const core::vector3df& end, SColor color)
2908{
2909 setVertexShader(EVT_STANDARD);
2910 setRenderStates3DMode();
2911 video::S3DVertex v[2];
2912 v[0].Color = color;
2913 v[1].Color = color;
2914 v[0].Pos = start;
2915 v[1].Pos = end;
2916
2917 pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, v, sizeof(S3DVertex));
2918}
2919
2920
2921//! resets the device
2922bool CD3D9Driver::reset()
2923{
2924 u32 i;
2925 os::Printer::log("Resetting D3D9 device.", ELL_INFORMATION);
2926
2927 for (i=0; i<Textures.size(); ++i)
2928 {
2929 if (Textures[i].Surface->isRenderTarget())
2930 {
2931 IDirect3DBaseTexture9* tex = ((CD3D9Texture*)(Textures[i].Surface))->getDX9Texture();
2932 if (tex)
2933 tex->Release();
2934 }
2935 }
2936 for (i=0; i<DepthBuffers.size(); ++i)
2937 {
2938 if (DepthBuffers[i]->Surface)
2939 DepthBuffers[i]->Surface->Release();
2940 }
2941 for (i=0; i<OcclusionQueries.size(); ++i)
2942 {
2943 if (OcclusionQueries[i].PID)
2944 {
2945 reinterpret_cast<IDirect3DQuery9*>(OcclusionQueries[i].PID)->Release();
2946 OcclusionQueries[i].PID=0;
2947 }
2948 }
2949 // this does not require a restore in the reset method, it's updated
2950 // automatically in the next render cycle.
2951 removeAllHardwareBuffers();
2952
2953 DriverWasReset=true;
2954
2955 HRESULT hr = pID3DDevice->Reset(&present);
2956
2957 // restore RTTs
2958 for (i=0; i<Textures.size(); ++i)
2959 {
2960 if (Textures[i].Surface->isRenderTarget())
2961 ((CD3D9Texture*)(Textures[i].Surface))->createRenderTarget();
2962 }
2963
2964 // restore screen depthbuffer
2965 pID3DDevice->GetDepthStencilSurface(&(DepthBuffers[0]->Surface));
2966 D3DSURFACE_DESC desc;
2967 // restore other depth buffers
2968 // depth format is taken from main depth buffer
2969 DepthBuffers[0]->Surface->GetDesc(&desc);
2970 // multisampling is taken from rendertarget
2971 D3DSURFACE_DESC desc2;
2972 for (i=1; i<DepthBuffers.size(); ++i)
2973 {
2974 for (u32 j=0; j<Textures.size(); ++j)
2975 {
2976 // all textures sharing this depth buffer must have the same setting
2977 // so take first one
2978 if (((CD3D9Texture*)(Textures[j].Surface))->DepthSurface==DepthBuffers[i])
2979 {
2980 ((CD3D9Texture*)(Textures[j].Surface))->Texture->GetLevelDesc(0,&desc2);
2981 break;
2982 }
2983 }
2984
2985 pID3DDevice->CreateDepthStencilSurface(DepthBuffers[i]->Size.Width,
2986 DepthBuffers[i]->Size.Height,
2987 desc.Format,
2988 desc2.MultiSampleType,
2989 desc2.MultiSampleQuality,
2990 TRUE,
2991 &(DepthBuffers[i]->Surface),
2992 NULL);
2993 }
2994 for (i=0; i<OcclusionQueries.size(); ++i)
2995 {
2996 pID3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, reinterpret_cast<IDirect3DQuery9**>(&OcclusionQueries[i].PID));
2997 }
2998
2999 if (FAILED(hr))
3000 {
3001 if (hr == D3DERR_DEVICELOST)
3002 {
3003 DeviceLost = true;
3004 os::Printer::log("Resetting failed due to device lost.", ELL_WARNING);
3005 }
3006#ifdef D3DERR_DEVICEREMOVED
3007 else if (hr == D3DERR_DEVICEREMOVED)
3008 {
3009 os::Printer::log("Resetting failed due to device removed.", ELL_WARNING);
3010 }
3011#endif
3012 else if (hr == D3DERR_DRIVERINTERNALERROR)
3013 {
3014 os::Printer::log("Resetting failed due to internal error.", ELL_WARNING);
3015 }
3016 else if (hr == D3DERR_OUTOFVIDEOMEMORY)
3017 {
3018 os::Printer::log("Resetting failed due to out of memory.", ELL_WARNING);
3019 }
3020 else if (hr == D3DERR_DEVICENOTRESET)
3021 {
3022 os::Printer::log("Resetting failed due to not reset.", ELL_WARNING);
3023 }
3024 else if (hr == D3DERR_INVALIDCALL)
3025 {
3026 os::Printer::log("Resetting failed due to invalid call", "You need to release some more surfaces.", ELL_WARNING);
3027 }
3028 else
3029 {
3030 os::Printer::log("Resetting failed due to unknown reason.", core::stringc((int)hr).c_str(), ELL_WARNING);
3031 }
3032 return false;
3033 }
3034
3035 DeviceLost = false;
3036 ResetRenderStates = true;
3037 LastVertexType = (E_VERTEX_TYPE)-1;
3038
3039 for (u32 i=0; i<MATERIAL_MAX_TEXTURES; ++i)
3040 CurrentTexture[i] = 0;
3041
3042 setVertexShader(EVT_STANDARD);
3043 setRenderStates3DMode();
3044 setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);
3045 setAmbientLight(AmbientLight);
3046
3047 return true;
3048}
3049
3050
3051void CD3D9Driver::OnResize(const core::dimension2d<u32>& size)
3052{
3053 if (!pID3DDevice)
3054 return;
3055
3056 CNullDriver::OnResize(size);
3057 present.BackBufferWidth = size.Width;
3058 present.BackBufferHeight = size.Height;
3059
3060 reset();
3061}
3062
3063
3064//! Returns type of video driver
3065E_DRIVER_TYPE CD3D9Driver::getDriverType() const
3066{
3067 return EDT_DIRECT3D9;
3068}
3069
3070
3071//! Returns the transformation set by setTransform
3072const core::matrix4& CD3D9Driver::getTransform(E_TRANSFORMATION_STATE state) const
3073{
3074 return Matrices[state];
3075}
3076
3077
3078//! Sets a vertex shader constant.
3079void CD3D9Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
3080{
3081 if (data)
3082 pID3DDevice->SetVertexShaderConstantF(startRegister, data, constantAmount);
3083}
3084
3085
3086//! Sets a pixel shader constant.
3087void CD3D9Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
3088{
3089 if (data)
3090 pID3DDevice->SetPixelShaderConstantF(startRegister, data, constantAmount);
3091}
3092
3093
3094//! Sets a constant for the vertex shader based on a name.
3095bool CD3D9Driver::setVertexShaderConstant(const c8* name, const f32* floats, int count)
3096{
3097 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
3098 {
3099 CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer;
3100 return r->setVariable(true, name, floats, count);
3101 }
3102
3103 return false;
3104}
3105
3106
3107//! Bool interface for the above.
3108bool CD3D9Driver::setVertexShaderConstant(const c8* name, const bool* bools, int count)
3109{
3110 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
3111 {
3112 CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer;
3113 return r->setVariable(true, name, bools, count);
3114 }
3115
3116 return false;
3117}
3118
3119
3120//! Int interface for the above.
3121bool CD3D9Driver::setVertexShaderConstant(const c8* name, const s32* ints, int count)
3122{
3123 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
3124 {
3125 CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer;
3126 return r->setVariable(true, name, ints, count);
3127 }
3128
3129 return false;
3130}
3131
3132
3133//! Sets a constant for the pixel shader based on a name.
3134bool CD3D9Driver::setPixelShaderConstant(const c8* name, const f32* floats, int count)
3135{
3136 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
3137 {
3138 CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer;
3139 return r->setVariable(false, name, floats, count);
3140 }
3141
3142 return false;
3143}
3144
3145
3146//! Bool interface for the above.
3147bool CD3D9Driver::setPixelShaderConstant(const c8* name, const bool* bools, int count)
3148{
3149 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
3150 {
3151 CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer;
3152 return r->setVariable(false, name, bools, count);
3153 }
3154
3155 return false;
3156}
3157
3158
3159//! Int interface for the above.
3160bool CD3D9Driver::setPixelShaderConstant(const c8* name, const s32* ints, int count)
3161{
3162 if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size())
3163 {
3164 CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer;
3165 return r->setVariable(false, name, ints, count);
3166 }
3167
3168 return false;
3169}
3170
3171
3172//! Adds a new material renderer to the VideoDriver, using pixel and/or
3173//! vertex shaders to render geometry.
3174s32 CD3D9Driver::addShaderMaterial(const c8* vertexShaderProgram,
3175 const c8* pixelShaderProgram,
3176 IShaderConstantSetCallBack* callback,
3177 E_MATERIAL_TYPE baseMaterial, s32 userData)
3178{
3179 s32 nr = -1;
3180 CD3D9ShaderMaterialRenderer* r = new CD3D9ShaderMaterialRenderer(
3181 pID3DDevice, this, nr, vertexShaderProgram, pixelShaderProgram,
3182 callback, getMaterialRenderer(baseMaterial), userData);
3183
3184 r->drop();
3185 return nr;
3186}
3187
3188
3189//! Adds a new material renderer to the VideoDriver, based on a high level shading
3190//! language.
3191s32 CD3D9Driver::addHighLevelShaderMaterial(
3192 const c8* vertexShaderProgram,
3193 const c8* vertexShaderEntryPointName,
3194 E_VERTEX_SHADER_TYPE vsCompileTarget,
3195 const c8* pixelShaderProgram,
3196 const c8* pixelShaderEntryPointName,
3197 E_PIXEL_SHADER_TYPE psCompileTarget,
3198 const c8* geometryShaderProgram,
3199 const c8* geometryShaderEntryPointName,
3200 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
3201 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
3202 u32 verticesOut,
3203 IShaderConstantSetCallBack* callback,
3204 E_MATERIAL_TYPE baseMaterial, s32 userData, E_GPU_SHADING_LANGUAGE shadingLang)
3205{
3206 s32 nr = -1;
3207
3208 #ifdef _IRR_COMPILE_WITH_CG_
3209 if(shadingLang == EGSL_CG)
3210 {
3211 CD3D9CgMaterialRenderer* r = new CD3D9CgMaterialRenderer(
3212 this, nr,
3213 vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
3214 pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
3215 geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
3216 inType, outType, verticesOut,
3217 callback,getMaterialRenderer(baseMaterial), userData);
3218
3219 r->drop();
3220 }
3221 else
3222 #endif
3223 {
3224 CD3D9HLSLMaterialRenderer* r = new CD3D9HLSLMaterialRenderer(
3225 pID3DDevice, this, nr,
3226 vertexShaderProgram,
3227 vertexShaderEntryPointName,
3228 vsCompileTarget,
3229 pixelShaderProgram,
3230 pixelShaderEntryPointName,
3231 psCompileTarget,
3232 callback,
3233 getMaterialRenderer(baseMaterial),
3234 userData);
3235
3236 r->drop();
3237 }
3238
3239 return nr;
3240}
3241
3242
3243//! Returns a pointer to the IVideoDriver interface. (Implementation for
3244//! IMaterialRendererServices)
3245IVideoDriver* CD3D9Driver::getVideoDriver()
3246{
3247 return this;
3248}
3249
3250
3251//! Creates a render target texture.
3252ITexture* CD3D9Driver::addRenderTargetTexture(const core::dimension2d<u32>& size,
3253 const io::path& name,
3254 const ECOLOR_FORMAT format)
3255{
3256 CD3D9Texture* tex = new CD3D9Texture(this, size, name, format);
3257 if (tex)
3258 {
3259 if (!tex->Texture)
3260 {
3261 tex->drop();
3262 return 0;
3263 }
3264 checkDepthBuffer(tex);
3265 addTexture(tex);
3266 tex->drop();
3267 }
3268 return tex;
3269}
3270
3271
3272//! Clears the ZBuffer.
3273void CD3D9Driver::clearZBuffer()
3274{
3275 HRESULT hr = pID3DDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0, 0);
3276
3277 if (FAILED(hr))
3278 os::Printer::log("CD3D9Driver clearZBuffer() failed.", ELL_WARNING);
3279}
3280
3281
3282//! Returns an image created from the last rendered frame.
3283IImage* CD3D9Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
3284{
3285 if (target != video::ERT_FRAME_BUFFER)
3286 return 0;
3287
3288 // query the screen dimensions of the current adapter
3289 D3DDISPLAYMODE displayMode;
3290 pID3DDevice->GetDisplayMode(0, &displayMode);
3291
3292 if (format==video::ECF_UNKNOWN)
3293 format=video::ECF_A8R8G8B8;
3294
3295 // create the image surface to store the front buffer image [always A8R8G8B8]
3296 HRESULT hr;
3297 LPDIRECT3DSURFACE9 lpSurface;
3298 if (FAILED(hr = pID3DDevice->CreateOffscreenPlainSurface(displayMode.Width, displayMode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &lpSurface, 0)))
3299 return 0;
3300
3301 // read the front buffer into the image surface
3302 if (FAILED(hr = pID3DDevice->GetFrontBufferData(0, lpSurface)))
3303 {
3304 lpSurface->Release();
3305 return 0;
3306 }
3307
3308 RECT clientRect;
3309 {
3310 POINT clientPoint;
3311 clientPoint.x = 0;
3312 clientPoint.y = 0;
3313
3314 ClientToScreen((HWND)getExposedVideoData().D3D9.HWnd, &clientPoint);
3315
3316 clientRect.left = clientPoint.x;
3317 clientRect.top = clientPoint.y;
3318 clientRect.right = clientRect.left + ScreenSize.Width;
3319 clientRect.bottom = clientRect.top + ScreenSize.Height;
3320
3321 // window can be off-screen partly, we can't take screenshots from that
3322 clientRect.left = core::max_(clientRect.left, 0l);
3323 clientRect.top = core::max_(clientRect.top, 0l);
3324 clientRect.right = core::min_(clientRect.right, (long)displayMode.Width);
3325 clientRect.bottom = core::min_(clientRect.bottom, (long)displayMode.Height );
3326 }
3327
3328 // lock our area of the surface
3329 D3DLOCKED_RECT lockedRect;
3330 if (FAILED(lpSurface->LockRect(&lockedRect, &clientRect, D3DLOCK_READONLY)))
3331 {
3332 lpSurface->Release();
3333 return 0;
3334 }
3335
3336 irr::core::dimension2d<u32> shotSize;
3337 shotSize.Width = core::min_( ScreenSize.Width, (u32)(clientRect.right-clientRect.left) );
3338 shotSize.Height = core::min_( ScreenSize.Height, (u32)(clientRect.bottom-clientRect.top) );
3339
3340 // this could throw, but we aren't going to worry about that case very much
3341 IImage* newImage = createImage(format, shotSize);
3342
3343 if (newImage)
3344 {
3345 // d3d pads the image, so we need to copy the correct number of bytes
3346 u32* dP = (u32*)newImage->lock();
3347 u8 * sP = (u8 *)lockedRect.pBits;
3348
3349 // If the display mode format doesn't promise anything about the Alpha value
3350 // and it appears that it's not presenting 255, then we should manually
3351 // set each pixel alpha value to 255.
3352 if (D3DFMT_X8R8G8B8 == displayMode.Format && (0xFF000000 != (*dP & 0xFF000000)))
3353 {
3354 for (u32 y = 0; y < shotSize.Height; ++y)
3355 {
3356 for (u32 x = 0; x < shotSize.Width; ++x)
3357 {
3358 newImage->setPixel(x,y,*((u32*)sP) | 0xFF000000);
3359 sP += 4;
3360 }
3361
3362 sP += lockedRect.Pitch - (4 * shotSize.Width);
3363 }
3364 }
3365 else
3366 {
3367 for (u32 y = 0; y < shotSize.Height; ++y)
3368 {
3369 convertColor(sP, video::ECF_A8R8G8B8, shotSize.Width, dP, format);
3370 sP += lockedRect.Pitch;
3371 dP += shotSize.Width;
3372 }
3373 }
3374
3375 newImage->unlock();
3376 }
3377
3378 // we can unlock and release the surface
3379 lpSurface->UnlockRect();
3380
3381 // release the image surface
3382 lpSurface->Release();
3383
3384 // return status of save operation to caller
3385 return newImage;
3386}
3387
3388
3389//! returns color format
3390ECOLOR_FORMAT CD3D9Driver::getColorFormat() const
3391{
3392 return ColorFormat;
3393}
3394
3395
3396//! returns color format
3397D3DFORMAT CD3D9Driver::getD3DColorFormat() const
3398{
3399 return D3DColorFormat;
3400}
3401
3402
3403// returns the current size of the screen or rendertarget
3404const core::dimension2d<u32>& CD3D9Driver::getCurrentRenderTargetSize() const
3405{
3406 if ( CurrentRendertargetSize.Width == 0 )
3407 return ScreenSize;
3408 else
3409 return CurrentRendertargetSize;
3410}
3411
3412
3413// Set/unset a clipping plane.
3414bool CD3D9Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
3415{
3416 if (index >= MaxUserClipPlanes)
3417 return false;
3418
3419 HRESULT ok = pID3DDevice->SetClipPlane(index, (const float*)&(plane.Normal.X));
3420 if (D3D_OK == ok)
3421 enableClipPlane(index, enable);
3422 return true;
3423}
3424
3425
3426// Enable/disable a clipping plane.
3427void CD3D9Driver::enableClipPlane(u32 index, bool enable)
3428{
3429 if (index >= MaxUserClipPlanes)
3430 return;
3431 DWORD renderstate;
3432 HRESULT ok = pID3DDevice->GetRenderState(D3DRS_CLIPPLANEENABLE, &renderstate);
3433 if (S_OK == ok)
3434 {
3435 if (enable)
3436 renderstate |= (1 << index);
3437 else
3438 renderstate &= ~(1 << index);
3439 ok = pID3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, renderstate);
3440 }
3441}
3442
3443
3444D3DFORMAT CD3D9Driver::getD3DFormatFromColorFormat(ECOLOR_FORMAT format) const
3445{
3446 switch(format)
3447 {
3448 case ECF_A1R5G5B5:
3449 return D3DFMT_A1R5G5B5;
3450 case ECF_R5G6B5:
3451 return D3DFMT_R5G6B5;
3452 case ECF_R8G8B8:
3453 return D3DFMT_R8G8B8;
3454 case ECF_A8R8G8B8:
3455 return D3DFMT_A8R8G8B8;
3456
3457 // Floating Point formats. Thanks to Patryk "Nadro" Nadrowski.
3458 case ECF_R16F:
3459 return D3DFMT_R16F;
3460 case ECF_G16R16F:
3461 return D3DFMT_G16R16F;
3462 case ECF_A16B16G16R16F:
3463 return D3DFMT_A16B16G16R16F;
3464 case ECF_R32F:
3465 return D3DFMT_R32F;
3466 case ECF_G32R32F:
3467 return D3DFMT_G32R32F;
3468 case ECF_A32B32G32R32F:
3469 return D3DFMT_A32B32G32R32F;
3470 }
3471 return D3DFMT_UNKNOWN;
3472}
3473
3474
3475ECOLOR_FORMAT CD3D9Driver::getColorFormatFromD3DFormat(D3DFORMAT format) const
3476{
3477 switch(format)
3478 {
3479 case D3DFMT_X1R5G5B5:
3480 case D3DFMT_A1R5G5B5:
3481 return ECF_A1R5G5B5;
3482 case D3DFMT_A8B8G8R8:
3483 case D3DFMT_A8R8G8B8:
3484 case D3DFMT_X8R8G8B8:
3485 return ECF_A8R8G8B8;
3486 case D3DFMT_R5G6B5:
3487 return ECF_R5G6B5;
3488 case D3DFMT_R8G8B8:
3489 return ECF_R8G8B8;
3490
3491 // Floating Point formats. Thanks to Patryk "Nadro" Nadrowski.
3492 case D3DFMT_R16F:
3493 return ECF_R16F;
3494 case D3DFMT_G16R16F:
3495 return ECF_G16R16F;
3496 case D3DFMT_A16B16G16R16F:
3497 return ECF_A16B16G16R16F;
3498 case D3DFMT_R32F:
3499 return ECF_R32F;
3500 case D3DFMT_G32R32F:
3501 return ECF_G32R32F;
3502 case D3DFMT_A32B32G32R32F:
3503 return ECF_A32B32G32R32F;
3504 default:
3505 return (ECOLOR_FORMAT)0;
3506 };
3507}
3508
3509
3510void CD3D9Driver::checkDepthBuffer(ITexture* tex)
3511{
3512 if (!tex)
3513 return;
3514 const core::dimension2du optSize = tex->getSize().getOptimalSize(
3515 !queryFeature(EVDF_TEXTURE_NPOT),
3516 !queryFeature(EVDF_TEXTURE_NSQUARE), true);
3517 SDepthSurface* depth=0;
3518 core::dimension2du destSize(0x7fffffff, 0x7fffffff);
3519 for (u32 i=0; i<DepthBuffers.size(); ++i)
3520 {
3521 if ((DepthBuffers[i]->Size.Width>=optSize.Width) &&
3522 (DepthBuffers[i]->Size.Height>=optSize.Height))
3523 {
3524 if ((DepthBuffers[i]->Size.Width<destSize.Width) &&
3525 (DepthBuffers[i]->Size.Height<destSize.Height))
3526 {
3527 depth = DepthBuffers[i];
3528 destSize=DepthBuffers[i]->Size;
3529 }
3530 }
3531 }
3532 if (!depth)
3533 {
3534 D3DSURFACE_DESC desc;
3535 DepthBuffers[0]->Surface->GetDesc(&desc);
3536 // the multisampling needs to match the RTT
3537 D3DSURFACE_DESC desc2;
3538 ((CD3D9Texture*)tex)->Texture->GetLevelDesc(0,&desc2);
3539 DepthBuffers.push_back(new SDepthSurface());
3540 HRESULT hr=pID3DDevice->CreateDepthStencilSurface(optSize.Width,
3541 optSize.Height,
3542 desc.Format,
3543 desc2.MultiSampleType,
3544 desc2.MultiSampleQuality,
3545 TRUE,
3546 &(DepthBuffers.getLast()->Surface),
3547 NULL);
3548 if (SUCCEEDED(hr))
3549 {
3550 depth=DepthBuffers.getLast();
3551 depth->Surface->GetDesc(&desc);
3552 depth->Size.set(desc.Width, desc.Height);
3553 }
3554 else
3555 {
3556 if (hr == D3DERR_OUTOFVIDEOMEMORY)
3557 os::Printer::log("Could not create DepthBuffer","out of video memory",ELL_ERROR);
3558 else if( hr == E_OUTOFMEMORY )
3559 os::Printer::log("Could not create DepthBuffer","out of memory",ELL_ERROR);
3560 else
3561 {
3562 char buffer[128];
3563 sprintf(buffer,"Could not create DepthBuffer of %ix%i",optSize.Width,optSize.Height);
3564 os::Printer::log(buffer,ELL_ERROR);
3565 }
3566 DepthBuffers.erase(DepthBuffers.size()-1);
3567 }
3568 }
3569 else
3570 depth->grab();
3571
3572 static_cast<CD3D9Texture*>(tex)->DepthSurface=depth;
3573}
3574
3575
3576void CD3D9Driver::removeDepthSurface(SDepthSurface* depth)
3577{
3578 for (u32 i=0; i<DepthBuffers.size(); ++i)
3579 {
3580 if (DepthBuffers[i]==depth)
3581 {
3582 DepthBuffers.erase(i);
3583 return;
3584 }
3585 }
3586}
3587
3588
3589core::dimension2du CD3D9Driver::getMaxTextureSize() const
3590{
3591 return core::dimension2du(Caps.MaxTextureWidth, Caps.MaxTextureHeight);
3592}
3593
3594#ifdef _IRR_COMPILE_WITH_CG_
3595const CGcontext& CD3D9Driver::getCgContext()
3596{
3597 return CgContext;
3598}
3599#endif
3600
3601
3602} // end namespace video
3603} // end namespace irr
3604
3605#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
3606
3607
3608
3609namespace irr
3610{
3611namespace video
3612{
3613
3614#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
3615//! creates a video driver
3616IVideoDriver* createDirectX9Driver(const SIrrlichtCreationParameters& params,
3617 io::IFileSystem* io, HWND window)
3618{
3619 const bool pureSoftware = false;
3620 CD3D9Driver* dx9 = new CD3D9Driver(params, io);
3621 if (!dx9->initDriver(window, pureSoftware))
3622 {
3623 dx9->drop();
3624 dx9 = 0;
3625 }
3626
3627 return dx9;
3628}
3629#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
3630
3631} // end namespace video
3632} // end namespace irr
3633