KiCad PCB EDA Suite
vrml.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) 2020 KiCad Developers, see CHANGELOG.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 /*
26  * Description:
27  * This plugin implements the legacy kicad VRML1/VRML2 and X3D parsers
28  * The plugin will invoke a VRML1 or VRML2 parser depending on the
29  * identifying information in the file header:
30  *
31  * #VRML V1.0 ascii
32  * #VRML V2.0 utf8
33  */
34 
35 #include "plugins/3d/3d_plugin.h"
36 #include "plugins/3dapi/ifsg_all.h"
37 #include "richio.h"
38 #include "vrml1_base.h"
39 #include "vrml2_base.h"
40 #include "wrlproc.h"
41 #include "x3d.h"
42 #include <clocale>
43 #include <wx/filename.h>
44 #include <wx/stdpaths.h>
45 #include <wx/string.h>
46 #include <wx/wfstream.h>
47 #include <wx/log.h>
48 
49 #include <decompress.hpp>
50 
51 
52 #define PLUGIN_VRML_MAJOR 1
53 #define PLUGIN_VRML_MINOR 3
54 #define PLUGIN_VRML_PATCH 2
55 #define PLUGIN_VRML_REVNO 2
56 
57 
58 const char* GetKicadPluginName( void )
59 {
60  return "PLUGIN_3D_VRML";
61 }
62 
63 
64 void GetPluginVersion( unsigned char* Major,
65  unsigned char* Minor, unsigned char* Patch, unsigned char* Revision )
66 {
67  if( Major )
68  *Major = PLUGIN_VRML_MAJOR;
69 
70  if( Minor )
71  *Minor = PLUGIN_VRML_MINOR;
72 
73  if( Patch )
74  *Patch = PLUGIN_VRML_PATCH;
75 
76  if( Revision )
77  *Revision = PLUGIN_VRML_REVNO;
78 
79  return;
80 }
81 
82 
83 static struct FILE_DATA
84 {
85  std::vector<std::string> extensions;
86  std::vector<std::string> filters;
87 
89  {
90 
91 #ifdef _WIN32
92  extensions = { "wrl", "wrz", "x3d" };
93  filters = { "VRML 1.0/2.0 (*.wrl;*.wrz)|*.wrl;*.wrz",
94  "X3D (*.x3d)|*.x3d" };
95 #else
96  extensions = { "wrl", "WRL", "wrz", "WRZ", "x3d", "X3D" };
97  filters = { "VRML 1.0/2.0 (*.wrl;*.WRL;*.wrz;*.WRZ)|*.wrl;*.WRL;*.wrz;*.WRZ",
98  "X3D (*.x3d;*.X3D)|*.x3d;*.X3D" };
99 #endif
100  }
101 
102 } file_data;
103 
104 
105 int GetNExtensions( void )
106 {
107  return file_data.extensions.size();
108 }
109 
110 
111 char const* GetModelExtension( int aIndex )
112 {
113  if( aIndex < 0 || aIndex >= int( file_data.extensions.size() ) )
114  return NULL;
115 
116  return file_data.extensions[aIndex].c_str();
117 }
118 
119 
120 int GetNFilters( void )
121 {
122  return file_data.filters.size();
123 }
124 
125 
126 char const* GetFileFilter( int aIndex )
127 {
128  if( aIndex < 0 || aIndex >= int( file_data.filters.size() ) )
129  return NULL;
130 
131  return file_data.filters[aIndex].c_str();
132 }
133 
134 
135 bool CanRender( void )
136 {
137  // this plugin supports rendering of IDF component outlines
138  return true;
139 }
140 
141 
142 class LOCALESWITCH
143 {
144  // Store the user locale name, to restore this locale later, in dtor
145  std::string m_locale;
146 
147 public:
149  {
150  m_locale = setlocale( LC_NUMERIC, 0 );
151  setlocale( LC_NUMERIC, "C" );
152  }
153 
155  {
156  setlocale( LC_NUMERIC, m_locale.c_str() );
157  }
158 };
159 
160 
161 SCENEGRAPH* LoadVRML( const wxString& aFileName, bool useInline )
162 {
163  FILE_LINE_READER* modelFile = NULL;
164  SCENEGRAPH* scene = NULL;
165  wxString filename = aFileName;
166  wxFileName tmpfilename;
167 
168  if( aFileName.Upper().EndsWith( "WRZ" ) )
169  {
170  wxFileInputStream ifile( aFileName );
171  tmpfilename = wxFileName( aFileName );
172 
173  tmpfilename.SetPath( wxStandardPaths::Get().GetTempDir() );
174  tmpfilename.SetExt( "WRL" );
175 
176  wxFileOffset size = ifile.GetLength();
177 
178  if( size == wxInvalidOffset )
179  return nullptr;
180 
181  {
182  wxFileOutputStream ofile( tmpfilename.GetFullPath() );
183 
184  if( !ofile.IsOk() )
185  return nullptr;
186 
187  char *buffer = new char[size];
188 
189  ifile.Read( buffer, size);
190  std::string expanded;
191 
192  try
193  {
194  expanded = gzip::decompress( buffer, size );
195  }
196  catch(...)
197  {
198  delete[] buffer;
199  return nullptr;
200  }
201 
202  delete[] buffer;
203 
204  ofile.Write( expanded.data(), expanded.size() );
205  ofile.Close();
206  }
207 
208  filename = tmpfilename.GetFullPath();
209  }
210 
211  try
212  {
213  // set the max char limit to 8MB; if a VRML file contains
214  // longer lines then perhaps it shouldn't be used
215  modelFile = new FILE_LINE_READER( filename, 0, 8388608 );
216  }
217  catch( IO_ERROR & )
218  {
219  wxLogError( wxS( " * " ) + _( "[INFO] load failed: input line too long\n" ) );
220  return NULL;
221  }
222 
223 
224  // VRML file processor
225  WRLPROC proc( modelFile );
226 
227  // Cleanup our temporary file
228  if( tmpfilename.IsOk() )
229  wxRemoveFile( tmpfilename.GetFullPath() );
230 
231  if( proc.GetVRMLType() == VRML_V1 )
232  {
233  wxLogTrace( MASK_VRML, " * [INFO] Processing VRML 1.0 file\n" );
234 
235  WRL1BASE* bp = new WRL1BASE;
236 
237  if( !bp->Read( proc ) )
238  {
239  wxLogTrace( MASK_VRML, " * [INFO] load failed\n" );
240  }
241  else
242  {
243  wxLogTrace( MASK_VRML, " * [INFO] load completed\n" );
244 
245  scene = (SCENEGRAPH*)bp->TranslateToSG( NULL, NULL );
246  }
247 
248  delete bp;
249  }
250  else
251  {
252  wxLogTrace( MASK_VRML, " * [INFO] Processing VRML 2.0 file\n" );
253 
254  WRL2BASE* bp = new WRL2BASE;
255 
256  // allow Inline{} files to be included
257  bp->SetEnableInline( true );
258 
259  if( !bp->Read( proc ) )
260  {
261  wxLogTrace( MASK_VRML, " * [INFO] load failed\n" );
262  }
263  else
264  {
265  wxLogTrace( MASK_VRML, " * [INFO] load completed\n" );
266 
267  // for now we recalculate all normals per-vertex per-face
268  scene = (SCENEGRAPH*)bp->TranslateToSG( NULL );
269  }
270 
271  delete bp;
272  }
273 
274  if( NULL != modelFile )
275  delete modelFile;
276 
277  // DEBUG: WRITE OUT VRML2 FILE TO CONFIRM STRUCTURE
278  #if ( defined( DEBUG_VRML1 ) && DEBUG_VRML1 > 3 ) \
279  || ( defined( DEBUG_VRML2 ) && DEBUG_VRML2 > 3 )
280  if( scene )
281  {
282  wxFileName fn( wxString::FromUTF8Unchecked( aFileName ) );
283  wxString output;
284 
285  if( proc.GetVRMLType() == VRML_V1 )
286  output = wxT( "_vrml1-" );
287  else
288  output = wxT( "_vrml2-" );
289 
290  output.append( fn.GetName() );
291  output.append( wxT(".wrl") );
292  S3D::WriteVRML( output.ToUTF8(), true, (SGNODE*)(scene), true, true );
293  }
294  #endif
295 
296  return scene;
297 }
298 
299 
300 SCENEGRAPH* LoadX3D( const wxString& aFileName )
301 {
302  SCENEGRAPH* scene = NULL;
303  X3DPARSER model;
304  scene = model.Load( aFileName );
305 
306  return scene;
307 }
308 
309 
310 SCENEGRAPH* Load( char const* aFileName )
311 {
312  if( NULL == aFileName )
313  return NULL;
314 
315  wxString fname = wxString::FromUTF8Unchecked( aFileName );
316 
317  if( !wxFileName::FileExists( fname ) )
318  return NULL;
319 
320  LOCALESWITCH switcher;
321 
322  SCENEGRAPH* scene = NULL;
323  wxString ext = wxFileName( fname ).GetExt();
324 
325  if( ext == "x3d" || ext == "X3D" )
326  scene = LoadX3D( fname );
327  else
328  scene = LoadVRML( fname, true );
329 
330  return scene;
331 }
int GetNExtensions(void)
Function GetNExtensions.
Definition: vrml.cpp:105
WRL1BASE represents the top node of a VRML1 model.
Definition: vrml1_base.h:45
defines the basic input class for VRML
SCENEGRAPH * Load(char const *aFileName)
reads a model file and creates a generic display structure
Definition: vrml.cpp:310
int GetNFilters(void)
Function GetNFilters.
Definition: vrml.cpp:120
#define PLUGIN_VRML_MAJOR
Definition: vrml.cpp:52
#define MASK_VRML
Definition: wrltypes.h:37
WRLVERSION GetVRMLType(void)
Definition: wrlproc.cpp:221
bool Read(WRLPROC &proc)
Definition: vrml2_base.cpp:193
bool Read(WRLPROC &proc)
Definition: vrml1_base.cpp:106
const char * GetKicadPluginName(void)
Function GetKicadPluginName returns the name of the plugin instance; for example IDFv3.
Definition: vrml.cpp:58
SGNODE represents the base class of all Scene Graph nodes.
Definition: sg_node.h:76
collects header files for all SG* wrappers and the API
FILE_DATA()
Definition: vrml.cpp:88
describes the runtime-loadable interface to support loading and parsing of 3D models.
~LOCALESWITCH()
Definition: vrml.cpp:154
#define PLUGIN_VRML_PATCH
Definition: vrml.cpp:54
SCENEGRAPH * LoadX3D(const wxString &aFileName)
Definition: vrml.cpp:300
SGLIB_API bool WriteVRML(const char *filename, bool overwrite, SGNODE *aTopNode, bool reuse, bool renameNodes)
Function WriteVRML writes out the given node and its subnodes to a VRML2 file.
Definition: ifsg_api.cpp:81
Definition: x3d.h:35
static struct FILE_DATA file_data
void SetEnableInline(bool enable)
Definition: vrml2_base.cpp:96
char const * extensions[NEXTS]
FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:181
char const * GetModelExtension(int aIndex)
Function GetModelExtension.
Definition: vrml.cpp:111
SCENEGRAPH * LoadVRML(const wxString &aFileName, bool useInline)
Definition: vrml.cpp:161
#define NULL
SGNODE * TranslateToSG(SGNODE *aParent, WRL1STATUS *sp) override
Function TranslateToSG produces a representation of the data using the intermediate scenegraph struct...
Definition: vrml1_base.cpp:713
#define PLUGIN_VRML_MINOR
Definition: vrml.cpp:53
LOCALESWITCH()
Definition: vrml.cpp:148
WRL2BASE represents the top node of a VRML2 model.
Definition: vrml2_base.h:59
std::string m_locale
Definition: vrml.cpp:145
#define _(s)
Definition: 3d_actions.cpp:33
#define PLUGIN_VRML_REVNO
Definition: vrml.cpp:55
SCENEGRAPH * Load(const wxString &aFileName)
Definition: x3d.cpp:44
char const * filters[NFILS]
char const * GetFileFilter(int aIndex)
Function GetFileFilter.
Definition: vrml.cpp:126
void GetPluginVersion(unsigned char *Major, unsigned char *Minor, unsigned char *Patch, unsigned char *Revision)
Function GetPluginVersion retrieves the version of the instantiated plugin for informational purposes...
Definition: vrml.cpp:64
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
bool CanRender(void)
Function CanRender.
Definition: vrml.cpp:135
SGNODE * TranslateToSG(SGNODE *aParent) override
Function TranslateToSG produces a representation of the data using the intermediate scenegraph struct...