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