From 79e05646220c407b88f4b0441ef222a997d30565 Mon Sep 17 00:00:00 2001 From: Cirilo Bernardo Date: Tue, 5 Jan 2016 16:38:53 +1100 Subject: [PATCH] Work in progress: VRML1 plugin --- plugins/3d/vrml/v1/vrml1_base.cpp | 420 +++++++++++++++++++++++ plugins/3d/vrml/v1/vrml1_base.h | 87 +++++ plugins/3d/vrml/v1/vrml1_node.cpp | 449 +++++++++++++++++++++++++ plugins/3d/vrml/v1/vrml1_node.h | 251 ++++++++++++++ plugins/3d/vrml/v1/vrml1_separator.cpp | 256 ++++++++++++++ plugins/3d/vrml/v1/vrml1_separator.h | 52 +++ 6 files changed, 1515 insertions(+) create mode 100644 plugins/3d/vrml/v1/vrml1_base.cpp create mode 100644 plugins/3d/vrml/v1/vrml1_base.h create mode 100644 plugins/3d/vrml/v1/vrml1_node.cpp create mode 100644 plugins/3d/vrml/v1/vrml1_node.h create mode 100644 plugins/3d/vrml/v1/vrml1_separator.cpp create mode 100644 plugins/3d/vrml/v1/vrml1_separator.h diff --git a/plugins/3d/vrml/v1/vrml1_base.cpp b/plugins/3d/vrml/v1/vrml1_base.cpp new file mode 100644 index 0000000000..6d7878617a --- /dev/null +++ b/plugins/3d/vrml/v1/vrml1_base.cpp @@ -0,0 +1,420 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015-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 "vrml1_base.h" +#include "vrml1_separator.h" +#include "plugins/3dapi/ifsg_all.h" + + +WRL1BASE::WRL1BASE() : WRL1NODE( NULL ) +{ + m_useInline = false; + m_Type = WRL1_BASE; + m_dictionary = new NAMEREGISTER; + return; +} + + +WRL1BASE::~WRL1BASE() +{ + if( m_dictionary ) + delete m_dictionary; + + return; +} + + +// functions inherited from WRL1NODE +bool WRL1BASE::SetParent( WRL1NODE* aParent ) +{ + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] attempting to set parent on WRL1BASE node\n"; + #endif + + return false; +} + + +void WRL1BASE::SetEnableInline( bool enable ) +{ + m_useInline = enable; + return; +} + + +bool WRL1BASE::GetEnableInline( void ) +{ + return m_useInline; +} + + +SGNODE* WRL1BASE::AddInlineData( const std::string& aName, WRL1INLINE* aObject ) +{ + std::map< std::string, WRL1INLINE* >::iterator dp = m_inlineModels.find( aName ); + // XXX; + // qwerty; + return NULL; +} + + +SGNODE* WRL1BASE::GetInlineData( const std::string& aName, WRL1INLINE* aObject ) +{ + // XXX; + // qwerty; + return NULL; +} + + +void WRL1BASE::DelInlineData( const std::string& aName, WRL1INLINE* aObject ) +{ + // XXX; + // qwerty; + return; +} + + +std::string WRL1BASE::GetName( void ) +{ + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] attempting to extract name from virtual base node\n"; + #endif + + return std::string( "" ); +} + + +bool WRL1BASE::SetName( const std::string& aName ) +{ + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] attempting to set name on virtual base node\n"; + #endif + return false; +} + + +bool WRL1BASE::Read( WRLPROC& proc ) +{ + if( proc.GetVRMLType() != VRML_V1 ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] no open file or file is not a VRML2 file\n"; + #endif + return false; + } + + WRL1NODE* node = NULL; + + while( ReadNode( proc, this, &node ) && !proc.eof() ); + + if( proc.eof() ) + return true; + + return false; +} + + +bool WRL1BASE::implementUse( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ) +{ + if( NULL != aNode ) + *aNode = NULL; + + if( !aParent ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] invoked with NULL parent\n"; + #endif + + return false; + } + + std::string glob; + + if( !proc.ReadName( glob ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << proc.GetError() << "\n"; + #endif + + return false; + } + + WRL1NODE* ref = aParent->FindNode( glob ); + + // return 'true' - the file may be defective but it may still be somewhat OK + if( NULL == ref ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] node '" << glob << "' not found\n"; + #endif + + return true; + } + + if( !aParent->AddRefNode( ref ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] failed to add node '" << glob << "' ("; + std::cerr << ref->GetNodeTypeName( ref->GetNodeType() ) << ") to parent of type "; + std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() ) << "\n"; + #endif + + return false; + } + + if( NULL != aNode ) + *aNode = ref; + + return true; +} + + +bool WRL1BASE::implementDef( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ) +{ + if( NULL != aNode ) + *aNode = NULL; + + if( NULL == aParent ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] invalid parent pointer (NULL)\n"; + #endif + + return false; + } + + std::string glob; + WRL1NODE* lnode = NULL; + + if( !proc.ReadName( glob ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << proc.GetError() << "\n"; + #endif + + return false; + } + + size_t line, column; + proc.GetFilePosData( line, column ); + + if( ReadNode( proc, aParent, &lnode ) ) + { + if( NULL != aNode ) + *aNode = lnode; + + if( lnode && !lnode->SetName( glob ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + size_t line, column; + proc.GetFilePosData( line, column ); + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] bad formatting (invalid name) at line"; + std::cerr << line << ", column " << column << "\n"; + #endif + + return false; + } + + if( !m_dictionary ) + return false; + + m_dictionary->AddName( glob, lnode ); + + return true; + } + + return false; +} + + +bool WRL1BASE::ReadNode( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ) +{ + // This function reads a node and stores a pointer to it in aNode. + // A value 'true' is returned if a node is successfully read or, + // if the node is not supported, successfully discarded. Callers + // must always check the value of aNode when the function returns + // 'true' since it will be NULL if the node type is not supported. + + if( NULL != aNode ) + *aNode = NULL; + + if( NULL == aParent ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] invalid parent pointer (NULL)\n"; + #endif + + return false; + } + + std::string glob; + WRL1NODES ntype; + + if( !proc.ReadName( glob ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + if( !proc.eof() ) + { + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << proc.GetError() << "\n"; + } + #endif + + return false; + } + + // Process node name: + // the names encountered at this point should be one of the + // built-in node names or one of: + // DEF, USE + if( !glob.compare( "USE" ) ) + { + if( !implementUse( proc, aParent, aNode ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << proc.GetError() << "\n"; + #endif + + return false; + } + + return true; + } + + if( !glob.compare( "DEF" ) ) + { + if( !implementDef( proc, aParent, aNode ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << proc.GetError() << "\n"; + #endif + + return false; + } + + return true; + } + + ntype = getNodeTypeID( glob ); + size_t line = 0; + size_t column = 0; + proc.GetFilePosData( line, column ); + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 2 ) + std::cerr << " * [INFO] Processing node '" << glob << "' ID: " << ntype << "\n"; + #endif + + switch( ntype ) + { + // + // items to be implemented: + // + case WRL1_SEPARATOR: + + if( !readSeparator( proc, aParent, aNode ) ) + return false; + + break; + + // + // items not implemented or for optional future implementation: + // + default: + + proc.GetFilePosData( line, column ); + + if( !proc.DiscardNode() ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << proc.GetError() << "\n"; + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] could not discard node at line " << line; + std::cerr << ", column " << column << "\n"; + #endif + + return false; + } + + break; + } + + return true; +} + + +bool WRL1BASE::Read( WRLPROC& proc, WRL1BASE* aTopNode ) +{ + // this function makes no sense in the base node + #ifdef DEBUG_VRML1 + std::cerr << proc.GetError() << "\n"; + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] this method must never be invoked on a WRL1BASE object\n"; + #endif + + return false; +} + + +bool WRL1BASE::readSeparator( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ) +{ + if( NULL != aNode ) + *aNode = NULL; + + WRL1SEPARATOR* np = new WRL1SEPARATOR( m_dictionary, aParent ); + + if( !np->Read( proc, this ) ) + { + delete np; + return false; + } + + if( NULL != aNode ) + *aNode = (WRL1NODE*) np; + + return true; +} + + +SGNODE* WRL1BASE::TranslateToSG( SGNODE* aParent, bool calcNormals ) +{ + if( m_Items.empty() ) + return NULL; + + // XXX - TO BE IMPLEMENTED + + return NULL; +} diff --git a/plugins/3d/vrml/v1/vrml1_base.h b/plugins/3d/vrml/v1/vrml1_base.h new file mode 100644 index 0000000000..7b96d49173 --- /dev/null +++ b/plugins/3d/vrml/v1/vrml1_base.h @@ -0,0 +1,87 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015-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 vrmlv2_node.h + * defines the base class for VRML1.0 nodes + */ + +#ifndef VRML1_BASE_H +#define VRML1_BASE_H + +#include +#include +#include + +#include "vrml1_node.h" + +class SGNODE; +class WRL1INLINE; + +/** + * Class WRL1BASE + * represents the top node of a VRML1 model + */ +class WRL1BASE : public WRL1NODE +{ +private: + bool m_useInline; + + // handle cases of USE / DEF + bool implementUse( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ); + bool implementDef( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ); + + bool readSeparator( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ); + + std::map< std::string, WRL1INLINE* > m_inlineModels; + +public: + WRL1BASE(); + virtual ~WRL1BASE(); + + // function to enable/disable Inline{} expansion + void SetEnableInline( bool enable ); + bool GetEnableInline( void ); + + // functions to manipulate Inline{} objects + SGNODE* AddInlineData( const std::string& aName, WRL1INLINE* aObject ); + SGNODE* GetInlineData( const std::string& aName, WRL1INLINE* aObject ); + void DelInlineData( const std::string& aName, WRL1INLINE* aObject ); + + // function to read entire VRML file + bool Read( WRLPROC& proc ); + + // read in a VRML node + bool ReadNode( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode ); + + // overrides + virtual std::string GetName( void ); + virtual bool SetName( const std::string& aName ); + + // functions inherited from WRL1NODE + bool Read( WRLPROC& proc, WRL1BASE* aTopNode ); + bool SetParent( WRL1NODE* aParent ); + SGNODE* TranslateToSG( SGNODE* aParent, bool calcNormals ); +}; + +#endif // VRML1_BASE_H diff --git a/plugins/3d/vrml/v1/vrml1_node.cpp b/plugins/3d/vrml/v1/vrml1_node.cpp new file mode 100644 index 0000000000..24f5d78188 --- /dev/null +++ b/plugins/3d/vrml/v1/vrml1_node.cpp @@ -0,0 +1,449 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015-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 +#include +#include +#include +#include +#include + +#include "vrml1_node.h" + + +bool NAMEREGISTER::AddName( const std::string aName, WRL1NODE* aNode ) +{ + if( aName.empty() ) + return false; + + std::map< std::string, WRL1NODE* >::iterator ir = reg.find( aName ); + + if( ir != reg.end() ) + reg.erase( ir ); + + reg.insert( std::pair< std::string, WRL1NODE* >( aName, aNode ) ); + + return true; +} + + +bool NAMEREGISTER::DelName( const std::string aName, WRL1NODE* aNode ) +{ + if( aName.empty() ) + return false; + + std::map< std::string, WRL1NODE* >::iterator ir = reg.find( aName ); + + if( ir != reg.end() && ir->second == aNode ) + { + reg.erase( ir ); + return true; + } + + return false; +} + + +WRL1NODE* NAMEREGISTER::FindName( const std::string aName ) +{ + if( aName.empty() ) + return NULL; + + std::map< std::string, WRL1NODE* >::iterator ir = reg.find( aName ); + + if( ir != reg.end() ) + return ir->second; + + return NULL; +} + + +typedef std::pair< std::string, WRL1NODES > NODEITEM; +typedef std::map< std::string, WRL1NODES > NODEMAP; +static NODEMAP nodenames; + + +WRL1NODE::WRL1NODE( NAMEREGISTER* aDictionary ) +{ + m_sgNode = NULL; + m_Parent = NULL; + m_Type = WRL1_END; + m_dictionary = aDictionary; + + if( nodenames.empty() ) + { + nodenames.insert( NODEITEM( "AsciiText", WRL1_ASCIITEXT ) ); + nodenames.insert( NODEITEM( "Cone", WRL1_CONE ) ); + nodenames.insert( NODEITEM( "Coordinate3", WRL1_COORDINATE3 ) ); + nodenames.insert( NODEITEM( "Cube", WRL1_CUBE ) ); + nodenames.insert( NODEITEM( "Cylinder", WRL1_CYLINDER ) ); + nodenames.insert( NODEITEM( "DirectionalLight", WRL1_DIRECTIONALLIGHT ) ); + nodenames.insert( NODEITEM( "FontStyle", WRL1_FONTSTYLE ) ); + nodenames.insert( NODEITEM( "IndexedFaceSet", WRL1_INDEXEDFACESET ) ); + nodenames.insert( NODEITEM( "IndexedLineSet", WRL1_INDEXEDLINESET ) ); + nodenames.insert( NODEITEM( "Info", WRL1_INFO ) ); + nodenames.insert( NODEITEM( "LOD", WRL1_LOD ) ); + nodenames.insert( NODEITEM( "Material", WRL1_MATERIAL ) ); + nodenames.insert( NODEITEM( "MaterialBinding", WRL1_MATERIALBINDING ) ); + nodenames.insert( NODEITEM( "MatrixTransform", WRL1_MATRIXTRANSFORM ) ); + nodenames.insert( NODEITEM( "Normal", WRL1_NORMAL ) ); + nodenames.insert( NODEITEM( "NormalBinding", WRL1_NORMALBINDING ) ); + nodenames.insert( NODEITEM( "OrthographicCamera", WRL1_ORTHOCAMERA ) ); + nodenames.insert( NODEITEM( "PerspectiveCamera", WRL1_PERSPECTIVECAMERA ) ); + nodenames.insert( NODEITEM( "PointLight", WRL1_POINTLIGHT ) ); + nodenames.insert( NODEITEM( "PointSet", WRL1_POINTSET ) ); + nodenames.insert( NODEITEM( "Rotation", WRL1_ROTATION ) ); + nodenames.insert( NODEITEM( "Scale", WRL1_SCALE ) ); + nodenames.insert( NODEITEM( "Separator", WRL1_SEPARATOR ) ); + nodenames.insert( NODEITEM( "ShapeHints", WRL1_SHAPEHINTS ) ); + nodenames.insert( NODEITEM( "Sphere", WRL1_SPHERE ) ); + nodenames.insert( NODEITEM( "SpotLight", WRL1_SPOTLIGHT ) ); + nodenames.insert( NODEITEM( "Switch", WRL1_SWITCH ) ); + nodenames.insert( NODEITEM( "Texture2", WRL1_TEXTURE2 ) ); + nodenames.insert( NODEITEM( "Testure2Transform", WRL1_TEXTURE2TRANSFORM ) ); + nodenames.insert( NODEITEM( "TextureCoordinate2", WRL1_TEXTURECOORDINATE2 ) ); + nodenames.insert( NODEITEM( "Transform", WRL1_TRANSFORM ) ); + nodenames.insert( NODEITEM( "Translation", WRL1_TRANSLATION ) ); + nodenames.insert( NODEITEM( "WWWAnchor", WRL1_WWWANCHOR ) ); + nodenames.insert( NODEITEM( "WWWInline", WRL1_WWWINLINE ) ); + } + + return; +} + + +WRL1NODE::~WRL1NODE() +{ + if( m_dictionary && !m_Name.empty() ) + m_dictionary->DelName( m_Name, this ); + + if( m_Parent ) + m_Parent->unlinkChildNode( this ); + + std::list< WRL1NODE* >::iterator sBP = m_BackPointers.begin(); + std::list< WRL1NODE* >::iterator eBP = m_BackPointers.end(); + + while( sBP != eBP ) + { + (*sBP)->unlinkRefNode( this ); + ++sBP; + } + + m_Refs.clear(); + std::list< WRL1NODE* >::iterator sC = m_Children.begin(); + std::list< WRL1NODE* >::iterator eC = m_Children.end(); + + while( sC != eC ) + { + (*sC)->SetParent( NULL, false ); + delete *sC; + ++sC; + } + + m_Children.clear(); + return; +} + + +void WRL1NODE::addNodeRef( WRL1NODE* aNode ) +{ + // note: for VRML1 we allow even parent nodes to be held as references + m_BackPointers.push_back( aNode ); + + return; +} + + +void WRL1NODE::delNodeRef( WRL1NODE* aNode ) +{ + std::list< WRL1NODE* >::iterator np = + std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode ); + + if( np != m_BackPointers.end() ) + { + m_BackPointers.erase( np ); + return; + } + + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] delNodeRef() did not find its target\n"; + #endif + + return; +} + + +WRL1NODES WRL1NODE::GetNodeType( void ) const +{ + return m_Type; +} + + +WRL1NODE* WRL1NODE::GetParent( void ) const +{ + return m_Parent; +} + + +std::string WRL1NODE::GetName( void ) +{ + return m_Name; +} + + +bool WRL1NODE::SetName( const std::string& aName ) +{ + if( aName.empty() ) + return false; + + if( isdigit( aName[0] ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] invalid node name '" << aName << "' (begins with digit)\n"; + #endif + return false; + } + + // The character '+' is not allowed in names as per the VRML1 specification; + // however many parsers accept them and many bad generators use them so the rules + // have been relaxed here. + #define BAD_CHARS1 "\"\'#,.\\[]{}\x00\x01\x02\x03\x04\x05\x06\x09\x0A\x0B\x0C\x0D\x0E\x0F" + #define BAD_CHARS2 "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + + if( std::string::npos != aName.find_first_of( BAD_CHARS1 ) + || std::string::npos != aName.find_first_of( BAD_CHARS2 ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 1 ) + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] invalid node name '" << aName; + std::cerr<< "' (contains invalid character)\n"; + #endif + return false; + } + + m_Name = aName; + + if( m_dictionary ) + m_dictionary->AddName( aName, this ); + + return true; +} + + +const char* WRL1NODE::GetNodeTypeName( WRL1NODES aNodeType ) const +{ + if( aNodeType < WRL1_BASE || aNodeType >= WRL1_END ) + return "*INVALID_TYPE*"; + + if( aNodeType == WRL1_BASE ) + return "*VIRTUAL_BASE*"; + + NODEMAP::iterator it = nodenames.begin(); + advance( it, (aNodeType - WRL1_BEGIN) ); + + return it->first.c_str(); +} + + +WRL1STATUS* WRL1NODE::GetCurrentSettings( void ) +{ + return &m_current; +} + + +WRL1NODES WRL1NODE::getNodeTypeID( const std::string aNodeName ) +{ + NODEMAP::iterator it = nodenames.find( aNodeName ); + + if( nodenames.end() != it ) + return it->second; + + return WRL1_INVALID; +} + + +std::string WRL1NODE::GetError( void ) +{ + return m_error; +} + + +WRL1NODE* WRL1NODE::FindNode( const std::string& aNodeName ) +{ + if( NULL == m_dictionary ) + return NULL; + + return m_dictionary->FindName( aNodeName ); +} + + +bool WRL1NODE::SetParent( WRL1NODE* aParent, bool doUnlink ) +{ + if( aParent == m_Parent ) + return true; + + if( NULL != m_Parent && doUnlink ) + m_Parent->unlinkChildNode( this ); + + m_Parent = aParent; + + if( NULL != m_Parent ) + m_Parent->AddChildNode( this ); + + return true; +} + + +bool WRL1NODE::AddChildNode( WRL1NODE* aNode ) +{ + if( aNode->GetNodeType() == WRL1_BASE ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] attempting to add a base node to another node\n"; + #endif + return false; + } + + std::list< WRL1NODE* >::iterator sC = m_Children.begin(); + std::list< WRL1NODE* >::iterator eC = m_Children.end(); + + while( sC != eC ) + { + if( *sC == aNode ) + return false; + + ++sC; + } + + aNode->SetParent( this ); + m_Children.push_back( aNode ); + addItem( aNode ); + + return true; +} + + +bool WRL1NODE::AddRefNode( WRL1NODE* aNode ) +{ + if( NULL == aNode ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] NULL passed as node pointer\n"; + #endif + return false; + } + + if( aNode->GetNodeType() == WRL1_BASE ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] attempting to add a base node ref to another base node\n"; + #endif + return false; + } + + // note: the VRML1 spec does not prevent the reuse of a node at + // the same level; for example a Coordinate3 node can be recalled + // at any time to set the current coordinate set. + m_Refs.push_back( aNode ); + addItem( aNode ); + + return true; +} + + +void WRL1NODE::unlinkChildNode( const WRL1NODE* aNode ) +{ + std::list< WRL1NODE* >::iterator sL = m_Children.begin(); + std::list< WRL1NODE* >::iterator eL = m_Children.end(); + + while( sL != eL ) + { + if( *sL == aNode ) + { + m_Children.erase( sL ); + return; + } + + ++sL; + } + + delItem( aNode ); + + return; +} + + +void WRL1NODE::unlinkRefNode( const WRL1NODE* aNode ) +{ + std::list< WRL1NODE* >::iterator sL = m_Refs.begin(); + std::list< WRL1NODE* >::iterator eL = m_Refs.end(); + + while( sL != eL ) + { + if( *sL == aNode ) + { + m_Refs.erase( sL ); + return; + } + + ++sL; + } + + delItem( aNode ); + + return; +} + + +void WRL1NODE::addItem( WRL1NODE* aNode ) +{ + m_Items.push_back( aNode ); + return; +} + + +void WRL1NODE::delItem( const WRL1NODE* aNode ) +{ + std::list< WRL1NODE* >::iterator sL = m_Items.begin(); + std::list< WRL1NODE* >::iterator eL = m_Items.end(); + + while( sL != eL ) + { + if( *sL == aNode ) + { + m_Items.erase( sL ); + return; + } + + ++sL; + } + + return; +} diff --git a/plugins/3d/vrml/v1/vrml1_node.h b/plugins/3d/vrml/v1/vrml1_node.h new file mode 100644 index 0000000000..aa5b12fe63 --- /dev/null +++ b/plugins/3d/vrml/v1/vrml1_node.h @@ -0,0 +1,251 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015-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 vrmlv1_node.h + * defines the base class for VRML1.0 nodes + */ + + +#ifndef VRML1_NODE_H +#define VRML1_NODE_H + +#define GLM_FORCE_RADIANS +#include +#include +#include + +#include +#include +#include + +#include "wrlproc.h" + +class WRL1NODE; + +// a class to hold the dictionary of node DEFs +class NAMEREGISTER +{ +private: + std::map< std::string, WRL1NODE* > reg; + +public: + bool AddName( const std::string aName, WRL1NODE* aNode ); + bool DelName( const std::string aName, WRL1NODE* aNode ); + WRL1NODE* FindName( const std::string aName ); +}; + + +class WRL1BASE; +class SGNODE; + + +// current settings which may affect all subsequent nodes +// during translation / rendering +struct WRL1STATUS +{ + // XXX - as much as possible do not use pointers and if + // pointers are necessary, use the specialized rather + // than base pointers + // material + WRL1NODE* mat; + // material binding + WRL1NODE* matbind; + // normals + WRL1NODE* norm; + // normal binding + WRL1NODE* normbind; + // coordinate3 + WRL1NODE* coord; + // transform + glm::dmat4 txmatrix; + + WRL1STATUS() + { + Init(); + return; + } + + void Init() + { + mat = NULL; + matbind = NULL; + norm = NULL; + normbind = NULL; + coord = NULL; + txmatrix = glm::scale( glm::dmat4( 1.0 ), glm::dvec3( 1.0 ) ); + return; + } +}; + + +/** + * Class WRL1NODE + * represents the base class of all VRML2 nodes + */ +class WRL1NODE +{ +private: + void addItem( WRL1NODE* aNode ); + void delItem( const WRL1NODE* aNode ); + +protected: + WRL1NODE* m_Parent; // pointer to parent node; may be NULL for top level node + WRL1NODES m_Type; // type of VRML node + std::string m_Name; // name to use for referencing the node by name + + std::list< WRL1NODE* > m_BackPointers; // nodes which hold a reference to this + std::list< WRL1NODE* > m_Children; // nodes owned by this node + std::list< WRL1NODE* > m_Refs; // nodes referenced by this node + std::list< WRL1NODE* > m_Items; // all nodes in order of addition + std::string m_error; + + WRL1STATUS m_current; // current settings + SGNODE* m_sgNode; // the SGNODE representation of the display data + + // note: once a node is orphaned from a base node it must never access + // the dictionary since there is no guarantee the dictionary had not + // been destroyed. It may be possible to enforce this rule via the + // SetParent() routine if we implement a GetDictionary() function so + // that a node can obtain the dictionary of its parent. Note that the + // dictionary must be propagated to all children as well - perhaps + // this is best done via a SetDictionary() function. + NAMEREGISTER* m_dictionary; + +public: + + /** + * Function GetCurrentSettings + * is used by children to retrieve and perhaps modify the + * current settings of the parent + */ + WRL1STATUS* GetCurrentSettings( void ); + + /** + * Function getNodeTypeID + * returns the ID based on the given aNodeName or WRL1_INVALID (WRL1_END) + * if no such node name exists + */ + WRL1NODES getNodeTypeID( const std::string aNodeName ); + + /** + * Function unlinkChild + * removes references to an owned child; it is invoked by the child upon destruction + * to ensure that the parent has no invalid references. + * + * @param aNode is the child which is being deleted + */ + virtual void unlinkChildNode( const WRL1NODE* aNode ); + + /** + * Function unlinkRef + * removes pointers to a referenced node; it is invoked by the referenced node + * upon destruction to ensure that the referring node has no invalid references. + * + * @param aNode is the node which is being deleted + */ + virtual void unlinkRefNode( const WRL1NODE* aNode ); + + /** + * Function addNodeRef + * adds a pointer to a node which references, but does not own, this node. + * Such back-pointers are required to ensure that invalidated references + * are removed when a node is deleted + * + * @param aNode is the node holding a reference to this object + */ + void addNodeRef( WRL1NODE* aNode ); + + /** + * Function delNodeRef + * removes a pointer to a node which references, but does not own, this node. + * + * @param aNode is the node holding a reference to this object + */ + void delNodeRef( WRL1NODE* aNode ); + +public: + WRL1NODE( NAMEREGISTER* aDictionary ); + virtual ~WRL1NODE(); + + // read data via the given file processor and WRL1BASE object + virtual bool Read( WRLPROC& proc, WRL1BASE* aTopNode ) = 0; + + /** + * Function GetNodeType + * returns the type of this node instance + */ + WRL1NODES GetNodeType( void ) const; + + /** + * Function GetParent + * returns a pointer to the parent SGNODE of this object + * or NULL if the object has no parent (ie. top level transform) + */ + WRL1NODE* GetParent( void ) const; + + /** + * Function SetParent + * sets the parent WRL1NODE of this object. + * + * @param aParent [in] is the desired parent node + * @param doUnlink indicates that the child must be unlinked from the parent + * @return true if the operation succeeds; false if + * the given node is not allowed to be a parent to + * the derived object. + */ + virtual bool SetParent( WRL1NODE* aParent, bool doUnlink = true ); + + virtual std::string GetName( void ); + virtual bool SetName( const std::string& aName ); + + const char* GetNodeTypeName( WRL1NODES aNodeType ) const; + + /** + * Function FindNode searches the tree of linked nodes and returns a + * reference to the current node with the given name. The reference + * is then typically added to another node via AddRefNode(). + * + * @param aNodeName is the name of the node to search for + * @return is a valid node pointer on success, otherwise NULL + */ + virtual WRL1NODE* FindNode( const std::string& aNodeName ); + + virtual bool AddChildNode( WRL1NODE* aNode ); + + virtual bool AddRefNode( WRL1NODE* aNode ); + + std::string GetError( void ); + + /** + * Function TranslateToSG + * produces a representation of the data using the intermediate + * scenegraph structures of the kicad_3dsg library. + * + * @param aParent is a pointer to the parent SG node + * @return is non-NULL on success + */ + virtual SGNODE* TranslateToSG( SGNODE* aParent, bool calcNormals ) = 0; +}; + +#endif // VRML1_NODE_H diff --git a/plugins/3d/vrml/v1/vrml1_separator.cpp b/plugins/3d/vrml/v1/vrml1_separator.cpp new file mode 100644 index 0000000000..d8eef24530 --- /dev/null +++ b/plugins/3d/vrml/v1/vrml1_separator.cpp @@ -0,0 +1,256 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015-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 "vrml1_base.h" +#include "vrml1_separator.h" +#include "plugins/3dapi/ifsg_all.h" + + +WRL1SEPARATOR::WRL1SEPARATOR( NAMEREGISTER* aDictionary ) : WRL1NODE( aDictionary ) +{ + m_Type = WRL1_SEPARATOR; + return; +} + + +WRL1SEPARATOR::WRL1SEPARATOR( NAMEREGISTER* aDictionary, WRL1NODE* aParent ) : + WRL1NODE( aDictionary ) +{ + m_Type = WRL1_SEPARATOR; + m_Parent = aParent; + + if( NULL != m_Parent ) + m_Parent->AddChildNode( this ); + + return; +} + + +WRL1SEPARATOR::~WRL1SEPARATOR() +{ + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 2 ) + std::cerr << " * [INFO] Destroying Transform with " << m_Children.size(); + std::cerr << " children, " << m_Refs.size() << " references and "; + std::cerr << m_BackPointers.size() << " backpointers\n"; + #endif + return; +} + + +// functions inherited from WRL1NODE +bool WRL1SEPARATOR::Read( WRLPROC& proc, WRL1BASE* aTopNode ) +{ + /* + * Structure of a Transform node (p.120): + * + * Transform { + * eventIn MFNode addChildren + * eventIn MFNode removeChildren + * exposedField SFVec3f center 0 0 0 + * exposedField MFNode children [] + * exposedField SFRotation rotation 0 0 1 0 + * exposedField SFVec3f scale 1 1 1 + * exposedField SFRotation scaleOrientation 0 0 1 0 + * exposedField SFVec3f translation 0 0 0 + * field SFVec3f bboxCenter 0 0 0 + * field SFVec3f bboxSize 0 0 0 + * } + */ + + if( NULL == aTopNode ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] aTopNode is NULL\n"; + #endif + return false; + } + + size_t line, column; + proc.GetFilePosData( line, column ); + + char tok = proc.Peek(); + + if( proc.eof() ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 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_VRML1 ) && ( DEBUG_VRML1 > 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(); + std::string glob; + + while( true ) + { + if( proc.Peek() == '}' ) + { + proc.Pop(); + break; + } + + proc.GetFilePosData( line, column ); + + if( !aTopNode->ReadNode( proc, this, NULL ) ) + { + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 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( proc.Peek() == ',' ) + proc.Pop(); + + } // while( true ) -- reading contents of Separator{} + + return true; +} + + +SGNODE* WRL1SEPARATOR::TranslateToSG( SGNODE* aParent, bool calcNormals ) +{ + return NULL; + + /* + #if defined( DEBUG_VRML1 ) && ( DEBUG_VRML1 > 2 ) + std::cerr << " * [INFO] Translating Transform with " << m_Children.size(); + std::cerr << " children, " << m_Refs.size() << " references and "; + std::cerr << m_BackPointers.size() << " backpointers\n"; + #endif + + if( m_Children.empty() && m_Refs.empty() ) + return NULL; + + S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent ); + + if( NULL != aParent && ptype != S3D::SGTYPE_TRANSFORM ) + { + #ifdef DEBUG_VRML1 + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [BUG] Transform does not have a Transform parent (parent ID: "; + std::cerr << ptype << ")\n"; + #endif + + return NULL; + } + + if( m_sgNode ) + { + if( NULL != aParent ) + { + if( NULL == S3D::GetSGNodeParent( m_sgNode ) + && !S3D::AddSGNodeChild( aParent, m_sgNode ) ) + { + return NULL; + } + else if( aParent != S3D::GetSGNodeParent( m_sgNode ) + && !S3D::AddSGNodeRef( aParent, m_sgNode ) ) + { + return NULL; + } + } + + return m_sgNode; + } + + IFSG_TRANSFORM txNode( aParent ); + + std::list< WRL1NODE* >::iterator sC = m_Children.begin(); + std::list< WRL1NODE* >::iterator eC = m_Children.end(); + WRL1NODES type; + + // Include only the following in a Transform node: + // Shape + // Switch + // Transform + // Inline + bool test = false; // set to true if there are any subnodes for display + + for( int i = 0; i < 2; ++i ) + { + while( sC != eC ) + { + type = (*sC)->GetNodeType(); + + switch( type ) + { + case WRL1_SHAPE: + case WRL1_SWITCH: + case WRL1_INLINE: + case WRL1_SEPARATOR: + + if( NULL != (*sC)->TranslateToSG( txNode.GetRawPtr(), calcNormals ) ) + test = true; + + break; + + default: + break; + } + + ++ sC; + } + + sC = m_Refs.begin(); + eC = m_Refs.end(); + } + + if( false == test ) + { + txNode.Destroy(); + return NULL; + } + + txNode.SetScale( SGPOINT( scale.x, scale.y, scale.z ) ); + txNode.SetCenter( SGPOINT( center.x, center.y, center.z ) ); + txNode.SetTranslation( SGPOINT( translation.x, translation.y, translation.z ) ); + txNode.SetScaleOrientation( SGVECTOR( scaleOrientation.x, scaleOrientation.y, + scaleOrientation.z ), scaleOrientation.w ); + txNode.SetRotation( SGVECTOR( rotation.x, rotation.y, rotation.z), rotation.w ); + + m_sgNode = txNode.GetRawPtr(); + + return m_sgNode; + */ +} diff --git a/plugins/3d/vrml/v1/vrml1_separator.h b/plugins/3d/vrml/v1/vrml1_separator.h new file mode 100644 index 0000000000..8f6708d7c3 --- /dev/null +++ b/plugins/3d/vrml/v1/vrml1_separator.h @@ -0,0 +1,52 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015-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 vrml1_separator.h + */ + + +#ifndef VRML1_SEPARATOR_H +#define VRML1_SEPARATOR_H + +#include "vrml1_node.h" + +class WRL1BASE; +class SGNODE; + +/** + * Class WRL1SEPARATOR + */ +class WRL1SEPARATOR : public WRL1NODE +{ +public: + WRL1SEPARATOR( NAMEREGISTER* aDictionary ); + WRL1SEPARATOR( NAMEREGISTER* aDictionary, WRL1NODE* aNode ); + virtual ~WRL1SEPARATOR(); + + // functions inherited from WRL1NODE + bool Read( WRLPROC& proc, WRL1BASE* aTopNode ); + SGNODE* TranslateToSG( SGNODE* aParent, bool calcNormals ); +}; + +#endif // VRML1_SEPARATOR_H