aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CD3D9Texture.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CD3D9Texture.cpp699
1 files changed, 699 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CD3D9Texture.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CD3D9Texture.cpp
new file mode 100644
index 0000000..122ee2a
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CD3D9Texture.cpp
@@ -0,0 +1,699 @@
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#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
7
8#define _IRR_DONT_DO_MEMORY_DEBUGGING_HERE
9#include "CD3D9Texture.h"
10#include "CD3D9Driver.h"
11#include "os.h"
12
13#include <d3dx9tex.h>
14
15#ifndef _IRR_COMPILE_WITH_DIRECT3D_8_
16// The D3DXFilterTexture function seems to get linked wrong when
17// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
18// So mipmapgeneration is replaced with my own bad generation in d3d 8 when
19// compiling with both D3D 8 and 9.
20// #define _IRR_USE_D3DXFilterTexture_
21#endif // _IRR_COMPILE_WITH_DIRECT3D_8_
22
23#ifdef _IRR_USE_D3DXFilterTexture_
24#pragma comment(lib, "d3dx9.lib")
25#endif
26
27namespace irr
28{
29namespace video
30{
31
32//! rendertarget constructor
33CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& size,
34 const io::path& name, const ECOLOR_FORMAT format)
35: ITexture(name), Texture(0), RTTSurface(0), Driver(driver), DepthSurface(0),
36 TextureSize(size), ImageSize(size), Pitch(0), ColorFormat(ECF_UNKNOWN),
37 HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(true)
38{
39 #ifdef _DEBUG
40 setDebugName("CD3D9Texture");
41 #endif
42
43 Device=driver->getExposedVideoData().D3D9.D3DDev9;
44 if (Device)
45 Device->AddRef();
46
47 createRenderTarget(format);
48}
49
50
51//! constructor
52CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
53 u32 flags, const io::path& name, void* mipmapData)
54: ITexture(name), Texture(0), RTTSurface(0), Driver(driver), DepthSurface(0),
55 TextureSize(0,0), ImageSize(0,0), Pitch(0), ColorFormat(ECF_UNKNOWN),
56 HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(false)
57{
58 #ifdef _DEBUG
59 setDebugName("CD3D9Texture");
60 #endif
61
62 HasMipMaps = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
63
64 Device=driver->getExposedVideoData().D3D9.D3DDev9;
65 if (Device)
66 Device->AddRef();
67
68 if (image)
69 {
70 if (createTexture(flags, image))
71 {
72 if (copyTexture(image))
73 {
74 regenerateMipMapLevels(mipmapData);
75 }
76 }
77 else
78 os::Printer::log("Could not create DIRECT3D9 Texture.", ELL_WARNING);
79 }
80}
81
82
83//! destructor
84CD3D9Texture::~CD3D9Texture()
85{
86 if (Texture)
87 Texture->Release();
88
89 if (RTTSurface)
90 RTTSurface->Release();
91
92 // if this texture was the last one using the depth buffer
93 // we can release the surface. We only use the value of the pointer
94 // hence it is safe to use the dropped pointer...
95 if (DepthSurface)
96 {
97 if (DepthSurface->drop())
98 Driver->removeDepthSurface(DepthSurface);
99 }
100
101 if (Device)
102 Device->Release();
103}
104
105
106void CD3D9Texture::createRenderTarget(const ECOLOR_FORMAT format)
107{
108 // are texture size restrictions there ?
109 if(!Driver->queryFeature(EVDF_TEXTURE_NPOT))
110 {
111 if (TextureSize != ImageSize)
112 os::Printer::log("RenderTarget size has to be a power of two", ELL_INFORMATION);
113 }
114 TextureSize = TextureSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), !Driver->queryFeature(EVDF_TEXTURE_NSQUARE), true, Driver->Caps.MaxTextureWidth);
115
116 D3DFORMAT d3dformat = Driver->getD3DColorFormat();
117
118 if(ColorFormat == ECF_UNKNOWN)
119 {
120 // get irrlicht format from backbuffer
121 // (This will get overwritten by the custom format if it is provided, else kept.)
122 ColorFormat = Driver->getColorFormat();
123 setPitch(d3dformat);
124
125 // Use color format if provided.
126 if(format != ECF_UNKNOWN)
127 {
128 ColorFormat = format;
129 d3dformat = Driver->getD3DFormatFromColorFormat(format);
130 setPitch(d3dformat); // This will likely set pitch to 0 for now.
131 }
132 }
133 else
134 {
135 d3dformat = Driver->getD3DFormatFromColorFormat(ColorFormat);
136 }
137
138 // create texture
139 HRESULT hr;
140
141 hr = Device->CreateTexture(
142 TextureSize.Width,
143 TextureSize.Height,
144 1, // mip map level count, we don't want mipmaps here
145 D3DUSAGE_RENDERTARGET,
146 d3dformat,
147 D3DPOOL_DEFAULT,
148 &Texture,
149 NULL);
150
151 if (FAILED(hr))
152 {
153 if (D3DERR_INVALIDCALL == hr)
154 os::Printer::log("Could not create render target texture", "Invalid Call");
155 else
156 if (D3DERR_OUTOFVIDEOMEMORY == hr)
157 os::Printer::log("Could not create render target texture", "Out of Video Memory");
158 else
159 if (E_OUTOFMEMORY == hr)
160 os::Printer::log("Could not create render target texture", "Out of Memory");
161 else
162 os::Printer::log("Could not create render target texture");
163 }
164}
165
166
167bool CD3D9Texture::createMipMaps(u32 level)
168{
169 if (level==0)
170 return true;
171
172 if (HardwareMipMaps && Texture)
173 {
174 // generate mipmaps in hardware
175 Texture->GenerateMipSubLevels();
176 return true;
177 }
178
179 // manual mipmap generation
180 IDirect3DSurface9* upperSurface = 0;
181 IDirect3DSurface9* lowerSurface = 0;
182
183 // get upper level
184 HRESULT hr = Texture->GetSurfaceLevel(level-1, &upperSurface);
185 if (FAILED(hr) || !upperSurface)
186 {
187 os::Printer::log("Could not get upper surface level for mip map generation", ELL_WARNING);
188 return false;
189 }
190
191 // get lower level
192 hr = Texture->GetSurfaceLevel(level, &lowerSurface);
193 if (FAILED(hr) || !lowerSurface)
194 {
195 os::Printer::log("Could not get lower surface level for mip map generation", ELL_WARNING);
196 upperSurface->Release();
197 return false;
198 }
199
200 D3DSURFACE_DESC upperDesc, lowerDesc;
201 upperSurface->GetDesc(&upperDesc);
202 lowerSurface->GetDesc(&lowerDesc);
203
204 D3DLOCKED_RECT upperlr;
205 D3DLOCKED_RECT lowerlr;
206
207 // lock upper surface
208 if (FAILED(upperSurface->LockRect(&upperlr, NULL, 0)))
209 {
210 upperSurface->Release();
211 lowerSurface->Release();
212 os::Printer::log("Could not lock upper texture for mip map generation", ELL_WARNING);
213 return false;
214 }
215
216 // lock lower surface
217 if (FAILED(lowerSurface->LockRect(&lowerlr, NULL, 0)))
218 {
219 upperSurface->UnlockRect();
220 upperSurface->Release();
221 lowerSurface->Release();
222 os::Printer::log("Could not lock lower texture for mip map generation", ELL_WARNING);
223 return false;
224 }
225
226 if (upperDesc.Format != lowerDesc.Format)
227 {
228 os::Printer::log("Cannot copy mip maps with different formats.", ELL_WARNING);
229 }
230 else
231 {
232 if ((upperDesc.Format == D3DFMT_A1R5G5B5) || (upperDesc.Format == D3DFMT_R5G6B5))
233 copy16BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits,
234 lowerDesc.Width, lowerDesc.Height,
235 upperlr.Pitch, lowerlr.Pitch);
236 else
237 if (upperDesc.Format == D3DFMT_A8R8G8B8)
238 copy32BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits,
239 lowerDesc.Width, lowerDesc.Height,
240 upperlr.Pitch, lowerlr.Pitch);
241 else
242 os::Printer::log("Unsupported mipmap format, cannot copy.", ELL_WARNING);
243 }
244
245 bool result=true;
246 // unlock
247 if (FAILED(upperSurface->UnlockRect()))
248 result=false;
249 if (FAILED(lowerSurface->UnlockRect()))
250 result=false;
251
252 // release
253 upperSurface->Release();
254 lowerSurface->Release();
255
256 if (!result || (upperDesc.Width <= 3 && upperDesc.Height <= 3))
257 return result; // stop generating levels
258
259 // generate next level
260 return createMipMaps(level+1);
261}
262
263
264//! creates the hardware texture
265bool CD3D9Texture::createTexture(u32 flags, IImage * image)
266{
267 ImageSize = image->getDimension();
268
269 core::dimension2d<u32> optSize = ImageSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), !Driver->queryFeature(EVDF_TEXTURE_NSQUARE), true, Driver->Caps.MaxTextureWidth);
270
271 D3DFORMAT format = D3DFMT_A1R5G5B5;
272
273 switch(getTextureFormatFromFlags(flags))
274 {
275 case ETCF_ALWAYS_16_BIT:
276 format = D3DFMT_A1R5G5B5; break;
277 case ETCF_ALWAYS_32_BIT:
278 format = D3DFMT_A8R8G8B8; break;
279 case ETCF_OPTIMIZED_FOR_QUALITY:
280 {
281 switch(image->getColorFormat())
282 {
283 case ECF_R8G8B8:
284 case ECF_A8R8G8B8:
285 format = D3DFMT_A8R8G8B8; break;
286 case ECF_A1R5G5B5:
287 case ECF_R5G6B5:
288 format = D3DFMT_A1R5G5B5; break;
289 }
290 }
291 break;
292 case ETCF_OPTIMIZED_FOR_SPEED:
293 format = D3DFMT_A1R5G5B5;
294 break;
295 default:
296 break;
297 }
298 if (Driver->getTextureCreationFlag(video::ETCF_NO_ALPHA_CHANNEL))
299 {
300 if (format == D3DFMT_A8R8G8B8)
301 format = D3DFMT_R8G8B8;
302 else if (format == D3DFMT_A1R5G5B5)
303 format = D3DFMT_R5G6B5;
304 }
305
306 const bool mipmaps = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
307
308 DWORD usage = 0;
309
310 // This enables hardware mip map generation.
311 if (mipmaps && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
312 {
313 LPDIRECT3D9 intf = Driver->getExposedVideoData().D3D9.D3D9;
314 D3DDISPLAYMODE d3ddm;
315 intf->GetAdapterDisplayMode(Driver->Params.DisplayAdapter, &d3ddm);
316
317 if (D3D_OK==intf->CheckDeviceFormat(Driver->Params.DisplayAdapter,D3DDEVTYPE_HAL,d3ddm.Format,D3DUSAGE_AUTOGENMIPMAP,D3DRTYPE_TEXTURE,format))
318 {
319 usage = D3DUSAGE_AUTOGENMIPMAP;
320 HardwareMipMaps = true;
321 }
322 }
323
324 HRESULT hr = Device->CreateTexture(optSize.Width, optSize.Height,
325 mipmaps ? 0 : 1, // number of mipmaplevels (0 = automatic all)
326 usage, // usage
327 format, D3DPOOL_MANAGED , &Texture, NULL);
328
329 if (FAILED(hr))
330 {
331 // try brute force 16 bit
332 HardwareMipMaps = false;
333 if (format == D3DFMT_A8R8G8B8)
334 format = D3DFMT_A1R5G5B5;
335 else if (format == D3DFMT_R8G8B8)
336 format = D3DFMT_R5G6B5;
337 else
338 return false;
339
340 hr = Device->CreateTexture(optSize.Width, optSize.Height,
341 mipmaps ? 0 : 1, // number of mipmaplevels (0 = automatic all)
342 0, format, D3DPOOL_MANAGED, &Texture, NULL);
343 }
344
345 ColorFormat = Driver->getColorFormatFromD3DFormat(format);
346 setPitch(format);
347 return (SUCCEEDED(hr));
348}
349
350
351//! copies the image to the texture
352bool CD3D9Texture::copyTexture(IImage * image)
353{
354 if (Texture && image)
355 {
356 D3DSURFACE_DESC desc;
357 Texture->GetLevelDesc(0, &desc);
358
359 TextureSize.Width = desc.Width;
360 TextureSize.Height = desc.Height;
361
362 D3DLOCKED_RECT rect;
363 HRESULT hr = Texture->LockRect(0, &rect, 0, 0);
364 if (FAILED(hr))
365 {
366 os::Printer::log("Texture data not copied", "Could not LockRect D3D9 Texture.", ELL_ERROR);
367 return false;
368 }
369
370 Pitch = rect.Pitch;
371 image->copyToScaling(rect.pBits, TextureSize.Width, TextureSize.Height, ColorFormat, Pitch);
372
373 hr = Texture->UnlockRect(0);
374 if (FAILED(hr))
375 {
376 os::Printer::log("Texture data not copied", "Could not UnlockRect D3D9 Texture.", ELL_ERROR);
377 return false;
378 }
379 }
380
381 return true;
382}
383
384
385//! lock function
386void* CD3D9Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
387{
388 if (!Texture)
389 return 0;
390
391 MipLevelLocked=mipmapLevel;
392 HRESULT hr;
393 D3DLOCKED_RECT rect;
394 if(!IsRenderTarget)
395 {
396 hr = Texture->LockRect(mipmapLevel, &rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0);
397 if (FAILED(hr))
398 {
399 os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR);
400 return 0;
401 }
402 }
403 else
404 {
405 if (!RTTSurface)
406 {
407 // Make RTT surface large enough for all miplevels (including 0)
408 D3DSURFACE_DESC desc;
409 Texture->GetLevelDesc(0, &desc);
410 hr = Device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &RTTSurface, 0);
411 if (FAILED(hr))
412 {
413 os::Printer::log("Could not lock DIRECT3D9 Texture", "Offscreen surface creation failed.", ELL_ERROR);
414 return 0;
415 }
416 }
417
418 IDirect3DSurface9 *surface = 0;
419 hr = Texture->GetSurfaceLevel(mipmapLevel, &surface);
420 if (FAILED(hr))
421 {
422 os::Printer::log("Could not lock DIRECT3D9 Texture", "Could not get surface.", ELL_ERROR);
423 return 0;
424 }
425 hr = Device->GetRenderTargetData(surface, RTTSurface);
426 surface->Release();
427 if(FAILED(hr))
428 {
429 os::Printer::log("Could not lock DIRECT3D9 Texture", "Data copy failed.", ELL_ERROR);
430 return 0;
431 }
432 hr = RTTSurface->LockRect(&rect, 0, (mode==ETLM_READ_ONLY)?D3DLOCK_READONLY:0);
433 if(FAILED(hr))
434 {
435 os::Printer::log("Could not lock DIRECT3D9 Texture", "LockRect failed.", ELL_ERROR);
436 return 0;
437 }
438 }
439 return rect.pBits;
440}
441
442
443//! unlock function
444void CD3D9Texture::unlock()
445{
446 if (!Texture)
447 return;
448
449 if (!IsRenderTarget)
450 Texture->UnlockRect(MipLevelLocked);
451 else if (RTTSurface)
452 RTTSurface->UnlockRect();
453}
454
455
456//! Returns original size of the texture.
457const core::dimension2d<u32>& CD3D9Texture::getOriginalSize() const
458{
459 return ImageSize;
460}
461
462
463//! Returns (=size) of the texture.
464const core::dimension2d<u32>& CD3D9Texture::getSize() const
465{
466 return TextureSize;
467}
468
469
470//! returns driver type of texture (=the driver, who created the texture)
471E_DRIVER_TYPE CD3D9Texture::getDriverType() const
472{
473 return EDT_DIRECT3D9;
474}
475
476
477//! returns color format of texture
478ECOLOR_FORMAT CD3D9Texture::getColorFormat() const
479{
480 return ColorFormat;
481}
482
483
484//! returns pitch of texture (in bytes)
485u32 CD3D9Texture::getPitch() const
486{
487 return Pitch;
488}
489
490
491//! returns the DIRECT3D9 Texture
492IDirect3DBaseTexture9* CD3D9Texture::getDX9Texture() const
493{
494 return Texture;
495}
496
497
498//! returns if texture has mipmap levels
499bool CD3D9Texture::hasMipMaps() const
500{
501 return HasMipMaps;
502}
503
504
505void CD3D9Texture::copy16BitMipMap(char* src, char* tgt,
506 s32 width, s32 height,
507 s32 pitchsrc, s32 pitchtgt) const
508{
509 for (s32 y=0; y<height; ++y)
510 {
511 for (s32 x=0; x<width; ++x)
512 {
513 u32 a=0, r=0, g=0, b=0;
514
515 for (s32 dy=0; dy<2; ++dy)
516 {
517 const s32 tgy = (y*2)+dy;
518 for (s32 dx=0; dx<2; ++dx)
519 {
520 const s32 tgx = (x*2)+dx;
521
522 SColor c;
523 if (ColorFormat == ECF_A1R5G5B5)
524 c = A1R5G5B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)]));
525 else
526 c = R5G6B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)]));
527
528 a += c.getAlpha();
529 r += c.getRed();
530 g += c.getGreen();
531 b += c.getBlue();
532 }
533 }
534
535 a /= 4;
536 r /= 4;
537 g /= 4;
538 b /= 4;
539
540 u16 c;
541 if (ColorFormat == ECF_A1R5G5B5)
542 c = RGBA16(r,g,b,a);
543 else
544 c = A8R8G8B8toR5G6B5(SColor(a,r,g,b).color);
545 *(u16*)(&tgt[(x*2)+(y*pitchtgt)]) = c;
546 }
547 }
548}
549
550
551void CD3D9Texture::copy32BitMipMap(char* src, char* tgt,
552 s32 width, s32 height,
553 s32 pitchsrc, s32 pitchtgt) const
554{
555 for (s32 y=0; y<height; ++y)
556 {
557 for (s32 x=0; x<width; ++x)
558 {
559 u32 a=0, r=0, g=0, b=0;
560 SColor c;
561
562 for (s32 dy=0; dy<2; ++dy)
563 {
564 const s32 tgy = (y*2)+dy;
565 for (s32 dx=0; dx<2; ++dx)
566 {
567 const s32 tgx = (x*2)+dx;
568
569 c = *(u32*)(&src[(tgx*4)+(tgy*pitchsrc)]);
570
571 a += c.getAlpha();
572 r += c.getRed();
573 g += c.getGreen();
574 b += c.getBlue();
575 }
576 }
577
578 a /= 4;
579 r /= 4;
580 g /= 4;
581 b /= 4;
582
583 c.set(a, r, g, b);
584 *(u32*)(&tgt[(x*4)+(y*pitchtgt)]) = c.color;
585 }
586 }
587}
588
589
590//! Regenerates the mip map levels of the texture. Useful after locking and
591//! modifying the texture
592void CD3D9Texture::regenerateMipMapLevels(void* mipmapData)
593{
594 if (mipmapData)
595 {
596 core::dimension2du size = TextureSize;
597 u32 level=0;
598 do
599 {
600 if (size.Width>1)
601 size.Width /=2;
602 if (size.Height>1)
603 size.Height /=2;
604 ++level;
605 IDirect3DSurface9* mipSurface = 0;
606 HRESULT hr = Texture->GetSurfaceLevel(level, &mipSurface);
607 if (FAILED(hr) || !mipSurface)
608 {
609 os::Printer::log("Could not get mipmap level", ELL_WARNING);
610 return;
611 }
612 D3DSURFACE_DESC mipDesc;
613 mipSurface->GetDesc(&mipDesc);
614 D3DLOCKED_RECT miplr;
615
616 // lock mipmap surface
617 if (FAILED(mipSurface->LockRect(&miplr, NULL, 0)))
618 {
619 mipSurface->Release();
620 os::Printer::log("Could not lock texture", ELL_WARNING);
621 return;
622 }
623
624 memcpy(miplr.pBits, mipmapData, size.getArea()*getPitch()/TextureSize.Width);
625 mipmapData = (u8*)mipmapData+size.getArea()*getPitch()/TextureSize.Width;
626 // unlock
627 mipSurface->UnlockRect();
628 // release
629 mipSurface->Release();
630 } while (size.Width != 1 || size.Height != 1);
631 }
632 else if (HasMipMaps)
633 {
634 // create mip maps.
635#ifdef _IRR_USE_D3DXFilterTexture_
636 // The D3DXFilterTexture function seems to get linked wrong when
637 // compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
638 // So mipmapgeneration is replaced with my own bad generation
639 HRESULT hr = D3DXFilterTexture(Texture, NULL, D3DX_DEFAULT, D3DX_DEFAULT);
640 if (FAILED(hr))
641#endif
642 createMipMaps();
643 }
644}
645
646
647//! returns if it is a render target
648bool CD3D9Texture::isRenderTarget() const
649{
650 return IsRenderTarget;
651}
652
653
654//! Returns pointer to the render target surface
655IDirect3DSurface9* CD3D9Texture::getRenderTargetSurface()
656{
657 if (!IsRenderTarget)
658 return 0;
659
660 IDirect3DSurface9 *pRTTSurface = 0;
661 if (Texture)
662 Texture->GetSurfaceLevel(0, &pRTTSurface);
663
664 if (pRTTSurface)
665 pRTTSurface->Release();
666
667 return pRTTSurface;
668}
669
670
671void CD3D9Texture::setPitch(D3DFORMAT d3dformat)
672{
673 switch(d3dformat)
674 {
675 case D3DFMT_X1R5G5B5:
676 case D3DFMT_A1R5G5B5:
677 Pitch = TextureSize.Width * 2;
678 break;
679 case D3DFMT_A8B8G8R8:
680 case D3DFMT_A8R8G8B8:
681 case D3DFMT_X8R8G8B8:
682 Pitch = TextureSize.Width * 4;
683 break;
684 case D3DFMT_R5G6B5:
685 Pitch = TextureSize.Width * 2;
686 break;
687 case D3DFMT_R8G8B8:
688 Pitch = TextureSize.Width * 3;
689 break;
690 default:
691 Pitch = 0;
692 };
693}
694
695
696} // end namespace video
697} // end namespace irr
698
699#endif // _IRR_COMPILE_WITH_DIRECT3D_9_