aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CD3D8Driver.cpp
diff options
context:
space:
mode:
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.cpp2455
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
21namespace irr
22{
23namespace video
24{
25
26
27//! constructor
28CD3D8Driver::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
65CD3D8Driver::~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
79void 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
143bool 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.
416bool 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.
476bool 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
516bool 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
569bool 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
620void 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
654bool 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
681void 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)
696video::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.
703void 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
714bool 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.
815ITexture* 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
835void 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
861const core::rect<s32>& CD3D8Driver::getViewPort() const
862{
863 return ViewPort;
864}
865
866
867//! draws a vertex primitive list
868void 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
887void 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
905void 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.
1006void 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
1140void 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.
1219void 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.
1259void 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
1288void 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
1306void 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
1342bool 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
1391D3DTEXTUREADDRESS 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.
1424void 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
1681void 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
1748void 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
1805void 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
1908void 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
1920s32 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
1969void 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
1979u32 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.
1988void 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".
2001const 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.
2010void 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.
2052void 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.
2087u32 CD3D8Driver::getMaximalPrimitiveCount() const
2088{
2089 return Caps.MaxPrimitiveCount;
2090}
2091
2092
2093//! Sets the fog mode.
2094void 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.
2126void 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
2141void 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
2152E_DRIVER_TYPE CD3D8Driver::getDriverType() const
2153{
2154 return EDT_DIRECT3D8;
2155}
2156
2157
2158//! Returns the transformation set by setTransform
2159const core::matrix4& CD3D8Driver::getTransform(E_TRANSFORMATION_STATE state) const
2160{
2161 return Matrices[state];
2162}
2163
2164
2165//! Sets a vertex shader constant.
2166void 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.
2174void 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.
2182bool 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.
2190bool 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.
2198bool 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.
2206bool 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.
2214bool 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.
2222bool 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.
2231s32 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)
2248IVideoDriver* CD3D8Driver::getVideoDriver()
2249{
2250 return this;
2251}
2252
2253
2254//! Clears the ZBuffer.
2255void 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.
2265IImage* 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
2376const 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.
2386bool 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.
2401void 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
2419core::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
2431namespace irr
2432{
2433namespace video
2434{
2435
2436#ifdef _IRR_COMPILE_WITH_DIRECT3D_8_
2437//! creates a video driver
2438IVideoDriver* 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