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;
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
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 )
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:328
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's pointer to the application'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:543
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
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: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
void SetProgramBase(PGM_BASE *aBase)
Function SetProgramBase sets a pointer to the application's PGM_BASE instance; the pointer is used to...
std::map< wxString, S3D_CACHE_ENTRY *, S3D::rsort_wxString > m_CacheMap
mapping of file names to cache names and data
Definition: 3d_cache.h:57
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'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:254
wxString m_CacheDir
3D cache directory
Definition: 3d_cache.h:69
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)
Function checkCache searches the cache list for the given filename and retrieves the cache data; a ca...
Definition: 3d_cache.cpp:277
bool m_DirtyCache
set true if the cache needs to be updated
Definition: 3d_cache.h:66
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
bool SetProjectDir(const wxString &aProjDir, bool *flgChanged=NULL)
Function SetProjectDir sets the current KiCad project directory as the first entry in the model path ...
S3DMODEL * renderData
Definition: 3d_cache.cpp:128
std::list< S3D_CACHE_ENTRY * > m_CacheList
cache entries
Definition: 3d_cache.h:54
manages 3D model plugins
provides an extensible class to resolve 3D model paths.
wxString ResolvePath(const wxString &aFileName)
Function ResolvePath determines the full path of the given file name.
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
wxString m_ConfigDir
base configuration path for 3D items
Definition: 3d_cache.h:72
SGLIB_API void DestroyNode(SGNODE *aNode)
Function DestroyNode deletes the given SG* class node.
Definition: ifsg_api.cpp:214
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...
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:236
wxString GetProjectDir(void)
Function GetProjectDir returns the current project'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
S3D_FILENAME_RESOLVER * m_FNResolver
object to resolve file names
Definition: 3d_cache.h:60
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:478
std::list< wxString > const * GetFileFilters(void) const
Function GetFileFilters returns the list of file filters; this will contain at least the default "All...
S3D_PLUGIN_MANAGER * m_Plugins
plugin manager
Definition: 3d_cache.h:63
bool Set3DConfigDir(const wxString &aConfigDir)
Function Set3DConfigDir sets the user's configuration directory for 3D models.