KiCad PCB EDA Suite
3d_cache.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
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 General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #define GLM_FORCE_RADIANS
26 
27 #include <fstream>
28 #include <iostream>
29 #include <iterator>
30 #include <mutex>
31 #include <sstream>
32 #include <utility>
33 
34 #include <wx/datetime.h>
35 #include <wx/filename.h>
36 #include <wx/log.h>
37 #include <wx/stdpaths.h>
38 
39 #include <boost/version.hpp>
40 
41 #if BOOST_VERSION >= 106800
42 #include <boost/uuid/detail/sha1.hpp>
43 #else
44 #include <boost/uuid/sha1.hpp>
45 #endif
46 
47 #include <glm/glm.hpp>
48 #include <glm/ext.hpp>
49 
50 #include "3d_cache.h"
51 #include "3d_info.h"
52 #include "3d_plugin_manager.h"
53 #include "sg/scenegraph.h"
54 #include "plugins/3dapi/ifsg_api.h"
55 
56 #include <common.h>
57 #include <filename_resolver.h>
58 #include <pgm_base.h>
59 #include <project.h>
60 
61 
62 #define MASK_3D_CACHE "3D_CACHE"
63 
64 static std::mutex mutex3D_cache;
65 static std::mutex mutex3D_cacheManager;
66 
67 
68 static bool isSHA1Same( const unsigned char* shaA, const unsigned char* shaB )
69 {
70  for( int i = 0; i < 20; ++i )
71  if( shaA[i] != shaB[i] )
72  return false;
73 
74  return true;
75 }
76 
77 
78 static bool checkTag( const char* aTag, void* aPluginMgrPtr )
79 {
80  if( NULL == aTag || NULL == aPluginMgrPtr )
81  return false;
82 
83  S3D_PLUGIN_MANAGER *pp = (S3D_PLUGIN_MANAGER*) aPluginMgrPtr;
84 
85  return pp->CheckTag( aTag );
86 }
87 
88 
89 static const wxString sha1ToWXString( const unsigned char* aSHA1Sum )
90 {
91  unsigned char uc;
92  unsigned char tmp;
93  char sha1[41];
94  int j = 0;
95 
96  for( int i = 0; i < 20; ++i )
97  {
98  uc = aSHA1Sum[i];
99  tmp = uc / 16;
100 
101  if( tmp > 9 )
102  tmp += 87;
103  else
104  tmp += 48;
105 
106  sha1[j++] = tmp;
107  tmp = uc % 16;
108 
109  if( tmp > 9 )
110  tmp += 87;
111  else
112  tmp += 48;
113 
114  sha1[j++] = tmp;
115  }
116 
117  sha1[j] = 0;
118 
119  return wxString::FromUTF8Unchecked( sha1 );
120 }
121 
122 
124 {
125 private:
126  // prohibit assignment and default copy constructor
127  S3D_CACHE_ENTRY( const S3D_CACHE_ENTRY& source );
128  S3D_CACHE_ENTRY& operator=( const S3D_CACHE_ENTRY& source );
129 
130  wxString m_CacheBaseName; // base name of cache file (a SHA1 digest)
131 
132 public:
133  S3D_CACHE_ENTRY();
135 
136  void SetSHA1( const unsigned char* aSHA1Sum );
137  const wxString GetCacheBaseName( void );
138 
139  wxDateTime modTime; // file modification time
140  unsigned char sha1sum[20];
141  std::string pluginInfo; // PluginName:Version string
144 };
145 
146 
148 {
149  sceneData = NULL;
150  renderData = NULL;
151  memset( sha1sum, 0, 20 );
152 }
153 
154 
156 {
157  if( NULL != sceneData )
158  delete sceneData;
159 
160  if( NULL != renderData )
162 }
163 
164 
165 void S3D_CACHE_ENTRY::SetSHA1( const unsigned char* aSHA1Sum )
166 {
167  if( NULL == aSHA1Sum )
168  {
169  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] NULL passed for aSHA1Sum",
170  __FILE__, __FUNCTION__, __LINE__ );
171 
172  return;
173  }
174 
175  memcpy( sha1sum, aSHA1Sum, 20 );
176  return;
177 }
178 
179 
180 const wxString S3D_CACHE_ENTRY::GetCacheBaseName( void )
181 {
182  if( m_CacheBaseName.empty() )
184 
185  return m_CacheBaseName;
186 }
187 
188 
190 {
191  m_DirtyCache = false;
194 
195  return;
196 }
197 
198 
200 {
201  FlushCache();
202 
203  if( m_FNResolver )
204  delete m_FNResolver;
205 
206  if( m_Plugins )
207  delete m_Plugins;
208 
209  return;
210 }
211 
212 
213 SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCachePtr )
214 {
215  if( aCachePtr )
216  *aCachePtr = NULL;
217 
218  wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile );
219 
220  if( full3Dpath.empty() )
221  {
222  // the model cannot be found; we cannot proceed
223  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [3D model] could not find model '%s'\n",
224  __FILE__, __FUNCTION__, __LINE__, aModelFile );
225  return NULL;
226  }
227 
228  // check cache if file is already loaded
229  std::lock_guard<std::mutex> lock( mutex3D_cache );
230 
231  std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
232  mi = m_CacheMap.find( full3Dpath );
233 
234  if( mi != m_CacheMap.end() )
235  {
236  wxFileName fname( full3Dpath );
237 
238  if( fname.FileExists() ) // Only check if file exists. If not, it will
239  { // use the same model in cache.
240  bool reload = false;
241  wxDateTime fmdate = fname.GetModificationTime();
242 
243  if( fmdate != mi->second->modTime )
244  {
245  unsigned char hashSum[20];
246  getSHA1( full3Dpath, hashSum );
247  mi->second->modTime = fmdate;
248 
249  if( !isSHA1Same( hashSum, mi->second->sha1sum ) )
250  {
251  mi->second->SetSHA1( hashSum );
252  reload = true;
253  }
254  }
255 
256  if( reload )
257  {
258  if( NULL != mi->second->sceneData )
259  {
260  S3D::DestroyNode( mi->second->sceneData );
261  mi->second->sceneData = NULL;
262  }
263 
264  if( NULL != mi->second->renderData )
265  S3D::Destroy3DModel( &mi->second->renderData );
266 
267  mi->second->sceneData = m_Plugins->Load3DModel( full3Dpath, mi->second->pluginInfo );
268  }
269  }
270 
271  if( NULL != aCachePtr )
272  *aCachePtr = mi->second;
273 
274  return mi->second->sceneData;
275  }
276 
277  // a cache item does not exist; search the Filename->Cachename map
278  return checkCache( full3Dpath, aCachePtr );
279 }
280 
281 
282 SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile )
283 {
284  return load( aModelFile );
285 }
286 
287 
288 SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** aCachePtr )
289 {
290  if( aCachePtr )
291  *aCachePtr = NULL;
292 
293  unsigned char sha1sum[20];
294 
295  if( !getSHA1( aFileName, sha1sum ) || m_CacheDir.empty() )
296  {
297  // just in case we can't get a hash digest (for example, on access issues)
298  // or we do not have a configured cache file directory, we create an
299  // entry to prevent further attempts at loading the file
301  m_CacheList.push_back( ep );
302  wxFileName fname( aFileName );
303  ep->modTime = fname.GetModificationTime();
304 
305  if( m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
306  ( aFileName, ep ) ).second == false )
307  {
308  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'",
309  __FILE__, __FUNCTION__, __LINE__, aFileName );
310 
311  m_CacheList.pop_back();
312  delete ep;
313  }
314  else
315  {
316  if( aCachePtr )
317  *aCachePtr = ep;
318 
319  }
320 
321  return NULL;
322  }
323 
325  m_CacheList.push_back( ep );
326  wxFileName fname( aFileName );
327  ep->modTime = fname.GetModificationTime();
328 
329  if( m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
330  ( aFileName, ep ) ).second == false )
331  {
332  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] duplicate entry in map file; key = '%s'",
333  __FILE__, __FUNCTION__, __LINE__, aFileName );
334 
335  m_CacheList.pop_back();
336  delete ep;
337  return NULL;
338  }
339 
340  if( aCachePtr )
341  *aCachePtr = ep;
342 
343  ep->SetSHA1( sha1sum );
344 
345  wxString bname = ep->GetCacheBaseName();
346  wxString cachename = m_CacheDir + bname + wxT( ".3dc" );
347 
348  if( wxFileName::FileExists( cachename ) && loadCacheData( ep ) )
349  return ep->sceneData;
350 
351  ep->sceneData = m_Plugins->Load3DModel( aFileName, ep->pluginInfo );
352 
353  if( NULL != ep->sceneData )
354  saveCacheData( ep );
355 
356  return ep->sceneData;
357 }
358 
359 
360 bool S3D_CACHE::getSHA1( const wxString& aFileName, unsigned char* aSHA1Sum )
361 {
362  if( aFileName.empty() )
363  {
364  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * [BUG] empty filename",
365  __FILE__, __FUNCTION__, __LINE__ );
366 
367  return false;
368  }
369 
370  if( NULL == aSHA1Sum )
371  {
372  wxLogTrace( MASK_3D_CACHE, "%s\n * [BUG] NULL pointer passed for aMD5Sum",
373  __FILE__, __FUNCTION__, __LINE__ );
374 
375  return false;
376  }
377 
378  #ifdef _WIN32
379  FILE* fp = _wfopen( aFileName.wc_str(), L"rb" );
380  #else
381  FILE* fp = fopen( aFileName.ToUTF8(), "rb" );
382  #endif
383 
384  if( NULL == fp )
385  return false;
386 
387  boost::uuids::detail::sha1 dblock;
388  unsigned char block[4096];
389  size_t bsize = 0;
390 
391  while( ( bsize = fread( &block, 1, 4096, fp ) ) > 0 )
392  dblock.process_bytes( block, bsize );
393 
394  fclose( fp );
395  unsigned int digest[5];
396  dblock.get_digest( digest );
397 
398  // ensure MSB order
399  for( int i = 0; i < 5; ++i )
400  {
401  int idx = i << 2;
402  unsigned int tmp = digest[i];
403  aSHA1Sum[idx+3] = tmp & 0xff;
404  tmp >>= 8;
405  aSHA1Sum[idx+2] = tmp & 0xff;
406  tmp >>= 8;
407  aSHA1Sum[idx+1] = tmp & 0xff;
408  tmp >>= 8;
409  aSHA1Sum[idx] = tmp & 0xff;
410  }
411 
412  return true;
413 }
414 
415 
417 {
418  wxString bname = aCacheItem->GetCacheBaseName();
419 
420  if( bname.empty() )
421  {
422  wxLogTrace( MASK_3D_CACHE,
423  " * [3D model] cannot load cached model; no file hash available" );
424 
425  return false;
426  }
427 
428  if( m_CacheDir.empty() )
429  {
430  wxLogTrace( MASK_3D_CACHE,
431  " * [3D model] cannot load cached model; config directory unknown" );
432 
433  return false;
434  }
435 
436  wxString fname = m_CacheDir + bname + wxT( ".3dc" );
437 
438  if( !wxFileName::FileExists( fname ) )
439  {
440  wxString errmsg = "cannot open file";
441  wxLogTrace( MASK_3D_CACHE, " * [3D model] %s '%s'", errmsg.GetData(), fname.GetData() );
442  return false;
443  }
444 
445  if( NULL != aCacheItem->sceneData )
446  S3D::DestroyNode( (SGNODE*) aCacheItem->sceneData );
447 
448  aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8(), m_Plugins, checkTag );
449 
450  if( NULL == aCacheItem->sceneData )
451  return false;
452 
453  return true;
454 }
455 
456 
458 {
459  if( NULL == aCacheItem )
460  {
461  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * NULL passed for aCacheItem",
462  __FILE__, __FUNCTION__, __LINE__ );
463 
464  return false;
465  }
466 
467  if( NULL == aCacheItem->sceneData )
468  {
469  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * aCacheItem has no valid scene data",
470  __FILE__, __FUNCTION__, __LINE__ );
471 
472  return false;
473  }
474 
475  wxString bname = aCacheItem->GetCacheBaseName();
476 
477  if( bname.empty() )
478  {
479  wxLogTrace( MASK_3D_CACHE,
480  " * [3D model] cannot load cached model; no file hash available" );
481 
482  return false;
483  }
484 
485  if( m_CacheDir.empty() )
486  {
487  wxLogTrace( MASK_3D_CACHE,
488  " * [3D model] cannot load cached model; config directory unknown" );
489 
490  return false;
491  }
492 
493  wxString fname = m_CacheDir + bname + wxT( ".3dc" );
494 
495  if( wxFileName::Exists( fname ) )
496  {
497  if( !wxFileName::FileExists( fname ) )
498  {
499  wxLogTrace( MASK_3D_CACHE, " * [3D model] path exists but is not a regular file '%s'",
500  fname );
501 
502  return false;
503  }
504  }
505 
506  return S3D::WriteCache( fname.ToUTF8(), true, (SGNODE*)aCacheItem->sceneData,
507  aCacheItem->pluginInfo.c_str() );
508 }
509 
510 
511 bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
512 {
513  if( !m_ConfigDir.empty() )
514  return false;
515 
516  wxFileName cfgdir;
517 
518  if( aConfigDir.StartsWith( "${" ) || aConfigDir.StartsWith( "$(" ) )
519  cfgdir.Assign( ExpandEnvVarSubstitutions( aConfigDir ), "" );
520  else
521  cfgdir.Assign( aConfigDir, "" );
522 
523  cfgdir.Normalize();
524 
525  if( !cfgdir.DirExists() )
526  {
527  cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
528 
529  if( !cfgdir.DirExists() )
530  {
531  wxLogTrace( MASK_3D_CACHE,
532  "%s:%s:%d\n * failed to create 3D configuration directory '%s'",
533  __FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
534 
535  return false;
536  }
537  }
538 
539  m_ConfigDir = cfgdir.GetPath();
540 
541  // inform the file resolver of the config directory
543  {
544  wxLogTrace( MASK_3D_CACHE,
545  "%s:%s:%d\n * could not set 3D Config Directory on filename resolver\n"
546  " * config directory: '%s'",
547  __FILE__, __FUNCTION__, __LINE__, m_ConfigDir );
548  }
549 
550  // 3D cache data must go to a user's cache directory;
551  // unfortunately wxWidgets doesn't seem to provide
552  // functions to retrieve such a directory.
553  //
554  // 1. OSX: ~/Library/Caches/kicad/3d/
555  // 2. Linux: ${XDG_CACHE_HOME}/kicad/3d ~/.cache/kicad/3d/
556  // 3. MSWin: AppData\Local\kicad\3d
557  wxString cacheDir;
558 
559 #if defined(_WIN32)
560  wxStandardPaths::Get().UseAppInfo( wxStandardPaths::AppInfo_None );
561  cacheDir = wxStandardPaths::Get().GetUserLocalDataDir();
562  cacheDir.append( "\\kicad\\3d" );
563 #elif defined(__APPLE)
564  cacheDir = "${HOME}/Library/Caches/kicad/3d";
565 #else // assume Linux
566  cacheDir = ExpandEnvVarSubstitutions( "${XDG_CACHE_HOME}" );
567 
568  if( cacheDir.empty() || cacheDir == "${XDG_CACHE_HOME}" )
569  cacheDir = "${HOME}/.cache";
570 
571  cacheDir.append( "/kicad/3d" );
572 #endif
573 
574  cacheDir = ExpandEnvVarSubstitutions( cacheDir );
575  cfgdir.Assign( cacheDir, "" );
576 
577  if( !cfgdir.DirExists() )
578  {
579  cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
580 
581  if( !cfgdir.DirExists() )
582  {
583  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * failed to create 3D cache directory '%s'",
584  __FILE__, __FUNCTION__, __LINE__, cfgdir.GetPath() );
585 
586  return false;
587  }
588  }
589 
590  m_CacheDir = cfgdir.GetPathWithSep();
591  return true;
592 }
593 
594 
595 wxString S3D_CACHE::Get3DConfigDir( bool createDefault )
596 {
597  if( !m_ConfigDir.empty() || !createDefault )
598  return m_ConfigDir;
599 
600  // note: duplicated from common/common.cpp GetKicadConfigPath() to avoid
601  // code coupling; ideally the instantiating code should call
602  // Set3DConfigDir() to set the directory rather than relying on this
603  // directory remaining the same in future KiCad releases.
604  wxFileName cfgpath;
605 
606  // From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
607  // Unix: ~ (the home directory)
608  // Windows: "C:\Documents and Settings\username\Application Data"
609  // Mac: ~/Library/Preferences
610  cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
611 
612 #if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
613  wxString envstr = ExpandEnvVarSubstitutions( "${XDG_CONFIG_HOME}" );
614 
615  if( envstr.IsEmpty() || envstr == "${XDG_CONFIG_HOME}" )
616  {
617  // XDG_CONFIG_HOME is not set, so use the fallback
618  cfgpath.AppendDir( wxT( ".config" ) );
619  }
620  else
621  {
622  // Override the assignment above with XDG_CONFIG_HOME
623  cfgpath.AssignDir( envstr );
624  }
625 #endif
626 
627  cfgpath.AppendDir( wxT( "kicad" ) );
628  cfgpath.AppendDir( wxT( "3d" ) );
629 
630  if( !cfgpath.DirExists() )
631  {
632  cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
633  }
634 
635  if( !cfgpath.DirExists() )
636  {
637  wxLogTrace( MASK_3D_CACHE, "%s:%s:%d\n * failed to create 3D configuration directory '%s'",
638  __FILE__, __FUNCTION__, __LINE__, cfgpath.GetPath() );
639 
640  return wxT( "" );
641  }
642 
643  if( Set3DConfigDir( cfgpath.GetPath() ) )
644  return m_ConfigDir;
645 
646  return wxEmptyString;
647 }
648 
649 
650 bool S3D_CACHE::SetProjectDir( const wxString& aProjDir )
651 {
652  bool hasChanged = false;
653 
654  if( m_FNResolver->SetProjectDir( aProjDir, &hasChanged ) && hasChanged )
655  {
656  m_CacheMap.clear();
657 
658  std::list< S3D_CACHE_ENTRY* >::iterator sL = m_CacheList.begin();
659  std::list< S3D_CACHE_ENTRY* >::iterator eL = m_CacheList.end();
660 
661  while( sL != eL )
662  {
663  delete *sL;
664  ++sL;
665  }
666 
667  m_CacheList.clear();
668 
669  return true;
670  }
671 
672  return false;
673 }
674 
675 
677 {
678  m_FNResolver->SetProgramBase( aBase );
679  return;
680 }
681 
682 
683 wxString S3D_CACHE::GetProjectDir( void )
684 {
685  return m_FNResolver->GetProjectDir();
686 }
687 
688 
690 {
691  return m_FNResolver;
692 }
693 
694 
695 std::list< wxString > const* S3D_CACHE::GetFileFilters( void ) const
696 {
697  return m_Plugins->GetFileFilters();
698 }
699 
700 
701 void S3D_CACHE::FlushCache( bool closePlugins )
702 {
703  std::list< S3D_CACHE_ENTRY* >::iterator sCL = m_CacheList.begin();
704  std::list< S3D_CACHE_ENTRY* >::iterator eCL = m_CacheList.end();
705 
706  while( sCL != eCL )
707  {
708  delete *sCL;
709  ++sCL;
710  }
711 
712  m_CacheList.clear();
713  m_CacheMap.clear();
714 
715  if( closePlugins )
716  ClosePlugins();
717 
718  return;
719 }
720 
721 
723 {
724  if( NULL != m_Plugins )
726 
727  return;
728 }
729 
730 
731 S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName )
732 {
733  S3D_CACHE_ENTRY* cp = NULL;
734  SCENEGRAPH* sp = load( aModelFileName, &cp );
735 
736  if( !sp )
737  return NULL;
738 
739  if( !cp )
740  {
741  wxLogTrace( MASK_3D_CACHE,
742  "%s:%s:%d\n * [BUG] model loaded with no associated S3D_CACHE_ENTRY",
743  __FILE__, __FUNCTION__, __LINE__ );
744 
745  return NULL;
746  }
747 
748  if( cp->renderData )
749  return cp->renderData;
750 
751  S3DMODEL* mp = S3D::GetModel( sp );
752  cp->renderData = mp;
753 
754  return mp;
755 }
756 
757 
758 wxString S3D_CACHE::GetModelHash( const wxString& aModelFileName )
759 {
760  wxString full3Dpath = m_FNResolver->ResolvePath( aModelFileName );
761 
762  if( full3Dpath.empty() || !wxFileName::FileExists( full3Dpath ) )
763  return wxEmptyString;
764 
765  // check cache if file is already loaded
766  std::map< wxString, S3D_CACHE_ENTRY*, rsort_wxString >::iterator mi;
767  mi = m_CacheMap.find( full3Dpath );
768 
769  if( mi != m_CacheMap.end() )
770  return mi->second->GetCacheBaseName();
771 
772  // a cache item does not exist; search the Filename->Cachename map
773  S3D_CACHE_ENTRY* cp = NULL;
774  checkCache( full3Dpath, &cp );
775 
776  if( NULL != cp )
777  return cp->GetCacheBaseName();
778 
779  return wxEmptyString;
780 }
781 
782 
783 S3D_CACHE* PROJECT::Get3DCacheManager( bool aUpdateProjDir )
784 {
785  std::lock_guard<std::mutex> lock( mutex3D_cacheManager );
786 
787  // Get the existing cache from the project
788  S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( GetElem( ELEM_3DCACHE ) );
789 
790  if( !cache )
791  {
792  // Create a cache if there is not one already
793  cache = new S3D_CACHE();
794 
795  wxFileName cfgpath;
796  cfgpath.AssignDir( GetKicadConfigPath() );
797  cfgpath.AppendDir( wxT( "3d" ) );
798 
799  cache->SetProgramBase( &Pgm() );
800  cache->Set3DConfigDir( cfgpath.GetFullPath() );
801 
803  aUpdateProjDir = true;
804  }
805 
806  if( aUpdateProjDir )
808 
809  return cache;
810 }
811 
812 
813 FILENAME_RESOLVER* PROJECT::Get3DFilenameResolver()
814 {
815  return Get3DCacheManager()->GetResolver();
816 }
static S3D_CACHE * cache
Definition: export_vrml.cpp:65
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:98
static const wxString sha1ToWXString(const unsigned char *aSHA1Sum)
Definition: 3d_cache.cpp:89
wxString m_CacheBaseName
Definition: 3d_cache.cpp:130
std::string pluginInfo
Definition: 3d_cache.cpp:141
S3D_CACHE_ENTRY()
Definition: 3d_cache.cpp:147
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.
Definition: ifsg_api.cpp:321
PGM_BASE keeps program (whole process) data for KiCad programs.
Definition: pgm_base.h:156
#define MASK_3D_CACHE
Definition: 3d_cache.cpp:62
const wxString GetCacheBaseName(void)
Definition: 3d_cache.cpp:180
static std::mutex mutex3D_cache
Definition: 3d_cache.cpp:64
wxString Get3DConfigDir(bool createDefault=false)
Function Get3DConfigDir returns the current 3D configuration directory on success,...
Definition: 3d_cache.cpp:595
void SetProgramBase(PGM_BASE *aBase)
Function SetProgramBase sets the filename resolver's pointer to the application's PGM_BASE instance; ...
Definition: 3d_cache.cpp:676
static bool isSHA1Same(const unsigned char *shaA, const unsigned char *shaB)
Definition: 3d_cache.cpp:68
provides an extensible class to resolve 3D model paths.
bool SetProjectDir(const wxString &aProjDir, bool *flgChanged=NULL)
Function SetProjectDir sets the current KiCad project directory as the first entry in the model path ...
SGLIB_API void Destroy3DModel(S3DMODEL **aModel)
Function Destroy3DModel frees memory used by an S3DMODEL structure and sets the pointer to the struct...
Definition: ifsg_api.cpp:536
std::map< wxString, S3D_CACHE_ENTRY *, rsort_wxString > m_CacheMap
mapping of file names to cache names and data
Definition: 3d_cache.h:61
VTBL_ENTRY _ELEM * GetElem(ELEM_T aIndex)
Typically wrapped somewhere else in a more meaningful function wrapper.
Definition: project.cpp:205
bool loadCacheData(S3D_CACHE_ENTRY *aCacheItem)
Definition: 3d_cache.cpp:416
SGNODE represents the base class of all Scene Graph nodes.
Definition: sg_node.h:76
S3D_CACHE.
Definition: 3d_cache.h:54
SCENEGRAPH * Load3DModel(const wxString &aFileName, std::string &aPluginInfo)
defines the basic data associated with a single 3D model.
wxString GetModelHash(const wxString &aModelFileName)
Definition: 3d_cache.cpp:758
defines the basic data set required to represent a 3D model; this model must remain compatible with V...
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
S3D_CACHE_ENTRY & operator=(const S3D_CACHE_ENTRY &source)
FILENAME_RESOLVER * m_FNResolver
object to resolve file names
Definition: 3d_cache.h:64
std::list< wxString > const * GetFileFilters(void) const
Function GetFileFilters returns the list of file filters; this will contain at least the default "All...
S3DMODEL * GetModel(const wxString &aModelFileName)
Function GetModel attempts to load the scene data for a model and to translate it into an S3D_MODEL s...
Definition: 3d_cache.cpp:731
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:217
bool saveCacheData(S3D_CACHE_ENTRY *aCacheItem)
Definition: 3d_cache.cpp:457
static std::mutex mutex3D_cacheManager
Definition: 3d_cache.cpp:65
void FlushCache(bool closePlugins=true)
Function FlushCache frees all data in the cache and by default closes all plugins.
Definition: 3d_cache.cpp:701
wxDateTime modTime
Definition: 3d_cache.cpp:139
bool SetProjectDir(const wxString &aProjDir)
Function SetProjectDir sets the current project's working directory; this affects the model search pa...
Definition: 3d_cache.cpp:650
#define NULL
const wxString ExpandEnvVarSubstitutions(const wxString &aString)
Replace any environment variable references with their values.
Definition: common.cpp:429
wxString m_CacheDir
3D cache directory
Definition: 3d_cache.h:73
void SetSHA1(const unsigned char *aSHA1Sum)
Definition: 3d_cache.cpp:165
static bool checkTag(const char *aTag, void *aPluginMgrPtr)
Definition: 3d_cache.cpp:78
~S3D_CACHE_ENTRY()
Definition: 3d_cache.cpp:155
wxString GetProjectDir(void)
bool getSHA1(const wxString &aFileName, unsigned char *aSHA1Sum)
Function getSHA1 calculates the SHA1 hash of the given file.
Definition: 3d_cache.cpp:360
SCENEGRAPH * checkCache(const wxString &aFileName, S3D_CACHE_ENTRY **aCachePtr=NULL)
Find or create cache entry for file name.
Definition: 3d_cache.cpp:288
bool m_DirtyCache
set true if the cache needs to be updated
Definition: 3d_cache.h:70
virtual ~S3D_CACHE()
Definition: 3d_cache.cpp:199
SCENEGRAPH * sceneData
Definition: 3d_cache.cpp:142
wxString GetKicadConfigPath()
Return the user configuration path used to store KiCad's configuration files.
Definition: common.cpp:242
defines the API calls for the manipulation of SG* classes
bool CheckTag(const char *aTag)
Function CheckTag checks the given tag and returns true if the plugin named in the tag is not loaded ...
SCENEGRAPH * load(const wxString &aModelFile, S3D_CACHE_ENTRY **aCachePtr=NULL)
Definition: 3d_cache.cpp:213
wxString ResolvePath(const wxString &aFileName)
Function ResolvePath determines the full path of the given file name.
S3DMODEL * renderData
Definition: 3d_cache.cpp:143
std::list< S3D_CACHE_ENTRY * > m_CacheList
cache entries
Definition: 3d_cache.h:58
see class PGM_BASE
manages 3D model plugins
bool Set3DConfigDir(const wxString &aConfigDir)
Function Set3DConfigDir Sets the configuration directory to be used by the model manager for storing ...
Definition: 3d_cache.cpp:511
wxString m_ConfigDir
base configuration path for 3D items
Definition: 3d_cache.h:76
SGLIB_API void DestroyNode(SGNODE *aNode)
Function DestroyNode deletes the given SG* class node.
Definition: ifsg_api.cpp:210
defines the display data cache manager for 3D models
The common library.
void ClosePlugins(void)
Function ClosePlugins iterates through all discovered plugins and closes them to reclaim memory.
bool Set3DConfigDir(const wxString &aConfigDir)
Function Set3DConfigDir sets the user's configuration directory for 3D models.
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.
Definition: ifsg_api.cpp:232
wxString GetProjectDir(void)
Function GetProjectDir returns the current project's working directory.
Definition: 3d_cache.cpp:683
FILENAME_RESOLVER * GetResolver(void)
Definition: 3d_cache.cpp:689
unsigned char sha1sum[20]
Definition: 3d_cache.cpp:140
void ClosePlugins(void)
Function ClosePlugins unloads plugins to free memory.
Definition: 3d_cache.cpp:722
Store the a model based on meshes and materials.
Definition: c3dmodel.h:90
void SetProgramBase(PGM_BASE *aBase)
Function SetProgramBase sets a pointer to the application's PGM_BASE instance; the pointer is used to...
SCENEGRAPH * Load(const wxString &aModelFile)
Function Load attempts to load the scene data for a model; it will consult the internal cache list an...
Definition: 3d_cache.cpp:282
Definition: 3d_cache.cpp:123
SGLIB_API S3DMODEL * GetModel(SCENEGRAPH *aNode)
Function GetModel creates an S3DMODEL representation of aNode (raw data, no transforms)
Definition: ifsg_api.cpp:471
std::list< wxString > const * GetFileFilters(void) const
Function GetFileFilters returns the list of file filters retrieved from the plugins; this will contai...
Definition: 3d_cache.cpp:695
S3D_PLUGIN_MANAGER * m_Plugins
plugin manager
Definition: 3d_cache.h:67