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