00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00062 nlassert(Texture);
00063 nlassert(Texture->getSize()>0);
00064
00065
00066 CoarseBitmap= *Texture;
00067
00068 CoarseBitmap.releaseMipMaps();
00069
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
00092 for(uint i=0;i<_TextureEntries.size();i++)
00093 {
00094 if(_TextureEntries[i])
00095 deleteTexture(i);
00096 }
00097
00098
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
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
00156 string textName= textNameNotLwr;
00157 strlwr(textName);
00158
00159
00160 ItTextureEntryMap it;
00161 it= _TextureEntryMap.find(textName);
00162
00163
00164 if(it==_TextureEntryMap.end())
00165 {
00166
00167 uint i= _TextureEntries.size();
00168 if(!_FreeTextureIds.empty())
00169 {
00170 i= _FreeTextureIds.back();
00171 _FreeTextureIds.pop_back();
00172 }
00173
00174 if(i>=_TextureEntries.size())
00175 {
00176 _TextureEntries.push_back(NULL);
00177 _FreeTextureIds.reserve(_TextureEntries.capacity());
00178 }
00179
00180
00181 CTextureEntry *text= new CTextureEntry();
00182 _TextureEntries[i]= text;
00183 text->Texture= new CTextureFile;
00184
00185 text->Texture->setAllowDegradation(false);
00186
00187
00188 it= _TextureEntryMap.insert(make_pair(textName, i)).first;
00189
00190 text->ItMap= it;
00191
00192
00193 text->Texture->setFileName(textName);
00194
00195 sint colorTextId= HLSManager.findTexture(textName);
00196
00197 if(colorTextId!=-1)
00198 {
00199
00200 text->Loaded= true;
00201 text->BuildFromHLSManager= true;
00202 text->HLSManagerTextId= colorTextId;
00203 }
00204
00205 else
00206 {
00207
00208 text->Texture->setMipMapSkipAtLoad(_BaseLodLevel);
00209
00210 CAsyncFileManager3D::getInstance().loadTexture(text->Texture, &text->Loaded);
00211 }
00212
00213 _WaitingTextures.push_back(i);
00214 }
00215
00216
00217 ret= it->second;
00218
00219
00220 CTextureEntry *text= _TextureEntries[ret];
00221 text->Instances.push_back(instance);
00222
00223
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
00238
00239
00240 if(!text->Loaded)
00241 {
00242 CAsyncFileManager3D::getInstance().cancelLoadTexture(text->Texture);
00243 }
00244
00245
00246 _TextureEntryMap.erase(text->ItMap);
00247
00248
00249 vector<uint>::iterator itWait= find(_WaitingTextures.begin(),_WaitingTextures.end(), id);
00250 if(itWait!=_WaitingTextures.end())
00251 _WaitingTextures.erase(itWait);
00252
00253
00254 if(_CurrentUploadTexture==text)
00255 {
00256 _CurrentUploadTexture= NULL;
00257 }
00258
00259
00260 if(!text->UpLoaded)
00261 {
00262
00263 for(uint i=0;i<text->Instances.size();i++)
00264 {
00265 text->Instances[i]->_AsyncTextureToLoadRefCount--;
00266 }
00267 }
00268
00269
00270 _TotalTextureSizeAsked-= text->TotalTextureSizeAsked;
00271
00272
00273
00274
00275
00276 CTextureLod *textLod= &text->HDLod;
00277 if(textLod==_CurrentTextureLodLoaded)
00278 {
00279
00280 if(!textLod->Loaded)
00281 {
00282 CAsyncFileManager3D::getInstance().cancelLoadTexture(textLod->Texture);
00283 }
00284
00285 if(_CurrentUploadTexture==textLod)
00286 {
00287 _CurrentUploadTexture= NULL;
00288 }
00289
00290 _CurrentTextureLodLoaded= NULL;
00291 }
00292
00293
00294 delete text;
00295 _TextureEntries[id]= NULL;
00296
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
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
00315 if(!text->UpLoaded)
00316 text->Instances[i]->_AsyncTextureToLoadRefCount--;
00317
00318 text->Instances[i]= text->Instances[instSize-1];
00319 text->Instances.pop_back();
00320
00321 break;
00322 }
00323 }
00324
00325
00326 if(text->Instances.empty())
00327 {
00328
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
00352 if(!textEntry->UpLoaded)
00353 return NULL;
00354
00355
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
00367 if(_CurrentUploadTexture==NULL)
00368 getNextTextureToUpLoad(nTotalColored, pDriver);
00369
00370
00371 while(_CurrentUploadTexture)
00372 {
00373 ITexture *pText= _CurrentUploadTexture->Texture;
00374 if(uploadTexturePart(pText, pDriver, nTotalUploaded))
00375 {
00376
00377 if(_CurrentUploadTexture->isTextureEntry())
00378 {
00379 uint i;
00380 CTextureEntry *textEntry= static_cast<CTextureEntry*>(_CurrentUploadTexture);
00381
00382 textEntry->UpLoaded= true;
00383
00384 textEntry->CanHaveLOD= validDXTCMipMap(pText) && _BaseLodLevel>_MaxLodLevel;
00385
00386 uint baseMipMapSize= pText->getSize(0)*CBitmap::bitPerPixels[pText->getPixelFormat()]/8;
00387
00388 textEntry->BaseSize= (uint)(baseMipMapSize*1.33f);
00389
00390 for(i=0;i<textEntry->Instances.size();i++)
00391 {
00392 textEntry->Instances[i]->_AsyncTextureToLoadRefCount--;
00393 }
00394
00395
00396 textEntry->createCoarseBitmap();
00397
00398
00399 if(textEntry->CanHaveLOD)
00400 {
00401
00402
00403
00404
00405
00406
00407 CTextureLod &textLod= textEntry->HDLod;
00408
00409 textLod.TextureEntry= textEntry;
00410 textLod.Level= _MaxLodLevel;
00411
00412 textLod.ExtraSize= textEntry->BaseSize*(1<<(2*(_BaseLodLevel-_MaxLodLevel))) - textEntry->BaseSize;
00413
00414 textLod.Loaded= false;
00415 textLod.UpLoaded= false;
00416 }
00417
00418
00419 textEntry->TotalTextureSizeAsked= textEntry->BaseSize + textEntry->HDLod.ExtraSize;
00420
00421
00422 _TotalTextureSizeAsked+= textEntry->TotalTextureSizeAsked;
00423 }
00424
00425 else
00426 {
00427 CTextureLod *textLod= static_cast<CTextureLod*>(_CurrentUploadTexture);
00428
00429 pDriver->swapTextureHandle(*textLod->Texture, *textLod->TextureEntry->Texture);
00430
00431 textLod->UpLoaded= true;
00432
00433 _CurrentTextureLodLoaded= NULL;
00434 }
00435
00436
00437 pText->release();
00438
00439
00440 _CurrentUploadTexture= NULL;
00441 getNextTextureToUpLoad(nTotalColored, pDriver);
00442 }
00443 else
00444
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
00458 if(_CurrentUploadTextureMipMap==0 && _CurrentUploadTextureLine==0)
00459 {
00460
00461 if(!validDXTCMipMap(pText))
00462 {
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 return true;
00478 }
00479 else
00480 {
00481
00482 bool isRel = pText->getReleasable ();
00483 pText->setReleasable (false);
00484 bool isAllUploaded = false;
00485
00486
00487
00488
00489
00490 pDriver->setupTextureEx (*pText, false, isAllUploaded, true);
00491 pText->setReleasable (isRel);
00492
00493 if (isAllUploaded)
00494 return true;
00495 }
00496 }
00497
00498
00499
00500 for(; _CurrentUploadTextureMipMap<nMipMap; _CurrentUploadTextureMipMap++)
00501 {
00502 CRect zeRect;
00503 uint nMM= _CurrentUploadTextureMipMap;
00504
00505
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
00512 uint nSizeToUpload = _MaxUploadPerFrame - nTotalUploaded ;
00513 uint nLineWeight = (pText->getWidth(nMM)*CBitmap::bitPerPixels[pText->getPixelFormat()])/8;
00514 uint nNbLineToUpload = nSizeToUpload / nLineWeight;
00515
00516 nNbLineToUpload = nNbLineToUpload / 4;
00517 nNbLineToUpload= max(nNbLineToUpload, 1U);
00518 nNbLineToUpload *= 4;
00519
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
00525 if (_CurrentUploadTextureLine == pText->getHeight(nMM))
00526 {
00527 _CurrentUploadTextureLine = 0;
00528 _CurrentUploadTextureMipMap++;
00529 }
00530 }
00531 else
00532 {
00533
00534 zeRect.set (0, _CurrentUploadTextureLine, pText->getWidth(nMM), pText->getHeight(nMM));
00535 _CurrentUploadTextureLine= 0;
00536 }
00537
00538
00539 pDriver->uploadTexture (*pText, zeRect, (uint8)nMM);
00540
00541 nTotalUploaded += nWeight;
00542
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
00555 _CurrentUploadTexture= NULL;
00556 _CurrentUploadTextureMipMap= 0;
00557 _CurrentUploadTextureLine= 0;
00558
00559
00560 vector<uint>::iterator it;
00561 for(it=_WaitingTextures.begin();it!=_WaitingTextures.end();it++)
00562 {
00563 CTextureEntry *text= _TextureEntries[*it];
00564
00565 if(text->Loaded)
00566 {
00567
00568 if(text->BuildFromHLSManager)
00569 {
00570
00571 if(nTotalColored<_MaxHLSColoringPerFrame)
00572 {
00573
00574 nlverify(HLSManager.buildTexture(text->HLSManagerTextId, *text->Texture));
00575
00576
00577 text->Texture->validateGenerateFlag();
00578
00579 uint size= (uint)(text->Texture->getSize(0)*1.33);
00580
00581 nTotalColored+= size;
00582 }
00583
00584 else
00585 return;
00586 }
00587
00588
00589 _CurrentUploadTexture= text;
00590
00591 _WaitingTextures.erase(it);
00592
00593 return;
00594 }
00595 }
00596
00597
00598 if(_WaitingTextures.empty())
00599 {
00600
00601 if(_CurrentTextureLodLoaded && _CurrentTextureLodLoaded->Loaded)
00602 {
00603
00604 _CurrentUploadTexture= _CurrentTextureLodLoaded;
00605 return;
00606 }
00607
00608
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
00634 static vector<CTextureLod*> lodArray;
00635 lodArray.clear();
00636 uint reserveSize= 0;
00637
00638
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
00647 if(text.CanHaveLOD)
00648 {
00649 text.MinDistance= FLT_MAX;
00650
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
00658 text.MinDistance= max(NL3D_ATM_MIN_DISTANCE, text.MinDistance);
00659
00660
00661 reserveSize++;
00662
00663
00664 currentBaseSize+= text.BaseSize;
00665 }
00666 }
00667
00668 lodArray.reserve(reserveSize);
00669
00670
00671
00672
00673 for(i=0;i<(sint)_TextureEntries.size();i++)
00674 {
00675 if(!_TextureEntries[i])
00676 continue;
00677 CTextureEntry &text= *_TextureEntries[i];
00678
00679 if(text.CanHaveLOD)
00680 {
00681
00682 CTextureLod *textLod= &text.HDLod;
00683 textLod->Weight= (1<<textLod->Level) / text.MinDistance;
00684
00685 lodArray.push_back(textLod);
00686 }
00687 }
00688
00689
00690
00691
00692 CPredTextLod pred;
00693 sort(lodArray.begin(), lodArray.end(), pred);
00694
00695
00696
00697
00698
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
00709 if(currentWantedSize > _MaxTotalTextureSize)
00710 {
00711 pivot= i;
00712 break;
00713 }
00714 }
00715
00716 for(;i>=0;i--)
00717 {
00718 if(lodArray[i]->UpLoaded)
00719 currentLoadedSize+= lodArray[i]->ExtraSize;
00720 }
00721
00722 _LastTextureSizeGot= currentLoadedSize;
00723
00724
00725
00726 CTextureLod *textLod= NULL;
00727 bool unload;
00728 if(currentLoadedSize<currentWantedSize)
00729 {
00730 unload= false;
00731
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
00741 nlassert(textLod);
00742 }
00743 else
00744 {
00745 unload= true;
00746
00747 for(i=0;i<(sint)pivot;i++)
00748 {
00749 if(lodArray[i]->UpLoaded)
00750 {
00751 textLod= lodArray[i];
00752 break;
00753 }
00754 }
00755
00756 if(textLod==NULL)
00757
00758 return;
00759 }
00760
00761
00762
00763
00764 if(!unload)
00765 {
00766
00767 nlassert(textLod->Texture==NULL);
00768 textLod->Texture= new CTextureFile;
00769
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
00775 _CurrentTextureLodLoaded= textLod;
00776
00777 CAsyncFileManager3D::getInstance().loadTexture(textLod->Texture, &textLod->Loaded);
00778 }
00779 else
00780 {
00781
00782 nlassert(textLod->Texture!=NULL);
00783
00784 pDriver->swapTextureHandle(*textLod->Texture, *textLod->TextureEntry->Texture);
00785
00786 textLod->UpLoaded= false;
00787 textLod->Loaded= false;
00788
00789 textLod->Texture= NULL;
00790 }
00791
00792 }
00793
00794
00795
00796 }