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