Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / driver / direct3d / driver_direct3d_texture.cpp
blob71af20f0087e2096692f410a0cfcef4d3ccebc88
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stddirect3d.h"
22 #include "nel/3d/vertex_buffer.h"
23 #include "nel/3d/light.h"
24 #include "nel/3d/index_buffer.h"
25 #include "nel/misc/rect.h"
26 #include "nel/3d/viewport.h"
27 #include "nel/3d/scissor.h"
28 #include "nel/3d/u_driver.h"
30 #include "driver_direct3d.h"
32 #ifdef DEBUG_NEW
33 #define new DEBUG_NEW
34 #endif
36 using namespace std;
37 using namespace NLMISC;
40 namespace NL3D
43 std::vector<uint8> CDriverD3D::_TempBuffer;
45 // ***************************************************************************
47 CTextureDrvInfosD3D::CTextureDrvInfosD3D(IDriver *drv, ItTexDrvInfoPtrMap it, CDriverD3D *drvD3D, bool renderTarget)
48 : ITextureDrvInfos(drv, it)
50 H_AUTO_D3D(CTextureDrvInfosD3D_CTextureDrvInfosD3D)
51 Texture = NULL;
52 Texture2d = NULL;
53 TextureCube = NULL;
54 TextureMemory = 0;
55 RenderTarget = renderTarget;
56 FirstMipMap = 0;
58 // Nb: at Driver dtor, all tex infos are deleted, so _Driver is always valid.
59 _Driver= drvD3D;
61 WrapS = D3DTADDRESS_WRAP;
62 WrapT = D3DTADDRESS_WRAP;
63 MagFilter = D3DTEXF_POINT;
64 MinFilter = D3DTEXF_POINT;
65 MipFilter = D3DTEXF_NONE;
68 // ***************************************************************************
70 CTextureDrvInfosD3D::~CTextureDrvInfosD3D()
72 H_AUTO_D3D(CTextureDrvInfosD3D_CTextureDrvInfosD3DDtor)
73 if (Texture)
75 // If a texture is in the cache state -> set to null (texture no more used)
76 for (uint32 i = 0; i < CDriverD3D::MaxTexture; ++i)
77 if (_Driver->_TexturePtrStateCache[i].Texture == Texture)
78 _Driver->setTexture(i, (LPDIRECT3DBASETEXTURE9)NULL);
80 Texture->Release();
81 Texture = NULL;
82 Texture2d = NULL;
83 TextureCube = NULL;
86 // release profiling texture mem.
87 _Driver->_AllocatedTextureMemory -= TextureMemory;
89 // release in TextureUsed.
90 _Driver->_TextureUsed.erase (this);
93 // ***************************************************************************
95 bool CDriverD3D::setupTexture (ITexture& tex)
97 H_AUTO_D3D(CDriverD3D_setupTexture )
98 bool nTmp;
99 return setupTextureEx (tex, true, nTmp, false);
102 // ***************************************************************************
104 const D3DTEXTUREADDRESS RemapTextureAdressTypeNeL2D3D[ITexture::WrapModeCount]=
106 D3DTADDRESS_WRAP, // Repeat
107 D3DTADDRESS_CLAMP, // Clamp
110 // ***************************************************************************
112 const D3DTEXTUREFILTERTYPE RemapMagTextureFilterTypeNeL2D3D[ITexture::MagFilterCount]=
114 D3DTEXF_POINT, // Nearest
115 D3DTEXF_LINEAR, // Linear
118 // ***************************************************************************
120 const D3DTEXTUREFILTERTYPE RemapMinTextureFilterTypeNeL2D3D[ITexture::MinFilterCount]=
122 D3DTEXF_POINT, // NearestMipMapOff
123 D3DTEXF_POINT, // NearestMipMapNearest
124 D3DTEXF_POINT, // NearestMipMapLinear
125 D3DTEXF_LINEAR, // LinearMipMapOff
126 D3DTEXF_LINEAR, // LinearMipMapNearest
127 D3DTEXF_LINEAR, // LinearMipMapLinear
130 // ***************************************************************************
132 const D3DTEXTUREFILTERTYPE RemapMipTextureFilterTypeNeL2D3D[ITexture::MinFilterCount]=
134 D3DTEXF_NONE, // NearestMipMapOff
135 D3DTEXF_POINT, // NearestMipMapNearest
136 D3DTEXF_LINEAR, // NearestMipMapLinear
137 D3DTEXF_NONE, // LinearMipMapOff
138 D3DTEXF_POINT, // LinearMipMapNearest
139 D3DTEXF_LINEAR, // LinearMipMapLinear
142 // ***************************************************************************
144 const D3DFORMAT RemapTextureFormatTypeNeL2D3D[CBitmap::ModeCount]=
146 D3DFMT_A8R8G8B8, // RGBA
147 D3DFMT_L8, // Luminance
148 D3DFMT_A8, // Alpha
149 D3DFMT_A8L8, // AlphaLuminance
150 D3DFMT_DXT1, // DXTC1
151 D3DFMT_DXT1, // DXTC1Alpha
152 D3DFMT_DXT3, // DXTC3
153 D3DFMT_DXT5, // DXTC5
154 D3DFMT_V8U8, // DsDt
157 // ***************************************************************************
159 const bool RemapTextureFormatCompressedTypeNeL2D3D[CBitmap::ModeCount]=
161 false, // RGBA
162 false, // Luminance
163 false, // Alpha
164 false, // AlphaLuminance
165 true, // DXTC1
166 true, // DXTC1Alpha
167 true, // DXTC3
168 true, // DXTC5
169 false, // DsDt
172 // ***************************************************************************
174 const D3DCUBEMAP_FACES RemapCubeFaceTypeNeL2D3D[6]=
176 D3DCUBEMAP_FACE_POSITIVE_X, // positive_x
177 D3DCUBEMAP_FACE_NEGATIVE_X, // negative_x
178 D3DCUBEMAP_FACE_POSITIVE_Z, // positive_y
179 D3DCUBEMAP_FACE_NEGATIVE_Z, // negative_y
180 D3DCUBEMAP_FACE_POSITIVE_Y, // positive_z
181 D3DCUBEMAP_FACE_NEGATIVE_Y, // negative_z
184 // ***************************************************************************
186 D3DFORMAT CDriverD3D::getD3DDestTextureFormat (ITexture& tex)
188 H_AUTO_D3D(CDriverD3D_getD3DDestTextureFormat )
189 ITexture::TUploadFormat texfmt= tex.getUploadFormat();
191 // If auto, retrieve the pixel format of the bitmap.
192 if(texfmt == ITexture::Auto)
194 switch(tex.getPixelFormat())
196 case CBitmap::RGBA:
197 if(_ForceDXTCCompression && tex.allowDegradation() )
198 texfmt= ITexture::DXTC5;
199 else
200 texfmt= ITexture::RGBA8888;
201 break;
202 case CBitmap::DXTC1:
203 texfmt= ITexture::DXTC1;
204 break;
205 case CBitmap::DXTC1Alpha:
206 texfmt= ITexture::DXTC1Alpha;
207 break;
208 case CBitmap::DXTC3:
209 texfmt= ITexture::DXTC3;
210 break;
211 case CBitmap::DXTC5:
212 texfmt= ITexture::DXTC5;
213 break;
214 case CBitmap::Luminance:
215 texfmt= ITexture::Luminance;
216 break;
217 case CBitmap::Alpha:
218 texfmt= ITexture::Alpha;
219 break;
220 case CBitmap::AlphaLuminance:
221 texfmt= ITexture::AlphaLuminance;
222 break;
223 case CBitmap::DsDt:
224 texfmt= ITexture::DsDt;
225 break;
226 default: texfmt= ITexture::RGBA8888; break;
230 // Get standard prefered tex format.
231 nlassert (texfmt<ITexture::UploadFormatCount);
232 return _PreferedTextureFormat[texfmt];
235 // ***************************************************************************
237 uint getPixelFormatSize (D3DFORMAT destFormat)
239 uint bits = 0;
240 switch (destFormat)
242 case D3DFMT_R8G8B8: bits=32; break;
243 case D3DFMT_A8R8G8B8: bits=32; break;
244 case D3DFMT_X8R8G8B8: bits=32; break;
245 case D3DFMT_R5G6B5: bits=16; break;
246 case D3DFMT_X1R5G5B5: bits=16; break;
247 case D3DFMT_A1R5G5B5: bits=16; break;
248 case D3DFMT_A4R4G4B4: bits=16; break;
249 case D3DFMT_R3G3B2: bits=8; break;
250 case D3DFMT_A8: bits=8; break;
251 case D3DFMT_A8R3G3B2: bits=16; break;
252 case D3DFMT_X4R4G4B4: bits=16; break;
253 case D3DFMT_A2B10G10R10: bits=32; break;
254 case D3DFMT_A8B8G8R8: bits=32; break;
255 case D3DFMT_X8B8G8R8: bits=32; break;
256 case D3DFMT_G16R16: bits=32; break;
257 case D3DFMT_A2R10G10B10: bits=32; break;
258 case D3DFMT_A16B16G16R16: bits=64; break;
259 case D3DFMT_A8P8: bits=16; break;
260 case D3DFMT_P8: bits=8; break;
261 case D3DFMT_L8: bits=8; break;
262 case D3DFMT_L16: bits=16; break;
263 case D3DFMT_A8L8: bits=16; break;
264 case D3DFMT_A4L4: bits=8; break;
265 case D3DFMT_V8U8: bits=16; break;
266 case D3DFMT_Q8W8V8U8: bits=32; break;
267 case D3DFMT_V16U16: bits=32; break;
268 case D3DFMT_Q16W16V16U16: bits=64; break;
269 case D3DFMT_CxV8U8: bits=16; break;
270 case D3DFMT_L6V5U5: bits=16; break;
271 case D3DFMT_X8L8V8U8: bits=32; break;
272 case D3DFMT_A2W10V10U10: bits=32; break;
273 case D3DFMT_G8R8_G8B8: bits=24; break;
274 case D3DFMT_R8G8_B8G8: bits=24; break;
275 case D3DFMT_DXT1: bits=4; break;
276 case D3DFMT_DXT2: bits=8; break;
277 case D3DFMT_DXT3: bits=8; break;
278 case D3DFMT_DXT4: bits=8; break;
279 case D3DFMT_DXT5: bits=8; break;
280 default: nlstop; break; // unknown pixel format
282 return bits;
285 // ***************************************************************************
287 uint32 CDriverD3D::computeTextureMemoryUsage (uint width, uint height, uint levels, D3DFORMAT destFormat, bool cube)
289 H_AUTO_D3D(CDriverD3D_computeTextureMemoryUsage )
290 // Get bit per pixel
291 uint bits = getPixelFormatSize (destFormat);
292 uint32 size = 0;
293 while (levels>0)
295 size += (width * height * bits) >> 3;
296 width = max((uint)(width>>1), 1U);
297 height = max((uint)(height>>1), 1U);
298 levels--;
300 if (cube)
301 size *= 6;
302 return size;
305 // ***************************************************************************
307 bool CDriverD3D::generateD3DTexture (ITexture& tex, bool textureDegradation, D3DFORMAT &destFormat, D3DFORMAT &srcFormat, bool &cube)
309 H_AUTO_D3D(CDriverD3D_generateD3DTexture )
310 // Regenerate all the texture.
311 tex.generate();
313 // Is a cube texture ?
314 cube = tex.isTextureCube();
316 // D3D infos
317 CTextureDrvInfosD3D* d3dtext;
318 d3dtext= getTextureD3D(tex);
320 // For each face
321 UINT width = 0;
322 UINT height = 0;
323 UINT levels = 0;
324 bool srcFormatCompressed = true;
325 bool renderTarget = false;
326 const uint faceCount = cube?6:1;
327 uint face;
328 uint firstMipMap = 0;
329 for (face=0; face<faceCount; face++)
331 // Get the texture pointer
332 ITexture *texture = cube?(static_cast<CTextureCube*>(&tex)->getTexture((CTextureCube::TFace)face)):&tex;
334 // getD3DTextureFormat choose a d3d dest and a src format. src format should be the tex one.
335 if (face==0)
337 srcFormatCompressed = RemapTextureFormatCompressedTypeNeL2D3D[texture->getPixelFormat()];
338 srcFormat = RemapTextureFormatTypeNeL2D3D[texture->getPixelFormat()];
339 destFormat = getD3DDestTextureFormat (*texture);
341 else
343 // All cube texture must have the same format
344 nlassert (srcFormatCompressed == RemapTextureFormatCompressedTypeNeL2D3D[texture->getPixelFormat()]);
345 nlassert (srcFormat == RemapTextureFormatTypeNeL2D3D[texture->getPixelFormat()]);
346 nlassert (destFormat == getD3DDestTextureFormat (*texture));
349 // Should not happen
350 nlassert (!((srcFormatCompressed) && (destFormat == D3DFMT_A8R8G8B8)));
352 // Get new texture format
353 width = texture->getWidth();
354 height = texture->getHeight();
355 levels = texture->getMipMapCount();
356 if (levels == 1 && !srcFormatCompressed)
358 // if not built-in mipmap levels, compute how many of them are needed
359 levels = texture->computeNeededMipMapCount();
361 if (cube && !_CubbedMipMapSupported)
363 levels = 1;
365 renderTarget = texture->getRenderTarget();
367 // Texture degradation
368 if (_ForceTextureResizePower>0 && texture->allowDegradation() && (!srcFormatCompressed || levels>1) && textureDegradation)
370 // New size
371 width = max(1U, (UINT)(texture->getWidth(0) >> _ForceTextureResizePower));
372 height = max(1U, (UINT)(texture->getHeight(0) >> _ForceTextureResizePower));
373 levels = (levels>_ForceTextureResizePower)?levels-_ForceTextureResizePower:1;
375 // Modify source texture
376 if (srcFormatCompressed)
378 if (cube && !_CubbedMipMapSupported)
380 // just uses one the level of interest and not the others
381 firstMipMap = (texture->getMipMapCount()>_ForceTextureResizePower)?_ForceTextureResizePower : texture->getMipMapCount() - 1;
382 levels = 1;
384 else
386 // Skip a compressed mipmap
387 firstMipMap = texture->getMipMapCount()-levels;
390 else
392 // Resample the non-compressed texture
393 texture->resample(width, height);
397 // Generate mipmap
398 if (!srcFormatCompressed)
400 if (texture->mipMapOn() && levels > 1)
402 texture->buildMipMaps();
403 levels= texture->getMipMapCount();
405 else
406 levels= 1;
410 // If compressed, width and height must be 4x4 aligned
411 if (srcFormatCompressed)
413 if (width & 3)
414 width = (width & ~3)+4;
415 if (height & 3)
416 height = (height & ~3)+4;
419 // Got an old texture ?
420 if (d3dtext->Texture &&
422 (d3dtext->Width != width) ||
423 (d3dtext->Height != height) ||
424 (d3dtext->Levels != levels) ||
425 (d3dtext->FirstMipMap != firstMipMap) ||
426 (d3dtext->DestFormat != destFormat) ||
427 (d3dtext->IsCube != cube) ||
428 (d3dtext->RenderTarget != renderTarget)
432 // Delete this texture
433 if (d3dtext->Texture)
435 d3dtext->Texture->Release();
436 d3dtext->Texture = NULL;
437 d3dtext->Texture2d = NULL;
438 d3dtext->TextureCube = NULL;
441 // profiling: count TextureMemory usage.
442 _AllocatedTextureMemory -= d3dtext->TextureMemory;
443 d3dtext->TextureMemory = 0;
446 // Texture must be created ?
447 if (d3dtext->Texture == NULL)
449 // profiling: count TextureMemory usage.
450 uint32 textureMemory = computeTextureMemoryUsage (width, height, levels, destFormat, cube);
452 // Create the texture
453 bool createSuccess;
455 if (cube)
457 createSuccess = _DeviceInterface->CreateCubeTexture(width, levels, renderTarget?D3DUSAGE_RENDERTARGET:0, destFormat, renderTarget?D3DPOOL_DEFAULT:D3DPOOL_MANAGED, &(d3dtext->TextureCube), NULL) == D3D_OK;
458 d3dtext->Texture = d3dtext->TextureCube;
460 else
463 // textures with mipmaps doesn't support not power of two sizes
464 // only DXTC formats are beginning with a 'D'
465 if (supportNonPowerOfTwoTextures() && (!isPowerOf2(width) || !isPowerOf2(height)) && levels == 1)
467 // support for non-power of two sizes for textures need these lines
468 _DeviceInterface->SetRenderState(D3DRS_WRAP0, 0);
469 _DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
470 _DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
471 _DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);
475 HRESULT hr = _DeviceInterface->CreateTexture (width, height, levels, renderTarget?D3DUSAGE_RENDERTARGET:0, destFormat, renderTarget?D3DPOOL_DEFAULT:D3DPOOL_MANAGED, &(d3dtext->Texture2d), NULL);
477 if (hr != D3D_OK)
479 nlwarning("CreateTexture failed with code 0x%x for texture %s in %ux%u", hr, tex.getShareName().c_str(), width, height);
482 createSuccess = hr == D3D_OK;
483 d3dtext->Texture = d3dtext->Texture2d;
486 if (!createSuccess)
487 return false;
489 // Stats
490 d3dtext->TextureMemory = textureMemory;
491 _AllocatedTextureMemory += d3dtext->TextureMemory;
493 // Copy parameters
494 d3dtext->Width = width;
495 d3dtext->Height = height;
496 d3dtext->Levels = uint8(levels);
497 d3dtext->FirstMipMap = uint8(firstMipMap);
498 d3dtext->DestFormat = destFormat;
499 d3dtext->SrcCompressed = srcFormatCompressed;
500 d3dtext->IsCube = cube;
503 return true;
506 // ***************************************************************************
507 inline void CDriverD3D::setupTextureWrapMode(ITexture& tex)
509 CTextureDrvInfosD3D *d3dtext = CDriverD3D::getTextureD3D(tex);
510 nlassert(d3dtext);
511 d3dtext->WrapS = RemapTextureAdressTypeNeL2D3D[tex.getWrapS()];
512 d3dtext->WrapT = RemapTextureAdressTypeNeL2D3D[tex.getWrapT()];
513 d3dtext->MagFilter = RemapMagTextureFilterTypeNeL2D3D[tex.getMagFilter()];
514 d3dtext->MinFilter = RemapMinTextureFilterTypeNeL2D3D[tex.getMinFilter()];
515 d3dtext->MipFilter = RemapMipTextureFilterTypeNeL2D3D[tex.getMinFilter()];
517 // only enable for min filter, because it's never supported for mag filter
518 if (_AnisotropicFilter > 1 && tex.getMinFilter() > ITexture::NearestMipMapLinear)
520 if (tex.isTextureCube())
522 if (_AnisotropicMinCubeSupported) d3dtext->MinFilter = D3DTEXF_ANISOTROPIC;
524 else
526 if (_AnisotropicMinSupported) d3dtext->MinFilter = D3DTEXF_ANISOTROPIC;
532 bool CDriverD3D::setupTextureEx (ITexture& tex, bool bUpload, bool &bAllUploaded, bool bMustRecreateSharedTexture)
534 H_AUTO_D3D(CDriverD3D_setupTextureEx )
535 bAllUploaded = false;
538 // 0. Create/Retrieve the driver texture.
539 //=======================================
540 bool mustCreate = false;
541 if ( !tex.TextureDrvShare )
543 // insert into driver list. (so it is deleted when driver is deleted).
544 ItTexDrvSharePtrList it= _TexDrvShares.insert(_TexDrvShares.end(), (NL3D::CTextureDrvShare*)NULL);
545 // create and set iterator, for future deletion.
546 *it= tex.TextureDrvShare= new CTextureDrvShare(this, it, &tex);
548 // Must (re)-create the texture.
549 mustCreate = true;
552 // Does the texture has been touched ?
553 if ( (!tex.touched()) && (!mustCreate) )
555 setupTextureWrapMode(tex); // update basics parameters if needed
556 return true; // Do not do anything
560 // 1. If modified, may (re)load texture part or all of the texture.
561 //=================================================================
564 bool mustLoadAll= false;
565 bool mustLoadPart= false;
567 // A. Share mgt.
568 //==============
569 if(tex.supportSharing())
571 // Try to get the shared texture.
573 // Create the shared Name.
574 std::string name;
575 getTextureShareName (tex, name);
577 // insert or get the texture.
579 CSynchronized<TTexDrvInfoPtrMap>::CAccessor access(&_SyncTexDrvInfos);
580 TTexDrvInfoPtrMap &rTexDrvInfos = access.value();
582 ItTexDrvInfoPtrMap itTex;
583 itTex= rTexDrvInfos.find(name);
585 // texture not found?
586 if( itTex==rTexDrvInfos.end() )
588 // insert into driver map. (so it is deleted when driver is deleted).
589 itTex= (rTexDrvInfos.insert(make_pair(name, (ITextureDrvInfos*)NULL))).first;
590 // create and set iterator, for future deletion.
591 itTex->second= tex.TextureDrvShare->DrvTexture= new CTextureDrvInfosD3D(this, itTex, this, tex.getRenderTarget());
593 // need to load ALL this texture.
594 mustLoadAll= true;
596 else
598 tex.TextureDrvShare->DrvTexture= itTex->second;
600 if(bMustRecreateSharedTexture)
601 // reload this shared texture (user request)
602 mustLoadAll= true;
603 else
604 // Do not need to reload this texture, even if the format/mipmap has changed, since we found this
605 // couple in the map.
606 mustLoadAll= false;
609 // Do not test if part of texture may need to be computed, because Rect invalidation is incompatible
610 // with texture sharing.
612 else
614 // If texture not already created.
615 if(!tex.TextureDrvShare->DrvTexture)
617 // Must create it. Create auto a D3D id (in constructor).
618 // Do not insert into the map. This un-shared texture will be deleted at deletion of the texture.
619 // Inform ITextureDrvInfos by passing NULL _Driver.
620 tex.TextureDrvShare->DrvTexture= new CTextureDrvInfosD3D(NULL, ItTexDrvInfoPtrMap(), this, tex.getRenderTarget());
622 // need to load ALL this texture.
623 mustLoadAll= true;
625 else if(tex.isAllInvalidated())
626 mustLoadAll= true;
627 else if(tex.touched())
628 mustLoadPart= true;
631 if(tex.isTextureCube() && (!_TextureCubeSupported))
633 return true;
636 // B. Setup texture.
637 //==================
638 if(mustLoadAll || mustLoadPart)
640 CTextureDrvInfosD3D* d3dtext;
641 d3dtext= getTextureD3D(tex);
643 // a. Load All the texture case.
644 //==============================
645 if (mustLoadAll)
647 D3DFORMAT srcFormat;
648 D3DFORMAT destFormat;
649 bool cube;
650 if (generateD3DTexture (tex, true, destFormat, srcFormat, cube))
652 if((tex.getSize()>0) || cube)
654 // Can support multi part upload ?
655 if ((destFormat != srcFormat) && d3dtext->SrcCompressed)
657 // No, force upload
658 bUpload = true; // Force all upload
661 // Must upload the texture ?
662 if (bUpload && !tex.getRenderTarget())
664 // Update the pixels
665 uint i;
666 UINT destLevel = 0;
667 uint blockCount = d3dtext->Height>>(d3dtext->SrcCompressed?2:0);
668 uint lineWidth = d3dtext->Width;
669 const uint srcPixelSize = getPixelFormatSize (srcFormat);
670 for(i=d3dtext->FirstMipMap;i<uint(d3dtext->FirstMipMap)+uint(d3dtext->Levels);i++, destLevel++)
672 // Size of a line
673 const uint blockSize = ((lineWidth*srcPixelSize)>>3)<<(d3dtext->SrcCompressed?2:0);
675 // Several faces for cube texture
676 const uint numFaces = d3dtext->IsCube?6:1;
677 uint face;
678 for (face=0; face<numFaces; face++)
680 // Get the cube texture
681 ITexture *texture = d3dtext->IsCube?(static_cast<CTextureCube*>(&tex)->getTexture((CTextureCube::TFace)face)):&tex;
682 if (texture)
684 // Same format ?
685 if (destFormat == srcFormat)
687 // Lock the surface level
688 D3DLOCKED_RECT rect;
689 bool locked = false;
690 if (!d3dtext->IsCube)
691 locked = d3dtext->Texture2d->LockRect (destLevel, &rect, NULL, 0) == D3D_OK;
692 else
693 locked = d3dtext->TextureCube->LockRect (RemapCubeFaceTypeNeL2D3D[face], destLevel, &rect, NULL, 0) == D3D_OK;
695 // Rect locked ?
696 if (locked)
698 uint block;
699 for (block=0; block<blockCount; block++)
701 // Copy the block
702 const uint8 *src = &(texture->getPixels(i)[block*blockSize]);
703 uint8 *dest = ((uint8*)rect.pBits)+block*rect.Pitch;
704 if (destFormat == D3DFMT_A8R8G8B8)
705 copyRGBA2BGRA ((uint32*)dest, (const uint32*)src, blockSize>>2);
706 else
707 memcpy (dest, src, blockSize);
710 // Unlock
711 if (!d3dtext->IsCube)
712 d3dtext->Texture2d->UnlockRect (destLevel);
713 else
714 d3dtext->TextureCube->UnlockRect (RemapCubeFaceTypeNeL2D3D[face], destLevel);
717 else
719 // Convert the surface using a D3DX method
720 IDirect3DSurface9 *pDestSurface;
721 bool surfaceOk = false;
722 if (!d3dtext->IsCube)
723 surfaceOk = d3dtext->Texture2d->GetSurfaceLevel(destLevel, &pDestSurface) == D3D_OK;
724 else
725 surfaceOk = d3dtext->TextureCube->GetCubeMapSurface(RemapCubeFaceTypeNeL2D3D[face], destLevel, &pDestSurface) == D3D_OK;
727 // Surface has been retrieved ?
728 if (surfaceOk)
730 if (srcFormat == D3DFMT_A8R8G8B8)
732 const uint8 *src = &(texture->getPixels(i)[0]);
734 // Fill the temp buffer with BGRA info
735 _TempBuffer.resize (blockCount*blockSize);
736 uint8 *dest = &(_TempBuffer[0]);
737 uint line;
738 for (line=0; line<blockCount; line++)
740 copyRGBA2BGRA ((uint32*)dest, (uint32*)(src+line*blockSize), lineWidth);
741 dest += blockSize;
744 // Upload the texture part
745 RECT srcRect;
746 srcRect.top = 0;
747 srcRect.bottom = blockCount;
748 srcRect.left = 0;
749 srcRect.right = lineWidth;
750 D3DXLoadSurfaceFromMemory (pDestSurface, NULL, NULL, &(_TempBuffer[0]), srcFormat,
751 blockSize, NULL, &srcRect, D3DX_FILTER_NONE, 0);
753 else
755 RECT rect;
756 rect.top = 0;
757 rect.bottom = blockCount;
758 rect.left = 0;
759 rect.right = lineWidth;
760 D3DXLoadSurfaceFromMemory (pDestSurface, NULL, NULL, &(texture->getPixels(i)[0]), srcFormat,
761 blockSize, NULL, &rect, D3DX_FILTER_NONE, 0);
763 pDestSurface->Release();
769 // Next level
770 lineWidth = max((UINT)(lineWidth>>1), (UINT)(d3dtext->SrcCompressed?4:1));
771 blockCount = max((UINT)(blockCount>>1), 1U);
774 // Upload now
775 if (!d3dtext->IsCube)
776 d3dtext->Texture->PreLoad();
777 else
778 d3dtext->Texture->PreLoad();
779 bAllUploaded = true;
784 // b. Load part of the texture case.
785 //==================================
786 // Replace parts of a compressed image. Maybe don't work with the actual system of invalidateRect()...
787 else if (mustLoadPart && !d3dtext->SrcCompressed)
789 D3DFORMAT destFormat;
790 D3DFORMAT srcFormat;
791 bool cube;
792 if (CDriverD3D::generateD3DTexture (tex, false, destFormat, srcFormat, cube))
794 // No degradation in load part
795 nlassert (d3dtext->FirstMipMap == 0);
797 if(tex.getSize()>0 && bUpload && !tex.getRenderTarget())
799 // For all rect, update the texture/mipmap.
800 //===============================================
801 list<NLMISC::CRect>::iterator itRect;
802 for(itRect=tex._ListInvalidRect.begin(); itRect!=tex._ListInvalidRect.end(); itRect++)
804 CRect &rect = *itRect;
805 sint x0= rect.X;
806 sint y0= rect.Y;
807 sint x1= rect.X+rect.Width;
808 sint y1= rect.Y+rect.Height;
810 // Update the pixels
811 uint i;
812 UINT destLevel = 0;
813 for(i=d3dtext->FirstMipMap;i<uint(d3dtext->FirstMipMap)+uint(d3dtext->Levels);i++, destLevel++)
815 CRect rectDest;
816 rectDest.X = x0;
817 rectDest.Y = y0;
818 rectDest.Width = x1-x0;
819 rectDest.Height = y1-y0;
820 uploadTextureInternal (tex, rectDest, uint8(destLevel), uint8(i), destFormat, srcFormat);
822 // floor .
823 x0= x0/2;
824 y0= y0/2;
825 // ceil.
826 x1= (x1+1)/2;
827 y1= (y1+1)/2;
834 // Release, if wanted.
835 if(tex.getReleasable())
836 tex.release();
839 setupTextureWrapMode(tex);
840 // The texture is correctly setuped.
841 tex.clearTouched();
842 return true;
845 // ***************************************************************************
847 bool CDriverD3D::uploadTexture (ITexture& tex, CRect& rect, uint8 nNumMipMap)
849 H_AUTO_D3D(CDriverD3D_uploadTexture )
850 if (tex.TextureDrvShare == NULL)
851 return false; // Texture not created
852 if (tex.TextureDrvShare->DrvTexture == NULL)
853 return false; // Texture not created
854 if (tex.isTextureCube())
855 return false;
857 CTextureDrvInfosD3D* d3dtext = getTextureD3D(tex);
858 // if the texture src is in DXTC MipMaped, and mipmapskip is enabled, skip first levels the user want to upload
859 if(d3dtext->FirstMipMap > nNumMipMap)
860 return false;
862 nlassert (rect.X < (sint)d3dtext->Width);
863 nlassert (rect.Y < (sint)d3dtext->Height);
864 nlassert (rect.X + rect.Width <= (sint)d3dtext->Width);
865 nlassert (rect.Y + rect.Height <= (sint)d3dtext->Height);
866 nlassert(nNumMipMap<(uint8)tex.getMipMapCount());
868 // validate rect.
869 sint x0 = rect.X;
870 sint y0 = rect.Y;
871 sint x1 = rect.X+rect.Width;
872 sint y1 = rect.Y+rect.Height;
873 sint w = tex.getWidth (nNumMipMap);
874 sint h = tex.getHeight (nNumMipMap);
875 clamp (x0, 0, w);
876 clamp (y0, 0, h);
877 clamp (x1, x0, w);
878 clamp (y1, y0, h);
879 rect.X = x0;
880 rect.Y = y0;
881 rect.Width = x1 - x0;
882 rect.Height = y1 - y0;
884 // Texture format
885 nlassert (!tex.isTextureCube());
886 D3DFORMAT srcFormat = RemapTextureFormatTypeNeL2D3D[tex.getPixelFormat()];
887 D3DFORMAT destFormat = getD3DDestTextureFormat (tex);
889 return uploadTextureInternal (tex, rect, nNumMipMap-d3dtext->FirstMipMap, nNumMipMap, destFormat, srcFormat);
892 // ***************************************************************************
894 bool CDriverD3D::uploadTextureInternal (ITexture& tex, CRect& rect, uint8 destMipmap, uint8 srcMipmap,
895 D3DFORMAT destFormat, D3DFORMAT srcFormat)
897 H_AUTO_D3D(CDriverD3D_uploadTextureInternal)
899 if (rect.Width == 0 || rect.Height == 0)
901 nlwarning("Rectangle width or height cannot be 0");
902 return false;
905 // The D3D texture
906 CTextureDrvInfosD3D* d3dtext = getTextureD3D(tex);
908 // The pixel size
909 const uint pixelSize = CBitmap::bitPerPixels[tex.getPixelFormat()];
911 // The line width of that mipmap level
912 uint lineWidth = max(d3dtext->Width>>destMipmap, uint(d3dtext->SrcCompressed?4:1));
914 sint x0= rect.X;
915 sint y0= rect.Y;
916 sint x1= rect.X+rect.Width;
917 sint y1= rect.Y+rect.Height;
918 sint x1Copy = x1;
919 sint y1Copy = y1;
921 if (d3dtext->SrcCompressed)
923 nlassert ((x0 & 0x3) == 0);
924 nlassert ((y0 & 0x3) == 0);
925 nlassert (((x1 & 0x3) == 0) || (x1<4));
926 nlassert (((y1 & 0x3) == 0) || (y1<4));
927 x1Copy = std::max(4, x1);
928 y1Copy = std::max(4, y1);
931 // Size of a line
932 const uint lineSize = ((lineWidth*pixelSize)>>3)<<(d3dtext->SrcCompressed?2:0);
933 const uint offsetX = (x0*pixelSize)>>3;
935 // Block of line (for compressed textures)
936 uint lineStart = y0;
937 uint lineEnd = y1Copy;
939 // Pitch for compressed texture
940 if (d3dtext->SrcCompressed)
942 lineStart >>= 2;
943 lineEnd >>= 2;
946 // Same format ?
947 if (destFormat == srcFormat)
949 // Lock the surface level
950 D3DLOCKED_RECT rect;
951 RECT region;
952 region.left = x0;
953 region.right = x1;
954 region.top = y0;
955 region.bottom = y1;
959 const sint dataToCopy = (((x1Copy-x0)*pixelSize)>>3)<<(d3dtext->SrcCompressed?2:0);
960 if (d3dtext->Texture2d->LockRect (destMipmap, &rect, &region, 0) == D3D_OK)
962 uint line;
963 for (line=lineStart; line<lineEnd; line++)
965 // Copy the line
966 const uint8 *src = &(tex.getPixels(srcMipmap)[line*lineSize+offsetX]);
967 uint8 *dest = ((uint8*)rect.pBits)+(line-lineStart)*rect.Pitch;
968 if (destFormat == D3DFMT_A8R8G8B8)
969 copyRGBA2BGRA ((uint32*)dest, (const uint32*)src, dataToCopy>>2);
970 else
971 memcpy (dest, src, dataToCopy);
973 d3dtext->Texture2d->UnlockRect (destMipmap);
975 else
977 return false;
980 else
982 // Convert the surface using a D3DX method
983 IDirect3DSurface9 *pDestSurface;
985 // Surface has been retrieved ?
986 if (d3dtext->Texture2d->GetSurfaceLevel(destMipmap, &pDestSurface) == D3D_OK)
988 RECT destRect;
989 destRect.top = y0;
990 destRect.bottom = y1;
991 destRect.left = x0;
992 destRect.right = x1;
994 if (srcFormat == D3DFMT_A8R8G8B8)
996 const uint8 *src = &(tex.getPixels(srcMipmap)[0]);
998 // Fill the temp buffer with BGRA info
999 const sint lineWidth = x1-x0;
1000 _TempBuffer.resize (((y1-y0)*lineWidth)<<2);
1001 uint8 *dest = &(_TempBuffer[0]);
1002 uint line;
1003 for (line=y0; line<(uint)y1; line++)
1005 copyRGBA2BGRA ((uint32*)dest, (uint32*)(src+line*lineSize+(x0<<2)), lineWidth);
1006 dest += lineWidth<<2;
1009 // Upload the texture part
1010 RECT srcRect;
1011 srcRect.top = 0;
1012 srcRect.bottom = y1-y0;
1013 srcRect.left = 0;
1014 srcRect.right = lineWidth;
1015 if (D3DXLoadSurfaceFromMemory (pDestSurface, NULL, &destRect, &(_TempBuffer[0]), srcFormat,
1016 lineWidth<<2, NULL, &srcRect, D3DX_FILTER_NONE, 0) != D3D_OK)
1017 return false;
1019 else
1021 RECT srcRect;
1022 srcRect.top = y0;
1023 srcRect.bottom = y1;
1024 srcRect.left = x0;
1025 srcRect.right = x1;
1026 const uint8 *src = &(tex.getPixels(srcMipmap)[0]);
1027 if (D3DXLoadSurfaceFromMemory (pDestSurface, NULL, &destRect, src, srcFormat,
1028 lineSize, NULL, &srcRect, D3DX_FILTER_NONE, 0) != D3D_OK)
1029 return false;
1031 pDestSurface->Release();
1035 return true;
1038 // ***************************************************************************
1040 bool CDriverD3D::isTextureExist(const ITexture&tex)
1042 H_AUTO_D3D(CDriverD3D_isTextureExist)
1043 bool result;
1045 // Create the shared Name.
1046 std::string name;
1047 getTextureShareName (tex, name);
1050 CSynchronized<TTexDrvInfoPtrMap>::CAccessor access(&_SyncTexDrvInfos);
1051 TTexDrvInfoPtrMap &rTexDrvInfos = access.value();
1052 result = (rTexDrvInfos.find(name) != rTexDrvInfos.end());
1054 return result;
1057 // ***************************************************************************
1059 void CDriverD3D::swapTextureHandle(ITexture &tex0, ITexture &tex1)
1061 H_AUTO_D3D(CDriverD3D_swapTextureHandle)
1062 // ensure creation of both texture
1063 setupTexture(tex0);
1064 setupTexture(tex1);
1066 // avoid any problem, disable all textures
1067 for(uint stage=0; stage<inlGetNumTextStages() ; stage++)
1069 setTexture (stage, (LPDIRECT3DBASETEXTURE9)NULL);
1072 // get the handle.
1073 CTextureDrvInfosD3D *t0= getTextureD3D(tex0);
1074 CTextureDrvInfosD3D *t1= getTextureD3D(tex1);
1076 /* Swap contents. Can't swap directly the pointers cause would have to change all CTextureDrvShare which point on
1077 Can't do swap(*t0, *t1), because must keep the correct _DriverIterator
1079 swap(t0->Texture, t1->Texture);
1080 swap(t0->Texture2d, t1->Texture2d);
1081 swap(t0->TextureCube, t1->TextureCube);
1082 swap(t0->DestFormat, t1->DestFormat);
1083 swap(t0->Width, t1->Width);
1084 swap(t0->Height, t1->Height);
1085 swap(t0->SrcCompressed, t1->SrcCompressed);
1086 swap(t0->IsCube, t1->IsCube);
1087 swap(t0->RenderTarget, t1->RenderTarget);
1088 swap(t0->Levels, t1->Levels);
1089 swap(t0->FirstMipMap, t1->FirstMipMap);
1090 swap(t0->TextureMemory, t1->TextureMemory);
1091 swap(t0->WrapS, t1->WrapS);
1092 swap(t0->WrapT, t1->WrapT);
1093 swap(t0->MagFilter, t1->MagFilter);
1094 swap(t0->MinFilter, t1->MinFilter);
1095 swap(t0->MipFilter, t1->MipFilter);
1098 // ***************************************************************************
1100 uintptr_t CDriverD3D::getTextureHandle(const ITexture &tex)
1102 H_AUTO_D3D(CDriverD3D_getTextureHandle)
1103 // If DrvShare not setuped
1104 if(!tex.TextureDrvShare)
1105 return 0;
1107 CTextureDrvInfosD3D *d3dtext= getTextureD3D(const_cast<ITexture&>(tex));
1109 // If DrvInfo not setuped
1110 if(!d3dtext)
1111 return 0;
1113 return (uintptr_t)(d3dtext->Texture);
1116 // ***************************************************************************
1118 bool CDriverD3D::setRenderTarget (ITexture *tex, uint32 /* x */, uint32 /* y */, uint32 /* width */, uint32 /* height */, uint32 mipmapLevel, uint32 cubeFace)
1120 H_AUTO_D3D(CDriverD3D_setRenderTarget )
1121 // Check the texture is a render target
1122 if (tex)
1123 nlassertex (tex->getRenderTarget(), ("The texture must be a render target. Call ITexture::setRenderTarget(true)."));
1125 if (tex == NULL)
1127 _InvertCullMode = false;
1128 if (_BackBuffer)
1130 setRenderTarget (_BackBuffer, NULL, 0, 0);
1131 _BackBuffer->Release();
1132 _BackBuffer = NULL;
1135 else
1137 _InvertCullMode = true;
1138 if (!_BackBuffer)
1140 updateRenderVariables ();
1141 _DeviceInterface->GetRenderTarget (0, &_BackBuffer);
1144 // Alread setuped ?
1145 if (tex->TextureDrvShare)
1147 // Get texture info
1148 CTextureDrvInfosD3D *d3dtext = getTextureD3D(*tex);
1150 // Renderable ? Erase and rebuild
1151 if (!d3dtext->RenderTarget)
1152 // Touch the texture
1153 tex->touch();
1156 // Setup the new texture
1157 bool nTmp;
1158 if (!setupTextureEx (*tex, false, nTmp, false))
1159 return false;
1161 // Get texture info
1162 CTextureDrvInfosD3D *d3dtext = getTextureD3D(*tex);
1164 // Setup texture for texture rendering
1165 IDirect3DSurface9 *pDestSurface;
1166 bool surfaceOk = false;
1167 if (!d3dtext->IsCube)
1168 surfaceOk = d3dtext->Texture2d->GetSurfaceLevel(mipmapLevel, &pDestSurface) == D3D_OK;
1169 else
1170 surfaceOk = d3dtext->TextureCube->GetCubeMapSurface(RemapCubeFaceTypeNeL2D3D[cubeFace], mipmapLevel, &pDestSurface) == D3D_OK;
1171 if (surfaceOk)
1173 setRenderTarget (pDestSurface, tex, (uint8)mipmapLevel, (uint8)cubeFace);
1174 pDestSurface->Release();
1176 else
1177 return false;
1180 // Handle backside
1181 if (!_DoubleSided)
1183 if (_CullMode == CCW)
1185 setRenderState (D3DRS_CULLMODE, _InvertCullMode?D3DCULL_CCW:D3DCULL_CW);
1187 else
1189 setRenderState (D3DRS_CULLMODE, _InvertCullMode?D3DCULL_CW:D3DCULL_CCW);
1193 return true;
1196 ITexture *CDriverD3D::getRenderTarget() const
1198 return _RenderTarget.Texture;
1201 // ***************************************************************************
1203 bool CDriverD3D::copyTargetToTexture (ITexture * /* tex */, uint32 /* offsetx */, uint32 /* offsety */, uint32 /* x */, uint32 /* y */, uint32 /* width */,
1204 uint32 /* height */, uint32 /* mipmapLevel */)
1206 H_AUTO_D3D(CDriverD3D_copyTargetToTexture)
1207 return false;
1210 // ***************************************************************************
1212 bool CDriverD3D::getRenderTargetSize (uint32 &width, uint32 &height)
1214 H_AUTO_D3D(CDriverD3D_getRenderTargetSize)
1215 // Target is the frame buffer ?
1216 if (_RenderTarget.Texture)
1218 CTextureDrvInfosD3D* d3dtext = getTextureD3D(*_RenderTarget.Texture);
1219 width = max ((uint32)1, (uint32)(d3dtext->Width >> (_RenderTarget.Level)));
1220 height = max ((uint32)1, (uint32)(d3dtext->Height >> (_RenderTarget.Level)));
1221 return true;
1223 else
1225 getWindowSize (width, height);
1226 return true;
1230 // ***************************************************************************
1233 } // NL3D