Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / async_texture_manager.cpp
blob77cc47f895a59d96dab756701c41930f14985f7a
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) 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 "std3d.h"
22 #include "nel/3d/async_texture_manager.h"
23 #include "nel/3d/async_file_manager_3d.h"
24 #include "nel/3d/mesh_base_instance.h"
25 #include "nel/3d/driver.h"
28 using namespace std;
29 using namespace NLMISC;
31 #ifdef DEBUG_NEW
32 #define new DEBUG_NEW
33 #endif
35 namespace NL3D
38 // ***************************************************************************
39 #define NL3D_ATM_MIN_DISTANCE 1.0f
41 // ***************************************************************************
42 CAsyncTextureManager::CTextureEntry::CTextureEntry()
44 IsTextureEntry= true;
46 Loaded= false;
47 UpLoaded= false;
48 CanHaveLOD= false;
49 BuildFromHLSManager= false;
50 HLSManagerTextId= -1;
51 BaseSize= 0;
52 TotalTextureSizeAsked= 0;
56 // ***************************************************************************
57 void CAsyncTextureManager::CTextureEntry::createCoarseBitmap()
59 // the texture must exist.
60 nlassert(Texture);
61 nlassert(Texture->getSize()>0);
63 // copy the bitmap.
64 CoarseBitmap= *Texture;
65 // remove all mipmaps, and convert to DXTC1 (if possible, ie if was DXTC5 or DXTC3 as example)
66 CoarseBitmap.releaseMipMaps();
67 // TODODO: conversion to DXTC1
68 CoarseBitmap.convertToType(CBitmap::DXTC1);
72 // ***************************************************************************
73 CAsyncTextureManager::CTextureLod::CTextureLod()
75 IsTextureEntry= false;
77 TextureEntry= NULL;
78 Weight= 0;
79 Level= 0;
80 Loaded= false;
81 UpLoaded= false;
82 ExtraSize= 0;
86 // ***************************************************************************
87 CAsyncTextureManager::~CAsyncTextureManager()
89 // For all remaining textures, delete them.
90 for(uint i=0;i<_TextureEntries.size();i++)
92 if(_TextureEntries[i])
93 deleteTexture(i);
96 // there must be no waitting textures, nor map, nor current upload texture
97 nlassert(_WaitingTextures.empty() && _TextureEntryMap.empty() && _CurrentUploadTexture==NULL
98 && _CurrentTextureLodLoaded==NULL);
101 // ***************************************************************************
102 CAsyncTextureManager::CAsyncTextureManager()
104 _BaseLodLevel= 3;
105 _MaxLodLevel= 1;
106 _MaxUploadPerFrame= 65536;
107 _MaxHLSColoringPerFrame= 20*1024;
108 _CurrentUploadTexture= NULL;
109 _MaxTotalTextureSize= 10*1024*1024;
110 _TotalTextureSizeAsked= 0;
111 _LastTextureSizeGot= 0;
113 // Do not share this texture, to force uploading of the lods.
114 _CurrentTextureLodLoaded= NULL;
116 // For Texture profiling
117 _TextureCategory= new ITexture::CTextureCategory("ASYNC ENTITY MANAGER");
121 // ***************************************************************************
122 void CAsyncTextureManager::setupLod(uint baseLevel, uint maxLevel)
124 nlassert(baseLevel>=maxLevel);
125 _BaseLodLevel= baseLevel;
126 _MaxLodLevel= maxLevel;
130 // ***************************************************************************
131 void CAsyncTextureManager::setupMaxUploadPerFrame(uint maxup)
133 if(maxup>0)
134 _MaxUploadPerFrame= maxup;
137 // ***************************************************************************
138 void CAsyncTextureManager::setupMaxHLSColoringPerFrame(uint maxCol)
140 if(maxCol>0)
141 _MaxHLSColoringPerFrame= maxCol;
144 // ***************************************************************************
145 void CAsyncTextureManager::setupMaxTotalTextureSize(uint maxText)
147 _MaxTotalTextureSize= maxText;
151 // ***************************************************************************
152 uint CAsyncTextureManager::addTextureRef(const string &textNameNotLwr, CMeshBaseInstance *instance, const NLMISC::CVector &position)
154 uint ret;
156 // lower case name
157 string textName = toLowerAscii(textNameNotLwr);
159 // find the texture in map
160 ItTextureEntryMap it;
161 it= _TextureEntryMap.find(textName);
163 // not found, create.
164 if(it==_TextureEntryMap.end())
166 // search a free id.
167 uint i= (uint)_TextureEntries.size();
168 if(!_FreeTextureIds.empty())
170 i= _FreeTextureIds.back();
171 _FreeTextureIds.pop_back();
173 // resize if needed.
174 if(i>=_TextureEntries.size())
176 _TextureEntries.push_back(NULL);
177 _FreeTextureIds.reserve(_TextureEntries.capacity());
180 // alloc new.
181 CTextureEntry *text= new CTextureEntry();
182 _TextureEntries[i]= text;
183 text->Texture= new CTextureFile;
184 // Do not allow degradation.
185 text->Texture->setAllowDegradation(false);
186 // For Profiling
187 text->Texture->setTextureCategory(_TextureCategory);
189 // add to map.
190 it= _TextureEntryMap.insert(make_pair(textName, i)).first;
191 // bkup the it for deletion
192 text->ItMap= it;
194 // Start Color or Async loading.
195 text->Texture->setFileName(textName);
196 // First try with the HLSManager
197 sint colorTextId= HLSManager.findTexture(textName);
198 // If found
199 if(colorTextId!=-1)
201 // Mark the texture as Loaded, and ready to colorize (done in update()).
202 text->Loaded= true;
203 text->BuildFromHLSManager= true;
204 text->HLSManagerTextId= colorTextId;
206 // else must async load it.
207 else
209 // start to load a small DDS version if possible
210 text->Texture->setMipMapSkipAtLoad(_BaseLodLevel);
211 // load it async.
212 CAsyncFileManager3D::getInstance().loadTexture(text->Texture, &text->Loaded, position);
214 // Add to a list so we can check each frame if it has ended.
215 _WaitingTextures.push_back(i);
218 // get the id of the text entry.
219 ret= it->second;
221 // add this instance to the list of ones which use this texture.
222 CTextureEntry *text= _TextureEntries[ret];
223 text->Instances.push_back(instance);
225 // if the texture is not yet ready, must increment the instance refCount.
226 if(!text->UpLoaded)
227 instance->_AsyncTextureToLoadRefCount++;
229 return ret;
233 // ***************************************************************************
234 void CAsyncTextureManager::deleteTexture(uint id)
236 CTextureEntry *text= _TextureEntries[id];
239 // **** Stop AsyncLoading/UpLoading of main texture.
241 // stop async loading if not ended
242 if(!text->Loaded)
244 CAsyncFileManager3D::getInstance().cancelLoadTexture(text->Texture);
247 // remove map entry
248 _TextureEntryMap.erase(text->ItMap);
250 // remove in list of waiting textures
251 vector<uint>::iterator itWait= find(_WaitingTextures.begin(),_WaitingTextures.end(), id);
252 if(itWait!=_WaitingTextures.end())
253 _WaitingTextures.erase(itWait);
255 // If it was the currently uploaded one, abort
256 if(_CurrentUploadTexture==text)
258 _CurrentUploadTexture= NULL;
261 // If not uploaded.
262 if(!text->UpLoaded)
264 // For all its remainding instances, dec refcount
265 for(uint i=0;i<text->Instances.size();i++)
267 text->Instances[i]->_AsyncTextureToLoadRefCount--;
271 // remove from bench
272 _TotalTextureSizeAsked-= text->TotalTextureSizeAsked;
275 // **** Stop AsyncLoading/UpLoading of HDLod 's texture.
277 // Check if must stop TextureLod loading/uploading.
278 CTextureLod *textLod= &text->HDLod;
279 if(textLod==_CurrentTextureLodLoaded)
281 // stop the async loading if not ended.
282 if(!textLod->Loaded)
284 CAsyncFileManager3D::getInstance().cancelLoadTexture(textLod->Texture);
286 // stop uploading if was me
287 if(_CurrentUploadTexture==textLod)
289 _CurrentUploadTexture= NULL;
291 // stop loading me.
292 _CurrentTextureLodLoaded= NULL;
295 // At last delete texture entry.
296 delete text;
297 _TextureEntries[id]= NULL;
298 // add a new free id.
299 _FreeTextureIds.push_back(id);
303 // ***************************************************************************
304 void CAsyncTextureManager::releaseTexture(uint id, CMeshBaseInstance *instance)
306 nlassert(id<_TextureEntries.size());
307 nlassert(_TextureEntries[id]);
309 // find an instance in this texture an remove it.
310 CTextureEntry *text= _TextureEntries[id];
311 uint instSize= (uint)text->Instances.size();
312 for(uint i=0;i<instSize;i++)
314 if(text->Instances[i]== instance)
316 // Must first release the refCount if the texture is not uploaded
317 if(!text->UpLoaded)
318 text->Instances[i]->_AsyncTextureToLoadRefCount--;
319 // remove it by swapping with last texture
320 text->Instances[i]= text->Instances[instSize-1];
321 text->Instances.pop_back();
322 // must stop: remove only the first occurence of instance.
323 break;
327 // if no more instance occurence, the texture is no more used => release it.
328 if(text->Instances.empty())
330 // do all the good stuff
331 deleteTexture(id);
335 // ***************************************************************************
336 bool CAsyncTextureManager::isTextureUpLoaded(uint id) const
338 nlassert(id<_TextureEntries.size());
339 nlassert(_TextureEntries[id]);
340 return _TextureEntries[id]->UpLoaded;
344 // ***************************************************************************
345 const NLMISC::CBitmap *CAsyncTextureManager::getCoarseBitmap(uint id) const
347 if(id>=_TextureEntries.size())
348 return NULL;
349 CTextureEntry *textEntry= _TextureEntries[id];
350 if(!textEntry)
351 return NULL;
353 // if the textEntry not uploaded, return NULL
354 if(!textEntry->UpLoaded)
355 return NULL;
357 // ok return the CoarseBitmap
358 return &textEntry->CoarseBitmap;
362 // ***************************************************************************
363 void CAsyncTextureManager::update(IDriver *pDriver)
365 uint nTotalUploaded = 0;
366 uint nTotalColored = 0;
368 // if no texture to upload, get the next one
369 if(_CurrentUploadTexture==NULL)
370 getNextTextureToUpLoad(nTotalColored, pDriver);
372 // while some texture to upload
373 while(_CurrentUploadTexture)
375 ITexture *pText= _CurrentUploadTexture->Texture;
376 if(uploadTexturePart(pText, pDriver, nTotalUploaded))
378 // Stuff for TextureEntry
379 if(_CurrentUploadTexture->isTextureEntry())
381 uint i;
382 CTextureEntry *textEntry= static_cast<CTextureEntry*>(_CurrentUploadTexture);
383 // If we are here, the texture is finally entirely uploaded. Compile it!
384 textEntry->UpLoaded= true;
385 // Can Have lod if texture is DXTC and have mipMaps! Also disalbe if system disable it
386 textEntry->CanHaveLOD= validDXTCMipMap(pText) && _BaseLodLevel>_MaxLodLevel;
387 // compute the size it takes in VRAM
388 uint baseMipMapSize= pText->getSize(0)*CBitmap::bitPerPixels[pText->getPixelFormat()]/8;
389 // full size with mipmap
390 textEntry->BaseSize= (uint)(baseMipMapSize*1.33f);
391 // UpLoaded !! => signal all instances.
392 for(i=0;i<textEntry->Instances.size();i++)
394 textEntry->Instances[i]->_AsyncTextureToLoadRefCount--;
397 // Create the coarse bitmap with the text (NB: still in memory here)
398 textEntry->createCoarseBitmap();
400 // If CanHaveLOD, create now the lods entries.
401 if(textEntry->CanHaveLOD)
403 /* Allow only the MaxLod to be loaded async
404 This is supposed to be faster since a fseek is much longer than a texture Read.
405 Then it is more intelligent to read only One texture (the High Def), than to try to
406 read intermediate ones (512, 256, 128) because this made 3 more fseek.
408 // create only the MaxLod possible entry
409 CTextureLod &textLod= textEntry->HDLod;
410 // fill textLod
411 textLod.TextureEntry= textEntry;
412 textLod.Level= _MaxLodLevel;
413 // extra size of the lod only (important for LoadBalacing in updateTextureLodSystem())
414 textLod.ExtraSize= textEntry->BaseSize*(1<<(2*(_BaseLodLevel-_MaxLodLevel))) - textEntry->BaseSize;
415 // not yet loaded/upLoaded
416 textLod.Loaded= false;
417 textLod.UpLoaded= false;
420 // compute texture size for bench
421 textEntry->TotalTextureSizeAsked= textEntry->BaseSize + textEntry->HDLod.ExtraSize;
423 // Add texture size to global texture size
424 _TotalTextureSizeAsked+= textEntry->TotalTextureSizeAsked;
426 // else, stuff for textureLod.
427 else
429 CTextureLod *textLod= static_cast<CTextureLod*>(_CurrentUploadTexture);
430 // Swap the uploaded Driver Handle with the Main texture.
431 pDriver->swapTextureHandle(*textLod->Texture, *textLod->TextureEntry->Texture);
432 // Flag the Lod.
433 textLod->UpLoaded= true;
434 // Ok, ended to completly load this textureLod.
435 _CurrentTextureLodLoaded= NULL;
438 // finally uploaded in VRAM, can release the RAM texture memory
439 pText->release();
441 // if not break because can't upload all parts, get next texture to upload
442 _CurrentUploadTexture= NULL;
443 getNextTextureToUpLoad(nTotalColored, pDriver);
445 else
446 // Fail to upload all, abort.
447 return;
452 // ***************************************************************************
453 bool CAsyncTextureManager::uploadTexturePart(ITexture *pText, IDriver *pDriver, uint &nTotalUploaded)
455 uint nMipMap;
456 nMipMap = pText->getMipMapCount();
459 // If this is the start of uploading, setup the texture in driver.
460 if(_CurrentUploadTextureMipMap==0 && _CurrentUploadTextureLine==0)
462 // If the texture is not a valid DXTC with mipmap
463 if(!validDXTCMipMap(pText))
465 /* For now, prefer do nothing, because this may be an error (texture not found)
466 and the texture may not be used at all, so don't take VRAM for nothing.
467 => if the texture is used, it will be loaded synchronously by the caller later in the process
468 => frame freeze.
471 // upload All now.
472 // MipMap generation and compression may be done here => Maybe Big Freeze.
473 // approximate*2 instead of *1.33 for mipmaps.
474 uint nWeight = pText->getSize (0) * 2;
475 nWeight= (nWeight*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
476 nTotalUploaded+= nWeight;
477 pDriver->setupTexture(*pText);
478 return true;*/
479 return true;
481 else
483 // Create the texture only and do not upload anything
484 bool isRel = pText->getReleasable ();
485 pText->setReleasable (false);
486 bool isAllUploaded = false;
487 /* Even if the shared texture is still referenced and so still exist in driver, we MUST recreate with good size
488 the texture. This is important for Texture Memory Load Balancing
489 (this may means that is used elsewhere than in the CAsyncTextureManager)
490 Hence: bMustRecreateSharedTexture==true
492 pDriver->setupTextureEx (*pText, false, isAllUploaded, true);
493 pText->setReleasable (isRel);
494 // if the texture is already uploaded, abort partial uploading.
495 if (isAllUploaded)
496 return true;
501 // try to upload all mipmap
502 for(; _CurrentUploadTextureMipMap<nMipMap; _CurrentUploadTextureMipMap++)
504 CRect zeRect;
505 uint nMM= _CurrentUploadTextureMipMap;
507 // What is left to upload ?
508 uint nWeight = pText->getSize (nMM) - _CurrentUploadTextureLine*pText->getWidth(nMM);
509 nWeight= (nWeight*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
511 if ((nTotalUploaded + nWeight) > _MaxUploadPerFrame)
513 // We cannot upload the whole mipmap -> we have to cut it
514 uint nSizeToUpload = _MaxUploadPerFrame - nTotalUploaded ;
515 // DXTC => min block of 4x4
516 uint nLineWeight = (max(pText->getWidth(nMM), (uint32)4)*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
517 uint nNbLineToUpload = nSizeToUpload / nLineWeight;
518 // Upload 4 line by 4 line, and upload at leat one 4*line.
519 nNbLineToUpload = nNbLineToUpload / 4;
520 nNbLineToUpload= max(nNbLineToUpload, 1U);
521 nNbLineToUpload *= 4;
522 // comput rect to upload
523 uint32 nNewLine = _CurrentUploadTextureLine + nNbLineToUpload;
524 nNewLine= min(nNewLine, pText->getHeight(nMM));
525 zeRect.set (0, _CurrentUploadTextureLine, pText->getWidth(nMM), nNewLine);
526 _CurrentUploadTextureLine = nNewLine;
527 // if fill all the mipmap, must go to next
528 if (_CurrentUploadTextureLine == pText->getHeight(nMM))
530 _CurrentUploadTextureLine = 0;
531 _CurrentUploadTextureMipMap++;
534 else
536 // We can upload the whole mipmap (or the whole rest of the mipmap)
537 zeRect.set (0, _CurrentUploadTextureLine, pText->getWidth(nMM), pText->getHeight(nMM));
538 _CurrentUploadTextureLine= 0;
541 // upload the texture
542 pDriver->uploadTexture (*pText, zeRect, (uint8)nMM);
544 nTotalUploaded += nWeight;
545 // If outpass max allocated upload, abort.
546 if (nTotalUploaded > _MaxUploadPerFrame)
547 return false;
550 return true;
554 // ***************************************************************************
555 void CAsyncTextureManager::getNextTextureToUpLoad(uint &nTotalColored, IDriver *pDriver)
557 // Reset texture uploading
558 _CurrentUploadTexture= NULL;
559 _CurrentUploadTextureMipMap= 0;
560 _CurrentUploadTextureLine= 0;
562 // Search in WaitingTextures if one has ended async loading
563 vector<uint>::iterator it;
564 for(it=_WaitingTextures.begin();it!=_WaitingTextures.end();it++)
566 CTextureEntry *text= _TextureEntries[*it];
567 // If Async loading done.
568 if(text->Loaded)
570 // Is it a "texture to color" with HLSManager? yes=> color it now.
571 if(text->BuildFromHLSManager)
573 // If not beyond the max coloring texture
574 if(nTotalColored<_MaxHLSColoringPerFrame)
576 // Build the texture directly in the TextureFile.
577 nlverify(HLSManager.buildTexture(text->HLSManagerTextId, *text->Texture));
578 // Must validate the textureFile generation. NB: little weird since this is not really a textureFile.
579 // But it is the easier way to do it.
580 text->Texture->validateGenerateFlag();
581 // compute the texture size (approx). NB: DXTC5 means 1 pixel==1 byte.
582 uint size= (uint)(text->Texture->getSize(0)*1.33);
583 // Add it to the num of colorised texture done in current update().
584 nTotalColored+= size;
586 // Else must quit and don't update any more texture this frame (_CurrentUploadTexture==NULL)
587 else
588 return;
591 // upload this one
592 _CurrentUploadTexture= text;
593 // remove it from list of waiting textures
594 _WaitingTextures.erase(it);
595 // found => end.
596 return;
600 // If here, and if no more waiting textures, update the Lod system.
601 if(_WaitingTextures.empty())
603 // if end to load the current lod.
604 if(_CurrentTextureLodLoaded && _CurrentTextureLodLoaded->Loaded)
606 // upload this one
607 _CurrentUploadTexture= _CurrentTextureLodLoaded;
608 return;
611 // if no Lod texture currently loading, try to load/unload one
612 if(_CurrentTextureLodLoaded == NULL)
614 updateTextureLodSystem(pDriver);
620 // ***************************************************************************
621 bool CAsyncTextureManager::validDXTCMipMap(ITexture *pText)
623 return pText->getMipMapCount()>1 && (
624 pText->getPixelFormat() == CBitmap::DXTC1 ||
625 pText->getPixelFormat() == CBitmap::DXTC1Alpha ||
626 pText->getPixelFormat() == CBitmap::DXTC3 ||
627 pText->getPixelFormat() == CBitmap::DXTC5 );
630 // ***************************************************************************
631 void CAsyncTextureManager::updateTextureLodSystem(IDriver *pDriver)
633 sint i;
635 // the array to sort
636 static vector<CTextureLodToSort> lodArray;
637 lodArray.clear();
638 uint reserveSize= 0;
640 // for each texture entry compute min distance of use
641 //=============
642 uint currentBaseSize= 0;
643 for(i=0;i<(sint)_TextureEntries.size();i++)
645 if(!_TextureEntries[i])
646 continue;
647 CTextureEntry &text= *_TextureEntries[i];
648 // do it only for Lodable textures
649 if(text.CanHaveLOD)
651 text.MinDistance= FLT_MAX;
652 // for all instances.
653 for(uint j=0;j<text.Instances.size();j++)
655 float instDist= text.Instances[j]->getAsyncTextureDistance();
657 if (instDist<text.MinDistance)
659 text.MinPosition = text.Instances[j]->getPos();
660 text.MinDistance = instDist;
664 // avoid /0
665 text.MinDistance= max(NL3D_ATM_MIN_DISTANCE, text.MinDistance);
667 // how many textLods to add
668 reserveSize++;
670 // the minimum mem size the system take with base lod.
671 currentBaseSize+= text.BaseSize;
674 // reserve space
675 lodArray.reserve(reserveSize);
678 // for each texture lod compute weight, and append
679 //=============
680 for(i=0;i<(sint)_TextureEntries.size();i++)
682 if(!_TextureEntries[i])
683 continue;
684 CTextureEntry &text= *_TextureEntries[i];
685 // do it only for Lodable textures
686 if(text.CanHaveLOD)
688 // This Weight is actually a screen Pixel Ratio! (divide by distance)
689 CTextureLod *textLod= &text.HDLod;
690 textLod->Weight= (1<<textLod->Level) / text.MinDistance;
691 // add to array
692 CTextureLodToSort toSort;
693 toSort.Lod = textLod;
694 toSort.Position = text.MinPosition;
695 lodArray.push_back(toSort);
700 // sort
701 //=============
702 sort(lodArray.begin(), lodArray.end());
705 // Compute lod to load/unload
706 //=============
707 // Compute Pivot, ie what lods have to be loaded, and what lods do not
708 uint pivot= 0;
709 uint currentWantedSize= currentBaseSize;
710 uint currentLoadedSize= currentBaseSize;
711 for(i=(sint)lodArray.size()-1;i>=0;i--)
713 uint lodSize= lodArray[i].Lod->ExtraSize;
714 currentWantedSize+= lodSize;
715 if(lodArray[i].Lod->UpLoaded)
716 currentLoadedSize+= lodSize;
717 // if > max allowed, stop the pivot here. NB: the pivot is included in the "must load them" part.
718 if(currentWantedSize > _MaxTotalTextureSize)
720 pivot= i;
721 break;
724 // continue to count currentLoadedSize
725 for(;i>=0;i--)
727 if(lodArray[i].Lod->UpLoaded)
728 currentLoadedSize+= lodArray[i].Lod->ExtraSize;
730 // save bench.
731 _LastTextureSizeGot= currentLoadedSize;
734 // if the loadedSize is inferior to the wanted size, we can load a new LOD
735 CTextureLodToSort *textLod= NULL;
736 bool unload;
737 if(currentLoadedSize<currentWantedSize)
739 unload= false;
740 // search from end of the list to pivot (included), the first LOD (ie the most important) to load.
741 for(i=(sint)lodArray.size()-1;i>=(sint)pivot;i--)
743 if(!lodArray[i].Lod->UpLoaded)
745 textLod= &(lodArray[i]);
746 break;
749 // One must have been found, since currentLoadedSize<currentWantedSize
750 nlassert(textLod);
752 else
754 unload= true;
755 // search from start to pivot (exclued), the first LOD (ie the less important) to unload.
756 for(i=0;i<(sint)pivot;i++)
758 if(lodArray[i].Lod->UpLoaded)
760 textLod= &(lodArray[i]);
761 break;
764 // it is possible that not found here. It means that All is Ok!!
765 if(textLod==NULL)
766 // no-op.
767 return;
771 // load/unload
772 //=============
773 if(!unload)
775 // create a new TextureFile, with no sharing system.
776 nlassert(textLod->Lod->Texture==NULL);
777 textLod->Lod->Texture= new CTextureFile;
778 // Do not allow degradation.
779 textLod->Lod->Texture->setAllowDegradation(false);
780 textLod->Lod->Texture->enableSharing(false);
781 textLod->Lod->Texture->setFileName(textLod->Lod->TextureEntry->Texture->getFileName());
782 textLod->Lod->Texture->setMipMapSkipAtLoad(textLod->Lod->Level);
783 // For Profiling
784 textLod->Lod->Texture->setTextureCategory(_TextureCategory);
785 // setup async loading
786 _CurrentTextureLodLoaded= textLod->Lod;
787 // load it async.
788 CAsyncFileManager3D::getInstance().loadTexture(textLod->Lod->Texture, &textLod->Lod->Loaded, textLod->Position);
790 else
792 // Swap now the lod.
793 nlassert(textLod->Lod->Texture!=NULL);
794 // Swap the uploaded Driver Handle with the Main texture (ot get the Ugly one)
795 pDriver->swapTextureHandle(*textLod->Lod->Texture, *textLod->Lod->TextureEntry->Texture);
796 // Flag the Lod.
797 textLod->Lod->UpLoaded= false;
798 textLod->Lod->Loaded= false;
799 // Release completly the texture in driver. (SmartPtr delete)
800 textLod->Lod->Texture= NULL;
807 } // NL3D