Work in progress: VRML1 plugin

This commit is contained in:
Cirilo Bernardo 2016-01-05 16:38:53 +11:00
parent 43c2c7223b
commit 79e0564622
6 changed files with 1515 additions and 0 deletions

View File

@ -0,0 +1,420 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <iostream>
#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;
}

View File

@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <list>
#include <string>
#include <map>
#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

View File

@ -0,0 +1,449 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <set>
#include <map>
#include <utility>
#include <iterator>
#include <cctype>
#include <iostream>
#include <algorithm>
#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;
}

View File

@ -0,0 +1,251 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <list>
#include <map>
#include <string>
#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

View File

@ -0,0 +1,256 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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 <iostream>
#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;
*/
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
*
* 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