3D-viewer: Fixes and enhancements. Add comments in header files. Fix some coding style issues.
This commit is contained in:
parent
33acfae75a
commit
eee901ff57
|
@ -105,9 +105,9 @@ void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUni
|
|||
ay = aVertices[1].y - aVertices[0].y;
|
||||
az = aVertices[1].z - aVertices[0].z;
|
||||
|
||||
bx = aVertices[aVertices.size() - 1].x - aVertices[0].x;
|
||||
by = aVertices[aVertices.size() - 1].y - aVertices[0].y;
|
||||
bz = aVertices[aVertices.size() - 1].z - aVertices[0].z;
|
||||
bx = aVertices[2].x - aVertices[0].x;
|
||||
by = aVertices[2].y - aVertices[0].y;
|
||||
bz = aVertices[2].z - aVertices[0].z;
|
||||
|
||||
nx = ay * bz - az * by;
|
||||
ny = az * bx - ax * bz;
|
||||
|
|
|
@ -94,6 +94,8 @@ EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) :
|
|||
m_ZBottom = 0.0;
|
||||
m_ZTop = 0.0;
|
||||
|
||||
m_lightPos = S3D_VERTEX(0.0f, 0.0f, 50.0f);
|
||||
|
||||
// Clear all gl list identifiers:
|
||||
for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ )
|
||||
m_glLists[ii] = 0;
|
||||
|
@ -110,6 +112,12 @@ EDA_3D_CANVAS::~EDA_3D_CANVAS()
|
|||
ClearLists();
|
||||
m_init = false;
|
||||
delete m_glRC;
|
||||
|
||||
// Free the list of parsers list
|
||||
for( unsigned int i = 0; i < m_model_parsers_list.size(); i++ )
|
||||
if( m_model_parsers_list[i] )
|
||||
delete m_model_parsers_list[i];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -132,6 +140,17 @@ void EDA_3D_CANVAS::ClearLists( int aGlList )
|
|||
|
||||
m_glLists[ii] = 0;
|
||||
}
|
||||
|
||||
if( m_text_fake_shadow_front >= 0 )
|
||||
glDeleteTextures( 1, &m_text_fake_shadow_front );
|
||||
|
||||
if( m_text_fake_shadow_back >= 0 )
|
||||
glDeleteTextures( 1, &m_text_fake_shadow_back );
|
||||
|
||||
if( m_text_fake_shadow_board >= 0 )
|
||||
glDeleteTextures( 1, &m_text_fake_shadow_board );
|
||||
|
||||
m_shadow_init = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -564,12 +583,12 @@ void EDA_3D_CANVAS::InitGL()
|
|||
void EDA_3D_CANVAS::SetLights()
|
||||
{
|
||||
// activate light. the source is above the xy plane, at source_pos
|
||||
GLfloat source_pos[4] = { 0.0, 0.0, 1000.0, 0.0 };
|
||||
GLfloat source_pos[4] = { m_lightPos.x, m_lightPos.y, m_lightPos.z, 0.0f };
|
||||
GLfloat light_color[4]; // color of lights (RGBA values)
|
||||
light_color[3] = 1.0;
|
||||
|
||||
// Light above the xy plane
|
||||
light_color[0] = light_color[1] = light_color[2] = 0.1;
|
||||
light_color[0] = light_color[1] = light_color[2] = 0.2;
|
||||
glLightfv( GL_LIGHT0, GL_AMBIENT, light_color );
|
||||
|
||||
light_color[0] = light_color[1] = light_color[2] = 1.0;
|
||||
|
@ -580,7 +599,7 @@ void EDA_3D_CANVAS::SetLights()
|
|||
|
||||
glLightfv( GL_LIGHT0, GL_POSITION, source_pos );
|
||||
|
||||
light_color[0] = light_color[1] = light_color[2] = 0.1;
|
||||
light_color[0] = light_color[1] = light_color[2] = 0.2;
|
||||
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, light_color );
|
||||
|
||||
glEnable( GL_LIGHT0 ); // White spot on Z axis ( top )
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
#endif
|
||||
|
||||
#include <3d_struct.h>
|
||||
#include <modelparsers.h>
|
||||
#include <class_module.h>
|
||||
#include <CBBox.h>
|
||||
|
||||
class BOARD_DESIGN_SETTINGS;
|
||||
class EDA_3D_FRAME;
|
||||
|
@ -78,16 +80,15 @@ class EDA_3D_CANVAS : public wxGLCanvas
|
|||
{
|
||||
private:
|
||||
bool m_init;
|
||||
bool m_reportWarnings; // true to report all wranings when build the 3D scene
|
||||
// false to report errors only
|
||||
GLuint m_glLists[GL_ID_END]; // GL lists
|
||||
bool m_reportWarnings; ///< true to report all wranings when build the 3D scene false to report errors only
|
||||
GLuint m_glLists[GL_ID_END]; ///< GL lists
|
||||
wxGLContext* m_glRC;
|
||||
wxRealPoint m_draw3dOffset; // offset to draw the 3D mesh.
|
||||
double m_ZBottom; // position of the back layer
|
||||
double m_ZTop; // position of the front layer
|
||||
wxRealPoint m_draw3dOffset; ///< offset to draw the 3D mesh.
|
||||
double m_ZBottom; ///< position of the back layer
|
||||
double m_ZTop; ///< position of the front layer
|
||||
|
||||
GLuint m_text_pcb; // an index to the texture generated for pcb texts
|
||||
GLuint m_text_silk; // an index to the texture generated for silk layers
|
||||
GLuint m_text_pcb; ///< an index to the texture generated for pcb texts
|
||||
GLuint m_text_silk; ///< an index to the texture generated for silk layers
|
||||
|
||||
// Index to the textures generated for shadows
|
||||
bool m_shadow_init;
|
||||
|
@ -95,9 +96,21 @@ private:
|
|||
GLuint m_text_fake_shadow_back;
|
||||
GLuint m_text_fake_shadow_board;
|
||||
|
||||
void Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture,
|
||||
CBBOX m_boardAABBox; ///< Axis Align Bounding Box of the board
|
||||
CBBOX m_fastAABBox; ///< Axis Align Bounding Box that contain the other bounding boxes
|
||||
CBBOX m_fastAABBox_Shadow; ///< A bit scalled version of the m_fastAABBox
|
||||
|
||||
S3D_VERTEX m_lightPos;
|
||||
|
||||
/// Stores the list of parsers for each new file name (dont repeat files already loaded)
|
||||
std::vector<S3D_MODEL_PARSER *> m_model_parsers_list;
|
||||
std::vector<wxString> m_model_filename_list;
|
||||
|
||||
void create_and_render_shadow_buffer( GLuint *aDst_gl_texture,
|
||||
GLuint aTexture_size, bool aDraw_body, int aBlurPasses );
|
||||
|
||||
void calcBBox();
|
||||
|
||||
public:
|
||||
EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList = 0 );
|
||||
~EDA_3D_CANVAS();
|
||||
|
@ -187,33 +200,33 @@ private:
|
|||
wxPoint getBoardCenter() const;
|
||||
|
||||
/**
|
||||
* Helper function SetGLTechLayersColor
|
||||
* Helper function setGLTechLayersColor
|
||||
* Initialize the color to draw the non copper layers
|
||||
* in realistic mode and normal mode.
|
||||
*/
|
||||
void setGLTechLayersColor( LAYER_NUM aLayer );
|
||||
|
||||
/**
|
||||
* Helper function SetGLCopperColor
|
||||
* Helper function setGLCopperColor
|
||||
* Initialize the copper color to draw the board
|
||||
* in realistic mode (a golden yellow color )
|
||||
*/
|
||||
void setGLCopperColor();
|
||||
|
||||
/**
|
||||
* Helper function SetGLEpoxyColor
|
||||
* Helper function setGLEpoxyColor
|
||||
* Initialize the color to draw the epoxy body board in realistic mode.
|
||||
*/
|
||||
void setGLEpoxyColor( float aTransparency = 1.0 );
|
||||
|
||||
/**
|
||||
* Helper function SetGLSolderMaskColor
|
||||
* Helper function setGLSolderMaskColor
|
||||
* Initialize the color to draw the solder mask layers in realistic mode.
|
||||
*/
|
||||
void setGLSolderMaskColor( float aTransparency = 1.0 );
|
||||
|
||||
/**
|
||||
* Function BuildBoard3DView
|
||||
* Function buildBoard3DView
|
||||
* Called by CreateDrawGL_List()
|
||||
* Populates the OpenGL GL_ID_BOARD draw list with board items only on copper layers.
|
||||
* 3D footprint shapes, tech layers and aux layers are not on this list
|
||||
|
@ -224,27 +237,27 @@ private:
|
|||
* created by the build process (can be NULL)
|
||||
* @param aShowWarnings = true to show all messages, false to show errors only
|
||||
*/
|
||||
void BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
|
||||
void buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
|
||||
wxString* aErrorMessages, bool aShowWarnings );
|
||||
|
||||
/**
|
||||
* Function BuildTechLayers3DView
|
||||
* Function buildTechLayers3DView
|
||||
* Called by CreateDrawGL_List()
|
||||
* Populates the OpenGL GL_ID_TECH_LAYERS draw list with items on tech layers
|
||||
* @param aErrorMessages = a wxString to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aShowWarnings = true to show all messages, false to show errors only
|
||||
*/
|
||||
void BuildTechLayers3DView( wxString* aErrorMessages, bool aShowWarnings );
|
||||
void buildTechLayers3DView( wxString* aErrorMessages, bool aShowWarnings );
|
||||
|
||||
/**
|
||||
* Function BuildShadowList
|
||||
* Function buildShadowList
|
||||
* Called by CreateDrawGL_List()
|
||||
*/
|
||||
void BuildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList );
|
||||
void buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList );
|
||||
|
||||
/**
|
||||
* Function BuildFootprintShape3DList
|
||||
* Function buildFootprintShape3DList
|
||||
* Called by CreateDrawGL_List()
|
||||
* Fills the OpenGL GL_ID_3DSHAPES_SOLID and GL_ID_3DSHAPES_TRANSP
|
||||
* draw lists with 3D footprint shapes
|
||||
|
@ -252,19 +265,18 @@ private:
|
|||
* @param aTransparentList is the gl list for non transparent items,
|
||||
* which need to be drawn after all other items
|
||||
*/
|
||||
void BuildFootprintShape3DList( GLuint aOpaqueList,
|
||||
GLuint aTransparentList,
|
||||
bool aSideToLoad );
|
||||
void buildFootprintShape3DList( GLuint aOpaqueList,
|
||||
GLuint aTransparentList );
|
||||
/**
|
||||
* Function BuildBoard3DAuxLayers
|
||||
* Function buildBoard3DAuxLayers
|
||||
* Called by CreateDrawGL_List()
|
||||
* Fills the OpenGL GL_ID_AUX_LAYERS draw list
|
||||
* with items on aux layers only
|
||||
*/
|
||||
void BuildBoard3DAuxLayers();
|
||||
void buildBoard3DAuxLayers();
|
||||
|
||||
void Draw3DGrid( double aGriSizeMM );
|
||||
void Draw3DAxis();
|
||||
void draw3DGrid( double aGriSizeMM );
|
||||
void draw3DAxis();
|
||||
|
||||
/**
|
||||
* Helper function BuildPadShapeThickOutlineAsPolygon:
|
||||
|
@ -272,7 +284,7 @@ private:
|
|||
* with a line thickness = aWidth
|
||||
* Used only to draw pads outlines on silkscreen layers.
|
||||
*/
|
||||
void BuildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
void buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
CPOLYGONS_LIST& aCornerBuffer,
|
||||
int aWidth,
|
||||
int aCircleToSegmentsCount,
|
||||
|
@ -280,54 +292,48 @@ private:
|
|||
|
||||
|
||||
/**
|
||||
* Helper function Draw3DViaHole:
|
||||
* Helper function draw3DViaHole:
|
||||
* Draw the via hole:
|
||||
* Build a vertical hole (a cylinder) between the first and the last via layers
|
||||
*/
|
||||
void Draw3DViaHole( const VIA * aVia );
|
||||
void draw3DViaHole( const VIA * aVia );
|
||||
|
||||
/**
|
||||
* Helper function Draw3DPadHole:
|
||||
* Helper function draw3DPadHole:
|
||||
* Draw the pad hole:
|
||||
* Build a vertical hole (round or oblong) between the front and back layers
|
||||
*/
|
||||
void Draw3DPadHole( const D_PAD * aPad );
|
||||
void draw3DPadHole( const D_PAD * aPad );
|
||||
|
||||
/**
|
||||
* function Render3DComponentShape
|
||||
* function render3DComponentShape
|
||||
* insert mesh in gl list
|
||||
* @param module
|
||||
* @param aIsRenderingJustNonTransparentObjects = true to load non transparent objects
|
||||
* @param aIsRenderingJustTransparentObjects = true to load non transparent objects
|
||||
* @param aSideToLoad = false will load not fliped, true will load fliped objects
|
||||
* in openGL, transparent objects should be drawn *after* non transparent objects
|
||||
*/
|
||||
void Render3DComponentShape( MODULE* module,
|
||||
void render3DComponentShape( MODULE* module,
|
||||
bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects,
|
||||
bool aSideToLoad );
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
|
||||
/**
|
||||
* function Read3DComponentShape
|
||||
* function read3DComponentShape
|
||||
* read the 3D component shape(s) of the footprint (physical shape).
|
||||
* @param module
|
||||
* @param model_parsers_list = list of each new model loaded
|
||||
* @param model_filename_list = list of each new filename model loaded
|
||||
* @return true if load was succeeded, false otherwise
|
||||
*/
|
||||
bool Read3DComponentShape( MODULE* module,
|
||||
std::vector<S3D_MODEL_PARSER *>& model_parsers_list,
|
||||
std::vector<wxString>& model_filename_list );
|
||||
bool read3DComponentShape( MODULE* module );
|
||||
|
||||
/**
|
||||
* function GenerateFakeShadowsTextures
|
||||
* function generateFakeShadowsTextures
|
||||
* creates shadows of the board an footprints
|
||||
* for aesthetical purpose
|
||||
* @param aErrorMessages = a wxString to add error and warning messages
|
||||
* created by the build process (can be NULL)
|
||||
* @param aShowWarnings = true to show all messages, false to show errors only
|
||||
*/
|
||||
void GenerateFakeShadowsTextures( wxString* aErrorMessages, bool aShowWarnings );
|
||||
void generateFakeShadowsTextures( wxString* aErrorMessages, bool aShowWarnings );
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
/**
|
||||
* @file 3d_class.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
|
@ -25,7 +21,10 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file 3d_class.cpp
|
||||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
|
||||
#include "3d_viewer.h"
|
||||
|
@ -79,12 +78,14 @@ S3D_MASTER:: ~S3D_MASTER()
|
|||
{
|
||||
next = m_3D_Drawings->Next();
|
||||
delete m_3D_Drawings;
|
||||
m_3D_Drawings = 0;
|
||||
}
|
||||
|
||||
for( ; m_Materials != NULL; m_Materials = nextmat )
|
||||
{
|
||||
nextmat = m_Materials->Next();
|
||||
delete m_Materials;
|
||||
m_Materials = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,19 +116,59 @@ void S3D_MASTER::SetShape3DName( const wxString& aShapeName )
|
|||
return;
|
||||
|
||||
wxFileName fn = m_Shape3DName;
|
||||
wxString ext = fn.GetExt();
|
||||
m_Shape3DNameExtension = fn.GetExt();
|
||||
|
||||
if( ext == wxT( "wrl" ) || ext == wxT( "x3d" ) )
|
||||
if( m_Shape3DNameExtension == wxT( "wrl" ) ||
|
||||
m_Shape3DNameExtension == wxT( "x3d" ) )
|
||||
m_ShapeType = FILE3D_VRML;
|
||||
else if( ext == wxT( "idf" ) )
|
||||
else if( m_Shape3DNameExtension == wxT( "idf" ) )
|
||||
m_ShapeType = FILE3D_IDF;
|
||||
else
|
||||
m_ShapeType = FILE3D_UNKNOWN;
|
||||
|
||||
// Expand any environment variables embedded in footprint's m_Shape3DName field.
|
||||
// To ensure compatibility with most of footprint's m_Shape3DName field,
|
||||
// if the m_Shape3DName is not an absolute path the default path
|
||||
// given by the environment variable KISYS3DMOD will be used
|
||||
|
||||
if( m_Shape3DName.StartsWith( wxT("${") ) )
|
||||
m_Shape3DFullFilename = wxExpandEnvVars( m_Shape3DName );
|
||||
else
|
||||
m_Shape3DFullFilename = m_Shape3DName;
|
||||
|
||||
wxFileName fnFull( m_Shape3DFullFilename );
|
||||
|
||||
if( !( fnFull.IsAbsolute() || m_Shape3DFullFilename.StartsWith( wxT(".") ) ) )
|
||||
{
|
||||
wxString default_path;
|
||||
wxGetEnv( KISYS3DMOD, &default_path );
|
||||
|
||||
if( !( default_path.IsEmpty() ) )
|
||||
{
|
||||
|
||||
if( !default_path.EndsWith( wxT("/") ) && !default_path.EndsWith( wxT("\\") ) )
|
||||
default_path += wxT("/");
|
||||
|
||||
m_Shape3DFullFilename = default_path + m_Shape3DFullFilename;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const wxString S3D_MASTER::GetShape3DFullFilename()
|
||||
{
|
||||
return m_Shape3DFullFilename;
|
||||
}
|
||||
|
||||
|
||||
const wxString S3D_MASTER::GetShape3DExtension()
|
||||
{
|
||||
return m_Shape3DNameExtension;
|
||||
}
|
||||
|
||||
|
||||
STRUCT_3D_SHAPE::STRUCT_3D_SHAPE( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( aParent, NOT_USED )
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,7 +36,7 @@
|
|||
#include <modelparsers.h>
|
||||
|
||||
// Number of segments to approximate a circle by segments
|
||||
#define SEGM_PER_CIRCLE 16
|
||||
#define SEGM_PER_CIRCLE 24
|
||||
|
||||
#ifndef CALLBACK
|
||||
#define CALLBACK
|
||||
|
@ -57,12 +57,12 @@ static void CALLBACK tessCPolyPt2Vertex( const GLvoid* data );
|
|||
// 2 helper functions to set the current normal vector for gle items
|
||||
static inline void SetNormalZpos()
|
||||
{
|
||||
//glNormal3f( 0.0, 0.0, 1.0 );
|
||||
glNormal3f( 0.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
static inline void SetNormalZneg()
|
||||
{
|
||||
//glNormal3f( 0.0, 0.0, -1.0 );
|
||||
glNormal3f( 0.0, 0.0, -1.0 );
|
||||
}
|
||||
|
||||
void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits );
|
||||
|
@ -203,7 +203,8 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
|
|||
}
|
||||
|
||||
// https://www.opengl.org/sdk/docs/man2/xhtml/gluTessNormal.xml
|
||||
gluTessNormal( tess, 0.0, 0.0, 0.0 );
|
||||
if( !aThickness )
|
||||
gluTessNormal( tess, 0.0, 0.0, 0.0 );
|
||||
|
||||
|
||||
v_data[0] = polylist.GetX( ii ) * aBiuTo3DUnits;
|
||||
|
@ -231,7 +232,8 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
|
|||
s_currentZpos = zpos; // for Tess callback functions
|
||||
v_data[2] = zpos;
|
||||
// Set normal toward negative Z axis, for a solid object on bottom side
|
||||
SetNormalZneg();
|
||||
if( aThickness )
|
||||
SetNormalZneg();
|
||||
}
|
||||
|
||||
if( startContour == 0 )
|
||||
|
@ -248,7 +250,7 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
|
|||
}
|
||||
|
||||
// Build the 3D data : vertical side
|
||||
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0), false, aBiuTo3DUnits );
|
||||
Draw3D_VerticalPolygonalCylinder( polylist, aThickness, aZpos - (aThickness / 2.0), true, aBiuTo3DUnits );
|
||||
}
|
||||
|
||||
|
||||
|
@ -292,9 +294,11 @@ void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
|
|||
|
||||
if( aHeight )
|
||||
{
|
||||
|
||||
// Draw the vertical outer side
|
||||
Draw3D_VerticalPolygonalCylinder( outer_cornerBuffer,
|
||||
aHeight, aZpos, false, aBiuTo3DUnits );
|
||||
|
||||
if( aThickness )
|
||||
// Draws the vertical inner side (hole)
|
||||
Draw3D_VerticalPolygonalCylinder( inner_cornerBuffer,
|
||||
|
|
|
@ -181,7 +181,7 @@ void EDA_3D_CANVAS::setGLTechLayersColor( LAYER_NUM aLayer )
|
|||
}
|
||||
}
|
||||
|
||||
void EDA_3D_CANVAS::Draw3DAxis()
|
||||
void EDA_3D_CANVAS::draw3DAxis()
|
||||
{
|
||||
if( ! m_glLists[GL_ID_AXIS] )
|
||||
{
|
||||
|
@ -207,7 +207,7 @@ void EDA_3D_CANVAS::Draw3DAxis()
|
|||
|
||||
// draw a 3D grid: an horizontal grid (XY plane and Z = 0,
|
||||
// and a vertical grid (XZ plane and Y = 0)
|
||||
void EDA_3D_CANVAS::Draw3DGrid( double aGriSizeMM )
|
||||
void EDA_3D_CANVAS::draw3DGrid( double aGriSizeMM )
|
||||
{
|
||||
double zpos = 0.0;
|
||||
EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines
|
||||
|
@ -343,7 +343,7 @@ void EDA_3D_CANVAS::Draw3DGrid( double aGriSizeMM )
|
|||
|
||||
|
||||
// Draw 3D pads.
|
||||
void EDA_3D_CANVAS::Draw3DPadHole( const D_PAD* aPad )
|
||||
void EDA_3D_CANVAS::draw3DPadHole( const D_PAD* aPad )
|
||||
{
|
||||
// Draw the pad hole
|
||||
wxSize drillsize = aPad->GetDrillSize();
|
||||
|
@ -363,13 +363,13 @@ void EDA_3D_CANVAS::Draw3DPadHole( const D_PAD* aPad )
|
|||
else
|
||||
SetGLColor( DARKGRAY );
|
||||
|
||||
int holeZpoz = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ) + thickness / 2;
|
||||
int holeHeight = height - thickness;
|
||||
int holeZpoz = GetPrm3DVisu().GetLayerZcoordBIU( B_Cu ) - thickness / 2;
|
||||
int holeHeight = height + thickness;
|
||||
|
||||
if( drillsize.x == drillsize.y ) // usual round hole
|
||||
{
|
||||
Draw3D_ZaxisCylinder( aPad->GetPosition(),
|
||||
(drillsize.x + thickness) / 2, holeHeight,
|
||||
(drillsize.x + thickness / 2) / 2, holeHeight,
|
||||
thickness, holeZpoz, GetPrm3DVisu().m_BiuTo3Dunits );
|
||||
}
|
||||
else // Oblong hole
|
||||
|
@ -401,11 +401,11 @@ void EDA_3D_CANVAS::Draw3DPadHole( const D_PAD* aPad )
|
|||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::Draw3DViaHole( const VIA* aVia )
|
||||
void EDA_3D_CANVAS::draw3DViaHole( const VIA* aVia )
|
||||
{
|
||||
LAYER_ID top_layer, bottom_layer;
|
||||
int inner_radius = aVia->GetDrillValue() / 2;
|
||||
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
|
||||
int inner_radius = (int)((float)aVia->GetDrillValue() * 1.01f) / 2.0f; // This add a bit more in order to correct a draw artifact while using tickness
|
||||
|
||||
aVia->LayerPair( &top_layer, &bottom_layer );
|
||||
|
||||
|
@ -419,17 +419,17 @@ void EDA_3D_CANVAS::Draw3DViaHole( const VIA* aVia )
|
|||
}
|
||||
|
||||
int height = GetPrm3DVisu().GetLayerZcoordBIU( top_layer ) -
|
||||
GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) - thickness;
|
||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) + thickness / 2;
|
||||
GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) + thickness;
|
||||
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( bottom_layer ) - thickness / 2;
|
||||
|
||||
Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius + thickness / 2, height,
|
||||
Draw3D_ZaxisCylinder( aVia->GetStart(), inner_radius, height,
|
||||
thickness, zpos, GetPrm3DVisu().m_BiuTo3Dunits );
|
||||
}
|
||||
|
||||
/* Build a pad outline as non filled polygon, to draw pads on silkscreen layer
|
||||
* Used only to draw pads outlines on silkscreen layers.
|
||||
*/
|
||||
void EDA_3D_CANVAS::BuildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
|
||||
CPOLYGONS_LIST& aCornerBuffer,
|
||||
int aWidth,
|
||||
int aCircleToSegmentsCount,
|
||||
|
|
|
@ -57,6 +57,7 @@ static const wxChar keyRenderTextures[] = wxT( "Render_Textures" );
|
|||
static const wxChar keyRenderSmoothNormals[] = wxT( "Render_Smooth_Normals" );
|
||||
static const wxChar keyRenderUseModelNormals[] =wxT( "Render_Use_Model_Normals" );
|
||||
static const wxChar keyRenderMaterial[] = wxT( "Render_Material" );
|
||||
static const wxChar keyRenderShowModelBBox[] = wxT( "Render_ShowModelBoudingBoxes" );
|
||||
|
||||
static const wxChar keyShowAxis[] = wxT( "ShowAxis" );
|
||||
static const wxChar keyShowGrid[] = wxT( "ShowGrid3D" );
|
||||
|
@ -257,6 +258,9 @@ void EDA_3D_FRAME::LoadSettings( wxConfigBase* aCfg )
|
|||
aCfg->Read( keyRenderMaterial, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_MATERIAL, tmp );
|
||||
|
||||
aCfg->Read( keyRenderShowModelBBox, &tmp, false );
|
||||
prms.SetFlag( FL_RENDER_SHOW_MODEL_BBOX, tmp );
|
||||
|
||||
aCfg->Read( keyShowAxis, &tmp, true );
|
||||
prms.SetFlag( FL_AXIS, tmp );
|
||||
|
||||
|
@ -319,7 +323,8 @@ void EDA_3D_FRAME::SaveSettings( wxConfigBase* aCfg )
|
|||
aCfg->Write( keyRenderSmoothNormals, prms.GetFlag( FL_RENDER_SMOOTH_NORMALS ) );
|
||||
aCfg->Write( keyRenderUseModelNormals, prms.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) );
|
||||
aCfg->Write( keyRenderMaterial, prms.GetFlag( FL_RENDER_MATERIAL ) );
|
||||
|
||||
aCfg->Write( keyRenderShowModelBBox, prms.GetFlag( FL_RENDER_SHOW_MODEL_BBOX ) );
|
||||
|
||||
aCfg->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) );
|
||||
aCfg->Write( keyShowGrid, prms.GetFlag( FL_GRID ) );
|
||||
aCfg->Write( keyShowGridSize, prms.m_3D_Grid );
|
||||
|
@ -509,6 +514,11 @@ void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX:
|
||||
GetPrm3DVisu().SetFlag( FL_RENDER_SHOW_MODEL_BBOX, isChecked );
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SHOW_BOARD_BODY:
|
||||
GetPrm3DVisu().SetFlag( FL_SHOW_BOARD_BODY, isChecked );
|
||||
NewDisplay();
|
||||
|
@ -526,43 +536,43 @@ void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
|
||||
case ID_MENU3D_USE_COPPER_THICKNESS:
|
||||
GetPrm3DVisu().SetFlag( FL_USE_COPPER_THICKNESS, isChecked );
|
||||
NewDisplay(GL_ID_BOARD);
|
||||
NewDisplay(GL_ID_TECH_LAYERS);
|
||||
NewDisplay( GL_ID_BOARD );
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ZONE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_ZONE, isChecked );
|
||||
NewDisplay(GL_ID_BOARD);
|
||||
NewDisplay( GL_ID_BOARD );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ADHESIVE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_ADHESIVE, isChecked );
|
||||
NewDisplay(GL_ID_TECH_LAYERS);
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SILKSCREEN_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_SILKSCREEN, isChecked );
|
||||
NewDisplay(GL_ID_TECH_LAYERS);
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDER_MASK_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_SOLDERMASK, isChecked );
|
||||
NewDisplay(GL_ID_TECH_LAYERS);
|
||||
NewDisplay( GL_ID_TECH_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_SOLDER_PASTE_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_SOLDERPASTE, isChecked );
|
||||
NewDisplay(GL_ID_TECH_LAYERS);
|
||||
NewDisplay();
|
||||
return;
|
||||
|
||||
case ID_MENU3D_COMMENTS_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_COMMENTS, isChecked );
|
||||
NewDisplay(GL_ID_AUX_LAYERS);
|
||||
NewDisplay( GL_ID_AUX_LAYERS );
|
||||
return;
|
||||
|
||||
case ID_MENU3D_ECO_ONOFF:
|
||||
GetPrm3DVisu().SetFlag( FL_ECO, isChecked );
|
||||
NewDisplay(GL_ID_AUX_LAYERS);
|
||||
NewDisplay( GL_ID_AUX_LAYERS );
|
||||
return;
|
||||
|
||||
default:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -55,10 +55,10 @@ S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) :
|
|||
|
||||
void SetOpenGlDefaultMaterial()
|
||||
{
|
||||
glm::vec4 ambient( 0.2, 0.2, 0.2, 1.0 );
|
||||
glm::vec4 specular( 0.0, 0.0, 0.0, 1.0 );
|
||||
glm::vec4 emissive( 0.0, 0.0, 0.0, 1.0 );
|
||||
glm::vec4 diffuse( 0.0, 0.0, 0.0, 1.0 );
|
||||
glm::vec4 ambient( 0.2f, 0.2f, 0.2f, 1.0f );
|
||||
glm::vec4 specular( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
glm::vec4 emissive( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
glm::vec4 diffuse( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||
GLint shininess_value = 0;
|
||||
|
||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -45,8 +45,8 @@ public:
|
|||
std::vector< glm::vec3 > m_DiffuseColor;
|
||||
std::vector< glm::vec3 > m_EmissiveColor;
|
||||
std::vector< glm::vec3 > m_SpecularColor;
|
||||
std::vector< float > m_Shininess;
|
||||
std::vector< float > m_Transparency;
|
||||
std::vector< float > m_Shininess;
|
||||
std::vector< float > m_Transparency;
|
||||
|
||||
public:
|
||||
S3D_MATERIAL( S3D_MASTER* father, const wxString& name );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -27,33 +27,130 @@
|
|||
* @brief
|
||||
*/
|
||||
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <3d_mesh_model.h>
|
||||
#include <boost/geometry/algorithms/area.hpp>
|
||||
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
|
||||
#ifdef __WXMAC__
|
||||
# ifdef __DARWIN__
|
||||
# include <OpenGL/glu.h>
|
||||
# else
|
||||
# include <glu.h>
|
||||
# endif
|
||||
#else
|
||||
# include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENMP
|
||||
#include <omp.h>
|
||||
#endif // USE_OPENMP
|
||||
|
||||
#include "info3d_visu.h"
|
||||
|
||||
|
||||
S3D_MESH::S3D_MESH()
|
||||
{
|
||||
isPerFaceNormalsComputed = false;
|
||||
isPointNormalizedComputed = false;
|
||||
isPerPointNormalsComputed = false;
|
||||
isPerVertexNormalsVerified = false;
|
||||
isPerFaceNormalsComputed = false;
|
||||
isPointNormalizedComputed = false;
|
||||
isPerPointNormalsComputed = false;
|
||||
isPerVertexNormalsVerified = false;
|
||||
m_Materials = NULL;
|
||||
childs.clear();
|
||||
|
||||
m_translation = glm::vec3( 0.0f, 0.0f, 0.0f );
|
||||
m_rotation = glm::vec4( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
m_scale = glm::vec3( 1.0f, 1.0f, 1.0f );
|
||||
m_scaleOrientation = glm::vec4( 0.0f, 0.0f, 1.0f, 0.0f ); // not used
|
||||
m_center = glm::vec3( 0.0f, 0.0f, 0.0f ); // not used
|
||||
m_translation = glm::vec3( 0.0f, 0.0f, 0.0f );
|
||||
m_rotation = glm::vec4( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
m_scale = glm::vec3( 1.0f, 1.0f, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
S3D_MESH::~S3D_MESH()
|
||||
{
|
||||
for( unsigned int idx = 0; idx < childs.size(); idx++ )
|
||||
{
|
||||
if( childs[idx] )
|
||||
{
|
||||
delete childs[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CBBOX &S3D_MESH::getBBox( )
|
||||
{
|
||||
if( !m_BBox.IsInitialized() )
|
||||
calcBBoxAllChilds();
|
||||
|
||||
return m_BBox;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MESH::calcBBoxAllChilds( )
|
||||
{
|
||||
// Calc your own boudingbox
|
||||
calcBBox();
|
||||
|
||||
for( unsigned int idx = 0; idx < childs.size(); idx++ )
|
||||
m_BBox.Union( childs[idx]->getBBox() );
|
||||
|
||||
CBBOX tmpBBox = m_BBox;
|
||||
|
||||
// Calc transformation matrix
|
||||
glm::mat4 fullTransformMatrix;
|
||||
glm::mat4 translationMatrix = glm::translate( glm::mat4(), m_translation );
|
||||
|
||||
if( m_rotation[3] != 0.0f )
|
||||
{
|
||||
glm::mat4 rotationMatrix = glm::rotate( translationMatrix, m_rotation[3],
|
||||
S3D_VERTEX( m_rotation[0], m_rotation[1], m_rotation[2] ) );
|
||||
fullTransformMatrix = glm::scale( rotationMatrix, m_scale );
|
||||
}
|
||||
else
|
||||
fullTransformMatrix = glm::scale( translationMatrix, m_scale );
|
||||
|
||||
|
||||
// Apply transformation
|
||||
m_BBox.Set( S3D_VERTEX( fullTransformMatrix * glm::vec4( tmpBBox.Min(), 1.0f ) ),
|
||||
S3D_VERTEX( fullTransformMatrix * glm::vec4( tmpBBox.Max(), 1.0f ) ) );
|
||||
}
|
||||
|
||||
|
||||
void S3D_MESH::calcBBox( )
|
||||
{
|
||||
CBBOX tmpBBox;
|
||||
|
||||
bool firstBBox = true;
|
||||
|
||||
bool useMaterial = g_Parm_3D_Visu.GetFlag( FL_RENDER_MATERIAL );
|
||||
|
||||
// Do not add complete transparent materials
|
||||
if( useMaterial && (m_Materials != 0) && ( m_MaterialIndex.size() == 0 ) )
|
||||
if( m_Materials->m_Transparency.size() > 0 )
|
||||
if( m_Materials->m_Transparency[0] >= 1.0f )
|
||||
return;
|
||||
|
||||
|
||||
// Calc boudingbox for all coords
|
||||
for( unsigned int idx = 0; idx < m_CoordIndex.size(); idx++ )
|
||||
{
|
||||
// Do not add complete transparent materials
|
||||
if( useMaterial && (m_Materials != 0) && ( m_MaterialIndex.size() > idx ) )
|
||||
if( (int)m_Materials->m_Transparency.size() > m_MaterialIndex[idx] )
|
||||
if( m_Materials->m_Transparency[m_MaterialIndex[idx]] >= 1.0f )
|
||||
continue;
|
||||
|
||||
for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ )
|
||||
if( firstBBox )
|
||||
{
|
||||
firstBBox = false;
|
||||
tmpBBox = CBBOX( m_Point[m_CoordIndex[idx][ii]] ); // Initialize with the first vertex found
|
||||
}
|
||||
else
|
||||
tmpBBox.Union( m_Point[m_CoordIndex[idx][ii]] );
|
||||
}
|
||||
|
||||
m_BBox = tmpBBox;
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,11 +169,11 @@ void S3D_MESH::openGL_RenderAllChilds( bool aIsRenderingJustNonTransparentObjec
|
|||
openGL_Render( aIsRenderingJustNonTransparentObjects,
|
||||
aIsRenderingJustTransparentObjects );
|
||||
|
||||
// Render childs
|
||||
// Render childs recursively
|
||||
for( unsigned int idx = 0; idx < childs.size(); idx++ )
|
||||
{
|
||||
childs[idx]->openGL_Render( aIsRenderingJustNonTransparentObjects,
|
||||
aIsRenderingJustTransparentObjects );
|
||||
childs[idx]->openGL_RenderAllChilds( aIsRenderingJustNonTransparentObjects,
|
||||
aIsRenderingJustTransparentObjects );
|
||||
}
|
||||
|
||||
SetOpenGlDefaultMaterial();
|
||||
|
@ -142,7 +239,7 @@ void S3D_MESH::openGL_Render( bool aIsRenderingJustNonTransparentObjects,
|
|||
{
|
||||
if( m_Materials )
|
||||
{
|
||||
if ( m_MaterialIndex.size() > 0 )
|
||||
if ( m_MaterialIndex.size() > idx )
|
||||
{
|
||||
bool isTransparent = m_Materials->SetOpenGLMaterial( m_MaterialIndex[idx], useMaterial );
|
||||
|
||||
|
@ -153,9 +250,9 @@ void S3D_MESH::openGL_Render( bool aIsRenderingJustNonTransparentObjects,
|
|||
continue;
|
||||
|
||||
if( useMaterial )
|
||||
if( m_Materials->m_Transparency.size() > idx )
|
||||
if( m_Materials->m_Transparency[idx] >= 1.0f )
|
||||
return;
|
||||
if( (int)m_Materials->m_Transparency.size() > m_MaterialIndex[idx] )
|
||||
if( m_Materials->m_Transparency[m_MaterialIndex[idx]] >= 1.0f )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -270,37 +367,37 @@ void S3D_MESH::perVertexNormalsVerify_and_Repair()
|
|||
{
|
||||
glm::vec3 normal = m_PerVertexNormalsNormalized[idx];
|
||||
|
||||
if( (normal.x == 1.0) && ((normal.y != 0.0) || (normal.z != 0.0)) )
|
||||
if( (normal.x == 1.0f) && ((normal.y != 0.0f) || (normal.z != 0.0f)) )
|
||||
{
|
||||
normal.y = 0.0;
|
||||
normal.z = 0.0;
|
||||
normal.y = 0.0f;
|
||||
normal.z = 0.0f;
|
||||
}
|
||||
else
|
||||
if( (normal.y == 1.0) && ((normal.x != 0.0) || (normal.z != 0.0)) )
|
||||
if( (normal.y == 1.0f) && ((normal.x != 0.0f) || (normal.z != 0.0f)) )
|
||||
{
|
||||
normal.x = 0.0;
|
||||
normal.z = 0.0;
|
||||
normal.x = 0.0f;
|
||||
normal.z = 0.0f;
|
||||
}
|
||||
else
|
||||
if( (normal.z == 1.0) && ((normal.x != 0.0) || (normal.y != 0.0)) )
|
||||
if( (normal.z == 1.0f) && ((normal.x != 0.0f) || (normal.y != 0.0f)) )
|
||||
{
|
||||
normal.x = 0.0;
|
||||
normal.y = 0.0;
|
||||
normal.x = 0.0f;
|
||||
normal.y = 0.0f;
|
||||
}
|
||||
else
|
||||
if( (normal.x < FLT_EPSILON) && (normal.x > -FLT_EPSILON) )
|
||||
{
|
||||
normal.x = 0.0;
|
||||
normal.x = 0.0f;
|
||||
}
|
||||
else
|
||||
if( (normal.y < FLT_EPSILON) && (normal.y > -FLT_EPSILON) )
|
||||
{
|
||||
normal.y = 0.0;
|
||||
normal.y = 0.0f;
|
||||
}
|
||||
else
|
||||
if( (normal.z < FLT_EPSILON) && (normal.z > -FLT_EPSILON) )
|
||||
{
|
||||
normal.z = 0.0;
|
||||
normal.z = 0.0f;
|
||||
}
|
||||
|
||||
float l = glm::length( normal );
|
||||
|
@ -328,10 +425,6 @@ void S3D_MESH::calcPointNormalized()
|
|||
|
||||
isPointNormalizedComputed = true;
|
||||
|
||||
/*
|
||||
m_PointNormalized = m_Point;
|
||||
*/
|
||||
|
||||
m_PointNormalized.clear();
|
||||
m_PointNormalized.resize( m_Point.size() );
|
||||
|
||||
|
@ -406,9 +499,9 @@ void S3D_MESH::calcPerFaceNormals()
|
|||
{
|
||||
glm::vec3 cross_prod;
|
||||
|
||||
cross_prod.x = 0.0;
|
||||
cross_prod.y = 0.0;
|
||||
cross_prod.z = 0.0;
|
||||
cross_prod.x = 0.0f;
|
||||
cross_prod.y = 0.0f;
|
||||
cross_prod.z = 0.0f;
|
||||
|
||||
// Newell's Method
|
||||
// http://www.opengl.org/wiki/Calculating_a_Surface_Normal
|
||||
|
@ -434,15 +527,6 @@ void S3D_MESH::calcPerFaceNormals()
|
|||
float area = glm::dot( cross_prod, cross_prod );
|
||||
area = fabs( area );
|
||||
|
||||
// Dont remmember why this code was used for..
|
||||
/*
|
||||
if( cross_prod[2] < 0.0 )
|
||||
area = -area;
|
||||
|
||||
if( area < FLT_EPSILON )
|
||||
area = FLT_EPSILON * 2.0f;
|
||||
*/
|
||||
|
||||
m_PerFaceNormalsRaw_X_PerFaceSquaredArea[idx] = cross_prod * area;
|
||||
|
||||
if( haveAlreadyNormals_from_model_file == false )
|
||||
|
@ -456,35 +540,35 @@ void S3D_MESH::calcPerFaceNormals()
|
|||
}
|
||||
else
|
||||
{
|
||||
DBG( printf( "Cannot calc normal idx: %u cross(%f, %f, %f) l:%f m_CoordIndex[idx].size: %u\n",
|
||||
/* DBG( printf( "Cannot calc normal idx: %u cross(%f, %f, %f) l:%f m_CoordIndex[idx].size: %u\n",
|
||||
idx,
|
||||
cross_prod.x, cross_prod.y, cross_prod.z,
|
||||
l,
|
||||
(unsigned int)m_CoordIndex[idx].size()) );
|
||||
|
||||
*/
|
||||
if( ( cross_prod.x > cross_prod.y ) && ( cross_prod.x > cross_prod.z ) )
|
||||
{
|
||||
cross_prod.x = 0.0;
|
||||
cross_prod.y = 1.0;
|
||||
cross_prod.z = 0.0;
|
||||
cross_prod.x = 0.0f;
|
||||
cross_prod.y = 1.0f;
|
||||
cross_prod.z = 0.0f;
|
||||
}
|
||||
else if( ( cross_prod.y > cross_prod.x ) && ( cross_prod.y > cross_prod.z ) )
|
||||
{
|
||||
cross_prod.x = 0.0;
|
||||
cross_prod.y = 1.0;
|
||||
cross_prod.z = 0.0;
|
||||
cross_prod.x = 0.0f;
|
||||
cross_prod.y = 1.0f;
|
||||
cross_prod.z = 0.0f;
|
||||
}
|
||||
else if( ( cross_prod.z > cross_prod.x ) && ( cross_prod.z > cross_prod.y ) )
|
||||
{
|
||||
cross_prod.x = 0.0;
|
||||
cross_prod.y = 0.0;
|
||||
cross_prod.z = 1.0;
|
||||
cross_prod.x = 0.0f;
|
||||
cross_prod.y = 0.0f;
|
||||
cross_prod.z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
cross_prod.x = 0.0;
|
||||
cross_prod.y = 0.0;
|
||||
cross_prod.z = 0.0;
|
||||
cross_prod.x = 0.0f;
|
||||
cross_prod.y = 0.0f;
|
||||
cross_prod.z = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,6 +578,7 @@ void S3D_MESH::calcPerFaceNormals()
|
|||
}
|
||||
|
||||
|
||||
// Documentation literature
|
||||
// http://www.bytehazard.com/code/vertnorm.html
|
||||
// http://www.emeyex.com/site/tuts/VertexNormals.pdf
|
||||
void S3D_MESH::calcPerPointNormals()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -30,24 +30,12 @@
|
|||
#ifndef __3D_MESH_MODEL_H__
|
||||
#define __3D_MESH_MODEL_H__
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <macros.h>
|
||||
#include <base_struct.h>
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
#include <vector>
|
||||
#include <kicad_string.h>
|
||||
#include <info3d_visu.h>
|
||||
#ifdef __WXMAC__
|
||||
# ifdef __DARWIN__
|
||||
# include <OpenGL/glu.h>
|
||||
# else
|
||||
# include <glu.h>
|
||||
# endif
|
||||
#else
|
||||
# include <GL/glu.h>
|
||||
#endif
|
||||
#include <wx/glcanvas.h>
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
#include "3d_struct.h"
|
||||
#include "3d_material.h"
|
||||
#include "CBBox.h"
|
||||
|
||||
|
||||
class S3D_MESH;
|
||||
|
||||
|
@ -59,33 +47,31 @@ public:
|
|||
~S3D_MESH();
|
||||
|
||||
void openGL_RenderAllChilds( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
|
||||
S3D_MATERIAL *m_Materials;
|
||||
S3D_MATERIAL *m_Materials;
|
||||
|
||||
// Point and index list
|
||||
std::vector< glm::vec3 > m_Point;
|
||||
std::vector< S3D_VERTEX > m_Point;
|
||||
std::vector< std::vector<int> > m_CoordIndex;
|
||||
std::vector< std::vector<int> > m_NormalIndex;
|
||||
std::vector< glm::vec3 > m_PerFaceNormalsNormalized;
|
||||
std::vector< glm::vec3 > m_PerVertexNormalsNormalized;
|
||||
std::vector< S3D_VERTEX > m_PerFaceNormalsNormalized;
|
||||
std::vector< S3D_VERTEX > m_PerVertexNormalsNormalized;
|
||||
std::vector< int > m_MaterialIndex;
|
||||
std::vector< S3D_MESH * > childs;
|
||||
|
||||
std::vector< int > m_MaterialIndex;
|
||||
S3D_VERTEX m_translation;
|
||||
glm::vec4 m_rotation;
|
||||
S3D_VERTEX m_scale;
|
||||
|
||||
glm::vec3 m_translation;
|
||||
glm::vec4 m_rotation;
|
||||
glm::vec3 m_scale;
|
||||
glm::vec4 m_scaleOrientation; // not used
|
||||
glm::vec3 m_center; // not used
|
||||
|
||||
std::vector<S3D_MESH *> childs;
|
||||
CBBOX &getBBox();
|
||||
|
||||
private:
|
||||
std::vector< glm::vec3 > m_PerFaceNormalsRaw_X_PerFaceSquaredArea;
|
||||
std::vector< std::vector< glm::vec3 > > m_PerFaceVertexNormals;
|
||||
std::vector< glm::vec3 > m_PointNormalized;
|
||||
std::vector< S3D_VERTEX > m_PerFaceNormalsRaw_X_PerFaceSquaredArea;
|
||||
std::vector< std::vector< S3D_VERTEX > > m_PerFaceVertexNormals;
|
||||
std::vector< S3D_VERTEX > m_PointNormalized;
|
||||
|
||||
std::vector< std::vector<int> > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index
|
||||
std::vector< std::vector<int> > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index
|
||||
|
||||
bool isPerFaceNormalsComputed;
|
||||
void calcPerFaceNormals ();
|
||||
|
@ -99,6 +85,11 @@ private:
|
|||
bool isPerVertexNormalsVerified;
|
||||
void perVertexNormalsVerify_and_Repair();
|
||||
|
||||
void calcBBox();
|
||||
void calcBBoxAllChilds();
|
||||
|
||||
CBBOX m_BBox;
|
||||
|
||||
void openGL_Render( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras@wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
|
@ -32,14 +33,14 @@
|
|||
#include <macros.h>
|
||||
#include <kicad_string.h>
|
||||
#include <pgm_base.h>
|
||||
|
||||
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
|
||||
#include <3d_viewer.h>
|
||||
#include <info3d_visu.h>
|
||||
#include "3d_struct.h"
|
||||
#include "modelparsers.h"
|
||||
|
||||
|
||||
S3D_MODEL_PARSER* S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
|
||||
S3D_MODEL_PARSER *S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
|
||||
const wxString aExtension )
|
||||
{
|
||||
if ( aExtension == wxT( "x3d" ) )
|
||||
|
@ -50,46 +51,25 @@ S3D_MODEL_PARSER* S3D_MODEL_PARSER::Create( S3D_MASTER* aMaster,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const wxString S3D_MASTER::GetShape3DFullFilename()
|
||||
{
|
||||
|
||||
wxString shapeName;
|
||||
|
||||
// Expand any environment variables embedded in footprint's m_Shape3DName field.
|
||||
// To ensure compatibility with most of footprint's m_Shape3DName field,
|
||||
// if the m_Shape3DName is not an absolute path the default path
|
||||
// given by the environment variable KISYS3DMOD will be used
|
||||
|
||||
if( m_Shape3DName.StartsWith( wxT("${") ) )
|
||||
shapeName = wxExpandEnvVars( m_Shape3DName );
|
||||
else
|
||||
shapeName = m_Shape3DName;
|
||||
|
||||
wxFileName fn( shapeName );
|
||||
|
||||
if( fn.IsAbsolute() || shapeName.StartsWith( wxT(".") ) )
|
||||
return shapeName;
|
||||
|
||||
wxString default_path;
|
||||
wxGetEnv( KISYS3DMOD, &default_path );
|
||||
|
||||
if( default_path.IsEmpty() )
|
||||
return shapeName;
|
||||
|
||||
if( !default_path.EndsWith( wxT("/") ) && !default_path.EndsWith( wxT("\\") ) )
|
||||
default_path += wxT("/");
|
||||
|
||||
default_path += shapeName;
|
||||
|
||||
return default_path;
|
||||
}
|
||||
|
||||
int S3D_MASTER::ReadData()
|
||||
int S3D_MASTER::ReadData( S3D_MODEL_PARSER* aParser )
|
||||
{
|
||||
if( m_Shape3DName.IsEmpty() )
|
||||
return 1;
|
||||
{
|
||||
//DBG( printf("m_Shape3DName.IsEmpty") );
|
||||
return -1;
|
||||
}
|
||||
|
||||
wxString filename = GetShape3DFullFilename();
|
||||
if( m_Shape3DFullFilename.IsEmpty() )
|
||||
{
|
||||
//DBG( printf("m_Shape3DFullFilename.IsEmpty") );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( aParser == NULL )
|
||||
return -1;
|
||||
|
||||
wxString filename = m_Shape3DFullFilename;
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
filename.Replace( wxT( "/" ), wxT( "\\" ) );
|
||||
|
@ -97,35 +77,30 @@ int S3D_MASTER::ReadData()
|
|||
filename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
#endif
|
||||
|
||||
if( !wxFileName::FileExists( filename ) )
|
||||
if( wxFileName::FileExists( filename ) )
|
||||
{
|
||||
wxLogDebug( wxT( "3D shape '%s' not found, even tried '%s' after env var substitution." ),
|
||||
GetChars( m_Shape3DName ),
|
||||
GetChars( filename )
|
||||
);
|
||||
return -1;
|
||||
wxFileName fn( filename );
|
||||
|
||||
if( aParser->Load( filename ) )
|
||||
{
|
||||
// Invalidate bounding boxes
|
||||
m_fastAABBox.Reset();
|
||||
m_BBox.Reset();
|
||||
|
||||
m_parser = aParser;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
wxFileName fn( filename );
|
||||
|
||||
wxString extension = fn.GetExt();
|
||||
|
||||
m_parser = S3D_MODEL_PARSER::Create( this, extension );
|
||||
|
||||
if( m_parser )
|
||||
{
|
||||
m_parser->Load( filename );
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogDebug( wxT( "Unknown file type '%s'" ), GetChars( extension ) );
|
||||
}
|
||||
wxLogDebug( wxT( "3D shape '%s' not found, even tried '%s' after env var substitution." ),
|
||||
GetChars( m_Shape3DName ),
|
||||
GetChars( filename ) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::Render( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects )
|
||||
{
|
||||
|
@ -136,31 +111,80 @@ void S3D_MASTER::Render( bool aIsRenderingJustNonTransparentObjects,
|
|||
|
||||
glScalef( aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits, aVrmlunits_to_3Dunits );
|
||||
|
||||
glm::vec3 matScale( m_MatScale.x,
|
||||
m_MatScale.y,
|
||||
m_MatScale.z );
|
||||
glTranslatef( m_MatPosition.x * SCALE_3D_CONV,
|
||||
m_MatPosition.y * SCALE_3D_CONV,
|
||||
m_MatPosition.z * SCALE_3D_CONV );
|
||||
|
||||
glm::vec3 matRot( m_MatRotation.x,
|
||||
m_MatRotation.y,
|
||||
m_MatRotation.z );
|
||||
glRotatef( -m_MatRotation.z, 0.0f, 0.0f, 1.0f );
|
||||
glRotatef( -m_MatRotation.y, 0.0f, 1.0f, 0.0f );
|
||||
glRotatef( -m_MatRotation.x, 1.0f, 0.0f, 0.0f );
|
||||
|
||||
glm::vec3 matPos( m_MatPosition.x,
|
||||
m_MatPosition.y,
|
||||
m_MatPosition.z );
|
||||
|
||||
glTranslatef( matPos.x * SCALE_3D_CONV,
|
||||
matPos.y * SCALE_3D_CONV,
|
||||
matPos.z * SCALE_3D_CONV );
|
||||
|
||||
glRotatef( -matRot.z, 0.0f, 0.0f, 1.0f );
|
||||
glRotatef( -matRot.y, 0.0f, 1.0f, 0.0f );
|
||||
glRotatef( -matRot.x, 1.0f, 0.0f, 0.0f );
|
||||
|
||||
glScalef( matScale.x, matScale.y, matScale.z );
|
||||
glScalef( m_MatScale.x, m_MatScale.y, m_MatScale.z );
|
||||
|
||||
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
|
||||
{
|
||||
m_parser->childs[idx]->openGL_RenderAllChilds( aIsRenderingJustNonTransparentObjects,
|
||||
aIsRenderingJustTransparentObjects );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CBBOX &S3D_MASTER::getBBox( )
|
||||
{
|
||||
if( !m_BBox.IsInitialized() )
|
||||
calcBBox();
|
||||
|
||||
return m_BBox;
|
||||
}
|
||||
|
||||
|
||||
CBBOX &S3D_MASTER::getFastAABBox( )
|
||||
{
|
||||
if( !m_fastAABBox.IsInitialized() )
|
||||
calcBBox();
|
||||
|
||||
return m_fastAABBox;
|
||||
}
|
||||
|
||||
|
||||
void S3D_MASTER::calcBBox()
|
||||
{
|
||||
if( m_parser == NULL )
|
||||
return;
|
||||
|
||||
bool firstBBox = true;
|
||||
|
||||
for( unsigned int idx = 0; idx < m_parser->childs.size(); idx++ )
|
||||
if( firstBBox )
|
||||
{
|
||||
firstBBox = false;
|
||||
m_BBox = m_parser->childs[idx]->getBBox();
|
||||
}
|
||||
else
|
||||
m_BBox.Union( m_parser->childs[idx]->getBBox() );
|
||||
|
||||
// Calc transformation matrix to apply in AABBox
|
||||
|
||||
float aVrmlunits_to_3Dunits = g_Parm_3D_Visu.m_BiuTo3Dunits * UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glm::mat4 fullTransformMatrix;
|
||||
|
||||
fullTransformMatrix = glm::scale( glm::mat4(), S3D_VERTEX( aVrmlunits_to_3Dunits,
|
||||
aVrmlunits_to_3Dunits,
|
||||
aVrmlunits_to_3Dunits ) );
|
||||
|
||||
fullTransformMatrix = glm::translate( fullTransformMatrix, S3D_VERTEX( m_MatPosition.x * SCALE_3D_CONV,
|
||||
m_MatPosition.y * SCALE_3D_CONV,
|
||||
m_MatPosition.z * SCALE_3D_CONV) );
|
||||
|
||||
if( m_MatRotation.z != 0.0 )
|
||||
fullTransformMatrix = glm::rotate( fullTransformMatrix, -(float)m_MatRotation.z, S3D_VERTEX( 0.0f, 0.0f, 1.0f ) );
|
||||
if( m_MatRotation.y != 0.0 )
|
||||
fullTransformMatrix = glm::rotate( fullTransformMatrix, -(float)m_MatRotation.y, S3D_VERTEX( 0.0f, 1.0f, 0.0f ) );
|
||||
if( m_MatRotation.x != 0.0 )
|
||||
fullTransformMatrix = glm::rotate( fullTransformMatrix, -(float)m_MatRotation.x, S3D_VERTEX( 1.0f, 0.0f, 0.0f ) );
|
||||
|
||||
fullTransformMatrix = glm::scale( fullTransformMatrix, S3D_VERTEX( m_MatScale.x, m_MatScale.y, m_MatScale.z ) );
|
||||
|
||||
// Apply transformation
|
||||
m_fastAABBox = m_BBox;
|
||||
m_fastAABBox.ApplyTransformationAA( fullTransformMatrix );
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
|
@ -34,54 +34,12 @@
|
|||
#include <common.h>
|
||||
#include <base_struct.h>
|
||||
#include <3d_material.h>
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
#include <3d_types.h>
|
||||
#include <CBBox.h>
|
||||
|
||||
|
||||
/**
|
||||
* @note For historical reasons the 3D modeling unit is 0.1 inch
|
||||
* 1 3Dunit = 2.54 mm = 0.1 inch = 100 mils
|
||||
*/
|
||||
#define UNITS3D_TO_UNITSPCB (IU_PER_MILS * 100)
|
||||
|
||||
/**
|
||||
* scaling factor for 3D shape offset ( S3D_MASTER::m_MatPosition member )
|
||||
* Was in inches in legacy version, and, due to a mistake, still in inches
|
||||
* in .kicad_pcb files (which are using mm)
|
||||
* so this scaling convert file units (inch) to 3D units (0.1 inch), only
|
||||
* for S3D_MASTER::m_MatPosition parameter
|
||||
*/
|
||||
#define SCALE_3D_CONV 10
|
||||
|
||||
class S3D_MASTER;
|
||||
class STRUCT_3D_SHAPE;
|
||||
|
||||
// S3D_VERTEX manages a opengl 3D coordinate (3 float numbers: x,y,z coordinates)
|
||||
// float are widely used in opengl functions.
|
||||
// they are used here in coordinates which are also used in opengl functions.
|
||||
#define S3D_VERTEX glm::vec3
|
||||
|
||||
// S3DPOINT manages a set of 3 double values (x,y,z )
|
||||
// It is used for values which are not directly used in opengl functions.
|
||||
// It is used in dialogs, or when reading/writing files for instance
|
||||
class S3DPOINT
|
||||
{
|
||||
public:
|
||||
double x, y, z;
|
||||
|
||||
public:
|
||||
S3DPOINT()
|
||||
{
|
||||
x = y = z = 0.0;
|
||||
}
|
||||
|
||||
S3DPOINT( double px, double py, double pz)
|
||||
{
|
||||
x = px;
|
||||
y = py;
|
||||
z = pz;
|
||||
}
|
||||
};
|
||||
|
||||
class S3D_MODEL_PARSER;
|
||||
|
||||
// Master structure for a 3D footprint shape description
|
||||
|
@ -112,8 +70,10 @@ public:
|
|||
bool m_use_modelfile_shininess;
|
||||
|
||||
private:
|
||||
wxString m_Shape3DName; // the 3D shape filename in 3D library
|
||||
FILE3D_TYPE m_ShapeType;
|
||||
wxString m_Shape3DName; ///< The 3D shape filename in 3D library
|
||||
FILE3D_TYPE m_ShapeType; ///< Shape type based on filename extension
|
||||
wxString m_Shape3DFullFilename; ///< Full file path name
|
||||
wxString m_Shape3DNameExtension; ///< Extension of the shape file name
|
||||
|
||||
public:
|
||||
S3D_MASTER( EDA_ITEM* aParent );
|
||||
|
@ -131,8 +91,9 @@ public:
|
|||
* Function ReadData
|
||||
* Select the parser to read the 3D data file (vrml, x3d ...)
|
||||
* and build the description objects list
|
||||
* @param aParser the parser that should be used to read model data and stored in
|
||||
*/
|
||||
int ReadData();
|
||||
int ReadData( S3D_MODEL_PARSER* aParser );
|
||||
|
||||
void Render( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
|
@ -177,6 +138,12 @@ public:
|
|||
*/
|
||||
const wxString GetShape3DFullFilename();
|
||||
|
||||
/**
|
||||
* Function GetShape3DExtension
|
||||
* @return the extension of the filename of the 3D shape,
|
||||
*/
|
||||
const wxString GetShape3DExtension();
|
||||
|
||||
/**
|
||||
* Function SetShape3DName
|
||||
* @param aShapeName = file name of the data file relative to the 3D shape
|
||||
|
@ -185,6 +152,23 @@ public:
|
|||
* (vrl, x3d, idf ) the type of file.
|
||||
*/
|
||||
void SetShape3DName( const wxString& aShapeName );
|
||||
|
||||
/**
|
||||
* Function getBBox Model Space Bouding Box
|
||||
* @return return the model space bouding box
|
||||
*/
|
||||
CBBOX &getBBox();
|
||||
|
||||
/**
|
||||
* Function getFastAABBox
|
||||
* @return return the Axis Align Bounding Box of the other bouding boxes
|
||||
*/
|
||||
CBBOX &getFastAABBox();
|
||||
|
||||
private:
|
||||
void calcBBox();
|
||||
CBBOX m_BBox; ///< Model oriented Bouding Box
|
||||
CBBOX m_fastAABBox; ///< Axis Align Bounding Box that contain the other bounding boxes
|
||||
};
|
||||
|
||||
|
||||
|
@ -208,30 +192,4 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class S3DPOINT_VALUE_CTRL
|
||||
* displays a S3DPOINT for editing (in dialogs). A S3DPOINT is a triplet of values
|
||||
* Values can be scale, rotation, offset...
|
||||
*/
|
||||
class S3DPOINT_VALUE_CTRL
|
||||
{
|
||||
private:
|
||||
wxTextCtrl* m_XValueCtrl, * m_YValueCtrl, * m_ZValueCtrl;
|
||||
|
||||
public:
|
||||
S3DPOINT_VALUE_CTRL( wxWindow* parent, wxBoxSizer* BoxSizer );
|
||||
|
||||
~S3DPOINT_VALUE_CTRL();
|
||||
|
||||
/**
|
||||
* Function GetValue
|
||||
* @return the 3D point in internal units.
|
||||
*/
|
||||
S3DPOINT GetValue();
|
||||
void SetValue( S3DPOINT a3Dpoint );
|
||||
void Enable( bool enbl );
|
||||
void SetToolTip( const wxString& text );
|
||||
};
|
||||
|
||||
#endif // STRUCT_3D_H
|
||||
|
|
|
@ -187,6 +187,10 @@ void EDA_3D_FRAME::CreateMenuBar()
|
|||
_( "Render Material Properties" ),
|
||||
KiBitmap( green_xpm ), wxITEM_CHECK );
|
||||
|
||||
AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX,
|
||||
_( "Show Model Bouding Boxes" ),
|
||||
KiBitmap( green_xpm ), wxITEM_CHECK );
|
||||
|
||||
prefsMenu->AppendSeparator();
|
||||
|
||||
wxMenu * backgrounColorMenu = new wxMenu;
|
||||
|
@ -300,6 +304,9 @@ void EDA_3D_FRAME::SetMenuBarOptionsState()
|
|||
item = menuBar->FindItem( ID_MENU3D_FL_RENDER_MATERIAL );
|
||||
item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_MATERIAL ) );
|
||||
|
||||
item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX );
|
||||
item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SHOW_MODEL_BBOX ) );
|
||||
|
||||
item = menuBar->FindItem( ID_MENU3D_SHOW_BOARD_BODY );
|
||||
item->Check( GetPrm3DVisu().GetFlag( FL_SHOW_BOARD_BODY ) );
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* 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_types.h
|
||||
*/
|
||||
|
||||
#ifndef _3D_TYPES_H_
|
||||
#define _3D_TYPES_H_
|
||||
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
#include <base_units.h> // for IU_PER_MILS
|
||||
|
||||
|
||||
/**
|
||||
* @note For historical reasons the 3D modeling unit is 0.1 inch
|
||||
* 1 3Dunit = 2.54 mm = 0.1 inch = 100 mils
|
||||
*/
|
||||
#define UNITS3D_TO_UNITSPCB (IU_PER_MILS * 100)
|
||||
|
||||
|
||||
/**
|
||||
* scaling factor for 3D shape offset ( S3D_MASTER::m_MatPosition member )
|
||||
* Was in inches in legacy version, and, due to a mistake, still in inches
|
||||
* in .kicad_pcb files (which are using mm)
|
||||
* so this scaling convert file units (inch) to 3D units (0.1 inch), only
|
||||
* for S3D_MASTER::m_MatPosition parameter
|
||||
*/
|
||||
#define SCALE_3D_CONV 10
|
||||
|
||||
|
||||
// S3D_VERTEX manages a opengl 3D coordinate (3 float numbers: x,y,z coordinates)
|
||||
// float are widely used in opengl functions.
|
||||
// they are used here in coordinates which are also used in opengl functions.
|
||||
#define S3D_VERTEX glm::vec3
|
||||
|
||||
|
||||
// S3DPOINT manages a set of 3 double values (x,y,z )
|
||||
// It is used for values which are not directly used in opengl functions.
|
||||
// It is used in dialogs, or when reading/writing files for instance
|
||||
class S3DPOINT
|
||||
{
|
||||
public:
|
||||
double x, y, z;
|
||||
|
||||
public:
|
||||
S3DPOINT()
|
||||
{
|
||||
x = y = z = 0.0;
|
||||
}
|
||||
|
||||
S3DPOINT( double px, double py, double pz)
|
||||
{
|
||||
x = px;
|
||||
y = py;
|
||||
z = pz;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class S3DPOINT_VALUE_CTRL
|
||||
* displays a S3DPOINT for editing (in dialogs). A S3DPOINT is a triplet of values
|
||||
* Values can be scale, rotation, offset...
|
||||
*/
|
||||
class S3DPOINT_VALUE_CTRL
|
||||
{
|
||||
private:
|
||||
wxTextCtrl* m_XValueCtrl, * m_YValueCtrl, * m_ZValueCtrl;
|
||||
|
||||
public:
|
||||
S3DPOINT_VALUE_CTRL( wxWindow* parent, wxBoxSizer* BoxSizer );
|
||||
|
||||
~S3DPOINT_VALUE_CTRL();
|
||||
|
||||
/**
|
||||
* Function GetValue
|
||||
* @return the 3D point in internal units.
|
||||
*/
|
||||
S3DPOINT GetValue();
|
||||
void SetValue( S3DPOINT a3Dpoint );
|
||||
void Enable( bool enbl );
|
||||
void SetToolTip( const wxString& text );
|
||||
};
|
||||
|
||||
#endif // 3D_TYPES_H
|
|
@ -52,6 +52,7 @@ enum id_3dview_frm
|
|||
ID_MENU3D_FL_RENDER_SMOOTH_NORMALS,
|
||||
ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS,
|
||||
ID_MENU3D_FL_RENDER_MATERIAL,
|
||||
ID_MENU3D_FL_RENDER_SHOW_MODEL_BBOX,
|
||||
ID_END_COMMAND_3D,
|
||||
|
||||
ID_TOOL_SET_VISIBLE_ITEMS,
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* 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 CBBox.cpp
|
||||
* @brief Bounding Box class implementation
|
||||
*/
|
||||
|
||||
#include "CBBox.h"
|
||||
|
||||
|
||||
// openGL includes used for debug the bounding box
|
||||
#ifdef __WXMAC__
|
||||
# ifdef __DARWIN__
|
||||
# include <OpenGL/glu.h>
|
||||
# else
|
||||
# include <glu.h>
|
||||
# endif
|
||||
#else
|
||||
# include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
CBBOX::CBBOX()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
CBBOX::CBBOX( const S3D_VERTEX &aPbInit )
|
||||
{
|
||||
m_min = aPbInit;
|
||||
m_max = aPbInit;
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
CBBOX::CBBOX( const S3D_VERTEX &aPbMin, const S3D_VERTEX &aPbMax )
|
||||
{
|
||||
Set( aPbMin, aPbMax );
|
||||
}
|
||||
|
||||
CBBOX::~CBBOX()
|
||||
{
|
||||
}
|
||||
|
||||
void CBBOX::Set( const S3D_VERTEX &aPbMin, const S3D_VERTEX &aPbMax )
|
||||
{
|
||||
m_min.x = glm::min( aPbMin.x, aPbMax.x );
|
||||
m_min.y = glm::min( aPbMin.y, aPbMax.y );
|
||||
m_min.z = glm::min( aPbMin.z, aPbMax.z );
|
||||
|
||||
m_max.x = glm::max( aPbMin.x, aPbMax.x );
|
||||
m_max.y = glm::max( aPbMin.y, aPbMax.y );
|
||||
m_max.z = glm::max( aPbMin.z, aPbMax.z );
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool CBBOX::IsInitialized() const
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void CBBOX::Reset()
|
||||
{
|
||||
m_min = S3D_VERTEX( 0.0f, 0.0f, 0.0f );
|
||||
m_max = S3D_VERTEX( 0.0f, 0.0f, 0.0f );
|
||||
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
void CBBOX::Union( const S3D_VERTEX &aPoint )
|
||||
{
|
||||
if( !m_initialized )
|
||||
{
|
||||
m_initialized = true;
|
||||
// Initialize the bounding box with the given point
|
||||
m_min = aPoint;
|
||||
m_max = aPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the minimun value between the added point and the existent bounding box
|
||||
m_min.x = glm::min( m_min.x, aPoint.x );
|
||||
m_min.y = glm::min( m_min.y, aPoint.y );
|
||||
m_min.z = glm::min( m_min.z, aPoint.z );
|
||||
|
||||
// get the maximun value between the added point and the existent bounding box
|
||||
m_max.x = glm::max( m_max.x, aPoint.x );
|
||||
m_max.y = glm::max( m_max.y, aPoint.y );
|
||||
m_max.z = glm::max( m_max.z, aPoint.z );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CBBOX::Union( const CBBOX &aBBox )
|
||||
{
|
||||
if( aBBox.m_initialized == false )
|
||||
return;
|
||||
|
||||
if( !m_initialized )
|
||||
{
|
||||
// Initialize the bounding box with the given bounding box
|
||||
m_initialized = true;
|
||||
m_min = aBBox.m_min;
|
||||
m_max = aBBox.m_max;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the minimun value between the added bounding box and the existent bounding box
|
||||
m_min.x = glm::min( m_min.x, aBBox.m_min.x );
|
||||
m_min.y = glm::min( m_min.y, aBBox.m_min.y );
|
||||
m_min.z = glm::min( m_min.z, aBBox.m_min.z );
|
||||
|
||||
// get the maximun value between the added bounding box and the existent bounding box
|
||||
m_max.x = glm::max( m_max.x, aBBox.m_max.x );
|
||||
m_max.y = glm::max( m_max.y, aBBox.m_max.y );
|
||||
m_max.z = glm::max( m_max.z, aBBox.m_max.z );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S3D_VERTEX CBBOX::GetCenter() const
|
||||
{
|
||||
return (m_max + m_min) * 0.5f;
|
||||
}
|
||||
|
||||
S3D_VERTEX CBBOX::Min() const
|
||||
{
|
||||
return m_min;
|
||||
}
|
||||
|
||||
S3D_VERTEX CBBOX::Max() const
|
||||
{
|
||||
return m_max;
|
||||
}
|
||||
|
||||
void CBBOX::Scale( float aScale )
|
||||
{
|
||||
if( m_initialized == false )
|
||||
return;
|
||||
|
||||
S3D_VERTEX scaleV = S3D_VERTEX( aScale, aScale, aScale );
|
||||
S3D_VERTEX centerV = GetCenter();
|
||||
|
||||
m_min = (m_min - centerV) * scaleV + centerV;
|
||||
m_max = (m_max - centerV) * scaleV + centerV;
|
||||
}
|
||||
|
||||
|
||||
bool CBBOX::OverlapsBox( const CBBOX &aBBox ) const
|
||||
{
|
||||
if( aBBox.m_initialized == false )
|
||||
return false;
|
||||
|
||||
bool x = ( m_max.x >= aBBox.m_min.x ) && ( m_min.x <= aBBox.m_max.x );
|
||||
bool y = ( m_max.y >= aBBox.m_min.y ) && ( m_min.y <= aBBox.m_max.y );
|
||||
bool z = ( m_max.z >= aBBox.m_min.z ) && ( m_min.z <= aBBox.m_max.z );
|
||||
|
||||
return ( x && y && z );
|
||||
}
|
||||
|
||||
|
||||
bool CBBOX::Inside( const S3D_VERTEX &aPoint ) const
|
||||
{
|
||||
if( m_initialized == false )
|
||||
return false;
|
||||
|
||||
return (( aPoint.x >= m_min.x ) && ( aPoint.x <= m_max.x ) &&
|
||||
( aPoint.y >= m_min.y ) && ( aPoint.y <= m_max.y ) &&
|
||||
( aPoint.z >= m_min.z ) && ( aPoint.z <= m_max.z ));
|
||||
}
|
||||
|
||||
|
||||
float CBBOX::Volume() const
|
||||
{
|
||||
if( m_initialized == false )
|
||||
return 0.0f;
|
||||
|
||||
S3D_VERTEX d = m_max - m_min;
|
||||
return d.x * d.y * d.z;
|
||||
}
|
||||
|
||||
|
||||
void CBBOX::ApplyTransformation( glm::mat4 aTransformMatrix )
|
||||
{
|
||||
if( m_initialized == false )
|
||||
return;
|
||||
|
||||
S3D_VERTEX v1 = S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) );
|
||||
S3D_VERTEX v2 = S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) );
|
||||
|
||||
Reset();
|
||||
Union( v1 );
|
||||
Union( v2 );
|
||||
}
|
||||
|
||||
|
||||
void CBBOX::ApplyTransformationAA( glm::mat4 aTransformMatrix )
|
||||
{
|
||||
if( m_initialized == false )
|
||||
return;
|
||||
|
||||
// apply the transformation matrix for each of vertices of the bounding box
|
||||
// and make a union with all vertices
|
||||
CBBOX tmpBBox = CBBOX( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_min.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_min.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_max.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_max.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_min.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_max.z, 1.0f ) ) );
|
||||
tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) ) );
|
||||
|
||||
m_min = tmpBBox.m_min;
|
||||
m_max = tmpBBox.m_max;
|
||||
}
|
||||
|
||||
|
||||
void CBBOX::GLdebug() const
|
||||
{
|
||||
if( m_initialized == false )
|
||||
return;
|
||||
|
||||
glBegin( GL_LINE_LOOP );
|
||||
glVertex3f( m_min.x, m_min.y, m_min.z );
|
||||
glVertex3f( m_max.x, m_min.y, m_min.z );
|
||||
glVertex3f( m_max.x, m_max.y, m_min.z );
|
||||
glVertex3f( m_min.x, m_max.y, m_min.z );
|
||||
glEnd();
|
||||
|
||||
glBegin( GL_LINE_LOOP );
|
||||
glVertex3f( m_min.x, m_min.y, m_max.z );
|
||||
glVertex3f( m_max.x, m_min.y, m_max.z );
|
||||
glVertex3f( m_max.x, m_max.y, m_max.z );
|
||||
glVertex3f( m_min.x, m_max.y, m_max.z );
|
||||
glEnd();
|
||||
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( m_min.x, m_min.y, m_min.z );
|
||||
glVertex3f( m_min.x, m_min.y, m_max.z );
|
||||
glEnd();
|
||||
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( m_max.x, m_min.y, m_min.z );
|
||||
glVertex3f( m_max.x, m_min.y, m_max.z );
|
||||
glEnd();
|
||||
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( m_max.x, m_max.y, m_min.z );
|
||||
glVertex3f( m_max.x, m_max.y, m_max.z );
|
||||
glEnd();
|
||||
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( m_min.x, m_max.y, m_min.z );
|
||||
glVertex3f( m_min.x, m_max.y, m_max.z );
|
||||
glEnd();
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* 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 CBBox.h
|
||||
* @brief Bounding Box class definition
|
||||
*/
|
||||
|
||||
#ifndef CBBox_h
|
||||
#define CBBox_h
|
||||
|
||||
|
||||
#include <gal/opengl/glm/glm.hpp>
|
||||
#include <3d_types.h>
|
||||
|
||||
|
||||
/**
|
||||
* Class CBBOX
|
||||
* manages a bounding box defined by two S3D_VERTEX points.
|
||||
*/
|
||||
class CBBOX
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor CBBOX
|
||||
* Create with default values a bounding box (not inizialized)
|
||||
*/
|
||||
CBBOX();
|
||||
|
||||
/**
|
||||
* Constructor CBBOX
|
||||
* Initialize a bounding box with a given point
|
||||
* @param aPbInit a point for the bounding box initialization
|
||||
*/
|
||||
CBBOX( const S3D_VERTEX &aPbInit );
|
||||
|
||||
/**
|
||||
* Constructor CBBOX
|
||||
* Initialize a bounding box with a minimon and a maximun point
|
||||
* @param aPbMin the minimun point to initialize the bounding box
|
||||
* @param aPbMax the maximun point to initialize the bounding box
|
||||
*/
|
||||
CBBOX( const S3D_VERTEX &aPbMin, const S3D_VERTEX &aPbMax );
|
||||
|
||||
~CBBOX();
|
||||
|
||||
|
||||
/**
|
||||
* Function Set
|
||||
* Set bounding box with new parameters
|
||||
* @param aPbMin the minimun point to initialize the bounding box
|
||||
* @param aPbMax the maximun point to initialize the bounding box
|
||||
*/
|
||||
void Set( const S3D_VERTEX &aPbMin, const S3D_VERTEX &aPbMax );
|
||||
|
||||
/**
|
||||
* Function Union
|
||||
* recalculate the bounding box adding a point
|
||||
* @param aPoint the point to be bounded
|
||||
*/
|
||||
void Union( const S3D_VERTEX &aPoint );
|
||||
|
||||
/**
|
||||
* Function Union
|
||||
* recalculate the bounding box adding other bounding box
|
||||
* @param aBBox the bounding box to be bounded
|
||||
*/
|
||||
void Union( const CBBOX &aBBox );
|
||||
|
||||
/**
|
||||
* Function Scale
|
||||
* scales a bounding box by its center
|
||||
* @param aScale scale factor to apply
|
||||
*/
|
||||
void Scale( float aScale );
|
||||
|
||||
/**
|
||||
* Function OverlapsBox
|
||||
* test if a bounding box overlaps this box
|
||||
* @param aBBox the bounding box to check if it overlaps
|
||||
*/
|
||||
bool OverlapsBox( const CBBOX &aBBox ) const;
|
||||
|
||||
/**
|
||||
* Function Inside
|
||||
* check is a point is inside this bounding box
|
||||
* @param aPoint point to test
|
||||
*/
|
||||
bool Inside( const S3D_VERTEX &aPoint ) const;
|
||||
|
||||
/**
|
||||
* Function ApplyTransformation
|
||||
* apply a transformation matrix to the box points
|
||||
* @param aTransformMatrix matrix to apply to the points of the bounding box
|
||||
*/
|
||||
void ApplyTransformation( glm::mat4 aTransformMatrix );
|
||||
|
||||
/**
|
||||
* Function ApplyTransformationAA
|
||||
* apply a transformation matrix to the box points and recalculate it
|
||||
* to fit an axis aligned bounding box
|
||||
* @param aTransformMatrix matrix to apply to the points of the bounding box
|
||||
*/
|
||||
void ApplyTransformationAA( glm::mat4 aTransformMatrix );
|
||||
|
||||
/**
|
||||
* Function Volume
|
||||
* calculate the volume of a bounding box
|
||||
* @return float - volume of this bounding box
|
||||
*/
|
||||
float Volume() const;
|
||||
|
||||
/**
|
||||
* Function GLdebug
|
||||
* render a wired bounding box using openGL
|
||||
*/
|
||||
void GLdebug() const;
|
||||
|
||||
/**
|
||||
* Function IsInitialized
|
||||
* check if this bounding box is already initialized
|
||||
* @return bool - return true if it was initialized, false if otherwise
|
||||
*/
|
||||
bool IsInitialized() const;
|
||||
|
||||
/**
|
||||
* Function Reset
|
||||
* reset the bounding box to zero and de-initialized it
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Function GetCenter
|
||||
* return the center point of the bounding box
|
||||
* @return S3D_VERTEX - the position of the center of this bounding box
|
||||
*/
|
||||
S3D_VERTEX GetCenter() const;
|
||||
|
||||
/**
|
||||
* Function Min
|
||||
* return the minimun vertex pointer
|
||||
* @return S3D_VERTEX - the minimun vertice position
|
||||
*/
|
||||
S3D_VERTEX Min() const;
|
||||
|
||||
/**
|
||||
* Function Max
|
||||
* return the maximum vertex pointer
|
||||
* @return S3D_VERTEX - the maximun vertice position
|
||||
*/
|
||||
S3D_VERTEX Max() const;
|
||||
|
||||
private:
|
||||
S3D_VERTEX m_min; ///< point of the lower position of the bounding box
|
||||
S3D_VERTEX m_max; ///< point of the higher position of the bounding box
|
||||
bool m_initialized; ///< initialization status of the bounding box. true - if initialized, false otherwise
|
||||
};
|
||||
|
||||
#endif // CBBox_h
|
|
@ -22,17 +22,26 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file CImage.cpp
|
||||
* @brief one 8bit-channel image implementation
|
||||
*/
|
||||
|
||||
#include "CImage.h"
|
||||
#include <wx/image.h> // Used for save an image to disk
|
||||
#include <string.h> // For memcpy
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(n, min, max) {if (n < min) n=min; else if (n > max) n = max;}
|
||||
#endif
|
||||
|
||||
|
||||
CIMAGE::CIMAGE( unsigned int xsize, unsigned int ysize )
|
||||
CIMAGE::CIMAGE( unsigned int aXsize, unsigned int aYsize )
|
||||
{
|
||||
m_pixels = (unsigned char*)malloc( xsize * ysize );
|
||||
m_width = xsize;
|
||||
m_height = ysize;
|
||||
m_wxh = xsize * ysize;
|
||||
m_wxh = aXsize * aYsize;
|
||||
m_pixels = (unsigned char*)malloc( m_wxh );
|
||||
m_width = aXsize;
|
||||
m_height = aYsize;
|
||||
m_wraping = (E_WRAP)WRAP_CLAMP;
|
||||
}
|
||||
|
||||
|
@ -43,10 +52,16 @@ CIMAGE::~CIMAGE()
|
|||
}
|
||||
|
||||
|
||||
bool CIMAGE::wrapCoords( int *xo, int *yo )
|
||||
unsigned char* CIMAGE::GetBuffer() const
|
||||
{
|
||||
int x = *xo;
|
||||
int y = *yo;
|
||||
return m_pixels;
|
||||
}
|
||||
|
||||
|
||||
bool CIMAGE::wrapCoords( int *aXo, int *aYo ) const
|
||||
{
|
||||
int x = *aXo;
|
||||
int y = *aYo;
|
||||
|
||||
switch(m_wraping)
|
||||
{
|
||||
|
@ -66,40 +81,41 @@ bool CIMAGE::wrapCoords( int *xo, int *yo )
|
|||
break;
|
||||
}
|
||||
|
||||
if( (x < 0) || (x >= (int)m_width) || (y < 0) || (y >= (int)m_height))
|
||||
if( (x < 0) || (x >= (int)m_width) ||
|
||||
(y < 0) || (y >= (int)m_height) )
|
||||
return false;
|
||||
|
||||
*xo = x;
|
||||
*yo = y;
|
||||
*aXo = x;
|
||||
*aYo = y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CIMAGE::setpixel( int x, int y, unsigned char value )
|
||||
void CIMAGE::Setpixel( int aX, int aY, unsigned char aValue )
|
||||
{
|
||||
if( wrapCoords( &x, &y ) )
|
||||
m_pixels[x + y * m_width] = value;
|
||||
if( wrapCoords( &aX, &aY ) )
|
||||
m_pixels[aX + aY * m_width] = aValue;
|
||||
}
|
||||
|
||||
|
||||
unsigned char CIMAGE::getpixel(int x, int y)
|
||||
unsigned char CIMAGE::Getpixel( int aX, int aY ) const
|
||||
{
|
||||
if( wrapCoords( &x, &y ) )
|
||||
return m_pixels[x + y * m_width];
|
||||
if( wrapCoords( &aX, &aY ) )
|
||||
return m_pixels[aX + aY * m_width];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CIMAGE::invert()
|
||||
void CIMAGE::Invert()
|
||||
{
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
for( unsigned int it = 0; it < m_wxh; it++ )
|
||||
m_pixels[it] = 255 - m_pixels[it];
|
||||
}
|
||||
|
||||
|
||||
void CIMAGE::copyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation )
|
||||
void CIMAGE::CopyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation )
|
||||
{
|
||||
int aV, bV;
|
||||
|
||||
|
@ -116,105 +132,116 @@ void CIMAGE::copyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOpe
|
|||
|
||||
switch(aOperation)
|
||||
{
|
||||
case COPY_RAW:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
m_pixels[it] = aImgA->m_pixels[it];
|
||||
break;
|
||||
case COPY_RAW:
|
||||
memcpy( m_pixels, aImgA->m_pixels, m_wxh );
|
||||
break;
|
||||
|
||||
case COPY_ADD:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
case COPY_ADD:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
aV = (aV + bV);
|
||||
aV = (aV > 255)?255:aV;
|
||||
aV = (aV + bV);
|
||||
aV = (aV > 255)?255:aV;
|
||||
|
||||
m_pixels[it] = aV;
|
||||
}
|
||||
break;
|
||||
m_pixels[it] = aV;
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_SUB:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
case COPY_SUB:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
aV = (aV - bV);
|
||||
aV = (aV < 0)?0:aV;
|
||||
aV = (aV - bV);
|
||||
aV = (aV < 0)?0:aV;
|
||||
|
||||
m_pixels[it] = aV;
|
||||
}
|
||||
break;
|
||||
m_pixels[it] = aV;
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_DIF:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
case COPY_DIF:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = abs(aV - bV);
|
||||
}
|
||||
break;
|
||||
m_pixels[it] = abs(aV - bV);
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_MUL:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
case COPY_MUL:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = (unsigned char)((((float)aV / 255.0f) * ((float)bV / 255.0f)) * 255);
|
||||
}
|
||||
break;
|
||||
m_pixels[it] = (unsigned char)((((float)aV / 255.0f) * ((float)bV / 255.0f)) * 255);
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_AND:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] & aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
case COPY_AND:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] & aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_OR:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] | aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
case COPY_OR:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] | aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_XOR:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] ^ aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_BLEND50:
|
||||
break;
|
||||
case COPY_XOR:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
m_pixels[it] = aImgA->m_pixels[it] ^ aImgB->m_pixels[it];
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_BLEND50:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
case COPY_MIN:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
m_pixels[it] = (aV + bV) / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
m_pixels[it] = (aV < bV)?aV:bV;
|
||||
}
|
||||
break;
|
||||
case COPY_MIN:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
case COPY_MAX:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
m_pixels[it] = (aV < bV)?aV:bV;
|
||||
}
|
||||
break;
|
||||
|
||||
m_pixels[it] = (aV > bV)?aV:bV;
|
||||
}
|
||||
break;
|
||||
case COPY_MAX:
|
||||
for( unsigned int it = 0;it < m_wxh; it++ )
|
||||
{
|
||||
aV = aImgA->m_pixels[it];
|
||||
bV = aImgB->m_pixels[it];
|
||||
|
||||
m_pixels[it] = (aV > bV)?aV:bV;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S_FILTER FILTERS[9] = {
|
||||
// TIP: If you want create or test filters you can use GIMP
|
||||
// with a generic convolution matrix and get the values from there.
|
||||
// http://docs.gimp.org/nl/plug-in-convmatrix.html
|
||||
static const S_FILTER FILTERS[] = {
|
||||
// Hi Pass
|
||||
{
|
||||
{ { 0, -1, -1, -1, 0},
|
||||
|
@ -230,17 +257,28 @@ S_FILTER FILTERS[9] = {
|
|||
// Blur
|
||||
{
|
||||
{ { 3, 5, 7, 5, 3},
|
||||
{ 4, 9, 12, 9, 5},
|
||||
{ 5, 9, 12, 9, 5},
|
||||
{ 7, 12, 20, 12, 7},
|
||||
{ 4, 9, 12, 9, 5},
|
||||
{ 5, 9, 12, 9, 5},
|
||||
{ 3, 5, 7, 5, 3}
|
||||
},
|
||||
180,
|
||||
182,
|
||||
0
|
||||
},
|
||||
|
||||
// Blur Invert
|
||||
{
|
||||
{ { 0, 0, 0, 0, 0},
|
||||
{ 0, 0, -1, 0, 0},
|
||||
{ 0, -1, 0, -1, 0},
|
||||
{ 0, 0, -1, 0, 0},
|
||||
{ 0, 0, 0, 0, 0}
|
||||
},
|
||||
4,
|
||||
255
|
||||
},
|
||||
|
||||
// KS 01
|
||||
//
|
||||
{
|
||||
{ { 0, 2, 4, 2, 0},
|
||||
{ 2, -2, 1, -2, 2},
|
||||
|
@ -326,31 +364,41 @@ S_FILTER FILTERS[9] = {
|
|||
};// Filters
|
||||
|
||||
|
||||
void CIMAGE::efxFilter( CIMAGE *aInImg, float aGain, E_FILTER aFilterType )
|
||||
//!TODO: This functions can be optimized slipting it between the edges and
|
||||
// do it without use the getpixel function.
|
||||
// Optimization can be done to m_pixels[ix + iy * m_width]
|
||||
// but keep in mind the parallel process of the algorithm
|
||||
void CIMAGE::EfxFilter( CIMAGE *aInImg, E_FILTER aFilterType )
|
||||
{
|
||||
S_FILTER filter = FILTERS[aFilterType];
|
||||
|
||||
aInImg->m_wraping = WRAP_CLAMP;
|
||||
m_wraping = WRAP_CLAMP;
|
||||
|
||||
#ifdef USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif /* USE_OPENMP */
|
||||
|
||||
for( int iy = 0; iy < (int)m_height; iy++)
|
||||
{
|
||||
for( int ix = 0; ix < (int)m_width; ix++ )
|
||||
{
|
||||
int v = filter.offset;
|
||||
int v = 0;
|
||||
|
||||
for( int sy = 0; sy < 5; sy++ )
|
||||
{
|
||||
for( int sx = 0; sx < 5; sx++ )
|
||||
{
|
||||
int factor = filter.kernel[sx][sy];
|
||||
unsigned char pixelv = aInImg->getpixel( ix + sx - 2, iy + sy - 2 );
|
||||
unsigned char pixelv = aInImg->Getpixel( ix + sx - 2, iy + sy - 2 );
|
||||
v += pixelv * factor;
|
||||
}
|
||||
}
|
||||
|
||||
v /= filter.div;
|
||||
|
||||
v += filter.offset;
|
||||
|
||||
CLAMP(v, 0, 255);
|
||||
|
||||
m_pixels[ix + iy * m_width] = v;
|
||||
|
@ -359,7 +407,7 @@ void CIMAGE::efxFilter( CIMAGE *aInImg, float aGain, E_FILTER aFilterType )
|
|||
}
|
||||
|
||||
|
||||
void CIMAGE::setPixelsFromNormalizedFloat( const float * aNormalizedFloatArray )
|
||||
void CIMAGE::SetPixelsFromNormalizedFloat( const float * aNormalizedFloatArray )
|
||||
{
|
||||
for( unsigned int i = 0; i < m_wxh; i++ )
|
||||
{
|
||||
|
@ -370,26 +418,23 @@ void CIMAGE::setPixelsFromNormalizedFloat( const float * aNormalizedFloatArray )
|
|||
}
|
||||
|
||||
|
||||
void CIMAGE::saveAsPNG( wxString aFileName )
|
||||
void CIMAGE::SaveAsPNG( wxString aFileName ) const
|
||||
{
|
||||
unsigned char* pixelbuffer = (unsigned char*) malloc( m_wxh * 3 );
|
||||
//unsigned char* alphabuffer = (unsigned char*) malloc( m_width * aHeight );
|
||||
|
||||
unsigned char* pixelbuffer = (unsigned char*) malloc( m_wxh * 3 );
|
||||
|
||||
wxImage image( m_width, m_height );
|
||||
|
||||
for( unsigned int i = 0; i < m_wxh; i++)
|
||||
{
|
||||
unsigned char v = m_pixels[i];
|
||||
// Set RGB value with all same values intensities
|
||||
pixelbuffer[i * 3 + 0] = v;
|
||||
pixelbuffer[i * 3 + 1] = v;
|
||||
pixelbuffer[i * 3 + 2] = v;
|
||||
//alphabuffer[i * 1 + 0] = aRGBABufferImage[i * 4 + 3];
|
||||
}
|
||||
|
||||
image.SetData( pixelbuffer );
|
||||
//image.SetAlpha( alphabuffer );
|
||||
image = image.Mirror( false );
|
||||
image.SaveFile( aFileName + ".png", wxBITMAP_TYPE_PNG );
|
||||
image.Destroy();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,17 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file CImage.h
|
||||
* @brief one 8bit-channel image definition
|
||||
*/
|
||||
|
||||
#ifndef CImage_h
|
||||
#define CImage_h
|
||||
|
||||
#include <wx/image.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
/// Image operation type
|
||||
enum E_IMAGE_OP {
|
||||
COPY_RAW,
|
||||
COPY_ADD,
|
||||
|
@ -41,17 +47,23 @@ enum E_IMAGE_OP {
|
|||
COPY_MAX
|
||||
};
|
||||
|
||||
|
||||
/// Image wrap type enumeration
|
||||
enum E_WRAP {
|
||||
WRAP_ZERO, ///< Coords that wraps are not evaluated
|
||||
WRAP_CLAMP,
|
||||
WRAP_WRAP ///< Coords are wrapped arround
|
||||
WRAP_ZERO, ///< Coords that wraps are not evaluated
|
||||
WRAP_CLAMP, ///< Coords are clamped to image size
|
||||
WRAP_WRAP ///< Coords are wrapped arround
|
||||
};
|
||||
|
||||
|
||||
/// Filter type enumeration
|
||||
enum E_FILTER {
|
||||
FILTER_HIPASS,
|
||||
FILTER_BLUR
|
||||
FILTER_GAUSSIAN_BLUR,
|
||||
FILTER_INVERT_BLUR,
|
||||
};
|
||||
|
||||
/// 5x5 Filter struct parameters
|
||||
typedef struct {
|
||||
signed char kernel[5][5];
|
||||
unsigned char div;
|
||||
|
@ -59,36 +71,120 @@ typedef struct {
|
|||
}S_FILTER;
|
||||
|
||||
|
||||
/**
|
||||
* Class CIMAGE
|
||||
* manages a 8-bit channel image
|
||||
*/
|
||||
class CIMAGE
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
CIMAGE( unsigned int xsize, unsigned int ysize );
|
||||
/**
|
||||
* Constructor CIMAGE
|
||||
* constructs a CIMAGE based on image size
|
||||
* @param aXsize x size
|
||||
* @param aYsize y size
|
||||
*/
|
||||
CIMAGE( unsigned int aXsize, unsigned int aYsize );
|
||||
|
||||
~CIMAGE();
|
||||
|
||||
void setpixel( int x, int y, unsigned char value );
|
||||
unsigned char getpixel( int x, int y );
|
||||
/**
|
||||
* Function Setpixel
|
||||
* set a value in a pixel position, position is clamped in accord with the
|
||||
* current clamp settings
|
||||
* @param aX x position
|
||||
* @param aY y position
|
||||
* @param aValue value to set the pixel
|
||||
*/
|
||||
void Setpixel( int aX, int aY, unsigned char aValue );
|
||||
|
||||
/**
|
||||
* Function Getpixel
|
||||
* get the pixel value from pixel position, position is clamped in accord with the
|
||||
* current clamp settings
|
||||
* @param aX x position
|
||||
* @param aY y position
|
||||
* @return unsigned char - pixel value
|
||||
*/
|
||||
unsigned char Getpixel( int aX, int aY ) const;
|
||||
|
||||
void copyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation );
|
||||
/**
|
||||
* Function CopyFull
|
||||
* perform a copy operation, based on operation type. The result destination is the self image class
|
||||
* @param aImgA an image input
|
||||
* @param aImgB an image input
|
||||
* @param aOperation operation to perform
|
||||
* COPY_RAW this <- aImgA
|
||||
* COPY_ADD this <- CLAMP(aImgA + aImgB)
|
||||
* COPY_SUB this <- CLAMP(aImgA - aImgB)
|
||||
* COPY_DIF this <- abs(aImgA - aImgB)
|
||||
* COPY_MUL this <- aImgA * aImgB
|
||||
* COPY_AND this <- aImgA & aImgB
|
||||
* COPY_OR this <- aImgA | aImgB
|
||||
* COPY_XOR this <- aImgA ^ aImgB
|
||||
* COPY_BLEND50 this <- (aImgA + aImgB) / 2
|
||||
* COPY_MIN this <- (aImgA < aImgB)?aImgA:aImgB
|
||||
* COPY_MAX this <- (aImgA > aImgB)?aImgA:aImgB
|
||||
*/
|
||||
void CopyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation );
|
||||
|
||||
void invert();
|
||||
/**
|
||||
* Function Invert
|
||||
* invert the values of image this <- (255 - this)
|
||||
*/
|
||||
void Invert();
|
||||
|
||||
void efxFilter( CIMAGE *aInImg, float aGain, E_FILTER aFilterType );
|
||||
/**
|
||||
* Function EfxFilter
|
||||
* apply a filter to the input image and stores it in the image class
|
||||
* this <- FilterType(aInImg)
|
||||
* @param aInImg input image
|
||||
* @param aFilterType filter type to apply
|
||||
*/
|
||||
void EfxFilter( CIMAGE *aInImg, E_FILTER aFilterType );
|
||||
|
||||
void saveAsPNG( wxString aFileName );
|
||||
/**
|
||||
* Function SaveAsPNG
|
||||
* save image buffer to a PNG file into the working folder.
|
||||
* each of RGB channel will have the 8bit-channel from the image.
|
||||
* @param aFileName fime name (without extension)
|
||||
*/
|
||||
void SaveAsPNG( wxString aFileName ) const;
|
||||
|
||||
/**
|
||||
* Function SetPixelsFromNormalizedFloat
|
||||
* set the current channel from a float normalized (0.0 - 1.0) buffer
|
||||
* this <- CLAMP(NormalizedFloat * 255)
|
||||
* @param aNormalizedFloatArray a float array with the same size of the image
|
||||
*/
|
||||
void SetPixelsFromNormalizedFloat( const float * aNormalizedFloatArray );
|
||||
|
||||
/**
|
||||
* Function GetBuffer
|
||||
* get the image buffer pointer
|
||||
* @return unsigned char * - the pointer of the buffer 8bit channel
|
||||
*/
|
||||
unsigned char* GetBuffer() const;
|
||||
|
||||
void setPixelsFromNormalizedFloat( const float * aNormalizedFloatArray );
|
||||
private:
|
||||
bool wrapCoords( int *xo, int *yo );
|
||||
|
||||
public:
|
||||
unsigned char* m_pixels;
|
||||
unsigned int m_width;
|
||||
unsigned int m_height;
|
||||
unsigned int m_wxh;
|
||||
E_WRAP m_wraping;
|
||||
/**
|
||||
* Function wrapCoords
|
||||
* calculate the coordinates points in accord with the current clamping settings
|
||||
* @param aXo X coordinate to be converted (output)
|
||||
* @param aXo Y coordinate to be converted (output)
|
||||
* @return bool - true if the coordinates are inside the image, false otherwise
|
||||
*/
|
||||
bool wrapCoords( int *aXo, int *aYo ) const;
|
||||
|
||||
private:
|
||||
unsigned char* m_pixels; ///< buffer to store the image 8bit-channel
|
||||
unsigned int m_width; ///< width of the image
|
||||
unsigned int m_height; ///< height of the image
|
||||
unsigned int m_wxh; ///< width * height precalc value
|
||||
E_WRAP m_wraping; ///< current wrapping type
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // CImage_h
|
||||
|
|
|
@ -31,6 +31,7 @@ set(3D-VIEWER_SRCS
|
|||
vrml_v2_modelparser.cpp
|
||||
x3dmodelparser.cpp
|
||||
CImage.cpp
|
||||
CBBox.cpp
|
||||
)
|
||||
|
||||
add_library(3d-viewer STATIC ${3D-VIEWER_SRCS})
|
||||
|
|
|
@ -231,10 +231,19 @@ void INFO3D_VISU::InitSettings( BOARD* aBoard )
|
|||
*/
|
||||
double INFO3D_VISU::GetModulesZcoord3DIU( bool aIsFlipped )
|
||||
{
|
||||
// NOTE: Z position to display modules in top of Paste and near the shadow
|
||||
if( aIsFlipped )
|
||||
return m_layerZcoord[B_Paste] - ( m_copperThickness / 2 );
|
||||
if( aIsFlipped )
|
||||
{
|
||||
if( g_Parm_3D_Visu.GetFlag( FL_SOLDERPASTE ) )
|
||||
return m_layerZcoord[B_SilkS] - ( m_copperThickness / 2.0 );
|
||||
else
|
||||
return m_layerZcoord[B_Paste] - ( m_copperThickness / 2.0 );
|
||||
}
|
||||
else
|
||||
return m_layerZcoord[F_Paste] + ( m_copperThickness / 2 );
|
||||
{
|
||||
if( g_Parm_3D_Visu.GetFlag( FL_SOLDERPASTE ) )
|
||||
return m_layerZcoord[F_SilkS] + ( m_copperThickness / 2.0 );
|
||||
else
|
||||
return m_layerZcoord[F_Paste] + ( m_copperThickness / 2.0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ enum DISPLAY3D_FLG {
|
|||
FL_RENDER_SMOOTH_NORMALS,
|
||||
FL_RENDER_USE_MODEL_NORMALS,
|
||||
FL_RENDER_MATERIAL,
|
||||
FL_RENDER_SHOW_MODEL_BBOX,
|
||||
FL_LAST
|
||||
};
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <3d_mesh_model.h>
|
||||
|
||||
class S3D_MASTER;
|
||||
class S3D_MODEL_PARSER;
|
||||
class X3D_MODEL_PARSER;
|
||||
|
||||
/**
|
||||
|
@ -49,13 +48,7 @@ public:
|
|||
master( aMaster )
|
||||
{}
|
||||
|
||||
~S3D_MODEL_PARSER()
|
||||
{
|
||||
for( unsigned int idx = 0; idx < childs.size(); idx++ )
|
||||
{
|
||||
delete childs[idx];
|
||||
}
|
||||
}
|
||||
virtual ~S3D_MODEL_PARSER(){}
|
||||
|
||||
S3D_MASTER* GetMaster()
|
||||
{
|
||||
|
@ -73,22 +66,14 @@ public:
|
|||
static S3D_MODEL_PARSER* Create( S3D_MASTER* aMaster, const wxString aExtension );
|
||||
|
||||
/**
|
||||
* pure virtual Function
|
||||
* virtual Function
|
||||
* Concrete parsers should implement this function
|
||||
* @param aFilename = the full file name of the file to load
|
||||
* @return true if as succeeded
|
||||
*/
|
||||
virtual bool Load( const wxString& aFilename ) = 0;
|
||||
|
||||
/**
|
||||
* Function Render
|
||||
* Render the model to openGL. The arguments can be both false but just only one
|
||||
* can be true.
|
||||
* @param aIsRenderingJustNonTransparentObjects
|
||||
* @param aIsRenderingJustTransparentObjects
|
||||
*/
|
||||
void Render( bool aIsRenderingJustNonTransparentObjects,
|
||||
bool aIsRenderingJustTransparentObjects );
|
||||
virtual bool Load( const wxString& aFilename ) {
|
||||
return false;
|
||||
};
|
||||
|
||||
std::vector< S3D_MESH* > childs;
|
||||
|
||||
|
@ -158,6 +143,7 @@ private:
|
|||
|
||||
|
||||
typedef std::map< std::string, std::vector< glm::vec3 > > VRML2_COORDINATE_MAP;
|
||||
typedef std::map< std::string, S3D_MESH* > VRML2_DEF_GROUP_MAP;
|
||||
|
||||
/**
|
||||
* class VRML2_MODEL_PARSER
|
||||
|
@ -171,6 +157,15 @@ public:
|
|||
|
||||
bool Load( const wxString& aFilename );
|
||||
|
||||
/**
|
||||
* Function Load
|
||||
* Load a VRML2 filename and apply a transformation to the root
|
||||
* @param aFilename file name with path
|
||||
* @param aTransformationModel a model with translation, rotation and scale to apply to default root
|
||||
* @return bool - true if finnished with success
|
||||
*/
|
||||
bool Load( const wxString& aFilename, S3D_MESH *aTransformationModel );
|
||||
|
||||
/**
|
||||
* Return string representing VRML2 file in vrml2 format
|
||||
* Function Load must be called before this function, otherwise empty
|
||||
|
@ -179,6 +174,7 @@ public:
|
|||
wxString VRML2_representation();
|
||||
|
||||
private:
|
||||
int loadFileModel( S3D_MESH *transformationModel );
|
||||
int read_Transform();
|
||||
int read_DEF();
|
||||
int read_DEF_Coordinate();
|
||||
|
@ -195,16 +191,33 @@ private:
|
|||
int read_Color();
|
||||
int read_coordIndex();
|
||||
int read_colorIndex();
|
||||
int read_USE();
|
||||
int read_geometry();
|
||||
int read_IndexedFaceSet_USE();
|
||||
int read_Transform_USE();
|
||||
int read_Inline();
|
||||
|
||||
/** Function debug_enter
|
||||
* Used in debug to increase a ' ' in the m_debugSpacer,
|
||||
* should be called after the first debug comment in a function
|
||||
*/
|
||||
void debug_enter();
|
||||
|
||||
/** Function debug_exit
|
||||
* Used in debug to decrease a ' ' in the m_debugSpacer,
|
||||
* should be called before the last debug comment in a funtion before exit
|
||||
*/
|
||||
void debug_exit();
|
||||
|
||||
bool m_normalPerVertex;
|
||||
bool colorPerVertex;
|
||||
S3D_MESH* m_model;
|
||||
S3D_MESH* m_model; ///< It stores the current model that the parsing is adding data
|
||||
FILE* m_file;
|
||||
wxString m_Filename;
|
||||
wxFileName m_Filename;
|
||||
VRML2_COORDINATE_MAP m_defCoordinateMap;
|
||||
VRML2_DEF_GROUP_MAP m_defGroupMap; ///< Stores a list of labels for groups and meshs that will be used later by the USE keyword
|
||||
S3D_MODEL_PARSER* m_ModelParser;
|
||||
S3D_MASTER* m_Master;
|
||||
wxString m_debugSpacer; ///< Used to give identation space
|
||||
};
|
||||
|
||||
|
||||
|
@ -267,7 +280,6 @@ public:
|
|||
* by the vrml file data
|
||||
*/
|
||||
VRML_MODEL_PARSER( S3D_MASTER* aMaster );
|
||||
|
||||
~VRML_MODEL_PARSER();
|
||||
|
||||
/**
|
||||
|
@ -279,11 +291,6 @@ public:
|
|||
* to our internal units.
|
||||
*/
|
||||
bool Load( const wxString& aFilename );
|
||||
|
||||
private:
|
||||
S3D_MASTER* m_curr3DShape; ///< the current 3D shape to build from the file
|
||||
VRML1_MODEL_PARSER* vrml1_parser;
|
||||
VRML2_MODEL_PARSER* vrml2_parser;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -24,11 +24,58 @@
|
|||
|
||||
/**
|
||||
* @file vrml_aux.cpp
|
||||
* @brief implements auxiliar functions to parse VRML files
|
||||
*/
|
||||
|
||||
#include "vrml_aux.h"
|
||||
|
||||
|
||||
bool GetString( FILE* File, char* aDstString, size_t maxDstLen )
|
||||
{
|
||||
|
||||
if( (!aDstString) || (maxDstLen == 0) )
|
||||
return false;
|
||||
|
||||
int c;
|
||||
|
||||
while( ( c = fgetc( File ) ) != EOF )
|
||||
{
|
||||
if( c == '\"' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( c != '\"' )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while( (( c = fgetc( File ) ) != EOF) && (maxDstLen > 0) )
|
||||
{
|
||||
if( c == '\"' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
maxDstLen--;
|
||||
|
||||
*aDstString = c;
|
||||
aDstString++;
|
||||
|
||||
}
|
||||
|
||||
*aDstString = 0;
|
||||
|
||||
if( c == '\"' )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int SkipGetChar ( FILE* File );
|
||||
|
||||
|
||||
|
@ -140,7 +187,7 @@ bool GetNextTag( FILE* File, char* tag, size_t len )
|
|||
}
|
||||
|
||||
|
||||
int read_NotImplemented( FILE* File, char closeChar )
|
||||
int Read_NotImplemented( FILE* File, char closeChar )
|
||||
{
|
||||
int c;
|
||||
|
||||
|
@ -150,12 +197,12 @@ int read_NotImplemented( FILE* File, char closeChar )
|
|||
if( c == '{' )
|
||||
{
|
||||
// DBG( printf( "{\n") );
|
||||
read_NotImplemented( File, '}' );
|
||||
Read_NotImplemented( File, '}' );
|
||||
}
|
||||
else if( c == '[' )
|
||||
{
|
||||
// DBG( printf( "[\n") );
|
||||
read_NotImplemented( File, ']' );
|
||||
Read_NotImplemented( File, ']' );
|
||||
}
|
||||
else if( c == closeChar )
|
||||
{
|
||||
|
@ -169,15 +216,15 @@ int read_NotImplemented( FILE* File, char closeChar )
|
|||
}
|
||||
|
||||
|
||||
int parseVertexList( FILE* File, std::vector<glm::vec3>& dst_vector )
|
||||
int ParseVertexList( FILE* File, std::vector<glm::vec3>& dst_vector )
|
||||
{
|
||||
// DBG( printf( " parseVertexList\n" ) );
|
||||
// DBG( printf( " ParseVertexList\n" ) );
|
||||
|
||||
dst_vector.clear();
|
||||
|
||||
glm::vec3 vertex;
|
||||
|
||||
while( parseVertex( File, vertex ) == 3 )
|
||||
while( ParseVertex( File, vertex ) == 3 )
|
||||
{
|
||||
dst_vector.push_back( vertex );
|
||||
}
|
||||
|
@ -186,7 +233,7 @@ int parseVertexList( FILE* File, std::vector<glm::vec3>& dst_vector )
|
|||
}
|
||||
|
||||
|
||||
int parseVertex( FILE* File, glm::vec3& dst_vertex )
|
||||
int ParseVertex( FILE* File, glm::vec3& dst_vertex )
|
||||
{
|
||||
float a, b, c;
|
||||
int ret = fscanf( File, "%e %e %e", &a, &b, &c );
|
||||
|
@ -209,7 +256,7 @@ int parseVertex( FILE* File, glm::vec3& dst_vertex )
|
|||
}
|
||||
|
||||
|
||||
int parseFloat( FILE* File, float* dst_float )
|
||||
int ParseFloat( FILE* File, float* dst_float )
|
||||
{
|
||||
float value;
|
||||
int ret = fscanf( File, "%e", &value );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 2014-2015 Mario Luzeiro <mrluzeiro@gmail.com>
|
||||
* Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -24,6 +24,7 @@
|
|||
|
||||
/**
|
||||
* @file vrml_aux.h
|
||||
* @brief auxiliar functions to parse VRML files
|
||||
*/
|
||||
|
||||
#ifndef _VRML_AUX_H
|
||||
|
@ -48,10 +49,63 @@
|
|||
#endif
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
int read_NotImplemented( FILE* File, char closeChar);
|
||||
int parseVertexList( FILE* File, std::vector< glm::vec3 > &dst_vector);
|
||||
int parseVertex( FILE* File, glm::vec3 &dst_vertex );
|
||||
int parseFloat( FILE* File, float *dst_float );
|
||||
/**
|
||||
* Function GetEpoxyThicknessBIU
|
||||
* skip a VRML block and eventualy internal blocks until it find the close char
|
||||
* @param File file to read from
|
||||
* @param closeChar the expected close char of the block
|
||||
* @return int - -1 if failed, 0 if OK
|
||||
*/
|
||||
int Read_NotImplemented( FILE* File, char closeChar);
|
||||
|
||||
|
||||
/**
|
||||
* Function ParseVertexList
|
||||
* parse a vertex list
|
||||
* @param File file to read from
|
||||
* @param dst_vector destination vector list
|
||||
* @return int - -1 if failed, 0 if OK
|
||||
*/
|
||||
int ParseVertexList( FILE* File, std::vector< glm::vec3 > &dst_vector);
|
||||
|
||||
|
||||
/**
|
||||
* Function ParseVertex
|
||||
* parse a vertex
|
||||
* @param File file to read from
|
||||
* @param dst_vertex destination vector
|
||||
* @return int - return the number of elements readed
|
||||
*/
|
||||
int ParseVertex( FILE* File, glm::vec3 &dst_vertex );
|
||||
|
||||
|
||||
/**
|
||||
* Function ParseFloat
|
||||
* parse a float value
|
||||
* @param File file to read from
|
||||
* @param dst_float destination float
|
||||
* @return int - Return the number of floats readed
|
||||
*/
|
||||
int ParseFloat( FILE* File, float *dst_float );
|
||||
|
||||
/**
|
||||
* Function GetNextTag
|
||||
* parse the next tag
|
||||
* @param File file to read from
|
||||
* @param tag destination pointer
|
||||
* @param len max length of storage
|
||||
* @return bool - true if succeeded, false if EOF
|
||||
*/
|
||||
bool GetNextTag( FILE* File, char* tag, size_t len );
|
||||
|
||||
/**
|
||||
* Function GetString
|
||||
* parse a string, it expects starting by " and end with "
|
||||
* @param File file to read from
|
||||
* @param aDstString destination pointer
|
||||
* @param maxDstLen max length of storage
|
||||
* @return bool - true if successful read the string, false if failed to get a string
|
||||
*/
|
||||
bool GetString( FILE* File, char* aDstString, size_t maxDstLen );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -138,7 +138,7 @@ int VRML1_MODEL_PARSER::read_separator()
|
|||
else if( ( *text != '}' ) )
|
||||
{
|
||||
// DBG( printf( "read_NotImplemented %s\n", text ) );
|
||||
read_NotImplemented( m_file, '}' );
|
||||
Read_NotImplemented( m_file, '}' );
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -272,7 +272,7 @@ int VRML1_MODEL_PARSER::readMaterial_ambientColor()
|
|||
{
|
||||
// DBG( printf( " readMaterial_ambientColor\n" ) );
|
||||
|
||||
return parseVertexList( m_file, m_model->m_Materials->m_AmbientColor );
|
||||
return ParseVertexList( m_file, m_model->m_Materials->m_AmbientColor );
|
||||
}
|
||||
|
||||
|
||||
|
@ -280,7 +280,7 @@ int VRML1_MODEL_PARSER::readMaterial_diffuseColor()
|
|||
{
|
||||
// DBG( printf( " readMaterial_diffuseColor\n" ) );
|
||||
|
||||
return parseVertexList( m_file, m_model->m_Materials->m_DiffuseColor );
|
||||
return ParseVertexList( m_file, m_model->m_Materials->m_DiffuseColor );
|
||||
}
|
||||
|
||||
|
||||
|
@ -288,7 +288,7 @@ int VRML1_MODEL_PARSER::readMaterial_emissiveColor()
|
|||
{
|
||||
// DBG( printf( " readMaterial_emissiveColor\n" ) );
|
||||
|
||||
int ret = parseVertexList( m_file, m_model->m_Materials->m_EmissiveColor );
|
||||
int ret = ParseVertexList( m_file, m_model->m_Materials->m_EmissiveColor );
|
||||
|
||||
if( m_Master->m_use_modelfile_emissiveColor == false )
|
||||
{
|
||||
|
@ -303,7 +303,7 @@ int VRML1_MODEL_PARSER::readMaterial_specularColor()
|
|||
{
|
||||
// DBG( printf( " readMaterial_specularColor\n" ) );
|
||||
|
||||
int ret = parseVertexList( m_file, m_model->m_Materials->m_SpecularColor );
|
||||
int ret = ParseVertexList( m_file, m_model->m_Materials->m_SpecularColor );
|
||||
|
||||
if( m_Master->m_use_modelfile_specularColor == false )
|
||||
{
|
||||
|
@ -368,7 +368,7 @@ int VRML1_MODEL_PARSER::readCoordinate3_point()
|
|||
{
|
||||
// DBG( printf( " readCoordinate3_point\n" ) );
|
||||
|
||||
if( parseVertexList( m_file, m_model->m_Point ) == 0 )
|
||||
if( ParseVertexList( m_file, m_model->m_Point ) == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -41,17 +41,20 @@
|
|||
VRML_MODEL_PARSER::VRML_MODEL_PARSER( S3D_MASTER* aMaster ) :
|
||||
S3D_MODEL_PARSER( aMaster )
|
||||
{
|
||||
vrml1_parser = NULL;
|
||||
vrml2_parser = NULL;
|
||||
m_curr3DShape = NULL;
|
||||
}
|
||||
|
||||
|
||||
VRML_MODEL_PARSER::~VRML_MODEL_PARSER()
|
||||
{
|
||||
for( unsigned int idx = 0; idx < childs.size(); idx++ )
|
||||
{
|
||||
if( childs[idx] )
|
||||
{
|
||||
delete childs[idx];
|
||||
childs[idx] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool VRML_MODEL_PARSER::Load( const wxString& aFilename )
|
||||
{
|
||||
char line[11 + 1];
|
||||
|
@ -72,20 +75,20 @@ bool VRML_MODEL_PARSER::Load( const wxString& aFilename )
|
|||
|
||||
fclose( file );
|
||||
|
||||
childs.clear();
|
||||
|
||||
if( stricmp( line, "#VRML V2.0" ) == 0 )
|
||||
{
|
||||
vrml2_parser = new VRML2_MODEL_PARSER( this );
|
||||
VRML2_MODEL_PARSER *vrml2_parser = new VRML2_MODEL_PARSER( this );
|
||||
vrml2_parser->Load( aFilename );
|
||||
delete vrml2_parser;
|
||||
vrml2_parser = NULL;
|
||||
return true;
|
||||
}
|
||||
else if( stricmp( line, "#VRML V1.0" ) == 0 )
|
||||
{
|
||||
vrml1_parser = new VRML1_MODEL_PARSER( this );
|
||||
VRML1_MODEL_PARSER *vrml1_parser = new VRML1_MODEL_PARSER( this );
|
||||
vrml1_parser->Load( aFilename );
|
||||
delete vrml1_parser;
|
||||
vrml1_parser = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,14 @@ X3D_MODEL_PARSER::X3D_MODEL_PARSER( S3D_MASTER* aMaster ) :
|
|||
|
||||
X3D_MODEL_PARSER::~X3D_MODEL_PARSER()
|
||||
{
|
||||
for( unsigned int idx = 0; idx < childs.size(); idx++ )
|
||||
{
|
||||
if( childs[idx] )
|
||||
{
|
||||
delete childs[idx];
|
||||
childs[idx] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue