KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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( std::runtime_error& e )
206 {
207 wxLogDebug( wxT( " * [INFO] wrz load failed: %s" ), wxString::FromUTF8Unchecked( e.what() ) );
208
209 delete[] buffer;
210 return nullptr;
211 }
212 catch( ... )
213 {
214 wxLogDebug( wxT( " * [INFO] wrz load failed: unknown error" ) );
215
216 delete[] buffer;
217 return nullptr;
218 }
219
220 delete[] buffer;
221
222 ofile.Write( expanded.data(), expanded.size() );
223 ofile.Close();
224 }
225
226 filename = tmpfilename.GetFullPath();
227 }
228
229 try
230 {
231 // set the max char limit to 8MB; if a VRML file contains
232 // longer lines then perhaps it shouldn't be used
233 modelFile = new FILE_LINE_READER( filename, 0, 8388608 );
234 }
235 catch( IO_ERROR& e )
236 {
237 wxLogError( wxString( wxS( " * " ) )
238 << wxString::Format( _( "[INFO] load failed: %s" ), e.What() ) );
239
240 return nullptr;
241 }
242
243
244 // VRML file processor
245 WRLPROC proc( modelFile );
246
247 // Cleanup our temporary file
248 if( tmpfilename.IsOk() )
249 wxRemoveFile( tmpfilename.GetFullPath() );
250
251 if( proc.GetVRMLType() == WRLVERSION::VRML_V1 )
252 {
253 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Processing VRML 1.0 file" ) );
254
255 WRL1BASE* bp = new WRL1BASE;
256
257 if( !bp->Read( proc ) )
258 {
259 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] load failed" ) );
260 }
261 else
262 {
263 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] load completed" ) );
264
265 scene = (SCENEGRAPH*)bp->TranslateToSG( nullptr, nullptr );
266 }
267
268 delete bp;
269 }
270 else
271 {
272 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Processing VRML 2.0 file" ) );
273
274 WRL2BASE* bp = new WRL2BASE;
275
276 // allow Inline{} files to be included
277 bp->SetEnableInline( true );
278
279 if( !bp->Read( proc ) )
280 {
281 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] load failed" ) );
282 }
283 else
284 {
285 wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] load completed" ) );
286
287 // for now we recalculate all normals per-vertex per-face
288 scene = (SCENEGRAPH*)bp->TranslateToSG( nullptr );
289 }
290
291 delete bp;
292 }
293
294 if( nullptr != modelFile )
295 delete modelFile;
296
297 // DEBUG: WRITE OUT VRML2 FILE TO CONFIRM STRUCTURE
298#if ( defined( DEBUG_VRML1 ) && DEBUG_VRML1 > 3 ) \
299 || ( defined( DEBUG_VRML2 ) && DEBUG_VRML2 > 3 )
300 if( scene )
301 {
302 wxFileName fn( wxString::FromUTF8Unchecked( aFileName ) );
303 wxString output;
304
305 if( proc.GetVRMLType() == VRML_V1 )
306 output = wxT( "_vrml1-" );
307 else
308 output = wxT( "_vrml2-" );
309
310 output.append( fn.GetName() );
311 output.append( wxT(".wrl") );
312 S3D::WriteVRML( output.ToUTF8(), true, (SGNODE*)(scene), true, true );
313 }
314#endif
315
316 return scene;
317}
318
319
320SCENEGRAPH* LoadX3D( const wxString& aFileName )
321{
322 SCENEGRAPH* scene = nullptr;
323 X3DPARSER model;
324 scene = model.Load( aFileName );
325
326 return scene;
327}
328
329
330SCENEGRAPH* Load( char const* aFileName )
331{
332 if( nullptr == aFileName )
333 return nullptr;
334
335 wxString fname = wxString::FromUTF8Unchecked( aFileName );
336
337 if( !wxFileName::FileExists( fname ) )
338 return nullptr;
339
340 LOCALESWITCH switcher;
341
342 SCENEGRAPH* scene = nullptr;
343 wxString ext = wxFileName( fname ).GetExt();
344
345 if( ext == wxT( "x3d" ) || ext == wxT( "X3D" ) )
346 scene = LoadX3D( fname );
347 else
348 scene = LoadVRML( fname, true );
349
350 return scene;
351}
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:185
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
~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:330
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:320
int GetNFilters(void)
Function GetNFilters.
Definition: vrml.cpp:128
#define PLUGIN_VRML_REVNO
Definition: vrml.cpp:55
defines the basic input class for VRML