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