diff options
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CD3D8Driver.cpp')
-rw-r--r-- | src/others/irrlicht-1.8.1/source/Irrlicht/CD3D8Driver.cpp | 2455 |
1 files changed, 2455 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D8Driver.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D8Driver.cpp new file mode 100644 index 0000000..9886b37 --- /dev/null +++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D8Driver.cpp | |||
@@ -0,0 +1,2455 @@ | |||
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 | #include "IrrCompileConfig.h" | ||
6 | |||
7 | #define _IRR_DONT_DO_MEMORY_DEBUGGING_HERE | ||
8 | #include "CD3D8Driver.h" | ||
9 | |||
10 | #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
11 | |||
12 | #include "os.h" | ||
13 | #include "S3DVertex.h" | ||
14 | #include "CD3D8Texture.h" | ||
15 | #include "CD3D8MaterialRenderer.h" | ||
16 | #include "CD3D8ShaderMaterialRenderer.h" | ||
17 | #include "CD3D8NormalMapRenderer.h" | ||
18 | #include "CD3D8ParallaxMapRenderer.h" | ||
19 | #include "SIrrCreationParameters.h" | ||
20 | |||
21 | namespace irr | ||
22 | { | ||
23 | namespace video | ||
24 | { | ||
25 | |||
26 | |||
27 | //! constructor | ||
28 | CD3D8Driver::CD3D8Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io) | ||
29 | : CNullDriver(io, params.WindowSize), CurrentRenderMode(ERM_NONE), | ||
30 | ResetRenderStates(true), Transformation3DChanged(false), | ||
31 | D3DLibrary(0), pID3D(0), pID3DDevice(0), PrevRenderTarget(0), | ||
32 | WindowId(0), SceneSourceRect(0), | ||
33 | LastVertexType((video::E_VERTEX_TYPE)-1), | ||
34 | MaxTextureUnits(0), MaxUserClipPlanes(0), | ||
35 | MaxLightDistance(0), LastSetLight(-1), DeviceLost(false), | ||
36 | DriverWasReset(true), Params(params) | ||
37 | { | ||
38 | #ifdef _DEBUG | ||
39 | setDebugName("CD3D8Driver"); | ||
40 | #endif | ||
41 | |||
42 | printVersion(); | ||
43 | |||
44 | for (u32 i=0; i<MATERIAL_MAX_TEXTURES; ++i) | ||
45 | CurrentTexture[i] = 0; | ||
46 | MaxLightDistance=sqrtf(FLT_MAX); | ||
47 | // create sphere map matrix | ||
48 | |||
49 | SphereMapMatrixD3D8._11 = 0.5f; SphereMapMatrixD3D8._12 = 0.0f; | ||
50 | SphereMapMatrixD3D8._13 = 0.0f; SphereMapMatrixD3D8._14 = 0.0f; | ||
51 | SphereMapMatrixD3D8._21 = 0.0f; SphereMapMatrixD3D8._22 =-0.5f; | ||
52 | SphereMapMatrixD3D8._23 = 0.0f; SphereMapMatrixD3D8._24 = 0.0f; | ||
53 | SphereMapMatrixD3D8._31 = 0.0f; SphereMapMatrixD3D8._32 = 0.0f; | ||
54 | SphereMapMatrixD3D8._33 = 1.0f; SphereMapMatrixD3D8._34 = 0.0f; | ||
55 | SphereMapMatrixD3D8._41 = 0.5f; SphereMapMatrixD3D8._42 = 0.5f; | ||
56 | SphereMapMatrixD3D8._43 = 0.0f; SphereMapMatrixD3D8._44 = 1.0f; | ||
57 | |||
58 | UnitMatrixD3D8 = *(D3DMATRIX*)((void*)core::IdentityMatrix.pointer()); | ||
59 | |||
60 | // init direct 3d is done in the factory function | ||
61 | } | ||
62 | |||
63 | |||
64 | //! destructor | ||
65 | CD3D8Driver::~CD3D8Driver() | ||
66 | { | ||
67 | deleteMaterialRenders(); | ||
68 | |||
69 | // drop d3d8 | ||
70 | |||
71 | if (pID3DDevice) | ||
72 | pID3DDevice->Release(); | ||
73 | |||
74 | if (pID3D) | ||
75 | pID3D->Release(); | ||
76 | } | ||
77 | |||
78 | |||
79 | void CD3D8Driver::createMaterialRenderers() | ||
80 | { | ||
81 | // create D3D8 material renderers | ||
82 | |||
83 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_SOLID(pID3DDevice, this)); | ||
84 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_SOLID_2_LAYER(pID3DDevice, this)); | ||
85 | |||
86 | // add the same renderer for all lightmap types | ||
87 | CD3D8MaterialRenderer_LIGHTMAP* lmr = new CD3D8MaterialRenderer_LIGHTMAP(pID3DDevice, this); | ||
88 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP: | ||
89 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD: | ||
90 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2: | ||
91 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4: | ||
92 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING: | ||
93 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2: | ||
94 | addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4: | ||
95 | lmr->drop(); | ||
96 | |||
97 | // add remaining material renderers | ||
98 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_DETAIL_MAP(pID3DDevice, this)); | ||
99 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_SPHERE_MAP(pID3DDevice, this)); | ||
100 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_REFLECTION_2_LAYER(pID3DDevice, this)); | ||
101 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_TRANSPARENT_ADD_COLOR(pID3DDevice, this)); | ||
102 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(pID3DDevice, this)); | ||
103 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(pID3DDevice, this)); | ||
104 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(pID3DDevice, this)); | ||
105 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(pID3DDevice, this)); | ||
106 | |||
107 | // add normal map renderers | ||
108 | s32 tmp = 0; | ||
109 | video::IMaterialRenderer* renderer = 0; | ||
110 | |||
111 | renderer = new CD3D8NormalMapRenderer(pID3DDevice, this, tmp, | ||
112 | MaterialRenderers[EMT_SOLID].Renderer); | ||
113 | renderer->drop(); | ||
114 | |||
115 | renderer = new CD3D8NormalMapRenderer(pID3DDevice, this, tmp, | ||
116 | MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); | ||
117 | renderer->drop(); | ||
118 | |||
119 | renderer = new CD3D8NormalMapRenderer(pID3DDevice, this, tmp, | ||
120 | MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); | ||
121 | renderer->drop(); | ||
122 | |||
123 | // add parallax map renderers | ||
124 | |||
125 | renderer = new CD3D8ParallaxMapRenderer(pID3DDevice, this, tmp, | ||
126 | MaterialRenderers[EMT_SOLID].Renderer); | ||
127 | renderer->drop(); | ||
128 | |||
129 | renderer = new CD3D8ParallaxMapRenderer(pID3DDevice, this, tmp, | ||
130 | MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); | ||
131 | renderer->drop(); | ||
132 | |||
133 | renderer = new CD3D8ParallaxMapRenderer(pID3DDevice, this, tmp, | ||
134 | MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); | ||
135 | renderer->drop(); | ||
136 | |||
137 | // add basic 1 texture blending | ||
138 | addAndDropMaterialRenderer(new CD3D8MaterialRenderer_ONETEXTURE_BLEND(pID3DDevice, this)); | ||
139 | } | ||
140 | |||
141 | |||
142 | //! initialises the Direct3D API | ||
143 | bool CD3D8Driver::initDriver(HWND hwnd, bool pureSoftware) | ||
144 | { | ||
145 | HRESULT hr; | ||
146 | typedef IDirect3D8 * (__stdcall *D3DCREATETYPE)(UINT); | ||
147 | |||
148 | #if defined( _IRR_XBOX_PLATFORM_) | ||
149 | D3DCREATETYPE d3dCreate = (D3DCREATETYPE) &Direct3DCreate8; | ||
150 | #else | ||
151 | D3DLibrary = LoadLibrary( __TEXT("d3d8.dll") ); | ||
152 | |||
153 | if (!D3DLibrary) | ||
154 | { | ||
155 | os::Printer::log("Error, could not load d3d8.dll.", ELL_ERROR); | ||
156 | return false; | ||
157 | } | ||
158 | |||
159 | D3DCREATETYPE d3dCreate = (D3DCREATETYPE) GetProcAddress(D3DLibrary, "Direct3DCreate8"); | ||
160 | |||
161 | if (!d3dCreate) | ||
162 | { | ||
163 | os::Printer::log("Error, could not get proc adress of Direct3DCreate8.", ELL_ERROR); | ||
164 | return false; | ||
165 | } | ||
166 | #endif | ||
167 | |||
168 | //just like pID3D = Direct3DCreate8(D3D_SDK_VERSION); | ||
169 | pID3D = (*d3dCreate)(D3D_SDK_VERSION); | ||
170 | |||
171 | if (!pID3D) | ||
172 | { | ||
173 | os::Printer::log("Error initializing D3D.", ELL_ERROR); | ||
174 | return false; | ||
175 | } | ||
176 | |||
177 | // print device information | ||
178 | D3DADAPTER_IDENTIFIER8 dai; | ||
179 | if (!FAILED(pID3D->GetAdapterIdentifier(Params.DisplayAdapter, D3DENUM_NO_WHQL_LEVEL, &dai))) | ||
180 | { | ||
181 | char tmp[512]; | ||
182 | |||
183 | s32 Product = HIWORD(dai.DriverVersion.HighPart); | ||
184 | s32 Version = LOWORD(dai.DriverVersion.HighPart); | ||
185 | s32 SubVersion = HIWORD(dai.DriverVersion.LowPart); | ||
186 | s32 Build = LOWORD(dai.DriverVersion.LowPart); | ||
187 | |||
188 | sprintf(tmp, "%s %s %d.%d.%d.%d", dai.Description, dai.Driver, Product, Version, | ||
189 | SubVersion, Build); | ||
190 | os::Printer::log(tmp, ELL_INFORMATION); | ||
191 | } | ||
192 | |||
193 | D3DDISPLAYMODE d3ddm; | ||
194 | hr = pID3D->GetAdapterDisplayMode(Params.DisplayAdapter, &d3ddm); | ||
195 | if (FAILED(hr)) | ||
196 | { | ||
197 | os::Printer::log("Error: Could not get Adapter Display mode.", ELL_ERROR); | ||
198 | return false; | ||
199 | } | ||
200 | |||
201 | ZeroMemory(&present, sizeof(present)); | ||
202 | |||
203 | present.SwapEffect = D3DSWAPEFFECT_DISCARD; | ||
204 | present.Windowed = TRUE; | ||
205 | present.BackBufferFormat = d3ddm.Format; | ||
206 | present.EnableAutoDepthStencil = TRUE; | ||
207 | |||
208 | if (Params.Fullscreen) | ||
209 | { | ||
210 | present.SwapEffect = D3DSWAPEFFECT_FLIP; | ||
211 | present.Windowed = FALSE; | ||
212 | present.BackBufferWidth = Params.WindowSize.Width; | ||
213 | present.BackBufferHeight = Params.WindowSize.Height; | ||
214 | present.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; | ||
215 | |||
216 | if (Params.Vsync) | ||
217 | present.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; | ||
218 | else | ||
219 | present.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; | ||
220 | |||
221 | if (Params.Bits == 32) | ||
222 | present.BackBufferFormat = D3DFMT_X8R8G8B8; | ||
223 | else | ||
224 | present.BackBufferFormat = D3DFMT_R5G6B5; | ||
225 | } | ||
226 | |||
227 | D3DDEVTYPE devtype = D3DDEVTYPE_HAL; | ||
228 | #ifndef _IRR_D3D_NO_SHADER_DEBUGGING | ||
229 | devtype = D3DDEVTYPE_REF; | ||
230 | #endif | ||
231 | |||
232 | // enable anti alias if possible and whished | ||
233 | if (Params.AntiAlias > 0) | ||
234 | { | ||
235 | if(Params.AntiAlias > 16) | ||
236 | Params.AntiAlias = 16; | ||
237 | |||
238 | while(Params.AntiAlias > 0) | ||
239 | { | ||
240 | if(!FAILED(pID3D->CheckDeviceMultiSampleType(Params.DisplayAdapter, | ||
241 | devtype , present.BackBufferFormat, !Params.Fullscreen, | ||
242 | (D3DMULTISAMPLE_TYPE)Params.AntiAlias))) | ||
243 | { | ||
244 | present.MultiSampleType = (D3DMULTISAMPLE_TYPE)Params.AntiAlias; | ||
245 | present.SwapEffect = D3DSWAPEFFECT_DISCARD; | ||
246 | break; | ||
247 | } | ||
248 | --Params.AntiAlias; | ||
249 | } | ||
250 | |||
251 | if(Params.AntiAlias==0) | ||
252 | os::Printer::log("Anti aliasing disabled because hardware/driver lacks necessary caps.", ELL_WARNING); | ||
253 | } | ||
254 | |||
255 | // check stencil buffer compatibility | ||
256 | if (Params.Stencilbuffer) | ||
257 | { | ||
258 | present.AutoDepthStencilFormat = D3DFMT_D24S8; | ||
259 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
260 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
261 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
262 | { | ||
263 | #if !defined( _IRR_XBOX_PLATFORM_) | ||
264 | present.AutoDepthStencilFormat = D3DFMT_D24X4S4; | ||
265 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
266 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
267 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
268 | { | ||
269 | present.AutoDepthStencilFormat = D3DFMT_D15S1; | ||
270 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
271 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
272 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
273 | { | ||
274 | os::Printer::log("Device does not support stencilbuffer, disabling stencil buffer.", ELL_WARNING); | ||
275 | Params.Stencilbuffer = false; | ||
276 | } | ||
277 | } | ||
278 | #endif | ||
279 | } | ||
280 | else | ||
281 | if(FAILED(pID3D->CheckDepthStencilMatch(Params.DisplayAdapter, devtype, | ||
282 | present.BackBufferFormat, present.BackBufferFormat, present.AutoDepthStencilFormat))) | ||
283 | { | ||
284 | os::Printer::log("Depth-stencil format is not compatible with display format, disabling stencil buffer.", ELL_WARNING); | ||
285 | Params.Stencilbuffer = false; | ||
286 | } | ||
287 | } | ||
288 | // do not use else here to cope with flag change in previous block | ||
289 | if (!Params.Stencilbuffer) | ||
290 | { | ||
291 | #if !defined( _IRR_XBOX_PLATFORM_) | ||
292 | present.AutoDepthStencilFormat = D3DFMT_D32; | ||
293 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
294 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
295 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
296 | { | ||
297 | present.AutoDepthStencilFormat = D3DFMT_D24X8; | ||
298 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
299 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
300 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
301 | { | ||
302 | present.AutoDepthStencilFormat = D3DFMT_D16; | ||
303 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
304 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
305 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
306 | { | ||
307 | os::Printer::log("Device does not support required depth buffer.", ELL_WARNING); | ||
308 | return false; | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | #else | ||
313 | present.AutoDepthStencilFormat = D3DFMT_D16; | ||
314 | if(FAILED(pID3D->CheckDeviceFormat(Params.DisplayAdapter, devtype, | ||
315 | present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, | ||
316 | D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) | ||
317 | { | ||
318 | os::Printer::log("Device does not support required depth buffer.", ELL_WARNING); | ||
319 | return false; | ||
320 | } | ||
321 | #endif | ||
322 | } | ||
323 | |||
324 | // create device | ||
325 | #if defined( _IRR_XBOX_PLATFORM_) | ||
326 | DWORD fpuPrecision = 0; | ||
327 | #else | ||
328 | DWORD fpuPrecision = Params.HighPrecisionFPU ? D3DCREATE_FPU_PRESERVE : 0; | ||
329 | DWORD multithreaded = Params.DriverMultithreaded ? D3DCREATE_MULTITHREADED : 0; | ||
330 | #endif | ||
331 | if (pureSoftware) | ||
332 | { | ||
333 | hr = pID3D->CreateDevice(Params.DisplayAdapter, D3DDEVTYPE_REF, hwnd, | ||
334 | fpuPrecision | multithreaded | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice); | ||
335 | |||
336 | if (FAILED(hr)) | ||
337 | os::Printer::log("Was not able to create Direct3D8 software device.", ELL_ERROR); | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | hr = pID3D->CreateDevice(Params.DisplayAdapter, devtype, hwnd, | ||
342 | fpuPrecision | multithreaded | D3DCREATE_HARDWARE_VERTEXPROCESSING, &present, &pID3DDevice); | ||
343 | |||
344 | if(FAILED(hr)) | ||
345 | hr = pID3D->CreateDevice(Params.DisplayAdapter, devtype, hwnd, | ||
346 | fpuPrecision | multithreaded | D3DCREATE_MIXED_VERTEXPROCESSING , &present, &pID3DDevice); | ||
347 | if(FAILED(hr)) | ||
348 | hr = pID3D->CreateDevice(Params.DisplayAdapter, devtype, hwnd, | ||
349 | fpuPrecision | multithreaded | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice); | ||
350 | if (FAILED(hr)) | ||
351 | os::Printer::log("Was not able to create Direct3D8 device.", ELL_ERROR); | ||
352 | } | ||
353 | |||
354 | if (!pID3DDevice) | ||
355 | { | ||
356 | os::Printer::log("Was not able to create Direct3D8 device.", ELL_ERROR); | ||
357 | return false; | ||
358 | } | ||
359 | |||
360 | // get caps | ||
361 | pID3DDevice->GetDeviceCaps(&Caps); | ||
362 | |||
363 | if (Params.Stencilbuffer && | ||
364 | (!(Caps.StencilCaps & D3DSTENCILCAPS_DECRSAT) || | ||
365 | !(Caps.StencilCaps & D3DSTENCILCAPS_INCRSAT) || | ||
366 | !(Caps.StencilCaps & D3DSTENCILCAPS_KEEP))) | ||
367 | { | ||
368 | os::Printer::log("Device not able to use stencil buffer, disabling stencil buffer.", ELL_WARNING); | ||
369 | Params.Stencilbuffer = false; | ||
370 | } | ||
371 | |||
372 | // set default vertex shader | ||
373 | setVertexShader(EVT_STANDARD); | ||
374 | |||
375 | // enable antialiasing | ||
376 | if (Params.AntiAlias>0) | ||
377 | pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); | ||
378 | |||
379 | // set fog mode | ||
380 | setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); | ||
381 | |||
382 | // set exposed data | ||
383 | ExposedData.D3D8.D3D8 = pID3D; | ||
384 | ExposedData.D3D8.D3DDev8 = pID3DDevice; | ||
385 | ExposedData.D3D8.HWnd = hwnd; | ||
386 | |||
387 | ResetRenderStates = true; | ||
388 | |||
389 | // create materials | ||
390 | createMaterialRenderers(); | ||
391 | |||
392 | MaxTextureUnits = core::min_((u32)Caps.MaxSimultaneousTextures, MATERIAL_MAX_TEXTURES); | ||
393 | MaxUserClipPlanes = (u32)Caps.MaxUserClipPlanes; | ||
394 | |||
395 | DriverAttributes->setAttribute("MaxTextures", (s32)MaxTextureUnits); | ||
396 | DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Caps.MaxSimultaneousTextures); | ||
397 | DriverAttributes->setAttribute("MaxLights", (s32)Caps.MaxActiveLights); | ||
398 | DriverAttributes->setAttribute("MaxAnisotropy", (s32)Caps.MaxAnisotropy); | ||
399 | DriverAttributes->setAttribute("MaxUserClipPlanes", (s32)Caps.MaxUserClipPlanes); | ||
400 | DriverAttributes->setAttribute("MaxIndices", (s32)Caps.MaxVertexIndex); | ||
401 | DriverAttributes->setAttribute("MaxTextureSize", (s32)core::min_(Caps.MaxTextureHeight,Caps.MaxTextureWidth)); | ||
402 | DriverAttributes->setAttribute("MaxTextureLODBias", 16.f); | ||
403 | DriverAttributes->setAttribute("Version", 800); | ||
404 | DriverAttributes->setAttribute("ShaderLanguageVersion", (s32)Caps.VertexShaderVersion*100); | ||
405 | DriverAttributes->setAttribute("AntiAlias", Params.AntiAlias); | ||
406 | |||
407 | // set the renderstates | ||
408 | setRenderStates3DMode(); | ||
409 | |||
410 | // so far so good. | ||
411 | return true; | ||
412 | } | ||
413 | |||
414 | |||
415 | //! applications must call this method before performing any rendering. returns false if failed. | ||
416 | bool CD3D8Driver::beginScene(bool backBuffer, bool zBuffer, SColor color, | ||
417 | const SExposedVideoData& videoData, core::rect<s32>* sourceRect) | ||
418 | { | ||
419 | CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect); | ||
420 | WindowId = (HWND)videoData.D3D8.HWnd; | ||
421 | SceneSourceRect = sourceRect; | ||
422 | |||
423 | if (!pID3DDevice) | ||
424 | return false; | ||
425 | |||
426 | HRESULT hr; | ||
427 | if (DeviceLost) | ||
428 | { | ||
429 | #ifndef _IRR_XBOX_PLATFORM_ | ||
430 | if(FAILED(hr = pID3DDevice->TestCooperativeLevel())) | ||
431 | { | ||
432 | if (hr == D3DERR_DEVICELOST) | ||
433 | { | ||
434 | Sleep(100); | ||
435 | hr = pID3DDevice->TestCooperativeLevel(); | ||
436 | if (hr == D3DERR_DEVICELOST) | ||
437 | return false; | ||
438 | } | ||
439 | |||
440 | if ((hr == D3DERR_DEVICENOTRESET) && !reset()) | ||
441 | return false; | ||
442 | } | ||
443 | #endif | ||
444 | } | ||
445 | |||
446 | DWORD flags = 0; | ||
447 | |||
448 | if (backBuffer) | ||
449 | flags |= D3DCLEAR_TARGET; | ||
450 | |||
451 | if (zBuffer) | ||
452 | flags |= D3DCLEAR_ZBUFFER; | ||
453 | |||
454 | if (Params.Stencilbuffer) | ||
455 | flags |= D3DCLEAR_STENCIL; | ||
456 | |||
457 | if (flags) | ||
458 | { | ||
459 | hr = pID3DDevice->Clear( 0, NULL, flags, color.color, 1.0, 0); | ||
460 | if (FAILED(hr)) | ||
461 | os::Printer::log("Direct3D8 clear failed.", ELL_WARNING); | ||
462 | } | ||
463 | |||
464 | hr = pID3DDevice->BeginScene(); | ||
465 | if (FAILED(hr)) | ||
466 | { | ||
467 | os::Printer::log("Direct3D8 begin scene failed.", ELL_WARNING); | ||
468 | return false; | ||
469 | } | ||
470 | |||
471 | return true; | ||
472 | } | ||
473 | |||
474 | |||
475 | //! applications must call this method after performing any rendering. returns false if failed. | ||
476 | bool CD3D8Driver::endScene() | ||
477 | { | ||
478 | CNullDriver::endScene(); | ||
479 | DriverWasReset=false; | ||
480 | |||
481 | HRESULT hr = pID3DDevice->EndScene(); | ||
482 | if (FAILED(hr)) | ||
483 | { | ||
484 | os::Printer::log("DIRECT3D8 end scene failed.", ELL_WARNING); | ||
485 | return false; | ||
486 | } | ||
487 | |||
488 | RECT* srcRct = 0; | ||
489 | RECT sourceRectData; | ||
490 | if ( SceneSourceRect) | ||
491 | { | ||
492 | srcRct = &sourceRectData; | ||
493 | sourceRectData.left = SceneSourceRect->UpperLeftCorner.X; | ||
494 | sourceRectData.top = SceneSourceRect->UpperLeftCorner.Y; | ||
495 | sourceRectData.right = SceneSourceRect->LowerRightCorner.X; | ||
496 | sourceRectData.bottom = SceneSourceRect->LowerRightCorner.Y; | ||
497 | } | ||
498 | |||
499 | hr = pID3DDevice->Present(srcRct, NULL, WindowId, NULL); | ||
500 | |||
501 | if (SUCCEEDED(hr)) | ||
502 | return true; | ||
503 | |||
504 | if (hr == D3DERR_DEVICELOST) | ||
505 | { | ||
506 | DeviceLost = true; | ||
507 | os::Printer::log("DIRECT3D8 device lost.", ELL_WARNING); | ||
508 | } | ||
509 | else | ||
510 | os::Printer::log("DIRECT3D8 present failed.", ELL_WARNING); | ||
511 | return false; | ||
512 | } | ||
513 | |||
514 | |||
515 | //! resets the device | ||
516 | bool CD3D8Driver::reset() | ||
517 | { | ||
518 | u32 i; | ||
519 | os::Printer::log("Resetting D3D8 device.", ELL_INFORMATION); | ||
520 | |||
521 | for (i=0; i<Textures.size(); ++i) | ||
522 | { | ||
523 | if (Textures[i].Surface->isRenderTarget()) | ||
524 | { | ||
525 | IDirect3DTexture8* tex = ((CD3D8Texture*)(Textures[i].Surface))->getDX8Texture(); | ||
526 | if (tex) | ||
527 | tex->Release(); | ||
528 | } | ||
529 | } | ||
530 | DriverWasReset=true; | ||
531 | |||
532 | HRESULT hr = pID3DDevice->Reset(&present); | ||
533 | |||
534 | for (i=0; i<Textures.size(); ++i) | ||
535 | { | ||
536 | if (Textures[i].Surface->isRenderTarget()) | ||
537 | ((CD3D8Texture*)(Textures[i].Surface))->createRenderTarget(); | ||
538 | } | ||
539 | |||
540 | if (FAILED(hr)) | ||
541 | { | ||
542 | if (hr == D3DERR_DEVICELOST) | ||
543 | { | ||
544 | DeviceLost = true; | ||
545 | os::Printer::log("Resetting failed due to device lost.", ELL_WARNING); | ||
546 | } | ||
547 | else | ||
548 | os::Printer::log("Resetting failed.", ELL_WARNING); | ||
549 | return false; | ||
550 | } | ||
551 | |||
552 | DeviceLost = false; | ||
553 | ResetRenderStates = true; | ||
554 | LastVertexType = (E_VERTEX_TYPE)-1; | ||
555 | |||
556 | for (i=0; i<MATERIAL_MAX_TEXTURES; ++i) | ||
557 | CurrentTexture[i] = 0; | ||
558 | |||
559 | setVertexShader(EVT_STANDARD); | ||
560 | setRenderStates3DMode(); | ||
561 | setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); | ||
562 | setAmbientLight(AmbientLight); | ||
563 | |||
564 | return true; | ||
565 | } | ||
566 | |||
567 | |||
568 | //! queries the features of the driver, returns true if feature is available | ||
569 | bool CD3D8Driver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const | ||
570 | { | ||
571 | if (!FeatureEnabled[feature]) | ||
572 | return false; | ||
573 | |||
574 | switch (feature) | ||
575 | { | ||
576 | case EVDF_RENDER_TO_TARGET: | ||
577 | case EVDF_MULTITEXTURE: | ||
578 | case EVDF_BILINEAR_FILTER: | ||
579 | return true; | ||
580 | case EVDF_HARDWARE_TL: | ||
581 | return (Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0; | ||
582 | case EVDF_MIP_MAP: | ||
583 | return (Caps.TextureCaps & D3DPTEXTURECAPS_MIPMAP) != 0; | ||
584 | case EVDF_STENCIL_BUFFER: | ||
585 | return Params.Stencilbuffer && Caps.StencilCaps; | ||
586 | case EVDF_VERTEX_SHADER_1_1: | ||
587 | return Caps.VertexShaderVersion >= D3DVS_VERSION(1,1); | ||
588 | case EVDF_VERTEX_SHADER_2_0: | ||
589 | return Caps.VertexShaderVersion >= D3DVS_VERSION(2,0); | ||
590 | case EVDF_VERTEX_SHADER_3_0: | ||
591 | return Caps.VertexShaderVersion >= D3DVS_VERSION(3,0); | ||
592 | case EVDF_PIXEL_SHADER_1_1: | ||
593 | return Caps.PixelShaderVersion >= D3DPS_VERSION(1,1); | ||
594 | case EVDF_PIXEL_SHADER_1_2: | ||
595 | return Caps.PixelShaderVersion >= D3DPS_VERSION(1,2); | ||
596 | case EVDF_PIXEL_SHADER_1_3: | ||
597 | return Caps.PixelShaderVersion >= D3DPS_VERSION(1,3); | ||
598 | case EVDF_PIXEL_SHADER_1_4: | ||
599 | return Caps.PixelShaderVersion >= D3DPS_VERSION(1,4); | ||
600 | case EVDF_PIXEL_SHADER_2_0: | ||
601 | return Caps.PixelShaderVersion >= D3DPS_VERSION(2,0); | ||
602 | case EVDF_PIXEL_SHADER_3_0: | ||
603 | return Caps.PixelShaderVersion >= D3DPS_VERSION(3,0); | ||
604 | case EVDF_TEXTURE_NSQUARE: | ||
605 | return (Caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) == 0; | ||
606 | case EVDF_TEXTURE_NPOT: | ||
607 | return (Caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0; | ||
608 | case EVDF_COLOR_MASK: | ||
609 | return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0; | ||
610 | case EVDF_BLEND_OPERATIONS: | ||
611 | case EVDF_TEXTURE_MATRIX: | ||
612 | return true; | ||
613 | default: | ||
614 | return false; | ||
615 | }; | ||
616 | } | ||
617 | |||
618 | |||
619 | //! sets transformation | ||
620 | void CD3D8Driver::setTransform(E_TRANSFORMATION_STATE state, | ||
621 | const core::matrix4& mat) | ||
622 | { | ||
623 | switch(state) | ||
624 | { | ||
625 | case ETS_VIEW: | ||
626 | pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)mat.pointer())); | ||
627 | Transformation3DChanged = true; | ||
628 | break; | ||
629 | case ETS_WORLD: | ||
630 | pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer())); | ||
631 | Transformation3DChanged = true; | ||
632 | break; | ||
633 | case ETS_PROJECTION: | ||
634 | pID3DDevice->SetTransform( D3DTS_PROJECTION, (D3DMATRIX*)((void*)mat.pointer())); | ||
635 | Transformation3DChanged = true; | ||
636 | break; | ||
637 | case ETS_COUNT: | ||
638 | return; | ||
639 | default: | ||
640 | if (state-ETS_TEXTURE_0 < MATERIAL_MAX_TEXTURES) | ||
641 | { | ||
642 | pID3DDevice->SetTextureStageState( state - ETS_TEXTURE_0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); | ||
643 | pID3DDevice->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0+ ( state - ETS_TEXTURE_0 )), | ||
644 | (D3DMATRIX*)((void*)mat.pointer())); | ||
645 | } | ||
646 | break; | ||
647 | } | ||
648 | |||
649 | Matrices[state] = mat; | ||
650 | } | ||
651 | |||
652 | |||
653 | //! sets the current Texture | ||
654 | bool CD3D8Driver::setActiveTexture(u32 stage, const video::ITexture* texture) | ||
655 | { | ||
656 | if (CurrentTexture[stage] == texture) | ||
657 | return true; | ||
658 | |||
659 | if (texture && (texture->getDriverType() != EDT_DIRECT3D8)) | ||
660 | { | ||
661 | os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); | ||
662 | return false; | ||
663 | } | ||
664 | |||
665 | CurrentTexture[stage] = texture; | ||
666 | |||
667 | if (!texture) | ||
668 | { | ||
669 | pID3DDevice->SetTexture(stage, 0); | ||
670 | pID3DDevice->SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | pID3DDevice->SetTexture(stage, ((const CD3D8Texture*)texture)->getDX8Texture()); | ||
675 | } | ||
676 | return true; | ||
677 | } | ||
678 | |||
679 | |||
680 | //! sets a material | ||
681 | void CD3D8Driver::setMaterial(const SMaterial& material) | ||
682 | { | ||
683 | Material = material; | ||
684 | OverrideMaterial.apply(Material); | ||
685 | |||
686 | for (u32 i=0; i<MaxTextureUnits; ++i) | ||
687 | { | ||
688 | setActiveTexture(i, Material.getTexture(i)); | ||
689 | setTransform((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ), | ||
690 | material.getTextureMatrix(i)); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | |||
695 | //! returns a device dependent texture from a software surface (IImage) | ||
696 | video::ITexture* CD3D8Driver::createDeviceDependentTexture(IImage* surface,const io::path& name, void* mipmapData) | ||
697 | { | ||
698 | return new CD3D8Texture(surface, this, TextureCreationFlags, name, mipmapData); | ||
699 | } | ||
700 | |||
701 | |||
702 | //! Enables or disables a texture creation flag. | ||
703 | void CD3D8Driver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, | ||
704 | bool enabled) | ||
705 | { | ||
706 | if (flag == video::ETCF_CREATE_MIP_MAPS && !queryFeature(EVDF_MIP_MAP)) | ||
707 | enabled = false; | ||
708 | |||
709 | CNullDriver::setTextureCreationFlag(flag, enabled); | ||
710 | } | ||
711 | |||
712 | |||
713 | //! sets a render target | ||
714 | bool CD3D8Driver::setRenderTarget(video::ITexture* texture, | ||
715 | bool clearBackBuffer, bool clearZBuffer, SColor color) | ||
716 | { | ||
717 | // check for right driver type | ||
718 | |||
719 | if (texture && texture->getDriverType() != EDT_DIRECT3D8) | ||
720 | { | ||
721 | os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); | ||
722 | return false; | ||
723 | } | ||
724 | |||
725 | // check for valid render target | ||
726 | |||
727 | CD3D8Texture* tex = (CD3D8Texture*)texture; | ||
728 | |||
729 | if (texture && !tex->isRenderTarget()) | ||
730 | { | ||
731 | os::Printer::log("Fatal Error: Tried to set a non render target texture as render target.", ELL_ERROR); | ||
732 | return false; | ||
733 | } | ||
734 | |||
735 | if (texture && (tex->getSize().Width > ScreenSize.Width || | ||
736 | tex->getSize().Height > ScreenSize.Height )) | ||
737 | { | ||
738 | os::Printer::log("Error: Tried to set a render target texture which is bigger than the screen.", ELL_ERROR); | ||
739 | return false; | ||
740 | } | ||
741 | |||
742 | // check if we should set the previous RT back | ||
743 | |||
744 | bool ret = true; | ||
745 | |||
746 | if (tex == 0) | ||
747 | { | ||
748 | if (PrevRenderTarget) | ||
749 | { | ||
750 | IDirect3DSurface8* dss = 0; | ||
751 | pID3DDevice->GetDepthStencilSurface(&dss); | ||
752 | |||
753 | if (FAILED(pID3DDevice->SetRenderTarget(PrevRenderTarget, dss))) | ||
754 | { | ||
755 | os::Printer::log("Error: Could not set back to previous render target.", ELL_ERROR); | ||
756 | ret = false; | ||
757 | } | ||
758 | |||
759 | if (dss) | ||
760 | dss->Release(); | ||
761 | |||
762 | CurrentRendertargetSize = core::dimension2d<u32>(0,0); | ||
763 | PrevRenderTarget->Release(); | ||
764 | PrevRenderTarget = 0; | ||
765 | } | ||
766 | } | ||
767 | else | ||
768 | { | ||
769 | // we want to set a new target. so do this. | ||
770 | |||
771 | // store previous target | ||
772 | |||
773 | if (!PrevRenderTarget && (FAILED(pID3DDevice->GetRenderTarget(&PrevRenderTarget)))) | ||
774 | { | ||
775 | os::Printer::log("Could not get previous render target.", ELL_ERROR); | ||
776 | return false; | ||
777 | } | ||
778 | |||
779 | // set new render target | ||
780 | |||
781 | IDirect3DSurface8* dss = 0; | ||
782 | pID3DDevice->GetDepthStencilSurface(&dss); | ||
783 | |||
784 | if (FAILED(pID3DDevice->SetRenderTarget(tex->getRenderTargetSurface(), dss))) | ||
785 | { | ||
786 | os::Printer::log("Error: Could not set render target.", ELL_ERROR); | ||
787 | ret = false; | ||
788 | } | ||
789 | |||
790 | if (dss) | ||
791 | dss->Release(); | ||
792 | |||
793 | CurrentRendertargetSize = tex->getSize(); | ||
794 | } | ||
795 | Transformation3DChanged = true; | ||
796 | |||
797 | if (clearBackBuffer || clearZBuffer) | ||
798 | { | ||
799 | DWORD flags = 0; | ||
800 | |||
801 | if (clearBackBuffer) | ||
802 | flags |= D3DCLEAR_TARGET; | ||
803 | |||
804 | if (clearZBuffer) | ||
805 | flags |= D3DCLEAR_ZBUFFER; | ||
806 | |||
807 | pID3DDevice->Clear(0, NULL, flags, color.color, 1.0f, 0); | ||
808 | } | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | |||
814 | //! Creates a render target texture. | ||
815 | ITexture* CD3D8Driver::addRenderTargetTexture( | ||
816 | const core::dimension2d<u32>& size, const io::path& name, | ||
817 | const ECOLOR_FORMAT format) | ||
818 | { | ||
819 | CD3D8Texture* tex = new CD3D8Texture(this, size, name); | ||
820 | if (tex) | ||
821 | { | ||
822 | if (!tex->Texture) | ||
823 | { | ||
824 | tex->drop(); | ||
825 | return 0; | ||
826 | } | ||
827 | addTexture(tex); | ||
828 | tex->drop(); | ||
829 | } | ||
830 | return tex; | ||
831 | } | ||
832 | |||
833 | |||
834 | //! sets a viewport | ||
835 | void CD3D8Driver::setViewPort(const core::rect<s32>& area) | ||
836 | { | ||
837 | core::rect<s32> vp(area); | ||
838 | core::rect<s32> rendert(0,0, ScreenSize.Width, ScreenSize.Height); | ||
839 | vp.clipAgainst(rendert); | ||
840 | |||
841 | D3DVIEWPORT8 viewPort; | ||
842 | viewPort.X = vp.UpperLeftCorner.X; | ||
843 | viewPort.Y = vp.UpperLeftCorner.Y; | ||
844 | viewPort.Width = vp.getWidth(); | ||
845 | viewPort.Height = vp.getHeight(); | ||
846 | viewPort.MinZ = 0.0f; | ||
847 | viewPort.MaxZ = 1.0f; | ||
848 | |||
849 | HRESULT hr = D3DERR_INVALIDCALL; | ||
850 | if (vp.getHeight()>0 && vp.getWidth()>0) | ||
851 | hr = pID3DDevice->SetViewport(&viewPort); | ||
852 | |||
853 | if (FAILED(hr)) | ||
854 | os::Printer::log("Failed setting the viewport.", ELL_WARNING); | ||
855 | |||
856 | ViewPort = vp; | ||
857 | } | ||
858 | |||
859 | |||
860 | //! gets the area of the current viewport | ||
861 | const core::rect<s32>& CD3D8Driver::getViewPort() const | ||
862 | { | ||
863 | return ViewPort; | ||
864 | } | ||
865 | |||
866 | |||
867 | //! draws a vertex primitive list | ||
868 | void CD3D8Driver::drawVertexPrimitiveList(const void* vertices, | ||
869 | u32 vertexCount, const void* indexList, u32 primitiveCount, | ||
870 | E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, | ||
871 | E_INDEX_TYPE iType) | ||
872 | { | ||
873 | if (!checkPrimitiveCount(primitiveCount)) | ||
874 | return; | ||
875 | |||
876 | CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType,iType); | ||
877 | |||
878 | if (!vertexCount || !primitiveCount) | ||
879 | return; | ||
880 | |||
881 | draw2D3DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, | ||
882 | vType, pType, iType, true); | ||
883 | } | ||
884 | |||
885 | |||
886 | //! draws a vertex primitive list in 2d | ||
887 | void CD3D8Driver::draw2DVertexPrimitiveList(const void* vertices, | ||
888 | u32 vertexCount, const void* indexList, u32 primitiveCount, | ||
889 | E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, | ||
890 | E_INDEX_TYPE iType) | ||
891 | { | ||
892 | if (!checkPrimitiveCount(primitiveCount)) | ||
893 | return; | ||
894 | |||
895 | CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType,iType); | ||
896 | |||
897 | if (!vertexCount || !primitiveCount) | ||
898 | return; | ||
899 | |||
900 | draw2D3DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, | ||
901 | vType, pType, iType, false); | ||
902 | } | ||
903 | |||
904 | |||
905 | void CD3D8Driver::draw2D3DVertexPrimitiveList(const void* vertices, | ||
906 | u32 vertexCount, const void* indexList, u32 primitiveCount, | ||
907 | E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, | ||
908 | E_INDEX_TYPE iType, bool is3D) | ||
909 | { | ||
910 | setVertexShader(vType); | ||
911 | |||
912 | const u32 stride = getVertexPitchFromType(vType); | ||
913 | |||
914 | D3DFORMAT indexType=D3DFMT_UNKNOWN; | ||
915 | switch (iType) | ||
916 | { | ||
917 | case (EIT_16BIT): | ||
918 | { | ||
919 | indexType=D3DFMT_INDEX16; | ||
920 | break; | ||
921 | } | ||
922 | case (EIT_32BIT): | ||
923 | { | ||
924 | indexType=D3DFMT_INDEX32; | ||
925 | break; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | if (is3D) | ||
930 | { | ||
931 | if (!setRenderStates3DMode()) | ||
932 | return; | ||
933 | } | ||
934 | else | ||
935 | { | ||
936 | if (Material.MaterialType==EMT_ONETEXTURE_BLEND) | ||
937 | { | ||
938 | E_BLEND_FACTOR srcFact; | ||
939 | E_BLEND_FACTOR dstFact; | ||
940 | E_MODULATE_FUNC modulo; | ||
941 | u32 alphaSource; | ||
942 | unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam); | ||
943 | setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0); | ||
944 | } | ||
945 | else | ||
946 | setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL); | ||
947 | } | ||
948 | |||
949 | switch (pType) | ||
950 | { | ||
951 | case scene::EPT_POINT_SPRITES: | ||
952 | case scene::EPT_POINTS: | ||
953 | { | ||
954 | f32 tmp=Material.Thickness/getScreenSize().Height; | ||
955 | if (pType==scene::EPT_POINT_SPRITES) | ||
956 | pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); | ||
957 | pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE); | ||
958 | pID3DDevice->SetRenderState(D3DRS_POINTSIZE, *(DWORD*)(&tmp)); | ||
959 | tmp=1.0f; | ||
960 | pID3DDevice->SetRenderState(D3DRS_POINTSCALE_A, *(DWORD*)(&tmp)); | ||
961 | pID3DDevice->SetRenderState(D3DRS_POINTSCALE_B, *(DWORD*)(&tmp)); | ||
962 | pID3DDevice->SetRenderState(D3DRS_POINTSIZE_MIN, *(DWORD*)(&tmp)); | ||
963 | tmp=0.0f; | ||
964 | pID3DDevice->SetRenderState(D3DRS_POINTSCALE_C, *(DWORD*)(&tmp)); | ||
965 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_POINTLIST, 0, vertexCount, | ||
966 | primitiveCount, indexList, indexType, vertices, stride); | ||
967 | pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); | ||
968 | if (pType==scene::EPT_POINT_SPRITES) | ||
969 | pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE); | ||
970 | } | ||
971 | break; | ||
972 | case scene::EPT_LINE_STRIP: | ||
973 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount, | ||
974 | primitiveCount, indexList, indexType, vertices, stride); | ||
975 | break; | ||
976 | case scene::EPT_LINE_LOOP: | ||
977 | { | ||
978 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount, | ||
979 | primitiveCount - 1, indexList, indexType, vertices, stride); | ||
980 | u16 tmpIndices[] = {primitiveCount - 1, 0}; | ||
981 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, vertexCount, | ||
982 | 1, tmpIndices, indexType, vertices, stride); | ||
983 | } | ||
984 | break; | ||
985 | case scene::EPT_LINES: | ||
986 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, vertexCount, | ||
987 | primitiveCount, indexList, indexType, vertices, stride); | ||
988 | break; | ||
989 | case scene::EPT_TRIANGLE_STRIP: | ||
990 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLESTRIP, 0, vertexCount, | ||
991 | primitiveCount, indexList, indexType, vertices, stride); | ||
992 | break; | ||
993 | case scene::EPT_TRIANGLE_FAN: | ||
994 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLEFAN, 0, vertexCount, | ||
995 | primitiveCount, indexList, indexType, vertices, stride); | ||
996 | break; | ||
997 | case scene::EPT_TRIANGLES: | ||
998 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, vertexCount, | ||
999 | primitiveCount, indexList, indexType, vertices, stride); | ||
1000 | break; | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. | ||
1006 | void CD3D8Driver::draw2DImage(const video::ITexture* texture, | ||
1007 | const core::position2d<s32>& pos, | ||
1008 | const core::rect<s32>& sourceRect, | ||
1009 | const core::rect<s32>* clipRect, SColor color, | ||
1010 | bool useAlphaChannelOfTexture) | ||
1011 | { | ||
1012 | if (!texture) | ||
1013 | return; | ||
1014 | |||
1015 | if (!sourceRect.isValid()) | ||
1016 | return; | ||
1017 | |||
1018 | if (!setActiveTexture(0, texture)) | ||
1019 | return; | ||
1020 | |||
1021 | core::position2d<s32> targetPos = pos; | ||
1022 | core::position2d<s32> sourcePos = sourceRect.UpperLeftCorner; | ||
1023 | // This needs to be signed as it may go negative. | ||
1024 | core::dimension2d<s32> sourceSize(sourceRect.getSize()); | ||
1025 | const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize(); | ||
1026 | |||
1027 | if (clipRect) | ||
1028 | { | ||
1029 | if (targetPos.X < clipRect->UpperLeftCorner.X) | ||
1030 | { | ||
1031 | sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; | ||
1032 | if (sourceSize.Width <= 0) | ||
1033 | return; | ||
1034 | |||
1035 | sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; | ||
1036 | targetPos.X = clipRect->UpperLeftCorner.X; | ||
1037 | } | ||
1038 | |||
1039 | if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) | ||
1040 | { | ||
1041 | sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; | ||
1042 | if (sourceSize.Width <= 0) | ||
1043 | return; | ||
1044 | } | ||
1045 | |||
1046 | if (targetPos.Y < clipRect->UpperLeftCorner.Y) | ||
1047 | { | ||
1048 | sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; | ||
1049 | if (sourceSize.Height <= 0) | ||
1050 | return; | ||
1051 | |||
1052 | sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; | ||
1053 | targetPos.Y = clipRect->UpperLeftCorner.Y; | ||
1054 | } | ||
1055 | |||
1056 | if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) | ||
1057 | { | ||
1058 | sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; | ||
1059 | if (sourceSize.Height <= 0) | ||
1060 | return; | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | // clip these coordinates | ||
1065 | |||
1066 | if (targetPos.X<0) | ||
1067 | { | ||
1068 | sourceSize.Width += targetPos.X; | ||
1069 | if (sourceSize.Width <= 0) | ||
1070 | return; | ||
1071 | |||
1072 | sourcePos.X -= targetPos.X; | ||
1073 | targetPos.X = 0; | ||
1074 | } | ||
1075 | |||
1076 | if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) | ||
1077 | { | ||
1078 | sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; | ||
1079 | if (sourceSize.Width <= 0) | ||
1080 | return; | ||
1081 | } | ||
1082 | |||
1083 | if (targetPos.Y<0) | ||
1084 | { | ||
1085 | sourceSize.Height += targetPos.Y; | ||
1086 | if (sourceSize.Height <= 0) | ||
1087 | return; | ||
1088 | |||
1089 | sourcePos.Y -= targetPos.Y; | ||
1090 | targetPos.Y = 0; | ||
1091 | } | ||
1092 | |||
1093 | if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) | ||
1094 | { | ||
1095 | sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; | ||
1096 | if (sourceSize.Height <= 0) | ||
1097 | return; | ||
1098 | } | ||
1099 | |||
1100 | // ok, we've clipped everything. | ||
1101 | // now draw it. | ||
1102 | |||
1103 | core::rect<f32> tcoords; | ||
1104 | tcoords.UpperLeftCorner.X = (f32)sourcePos.X / texture->getOriginalSize().Width ; | ||
1105 | tcoords.UpperLeftCorner.Y = (f32)sourcePos.Y / texture->getOriginalSize().Height; | ||
1106 | tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + (f32)sourceSize.Width / texture->getOriginalSize().Width; | ||
1107 | tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + (f32)sourceSize.Height / texture->getOriginalSize().Height; | ||
1108 | |||
1109 | const core::rect<s32> poss(targetPos, sourceSize); | ||
1110 | |||
1111 | setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); | ||
1112 | |||
1113 | S3DVertex vtx[4]; | ||
1114 | vtx[0] = S3DVertex((f32)poss.UpperLeftCorner.X, | ||
1115 | (f32)poss.UpperLeftCorner.Y, 0.0f, | ||
1116 | 0.0f, 0.0f, 0.0f, color, | ||
1117 | tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); | ||
1118 | vtx[1] = S3DVertex((f32)poss.LowerRightCorner.X, | ||
1119 | (f32)poss.UpperLeftCorner.Y, 0.0f, | ||
1120 | 0.0f, 0.0f, 0.0f, color, | ||
1121 | tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); | ||
1122 | vtx[2] = S3DVertex((f32)poss.LowerRightCorner.X, | ||
1123 | (f32)poss.LowerRightCorner.Y, 0.0f, | ||
1124 | 0.0f, 0.0f, 0.0f, color, | ||
1125 | tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); | ||
1126 | vtx[3] = S3DVertex((f32)poss.UpperLeftCorner.X, | ||
1127 | (f32)poss.LowerRightCorner.Y, 0.0f, | ||
1128 | 0.0f, 0.0f, 0.0f, color, | ||
1129 | tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); | ||
1130 | |||
1131 | const s16 indices[6] = {0,1,2,0,2,3}; | ||
1132 | |||
1133 | setVertexShader(EVT_STANDARD); | ||
1134 | |||
1135 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], | ||
1136 | D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); | ||
1137 | } | ||
1138 | |||
1139 | |||
1140 | void CD3D8Driver::draw2DImage(const video::ITexture* texture, | ||
1141 | const core::rect<s32>& destRect, | ||
1142 | const core::rect<s32>& sourceRect, | ||
1143 | const core::rect<s32>* clipRect, | ||
1144 | const video::SColor* const colors, | ||
1145 | bool useAlphaChannelOfTexture) | ||
1146 | { | ||
1147 | if(!texture) | ||
1148 | return; | ||
1149 | |||
1150 | const core::dimension2d<u32>& ss = texture->getOriginalSize(); | ||
1151 | core::rect<f32> tcoords; | ||
1152 | tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width; | ||
1153 | tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height; | ||
1154 | tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width; | ||
1155 | tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height; | ||
1156 | |||
1157 | core::rect<s32> clippedRect(destRect); | ||
1158 | if (clipRect) | ||
1159 | { | ||
1160 | clippedRect.clipAgainst(*clipRect); | ||
1161 | |||
1162 | //tcoords must be clipped by the same factors | ||
1163 | const f32 tcWidth = tcoords.getWidth(); | ||
1164 | const f32 tcHeight = tcoords.getHeight(); | ||
1165 | |||
1166 | const f32 invDestRectWidth = 1.f / (f32)(destRect.getWidth()); | ||
1167 | f32 scale = (f32)(clippedRect.UpperLeftCorner.X - destRect.UpperLeftCorner.X) * invDestRectWidth; | ||
1168 | tcoords.UpperLeftCorner.X += scale * tcWidth; | ||
1169 | scale = (f32)(destRect.LowerRightCorner.X - clippedRect.LowerRightCorner.X) * invDestRectWidth; | ||
1170 | tcoords.LowerRightCorner.X -= scale * tcWidth; | ||
1171 | |||
1172 | const f32 invDestRectHeight = 1.f / (f32)(destRect.getHeight()); | ||
1173 | scale = (f32)(clippedRect.UpperLeftCorner.Y - destRect.UpperLeftCorner.Y) * invDestRectHeight; | ||
1174 | tcoords.UpperLeftCorner.Y += scale * tcHeight; | ||
1175 | scale = (f32)(destRect.LowerRightCorner.Y - clippedRect.LowerRightCorner.Y) * invDestRectHeight; | ||
1176 | tcoords.LowerRightCorner.Y -= scale * tcHeight; | ||
1177 | } | ||
1178 | |||
1179 | const video::SColor temp[4] = | ||
1180 | { | ||
1181 | 0xFFFFFFFF, | ||
1182 | 0xFFFFFFFF, | ||
1183 | 0xFFFFFFFF, | ||
1184 | 0xFFFFFFFF | ||
1185 | }; | ||
1186 | |||
1187 | const video::SColor* const useColor = colors ? colors : temp; | ||
1188 | |||
1189 | S3DVertex vtx[4]; // clock wise | ||
1190 | vtx[0] = S3DVertex((f32)clippedRect.UpperLeftCorner.X, (f32)clippedRect.UpperLeftCorner.Y, 0.0f, | ||
1191 | 0.0f, 0.0f, 0.0f, useColor[0], | ||
1192 | tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); | ||
1193 | vtx[1] = S3DVertex((f32)clippedRect.LowerRightCorner.X, (f32)clippedRect.UpperLeftCorner.Y, 0.0f, | ||
1194 | 0.0f, 0.0f, 0.0f, useColor[3], | ||
1195 | tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); | ||
1196 | vtx[2] = S3DVertex((f32)clippedRect.LowerRightCorner.X, (f32)clippedRect.LowerRightCorner.Y, 0.0f, | ||
1197 | 0.0f, 0.0f, 0.0f, useColor[2], | ||
1198 | tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); | ||
1199 | vtx[3] = S3DVertex((f32)clippedRect.UpperLeftCorner.X, (f32)clippedRect.LowerRightCorner.Y, 0.0f, | ||
1200 | 0.0f, 0.0f, 0.0f, useColor[1], | ||
1201 | tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); | ||
1202 | |||
1203 | const s16 indices[6] = {0,1,2,0,2,3}; | ||
1204 | |||
1205 | setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || | ||
1206 | useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, | ||
1207 | true, useAlphaChannelOfTexture); | ||
1208 | |||
1209 | setActiveTexture(0, texture); | ||
1210 | |||
1211 | setVertexShader(EVT_STANDARD); | ||
1212 | |||
1213 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], | ||
1214 | D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); | ||
1215 | } | ||
1216 | |||
1217 | |||
1218 | //!Draws an 2d rectangle with a gradient. | ||
1219 | void CD3D8Driver::draw2DRectangle(const core::rect<s32>& position, | ||
1220 | SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, | ||
1221 | SColor colorRightDown, const core::rect<s32>* clip) | ||
1222 | { | ||
1223 | core::rect<s32> pos(position); | ||
1224 | |||
1225 | if (clip) | ||
1226 | pos.clipAgainst(*clip); | ||
1227 | |||
1228 | if (!pos.isValid()) | ||
1229 | return; | ||
1230 | |||
1231 | S3DVertex vtx[4]; | ||
1232 | vtx[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f, | ||
1233 | 0.0f, 0.0f, 0.0f, colorLeftUp, 0.0f, 0.0f); | ||
1234 | vtx[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f, | ||
1235 | 0.0f, 0.0f, 0.0f, colorRightUp, 0.0f, 1.0f); | ||
1236 | vtx[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f, | ||
1237 | 0.0f, 0.0f, 0.0f, colorRightDown, 1.0f, 0.0f); | ||
1238 | vtx[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f, | ||
1239 | 0.0f, 0.0f, 0.0f, colorLeftDown, 1.0f, 1.0f); | ||
1240 | |||
1241 | const s16 indices[6] = {0,1,2,0,2,3}; | ||
1242 | |||
1243 | setRenderStates2DMode( | ||
1244 | colorLeftUp.getAlpha() < 255 || | ||
1245 | colorRightUp.getAlpha() < 255 || | ||
1246 | colorLeftDown.getAlpha() < 255 || | ||
1247 | colorRightDown.getAlpha() < 255, false, false); | ||
1248 | |||
1249 | setActiveTexture(0,0); | ||
1250 | |||
1251 | setVertexShader(EVT_STANDARD); | ||
1252 | |||
1253 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], | ||
1254 | D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | //! Draws a 2d line. | ||
1259 | void CD3D8Driver::draw2DLine(const core::position2d<s32>& start, | ||
1260 | const core::position2d<s32>& end, | ||
1261 | SColor color) | ||
1262 | { | ||
1263 | if (start==end) | ||
1264 | drawPixel(start.X, start.Y, color); | ||
1265 | else | ||
1266 | { | ||
1267 | // thanks to Vash TheStampede who sent in his implementation | ||
1268 | S3DVertex vtx[2]; | ||
1269 | vtx[0] = S3DVertex((f32)start.X+0.375f, (f32)start.Y+0.375f, 0.0f, | ||
1270 | 0.0f, 0.0f, 0.0f, // normal | ||
1271 | color, 0.0f, 0.0f); // texture | ||
1272 | |||
1273 | vtx[1] = S3DVertex((f32)end.X+0.375f, (f32)end.Y+0.375f, 0.0f, | ||
1274 | 0.0f, 0.0f, 0.0f, | ||
1275 | color, 0.0f, 0.0f); | ||
1276 | |||
1277 | setRenderStates2DMode(color.getAlpha() < 255, false, false); | ||
1278 | setActiveTexture(0,0); | ||
1279 | |||
1280 | setVertexShader(EVT_STANDARD); | ||
1281 | |||
1282 | pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, &vtx[0], sizeof(S3DVertex)); | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | |||
1287 | //! Draws a pixel | ||
1288 | void CD3D8Driver::drawPixel(u32 x, u32 y, const SColor & color) | ||
1289 | { | ||
1290 | const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize(); | ||
1291 | if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) | ||
1292 | return; | ||
1293 | |||
1294 | setRenderStates2DMode(color.getAlpha() < 255, false, false); | ||
1295 | setActiveTexture(0,0); | ||
1296 | |||
1297 | setVertexShader(EVT_STANDARD); | ||
1298 | |||
1299 | S3DVertex vertex((f32)x+0.375f, (f32)y+0.375f, 0.f, 0.f, 0.f, 0.f, color, 0.f, 0.f); | ||
1300 | |||
1301 | pID3DDevice->DrawPrimitiveUP(D3DPT_POINTLIST, 1, &vertex, sizeof(vertex)); | ||
1302 | } | ||
1303 | |||
1304 | |||
1305 | //! sets right vertex shader | ||
1306 | void CD3D8Driver::setVertexShader(E_VERTEX_TYPE newType) | ||
1307 | { | ||
1308 | // Because we don't know if a vertex shader was set in a material instead of a | ||
1309 | // fvf, this call cannot be prevented in D3D8. | ||
1310 | //if (newType != LastVertexType) | ||
1311 | { | ||
1312 | LastVertexType = newType; | ||
1313 | HRESULT hr = 0; | ||
1314 | |||
1315 | switch(newType) | ||
1316 | { | ||
1317 | case EVT_STANDARD: | ||
1318 | hr = pID3DDevice->SetVertexShader(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1); | ||
1319 | break; | ||
1320 | case EVT_2TCOORDS: | ||
1321 | hr = pID3DDevice->SetVertexShader(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX2); | ||
1322 | break; | ||
1323 | case EVT_TANGENTS: | ||
1324 | hr = pID3DDevice->SetVertexShader(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX3 | | ||
1325 | D3DFVF_TEXCOORDSIZE2(0) | // real texture coord | ||
1326 | D3DFVF_TEXCOORDSIZE3(1) | // misuse texture coord 2 for tangent | ||
1327 | D3DFVF_TEXCOORDSIZE3(2) // misuse texture coord 3 for binormal | ||
1328 | ); | ||
1329 | break; | ||
1330 | } | ||
1331 | |||
1332 | if (FAILED(hr)) | ||
1333 | { | ||
1334 | os::Printer::log("Could not set vertex Shader.", ELL_ERROR); | ||
1335 | return; | ||
1336 | } | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1340 | |||
1341 | //! sets the needed renderstates | ||
1342 | bool CD3D8Driver::setRenderStates3DMode() | ||
1343 | { | ||
1344 | if (!pID3DDevice) | ||
1345 | return false; | ||
1346 | |||
1347 | if (CurrentRenderMode != ERM_3D) | ||
1348 | { | ||
1349 | // switch back the matrices | ||
1350 | pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)&Matrices[ETS_VIEW])); | ||
1351 | pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)&Matrices[ETS_WORLD])); | ||
1352 | pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)&Matrices[ETS_PROJECTION])); | ||
1353 | |||
1354 | pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); | ||
1355 | |||
1356 | ResetRenderStates = true; | ||
1357 | } | ||
1358 | |||
1359 | if (ResetRenderStates || LastMaterial != Material) | ||
1360 | { | ||
1361 | // unset old material | ||
1362 | |||
1363 | if (CurrentRenderMode == ERM_3D && | ||
1364 | LastMaterial.MaterialType != Material.MaterialType && | ||
1365 | LastMaterial.MaterialType >= 0 && LastMaterial.MaterialType < (s32)MaterialRenderers.size()) | ||
1366 | MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); | ||
1367 | |||
1368 | // set new material. | ||
1369 | |||
1370 | if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) | ||
1371 | MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( | ||
1372 | Material, LastMaterial, ResetRenderStates, this); | ||
1373 | } | ||
1374 | |||
1375 | bool shaderOK = true; | ||
1376 | |||
1377 | if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) | ||
1378 | shaderOK = MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, LastVertexType); | ||
1379 | |||
1380 | LastMaterial = Material; | ||
1381 | |||
1382 | ResetRenderStates = false; | ||
1383 | |||
1384 | CurrentRenderMode = ERM_3D; | ||
1385 | |||
1386 | return shaderOK; | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | //! Map Irrlicht texture wrap mode to native values | ||
1391 | D3DTEXTUREADDRESS CD3D8Driver::getTextureWrapMode(const u8 clamp) | ||
1392 | { | ||
1393 | switch (clamp) | ||
1394 | { | ||
1395 | case ETC_REPEAT: | ||
1396 | if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP) | ||
1397 | return D3DTADDRESS_WRAP; | ||
1398 | case ETC_CLAMP: | ||
1399 | case ETC_CLAMP_TO_EDGE: | ||
1400 | if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_CLAMP) | ||
1401 | return D3DTADDRESS_CLAMP; | ||
1402 | case ETC_MIRROR: | ||
1403 | if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRROR) | ||
1404 | return D3DTADDRESS_MIRROR; | ||
1405 | case ETC_CLAMP_TO_BORDER: | ||
1406 | if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_BORDER) | ||
1407 | return D3DTADDRESS_BORDER; | ||
1408 | else | ||
1409 | return D3DTADDRESS_CLAMP; | ||
1410 | case ETC_MIRROR_CLAMP: | ||
1411 | case ETC_MIRROR_CLAMP_TO_EDGE: | ||
1412 | case ETC_MIRROR_CLAMP_TO_BORDER: | ||
1413 | if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRRORONCE) | ||
1414 | return D3DTADDRESS_MIRRORONCE; | ||
1415 | else | ||
1416 | return D3DTADDRESS_CLAMP; | ||
1417 | default: | ||
1418 | return D3DTADDRESS_WRAP; | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | |||
1423 | //! Can be called by an IMaterialRenderer to make its work easier. | ||
1424 | void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, | ||
1425 | bool resetAllRenderstates) | ||
1426 | { | ||
1427 | if (resetAllRenderstates || | ||
1428 | lastmaterial.AmbientColor != material.AmbientColor || | ||
1429 | lastmaterial.DiffuseColor != material.DiffuseColor || | ||
1430 | lastmaterial.SpecularColor != material.SpecularColor || | ||
1431 | lastmaterial.EmissiveColor != material.EmissiveColor || | ||
1432 | lastmaterial.Shininess != material.Shininess) | ||
1433 | { | ||
1434 | D3DMATERIAL8 mat; | ||
1435 | mat.Diffuse = colorToD3D(material.DiffuseColor); | ||
1436 | mat.Ambient = colorToD3D(material.AmbientColor); | ||
1437 | mat.Specular = colorToD3D(material.SpecularColor); | ||
1438 | mat.Emissive = colorToD3D(material.EmissiveColor); | ||
1439 | mat.Power = material.Shininess; | ||
1440 | pID3DDevice->SetMaterial(&mat); | ||
1441 | } | ||
1442 | |||
1443 | if (lastmaterial.ColorMaterial != material.ColorMaterial) | ||
1444 | { | ||
1445 | pID3DDevice->SetRenderState(D3DRS_COLORVERTEX, (material.ColorMaterial != ECM_NONE)); | ||
1446 | pID3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, | ||
1447 | ((material.ColorMaterial == ECM_DIFFUSE)|| | ||
1448 | (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT))?D3DMCS_COLOR1:D3DMCS_MATERIAL); | ||
1449 | pID3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, | ||
1450 | ((material.ColorMaterial == ECM_AMBIENT)|| | ||
1451 | (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT))?D3DMCS_COLOR1:D3DMCS_MATERIAL); | ||
1452 | pID3DDevice->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, | ||
1453 | (material.ColorMaterial == ECM_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL); | ||
1454 | pID3DDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, | ||
1455 | (material.ColorMaterial == ECM_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL); | ||
1456 | } | ||
1457 | |||
1458 | // fillmode | ||
1459 | if (resetAllRenderstates || lastmaterial.Wireframe != material.Wireframe || lastmaterial.PointCloud != material.PointCloud) | ||
1460 | { | ||
1461 | if (material.Wireframe) | ||
1462 | pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); | ||
1463 | else | ||
1464 | if (material.PointCloud) | ||
1465 | pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT); | ||
1466 | else | ||
1467 | pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); | ||
1468 | } | ||
1469 | |||
1470 | // shademode | ||
1471 | if (resetAllRenderstates || lastmaterial.GouraudShading != material.GouraudShading) | ||
1472 | { | ||
1473 | if (material.GouraudShading) | ||
1474 | pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); | ||
1475 | else | ||
1476 | pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); | ||
1477 | } | ||
1478 | |||
1479 | // lighting | ||
1480 | if (resetAllRenderstates || lastmaterial.Lighting != material.Lighting) | ||
1481 | { | ||
1482 | if (material.Lighting) | ||
1483 | pID3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE); | ||
1484 | else | ||
1485 | pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); | ||
1486 | } | ||
1487 | |||
1488 | // zbuffer | ||
1489 | if (resetAllRenderstates || lastmaterial.ZBuffer != material.ZBuffer) | ||
1490 | { | ||
1491 | switch (material.ZBuffer) | ||
1492 | { | ||
1493 | case ECFN_NEVER: | ||
1494 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); | ||
1495 | break; | ||
1496 | case ECFN_LESSEQUAL: | ||
1497 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1498 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); | ||
1499 | break; | ||
1500 | case ECFN_EQUAL: | ||
1501 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1502 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); | ||
1503 | break; | ||
1504 | case ECFN_LESS: | ||
1505 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1506 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); | ||
1507 | break; | ||
1508 | case ECFN_NOTEQUAL: | ||
1509 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1510 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL); | ||
1511 | break; | ||
1512 | case ECFN_GREATEREQUAL: | ||
1513 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1514 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL); | ||
1515 | break; | ||
1516 | case ECFN_GREATER: | ||
1517 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1518 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER); | ||
1519 | break; | ||
1520 | case ECFN_ALWAYS: | ||
1521 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); | ||
1522 | pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); | ||
1523 | break; | ||
1524 | } | ||
1525 | } | ||
1526 | |||
1527 | // zwrite | ||
1528 | // if (resetAllRenderstates || lastmaterial.ZWriteEnable != material.ZWriteEnable) | ||
1529 | { | ||
1530 | if (material.ZWriteEnable && (AllowZWriteOnTransparent || !material.isTransparent())) | ||
1531 | pID3DDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE); | ||
1532 | else | ||
1533 | pID3DDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE); | ||
1534 | } | ||
1535 | |||
1536 | // back face culling | ||
1537 | if (resetAllRenderstates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) | ||
1538 | { | ||
1539 | // if (material.FrontfaceCulling && material.BackfaceCulling) | ||
1540 | // pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW|D3DCULL_CCW); | ||
1541 | // else | ||
1542 | if (material.FrontfaceCulling) | ||
1543 | pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); | ||
1544 | else | ||
1545 | if (material.BackfaceCulling) | ||
1546 | pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); | ||
1547 | else | ||
1548 | pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); | ||
1549 | } | ||
1550 | |||
1551 | // fog | ||
1552 | if (resetAllRenderstates || lastmaterial.FogEnable != material.FogEnable) | ||
1553 | { | ||
1554 | pID3DDevice->SetRenderState(D3DRS_FOGENABLE, material.FogEnable); | ||
1555 | } | ||
1556 | |||
1557 | // specular highlights | ||
1558 | if (resetAllRenderstates || !core::equals(lastmaterial.Shininess, material.Shininess)) | ||
1559 | { | ||
1560 | bool enable = (material.Shininess!=0); | ||
1561 | pID3DDevice->SetRenderState(D3DRS_SPECULARENABLE, enable); | ||
1562 | pID3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, enable); | ||
1563 | pID3DDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); | ||
1564 | } | ||
1565 | |||
1566 | // normalization | ||
1567 | if (resetAllRenderstates || lastmaterial.NormalizeNormals != material.NormalizeNormals) | ||
1568 | { | ||
1569 | pID3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, material.NormalizeNormals); | ||
1570 | } | ||
1571 | |||
1572 | // Color Mask | ||
1573 | if (queryFeature(EVDF_COLOR_MASK) && | ||
1574 | (resetAllRenderstates || lastmaterial.ColorMask != material.ColorMask)) | ||
1575 | { | ||
1576 | const DWORD flag = | ||
1577 | ((material.ColorMask & ECP_RED)?D3DCOLORWRITEENABLE_RED:0) | | ||
1578 | ((material.ColorMask & ECP_GREEN)?D3DCOLORWRITEENABLE_GREEN:0) | | ||
1579 | ((material.ColorMask & ECP_BLUE)?D3DCOLORWRITEENABLE_BLUE:0) | | ||
1580 | ((material.ColorMask & ECP_ALPHA)?D3DCOLORWRITEENABLE_ALPHA:0); | ||
1581 | pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, flag); | ||
1582 | } | ||
1583 | |||
1584 | if (queryFeature(EVDF_BLEND_OPERATIONS) && | ||
1585 | (resetAllRenderstates|| lastmaterial.BlendOperation != material.BlendOperation)) | ||
1586 | { | ||
1587 | if (material.BlendOperation==EBO_NONE) | ||
1588 | pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); | ||
1589 | else | ||
1590 | { | ||
1591 | pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); | ||
1592 | switch (material.BlendOperation) | ||
1593 | { | ||
1594 | case EBO_MAX: | ||
1595 | case EBO_MAX_FACTOR: | ||
1596 | case EBO_MAX_ALPHA: | ||
1597 | pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MAX); | ||
1598 | break; | ||
1599 | case EBO_MIN: | ||
1600 | case EBO_MIN_FACTOR: | ||
1601 | case EBO_MIN_ALPHA: | ||
1602 | pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN); | ||
1603 | break; | ||
1604 | case EBO_SUBTRACT: | ||
1605 | pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT); | ||
1606 | break; | ||
1607 | case EBO_REVSUBTRACT: | ||
1608 | pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT); | ||
1609 | break; | ||
1610 | default: | ||
1611 | pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); | ||
1612 | break; | ||
1613 | } | ||
1614 | } | ||
1615 | } | ||
1616 | |||
1617 | // Polygon offset | ||
1618 | if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderstates || | ||
1619 | lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection || | ||
1620 | lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor)) | ||
1621 | { | ||
1622 | pID3DDevice->SetRenderState(D3DRS_ZBIAS, material.PolygonOffsetFactor); | ||
1623 | } | ||
1624 | |||
1625 | // thickness | ||
1626 | if (resetAllRenderstates || lastmaterial.Thickness != material.Thickness) | ||
1627 | { | ||
1628 | pID3DDevice->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&material.Thickness)); | ||
1629 | } | ||
1630 | |||
1631 | // texture address mode | ||
1632 | for (u32 st=0; st<MaxTextureUnits; ++st) | ||
1633 | { | ||
1634 | if (resetAllRenderstates || lastmaterial.TextureLayer[st].LODBias != material.TextureLayer[st].LODBias) | ||
1635 | { | ||
1636 | const float tmp = material.TextureLayer[st].LODBias * 0.125f; | ||
1637 | pID3DDevice->SetTextureStageState(st, D3DTSS_MIPMAPLODBIAS, *(DWORD*)(&tmp)); | ||
1638 | } | ||
1639 | |||
1640 | if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapU != material.TextureLayer[st].TextureWrapU) | ||
1641 | pID3DDevice->SetTextureStageState(st, D3DTSS_ADDRESSU, getTextureWrapMode(material.TextureLayer[st].TextureWrapU)); | ||
1642 | // If separate UV not supported reuse U for V | ||
1643 | if (!(Caps.TextureAddressCaps & D3DPTADDRESSCAPS_INDEPENDENTUV)) | ||
1644 | pID3DDevice->SetTextureStageState(st, D3DTSS_ADDRESSV, getTextureWrapMode(material.TextureLayer[st].TextureWrapU)); | ||
1645 | else if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapV != material.TextureLayer[st].TextureWrapV) | ||
1646 | pID3DDevice->SetTextureStageState(st, D3DTSS_ADDRESSV, getTextureWrapMode(material.TextureLayer[st].TextureWrapV)); | ||
1647 | |||
1648 | // Bilinear and/or trilinear | ||
1649 | if (resetAllRenderstates || | ||
1650 | lastmaterial.TextureLayer[st].BilinearFilter != material.TextureLayer[st].BilinearFilter || | ||
1651 | lastmaterial.TextureLayer[st].TrilinearFilter != material.TextureLayer[st].TrilinearFilter || | ||
1652 | lastmaterial.TextureLayer[st].AnisotropicFilter != material.TextureLayer[st].AnisotropicFilter || | ||
1653 | lastmaterial.UseMipMaps != material.UseMipMaps) | ||
1654 | { | ||
1655 | if (material.TextureLayer[st].BilinearFilter || material.TextureLayer[st].TrilinearFilter || material.TextureLayer[st].AnisotropicFilter>1) | ||
1656 | { | ||
1657 | const D3DTEXTUREFILTERTYPE tftMag = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) && | ||
1658 | material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; | ||
1659 | const D3DTEXTUREFILTERTYPE tftMin = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) && | ||
1660 | material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; | ||
1661 | const D3DTEXTUREFILTERTYPE tftMip = material.UseMipMaps? (material.TextureLayer[st].TrilinearFilter ? D3DTEXF_LINEAR : D3DTEXF_POINT) : D3DTEXF_NONE; | ||
1662 | |||
1663 | if (tftMag==D3DTEXF_ANISOTROPIC || tftMin == D3DTEXF_ANISOTROPIC) | ||
1664 | pID3DDevice->SetTextureStageState(st, D3DTSS_MAXANISOTROPY, core::min_((DWORD)material.TextureLayer[st].AnisotropicFilter, Caps.MaxAnisotropy)); | ||
1665 | pID3DDevice->SetTextureStageState(st, D3DTSS_MAGFILTER, tftMag); | ||
1666 | pID3DDevice->SetTextureStageState(st, D3DTSS_MINFILTER, tftMin); | ||
1667 | pID3DDevice->SetTextureStageState(st, D3DTSS_MIPFILTER, tftMip); | ||
1668 | } | ||
1669 | else | ||
1670 | { | ||
1671 | pID3DDevice->SetTextureStageState(st, D3DTSS_MINFILTER, D3DTEXF_POINT); | ||
1672 | pID3DDevice->SetTextureStageState(st, D3DTSS_MIPFILTER, D3DTEXF_NONE); | ||
1673 | pID3DDevice->SetTextureStageState(st, D3DTSS_MAGFILTER, D3DTEXF_POINT); | ||
1674 | } | ||
1675 | } | ||
1676 | } | ||
1677 | } | ||
1678 | |||
1679 | |||
1680 | //! sets the needed renderstates | ||
1681 | void CD3D8Driver::setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisible) | ||
1682 | { | ||
1683 | if ((CurrentRenderMode != ERM_SHADOW_VOLUME_ZFAIL && | ||
1684 | CurrentRenderMode != ERM_SHADOW_VOLUME_ZPASS) || | ||
1685 | Transformation3DChanged) | ||
1686 | { | ||
1687 | // unset last 3d material | ||
1688 | if (CurrentRenderMode == ERM_3D && | ||
1689 | static_cast<u32>(Material.MaterialType) < MaterialRenderers.size()) | ||
1690 | { | ||
1691 | MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); | ||
1692 | ResetRenderStates = true; | ||
1693 | } | ||
1694 | // switch back the matrices | ||
1695 | pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)&Matrices[ETS_VIEW])); | ||
1696 | pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)&Matrices[ETS_WORLD])); | ||
1697 | pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)&Matrices[ETS_PROJECTION])); | ||
1698 | |||
1699 | Transformation3DChanged = false; | ||
1700 | |||
1701 | setActiveTexture(0,0); | ||
1702 | setActiveTexture(1,0); | ||
1703 | setActiveTexture(2,0); | ||
1704 | setActiveTexture(3,0); | ||
1705 | |||
1706 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1707 | |||
1708 | pID3DDevice->SetVertexShader(D3DFVF_XYZ); | ||
1709 | LastVertexType = (video::E_VERTEX_TYPE)(-1); | ||
1710 | |||
1711 | pID3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); | ||
1712 | pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); | ||
1713 | pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); | ||
1714 | //pID3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); | ||
1715 | //pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); | ||
1716 | |||
1717 | pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); | ||
1718 | pID3DDevice->SetRenderState(D3DRS_STENCILREF, 0x0); | ||
1719 | pID3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff); | ||
1720 | pID3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff); | ||
1721 | if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) | ||
1722 | pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); | ||
1723 | if ((debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)) | ||
1724 | pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); | ||
1725 | } | ||
1726 | |||
1727 | if (CurrentRenderMode != ERM_SHADOW_VOLUME_ZPASS && !zfail) | ||
1728 | { | ||
1729 | // USE THE ZPASS METHOD | ||
1730 | pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); | ||
1731 | pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); | ||
1732 | pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR); | ||
1733 | } | ||
1734 | else | ||
1735 | if (CurrentRenderMode != ERM_SHADOW_VOLUME_ZFAIL && zfail) | ||
1736 | { | ||
1737 | // USE THE ZFAIL METHOD | ||
1738 | pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); | ||
1739 | pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR); | ||
1740 | pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); | ||
1741 | } | ||
1742 | |||
1743 | CurrentRenderMode = zfail ? ERM_SHADOW_VOLUME_ZFAIL : ERM_SHADOW_VOLUME_ZPASS; | ||
1744 | } | ||
1745 | |||
1746 | |||
1747 | //! sets the needed renderstates | ||
1748 | void CD3D8Driver::setRenderStatesStencilFillMode(bool alpha) | ||
1749 | { | ||
1750 | if (CurrentRenderMode != ERM_STENCIL_FILL || Transformation3DChanged) | ||
1751 | { | ||
1752 | pID3DDevice->SetTransform(D3DTS_VIEW, &UnitMatrixD3D8); | ||
1753 | pID3DDevice->SetTransform(D3DTS_WORLD, &UnitMatrixD3D8); | ||
1754 | pID3DDevice->SetTransform(D3DTS_PROJECTION, &UnitMatrixD3D8); | ||
1755 | |||
1756 | pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); | ||
1757 | pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); | ||
1758 | pID3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); | ||
1759 | |||
1760 | pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1761 | pID3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); | ||
1762 | pID3DDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1763 | pID3DDevice->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE); | ||
1764 | pID3DDevice->SetTextureStageState(3, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1765 | pID3DDevice->SetTextureStageState(3, D3DTSS_ALPHAOP, D3DTOP_DISABLE); | ||
1766 | |||
1767 | pID3DDevice->SetRenderState(D3DRS_STENCILREF, 0x1 ); | ||
1768 | pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL); | ||
1769 | //pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL); | ||
1770 | pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP ); | ||
1771 | pID3DDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP ); | ||
1772 | pID3DDevice->SetRenderState( D3DRS_STENCILMASK, 0xffffffff ); | ||
1773 | pID3DDevice->SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff ); | ||
1774 | |||
1775 | pID3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW); | ||
1776 | |||
1777 | Transformation3DChanged = false; | ||
1778 | |||
1779 | if (alpha) | ||
1780 | { | ||
1781 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE ); | ||
1782 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); | ||
1783 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); | ||
1784 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); | ||
1785 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); | ||
1786 | pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); | ||
1787 | pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); | ||
1788 | pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); | ||
1789 | } | ||
1790 | else | ||
1791 | { | ||
1792 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE ); | ||
1793 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); | ||
1794 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); | ||
1795 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); | ||
1796 | pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); | ||
1797 | } | ||
1798 | } | ||
1799 | |||
1800 | CurrentRenderMode = ERM_STENCIL_FILL; | ||
1801 | } | ||
1802 | |||
1803 | |||
1804 | //! sets the needed renderstates | ||
1805 | void CD3D8Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) | ||
1806 | { | ||
1807 | if (!pID3DDevice) | ||
1808 | return; | ||
1809 | |||
1810 | if (CurrentRenderMode != ERM_2D || Transformation3DChanged) | ||
1811 | { | ||
1812 | // unset last 3d material | ||
1813 | if (CurrentRenderMode == ERM_3D) | ||
1814 | { | ||
1815 | if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size()) | ||
1816 | MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); | ||
1817 | } | ||
1818 | if (!OverrideMaterial2DEnabled) | ||
1819 | { | ||
1820 | setBasicRenderStates(InitMaterial2D, LastMaterial, true); | ||
1821 | LastMaterial=InitMaterial2D; | ||
1822 | |||
1823 | // fix everything that is wrongly set by SMaterial default | ||
1824 | pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1825 | pID3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); | ||
1826 | pID3DDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1827 | pID3DDevice->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); | ||
1828 | pID3DDevice->SetTextureStageState(3, D3DTSS_COLOROP, D3DTOP_DISABLE); | ||
1829 | pID3DDevice->SetTextureStageState(3, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); | ||
1830 | |||
1831 | pID3DDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE ); | ||
1832 | |||
1833 | } | ||
1834 | pID3DDevice->SetTransform(D3DTS_WORLD, &UnitMatrixD3D8); | ||
1835 | core::matrix4 m; | ||
1836 | m.setTranslation(core::vector3df(-0.5f,-0.5f,0)); | ||
1837 | pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)m.pointer())); | ||
1838 | |||
1839 | const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize(); | ||
1840 | m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0, 1.0); | ||
1841 | m.setTranslation(core::vector3df(-1,1,0)); | ||
1842 | pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)m.pointer())); | ||
1843 | |||
1844 | Transformation3DChanged = false; | ||
1845 | } | ||
1846 | if (OverrideMaterial2DEnabled) | ||
1847 | { | ||
1848 | OverrideMaterial2D.Lighting=false; | ||
1849 | setBasicRenderStates(OverrideMaterial2D, LastMaterial, false); | ||
1850 | LastMaterial = OverrideMaterial2D; | ||
1851 | } | ||
1852 | |||
1853 | // no alphaChannel without texture | ||
1854 | alphaChannel &= texture; | ||
1855 | |||
1856 | if (alpha || alphaChannel) | ||
1857 | { | ||
1858 | pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); | ||
1859 | pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); | ||
1860 | pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); | ||
1861 | } | ||
1862 | else | ||
1863 | pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); | ||
1864 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); | ||
1865 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); | ||
1866 | pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); | ||
1867 | if (texture) | ||
1868 | { | ||
1869 | setTransform(ETS_TEXTURE_0, core::IdentityMatrix); | ||
1870 | // Due to the transformation change, the previous line would call a reset each frame | ||
1871 | // but we can safely reset the variable as it was false before | ||
1872 | Transformation3DChanged=false; | ||
1873 | } | ||
1874 | if (alphaChannel) | ||
1875 | { | ||
1876 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); | ||
1877 | |||
1878 | if (alpha) | ||
1879 | { | ||
1880 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); | ||
1881 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); | ||
1882 | } | ||
1883 | else | ||
1884 | { | ||
1885 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); | ||
1886 | } | ||
1887 | |||
1888 | } | ||
1889 | else | ||
1890 | { | ||
1891 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); | ||
1892 | if (alpha) | ||
1893 | { | ||
1894 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); | ||
1895 | } | ||
1896 | else | ||
1897 | { | ||
1898 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); | ||
1899 | pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); | ||
1900 | } | ||
1901 | } | ||
1902 | |||
1903 | CurrentRenderMode = ERM_2D; | ||
1904 | } | ||
1905 | |||
1906 | |||
1907 | //! deletes all dynamic lights there are | ||
1908 | void CD3D8Driver::deleteAllDynamicLights() | ||
1909 | { | ||
1910 | for (s32 i=0; i<LastSetLight+1; ++i) | ||
1911 | pID3DDevice->LightEnable(i, false); | ||
1912 | |||
1913 | LastSetLight = -1; | ||
1914 | |||
1915 | CNullDriver::deleteAllDynamicLights(); | ||
1916 | } | ||
1917 | |||
1918 | |||
1919 | //! adds a dynamic light | ||
1920 | s32 CD3D8Driver::addDynamicLight(const SLight& dl) | ||
1921 | { | ||
1922 | CNullDriver::addDynamicLight(dl); | ||
1923 | |||
1924 | D3DLIGHT8 light; | ||
1925 | |||
1926 | switch (dl.Type) | ||
1927 | { | ||
1928 | case ELT_POINT: | ||
1929 | light.Type = D3DLIGHT_POINT; | ||
1930 | break; | ||
1931 | case ELT_SPOT: | ||
1932 | light.Type = D3DLIGHT_SPOT; | ||
1933 | break; | ||
1934 | case ELT_DIRECTIONAL: | ||
1935 | light.Type = D3DLIGHT_DIRECTIONAL; | ||
1936 | break; | ||
1937 | } | ||
1938 | |||
1939 | light.Position = *(D3DVECTOR*)((void*)(&dl.Position)); | ||
1940 | light.Direction = *(D3DVECTOR*)((void*)(&dl.Direction)); | ||
1941 | |||
1942 | light.Range = core::min_(dl.Radius, MaxLightDistance); | ||
1943 | light.Falloff = dl.Falloff; | ||
1944 | |||
1945 | light.Diffuse = *(D3DCOLORVALUE*)((void*)(&dl.DiffuseColor)); | ||
1946 | light.Specular = *(D3DCOLORVALUE*)((void*)(&dl.SpecularColor)); | ||
1947 | light.Ambient = *(D3DCOLORVALUE*)((void*)(&dl.AmbientColor)); | ||
1948 | |||
1949 | light.Attenuation0 = dl.Attenuation.X; | ||
1950 | light.Attenuation1 = dl.Attenuation.Y; | ||
1951 | light.Attenuation2 = dl.Attenuation.Z; | ||
1952 | |||
1953 | light.Theta = dl.InnerCone * 2.0f * core::DEGTORAD; | ||
1954 | light.Phi = dl.OuterCone * 2.0f * core::DEGTORAD; | ||
1955 | |||
1956 | ++LastSetLight; | ||
1957 | |||
1958 | if(D3D_OK == pID3DDevice->SetLight(LastSetLight, &light)) | ||
1959 | { | ||
1960 | // I don't care if this succeeds | ||
1961 | (void)pID3DDevice->LightEnable(LastSetLight, true); | ||
1962 | return LastSetLight; | ||
1963 | } | ||
1964 | |||
1965 | return -1; | ||
1966 | } | ||
1967 | |||
1968 | |||
1969 | void CD3D8Driver::turnLightOn(s32 lightIndex, bool turnOn) | ||
1970 | { | ||
1971 | if(lightIndex < 0 || lightIndex > LastSetLight) | ||
1972 | return; | ||
1973 | |||
1974 | (void)pID3DDevice->LightEnable(lightIndex, turnOn); | ||
1975 | } | ||
1976 | |||
1977 | |||
1978 | //! returns the maximal amount of dynamic lights the device can handle | ||
1979 | u32 CD3D8Driver::getMaximalDynamicLightAmount() const | ||
1980 | { | ||
1981 | return Caps.MaxActiveLights; | ||
1982 | } | ||
1983 | |||
1984 | |||
1985 | //! Sets the dynamic ambient light color. The default color is | ||
1986 | //! (0,0,0,0) which means it is dark. | ||
1987 | //! \param color: New color of the ambient light. | ||
1988 | void CD3D8Driver::setAmbientLight(const SColorf& color) | ||
1989 | { | ||
1990 | if (!pID3DDevice) | ||
1991 | return; | ||
1992 | |||
1993 | AmbientLight = color; | ||
1994 | D3DCOLOR col = color.toSColor().color; | ||
1995 | pID3DDevice->SetRenderState(D3DRS_AMBIENT, col); | ||
1996 | } | ||
1997 | |||
1998 | |||
1999 | //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 | ||
2000 | //! driver, it would return "Direct3D8.1". | ||
2001 | const wchar_t* CD3D8Driver::getName() const | ||
2002 | { | ||
2003 | return L"Direct3D 8.1"; | ||
2004 | } | ||
2005 | |||
2006 | |||
2007 | //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do | ||
2008 | //! this: First, draw all geometry. Then use this method, to draw the shadow | ||
2009 | //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. | ||
2010 | void CD3D8Driver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible) | ||
2011 | { | ||
2012 | const u32 count = triangles.size(); | ||
2013 | if (!Params.Stencilbuffer || !count) | ||
2014 | return; | ||
2015 | |||
2016 | setRenderStatesStencilShadowMode(zfail, debugDataVisible); | ||
2017 | |||
2018 | if (!zfail) | ||
2019 | { | ||
2020 | // ZPASS Method | ||
2021 | |||
2022 | // Draw front-side of shadow volume in stencil only | ||
2023 | pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW ); | ||
2024 | pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCRSAT); | ||
2025 | pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); | ||
2026 | |||
2027 | // Now reverse cull order so front sides of shadow volume are written. | ||
2028 | pID3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW ); | ||
2029 | pID3DDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECRSAT); | ||
2030 | pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); | ||
2031 | } | ||
2032 | else | ||
2033 | { | ||
2034 | // ZFAIL Method | ||
2035 | |||
2036 | // Draw front-side of shadow volume in stencil only | ||
2037 | pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW ); | ||
2038 | pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCRSAT ); | ||
2039 | pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); | ||
2040 | |||
2041 | // Now reverse cull order so front sides of shadow volume are written. | ||
2042 | pID3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); | ||
2043 | pID3DDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_DECRSAT ); | ||
2044 | pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); | ||
2045 | } | ||
2046 | } | ||
2047 | |||
2048 | |||
2049 | //! Fills the stencil shadow with color. After the shadow volume has been drawn | ||
2050 | //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this | ||
2051 | //! to draw the color of the shadow. | ||
2052 | void CD3D8Driver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, | ||
2053 | video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) | ||
2054 | { | ||
2055 | if (!Params.Stencilbuffer) | ||
2056 | return; | ||
2057 | |||
2058 | S3DVertex vtx[4]; | ||
2059 | vtx[0] = S3DVertex(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, leftUpEdge, 0.0f, 0.0f); | ||
2060 | vtx[1] = S3DVertex(1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, rightUpEdge, 0.0f, 1.0f); | ||
2061 | vtx[2] = S3DVertex(-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, leftDownEdge, 1.0f, 0.0f); | ||
2062 | vtx[3] = S3DVertex(-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, rightDownEdge, 1.0f, 1.0f); | ||
2063 | |||
2064 | const s16 indices[6] = {0,1,2,1,3,2}; | ||
2065 | |||
2066 | setRenderStatesStencilFillMode( | ||
2067 | leftUpEdge.getAlpha() < 255 || | ||
2068 | rightUpEdge.getAlpha() < 255 || | ||
2069 | leftDownEdge.getAlpha() < 255 || | ||
2070 | rightDownEdge.getAlpha() < 255); | ||
2071 | |||
2072 | setActiveTexture(0,0); | ||
2073 | |||
2074 | setVertexShader(EVT_STANDARD); | ||
2075 | |||
2076 | pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], | ||
2077 | D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); | ||
2078 | |||
2079 | if (clearStencilBuffer) | ||
2080 | pID3DDevice->Clear(0, NULL, D3DCLEAR_STENCIL,0, 1.0, 0); | ||
2081 | } | ||
2082 | |||
2083 | |||
2084 | //! Returns the maximum amount of primitives (mostly vertices) which | ||
2085 | //! the device is able to render with one drawIndexedTriangleList | ||
2086 | //! call. | ||
2087 | u32 CD3D8Driver::getMaximalPrimitiveCount() const | ||
2088 | { | ||
2089 | return Caps.MaxPrimitiveCount; | ||
2090 | } | ||
2091 | |||
2092 | |||
2093 | //! Sets the fog mode. | ||
2094 | void CD3D8Driver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, | ||
2095 | f32 end, f32 density, bool pixelFog, bool rangeFog) | ||
2096 | { | ||
2097 | CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); | ||
2098 | |||
2099 | if (!pID3DDevice) | ||
2100 | return; | ||
2101 | |||
2102 | pID3DDevice->SetRenderState(D3DRS_FOGCOLOR, color.color); | ||
2103 | |||
2104 | pID3DDevice->SetRenderState( | ||
2105 | #if defined( _IRR_XBOX_PLATFORM_) | ||
2106 | D3DRS_FOGTABLEMODE, | ||
2107 | #else | ||
2108 | pixelFog ? D3DRS_FOGTABLEMODE : D3DRS_FOGVERTEXMODE, | ||
2109 | #endif | ||
2110 | (fogType==EFT_FOG_LINEAR)? D3DFOG_LINEAR : (fogType==EFT_FOG_EXP)?D3DFOG_EXP:D3DFOG_EXP2); | ||
2111 | |||
2112 | if (fogType==EFT_FOG_LINEAR) | ||
2113 | { | ||
2114 | pID3DDevice->SetRenderState(D3DRS_FOGSTART, *(DWORD*)(&start)); | ||
2115 | pID3DDevice->SetRenderState(D3DRS_FOGEND, *(DWORD*)(&end)); | ||
2116 | } | ||
2117 | else | ||
2118 | pID3DDevice->SetRenderState(D3DRS_FOGDENSITY, *(DWORD*)(&density)); | ||
2119 | |||
2120 | if(!pixelFog) | ||
2121 | pID3DDevice->SetRenderState(D3DRS_RANGEFOGENABLE, rangeFog); | ||
2122 | } | ||
2123 | |||
2124 | |||
2125 | //! Draws a 3d line. | ||
2126 | void CD3D8Driver::draw3DLine(const core::vector3df& start, | ||
2127 | const core::vector3df& end, SColor color) | ||
2128 | { | ||
2129 | setVertexShader(EVT_STANDARD); | ||
2130 | setRenderStates3DMode(); | ||
2131 | video::S3DVertex v[2]; | ||
2132 | v[0].Color = color; | ||
2133 | v[1].Color = color; | ||
2134 | v[0].Pos = start; | ||
2135 | v[1].Pos = end; | ||
2136 | |||
2137 | pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, v, sizeof(S3DVertex)); | ||
2138 | } | ||
2139 | |||
2140 | |||
2141 | void CD3D8Driver::OnResize(const core::dimension2d<u32>& size) | ||
2142 | { | ||
2143 | if (!pID3DDevice) | ||
2144 | return; | ||
2145 | |||
2146 | CNullDriver::OnResize(size); | ||
2147 | reset(); | ||
2148 | } | ||
2149 | |||
2150 | |||
2151 | //! Returns type of video driver | ||
2152 | E_DRIVER_TYPE CD3D8Driver::getDriverType() const | ||
2153 | { | ||
2154 | return EDT_DIRECT3D8; | ||
2155 | } | ||
2156 | |||
2157 | |||
2158 | //! Returns the transformation set by setTransform | ||
2159 | const core::matrix4& CD3D8Driver::getTransform(E_TRANSFORMATION_STATE state) const | ||
2160 | { | ||
2161 | return Matrices[state]; | ||
2162 | } | ||
2163 | |||
2164 | |||
2165 | //! Sets a vertex shader constant. | ||
2166 | void CD3D8Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) | ||
2167 | { | ||
2168 | if (data) | ||
2169 | pID3DDevice->SetVertexShaderConstant(startRegister, data, constantAmount); | ||
2170 | } | ||
2171 | |||
2172 | |||
2173 | //! Sets a pixel shader constant. | ||
2174 | void CD3D8Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) | ||
2175 | { | ||
2176 | if (data) | ||
2177 | pID3DDevice->SetPixelShaderConstant(startRegister, data, constantAmount); | ||
2178 | } | ||
2179 | |||
2180 | |||
2181 | //! Sets a constant for the vertex shader based on a name. | ||
2182 | bool CD3D8Driver::setVertexShaderConstant(const c8* name, const f32* floats, int count) | ||
2183 | { | ||
2184 | os::Printer::log("Cannot set constant, no HLSL supported in D3D8"); | ||
2185 | return false; | ||
2186 | } | ||
2187 | |||
2188 | |||
2189 | //! Bool interface for the above. | ||
2190 | bool CD3D8Driver::setVertexShaderConstant(const c8* name, const bool* bools, int count) | ||
2191 | { | ||
2192 | os::Printer::log("Cannot set constant, no HLSL supported in D3D8"); | ||
2193 | return false; | ||
2194 | } | ||
2195 | |||
2196 | |||
2197 | //! Int interface for the above. | ||
2198 | bool CD3D8Driver::setVertexShaderConstant(const c8* name, const s32* ints, int count) | ||
2199 | { | ||
2200 | os::Printer::log("Cannot set constant, no HLSL supported in D3D8"); | ||
2201 | return false; | ||
2202 | } | ||
2203 | |||
2204 | |||
2205 | //! Sets a constant for the pixel shader based on a name. | ||
2206 | bool CD3D8Driver::setPixelShaderConstant(const c8* name, const f32* floats, int count) | ||
2207 | { | ||
2208 | os::Printer::log("Cannot set constant, no HLSL supported in D3D8"); | ||
2209 | return false; | ||
2210 | } | ||
2211 | |||
2212 | |||
2213 | //! Bool interface for the above. | ||
2214 | bool CD3D8Driver::setPixelShaderConstant(const c8* name, const bool* bools, int count) | ||
2215 | { | ||
2216 | os::Printer::log("Cannot set constant, no HLSL supported in D3D8"); | ||
2217 | return false; | ||
2218 | } | ||
2219 | |||
2220 | |||
2221 | //! Int interface for the above. | ||
2222 | bool CD3D8Driver::setPixelShaderConstant(const c8* name, const s32* ints, int count) | ||
2223 | { | ||
2224 | os::Printer::log("Cannot set constant, no HLSL supported in D3D8"); | ||
2225 | return false; | ||
2226 | } | ||
2227 | |||
2228 | |||
2229 | //! Adds a new material renderer to the VideoDriver, using pixel and/or | ||
2230 | //! vertex shaders to render geometry. | ||
2231 | s32 CD3D8Driver::addShaderMaterial(const c8* vertexShaderProgram, | ||
2232 | const c8* pixelShaderProgram, | ||
2233 | IShaderConstantSetCallBack* callback, | ||
2234 | E_MATERIAL_TYPE baseMaterial, s32 userData) | ||
2235 | { | ||
2236 | s32 nr = -1; | ||
2237 | CD3D8ShaderMaterialRenderer* r = new CD3D8ShaderMaterialRenderer( | ||
2238 | pID3DDevice, this, nr, vertexShaderProgram, pixelShaderProgram, | ||
2239 | callback, getMaterialRenderer(baseMaterial), userData); | ||
2240 | |||
2241 | r->drop(); | ||
2242 | return nr; | ||
2243 | } | ||
2244 | |||
2245 | |||
2246 | //! Returns a pointer to the IVideoDriver interface. (Implementation for | ||
2247 | //! IMaterialRendererServices) | ||
2248 | IVideoDriver* CD3D8Driver::getVideoDriver() | ||
2249 | { | ||
2250 | return this; | ||
2251 | } | ||
2252 | |||
2253 | |||
2254 | //! Clears the ZBuffer. | ||
2255 | void CD3D8Driver::clearZBuffer() | ||
2256 | { | ||
2257 | const HRESULT hr = pID3DDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0, 0); | ||
2258 | |||
2259 | if (FAILED(hr)) | ||
2260 | os::Printer::log("CD3D8Driver clearZBuffer() failed.", ELL_WARNING); | ||
2261 | } | ||
2262 | |||
2263 | |||
2264 | //! Returns an image created from the last rendered frame. | ||
2265 | IImage* CD3D8Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) | ||
2266 | { | ||
2267 | #if defined( _IRR_XBOX_PLATFORM_) | ||
2268 | return 0; | ||
2269 | #else | ||
2270 | if (target != video::ERT_FRAME_BUFFER) | ||
2271 | return 0; | ||
2272 | |||
2273 | // query the screen dimensions of the current adapter | ||
2274 | D3DDISPLAYMODE displayMode; | ||
2275 | pID3DDevice->GetDisplayMode(&displayMode); | ||
2276 | |||
2277 | if (format==video::ECF_UNKNOWN) | ||
2278 | format=video::ECF_A8R8G8B8; | ||
2279 | |||
2280 | // create the image surface to store the front buffer image [always A8R8G8B8] | ||
2281 | HRESULT hr; | ||
2282 | LPDIRECT3DSURFACE8 lpSurface; | ||
2283 | if (FAILED(hr = pID3DDevice->CreateImageSurface(displayMode.Width, displayMode.Height, D3DFMT_A8R8G8B8, &lpSurface))) | ||
2284 | return 0; | ||
2285 | |||
2286 | // read the front buffer into the image surface | ||
2287 | if (FAILED(hr = pID3DDevice->GetFrontBuffer(lpSurface))) | ||
2288 | { | ||
2289 | lpSurface->Release(); | ||
2290 | return 0; | ||
2291 | } | ||
2292 | |||
2293 | RECT clientRect; | ||
2294 | { | ||
2295 | POINT clientPoint; | ||
2296 | clientPoint.x = 0; | ||
2297 | clientPoint.y = 0; | ||
2298 | |||
2299 | ClientToScreen( (HWND)getExposedVideoData().D3D8.HWnd, &clientPoint ); | ||
2300 | |||
2301 | clientRect.left = clientPoint.x; | ||
2302 | clientRect.top = clientPoint.y; | ||
2303 | clientRect.right = clientRect.left + ScreenSize.Width; | ||
2304 | clientRect.bottom = clientRect.top + ScreenSize.Height; | ||
2305 | |||
2306 | // window can be off-screen partly, we can't take screenshots from that | ||
2307 | clientRect.left = core::max_(clientRect.left, 0l); | ||
2308 | clientRect.top = core::max_(clientRect.top, 0l); | ||
2309 | clientRect.right = core::min_(clientRect.right, (long)displayMode.Width); | ||
2310 | clientRect.bottom = core::min_(clientRect.bottom, (long)displayMode.Height ); | ||
2311 | } | ||
2312 | |||
2313 | // lock our area of the surface | ||
2314 | D3DLOCKED_RECT lockedRect; | ||
2315 | if (FAILED(lpSurface->LockRect(&lockedRect, &clientRect, D3DLOCK_READONLY))) | ||
2316 | { | ||
2317 | lpSurface->Release(); | ||
2318 | return 0; | ||
2319 | } | ||
2320 | |||
2321 | irr::core::dimension2d<u32> shotSize; | ||
2322 | shotSize.Width = core::min_( ScreenSize.Width, (u32)(clientRect.right-clientRect.left) ); | ||
2323 | shotSize.Height = core::min_( ScreenSize.Height, (u32)(clientRect.bottom-clientRect.top) ); | ||
2324 | |||
2325 | // this could throw, but we aren't going to worry about that case very much | ||
2326 | IImage* newImage = createImage(format, shotSize); | ||
2327 | |||
2328 | if (newImage) | ||
2329 | { | ||
2330 | // d3d pads the image, so we need to copy the correct number of bytes | ||
2331 | u32* dP = (u32*)newImage->lock(); | ||
2332 | u8 * sP = (u8 *)lockedRect.pBits; | ||
2333 | |||
2334 | // If the display mode format doesn't promise anything about the Alpha value | ||
2335 | // and it appears that it's not presenting 255, then we should manually | ||
2336 | // set each pixel alpha value to 255. | ||
2337 | if(D3DFMT_X8R8G8B8 == displayMode.Format && (0xFF000000 != (*dP & 0xFF000000))) | ||
2338 | { | ||
2339 | for (u32 y = 0; y < shotSize.Height; ++y) | ||
2340 | { | ||
2341 | for(u32 x = 0; x < shotSize.Width; ++x) | ||
2342 | { | ||
2343 | newImage->setPixel(x,y,*((u32*)sP) | 0xFF000000); | ||
2344 | sP += 4; | ||
2345 | } | ||
2346 | |||
2347 | sP += lockedRect.Pitch - (4 * shotSize.Width); | ||
2348 | } | ||
2349 | } | ||
2350 | else | ||
2351 | { | ||
2352 | for (u32 y = 0; y < shotSize.Height; ++y) | ||
2353 | { | ||
2354 | convertColor(sP, video::ECF_A8R8G8B8, shotSize.Width, dP, format); | ||
2355 | sP += lockedRect.Pitch; | ||
2356 | dP += shotSize.Width; | ||
2357 | } | ||
2358 | } | ||
2359 | |||
2360 | newImage->unlock(); | ||
2361 | } | ||
2362 | |||
2363 | // we can unlock and release the surface | ||
2364 | lpSurface->UnlockRect(); | ||
2365 | |||
2366 | // release the image surface | ||
2367 | lpSurface->Release(); | ||
2368 | |||
2369 | // return status of save operation to caller | ||
2370 | return newImage; | ||
2371 | #endif | ||
2372 | } | ||
2373 | |||
2374 | |||
2375 | // returns the current size of the screen or rendertarget | ||
2376 | const core::dimension2d<u32>& CD3D8Driver::getCurrentRenderTargetSize() const | ||
2377 | { | ||
2378 | if ( CurrentRendertargetSize.Width == 0 ) | ||
2379 | return ScreenSize; | ||
2380 | else | ||
2381 | return CurrentRendertargetSize; | ||
2382 | } | ||
2383 | |||
2384 | |||
2385 | // Set/unset a clipping plane. | ||
2386 | bool CD3D8Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) | ||
2387 | { | ||
2388 | #if defined( _IRR_XBOX_PLATFORM_) | ||
2389 | return false; | ||
2390 | #else | ||
2391 | if (index >= MaxUserClipPlanes) | ||
2392 | return false; | ||
2393 | pID3DDevice->SetClipPlane(index, (const float*)&plane); | ||
2394 | enableClipPlane(index, enable); | ||
2395 | return true; | ||
2396 | #endif | ||
2397 | } | ||
2398 | |||
2399 | |||
2400 | // Enable/disable a clipping plane. | ||
2401 | void CD3D8Driver::enableClipPlane(u32 index, bool enable) | ||
2402 | { | ||
2403 | #if defined( _IRR_XBOX_PLATFORM_) | ||
2404 | return; | ||
2405 | #else | ||
2406 | if (index >= MaxUserClipPlanes) | ||
2407 | return; | ||
2408 | DWORD renderstate; | ||
2409 | pID3DDevice->GetRenderState(D3DRS_CLIPPLANEENABLE, &renderstate); | ||
2410 | if (enable) | ||
2411 | renderstate |= (1 << index); | ||
2412 | else | ||
2413 | renderstate &= ~(1 << index); | ||
2414 | pID3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, renderstate); | ||
2415 | #endif | ||
2416 | } | ||
2417 | |||
2418 | |||
2419 | core::dimension2du CD3D8Driver::getMaxTextureSize() const | ||
2420 | { | ||
2421 | return core::dimension2du(Caps.MaxTextureWidth, Caps.MaxTextureHeight); | ||
2422 | } | ||
2423 | |||
2424 | |||
2425 | } // end namespace video | ||
2426 | } // end namespace irr | ||
2427 | |||
2428 | #endif // _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
2429 | |||
2430 | |||
2431 | namespace irr | ||
2432 | { | ||
2433 | namespace video | ||
2434 | { | ||
2435 | |||
2436 | #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
2437 | //! creates a video driver | ||
2438 | IVideoDriver* createDirectX8Driver(const SIrrlichtCreationParameters& params, | ||
2439 | io::IFileSystem* io, HWND window) | ||
2440 | { | ||
2441 | const bool pureSoftware = false; | ||
2442 | CD3D8Driver* dx8 = new CD3D8Driver(params, io); | ||
2443 | |||
2444 | if (!dx8->initDriver(window, pureSoftware)) | ||
2445 | { | ||
2446 | dx8->drop(); | ||
2447 | dx8 = 0; | ||
2448 | } | ||
2449 | |||
2450 | return dx8; | ||
2451 | } | ||
2452 | #endif // _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
2453 | |||
2454 | } // end namespace video | ||
2455 | } // end namespace irr | ||