1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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"
31 using namespace NLMISC
;
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
);
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
);
99 nlwarning ("Trying to release a mesh that have not be added to the shape bank");
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
));
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
;
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
147 case AsyncLoad_Shape
: // Check if we can pass to the AsyncLoad_Texture state
150 if (pShp
== (IShape
*)-1)
151 rWS
.State
= AsyncLoad_Error
;
153 rWS
.State
= AsyncLoad_Texture
;
157 case AsyncLoad_Texture
:
159 // Setup all textures and lightmaps of the shape
160 if (nTotalUploaded
> _MaxUploadPerFrame
)
163 CMeshBase
*pMesh
= dynamic_cast<CMeshBase
*>(pShp
);
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
)))
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
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())
212 ++rWS
.UpTextProgress
;
215 if (nTotalUploaded
> _MaxUploadPerFrame
)
219 if (nTotalUploaded
> _MaxUploadPerFrame
)
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
))
240 // see above for explanation
241 if(pText
->getReleasable())
245 ++rWS
.UpTextProgress
;
248 ++j
; pText
= rMat
.getLightMap (j
);
249 if (nTotalUploaded
> _MaxUploadPerFrame
)
253 if (nTotalUploaded
> _MaxUploadPerFrame
)
257 if (nTotalUploaded
> _MaxUploadPerFrame
)
260 rWS
.State
= AsyncLoad_Ready
;
264 case AsyncLoad_Ready
:
265 add (wsmmIt
->first
, pShp
);
266 rWS
.State
= AsyncLoad_Delete
;
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
:
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
;
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
)
303 if (ite2
!= wsmmIt2
->second
.Signal
.end())
315 WaitingShapes
.erase (wsmmIt
);
320 nlstop
; // This must never happen
328 // ***************************************************************************
329 void CShapeBank::setMaxBytesToUpload (uint32 MaxUploadPerFrame
)
331 _MaxUploadPerFrame
= MaxUploadPerFrame
;
334 // ***************************************************************************
335 bool CShapeBank::processWSUploadTexture (CWaitingShape
&rWS
, uint32
&nTotalUploaded
, ITexture
*pText
)
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
);
352 if (pText
->mipMapOn())
353 nMipMap
= pText
->getMipMapCount();
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())
368 // NB: nWeight can be 0 in case of 1x1 in DXTC1. Estimate 1 byte
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)
381 if (pText
->isTextureCube())
383 // compute the number of lines we'll upload
384 uint32 nNbLineToUpload
= nSizeToUpload
/ nLineWeight
;
385 nNbLineToUpload
= nNbLineToUpload
/ 4;
386 if (nNbLineToUpload
== 0)
388 nNbLineToUpload
*= 4; // Upload 4 line by 4 line
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
))
398 rWS
.UpTextMipMap
+= 1;
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
));
406 rWS
.UpTextMipMap
+= 1;
410 if (pText
->isTextureCube())
412 for (nFace
= 0; nFace
< 6; ++nFace
)
413 _pDriver
->uploadTextureCube (*pText
, zeRect
, (uint8
)nMM
, (uint8
)nFace
);
417 _pDriver
->uploadTexture (*pText
, zeRect
, (uint8
)nMM
);
420 nTotalUploaded
+= nWeight
;
421 if (nTotalUploaded
> _MaxUploadPerFrame
)
425 if (pText
->getReleasable())
428 rWS
.UpTextMipMap
= 0;
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() )
443 // Look in the waiting shapes
444 TWaitingShapesMap::iterator wsmmIt
= WaitingShapes
.find (shapeName
);
445 if (wsmmIt
!= WaitingShapes
.end())
446 return wsmmIt
->second
.State
; // AsyncLoad_*
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() )
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())
479 if (meshfile
.open(CPath::lookup(shapeName
, false)))
481 meshfile
.serial( mesh
);
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())
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();
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
);
524 // Launch an async mesh loader the first time
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
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
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
)
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
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";
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" )
660 // Free the shape cache
661 CShapeCache
*pShpCache
= getShapeCachePtrFromShapeCacheName( shapeCacheName
);
662 if( pShpCache
== NULL
)
664 pShpCache
->MaxSize
= 0;
665 checkShapeCache( pShpCache
);
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";
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
);
690 pShpCache
->MaxSize
= 0;
691 checkShapeCache( pShpCache
);
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();
723 // ***************************************************************************
725 void CShapeBank::linkShapeToShapeCache(const string
&shapeNameNotLwr
, const string
&shapeCacheName
)
727 string shapeName
= toLowerAscii(shapeNameNotLwr
);
732 IShape
*shapePtr
= getShapePtrFromShapeName(shapeName
);
734 // No, but still link the shape name to the shapeCache name.
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
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
748 // If The shape is In the cache of another Shape Cache, abort.
749 if( shapeInfo
.isAdded
)
750 // Abort, because impossible.
753 // Is the shape is present ?
754 // Yes -> Update the ShapeInfo
755 shapeInfo
.pShpCache
= shapeCachePtr
;
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
;
776 // ***************************************************************************
778 IShape
* CShapeBank::getShapePtrFromShapeName(const std::string
&pShpName
)
780 TShapeMap::iterator smIt
= ShapeMap
.find(pShpName
);
781 if( smIt
!= ShapeMap
.end() )
784 IShape
*ptr
= (IShape
*)(smIt
->second
);
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
);
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
);
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
);
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
);
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
))
860 string wildCard
= toLowerAscii(wildCardNotLwr
);
863 for(uint i
=0;i
<listFile
.size();i
++)
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 )
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
);
893 //nlinfo("Loading %s", CPath::lookup(fileName.c_str(), false, false).c_str());
894 if (flushTextures
&& drv
)
896 shp
->flushTextures(*drv
, 0);
908 // ***************************************************************************
909 void CShapeBank::buildSystemGeometryForshape(const std::string
&shapeName
)
911 _ShapeNeedingSystemGeometryCopy
.insert(toLowerAscii(shapeName
));