+ Removed glm source from kicad tree (Maciej / Cirilo)

+ Added renderer for 3D model preview (Mario)
+ Added 3d_cache including name resolver and modifications to 3D model dialogs (Cirilo)
This commit is contained in:
Mario Luzeiro 2015-12-08 18:31:57 +11:00 committed by Cirilo Bernardo
parent ab7350bf2d
commit 69cc788e8e
397 changed files with 28372 additions and 54098 deletions

View File

@ -0,0 +1,622 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <fstream>
#include <cstdio>
#include <string>
#include <utility>
#include <wx/filename.h>
#include <wx/utils.h>
#include <wx/stdpaths.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "md5.h"
#include "3d_cache.h"
#include "3d_info.h"
#include "sg/scenegraph.h"
#include "3d_filename_resolver.h"
#include "3d_plugin_manager.h"
#include "sg/ifsg_api.h"
#define CACHE_CONFIG_NAME wxT( "cache.cfg" )
static const wxString md5ToWXString( const unsigned char* aMD5Sum )
{
unsigned char uc;
unsigned char tmp;
char md5[33];
int j = 0;
for( int i = 0; i < 16; ++i )
{
uc = aMD5Sum[i];
tmp = uc / 16;
if( tmp > 9 )
tmp += 87;
else
tmp += 48;
md5[j++] = tmp;
tmp = uc % 16;
if( tmp > 9 )
tmp += 87;
else
tmp += 48;
md5[j++] = tmp;
}
md5[j] = 0;
return wxString::FromUTF8Unchecked( md5 );
}
static bool md5matches( const unsigned char* md5a, const unsigned char* md5b )
{
for( int i = 0; i < 16; ++i )
{
if( md5a[i] != md5b[i] )
return false;
}
return true;
}
static bool isMD5null( const unsigned char* aMD5Sum )
{
if( NULL == aMD5Sum )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL passed for aMD5Sum\n";
return false;
}
for( int i = 0; i < 16; ++i )
{
if( 0 != aMD5Sum[i] )
return false;
}
return true;
}
class S3D_CACHE_ENTRY
{
private:
// prohibit assignment and default copy constructor
S3D_CACHE_ENTRY( const S3D_CACHE_ENTRY& source );
S3D_CACHE_ENTRY& operator=( const S3D_CACHE_ENTRY& source );
wxString m_CacheBaseName; // base name of cache file (an MD5 sum)
public:
S3D_CACHE_ENTRY();
~S3D_CACHE_ENTRY();
void SetMD5( const unsigned char* aMD5Sum );
const wxString GetCacheBaseName( void );
unsigned char md5sum[16];
SCENEGRAPH* sceneData;
};
S3D_CACHE_ENTRY::S3D_CACHE_ENTRY()
{
sceneData = NULL;
memset( md5sum, 0, 16 );
}
S3D_CACHE_ENTRY::~S3D_CACHE_ENTRY()
{
if( NULL != sceneData )
delete sceneData;
}
void S3D_CACHE_ENTRY::SetMD5( const unsigned char* aMD5Sum )
{
if( NULL == aMD5Sum )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL passed for aMD5Sum\n";
return;
}
memcpy( md5sum, aMD5Sum, 16 );
return;
}
const wxString S3D_CACHE_ENTRY::GetCacheBaseName( void )
{
if( m_CacheBaseName.empty() )
m_CacheBaseName = md5ToWXString( md5sum );
return m_CacheBaseName;
}
S3D_CACHE::S3D_CACHE()
{
m_DirtyCache = false;
m_FNResolver = new S3D_FILENAME_RESOLVER;
m_Plugins = new S3D_PLUGIN_MANAGER;
return;
}
S3D_CACHE::~S3D_CACHE()
{
FlushCache();
if( m_FNResolver )
delete m_FNResolver;
if( m_Plugins )
delete m_Plugins;
return;
}
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile )
{
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile );
if( full3Dpath.empty() )
{
// the model cannot be found; we cannot proceed
std::cout << " * [3D model] could not find model '";
std::cout << aModelFile.ToUTF8() << "'\n";
return NULL;
}
// check cache if file is already loaded
std::map< wxString, S3D_CACHE_ENTRY*, S3D::rsort_wxString >::iterator mi;
mi = m_CacheMap.find( full3Dpath );
if( mi != m_CacheMap.end() )
return mi->second->sceneData;
// a cache item does not exist; search the Filename->Cachename map
return checkCache( full3Dpath );
}
SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName )
{
unsigned char md5sum[16];
if( !getMD5( aFileName, md5sum ) || m_CacheDir.empty() )
{
// just in case we can't get an MD5 sum (for example, on access issues)
// or we do not have a configured cache file directory, we create an
// entry to prevent further attempts at loading the file
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
m_CacheList.push_back( ep );
if( m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
( aFileName, ep ) ).second == false )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] duplicate entry in map file; key = ";
std::cerr << aFileName.ToUTF8() << "\n";
m_CacheList.pop_back();
delete ep;
}
else
{
std::cerr << " * [3D Model] [0] added cached name '" << aFileName.ToUTF8() << "'\n";
}
return NULL;
}
S3D_CACHE_ENTRY* ep = new S3D_CACHE_ENTRY;
m_CacheList.push_back( ep );
if( m_CacheMap.insert( std::pair< wxString, S3D_CACHE_ENTRY* >
( aFileName, ep ) ).second == false )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] duplicate entry in map file; key = ";
std::cerr << aFileName.ToUTF8() << "\n";
m_CacheList.pop_back();
delete ep;
return NULL;
}
else
{
std::cerr << " * [3D Model] [1] added cached name '" << aFileName.ToUTF8() << "'\n";
}
ep->SetMD5( md5sum );
wxString bname = ep->GetCacheBaseName();
wxString cachename = m_CacheDir + bname + wxT( ".3dc" );
if( wxFileName::FileExists( cachename ) )
{
loadCacheData( ep );
return ep->sceneData;
}
ep->sceneData = m_Plugins->Load3DModel( aFileName );
return ep->sceneData;
}
bool S3D_CACHE::getMD5( const wxString& aFileName, unsigned char* aMD5Sum )
{
if( aFileName.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] empty filename\n";
return false;
}
if( NULL == aMD5Sum )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aMD5Sum\n";
return false;
}
FILE* fp = fopen( aFileName.ToUTF8(), "rb" );
if( !fp )
{
std::cerr << " * [3dmodel] could not open file '" << aFileName.ToUTF8() << "'\n";
return false;
}
struct md5_ctx msum;
md5_init_ctx( &msum );
int res = md5_stream( fp, aMD5Sum );
fclose( fp );
if( 0 != res )
{
std::cerr << " * [3dmodel] md5 calculation failed on file '" << aFileName.ToUTF8() << "'\n";
return false;
}
return true;
}
bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem )
{
wxString bname = aCacheItem->GetCacheBaseName();
if( bname.empty() )
{
std::cerr << " * [3D model] cannot load cached model; no md5 hash available\n";
return false;
}
if( m_CacheDir.empty() )
{
std::cerr << " * [3D model] cannot load cached model; config directory unknown\n";
return false;
}
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
// determine if the file exists and is a regular file
struct stat info;
if( stat( fname.ToUTF8(), &info ) )
return false;
if( !S_ISREG( info.st_mode ) )
{
std::cerr << " * [3D model] path exists but is not a regular file: '";
std::cerr << fname.ToUTF8() << "'\n";
return false;
}
#warning NOT IMPLEMENTED
// XXX - proceed with loading the cache data
return false;
}
bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem )
{
if( NULL == aCacheItem )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * NULL passed for aCacheItem\n";
return false;
}
if( NULL == aCacheItem->sceneData )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * aCacheItem has no valid scene data\n";
return false;
}
wxString bname = aCacheItem->GetCacheBaseName();
if( bname.empty() )
{
std::cerr << " * [3D model] cannot load cached model; no md5 hash available\n";
return false;
}
if( m_CacheDir.empty() )
{
std::cerr << " * [3D model] cannot load cached model; config directory unknown\n";
return false;
}
wxString fname = m_CacheDir + bname + wxT( ".3dc" );
if( wxFileName::Exists( fname ) )
{
// determine if the file is a regular file
struct stat info;
if( stat( fname.ToUTF8(), &info ) )
return false;
if( !S_ISREG( info.st_mode ) )
{
std::cerr << " * [3D model] path exists but is not a regular file: '";
std::cerr << fname.ToUTF8() << "'\n";
return false;
}
// the file already exists on disk; just exit
return true;
}
#warning NOT IMPLEMENTED
// XXX - proceed with saving the cache data
return false;
}
bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
{
if( !m_ConfigDir.empty() )
return false;
wxFileName cfgdir( aConfigDir, "" );
cfgdir.Normalize();
if( cfgdir.DirExists() )
{
m_ConfigDir = cfgdir.GetPath();
// inform the file resolver of the config directory
if( !m_FNResolver->Set3DConfigDir( m_ConfigDir ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * could not set 3D Config Directory on filename resolver\n";
std::cerr << " * config directory: '" << m_ConfigDir.ToUTF8() << "'\n";
}
cfgdir.AppendDir( wxT( "cache" ) );
if( !cfgdir.DirExists() )
{
cfgdir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
if( !cfgdir.DirExists() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * failed to create 3D cache directory\n";
std::cerr << " * cache directory: '";
std::cerr << cfgdir.GetPath().ToUTF8() << "'\n";
return false;
}
}
m_CacheDir = cfgdir.GetPathWithSep();
return true;
}
return false;
}
wxString S3D_CACHE::Get3DConfigDir( bool createDefault )
{
if( !m_ConfigDir.empty() || !createDefault )
return m_ConfigDir;
// note: duplicated from common/common.cpp GetKicadConfigPath() to avoid
// code coupling; ideally the instantiating code should call
// Set3DConfigDir() to set the directory rather than relying on this
// directory remaining the same in future KiCad releases.
wxFileName cfgpath;
// From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
// Unix: ~ (the home directory)
// Windows: "C:\Documents and Settings\username\Application Data"
// Mac: ~/Library/Preferences
cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
#if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
wxString envstr;
if( !wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) || envstr.IsEmpty() )
{
// XDG_CONFIG_HOME is not set, so use the fallback
cfgpath.AppendDir( wxT( ".config" ) );
}
else
{
// Override the assignment above with XDG_CONFIG_HOME
cfgpath.AssignDir( envstr );
}
#endif
cfgpath.AppendDir( wxT( "kicad" ) );
cfgpath.AppendDir( wxT( "3d" ) );
if( !cfgpath.DirExists() )
{
cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
}
if( !cfgpath.DirExists() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * failed to create 3D configuration directory\n";
return wxT( "" );
}
if( Set3DConfigDir( cfgpath.GetPath() ) )
return m_ConfigDir;
return wxEmptyString;
}
bool S3D_CACHE::SetProjectDir( const wxString& aProjDir )
{
bool hasChanged = false;
if( m_FNResolver->SetProjectDir( aProjDir, &hasChanged ) && hasChanged )
{
m_CacheMap.clear();
std::list< S3D_CACHE_ENTRY* >::iterator sL = m_CacheList.begin();
std::list< S3D_CACHE_ENTRY* >::iterator eL = m_CacheList.end();
while( sL != eL )
{
delete *sL;
++sL;
}
m_CacheList.clear();
return true;
}
return false;
}
wxString S3D_CACHE::GetProjectDir( void )
{
return m_FNResolver->GetProjectDir();
}
S3D_FILENAME_RESOLVER* S3D_CACHE::GetResolver( void )
{
return m_FNResolver;
}
std::list< wxString > const* S3D_CACHE::GetFileFilters( void ) const
{
return m_Plugins->GetFileFilters();
}
void S3D_CACHE::FlushCache( void )
{
std::list< S3D_CACHE_ENTRY* >::iterator sCL = m_CacheList.begin();
std::list< S3D_CACHE_ENTRY* >::iterator eCL = m_CacheList.end();
while( sCL != eCL )
{
delete *sCL;
++sCL;
}
m_CacheList.clear();
ClosePlugins();
return;
}
void S3D_CACHE::ClosePlugins( void )
{
if( NULL != m_Plugins )
m_Plugins->ClosePlugins();
return;
}
// notes:
// 1. aModelEntry:
// + rotation: degrees, model space X, Y, Z; rotations are specified in sequence
//
S3DMODEL* S3D_CACHE::Prepare( S3D_INFO const* aModelEntry,
const SGPOINT& aRotation, const SGPOINT& aOffset )
{
SCENEGRAPH* sp = Load( aModelEntry->filename );
if( !sp )
return NULL;
// create a single transform entity to apply to the models
glm::dmat4 t0 = glm::translate( glm::dvec3( 25.4 * aModelEntry->offset.x, 25.4 * aModelEntry->offset.y,
25.4 * aModelEntry->offset.z ) );
glm::dmat4 rX = glm::rotate( aModelEntry->rotation.x, glm::dvec3( 1.0, 0.0, 0.0 ) );
glm::dmat4 rY = glm::rotate( -aModelEntry->rotation.y, glm::dvec3( 0.0, 1.0, 0.0 ) );
glm::dmat4 rZ = glm::rotate( aModelEntry->rotation.z, glm::dvec3( 0.0, 0.0, 1.0 ) );
glm::dmat4 s0 = glm::scale( glm::dvec3( aModelEntry->scale.x, aModelEntry->scale.y,
aModelEntry->scale.z ) );
glm::dmat4 m0 = rZ * rY * rX * s0 * t0;
rX = glm::rotate( aRotation.x, glm::dvec3( 1.0, 0.0, 0.0 ) );
rY = glm::rotate( aRotation.y, glm::dvec3( 0.0, 1.0, 0.0 ) );
rZ = glm::rotate( aRotation.z, glm::dvec3( 0.0, 0.0, 1.0 ) );
glm::dmat4 t1 = glm::translate( glm::dvec3( aOffset.x, aOffset.y, aOffset.z ) );
glm::dmat4 m1 = t1 * rZ * rY * rX * m0;
return S3D::Prepare( sp, &m1 );
}

View File

@ -0,0 +1,214 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 3d_cache.h
* defines the display data cache manager for 3D models
*/
#ifndef CACHE_3D_H
#define CACHE_3D_H
#include <list>
#include <map>
#include <wx/string.h>
#include "str_rsort.h"
#include "3d_filename_resolver.h"
#include "3d_info.h"
#include <3d_rendering/c3dmodel.h>
class S3D_CACHE;
class S3D_CACHE_ENTRY;
class SCENEGRAPH;
class S3D_FILENAME_RESOLVER;
class S3D_PLUGIN_MANAGER;
struct S3D_INFO;
class S3D_CACHE
{
private:
/// cache entries
std::list< S3D_CACHE_ENTRY* > m_CacheList;
/// mapping of file names to cache names and data
std::map< wxString, S3D_CACHE_ENTRY*, S3D::rsort_wxString > m_CacheMap;
/// object to resolve file names
S3D_FILENAME_RESOLVER* m_FNResolver;
/// plugin manager
S3D_PLUGIN_MANAGER* m_Plugins;
/// set true if the cache needs to be updated
bool m_DirtyCache;
/// 3D cache directory
wxString m_CacheDir;
/// base configuration path for 3D items
wxString m_ConfigDir;
/// current KiCad project dir
wxString m_ProjDir;
/**
* Function checkCache
* searches the cache list for the given filename and retrieves
* the cache data; a cache entry is created if one does not
* already exist
*
* @param aFileName [in] is a partial or full file path; a partial path is accepted
* so that a cached model may be used in cases where the user has moved or deleted
* the original model file.
* @param aModelEntry [in, out] is the model entry for which we are retrieving
* scene data.
* @param aMD5Sum [in] is an optional MD5 sum; if this parameter is supplied and its value
* differs from the cached file then the function will fail and the flag aMD5Mismatch
* will be set to true. If the parameter is not supplied then the cache model is used
* if available and with no regard to the MD5 sum.
* @param aMD5Mismatch [out] if the function succeeds then this flag is set to false;
* the flag is set true if aMD5Sum is specified and differs from the cached object's
* md5sum.
* @return on success a pointer to a SCENEGRAPH, otherwise NULL
*/
SCENEGRAPH* checkCache( const wxString& aFileName );
/**
* Function getMD5
* calculates the MD5 hash of the given file
*
* @param aFileName [in] is a fully qualified path to the model file
* @param aMD5Sum [out] is a 16-byte character array to hold the MD5 hash
* @return true if the md5 hash was calculated; otherwise false
*/
bool getMD5( const wxString& aFileName, unsigned char* aMD5Sum );
// load scene data from a cache file
bool loadCacheData( S3D_CACHE_ENTRY* aCacheItem );
// save scene data to a cache file
bool saveCacheData( S3D_CACHE_ENTRY* aCacheItem );
public:
S3D_CACHE();
virtual ~S3D_CACHE();
/**
* Function Set3DConfigDir
* Sets the configuration directory to be used by the
* model manager for storing 3D model manager configuration
* data and the model cache. The config directory may only be
* set once in the lifetime of the object.
*
* @param aConfigDir is the configuration directory to use
* for 3D model manager data
* @return true on success
*/
bool Set3DConfigDir( const wxString& aConfigDir );
/**
* Function Get3DConfigDir
* returns the current 3D configuration directory on
* success, otherwise it returns wxEmptyString. If the
* directory was not previously set via Set3DConfigDir()
* then a default is used which is based on kicad's
* configuration directory code as of September 2015.
*/
wxString Get3DConfigDir( bool createDefault = false );
/**
* Function SetProjectDir
* sets the current project's working directory; this
* affects the model search path
*/
bool SetProjectDir( const wxString& aProjDir );
/**
* Function GetProjectDir
* returns the current project's working directory
*/
wxString GetProjectDir( void );
/**
* Function Load
* attempts to load the scene data for a model; it will consult the
* internal cache list and load from cache if possible before invoking
* the load() function of the available plugins.
*
* @param aModelFile [in] is the partial or full path to the model to be loaded
* @return true if the model was successfully loaded, otherwise false.
* The model may fail to load if, for example, the plugin does not
* support rendering of the 3D model.
*/
SCENEGRAPH* Load( const wxString& aModelFile );
S3D_FILENAME_RESOLVER* GetResolver( void );
/**
* Function GetFileFilters
* returns the list of file filters retrieved from the plugins;
* this will contain at least the default "All Files (*.*)|*.*"
*
* @return a pointer to the filter list
*/
std::list< wxString > const* GetFileFilters( void ) const;
/**
* Function FlushCache
* frees all data in the cache and closes all plugins
*/
void FlushCache( void );
/**
* Function ClosePlugins
* unloads plugins to free memory
*/
void ClosePlugins( void );
/**
* Function Prepare
* attempts to load the scene data for a model and to translate it
* into an S3D_MODEL structure for display by a renderer
*
* @param aModelEntry is the structure containing the model name,
* scale, offset, and rotation. Note that by kicad convention the
* operations are Offset-Scale-Rotation, the Y value of the offset
* is negative (Left-hand coordinate system), and the units of the
* offset is inches. Application of the Offset, Scale. Rotation
* within the aModelEntry structure places the model into a nominal
* (0, 0, 0) position and orientation. Final positioning of the
* model instance is determined by the aOffset, aAxis, and aAngle
* parameters.
* @ aRotation is a X, Y, Z rotation to calculate the final orientation
* of the model instance
* @param aOffset is an offset to apply to obtain the final position
* of the model instance; this offset is applied after the aAxis/aAngle
* orientation in the common Rotation-Scale-Translation order of transforms.
*/
S3DMODEL* Prepare( S3D_INFO const* aModelEntry,
const SGPOINT& aRotation, const SGPOINT& aOffset );
};
#endif // CACHE_3D_H

View File

@ -0,0 +1,66 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <common.h>
#include "3d_cache_wrapper.h"
CACHE_WRAPPER::CACHE_WRAPPER()
{
return;
}
CACHE_WRAPPER::~CACHE_WRAPPER()
{
return;
}
S3D_CACHE* PROJECT::Get3DCacheManager( bool updateProjDir )
{
CACHE_WRAPPER* cw = (CACHE_WRAPPER*) GetElem( ELEM_3DCACHE );
S3D_CACHE* cache = dynamic_cast<S3D_CACHE*>( cw );
// check that we get the expected type of object or NULL
wxASSERT( !cw || cache );
if( !cw )
{
cw = new CACHE_WRAPPER;
cache = dynamic_cast<S3D_CACHE*>( cw );
wxFileName cfgpath;
cfgpath.AssignDir( GetKicadConfigPath() );
cfgpath.AppendDir( wxT( "3d" ) );
cache->Set3DConfigDir( cfgpath.GetFullPath() );
SetElem( ELEM_3DCACHE, cw );
updateProjDir = true;
}
if( updateProjDir )
cache->SetProjectDir( GetProjectPath() );
return cache;
}

View File

@ -0,0 +1,37 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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
*/
#ifndef CACHE_WRAPPER_3D_H
#define CACHE_WRAPPER_3D_H
#include <project.h>
#include "3d_cache.h"
class CACHE_WRAPPER : public S3D_CACHE, public PROJECT::_ELEM
{
public:
CACHE_WRAPPER();
virtual ~CACHE_WRAPPER();
};
#endif // CACHE_WRAPPER_3D_H

View File

@ -0,0 +1,457 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <cstdlib>
#include <cstring>
#include <fstream>
#include <wx/filename.h>
#include <wx/utils.h>
#include "3d_filename_resolver.h"
#define S3D_RESOLVER_CONFIG wxT( "3Dresolver.cfg" )
bool S3D_FILENAME_RESOLVER::Set3DConfigDir( const wxString& aConfigDir )
{
if( aConfigDir.empty() )
return false;
wxFileName cfgdir( aConfigDir, "" );
cfgdir.Normalize();
if( false == cfgdir.DirExists() )
return false;
m_ConfigDir = cfgdir.GetPath();
createPathList();
return true;
}
bool S3D_FILENAME_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgChanged )
{
if( aProjDir.empty() )
return false;
wxFileName projdir( aProjDir, "" );
projdir.Normalize();
if( false == projdir.DirExists() )
return false;
wxString path = projdir.GetPath();
if( flgChanged )
*flgChanged = false;
if( m_Paths.empty() )
{
m_Paths.push_back( path );
if( flgChanged )
*flgChanged = true;
}
else
{
if( m_Paths.front().Cmp( path ) )
{
m_Paths.pop_front();
m_Paths.push_front( path );
m_NameMap.clear();
if( flgChanged )
*flgChanged = true;
}
else
{
return true;
}
}
#ifdef DEBUG
std::cout << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cout << " * [INFO] changed project dir to " << m_Paths.front().ToUTF8() << "\n";
#endif
return true;
}
wxString S3D_FILENAME_RESOLVER::GetProjectDir( void )
{
if( m_Paths.empty() )
return wxEmptyString;
return m_Paths.front();
}
bool S3D_FILENAME_RESOLVER::createPathList( void )
{
if( !m_Paths.empty() )
return true;
wxString kmod;
// add the current working directory as the first entry by
// default; since CWD is not necessarily what we really want,
// the user may change this later with a call to SetProjectDir()
if( !addPath( wxFileName::GetCwd() ) )
m_Paths.push_back( wxEmptyString );
if( wxGetEnv( wxT( "KISYS3DMOD" ), &kmod ) )
addPath( kmod );
if( !m_ConfigDir.empty() )
readPathList();
if( m_Paths.empty() )
return false;
#ifdef DEBUG
std::cout << " * [3D model] search paths:\n";
std::list< wxString >::const_iterator sPL = m_Paths.begin();
std::list< wxString >::const_iterator ePL = m_Paths.end();
while( sPL != ePL )
{
std::cout << " + '" << (*sPL).ToUTF8() << "'\n";
++sPL;
}
#endif
return true;
}
bool S3D_FILENAME_RESOLVER::UpdatePathList( std::vector< wxString >& aPathList )
{
while( m_Paths.size() > 1 )
m_Paths.pop_back();
size_t nI = aPathList.size();
for( size_t i = 0; i < nI; ++i )
addPath( aPathList[i] );
#ifdef DEBUG
std::cerr << "* S3D_FILENAME_RESOLVER::UpdatePathList()\n";
std::cerr << "NItems: " << aPathList.size() << "\n";
for( size_t i = 0; i < aPathList.size(); ++i )
std::cerr << "Item #" << i << ": " << aPathList[i].ToUTF8() << "\n";
#endif
return writePathList();
}
wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
{
if( aFileName.empty() )
return wxEmptyString;
if( m_Paths.empty() )
createPathList();
// first attempt to use the name as specified:
wxString aResolvedName;
wxString fname = aFileName;
#ifdef _WIN32
// translate from KiCad's internal UNIX-like path to MSWin paths
fname.Replace( wxT( "/" ), wxT( "\\" ) );
#endif
if( checkRealPath( fname, aResolvedName ) )
return aResolvedName;
// look up the filename in the internal filename map
std::map< wxString, wxString, S3D::rsort_wxString >::iterator mi;
mi = m_NameMap.find( fname );
if( mi != m_NameMap.end() )
return mi->second;
std::list< wxString >::const_iterator sPL = m_Paths.begin();
std::list< wxString >::const_iterator ePL = m_Paths.end();
while( sPL != ePL )
{
wxFileName fpath( wxFileName::DirName( *sPL ) );
wxFileName filename( fname );
// we can only attempt a search if the filename is incomplete
if( filename.IsRelative() )
{
wxString fullPath = fpath.GetPathWithSep() + fname;
if( checkRealPath( fullPath, aResolvedName ) )
return aResolvedName;
}
++sPL;
}
std::cerr << " * [3D Model] filename could not be resolved: '";
std::cerr << aFileName.ToUTF8() << "'\n";
return wxEmptyString;
}
bool S3D_FILENAME_RESOLVER::checkRealPath( const wxString& aFileName,
wxString& aResolvedName )
{
aResolvedName.clear();
wxFileName fname( aFileName );
fname.Normalize();
if( !fname.FileExists() )
return false;
aResolvedName = fname.GetFullPath();
m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, aResolvedName ) );
return true;
}
bool S3D_FILENAME_RESOLVER::addPath( const wxString& aPath )
{
if( aPath.empty() )
return false;
wxFileName path( aPath, "" );
path.Normalize();
if( !path.DirExists() )
{
std::cerr << " * [3D Model] invalid path: '" << path.GetPath().ToUTF8() << "'\n";
return false;
}
wxString pname = path.GetPath();
std::list< wxString >::const_iterator sPL = m_Paths.begin();
std::list< wxString >::const_iterator ePL = m_Paths.end();
while( sPL != ePL )
{
if( !pname.Cmp( *sPL ) )
return true;
++sPL;
}
m_Paths.push_back( pname );
return true;
}
bool S3D_FILENAME_RESOLVER::readPathList( void )
{
if( m_ConfigDir.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * 3D configuration directory is unknown\n";
return false;
}
wxFileName cfgpath( m_ConfigDir, S3D_RESOLVER_CONFIG );
cfgpath.Normalize();
wxString cfgname = cfgpath.GetFullPath();
size_t nitems = m_Paths.size();
std::ifstream cfgFile;
std::string cfgLine;
if( !wxFileName::Exists( cfgname ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * no 3D configuration file: '";
std::cerr << cfgname.ToUTF8() << "'\n";
return false;
}
cfgFile.open( cfgname.ToUTF8() );
if( !cfgFile.is_open() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * could not open configuration file '" << cfgname.ToUTF8() << "'\n";
return false;
}
int lineno = 0;
bool mod = false; // set to true if there are non-existent paths in the file
while( cfgFile.good() )
{
cfgLine.clear();
std::getline( cfgFile, cfgLine );
++lineno;
if( cfgLine.empty() )
{
if( cfgFile.eof() )
break;
continue;
}
std::string::size_type spos = cfgLine.find_first_of( '"', 0 );
if( std::string::npos == spos )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * bad config entry in config file '" << cfgname.ToUTF8() << "'\n";
std::cerr << " line " << lineno << " [missing opening quote mark]\n";
}
cfgLine.erase( 0, spos + 1 );
spos = cfgLine.find_last_of( '"' );
if( std::string::npos == spos )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * bad config entry in config file '" << cfgname.ToUTF8() << "'\n";
std::cerr << " line " << lineno << " [missing closing quote mark]\n";
}
cfgLine.erase( spos );
if( !addPath( cfgLine ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * bad config entry in config file '" << cfgname.ToUTF8() << "'\n";
std::cerr << " line " << lineno << " [not a valid path]: '";
std::cerr << cfgLine << "'\n";
mod = true;
}
}
cfgFile.close();
if( mod )
writePathList();
if( m_Paths.size() != nitems )
return true;
return false;
}
bool S3D_FILENAME_RESOLVER::writePathList( void )
{
if( m_ConfigDir.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * 3D configuration directory is unknown\n";
return false;
}
if( m_Paths.empty() || 1 == m_Paths.size() )
return false;
wxString cfgname = m_ConfigDir + S3D_RESOLVER_CONFIG;
std::ofstream cfgFile;
cfgFile.open( cfgname.ToUTF8(), std::ios_base::trunc );
if( !cfgFile.is_open() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * could not open configuration file '" << cfgname.ToUTF8() << "'\n";
return false;
}
std::list< wxString >::const_iterator sPL = m_Paths.begin();
std::list< wxString >::const_iterator ePL = m_Paths.end();
// the first entry is the current project dir; we never add a project dir
// to the path list in the configuration file
++sPL;
while( sPL != ePL )
{
cfgFile << "\"" << (*sPL).ToUTF8() << "\"\n";
++sPL;
}
bool bad = cfgFile.bad();
cfgFile.close();
if( bad )
return false;
return true;
}
wxString S3D_FILENAME_RESOLVER::ShortenPath( const wxString& aFullPathName )
{
wxString fname = aFullPathName;
if( m_Paths.empty() )
createPathList();
std::list< wxString >::const_iterator sL = m_Paths.begin();
std::list< wxString >::const_iterator eL = m_Paths.end();
while( sL != eL )
{
wxFileName fpath( *sL, "" );
wxString fps = fpath.GetPathWithSep();
if( std::string::npos != fname.find( fps ) )
{
fname = fname.substr( fps.size() );
#ifdef _WIN32
fname.Replace( wxT( "\\" ), wxT( "/" ) );
#endif
return fname;
}
++sL;
}
return fname;
}
const std::list< wxString >* S3D_FILENAME_RESOLVER::GetPaths( void )
{
return &m_Paths;
}

View File

@ -0,0 +1,165 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 3d_filename_resolver.h
* provides an extensible class to resolve 3D model paths. Initially
* the legacy behavior will be implemented and an incomplete path
* would be checked against the project directory or the KISYS3DMOD
* environment variable. In the future a configurable set of search
* paths may be specified.
*/
#ifndef FILENAME_RESOLVER_3D_H
#define FILENAME_RESOLVER_3D_H
#include <list>
#include <map>
#include <vector>
#include <wx/string.h>
#include "str_rsort.h"
class S3D_FILENAME_RESOLVER
{
private:
wxString m_ConfigDir; // 3D configuration directory
std::list< wxString > m_Paths; // list of base paths to search from
// mapping of (short) file names to resolved names
std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap;
/**
* Function checkRealPath
* checks if a file exists, is a regular file, and retrieves
* the canonical name and extension.
*
* @param aFileName [in] is the file name and path to be checked
* @param aResolvedName [out] is the canonical resolved filename
* @param aFileExtension [out] is the file's extension string
* @return true if the file was found and is a regular file
*/
bool checkRealPath( const wxString& aFileName, wxString& aResolvedName );
/**
* Function createPathList
* builds the path list using available information such as
* KISYS3DMOD and the 3d_path_list configuration file. Invalid
* paths are silently discarded and removed from the configuration
* file.
*
* @return true if at least one valid path was found
*/
bool createPathList( void );
/**
* Function addPath
* checks that a path is valid and adds it to the search list
*
* @param aPath is the path to be checked and added
* @return true if aPath is valid
*/
bool addPath( const wxString& aPath );
/**
* Function readPathList
* reads a list of path names from a configuration file
*
* @return true if a file was found and contained at least
* one valid path
*/
bool readPathList( void );
/**
* Function writePathList
* writes the current path list to a configuration file
*
* @return true if the path list was not empty and was
* successfully written to the configuration file
*/
bool writePathList( void );
public:
/**
* Function Set3DConfigDir
* sets the user's configuration directory
* for 3D models.
*
* @param aConfigDir
* @return true if the call succeeds (directory exists)
*/
bool Set3DConfigDir( const wxString& aConfigDir );
/**
* Function SetProjectDir
* sets the current KiCad project directory as the first
* entry in the model path list
*
* @param aProjDir is the current project directory
* @param flgChanged, if specified, is set to true if the directory actually changed
* @return true if the call succeeds
*/
bool SetProjectDir( const wxString& aProjDir, bool* flgChanged = NULL );
wxString GetProjectDir( void );
/**
* Function UpdatePathList
* clears the current path list and substitutes the given path
* list, updating the path configuration file on success.
*/
bool UpdatePathList( std::vector< wxString >& aPathList );
/**
* Function ResolvePath
* determines the full path of the given file name. In the future
* remote files may be supported, in which case it is best to
* require a full URI in which case ResolvePath should check that
* the URI conforms to RFC-2396 and related documents and copies
* aFileName into aResolvedName if the URI is valid.
*/
wxString ResolvePath( const wxString& aFileName );
/**
* Function ShortenPath
* produces a relative path based on the existing
* search directories or returns the same path if
* the path is not a superset of an existing search path.
*
* @param aFullPathName is an absolute path to shorten
* @return the shortened path or aFullPathName
*/
wxString ShortenPath( const wxString& aFullPathName );
/**
* Function GetPaths
* returns a pointer to the internal path list; the items in:load
*
* the list can be used to set up the list of search paths
* available to a 3D file browser.
*
* @return pointer to the internal path list
*/
const std::list< wxString >* GetPaths( void );
};
#endif // FILENAME_RESOLVER_3D_H

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 3d_info.h
* defines the basic data associated with a single 3D model.
*/
#ifndef INFO_3D_H
#define INFO_3D_H
#include <wx/string.h>
#include <3d_cache/sg/sg_base.h>
struct S3D_INFO
{
SGPOINT scale; ///< scaling factors for the 3D footprint shape
SGPOINT rotation; ///< an X,Y,Z rotation (unit = degrees) for the 3D shape
SGPOINT offset; ///< an offset (unit = inch) for the 3D shape
// note: the models are treated in a peculiar fashion since it is the
// SCALE which is applied first, followed by the ROTATION and finally
// the TRANSLATION/Offset (S-R-T). The usual order of operations is T-R-S.
wxString filename; ///< The 3D shape filename in 3D library
};
#endif // INFO_3D_H

View File

@ -0,0 +1,602 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <utility>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <string>
#include <wx/string.h>
#include <wx/dir.h>
#include <wx/config.h>
#include <wx/stdpaths.h>
#include <wx/filename.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <pwd.h>
#endif
#include <3d_plugin_manager.h>
#include <plugins/3d/3d_plugin.h>
#include <3d_cache/sg/scenegraph.h>
class S3D_PLUGIN_ITEM
{
private:
#ifdef _WIN32
HMODULE m_dlHandle;
#else
void* m_dlHandle; // handle to the opened plugin
#endif
S3D_PLUGIN* m_plugin; // pointer to an instance
wxString m_pluginName; // plugin name
public:
S3D_PLUGIN_ITEM( const wxString& aPluginPath );
~S3D_PLUGIN_ITEM();
bool Open( void );
void Close( void );
S3D_PLUGIN* GetPlugin( void );
const wxString GetPluginName( void );
};
S3D_PLUGIN_ITEM::S3D_PLUGIN_ITEM( const wxString& aPluginPath )
{
m_pluginName = aPluginPath;
m_dlHandle = NULL;
m_plugin = NULL;
return;
}
S3D_PLUGIN_ITEM::~S3D_PLUGIN_ITEM()
{
Close();
}
bool S3D_PLUGIN_ITEM::Open( void )
{
if( NULL != m_dlHandle )
return true;
if( m_pluginName.IsEmpty() )
return false;
m_plugin = NULL;
#ifdef _WIN32
// NOTE: MSWin uses UTF-16 encoding
#if defined( UNICODE ) || defined( _UNICODE )
m_dlHandle = LoadLibrary( m_pluginName.wc_str() );
#else
m_dlHandle = LoadLibrary( m_pluginName.ToUTF8() );
#endif
#else
m_dlHandle = dlopen( m_pluginName.ToUTF8(), RTLD_LAZY | RTLD_LOCAL );
#endif
if( NULL == m_dlHandle )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * could not open file: '" << m_pluginName.ToUTF8() << "'\n";
return false;
}
else
{
#ifdef _WIN32
typedef S3D_PLUGIN* (*pPLUGIN)( void );
pPLUGIN Get3DPlugin = (pPLUGIN) GetProcAddress( m_dlHandle, "Get3DPlugin" );
#else
S3D_PLUGIN* (*Get3DPlugin)( void );
*(void **) (&Get3DPlugin) = dlsym( m_dlHandle, "Get3DPlugin" );
#endif
if( NULL == Get3DPlugin )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
#ifdef _WIN32
std::cerr << " * [INFO] could not find symbol\n";
#else
char* err = dlerror();
std::cerr << " * [INFO] could not find symbol: '" << err << "'\n";
#endif
}
else
{
// set the 3D Model Plugin object
m_plugin = (*Get3DPlugin)();
return true;
}
}
#ifdef _WIN32
FreeLibrary( m_dlHandle );
#else
dlclose( m_dlHandle );
#endif
m_dlHandle = NULL;
return false;
}
void S3D_PLUGIN_ITEM::Close( void )
{
m_plugin = NULL;
if( m_dlHandle )
{
#ifdef _WIN32
FreeLibrary( m_dlHandle );
#else
dlclose( m_dlHandle );
#endif
m_dlHandle = NULL;
}
return;
}
S3D_PLUGIN* S3D_PLUGIN_ITEM::GetPlugin( void )
{
if( NULL == m_plugin && !Open() )
return NULL;
return m_plugin;
}
const wxString S3D_PLUGIN_ITEM::GetPluginName( void )
{
return m_pluginName;
}
S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
{
// create the initial file filter list entry
m_FileFilters.push_back( _( "All Files (*.*)|*.*" ) );
// discover and load plugins
loadPlugins();
#ifdef DEBUG
if( !m_ExtMap.empty() )
{
std::multimap< const wxString, S3D_PLUGIN_ITEM* >::const_iterator sM = m_ExtMap.begin();
std::multimap< const wxString, S3D_PLUGIN_ITEM* >::const_iterator eM = m_ExtMap.end();
std::cout << "* Extension [plugin name]:\n";
while( sM != eM )
{
std::cout << " + '" << sM->first.ToUTF8() << "' [";
std::cout << sM->second->GetPluginName().ToUTF8() << "]\n";
++sM;
}
}
else
{
std::cout << "* No plugins available\n";
}
if( !m_FileFilters.empty() )
{
/// list of file filters
std::list< wxString >::const_iterator sFF = m_FileFilters.begin();
std::list< wxString >::const_iterator eFF = m_FileFilters.end();
std::cout << "* File filters:\n";
int i = 0;
while( sFF != eFF )
{
std::cout << " + '" << *sFF << "'\n";
++sFF;
}
}
else
{
std::cout << "* No file filters available\n";
}
#endif // DEBUG
return;
}
S3D_PLUGIN_MANAGER::~S3D_PLUGIN_MANAGER()
{
std::list< S3D_PLUGIN_ITEM* >::iterator sP = m_Plugins.begin();
std::list< S3D_PLUGIN_ITEM* >::iterator eP = m_Plugins.end();
while( sP != eP )
{
(*sP)->Close();
delete *sP;
++sP;
}
m_Plugins.clear();
return;
}
void S3D_PLUGIN_MANAGER::loadPlugins( void )
{
std::list< std::string > pathlist;
std::list< wxString > searchpaths;
std::list< wxString > pluginlist;
wxFileName fn;
#ifdef DEBUG
// set up to work from the build directory
fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
fn.AppendDir( wxT("..") );
fn.AppendDir( wxT("plugins") );
fn.AppendDir( wxT("3d") );
std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
checkPluginPath( testpath, searchpaths );
#endif
fn.Assign( wxStandardPaths::Get().GetPluginsDir() );
fn.AppendDir( wxT( "kicad" ) );
fn.AppendDir( wxT( "plugins" ) );
fn.AppendDir( wxT( "3d" ) );
checkPluginPath( std::string( fn.GetPathWithSep().ToUTF8() ), searchpaths );
checkPluginPath( wxT( "/usr/lib/kicad/plugins/3d" ), searchpaths );
checkPluginPath( wxT( "/usr/local/lib/kicad/plugins/3d" ), searchpaths );
checkPluginPath( wxT( "/opt/kicad/lib/kicad/plugins/3d" ), searchpaths );
#ifdef __APPLE__
// XXX - we want to use GetOSX... so add support for that somehow in order to avoid hard coding
// "/Library/Application Support/kicad/plugins/3d"
checkPluginPath( wxT( "/Library/Application Support/kicad/plugins/3d" ), searchpaths );
// /Library/Application Support/kicad/plugins
//fn.Assign( GetOSXKicadMachineDataDir() );
//fn.AppendDir( wxT( "plugins" ) );
//fn.AppendDir( wxT( "3d" ) );
//checkPluginPath( fn.GetPathWithSep(), searchpaths );
#endif
// note: GetUserDataDir() gives '.pcbnew' rather than '.kicad' since it uses the exe name;
fn.Assign( wxStandardPaths::Get().GetUserDataDir() );
fn.AppendDir( wxT( ".kicad" ) );
fn.AppendDir( wxT( "plugins" ) );
fn.AppendDir( wxT( "3d" ) );
checkPluginPath( fn.GetPathWithSep(), searchpaths );
std::list< wxString >::iterator sPL = searchpaths.begin();
std::list< wxString >::iterator ePL = searchpaths.end();
while( sPL != ePL )
{
#ifdef DEBUG
std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
std::cout << "* [DEBUG] searching path: '" << (*sPL).ToUTF8() << "'\n";
#endif
listPlugins( *sPL, pluginlist );
++sPL;
}
if( pluginlist.empty() )
return;
sPL = pluginlist.begin();
ePL = pluginlist.end();
while( sPL != ePL )
{
S3D_PLUGIN_ITEM* pp = new S3D_PLUGIN_ITEM( *sPL );
if( pp )
{
if( pp->Open() )
{
#ifdef DEBUG
std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
std::cout << "* [DEBUG] adding plugin\n";
#endif
m_Plugins.push_back( pp );
S3D_PLUGIN* lpp = pp->GetPlugin();
if( lpp )
{
int nf = lpp->GetNFilters();
for( int i = 0; i < nf; ++i )
addFilterString( lpp->GetFileFilter( i ) );
}
addExtensionMap( pp );
// close the loaded library
pp->Close();
}
else
{
#ifdef DEBUG
std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
std::cout << "* [DEBUG] deleting plugin\n";
#endif
delete pp;
}
}
++sPL;
}
#ifdef DEBUG
std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
std::cout << "* [DEBUG] plugins loaded\n";
#endif
return;
}
void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath,
std::list< wxString >& aPluginList )
{
// list potential plugins given a search paths
// note on typical plugin names:
// Linux: *.so, *.so.* (note: *.so.* will not be supported)
// MSWin: *.dll
// OSX: *.dylib, *.bundle
std::list< wxString > nameFilter; // filter to apply to files
wxString lName; // stores name of enumerated files
wxString fName; // full name of file
#ifdef __linux
nameFilter.push_back( wxString::FromUTF8Unchecked( "*.so" ) );
#elif defined _WIN32
nameFilter.push_back( wxString::FromUTF8Unchecked( "*.dll" ) );
#elif defined __APPLE__
nameFilter.push_back( wxString::FromUTF8Unchecked( "*.dylib" ) );
nameFilter.push_back( wxString::FromUTF8Unchecked( "*.bundle" ) );
#else
// note: we need to positively identify a supported OS here
// and add suffixes which may be used for 3D model plugins
// on the specific OS
#warning NOT IMPLEMENTED
#endif
wxDir wd;
wd.Open( aPath );
if( !wd.IsOpened() )
return;
wxString lp = wd.GetNameWithSep();
std::list< wxString >::iterator sExt = nameFilter.begin();
std::list< wxString >::iterator eExt = nameFilter.end();
while( sExt != eExt )
{
if( wd.GetFirst( &lName, *sExt, wxDIR_FILES ) )
{
fName = lp + lName;
checkPluginName( fName, aPluginList );
while( wd.GetNext( &lName ) )
{
fName = lp + lName;
checkPluginName( fName, aPluginList );
}
}
++sExt;
}
wd.Close();
return;
}
void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
std::list< wxString >& aPluginList )
{
// check the existence of a plugin name and add it to the list
if( aPath.empty() || !wxFileName::FileExists( aPath ) )
return;
wxFileName path( aPath );
path.Normalize();
// determine if the path is already in the list
wxString wxpath = path.GetFullPath();
std::list< wxString >::iterator bl = aPluginList.begin();
std::list< wxString >::iterator el = aPluginList.end();
while( bl != el )
{
if( 0 == (*bl).Cmp( wxpath ) )
return;
++bl;
}
aPluginList.push_back( wxpath );
return;
}
void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
std::list< wxString >& aSearchList )
{
// check the existence of a path and add it to the path search list
if( aPath.empty() )
return;
wxFileName path( wxFileName::DirName( aPath ) );
path.Normalize();
if( !wxFileName::DirExists( path.GetFullPath() ) )
return;
// determine if the directory is already in the list
wxString wxpath = path.GetFullPath();
std::list< wxString >::iterator bl = aSearchList.begin();
std::list< wxString >::iterator el = aSearchList.end();
while( bl != el )
{
if( 0 == (*bl).Cmp( wxpath ) )
return;
++bl;
}
aSearchList.push_back( wxpath );
return;
}
void S3D_PLUGIN_MANAGER::addFilterString( const wxString& aFilterString )
{
// add an entry to the file filter list
if( aFilterString.empty() )
return;
std::list< wxString >::iterator sFF = m_FileFilters.begin();
std::list< wxString >::iterator eFF = m_FileFilters.end();
while( sFF != eFF )
{
if( 0 == (*sFF).Cmp( aFilterString ) )
return;
++sFF;
}
m_FileFilters.push_back( aFilterString );
return;
}
void S3D_PLUGIN_MANAGER::addExtensionMap( S3D_PLUGIN_ITEM* aPlugin )
{
// add entries to the extension map
if( NULL == aPlugin )
return;
S3D_PLUGIN* pp = aPlugin->GetPlugin();
if( NULL == pp )
return;
int nExt = pp->GetNExtensions();
for( int i = 0; i < nExt; ++i )
{
wxString ws = pp->GetModelExtension( i );
if( !ws.empty() )
{
m_ExtMap.insert( std::pair< const wxString, S3D_PLUGIN_ITEM* >( ws, aPlugin ) );
}
}
return;
}
std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const
{
return &m_FileFilters;
}
SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName )
{
wxFileName raw( aFileName );
wxString ext = raw.GetExt();
std::pair < std::multimap< const wxString, S3D_PLUGIN_ITEM* >::iterator,
std::multimap< const wxString, S3D_PLUGIN_ITEM* >::iterator > items;
items = m_ExtMap.equal_range( ext );
std::multimap< const wxString, S3D_PLUGIN_ITEM* >::iterator sL = items.first;
while( sL != items.second )
{
S3D_PLUGIN* pplug = sL->second->GetPlugin();
if( NULL != pplug && pplug->CanRender() )
{
SCENEGRAPH* sp = pplug->Load( aFileName );
if( NULL != sp )
return sp;
}
++sL;
}
return NULL;
}
void S3D_PLUGIN_MANAGER::ClosePlugins( void )
{
std::list< S3D_PLUGIN_ITEM* >::iterator sP = m_Plugins.begin();
std::list< S3D_PLUGIN_ITEM* >::iterator eP = m_Plugins.end();
while( sP != eP )
{
(*sP)->Close();
++sP;
}
return;
}

View File

@ -0,0 +1,96 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 3d_plugin_manager.h
* manages 3D model plugins
*/
#ifndef PLUGIN_MANAGER_3D_H
#define PLUGIN_MANAGER_3D_H
#include <map>
#include <list>
#include <wx/string.h>
class wxWindow;
class S3D_PLUGIN_ITEM;
struct S3D_INFO;
class SCENEGRAPH;
class S3D_PLUGIN_MANAGER
{
private:
/// list of discovered plugins
std::list< S3D_PLUGIN_ITEM* > m_Plugins;
/// mapping of extensions to available plugins
std::multimap< const wxString, S3D_PLUGIN_ITEM* > m_ExtMap;
/// list of file filters
std::list< wxString > m_FileFilters;
/// load plugins
void loadPlugins( void );
/// list potential plugins
void listPlugins( const wxString& aPath, std::list< wxString >& aPluginList );
/// check the existence of a plugin name and add it to the list
void checkPluginName( const wxString& aPath, std::list< wxString >& aPluginList );
/// check the existence of a path and add it to the path search list
void checkPluginPath( const wxString& aPath, std::list< wxString >& aSearchList );
/// add an entry to the file filter list
void addFilterString( const wxString& aFilterString );
/// add entries to the extension map
void addExtensionMap( S3D_PLUGIN_ITEM* aPlugin );
public:
S3D_PLUGIN_MANAGER();
virtual ~S3D_PLUGIN_MANAGER();
/**
* Function GetFileFilters
* returns the list of file filters; this will contain at least
* the default "All Files (*.*)|*.*" and the file filters supported
* by any available plugins
*
* @return a pointer to the internal filter list
*/
std::list< wxString > const* GetFileFilters( void ) const;
SCENEGRAPH* Load3DModel( const wxString& aFileName );
/**
* Function ClosePlugins
* iterates through all discovered plugins and closes them to
* reclaim memory. The individual plugins will be automatically
* reloaded as calls are made to load specific models.
*/
void ClosePlugins( void );
};
#endif // PLUGIN_MANAGER_3D_H

View File

@ -0,0 +1,3 @@
# unset CMAKE_CXX_FLAGS because it's contaminated with too many options
set( CMAKE_CXX_FLAGS "" )
add_subdirectory( sg )

132
3d-viewer/3d_cache/README Normal file
View File

@ -0,0 +1,132 @@
This directory will contain code used in the refactoring of
the 3D viewer and 3D model management.
Notes on building the test program on Linux:
1. Configure to build KiCad; ensue you have "-DS3D_TEST=ON" to
enable the "test3dmm" test program.
mkdir build
cd build
cmake -DKICAD_SCRIPTING=ON \
-DKICAD_SCRIPTING_MODULES=ON \
-DBUILD_GITHUB_PLUGIN=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DKICAD_SKIP_BOOST=ON \
-DCMAKE_INSTALL_PREFIX=/usr \
-DS3D_TEST=ON \
-DCMAKE_VERBOSE_MAKEFILE=ON ..
2. After configuring to build KiCad, descend into the 3dv build
directory:
cd 3dv
3. Build all files in the 3dv directory:
make -j8
4. Install to a directory within the build directory:
mkdir inst
make install DESTDIR=./inst
5. Set LD_LIBRARY_PATH so that the 3d manager code can be found:
export LD_LIBRARY_PATH=${PWD}/inst/usr/lib/kicad
( note: the previous step may have installed the library in
${PWD}/inst/usr/local/lib/kicad )
There is no need to include the plugins directory in
LD_LIBRARY_PATH since the manager should magically find
plugins there and load them.
6. Run the test program:
./inst/usr/bin/test3dmm
===========================
For OSX and MSWin
===========================
The dynamic plugin has only been built and tested on Linux; until
the dynamic plugin system can be made to work on MSWin and OSX, those
systems will not be able to use the 3D cache framework for anything
other than a filename resolver and model file browser. Without the
plugins the 3D viewer will not be able to use the new framework for
loading generic 3D model formats.
Dynamic plugins are managed in 3dv/3d_plugin_manager.cpp so that is the
only source file which developers need to modify to support plugins
on OSX and MSWin
1. OSX:
+ In general some attention is required wherever the __APPLE__
macro is found
+ void S3D_PLUGIN_MANAGER::loadPlugins( void )
In this function a list of reasonable search paths must be provided;
these paths will be checked for the existence of a plugin
+ void S3D_PLUGIN_MANAGER::listPlugins( ... )
In this function the list of suffixes to use in the plugin
discovery should be checked to ensure that they comply with
the expectations of OSX
+ bool S3D_PLUGIN_ITEM::Open( void )
This function loads the dynamic plugins. If OSX use the gcc dlopen
set of functions then there may be no further work to be done here.
2. MSWin:
+ In general some attention is required wherever the _WIN32 macro is found
+ void S3D_PLUGIN_MANAGER::loadPlugins( void )
In this function a list of reasonable search paths must be provided;
these paths will be checked for the existence of a plugin
+ bool S3D_PLUGIN_ITEM::Open( void )
This function loads the dynamic plugins. Since the gcc dlopen family
of functions do not exist on MSWin, some _WIN32 specific code must
be added to handle the library loading.
===
Q. How do you know the plugin system is working?
A. The plugin system is working if the dummy plugin is located and loaded.
If the plugin is located and the software was built with the DEBUG flag,
you will see a group of messages which, among other things, advertises
the file types supported by the dummy plugin:
~/code/kicad/branch_3d/3dv/3d_plugin_manager.cpp:loadPlugins:404:
* [DEBUG] searching path: '~/usr/lib/kicad/plugins'
XXX - Initializing S3D_PLUGIN_DUMMY
~/code/kicad/branch_3d/3dv/3d_plugin_manager.cpp:loadPlugins:426:
* [DEBUG] adding plugin
XXX - Destroying S3D_PLUGIN_DUMMY
~/code/kicad/branch_3d/3dv/3d_plugin_manager.cpp:loadPlugins:461:
* [DEBUG] plugins loaded
* Extension [plugin name]:
+ 'IDF' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'IGES' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'IGS' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'STEP' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'STP' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'WRL' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'X3D' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'idf' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'iges' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'igs' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'step' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'stp' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'wrl' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
+ 'x3d' [~/usr/lib/kicad/plugins/libs3d_plugin_dummy.so]
* File filters:
+ 'All Files (*.*)|*.*'
+ 'VRML 1.0/2.0 (*.wrl;*.WRL)|*.wrl;*.WRL'
+ 'X3D (*.x3d;*.X3D)|*.x3d;*.X3D'
+ 'IDF 2.0/3.0 (*.idf;*.IDF)|*.idf;*.IDF'
+ 'IGESv5.3 (*.igs;*.iges;*.IGS;*.IGES)|*.igs;*.iges;*.IGS;*.IGES'
+ 'STEP (*.stp;*.step;*.STP;*.STEP)|*.stp;*.step;*.STP;*.STEP'
The supported file extensions should appear in the list of file filters within the
model selection dialog; if no plugins are loaded then the only available file
filter will be the wildcard filter *.*

View File

@ -0,0 +1,297 @@
/* ANSI and traditional C compatability macros
Copyright 1991, 1992, 1*993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of the GNU C Library.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* ANSI and traditional C compatibility macros
ANSI C is assumed if __STDC__ is #defined.
Macro ANSI C definition Traditional C definition
----- ---- - ---------- ----------- - ----------
ANSI_PROTOTYPES 1 not defined
PTR `void *' `char *'
PTRCONST `void *const' `char *'
LONG_DOUBLE `long double' `double'
const not defined `'
volatile not defined `'
signed not defined `'
VA_START(ap, var) va_start(ap, var) va_start(ap)
Note that it is safe to write "void foo();" indicating a function
with no return value, in all K+R compilers we have been able to test.
For declaring functions with prototypes, we also provide these:
PARAMS ((prototype))
-- for functions which take a fixed number of arguments. Use this
when declaring the function. When defining the function, write a
K+R style argument list. For example:
char *strcpy PARAMS ((char *dest, char *source));
...
char *
strcpy (dest, source)
char *dest;
char *source;
{ ... }
VPARAMS ((prototype, ...))
-- for functions which take a variable number of arguments. Use
PARAMS to declare the function, VPARAMS to define it. For example:
int printf PARAMS ((const char *format, ...));
...
int
printf VPARAMS ((const char *format, ...))
{
...
}
For writing functions which take variable numbers of arguments, we
also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These
hide the differences between K+R <varargs.h> and C89 <stdarg.h> more
thoroughly than the simple VA_START() macro mentioned above.
VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end.
Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls
corresponding to the list of fixed arguments. Then use va_arg
normally to get the variable arguments, or pass your va_list object
around. You do not declare the va_list yourself; VA_OPEN does it
for you.
Here is a complete example:
int
printf VPARAMS ((const char *format, ...))
{
int result;
VA_OPEN (ap, format);
VA_FIXEDARG (ap, const char *, format);
result = vfprintf (stdout, format, ap);
VA_CLOSE (ap);
return result;
}
You can declare variables either before or after the VA_OPEN,
VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning
and end of a block. They must appear at the same nesting level,
and any variables declared after VA_OPEN go out of scope at
VA_CLOSE. Unfortunately, with a K+R compiler, that includes the
argument list. You can have multiple instances of VA_OPEN/VA_CLOSE
pairs in a single function in case you need to traverse the
argument list more than once.
For ease of writing code which uses GCC extensions but needs to be
portable to other compilers, we provide the GCC_VERSION macro that
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
wrappers around __attribute__. Also, __extension__ will be #defined
to nothing if it doesn't work. See below.
This header also defines a lot of obsolete macros:
CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID,
AND, DOTS, NOARGS. Don't use them. */
#ifndef _ANSIDECL_H
#define _ANSIDECL_H 1
/* Every source file includes this file,
so they will all get the switch for lint. */
/* LINTLIBRARY */
/* Using MACRO(x,y) in cpp #if conditionals does not work with some
older preprocessors. Thus we can't define something like this:
#define HAVE_GCC_VERSION(MAJOR, MINOR) \
(__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
and then test "#if HAVE_GCC_VERSION(2,7)".
So instead we use the macro below and test it against specific values. */
/* This macro simplifies testing whether we are using gcc, and if it
is of a particular mini*mum version. (Both major & minor numbers are
significant.) This macro will evaluate to 0 if we are not using
gcc at all. */
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#endif /* GCC_VERSION */
#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus))
/* All known AIX compilers implement these things (but don't always
define __STDC__). The RISC/OS MIPS compiler defines these things
in SVR4 mode, but does not define __STDC__. */
/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
C ++ compilers, does not define __STDC__, though it acts as if this
was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
#define ANSI_PROTOTYPES 1
#define PTR void *
#define PTRCONST void *const
#define LONG_DOUBLE long double
#define PARAMS(ARGS) ARGS
#define VPARAMS(ARGS) ARGS
#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR)
/* variadic function helper macros */
/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's
use without inhibiting further decls and without declaring an
actual variable. */
#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy
#define VA_CLOSE(AP) } va_end(AP); }
#define VA_FIXEDARG(AP, T, N) struct Qdmy
#undef const
#undef volatile
#undef signed
/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
it too, but it's not in C89. */
#undef inline
#if __STDC_VERSION__ > 199901L
/* it's a keyword */
#else
# if GCC_VERSION >= 2007
# define inline __inline__ /* __inline__ prevents -pedantic warnings */
# else
# define inline /* nothing */
# endif
#endif
/* These are obsolete. Do not use. */
#ifndef IN_GCC
#define CONST const
#define VOLATILE volatile
#define SIGNED signed
#define PROTO(type, name, arglist) type name arglist
#define EXFUN(name, proto) name proto
#define DEFUN(name, arglist, args) name(args)
#define DEFUN_VOID(name) name(void)
#define AND ,
#define DOTS , ...
#define NOARGS void
#endif /* ! IN_GCC */
#else /* Not ANSI C. */
#undef ANSI_PROTOTYPES
#define PTR char *
#define PTRCONST PTR
#define LONG_DOUBLE double
#define PARAMS(args) ()
#define VPARAMS(args) (va_alist) va_dcl
#define VA_START(va_list, var) va_start(va_list)
#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy
#define VA_CLOSE(AP) } va_end(AP); }
#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE)
/* some systems define these in header files for non-ansi mode */
#undef const
#undef volatile
#undef signed
#undef inline
#define const
#define volatile
#define signed
#define inline
#ifndef IN_GCC
#define CONST
#define VOLATILE
#define SIGNED
#define PROTO(type, name, arglist) type name ()
#define EXFUN(name, proto) name()
#define DEFUN(name, arglist, args) name arglist args;
#define DEFUN_VOID(name) name()
#define AND ;
#define DOTS
#define NOARGS
#endif /* ! IN_GCC */
#endif /* ANSI C. */
/* Define macros for some gcc attributes. This permits us to use the
macros freely, and know that they will come into play for the
version of gcc in which they are supported. */
#if (GCC_VERSION < 2007)
# define __attribute__(x)
#endif
/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
#ifndef ATTRIBUTE_MALLOC
# if (GCC_VERSION >= 2096)
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
# else
# define ATTRIBUTE_MALLOC
# endif /* GNUC >= 2.96 */
#endif /* ATTRIBUTE_MALLOC */
/* Attributes on labels were valid as of gcc 2.93. */
#ifndef ATTRIBUTE_UNUSED_LABEL
# if (GCC_VERSION >= 2093)
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
# else
# define ATTRIBUTE_UNUSED_LABEL
# endif /* GNUC >= 2.93 */
#endif /* ATTRIBUTE_UNUSED_LABEL */
#ifndef ATTRIBUTE_UNUSED
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif /* ATTRIBUTE_UNUSED */
#ifndef ATTRIBUTE_NORETURN
#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#endif /* ATTRIBUTE_NORETURN */
#ifndef ATTRIBUTE_PRINTF
#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
#endif /* ATTRIBUTE_PRINTF */
/* We use __extension__ in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before
gcc 2.8. */
#if GCC_VERSION < 2008
#define __extension__
#endif
/* Bootstrap support: Adjust certain macros defined by Autoconf,
which are only valid for the stage1 compiler. If we detect
a modern version of GCC, we are probably in stage2 or beyond,
so unconditionally reset the values. Note that const, inline,
etc. have been dealt with above. */
#if (GCC_VERSION >= 2007)
# ifndef HAVE_LONG_DOUBLE
# define HAVE_LONG_DOUBLE 1
# endif
#endif /* GCC >= 2.7 */
#endif /* ansidecl.h */

View File

@ -0,0 +1,72 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <wx/filename.h>
#include <3d_info.h>
#include <3d_cache.h>
#include <sg/ifsg_api.h>
#include "3d_cache_dialogs.h"
#include "dialog_config_3dpath.h"
#include "dialog_select_3dmodel.h"
bool S3D::Select3DModel( wxWindow* aParent, S3D_CACHE* aCache,
wxString& prevModelSelectDir, int& prevModelWildcard, S3D_INFO* aModel )
{
DLG_SEL_3DMODEL* dm = new DLG_SEL_3DMODEL( aParent, aCache,
prevModelSelectDir, prevModelWildcard );
if( wxID_OK == dm->ShowModal() )
{
// retrieve the data entry for the 3D model
dm->GetModelData( aModel );
// remember the previous settings
prevModelWildcard = dm->GetFilterIndex();
wxFileName name( dm->GetPath() );
name.Normalize();
prevModelSelectDir = name.GetPath();
delete dm;
return true;
}
delete dm;
return false;
}
bool S3D::Configure3DPaths( wxWindow* aParent, S3D_FILENAME_RESOLVER* aResolver )
{
DLG_CFG_3DPATH* dp = new DLG_CFG_3DPATH( aParent, aResolver );
if( wxID_OK == dp->ShowModal() )
{
delete dp;
return true;
}
delete dp;
return false;
}

View File

@ -0,0 +1,41 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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
*/
#ifndef CACHE_DIALOGS_3D_H
#define CACHE_DIALOGS_3D_H
#include <wx/wx.h>
class S3D_CACHE;
class S3D_FILENAME_RESOLVER;
struct S3D_INFO;
namespace S3D
{
bool Select3DModel( wxWindow* aParent, S3D_CACHE* aCache,
wxString& prevModelSelectDir, int& prevModelWildcard, S3D_INFO* aModel );
bool Configure3DPaths( wxWindow* aParent, S3D_FILENAME_RESOLVER* aResolver );
};
#endif // CACHE_DIALOGS_3D_H

View File

@ -0,0 +1,257 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <cstdlib>
#include <list>
#include <wx/filename.h>
#include <3d_cache.h>
#include "dialog_config_3dpath.h"
enum
{
btnEditPath = wxID_HIGHEST + 1,
btnAddPath,
btnDeletePath,
lbPathList
};
wxBEGIN_EVENT_TABLE( DLG_CFG_3DPATH, wxDialog )
EVT_BUTTON( wxID_OK, DLG_CFG_3DPATH::OnOK )
EVT_BUTTON( wxID_CANCEL, DLG_CFG_3DPATH::OnExit )
EVT_BUTTON( btnEditPath, DLG_CFG_3DPATH::EditPath )
EVT_BUTTON( btnAddPath, DLG_CFG_3DPATH::AddPath )
EVT_BUTTON( btnDeletePath, DLG_CFG_3DPATH::DeletePath )
wxEND_EVENT_TABLE()
DLG_CFG_3DPATH::DLG_CFG_3DPATH( wxWindow* aParent, S3D_FILENAME_RESOLVER* aResolver )
: wxDialog( aParent, -1, _( "3D Model Path Configuration" ),
wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU
| wxRESIZE_BORDER | wxMINIMIZE_BOX )
{
resolver = aResolver;
Bind( wxEVT_LIST_ITEM_ACTIVATED, &DLG_CFG_3DPATH::EditPath, this, lbPathList );
Bind( wxEVT_LIST_ITEM_SELECTED, &DLG_CFG_3DPATH::PathSelect, this, lbPathList );
Bind( wxEVT_LIST_ITEM_DESELECTED, &DLG_CFG_3DPATH::PathSelect, this, lbPathList );
wxBoxSizer *vboxMain = new wxBoxSizer( wxVERTICAL );
wxBoxSizer *vboxSide = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* hboxTop = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hboxBot = new wxBoxSizer( wxHORIZONTAL );
pathList = new wxListView( this, lbPathList, wxDefaultPosition, wxSize( 400, 200 ),
wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL );
pathList->AppendColumn( wxEmptyString );
editButton = new wxButton( this, btnEditPath, _( "Edit" ),
wxDefaultPosition, wxSize( 100, 30 ) );
editButton->Enable( false );
wxButton* addButton = new wxButton( this, btnAddPath, _( "Add" ),
wxDefaultPosition, wxSize( 100, 30 ) );
deleteButton = new wxButton( this, btnDeletePath, _( "Delete" ),
wxDefaultPosition, wxSize( 100, 30 ) );
deleteButton->Enable( false );
wxButton* okButton = new wxButton( this, wxID_OK, _( "Ok" ),
wxDefaultPosition, wxSize( 100, 30 ) );
wxButton* cancelButton = new wxButton( this, wxID_CANCEL, _( "Cancel" ),
wxDefaultPosition, wxSize( 100, 30 ) );
vboxSide->Add( editButton, 0, wxALL, 10 );
vboxSide->Add( addButton, 0, wxALL, 10 );
vboxSide->Add( deleteButton, 0, wxALL, 10 );
hboxTop->Add( pathList, 1, wxEXPAND | wxALL, 10 );
hboxTop->Add( vboxSide, 0, wxEXPAND | wxALL, 10 );
hboxBot->Add( okButton, 0, wxALL, 10 );
hboxBot->Add( cancelButton, 0, wxALL, 10 );
vboxMain->Add( hboxTop, 1, wxEXPAND | wxALL, 10 );
vboxMain->Add( hboxBot, 0, wxEXPAND | wxALL, 10 );
if( resolver )
{
const std::list< wxString >* pl = resolver->GetPaths();
std::list< wxString >::const_iterator sL = pl->begin();
std::list< wxString >::const_iterator eL = pl->end();
// always skip the first entry which is the current project dir
if( sL != eL )
++sL;
long i = 0;
while( sL != eL )
{
m_paths.push_back( *sL );
pathList->InsertItem( i, *sL );
++i;
++sL;
}
pathList->SetColumnWidth(0, wxLIST_AUTOSIZE);
}
SetSizerAndFit( vboxMain );
Centre();
return;
}
void DLG_CFG_3DPATH::OnExit( wxCommandEvent& event )
{
if( IsModal() )
EndModal( wxID_EXIT );
else
Close( true );
return;
}
void DLG_CFG_3DPATH::OnOK( wxCommandEvent& event )
{
if( resolver )
resolver->UpdatePathList( m_paths );
if( IsModal() )
EndModal( wxID_OK );
else
Close( true );
return;
}
void DLG_CFG_3DPATH::EditPath( wxCommandEvent& event )
{
long nItem = pathList->GetFirstSelected();
wxString tmpname = m_paths[ nItem ];
wxDirDialog* dd = new wxDirDialog( this, _( "Change 3D model directory" ),
m_paths[ nItem ] );
if( wxID_OK == dd->ShowModal() )
{
wxFileName path( wxFileName::DirName( dd->GetPath() ) );
path.Normalize();
wxString newname = path.GetPath();
if( tmpname.Cmp( newname ) )
{
pathList->DeleteItem( nItem );
pathList->InsertItem( nItem, newname );
m_paths[ nItem ] = newname;
pathList->Focus( nItem );
editButton->Enable( false );
deleteButton->Enable( false );
pathList->SetColumnWidth(0, wxLIST_AUTOSIZE);
}
}
delete dd;
return;
}
void DLG_CFG_3DPATH::AddPath( wxCommandEvent& event )
{
wxDirDialog* dd = new wxDirDialog( this, _( "Add a 3D model directory" ) );
if( wxID_OK == dd->ShowModal() )
{
wxFileName path( wxFileName::DirName( dd->GetPath() ) );
path.Normalize();
wxString newname = path.GetPath();
m_paths.push_back( newname );
pathList->InsertItem( pathList->GetItemCount(), *m_paths.rbegin() );
pathList->Focus( pathList->GetItemCount() -1 );
editButton->Enable( false );
deleteButton->Enable( false );
pathList->SetColumnWidth(0, wxLIST_AUTOSIZE);
}
delete dd;
return;
}
void DLG_CFG_3DPATH::DeletePath( wxCommandEvent& event )
{
long nItem = pathList->GetFirstSelected();
if( -1 == nItem )
return;
m_paths.erase( m_paths.begin() + nItem );
pathList->DeleteItem( nItem );
if( m_paths.size() > 0 )
{
if( nItem > 0 )
--nItem;
pathList->Select( nItem );
}
else
{
editButton->Enable( false );
deleteButton->Enable( false );
pathList->Select( -1 );
}
return;
}
void DLG_CFG_3DPATH::PathSelect( wxCommandEvent& event )
{
long nItem = pathList->GetFirstSelected();
if( -1 == nItem )
{
editButton->Enable( false );
deleteButton->Enable( false );
return;
}
editButton->Enable( true );
deleteButton->Enable( true );
return;
}

View File

@ -0,0 +1,62 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 dialog_config_3dpath.h
* creates a dialog to edit the default search paths for 3D model files.
*/
#ifndef DIALOG_CONFIG_3DPATH_H
#define DIALOG_CONFIG_3DPATH_H
#include <vector>
#include <wx/wx.h>
#include <wx/listctrl.h>
class S3D_FILENAME_RESOLVER;
class DLG_CFG_3DPATH : public wxDialog
{
private:
wxListView* pathList;
wxButton* editButton;
wxButton* deleteButton;
S3D_FILENAME_RESOLVER* resolver;
std::vector< wxString > m_paths;
public:
DLG_CFG_3DPATH( wxWindow* aParent, S3D_FILENAME_RESOLVER* aResolver );
private:
void OnExit( wxCommandEvent& event );
void OnOK( wxCommandEvent& event );
void EditPath( wxCommandEvent& event );
void AddPath( wxCommandEvent& event );
void DeletePath( wxCommandEvent& event );
void PathSelect( wxCommandEvent& event );
wxDECLARE_EVENT_TABLE();
};
#endif // DIALOG_CONFIG_3DPATH_H

View File

@ -0,0 +1,119 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache.h>
#include "dialog_select_3dmodel.h"
#include "panel_prev_model.h"
static S3D_CACHE* mm = NULL;
static wxFileDialog* fm = NULL;
static wxWindow* mkPreviewPanel( wxWindow* aParent )
{
PANEL_PREV_3D* pp = new PANEL_PREV_3D( aParent, true );
pp->SetModelManager( mm );
pp->SetFileSelectorDlg( fm );
return (wxWindow*)pp;
}
wxBEGIN_EVENT_TABLE( DLG_SEL_3DMODEL, wxFileDialog )
EVT_BUTTON( wxID_OK, DLG_SEL_3DMODEL::OnOK )
EVT_BUTTON( wxID_CANCEL, DLG_SEL_3DMODEL::OnExit )
wxEND_EVENT_TABLE()
DLG_SEL_3DMODEL::DLG_SEL_3DMODEL( wxWindow* aParent, S3D_CACHE* aManager,
const wxString& aDefaultDir, int aFilterIndex )
: wxFileDialog( aParent, _( "Select a 3D Model" ), aDefaultDir )
{
m_manager = aManager;
mm = aManager;
fm = this;
long ws = GetWindowStyleFlag();
ws |= wxFD_FILE_MUST_EXIST;
SetWindowStyleFlag( ws );
SetExtraControlCreator( mkPreviewPanel );
if( NULL != m_manager )
{
std::list< wxString > const* fl = m_manager->GetFileFilters();
std::list< wxString >::const_iterator sL = fl->begin();
std::list< wxString >::const_iterator eL = fl->end();
wxString filter;
while( sL != eL )
{
filter.Append( *sL );
++sL;
if( sL != eL )
filter.Append( wxT( "|" ) );
}
if( !filter.empty() )
SetWildcard( filter );
if( aFilterIndex >= 0 && aFilterIndex < (int)fl->size() )
SetFilterIndex( aFilterIndex );
}
return;
}
void DLG_SEL_3DMODEL::OnExit( wxCommandEvent& event )
{
if( IsModal() )
EndModal( wxID_EXIT );
else
Close( true );
return;
}
void DLG_SEL_3DMODEL::OnOK( wxCommandEvent& event )
{
if( IsModal() )
EndModal( wxID_OK );
else
Close( true );
return;
}
void DLG_SEL_3DMODEL::GetModelData( S3D_INFO* aModel )
{
PANEL_PREV_3D* pp = (PANEL_PREV_3D*)GetExtraControl();
if( pp )
pp->GetModelData( aModel );
return;
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 dialog_select_3dmodel.h
* creates a dialog to select 3D model files
*/
#ifndef DIALOG_SELECT_3DMODEL_H
#define DIALOG_SELECT_3DMODEL_H
#include <wx/wx.h>
#include <wx/filedlg.h>
class S3D_CACHE;
class S3D_INFO;
class DLG_SEL_3DMODEL : public wxFileDialog
{
private:
S3D_CACHE* m_manager;
public:
DLG_SEL_3DMODEL( wxWindow* aParent, S3D_CACHE* aManager,
const wxString& aDefaultDir, int aFilterIndex );
// Retrieve model data
void GetModelData( S3D_INFO* aModel );
private:
void OnExit( wxCommandEvent& event );
void OnOK( wxCommandEvent& event );
wxDECLARE_EVENT_TABLE();
};
#endif // DIALOG_SELECT_3DMODEL_H

View File

@ -0,0 +1,634 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_model_viewer/c3d_model_viewer.h>
#include <3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.h>
#include <common_ogl/cogl_att_list.h>
#include <iostream>
#include <cstdlib>
#include <wx/sizer.h>
#include <wx/choice.h>
#include <wx/filename.h>
#include <wx/glcanvas.h>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <3d_cache.h>
#include <3d_info.h>
#include <3d_filename_resolver.h>
#include <3d_cache/sg/ifsg_api.h>
#include "panel_prev_model.h"
#include "dialog_select_3dmodel.h"
#include "3d_cache_dialogs.h"
// ensure -360 < rotation < 360
static void checkRotation( double& rot )
{
if( rot >= 360.0 )
{
int n = rot / 360.0;
rot -= 360.0 * (double)n;
}
else if( rot <= -360.0 )
{
int n = -rot / 360.0;
rot += 360.0 * (double)n;
}
return;
}
enum {
ID_SET_DIR = wxID_LAST + 1,
ID_CFG_PATHS,
ID_3D_ISO,
ID_3D_UPDATE,
ID_3D_LEFT,
ID_3D_RIGHT,
ID_3D_FRONT,
ID_3D_BACK,
ID_3D_TOP,
ID_3D_BOTTOM
};
wxBEGIN_EVENT_TABLE( PANEL_PREV_3D, wxPanel)
EVT_CHOICE( ID_SET_DIR, PANEL_PREV_3D::SetRootDir )
EVT_BUTTON( ID_CFG_PATHS, PANEL_PREV_3D::Cfg3DPaths )
EVT_BUTTON( ID_3D_ISO, PANEL_PREV_3D::View3DISO )
EVT_BUTTON( ID_3D_UPDATE, PANEL_PREV_3D::View3DUpdate )
EVT_BUTTON( ID_3D_LEFT, PANEL_PREV_3D::View3DLeft )
EVT_BUTTON( ID_3D_RIGHT, PANEL_PREV_3D::View3DRight )
EVT_BUTTON( ID_3D_FRONT, PANEL_PREV_3D::View3DFront )
EVT_BUTTON( ID_3D_BACK, PANEL_PREV_3D::View3DBack )
EVT_BUTTON( ID_3D_TOP, PANEL_PREV_3D::View3DTop )
EVT_BUTTON( ID_3D_BOTTOM, PANEL_PREV_3D::View3DBottom )
wxEND_EVENT_TABLE()
PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, bool hasFileSelector ) :
wxPanel( aParent, -1 )
{
m_ModelManager = NULL;
m_FileDlg = NULL;
canvas = NULL;
model = NULL;
wxBoxSizer* mainBox = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* vbox = new wxStaticBoxSizer( wxVERTICAL, this, _( "3D Model Orientation" ) );
wxBoxSizer* hboxDirChoice = NULL;
dirChoices = NULL;
if( hasFileSelector )
{
hboxDirChoice = new wxBoxSizer( wxHORIZONTAL );
dirChoices = new wxChoice( this, ID_SET_DIR );
#ifdef _WIN32
// Note: On Win32 the native selector box will truncate text
// if the text is too long.
dirChoices->SetMinSize( wxSize( 450, -1 ) );
#endif
wxStaticText* stDirChoice = new wxStaticText( this, -1, _( "Paths:" ) );
wxButton* cfgPaths = new wxButton( this, ID_CFG_PATHS, _( "Configure Paths" ) );
hboxDirChoice->Add( stDirChoice, 0, wxALL | wxCENTER, 5 );
hboxDirChoice->Add( dirChoices, 1, wxEXPAND | wxALL, 5 );
hboxDirChoice->Add( cfgPaths, 0, wxALL, 5 );
}
wxStaticBoxSizer* vbScale = new wxStaticBoxSizer( wxVERTICAL, this, _( "Scale" ) );
wxStaticBoxSizer* vbRotate = new wxStaticBoxSizer( wxVERTICAL, this, _( "Rotation" ) );
wxStaticBoxSizer* vbOffset = new wxStaticBoxSizer( wxVERTICAL, this, _( "Offset (inches)" ) );
wxStaticBox* modScale = vbScale->GetStaticBox();
wxStaticBox* modRotate = vbRotate->GetStaticBox();
wxStaticBox* modOffset = vbOffset->GetStaticBox();
wxBoxSizer* hbS1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbS2 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbS3 = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* txtS1 = new wxStaticText( modScale, -1, wxT( "X:" ) );
wxStaticText* txtS2 = new wxStaticText( modScale, -1, wxT( "Y:" ) );
wxStaticText* txtS3 = new wxStaticText( modScale, -1, wxT( "Z:" ) );
xscale = new wxTextCtrl( modScale, -1, "1.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
yscale = new wxTextCtrl( modScale, -1, "1.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
zscale = new wxTextCtrl( modScale, -1, "1.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
xscale->SetMaxLength( 9 );
yscale->SetMaxLength( 9 );
zscale->SetMaxLength( 9 );
hbS1->Add( txtS1, 0, wxALL, 2 );
hbS1->Add( xscale, 0, wxALL, 2 );
hbS2->Add( txtS2, 0, wxALL, 2 );
hbS2->Add( yscale, 0, wxALL, 2 );
hbS3->Add( txtS3, 0, wxALL, 2 );
hbS3->Add( zscale, 0, wxALL, 2 );
vbScale->Add( hbS1, 0, wxEXPAND | wxALL, 2 );
vbScale->Add( hbS2, 0, wxEXPAND | wxALL, 2 );
vbScale->Add( hbS3, 0, wxEXPAND | wxALL, 2 );
wxBoxSizer* hbR1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbR2 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbR3 = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* txtR1 = new wxStaticText( modRotate, -1, wxT( "X:" ) );
wxStaticText* txtR2 = new wxStaticText( modRotate, -1, wxT( "Y:" ) );
wxStaticText* txtR3 = new wxStaticText( modRotate, -1, wxT( "Z:" ) );
xrot = new wxTextCtrl( modRotate, -1, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
yrot = new wxTextCtrl( modRotate, -1, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
zrot = new wxTextCtrl( modRotate, -1, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
xrot->SetMaxLength( 9 );
yrot->SetMaxLength( 9 );
zrot->SetMaxLength( 9 );
hbR1->Add( txtR1, 0, wxALL, 2 );
hbR1->Add( xrot, 0, wxALL, 2 );
hbR2->Add( txtR2, 0, wxALL, 2 );
hbR2->Add( yrot, 0, wxALL, 2 );
hbR3->Add( txtR3, 0, wxALL, 2 );
hbR3->Add( zrot, 0, wxALL, 2 );
vbRotate->Add( hbR1, 0, wxEXPAND | wxALL, 2 );
vbRotate->Add( hbR2, 0, wxEXPAND | wxALL, 2 );
vbRotate->Add( hbR3, 0, wxEXPAND | wxALL, 2 );
wxBoxSizer* hbO1 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbO2 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbO3 = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* txtO1 = new wxStaticText( modOffset, -1, wxT( "X:" ) );
wxStaticText* txtO2 = new wxStaticText( modOffset, -1, wxT( "Y:" ) );
wxStaticText* txtO3 = new wxStaticText( modOffset, -1, wxT( "Z:" ) );
xoff = new wxTextCtrl( modOffset, -1, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
yoff = new wxTextCtrl( modOffset, -1, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
zoff = new wxTextCtrl( modOffset, -1, "0.0", wxDefaultPosition, wxDefaultSize,
wxTE_PROCESS_ENTER );
xoff->SetMaxLength( 9 );
yoff->SetMaxLength( 9 );
zoff->SetMaxLength( 9 );
hbO1->Add( txtO1, 0, wxALL, 2 );
hbO1->Add( xoff, 0, wxALL, 2 );
hbO2->Add( txtO2, 0, wxALL, 2 );
hbO2->Add( yoff, 0, wxALL, 2 );
hbO3->Add( txtO3, 0, wxALL, 2 );
hbO3->Add( zoff, 0, wxALL, 2 );
vbOffset->Add( hbO1, 0, wxEXPAND | wxALL, 2 );
vbOffset->Add( hbO2, 0, wxEXPAND | wxALL, 2 );
vbOffset->Add( hbO3, 0, wxEXPAND | wxALL, 2 );
if( NULL != hboxDirChoice )
mainBox->Add( hboxDirChoice, 0, wxEXPAND );
// hbox holding orientation data and preview
wxBoxSizer* hbox = new wxBoxSizer( wxHORIZONTAL );
// vbox holding orientation data
wxBoxSizer* vboxOrient = new wxBoxSizer( wxVERTICAL );
// vbox holding the preview and view buttons
wxBoxSizer* vboxPrev = new wxBoxSizer( wxVERTICAL );
vboxOrient->Add( vbScale, 0, wxALL, 5 );
vboxOrient->Add( vbRotate, 0, wxALL, 5 );
vboxOrient->Add( vbOffset, 0, wxALL, 5 );
vboxOrient->AddSpacer( 20 );
// add preview items
preview = new wxPanel( this, -1 );
preview->SetMinSize( wxSize( 320, 240 ) );
preview->SetBackgroundColour( wxColor( 0, 0, 0 ));
vboxPrev->Add( preview, 1, wxEXPAND | wxALIGN_CENTER | wxLEFT | wxRIGHT, 5 );
// buttons:
wxButton* vFront = new wxButton( this, ID_3D_FRONT, wxT( "F" ) );
wxButton* vBack = new wxButton( this, ID_3D_BACK, wxT( "B" ) );
wxButton* vLeft = new wxButton( this, ID_3D_LEFT, wxT( "L" ) );
wxButton* vRight = new wxButton( this, ID_3D_RIGHT, wxT( "R" ) );
wxButton* vTop = new wxButton( this, ID_3D_TOP, wxT( "T" ) );
wxButton* vBottom = new wxButton( this, ID_3D_BOTTOM, wxT( "B" ) );
wxButton* vISO = new wxButton( this, ID_3D_ISO, wxT( "I" ) );
wxButton* vUpdate = new wxButton( this, ID_3D_UPDATE, wxT( "U" ) );
wxBoxSizer* hbBT = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* hbBB = new wxBoxSizer( wxHORIZONTAL );
hbBT->Add( vISO, 0, wxCENTER | wxALL, 3 );
hbBT->Add( vLeft, 0, wxCENTER | wxALL, 3 );
hbBT->Add( vFront, 0, wxCENTER | wxALL, 3 );
hbBT->Add( vTop, 0, wxCENTER | wxALL, 3 );
hbBT->AddSpacer( 17 );
hbBB->Add( vUpdate, 0, wxCENTER | wxALL, 3 );
hbBB->Add( vRight, 0, wxCENTER | wxALL, 3 );
hbBB->Add( vBack, 0, wxCENTER | wxALL, 3 );
hbBB->Add( vBottom, 0, wxCENTER | wxALL, 3 );
hbBB->AddSpacer( 17 );
vboxPrev->AddSpacer( 7 );
vboxPrev->Add( hbBT, 0 );
vboxPrev->Add( hbBB, 0 );
// XXX - Suppress the buttons until the Renderer code is ready.
// vboxPrev->Hide( preview, true );
vboxPrev->Hide( hbBT, true );
vboxPrev->Hide( hbBB, true );
hbox->Add( vboxOrient, 0, wxALL, 5 );
hbox->Add( vboxPrev, 1, wxEXPAND );
vbox->Add( hbox, 1, wxEXPAND );
mainBox->Add( vbox, 1, wxEXPAND | wxALL, 5 );
if( hasFileSelector )
{
// NOTE: if/when the FIle Selector preview is implemented
// we may need to hide the orientation boxes to ensure the
// users have sufficient display area for the browser.
// hbox->Hide( vboxOrient, true );
// XXX -
// NOTE: for now we always suppress the preview and model orientation
// panels while in the file selector
mainBox->Hide( vbox, true );
}
SetSizerAndFit( mainBox );
Centre();
return;
}
PANEL_PREV_3D::~PANEL_PREV_3D()
{
if( NULL != canvas )
{
canvas->Clear3DModel();
canvas->Refresh();
canvas->Update();
}
if( model )
S3D::Destroy3DModel( &model );
return;
}
void PANEL_PREV_3D::SetModelManager( S3D_CACHE* aModelManager )
{
m_ModelManager = aModelManager;
updateDirChoiceList();
return;
}
void PANEL_PREV_3D::SetFileSelectorDlg( wxFileDialog* aFileDlg )
{
m_FileDlg = aFileDlg;
updateDirChoiceList();
return;
}
void PANEL_PREV_3D::updateDirChoiceList( void )
{
if( NULL == m_FileDlg || NULL == m_ModelManager || NULL == dirChoices )
return;
std::list< wxString > const* md = m_ModelManager->GetResolver()->GetPaths();
std::list< wxString >::const_iterator sL = md->begin();
std::list< wxString >::const_iterator eL = md->end();
std::vector< wxString > cl;
while( sL != eL )
{
cl.push_back( *sL );
++sL;
}
if( !cl.empty() )
{
dirChoices->Clear();
dirChoices->Append( (int)cl.size(), &cl[0] );
dirChoices->Select( 0 );
}
Layout();
return;
}
void PANEL_PREV_3D::SetRootDir( wxCommandEvent& event )
{
if( !m_FileDlg )
return;
m_FileDlg->SetDirectory( dirChoices->GetString( dirChoices->GetSelection() ) );
return;
}
void PANEL_PREV_3D::Cfg3DPaths( wxCommandEvent& event )
{
if( !m_FileDlg || !m_ModelManager )
return;
if( S3D::Configure3DPaths( this, m_ModelManager->GetResolver() ) )
updateDirChoiceList();
return;
}
void PANEL_PREV_3D::View3DISO( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Isometric View\n";
return;
}
void PANEL_PREV_3D::View3DUpdate( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Update 3D View\n";
// update the model filename if appropriate
if( NULL != m_FileDlg )
{
wxString modelName = m_FileDlg->GetCurrentlySelectedFilename();
UpdateModelName( modelName );
}
return;
}
void PANEL_PREV_3D::View3DLeft( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Left View\n";
return;
}
void PANEL_PREV_3D::View3DRight( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Right View\n";
return;
}
void PANEL_PREV_3D::View3DFront( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Front View\n";
return;
}
void PANEL_PREV_3D::View3DBack( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Back View\n";
return;
}
void PANEL_PREV_3D::View3DTop( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Top View\n";
return;
}
void PANEL_PREV_3D::View3DBottom( wxCommandEvent& event )
{
// XXX - TO BE IMPLEMENTED
std::cout << "Switch to Bottom View\n";
return;
}
void PANEL_PREV_3D::GetModelData( S3D_INFO* aModel )
{
if( NULL == aModel )
return;
SGPOINT scale;
SGPOINT rotation;
SGPOINT offset;
xscale->GetValue().ToDouble( &scale.x );
yscale->GetValue().ToDouble( &scale.y );
zscale->GetValue().ToDouble( &scale.z );
if( 0.001 > scale.x || 0.001 > scale.y || 0.001 > scale.z )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] invalid scale values; setting all to 1.0\n";
scale.x = 1.0;
scale.y = 1.0;
scale.z = 1.0;
}
xrot->GetValue().ToDouble( &rotation.x );
yrot->GetValue().ToDouble( &rotation.y );
zrot->GetValue().ToDouble( &rotation.z );
checkRotation( rotation.x );
checkRotation( rotation.y );
checkRotation( rotation.z );
xoff->GetValue().ToDouble( &offset.x );
yoff->GetValue().ToDouble( &offset.y );
zoff->GetValue().ToDouble( &offset.z );
aModel->scale = scale;
aModel->offset = offset;
aModel->rotation = rotation;
// return if we are not in file selection mode
if( NULL == m_FileDlg )
return;
// file selection mode: retrieve the filename and specify a
// path relative to one of the config paths
wxFileName fname = m_FileDlg->GetPath();
fname.Normalize();
aModel->filename = m_ModelManager->GetResolver()->ShortenPath( fname.GetFullPath() );
return;
}
void PANEL_PREV_3D::SetModelData( S3D_INFO const* aModel )
{
xscale->SetValue( wxString::FromDouble( aModel->scale.x ) );
yscale->SetValue( wxString::FromDouble( aModel->scale.y ) );
zscale->SetValue( wxString::FromDouble( aModel->scale.z ) );
xrot->SetValue( wxString::FromDouble( aModel->rotation.x ) );
yrot->SetValue( wxString::FromDouble( aModel->rotation.y ) );
zrot->SetValue( wxString::FromDouble( aModel->rotation.z ) );
xoff->SetValue( wxString::FromDouble( aModel->offset.x ) );
yoff->SetValue( wxString::FromDouble( aModel->offset.y ) );
zoff->SetValue( wxString::FromDouble( aModel->offset.z ) );
modelInfo = *aModel;
UpdateModelName( aModel->filename );
return;
}
void PANEL_PREV_3D::UpdateModelName( wxString const& aModelName )
{
bool newModel = false;
// if the model name is a directory simply clear the current model
if( aModelName.empty() || wxFileName::DirExists( aModelName ) )
{
currentModelFile.clear();
modelInfo.filename.clear();
}
else
{
wxString newModelFile;
if( m_ModelManager )
newModelFile = m_ModelManager->GetResolver()->ResolvePath( aModelName );
else if( wxFileName::FileExists( aModelName ) )
newModelFile = aModelName;
if( newModelFile.empty() )
{
#ifdef DEBUG
std::cout << "[3dv] Update Model: (no such file) " << aModelName.ToUTF8() << "\n";
#endif
}
else if( newModelFile.Cmp( currentModelFile ) )
{
newModel = true;
#ifdef DEBUG
std::cout << "[3dv] Update Model: " << newModelFile.ToUTF8() << "\n";
#endif
}
#ifdef DEBUG
else
{
std::cout << "[3dv] Update Model: [model unchanged]\n";
}
#endif
currentModelFile = newModelFile;
modelInfo.filename = currentModelFile;
}
if( currentModelFile.empty() || newModel )
{
#ifdef DEBUG
std::cout << "[3dv] Update Model: painting black\n";
#endif
if( NULL != canvas )
canvas->Clear3DModel();
if( model )
S3D::Destroy3DModel( &model );
if( currentModelFile.empty() )
return;
}
SGPOINT rot;
SGPOINT trans;
model = m_ModelManager->Prepare( &modelInfo, rot, trans );
if( NULL == model )
{
#ifdef DEBUG
std::cout << "[3dv] Update Model: no model loaded\n";
#endif
if( NULL != canvas )
{
canvas->Refresh();
canvas->Update();
}
return;
}
#ifdef DEBUG
std::cout << "[3dv] Update Model: loading preview\n";
#endif
if( NULL == canvas )
{
#ifdef DEBUG
std::cout << "[3dv] Update Model: creating canvas\n";
#endif
canvas = new C3D_MODEL_VIEWER( preview,
COGL_ATT_LIST::GetAttributesList( true ) );
#ifdef DEBUG
if( NULL == canvas )
std::cout << "[3dv] Update Model: canvas creation FAILED\n";
#endif
canvas->SetSize( preview->GetClientSize() );
}
canvas->Set3DModel( *model );
canvas->Refresh();
canvas->Update();
return;
}
void PANEL_PREV_3D::UpdateWindowUI( long flags )
{
/*
XXX -
NOTE: until we figure out how to ensure that a Paint Event is
generated for the File Selector's UI, we cannot display any
preview within the file browser.
if( wxUPDATE_UI_RECURSE == flags && m_FileDlg && m_ModelManager )
{
// check for a change in the current model file
S3D_INFO info;
modelInfo = info;
UpdateModelName( m_FileDlg->GetCurrentlySelectedFilename() );
}
*/
wxPanel::UpdateWindowUI( flags );
return;
}

View File

@ -0,0 +1,97 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 panel_prev_model.h
* defines a panel which is to be added to a wxFileDialog via SetExtraControl();
* the panel shows a preview of the model being browsed (if preview is supported
* by a plugin) and provides controls to set the offset/rotation/scale of the
* model as per KiCad's current behavior. The panel may also be used in the 3D
* configuration dialog to tune the positioning of the models without invoking
* a file selector dialog.
*/
#ifndef PANEL_PREV_MODEL_H
#define PANEL_PREV_MODEL_H
#include <wx/wx.h>
#include <wx/panel.h>
#include <3d_rendering/c3dmodel.h>
#include <3d_cache/3d_info.h>
class S3D_CACHE;
class C3D_MODEL_VIEWER;
class PANEL_PREV_3D : public wxPanel
{
public:
PANEL_PREV_3D( wxWindow* aParent, bool hasFileSelector = false );
~PANEL_PREV_3D();
void SetModelManager( S3D_CACHE* aModelManager );
void SetFileSelectorDlg( wxFileDialog* aFileDlg );
void SetRootDir( wxCommandEvent& event );
void Cfg3DPaths( wxCommandEvent& event );
// 3D views
void View3DISO( wxCommandEvent& event );
void View3DUpdate( wxCommandEvent& event );
void View3DLeft( wxCommandEvent& event );
void View3DRight( wxCommandEvent& event );
void View3DFront( wxCommandEvent& event );
void View3DBack( wxCommandEvent& event );
void View3DTop( wxCommandEvent& event );
void View3DBottom( wxCommandEvent& event );
// Set / Retrieve model data
void SetModelData( S3D_INFO const* aModel );
void GetModelData( S3D_INFO* aModel );
void UpdateModelName( wxString const& aModel );
// Update on change of FileDlg selection
virtual void UpdateWindowUI( long flags = wxUPDATE_UI_NONE );
private:
wxString currentModelFile;
S3D_CACHE* m_ModelManager;
wxFileDialog* m_FileDlg;
wxChoice* dirChoices;
wxTextCtrl* xscale;
wxTextCtrl* yscale;
wxTextCtrl* zscale;
wxTextCtrl* xrot;
wxTextCtrl* yrot;
wxTextCtrl* zrot;
wxTextCtrl* xoff;
wxTextCtrl* yoff;
wxTextCtrl* zoff;
wxPanel* preview;
C3D_MODEL_VIEWER* canvas;
S3DMODEL* model;
S3D_INFO modelInfo;
private:
void updateDirChoiceList( void );
wxDECLARE_EVENT_TABLE();
};
#endif // PANEL_PREV_MODEL_H

409
3d-viewer/3d_cache/md5.cpp Normal file
View File

@ -0,0 +1,409 @@
/* md5.c - Functions to compute MD5 message digest of files or memory blocks
* according to the definition of MD5 in RFC 1321 from April 1992.
* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
*
* NOTE: This source is derived from an old version taken from the GNU C
* Library (glibc).
*
* 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, 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, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
# include <stdlib.h>
# include <string.h>
#include "ansidecl.h"
#include "md5.h"
#ifdef __APPLE__
# include <machine/endian.h>
#elif !defined( _WIN32 )
# include <endian.h>
#endif
# if __BYTE_ORDER == __BIG_ENDIAN
# define WORDS_BIGENDIAN 1
# endif
#ifdef WORDS_BIGENDIAN
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#else
# define SWAP(n) (n)
#endif
/* This array contains the bytes used to pad the buffer to the next
* 64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* Initialize structure containing state of computation.
* (RFC 1321, 3.3: Step 3) */
void
md5_init_ctx ( struct md5_ctx *ctx )
{
ctx->A = (md5_uint32) 0x67452301;
ctx->B = (md5_uint32) 0xefcdab89;
ctx->C = (md5_uint32) 0x98badcfe;
ctx->D = (md5_uint32) 0x10325476;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Put result from CTX in first 16 bytes following RESBUF. The result
* must be in little endian byte order.
*
* IMPORTANT: On some systems it is required that RESBUF is correctly
* aligned for a 32 bits value. */
void *
md5_read_ctx ( const struct md5_ctx *ctx, void *resbuf )
{
((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
* prolog according to the standard and write the result to RESBUF.
*
* IMPORTANT: On some systems it is required that RESBUF is correctly
* aligned for a 32 bits value. */
void *
md5_finish_ctx ( struct md5_ctx *ctx, void *resbuf )
{
/* Take yet unprocessed bytes into account. */
md5_uint32 bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy (&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
*(md5_uint32 *) (&ctx->buffer[bytes + pad]) = SWAP (ctx->total[0] << 3);
*(md5_uint32 *) (&ctx->buffer[bytes + pad + 4]) = SWAP ((ctx->total[1] << 3) |
(ctx->total[0] >> 29));
/* Process last bytes. */
md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
return md5_read_ctx (ctx, resbuf);
}
/* Compute MD5 message digest for bytes read from STREAM. The
* resulting message digest number will be written into the 16 bytes
* beginning at RESBLOCK. */
int
md5_stream ( FILE *stream, void *resblock )
{
/* Important: BLOCKSIZE must be a multiple of 64. */
#define BLOCKSIZE 4096
struct md5_ctx ctx;
char buffer[BLOCKSIZE + 72];
size_t sum;
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Iterate over full file contents. */
while (1)
{
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
* computation function processes the whole buffer so that with the
* next round of the loop another block can be read. */
size_t n;
sum = 0;
/* Read block. Take care for partial reads. */
do
{
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
sum += n;
}
while (sum < BLOCKSIZE && n != 0);
if (n == 0 && ferror (stream))
return 1;
/* If end of file is reached, end the loop. */
if (n == 0)
break;
/* Process buffer with BLOCKSIZE bytes. Note that
* BLOCKSIZE % 64 == 0
*/
md5_process_block (buffer, BLOCKSIZE, &ctx);
}
/* Add the last bytes if necessary. */
if (sum > 0)
md5_process_bytes (buffer, sum, &ctx);
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
return 0;
}
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
* result is always in little endian byte order, so that a byte-wise
* output yields to the wanted ASCII representation of the message
* digest. */
void *
md5_buffer ( const char *buffer, size_t len, void *resblock )
{
struct md5_ctx ctx;
/* Initialize the computation context. */
md5_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
md5_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return md5_finish_ctx (&ctx, resblock);
}
void
md5_process_bytes ( const void *buffer, size_t len, struct md5_ctx *ctx )
{
/* When we already have some bits in our internal buffer concatenate
* both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (left_over + add > 64)
{
md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
(left_over + add) & 63);
ctx->buflen = (left_over + add) & 63;
}
buffer = (const void *) ((const char *) buffer + add);
len -= add;
}
/* Process available complete blocks. */
if (len > 64)
{
md5_process_block (buffer, len & ~63, ctx);
buffer = (const void *) ((const char *) buffer + (len & ~63));
len &= 63;
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
memcpy (ctx->buffer, buffer, len);
ctx->buflen = len;
}
}
/* These are the four functions used in the four steps of the MD5 algorithm
* and defined in the RFC 1321. The first function is a little bit optimized
* (as found in Colin Plumbs public domain implementation). */
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
#define FF(b, c, d) (d ^ (b & (c ^ d)))
#define FG(b, c, d) FF (d, b, c)
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))
/* Process LEN bytes of BUFFER, accumulating context into CTX.
* It is assumed that LEN % 64 == 0. */
void
md5_process_block ( const void *buffer, size_t len, struct md5_ctx *ctx )
{
md5_uint32 correct_words[16];
const md5_uint32 *words = (const md5_uint32 *) buffer;
size_t nwords = len / sizeof (md5_uint32);
const md5_uint32 *endp = words + nwords;
md5_uint32 A = ctx->A;
md5_uint32 B = ctx->B;
md5_uint32 C = ctx->C;
md5_uint32 D = ctx->D;
/* First increment the byte count. RFC 1321 specifies the possible
* length of the file up to 2^64 bits. Here we only compute the
* number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* Process all bytes in the buffer with 64 bytes in each round of
* the loop. */
while (words < endp)
{
md5_uint32 *cwp = correct_words;
md5_uint32 A_save = A;
md5_uint32 B_save = B;
md5_uint32 C_save = C;
md5_uint32 D_save = D;
/* First round: using the given function, the context and a constant
* the next context is computed. Because the algorithms processing
* unit is a 32-bit word and it is determined to work on words in
* little endian byte order we perhaps have to change the byte order
* before the computation. To reduce the work for the next steps
* we store the swapped words in the array CORRECT_WORDS. */
#define OP(a, b, c, d, s, T) \
do \
{ \
a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
++words; \
CYCLIC (a, s); \
a += b; \
} \
while (0)
/* It is unfortunate that C does not provide an operator for
* cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
/* Before we start, one word to the strange constants.
* They are defined in RFC 1321 as
*
* T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
*/
/* Round 1. */
OP (A, B, C, D, 7, (md5_uint32) 0xd76aa478);
OP (D, A, B, C, 12, (md5_uint32) 0xe8c7b756);
OP (C, D, A, B, 17, (md5_uint32) 0x242070db);
OP (B, C, D, A, 22, (md5_uint32) 0xc1bdceee);
OP (A, B, C, D, 7, (md5_uint32) 0xf57c0faf);
OP (D, A, B, C, 12, (md5_uint32) 0x4787c62a);
OP (C, D, A, B, 17, (md5_uint32) 0xa8304613);
OP (B, C, D, A, 22, (md5_uint32) 0xfd469501);
OP (A, B, C, D, 7, (md5_uint32) 0x698098d8);
OP (D, A, B, C, 12, (md5_uint32) 0x8b44f7af);
OP (C, D, A, B, 17, (md5_uint32) 0xffff5bb1);
OP (B, C, D, A, 22, (md5_uint32) 0x895cd7be);
OP (A, B, C, D, 7, (md5_uint32) 0x6b901122);
OP (D, A, B, C, 12, (md5_uint32) 0xfd987193);
OP (C, D, A, B, 17, (md5_uint32) 0xa679438e);
OP (B, C, D, A, 22, (md5_uint32) 0x49b40821);
/* For the second to fourth round we have the possibly swapped words
* in CORRECT_WORDS. Redefine the macro to take an additional first
* argument specifying the function to use. */
#undef OP
#define OP(a, b, c, d, k, s, T) \
do \
{ \
a += FX (b, c, d) + correct_words[k] + T; \
CYCLIC (a, s); \
a += b; \
} \
while (0)
#define FX(b, c, d) FG (b, c, d)
/* Round 2. */
OP (A, B, C, D, 1, 5, (md5_uint32) 0xf61e2562);
OP (D, A, B, C, 6, 9, (md5_uint32) 0xc040b340);
OP (C, D, A, B, 11, 14, (md5_uint32) 0x265e5a51);
OP (B, C, D, A, 0, 20, (md5_uint32) 0xe9b6c7aa);
OP (A, B, C, D, 5, 5, (md5_uint32) 0xd62f105d);
OP (D, A, B, C, 10, 9, (md5_uint32) 0x02441453);
OP (C, D, A, B, 15, 14, (md5_uint32) 0xd8a1e681);
OP (B, C, D, A, 4, 20, (md5_uint32) 0xe7d3fbc8);
OP (A, B, C, D, 9, 5, (md5_uint32) 0x21e1cde6);
OP (D, A, B, C, 14, 9, (md5_uint32) 0xc33707d6);
OP (C, D, A, B, 3, 14, (md5_uint32) 0xf4d50d87);
OP (B, C, D, A, 8, 20, (md5_uint32) 0x455a14ed);
OP (A, B, C, D, 13, 5, (md5_uint32) 0xa9e3e905);
OP (D, A, B, C, 2, 9, (md5_uint32) 0xfcefa3f8);
OP (C, D, A, B, 7, 14, (md5_uint32) 0x676f02d9);
OP (B, C, D, A, 12, 20, (md5_uint32) 0x8d2a4c8a);
#undef FX
#define FX(b, c, d) FH (b, c, d)
/* Round 3. */
OP (A, B, C, D, 5, 4, (md5_uint32) 0xfffa3942);
OP (D, A, B, C, 8, 11, (md5_uint32) 0x8771f681);
OP (C, D, A, B, 11, 16, (md5_uint32) 0x6d9d6122);
OP (B, C, D, A, 14, 23, (md5_uint32) 0xfde5380c);
OP (A, B, C, D, 1, 4, (md5_uint32) 0xa4beea44);
OP (D, A, B, C, 4, 11, (md5_uint32) 0x4bdecfa9);
OP (C, D, A, B, 7, 16, (md5_uint32) 0xf6bb4b60);
OP (B, C, D, A, 10, 23, (md5_uint32) 0xbebfbc70);
OP (A, B, C, D, 13, 4, (md5_uint32) 0x289b7ec6);
OP (D, A, B, C, 0, 11, (md5_uint32) 0xeaa127fa);
OP (C, D, A, B, 3, 16, (md5_uint32) 0xd4ef3085);
OP (B, C, D, A, 6, 23, (md5_uint32) 0x04881d05);
OP (A, B, C, D, 9, 4, (md5_uint32) 0xd9d4d039);
OP (D, A, B, C, 12, 11, (md5_uint32) 0xe6db99e5);
OP (C, D, A, B, 15, 16, (md5_uint32) 0x1fa27cf8);
OP (B, C, D, A, 2, 23, (md5_uint32) 0xc4ac5665);
#undef FX
#define FX(b, c, d) FI (b, c, d)
/* Round 4. */
OP (A, B, C, D, 0, 6, (md5_uint32) 0xf4292244);
OP (D, A, B, C, 7, 10, (md5_uint32) 0x432aff97);
OP (C, D, A, B, 14, 15, (md5_uint32) 0xab9423a7);
OP (B, C, D, A, 5, 21, (md5_uint32) 0xfc93a039);
OP (A, B, C, D, 12, 6, (md5_uint32) 0x655b59c3);
OP (D, A, B, C, 3, 10, (md5_uint32) 0x8f0ccc92);
OP (C, D, A, B, 10, 15, (md5_uint32) 0xffeff47d);
OP (B, C, D, A, 1, 21, (md5_uint32) 0x85845dd1);
OP (A, B, C, D, 8, 6, (md5_uint32) 0x6fa87e4f);
OP (D, A, B, C, 15, 10, (md5_uint32) 0xfe2ce6e0);
OP (C, D, A, B, 6, 15, (md5_uint32) 0xa3014314);
OP (B, C, D, A, 13, 21, (md5_uint32) 0x4e0811a1);
OP (A, B, C, D, 4, 6, (md5_uint32) 0xf7537e82);
OP (D, A, B, C, 11, 10, (md5_uint32) 0xbd3af235);
OP (C, D, A, B, 2, 15, (md5_uint32) 0x2ad7d2bb);
OP (B, C, D, A, 9, 21, (md5_uint32) 0xeb86d391);
/* Add the starting values of the context. */
A += A_save;
B += B_save;
C += C_save;
D += D_save;
}
/* Put checksum in context given as argument. */
ctx->A = A;
ctx->B = B;
ctx->C = C;
ctx->D = D;
}

146
3d-viewer/3d_cache/md5.h Normal file
View File

@ -0,0 +1,146 @@
/* md5.h - Declaration of functions and data types used for MD5 sum
computing library functions.
Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C
Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
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, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _MD5_H
#define _MD5_H 1
#include <stdio.h>
#if defined HAVE_LIMITS_H || _LIBC
# include <limits.h>
#endif
/* The following contortions are an attempt to use the C preprocessor
to determine an unsigned integral type that is 32 bits wide. An
alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
doing that would require that the configure script compile and *run*
the resulting executable. Locally running cross-compiled executables
is usually not possible.
*/
#ifdef _LIBC
# include <sys/types.h>
typedef u_int32_t md5_uint32;
#else
# define INT_MAX_32_BITS 2147483647
/* If UINT_MAX isn't defined, assume it's a 32-bit type.
This should be valid for all systems GNU cares about because
that doesn't include 16-bit systems, and only modern systems
(that certainly have <limits.h>) have 64+-bit integral types.
*/
# ifndef INT_MAX
# define INT_MAX INT_MAX_32_BITS
# endif
# if INT_MAX == INT_MAX_32_BITS
typedef unsigned int md5_uint32;
# else
# if SHRT_MAX == INT_MAX_32_BITS
typedef unsigned short md5_uint32;
# else
# if LONG_MAX == INT_MAX_32_BITS
typedef unsigned long md5_uint32;
# else
/* The following line is intended to evoke an error.
* Using #error is not portable enough. */
"Cannot determine unsigned 32-bit data type."
# endif
# endif
# endif
#endif
#undef __P
#if defined (__STDC__) && __STDC__
#define __P(x) x
#else
#define __P(x) ()
#endif
/* Structure to save state of computation between the single steps. */
struct md5_ctx
{
md5_uint32 A;
md5_uint32 B;
md5_uint32 C;
md5_uint32 D;
md5_uint32 total[2];
md5_uint32 buflen;
char buffer[128];
};
/*
* The following three functions are build up the low level used in
* the functions `md5_stream' and `md5_buffer'.
*/
/* Initialize structure containing state of computation.
(RFC 1321, 3.3: Step 3) */
extern void md5_init_ctx __P ((struct md5_ctx *ctx));
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void md5_process_block __P ((const void *buffer, size_t len,
struct md5_ctx *ctx));
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void md5_process_bytes __P ((const void *buffer, size_t len,
struct md5_ctx *ctx));
/* Process the remaining bytes in the buffer and put result from CTX
in first 16 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
/* Put result from CTX in first 16 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
/* Compute MD5 message digest for bytes read from STREAM. The
resulting message digest number will be written into the 16 bytes
beginning at RESBLOCK. */
extern int md5_stream __P ((FILE *stream, void *resblock));
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
#endif

View File

@ -0,0 +1,55 @@
include_directories(
${CMAKE_SOURCE_DIR}/include
# ${CMAKE_SOURCE_DIR}/include/gal/opengl
${CMAKE_SOURCE_DIR}/3d-viewer
)
add_library( s3d_sg SHARED
sg_base.cpp
sg_node.cpp
sg_helpers.cpp
scenegraph.cpp
sg_appearance.cpp
sg_faceset.cpp
sg_shape.cpp
sg_colors.cpp
sg_coords.cpp
sg_normals.cpp
sg_index.cpp
sg_colorindex.cpp
sg_coordindex.cpp
ifsg_node.cpp
ifsg_transform.cpp
ifsg_appearance.cpp
ifsg_index.cpp
ifsg_colorindex.cpp
ifsg_coordindex.cpp
ifsg_colors.cpp
ifsg_coords.cpp
ifsg_faceset.cpp
ifsg_normals.cpp
ifsg_shape.cpp
ifsg_api.cpp
)
if( MSVC )
# Define a flag to expose the appropriate SG_DLL macro at build time
target_compile_definitions( s3d_sg PRIVATE -DDLL_SGIF )
endif()
target_link_libraries( s3d_sg ${wxWidgets_LIBRARIES} )
if( APPLE )
install( TARGETS
s3d_sg
DESTINATION /Applications/kicad.app/SharedSupport
COMPONENT binary
)
else()
install( TARGETS
s3d_sg
DESTINATION lib/kicad
COMPONENT binary
)
endif()

View File

@ -0,0 +1,149 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 "sg_api.h"
#include "sg_node.h"
S3D::API_SGNODE::API_SGNODE()
{
node = NULL;
nodeType = SGTYPE_END; // signal an invalid type by default
return;
}
SGNODE* S3D::API_SGNODE::GetNode( void )
{
return node;
}
bool S3D::API_SGNODE::AttachNode( SGNODE* aNode )
{
if( NULL == aNode )
{
node = NULL;
return true;
}
if( aNode->GetNodeType() != nodeType )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] object with node type " << aNode->GetNodeType();
std::cerr << " is being attached to API node type " << nodeType << "\n";
return false;
}
node = aNode;
return true;
}
bool S3D::API_SGNODE::GetNodeType( S3D::SGTYPES& aNodeType ) const
{
if( NULL == node )
{
aNodeType = SGTYPE_END;
return false;
}
aNodeType = node->GetNodeType();
return true;
}
bool S3D::API_SGNODE::GetParent( SGNODE const*& aParent ) const
{
if( NULL == node )
{
aParent = NULL;
return false;
}
aParent = node->GetParent();
return true;
}
bool S3D::API_SGNODE::SetParent( SGNODE* aParent )
{
if( NULL == node )
return false;
return node->SetParent( aParent );
}
bool S3D::API_SGNODE::GetName( const char*& aName )
{
if( NULL == node )
{
aName = NULL;
return false;
}
aName = node->GetName();
return true;
}
bool S3D::API_SGNODE::SetName( const char *aName )
{
if( NULL == node )
return false;
node->SetName( aName );
return true;
}
bool S3D::API_SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType, const char*& aName ) const
{
if( NULL == node )
{
aName = NULL;
return false;
}
aName = node->GetNodeTypeName( aNodeType );
return true;
}
bool S3D::API_SGNODE::FindNode( const char *aNodeName, const SGNODE *aCaller, SGNODE*& aNode )
{
if( NULL == node )
{
aNode = NULL;
return false;
}
aNode = node->FindNode( aNodeName, aCaller );
if( NULL == aNode )
return false;
return true;
}

View File

@ -0,0 +1,26 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/sg_api.h>
XXX - TO BE IMPLEMENTED

View File

@ -0,0 +1,38 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_all.h
* collects header files for all SG* wrappers and the API
*/
#include <3d_cache/sg/ifsg_transform.h>
#include <3d_cache/sg/ifsg_appearance.h>
#include <3d_cache/sg/ifsg_colors.h>
#include <3d_cache/sg/ifsg_coords.h>
#include <3d_cache/sg/ifsg_faceset.h>
#include <3d_cache/sg/ifsg_colorindex.h>
#include <3d_cache/sg/ifsg_coordindex.h>
#include <3d_cache/sg/ifsg_normals.h>
#include <3d_cache/sg/ifsg_shape.h>
#include <3d_cache/sg/ifsg_api.h>

View File

@ -0,0 +1,413 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <fstream>
#include <string>
#include <locale.h>
#include <wx/filename.h>
#include <wx/string.h>
#include <3d_cache/sg/ifsg_api.h>
#include <3d_cache/sg/sg_types.h>
#include <3d_cache/sg/sg_node.h>
#include <3d_cache/sg/scenegraph.h>
#include <3d_cache/sg/sg_appearance.h>
#include <3d_cache/sg/sg_colorindex.h>
#include <3d_cache/sg/sg_colors.h>
#include <3d_cache/sg/sg_coordindex.h>
#include <3d_cache/sg/sg_coords.h>
#include <3d_cache/sg/sg_faceset.h>
#include <3d_cache/sg/sg_normals.h>
#include <3d_cache/sg/sg_shape.h>
#include <3d_info.h>
#include <3d_rendering/c3dmodel.h>
static char BadNode[] = " * [BUG] NULL pointer passed for aNode\n";
static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app )
{
float v0, v1, v2;
v0 = app->ambient;
mat.m_Ambient.x = v0;
mat.m_Ambient.y = v0;
mat.m_Ambient.z = v0;
app->diffuse.GetColor( v0, v1, v2 );
mat.m_Diffuse.x = v0;
mat.m_Diffuse.y = v1;
mat.m_Diffuse.z = v2;
app->emissive.GetColor( v0, v1, v2 );
mat.m_Emissive.x = v0;
mat.m_Emissive.y = v1;
mat.m_Emissive.z = v2;
app->specular.GetColor( v0, v1, v2 );
mat.m_Specular.x = v0;
mat.m_Specular.y = v1;
mat.m_Specular.z = v2;
mat.m_Shininess = app->shininess;
mat.m_Transparency = app->transparency;
return;
}
class VRML_LOCALE
{
private:
std::string lname;
public:
VRML_LOCALE()
{
lname = setlocale( LC_NUMERIC, NULL );
setlocale( LC_NUMERIC, "C" ); // switch the numerics locale to "C"
}
~VRML_LOCALE()
{
setlocale( LC_NUMERIC, lname.c_str() ); // revert to the previous locale
}
};
bool S3D::WriteVRML( const wxString& filename, bool overwrite, SGNODE* aTopNode,
bool reuse, bool renameNodes )
{
if( wxFileName::Exists( filename ) )
{
if( !overwrite )
return false;
// make sure we make no attempt to write a directory
if( !wxFileName::FileExists( filename ) )
return false;
}
if( NULL == aTopNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aTopNode\n";
return false;
}
if( S3D::SGTYPE_TRANSFORM != aTopNode->GetNodeType() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] aTopNode is not a SCENEGRAPH object\n";
return false;
}
VRML_LOCALE vrmlLocale;
std::ofstream op;
op.open( filename.ToUTF8(), std::ios_base::out | std::ios_base::trunc
| std::ios_base::binary );
if( !op.is_open() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] failed to open file '" << filename.ToUTF8() << "'\n";
return false;
}
op << "#VRML V2.0 utf8\n";
if( renameNodes )
{
aTopNode->ResetNodeIndex();
aTopNode->ReNameNodes();
}
aTopNode->WriteVRML( op, reuse );
if( !op.fail() )
{
op.close();
return true;
}
op.close();
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] problems encountered writing file '" << filename.ToUTF8() << "'\n";
return false;
}
void S3D::ResetNodeIndex( SGNODE* aNode )
{
if( NULL == aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadNode;
return;
}
aNode->ResetNodeIndex();
return;
}
void S3D::RenameNodes( SGNODE* aNode )
{
if( NULL == aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadNode;
return;
}
aNode->ReNameNodes();
return;
}
void S3D::DestroyNode( SGNODE* aNode )
{
if( NULL == aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadNode;
return;
}
delete aNode;
return;
}
bool S3D::WriteCache( const wxString& aFileName, bool overwrite, SGNODE* aNode )
{
if( NULL == aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadNode;
return false;
}
if( wxFileName::Exists( aFileName ) )
{
if( !overwrite )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] file exists; not overwriting: '";
std::cerr << aFileName.ToUTF8() << "'\n";
return false;
}
// make sure we make no attempt to write a directory
if( !wxFileName::FileExists( aFileName ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] specified path is a directory: '";
std::cerr << aFileName.ToUTF8() << "'\n";
return false;
}
}
std::ofstream output;
output.open( aFileName.ToUTF8(), std::ios_base::out | std::ios_base::trunc
| std::ios_base::binary );
if( !output.is_open() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] failed to open file '" << aFileName.ToUTF8() << "'\n";
return false;
}
bool rval = aNode->WriteCache( output, NULL );
output.close();
if( !rval )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] problems encountered writing cache file '";
std::cerr << aFileName.ToUTF8() << "'\n";
}
return rval;
}
SGNODE* S3D::ReadCache( const wxString& aFileName )
{
if( !wxFileName::FileExists( aFileName ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] no such file: '";
std::cerr << aFileName.ToUTF8() << "'\n";
}
SGNODE* np = new SCENEGRAPH( NULL );
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] failed to instantiate SCENEGRAPH\n";
return NULL;
}
std::ifstream file;
file.open( aFileName.ToUTF8(), std::ios_base::in | std::ios_base::binary );
if( !file.is_open() )
{
delete np;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] failed to open file '";
std::cerr << aFileName.ToUTF8() << "'\n";
return NULL;
}
bool rval = np->ReadCache( file, NULL );
file.close();
if( !rval )
{
delete np;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] problems encountered reading cache file '";
std::cerr << aFileName.ToUTF8() << "'\n";
return NULL;
}
return np;
}
S3DMODEL* S3D::Prepare( SCENEGRAPH* aNode, const glm::dmat4* aTransform )
{
S3D::MATLIST materials;
std::vector< SMESH > meshes;
// the materials list shall have a default color; although the VRML
// default is an opaque black, the default used here shall be a median
// gray in hopes that it may help highlight faulty models; this color is
// also typical of MCAD applications. When a model has no associated
// material color it shall be assigned the index 0.
SGAPPEARANCE app( NULL );
app.ambient = 0.9;
app.diffuse = SGCOLOR( 0.6, 0.6, 0.6 );
app.specular = app.diffuse;
app.shininess = 0.05;
app.transparency = 0.0;
materials.matorder.push_back( &app );
materials.matmap.insert( std::pair< SGAPPEARANCE const*, int >( &app, 0 ) );
if( aNode->Prepare( aTransform, materials, meshes ) )
{
if( meshes.empty() )
return NULL;
S3DMODEL* model = S3D::New3DModel();
// add all the materials
size_t j = materials.matorder.size();
SMATERIAL* lmat = new SMATERIAL[j];
for( int i = 0; i < j; ++i )
formatMaterial( lmat[i], materials.matorder[i] );
model->m_Materials = lmat;
model->m_MaterialsSize = j;
// add all the meshes
j = meshes.size();
SMESH* lmesh = new SMESH[j];
for( int i = 0; i < j; ++i )
lmesh[i] = meshes[i];
model->m_Meshes = lmesh;
model->m_MeshesSize = j;
return model;
}
size_t j = meshes.size();
for( size_t i = 0; i < j; ++i )
S3D::Free3DMesh( meshes[i] );
return NULL;
}
void S3D::Destroy3DModel( S3DMODEL** aModel )
{
if( NULL == aModel || NULL == *aModel )
return;
S3DMODEL* m = *aModel;
S3D::FREE_S3DMODEL( *m );
delete m;
*aModel = NULL;
return;
}
void Free3DModel( S3DMODEL& aModel )
{
S3D::FREE_S3DMODEL( aModel );
return;
}
void S3D::Free3DMesh( SMESH& aMesh )
{
S3D::FREE_SMESH( aMesh );
return;
}
S3DMODEL* S3D::New3DModel( void )
{
S3DMODEL* mp = new S3DMODEL;
S3D::INIT_S3DMODEL( *mp );
return mp;
}
void S3D::Init3DMaterial( SMATERIAL& aMat )
{
S3D::INIT_SMATERIAL( aMat );
return;
}
void S3D::Init3DMesh( SMESH& aMesh )
{
S3D::INIT_SMESH( aMesh );
return;
}

View File

@ -0,0 +1,182 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_api.h
* defines the API calls for the manipulation of SG* classes
*/
#ifndef IFSG_API_H
#define IFSG_API_H
#include <wx/string.h>
#include <glm/glm.hpp>
#include <3d_cache/sg/sg_types.h>
#include <3d_cache/sg/sg_base.h>
#include <3d_rendering/c3dmodel.h>
class SGNODE;
class SCENEGRAPH;
struct S3D_INFO;
struct S3D_POINT;
namespace S3D
{
/**
* Function WriteCache
* writes the SGNODE tree to a binary cache file
*
* @param aFileName is the name of the file to write
* @param overwrite must be set to true to overwrite an existing file
* @param aNode is any node within the node tree which is to be written
* @return true on success
*/
bool WriteCache( const wxString& aFileName, bool overwrite, SGNODE* aNode );
/**
* Function ReadCache
* reads a binary cache file and creates an SGNODE tree
*
* @param aFileName is the name of the binary cache file to be read
* @return NULL on failure, on success a pointer to the top level SCENEGRAPH node;
* if desired this node can be associated with an IFSG_TRANSFORM wrapper via
* the IFSG_TRANSFORM::Attach() function.
*/
SGNODE* ReadCache( const wxString& aFileName );
/**
* Function WriteVRML
* writes out the given node and its subnodes to a VRML2 file
*
* @param filename is the name of the output file
* @param overwrite should be set to true to overwrite an existing VRML file
* @param aTopNode is a pointer to a SCENEGRAPH object representing the VRML scene
* @param reuse should be set to true to make use of VRML DEF/USE features
* @return true on success
*/
bool WriteVRML( const wxString& filename, bool overwrite, SGNODE* aTopNode,
bool reuse, bool renameNodes );
// NOTE: The following functions are used in combination to create a VRML
// assembly which may use various instances of each SG* representation of a module.
// A typical use case would be:
// 1. invoke 'ResetNodeIndex()' to reset the global node name indices
// 2. for each model pointer provided by 'S3DCACHE->Load()', invoke 'RenameNodes()' once;
// this ensures that all nodes have a unique name to present to the final output file.
// Internally, RenameNodes() will only rename the given node and all Child subnodes;
// nodes which are only referenced will not be renamed. Using the pointer supplied
// by 'S3DCACHE->Load()' ensures that all nodes but the returned node (top node) are
// children of at least one node, so all nodes are given unique names.
// 3. if SG* trees are created independently of S3DCACHE->Load() the user must invoke
// RenameNodes() as appropriate to ensure that all nodes have a unique name
// 4. create an assembly structure by creating new IFSG_TRANSFORM nodes as appropriate
// for each instance of a component; the component base model as returned by
// S3DCACHE->Load() may be added to these IFSG_TRANSFORM nodes via 'AddRefNode()';
// set the offset, rotation, etc of the IFSG_TRANSFORM node to ensure correct
// 5. Ensure that all new IFSG_TRANSFORM nodes are placed as child nodes within a
// top level IFSG_TRANSFORM node in preparation for final node naming and output
// 6. Invoke RenameNodes() on the top level assembly node
// 7. Invoke WriteVRML() as normal, with renameNodes = false, to write the entire assembly
// structure to a single VRML file
// 8. Clean up by deleting any extra IFSG_TRANSFORM wrappers and their underlying SG*
// classes which have been created solely for the assembly output
/**
* Function ResetNodeIndex
* resets the global SG* class indices
*
* @param aNode may be any valid SGNODE
*/
void ResetNodeIndex( SGNODE* aNode );
/**
* Function RenameNodes
* renames a node and all children nodes based on the current
* values of the global SG* class indices
*
* @param aNode is a top level node
*/
void RenameNodes( SGNODE* aNode );
/**
* Function DestroyNode
* deletes the given SG* class node. This function makes it possible
* to safely delete an SG* node without associating the node with
* its corresponding IFSG* wrapper.
*/
void DestroyNode( SGNODE* aNode );
// NOTE: The following functions facilitate the creation and destruction
// of data structures for rendering
/**
* Function Prepare
* creates an S3DMODEL representation of aNode transformed by aTransform.
*
* @param aNode is the node to be transcribed into an S3DMODEL representation
* @param aTransform is the transform (Translation * Rotation * Scale) to apply
* to the representation of aNode; it must be a pointer to a glm::dmat4 entity
*
* @return an S3DMODEL representation of aNode on success, otherwise NULL
*/
S3DMODEL* Prepare( SCENEGRAPH* aNode, const glm::dmat4* aTransform );
/**
* Function Destroy3DModel
* frees memory used by an S3DMODEL structure and sets the pointer to
* the structure to NULL
*/
void Destroy3DModel( S3DMODEL** aModel );
/**
* Function Free3DModel
* frees memory used internally by an S3DMODEL structure
*/
void Free3DModel( S3DMODEL& aModel );
/**
* Function Free3DMesh
* frees memory used internally by an SMESH structure
*/
void Free3DMesh( SMESH& aMesh );
/**
* Function New3DModel
* creates and initializes an S3DMODEL struct
*/
S3DMODEL* New3DModel( void );
/**
* Function Init3DMaterial
* initializes an SMATERIAL struct
*/
void Init3DMaterial( SMATERIAL& aMat );
/**
* Function Init3DMesh
* creates and initializes an SMESH struct
*/
void Init3DMesh( SMESH& aMesh );
};
#endif // IFSG_API_H

View File

@ -0,0 +1,344 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_appearance.h>
#include <3d_cache/sg/sg_appearance.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_APPEARANCE::IFSG_APPEARANCE( bool create )
{
m_node = NULL;
if( !create )
return ;
m_node = new SGAPPEARANCE( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_APPEARANCE::IFSG_APPEARANCE( SGNODE* aParent )
{
m_node = new SGAPPEARANCE( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
IFSG_APPEARANCE::IFSG_APPEARANCE( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( ! pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
}
m_node = new SGAPPEARANCE( NULL );
if( m_node )
{
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_APPEARANCE::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_APPEARANCE != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_APPEARANCE::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGAPPEARANCE( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGAPPEARANCE\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_APPEARANCE::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}
bool IFSG_APPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetEmissive( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetEmissive( aRGBColor );
}
bool IFSG_APPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetEmissive( aRGBColor );
}
bool IFSG_APPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetDiffuse( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetDiffuse( aRGBColor );
}
bool IFSG_APPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetDiffuse( aRGBColor );
}
bool IFSG_APPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetSpecular( aRVal, aGVal, aBVal );
}
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetSpecular( aRGBColor );
}
bool IFSG_APPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGAPPEARANCE*)m_node)->SetSpecular( aRGBColor );
}
bool IFSG_APPEARANCE::SetAmbient( float aAmbientLight )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
if( aAmbientLight < 0 || aAmbientLight > 1.0 )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] ambient intensity out of range [0..1]\n";
return false;
}
((SGAPPEARANCE*)m_node)->ambient = aAmbientLight;
return true;
}
bool IFSG_APPEARANCE::SetShininess( float aShininess )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
if( aShininess < 0 || aShininess > 1.0 )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] shininess out of range [0..1]\n";
return false;
}
((SGAPPEARANCE*)m_node)->shininess = aShininess;
return true;
}
bool IFSG_APPEARANCE::SetTransparency( float aTransparency )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
if( aTransparency < 0 || aTransparency > 1.0 )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] shininess out of range [0..1]\n";
return false;
}
((SGAPPEARANCE*)m_node)->transparency = aTransparency;
return true;
}

View File

@ -0,0 +1,63 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_appearance.h
* defines the wrapper of the SGAPPEARANCE class
*/
#ifndef IFSG_APPEARANCE_H
#define IFSG_APPEARANCE_H
#include <3d_cache/sg/ifsg_node.h>
class IFSG_APPEARANCE : public IFSG_NODE
{
public:
IFSG_APPEARANCE( bool create );
IFSG_APPEARANCE( SGNODE* aParent );
IFSG_APPEARANCE( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
bool SetEmissive( float aRVal, float aGVal, float aBVal );
bool SetEmissive( const SGCOLOR* aRGBColor );
bool SetEmissive( const SGCOLOR& aRGBColor );
bool SetDiffuse( float aRVal, float aGVal, float aBVal );
bool SetDiffuse( const SGCOLOR* aRGBColor );
bool SetDiffuse( const SGCOLOR& aRGBColor );
bool SetSpecular( float aRVal, float aGVal, float aBVal );
bool SetSpecular( const SGCOLOR* aRGBColor );
bool SetSpecular( const SGCOLOR& aRGBColor );
bool SetAmbient( float aAmbientLight );
bool SetShininess( float aShininess );
bool SetTransparency( float aTransparency );
};
#endif // IFSG_APPEARANCE_H

View File

@ -0,0 +1,158 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_colorindex.h>
#include <3d_cache/sg/sg_colorindex.h>
#include <3d_cache/sg/sg_types.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COLORINDEX::IFSG_COLORINDEX( bool create )
{
m_node = NULL;
if( !create )
return;
m_node = new SGCOLORINDEX( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COLORINDEX::IFSG_COLORINDEX( SGNODE* aParent )
{
m_node = new SGCOLORINDEX( NULL );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COLORINDEX::IFSG_COLORINDEX( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( !pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return;
}
m_node = new SGCOLORINDEX( NULL );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
bool IFSG_COLORINDEX::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_COLORINDEX != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COLORINDEX::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOLORINDEX( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGCOLORINDEX\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COLORINDEX::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_colorindex.h
* defines the ColorIndex node wrapper
*/
#ifndef IFSG_COLORINDEX_H
#define IFSG_COLORINDEX_H
#include <3d_cache/sg/ifsg_index.h>
/**
* Class IFSG_COLORINDEX
* is the wrapper for SGCOLORINDEX
*/
class SG_DLL IFSG_COLORINDEX : public IFSG_INDEX
{
public:
IFSG_COLORINDEX( bool create );
IFSG_COLORINDEX( SGNODE* aParent );
IFSG_COLORINDEX( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
};
#endif // IFSG_COLORINDEX_H

View File

@ -0,0 +1,218 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_colors.h>
#include <3d_cache/sg/sg_colors.h>
extern char BadObject[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COLORS::IFSG_COLORS( bool create )
{
m_node = NULL;
if( !create )
return ;
m_node = new SGCOLORS( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COLORS::IFSG_COLORS( SGNODE* aParent )
{
m_node = new SGCOLORS( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
IFSG_COLORS::IFSG_COLORS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( ! pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
}
m_node = new SGCOLORS( NULL );
if( m_node )
{
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_COLORS::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_COLORS != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COLORS::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOLORS( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGCOLORS\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COLORS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}
bool IFSG_COLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGCOLORS*)m_node)->GetColorList( aListSize, aColorList );
}
bool IFSG_COLORS::SetColorList( size_t& aListSize, const SGCOLOR* aColorList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGCOLORS*)m_node)->SetColorList( aListSize, aColorList );
return true;
}
bool IFSG_COLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGCOLORS*)m_node)->AddColor( aRedValue, aGreenValue, aBlueValue );
return true;
}
bool IFSG_COLORS::AddColor( const SGCOLOR& aColor )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGCOLORS*)m_node)->AddColor( aColor );
return true;
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_colors.h
* defines the color list wrapper
*/
#ifndef IFSG_COLORS_H
#define IFSG_COLORS_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_INDEX
* is the wrapper for SGCOLORS
*/
class SG_DLL IFSG_COLORS : public IFSG_NODE
{
public:
IFSG_COLORS( bool create );
IFSG_COLORS( SGNODE* aParent );
IFSG_COLORS( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
bool GetColorList( size_t& aListSize, SGCOLOR*& aColorList );
bool SetColorList( size_t& aListSize, const SGCOLOR* aColorList );
bool AddColor( double aRedValue, double aGreenValue, double aBlueValue );
bool AddColor( const SGCOLOR& aColor );
};
#endif // IFSG_COLORS_H

View File

@ -0,0 +1,158 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_coordindex.h>
#include <3d_cache/sg/sg_coordindex.h>
#include <3d_cache/sg/sg_types.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COORDINDEX::IFSG_COORDINDEX( bool create )
{
m_node = NULL;
if( !create )
return;
m_node = new SGCOORDINDEX( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COORDINDEX::IFSG_COORDINDEX( SGNODE* aParent )
{
m_node = new SGCOORDINDEX( NULL );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COORDINDEX::IFSG_COORDINDEX( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( !pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return;
}
m_node = new SGCOORDINDEX( NULL );
if( !m_node->SetParent( pp ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
delete m_node;
m_node = NULL;
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
bool IFSG_COORDINDEX::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_COORDINDEX != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDINDEX::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOORDINDEX( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGCOORDINDEX\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDINDEX::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_coordindex.h
* defines the CoordIndex node wrapper
*/
#ifndef IFSG_COORDINDEX_H
#define IFSG_COORDINDEX_H
#include <3d_cache/sg/ifsg_index.h>
/**
* Class IFSG_COORDINDEX
* is the wrapper for SGCOORDINDEX
*/
class SG_DLL IFSG_COORDINDEX : public IFSG_INDEX
{
public:
IFSG_COORDINDEX( bool create );
IFSG_COORDINDEX( SGNODE* aParent );
IFSG_COORDINDEX( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
};
#endif // IFSG_COORDINDEX_H

View File

@ -0,0 +1,218 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_coords.h>
#include <3d_cache/sg/sg_coords.h>
extern char BadObject[];
extern char BadParent[];
extern char WrongParent[];
IFSG_COORDS::IFSG_COORDS( bool create )
{
m_node = NULL;
if( !create )
return ;
m_node = new SGCOORDS( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_COORDS::IFSG_COORDS( SGNODE* aParent )
{
m_node = new SGCOORDS( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
IFSG_COORDS::IFSG_COORDS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( ! pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
}
m_node = new SGCOORDS( NULL );
if( m_node )
{
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_COORDS::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_COORDS != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDS::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGCOORDS( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGCOORDS\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_COORDS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}
bool IFSG_COORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGCOORDS*)m_node)->GetCoordsList( aListSize, aCoordsList );
}
bool IFSG_COORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGCOORDS*)m_node)->SetCoordsList( aListSize, aCoordsList );
return true;
}
bool IFSG_COORDS::AddCoord( double aXValue, double aYValue, double aZValue )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGCOORDS*)m_node)->AddCoord( aXValue, aYValue, aZValue );
return true;
}
bool IFSG_COORDS::AddCoord( const SGPOINT& aPoint )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGCOORDS*)m_node)->AddCoord( aPoint );
return true;
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_coords.h
* defines the coordinate list wrapper
*/
#ifndef IFSG_COORDS_H
#define IFSG_COORDS_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_INDEX
* is the wrapper for SGCOORDS
*/
class SG_DLL IFSG_COORDS : public IFSG_NODE
{
public:
IFSG_COORDS( bool create );
IFSG_COORDS( SGNODE* aParent );
IFSG_COORDS( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
bool GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList );
bool SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList );
bool AddCoord( double aXValue, double aYValue, double aZValue );
bool AddCoord( const SGPOINT& aPoint );
};
#endif // IFSG_COORDS_H

View File

@ -0,0 +1,39 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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
*/
#ifndef IFSG_DEFS_H
#define IFSG_DEFS_H
#if defined( MSVC )
#if defined( DLL_SGIF )
// we are building the library
#define SG_DLL __declspec( dllexport )
#else
// we must be using the library
#define SG_DLL __declspec( dllimport )
#endif
#else
#define SG_DLL
#endif
#endif // IFSG_DEFS_H

View File

@ -0,0 +1,161 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_faceset.h>
#include <3d_cache/sg/sg_faceset.h>
extern char BadObject[];
extern char BadParent[];
extern char WrongParent[];
IFSG_FACESET::IFSG_FACESET( bool create )
{
m_node = NULL;
if( !create )
return ;
m_node = new SGFACESET( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_FACESET::IFSG_FACESET( SGNODE* aParent )
{
m_node = new SGFACESET( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
IFSG_FACESET::IFSG_FACESET( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( ! pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
}
m_node = new SGFACESET( NULL );
if( m_node )
{
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_FACESET::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_FACESET != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_FACESET::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGFACESET( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGFACESET\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_faceset.h
* defines the wrapper for the SGFACESET class
*/
#ifndef IFSG_FACESET_H
#define IFSG_FACESET_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_FACESET
* is the wrapper for the SGFACESET class
*/
class SG_DLL IFSG_FACESET : public IFSG_NODE
{
public:
IFSG_FACESET( bool create );
IFSG_FACESET( SGNODE* aParent );
IFSG_FACESET( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
};
#endif // IFSG_FACESET_H

View File

@ -0,0 +1,83 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_index.h>
#include <3d_cache/sg/sg_coordindex.h>
#include <3d_cache/sg/sg_colorindex.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_INDEX::IFSG_INDEX() : IFSG_NODE()
{
return;
}
bool IFSG_INDEX::GetIndices( size_t& nIndices, int*& aIndexList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGINDEX*)m_node)->GetIndices( nIndices, aIndexList );
}
bool IFSG_INDEX::SetIndices( size_t nIndices, int* aIndexList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGINDEX*)m_node)->SetIndices( nIndices, aIndexList );
return true;
}
bool IFSG_INDEX::AddIndex( int aIndex )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGINDEX*)m_node)->AddIndex( aIndex );
return true;
}

View File

@ -0,0 +1,71 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_index.h
* defines the index nodes wrapper
*/
#ifndef IFSG_INDEX_H
#define IFSG_INDEX_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_INDEX
* is the wrapper for SGINDEX
*/
class SG_DLL IFSG_INDEX : public IFSG_NODE
{
public:
IFSG_INDEX();
virtual bool Attach( SGNODE* aNode ) = 0;
virtual bool NewNode( SGNODE* aParent ) = 0;
virtual bool NewNode( IFSG_NODE& aParent ) = 0;
bool GetIndices( size_t& nIndices, int*& aIndexList );
/**
* Function SetIndices
* sets the number of indices and creates a copy of the given index data.
*
* @param nIndices [in] the number of indices to be stored
* @param aIndexList [in] the index data
*/
bool SetIndices( size_t nIndices, int* aIndexList );
/**
* Function AddIndex
* adds a single index to the list
*
* @param nIndices [in] the number of indices to be stored
* @param aIndexList [in] the index data
*/
bool AddIndex( int aIndex );
};
#endif // IFSG_INDEX_H

View File

@ -0,0 +1,216 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_node.h>
#include <3d_cache/sg/sg_node.h>
#include <3d_cache/sg/ifsg_api.h>
// collection of common error strings used by the wrappers
char BadObject[] = " * [BUG] operating on an invalid wrapper (object may have been deleted)";
char BadOperand[] = " * [BUG] parameter aNode is an invalid wrapper; its data may have been deleted";
char BadParent[] = " * [BUG] invalid parent node (data may have been deleted)";
char WrongParent[] = " * [BUG] parent node type is incompatible";
IFSG_NODE::IFSG_NODE()
{
m_node = NULL;
}
IFSG_NODE::~IFSG_NODE()
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
return;
}
SGNODE* IFSG_NODE::GetRawPtr( void )
{
return m_node;
}
S3D::SGTYPES IFSG_NODE::GetNodeType( void ) const
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return S3D::SGTYPE_END;
}
return m_node->GetNodeType();
}
SGNODE* IFSG_NODE::GetParent( void ) const
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return NULL;
}
return m_node->GetParent();
}
bool IFSG_NODE::SetParent( SGNODE* aParent )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return m_node->SetParent( aParent );
}
const char* IFSG_NODE::GetName( void )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return NULL;
}
return m_node->GetName();
}
bool IFSG_NODE::SetName( const char *aName )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
m_node->SetName( aName );
return true;
}
const char * IFSG_NODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return NULL;
}
return m_node->GetNodeTypeName( aNodeType );
}
SGNODE* IFSG_NODE::FindNode( const char *aNodeName )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return NULL;
}
return m_node->FindNode( aNodeName, NULL );
}
bool IFSG_NODE::AddRefNode( SGNODE* aNode )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return m_node->AddRefNode( aNode );
}
bool IFSG_NODE::AddRefNode( IFSG_NODE& aNode )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
SGNODE* np = aNode.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadOperand << "\n";
return false;
}
return m_node->AddRefNode( np );
}
bool IFSG_NODE::AddChildNode( SGNODE* aNode )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return m_node->AddChildNode( aNode );
}
bool IFSG_NODE::AddChildNode( IFSG_NODE& aNode )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
SGNODE* np = aNode.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadOperand << "\n";
return false;
}
return m_node->AddChildNode( np );
}

View File

@ -0,0 +1,174 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_node.h
* defines the wrapper of the base class SG_NODE
*/
/*
* NOTES:
* 1. The IFSG wrapper classes shall be aimed at creating a VRML-like
* intermediate scenegraph representation. Although objects are
* readily created and added to the structure, no provision shall
* be made to inspect the structures in detail. For example the
* SCENEGRAPH class may contain various SGSHAPE and SCENEGRAPH
* nodes but there shall be no provision to extract those nodes.
* This was done because in principle all the detailed data shall
* only be handled within the SG* classes and only data processed
* via GetRenderData() shall be available via the wrappers.
*/
#ifndef IFSG_NODE_H
#define IFSG_NODE_H
#include <3d_cache/sg/sg_base.h>
#include <3d_cache/sg/sg_types.h>
#include <3d_cache/sg/ifsg_defs.h>
class SGNODE;
/**
* Class IFSG_NODE
* represents the base class of all DLL-safe Scene Graph nodes
*/
class SG_DLL IFSG_NODE
{
private:
// hide the copy constructors and assignment operator to avoid accidental misuse
IFSG_NODE( const IFSG_NODE& aParent );
IFSG_NODE( IFSG_NODE& aParent );
IFSG_NODE( volatile const IFSG_NODE& aParent );
IFSG_NODE( volatile IFSG_NODE& aParent );
IFSG_NODE& operator= ( const IFSG_NODE& );
protected:
SGNODE* m_node;
public:
IFSG_NODE();
virtual ~IFSG_NODE();
/**
* Function Destroy
* deletes the object held by this wrapper
*/
void Destroy( void );
/**
* Function Attach
* associates a given SGNODE* with this wrapper
*/
virtual bool Attach( SGNODE* aNode ) = 0;
/**
* Function NewNode
* creates a new node to associate with this wrapper
*/
virtual bool NewNode( SGNODE* aParent ) = 0;
virtual bool NewNode( IFSG_NODE& aParent ) = 0;
/**
* Function GetRawPtr()
* returns the raw internal SGNODE pointer
*/
SGNODE* GetRawPtr( void );
/**
* Function GetNodeType
* returns the type of this node instance
*/
S3D::SGTYPES 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).
*/
SGNODE* GetParent( void ) const;
/**
* Function SetParent
* sets the parent SGNODE of this object.
*
* @param aParent [in] is the desired parent node
* @return true if the operation succeeds; false if
* the given node is not allowed to be a parent to
* the derived object
*/
bool SetParent( SGNODE* aParent );
/**
* Function GetName
* returns a pointer to the node name (NULL if no name assigned)
*/
const char* GetName( void );
/**
* Function SetName
* sets the node's name; if the pointer passed is NULL
* then the node's name is erased
*
* @return true on success
*/
bool SetName( const char *aName );
/**
* Function GetNodeTypeName
* returns the text representation of the node type
* or NULL if the node somehow has an invalid type
*/
const char * GetNodeTypeName( S3D::SGTYPES aNodeType ) const;
/**
* Function FindNode searches the tree of linked nodes and returns a
* reference to the first node found 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
* @param aCaller is a pointer to the node invoking this function
* @return is a valid node pointer on success, otherwise NULL
*/
SGNODE* FindNode( const char *aNodeName );
/**
* Function AddRefNode
* adds a reference to an existing node which is not owned by
* (not a child of) this node.
*
* @return true on success
*/
bool AddRefNode( SGNODE* aNode );
bool AddRefNode( IFSG_NODE& aNode );
/**
* Function AddChildNode
* adds a node as a child owned by this node.
*
* @return true on success
*/
bool AddChildNode( SGNODE* aNode );
bool AddChildNode( IFSG_NODE& aNode );
};
#endif // IFSG_NODE_H

View File

@ -0,0 +1,158 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_normalindex.h>
#include <3d_cache/sg/sg_normalindex.h>
#include <3d_cache/sg/sg_types.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_NORMALINDEX::IFSG_NORMALINDEX( bool create )
{
m_node = NULL;
if( !create )
return;
m_node = new SGNORMALINDEX( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_NORMALINDEX::IFSG_NORMALINDEX( SGNODE* aParent )
{
m_node = new SGNORMALINDEX( NULL );
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_NORMALINDEX::IFSG_NORMALINDEX( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( !pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return;
}
m_node = new SGNORMALINDEX( NULL );
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
return;
}
bool IFSG_NORMALINDEX::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_NORMALINDEX != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_NORMALINDEX::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGNORMALINDEX( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGNORMALINDEX\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_NORMALINDEX::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_coordindex.h
* defines the CoordIndex node wrapper
*/
#ifndef IFSG_NORMALINDEX_H
#define IFSG_NORMALINDEX_H
#include <3d_cache/sg/ifsg_index.h>
/**
* Class IFSG_NORMALINDEX
* is the wrapper for SGNORMALINDEX
*/
class SG_DLL IFSG_NORMALINDEX : public IFSG_INDEX
{
public:
IFSG_NORMALINDEX( bool create );
IFSG_NORMALINDEX( SGNODE* aParent );
IFSG_NORMALINDEX( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
};
#endif // IFSG_NORMALINDEX_H

View File

@ -0,0 +1,217 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_normals.h>
#include <3d_cache/sg/sg_normals.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_NORMALS::IFSG_NORMALS( bool create )
{
m_node = NULL;
if( !create )
return;
m_node = new SGNORMALS( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_NORMALS::IFSG_NORMALS( SGNODE* aParent )
{
m_node = new SGNORMALS( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
IFSG_NORMALS::IFSG_NORMALS( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( ! pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
}
m_node = new SGNORMALS( NULL );
if( m_node )
{
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_NORMALS::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_NORMALS != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_NORMALS::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGNORMALS( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGNORMALS\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_NORMALS::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}
bool IFSG_NORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
return ((SGNORMALS*)m_node)->GetNormalList( aListSize, aNormalList );
}
bool IFSG_NORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGNORMALS*)m_node)->SetNormalList( aListSize, aNormalList );
return true;
}
bool IFSG_NORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGNORMALS*)m_node)->AddNormal( aXValue, aYValue, aZValue );
return true;
}
bool IFSG_NORMALS::AddNormal( const SGVECTOR& aNormal )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SGNORMALS*)m_node)->AddNormal( aNormal );
return true;
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_transform.h
* defines the wrapper for the SGNORMALS class
*/
#ifndef IFSG_NORMALS_H
#define IFSG_NORMALS_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_NORMALS
* is the wrapper for the SGNORMALS class
*/
class SG_DLL IFSG_NORMALS : public IFSG_NODE
{
public:
IFSG_NORMALS( bool create );
IFSG_NORMALS( SGNODE* aParent );
IFSG_NORMALS( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
bool GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList );
bool SetNormalList( size_t aListSize, const SGVECTOR* aNormalList );
bool AddNormal( double aXValue, double aYValue, double aZValue );
bool AddNormal( const SGVECTOR& aNormal );
};
#endif // IFSG_NORMALS_H

View File

@ -0,0 +1,162 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_shape.h>
#include <3d_cache/sg/sg_shape.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_SHAPE::IFSG_SHAPE( bool create )
{
m_node = NULL;
if( !create )
return ;
m_node = new SGSHAPE( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_SHAPE::IFSG_SHAPE( SGNODE* aParent )
{
m_node = new SGSHAPE( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
IFSG_SHAPE::IFSG_SHAPE( IFSG_NODE& aParent )
{
SGNODE* pp = aParent.GetRawPtr();
if( ! pp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
}
m_node = new SGSHAPE( NULL );
if( m_node )
{
if( !m_node->SetParent( pp ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_SHAPE::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_SHAPE != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_SHAPE::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SGSHAPE( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SGSHAPE\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_SHAPE::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}

View File

@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_shape.h
* defines the wrapper for the SGSHAPE class
*/
#ifndef IFSG_SHAPE_H
#define IFSG_SHAPE_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_SHAPE
* is the wrapper for the SGSHAPE class
*/
class SG_DLL IFSG_SHAPE : public IFSG_NODE
{
public:
IFSG_SHAPE( bool create );
IFSG_SHAPE( SGNODE* aParent );
IFSG_SHAPE( IFSG_NODE& aParent );
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
};
#endif // IFSG_SHAPE_H

View File

@ -0,0 +1,230 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/ifsg_transform.h>
#include <3d_cache/sg/scenegraph.h>
extern char BadObject[];
extern char BadOperand[];
extern char BadParent[];
extern char WrongParent[];
IFSG_TRANSFORM::IFSG_TRANSFORM( bool create )
{
m_node = NULL;
if( !create )
return ;
m_node = new SCENEGRAPH( NULL );
if( m_node )
m_node->AssociateWrapper( &m_node );
return;
}
IFSG_TRANSFORM::IFSG_TRANSFORM( SGNODE* aParent )
{
m_node = new SCENEGRAPH( NULL );
if( m_node )
{
if( !m_node->SetParent( aParent ) )
{
delete m_node;
m_node = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << WrongParent << "\n";
return;
}
m_node->AssociateWrapper( &m_node );
}
return;
}
bool IFSG_TRANSFORM::Attach( SGNODE* aNode )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = NULL;
if( !aNode )
return false;
if( S3D::SGTYPE_TRANSFORM != aNode->GetNodeType() )
{
return false;
}
m_node = aNode;
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_TRANSFORM::NewNode( SGNODE* aParent )
{
if( m_node )
m_node->DisassociateWrapper( &m_node );
m_node = new SCENEGRAPH( aParent );
if( aParent != m_node->GetParent() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid SGNODE parent (";
std::cerr << aParent->GetNodeTypeName( aParent->GetNodeType() );
std::cerr << ") to SCENEGRAPH\n";
delete m_node;
m_node = NULL;
return false;
}
m_node->AssociateWrapper( &m_node );
return true;
}
bool IFSG_TRANSFORM::NewNode( IFSG_NODE& aParent )
{
SGNODE* np = aParent.GetRawPtr();
if( NULL == np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadParent << "\n";
return false;
}
return NewNode( np );
}
bool IFSG_TRANSFORM::SetRotation( const SGVECTOR& aRotationAxis, double aAngle )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SCENEGRAPH*)m_node)->rotation_axis = aRotationAxis;
((SCENEGRAPH*)m_node)->rotation_angle = aAngle;
return true;
}
bool IFSG_TRANSFORM::SetScale( const SGPOINT& aScale )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SCENEGRAPH*)m_node)->scale = aScale;
return true;
}
bool IFSG_TRANSFORM::SetScale( double aScale )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
if( aScale < 1e-8 && aScale > -1e-8 )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] |scale| is < 1e-8 - this seems strange\n";
return false;
}
((SCENEGRAPH*)m_node)->scale = SGPOINT( aScale, aScale, aScale );
return true;
}
bool IFSG_TRANSFORM::SetTranslation( const SGPOINT& aTranslation )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SCENEGRAPH*)m_node)->translation = aTranslation;
return true;
}
bool IFSG_TRANSFORM::SetScaleOrientation( const SGVECTOR& aScaleAxis, double aAngle )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SCENEGRAPH*)m_node)->scale_axis = aScaleAxis;
((SCENEGRAPH*)m_node)->scale_angle = aAngle;
return true;
}
bool IFSG_TRANSFORM::SetCenter( const SGPOINT& aCenter )
{
if( NULL == m_node )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << BadObject << "\n";
return false;
}
((SCENEGRAPH*)m_node)->center = aCenter;
return true;
}

View File

@ -0,0 +1,61 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 ifsg_transform.h
* defines the wrapper for the SCENEGRAPH class
*/
#ifndef IFSG_TRANSFORM_H
#define IFSG_TRANSFORM_H
#include <3d_cache/sg/ifsg_node.h>
/**
* Class IFSG_TRANSFORM
* is the wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH
*/
class SG_DLL IFSG_TRANSFORM : public IFSG_NODE
{
public:
IFSG_TRANSFORM( bool create );
IFSG_TRANSFORM( SGNODE* aParent );
// note: IFSG_TRANSFORM( IFSG_NODE& aParent ) does not exist
// since a transform may own another transform and that construct
// invites accidental misuse of the copy constructor
bool Attach( SGNODE* aNode );
bool NewNode( SGNODE* aParent );
bool NewNode( IFSG_NODE& aParent );
bool SetScaleOrientation( const SGVECTOR& aScaleAxis, double aAngle );
bool SetRotation( const SGVECTOR& aRotationAxis, double aAngle );
bool SetScale( const SGPOINT& aScale );
bool SetScale( double aScale );
bool SetCenter( const SGPOINT& aCenter );
bool SetTranslation( const SGPOINT& aTranslation );
};
#endif // IFSG_TRANSFORM_H

View File

@ -0,0 +1,636 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <3d_cache/sg/scenegraph.h>
#include <3d_cache/sg/sg_shape.h>
#include <3d_cache/sg/sg_helpers.h>
SCENEGRAPH::SCENEGRAPH( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_TRANSFORM;
rotation_angle = 0.0;
scale.x = 1.0;
scale.y = 1.0;
scale.z = 1.0;
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SCENEGRAPH (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
else if( NULL != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SCENEGRAPH::~SCENEGRAPH()
{
// drop references
DROP_REFS( SCENEGRAPH, m_RTransforms );
DROP_REFS( SGSHAPE, m_RShape );
// delete owned objects
DEL_OBJS( SCENEGRAPH, m_Transforms );
DEL_OBJS( SGSHAPE, m_Shape );
return;
}
bool SCENEGRAPH::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a transform may be parent to a transform
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SCENEGRAPH::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
FIND_NODE( SCENEGRAPH, aNodeName, m_Transforms, aCaller );
FIND_NODE( SGSHAPE, aNodeName, m_Shape, aCaller );
// query the parent if appropriate
if( aCaller == m_Parent || NULL == m_Parent )
return NULL;
return m_Parent->FindNode( aNodeName, this );
}
void SCENEGRAPH::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( NULL == aNode )
return;
UNLINK_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms, isChild );
UNLINK_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unlinkNode() did not find its target\n";
return;
}
void SCENEGRAPH::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
return;
}
void SCENEGRAPH::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
return;
}
bool SCENEGRAPH::addNode( SGNODE* aNode, bool isChild )
{
if( NULL == aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aNode\n";
return false;
}
ADD_NODE( S3D::SGTYPE_TRANSFORM, SCENEGRAPH, aNode, m_Transforms, m_RTransforms, isChild );
ADD_NODE( S3D::SGTYPE_SHAPE, SGSHAPE, aNode, m_Shape, m_RShape, isChild );
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] object '" << aNode->GetName();
std::cerr << "' is not a valid type for this object (" << aNode->GetNodeType() << ")\n";
return false;
}
bool SCENEGRAPH::AddRefNode( SGNODE* aNode )
{
return addNode( aNode, false );
}
bool SCENEGRAPH::AddChildNode( SGNODE* aNode )
{
return addNode( aNode, true );
}
void SCENEGRAPH::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
// rename all shapes
do
{
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
while( sL != eL )
{
(*sL)->ReNameNodes();
++sL;
}
} while(0);
// rename all transforms
do
{
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
while( sL != eL )
{
(*sL)->ReNameNodes();
++sL;
}
} while(0);
return;
}
bool SCENEGRAPH::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( m_Transforms.empty() && m_RTransforms.empty()
&& m_Shape.empty() && m_RShape.empty() )
{
return false;
}
std::string tmp;
if( aReuseFlag )
{
if( !m_written )
{
aFile << "DEF " << GetName() << " Transform {\n";
m_written = true;
}
else
{
aFile << "USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " Transform {\n";
}
S3D::FormatPoint( tmp, center );
aFile << " center " << tmp << "\n";
S3D::FormatOrientation( tmp, rotation_axis, rotation_angle );
aFile << " rotation " << tmp << "\n";
S3D::FormatPoint( tmp, scale );
aFile << " scale " << tmp << "\n";
S3D::FormatOrientation( tmp, scale_axis, scale_angle );
aFile << " scaleOrientation " << tmp << "\n";
S3D::FormatPoint( tmp, translation );
aFile << " translation " << tmp << "\n";
aFile << " children [\n";
if( !m_Transforms.empty() )
{
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
if( !m_RTransforms.empty() )
{
std::vector< SCENEGRAPH* >::iterator sL = m_RTransforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_RTransforms.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
if( !m_Shape.empty() )
{
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
if( !m_RShape.empty() )
{
std::vector< SGSHAPE* >::iterator sL = m_RShape.begin();
std::vector< SGSHAPE* >::iterator eL = m_RShape.end();
while( sL != eL )
{
(*sL)->WriteVRML( aFile, aReuseFlag );
++sL;
}
}
aFile << "] }\n";
return true;
}
bool SCENEGRAPH::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode && NULL != m_Parent )
{
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( NULL == m_Parent )
{
// ensure unique node names
ResetNodeIndex();
ReNameNodes();
}
if( aFile.fail() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
S3D::WritePoint( aFile, center );
S3D::WritePoint( aFile, translation );
S3D::WriteVector( aFile, rotation_axis );
aFile.write( (char*)&rotation_angle, sizeof( rotation_angle ) );
S3D::WritePoint( aFile, scale );
S3D::WriteVector( aFile, scale_axis );
aFile.write( (char*)&scale_angle, sizeof( scale_angle ) );
size_t asize = m_Transforms.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_RTransforms.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_Shape.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
asize = m_RShape.size();
aFile.write( (char*)&asize, sizeof( size_t ) );
size_t i;
asize = m_Transforms.size();
// write child transforms
for( i = 0; i < asize; ++i )
{
if( !m_Transforms[i]->WriteCache( aFile, this ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream while writing child transforms\n";
return false;
}
}
// write referenced transform names
asize = m_RTransforms.size();
for( i = 0; i < asize; ++i )
aFile << "[" << m_RTransforms[i]->GetName() << "]";
// write child shapes
asize = m_Shape.size();
for( i = 0; i < asize; ++i )
{
if( !m_Shape[i]->WriteCache( aFile, this ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream while writing child shapes\n";
return false;
}
}
// write referenced transform names
asize = m_RShape.size();
for( i = 0; i < asize; ++i )
aFile << "[" << m_RShape[i]->GetName() << "]";
if( aFile.fail() )
return false;
return true;
}
bool SCENEGRAPH::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
if( !m_Transforms.empty() || !m_RTransforms.empty()
|| !m_Shape.empty() || !m_RShape.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] non-empty node\n";
return false;
}
std::string name; // name of the node
if( NULL == parentNode )
{
// we need to read the tag and verify its type
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; tag mismatch at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
m_Name = name;
}
// read fixed member data
S3D::ReadPoint( aFile, center );
S3D::ReadPoint( aFile, translation );
S3D::ReadVector( aFile, rotation_axis );
aFile.read( (char*)&rotation_angle, sizeof( rotation_angle ) );
S3D::ReadPoint( aFile, scale );
S3D::ReadVector( aFile, scale_axis );
aFile.read( (char*)&scale_angle, sizeof( scale_angle ) );
size_t sizeCT = 0; // child transforms
size_t sizeRT = 0; // referenced transforms
size_t sizeCS = 0; // child shapes
size_t sizeRS = 0; // referenced shapes
aFile.read( (char*)&sizeCT, sizeof( size_t ) );
aFile.read( (char*)&sizeRT, sizeof( size_t ) );
aFile.read( (char*)&sizeCS, sizeof( size_t ) );
aFile.read( (char*)&sizeRS, sizeof( size_t ) );
size_t i;
// read child transforms
for( i = 0; i < sizeCT; ++i )
{
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad child transform tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
SCENEGRAPH* sp = new SCENEGRAPH( this );
sp->SetName( name.c_str() );
if( !sp->ReadCache( aFile, this ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data while reading transform '";
std::cerr << name << "'\n";
return false;
}
}
// read referenced transforms
for( i = 0; i < sizeRT; ++i )
{
if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad ref transform tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
SGNODE* sp = FindNode( name.c_str(), this );
if( !sp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: cannot find ref transform '";
std::cerr << name << "'\n";
return false;
}
if( S3D::SGTYPE_TRANSFORM != sp->GetNodeType() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: type is not TRANSFORM '";
std::cerr << name << "'\n";
return false;
}
AddRefNode( sp );
}
// read child shapes
for( i = 0; i < sizeCS; ++i )
{
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad child shape tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
SGSHAPE* sp = new SGSHAPE( this );
sp->SetName( name.c_str() );
if( !sp->ReadCache( aFile, this ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data while reading shape '";
std::cerr << name << "'\n";
return false;
}
}
// read referenced shapes
for( i = 0; i < sizeRS; ++i )
{
if( S3D::SGTYPE_SHAPE != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad ref shape tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
SGNODE* sp = FindNode( name.c_str(), this );
if( !sp )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: cannot find ref shape '";
std::cerr << name << "'\n";
return false;
}
if( S3D::SGTYPE_SHAPE != sp->GetNodeType() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: type is not SGSHAPE '";
std::cerr << name << "'\n";
return false;
}
AddRefNode( sp );
}
if( aFile.fail() )
return false;
return true;
}
bool SCENEGRAPH::Prepare( const glm::dmat4* aTransform,
S3D::MATLIST& materials, std::vector< SMESH >& meshes )
{
// calculate the accumulated transform
double rX, rY, rZ;
rotation_axis.GetVector( rX, rY, rZ );
glm::dmat4 rM = glm::rotate( glm::degrees( rotation_angle ), glm::dvec3( rX, rY, rZ ) );
glm::dmat4 tM = glm::translate( glm::dvec3( translation.x, translation.y, translation.z ) );
glm::dmat4 tx0 = (*aTransform) * tM * rM;
bool ok = true;
// prepare all shapes
do
{
std::vector< SGSHAPE* >::iterator sL = m_Shape.begin();
std::vector< SGSHAPE* >::iterator eL = m_Shape.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
sL = m_RShape.begin();
eL = m_RShape.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
} while(0);
// prepare all transforms
do
{
std::vector< SCENEGRAPH* >::iterator sL = m_Transforms.begin();
std::vector< SCENEGRAPH* >::iterator eL = m_Transforms.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
sL = m_RTransforms.begin();
eL = m_RTransforms.end();
while( sL != eL && ok )
{
ok = (*sL)->Prepare( &tx0, materials, meshes );
++sL;
}
} while(0);
return ok;
}

View File

@ -0,0 +1,105 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 scenegraph.h
* defines the basic data set required to represent a 3D model;
* this model must remain compatible with VRML2.0 in order to
* facilitate VRML export of scene graph data created by avaiable
* 3D plugins.
*/
#ifndef SCENE_GRAPH_H
#define SCENE_GRAPH_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
class SGSHAPE;
class SCENEGRAPH : public SGNODE
{
private:
// The following are items which may be defined for reuse
// in a VRML output file. They do not necessarily correspond
// to the use of DEF within a VRML input file; it is the
// responsibility of the plugin to perform any necessary
// conversions to comply with the restrictions imposed by
// this scene graph structure
std::vector< SCENEGRAPH* > m_Transforms; // local Transform nodes
std::vector< SGSHAPE* > m_Shape; // local Shape nodes
std::vector< SCENEGRAPH* > m_RTransforms; // referenced Transform nodes
std::vector< SGSHAPE* > m_RShape; // referenced Shape nodes
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
public:
// note: order of transformation is Translate, Rotate, Offset
SGPOINT center;
SGPOINT translation;
SGVECTOR rotation_axis;
double rotation_angle; // radians
SGPOINT scale;
SGVECTOR scale_axis;
double scale_angle; // radians
SCENEGRAPH( SGNODE* aParent );
virtual ~SCENEGRAPH();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
bool Prepare( const glm::dmat4* aTransform,
S3D::MATLIST& materials, std::vector< SMESH >& meshes );
};
/*
p.120
Transform {
center 0 0 0
children []
rotation 0 0 1 0
scale 1 1 1
scaleOrientation 0 0 1 0
translation 0 0 0
bboxCenter 0 0 0
bboxSize -1 -1 -1
}
*/
#endif // SCENE_GRAPH_H

View File

@ -0,0 +1,172 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_api.h
* provides the API which plugins require to manipulate the SG* classes.
*
*/
#ifndef SG_API_H
#define SG_API_H
#include <3d_cache/sg/sg_types.h>
class SGCOLOR;
class SGPOINT;
class SGVECTOR;
class SGNODE;
class SCENEGRAPH;
// creation and manipulation of base types
typedef SGCOLOR* (*NEW_SGBASE_COLOR)(void);
typedef bool ( *SET_SGBASE_COLOR )( SGCOLOR* aColor,
float aRedVal, float aGreenVal, float aBlueVal );
typedef bool ( *GET_SGBASE_COLOR )( SGCOLOR* aColor,
float& aRedVal, float& aGreenVal, float& aBlueVal );
typedef SGPOINT* ( *NEW_SGBASE_POINT )(void);
typedef bool ( *SET_SGBASE_POINT )( SGPOINT* aPoint,
double aXVal, double aYVal, double aZVal );
typedef bool ( *GET_SGBASE_POINT )( SGPOINT* aPoint,
double& aXVal, double& aYVal, double& aZVal );
typedef SGVECTOR* (*NEW_SGBASE_VECTOR)(void);
typedef bool ( *SET_SGBASE_VECTOR )( SGPOINT* aVector,
double aXVal, double aYVal, double aZVal );
typedef bool ( *GET_SGBASE_VECTOR )( SGPOINT* aVector,
double& aXVal, double& aYVal, double& aZVal );
// creation of scenegraph nodes:
typedef SGNODE* (*NEW_SG_NODE)( SGNODE* aParent, S3D::SGTYPES aNodeType);
namespace S3D
{
struct SG_API
{
// creation of basic SG types
NEW_SGBASE_COLOR NewColor;
NEW_SGBASE_POINT NewPoint;
NEW_SGBASE_VECTOR NewVector;
// manipulators for basic SG types
SET_SGBASE_COLOR SetSGColor;
GET_SGBASE_COLOR GetSGColor;
SET_SGBASE_POINT SetSGPoint;
GET_SGBASE_POINT GetSGPoint;
SET_SGBASE_VECTOR SetSGVector;
GET_SGBASE_VECTOR GetSGVector;
// creation of nodes
NEW_SG_NODE NewNode;
};
// generic node class; this must never be instantiated as an underived class
class API_SGNODE
{
protected:
SGNODE* node;
S3D::SGTYPES nodeType;
public:
API_SGNODE();
SGNODE* GetNode( void );
bool AttachNode( SGNODE* aNode );
bool GetNodeType( S3D::SGTYPES& aNodeType ) const;
bool GetParent( SGNODE const*& aParent ) const;
bool SetParent( SGNODE* aParent );
bool GetName( const char*& aName );
bool SetName( const char *aName );
bool GetNodeTypeName( S3D::SGTYPES aNodeType, const char*& aName ) const;
bool FindNode( const char *aNodeName, const SGNODE *aCaller, SGNODE*& aNode );
};
// Transforms and operations
class API_TRANSFORM : public API_SGNODE
{
public:
API_TRANSFORM( SGNODE* aParent );
bool GetLocalTransforms( SGNODE** aNodeList, int& nListItems );
bool GetOtherTransforms( SGNODE** aNodeList, int& nListItems );
bool AddOtherTransform( SGNODE* aTransformNode );
bool GetLocalShapes( SGNODE** aNodeList, int& nListItems );
bool GetOtherShapes( SGNODE** aNodeList, int& nListItems );
bool AddOtherShape( SGNODE* aTransformNode );
bool GetTranslation( SGPOINT& aPoint ) const;
bool GetRotation( SGVECTOR& aVector, double& aAngle ) const;
bool GetScale( SGPOINT& aScale ) const;
bool SetTranslation( const SGPOINT& aPoint );
bool SetRotation( const SGVECTOR& aVector, double aAngle );
bool SetScale( const SGPOINT& aScale );
};
// Appearance and operations
class API_APPEARANCE : public API_SGNODE
{
public:
API_APPEARANCE( SGNODE *aParent );
bool SetEmissive( float aRVal, float aGVal, float aBVal );
bool SetEmissive( const SGCOLOR* aRGBColor );
bool SetEmissive( const SGCOLOR& aRGBColor );
bool SetDiffuse( float aRVal, float aGVal, float aBVal );
bool SetDiffuse( const SGCOLOR* aRGBColor );
bool SetDiffuse( const SGCOLOR& aRGBColor );
bool SetSpecular( float aRVal, float aGVal, float aBVal );
bool SetSpecular( const SGCOLOR* aRGBColor );
bool SetSpecular( const SGCOLOR& aRGBColor );
bool SetAmbient( double aVal );
bool SetShininess( double aVal );
bool SetTransparency( double aVal );
bool GetEmissive( SGCOLOR& aRGBColor );
bool GetDiffuse( SGCOLOR& aRGBColor );
bool GetSpecular( SGCOLOR& aRGBColor );
bool GetAmbient( double& aVal );
bool GetShininess( double& aVal );
bool GetTransparency( double& aVal );
};
// XXX - Color Index and operations
// XXX - Colors and operations
// XXX - Coordinate Index and operations
// XXX - Coordinates and operations
// XXX - Face Set and operations
// XXX - Face Set Index (base class for other indices) and operations
// XXX - Normals Index and operations
// XXX - Normals and operations
// XXX - Shape and operations
};
#endif // SG_API_H

View File

@ -0,0 +1,347 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <utility>
#include <3d_cache/sg/sg_appearance.h>
#include <3d_cache/sg/sg_helpers.h>
SGAPPEARANCE::SGAPPEARANCE( SGNODE* aParent ) : SGNODE( aParent)
{
m_SGtype = S3D::SGTYPE_APPEARANCE;
// defaults in accord with VRML2.0 spec
ambient = 0.2;
shininess = 0.2;
transparency = 0.0;
diffuse.SetColor( 0.8, 0.8, 0.8 );
if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SGAPPEARANCE (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
else if( NULL != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGAPPEARANCE::~SGAPPEARANCE()
{
return;
}
bool SGAPPEARANCE::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a SGSHAPE may be parent to a SGAPPEARANCE
if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
bool SGAPPEARANCE::SetEmissive( float aRVal, float aGVal, float aBVal )
{
return emissive.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetEmissive( const SGCOLOR* aRGBColor )
{
if( NULL == aRGBColor )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aRGBColor\n";
return false;
}
return emissive.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetEmissive( const SGCOLOR& aRGBColor )
{
return emissive.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetDiffuse( float aRVal, float aGVal, float aBVal )
{
return diffuse.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR* aRGBColor )
{
if( NULL == aRGBColor )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aRGBColor\n";
return false;
}
return diffuse.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetDiffuse( const SGCOLOR& aRGBColor )
{
return diffuse.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetSpecular( float aRVal, float aGVal, float aBVal )
{
return specular.SetColor( aRVal, aGVal, aBVal );
}
bool SGAPPEARANCE::SetSpecular( const SGCOLOR* aRGBColor )
{
if( NULL == aRGBColor )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aRGBColor\n";
return false;
}
return specular.SetColor( aRGBColor );
}
bool SGAPPEARANCE::SetSpecular( const SGCOLOR& aRGBColor )
{
return specular.SetColor( aRGBColor );
}
SGNODE* SGAPPEARANCE::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return NULL;
}
void SGAPPEARANCE::unlinkChildNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
void SGAPPEARANCE::unlinkRefNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
bool SGAPPEARANCE::AddRefNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGAPPEARANCE::AddChildNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
void SGAPPEARANCE::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGAPPEARANCE::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( aReuseFlag )
{
if( !m_written )
{
aFile << " appearance DEF " << GetName() << " Appearance {\n";
m_written = true;
}
else
{
aFile << " appearance USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " appearance Appearance {\n";
}
aFile << " material Material {\n";
std::string tmp;
S3D::FormatFloat( tmp, ambient );
aFile << " ambientIntensity " << tmp << "\n";
float red, green, blue;
diffuse.GetColor( red, green, blue );
S3D::FormatFloat( tmp, red );
aFile << " diffuseColor " << tmp << " ";
S3D::FormatFloat( tmp, green );
aFile << tmp << " ";
S3D::FormatFloat( tmp, blue);
aFile << tmp << "\n";
emissive.GetColor( red, green, blue );
S3D::FormatFloat( tmp, red );
aFile << " emissiveColor " << tmp << " ";
S3D::FormatFloat( tmp, green );
aFile << tmp << " ";
S3D::FormatFloat( tmp, blue);
aFile << tmp << "\n";
S3D::FormatFloat( tmp, shininess );
aFile << " shininess " << tmp << "\n";
specular.GetColor( red, green, blue );
S3D::FormatFloat( tmp, red );
aFile << " specularColor " << tmp << " ";
S3D::FormatFloat( tmp, green );
aFile << tmp << " ";
S3D::FormatFloat( tmp, blue);
aFile << tmp << "\n";
S3D::FormatFloat( tmp, transparency );
aFile << " transparency " << tmp << "\n";
aFile << "} }\n";
return true;
}
bool SGAPPEARANCE::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode )
{
if( NULL == m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; m_aParent is NULL\n";
return false;
}
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( !aFile.good() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
aFile.write( (char*)&ambient, sizeof(ambient) );
aFile.write( (char*)&shininess, sizeof(shininess) );
aFile.write( (char*)&transparency, sizeof(transparency) );
S3D::WriteColor( aFile, diffuse );
S3D::WriteColor( aFile, emissive );
S3D::WriteColor( aFile, specular );
if( aFile.fail() )
return false;
return true;
}
bool SGAPPEARANCE::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
aFile.read( (char*)&ambient, sizeof(ambient) );
aFile.read( (char*)&shininess, sizeof(shininess) );
aFile.read( (char*)&transparency, sizeof(transparency) );
S3D::ReadColor( aFile, diffuse );
S3D::ReadColor( aFile, emissive );
S3D::ReadColor( aFile, specular );
if( aFile.fail() )
return false;
return true;
}

View File

@ -0,0 +1,76 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_appearance.h
* defines the generic material appearance of a scenegraph object
*/
#ifndef SG_APPEARANCE_H
#define SG_APPEARANCE_H
#include <3d_cache/sg/sg_node.h>
class SGAPPEARANCE : public SGNODE
{
public:
float ambient; // default 0.2
float shininess; // default 0.2
float transparency; // default 0.0
SGCOLOR diffuse; // default 0.8 0.8 0.8
SGCOLOR emissive; // default 0.0 0.0 0.0
SGCOLOR specular; // default 0.0 0.0 0.0
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
public:
SGAPPEARANCE( SGNODE* aParent );
virtual ~SGAPPEARANCE();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
bool SetEmissive( float aRVal, float aGVal, float aBVal );
bool SetEmissive( const SGCOLOR* aRGBColor );
bool SetEmissive( const SGCOLOR& aRGBColor );
bool SetDiffuse( float aRVal, float aGVal, float aBVal );
bool SetDiffuse( const SGCOLOR* aRGBColor );
bool SetDiffuse( const SGCOLOR& aRGBColor );
bool SetSpecular( float aRVal, float aGVal, float aBVal );
bool SetSpecular( const SGCOLOR* aRGBColor );
bool SetSpecular( const SGCOLOR& aRGBColor );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
};
#endif // SG_APPEARANCE_H

View File

@ -0,0 +1,325 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <cmath>
#include <3d_cache/sg/sg_base.h>
SGCOLOR::SGCOLOR()
{
red = 0.0;
green = 0.0;
blue = 0.0;
return;
}
SGCOLOR::SGCOLOR( float aRVal, float aGVal, float aBVal )
{
if( !checkRange( aRVal, aGVal, aBVal ) )
{
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid value passed to constructor\n";
#endif
red = 0.0;
green = 0.0;
blue = 0.0;
return;
}
red = aRVal;
green = aGVal;
blue = aBVal;
return;
}
void SGCOLOR::GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const
{
aRedVal = red;
aGreenVal = green;
aBlueVal = blue;
return;
}
void SGCOLOR::GetColor( SGCOLOR& aColor ) const
{
aColor.red = red;
aColor.green = green;
aColor.blue = blue;
return;
}
void SGCOLOR::GetColor( SGCOLOR* aColor ) const
{
if( NULL == aColor )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aColor\n";
return;
}
aColor->red = red;
aColor->green = green;
aColor->blue = blue;
return;
}
bool SGCOLOR::SetColor( float aRedVal, float aGreenVal, float aBlueVal )
{
if( !checkRange( aRedVal, aGreenVal, aBlueVal ) )
return false;
red = aRedVal;
green = aGreenVal;
blue = aBlueVal;
return true;
}
bool SGCOLOR::SetColor( const SGCOLOR& aColor )
{
red = aColor.red;
green = aColor.green;
blue = aColor.blue;
return true;
}
bool SGCOLOR::SetColor( const SGCOLOR* aColor )
{
if( NULL == aColor )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aColor\n";
return false;
}
red = aColor->red;
green = aColor->green;
blue = aColor->blue;
return true;
}
bool SGCOLOR::checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const
{
bool ok = true;
if( aRedVal < 0.0 || aRedVal > 1.0 )
{
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid RED value: " << aRedVal << "\n";
#endif
ok = false;
}
if( aGreenVal < 0.0 || aGreenVal > 1.0 )
{
#ifdef DEBUG
if( ok )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
}
std::cerr << " * [BUG] invalid GREEN value: " << aGreenVal << "\n";
#endif
ok = false;
}
if( aBlueVal < 0.0 || aBlueVal > 1.0 )
{
#ifdef DEBUG
if( ok )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
}
std::cerr << " * [BUG] invalid BLUE value: " << aBlueVal << "\n";
#endif
ok = false;
}
return ok;
}
SGPOINT::SGPOINT()
{
x = 0.0;
y = 0.0;
z = 0.0;
return;
}
SGPOINT::SGPOINT( double aXVal, double aYVal, double aZVal )
{
x = aXVal;
y = aYVal;
z = aZVal;
}
void SGPOINT::GetPoint( double& aXVal, double& aYVal, double& aZVal )
{
x = aXVal;
y = aYVal;
z = aZVal;
return;
}
void SGPOINT::GetPoint( SGPOINT& aPoint )
{
x = aPoint.x;
y = aPoint.y;
z = aPoint.z;
return;
}
void SGPOINT::GetPoint( SGPOINT* aPoint )
{
if( NULL == aPoint )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aPoint\n";
return;
}
x = aPoint->x;
y = aPoint->y;
z = aPoint->z;
return;
}
void SGPOINT::SetPoint( double aXVal, double aYVal, double aZVal )
{
x = aXVal;
y = aYVal;
z = aZVal;
return;
}
void SGPOINT::SetPoint( const SGPOINT& aPoint )
{
x = aPoint.x;
y = aPoint.y;
z = aPoint.z;
return;
}
SGVECTOR::SGVECTOR()
{
vx = 0.0;
vy = 0.0;
vz = 1.0;
return;
}
SGVECTOR::SGVECTOR( double aXVal, double aYVal, double aZVal )
{
vx = aXVal;
vy = aYVal;
vz = aZVal;
normalize();
return;
}
void SGVECTOR::GetVector( double& aXVal, double& aYVal, double& aZVal ) const
{
aXVal = vx;
aYVal = vy;
aZVal = vz;
return;
}
void SGVECTOR::SetVector( double aXVal, double aYVal, double aZVal )
{
vx = aXVal;
vy = aYVal;
vz = aZVal;
normalize();
return;
}
void SGVECTOR::SetVector( const SGVECTOR& aVector )
{
aVector.GetVector( vx, vy, vz );
return;
}
void SGVECTOR::normalize( void )
{
double dx = vx * vx;
double dy = vy * vy;
double dz = vz * vz;
double dv2 = dx + dy + dz;
// note: placing the limit at 1e-14 ensures that
// models representing mm to 1e-4 precision can
// be accepted before the calculations blow up
if( (dx + dy + dz) < 1e-14 )
{
// use the default; the numbers are too small
// to be believable
vx = 0.0;
vy = 0.0;
vz = 1.0;
return;
}
dx /= dv2;
dy /= dv2;
dz /= dv2;
vx = sqrt( dx );
vy = sqrt( dy );
vz = sqrt( dz );
return;
}
SGVECTOR& SGVECTOR::operator=( const SGVECTOR& source )
{
vx = source.vx;
vy = source.vy;
vz = source.vz;
return *this;
}

View File

@ -0,0 +1,100 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_base.h
* defines the low level classes common to scene graph nodes
*/
#ifndef SG_BASE_H
#define SG_BASE_H
class SGCOLOR
{
protected:
float red;
float green;
float blue;
public:
SGCOLOR();
SGCOLOR( float aRVal, float aGVal, float aBVal );
void GetColor( float& aRedVal, float& aGreenVal, float& aBlueVal ) const;
void GetColor( SGCOLOR& aColor ) const;
void GetColor( SGCOLOR* aColor ) const;
bool SetColor( float aRedVal, float aGreenVal, float aBlueVal );
bool SetColor( const SGCOLOR& aColor );
bool SetColor( const SGCOLOR* aColor );
private:
bool checkRange( float aRedVal, float aGreenVal, float aBlueVal ) const;
};
class SGPOINT
{
public:
double x;
double y;
double z;
public:
SGPOINT();
SGPOINT( double aXVal, double aYVal, double aZVal );
void GetPoint( double& aXVal, double& aYVal, double& aZVal );
void GetPoint( SGPOINT& aPoint );
void GetPoint( SGPOINT* aPoint );
void SetPoint( double aXVal, double aYVal, double aZVal );
void SetPoint( const SGPOINT& aPoint );
};
class SGVECTOR
{
private:
void normalize( void );
double vx;
double vy;
double vz;
public:
SGVECTOR();
SGVECTOR( double aXVal, double aYVal, double aZVal );
void GetVector( double& aXVal, double& aYVal, double& aZVal ) const;
void SetVector( double aXVal, double aYVal, double aZVal );
void SetVector( const SGVECTOR& aVector );
SGVECTOR& operator=( const SGVECTOR& source );
};
#endif // SG_BASE_H

View File

@ -0,0 +1,42 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/sg_colorindex.h>
SGCOLORINDEX::SGCOLORINDEX( SGNODE* aParent ) : SGINDEX( aParent )
{
m_SGtype = S3D::SGTYPE_COLORINDEX;
if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOLORINDEX::~SGCOLORINDEX()
{
return;
}

View File

@ -0,0 +1,41 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_colorindex.h
* defines an RGB color index mapping for a scenegraph object
*/
#ifndef SG_COLORINDEX_H
#define SG_COLORINDEX_H
#include <3d_cache/sg/sg_index.h>
class SGCOLORINDEX : public SGINDEX
{
public:
SGCOLORINDEX( SGNODE* aParent );
virtual ~SGCOLORINDEX();
};
#endif // SG_COLORINDEX_H

View File

@ -0,0 +1,313 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/sg_colors.h>
#include <3d_cache/sg/sg_helpers.h>
SGCOLORS::SGCOLORS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_COLORS;
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SGCOLORS (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
else if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOLORS::~SGCOLORS()
{
colors.clear();
return;
}
bool SGCOLORS::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGCOLORS
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGCOLORS::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return NULL;
}
void SGCOLORS::unlinkChildNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
void SGCOLORS::unlinkRefNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
bool SGCOLORS::AddRefNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGCOLORS::AddChildNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGCOLORS::GetColorList( size_t& aListSize, SGCOLOR*& aColorList )
{
if( colors.size() )
{
aListSize = 0;
aColorList = NULL;
return false;
}
aListSize = colors.size();
aColorList = &colors[0];
return true;
}
void SGCOLORS::SetColorList( size_t& aListSize, const SGCOLOR* aColorList )
{
colors.clear();
if( 0 == aListSize || NULL == aColorList )
return;
for( size_t i = 0; i < aListSize; ++i )
colors.push_back( aColorList[i] );
return;
}
void SGCOLORS::AddColor( double aRedValue, double aGreenValue, double aBlueValue )
{
colors.push_back( SGCOLOR( aRedValue, aGreenValue, aBlueValue ) );
return;
}
void SGCOLORS::AddColor( const SGCOLOR& aColor )
{
colors.push_back( aColor );
return;
}
void SGCOLORS::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGCOLORS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( colors.empty() )
return false;
if( aReuseFlag )
{
if( !m_written )
{
aFile << "color DEF " << GetName() << " Color { color [\n ";
m_written = true;
}
else
{
aFile << "color USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << "color Color { color [\n ";
}
std::string tmp;
size_t n = colors.size();
bool nline = false;
for( size_t i = 0; i < n; )
{
S3D::FormatColor( tmp, colors[i] );
aFile << tmp ;
++i;
if( i < n )
{
aFile << ",";
if( nline )
{
aFile << "\n ";
nline = false;
}
else
{
nline = true;
}
}
}
aFile << "] }\n";
return true;
}
bool SGCOLORS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode )
{
if( NULL == m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; m_aParent is NULL\n";
return false;
}
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( !aFile.good() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
size_t ncolors = colors.size();
aFile.write( (char*)&ncolors, sizeof(size_t) );
for( size_t i = 0; i < ncolors; ++i )
S3D::WriteColor( aFile, colors[i] );
if( aFile.fail() )
return false;
return true;
}
bool SGCOLORS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
if( !colors.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] non-empty node\n";
return false;
}
size_t ncolors;
aFile.read( (char*)&ncolors, sizeof(size_t) );
SGCOLOR tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < ncolors; ++i )
{
if( !S3D::ReadColor( aFile, tmp ) || aFile.fail() )
return false;
colors.push_back( tmp );
}
return true;
}

View File

@ -0,0 +1,65 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_colors.h
* defines an RGB color set for a scenegraph object
*/
#ifndef SG_COLORS_H
#define SG_COLORS_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
class SGCOLORS : public SGNODE
{
public:
std::vector< SGCOLOR > colors;
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
public:
SGCOLORS( SGNODE* aParent );
virtual ~SGCOLORS();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
bool GetColorList( size_t& aListSize, SGCOLOR*& aColorList );
void SetColorList( size_t& aListSize, const SGCOLOR* aColorList );
void AddColor( double aRedValue, double aGreenValue, double aBlueValue );
void AddColor( const SGCOLOR& aColor );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
};
#endif // SG_COLORS_H

View File

@ -0,0 +1,43 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/sg_coordindex.h>
SGCOORDINDEX::SGCOORDINDEX( SGNODE* aParent ) : SGINDEX( aParent )
{
m_SGtype = S3D::SGTYPE_COORDINDEX;
if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOORDINDEX::~SGCOORDINDEX()
{
return;
}

View File

@ -0,0 +1,51 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_coordindex.h
* defines an coordinate index set for a scenegraph object
*/
#ifndef SG_COORDINDEX_H
#define SG_COORDINDEX_H
#include <3d_cache/sg/sg_index.h>
/**
* Class SGCOORDINDEX
* is a class which maintains a coordinate index list. Users
* must ensure that coordinate indices are specified as
* triplets (triangular faces) since no checking is performed.
* In instances where it is not possible to determine which
* side of the triangle is to be rendered (for example IGES
* entities) then the user must supply each triplet in both
* point orders.
*/
class SGCOORDINDEX : public SGINDEX
{
public:
SGCOORDINDEX( SGNODE* aParent );
virtual ~SGCOORDINDEX();
};
#endif // SG_COORDINDEX_H

View File

@ -0,0 +1,314 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/sg_coords.h>
#include <3d_cache/sg/sg_helpers.h>
SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_COORDS;
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SGCOORDS (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
else if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGCOORDS::~SGCOORDS()
{
coords.clear();
return;
}
bool SGCOORDS::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGCOORDS
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGCOORDS::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return NULL;
}
void SGCOORDS::unlinkChildNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
void SGCOORDS::unlinkRefNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
bool SGCOORDS::AddRefNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGCOORDS::AddChildNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGCOORDS::GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList )
{
if( coords.empty() )
{
aListSize = 0;
aCoordsList = NULL;
return false;
}
aListSize = coords.size();
aCoordsList = &coords[0];
return true;
}
void SGCOORDS::SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList )
{
coords.clear();
if( 0 == aListSize || NULL == aCoordsList )
return;
for( size_t i = 0; i < aListSize; ++i )
coords.push_back( aCoordsList[i] );
return;
}
void SGCOORDS::AddCoord( double aXValue, double aYValue, double aZValue )
{
coords.push_back( SGPOINT( aXValue, aYValue, aZValue ) );
return;
}
void SGCOORDS::AddCoord( const SGPOINT& aPoint )
{
coords.push_back( aPoint );
return;
}
void SGCOORDS::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGCOORDS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( coords.empty() )
return false;
if( aReuseFlag )
{
if( !m_written )
{
aFile << " coord DEF " << GetName() << " Coordinate { point [\n ";
m_written = true;
}
else
{
aFile << " coord USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " coord Coordinate { point [\n ";
}
std::string tmp;
size_t n = coords.size();
bool nline = false;
for( size_t i = 0; i < n; )
{
S3D::FormatPoint( tmp, coords[i] );
aFile << tmp ;
++i;
if( i < n )
{
aFile << ",";
if( nline )
{
aFile << "\n ";
nline = false;
}
else
{
nline = true;
}
}
}
aFile << "] }\n";
return true;
}
bool SGCOORDS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode )
{
if( NULL == m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; m_aParent is NULL\n";
return false;
}
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( !aFile.good() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
size_t npts = coords.size();
aFile.write( (char*)&npts, sizeof(size_t) );
for( size_t i = 0; i < npts; ++i )
S3D::WritePoint( aFile, coords[i] );
if( aFile.fail() )
return false;
return true;
}
bool SGCOORDS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
if( !coords.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] non-empty node\n";
return false;
}
size_t npts;
aFile.read( (char*)&npts, sizeof(size_t) );
SGPOINT tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < npts; ++i )
{
if( !S3D::ReadPoint( aFile, tmp ) || aFile.fail() )
return false;
coords.push_back( tmp );
}
return true;
}

View File

@ -0,0 +1,65 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_coords.h
* defines a vertex coordinate set for a scenegraph object
*/
#ifndef SG_COORDS_H
#define SG_COORDS_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
class SGCOORDS : public SGNODE
{
public:
std::vector< SGPOINT > coords;
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
public:
SGCOORDS( SGNODE* aParent );
virtual ~SGCOORDS();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
bool GetCoordsList( size_t& aListSize, SGPOINT*& aCoordsList );
void SetCoordsList( size_t aListSize, const SGPOINT* aCoordsList );
void AddCoord( double aXValue, double aYValue, double aZValue );
void AddCoord( const SGPOINT& aPoint );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
};
#endif // SG_COORDS_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_faceset.h
* defines an indexed face set for a scenegraph
*/
// BUG:
// 1. Since we always use Normal Per Vertex we can deprecate SGNORMALINDEX
// 2. There is no such thing as a Referenced Index so deprecate these
#ifndef SG_FACESET_H
#define SG_FACESET_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
// BUG: eliminate NormalIndices; they are not necessary since
// we use per-vertex normals
class SGCOLORS;
class SGCOORDS;
class SGNORMALS;
class SGCOLORINDEX;
class SGCOORDINDEX;
class SGNORMALINDEX;
class SGFACESET : public SGNODE
{
private:
bool valid;
bool validated;
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
// owned objects
SGCOLORS* m_Colors;
SGCOLORINDEX* m_ColorIndices;
SGCOORDS* m_Coords;
SGCOORDINDEX* m_CoordIndices;
SGNORMALS* m_Normals;
// referenced objects
SGCOLORS* m_RColors;
SGCOORDS* m_RCoords;
SGNORMALS* m_RNormals;
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
// validate the data held by this face set
bool validate( void );
public:
SGFACESET( SGNODE* aParent );
virtual ~SGFACESET();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode( const char *aNodeName, const SGNODE *aCaller );
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
};
/*
p.88
IndexedFaceSet {
color NULL
coord NULL
normal NULL
texCoord NULL
ccw TRUE
colorIndex []
colorPerVertex TRUE
convex TRUE
coordIndex []
creaseAngle 0
normalIndex []
normalPerVertex TRUE
solid TRUE
texCoordIndex []
}
*/
#endif // SG_FACESET_H

View File

@ -0,0 +1,306 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <sstream>
#include <streambuf>
#include <iomanip>
#include <string>
#include <3d_cache/sg/sg_helpers.h>
#include <3d_cache/sg/sg_node.h>
// formats a floating point number for text output to a VRML file
void S3D::FormatFloat( std::string& result, double value )
{
if( value < 1e-8 && value > -1e-8 )
{
result = "0";
return;
}
// note: many VRML implementations use float so we use the max.
// precision here of 8 digits.
std::ostringstream out;
out << std::setprecision( 8 ) << value;
result = out.str();
size_t p = result.find( "." );
// trim trailing 0 if appropriate
if( std::string::npos == p )
return;
p = result.find_first_of( "eE" );
if( std::string::npos == p )
{
while( '0' == *(result.rbegin()) )
result.erase( result.size() - 1 );
return;
}
if( '0' != result.at( p -1 ) )
return;
// trim all 0 to the left of 'p'
std::string tmp = result.substr( p );
result = result.substr( 0, p );
while( '0' == *(result.rbegin()) )
result.erase( result.size() - 1 );
result.append( tmp );
return;
}
// format orientation data for VRML output
void S3D::FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation )
{
double aX;
double aY;
double aZ;
axis.GetVector( aX, aY, aZ );
FormatFloat( result, aX );
std::string tmp;
FormatFloat( tmp, aY );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, aZ );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, rotation );
result.append( " " );
result.append( tmp );
return;
}
// format point data for VRML output
void S3D::FormatPoint( std::string& result, const SGPOINT& point )
{
FormatFloat( result, point.x );
std::string tmp;
FormatFloat( tmp, point.y );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, point.z );
result.append( " " );
result.append( tmp );
return;
}
// format vector data for VRML output
void S3D::FormatVector( std::string& result, const SGVECTOR& aVector )
{
double X, Y, Z;
aVector.GetVector( X, Y, Z );
FormatFloat( result, X );
std::string tmp;
FormatFloat( tmp, Y );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, Z );
result.append( " " );
result.append( tmp );
return;
}
// format Color data for VRML output
void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
{
float R, G, B;
aColor.GetColor( R, G, B );
FormatFloat( result, R );
std::string tmp;
FormatFloat( tmp, G );
result.append( " " );
result.append( tmp );
FormatFloat( tmp, B );
result.append( " " );
result.append( tmp );
return;
}
bool S3D::WritePoint( std::ofstream& aFile, const SGPOINT& aPoint )
{
aFile.write( (char*)&aPoint.x, sizeof(aPoint.x) );
aFile.write( (char*)&aPoint.y, sizeof(aPoint.y) );
aFile.write( (char*)&aPoint.z, sizeof(aPoint.z) );
}
bool S3D::WriteVector( std::ofstream& aFile, const SGVECTOR& aVector )
{
double x, y, z;
aVector.GetVector( x, y, z );
aFile.write( (char*)&x, sizeof(double) );
aFile.write( (char*)&y, sizeof(double) );
aFile.write( (char*)&z, sizeof(double) );
if( aFile.fail() )
return false;
return true;
}
bool S3D::WriteColor( std::ofstream& aFile, const SGCOLOR& aColor )
{
float r, g, b;
aColor.GetColor( r, g, b );
aFile.write( (char*)&r, sizeof(float) );
aFile.write( (char*)&g, sizeof(float) );
aFile.write( (char*)&b, sizeof(float) );
if( aFile.fail() )
return false;
return true;
}
S3D::SGTYPES S3D::ReadTag( std::ifstream& aFile, std::string& aName )
{
char schar;
aFile.get( schar );
if( '[' != schar )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; missing left bracket at position ";
std::cerr << aFile.tellg() << "\n";
return S3D::SGTYPE_END;
}
std::string name;
aFile.get( schar );
while( ']' != schar && aFile.good() )
{
name.push_back( schar );
aFile.get( schar );
}
if( schar != ']' )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; could not find right bracket\n";
return S3D::SGTYPE_END;
}
aName = name;
size_t upos = name.find( '_' );
if( std::string::npos == upos )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; no underscore in name '";
std::cerr << name << "'\n";
return S3D::SGTYPE_END;
}
name = name.substr( 0, upos );
S3D::SGTYPES types[S3D::SGTYPE_END] = {
SGTYPE_TRANSFORM,
SGTYPE_APPEARANCE,
SGTYPE_COLORS,
SGTYPE_COLORINDEX,
SGTYPE_FACESET,
SGTYPE_COORDS,
SGTYPE_COORDINDEX,
SGTYPE_NORMALS,
SGTYPE_SHAPE
};
for( int i = 0; i < S3D::SGTYPE_END; ++i )
{
if( !name.compare( S3D::GetNodeTypeName( types[i] ) ) )
return types[i];
}
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; no node type matching '";
std::cerr << name << "'\n";
return S3D::SGTYPE_END;
}
bool S3D::ReadPoint( std::ifstream& aFile, SGPOINT& aPoint )
{
aFile.read( (char*)&aPoint.x, sizeof( aPoint.x ) );
aFile.read( (char*)&aPoint.y, sizeof( aPoint.y ) );
aFile.read( (char*)&aPoint.z, sizeof( aPoint.z ) );
if( aFile.fail() )
return false;
return true;
}
bool S3D::ReadVector( std::ifstream& aFile, SGVECTOR& aVector )
{
double x, y, z;
aFile.read( (char*)&x, sizeof(double) );
aFile.read( (char*)&y, sizeof(double) );
aFile.read( (char*)&z, sizeof(double) );
aVector.SetVector( x, y, z );
if( aFile.fail() )
return false;
return true;
}
bool S3D::ReadColor( std::ifstream& aFile, SGCOLOR& aColor )
{
float r, g, b;
aFile.read( (char*)&r, sizeof(float) );
aFile.read( (char*)&g, sizeof(float) );
aFile.read( (char*)&b, sizeof(float) );
aColor.SetColor( r, g, b );
if( aFile.fail() )
return false;
return true;
}

View File

@ -0,0 +1,209 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_helpers.h
* defines a number of macro functions to aid in repetitious code which
* is probably best expressed as a preprocessor macro rather than as
* a template. This header also declares a number of functions which are
* only of use within the sg_* classes.
*/
#ifndef SG_HELPERS_H
#define SG_HELPERS_H
#include <fstream>
#include <string>
#include <algorithm>
#include <3d_cache/sg/sg_base.h>
#include "sg_types.h"
// Function to drop references within an SGNODE
// The node being destroyed must remove itself from the object reference's
// backpointer list in order to avoid a segfault.
#define DROP_REFS( aType, aList ) do { \
std::vector< aType* >::iterator sL = aList.begin(); \
std::vector< aType* >::iterator eL = aList.end(); \
while( sL != eL ) { \
((SGNODE*)*sL)->delNodeRef( this ); \
++sL; \
} \
aList.clear(); \
} while( 0 )
// Function to delete owned objects within an SGNODE
// The owned object's parent is set to NULL before
// deletion to avoid a redundant 'unlinkChildNode' call.
#define DEL_OBJS( aType, aList ) do { \
std::vector< aType* >::iterator sL = aList.begin(); \
std::vector< aType* >::iterator eL = aList.end(); \
while( sL != eL ) { \
((SGNODE*)*sL)->SetParent( NULL, false ); \
delete *sL; \
++sL; \
} \
aList.clear(); \
} while( 0 )
// Function to unlink a child or reference node when that child or
// reference node is being destroyed.
#define UNLINK_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) do { \
if( aNodeID == aNode->GetNodeType() ) { \
std::vector< aType* >* oSL; \
std::vector< aType* >::iterator sL; \
std::vector< aType* >::iterator eL; \
if( isChild ) { \
oSL = &aOwnedList; \
sL = aOwnedList.begin(); \
eL = aOwnedList.end(); \
} else { \
oSL = &aRefList; \
sL = aRefList.begin(); \
eL = aRefList.end(); \
} \
while( sL != eL ) { \
if( (SGNODE*)*sL == aNode ) { \
oSL->erase( sL ); \
return; \
} \
++sL; \
} \
return; \
} } while( 0 )
// Function to check a node type, check for an existing reference,
// and add the node type to the reference list if applicable
#define ADD_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) do { \
if( aNodeID == aNode->GetNodeType() ) { \
std::vector< aType* >::iterator sL; \
SGNODE* psg = NULL; \
sL = std::find( aOwnedList.begin(), aOwnedList.end(), aNode ); \
if( sL != aOwnedList.end() ) return true; \
sL = std::find( aRefList.begin(), aRefList.end(), aNode ); \
if( sL != aRefList.end() ) return true; \
if( isChild ) { \
SGNODE* ppn = (SGNODE*)aNode->GetParent(); \
if( NULL != ppn ) { \
if( this != ppn ) { \
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
std::cerr << " * [BUG] object '" << aNode->GetName(); \
std::cerr << "' has multiple parents '" << ppn->GetName() << "', '"; \
std::cerr << m_Name << "'\n"; \
return false; \
} \
} \
aOwnedList.push_back( (aType*)aNode ); \
aNode->SetParent( this, false ); \
} else { \
if( NULL == aNode->GetParent() ) { \
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
std::cerr << " * [BUG] object '" << aNode->GetName(); \
std::cerr << "' has no parent\n"; \
std::cerr << " * [INFO] possible copy assignment or copy constructor bug\n"; \
return false; \
} \
aRefList.push_back( (aType*)aNode ); \
aNode->addNodeRef( this ); \
} \
return true; \
} } while( 0 )
// Function to find a node object given a (non-unique) node name
#define FIND_NODE( aType, aName, aNodeList, aCallingNode ) do { \
std::vector< aType* >::iterator sLA = aNodeList.begin(); \
std::vector< aType* >::iterator eLA = aNodeList.end(); \
SGNODE* psg = NULL; \
while( sLA != eLA ) { \
if( (SGNODE*)*sLA != aCallingNode ) { \
psg = (SGNODE*) (*sLA)->FindNode( aName, this ); \
if( NULL != psg) \
return psg; \
} \
++sLA; \
} } while ( 0 )
namespace S3D
{
//
// VRML related functions
//
// formats a floating point number for text output to a VRML file
void FormatFloat( std::string& result, double value );
// format orientation data for VRML output
void FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation );
// format point data for VRML output
void FormatPoint( std::string& result, const SGPOINT& point );
// format vector data for VRML output
void FormatVector( std::string& result, const SGVECTOR& aVector );
// format Color data for VRML output
void FormatColor( std::string& result, const SGCOLOR& aColor );
//
// Cache related WRITE functions
//
// write out an XYZ vertex
bool WritePoint( std::ofstream& aFile, const SGPOINT& aPoint );
// write out a unit vector
bool WriteVector( std::ofstream& aFile, const SGVECTOR& aVector );
// write out an RGB color
bool WriteColor( std::ofstream& aFile, const SGCOLOR& aColor );
//
// Cache related READ functions
//
/**
* Function ReadTag
* reads the text tag of a binary cache file which is the
* NodeTag and unique ID number combined
*
* @param aFile is a binary file open for reading
* @param aName will hold the tag name on successful return
* @return will be the NodeType which the tag represents or
* S3D::SGTYPES::SGTYPE_END on failure
*/
S3D::SGTYPES ReadTag( std::ifstream& aFile, std::string& aName );
// read an XYZ vertex
bool ReadPoint( std::ifstream& aFile, SGPOINT& aPoint );
// read a unit vector
bool ReadVector( std::ifstream& aFile, SGVECTOR& aVector );
// read an RGB color
bool ReadColor( std::ifstream& aFile, SGCOLOR& aColor );
};
#endif // SG_HELPERS_H

View File

@ -0,0 +1,342 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <fstream>
#include <3d_cache/sg/sg_index.h>
SGINDEX::SGINDEX( SGNODE* aParent ) : SGNODE( aParent )
{
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SGINDEX (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
return;
}
SGINDEX::~SGINDEX()
{
index.clear();
return;
}
bool SGINDEX::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGINDEX and derived types
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGINDEX::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return NULL;
}
void SGINDEX::unlinkChildNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
void SGINDEX::unlinkRefNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
bool SGINDEX::AddRefNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGINDEX::AddChildNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGINDEX::GetIndices( size_t& nIndices, int*& aIndexList )
{
if( index.empty() )
{
nIndices = 0;
aIndexList = NULL;
return false;
}
nIndices = index.size();
aIndexList = & index[0];
return true;
}
void SGINDEX::SetIndices( size_t nIndices, int* aIndexList )
{
index.clear();
if( 0 == nIndices || NULL == aIndexList )
return;
for( size_t i = 0; i < nIndices; ++i )
index.push_back( aIndexList[i] );
return;
}
void SGINDEX::AddIndex( int aIndex )
{
index.push_back( aIndex );
return;
}
void SGINDEX::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGINDEX::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( index.empty() )
return false;
if( S3D::SGTYPE_COORDINDEX == m_SGtype )
return writeCoordIndex( aFile );
return writeColorIndex( aFile );
}
bool SGINDEX::writeCoordIndex( std::ofstream& aFile )
{
size_t n = index.size();
if( n % 3 )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] coord index is not divisible by three (violates triangle constraint)\n";
return false;
}
aFile << " coordIndex [\n ";
// indices to control formatting
int nv0 = 0;
int nv1 = 0;
for( size_t i = 0; i < n; )
{
aFile << index[i];
++i;
if( ++nv0 == 3 )
{
aFile << ",-1";
++nv1;
nv0 = 0;
}
if( i < n )
{
aFile << ",";
if( nv1 == 8 )
{
nv1 = 0;
aFile << "\n ";
}
}
}
aFile << "]\n";
return true;
}
bool SGINDEX::writeColorIndex( std::ofstream& aFile )
{
aFile << " colorIndex [\n ";
return writeIndexList( aFile );
}
bool SGINDEX::writeIndexList( std::ofstream& aFile )
{
// index to control formatting
int nv = 0;
size_t n = index.size();
for( size_t i = 0; i < n; )
{
aFile << index[i];
++i;
if( i < n )
{
aFile << ",";
if( ++nv == 20 )
{
aFile << "\n ";
nv = 0;
}
}
}
aFile << "]\n";
return true;
}
bool SGINDEX::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode )
{
if( NULL == m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; m_aParent is NULL\n";
return false;
}
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( !aFile.good() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
size_t npts = index.size();
aFile.write( (char*)&npts, sizeof(size_t) );
for( size_t i = 0; i < npts; ++i )
aFile.write( (char*)&index[i], sizeof(int) );
if( aFile.fail() )
return false;
return true;
}
bool SGINDEX::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
if( !index.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] non-empty node\n";
return false;
}
size_t npts;
aFile.read( (char*)&npts, sizeof(size_t) );
int tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < npts; ++i )
{
aFile.read( (char*)&tmp, sizeof(int) );
if( aFile.fail() )
return false;
index.push_back( tmp );
}
return true;
}

View File

@ -0,0 +1,98 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_index.h
* defines a generic Index interface for a scenegraph object
*/
#ifndef SG_INDEX_H
#define SG_INDEX_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
class SGINDEX : public SGNODE
{
protected:
bool writeCoordIndex( std::ofstream& aFile );
bool writeColorIndex( std::ofstream& aFile );
bool writeIndexList( std::ofstream& aFile );
public:
// for internal SG consumption only
std::vector< int > index;
void unlinkChildNode( const SGNODE* aCaller );
void unlinkRefNode( const SGNODE* aCaller );
public:
SGINDEX( SGNODE* aParent );
virtual ~SGINDEX();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
/**
* Function GetIndices
* retrieves the number of indices and a pointer to
* the list. Note: the returned pointer may be invalidated
* by future operations on the SGNODE; the caller must make
* immediate use of the data and must not rely on the pointer's
* validity in the future.
*
* @param nIndices [out] will hold the number of indices in the list
* @param aIndexList [out] will store a pointer to the data
* @return true if there was available data (nIndices > 0) otherwise false
*/
bool GetIndices( size_t& nIndices, int*& aIndexList );
/**
* Function SetIndices
* sets the number of indices and creates a copy of the given index data.
*
* @param nIndices [in] the number of indices to be stored
* @param aIndexList [in] the index data
*/
void SetIndices( size_t nIndices, int* aIndexList );
/**
* Function AddIndex
* adds a single index to the list
*
* @param nIndices [in] the number of indices to be stored
* @param aIndexList [in] the index data
*/
void AddIndex( int aIndex );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
};
#endif // SG_INDEX_H

View File

@ -0,0 +1,367 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <sstream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <3d_cache/sg/sg_node.h>
#include <3d_rendering/c3dmodel.h>
static const std::string node_names[S3D::SGTYPE_END + 1] = {
"TXFM",
"APP",
"COL",
"COLIDX",
"FACE",
"COORD",
"COORDIDX",
"NORM",
"SHAPE",
"INVALID"
};
static unsigned int node_counts[S3D::SGTYPE_END] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
char const* S3D::GetNodeTypeName( S3D::SGTYPES aType )
{
return node_names[aType].c_str();
}
static void getNodeName( S3D::SGTYPES nodeType, std::string& aName )
{
if( nodeType < 0 || nodeType >= S3D::SGTYPE_END )
{
aName = node_names[S3D::SGTYPE_END];
return;
}
unsigned int seqNum = node_counts[nodeType];
++node_counts[nodeType];
std::ostringstream ostr;
ostr << node_names[nodeType] << "_" << seqNum;
aName = ostr.str();
return;
}
SGNODE::SGNODE( SGNODE* aParent )
{
m_Parent = aParent;
m_Association = NULL;
m_written = false;
m_SGtype = S3D::SGTYPE_END;
return;
}
SGNODE::~SGNODE()
{
if( m_Parent )
m_Parent->unlinkChildNode( this );
if( m_Association )
*m_Association = NULL;
std::list< SGNODE* >::iterator sBP = m_BackPointers.begin();
std::list< SGNODE* >::iterator eBP = m_BackPointers.end();
while( sBP != eBP )
{
(*sBP)->unlinkRefNode( this );
++sBP;
}
return;
}
S3D::SGTYPES SGNODE::GetNodeType( void ) const
{
return m_SGtype;
}
SGNODE* SGNODE::GetParent( void ) const
{
return m_Parent;
}
const char* SGNODE::GetName( void )
{
if( m_Name.empty() )
getNodeName( m_SGtype, m_Name );
return m_Name.c_str();
}
void SGNODE::SetName( const char *aName )
{
if( NULL == aName || 0 == aName[0] )
getNodeName( m_SGtype, m_Name );
else
m_Name = aName;
return;
}
const char * SGNODE::GetNodeTypeName( S3D::SGTYPES aNodeType ) const
{
return node_names[aNodeType].c_str();
}
void SGNODE::addNodeRef( SGNODE* aNode )
{
std::list< SGNODE* >::iterator np =
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
if( np != m_BackPointers.end() )
return;
m_BackPointers.push_back( aNode );
return;
}
void SGNODE::delNodeRef( SGNODE* aNode )
{
std::list< SGNODE* >::iterator np =
std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
if( np != m_BackPointers.end() )
{
m_BackPointers.erase( np );
return;
}
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] delNodeRef() did not find its target\n";
return;
}
void SGNODE::AssociateWrapper( SGNODE** aWrapperRef )
{
if( NULL == aWrapperRef )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL handle\n";
return;
}
if( *aWrapperRef != this )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] handle value does not match this object's pointer\n";
return;
}
// if there is an existing association then break it and emit a warning
// just in case the behavior is undesired
if( m_Association )
{
*m_Association = NULL;
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [WARNING] association being broken with previous wrapper\n";
}
m_Association = aWrapperRef;
return;
}
void SGNODE::DisassociateWrapper( SGNODE** aWrapperRef )
{
if( !m_Association )
return;
if( !aWrapperRef )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] invalid handle value aWrapperRef\n";
return;
}
if( *aWrapperRef != *m_Association || aWrapperRef != m_Association )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] *aWrapperRef (" << *aWrapperRef;
std::cerr << ") does not match *m_Association (" << *m_Association << ") in type ";
std::cerr << node_names[ m_SGtype] << "\n";
std::cerr << " * [INFO] OR aWrapperRef(" << aWrapperRef << ") != m_Association(";
std::cerr << m_Association << ")\n";
std::cerr << " * [INFO] node name: " << GetName() << "\n";
return;
}
m_Association = NULL;
return;
}
void SGNODE::ResetNodeIndex( void )
{
for( int i = 0; i < (int)S3D::SGTYPE_END; ++i )
node_counts[i] = 1;
return;
}
bool S3D::GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex )
{
aIndex = 0;
if( NULL == aNode || S3D::SGTYPE_APPEARANCE != aNode->GetNodeType() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
if( NULL == aNode )
{
std::cerr << " * [BUG] aNode is NULL\n";
}
else
{
std::cerr << " * [BUG] invalid node type (" << aNode->GetNodeType();
std::cerr << "), expected " << S3D::SGTYPE_APPEARANCE << "\n";
}
return false;
}
SGAPPEARANCE* node = (SGAPPEARANCE*)aNode;
std::map< SGAPPEARANCE const*, int >::iterator it = aList.matmap.find( node );
if( it != aList.matmap.end() )
{
aIndex = it->second;
return true;
}
int idx = (int)aList.matorder.size();
aList.matorder.push_back( node );
aList.matmap.insert( std::pair< SGAPPEARANCE const*, int >( node, idx ) );
aIndex = idx;
return true;
}
void S3D::INIT_SMATERIAL( SMATERIAL& aMaterial )
{
memset( &aMaterial, 0, sizeof( aMaterial ) );
return;
}
void S3D::INIT_SMESH( SMESH& aMesh )
{
memset( &aMesh, 0, sizeof( aMesh ) );
return;
}
void S3D::INIT_S3DMODEL( S3DMODEL& aModel )
{
memset( &aModel, 0, sizeof( aModel ) );
return;
}
void S3D::FREE_SMESH( SMESH& aMesh)
{
if( NULL != aMesh.m_Positions )
{
delete [] aMesh.m_Positions;
aMesh.m_Positions = NULL;
}
if( NULL != aMesh.m_Normals )
{
delete [] aMesh.m_Normals;
aMesh.m_Normals = NULL;
}
if( NULL != aMesh.m_Texcoords )
{
delete [] aMesh.m_Texcoords;
aMesh.m_Texcoords = NULL;
}
if( NULL != aMesh.m_Color )
{
delete [] aMesh.m_Color;
aMesh.m_Color = NULL;
}
if( NULL != aMesh.m_FaceIdx )
{
delete [] aMesh.m_FaceIdx;
aMesh.m_FaceIdx = NULL;
}
aMesh.m_VertexSize = 0;
aMesh.m_FaceIdxSize = 0;
aMesh.m_MaterialIdx = 0;
return;
}
void S3D::FREE_S3DMODEL( S3DMODEL& aModel )
{
if( NULL != aModel.m_Materials )
{
delete [] aModel.m_Materials;
aModel.m_Materials = NULL;
}
aModel.m_MaterialsSize = 0;
if( NULL != aModel.m_Meshes )
{
for( unsigned int i = 0; i < aModel.m_MeshesSize; ++i )
FREE_SMESH( aModel.m_Meshes[i] );
delete [] aModel.m_Meshes;
aModel.m_Meshes = NULL;
}
aModel.m_MeshesSize = 0;
return;
}

View File

@ -0,0 +1,229 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_node.h
* defines the base class of the intermediate scene graph NODE
*/
#ifndef SG_NODE_H
#define SG_NODE_H
#include <fstream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <glm/glm.hpp>
#include <3d_rendering/c3dmodel.h>
#include <3d_cache/sg/sg_base.h>
#include <3d_cache/sg/sg_types.h>
class SGNODE;
class SGAPPEARANCE;
namespace S3D
{
/**
* Function GetNodeTypeName
* returns the name of the given type of node
*/
char const* GetNodeTypeName( S3D::SGTYPES aType );
struct MATLIST
{
std::vector< SGAPPEARANCE const* > matorder; // materials in order of addition
std::map< SGAPPEARANCE const*, int > matmap; // mapping from material to index
};
bool GetMatIndex( MATLIST& aList, SGNODE* aNode, int& aIndex );
void INIT_SMATERIAL( SMATERIAL& aMaterial );
void INIT_SMESH( SMESH& aMesh );
void INIT_S3DMODEL( S3DMODEL& aModel );
void FREE_SMESH( SMESH& aMesh);
void FREE_S3DMODEL( S3DMODEL& aModel );
};
/**
* Class SGNODE
* represents the base class of all Scene Graph nodes
*/
class SGNODE
{
private:
std::list< SGNODE* > m_BackPointers; // nodes which hold a reference to this
SGNODE** m_Association; // handle to the instance held by a wrapper
protected:
SGNODE* m_Parent; // pointer to parent node; may be NULL for top level transform
S3D::SGTYPES m_SGtype; // type of SG node
std::string m_Name; // name to use for referencing the entity by name
bool m_written; // set true when the object has been written after a ReNameNodes()
public:
/**
* 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 SGNODE* aNode ) = 0;
/**
* 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 SGNODE* aNode ) = 0;
/**
* 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( SGNODE* 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( SGNODE* aNode );
public:
SGNODE( SGNODE* aParent );
virtual ~SGNODE();
/**
* Function GetNodeType
* returns the type of this node instance
*/
S3D::SGTYPES 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)
*/
SGNODE* GetParent( void ) const;
/**
* Function SetParent
* sets the parent SGNODE of this object.
*
* @param aParent [in] is the desired parent node
* @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( SGNODE* aParent, bool notify = true ) = 0;
const char* GetName( void );
void SetName(const char *aName);
const char * GetNodeTypeName( S3D::SGTYPES aNodeType ) const;
/**
* Function FindNode searches the tree of linked nodes and returns a
* reference to the first node found 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
* @param aCaller is a pointer to the node invoking this function
* @return is a valid node pointer on success, otherwise NULL
*/
virtual SGNODE* FindNode( const char *aNodeName, const SGNODE *aCaller ) = 0;
virtual bool AddRefNode( SGNODE* aNode ) = 0;
virtual bool AddChildNode( SGNODE* aNode ) = 0;
/**
* Function AssociateWrapper
* associates this object with a handle to itself; this handle
* is typically held by an IFSG* wrapper and the pointer which
* it refers to is set to NULL upon destruction of this object.
* This mechanism provides a scheme by which a wrapper can be
* notified of the destruction of the object which it wraps.
*/
void AssociateWrapper( SGNODE** aWrapperRef );
/**
* Function DisassociateWrapper
* removes the association between an IFSG* wrapper
* object and this object.
*/
void DisassociateWrapper( SGNODE** aWrapperRef );
/**
* Function ResetNodeIndex
* resets the global SG* node indices in preparation for
* Write() operations
*/
void ResetNodeIndex( void );
/**
* Function ReNameNodes
* renames a node and all its child nodes in preparation for
* Write() operations
*/
virtual void ReNameNodes( void ) = 0;
/**
* Function WriteVRML
* writes this node's data to a VRML file; this includes
* all data of child and referenced nodes.
*/
virtual bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) = 0;
/**
* Function WriteCache
* write's this node's data to a binary cache file; the data
* includes all data of children and references to children.
* If this function is invoked by the user, parentNode must be
* set to NULL in order to ensure coherent data.
*/
virtual bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) = 0;
/**
* Function ReadCache
* Reads binary format data from a cache file. To read a cache file,
* open the file for reading and invoke this function from a new
* SCENEGRAPH node.
*/
virtual bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) = 0;
};
#endif // SG_NODE_H

View File

@ -0,0 +1,314 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <3d_cache/sg/sg_normals.h>
#include <3d_cache/sg/sg_helpers.h>
SGNORMALS::SGNORMALS( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_NORMALS;
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SGNORMALS (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
else if( NULL != aParent && S3D::SGTYPE_FACESET == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGNORMALS::~SGNORMALS()
{
norms.clear();
return;
}
bool SGNORMALS::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a SGFACESET may be parent to a SGNORMALS
if( NULL != aParent && S3D::SGTYPE_FACESET != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGNORMALS::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
return NULL;
}
void SGNORMALS::unlinkChildNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
void SGNORMALS::unlinkRefNode( const SGNODE* aCaller )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unexpected code branch; node should have no children or refs\n";
return;
}
bool SGNORMALS::AddRefNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGNORMALS::AddChildNode( SGNODE* aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] this node does not accept children or refs\n";
return false;
}
bool SGNORMALS::GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList )
{
if( norms.empty() )
{
aListSize = 0;
aNormalList = NULL;
return false;
}
aListSize = norms.size();
aNormalList = &norms[0];
return true;
}
void SGNORMALS::SetNormalList( size_t aListSize, const SGVECTOR* aNormalList )
{
norms.clear();
if( 0 == aListSize || NULL == aNormalList )
return;
for( int i = 0; i < aListSize; ++i )
norms.push_back( aNormalList[i] );
return;
}
void SGNORMALS::AddNormal( double aXValue, double aYValue, double aZValue )
{
norms.push_back( SGVECTOR( aXValue, aYValue, aZValue ) );
return;
}
void SGNORMALS::AddNormal( const SGVECTOR& aNormal )
{
norms.push_back( aNormal );
return;
}
void SGNORMALS::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
}
bool SGNORMALS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( norms.empty() )
return false;
if( aReuseFlag )
{
if( !m_written )
{
aFile << " normal DEF " << GetName() << " Normal { vector [\n ";
m_written = true;
}
else
{
aFile << " normal USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " normal Normal { vector [\n ";
}
std::string tmp;
size_t n = norms.size();
bool nline = false;
for( size_t i = 0; i < n; )
{
S3D::FormatVector( tmp, norms[i] );
aFile << tmp ;
++i;
if( i < n )
{
aFile << ",";
if( nline )
{
aFile << "\n ";
nline = false;
}
else
{
nline = true;
}
}
}
aFile << "] }\n";
return true;
}
bool SGNORMALS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode )
{
if( NULL == m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; m_aParent is NULL\n";
return false;
}
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( !aFile.good() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
size_t npts = norms.size();
aFile.write( (char*)&npts, sizeof(size_t) );
for( size_t i = 0; i < npts; ++i )
S3D::WriteVector( aFile, norms[i] );
if( aFile.fail() )
return false;
return true;
}
bool SGNORMALS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
if( !norms.empty() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] non-empty node\n";
return false;
}
size_t npts;
aFile.read( (char*)&npts, sizeof(size_t) );
SGVECTOR tmp;
if( aFile.fail() )
return false;
for( size_t i = 0; i < npts; ++i )
{
if( !S3D::ReadVector( aFile, tmp ) || aFile.fail() )
return false;
norms.push_back( tmp );
}
return true;
}

View File

@ -0,0 +1,65 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_normals.h
* defines a set of vertex normals for a scene graph object
*/
#ifndef SG_NORMALS_H
#define SG_NORMALS_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
class SGNORMALS : public SGNODE
{
public:
std::vector< SGVECTOR > norms;
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
public:
SGNORMALS( SGNODE* aParent );
virtual ~SGNORMALS();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
bool GetNormalList( size_t& aListSize, SGVECTOR*& aNormalList );
void SetNormalList( size_t aListSize, const SGVECTOR* aNormalList );
void AddNormal( double aXValue, double aYValue, double aZValue );
void AddNormal( const SGVECTOR& aNormal );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
};
#endif // SG_NORMALS_H

View File

@ -0,0 +1,748 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 <fstream>
#include <3d_cache/sg/sg_shape.h>
#include <3d_cache/sg/sg_faceset.h>
#include <3d_cache/sg/sg_appearance.h>
#include <3d_cache/sg/sg_helpers.h>
#include <3d_cache/sg/sg_coordindex.h>
#include <3d_cache/sg/sg_colorindex.h>
#include <3d_cache/sg/sg_coords.h>
#include <3d_cache/sg/sg_colors.h>
#include <3d_cache/sg/sg_normals.h>
SGSHAPE::SGSHAPE( SGNODE* aParent ) : SGNODE( aParent )
{
m_SGtype = S3D::SGTYPE_SHAPE;
m_Appearance = NULL;
m_RAppearance = NULL;
m_FaceSet = NULL;
m_RFaceSet = NULL;
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
{
m_Parent = NULL;
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] inappropriate parent to SGSHAPE (type ";
std::cerr << aParent->GetNodeType() << ")\n";
#endif
}
else if( NULL != aParent && S3D::SGTYPE_TRANSFORM == aParent->GetNodeType() )
{
m_Parent->AddChildNode( this );
}
return;
}
SGSHAPE::~SGSHAPE()
{
// drop references
if( m_RAppearance )
{
m_RAppearance->delNodeRef( this );
m_RAppearance = NULL;
}
if( m_RFaceSet )
{
m_RFaceSet->delNodeRef( this );
m_RFaceSet = NULL;
}
// delete objects
if( m_Appearance )
{
m_Appearance->SetParent( NULL, false );
delete m_Appearance;
m_Appearance = NULL;
}
if( m_FaceSet )
{
m_FaceSet->SetParent( NULL, false );
delete m_FaceSet;
m_FaceSet = NULL;
}
return;
}
bool SGSHAPE::SetParent( SGNODE* aParent, bool notify )
{
if( NULL != m_Parent )
{
if( aParent == m_Parent )
return true;
// handle the change in parents
if( notify )
m_Parent->unlinkChildNode( this );
m_Parent = NULL;
if( NULL == aParent )
return true;
}
// only a SGTRANSFORM may be parent to a SGSHAPE
if( NULL != aParent && S3D::SGTYPE_TRANSFORM != aParent->GetNodeType() )
return false;
m_Parent = aParent;
if( m_Parent )
m_Parent->AddChildNode( this );
return true;
}
SGNODE* SGSHAPE::FindNode(const char *aNodeName, const SGNODE *aCaller)
{
if( NULL == aNodeName || 0 == aNodeName[0] )
return NULL;
if( !m_Name.compare( aNodeName ) )
return this;
SGNODE* tmp = NULL;
if( NULL != m_Appearance )
{
tmp = m_Appearance->FindNode( aNodeName, this );
if( tmp )
{
return tmp;
}
}
if( NULL != m_FaceSet )
{
tmp = m_FaceSet->FindNode( aNodeName, this );
if( tmp )
{
return tmp;
}
}
// query the parent if appropriate
if( aCaller == m_Parent || NULL == m_Parent )
return NULL;
return m_Parent->FindNode( aNodeName, this );
}
void SGSHAPE::unlinkNode( const SGNODE* aNode, bool isChild )
{
if( NULL == aNode )
return;
if( isChild )
{
if( aNode == m_Appearance )
{
m_Appearance = NULL;
return;
}
if( aNode == m_FaceSet )
{
m_FaceSet = NULL;
return;
}
}
else
{
if( aNode == m_RAppearance )
{
m_RAppearance = NULL;
return;
}
if( aNode == m_RFaceSet )
{
m_RFaceSet = NULL;
}
}
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] unlinkNode() did not find its target\n";
return;
}
void SGSHAPE::unlinkChildNode( const SGNODE* aNode )
{
unlinkNode( aNode, true );
return;
}
void SGSHAPE::unlinkRefNode( const SGNODE* aNode )
{
unlinkNode( aNode, false );
return;
}
bool SGSHAPE::addNode( SGNODE* aNode, bool isChild )
{
if( NULL == aNode )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] NULL pointer passed for aNode\n";
return false;
}
if( S3D::SGTYPE_APPEARANCE == aNode->GetNodeType() )
{
if( m_Appearance || m_RAppearance )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] assigning multiple Appearance nodes\n";
return false;
}
if( isChild )
{
m_Appearance = (SGAPPEARANCE*)aNode;
m_Appearance->SetParent( this );
}
else
{
m_RAppearance = (SGAPPEARANCE*)aNode;
m_RAppearance->addNodeRef( this );
}
return true;
}
if( S3D::SGTYPE_FACESET == aNode->GetNodeType() )
{
if( m_FaceSet || m_RFaceSet )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] assigning multiple FaceSet nodes\n";
return false;
}
if( isChild )
{
m_FaceSet = (SGFACESET*)aNode;
m_FaceSet->SetParent( this );
}
else
{
m_RFaceSet = (SGFACESET*)aNode;
m_RFaceSet->addNodeRef( this );
}
return true;
}
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] object '" << aNode->GetName();
std::cerr << "' is not a valid type for this object (" << aNode->GetNodeType() << ")\n";
return false;
}
bool SGSHAPE::AddRefNode( SGNODE* aNode )
{
return addNode( aNode, false );
}
bool SGSHAPE::AddChildNode( SGNODE* aNode )
{
return addNode( aNode, true );
}
void SGSHAPE::ReNameNodes( void )
{
m_written = false;
// rename this node
m_Name.clear();
GetName();
// rename Appearance
if( m_Appearance )
m_Appearance->ReNameNodes();
// rename FaceSet
if( m_FaceSet )
m_FaceSet->ReNameNodes();
return;
}
bool SGSHAPE::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
{
if( !m_Appearance && !m_RAppearance
&& !m_FaceSet && !m_RFaceSet )
{
return false;
}
std::string tmp;
if( aReuseFlag )
{
if( !m_written )
{
aFile << "DEF " << GetName() << " Shape {\n";
m_written = true;
}
else
{
aFile << " USE " << GetName() << "\n";
return true;
}
}
else
{
aFile << " Shape {\n";
}
if( m_Appearance )
m_Appearance->WriteVRML( aFile, aReuseFlag );
if( m_RAppearance )
m_RAppearance->WriteVRML( aFile, aReuseFlag );
if( m_FaceSet )
m_FaceSet->WriteVRML( aFile, aReuseFlag );
if( m_RFaceSet )
m_RFaceSet->WriteVRML( aFile, aReuseFlag );
aFile << "}\n";
return true;
}
bool SGSHAPE::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
{
if( NULL == parentNode )
{
if( NULL == m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; m_aParent is NULL\n";
return false;
}
SGNODE* np = m_Parent;
while( NULL != np->GetParent() )
np = np->GetParent();
return np->WriteCache( aFile, NULL );
}
if( parentNode != m_Parent )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] corrupt data; parentNode != m_aParent\n";
return false;
}
if( !aFile.good() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad stream\n";
return false;
}
aFile << "[" << GetName() << "]";
#define NITEMS 4
bool items[NITEMS];
int i;
for( i = 0; i < NITEMS; ++i )
items[i] = 0;
i = 0;
if( NULL != m_Appearance )
items[i] = true;
++i;
if( NULL != m_RAppearance )
items[i] = true;
++i;
if( NULL != m_FaceSet )
items[i] = true;
++i;
if( NULL != m_RFaceSet )
items[i] = true;
for( int i = 0; i < NITEMS; ++i )
aFile.write( (char*)&items[i], sizeof(bool) );
if( items[0] )
m_Appearance->WriteCache( aFile, this );
if( items[1] )
aFile << "[" << m_RAppearance->GetName() << "]";
if( items[2] )
m_FaceSet->WriteCache( aFile, this );
if( items[3] )
aFile << "[" << m_RFaceSet->GetName() << "]";
if( aFile.fail() )
return false;
return true;
}
bool SGSHAPE::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
{
if( m_Appearance || m_RAppearance || m_FaceSet || m_RFaceSet )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [BUG] non-empty node\n";
return false;
}
#define NITEMS 4
bool items[NITEMS];
for( int i = 0; i < NITEMS; ++i )
aFile.read( (char*)&items[i], sizeof(bool) );
if( ( items[0] && items[1] ) || ( items[2] && items[3] ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; multiple item definitions at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
std::string name;
if( items[0] )
{
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad child apperance tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
m_Appearance = new SGAPPEARANCE( this );
m_Appearance->SetName( name.c_str() );
if( !m_Appearance->ReadCache( aFile, this ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data while reading appearance '";
std::cerr << name << "'\n";
return false;
}
}
if( items[1] )
{
if( S3D::SGTYPE_APPEARANCE != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad ref appearance tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: cannot find ref appearance '";
std::cerr << name << "'\n";
return false;
}
if( S3D::SGTYPE_APPEARANCE != np->GetNodeType() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: type is not SGAPPEARANCE '";
std::cerr << name << "'\n";
return false;
}
m_RAppearance = (SGAPPEARANCE*)np;
m_RAppearance->addNodeRef( this );
}
if( items[2] )
{
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad child face set tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
m_FaceSet = new SGFACESET( this );
m_FaceSet->SetName( name.c_str() );
if( !m_FaceSet->ReadCache( aFile, this ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data while reading face set '";
std::cerr << name << "'\n";
return false;
}
}
if( items[3] )
{
if( S3D::SGTYPE_FACESET != S3D::ReadTag( aFile, name ) )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data; bad ref face set tag at position ";
std::cerr << aFile.tellg() << "\n";
return false;
}
SGNODE* np = FindNode( name.c_str(), this );
if( !np )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: cannot find ref face set '";
std::cerr << name << "'\n";
return false;
}
if( S3D::SGTYPE_FACESET != np->GetNodeType() )
{
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] corrupt data: type is not SGFACESET '";
std::cerr << name << "'\n";
return false;
}
m_RFaceSet = (SGFACESET*)np;
m_RFaceSet->addNodeRef( this );
}
if( aFile.fail() )
return false;
return true;
}
bool SGSHAPE::Prepare( const glm::dmat4* aTransform,
S3D::MATLIST& materials, std::vector< SMESH >& meshes )
{
SMESH m;
S3D::INIT_SMESH( m );
SGAPPEARANCE* pa = m_Appearance;
SGFACESET* pf = m_FaceSet;
if( NULL == pa )
pa = m_RAppearance;
if( NULL == pf )
pf = m_RFaceSet;
// no face sets = nothing to render, which is valid though pointless
if( NULL == pf )
return true;
if( !pf->validate() )
{
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad model; inconsistent data\n";
#endif
return true;
}
if( NULL == m_Appearance )
{
m.m_MaterialIdx = 0;
}
else
{
int idx;
if( !S3D::GetMatIndex( materials, pa, idx ) )
{
m.m_MaterialIdx = 0;
}
else
{
m.m_MaterialIdx = idx;
}
}
SGCOLORS* pc = pf->m_Colors;
SGCOLORINDEX* cidx = pf->m_ColorIndices;
SGCOORDS* pv = pf->m_Coords;
SGCOORDINDEX* vidx = pf->m_CoordIndices;
SGNORMALS* pn = pf->m_Normals;
if( NULL == pc )
pc = pf->m_RColors;
if( NULL == pv )
pv = pf->m_RCoords;
if( NULL == pn )
pn = pf->m_RNormals;
// set the vertex points and indices
size_t nCoords = 0;
SGPOINT* pCoords = NULL;
pv->GetCoordsList( nCoords, pCoords );
// set the vertex indices
size_t nvidx = 0;
int* lv = NULL;
vidx->GetIndices( nvidx, lv );
// note: reduce the vertex set to include only the referenced vertices
std::vector< int > vertices; // store the list of temp vertex indices
std::map< int, unsigned int > indexmap; // map temp vertex to true vertex
std::map< int, unsigned int >::iterator mit;
for( unsigned int i = 0; i < nvidx; ++i )
{
mit = indexmap.find( lv[i] );
if( mit == indexmap.end() )
{
indexmap.insert( std::pair< int, unsigned int >( lv[i], vertices.size() ) );
vertices.push_back( lv[i] );
}
}
if( vertices.size() < 3 )
{
#ifdef DEBUG
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
std::cerr << " * [INFO] bad model; not enough vertices\n";
#endif
return true;
}
// construct the final vertex list
SFVEC3F* lCoords = new SFVEC3F[ vertices.size() ];
int ti, ii;
for( size_t i = 0; i < vertices.size(); ++i )
{
ti = vertices[i];
glm::dvec4 pt( pCoords[ti].x, pCoords[ti].y, pCoords[ti].z, 1.0 );
pt = (*aTransform) * pt;
lCoords[i] = SFVEC3F( pt.x, pt.y, pt.z );
}
m.m_VertexSize = (unsigned int) vertices.size();
m.m_Positions = lCoords;
unsigned int* lvidx = new unsigned int[ nvidx ];
for( unsigned int i = 0; i < nvidx; ++i )
{
mit = indexmap.find( lv[i] );
lvidx[i] = mit->second;
}
m.m_FaceIdxSize = (unsigned int )nvidx;
m.m_FaceIdx = lvidx;
// set the per-vertex normals
size_t nNorms = 0;
SGVECTOR* pNorms = NULL;
double x, y, z;
pn->GetNormalList( nNorms, pNorms );
SFVEC3F* lNorms = new SFVEC3F[ vertices.size() ];
for( size_t i = 0; i < vertices.size(); ++i )
{
ti = vertices[i];
pNorms[ti].GetVector( x, y, z );
glm::dvec4 pt( x, y, z, 0.0 );
pt = (*aTransform) * pt;
lNorms[i] = SFVEC3F( pt.x, pt.y, pt.z );
}
m.m_Normals = lNorms;
// use per-vertex colors if available
if( pc )
{
size_t ncidx = 0;
int* lcidx = NULL;
cidx->GetIndices( ncidx, lcidx );
// set the vertex colors
size_t nColors = 0;
SGCOLOR* pColors = NULL;
pc->GetColorList( nColors, pColors );
SFVEC3F* lColors = new SFVEC3F[ vertices.size() ];
double red, green, blue;
for( size_t i = 0; i < vertices.size(); ++i )
{
ti = vertices[i];
pColors[ lcidx[ti] ].GetColor( lColors[i].x, lColors[i].y, lColors[i].z );
}
m.m_Color = lColors;
}
meshes.push_back( m );
return true;
}

View File

@ -0,0 +1,85 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 sg_shape.h
* defines a complex 3D shape for a scenegraph object
*/
#ifndef SG_SHAPE_H
#define SG_SHAPE_H
#include <vector>
#include <3d_cache/sg/sg_node.h>
class SGAPPEARANCE;
class SGFACESET;
class SGSHAPE : public SGNODE
{
private:
void unlinkNode( const SGNODE* aNode, bool isChild );
bool addNode( SGNODE* aNode, bool isChild );
public:
// owned node
SGAPPEARANCE* m_Appearance;
SGFACESET* m_FaceSet;
// referenced nodes
SGAPPEARANCE* m_RAppearance;
SGFACESET* m_RFaceSet;
void unlinkChildNode( const SGNODE* aNode );
void unlinkRefNode( const SGNODE* aNode );
public:
SGSHAPE( SGNODE* aParent );
virtual ~SGSHAPE();
virtual bool SetParent( SGNODE* aParent, bool notify = true );
SGNODE* FindNode(const char *aNodeName, const SGNODE *aCaller);
bool AddRefNode( SGNODE* aNode );
bool AddChildNode( SGNODE* aNode );
void ReNameNodes( void );
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
bool Prepare( const glm::dmat4* aTransform,
S3D::MATLIST& materials, std::vector< SMESH >& meshes );
};
/*
p.107
Shape {
appearance NULL
geometry NULL
}
*/
#endif // SG_SHAPE_H

View File

@ -0,0 +1,22 @@
#ifndef SG_TYPES_H
#define SG_TYPES_H
namespace S3D
{
enum SGTYPES
{
SGTYPE_TRANSFORM = 0,
SGTYPE_APPEARANCE,
SGTYPE_COLORS,
SGTYPE_COLORINDEX,
SGTYPE_FACESET,
SGTYPE_COORDS,
SGTYPE_COORDINDEX,
SGTYPE_NORMALS,
SGTYPE_SHAPE,
SGTYPE_END
};
};
#endif // SG_TYPES_H

View File

@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 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 str_rsort.h
* provides a wxString sorting functino which works from the
* end of the string towards the beginning
*/
#ifndef STR_RSORT_H
#define STR_RSORT_H
#include <wx/string.h>
namespace S3D
{
struct rsort_wxString
{
bool operator() (const wxString& strA, const wxString& strB ) const
{
// sort a wxString using the reverse character order; for 3d model
// filenames this will typically be a much faster operation than
// a normal alphabetic sort
wxString::const_reverse_iterator sA = strA.rbegin();
wxString::const_reverse_iterator eA = strA.rend();
wxString::const_reverse_iterator sB = strB.rbegin();
wxString::const_reverse_iterator eB = strB.rend();
if( strA.empty() )
{
if( strB.empty() )
return false;
// note: this rule implies that a null string is first in the sort order
return true;
}
if( strB.empty() )
return false;
while( sA != eA && sB != eB )
{
if( (*sA) == (*sB) )
{
++sA;
++sB;
continue;
}
if( (*sA) < (*sB) )
return true;
else
return false;
}
if( sB == eB )
return false;
return true;
}
};
}; // end NAMESPACE
#endif // STR_RSORT_H

View File

@ -0,0 +1,63 @@
#include <iostream>
#include <fstream>
#include <cstdio>
#include <iomanip>
#include <stdint.h>
#include "md5.h"
using namespace std;
int main( int argc, char** argv )
{
if( argc != 2 )
{
cerr << "No filename given\n";
return 0;
}
FILE* fp = fopen( argv[1], "rb" );
if( !fp )
{
cout << "Could not open file '" << argv[1] << "'\n";
return 0;
}
struct md5_ctx msum;
md5_init_ctx( &msum );
unsigned char rb[16];
int res = md5_stream( fp, rb );
cout << "Result: " << res << "\n";
cout << "md5sum:\n";
for( int i = 0; i < 16; ++i )
{
cout << setfill( '0' ) << setw(2) << nouppercase << hex << ((int)rb[i] & 0xff);
}
cout << "\n";
fclose( fp );
/*
ifstream afile;
afile.open( argv[1], ios::in | ios::binary | ios::ate );
streampos fsize;
if( !afile.is_open() )
{
cout << "Could not open file '" << argv[1] << "'\n";
return 0;
}
fsize = afile.tellg();
afile.seekg( 0, ios::beg );
afile.close();
*/
return 0;
}

View File

@ -45,7 +45,7 @@
#include <3d_struct.h>
#include <modelparsers.h>
#include <class_module.h>
#include <CBBox.h>
#include "3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
class BOARD_DESIGN_SETTINGS;
class EDA_3D_FRAME;

View File

@ -0,0 +1,376 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 cinfo3d_visu.h
* @brief Handles data related with the board to be visualized
*/
#ifndef CINFO3D_VISU_H
#define CINFO3D_VISU_H
#include <vector>
#include "../3d_rendering/3d_render_raytracing/accelerators/ccontainer2d.h"
#include "../3d_rendering/3d_render_raytracing/accelerators/ccontainer.h"
#include "../3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
#include "../3d_rendering/ccamera.h"
#include "../3d_rendering/ctrack_ball.h"
#include <layers_id_colors_and_visibility.h>
#include <class_pad.h>
#include <class_track.h>
#include <wx/gdicmn.h>
#include <wxBasePcbFrame.h>
#include <clipper.hpp>
#include <class_pcb_text.h>
#include <class_drawsegment.h>
#include <class_zone.h>
/**
* Flags used in rendering options
*/
enum DISPLAY3D_FLG {
FL_AXIS=0, FL_MODULE, FL_ZONE,
FL_ADHESIVE, FL_SILKSCREEN, FL_SOLDERMASK, FL_SOLDERPASTE,
FL_COMMENTS, FL_ECO,
FL_USE_COPPER_THICKNESS,
FL_SHOW_BOARD_BODY,
FL_USE_REALISTIC_MODE,
FL_RENDER_SHADOWS,
FL_RENDER_SHOW_HOLES_IN_ZONES,
FL_RENDER_TEXTURES,
FL_RENDER_SMOOTH_NORMALS,
FL_RENDER_USE_MODEL_NORMALS,
FL_RENDER_MATERIAL,
FL_RENDER_SHOW_MODEL_BBOX,
FL_LAST
};
/**
* Camera types
*/
enum CAMERA_TYPE
{
CAMERA_TRACKBALL
};
/**
* Grid types
*/
enum GRID3D_TYPE
{
GRID3D_NONE,
GRID3D_1MM,
GRID3D_2P5MM,
GRID3D_5MM,
GRID3D_10MM
};
/// A type that stores a container of 2d objects for each layer id
typedef std::map< LAYER_ID, CBVHCONTAINER2D *> MAP_CONTAINER_2D;
/// This defines the range that all coord will have to be rendered.
/// It will use this value to convert to a normalized value between
/// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
#define RANGE_SCALE_3D 8.0f
/**
* Class CINFO3D_VISU
* Helper class to handle information needed to display 3D board
*/
class CINFO3D_VISU
{
public:
CINFO3D_VISU();
~CINFO3D_VISU();
/**
* @brief GetFlag - get a configuration status of a flag
* @param aFlag: the flag to get the status
* @return true if flag is set, false if not
*/
bool GetFlag( DISPLAY3D_FLG aFlag ) const ;
/**
* @brief SetFlag - set the status of a flag
* @param aFlag: the flag to get the status
* @param aState: status to set
*/
void SetFlag( DISPLAY3D_FLG aFlag, bool aState );
/**
* @brief Is3DLayerEnabled - Check if a layer is enabled
* @param aLayer: layer ID to get status
* @return true if layer should be displayed, false if not
*/
bool Is3DLayerEnabled( LAYER_ID aLayer ) const;
/**
* @brief SetBoard - Set current board to be rendered
* @param aBoard: board to process
*/
void SetBoard( BOARD *aBoard ) { m_board = aBoard; }
/**
* @brief GetBoard - Get current board to be rendered
* @return BOARD pointer
*/
const BOARD *GetBoard() const { return m_board; }
/**
* @brief InitSettings - Function to be called by the render when it need to
* reload the settings for the board.
*/
void InitSettings();
/**
* Function BiuTo3Dunits
* @return the conversion factor to transform a position from the board to 3d units
*/
double BiuTo3Dunits() const { return m_biuTo3Dunits; }
/**
* @brief GetBBox3DU - Get the bbox of the pcb board
* @return
*/
const CBBOX &GetBBox3DU() const { return m_boardBoudingBox; }
/**
* @brief GetEpoxyThickness3DU - Get the current epoxy thickness
* @return thickness in 3d unities
*/
float GetEpoxyThickness3DU() const { return m_epoxyThickness; }
/**
* @brief GetNonCopperLayerThickness3DU - Get the current non copper layers thickness
* @return thickness in 3d unities of non copperlayers
*/
float GetNonCopperLayerThickness3DU() const { return m_nonCopperLayerThickness; }
/**
* @brief GetCopperThickness3DU - Get the current copper layer thickness
* @return thickness in 3d unities of copperlayers
*/
float GetCopperThickness3DU() const { return m_copperThickness; }
/**
* @brief GetCopperThicknessBIU - Get the current copper layer thickness
* @return thickness in board unities
*/
int GetCopperThicknessBIU() const;
/**
* @brief GetBoardSize3DU - Get the board size
* @return size in 3D unities
*/
wxSize GetBoardSize3DU() const { return m_boardSize; }
/**
* Function GetBoardCenter
* @return board center in 3d units
*/
SFVEC3F &GetBoardCenter3DU() { return m_boardCenter; }
/**
* @param aIsFlipped: true for use in modules on Front (top) layer, false
* if module is on back (bottom) layer
* @return the Z position of 3D shapes, in 3D Units
*/
float GetModulesZcoord3DIU( bool aIsFlipped ) const ;
/**
* @param aCameraType: camera type to use in this canvas
*/
void CameraSetType( CAMERA_TYPE aCameraType );
/**
* @brief CameraGet - get current camera in use
* @return a camera
*/
CCAMERA &CameraGet() const { return m_currentCamera; }
/**
* Function GridGet
* @return space type of the grid
*/
GRID3D_TYPE GridGet() const { return m_3D_Grid_type; }
/**
* Function GridSet
* @param aGridType = the type space of the grid
*/
void GridSet( GRID3D_TYPE aGridType ) { m_3D_Grid_type = aGridType; }
/**
* @brief GetBoardPoly - Get the current polygon of the epoxy board
* @return the shape polygon
*/
const SHAPE_POLY_SET &GetBoardPoly() const { return m_boardPoly; }
/**
* @brief GetLayerColor - get the technical color of a layer
* @param aLayerId: the layer to get the color information
* @return the color in SFVEC3F format
*/
SFVEC3F GetLayerColor( LAYER_ID aLayerId ) const;
/**
* @brief GetItemColor - get the technical color of a layer
* @param aItemId: the item id to get the color information
* @return the color in SFVEC3F format
*/
SFVEC3F GetItemColor( int aItemId ) const;
/**
* @brief GetLayerTopZpos3DU - Get the top z position
* @param aLayerId: layer id
* @return position in 3D unities
*/
float GetLayerTopZpos3DU( LAYER_ID aLayerId ) const { return m_layerZcoordTop[aLayerId]; }
/**
* @brief GetLayerBottomZpos3DU - Get the bottom z position
* @param aLayerId: layer id
* @return position in 3D unities
*/
float GetLayerBottomZpos3DU( LAYER_ID aLayerId ) const { return m_layerZcoordBottom[aLayerId]; }
/**
* @brief GetMapLayers - Get the map of container that have the objects per layer
* @return the map containers of this board
*/
const MAP_CONTAINER_2D &GetMapLayers() const { return m_layers_container2D; }
/**
* @brief GetMapLayersHoles -Get the map of container that have the holes per layer
* @return the map containers of holes from this board
*/
const MAP_CONTAINER_2D &GetMapLayersHoles() const { return m_layers_holes2D; }
/**
* @brief GetThroughHole_Inflated - Get the inflated ThroughHole container
* @return a container with holes
*/
const CBVHCONTAINER2D &GetThroughHole_Inflated() const { return m_throughHoles_inflated; }
/**
* @brief GetThroughHole - Get the ThroughHole container
* @return a container with holes
*/
const CBVHCONTAINER2D &GetThroughHole() const { return m_throughHoles; }
unsigned int GetStats_Nr_Vias() const { return m_stats_nr_vias; }
unsigned int GetStats_Nr_Holes() const { return m_stats_nr_holes; }
float GetStats_Med_Via_Hole_Diameter3DU() const { return m_stats_via_med_hole_diameter; }
float GetStats_Med_Hole_Diameter3DU() const { return m_stats_hole_med_diameter; }
float GetStats_Med_Track_Width() const { return m_stats_track_med_width; }
private:
void createBoardPolygon();
void createLayers();
void destroyLayers();
// Helper functions to create the board
COBJECT2D *createNewTrack( const TRACK* aTrack , int aClearanceValue ) const;
void createNewPad(const D_PAD* aPad, CGENERICCONTAINER2D *aDstContainer, const wxSize &aInflateValue ) const;
void createNewPadWithClearance( const D_PAD* aPad, CGENERICCONTAINER2D *aDstContainer, int aClearanceValue ) const;
COBJECT2D *createNewPadDrill(const D_PAD* aPad, int aInflateValue);
void AddPadsShapesWithClearanceToContainer( const MODULE* aModule, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aInflateValue, bool aSkipNPTHPadsWihNoCopper );
void AddGraphicsShapesWithClearanceToContainer( const MODULE* aModule, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aInflateValue );
void AddShapeWithClearanceToContainer( const TEXTE_PCB* aTextPCB, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aClearanceValue );
void AddShapeWithClearanceToContainer(const DRAWSEGMENT* aDrawSegment, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId, int aClearanceValue );
void AddSolidAreasShapesToContainer( const ZONE_CONTAINER* aZoneContainer, CGENERICCONTAINER2D *aDstContainer, LAYER_ID aLayerId );
void TransformArcToSegments(const wxPoint &aCentre, const wxPoint &aStart, double aArcAngle, int aCircleToSegmentsCount, int aWidth, CGENERICCONTAINER2D *aDstContainer , const BOARD_ITEM &aBoardItem);
void buildPadShapeThickOutlineAsSegments( const D_PAD* aPad, CGENERICCONTAINER2D *aDstContainer, int aWidth);
public:
wxColour m_BgColor;
wxColour m_BgColor_Top;
private:
BOARD *m_board;
// Render options
std::vector< bool > m_drawFlags; ///< options flags to render the board
GRID3D_TYPE m_3D_Grid_type; ///< Stores the current grid type
// Pcb board position
wxPoint m_boardPos; ///< center board actual position in board units
wxSize m_boardSize; ///< board actual size in board units
SFVEC3F m_boardCenter; ///< 3d center position of the pcb board in 3d units
// Pcb board bounding boxes
CBBOX m_boardBoudingBox; ///< 3d bouding box of the pcb board in 3d units
CBBOX2D m_board2dBBox3DU; ///< 2d bouding box of the pcb board in 3d units
SHAPE_POLY_SET m_boardPoly; ///< PCB board outline polygon
// 2D element containers
MAP_CONTAINER_2D m_layers_container2D; ///< It contains the 2d elements of each layer
MAP_CONTAINER_2D m_layers_holes2D; ///< It contains the holes per each layer
CBVHCONTAINER2D m_throughHoles_inflated; ///< It contains the list of throughHoles of the board, the radius of the hole is inflated with the copper tickness
CBVHCONTAINER2D m_throughHoles; ///< It contains the list of throughHoles of the board, the radius of the hole is inflated with the copper tickness
// Layers information
unsigned int m_copperLayersCount; ///< Number of copper layers actually used by the board
double m_biuTo3Dunits; ///< Normalization scale to convert board internal units to 3D units to normalize 3D units between -1.0 and +1.0
float m_layerZcoordTop[LAYER_ID_COUNT]; ///< Top (End) Z position of each layer (normalized)
float m_layerZcoordBottom[LAYER_ID_COUNT]; ///< Bottom (Start) Z position of each layer (normalized)
float m_copperThickness; ///< Copper thickness (normalized)
float m_epoxyThickness; ///< Epoxy thickness (normalized)
float m_nonCopperLayerThickness; ///< Non copper layers thickness
// Cameras
CCAMERA &m_currentCamera; ///< Holds a pointer to current camera in use.
CTRACK_BALL m_trackBallCamera;
// Statistics
unsigned int m_stats_nr_tracks;
float m_stats_track_med_width;
unsigned int m_stats_nr_vias; ///< Nr of vias
float m_stats_via_med_hole_diameter; ///< Computed medium diameter of the via holes in 3dunits
unsigned int m_stats_nr_holes;
float m_stats_hole_med_diameter; ///< Computed medium diameter of the holes in 3dunits
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_CINFO3D_VISU". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar *m_logTrace;
};
extern CINFO3D_VISU G_null_CINFO3D_VISU;
#endif // CINFO3D_VISU_H

View File

@ -45,7 +45,7 @@
#include <colors_selection.h>
#include <convert_basic_shapes_to_polygon.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <gal/opengl/opengl_compositor.h>
#ifdef __WINDOWS__
#include <GL/glew.h> // must be included before gl.h
@ -1128,6 +1128,13 @@ void EDA_3D_CANVAS::render3DComponentShape( MODULE* module,
shape3D->Render( aIsRenderingJustNonTransparentObjects,
aIsRenderingJustTransparentObjects );
/*
* XXX - CB - DEPRECATE THIS - the old renderer will eventually
* be replaced anyway so all debugging of 3D Plugins should be
* done via the new rendering system
*/
if( 0 )
{
if( isEnabled( FL_RENDER_SHOW_MODEL_BBOX ) )
{
// Set the alpha current color to opaque
@ -1139,6 +1146,7 @@ void EDA_3D_CANVAS::render3DComponentShape( MODULE* module,
CBBOX thisBBox = shape3D->getBBox();
thisBBox.GLdebug();
}
}
glPopMatrix();

View File

@ -45,7 +45,7 @@
#include <colors_selection.h>
#include <convert_basic_shapes_to_polygon.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <gal/opengl/opengl_compositor.h>
#ifdef __WINDOWS__
#include <GL/glew.h> // must be included before gl.h

View File

@ -32,7 +32,7 @@
#include <common.h>
#include <base_struct.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/glm.hpp>
#include <glm/glm.hpp>
class S3D_MASTER;

View File

@ -0,0 +1,138 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 3d_fastmath.h
* @brief Defines math related functions
*/
#ifndef _3D_FASTMATH_H
#define _3D_FASTMATH_H
#include <string.h>
#include <stdint.h>
#include <cmath>
// Define this flag to use fast math optimizations
#define FASTMATH_USE
#define L1_CACHE_LINE_SIZE 64
#ifdef FASTMATH_USE
#define INTFLOORF(s) (lrintf( (s) - (0.5f - FLT_EPSILON) ))
#else
#define INTFLOORF(s) ((int)( floor(s) ))
#endif
/**
* This part contains some functions from the PBRT 3 source code.
* https://github.com/mmp/pbrt-v3/blob/master/src/core/pbrt.h
*/
/*
pbrt source code is Copyright(c) 1998-2015
Matt Pharr, Greg Humphreys, and Wenzel Jakob.
This file is part of pbrt.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Global Inline Functions
inline uint32_t FloatToBits(float f) {
uint32_t ui;
memcpy(&ui, &f, sizeof(float));
return ui;
}
inline float BitsToFloat(uint32_t ui) {
float f;
memcpy(&f, &ui, sizeof(uint32_t));
return f;
}
inline uint64_t FloatToBits(double f) {
uint64_t ui;
memcpy(&ui, &f, sizeof(double));
return ui;
}
inline double BitsToFloat(uint64_t ui) {
double f;
memcpy(&f, &ui, sizeof(uint64_t));
return f;
}
inline float NextFloatUp(float v) {
// Handle infinity and negative zero for _NextFloatUp()_
if (std::isinf(v) && v > 0.) return v;
if (v == -0.f) v = 0.f;
// Advance _v_ to next higher float
uint32_t ui = FloatToBits(v);
if (v >= 0.)
++ui;
else
--ui;
return BitsToFloat(ui);
}
inline float NextFloatDown(float v) {
// Handle infinity and positive zero for _NextFloatDown()_
if (std::isinf(v) && v < 0.) return v;
if (v == 0.f) v = -0.f;
uint32_t ui = FloatToBits(v);
if (v > 0.)
--ui;
else
++ui;
return BitsToFloat(ui);
}
#endif // 3D_FASTMATH_H

125
3d-viewer/3d_math/3d_math.h Normal file
View File

@ -0,0 +1,125 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 3d_math.h
* @brief Defines math related functions
*/
#ifndef _3D_MATH_H
#define _3D_MATH_H
#include "3d_xv3d/xv3d_types.h"
// https://en.wikipedia.org/wiki/Spherical_coordinate_system
/**
* @brief SphericalToCartesian
* @param aInclination θ [0, π]
* @param aAzimuth φ [0, 2π]
* @return Cartesian cordinates
*/
inline SFVEC3F SphericalToCartesian( float aInclination, float aAzimuth )
{
float sinInc = glm::sin( aInclination );
return SFVEC3F( sinInc * glm::cos( aAzimuth ),
sinInc * glm::sin( aAzimuth ),
glm::cos( aInclination ) );
}
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
// !TODO: this is not correct because it is not a gaussian random
inline SFVEC3F UniformRandomHemisphereDirection( )
{
SFVEC3F b( (rand()/(float)RAND_MAX) - 0.5f, (rand()/(float)RAND_MAX) - 0.5f, (rand()/(float)RAND_MAX) - 0.5f);
return b;
}
// https://pathtracing.wordpress.com/2011/03/03/cosine-weighted-hemisphere/
inline SFVEC3F CosWeightedRandomHemisphereDirection( SFVEC3F n )
{
const float Xi1 = (float)rand() / (float)RAND_MAX;
const float Xi2 = (float)rand() / (float)RAND_MAX;
const float theta = acos( sqrt( 1.0f - Xi1 ) );
const float phi = 2.0f * glm::pi<float>() * Xi2;
const float xs = sinf( theta ) * cosf( phi );
const float ys = cosf( theta );
const float zs = sinf( theta ) * sinf( phi );
const SFVEC3F y( n.x, n.y, n.z );
SFVEC3F h = y;
if (fabs( h.x ) <= fabs( h.y ) && fabs( h.x ) <= fabs( h.z ) )
h.x= 1.0f;
else if (fabs(h.y)<=fabs(h.x) && fabs(h.y)<=fabs(h.z))
h.y= 1.0f;
else
h.z= 1.0f;
const SFVEC3F x = glm::normalize( glm::cross( h, y ) );
const SFVEC3F z = glm::normalize( glm::cross( x, y ) );
SFVEC3F direction = xs * x + ys * y + zs * z;
return glm::normalize( direction );
}
/**
* @brief Refract
* Based on: https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h
* See also: http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_3_Refractions_and_Beers_Law.shtml
* @param aInVector incoming vector
* @param aNormal normal in the intersection point
* @param aRin_over_Rout incoming refraction index / out refraction index
* @param aOutVector the refracted vector
* @return true
*/
inline bool Refract( const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout, SFVEC3F &aOutVector )
{
float cosThetaI = -glm::dot( aNormal, aInVector );
float sin2ThetaI = glm::max( 0.0f, 1.0f - cosThetaI * cosThetaI );
float sin2ThetaT = aRin_over_Rout * aRin_over_Rout * sin2ThetaI;
// Handle total internal reflection for transmission
if( sin2ThetaT >= 1.0f )
return false;
float cosThetaT = sqrtf( 1.0f - sin2ThetaT );
aOutVector = glm::normalize( aRin_over_Rout * aInVector + ( aRin_over_Rout * cosThetaI - cosThetaT ) * aNormal );
return true;
}
inline float mapf( float x, float in_min, float in_max, float out_min, float out_max)
{
x = glm::clamp( x, in_min, in_max );
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
#endif // 3D_MATH_H

View File

@ -31,8 +31,8 @@
#include <3d_mesh_model.h>
#include <boost/geometry/algorithms/area.hpp>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <gal/opengl/glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
#ifdef __WXMAC__
# ifdef __DARWIN__

View File

@ -34,10 +34,10 @@
#include <boost/shared_ptr.hpp>
#include <vector>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/glm.hpp>
#include <glm/glm.hpp>
#include "3d_struct.h"
#include "3d_material.h"
#include "CBBox.h"
#include "3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
class S3D_MESH;

View File

@ -0,0 +1,436 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_model_viewer.cpp
* @brief Implements a model viewer canvas
*/
#include <iostream>
#include "c3d_model_viewer.h"
#include "3d_rendering/3d_render_ogl_legacy/ogl_legacy_utils.h"
#include "common_ogl/ogl_utils.h"
#include <wx/dcclient.h>
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
const wxChar * C3D_MODEL_VIEWER::m_logTrace = wxT( "KI_TRACE_EDA_3D_MODEL_VIEWER" );
BEGIN_EVENT_TABLE( C3D_MODEL_VIEWER, wxGLCanvas )
EVT_PAINT( C3D_MODEL_VIEWER::OnPaint )
// mouse events
EVT_LEFT_DOWN( C3D_MODEL_VIEWER::OnLeftDown )
EVT_LEFT_UP( C3D_MODEL_VIEWER::OnLeftUp )
EVT_MIDDLE_UP( C3D_MODEL_VIEWER::OnMiddleUp )
EVT_MIDDLE_DOWN(C3D_MODEL_VIEWER::OnMiddleDown)
EVT_RIGHT_DOWN( C3D_MODEL_VIEWER::OnRightClick )
EVT_MOUSEWHEEL( C3D_MODEL_VIEWER::OnMouseWheel )
EVT_MOTION( C3D_MODEL_VIEWER::OnMouseMove )
#ifdef USE_OSX_MAGNIFY_EVENT
EVT_MAGNIFY( C3D_MODEL_VIEWER::OnMagnify )
#endif
// other events
EVT_ERASE_BACKGROUND( C3D_MODEL_VIEWER::OnEraseBackground )
END_EVENT_TABLE()
/// This defines the range that all coord will have to be rendered.
/// It will use this value to convert to a normalized value between
/// -(RANGE_SCALE_3D/2) .. +(RANGE_SCALE_3D/2)
#define RANGE_SCALE_3D 8.0f
C3D_MODEL_VIEWER::C3D_MODEL_VIEWER( wxWindow *aParent,
const int *aAttribList ) :
wxGLCanvas( aParent,
wxID_ANY,
aAttribList,
wxDefaultPosition,
wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE ),
m_trackBallCamera( RANGE_SCALE_3D * 2.0f )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::C3D_MODEL_VIEWER" ) );
m_ogl_initialized = false;
m_reload_is_needed = false;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
// Explicitly create a new rendering context instance for this canvas.
m_glRC = new wxGLContext( this );
}
C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER()
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::~C3D_MODEL_VIEWER" ) );
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
delete m_glRC;
m_glRC = NULL;
}
void C3D_MODEL_VIEWER::Set3DModel( const S3DMODEL &a3DModel )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::Set3DModel" ) );
// Validate a3DModel pointers
wxASSERT( a3DModel.m_Materials != NULL );
wxASSERT( a3DModel.m_Meshes != NULL );
wxASSERT( a3DModel.m_MaterialsSize > 0 );
wxASSERT( a3DModel.m_MeshesSize > 0 );
// Delete the old model
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
(a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
{
m_3d_model = &a3DModel;
m_reload_is_needed = true;
}
}
void C3D_MODEL_VIEWER::Clear3DModel()
{
// Delete the old model
m_reload_is_needed = false;
delete m_ogl_3dmodel;
m_ogl_3dmodel = NULL;
m_3d_model = NULL;
}
void C3D_MODEL_VIEWER::ogl_initialize()
{
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glEnable( GL_DEPTH_TEST );
//glDepthFunc( GL_LEQUAL );
glEnable( GL_CULL_FACE );
glShadeModel( GL_SMOOTH );
glEnable( GL_LINE_SMOOTH );
glEnable( GL_NORMALIZE );
// Setup light
// https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
// /////////////////////////////////////////////////////////////////////////
const GLfloat ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat position[] = { 0.0f, 0.0f, 1.0f, 0.0f }; // defines a directional light that points along the negative z-axis
const GLfloat lmodel_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
glLightfv( GL_LIGHT0, GL_POSITION, position );
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
}
void C3D_MODEL_VIEWER::ogl_set_arrow_material()
{
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
}
void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
{
wxPaintDC( this );
// SwapBuffer requires the window to be shown before calling
if( !IsShownOnScreen() )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnPaint !IsShown" ) );
return;
}
// "Makes the OpenGL state that is represented by the OpenGL rendering
// context context current, i.e. it will be used by all subsequent OpenGL calls.
// This function may only be called when the window is shown on screen"
SetCurrent( *m_glRC );
// Set the OpenGL viewport according to the client size of this canvas.
// This is done here rather than in a wxSizeEvent handler because our
// OpenGL rendering context (and thus viewport setting) is used with
// multiple canvases: If we updated the viewport in the wxSizeEvent
// handler, changing the size of one canvas causes a viewport setting that
// is wrong when next another canvas is repainted.
wxSize clientSize = GetClientSize();
if( !m_ogl_initialized )
{
m_ogl_initialized = true;
ogl_initialize();
}
if( m_reload_is_needed )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnPaint m_reload_is_needed" ) );
m_reload_is_needed = false;
m_ogl_3dmodel = new C_OGL_3DMODEL( *m_3d_model );
// It convert a model as it was a board, so get the max size dimension of the board
// and compute the conversion scale
m_BiuTo3Dunits = (double)RANGE_SCALE_3D / ((double)m_ogl_3dmodel->GetBBox().GetMaxDimension() * UNITS3D_TO_UNITSPCB);
}
glViewport( 0, 0, clientSize.x, clientSize.y );
m_trackBallCamera.SetCurWindowSize( clientSize );
// clear color and depth buffers
// /////////////////////////////////////////////////////////////////////////
glEnable( GL_DEPTH_TEST );
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
glClearDepth( 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Set projection and modelview matrixes
// /////////////////////////////////////////////////////////////////////////
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
glLoadMatrixf( glm::value_ptr( m_trackBallCamera.GetViewMatrix() ) );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
ogl_set_arrow_material();
glColor3f( 0.9f, 0.0f, 0.0f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( RANGE_SCALE_3D / 1.0f, 0.0f, 0.0f ),
0.2f );
glColor3f( 0.0f, 0.9f, 0.0f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, RANGE_SCALE_3D / 1.0f, 0.0f ),
0.2f );
glColor3f( 0.0f, 0.0f, 0.9f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 1.0f ),
0.2f );
// Render Model
if( m_ogl_3dmodel )
{
glPushMatrix();
double modelunit_to_3d_units_factor = m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
const SFVEC3F model_center = m_ogl_3dmodel->GetBBox().GetCenter();
glTranslatef( model_center.x, model_center.y, model_center.z );
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor, modelunit_to_3d_units_factor);
m_ogl_3dmodel->Draw_opaque();
//m_ogl_3dmodel->Draw_transparent();
//m_ogl_3dmodel->Draw_bboxes();
glPopMatrix();
}
glViewport( 0, 0, clientSize.y / 8 , clientSize.y / 8 ); // YxY squared view port
glClear( GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, 1.0f, 0.01f, RANGE_SCALE_3D * 2.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glm::mat4 TranslationMatrix = glm::translate( glm::mat4(1.0f), SFVEC3F( 0.0f, 0.0f, -RANGE_SCALE_3D ) );
glm::mat4 ViewMatrix = TranslationMatrix * m_trackBallCamera.GetRotationMatrix();
glLoadMatrixf( glm::value_ptr( ViewMatrix ) );
ogl_set_arrow_material();
glColor3f( 0.9f, 0.0f, 0.0f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( RANGE_SCALE_3D / 2.65f, 0.0f, 0.0f ),
0.275f );
glColor3f( 0.0f, 0.9f, 0.0f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, RANGE_SCALE_3D / 2.65f, 0.0f ),
0.275f );
glColor3f( 0.0f, 0.0f, 0.9f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 2.65f ),
0.275f );
// "Swaps the double-buffer of this window, making the back-buffer the
// front-buffer and vice versa, so that the output of the previous OpenGL
// commands is displayed on the window."
SwapBuffers();
event.Skip();
}
void C3D_MODEL_VIEWER::OnEraseBackground( wxEraseEvent &event )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnEraseBackground" ) );
// Do nothing, to avoid flashing.
}
void C3D_MODEL_VIEWER::OnMouseWheel( wxMouseEvent &event )
{
wxLogTrace( m_logTrace, wxT( "C3D_MODEL_VIEWER::OnMouseWheel" ) );
if( event.ShiftDown() )
{
//if( event.GetWheelRotation() < 0 )
//SetView3D( WXK_UP ); // move up
//else
//SetView3D( WXK_DOWN ); // move down
}
else if( event.ControlDown() )
{
//if( event.GetWheelRotation() > 0 )
//SetView3D( WXK_RIGHT ); // move right
//else
//SetView3D( WXK_LEFT ); // move left
}
else
{
if( event.GetWheelRotation() > 0 )
{
m_trackBallCamera.ZoomIn( 1.1f );
}
else
{
m_trackBallCamera.ZoomOut( 1.1f );
}
//DisplayStatus();
Refresh( false );
}
m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
}
#ifdef USE_OSX_MAGNIFY_EVENT
void C3D_MODEL_VIEWER::OnMagnify( wxMouseEvent& event )
{
/*
double magnification = ( event.GetMagnification() + 1.0f );
GetPrm3DVisu().m_Zoom /= magnification;
if( GetPrm3DVisu().m_Zoom <= 0.01 )
GetPrm3DVisu().m_Zoom = 0.01;
DisplayStatus();
Refresh( false );
*/
}
#endif
void C3D_MODEL_VIEWER::OnMouseMove( wxMouseEvent &event )
{
m_trackBallCamera.SetCurWindowSize( GetClientSize() );
if( event.Dragging() )
{
if( event.LeftIsDown() ) // Drag
m_trackBallCamera.Drag( event.GetPosition() );
//else if( event.MiddleIsDown() ) // Pan
// m_trackBallCamera.Pan( event.GetPosition() );
// orientation has changed, redraw mesh
Refresh( false );
}
m_trackBallCamera.SetCurMousePosition( event.GetPosition() );
}
void C3D_MODEL_VIEWER::OnLeftDown( wxMouseEvent &event )
{
//m_is_moving_mouse = true;
}
void C3D_MODEL_VIEWER::OnLeftUp( wxMouseEvent &event )
{
//m_is_moving_mouse = false;
//Refresh( false );
}
void C3D_MODEL_VIEWER::OnMiddleDown( wxMouseEvent &event )
{
//m_is_moving_mouse = true;
}
void C3D_MODEL_VIEWER::OnMiddleUp( wxMouseEvent &event )
{
//m_is_moving_mouse = false;
//Refresh( false );
}
void C3D_MODEL_VIEWER::OnRightClick( wxMouseEvent &event )
{
}

View File

@ -0,0 +1,131 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_model_viewer.h
* @brief Implements a model viewer canvas
*/
#ifndef _C3D_MODEL_VIEWER_H_
#define _C3D_MODEL_VIEWER_H_
#include "3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.h"
#include "3d_rendering/ctrack_ball.h"
#include <wx/glcanvas.h>
/**
* Class C3D_MODEL_VIEWER
* Implement a canvas based on a wxGLCanvas
*/
class C3D_MODEL_VIEWER : public wxGLCanvas
{
public:
/**
* Creates a new 3D Canvas with a attribute list
* @param aParent = the parent creator of this canvas
* @param aAttribList = a list of openGL options created by COGL_ATT_LIST::GetAttributesList
*/
C3D_MODEL_VIEWER( wxWindow *aParent,
const int *aAttribList = 0 );
~C3D_MODEL_VIEWER();
/**
* @brief Set3DModel - Set this model to be displayed
* @param a3DModel - 3d model data
*/
void Set3DModel( const S3DMODEL &a3DModel );
/**
* @brief Clear3DModel - Unloads the displayed 3d model
*/
void Clear3DModel();
private:
void ogl_initialize();
void ogl_set_arrow_material();
private:
void OnPaint( wxPaintEvent &event );
void OnEraseBackground( wxEraseEvent &event );
void OnMouseWheel( wxMouseEvent &event );
#ifdef USE_OSX_MAGNIFY_EVENT
void OnMagnify( wxMouseEvent& event );
#endif
void OnMouseMove( wxMouseEvent &event );
void OnLeftDown( wxMouseEvent &event );
void OnLeftUp( wxMouseEvent &event );
void OnMiddleUp( wxMouseEvent &event );
void OnMiddleDown( wxMouseEvent &event );
void OnRightClick( wxMouseEvent &event );
DECLARE_EVENT_TABLE();
private:
/// openGL context
wxGLContext *m_glRC;
/// Camera used in this canvas
CTRACK_BALL m_trackBallCamera;
/// Original 3d model data
const S3DMODEL *m_3d_model;
/// Class holder for 3d model to display on openGL
C_OGL_3DMODEL *m_ogl_3dmodel;
/// Flag that we have a new model and it need to be reloaded when the paint is called
bool m_reload_is_needed;
/// Flag if open gl was initialized
bool m_ogl_initialized;
/// factor to convert the model or any other items to keep it in relation to the +/-RANGE_SCALE_3D
/// (it is named same as the board render for better understanding proposes)
double m_BiuTo3Dunits;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_EDA_3D_MODEL_VIEWER". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar *m_logTrace;
};
#endif // _C3D_MODEL_VIEWER_H_

View File

@ -34,7 +34,7 @@
#include <kicad_string.h>
#include <pgm_base.h>
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <3d_viewer.h>
#include <info3d_visu.h>
#include "3d_struct.h"

View File

@ -0,0 +1,816 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_render_createscene_ogl_legacy.cpp
* @brief
*/
#include "c3d_render_ogl_legacy.h"
#include "ogl_legacy_utils.h"
#include "../3d_render_raytracing/shapes2D/cpolygon2d.h"
#include "../3d_render_raytracing/shapes2D/ctriangle2d.h"
#include "../3d_render_raytracing/shapes2D/cpolygon4pts2d.h"
#include "../3d_render_raytracing/shapes2D/cfilledcircle2d.h"
#include "../3d_render_raytracing/shapes2D/cring2d.h"
#include "3d_math/3d_math.h"
#include "3d_math/3d_fastmath.h"
#include <trigo.h>
void C3D_RENDER_OGL_LEGACY::reload()
{
m_reloadRequested = false;
ogl_free_all_display_lists();
COBJECT2D_STATS::Instance().ResetStats();
printf("InitSettings...\n");
unsigned stats_startReloadTime = GetRunningMicroSecs();
m_settings.InitSettings();
unsigned stats_endReloadTime = GetRunningMicroSecs();
SFVEC3F camera_pos = m_settings.GetBoardCenter3DU();
m_settings.CameraGet().SetBoardLookAtPos( camera_pos );
unsigned stats_start_OpenGL_Load_Time = GetRunningMicroSecs();
// Create Board
// /////////////////////////////////////////////////////////////////////////
printf("Create board...\n");
CCONTAINER2D boardContainer;
Convert_shape_line_polygon_to_triangles( m_settings.GetBoardPoly(),
boardContainer,
m_settings.BiuTo3Dunits(),
(const BOARD_ITEM &)*m_settings.GetBoard() );
const LIST_OBJECT2D listBoardObject2d = boardContainer.GetList();
if( listBoardObject2d.size() > 0 )
{
/*
float layer_z_top = m_settings.GetLayerBottomZpos3DU( F_Cu );
float layer_z_bot = m_settings.GetLayerBottomZpos3DU( B_Cu );
*/
float layer_z_top = m_settings.GetLayerBottomZpos3DU( B_Mask );
float layer_z_bot = m_settings.GetLayerTopZpos3DU( B_Mask );
CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() );
for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin();
itemOnLayer != listBoardObject2d.end();
itemOnLayer++ )
{
const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE );
const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
const SFVEC2F &v1 = tri->GetP1();
const SFVEC2F &v2 = tri->GetP2();
const SFVEC2F &v3 = tri->GetP3();
add_triangle_top_bot( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
}
const SHAPE_POLY_SET boardPoly = m_settings.GetBoardPoly();
SHAPE_POLY_SET boardPolyCopy = boardPoly;
boardPolyCopy.Simplify( true );
if( boardPolyCopy.OutlineCount() == 1 )
{
const SHAPE_LINE_CHAIN& outlinePath = boardPolyCopy.COutline( 0 );
std::vector< SFVEC2F > contournPoints;
contournPoints.clear();
contournPoints.reserve( outlinePath.PointCount() + 2 );
for( unsigned int i = 0; i < (unsigned int)outlinePath.PointCount(); ++i )
{
const VECTOR2I& v = outlinePath.CPoint( i );
contournPoints.push_back( SFVEC2F( v.x * m_settings.BiuTo3Dunits(),
-v.y * m_settings.BiuTo3Dunits() ) );
}
contournPoints.push_back( contournPoints[0] );
if( contournPoints.size() > 4 )
{
// Calculate normals of each segment of the contourn
std::vector< SFVEC2F > contournNormals;
contournNormals.clear();
contournNormals.reserve( contournPoints.size() );
for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = contournPoints[i + 0];
const SFVEC2F &v1 = contournPoints[i + 1];
SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals.push_back( SFVEC2F( -n.y, n.x ) );
}
SFVEC2F lastNormal = contournNormals[contournPoints.size() - 2];
for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = contournPoints[i + 0];
const SFVEC2F &v1 = contournPoints[i + 1];
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_top ) ),
SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_top ) ),
SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_bot ) ),
SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_bot ) ) );
SFVEC2F n0 = contournNormals[i];
if( glm::dot( n0, lastNormal ) > 0.5f )
n0 += lastNormal;
else
n0 += contournNormals[i];
const SFVEC2F &nextNormal = contournNormals[ (i + 1) % (contournPoints.size() - 1) ];
SFVEC2F n1 = contournNormals[i];
if( glm::dot( n1, nextNormal ) > 0.5f )
n1 += nextNormal;
else
n1 += contournNormals[i];
n0 = glm::normalize( n0 );
n1 = glm::normalize( n1 );
const SFVEC3F n3d0 = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n3d1 = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d0, n3d1, n3d1, n3d0 );
lastNormal = contournNormals[i];
/*
const SFVEC2F n0 = glm::normalize( v0 - center );
const SFVEC2F n1 = glm::normalize( v1 - center );
const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );*/
}
}
contournPoints.clear();
}
m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles, m_ogl_circle_texture, SFVEC3F(0.65f,0.55f,0.05f) );
delete layerTriangles;
}
float calc_sides_min_factor = (float)( 10.0 * IU_PER_MILS * m_settings.BiuTo3Dunits() );
float calc_sides_max_factor = (float)( 1000.0 * IU_PER_MILS * m_settings.BiuTo3Dunits() );
// Add layers maps (except B_Mask and F_Mask)
// /////////////////////////////////////////////////////////////////////////
printf("Add layers maps...\n");
for( MAP_CONTAINER_2D::const_iterator ii = m_settings.GetMapLayers().begin();
ii != m_settings.GetMapLayers().end();
ii++ )
{
LAYER_ID layer_id = static_cast<LAYER_ID>(ii->first);
if( !m_settings.Is3DLayerEnabled( layer_id ) )
continue;
const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(ii->second);
const LIST_OBJECT2D listObject2d = container2d->GetList();
if( listObject2d.size() == 0 )
continue;
//CMATERIAL *materialLayer = &m_materials.m_SilkS;
SFVEC3F layerColor = SFVEC3F( 0.3f, 0.4f, 0.5f );
float layer_z_bot = m_settings.GetLayerBottomZpos3DU( layer_id );
float layer_z_top = m_settings.GetLayerTopZpos3DU( layer_id );
if( layer_z_top < layer_z_bot )
{
float tmpFloat = layer_z_bot;
layer_z_bot = layer_z_top;
layer_z_top = tmpFloat;
}
layer_z_bot -= m_settings.GetNonCopperLayerThickness3DU();
layer_z_top += m_settings.GetNonCopperLayerThickness3DU();
if( m_settings.GetFlag( FL_USE_REALISTIC_MODE ) )
{
switch( layer_id )
{
case B_Adhes:
case F_Adhes:
break;
case B_Paste:
case F_Paste:
// materialLayer = &m_materials.m_Paste;
break;
case B_SilkS:
case F_SilkS:
// materialLayer = &m_materials.m_SilkS;
// layerColor = g_silkscreenColor;
break;
case Dwgs_User:
case Cmts_User:
case Eco1_User:
case Eco2_User:
case Edge_Cuts:
case Margin:
break;
case B_CrtYd:
case F_CrtYd:
break;
case B_Fab:
case F_Fab:
break;
default:
//materialLayer = &m_materials.m_Copper;
//layerColor = g_copperColor;
break;
}
}
else
{
layerColor = m_settings.GetLayerColor( layer_id );
}
// Calculate an estiation for then nr of triangles based on the nr of objects
unsigned int nrTrianglesEstimation = listObject2d.size() * 8;
CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation );
m_triangles[layer_id] = layerTriangles;
for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
itemOnLayer != listObject2d.end();
itemOnLayer++ )
{
const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer);
switch( object2d_A->GetObjectType() )
{
case OBJ2D_FILLED_CIRCLE:
{
const CFILLEDCIRCLE2D *filledCircle = (const CFILLEDCIRCLE2D *)object2d_A;
const SFVEC2F &center = filledCircle->GetCenter();
float radius = filledCircle->GetRadius() * 2.0f; // Double because the render triangle
float radiusSquared = radius * radius;
const float texture_factor = (0.9f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
const float f = (sqrtf(2.0f) / 2.0f) * radius * 0.9;// * texture_factor;
layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, layer_z_top ),
SFVEC3F( center.x - f, center.y, layer_z_top ),
SFVEC3F( center.x,
center.y - f, layer_z_top ) );
layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, layer_z_top ),
SFVEC3F( center.x + f, center.y, layer_z_top ),
SFVEC3F( center.x,
center.y + f, layer_z_top ) );
layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, layer_z_bot ),
SFVEC3F( center.x + f, center.y, layer_z_bot ),
SFVEC3F( center.x,
center.y - f, layer_z_bot ) );
layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, layer_z_bot ),
SFVEC3F( center.x - f, center.y, layer_z_bot ),
SFVEC3F( center.x,
center.y + f, layer_z_bot ) );
unsigned int nr_sides_per_circle = (unsigned int)mapf( radiusSquared,
calc_sides_min_factor, calc_sides_max_factor,
24.0f, 256.0f );
wxASSERT( nr_sides_per_circle >= 24 );
// Normal radius for the circle
radius = filledCircle->GetRadius();
std::vector< SFVEC2F > contournPoints;
contournPoints.clear();
contournPoints.reserve( nr_sides_per_circle + 2 );
int delta = 3600 / nr_sides_per_circle;
int ii;
for( ii = 0; ii < 3600; ii += delta )
{
const SFVEC2F rotatedDir = glm::rotate( SFVEC2F( 0.0f, 1.0f ), (float)ii * 2.0f * 3.14f / 3600.0f );
contournPoints.push_back( SFVEC2F( center.x - rotatedDir.y * radius, center.y + rotatedDir.x * radius ) );
}
contournPoints.push_back( contournPoints[0] );
if( contournPoints.size() > 1 )
{
for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i )
{
const SFVEC2F &v0 = contournPoints[i + 0];
const SFVEC2F &v1 = contournPoints[i + 1];
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ),
SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ),
SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ),
SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ) );
const SFVEC2F n0 = glm::normalize( v0 - center );
const SFVEC2F n1 = glm::normalize( v1 - center );
const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
}
}
contournPoints.clear();
}
break;
case OBJ2D_DUMMYBLOCK:
{
}
break;
case OBJ2D_POLYGON4PT:
{
const CPOLYGON4PTS2D *poly = (const CPOLYGON4PTS2D *)object2d_A;
const SFVEC2F &v0 = poly->GetV0();
const SFVEC2F &v1 = poly->GetV1();
const SFVEC2F &v2 = poly->GetV2();
const SFVEC2F &v3 = poly->GetV3();
add_triangle_top_bot( layerTriangles, v0, v2, v1, layer_z_top, layer_z_bot );
add_triangle_top_bot( layerTriangles, v2, v0, v3, layer_z_top, layer_z_bot );
const SFVEC2F &n0 = poly->GetN0();
const SFVEC2F &n1 = poly->GetN1();
const SFVEC2F &n2 = poly->GetN2();
const SFVEC2F &n3 = poly->GetN3();
const SFVEC3F n3d0 = SFVEC3F(-n0.y, n0.x, 0.0f );
const SFVEC3F n3d1 = SFVEC3F(-n1.y, n1.x, 0.0f );
const SFVEC3F n3d2 = SFVEC3F(-n2.y, n2.x, 0.0f );
const SFVEC3F n3d3 = SFVEC3F(-n3.y, n3.x, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_bot ),
SFVEC3F( v1.x, v1.y, layer_z_bot ),
SFVEC3F( v1.x, v1.y, layer_z_top ),
SFVEC3F( v0.x, v0.y, layer_z_top ) );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d0, n3d0, n3d0, n3d0 );
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v2.x, v2.y, layer_z_top ),
SFVEC3F( v1.x, v1.y, layer_z_top ),
SFVEC3F( v1.x, v1.y, layer_z_bot ),
SFVEC3F( v2.x, v2.y, layer_z_bot ) );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d1, n3d1, n3d1, n3d1 );
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v3.x, v3.y, layer_z_top ),
SFVEC3F( v2.x, v2.y, layer_z_top ),
SFVEC3F( v2.x, v2.y, layer_z_bot ),
SFVEC3F( v3.x, v3.y, layer_z_bot ) );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d2, n3d2, n3d2, n3d2 );
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_top ),
SFVEC3F( v3.x, v3.y, layer_z_top ),
SFVEC3F( v3.x, v3.y, layer_z_bot ),
SFVEC3F( v0.x, v0.y, layer_z_bot ) );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d3, n3d3, n3d3, n3d3 );
}
break;
case OBJ2D_RING:
{
const CRING2D *ring = (const CRING2D *)object2d_A;
const SFVEC2F &center = ring->GetCenter();
float inner = ring->GetInnerRadius();
float outer = ring->GetOuterRadius();
unsigned int nr_sides_per_circle = (unsigned int)mapf( outer,
calc_sides_min_factor, calc_sides_max_factor,
24.0f, 256.0f );
wxASSERT( nr_sides_per_circle >= 24 );
std::vector< SFVEC2F > innerContour;
std::vector< SFVEC2F > outerContour;
innerContour.clear();
innerContour.reserve( nr_sides_per_circle + 2 );
outerContour.clear();
outerContour.reserve( nr_sides_per_circle + 2 );
int delta = 3600 / nr_sides_per_circle;
for( int ii = 0; ii < 3600; ii += delta )
{
const SFVEC2F rotatedDir = glm::rotate( SFVEC2F( 0.0f, 1.0f), (float) ii * 2.0f * 3.14f / 3600.0f );
innerContour.push_back( SFVEC2F( center.x - rotatedDir.y * inner, center.y + rotatedDir.x * inner ) );
outerContour.push_back( SFVEC2F( center.x - rotatedDir.y * outer, center.y + rotatedDir.x * outer ) );
}
innerContour.push_back( innerContour[0] );
outerContour.push_back( outerContour[0] );
wxASSERT( innerContour.size() == outerContour.size() );
for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
{
const SFVEC2F &vi0 = innerContour[i + 0];
const SFVEC2F &vi1 = innerContour[i + 1];
const SFVEC2F &vo0 = outerContour[i + 0];
const SFVEC2F &vo1 = outerContour[i + 1];
layerTriangles->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, layer_z_top ),
SFVEC3F( vi0.x, vi0.y, layer_z_top ),
SFVEC3F( vo0.x, vo0.y, layer_z_top ),
SFVEC3F( vo1.x, vo1.y, layer_z_top ) );
layerTriangles->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, layer_z_bot ),
SFVEC3F( vo1.x, vo1.y, layer_z_bot ),
SFVEC3F( vo0.x, vo0.y, layer_z_bot ),
SFVEC3F( vi0.x, vi0.y, layer_z_bot ) );
}
for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i )
{
const SFVEC2F &v0 = innerContour[i + 0];
const SFVEC2F &v1 = innerContour[i + 1];
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ),
SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ),
SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ),
SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ) );
const SFVEC2F n0 = glm::normalize( v0 - center );
const SFVEC2F n1 = glm::normalize( v1 - center );
const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
}
for( unsigned int i = 0; i < ( outerContour.size() - 1 ); ++i )
{
const SFVEC2F &v0 = outerContour[i + 0];
const SFVEC2F &v1 = outerContour[i + 1];
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ),
SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ),
SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ),
SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ) );
const SFVEC2F n0 = glm::normalize( v0 - center );
const SFVEC2F n1 = glm::normalize( v1 - center );
const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
}
}
break;
case OBJ2D_TRIANGLE:
{
const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A;
const SFVEC2F &v1 = tri->GetP1();
const SFVEC2F &v2 = tri->GetP2();
const SFVEC2F &v3 = tri->GetP3();
add_triangle_top_bot( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot );
}
break;
case OBJ2D_ROUNDSEG:
{
const CROUNDSEGMENT2D &roundSeg = (const CROUNDSEGMENT2D &) *object2d_A;
unsigned int nr_sides_per_circle = (unsigned int)mapf( roundSeg.GetWidth(),
calc_sides_min_factor, calc_sides_max_factor,
24.0f, 256.0f );
wxASSERT( nr_sides_per_circle >= 24 );
SFVEC2F leftStart = roundSeg.GetLeftStar();
SFVEC2F leftEnd = roundSeg.GetLeftEnd();
SFVEC2F leftDir = roundSeg.GetLeftDir();
SFVEC2F rightStart = roundSeg.GetRightStar();
SFVEC2F rightEnd = roundSeg.GetRightEnd();
SFVEC2F rightDir = roundSeg.GetRightDir();
float radius = roundSeg.GetRadius();
SFVEC2F start = roundSeg.GetStart();
SFVEC2F end = roundSeg.GetEnd();
float texture_factor = (12.0f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
float texture_factorF= ( 4.0f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f;
const float radius_of_the_square = sqrtf( roundSeg.GetRadiusSquared() * 2.0f );
const float radius_triangle_factor = (radius_of_the_square - radius) / radius;
const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor, rightDir.x * radius * radius_triangle_factor );
const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor, leftDir.x * radius * radius_triangle_factor );
// Top end segment triangles
layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( rightEnd.x + texture_factor * factorS.x, rightEnd.y + texture_factor * factorS.y, layer_z_top ),
SFVEC3F( leftStart.x + texture_factor * factorE.x, leftStart.y + texture_factor * factorE.y, layer_z_top ),
SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf(2.0f),
start.y - texture_factorF * leftDir.y * radius * sqrtf(2.0f), layer_z_top ) );
layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( leftEnd.x + texture_factor * factorE.x, leftEnd.y + texture_factor * factorE.y, layer_z_top ),
SFVEC3F( rightStart.x + texture_factor * factorS.x, rightStart.y + texture_factor * factorS.y, layer_z_top ),
SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf(2.0f),
end.y - texture_factorF * rightDir.y * radius * sqrtf(2.0f), layer_z_top ) );
// Bot end segment triangles
layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( leftStart.x + texture_factor * factorE.x, leftStart.y + texture_factor * factorE.y, layer_z_bot ),
SFVEC3F( rightEnd.x + texture_factor * factorS.x, rightEnd.y + texture_factor * factorS.y, layer_z_bot ),
SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf(2.0f),
start.y - texture_factorF * leftDir.y * radius * sqrtf(2.0f), layer_z_bot ) );
layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( rightStart.x + texture_factor * factorS.x, rightStart.y + texture_factor * factorS.y, layer_z_bot ),
SFVEC3F( leftEnd.x + texture_factor * factorE.x, leftEnd.y + texture_factor * factorE.y, layer_z_bot ),
SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf(2.0f),
end.y - texture_factorF * rightDir.y * radius * sqrtf(2.0f), layer_z_bot ) );
// Segment top and bot planes
layerTriangles->m_layer_top_triangles->AddQuad( SFVEC3F( rightEnd.x, rightEnd.y, layer_z_top ),
SFVEC3F( rightStart.x, rightStart.y, layer_z_top ),
SFVEC3F( leftEnd.x, leftEnd.y, layer_z_top ),
SFVEC3F( leftStart.x, leftStart.y, layer_z_top ) );
layerTriangles->m_layer_bot_triangles->AddQuad( SFVEC3F( rightEnd.x, rightEnd.y, layer_z_bot ),
SFVEC3F( leftStart.x, leftStart.y, layer_z_bot ),
SFVEC3F( leftEnd.x, leftEnd.y, layer_z_bot ),
SFVEC3F( rightStart.x, rightStart.y, layer_z_bot ) );
// Middle contourns (two sides of the segment)
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( leftStart.x, leftStart.y, layer_z_top ),
SFVEC3F( leftEnd.x, leftEnd.y, layer_z_top ),
SFVEC3F( leftEnd.x, leftEnd.y, layer_z_bot ),
SFVEC3F( leftStart.x, leftStart.y, layer_z_bot ) );
const SFVEC3F leftNormal = SFVEC3F( -leftDir.y, leftDir.x, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( leftNormal, leftNormal, leftNormal, leftNormal );
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( rightStart.x, rightStart.y, layer_z_top ),
SFVEC3F( rightEnd.x, rightEnd.y, layer_z_top ),
SFVEC3F( rightEnd.x, rightEnd.y, layer_z_bot ),
SFVEC3F( rightStart.x, rightStart.y, layer_z_bot ) );
const SFVEC3F rightNormal = SFVEC3F( -rightDir.y, rightDir.x, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( rightNormal, rightNormal, rightNormal, rightNormal );
// Compute the outlines of the segment, and creates a polygon
// add right rounded end:
std::vector< SFVEC2F > roundedEndPointsStart;
std::vector< SFVEC2F > roundedEndPointsEnd;
roundedEndPointsStart.clear();
roundedEndPointsStart.reserve( nr_sides_per_circle + 2 );
roundedEndPointsEnd.clear();
roundedEndPointsEnd.reserve( nr_sides_per_circle + 2 );
roundedEndPointsStart.push_back( SFVEC2F( leftStart.x, leftStart.y ) );
roundedEndPointsEnd.push_back( SFVEC2F( leftEnd.x, leftEnd.y ) );
int delta = 3600 / nr_sides_per_circle;
for( int ii = delta; ii < 1800; ii += delta )
{
const SFVEC2F rotatedDirL = glm::rotate( leftDir, (float) ii * 2.0f * 3.14f / 3600.0f );
const SFVEC2F rotatedDirR = glm::rotate( rightDir, (float)(1800 - ii) * 2.0f * 3.14f / 3600.0f );
roundedEndPointsStart.push_back( SFVEC2F( start.x - rotatedDirL.y * radius, start.y + rotatedDirL.x * radius ) );
roundedEndPointsEnd.push_back( SFVEC2F( end.x - rotatedDirR.y * radius, end.y + rotatedDirR.x * radius ) );
}
roundedEndPointsStart.push_back( SFVEC2F( rightEnd.x, rightEnd.y ) );
roundedEndPointsEnd.push_back( SFVEC2F( rightStart.x, rightStart.y ) );
if( roundedEndPointsStart.size() > 1 )
{
for( unsigned int i = 0; i < ( roundedEndPointsStart.size() - 1 ); ++i )
{
const SFVEC2F &v0 = roundedEndPointsStart[i + 0];
const SFVEC2F &v1 = roundedEndPointsStart[i + 1];
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_bot ),
SFVEC3F( v1.x, v1.y, layer_z_bot ),
SFVEC3F( v1.x, v1.y, layer_z_top ),
SFVEC3F( v0.x, v0.y, layer_z_top ) );
const SFVEC2F n0 = glm::normalize( v0 - start );
const SFVEC2F n1 = glm::normalize( v1 - start );
const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
}
}
roundedEndPointsStart.clear();
if( roundedEndPointsEnd.size() > 1 )
{
for( unsigned int i = 0; i < ( roundedEndPointsEnd.size() - 1 ); ++i )
{
const SFVEC2F &v0 = roundedEndPointsEnd[i + 0];
const SFVEC2F &v1 = roundedEndPointsEnd[i + 1];
layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_top ),
SFVEC3F( v1.x, v1.y, layer_z_top ),
SFVEC3F( v1.x, v1.y, layer_z_bot ),
SFVEC3F( v0.x, v0.y, layer_z_bot ) );
const SFVEC2F n0 = glm::normalize( v0 - end );
const SFVEC2F n1 = glm::normalize( v1 - end );
const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f );
layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );
}
}
roundedEndPointsEnd.clear();
}
break;
default:
{
}
break;
}
#if 0
// not yet used / implemented (can be used in future to clip the objects in the board borders
COBJECT2D *object2d_C = CSGITEM_FULL;
std::vector<const COBJECT2D *> *object2d_B = CSGITEM_EMPTY;
if( m_settings.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) )
{
object2d_B = new std::vector<const COBJECT2D *>();
// Check if there are any layerhole that intersects this object
// Eg: a segment is cutted by a via hole or THT hole.
// /////////////////////////////////////////////////////////////
const MAP_CONTAINER_2D &layerHolesMap = m_settings.GetMapLayersHoles();
if( layerHolesMap.find(layer_id) != layerHolesMap.end() )
{
MAP_CONTAINER_2D::const_iterator ii_hole = layerHolesMap.find(layer_id);
const CBVHCONTAINER2D *containerLayerHoles2d = static_cast<const CBVHCONTAINER2D *>(ii_hole->second);
CONST_LIST_OBJECT2D intersectionList;
containerLayerHoles2d->GetListObjectsIntersects( object2d_A->GetBBox(), intersectionList );
if( !intersectionList.empty() )
{
for( CONST_LIST_OBJECT2D::const_iterator holeOnLayer = intersectionList.begin();
holeOnLayer != intersectionList.end();
holeOnLayer++ )
{
const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*holeOnLayer);
//if( object2d_A->Intersects( hole2d->GetBBox() ) )
//if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
object2d_B->push_back( hole2d );
}
}
}
// Check if there are any THT that intersects this object
// /////////////////////////////////////////////////////////////
if( !m_settings.GetThroughHole_Inflated().GetList().empty() )
{
CONST_LIST_OBJECT2D intersectionList;
m_settings.GetThroughHole_Inflated().GetListObjectsIntersects( object2d_A->GetBBox(), intersectionList );
if( !intersectionList.empty() )
{
for( CONST_LIST_OBJECT2D::const_iterator hole = intersectionList.begin();
hole != intersectionList.end();
hole++ )
{
const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*hole);
//if( object2d_A->Intersects( hole2d->GetBBox() ) )
//if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
object2d_B->push_back( hole2d );
}
}
}
if( object2d_B->empty() )
{
delete object2d_B;
object2d_B = CSGITEM_EMPTY;
}
}
if( (object2d_B == CSGITEM_EMPTY) &&
(object2d_C == CSGITEM_FULL) )
{
#if 0
create_3d_object_from( m_object_container, object2d_A, m_settings.GetLayerBottomZpos3DU( layer_id ),
m_settings.GetLayerTopZpos3DU( layer_id ),
materialLayer,
layerColor );
#else
CLAYERITEM *objPtr = new CLAYERITEM( object2d_A, m_settings.GetLayerBottomZpos3DU( layer_id ),
m_settings.GetLayerTopZpos3DU( layer_id ) );
objPtr->SetMaterial( materialLayer );
objPtr->SetColor( layerColor );
m_object_container.Add( objPtr );
#endif
}
else
{
#if 1
CITEMLAYERCSG2D *itemCSG2d = new CITEMLAYERCSG2D( object2d_A, object2d_B, object2d_C,
object2d_A->GetBoardItem() );
m_containerWithObjectsToDelete.Add( itemCSG2d );
CLAYERITEM *objPtr = new CLAYERITEM( itemCSG2d, m_settings.GetLayerBottomZpos3DU( layer_id ),
m_settings.GetLayerTopZpos3DU( layer_id ) );
objPtr->SetMaterial( materialLayer );
objPtr->SetColor( layerColor );
m_object_container.Add( objPtr );
#endif
}
#endif
}
// Create display list
// /////////////////////////////////////////////////////////////////////
m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles,
m_ogl_circle_texture,
layerColor );
}// for each layer on map
unsigned stats_end_OpenGL_Load_Time = GetRunningMicroSecs();
#ifdef RAYTRACING_PRINT_STATISTICS
printf( "C3D_RENDER_OGL_LEGACY::reload times:\n" );
printf( " Reload board: %.3f ms\n", (float)( stats_endReloadTime - stats_startReloadTime ) / 1000.0f );
printf( " Loading to openGL: %.3f ms\n", (float)( stats_end_OpenGL_Load_Time - stats_start_OpenGL_Load_Time ) / 1000.0f );
COBJECT2D_STATS::Instance().PrintStats();
#endif
}
void C3D_RENDER_OGL_LEGACY::add_triangle_top_bot( CLAYER_TRIANGLES *aDst, const SFVEC2F &v0, const SFVEC2F &v1, const SFVEC2F &v2, float top, float bot )
{
aDst->m_layer_bot_triangles->AddTriangle( SFVEC3F( v0.x, v0.y, bot ),
SFVEC3F( v1.x, v1.y, bot ),
SFVEC3F( v2.x, v2.y, bot ) );
aDst->m_layer_top_triangles->AddTriangle( SFVEC3F( v2.x, v2.y, top ),
SFVEC3F( v1.x, v1.y, top ),
SFVEC3F( v0.x, v0.y, top ) );
}

View File

@ -0,0 +1,723 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_render_ogl_legacy.cpp
* @brief
*/
#include "c3d_render_ogl_legacy.h"
#include "ogl_legacy_utils.h"
#include "common_ogl/ogl_utils.h"
#include "../cimage.h"
C3D_RENDER_OGL_LEGACY::C3D_RENDER_OGL_LEGACY( CINFO3D_VISU &aSettings,
S3D_CACHE *a3DModelManager ) :
C3D_RENDER_BASE( aSettings, a3DModelManager )
{
wxLogTrace( m_logTrace, wxT( "C3D_RENDER_OGL_LEGACY::C3D_RENDER_OGL_LEGACY" ) );
m_ogl_disp_lists_layers.clear();
m_triangles.clear();
m_ogl_disp_list_board = 0;
}
C3D_RENDER_OGL_LEGACY::~C3D_RENDER_OGL_LEGACY()
{
wxLogTrace( m_logTrace, wxT( "C3D_RENDER_OGL_LEGACY::~C3D_RENDER_OGL_LEGACY" ) );
}
void C3D_RENDER_OGL_LEGACY::SetCurWindowSize( const wxSize &aSize )
{
if( m_windowSize != aSize )
{
m_windowSize = aSize;
glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
// Initialize here any screen dependent data
}
}
/* defines */
#define SPHERE 1
#define CONE 2
#define CUBE 3
/* csgOperation
* types of CSG operations
*/
typedef enum {
CSG_A,
CSG_B,
CSG_A_OR_B,
CSG_A_AND_B,
CSG_A_SUB_B,
CSG_B_SUB_A
} csgOperation;
GLfloat cone_x = 0.0;
GLfloat cone_y = 0.0;
GLfloat cone_z = 0.0;
GLfloat cube_x = 0.0;
GLfloat cube_y = 0.0;
GLfloat cube_z = 0.0;
GLfloat sphere_x = 0.0;
GLfloat sphere_y = 0.0;
GLfloat sphere_z = 0.0;
GLint mouse_state = -1;
GLint mouse_button = -1;
csgOperation Op = CSG_A_OR_B;
void (*A)(void);
void (*B)(void);
/* functions */
/* one()
* draw a single object
*/
void op_one(void(*a)(void))
{
glEnable(GL_DEPTH_TEST);
a();
glDisable(GL_DEPTH_TEST);
}
/* or()
* boolean A or B (draw wherever A or B)
* algorithm: simple, just draw both with depth test enabled
*/
void op_or(void(*a)(void), void(*b)())
{
glPushAttrib(GL_ALL_ATTRIB_BITS); /* TODO - should just push depth */
glEnable(GL_DEPTH_TEST);
//glDisable(GL_CULL_FACE);
a(); b();
glPopAttrib();
}
/* inside()
* sets stencil buffer to show the part of A
* (front or back face according to 'face')
* that is inside of B.
*/
void op_inside(void(*a)(void), void(*b)(void), GLenum face, GLenum test)
{
/* draw A into depth buffer, but not into color buffer */
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glCullFace(face);
a();
/* use stencil buffer to find the parts of A that are inside of B
* by first incrementing the stencil buffer wherever B's front faces
* are...
*/
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
//glStencilFunc(GL_LESS, 1, 0);
glStencilFunc(GL_ALWAYS, 0, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT ); //GL_INCR);
glCullFace(GL_BACK);
b();
/* ...then decrement the stencil buffer wherever B's back faces are */
//glStencilFunc(GL_EQUAL, 0, 0);
//glStencilFunc(GL_ALWAYS, 0, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO );
glCullFace(GL_FRONT);
b();
/* now draw the part of A that is inside of B */
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(test, 0, 1);
glDisable(GL_DEPTH_TEST);
glCullFace(face);
a();
/* reset stencil test */
glDisable(GL_STENCIL_TEST);
}
/* fixup()
* fixes up the depth buffer with A's depth values
*/
void fixup(void(*a)(void))
{
/* fix up the depth buffer */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDepthFunc(GL_ALWAYS);
a();
/* reset depth func */
glDepthFunc(GL_LESS);
}
/* and()
* boolean A and B (draw wherever A intersects B)
* algorithm: find where A is inside B, then find where
* B is inside A
*/
void op_and(void(*a)(void), void(*b)(void))
{
op_inside(a, b, GL_BACK, GL_NOTEQUAL);
#if 1 /* set to 0 for faster, but incorrect results */
fixup(b);
#endif
op_inside(b, a, GL_BACK, GL_NOTEQUAL);
}
/*
* sub()
* boolean A subtract B (draw wherever A is and B is NOT)
* algorithm: find where a is inside B, then find where
* the BACK faces of B are NOT in A
*/
void op_sub(void(*a)(void), void(*b)(void))
{
op_inside(a, b, GL_FRONT, GL_NOTEQUAL);
#if 1 /* set to 0 for faster, but incorrect results */
fixup(b);
#endif
op_inside(b, a, GL_BACK, GL_EQUAL);
//op_inside(a, b, GL_FRONT, GL_NOTEQUAL);
}
/* sphere()
* draw a yellow sphere
*/
void sphere(void)
{/*
glLoadName(2);
glPushMatrix();
glTranslatef(sphere_x, sphere_y, sphere_z);
glColor3f(1.0, 1.0, 0.0);
glutSolidSphere(5.0, 16, 16);
glPopMatrix();*/
glBegin(GL_QUADS); // Begin drawing the color cube with 6 quads
// Top face (y = 1.0f)
// Define vertices in counter-clockwise (CCW) order with normal pointing out
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
// Bottom face (y = -1.0f)
glColor3f(1.0f, 0.5f, 0.0f); // Orange
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
// Front face (z = 1.0f)
glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
// Back face (z = -1.0f)
glColor3f(1.0f, 1.0f, 0.0f); // Yellow
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
// Left face (x = -1.0f)
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face (x = 1.0f)
glColor3f(1.0f, 0.0f, 1.0f); // Magenta
glVertex3f(1.0f, 1.0f, -1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glEnd(); // End of drawing color-cube
}
/* cube()
* draw a red cube
*/
void cube(void)
{
glPushMatrix();
glColor3f(0.3, 0.8, 0.1);
OGL_draw_arrow( SFVEC3F( 1.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, 0.0f, 0.0f ),
0.2f );
glPopMatrix();
}
/* cone()
* draw a green cone
*/
void cone(void)
{
/* glLoadName(3);
glPushMatrix();
glTranslatef(cone_x, cone_y, cone_z);
glColor3f(0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, -6.5);
glutSolidCone(4.0, 15.0, 16, 16);
glRotatef(180.0, 1.0, 0.0, 0.0);
glutSolidCone(4.0, 0.0, 16, 1);
glPopMatrix();*/
}
void init(void)
{
//tbInit(GLUT_MIDDLE_BUTTON);
//glSelectBuffer(SELECT_BUFFER, select_buffer);
// glEnable( GL_DITHER );
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
//glEnable(GL_LIGHT0);
//glEnable(GL_LIGHT1);
//glEnable(GL_LIGHT2);
//glEnable(GL_LIGHTING);
// Setup light
// https://www.opengl.org/sdk/docs/man2/xhtml/glLight.xml
// /////////////////////////////////////////////////////////////////////////
{
const GLfloat ambient[] = { 0.1f, 0.0f, 0.1f, 1.0f };
const GLfloat diffuse[] = { 0.3f, 0.3f, 0.3f, 1.0f };
const GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
//const GLfloat lmodel_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
const GLfloat position1[]= { 0.0f, 0.0f, 1.0f, 0.0f }; // defines a directional light that points along the negative z-axis
glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT2, GL_SPECULAR, specular );
glLightfv( GL_LIGHT2, GL_POSITION, position1 );
const GLfloat position2[]= { 0.0f, 0.0f, -1.0f, 0.0f }; // defines a directional light that points along the positive z-axis
glLightfv( GL_LIGHT2, GL_AMBIENT, ambient );
glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse );
glLightfv( GL_LIGHT2, GL_SPECULAR, specular );
glLightfv( GL_LIGHT2, GL_POSITION, position2 );
//glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
}
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glEnable(GL_CULL_FACE);
glClearColor(0.0, 0.0, 1.0, 0.0);
{
const SFVEC4F ambient = SFVEC4F( 0.2,0.2,0.2, 1.0f );
const SFVEC4F diffuse = SFVEC4F( 0.5,0.1,0.1, 1.0f );
const SFVEC4F specular = SFVEC4F( 0.1,0.1,0.8, 1.0f );
//const SFVEC4F emissive = SFVEC4F( material.m_Emissive, 1.0f );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, &ambient.r );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &diffuse.r );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
//glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, &emissive.r );
}
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 128 );
glDisable( GL_COLOR_MATERIAL );
glFrontFace( GL_CCW ); // This is the openGL default
glEnable( GL_NORMALIZE ); // This allow openGL to normalize the normals after transformations
}
void display(void)
{
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
//glClearDepth( 1.0f );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glPushMatrix();
//tbMatrix();
switch(Op) {
case CSG_A:
op_one(A);
break;
case CSG_B:
op_one(B);
break;
case CSG_A_OR_B:
op_or(A, B);
break;
case CSG_A_AND_B:
op_and(A, B);
break;
case CSG_A_SUB_B:
op_sub(A, B);
break;
case CSG_B_SUB_A:
op_sub(B, A);
break;
}
glPopMatrix();
}
static const C3D_RENDER_OGL_LEGACY *renderclass = NULL;
void draw_board(void)
{
if( renderclass )
{
renderclass->GetBoardDispList()->DrawTop();
renderclass->GetBoardDispList()->DrawBot();
}
}
void draw_b_mask(void)
{
if( renderclass )
{
const CLAYERS_OGL_DISP_LISTS *layer = renderclass->GetLayerDispList( B_Mask );
layer->DrawTop();
layer->DrawBot();
}
}
static SFVEC3F light = SFVEC3F();
void C3D_RENDER_OGL_LEGACY::Redraw( bool aIsMoving )
{
// Initialize openGL
if( !m_is_opengl_initialized )
{
if( !initializeOpenGL() )
return;
aIsMoving = true;
A = sphere;
B = cube;
//Op = CSG_A;
//Op = CSG_B;
//Op = CSG_A_OR_B;
//Op = CSG_A_AND_B;
//Op = CSG_A_SUB_B;
Op = CSG_B_SUB_A;
}
/*
const GLfloat position0[]= { 0.0f, 0.0f, 1.0f, 0.0f }; // defines a directional light that points along the negative z-axis
glLightfv( GL_LIGHT0, GL_POSITION, position0 );
*/
if( m_reloadRequested )
reload();
init();
glEnable( GL_LIGHT0 );
glEnable(GL_LIGHTING);
// clear color and depth buffers
// /////////////////////////////////////////////////////////////////////////
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
glClearDepth( 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
// Set projection and modelview matrixes
// /////////////////////////////////////////////////////////////////////////
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( glm::value_ptr( m_settings.CameraGet().GetProjectionMatrix() ) );
glMatrixMode( GL_MODELVIEW );
// Position the headlight
glLoadIdentity();
//glTranslatef( -m_settings.GetBBox3DU().GetCenter().x, -m_settings.GetBBox3DU().GetCenter().y, -m_settings.GetBBox3DU().GetCenter().z );
// glTranslatef( m_settings.GetBBox3DU().GetCenter().x, m_settings.GetBBox3DU().GetCenter().y, m_settings.GetBBox3DU().GetCenter().z );
glLoadMatrixf( glm::value_ptr( m_settings.CameraGet().GetViewMatrix() ) );
{
const SFVEC3F &cameraPos = m_settings.CameraGet().GetPos();//m_settings.CameraGet().GetPos();
const GLfloat headlight_pos[] = { cameraPos.x, cameraPos.y, cameraPos.z, 1.0f };
glLightfv( GL_LIGHT0, GL_POSITION, headlight_pos );
}
const SFVEC4F specular = SFVEC4F( 0.5f, 1.0f, 0.5f, 1.0f );
glMaterialfv( GL_FRONT, GL_SPECULAR, &specular.r );
glMaterialf( GL_FRONT, GL_SHININESS, 10.0f );
SFVEC4F layerColor4 = SFVEC4F( specular.x, specular.y, specular.z, 1.0f );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, &layerColor4.x );
glDisable( GL_COLOR_MATERIAL );
/*
glPushMatrix();
glTranslatef( m_settings.GetBBox3DU().GetCenter().x, m_settings.GetBBox3DU().GetCenter().y, m_settings.GetBBox3DU().GetCenter().z );
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
//const SFVEC4F specular = SFVEC4F( 0.5f, 0.5f, 0.5f, 1.0f );
glMaterialfv( GL_FRONT, GL_SPECULAR, &specular.r );
glMaterialf( GL_FRONT, GL_SHININESS, 10.0f );
glColor3f( 0.9f, 0.0f, 0.0f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( RANGE_SCALE_3D / 1.0f, 0.0f, 0.0f ),
0.2f );
glColor3f( 0.0f, 0.9f, 0.0f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, RANGE_SCALE_3D / 1.0f, 0.0f ),
0.2f );
glColor3f( 0.0f, 0.0f, 0.9f );
OGL_draw_arrow( SFVEC3F( 0.0f, 0.0f, 0.0f ),
SFVEC3F( 0.0f, 0.0f, RANGE_SCALE_3D / 1.0f ),
0.2f );
glPopMatrix();
*/
/*
for( MAP_OGL_DISP_LISTS::const_iterator ii = m_ogl_disp_lists_layers.begin();
ii != m_ogl_disp_lists_layers.end();
ii++ )
{
LAYER_ID layer_id = (LAYER_ID)(ii->first);
// Mask kayers are not processed here because they are a special case
if( (layer_id == B_Mask) || (layer_id == F_Mask) )
continue;
CLAYERS_OGL_DISP_LISTS *pLayerDispList = static_cast<CLAYERS_OGL_DISP_LISTS*>(ii->second);
pLayerDispList->DrawAll();
}
*/
renderclass = this;
//op_sub( draw_b_mask, draw_board );
//op_sub( draw_board, draw_b_mask );
const CLAYERS_OGL_DISP_LISTS *layer = renderclass->GetLayerDispList( B_Mask );
//glEnable(GL_LIGHTING);
//glEnable(GL_LIGHT0);
/*
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_CULL_FACE);
m_ogl_disp_list_board->DrawBot();
*/
glCullFace(GL_BACK);
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE );
layer->DrawBot();
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP );
//glDisable(GL_DEPTH_TEST);
//glCullFace(face);
m_ogl_disp_list_board->DrawBot();
//glClear( GL_STENCIL_BUFFER_BIT );
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 2, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE );
layer->DrawTop();
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_NOTEQUAL, 2, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR );
//glDisable(GL_DEPTH_TEST);
//glCullFace(face);
m_ogl_disp_list_board->DrawTop();
//glClear( GL_STENCIL_BUFFER_BIT );
//glCullFace(GL_FRONT);
/*
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_GEQUAL, 3, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR );
layer->DrawBot();
layer->DrawTop();
*/
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glCullFace(GL_FRONT);
glStencilFunc(GL_GEQUAL, 3, 0x03);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP );
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
layer->DrawMiddle();
}
bool C3D_RENDER_OGL_LEGACY::initializeOpenGL()
{
GLenum err = glewInit();
if( GLEW_OK != err )
{
std::string msgError = (const char*) glewGetErrorString( err );
return false;
}
else
{
wxLogTrace( m_logTrace,
wxString( wxT( "C3D_RENDER_OGL_LEGACY::initializeOpenGL Using GLEW " ) ) +
FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
}
// 4-byte pixel alignment
glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
// Initialize the open GL texture to draw the filled semi-circle of the segments
CIMAGE *circleImage = new CIMAGE( SIZE_OF_CIRCLE_TEXTURE, SIZE_OF_CIRCLE_TEXTURE );
if( !circleImage )
return false;
circleImage->CircleFilled( (SIZE_OF_CIRCLE_TEXTURE / 2) - 0, (SIZE_OF_CIRCLE_TEXTURE / 2) - 0, (SIZE_OF_CIRCLE_TEXTURE / 2) - 4, 0xFF );
//circleImage->CircleFilled( (SIZE_OF_CIRCLE_TEXTURE / 4)*1.5f - 1, (SIZE_OF_CIRCLE_TEXTURE / 4)*1.5f - 1, (SIZE_OF_CIRCLE_TEXTURE / 4)*1.5f - 2, 0xFF );
CIMAGE *bluredCircle = new CIMAGE( *circleImage );
circleImage->EfxFilter( bluredCircle, FILTER_GAUSSIAN_BLUR2 );
m_ogl_circle_texture = OGL_LoadTexture( *circleImage );
circleImage->SaveAsPNG("circleImage.png");
delete circleImage;
circleImage = 0;
if( bluredCircle )
{
bluredCircle->SaveAsPNG("circleImage_blured.png");
delete bluredCircle;
bluredCircle = 0;
}
m_is_opengl_initialized = true;
return true;
}
void C3D_RENDER_OGL_LEGACY::ogl_set_arrow_material()
{
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
const SFVEC4F specular = SFVEC4F( 0.1f, 0.1f, 0.1f, 1.0f );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.r );
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, 96.0f );
}
void C3D_RENDER_OGL_LEGACY::ogl_free_all_display_lists()
{
for( MAP_OGL_DISP_LISTS::const_iterator ii = m_ogl_disp_lists_layers.begin();
ii != m_ogl_disp_lists_layers.end();
ii++ )
{
CLAYERS_OGL_DISP_LISTS *pLayerDispList = static_cast<CLAYERS_OGL_DISP_LISTS*>(ii->second);
delete pLayerDispList;
}
m_ogl_disp_lists_layers.clear();
for( MAP_TRIANGLES::const_iterator ii = m_triangles.begin();
ii != m_triangles.end();
ii++ )
{
CLAYER_TRIANGLES *pointer = static_cast<CLAYER_TRIANGLES*>(ii->second);
delete pointer;
}
m_triangles.clear();
delete m_ogl_disp_list_board;
m_ogl_disp_list_board = 0;
}

View File

@ -0,0 +1,80 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c3d_render_ogl_legacy.h
* @brief
*/
#ifndef C3D_RENDER_OGL_LEGACY_H_
#define C3D_RENDER_OGL_LEGACY_H_
#include "../c3d_render_base.h"
#include "clayer_triangles.h"
#include <map>
typedef std::map< LAYER_ID, CLAYERS_OGL_DISP_LISTS* > MAP_OGL_DISP_LISTS;
typedef std::map< LAYER_ID, CLAYER_TRIANGLES * > MAP_TRIANGLES;
#define SIZE_OF_CIRCLE_TEXTURE 512
/**
* @brief The C3D_RENDER_OGL_LEGACY class render the board using openGL legacy mode
*/
class C3D_RENDER_OGL_LEGACY : public C3D_RENDER_BASE
{
public:
C3D_RENDER_OGL_LEGACY( CINFO3D_VISU &aSettings,
S3D_CACHE *a3DModelManager );
~C3D_RENDER_OGL_LEGACY();
// Imported from C3D_RENDER_BASE
void SetCurWindowSize( const wxSize &aSize );
void Redraw( bool aIsMoving );
private:
bool initializeOpenGL();
void reload();
void ogl_set_arrow_material();
void ogl_free_all_display_lists();
MAP_OGL_DISP_LISTS m_ogl_disp_lists_layers;
CLAYERS_OGL_DISP_LISTS* m_ogl_disp_list_board;
MAP_TRIANGLES m_triangles;
GLuint m_ogl_circle_texture;
private:
void add_triangle_top_bot( CLAYER_TRIANGLES *aDst, const SFVEC2F &v0, const SFVEC2F &v1, const SFVEC2F &v2, float top, float bot );
public:
const MAP_OGL_DISP_LISTS &GetLayerDispListMap() const { return m_ogl_disp_lists_layers; }
const CLAYERS_OGL_DISP_LISTS *GetLayerDispList( LAYER_ID aLayerId ) const { return m_ogl_disp_lists_layers.at( aLayerId ); }
const CLAYERS_OGL_DISP_LISTS *GetBoardDispList() const { return m_ogl_disp_list_board; }
};
#endif // C3D_RENDER_OGL_LEGACY_H_

View File

@ -0,0 +1,281 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c_ogl_3dmodel.cpp
* @brief
*/
#include "c_ogl_3dmodel.h"
#include "ogl_legacy_utils.h"
#include "common_ogl/ogl_utils.h"
#include <wx/debug.h>
C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel )
{
m_ogl_idx_list_opaque = 0;
m_ogl_idx_list_transparent = 0;
m_nr_meshes = 0;
m_meshs_bbox = NULL;
// Validate a3DModel pointers
wxASSERT( a3DModel.m_Materials != NULL );
wxASSERT( a3DModel.m_Meshes != NULL );
wxASSERT( a3DModel.m_MaterialsSize > 0 );
wxASSERT( a3DModel.m_MeshesSize > 0 );
if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
(a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
{
m_nr_meshes = a3DModel.m_MeshesSize;
m_meshs_bbox = new CBBOX[a3DModel.m_MeshesSize];
// Generate m_MeshesSize auxiliar lists to render the meshes
GLuint m_ogl_idx_list_meshes = glGenLists( a3DModel.m_MeshesSize );
// Render each mesh of the model
// /////////////////////////////////////////////////////////////////////
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
{
if( glIsList( m_ogl_idx_list_meshes + mesh_i ) )
{
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
// Validate the mesh pointers
wxASSERT( mesh.m_Positions != NULL );
wxASSERT( mesh.m_FaceIdx != NULL );
wxASSERT( mesh.m_Normals != NULL );
if( (mesh.m_Positions != NULL) &&
(mesh.m_Normals != NULL) &&
(mesh.m_FaceIdx != NULL) &&
(mesh.m_FaceIdxSize > 0) && (mesh.m_VertexSize > 0) )
{
// Create the bbox for this mesh
// /////////////////////////////////////////////////////////
m_meshs_bbox[mesh_i].Reset();
for( unsigned int vertex_i = 0; vertex_i < mesh.m_VertexSize; ++vertex_i )
m_meshs_bbox[mesh_i].Union( mesh.m_Positions[vertex_i] );
// Make sure we start with client state disabled
// /////////////////////////////////////////////////////////
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
// Enable arrays client states
// /////////////////////////////////////////////////////////
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, mesh.m_Positions );
glNormalPointer( GL_FLOAT, 0, mesh.m_Normals );
if( mesh.m_Color != NULL )
{
glEnableClientState( GL_COLOR_ARRAY );
glColorPointer( 3, GL_FLOAT, 0, mesh.m_Color );
}
if( mesh.m_Texcoords != NULL )
{
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 0, mesh.m_Texcoords );
}
// Compile the display list to store triangles
// /////////////////////////////////////////////////////////
glNewList( m_ogl_idx_list_meshes + mesh_i, GL_COMPILE );
// Set material properties
// /////////////////////////////////////////////////////////
if( mesh.m_Color != NULL )
{
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
}
else
{
glDisable( GL_COLOR_MATERIAL );
}
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
OGL_SetMaterial( a3DModel.m_Materials[mesh.m_MaterialIdx] );
}
// Draw mesh
// /////////////////////////////////////////////////////////
glDrawElements( GL_TRIANGLES, mesh.m_FaceIdxSize, GL_UNSIGNED_INT, mesh.m_FaceIdx );
glEndList();
// Disable arrays client states
// /////////////////////////////////////////////////////////
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
}
}
}// for each mesh
bool have_opaque_meshes = false;
bool have_transparent_meshes = false;
m_ogl_idx_list_opaque = glGenLists( 1 );
// Check if the generated list is valid
if( glIsList( m_ogl_idx_list_opaque ) )
{
// Compile the model display list
glNewList( m_ogl_idx_list_opaque, GL_COMPILE );
// Render each mesh display list (opaque first)
// /////////////////////////////////////////////////////////////////
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
{
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
if( material.m_Transparency == 0.0f )
{
have_opaque_meshes = true; // Flag that we have at least one opaque mesh
glCallList( m_ogl_idx_list_meshes + mesh_i );
}
else
{
have_transparent_meshes = true; // Flag that we found a transparent mesh
}
}
}
glEndList();
if( !have_opaque_meshes )
{
glDeleteLists( m_ogl_idx_list_opaque, 1 ); // If we dont have opaque meshes, we can free the list
m_ogl_idx_list_opaque = 0;
}
if( have_transparent_meshes )
{
m_ogl_idx_list_transparent = glGenLists( 1 );
// Check if the generated list is valid
if( glIsList( m_ogl_idx_list_transparent ) )
{
// Compile the model display list
glNewList( m_ogl_idx_list_transparent, GL_COMPILE );
// Render each mesh display list (opaque first)
// /////////////////////////////////////////////////////////
for( unsigned mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
{
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
{
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
if( material.m_Transparency != 0.0f )
glCallList( m_ogl_idx_list_meshes + mesh_i ); // Render the transparent mesh
}
}
glEndList();
}
else
{
m_ogl_idx_list_transparent = 0;
}
}
}
else
{
m_ogl_idx_list_opaque = 0;
}
// Create the main bbox
// /////////////////////////////////////////////////////////////////////
m_model_bbox.Reset();
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
m_model_bbox.Union( m_meshs_bbox[mesh_i] );
}
}
void C_OGL_3DMODEL::Draw_opaque() const
{
if( glIsList( m_ogl_idx_list_opaque ) )
glCallList( m_ogl_idx_list_opaque );
}
void C_OGL_3DMODEL::Draw_transparent() const
{
if( glIsList( m_ogl_idx_list_transparent ) )
glCallList( m_ogl_idx_list_transparent );
}
C_OGL_3DMODEL::~C_OGL_3DMODEL()
{
if( glIsList( m_ogl_idx_list_opaque ) )
glDeleteLists( m_ogl_idx_list_opaque, 1 );
if( glIsList( m_ogl_idx_list_transparent ) )
glDeleteLists( m_ogl_idx_list_transparent, 1 );
if( glIsList( m_ogl_idx_list_meshes ) )
glDeleteLists( m_ogl_idx_list_meshes, m_nr_meshes );
m_ogl_idx_list_meshes = 0;
m_ogl_idx_list_opaque = 0;
m_ogl_idx_list_transparent = 0;
delete[] m_meshs_bbox;
m_meshs_bbox = NULL;
}
void C_OGL_3DMODEL::Draw_bbox() const
{
OGL_draw_bbox( m_model_bbox );
}
void C_OGL_3DMODEL::Draw_bboxes() const
{
for( unsigned int mesh_i = 0; mesh_i < m_nr_meshes; ++mesh_i )
OGL_draw_bbox( m_meshs_bbox[mesh_i] );
}

View File

@ -0,0 +1,85 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 c_ogl_3dmodel.h
* @brief implement a legacy 3dmodel render
*/
#ifndef _C_OGL_3DMODEL_H_
#define _C_OGL_3DMODEL_H_
#include "3d_rendering/c3dmodel.h"
#include "common_ogl/openGL_includes.h"
#include "3d_rendering/3d_render_raytracing/shapes3D/cbbox.h"
///
class GLM_ALIGN(CLASS_ALIGNMENT) C_OGL_3DMODEL
{
public:
/**
* @brief C_OGL_3DMODEL - Load a 3d model. This must be called inside a gl context
* @param a3DModel: a 3d model data to load.
*/
C_OGL_3DMODEL( const S3DMODEL &a3DModel );
~C_OGL_3DMODEL();
/**
* @brief Draw_opaque - render the model into the current context
*/
void Draw_opaque() const;
/**
* @brief Draw_transparent - render the model into the current context
*/
void Draw_transparent() const;
/**
* @brief Draw_bbox - draw main bounding box of the model
*/
void Draw_bbox() const;
/**
* @brief Draw_bboxes - draw individual bounding boxes of each mesh
*/
void Draw_bboxes() const;
/**
* @brief GetBBox - Get main bbox
* @return the main model bbox
*/
const CBBOX &GetBBox() const { return m_model_bbox; }
private:
GLuint m_ogl_idx_list_opaque; ///< display list for rendering opaque meshes
GLuint m_ogl_idx_list_transparent; ///< display list for rendering transparent meshes
GLuint m_ogl_idx_list_meshes; ///< display lists for all meshes.
unsigned int m_nr_meshes; ///< number of meshes of this model
CBBOX m_model_bbox; ///< global bounding box for this model
CBBOX *m_meshs_bbox; ///< individual bbox for each mesh
};
#endif // _C_OGL_3DMODEL_H_

Some files were not shown because too many files have changed in this diff Show More