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