You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
6.6 KiB

  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. * Description:
  25. * This plugin implements the legacy kicad VRML1/VRML2 and X3D parsers
  26. * The plugin will invoke a VRML1 or VRML2 parser depending on the
  27. * identifying information in the file header:
  28. *
  29. * #VRML V1.0 ascii
  30. * #VRML V2.0 utf8
  31. */
  32. #include "plugins/3d/3d_plugin.h"
  33. #include "plugins/3dapi/ifsg_all.h"
  34. #include "richio.h"
  35. #include "vrml1_base.h"
  36. #include "vrml2_base.h"
  37. #include "wrlproc.h"
  38. #include "x3d.h"
  39. #include <clocale>
  40. #include <wx/filename.h>
  41. #include <wx/log.h>
  42. #define PLUGIN_VRML_MAJOR 1
  43. #define PLUGIN_VRML_MINOR 3
  44. #define PLUGIN_VRML_PATCH 2
  45. #define PLUGIN_VRML_REVNO 2
  46. const char* GetKicadPluginName( void )
  47. {
  48. return "PLUGIN_3D_VRML";
  49. }
  50. void GetPluginVersion( unsigned char* Major,
  51. unsigned char* Minor, unsigned char* Patch, unsigned char* Revision )
  52. {
  53. if( Major )
  54. *Major = PLUGIN_VRML_MAJOR;
  55. if( Minor )
  56. *Minor = PLUGIN_VRML_MINOR;
  57. if( Patch )
  58. *Patch = PLUGIN_VRML_PATCH;
  59. if( Revision )
  60. *Revision = PLUGIN_VRML_REVNO;
  61. return;
  62. }
  63. // number of extensions supported
  64. #ifdef _WIN32
  65. #define NEXTS 2
  66. #else
  67. #define NEXTS 4
  68. #endif
  69. // number of filter sets supported
  70. #define NFILS 2
  71. static char ext0[] = "wrl";
  72. static char ext1[] = "x3d";
  73. #ifdef _WIN32
  74. static char fil0[] = "VRML 1.0/2.0 (*.wrl)|*.wrl";
  75. static char fil1[] = "X3D (*.x3d)|*.x3d";
  76. #else
  77. static char ext2[] = "WRL";
  78. static char ext3[] = "X3D";
  79. static char fil0[] = "VRML 1.0/2.0 (*.wrl;*.WRL)|*.wrl;*.WRL";
  80. static char fil1[] = "X3D (*.x3d;*.X3D)|*.x3d;*.X3D";
  81. #endif
  82. static struct FILE_DATA
  83. {
  84. char const* extensions[NEXTS];
  85. char const* filters[NFILS];
  86. FILE_DATA()
  87. {
  88. extensions[0] = ext0;
  89. extensions[1] = ext1;
  90. filters[0] = fil0;
  91. filters[1] = fil1;
  92. #ifndef _WIN32
  93. extensions[2] = ext2;
  94. extensions[3] = ext3;
  95. #endif
  96. return;
  97. }
  98. } file_data;
  99. int GetNExtensions( void )
  100. {
  101. return NEXTS;
  102. }
  103. char const* GetModelExtension( int aIndex )
  104. {
  105. if( aIndex < 0 || aIndex >= NEXTS )
  106. return NULL;
  107. return file_data.extensions[aIndex];
  108. }
  109. int GetNFilters( void )
  110. {
  111. return NFILS;
  112. }
  113. char const* GetFileFilter( int aIndex )
  114. {
  115. if( aIndex < 0 || aIndex >= NFILS )
  116. return NULL;
  117. return file_data.filters[aIndex];
  118. }
  119. bool CanRender( void )
  120. {
  121. // this plugin supports rendering of IDF component outlines
  122. return true;
  123. }
  124. class LOCALESWITCH
  125. {
  126. // Store the user locale name, to restore this locale later, in dtor
  127. std::string m_locale;
  128. public:
  129. LOCALESWITCH()
  130. {
  131. m_locale = setlocale( LC_NUMERIC, 0 );
  132. setlocale( LC_NUMERIC, "C" );
  133. }
  134. ~LOCALESWITCH()
  135. {
  136. setlocale( LC_NUMERIC, m_locale.c_str() );
  137. }
  138. };
  139. SCENEGRAPH* LoadVRML( const wxString& aFileName, bool useInline )
  140. {
  141. FILE_LINE_READER* modelFile = NULL;
  142. SCENEGRAPH* scene = NULL;
  143. try
  144. {
  145. // set the max char limit to 8MB; if a VRML file contains
  146. // longer lines then perhaps it shouldn't be used
  147. modelFile = new FILE_LINE_READER( aFileName, 0, 8388608 );
  148. }
  149. catch( IO_ERROR & )
  150. {
  151. wxLogError( _( " * [INFO] load failed: input line too long\n" ) );
  152. return NULL;
  153. }
  154. // VRML file processor
  155. WRLPROC proc( modelFile );
  156. if( proc.GetVRMLType() == VRML_V1 )
  157. {
  158. wxLogTrace( MASK_VRML, " * [INFO] Processing VRML 1.0 file\n" );
  159. WRL1BASE* bp = new WRL1BASE;
  160. if( !bp->Read( proc ) )
  161. {
  162. wxLogTrace( MASK_VRML, " * [INFO] load failed\n" );
  163. }
  164. else
  165. {
  166. wxLogTrace( MASK_VRML, " * [INFO] load completed\n" );
  167. scene = (SCENEGRAPH*)bp->TranslateToSG( NULL, NULL );
  168. }
  169. delete bp;
  170. }
  171. else
  172. {
  173. wxLogTrace( MASK_VRML, " * [INFO] Processing VRML 2.0 file\n" );
  174. WRL2BASE* bp = new WRL2BASE;
  175. // allow Inline{} files to be included
  176. bp->SetEnableInline( true );
  177. if( !bp->Read( proc ) )
  178. {
  179. wxLogTrace( MASK_VRML, " * [INFO] load failed\n" );
  180. }
  181. else
  182. {
  183. wxLogTrace( MASK_VRML, " * [INFO] load completed\n" );
  184. // for now we recalculate all normals per-vertex per-face
  185. scene = (SCENEGRAPH*)bp->TranslateToSG( NULL );
  186. }
  187. delete bp;
  188. }
  189. if( NULL != modelFile )
  190. delete modelFile;
  191. // DEBUG: WRITE OUT VRML2 FILE TO CONFIRM STRUCTURE
  192. #if ( defined( DEBUG_VRML1 ) && DEBUG_VRML1 > 3 ) \
  193. || ( defined( DEBUG_VRML2 ) && DEBUG_VRML2 > 3 )
  194. if( scene )
  195. {
  196. wxFileName fn( wxString::FromUTF8Unchecked( aFileName ) );
  197. wxString output;
  198. if( proc.GetVRMLType() == VRML_V1 )
  199. output = wxT( "_vrml1-" );
  200. else
  201. output = wxT( "_vrml2-" );
  202. output.append( fn.GetName() );
  203. output.append( wxT(".wrl") );
  204. S3D::WriteVRML( output.ToUTF8(), true, (SGNODE*)(scene), true, true );
  205. }
  206. #endif
  207. return scene;
  208. }
  209. SCENEGRAPH* LoadX3D( const wxString& aFileName )
  210. {
  211. SCENEGRAPH* scene = NULL;
  212. X3DPARSER model;
  213. scene = model.Load( aFileName );
  214. return scene;
  215. }
  216. SCENEGRAPH* Load( char const* aFileName )
  217. {
  218. if( NULL == aFileName )
  219. return NULL;
  220. wxString fname = wxString::FromUTF8Unchecked( aFileName );
  221. if( !wxFileName::FileExists( fname ) )
  222. return NULL;
  223. LOCALESWITCH switcher;
  224. SCENEGRAPH* scene = NULL;
  225. wxString ext = wxFileName( fname ).GetExt();
  226. if( ext == "x3d" || ext == "X3D" )
  227. scene = LoadX3D( fname );
  228. else
  229. scene = LoadVRML( fname, true );
  230. return scene;
  231. }