Show bonus/malus timer text if available
[ryzomcore.git] / nel / src / 3d / shape_bank.cpp
blobcb6ea8c21d20722bb67064c491f3e994044508c9
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/shape_bank.h"
23 #include "nel/3d/mesh_base.h"
24 #include "nel/misc/file.h"
25 #include "nel/misc/path.h"
26 #include "nel/misc/rect.h"
27 #include "nel/misc/algo.h"
28 #include "nel/misc/progress_callback.h"
30 using namespace std;
31 using namespace NLMISC;
33 #ifdef DEBUG_NEW
34 #define new DEBUG_NEW
35 #endif
37 namespace NL3D
40 // ***************************************************************************
42 CShapeBank::CShapeBank()
44 // Default cache creation
45 addShapeCache( "default" );
46 _MaxUploadPerFrame = 16*1024;
49 // ***************************************************************************
51 CShapeBank::~CShapeBank()
55 // ***************************************************************************
57 IShape*CShapeBank::addRef(const string &shapeNameNotLwr)
59 string shapeName= toLowerAscii(shapeNameNotLwr);
61 // get the shape info (must succeed)
62 TShapeInfoMap::iterator scfpmIt = ShapePtrToShapeInfo.find( getShapePtrFromShapeName( shapeName ) );
63 nlassert( scfpmIt != ShapePtrToShapeInfo.end() );
65 // If The shape is not inserted into a cache, just return it
66 if( !scfpmIt->second.isAdded )
67 return getShapePtrFromShapeName( shapeName );
69 // else If the shape is inserted in a shape cache remove it
70 scfpmIt->second.isAdded = false;
71 CShapeCache *pShpCache = scfpmIt->second.pShpCache;
72 nlassert( pShpCache != NULL );
73 // Search the shape cache for the shape we want to remove
74 list<IShape*>::iterator lsIt = pShpCache->Elements.begin();
75 while(lsIt != pShpCache->Elements.end())
77 const string *sTemp = getShapeNameFromShapePtr(*lsIt);
78 if( *sTemp == shapeName )
80 // Ok the shape cache contains the shape remove it and return
81 pShpCache->Elements.erase( lsIt );
82 return getShapePtrFromShapeName( shapeName );
84 ++lsIt;
86 nlassert( false );
87 return getShapePtrFromShapeName( shapeName );
90 // ***************************************************************************
92 void CShapeBank::release(IShape* pShp)
94 // Do we have the last smartPtr on the shape ?
95 const string* str = getShapeNameFromShapePtr( pShp );
97 if (str == NULL)
99 nlwarning ("Trying to release a mesh that have not be added to the shape bank");
101 else
103 TShapeMap::iterator smIt = ShapeMap.find( *str );
104 if( smIt != ShapeMap.end() )
106 if( smIt->second.getNbRef() == 1 )
108 // Yes -> add the shape to its shapeCache
109 CShapeCache *pShpCache = getShapeCachePtrFromShapePtr( pShp );
110 pShpCache->Elements.push_front( pShp );
112 TShapeInfoMap::iterator scfpmIt = ShapePtrToShapeInfo.find( pShp );
113 if( scfpmIt != ShapePtrToShapeInfo.end() )
115 scfpmIt->second.isAdded = true;
118 // check the shape cache
119 checkShapeCache(getShapeCachePtrFromShapePtr(pShp));
122 else
124 nlassert( false );
129 // ***************************************************************************
131 void CShapeBank::processWaitingShapes ()
133 uint32 nTotalUploaded = 0;
134 TWaitingShapesMap::iterator wsmmIt = WaitingShapes.begin();
135 while( wsmmIt != WaitingShapes.end() )
137 // Backup next iterator
138 TWaitingShapesMap::iterator wsmmItNext = wsmmIt;
139 wsmmItNext++;
141 const string &shapeName = wsmmIt->first;
142 CWaitingShape &rWS = wsmmIt->second;
143 IShape *pShp = rWS.ShapePtr; // Take care this value is shared between thread so copy it in a local variable first
145 switch (rWS.State)
147 case AsyncLoad_Shape: // Check if we can pass to the AsyncLoad_Texture state
148 if (pShp != NULL)
150 if (pShp == (IShape*)-1)
151 rWS.State = AsyncLoad_Error;
152 else
153 rWS.State = AsyncLoad_Texture;
155 break;
157 case AsyncLoad_Texture:
159 // Setup all textures and lightmaps of the shape
160 if (nTotalUploaded > _MaxUploadPerFrame)
161 break;
163 CMeshBase *pMesh = dynamic_cast<CMeshBase*>(pShp);
164 if( pMesh != NULL )
166 uint8 j;
167 uint32 i, CurrentProgress = 0;
168 uint32 nNbMat = pMesh->getNbMaterial();
170 for (i = 0; i < nNbMat; ++i)
172 const CMaterial &rMat = pMesh->getMaterial(i);
173 // Parse all textures from this material and setup
174 for (j = 0; j < IDRV_MAT_MAXTEXTURES; ++j)
176 if (CurrentProgress >= rWS.UpTextProgress)
178 if (rMat.texturePresent(j))
180 if ((!_pDriver->isTextureExist(*rMat.getTexture(j))) ||
181 (rWS.UpTextLine > 0) || (rWS.UpTextMipMap > 0))
183 //_pDriver->setupTexture (*rMat.getTexture(j));
185 if (!processWSUploadTexture (rWS, nTotalUploaded, rMat.getTexture(j)))
186 break;
188 else
191 Must release texture data because of the following scenario (common!)
192 - An IG with 2 different meshs is async loaded
193 - the 2 meshs access the same texture "pipo.tga"
194 - in CAsyncFileManager3D::loadMesh(), if this case arise, the
195 textures are loaded twice in RAM!!!! (is managed per mesh, but not
196 thourhg meshs)
197 - hence the first mesh setup and upload above the texture in VRAM
198 but the second still have data in RAM!! (because 2nd will
199 say that isTextureExist() ....
201 Note: you could say that the cool stuff would be to not load the 2 :)
202 but it appears that this case arise rarely because of the following statement:
203 - while the second mesh is async loaded, the first upload in VRAM
204 so there is good change that the second don't load the texture
205 (isTextureExist() return true in the thread)
207 ITexture *tex= rMat.getTexture(j);
208 if(tex->getReleasable())
209 tex->release();
212 ++rWS.UpTextProgress;
214 ++CurrentProgress;
215 if (nTotalUploaded > _MaxUploadPerFrame)
216 break;
219 if (nTotalUploaded > _MaxUploadPerFrame)
220 break;
222 // Do the same with lightmaps
223 if (rMat.getShader() == CMaterial::LightMap)
225 uint j = 0; ITexture *pText = rMat.getLightMap (j);
226 while (pText != NULL)
228 if (CurrentProgress >= rWS.UpTextProgress)
230 if ((!_pDriver->isTextureExist(*pText)) ||
231 (rWS.UpTextLine > 0) || (rWS.UpTextMipMap > 0))
233 //_pDriver->setupTexture (*pText);
235 if (!processWSUploadTexture (rWS, nTotalUploaded, pText))
236 break;
238 else
240 // see above for explanation
241 if(pText->getReleasable())
242 pText->release();
245 ++rWS.UpTextProgress;
247 ++CurrentProgress;
248 ++j; pText = rMat.getLightMap (j);
249 if (nTotalUploaded > _MaxUploadPerFrame)
250 break;
253 if (nTotalUploaded > _MaxUploadPerFrame)
254 break;
257 if (nTotalUploaded > _MaxUploadPerFrame)
258 break;
260 rWS.State = AsyncLoad_Ready;
262 break;
264 case AsyncLoad_Ready:
265 add (wsmmIt->first, pShp);
266 rWS.State = AsyncLoad_Delete;
267 break;
269 // The delete operation can take several frames to complete but this is not a problem
271 // For error do the same as delete but let the flag to error if a shape is asked just after
272 // the error was found
274 case AsyncLoad_Error:
275 case AsyncLoad_Delete:
276 rWS.RefCnt -= 1;
277 if (rWS.RefCnt == 0)
279 // We have to signal if we are the last
280 std::set<bool *>::iterator ite = rWS.Signal.begin();
281 while (ite != rWS.Signal.end())
283 bool *bSignal = *ite;
284 if (bSignal != NULL)
286 bool bFound = false;
287 TWaitingShapesMap::iterator wsmmIt2 = WaitingShapes.begin();
288 while (wsmmIt2 != WaitingShapes.end())
290 const string &shapeName2 = wsmmIt2->first;
291 if (shapeName2 != shapeName)
293 std::set<bool *>::iterator ite2 = wsmmIt2->second.Signal.begin();
294 while (ite2 != wsmmIt2->second.Signal.end())
296 if (*ite2 == bSignal)
298 bFound = true;
299 break;
301 ite2++;
303 if (ite2 != wsmmIt2->second.Signal.end())
304 break;
306 ++wsmmIt2;
308 if (!bFound)
309 *bSignal = true;
312 // Next iterator
313 ite++;
315 WaitingShapes.erase (wsmmIt);
317 break;
319 default:
320 nlstop; // This must never happen
321 break;
324 wsmmIt = wsmmItNext;
328 // ***************************************************************************
329 void CShapeBank::setMaxBytesToUpload (uint32 MaxUploadPerFrame)
331 _MaxUploadPerFrame = MaxUploadPerFrame;
334 // ***************************************************************************
335 bool CShapeBank::processWSUploadTexture (CWaitingShape &rWS, uint32 &nTotalUploaded, ITexture *pText)
337 CRect zeRect;
338 uint32 nFace, nWeight = 0, nMipMap;
340 if ((rWS.UpTextMipMap == 0) && (rWS.UpTextLine == 0))
342 // Create the texture only and do not upload anything
343 bool isRel = pText->getReleasable ();
344 pText->setReleasable (false);
345 bool isAllUploaded = false;
346 _pDriver->setupTextureEx (*pText, false, isAllUploaded);
347 pText->setReleasable (isRel);
348 if (isAllUploaded)
349 return true;
352 if (pText->mipMapOn())
353 nMipMap = pText->getMipMapCount();
354 else
355 nMipMap = 1;
357 // Upload all mipmaps
358 for (; rWS.UpTextMipMap < nMipMap;)
360 uint32 nMM = rWS.UpTextMipMap;
361 // What is left to upload ?
362 nWeight = pText->getSize (nMM) - rWS.UpTextLine*pText->getWidth(nMM);
363 // Yoyo: important: in case of DXTC1, must mul before div
364 nWeight= (nWeight*CBitmap::bitPerPixels[pText->getPixelFormat()]) / 8;
365 if (pText->isTextureCube())
366 nWeight *= 6;
368 // NB: nWeight can be 0 in case of 1x1 in DXTC1. Estimate 1 byte
369 if(nWeight==0)
370 nWeight= 1;
372 // Setup rectangle
373 if ((nTotalUploaded + nWeight) > _MaxUploadPerFrame)
375 // We cannot upload the whole mipmap -> we have to cut it
376 uint32 nSizeToUpload = _MaxUploadPerFrame - nTotalUploaded;
377 uint32 nLineWeight = (pText->getWidth(nMM)*CBitmap::bitPerPixels[pText->getPixelFormat()]) / 8;
378 // NB: nLineWeight can be 0 in case of 1x1 in DXTC1. Estimate 1 byte (avoid divide by zero)
379 if(nLineWeight==0)
380 nLineWeight= 1;
381 if (pText->isTextureCube())
382 nLineWeight *= 6;
383 // compute the number of lines we'll upload
384 uint32 nNbLineToUpload = nSizeToUpload / nLineWeight;
385 nNbLineToUpload = nNbLineToUpload / 4;
386 if (nNbLineToUpload == 0)
387 nNbLineToUpload = 1;
388 nNbLineToUpload *= 4; // Upload 4 line by 4 line
389 // setup the rect
390 uint32 nNewLine = rWS.UpTextLine + nNbLineToUpload;
391 if (nNewLine > pText->getHeight(nMM))
392 nNewLine = pText->getHeight(nMM);
393 zeRect.set (0, rWS.UpTextLine, pText->getWidth(nMM), nNewLine);
394 rWS.UpTextLine = nNewLine;
395 if (rWS.UpTextLine == pText->getHeight(nMM))
397 rWS.UpTextLine = 0;
398 rWS.UpTextMipMap += 1;
401 else
403 // We can upload the whole mipmap (or the whole rest of the mipmap)
404 zeRect.set (0, rWS.UpTextLine, pText->getWidth(nMM), pText->getHeight(nMM));
405 rWS.UpTextLine = 0;
406 rWS.UpTextMipMap += 1;
409 // Upload !
410 if (pText->isTextureCube())
412 for (nFace = 0; nFace < 6; ++nFace)
413 _pDriver->uploadTextureCube (*pText, zeRect, (uint8)nMM, (uint8)nFace);
415 else
417 _pDriver->uploadTexture (*pText, zeRect, (uint8)nMM);
420 nTotalUploaded += nWeight;
421 if (nTotalUploaded > _MaxUploadPerFrame)
422 return false;
425 if (pText->getReleasable())
426 pText->release();
428 rWS.UpTextMipMap = 0;
429 rWS.UpTextLine = 0;
430 return true;
433 // ***************************************************************************
435 CShapeBank::TShapeState CShapeBank::getPresentState (const string &shapeNameNotLwr)
437 string shapeName= toLowerAscii(shapeNameNotLwr);
439 // Is the shape is found in the shape map so return Present
440 TShapeMap::iterator smIt = ShapeMap.find (shapeName);
441 if( smIt != ShapeMap.end() )
442 return Present;
443 // Look in the waiting shapes
444 TWaitingShapesMap::iterator wsmmIt = WaitingShapes.find (shapeName);
445 if (wsmmIt != WaitingShapes.end())
446 return wsmmIt->second.State; // AsyncLoad_*
447 return NotPresent;
450 // ***************************************************************************
451 IShape *CShapeBank::getShape (const std::string &shapeNameNotLwr)
453 string shapeName= toLowerAscii(shapeNameNotLwr);
455 // Is the shape is found in the shape map so return Present
456 TShapeMap::iterator smIt = ShapeMap.find (shapeName);
457 if( smIt != ShapeMap.end() )
458 return smIt->second;
460 return NULL;
463 // ***************************************************************************
465 void CShapeBank::load (const string &shapeNameNotLwr)
467 string shapeName= toLowerAscii(shapeNameNotLwr);
469 TShapeMap::iterator smIt = ShapeMap.find(shapeName);
470 if( smIt == ShapeMap.end() )
472 // If we are loading it asynchronously so we do not have to try to load it in sync mode
473 TWaitingShapesMap::iterator wsmmIt = WaitingShapes.find (shapeName);
474 if (wsmmIt != WaitingShapes.end())
475 return;
477 CShapeStream mesh;
478 CIFile meshfile;
479 if (meshfile.open(CPath::lookup(shapeName, false)))
481 meshfile.serial( mesh );
482 meshfile.close();
484 else
486 nlwarning ("CShapeBank::load() : Can't open file %s", shapeName.c_str());
489 if (mesh.getShapePointer() != NULL)
491 // Add the shape to the map.
492 add( shapeName, mesh.getShapePointer() );
497 // ***************************************************************************
499 void CShapeBank::loadAsync (const std::string &shapeNameNotLwr, IDriver *pDriver, const CVector &position, bool *bSignal, uint selectedTexture)
501 string shapeName= toLowerAscii(shapeNameNotLwr);
503 TShapeMap::iterator smIt = ShapeMap.find(shapeName);
504 if (smIt != ShapeMap.end())
505 return;
506 _pDriver = pDriver; // Backup the pointer to the driver for later use
507 TWaitingShapesMap::iterator wsmmIt = WaitingShapes.find (shapeName);
509 // First time this shape is loaded ?
510 bool firstTime = wsmmIt == WaitingShapes.end();
512 if (firstTime)
513 wsmmIt = WaitingShapes.insert (TWaitingShapesMap::value_type(shapeName, CWaitingShape())).first;
515 // Add a reference to it
516 CWaitingShape &rWS = wsmmIt->second;
518 // Insert a new signal pointer
519 rWS.Signal.insert (bSignal);
521 // Add a signal
522 rWS.RefCnt += 1;
524 // Launch an async mesh loader the first time
525 if (firstTime)
526 CAsyncFileManager3D::getInstance().loadMesh (shapeName, &(wsmmIt->second.ShapePtr), pDriver, position, selectedTexture);
529 // ***************************************************************************
531 void CShapeBank::cancelLoadAsync (const std::string &shapeNameNotLwr)
533 string shapeName= toLowerAscii(shapeNameNotLwr);
535 TWaitingShapesMap::iterator wsmmIt = WaitingShapes.find(shapeName);
536 if (wsmmIt != WaitingShapes.end())
538 wsmmIt->second.RefCnt -= 1;
539 if (wsmmIt->second.RefCnt == 0)
541 // nlinfo("unloadasync %s", shapeName);
542 CAsyncFileManager3D::getInstance().cancelLoadMesh (shapeName);
544 // If the state is not Delete, or Error, then the mesh has not been added to the map.
545 if(wsmmIt->second.State!=AsyncLoad_Delete && wsmmIt->second.State!=AsyncLoad_Error)
547 /* but it can still have been loaded:
548 - just ended in above cancelLoadMesh() because it was the current task
549 - ended in async far before this cancelLoadAsync() call, but processWaintingShape() still
550 not called on it
551 In this case we have to delete this shape, or even cancel texture upload!
552 NB: don't forget that the load can still be a fail too....
554 IShape *shape= wsmmIt->second.ShapePtr;
555 if(shape!=NULL && shape!=(IShape*)-1)
557 // this ptr should not be added to the map
558 nlassert(ShapePtrToShapeInfo.find(shape)==ShapePtrToShapeInfo.end());
560 // Before deleting this shape, we must ensure it is not currently uploading texture
561 if(wsmmIt->second.State==AsyncLoad_Texture)
563 /* if it was uploading a texture, then force him to end, else may have a bug
564 in this scenario (very improbable, but possible I think):
565 - a mesh is loaded asynchronously, and reference a texture "pipo.tga"
566 - mesh load async is ended, and the texture is not found in the driver
567 => texture generate()-d too
568 - mesh state is AsyncLoad_Texture, and begin (but doesn't end) to upload the texture
569 - another mesh is created syncrhonously using also this texture (thus
570 found in driver, and so just referencing it, no generate)
571 - the async mesh is then canceled, while the texture has not end to load!
572 - the texture is still in memory (the sync mesh still point to it), but with
573 partialy uploaded data!
575 // \todo yoyo: should be very rare, and don't know if really happens. must do tests
576 //forceEndUpLoadTexture(wsmmIt->second);
579 // then delete this shape
580 delete shape;
581 wsmmIt->second.ShapePtr= NULL;
585 // erase this waiting shape
586 WaitingShapes.erase (wsmmIt); // Delete the waiting shape
591 // ***************************************************************************
593 bool CShapeBank::isShapeWaiting ()
595 return !WaitingShapes.empty();
598 // ***************************************************************************
600 void CShapeBank::add (const string &shapeNameNotLwr, IShape* pShp)
602 nlassert(pShp);
603 string shapeName= toLowerAscii(shapeNameNotLwr);
605 // request a system mem geometry copy?
606 if(pShp && _ShapeNeedingSystemGeometryCopy.find(shapeName)!=_ShapeNeedingSystemGeometryCopy.end())
608 // make a copy of the geometry, in RAM
609 pShp->buildSystemGeometry();
612 // Is the shape name already used ?
613 TShapeMap::iterator smIt = ShapeMap.find( shapeName );
614 if( smIt == ShapeMap.end() )
616 // No ok so lets add the smart pointer
617 CSmartPtr<IShape> spShape = pShp;
618 ShapeMap[shapeName] = spShape;
620 // create the shape info
621 CShapeInfo siTemp;
622 siTemp.sShpName = shapeName;
623 siTemp.pShpCache = getShapeCachePtrFromShapeName( shapeName );
624 // Is the shape has a valid shape cache ?
625 if( siTemp.pShpCache == NULL )
627 // No -> link to default (which do the UpdateShapeInfo)
628 siTemp.pShpCache = getShapeCachePtrFromShapeCacheName( "default" );
629 // Add the shape to the default shape cache
630 ShapePtrToShapeInfo[pShp]= siTemp;
631 ShapeNameToShapeCacheName[shapeName]= "default";
633 else
635 // Yes -> add or replace the shape info
636 ShapePtrToShapeInfo[pShp] = siTemp;
641 // ***************************************************************************
643 void CShapeBank::addShapeCache(const string &shapeCacheName)
645 TShapeCacheMap::iterator scmIt = ShapeCacheNameToShapeCache.find( shapeCacheName );
646 if( scmIt == ShapeCacheNameToShapeCache.end() )
648 // Not found so add it
649 ShapeCacheNameToShapeCache.insert(TShapeCacheMap::value_type(shapeCacheName,CShapeCache()));
653 // ***************************************************************************
655 void CShapeBank::removeShapeCache(const std::string &shapeCacheName)
657 if( shapeCacheName == "default" )
658 return;
660 // Free the shape cache
661 CShapeCache *pShpCache = getShapeCachePtrFromShapeCacheName( shapeCacheName );
662 if( pShpCache == NULL )
663 return;
664 pShpCache->MaxSize = 0;
665 checkShapeCache( pShpCache );
667 // Remove it
668 ShapeCacheNameToShapeCache.erase( shapeCacheName );
670 // All links are redirected to the default cache
671 TShapeCacheNameMap::iterator scnIt = ShapeNameToShapeCacheName.begin();
672 while( scnIt != ShapeNameToShapeCacheName.end() )
674 if( scnIt->second == shapeCacheName )
675 scnIt->second = "default";
676 ++scnIt;
680 // ***************************************************************************
682 void CShapeBank::reset()
684 // Parse map ShapeCacheNameToShapeCache to delete all caches
685 TShapeCacheMap::iterator scmIt = ShapeCacheNameToShapeCache.begin();
686 while( scmIt != ShapeCacheNameToShapeCache.end() )
688 CShapeCache *pShpCache = getShapeCachePtrFromShapeCacheName( scmIt->first );
689 nlassert(pShpCache);
690 pShpCache->MaxSize = 0;
691 checkShapeCache( pShpCache );
693 ++scmIt;
695 ShapeNameToShapeCacheName.clear();
696 ShapeCacheNameToShapeCache.clear();
697 addShapeCache( "default" );
700 // ***************************************************************************
702 void CShapeBank::setShapeCacheSize(const string &shapeCacheName, sint32 maxSize)
704 TShapeCacheMap::iterator scmIt = ShapeCacheNameToShapeCache.find( shapeCacheName );
705 if( scmIt != ShapeCacheNameToShapeCache.end() )
707 scmIt->second.MaxSize = maxSize;
708 checkShapeCache(getShapeCachePtrFromShapeCacheName(shapeCacheName));
712 // ***************************************************************************
713 sint CShapeBank::getShapeCacheFreeSpace(const std::string &shapeCacheName) const
715 TShapeCacheMap::const_iterator scmIt = ShapeCacheNameToShapeCache.find( shapeCacheName );
716 if( scmIt != ShapeCacheNameToShapeCache.end() )
718 return scmIt->second.MaxSize - (sint)scmIt->second.Elements.size();
720 return 0;
723 // ***************************************************************************
725 void CShapeBank::linkShapeToShapeCache(const string &shapeNameNotLwr, const string &shapeCacheName)
727 string shapeName= toLowerAscii(shapeNameNotLwr);
729 for(;;)
731 // Shape exist?
732 IShape *shapePtr= getShapePtrFromShapeName(shapeName);
733 if(shapePtr == NULL)
734 // No, but still link the shape name to the shapeCache name.
735 break;
736 // Is the shape cache exist ?
737 CShapeCache *shapeCachePtr = getShapeCachePtrFromShapeCacheName( shapeCacheName );
738 if( shapeCachePtr == NULL )
739 // abort, since cannot correctly link to a valid shapeCache
740 return;
742 // Try to set to the same shape Cache as before?
743 CShapeInfo &shapeInfo= ShapePtrToShapeInfo[shapePtr];
744 if( shapeCachePtr == shapeInfo.pShpCache)
745 // abort, since same cache name / cache ptr
746 return;
748 // If The shape is In the cache of another Shape Cache, abort.
749 if( shapeInfo.isAdded )
750 // Abort, because impossible.
751 return;
753 // Is the shape is present ?
754 // Yes -> Update the ShapeInfo
755 shapeInfo.pShpCache= shapeCachePtr;
757 break;
760 // change the cache name of the shape
761 ShapeNameToShapeCacheName[shapeName] = shapeCacheName;
764 // ***************************************************************************
766 CShapeBank::CShapeCache* CShapeBank::getShapeCachePtrFromShapePtr(IShape* pShp)
768 TShapeInfoMap::iterator scfpmIt = ShapePtrToShapeInfo.find( pShp );
769 if( scfpmIt != ShapePtrToShapeInfo.end() )
771 return scfpmIt->second.pShpCache;
773 return NULL;
776 // ***************************************************************************
778 IShape* CShapeBank::getShapePtrFromShapeName(const std::string &pShpName)
780 TShapeMap::iterator smIt = ShapeMap.find(pShpName);
781 if( smIt != ShapeMap.end() )
783 // TMP
784 IShape *ptr = (IShape*)(smIt->second);
785 return ptr;
787 return NULL;
790 // ***************************************************************************
792 CShapeBank::CShapeCache* CShapeBank::getShapeCachePtrFromShapeCacheName(const string &shapeCacheName)
794 TShapeCacheMap::iterator scmIt = ShapeCacheNameToShapeCache.find( shapeCacheName );
795 if( scmIt != ShapeCacheNameToShapeCache.end())
797 return &(scmIt->second);
799 return NULL;
802 // ***************************************************************************
804 const string* CShapeBank::getShapeNameFromShapePtr(IShape* pShp) const
806 TShapeInfoMap::const_iterator scfpmIt = ShapePtrToShapeInfo.find( pShp );
807 if( scfpmIt != ShapePtrToShapeInfo.end() )
809 return &(scfpmIt->second.sShpName);
811 return NULL;
814 // ***************************************************************************
816 CShapeBank::CShapeCache* CShapeBank::getShapeCachePtrFromShapeName(const std::string &shapeName)
818 TShapeCacheNameMap::iterator scnIt = ShapeNameToShapeCacheName.find( shapeName );
819 if( scnIt != ShapeNameToShapeCacheName.end() )
821 return getShapeCachePtrFromShapeCacheName(scnIt->second);
823 return NULL;
826 // ***************************************************************************
828 void CShapeBank::checkShapeCache(CShapeCache* pShpCache)
830 if( pShpCache != NULL )
831 while( (sint)pShpCache->Elements.size() > pShpCache->MaxSize )
833 // Suppress the last shape of the cache
834 IShape *pShp = pShpCache->Elements.back();
835 // Physical suppression because we own the last smart pointer on the shape
836 ShapeMap.erase(*getShapeNameFromShapePtr(pShp));
837 // delete information associated with the shape
838 ShapePtrToShapeInfo.erase( pShp );
839 // remove from queue
840 pShpCache->Elements.pop_back();
845 // ***************************************************************************
846 bool CShapeBank::isShapeCache(const std::string &shapeCacheName) const
848 return ShapeCacheNameToShapeCache.find(shapeCacheName) != ShapeCacheNameToShapeCache.end();
851 // ***************************************************************************
852 void CShapeBank::preLoadShapes(const std::string &shapeCacheName,
853 const std::vector<std::string> &listFile, const std::string &wildCardNotLwr, NLMISC::IProgressCallback *progress, bool flushTextures /*= false*/, IDriver *drv /*= NULL*/)
855 // Abort if cache don't exist.
856 if(!isShapeCache(shapeCacheName))
857 return;
859 // lower case
860 string wildCard= toLowerAscii(wildCardNotLwr);
862 // For all files
863 for(uint i=0;i<listFile.size();i++)
865 // Progress bar
866 if (progress)
867 progress->progress ((float)i/(float)listFile.size ());
869 string fileName= toLowerAscii(CFile::getFilename(listFile[i]));
870 // if the file is ok for the wildCard, process it
871 if( testWildCard(fileName.c_str(), wildCard.c_str()) )
873 // link the shape to the shapeCache
874 linkShapeToShapeCache(fileName, shapeCacheName);
876 // If !present in the shapeBank
877 if( getPresentState(fileName)==CShapeBank::NotPresent )
879 // Don't load it if no more space in the cache
880 if( getShapeCacheFreeSpace(shapeCacheName)>0 )
882 // load it.
883 load(fileName);
885 // If success
886 if( getPresentState(fileName)==CShapeBank::Present )
888 // When a shape is first added to the bank, it is not in the cache.
889 // add it and release it to force it to be in the cache.
890 IShape *shp= addRef(fileName);
891 if(shp)
893 //nlinfo("Loading %s", CPath::lookup(fileName.c_str(), false, false).c_str());
894 if (flushTextures && drv)
896 shp->flushTextures(*drv, 0);
898 release(shp);
908 // ***************************************************************************
909 void CShapeBank::buildSystemGeometryForshape(const std::string &shapeName)
911 _ShapeNeedingSystemGeometryCopy.insert(toLowerAscii(shapeName));