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