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