From 684e41358a54add73167cbbb124dc8e049853be4 Mon Sep 17 00:00:00 2001 From: Cirilo Bernardo Date: Mon, 22 Feb 2016 19:59:07 +1100 Subject: [PATCH] Added support for VRML2 Inline{} --- plugins/3d/vrml/v2/vrml2_base.cpp | 128 ++++++++++++-- plugins/3d/vrml/v2/vrml2_base.h | 7 +- plugins/3d/vrml/v2/vrml2_inline.cpp | 257 ++++++++++++++++++++++++++++ plugins/3d/vrml/v2/vrml2_inline.h | 65 +++++++ plugins/3d/vrml/vrml.cpp | 12 +- plugins/3d/vrml/wrlproc.cpp | 7 +- 6 files changed, 446 insertions(+), 30 deletions(-) create mode 100644 plugins/3d/vrml/v2/vrml2_inline.cpp create mode 100644 plugins/3d/vrml/v2/vrml2_inline.h diff --git a/plugins/3d/vrml/v2/vrml2_base.cpp b/plugins/3d/vrml/v2/vrml2_base.cpp index c8aa3efcde..87d6376b1b 100644 --- a/plugins/3d/vrml/v2/vrml2_base.cpp +++ b/plugins/3d/vrml/v2/vrml2_base.cpp @@ -22,6 +22,9 @@ */ #include +#include +#include +#include #include "vrml2_base.h" #include "vrml2_transform.h" @@ -36,9 +39,12 @@ #include "vrml2_color.h" #include "vrml2_box.h" #include "vrml2_switch.h" +#include "vrml2_inline.h" #include "plugins/3dapi/ifsg_all.h" +SCENEGRAPH* LoadVRML( const wxString& aFileName, bool useInline ); + WRL2BASE::WRL2BASE() : WRL2NODE() { m_useInline = false; @@ -49,6 +55,22 @@ WRL2BASE::WRL2BASE() : WRL2NODE() WRL2BASE::~WRL2BASE() { + std::map< std::string, SGNODE* >::iterator iS = m_inlineModels.begin(); + std::map< std::string, SGNODE* >::iterator eS = m_inlineModels.end(); + + while( iS != eS ) + { + SGNODE* np = iS->second; + + // destroy any orphaned Inline{} node data + if( np && NULL == S3D::GetSGNodeParent( np ) ) + S3D::DestroyNode( np ); + + ++iS; + } + + m_inlineModels.clear(); + return; } @@ -78,28 +100,50 @@ bool WRL2BASE::GetEnableInline( void ) } -SGNODE* WRL2BASE::AddInlineData( const std::string& aName, WRL2INLINE* aObject ) +SGNODE* WRL2BASE::GetInlineData( const std::string& aName ) { - std::map< std::string, WRL2INLINE* >::iterator dp = m_inlineModels.find( aName ); - // XXX; - // qwerty; - return NULL; -} + if( aName.empty() ) + return NULL; + std::map< std::string, SGNODE* >::iterator dp = m_inlineModels.find( aName ); -SGNODE* WRL2BASE::GetInlineData( const std::string& aName, WRL2INLINE* aObject ) -{ - // XXX; - // qwerty; - return NULL; -} + if( dp != m_inlineModels.end() ) + return dp->second; + wxString tname; -void WRL2BASE::DelInlineData( const std::string& aName, WRL2INLINE* aObject ) -{ - // XXX; - // qwerty; - return; + if( aName.find( "file://", 0, 7 ) == 0 ) + { + if( aName.length() <= 7 ) + return NULL; + + tname = wxString::FromUTF8Unchecked( aName.substr( 7 ).c_str() ); + } + else + { + tname = wxString::FromUTF8Unchecked( aName.c_str() ); + } + + wxFileName fn; + fn.Assign( tname ); + + if( !fn.Normalize() ) + { + m_inlineModels.insert( std::pair< std::string, SGNODE* >( aName, NULL ) ); + return NULL; + } + + SCENEGRAPH* sp = LoadVRML( fn.GetFullPath(), false ); + + if( NULL == sp ) + { + m_inlineModels.insert( std::pair< std::string, SGNODE* >( aName, NULL ) ); + return NULL; + } + + m_inlineModels.insert( std::pair< std::string, SGNODE* >( aName, (SGNODE*)sp ) ); + + return (SGNODE*)sp; } @@ -587,6 +631,13 @@ bool WRL2BASE::ReadNode( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ) break; + case WRL2_INLINE: + + if( !readInline( proc, aParent, aNode ) ) + return false; + + break; + // // items not implemented or for optional future implementation: // @@ -602,7 +653,6 @@ bool WRL2BASE::ReadNode( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ) case WRL2_FOG: case WRL2_FONTSTYLE: case WRL2_IMAGETEXTURE: - case WRL2_INLINE: case WRL2_LOD: case WRL2_MOVIETEXTURE: case WRL2_NAVIGATIONINFO: @@ -910,6 +960,47 @@ bool WRL2BASE::readSwitch( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ) } +bool WRL2BASE::readInline( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ) +{ + if( NULL != aNode ) + *aNode = NULL; + + if( !m_useInline ) + { + size_t line = 0; + size_t column = 0; + proc.GetFilePosData( line, column ); + + if( !proc.DiscardNode() ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << proc.GetError() << "\n"; + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] could not discard Inline node at line " << line; + std::cerr << ", column " << column << "\n"; + #endif + + return false; + } + + return true; + } + + WRL2INLINE* np = new WRL2INLINE( aParent ); + + if( !np->Read( proc, this ) ) + { + delete np; + return false; + } + + if( NULL != aNode ) + *aNode = (WRL2NODE*) np; + + return true; +} + + SGNODE* WRL2BASE::TranslateToSG( SGNODE* aParent ) { if( m_Children.empty() ) @@ -980,6 +1071,7 @@ SGNODE* WRL2BASE::TranslateToSG( SGNODE* aParent ) case WRL2_TRANSFORM: case WRL2_SWITCH: + case WRL2_INLINE: if( NULL != (*sC)->TranslateToSG( topNode.GetRawPtr() ) ) test = true; diff --git a/plugins/3d/vrml/v2/vrml2_base.h b/plugins/3d/vrml/v2/vrml2_base.h index 377ff5f04e..36ba710912 100644 --- a/plugins/3d/vrml/v2/vrml2_base.h +++ b/plugins/3d/vrml/v2/vrml2_base.h @@ -77,8 +77,9 @@ private: bool readColor( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ); bool readBox( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ); bool readSwitch( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ); + bool readInline( WRLPROC& proc, WRL2NODE* aParent, WRL2NODE** aNode ); - std::map< std::string, WRL2INLINE* > m_inlineModels; + std::map< std::string, SGNODE* > m_inlineModels; public: @@ -94,9 +95,7 @@ public: bool GetEnableInline( void ); // functions to manipulate Inline{} objects - SGNODE* AddInlineData( const std::string& aName, WRL2INLINE* aObject ); - SGNODE* GetInlineData( const std::string& aName, WRL2INLINE* aObject ); - void DelInlineData( const std::string& aName, WRL2INLINE* aObject ); + SGNODE* GetInlineData( const std::string& aName ); // function to read entire VRML file bool Read( WRLPROC& proc ); diff --git a/plugins/3d/vrml/v2/vrml2_inline.cpp b/plugins/3d/vrml/v2/vrml2_inline.cpp new file mode 100644 index 0000000000..f7c12c48ce --- /dev/null +++ b/plugins/3d/vrml/v2/vrml2_inline.cpp @@ -0,0 +1,257 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 Cirilo Bernardo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include + +#include "vrml2_inline.h" +#include "vrml2_base.h" +#include "plugins/3dapi/ifsg_all.h" + + +WRL2INLINE::WRL2INLINE() : WRL2NODE() +{ + m_Type = WRL2_INLINE; + m_Parent = NULL; + + return; +} + + +WRL2INLINE::WRL2INLINE( WRL2NODE* aParent ) : WRL2NODE() +{ + m_Type = WRL2_INLINE; + m_Parent = aParent; + + if( NULL != m_Parent ) + m_Parent->AddChildNode( this ); + + return; +} + + +WRL2INLINE::~WRL2INLINE() +{ + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 2 ) + std::cerr << " * [INFO] Destroying Inline node\n"; + #endif + return; +} + + +bool WRL2INLINE::isDangling( void ) +{ + // this node is never dangling + return false; +} + + +bool WRL2INLINE::Read( WRLPROC& proc, WRL2BASE* aTopNode ) +{ + if( aTopNode == NULL || aTopNode->GetNodeType() != WRL2_BASE ) + return false; + + m_VRML2Base = aTopNode; + size_t line, column; + proc.GetFilePosData( line, column ); + char tok = proc.Peek(); + + if( proc.eof() ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] bad file format; unexpected eof at line "; + std::cerr << line << ", column " << column << "\n"; + #endif + return false; + } + + if( '{' != tok ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << proc.GetError() << "\n"; + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] bad file format; expecting '{' but got '" << tok; + std::cerr << "' at line " << line << ", column " << column << "\n"; + #endif + + return false; + } + + proc.Pop(); + + while( ( tok = proc.Peek() ) ) + { + std::string glob; + + if( tok == '}' ) + { + proc.Pop(); + return true; + } + + if( !proc.ReadName( glob ) ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << proc.GetError() << "\n"; + #endif + + return false; + } + + proc.GetFilePosData( line, column ); + + // expecting one of 'url', 'bboxCenter', 'bboxSize' + if( !glob.compare( "url" ) ) + { + if( !proc.ReadMFString( url ) ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] invalid url at line " << line << ", column "; + std::cerr << column << "\n"; + std::cerr << " * [INFO] file: '" << proc.GetFileName() << "'\n"; + std::cerr << " * [INFO] message: '" << proc.GetError() << "'\n"; + #endif + return false; + } + } + else if( !glob.compare( "bboxCenter" ) ) + { + if( !proc.ReadSFVec3f( bboxCenter ) ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] invalid bboxCenter at line " << line << ", column "; + std::cerr << column << "\n"; + std::cerr << " * [INFO] file: '" << proc.GetFileName() << "'\n"; + std::cerr << " * [INFO] message: '" << proc.GetError() << "'\n"; + #endif + return false; + } + } + else if( !glob.compare( "bboxSize" ) ) + { + if( !proc.ReadSFVec3f( bboxSize ) ) + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] invalid bboxSize at line " << line << ", column "; + std::cerr << column << "\n"; + std::cerr << " * [INFO] file: '" << proc.GetFileName() << "'\n"; + std::cerr << " * [INFO] message: '" << proc.GetError() << "'\n"; + #endif + return false; + } + } + else + { + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] bad Inline at line " << line << ", column "; + std::cerr << column << "\n"; + std::cerr << " * [INFO] file: '" << proc.GetFileName() << "'\n"; + #endif + + return false; + } + } + + proc.GetFilePosData( line, column ); + + #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] bad Inline at line " << line << ", column "; + std::cerr << column << " (no closing brace)\n"; + std::cerr << " * [INFO] file: '" << proc.GetFileName() << "'\n"; + #endif + + return false; +} + + +bool WRL2INLINE::AddRefNode( WRL2NODE* aNode ) +{ + // this node may not own or reference any other node + + #ifdef DEBUG_VRML2 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] AddRefNode is not applicable\n"; + #endif + + return false; +} + + +bool WRL2INLINE::AddChildNode( WRL2NODE* aNode ) +{ + // this node may not own or reference any other node + + #ifdef DEBUG_VRML2 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] AddChildNode is not applicable\n"; + #endif + + return false; +} + + +SGNODE* WRL2INLINE::TranslateToSG( SGNODE* aParent ) +{ + if( NULL == aParent || NULL == m_VRML2Base ) + return NULL; + + if( url.empty() ) + return NULL; + + S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent ); + + if( ptype != S3D::SGTYPE_TRANSFORM ) + { + #ifdef DEBUG_VRML2 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] Inline does not have a Transform parent (parent ID: "; + std::cerr << ptype << ")\n"; + #endif + + return NULL; + } + + SGNODE* np = m_VRML2Base->GetInlineData( url.front() ); + + if( NULL == np ) + return NULL; + + bool OK = false; + + if( NULL == S3D::GetSGNodeParent( np ) ) + OK = S3D::AddSGNodeChild( aParent, np ); + else + OK = S3D::AddSGNodeRef( aParent, np ); + + if( !OK ) + return NULL; + + return np; +} diff --git a/plugins/3d/vrml/v2/vrml2_inline.h b/plugins/3d/vrml/v2/vrml2_inline.h new file mode 100644 index 0000000000..d12293ae3b --- /dev/null +++ b/plugins/3d/vrml/v2/vrml2_inline.h @@ -0,0 +1,65 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 Cirilo Bernardo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vrml2_inline.h + */ + + +#ifndef VRML2_INLINE_H +#define VRML2_INLINE_H + +#include "vrml2_node.h" + +class WRL2BASE; +class SGNODE; + +/** + * Class WRL2INLINE + */ +class WRL2INLINE : public WRL2NODE +{ +private: + WRL2BASE* m_VRML2Base; + std::vector< std::string > url; + WRLVEC3F bboxCenter; + WRLVEC3F bboxSize; + +public: + + // functions inherited from WRL2NODE + bool isDangling( void ); + +public: + WRL2INLINE(); + WRL2INLINE( WRL2NODE* aParent ); + virtual ~WRL2INLINE(); + + // functions inherited from WRL2NODE + bool Read( WRLPROC& proc, WRL2BASE* aTopNode ); + bool AddRefNode( WRL2NODE* aNode ); + bool AddChildNode( WRL2NODE* aNode ); + SGNODE* TranslateToSG( SGNODE* aParent ); +}; + +#endif // VRML2_INLINE_H diff --git a/plugins/3d/vrml/vrml.cpp b/plugins/3d/vrml/vrml.cpp index 12a0d78d22..4f2f009e89 100644 --- a/plugins/3d/vrml/vrml.cpp +++ b/plugins/3d/vrml/vrml.cpp @@ -48,9 +48,9 @@ #define PLUGIN_VRML_MAJOR 1 -#define PLUGIN_VRML_MINOR 2 +#define PLUGIN_VRML_MINOR 3 #define PLUGIN_VRML_PATCH 0 -#define PLUGIN_VRML_REVNO 1 +#define PLUGIN_VRML_REVNO 0 const char* GetKicadPluginName( void ) @@ -175,7 +175,7 @@ public: }; -SCENEGRAPH* LoadVRML( const wxString& aFileName ) +SCENEGRAPH* LoadVRML( const wxString& aFileName, bool useInline ) { FILE_LINE_READER* modelFile = NULL; SCENEGRAPH* scene = NULL; @@ -206,8 +206,8 @@ SCENEGRAPH* LoadVRML( const wxString& aFileName ) WRL1BASE* bp = new WRL1BASE; - // allow Inline{} files to be included - bp->SetEnableInline( true ); + // allow or ignore Inline{} files + bp->SetEnableInline( useInline ); if( !bp->Read( proc ) ) { @@ -310,7 +310,7 @@ SCENEGRAPH* Load( char const* aFileName ) if( ext == "x3d" || ext == "X3D" ) scene = LoadX3D( fname ); else - scene = LoadVRML( fname ); + scene = LoadVRML( fname, true ); return scene; } diff --git a/plugins/3d/vrml/wrlproc.cpp b/plugins/3d/vrml/wrlproc.cpp index be8a57fa35..54afce3ca1 100644 --- a/plugins/3d/vrml/wrlproc.cpp +++ b/plugins/3d/vrml/wrlproc.cpp @@ -687,14 +687,17 @@ bool WRLPROC::ReadString( std::string& aSFString ) continue; } - - if( '"' == m_buf[m_bufpos] ) + else if( '"' == m_buf[m_bufpos] ) { if( isesc ) aSFString.append( 1, '"' ); else break; } + else + { + aSFString.append( 1, m_buf[m_bufpos] ); + } // ensure that the backslash escape cannot extend beyond the first character isesc = false;