7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-20 20:51:42 +00:00

+ 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
3d-viewer
3d_cache
3d_canvas.h
3d_canvas
3d_draw.cpp3d_draw_board_body.cpp3d_material.h
3d_math
3d_mesh_model.cpp3d_mesh_model.h
3d_model_viewer
3d_read_mesh.cpp
3d_rendering
3d_struct.h3d_types.h
3d_xv3d
CBBox.cppCMakeLists.txt
common_ogl
vrml_aux.h
CMakeLists.txt
CMakeModules
common
cvpcb
include
gal/opengl
glm
core
ext.hppglm.hpp
gtc
gtx
associated_min_max.hppassociated_min_max.inlbit.hppbit.inlclosest_point.hppclosest_point.inlcolor_cast.hppcolor_cast.inlcolor_space.hppcolor_space.inlcolor_space_YCoCg.hppcolor_space_YCoCg.inlcompatibility.hppcompatibility.inlcomponent_wise.hppcomponent_wise.inlconstants.hppepsilon.hppeuler_angles.hppeuler_angles.inlextend.hppextend.inlextented_min_max.hppextented_min_max.inlfast_exponential.hppfast_exponential.inlfast_square_root.hppfast_square_root.inlfast_trigonometry.hppfast_trigonometry.inlgradient_paint.hppgradient_paint.inlhanded_coordinate_space.hpphanded_coordinate_space.inlinertia.hppinertia.inlint_10_10_10_2.hppint_10_10_10_2.inlinteger.hppinteger.inlintersect.hppintersect.inllog_base.hpplog_base.inlmatrix_cross_product.hppmatrix_cross_product.inlmatrix_interpolation.hppmatrix_interpolation.inlmatrix_major_storage.hppmatrix_major_storage.inlmatrix_operation.hppmatrix_operation.inlmatrix_query.hppmatrix_query.inlmixed_product.hppmixed_product.inlmultiple.hppmultiple.inlnoise.hppnorm.hppnorm.inlnormal.hppnormal.inlnormalize_dot.hppnormalize_dot.inlnumber_precision.hppnumber_precision.inlocl_type.hppocl_type.inloptimum_pow.hppoptimum_pow.inlorthonormalize.hpporthonormalize.inlperpendicular.hppperpendicular.inlpolar_coordinates.hpppolar_coordinates.inlprojection.hppprojection.inlquaternion.hppquaternion.inlrandom.hppraw_data.hppraw_data.inlreciprocal.hpprotate_vector.hpprotate_vector.inlsimd_mat4.hppsimd_mat4.inlsimd_vec4.hppsimd_vec4.inlspline.hppspline.inlstd_based_type.hppstd_based_type.inlstring_cast.hppstring_cast.inltransform.hpptransform.inltransform2.hpptransform2.inlulp.hppunsigned_int.hppunsigned_int.inlvec1.hppvec1.inlvector_access.hppvector_access.inlvector_angle.hppvector_angle.inlvector_query.hppvector_query.inlverbose_operator.hppverbose_operator.inlwrap.hppwrap.inl
virtrev
vertex_manager.h
plugins
project.h
pcbnew
plugins

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

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