25 #define GLM_FORCE_RADIANS 30 #include <wx/datetime.h> 32 #include <wx/filename.h> 34 #include <wx/stdpaths.h> 36 #include <boost/version.hpp> 38 #if BOOST_VERSION >= 106800 39 #include <boost/uuid/detail/sha1.hpp> 41 #include <boost/uuid/sha1.hpp> 60 #define MASK_3D_CACHE "3D_CACHE" 66 static bool isSHA1Same(
const unsigned char* shaA,
const unsigned char* shaB ) noexcept
68 for(
int i = 0; i < 20; ++i )
70 if( shaA[i] != shaB[i] )
78 static bool checkTag(
const char* aTag,
void* aPluginMgrPtr )
80 if(
nullptr == aTag ||
nullptr == aPluginMgrPtr )
96 for(
int i = 0; i < 20; ++i )
119 return wxString::FromUTF8Unchecked( sha1 );
129 void SetSHA1(
const unsigned char* aSHA1Sum );
166 if(
nullptr == aSHA1Sum )
168 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * [BUG] NULL passed for aSHA1Sum" ),
169 __FILE__, __FUNCTION__, __LINE__ );
174 memcpy(
sha1sum, aSHA1Sum, 20 );
206 if( clearCacheInterval > 0 )
217 *aCachePtr =
nullptr;
221 if( full3Dpath.empty() )
224 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * [3D model] could not find model '%s'\n" ),
225 __FILE__, __FUNCTION__, __LINE__, aModelFile );
232 std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
237 wxFileName fname( full3Dpath );
239 if( fname.FileExists() )
242 wxDateTime fmdate = fname.GetModificationTime();
244 if( fmdate != mi->second->modTime )
246 unsigned char hashSum[20];
247 getSHA1( full3Dpath, hashSum );
248 mi->second->modTime = fmdate;
250 if( !
isSHA1Same( hashSum, mi->second->sha1sum ) )
252 mi->second->SetSHA1( hashSum );
259 if(
nullptr != mi->second->sceneData )
262 mi->second->sceneData =
nullptr;
265 if(
nullptr != mi->second->renderData )
269 mi->second->pluginInfo );
273 if(
nullptr != aCachePtr )
274 *aCachePtr = mi->second;
286 return load( aModelFile );
293 *aCachePtr =
nullptr;
295 unsigned char sha1sum[20];
298 wxFileName fname( aFileName );
299 ep->
modTime = fname.GetModificationTime();
307 if(
m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
308 ( aFileName, ep ) ).second == false )
311 wxT(
"%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
312 __FILE__, __FUNCTION__, __LINE__, aFileName );
326 if(
m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
327 ( aFileName, ep ) ).second == false )
330 wxT(
"%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
331 __FILE__, __FUNCTION__, __LINE__, aFileName );
344 wxString cachename =
m_CacheDir + bname + wxT(
".3dc" );
361 if( aFileName.empty() )
363 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * [BUG] empty filename" ),
364 __FILE__, __FUNCTION__, __LINE__ );
369 if(
nullptr == aSHA1Sum )
371 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s\n * [BUG] NULL pointer passed for aMD5Sum" ),
372 __FILE__, __FUNCTION__, __LINE__ );
378 FILE* fp = _wfopen( aFileName.wc_str(), L
"rb" );
380 FILE* fp = fopen( aFileName.ToUTF8(),
"rb" );
386 boost::uuids::detail::sha1 dblock;
387 unsigned char block[4096];
390 while( ( bsize = fread( &block, 1, 4096, fp ) ) > 0 )
391 dblock.process_bytes( block, bsize );
394 unsigned int digest[5];
395 dblock.get_digest( digest );
398 for(
int i = 0; i < 5; ++i )
401 unsigned int tmp = digest[i];
402 aSHA1Sum[idx+3] = tmp & 0xff;
404 aSHA1Sum[idx+2] = tmp & 0xff;
406 aSHA1Sum[idx+1] = tmp & 0xff;
408 aSHA1Sum[idx] = tmp & 0xff;
422 wxT(
" * [3D model] cannot load cached model; no file hash available" ) );
430 wxT(
" * [3D model] cannot load cached model; config directory unknown" ) );
435 wxString fname =
m_CacheDir + bname + wxT(
".3dc" );
437 if( !wxFileName::FileExists( fname ) )
439 wxLogTrace(
MASK_3D_CACHE, wxT(
" * [3D model] cannot open file '%s'" ), fname.GetData() );
457 if(
nullptr == aCacheItem )
459 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * NULL passed for aCacheItem" ),
460 __FILE__, __FUNCTION__, __LINE__ );
467 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * aCacheItem has no valid scene data" ),
468 __FILE__, __FUNCTION__, __LINE__ );
478 wxT(
" * [3D model] cannot load cached model; no file hash available" ) );
486 wxT(
" * [3D model] cannot load cached model; config directory unknown" ) );
491 wxString fname =
m_CacheDir + bname + wxT(
".3dc" );
493 if( wxFileName::Exists( fname ) )
495 if( !wxFileName::FileExists( fname ) )
498 wxT(
" * [3D model] path exists but is not a regular file '%s'" ), fname );
518 if( !cfgdir.DirExists() )
520 cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
522 if( !cfgdir.DirExists() )
525 wxT(
"%s:%s:%d\n * failed to create 3D configuration directory '%s'" ),
526 __FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
538 wxT(
"%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n" 539 " * config directory: '%s'" ),
552 cacheDir.AppendDir( wxT(
"3d" ) );
554 if( !cacheDir.DirExists() )
556 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
558 if( !cacheDir.DirExists() )
561 wxT(
"%s:%s:%d\n * failed to create 3D cache directory '%s'" ),
562 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
577 bool hasChanged =
false;
583 std::list< S3D_CACHE_ENTRY* >::iterator sL =
m_CacheList.begin();
584 std::list< S3D_CACHE_ENTRY* >::iterator eL =
m_CacheList.end();
621 std::list< S3D_CACHE_ENTRY* >::iterator sCL =
m_CacheList.begin();
622 std::list< S3D_CACHE_ENTRY* >::iterator eCL =
m_CacheList.end();
656 wxT(
"%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY" ),
657 __FILE__, __FUNCTION__, __LINE__ );
674 wxString fileSpec = wxT(
"*.3dc" );
675 wxArrayString fileList;
676 size_t numFilesFound = 0;
679 wxDateTime lastAccess, thresholdDate;
680 wxDateSpan durationInDays;
683 durationInDays.SetDays( aNumDaysOld );
684 thresholdDate = wxDateTime::Now() - durationInDays;
692 numFilesFound = dir.GetAllFiles(
m_CacheDir, &fileList, fileSpec );
694 for(
unsigned int i = 0; i < numFilesFound; i++ )
697 thisFile.SetFullName( fileList[i] );
700 if( thisFile.GetTimes( &lastAccess,
nullptr,
nullptr ) )
702 if( lastAccess.IsEarlierThan( thresholdDate ) )
705 wxRemoveFile( thisFile.GetFullPath() );
713 S3D_CACHE* PROJECT::Get3DCacheManager(
bool aUpdateProjDir )
727 cfgpath.AppendDir( wxT(
"3d" ) );
733 aUpdateProjDir =
true;
745 return Get3DCacheManager()->GetResolver();
static const wxString sha1ToWXString(const unsigned char *aSHA1Sum)
Container for project specific data.
SGLIB_API SGNODE * ReadCache(const char *aFileName, void *aPluginMgr, bool(*aTagCheck)(const char *, void *))
Function ReadCache reads a binary cache file and creates an SGNODE tree.
Container for data for KiCad programs.
std::list< wxString > const * GetFileFilters() const
Return the list of file filters retrieved from the plugins.
static std::mutex mutex3D_cache
void SetProgramBase(PGM_BASE *aBase)
Set the filename resolver's pointer to the application's PGM_BASE instance.
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
SGLIB_API void Destroy3DModel(S3DMODEL **aModel)
Function Destroy3DModel frees memory used by an S3DMODEL structure and sets the pointer to the struct...
std::map< wxString, S3D_CACHE_ENTRY *, rsort_wxString > m_CacheMap
mapping of file names to cache names and data
virtual _ELEM * GetElem(ELEM_T aIndex)
Get and set the elements for this project.
SCENEGRAPH * checkCache(const wxString &aFileName, S3D_CACHE_ENTRY **aCachePtr=nullptr)
Find or create cache entry for file name.
bool loadCacheData(S3D_CACHE_ENTRY *aCacheItem)
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
The base class of all Scene Graph nodes.
Cache for storing the 3D shapes.
SCENEGRAPH * Load3DModel(const wxString &aFileName, std::string &aPluginInfo)
const wxString GetCacheBaseName()
defines the basic data associated with a single 3D model.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
S3D_CACHE_ENTRY & operator=(const S3D_CACHE_ENTRY &source)
FILENAME_RESOLVER * m_FNResolver
S3DMODEL * GetModel(const wxString &aModelFileName)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
bool saveCacheData(S3D_CACHE_ENTRY *aCacheItem)
static std::mutex mutex3D_cacheManager
void FlushCache(bool closePlugins=true)
Free all data in the cache and by default closes all plugins.
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Function DestroyNode deletes the given SG* class node.
int clear_3d_cache_interval
void SetSHA1(const unsigned char *aSHA1Sum)
static bool checkTag(const char *aTag, void *aPluginMgrPtr)
void ClosePlugins()
Unload plugins to free memory.
void CleanCacheDir(int aNumDaysOld)
Delete up old cache files in cache directory.
bool getSHA1(const wxString &aFileName, unsigned char *aSHA1Sum)
Calculate the SHA1 hash of the given file.
bool m_Skip3DModelMemoryCache
Skip reading/writing 3d model memory caches This ensures 3d models are always reloaded from disk even...
defines the API calls for the manipulation of SG* classes
bool CheckTag(const char *aTag)
Check the given tag and returns true if the plugin named in the tag is not loaded or the plugin is lo...
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
wxString ResolvePath(const wxString &aFileName)
Determines the full path of the given file name.
std::list< S3D_CACHE_ENTRY * > m_CacheList
cache entries
std::list< wxString > const * GetFileFilters(void) const noexcept
Return the list of file filters; this will contain at least the default "All Files (*....
Provide an extensible class to resolve 3D model paths.
bool Set3DConfigDir(const wxString &aConfigDir)
Sets the configuration directory to be used by the model manager for storing 3D model manager configu...
FILENAME_RESOLVER * GetResolver() noexcept
bool SetProject(PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
bool SetProject(PROJECT *aProject)
Set the current project's working directory; this affects the model search path.
void ClosePlugins(void)
Iterate through all discovered plugins and closes them to reclaim memory.
bool Set3DConfigDir(const wxString &aConfigDir)
Set the user's configuration directory for 3D models.
Define the basic data set required to represent a 3D model.
SGLIB_API bool WriteCache(const char *aFileName, bool overwrite, SGNODE *aNode, const char *aPluginInfo)
Function WriteCache writes the SGNODE tree to a binary cache file.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
unsigned char sha1sum[20]
Store the a model based on meshes and materials.
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
SCENEGRAPH * Load(const wxString &aModelFile)
Attempt to load the scene data for a model.
SGLIB_API S3DMODEL * GetModel(SCENEGRAPH *aNode)
Function GetModel creates an S3DMODEL representation of aNode (raw data, no transforms)
SCENEGRAPH * load(const wxString &aModelFile, S3D_CACHE_ENTRY **aCachePtr=nullptr)
S3D_PLUGIN_MANAGER * m_Plugins
static bool isSHA1Same(const unsigned char *shaA, const unsigned char *shaB) noexcept