# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

async_texture_manager.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "3d/async_texture_manager.h"
00029 #include "3d/async_file_manager_3d.h"
00030 #include "3d/mesh_base_instance.h"
00031 #include "3d/driver.h"
00032 
00033 
00034 using   namespace std;
00035 using   namespace NLMISC;
00036 
00037 namespace NL3D 
00038 {
00039 
00040 // ***************************************************************************
00041 #define NL3D_ATM_MIN_DISTANCE           1.0f
00042 
00043 // ***************************************************************************
00044 CAsyncTextureManager::CTextureEntry::CTextureEntry()
00045 {
00046         IsTextureEntry= true;
00047 
00048         Loaded= false;
00049         UpLoaded= false;
00050         CanHaveLOD= false;
00051         BuildFromHLSManager= false;
00052         HLSManagerTextId= -1;
00053         BaseSize= 0;
00054         TotalTextureSizeAsked= 0;
00055 }
00056 
00057 
00058 // ***************************************************************************
00059 void            CAsyncTextureManager::CTextureEntry::createCoarseBitmap()
00060 {
00061         // the texture must exist.
00062         nlassert(Texture);
00063         nlassert(Texture->getSize()>0);
00064 
00065         // copy the bitmap.
00066         CoarseBitmap= *Texture;
00067         // remove all mipmaps, and convert to DXTC1 (if possible, ie if was DXTC5 or DXTC3 as example)
00068         CoarseBitmap.releaseMipMaps();
00069         // TODODO: consersion to DXTC1
00070         CoarseBitmap.convertToType(CBitmap::DXTC1);
00071 }
00072 
00073 
00074 // ***************************************************************************
00075 CAsyncTextureManager::CTextureLod::CTextureLod()
00076 {
00077         IsTextureEntry= false;
00078 
00079         TextureEntry= NULL;
00080         Weight= 0;
00081         Level= 0;
00082         Loaded= false;
00083         UpLoaded= false;
00084         ExtraSize= 0;
00085 }
00086 
00087 
00088 // ***************************************************************************
00089 CAsyncTextureManager::~CAsyncTextureManager()
00090 {
00091         // For all remaining textures, delete them.
00092         for(uint i=0;i<_TextureEntries.size();i++)
00093         {
00094                 if(_TextureEntries[i])
00095                         deleteTexture(i);
00096         }
00097 
00098         // there must be no waitting textures, nor map, nor current upload texture
00099         nlassert(_WaitingTextures.empty() && _TextureEntryMap.empty() && _CurrentUploadTexture==NULL 
00100                 && _CurrentTextureLodLoaded==NULL);
00101 }
00102 
00103 // ***************************************************************************
00104 CAsyncTextureManager::CAsyncTextureManager()
00105 {
00106         _BaseLodLevel= 3;
00107         _MaxLodLevel= 1;
00108         _MaxUploadPerFrame= 65536;
00109         _MaxHLSColoringPerFrame= 20*1024;
00110         _CurrentUploadTexture= NULL;
00111         _MaxTotalTextureSize= 10*1024*1024;
00112         _TotalTextureSizeAsked= 0;
00113         _LastTextureSizeGot= 0;
00114 
00115         // Do not share this texture, to force uploading of the lods.
00116         _CurrentTextureLodLoaded= NULL;
00117 }
00118 
00119 
00120 // ***************************************************************************
00121 void                    CAsyncTextureManager::setupLod(uint baseLevel, uint maxLevel)
00122 {
00123         nlassert(baseLevel>=maxLevel);
00124         _BaseLodLevel= baseLevel;
00125         _MaxLodLevel= maxLevel;
00126 }
00127 
00128 
00129 // ***************************************************************************
00130 void                    CAsyncTextureManager::setupMaxUploadPerFrame(uint maxup)
00131 {
00132         if(maxup>0)
00133                 _MaxUploadPerFrame= maxup;
00134 }
00135 
00136 // ***************************************************************************
00137 void                    CAsyncTextureManager::setupMaxHLSColoringPerFrame(uint maxCol)
00138 {
00139         if(maxCol>0)
00140                 _MaxHLSColoringPerFrame= maxCol;
00141 }
00142 
00143 // ***************************************************************************
00144 void                    CAsyncTextureManager::setupMaxTotalTextureSize(uint maxText)
00145 {
00146         _MaxTotalTextureSize= maxText;
00147 }
00148 
00149 
00150 // ***************************************************************************
00151 uint                    CAsyncTextureManager::addTextureRef(const string &textNameNotLwr, CMeshBaseInstance *instance)
00152 {
00153         uint    ret;
00154 
00155         // strlwr name
00156         string  textName= textNameNotLwr;
00157         strlwr(textName);
00158 
00159         // find the texture in map
00160         ItTextureEntryMap       it;
00161         it= _TextureEntryMap.find(textName);
00162 
00163         // not found, create.
00164         if(it==_TextureEntryMap.end())
00165         {
00166                 // search a free id.
00167                 uint    i= _TextureEntries.size();
00168                 if(!_FreeTextureIds.empty())
00169                 {
00170                         i= _FreeTextureIds.back();
00171                         _FreeTextureIds.pop_back();
00172                 }
00173                 // resize if needed.
00174                 if(i>=_TextureEntries.size())
00175                 {
00176                         _TextureEntries.push_back(NULL);
00177                         _FreeTextureIds.reserve(_TextureEntries.capacity());
00178                 }
00179 
00180                 // alloc new.
00181                 CTextureEntry   *text= new CTextureEntry();
00182                 _TextureEntries[i]= text;
00183                 text->Texture= new CTextureFile;
00184                 // Do not allow degradation.
00185                 text->Texture->setAllowDegradation(false);
00186 
00187                 // add to map.
00188                 it= _TextureEntryMap.insert(make_pair(textName, i)).first;
00189                 // bkup the it for deletion
00190                 text->ItMap= it;
00191 
00192                 // Start Color or Async loading.
00193                 text->Texture->setFileName(textName);
00194                 // First try with the HLSManager
00195                 sint    colorTextId= HLSManager.findTexture(textName);
00196                 // If found
00197                 if(colorTextId!=-1)
00198                 {
00199                         // Mark the texture as Loaded, and ready to colorize (done in update()).
00200                         text->Loaded= true;
00201                         text->BuildFromHLSManager= true;
00202                         text->HLSManagerTextId= colorTextId;
00203                 }
00204                 // else must async load it.
00205                 else
00206                 {
00207                         // start to load a small DDS version if possible
00208                         text->Texture->setMipMapSkipAtLoad(_BaseLodLevel);
00209                         // load it async.
00210                         CAsyncFileManager3D::getInstance().loadTexture(text->Texture, &text->Loaded);
00211                 }
00212                 // Add to a list so we can check each frame if it has ended.
00213                 _WaitingTextures.push_back(i);
00214         }
00215 
00216         // get the id of the text entry.
00217         ret= it->second;
00218 
00219         // add this instance to the list of ones which use this texture.
00220         CTextureEntry   *text= _TextureEntries[ret];
00221         text->Instances.push_back(instance);
00222 
00223         // if the texture is not yet ready, must increment the instance refCount.
00224         if(!text->UpLoaded)
00225                 instance->_AsyncTextureToLoadRefCount++;
00226 
00227         return ret;
00228 }
00229 
00230 
00231 // ***************************************************************************
00232 void                    CAsyncTextureManager::deleteTexture(uint id)
00233 {
00234         CTextureEntry   *text= _TextureEntries[id];
00235 
00236 
00237         // **** Stop AsyncLoading/UpLoading of main texture.
00238 
00239         // stop async loading if not ended
00240         if(!text->Loaded)
00241         {
00242                 CAsyncFileManager3D::getInstance().cancelLoadTexture(text->Texture);
00243         }
00244 
00245         // remove map entry
00246         _TextureEntryMap.erase(text->ItMap);
00247 
00248         // remove in list of waiting textures
00249         vector<uint>::iterator  itWait= find(_WaitingTextures.begin(),_WaitingTextures.end(), id);
00250         if(itWait!=_WaitingTextures.end())
00251                 _WaitingTextures.erase(itWait);
00252 
00253         // If it was the currently uploaded one, abort
00254         if(_CurrentUploadTexture==text)
00255         {
00256                 _CurrentUploadTexture= NULL;
00257         }
00258 
00259         // If not uploaded.
00260         if(!text->UpLoaded)
00261         {
00262                 // For all its remainding instances, dec refcount
00263                 for(uint i=0;i<text->Instances.size();i++)
00264                 {
00265                         text->Instances[i]->_AsyncTextureToLoadRefCount--;
00266                 }
00267         }
00268 
00269         // remove from bench
00270         _TotalTextureSizeAsked-= text->TotalTextureSizeAsked;
00271 
00272 
00273         // **** Stop AsyncLoading/UpLoading of HDLod 's texture.
00274 
00275         // Check if must stop TextureLod loading/uploading.
00276         CTextureLod             *textLod= &text->HDLod;
00277         if(textLod==_CurrentTextureLodLoaded)
00278         {
00279                 // stop the async loading if not ended.
00280                 if(!textLod->Loaded)
00281                 {
00282                         CAsyncFileManager3D::getInstance().cancelLoadTexture(textLod->Texture);
00283                 }
00284                 // stop uploading if was me
00285                 if(_CurrentUploadTexture==textLod)
00286                 {
00287                         _CurrentUploadTexture= NULL;
00288                 }
00289                 // stop loading me.
00290                 _CurrentTextureLodLoaded= NULL;
00291         }
00292 
00293         // At last delete texture entry.
00294         delete text;
00295         _TextureEntries[id]= NULL;
00296         // add a new free id.
00297         _FreeTextureIds.push_back(id);
00298 }
00299 
00300 
00301 // ***************************************************************************
00302 void                    CAsyncTextureManager::releaseTexture(uint id, CMeshBaseInstance *instance)
00303 {
00304         nlassert(id<_TextureEntries.size());
00305         nlassert(_TextureEntries[id]);
00306 
00307         // find an instance in this texture an remove it.
00308         CTextureEntry   *text= _TextureEntries[id];
00309         uint                    instSize= text->Instances.size();
00310         for(uint i=0;i<instSize;i++)
00311         {
00312                 if(text->Instances[i]== instance)
00313                 {
00314                         // Must first release the refCount if the texture is not uploaded
00315                         if(!text->UpLoaded)
00316                                 text->Instances[i]->_AsyncTextureToLoadRefCount--;
00317                         // remove it by swapping with last texture
00318                         text->Instances[i]= text->Instances[instSize-1];
00319                         text->Instances.pop_back();
00320                         // must stop: remove only the first occurence of instance.
00321                         break;
00322                 }
00323         }
00324 
00325         // if no more instance occurence, the texture is no more used => release it.
00326         if(text->Instances.empty())
00327         {
00328                 // do all the good stuff
00329                 deleteTexture(id);
00330         }
00331 }
00332 
00333 // ***************************************************************************
00334 bool                    CAsyncTextureManager::isTextureUpLoaded(uint id) const
00335 {
00336         nlassert(id<_TextureEntries.size());
00337         nlassert(_TextureEntries[id]);
00338         return _TextureEntries[id]->UpLoaded;
00339 }
00340 
00341 
00342 // ***************************************************************************
00343 const NLMISC::CBitmap   *CAsyncTextureManager::getCoarseBitmap(uint id) const
00344 {
00345         if(id>=_TextureEntries.size())
00346                 return NULL;
00347         CTextureEntry   *textEntry= _TextureEntries[id];
00348         if(!textEntry)
00349                 return NULL;
00350 
00351         // if the textEntry not uploaded, return NULL
00352         if(!textEntry->UpLoaded)
00353                 return NULL;
00354 
00355         // ok return the CoarseBitmap
00356         return &textEntry->CoarseBitmap;
00357 }
00358 
00359 
00360 // ***************************************************************************
00361 void                    CAsyncTextureManager::update(IDriver *pDriver)
00362 {
00363         uint    nTotalUploaded = 0;
00364         uint    nTotalColored = 0;
00365 
00366         // if no texture to upload, get the next one
00367         if(_CurrentUploadTexture==NULL)
00368                 getNextTextureToUpLoad(nTotalColored, pDriver);
00369 
00370         // while some texture to upload
00371         while(_CurrentUploadTexture)
00372         {
00373                 ITexture        *pText= _CurrentUploadTexture->Texture;
00374                 if(uploadTexturePart(pText, pDriver, nTotalUploaded))
00375                 {
00376                         // Stuff for TextureEntry
00377                         if(_CurrentUploadTexture->isTextureEntry())
00378                         {
00379                                 uint    i;
00380                                 CTextureEntry   *textEntry= static_cast<CTextureEntry*>(_CurrentUploadTexture);
00381                                 // If we are here, the texture is finally entirely uploaded. Compile it!
00382                                 textEntry->UpLoaded= true;
00383                                 // Can Have lod if texture is DXTC and have mipMaps! Also disalbe if system disable it
00384                                 textEntry->CanHaveLOD= validDXTCMipMap(pText) && _BaseLodLevel>_MaxLodLevel;
00385                                 // compute the size it takes in VRAM
00386                                 uint    baseMipMapSize= pText->getSize(0)*CBitmap::bitPerPixels[pText->getPixelFormat()]/8;
00387                                 // full size with mipmap
00388                                 textEntry->BaseSize= (uint)(baseMipMapSize*1.33f);
00389                                 // UpLoaded !! => signal all instances.
00390                                 for(i=0;i<textEntry->Instances.size();i++)
00391                                 {
00392                                         textEntry->Instances[i]->_AsyncTextureToLoadRefCount--;
00393                                 }
00394 
00395                                 // Create the coarse bitmap with the text (NB: still in memory here)
00396                                 textEntry->createCoarseBitmap();
00397 
00398                                 // If CanHaveLOD, create now the lods entries.
00399                                 if(textEntry->CanHaveLOD)
00400                                 {
00401                                         /* Allow only the MaxLod to be loaded async
00402                                                 This is supposed to be faster since a fseek is much longer than a texture Read.
00403                                                 Then it is more intelligent to read only One texture (the High Def), than to try to
00404                                                 read intermediate ones (512, 256, 128) because this made 3 more fseek.
00405                                         */
00406                                         // create only the MaxLod possible entry
00407                                         CTextureLod             &textLod= textEntry->HDLod;
00408                                         // fill textLod
00409                                         textLod.TextureEntry= textEntry;
00410                                         textLod.Level= _MaxLodLevel;
00411                                         // extra size of the lod only (important for LoadBalacing in updateTextureLodSystem())
00412                                         textLod.ExtraSize= textEntry->BaseSize*(1<<(2*(_BaseLodLevel-_MaxLodLevel))) - textEntry->BaseSize;
00413                                         // not yet loaded/upLoaded
00414                                         textLod.Loaded= false;
00415                                         textLod.UpLoaded= false;
00416                                 }
00417 
00418                                 // compute texture size for bench
00419                                 textEntry->TotalTextureSizeAsked= textEntry->BaseSize + textEntry->HDLod.ExtraSize;
00420 
00421                                 // Add texture size to global texture size
00422                                 _TotalTextureSizeAsked+= textEntry->TotalTextureSizeAsked;
00423                         }
00424                         // else, stuff for textureLod.
00425                         else
00426                         {
00427                                 CTextureLod             *textLod= static_cast<CTextureLod*>(_CurrentUploadTexture);
00428                                 // Swap the uploaded Driver Handle with the Main texture.
00429                                 pDriver->swapTextureHandle(*textLod->Texture, *textLod->TextureEntry->Texture);
00430                                 // Flag the Lod.
00431                                 textLod->UpLoaded= true;
00432                                 // Ok, ended to completly load this textureLod.
00433                                 _CurrentTextureLodLoaded= NULL;
00434                         }
00435 
00436                         // finally uploaded in VRAM, can release the RAM texture memory
00437                         pText->release();
00438 
00439                         // if not break because can't upload all parts, get next texture to upload
00440                         _CurrentUploadTexture= NULL;
00441                         getNextTextureToUpLoad(nTotalColored, pDriver);
00442                 }
00443                 else
00444                         // Fail to upload all, abort.
00445                         return;
00446         }
00447 }
00448 
00449 
00450 // ***************************************************************************
00451 bool                    CAsyncTextureManager::uploadTexturePart(ITexture *pText, IDriver *pDriver, uint &nTotalUploaded)
00452 {
00453         uint            nMipMap;
00454         nMipMap = pText->getMipMapCount();
00455 
00456 
00457         // If this is the start of uploading, setup the texture in driver.
00458         if(_CurrentUploadTextureMipMap==0 && _CurrentUploadTextureLine==0)
00459         {
00460                 // If the texture is not a valid DXTC with mipmap
00461                 if(!validDXTCMipMap(pText))
00462                 {
00463                         /* For now, prefer do nothing, because this may be an error (texture not found)
00464                                 and the texture may not be used at all, so don't take VRAM for nothing.
00465                                 => if the texture is used, it will be loaded synchronously by the caller later in the process
00466                                 => frame freeze.
00467                         */
00468                         /*
00469                         // upload All now.
00470                         // MipMap generation and compression may be done here => Maybe Big Freeze.
00471                         // approximate*2 instead of *1.33 for mipmaps.
00472                         uint    nWeight = pText->getSize (0) * 2;
00473                         nWeight= (nWeight*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
00474                         nTotalUploaded+= nWeight;
00475                         pDriver->setupTexture(*pText);
00476                         return true;*/
00477                         return true;
00478                 }
00479                 else
00480                 {
00481                         // Create the texture only and do not upload anything
00482                         bool isRel = pText->getReleasable ();
00483                         pText->setReleasable (false);
00484                         bool isAllUploaded = false;
00485                         /* Even if the shared texture is still referenced and so still exist in driver, we MUST recreate with good size
00486                                 the texture. This is important for Texture Memory Load Balancing
00487                                 (this may means that is used elsewhere than in the CAsyncTextureManager)
00488                                 Hence: bMustRecreateSharedTexture==true
00489                         */
00490                         pDriver->setupTextureEx (*pText, false, isAllUploaded, true);
00491                         pText->setReleasable (isRel);
00492                         // if the texture is already uploaded, abort partial uploading.
00493                         if (isAllUploaded)
00494                                 return true;
00495                 }
00496         }
00497 
00498 
00499         // try to upload all mipmap
00500         for(; _CurrentUploadTextureMipMap<nMipMap; _CurrentUploadTextureMipMap++)
00501         {
00502                 CRect zeRect;
00503                 uint nMM= _CurrentUploadTextureMipMap;
00504 
00505                 // What is left to upload ?
00506                 uint    nWeight = pText->getSize (nMM) - _CurrentUploadTextureLine*pText->getWidth(nMM);
00507                 nWeight= (nWeight*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
00508 
00509                 if ((nTotalUploaded  + nWeight) > _MaxUploadPerFrame)
00510                 {
00511                         // We cannot upload the whole mipmap -> we have to cut it
00512                         uint nSizeToUpload = _MaxUploadPerFrame - nTotalUploaded ;
00513                         uint nLineWeight = (pText->getWidth(nMM)*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
00514                         uint nNbLineToUpload = nSizeToUpload / nLineWeight;
00515                         // Upload 4 line by 4 line, and upload at leat one 4*line.
00516                         nNbLineToUpload = nNbLineToUpload / 4;
00517                         nNbLineToUpload= max(nNbLineToUpload, 1U);
00518                         nNbLineToUpload *= 4;
00519                         // comput rect to upload
00520                         uint32 nNewLine = _CurrentUploadTextureLine + nNbLineToUpload;
00521                         nNewLine= min(nNewLine, pText->getHeight(nMM));
00522                         zeRect.set (0, _CurrentUploadTextureLine, pText->getWidth(nMM), nNewLine);
00523                         _CurrentUploadTextureLine = nNewLine;
00524                         // if fill all the mipmap, must go to next
00525                         if (_CurrentUploadTextureLine == pText->getHeight(nMM))
00526                         {
00527                                 _CurrentUploadTextureLine = 0;
00528                                 _CurrentUploadTextureMipMap++;
00529                         }
00530                 }
00531                 else
00532                 {
00533                         // We can upload the whole mipmap (or the whole rest of the mipmap)
00534                         zeRect.set (0, _CurrentUploadTextureLine, pText->getWidth(nMM), pText->getHeight(nMM));
00535                         _CurrentUploadTextureLine= 0;
00536                 }
00537 
00538                 // upload the texture 
00539                 pDriver->uploadTexture (*pText, zeRect, (uint8)nMM);
00540 
00541                 nTotalUploaded += nWeight;
00542                 // If outpass max allocated upload, abort.
00543                 if (nTotalUploaded > _MaxUploadPerFrame)
00544                         return false;
00545         }
00546 
00547         return true;
00548 }
00549 
00550 
00551 // ***************************************************************************
00552 void                    CAsyncTextureManager::getNextTextureToUpLoad(uint &nTotalColored, IDriver *pDriver)
00553 {
00554         // Reset texture uploading
00555         _CurrentUploadTexture= NULL;
00556         _CurrentUploadTextureMipMap= 0;
00557         _CurrentUploadTextureLine= 0;
00558 
00559         // Search in WaitingTextures if one has ended async loading
00560         vector<uint>::iterator  it;
00561         for(it=_WaitingTextures.begin();it!=_WaitingTextures.end();it++)
00562         {
00563                 CTextureEntry   *text= _TextureEntries[*it];
00564                 // If Async loading done.
00565                 if(text->Loaded)
00566                 {
00567                         // Is it a "texture to color" with HLSManager? yes=> color it now.
00568                         if(text->BuildFromHLSManager)
00569                         {
00570                                 // If not beyond the max coloring texture
00571                                 if(nTotalColored<_MaxHLSColoringPerFrame)
00572                                 {
00573                                         // Build the texture directly in the TextureFile.
00574                                         nlverify(HLSManager.buildTexture(text->HLSManagerTextId, *text->Texture));
00575                                         // Must validate the textureFile generation. NB: little weird since this is not really a textureFile.
00576                                         // But it is the easier way to do it.
00577                                         text->Texture->validateGenerateFlag();
00578                                         // compute the texture size (approx). NB: DXTC5 means 1 pixel==1 byte.
00579                                         uint    size= (uint)(text->Texture->getSize(0)*1.33);
00580                                         // Add it to the num of colorised texture done in current update().
00581                                         nTotalColored+= size;
00582                                 }
00583                                 // Else must quit and don't update any more texture this frame (_CurrentUploadTexture==NULL)
00584                                 else
00585                                         return;
00586                         }
00587 
00588                         // upload this one
00589                         _CurrentUploadTexture= text;
00590                         // remove it from list of waiting textures
00591                         _WaitingTextures.erase(it);
00592                         // found => end.
00593                         return;
00594                 }
00595         }
00596 
00597         // If here, and if no more waiting textures, update the Lod system.
00598         if(_WaitingTextures.empty())
00599         {
00600                 // if end to load the current lod.
00601                 if(_CurrentTextureLodLoaded && _CurrentTextureLodLoaded->Loaded)
00602                 {
00603                         // upload this one
00604                         _CurrentUploadTexture= _CurrentTextureLodLoaded;
00605                         return;
00606                 }
00607 
00608                 // if no Lod texture currently loading, try to load/unload one
00609                 if(_CurrentTextureLodLoaded == NULL)
00610                 {
00611                         updateTextureLodSystem(pDriver);
00612                 }
00613         }
00614 }
00615 
00616 
00617 // ***************************************************************************
00618 bool                    CAsyncTextureManager::validDXTCMipMap(ITexture *pText)
00619 {
00620         return pText->getMipMapCount()>1 && (
00621                 pText->getPixelFormat() == CBitmap::DXTC1 ||
00622                 pText->getPixelFormat() == CBitmap::DXTC1Alpha ||
00623                 pText->getPixelFormat() == CBitmap::DXTC3 ||
00624                 pText->getPixelFormat() == CBitmap::DXTC5 );
00625 }
00626 
00627 
00628 // ***************************************************************************
00629 void                    CAsyncTextureManager::updateTextureLodSystem(IDriver *pDriver)
00630 {
00631         sint    i;
00632 
00633         // the array to sort
00634         static  vector<CTextureLod*>    lodArray;
00635         lodArray.clear();
00636         uint    reserveSize= 0;
00637 
00638         // for each texture entry compute min distance of use
00639         //=============
00640         uint    currentBaseSize= 0;
00641         for(i=0;i<(sint)_TextureEntries.size();i++)
00642         {
00643                 if(!_TextureEntries[i])
00644                         continue;
00645                 CTextureEntry   &text= *_TextureEntries[i];
00646                 // do it only for Lodable textures
00647                 if(text.CanHaveLOD)
00648                 {
00649                         text.MinDistance= FLT_MAX;
00650                         // for all instances.
00651                         for(uint j=0;j<text.Instances.size();j++)
00652                         {
00653                                 float   instDist= text.Instances[j]->getAsyncTextureDistance();
00654                                 text.MinDistance= min(text.MinDistance, instDist);
00655                         }
00656 
00657                         // avoid /0
00658                         text.MinDistance= max(NL3D_ATM_MIN_DISTANCE, text.MinDistance);
00659 
00660                         // how many textLods to add
00661                         reserveSize++;
00662 
00663                         // the minimum mem size the system take with base lod.
00664                         currentBaseSize+= text.BaseSize;
00665                 }
00666         }
00667         // reserve space
00668         lodArray.reserve(reserveSize);
00669 
00670 
00671         // for each texture lod compute weight, and append
00672         //=============
00673         for(i=0;i<(sint)_TextureEntries.size();i++)
00674         {
00675                 if(!_TextureEntries[i])
00676                         continue;
00677                 CTextureEntry   &text= *_TextureEntries[i];
00678                 // do it only for Lodable textures
00679                 if(text.CanHaveLOD)
00680                 {
00681                         // This Weight is actually a screen Pixel Ratio! (divide by distance)
00682                         CTextureLod     *textLod= &text.HDLod;
00683                         textLod->Weight= (1<<textLod->Level) / text.MinDistance;
00684                         // add to array
00685                         lodArray.push_back(textLod);
00686                 }
00687         }
00688 
00689 
00690         // sort
00691         //=============
00692         CPredTextLod    pred;
00693         sort(lodArray.begin(), lodArray.end(), pred);
00694 
00695 
00696         // Compute lod to load/unload
00697         //=============
00698         // Compute Pivot, ie what lods have to be loaded, and what lods do not
00699         uint    pivot= 0;
00700         uint    currentWantedSize= currentBaseSize;
00701         uint    currentLoadedSize= currentBaseSize;
00702         for(i=lodArray.size()-1;i>=0;i--)
00703         {
00704                 uint    lodSize= lodArray[i]->ExtraSize;
00705                 currentWantedSize+= lodSize;
00706                 if(lodArray[i]->UpLoaded)
00707                         currentLoadedSize+= lodSize;
00708                 // if > max allowed, stop the pivot here. NB: the pivot is included in the "must load them" part.
00709                 if(currentWantedSize > _MaxTotalTextureSize)
00710                 {
00711                         pivot= i;
00712                         break;
00713                 }
00714         }
00715         // continue to count currentLoadedSize
00716         for(;i>=0;i--)
00717         {
00718                 if(lodArray[i]->UpLoaded)
00719                         currentLoadedSize+= lodArray[i]->ExtraSize;
00720         }
00721         // save bench.
00722         _LastTextureSizeGot= currentLoadedSize;
00723 
00724 
00725         // if the loadedSize is inferior to the wanted size, we can load a new LOD
00726         CTextureLod             *textLod= NULL;
00727         bool                    unload;
00728         if(currentLoadedSize<currentWantedSize)
00729         {
00730                 unload= false;
00731                 // search from end of the list to pivot (included), the first LOD (ie the most important) to load.
00732                 for(i=lodArray.size()-1;i>=(sint)pivot;i--)
00733                 {
00734                         if(!lodArray[i]->UpLoaded)
00735                         {
00736                                 textLod= lodArray[i];
00737                                 break;
00738                         }
00739                 }
00740                 // One must have been found, since currentLoadedSize<currentWantedSize
00741                 nlassert(textLod);
00742         }
00743         else
00744         {
00745                 unload= true;
00746                 // search from start to pivot (exclued), the first LOD (ie the less important) to unload.
00747                 for(i=0;i<(sint)pivot;i++)
00748                 {
00749                         if(lodArray[i]->UpLoaded)
00750                         {
00751                                 textLod= lodArray[i];
00752                                 break;
00753                         }
00754                 }
00755                 // it is possible that not found here. It means that All is Ok!!
00756                 if(textLod==NULL)
00757                         // no-op.
00758                         return;
00759         }
00760 
00761 
00762         // load/unload
00763         //=============
00764         if(!unload)
00765         {
00766                 // create a new TextureFile, with no sharing system.
00767                 nlassert(textLod->Texture==NULL);
00768                 textLod->Texture= new CTextureFile;
00769                 // Do not allow degradation.
00770                 textLod->Texture->setAllowDegradation(false);
00771                 textLod->Texture->enableSharing(false);
00772                 textLod->Texture->setFileName(textLod->TextureEntry->Texture->getFileName());
00773                 textLod->Texture->setMipMapSkipAtLoad(textLod->Level);
00774                 // setup async loading
00775                 _CurrentTextureLodLoaded= textLod;
00776                 // load it async.
00777                 CAsyncFileManager3D::getInstance().loadTexture(textLod->Texture, &textLod->Loaded);
00778         }
00779         else
00780         {
00781                 // Swap now the lod.
00782                 nlassert(textLod->Texture!=NULL);
00783                 // Swap the uploaded Driver Handle with the Main texture (ot get the Ugly one)
00784                 pDriver->swapTextureHandle(*textLod->Texture, *textLod->TextureEntry->Texture);
00785                 // Flag the Lod.
00786                 textLod->UpLoaded= false;
00787                 textLod->Loaded= false;
00788                 // Release completly the texture in driver. (SmartPtr delete)
00789                 textLod->Texture= NULL;
00790         }
00791 
00792 }
00793 
00794 
00795 
00796 } // NL3D