22#define GLM_FORCE_RADIANS
27#include <wx/datetime.h>
30#include <wx/stdpaths.h>
51#define MASK_3D_CACHE "3D_CACHE"
56static bool checkTag(
const char* aTag,
void* aPluginMgrPtr )
58 if(
nullptr == aTag ||
nullptr == aPluginMgrPtr )
142 std::vector<const EMBEDDED_FILES*> aEmbeddedFilesStack )
145 *aCachePtr =
nullptr;
147 wxString full3Dpath =
m_FNResolver->ResolvePath( aModelFile, aBasePath, std::move( aEmbeddedFilesStack ) );
149 if( full3Dpath.empty() )
162 const wxString projectPath =
170 if( !subst.IsEmpty() )
173 wxT(
"%s:%s:%d\n * [3D model] substituting '%s' -> '%s'\n" ),
174 __FILE__, __FUNCTION__, __LINE__, aModelFile, subst );
179 if( full3Dpath.empty() )
182 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * [3D model] could not find model '%s'\n" ),
183 __FILE__, __FUNCTION__, __LINE__, aModelFile );
191 std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
196 wxFileName fname( full3Dpath );
198 if( fname.FileExists() )
201 wxDateTime fmdate = fname.GetModificationTime();
203 if( fmdate != mi->second->modTime )
206 getHash( full3Dpath, hashSum );
207 mi->second->modTime = fmdate;
209 if( hashSum != mi->second->m_hash )
211 mi->second->SetHash( hashSum );
218 if(
nullptr != mi->second->sceneData )
221 mi->second->sceneData =
nullptr;
224 if(
nullptr != mi->second->renderData )
227 mi->second->sceneData =
m_Plugins->Load3DModel( full3Dpath,
228 mi->second->pluginInfo );
232 if(
nullptr != aCachePtr )
233 *aCachePtr = mi->second;
235 return mi->second->sceneData;
244 std::vector<const EMBEDDED_FILES*> aEmbeddedFilesStack )
246 return load( aModelFile, aBasePath,
nullptr, std::move( aEmbeddedFilesStack ) );
253 *aCachePtr =
nullptr;
258 wxFileName fname( aFileName );
259 ep->
modTime = fname.GetModificationTime();
267 if(
m_CacheMap.emplace( aFileName, ep ).second ==
false )
270 wxT(
"%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
271 __FILE__, __FUNCTION__, __LINE__, aFileName );
285 if(
m_CacheMap.emplace( aFileName, ep ).second ==
false )
288 wxT(
"%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'" ),
289 __FILE__, __FUNCTION__, __LINE__, aFileName );
302 wxString cachename =
m_CacheDir + bname + wxT(
".3dc" );
319 if( aFileName.empty() )
321 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * [BUG] empty filename" ),
322 __FILE__, __FUNCTION__, __LINE__ );
328 FILE* fp = _wfopen( aFileName.wc_str(),
L"rb" );
330 FILE* fp = fopen( aFileName.ToUTF8(),
"rb" );
337 std::vector<char> block( 4096 );
340 while( ( bsize = fread( block.data(), 1, 4096, fp ) ) > 0 )
356 wxT(
" * [3D model] cannot load cached model; no file hash available" ) );
364 wxT(
" * [3D model] cannot load cached model; config directory unknown" ) );
369 wxString fname =
m_CacheDir + bname + wxT(
".3dc" );
371 if( !wxFileName::FileExists( fname ) )
373 wxLogTrace(
MASK_3D_CACHE, wxT(
" * [3D model] cannot open file '%s'" ), fname.GetData() );
391 if(
nullptr == aCacheItem )
393 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * NULL passed for aCacheItem" ),
394 __FILE__, __FUNCTION__, __LINE__ );
401 wxLogTrace(
MASK_3D_CACHE, wxT(
"%s:%s:%d\n * aCacheItem has no valid scene data" ),
402 __FILE__, __FUNCTION__, __LINE__ );
412 wxT(
" * [3D model] cannot load cached model; no file hash available" ) );
420 wxT(
" * [3D model] cannot load cached model; config directory unknown" ) );
425 wxString fname =
m_CacheDir + bname + wxT(
".3dc" );
427 if( wxFileName::Exists( fname ) )
429 if( !wxFileName::FileExists( fname ) )
432 wxT(
" * [3D model] path exists but is not a regular file '%s'" ), fname );
452 if( !cfgdir.DirExists() )
454 cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
456 if( !cfgdir.DirExists() )
459 wxT(
"%s:%s:%d\n * failed to create 3D configuration directory '%s'" ),
460 __FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
472 wxT(
"%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n"
473 " * config directory: '%s'" ),
486 cacheDir.AppendDir( wxT(
"3d" ) );
488 if( !cacheDir.DirExists() )
490 cacheDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
492 if( !cacheDir.DirExists() )
495 wxT(
"%s:%s:%d\n * failed to create 3D cache directory '%s'" ),
496 __FILE__, __FUNCTION__, __LINE__, cacheDir.GetPath() );
511 bool hasChanged =
false;
513 if(
m_FNResolver->SetProject( aProject, &hasChanged ) && hasChanged )
517 std::list< S3D_CACHE_ENTRY* >::iterator sL =
m_CacheList.begin();
518 std::list< S3D_CACHE_ENTRY* >::iterator eL =
m_CacheList.end();
555 std::list< S3D_CACHE_ENTRY* >::iterator sCL =
m_CacheList.begin();
556 std::list< S3D_CACHE_ENTRY* >::iterator eCL =
m_CacheList.end();
580 std::vector<const EMBEDDED_FILES*> aEmbeddedFilesStack )
583 SCENEGRAPH* sp =
load( aModelFileName, aBasePath, &cp, std::move( aEmbeddedFilesStack ) );
591 wxT(
"%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY" ),
592 __FILE__, __FUNCTION__, __LINE__ );
609 wxString fileSpec = wxT(
"*.3dc" );
610 wxArrayString fileList;
611 size_t numFilesFound = 0;
614 wxDateTime lastAccess, thresholdDate;
615 wxDateSpan durationInDays;
618 durationInDays.SetDays( aNumDaysOld );
619 thresholdDate = wxDateTime::Now() - durationInDays;
627 numFilesFound = dir.GetAllFiles(
m_CacheDir, &fileList, fileSpec );
629 for(
unsigned int i = 0; i < numFilesFound; i++ )
632 thisFile.SetFullName( fileList[i] );
635 if( thisFile.GetTimes( &lastAccess,
nullptr,
nullptr ) )
637 if( lastAccess.IsEarlierThan( thresholdDate ) )
640 wxRemoveFile( thisFile.GetFullPath() );
static std::mutex mutex3D_cache
static bool checkTag(const char *aTag, void *aPluginMgrPtr)
defines the basic data associated with a single 3D model.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Provide an extensible class to resolve 3D model paths.
A streaming C++ equivalent for MurmurHash3_x64_128.
FORCE_INLINE void add(const std::string &input)
FORCE_INLINE HASH_128 digest()
static wxString GetUserCachePath()
Gets the stock (install) 3d viewer plugins path.
Container for data for KiCad programs.
Container for project specific data.
S3D_CACHE_ENTRY & operator=(const S3D_CACHE_ENTRY &source)
S3D_CACHE_ENTRY(const S3D_CACHE_ENTRY &source)
void SetHash(const HASH_128 &aHash)
const wxString GetCacheBaseName()
void SetProgramBase(PGM_BASE *aBase)
Set the filename resolver's pointer to the application's PGM_BASE instance.
bool loadCacheData(S3D_CACHE_ENTRY *aCacheItem)
void FlushCache(bool closePlugins=true)
Free all data in the cache and by default closes all plugins.
bool Set3DConfigDir(const wxString &aConfigDir)
Set the configuration directory to be used by the model manager for storing 3D model manager configur...
S3DMODEL * GetModel(const wxString &aModelFileName, const wxString &aBasePath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
SCENEGRAPH * checkCache(const wxString &aFileName, S3D_CACHE_ENTRY **aCachePtr=nullptr)
Find or create cache entry for file name.
MODEL_SUBSTITUTION::STEP_CATALOG m_substCatalog
S3D_PLUGIN_MANAGER * m_Plugins
bool saveCacheData(S3D_CACHE_ENTRY *aCacheItem)
SCENEGRAPH * load(const wxString &aModelFile, const wxString &aBasePath, S3D_CACHE_ENTRY **aCachePtr=nullptr, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack={})
wxString m_ConfigDir
base configuration path for 3D items.
std::mutex m_substCatalogMutex
Lazy STEP-catalog used by the headless resolver fallback in load().
std::list< wxString > const * GetFileFilters() const
Return the list of file filters retrieved from the plugins.
FILENAME_RESOLVER * GetResolver() noexcept
std::list< S3D_CACHE_ENTRY * > m_CacheList
Cache entries.
bool SetProject(PROJECT *aProject)
Set the current project's working directory; this affects the model search path.
void CleanCacheDir(int aNumDaysOld)
Delete up old cache files in cache directory.
std::map< wxString, S3D_CACHE_ENTRY *, rsort_wxString > m_CacheMap
Mapping of file names to cache names and data.
SCENEGRAPH * Load(const wxString &aModelFile, const wxString &aBasePath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Attempt to load the scene data for a model.
void ClosePlugins()
Unload plugins to free memory.
bool getHash(const wxString &aFileName, HASH_128 &aHash)
Calculate the SHA1 hash of the given file.
FILENAME_RESOLVER * m_FNResolver
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...
Define the basic data set required to represent a 3D model.
The base class of all Scene Graph nodes.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
bool m_Skip3DModelMemoryCache
Skip reading/writing 3D model memory caches.
defines the API calls for the manipulation of SG* classes
bool IsWrlExtension(const wxString &aFilename)
True iff aFilename ends in .wrl or .wrz (case-insensitive).
SGLIB_API SGNODE * ReadCache(const char *aFileName, void *aPluginMgr, bool(*aTagCheck)(const char *, void *))
Read a binary cache file and creates an SGNODE tree.
SGLIB_API bool WriteCache(const char *aFileName, bool overwrite, SGNODE *aNode, const char *aPluginInfo)
Write the SGNODE tree to a binary cache file.
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Delete the given SG* class node.
SGLIB_API S3DMODEL * GetModel(SCENEGRAPH *aNode)
Create an S3DMODEL representation of aNode (raw data, no transforms).
SGLIB_API void Destroy3DModel(S3DMODEL **aModel)
Free memory used by an S3DMODEL structure and sets the pointer to the structure to NULL.
PGM_BASE & Pgm()
The global program "get" accessor.
A storage class for 128-bit hash value.
Store the a model based on meshes and materials.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().