From eee901ff57a14d4795e6e1a73319f9ed8ea5a157 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 28 Mar 2015 12:33:56 +0100 Subject: [PATCH] 3D-viewer: Fixes and enhancements. Add comments in header files. Fix some coding style issues. --- 3d-viewer/3d_aux.cpp | 6 +- 3d-viewer/3d_canvas.cpp | 25 +- 3d-viewer/3d_canvas.h | 96 +-- 3d-viewer/3d_class.cpp | 57 +- 3d-viewer/3d_draw.cpp | 640 ++++++++++++-------- 3d-viewer/3d_draw_basic_functions.cpp | 16 +- 3d-viewer/3d_draw_helper_functions.cpp | 24 +- 3d-viewer/3d_frame.cpp | 30 +- 3d-viewer/3d_material.cpp | 10 +- 3d-viewer/3d_material.h | 6 +- 3d-viewer/3d_mesh_model.cpp | 205 +++++-- 3d-viewer/3d_mesh_model.h | 61 +- 3d-viewer/3d_read_mesh.cpp | 188 +++--- 3d-viewer/3d_struct.h | 106 +--- 3d-viewer/3d_toolbar.cpp | 7 + 3d-viewer/3d_types.h | 107 ++++ 3d-viewer/3d_viewer_id.h | 1 + 3d-viewer/CBBox.cpp | 278 +++++++++ 3d-viewer/CBBox.h | 182 ++++++ 3d-viewer/CImage.cpp | 273 +++++---- 3d-viewer/CImage.h | 138 ++++- 3d-viewer/CMakeLists.txt | 1 + 3d-viewer/info3d_visu.cpp | 17 +- 3d-viewer/info3d_visu.h | 1 + 3d-viewer/modelparsers.h | 65 +- 3d-viewer/vrml_aux.cpp | 65 +- 3d-viewer/vrml_aux.h | 64 +- 3d-viewer/vrml_v1_modelparser.cpp | 12 +- 3d-viewer/vrml_v2_modelparser.cpp | 803 +++++++++++++++++++++---- 3d-viewer/vrmlmodelparser.cpp | 21 +- 3d-viewer/x3dmodelparser.cpp | 8 + 31 files changed, 2599 insertions(+), 914 deletions(-) create mode 100644 3d-viewer/3d_types.h create mode 100644 3d-viewer/CBBox.cpp create mode 100644 3d-viewer/CBBox.h diff --git a/3d-viewer/3d_aux.cpp b/3d-viewer/3d_aux.cpp index aee7d99922..1fed39acf9 100644 --- a/3d-viewer/3d_aux.cpp +++ b/3d-viewer/3d_aux.cpp @@ -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; diff --git a/3d-viewer/3d_canvas.cpp b/3d-viewer/3d_canvas.cpp index ff15f9bb2f..706014eb4a 100644 --- a/3d-viewer/3d_canvas.cpp +++ b/3d-viewer/3d_canvas.cpp @@ -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 ) diff --git a/3d-viewer/3d_canvas.h b/3d-viewer/3d_canvas.h index dba7f93c07..94f5155852 100644 --- a/3d-viewer/3d_canvas.h +++ b/3d-viewer/3d_canvas.h @@ -43,7 +43,9 @@ #endif #include <3d_struct.h> +#include #include +#include 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 m_model_parsers_list; + std::vector 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& model_parsers_list, - std::vector& 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() }; diff --git a/3d-viewer/3d_class.cpp b/3d-viewer/3d_class.cpp index eb34a67c6f..159a74bb69 100644 --- a/3d-viewer/3d_class.cpp +++ b/3d-viewer/3d_class.cpp @@ -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 #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 ) { diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index c9dd338282..38a3406ef7 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -1,6 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * + * Copyright (C) 2014-2015 Mario Luzeiro * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or @@ -23,6 +24,7 @@ /** * @file 3d_draw.cpp + * */ #include @@ -42,7 +44,8 @@ #include #include #include - +#include +#include #ifdef __WINDOWS__ #include // must be included before gl.h #endif @@ -65,11 +68,9 @@ static GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer ); -void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, +void EDA_3D_CANVAS::create_and_render_shadow_buffer( GLuint *aDst_gl_texture, GLuint aTexture_size, bool aDraw_body, int aBlurPasses ) { - unsigned char *depthbufferRGBA = (unsigned char*) malloc( aTexture_size * aTexture_size * 4 ); - glDisable( GL_TEXTURE_2D ); glViewport( 0, 0, aTexture_size, aTexture_size); @@ -77,10 +78,7 @@ void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - // move the board in order to draw it with its center at 0,0 3D coordinates - glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits, - -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits, - 0.0F ); + // Render body and shapes if( aDraw_body && m_glLists[GL_ID_BODY] ) glCallList( m_glLists[GL_ID_BODY] ); @@ -88,9 +86,10 @@ void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, if( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] ) glCallList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] ); - glFinish(); + // Create and Initialize the float depth buffer float *depthbufferFloat = (float*) malloc( aTexture_size * aTexture_size * sizeof(float) ); + for( unsigned int i = 0; i < (aTexture_size * aTexture_size); i++ ) depthbufferFloat[i] = 1.0f; @@ -101,6 +100,7 @@ void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, aTexture_size, aTexture_size, GL_DEPTH_COMPONENT, GL_FLOAT, depthbufferFloat ); + CheckGLError( __FILE__, __LINE__ ); glEnable( GL_TEXTURE_2D ); glGenTextures( 1, aDst_gl_texture ); @@ -109,43 +109,36 @@ void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, CIMAGE imgDepthBuffer( aTexture_size, aTexture_size ); CIMAGE imgDepthBufferAux( aTexture_size, aTexture_size ); - imgDepthBuffer.setPixelsFromNormalizedFloat( depthbufferFloat ); - + imgDepthBuffer.SetPixelsFromNormalizedFloat( depthbufferFloat ); + free( depthbufferFloat ); - wxString filename; + // Debug texture image + //wxString filename; //filename.Printf( "imgDepthBuffer_%04d", *aDst_gl_texture ); - //imgDepthBuffer.saveAsPNG( filename ); + //imgDepthBuffer.SaveAsPNG( filename ); - while (aBlurPasses > 0) + while( aBlurPasses > 0 ) { aBlurPasses--; - imgDepthBufferAux.efxFilter( &imgDepthBuffer, 1.0, FILTER_BLUR); - imgDepthBuffer.efxFilter( &imgDepthBufferAux, 1.0, FILTER_BLUR); + imgDepthBufferAux.EfxFilter( &imgDepthBuffer, FILTER_GAUSSIAN_BLUR ); + imgDepthBuffer.EfxFilter( &imgDepthBufferAux, FILTER_GAUSSIAN_BLUR ); } - //filename.Printf( "imgDepthBuffer_blur_%04d", *aDst_gl_texture ); - //imgDepthBuffer.saveAsPNG( filename ); - imgDepthBuffer.copyFull( &imgDepthBuffer, &imgDepthBuffer, COPY_MUL ); - //imgDepthBuffer.copyFull( &imgDepthBuffer, &imgDepthBuffer, COPY_MUL ); - //filename.Printf( "imgDepthBuffer_mul_%04d", *aDst_gl_texture ); - //imgDepthBuffer.saveAsPNG( filename ); + // Debug texture image + //filename.Printf( "imgDepthBuffer_blur%04d", *aDst_gl_texture ); + //imgDepthBuffer.SaveAsPNG( filename ); - //imgDepthBufferAux.efxFilter( &imgDepthBuffer, 1.0, FILTER_BLUR); - //imgDepthBuffer.efxFilter( &imgDepthBufferAux, 1.0, FILTER_BLUR); - //filename.Printf( "imgDepthBuffer_mulblur_%04d", *aDst_gl_texture ); - //imgDepthBuffer.saveAsPNG( filename ); + unsigned char *depthbufferRGBA = (unsigned char*) malloc( aTexture_size * aTexture_size * 4 ); + unsigned char *pPixels = imgDepthBuffer.GetBuffer(); - imgDepthBuffer.invert(); - //filename.Printf( "imgDepthBuffer_invert_%04d", *aDst_gl_texture ); - //imgDepthBuffer.saveAsPNG( filename ); - - for(unsigned int i = 0; i < (aTexture_size * aTexture_size); i++) + // Convert it to a RGBA buffer + for( unsigned int i = 0; i < (aTexture_size * aTexture_size); i++ ) { depthbufferRGBA[i * 4 + 0] = 0; depthbufferRGBA[i * 4 + 1] = 0; depthbufferRGBA[i * 4 + 2] = 0; - depthbufferRGBA[i * 4 + 3] = imgDepthBuffer.m_pixels[i]; + depthbufferRGBA[i * 4 + 3] = 255 - pPixels[i]; // Store in alpha channel the inversion of the image } glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); @@ -156,11 +149,14 @@ void EDA_3D_CANVAS::Create_and_Render_Shadow_Buffer( GLuint *aDst_gl_texture, glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, aTexture_size, aTexture_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, depthbufferRGBA ); free( depthbufferRGBA ); + + CheckGLError( __FILE__, __LINE__ ); } -#define SHADOW_BOARD_SCALE 1.5f +/// Scale factor to make a bigger BBox in order to blur the texture and dont have artifacts in the edges +#define SHADOW_BOUNDING_BOX_SCALE 1.25f -void EDA_3D_CANVAS::GenerateFakeShadowsTextures( wxString* aErrorMessages, bool aShowWarnings ) +void EDA_3D_CANVAS::generateFakeShadowsTextures( wxString* aErrorMessages, bool aShowWarnings ) { if( m_shadow_init == true ) { @@ -170,6 +166,8 @@ void EDA_3D_CANVAS::GenerateFakeShadowsTextures( wxString* aErrorMessages, bool // Init info 3d parameters and create gl lists: CreateDrawGL_List( aErrorMessages, aShowWarnings ); + DBG( unsigned strtime = GetRunningMicroSecs() ); + m_shadow_init = true; glClearColor( 0, 0, 0, 1 ); @@ -177,45 +175,80 @@ void EDA_3D_CANVAS::GenerateFakeShadowsTextures( wxString* aErrorMessages, bool glMatrixMode( GL_PROJECTION ); glLoadIdentity(); - const double ZDIST_MAX = Millimeter2iu( 3.5 ) * GetPrm3DVisu().m_BiuTo3Dunits; + const float zDistMax = Millimeter2iu( 3.5 ) * GetPrm3DVisu().m_BiuTo3Dunits; + glOrtho( -GetPrm3DVisu().m_BoardSize.x * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, GetPrm3DVisu().m_BoardSize.x * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, -GetPrm3DVisu().m_BoardSize.y * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, GetPrm3DVisu().m_BoardSize.y * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, - 0.0, ZDIST_MAX ); + 0.0, zDistMax ); + + float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits; // Render FRONT shadow glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); - glTranslatef( 0, 0, 0.03 ); - glRotatef( 180, 0.0, 1.0, 0.0 ); + glTranslatef( 0.0f, 0.0f, zpos ); + glRotatef( 180.0f, 0.0f, 1.0f, 0.0f ); - Create_and_Render_Shadow_Buffer( &m_text_fake_shadow_front, 512, false, 1 ); + // move the board in order to draw it with its center at 0,0 3D coordinates + glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits, + -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits, + 0.0f ); + create_and_render_shadow_buffer( &m_text_fake_shadow_front, 512, false, 1 ); + + zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits; // Render BACK shadow glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); - glTranslatef( 0, 0, 0.03 ); - ///glRotatef( 0.0, 0.0, 1.0, 0.0 ); + glTranslatef( 0.0f, 0.0f, fabs( zpos ) ); + + + // move the board in order to draw it with its center at 0,0 3D coordinates + glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits, + -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits, + 0.0f ); + + create_and_render_shadow_buffer( &m_text_fake_shadow_back, 512, false, 1 ); - Create_and_Render_Shadow_Buffer( &m_text_fake_shadow_back, 512, false, 1 ); // Render ALL BOARD shadow glMatrixMode( GL_PROJECTION ); glLoadIdentity(); - glOrtho( -GetPrm3DVisu().m_BoardSize.x * SHADOW_BOARD_SCALE * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, - GetPrm3DVisu().m_BoardSize.x * SHADOW_BOARD_SCALE * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, - -GetPrm3DVisu().m_BoardSize.y * SHADOW_BOARD_SCALE * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, - GetPrm3DVisu().m_BoardSize.y * SHADOW_BOARD_SCALE * GetPrm3DVisu().m_BiuTo3Dunits / 2.0f, - 0.0, 6.0f * ZDIST_MAX ); + + // Normalization scale to convert bouding box + // to normalize 3D units between -1.0 and +1.0 + + S3D_VERTEX v = m_fastAABBox_Shadow.Max() - m_fastAABBox_Shadow.Min(); + float BoundingBoxBoardiuTo3Dunits = 2.0f / glm::max( v.x, v.y ); + + //float zDistance = (m_lightPos.z * zDistMax) / sqrt( (m_lightPos.z - m_fastAABBox_Shadow.Min().z) ); + float zDistance = (m_lightPos.z - m_fastAABBox_Shadow.Min().z) / 3.0f; + + glOrtho( -v.x * BoundingBoxBoardiuTo3Dunits / 2.0f, + v.x * BoundingBoxBoardiuTo3Dunits / 2.0f, + -v.y * BoundingBoxBoardiuTo3Dunits / 2.0f, + v.y * BoundingBoxBoardiuTo3Dunits / 2.0f, + 0.0f, zDistance ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); - glTranslatef( 0, 0, -0.4f ); - glRotatef( 180.0, 0.0, 1.0, 0.0 ); - Create_and_Render_Shadow_Buffer( &m_text_fake_shadow_board, 512, true, 5 ); + // fits the bouding box to scale this size + glScalef( BoundingBoxBoardiuTo3Dunits, BoundingBoxBoardiuTo3Dunits, 1.0f ); + + // Place the eye in the lowerpoint of boudingbox and turn arround and look up to the model + glTranslatef( 0.0f, 0.0f, m_fastAABBox_Shadow.Min().z ); + glRotatef( 180.0, 0.0f, 1.0f, 0.0f ); + + // move the bouding box in order to draw it with its center at 0,0 3D coordinates + glTranslatef( -(m_fastAABBox_Shadow.Min().x + v.x / 2.0f), -(m_fastAABBox_Shadow.Min().y + v.y / 2.0f), 0.0f ); + + create_and_render_shadow_buffer( &m_text_fake_shadow_board, 512, true, 10 ); + + DBG( printf( " generateFakeShadowsTextures total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) ); } @@ -243,7 +276,7 @@ void EDA_3D_CANVAS::Redraw() if( isEnabled( FL_MODULE ) && isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) ) { - GenerateFakeShadowsTextures( &errorMessages, showWarnings ); + generateFakeShadowsTextures( &errorMessages, showWarnings ); } // *MUST* be called *after* SetCurrent( ): @@ -290,6 +323,7 @@ void EDA_3D_CANVAS::Redraw() glLoadIdentity(); #define MAX_VIEW_ANGLE 160.0 / 45.0 + if( GetPrm3DVisu().m_Zoom > MAX_VIEW_ANGLE ) GetPrm3DVisu().m_Zoom = MAX_VIEW_ANGLE; @@ -309,14 +343,14 @@ void EDA_3D_CANVAS::Redraw() double ratio_HV = (double) size.x / size.y; // Initialize Projection Matrix for Perspective View - gluPerspective( 45.0 * GetPrm3DVisu().m_Zoom, ratio_HV, 1, 100 ); + gluPerspective( 45.0f * GetPrm3DVisu().m_Zoom, ratio_HV, 1, 100 ); } // position viewer glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); - glTranslatef( 0.0F, 0.0F, -( m_ZBottom + m_ZTop) / 2 ); + glTranslatef( 0.0f, 0.0f, -(m_ZBottom + m_ZTop) / 2.0f ); // Setup light sources: SetLights(); @@ -324,6 +358,7 @@ void EDA_3D_CANVAS::Redraw() CheckGLError( __FILE__, __LINE__ ); glMatrixMode( GL_MODELVIEW ); // position viewer + // transformations GLfloat mat[4][4]; @@ -347,10 +382,7 @@ void EDA_3D_CANVAS::Redraw() // move the board in order to draw it with its center at 0,0 3D coordinates glTranslatef( -GetPrm3DVisu().m_BoardPos.x * GetPrm3DVisu().m_BiuTo3Dunits, -GetPrm3DVisu().m_BoardPos.y * GetPrm3DVisu().m_BiuTo3Dunits, - 0.0F ); - - // draw all objects in lists - // transparent objects should be drawn after opaque objects + 0.0f ); if( isEnabled( FL_MODULE ) ) { @@ -358,29 +390,42 @@ void EDA_3D_CANVAS::Redraw() CreateDrawGL_List( &errorMessages, showWarnings ); } + glEnable( GL_LIGHTING ); + glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - if( isEnabled( FL_SHOW_BOARD_BODY ) ) - { - glDisable( GL_LIGHTING ); + if( isRealisticMode() && isEnabled( FL_RENDER_TEXTURES ) ) + glEnable( GL_TEXTURE_2D ); + else + glDisable( GL_TEXTURE_2D ); - if( m_glLists[GL_ID_BODY] ) - { - glCallList( m_glLists[GL_ID_BODY] ); - } - - glEnable( GL_LIGHTING ); - } - - glEnable( GL_COLOR_MATERIAL ); - SetOpenGlDefaultMaterial(); - glm::vec4 specular( GetPrm3DVisu().m_CopperColor.m_Red * 0.3, - GetPrm3DVisu().m_CopperColor.m_Green * 0.3, - GetPrm3DVisu().m_CopperColor.m_Blue * 0.3, 1.0 ); - GLint shininess_value = 8; + // Set material for the board + glEnable( GL_COLOR_MATERIAL ); + SetOpenGlDefaultMaterial(); + + // Board Body + GLint shininess_value = 32; glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value ); + + if( isEnabled( FL_SHOW_BOARD_BODY ) ) + { + if( m_glLists[GL_ID_BODY] ) + { + glCallList( m_glLists[GL_ID_BODY] ); + } + } + + + // Board + + shininess_value = 52; + glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value ); + + glm::vec4 specular( GetPrm3DVisu().m_CopperColor.m_Red * 0.20f, + GetPrm3DVisu().m_CopperColor.m_Green * 0.20f, + GetPrm3DVisu().m_CopperColor.m_Blue * 0.20f, 1.0f ); glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specular.x ); if( m_glLists[GL_ID_BOARD] ) @@ -388,17 +433,17 @@ void EDA_3D_CANVAS::Redraw() glCallList( m_glLists[GL_ID_BOARD] ); } - if( isRealisticMode() && isEnabled( FL_RENDER_TEXTURES ) ) - glEnable( GL_TEXTURE_2D ); - else - glDisable( GL_TEXTURE_2D ); - SetOpenGlDefaultMaterial(); + // Tech layers + + shininess_value = 32; + glMateriali ( GL_FRONT_AND_BACK, GL_SHININESS, shininess_value ); + + glm::vec4 specularTech( 0.0f, 0.0f, 0.0f, 1.0f ); + glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, &specularTech.x ); if( m_glLists[GL_ID_TECH_LAYERS] ) { - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glCallList( m_glLists[GL_ID_TECH_LAYERS] ); } @@ -410,7 +455,9 @@ void EDA_3D_CANVAS::Redraw() glCallList( m_glLists[GL_ID_AUX_LAYERS] ); } + // Draw Component Shadow + if( isEnabled( FL_MODULE ) && isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) ) { @@ -419,7 +466,7 @@ void EDA_3D_CANVAS::Redraw() glEnable( GL_COLOR_MATERIAL ) ; SetOpenGlDefaultMaterial(); - glColor4f( 1.0, 1.0, 1.0, 1.0 ); + glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glEnable( GL_TEXTURE_2D ); @@ -437,19 +484,21 @@ void EDA_3D_CANVAS::Redraw() glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_back ); glCallList( m_glLists[GL_ID_SHADOW_BACK] ); } - glColor4f( 1.0, 1.0, 1.0, 1.0 ); + glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glEnable( GL_DEPTH_TEST ); glDisable( GL_TEXTURE_2D ); glDisable( GL_CULL_FACE ); } - glEnable(GL_COLOR_MATERIAL); + glEnable( GL_COLOR_MATERIAL ); SetOpenGlDefaultMaterial(); glDisable( GL_BLEND ); + // Draw Solid Shapes + if( isEnabled( FL_MODULE ) ) { if( ! m_glLists[GL_ID_3DSHAPES_SOLID_FRONT] ) @@ -461,25 +510,29 @@ void EDA_3D_CANVAS::Redraw() glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + // Grid uses transparency: draw it after all objects + if( isEnabled( FL_GRID ) && m_glLists[GL_ID_GRID] ) glCallList( m_glLists[GL_ID_GRID] ); + // Draw Board Shadow - if( isEnabled( FL_MODULE ) && isRealisticMode() && - isEnabled( FL_RENDER_SHADOWS ) ) + + if( isRealisticMode() && isEnabled( FL_RENDER_SHADOWS ) ) { if( m_glLists[GL_ID_SHADOW_BOARD] ) { glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glColor4f( 1.0, 1.0, 1.0, 1.0 ); + glColor4f( 1.0, 1.0, 1.0, 0.85f ); glEnable( GL_CULL_FACE ); glDisable( GL_COLOR_MATERIAL ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, m_text_fake_shadow_board ); glCallList( m_glLists[GL_ID_SHADOW_BOARD] ); glDisable( GL_CULL_FACE ); + glDisable( GL_TEXTURE_2D ); } } @@ -488,12 +541,23 @@ void EDA_3D_CANVAS::Redraw() // non transparent objects if( isEnabled( FL_MODULE ) && m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] ) { - glDisable( GL_TEXTURE_2D ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] ); } + // Debug bounding boxes + /* + glDisable( GL_BLEND ); + glDisable( GL_COLOR_MATERIAL ); + glDisable( GL_LIGHTING ); + glColor4f( 1.0f, 0.0f, 1.0f, 1.0f ); + m_fastAABBox_Shadow.GLdebug(); + + glColor4f( 0.0f, 1.0f, 1.0f, 1.0f ); + m_boardAABBox.GLdebug(); + */ + SwapBuffers(); if( !errorMessages.IsEmpty() ) @@ -503,23 +567,16 @@ void EDA_3D_CANVAS::Redraw() } -void EDA_3D_CANVAS::BuildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList ) -{ - // Use similar calculation as Grid limits, in 3D units - wxSize brd_size = getBoardSize(); - wxPoint brd_center_pos = getBoardCenter(); +void EDA_3D_CANVAS::buildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint aBoardList ) +{ + // Board shadows are based on board dimension. - float xsize = brd_size.x; - float ysize = brd_size.y; + float xmin = m_boardAABBox.Min().x; + float xmax = m_boardAABBox.Max().x; + float ymin = m_boardAABBox.Min().y; + float ymax = m_boardAABBox.Max().y; - float scale = GetPrm3DVisu().m_BiuTo3Dunits; - float xmin = (brd_center_pos.x - xsize / 2.0) * scale; - float xmax = (brd_center_pos.x + xsize / 2.0) * scale; - float ymin = (brd_center_pos.y - ysize / 2.0) * scale; - float ymax = (brd_center_pos.y + ysize / 2.0) * scale; - - float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ); - zpos *= GetPrm3DVisu().m_BiuTo3Dunits; + float zpos = GetPrm3DVisu().GetLayerZcoordBIU( F_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits; // Shadow FRONT glNewList( aFrontList, GL_COMPILE ); @@ -537,8 +594,7 @@ void EDA_3D_CANVAS::BuildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint // Shadow BACK - zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ); - zpos *= GetPrm3DVisu().m_BiuTo3Dunits; + zpos = GetPrm3DVisu().GetLayerZcoordBIU( B_Paste ) * GetPrm3DVisu().m_BiuTo3Dunits; glNewList( aBacklist, GL_COMPILE ); @@ -553,33 +609,29 @@ void EDA_3D_CANVAS::BuildShadowList( GLuint aFrontList, GLuint aBacklist, GLuint glEndList(); - // Shadow BOARD - xsize = brd_size.x * SHADOW_BOARD_SCALE; - ysize = brd_size.y * SHADOW_BOARD_SCALE; - - scale = GetPrm3DVisu().m_BiuTo3Dunits; - xmin = (brd_center_pos.x - xsize / 2.0) * scale; - xmax = (brd_center_pos.x + xsize / 2.0) * scale; - ymin = (brd_center_pos.y - ysize / 2.0) * scale; - ymax = (brd_center_pos.y + ysize / 2.0) * scale; + // Floor shadow is based on axis alighned bounding box dimension + xmin = m_fastAABBox_Shadow.Min().x; + xmax = m_fastAABBox_Shadow.Max().x; + ymin = m_fastAABBox_Shadow.Min().y; + ymax = m_fastAABBox_Shadow.Max().y; glNewList( aBoardList, GL_COMPILE ); glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Paste ) ); glBegin (GL_QUADS); - glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, zpos * 30.0); - glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, zpos * 30.0); - glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, zpos * 30.0); - glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, zpos * 30.0); + glTexCoord2f( 1.0, 0.0 ); glVertex3f( xmin, ymin, m_fastAABBox_Shadow.Min().z ); + glTexCoord2f( 0.0, 0.0 ); glVertex3f( xmax, ymin, m_fastAABBox_Shadow.Min().z ); + glTexCoord2f( 0.0, 1.0 ); glVertex3f( xmax, ymax, m_fastAABBox_Shadow.Min().z ); + glTexCoord2f( 1.0, 1.0 ); glVertex3f( xmin, ymax, m_fastAABBox_Shadow.Min().z ); glEnd(); glEndList(); } -void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, +void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, wxString* aErrorMessages, bool aShowWarnings ) { BOARD* pcb = GetBoard(); @@ -599,12 +651,12 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, // ( We already used this trick in plot_board_layers.cpp, // see PlotSolderMaskLayer() ) const int segcountforcircle = 18; - double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) ); - const int segcountLowQuality = 12; // segments to draw a circle with low quality + double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2.0) ); + const int segcountLowQuality = 8; // segments to draw a circle with low quality // to reduce time calculations // for holes and items which do not need // a fine representation - double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) ); + double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) ); CPOLYGONS_LIST bufferPolys; bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly) @@ -640,7 +692,7 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, glNewList( aBoardList, GL_COMPILE ); - for( unsigned i=0; iPads(); for( ; pad; pad = pad->Next() ) + { + // Calculate a factor to apply to segcount (bigger pad size -> more segments) + wxSize padSize = pad->GetSize(); + int maxPadSize = glm::max( padSize.x, padSize.y ); + float segFactor = (float)maxPadSize / (float)Millimeter2iu( 0.6 ); + pad->BuildPadDrillShapePolygon( allLayerHoles, 0, - segcountLowQuality ); + (int)(segcountLowQuality * segFactor) ); + } } } @@ -801,7 +860,7 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, if( isEnabled( FL_USE_COPPER_THICKNESS ) == true ) { - thickness -= ( 0.04 * IU_PER_MM ); + thickness -= ( 0.04 * IU_PER_MM ); } glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) ); @@ -813,7 +872,8 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, throughHolesListBuilt = true; } - if ( !isEnabled( FL_SHOW_BOARD_BODY ) ) + if ( !isEnabled( FL_SHOW_BOARD_BODY ) || + isEnabled( FL_USE_COPPER_THICKNESS ) ) { setGLCopperColor(); @@ -823,25 +883,26 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, const VIA *via = dynamic_cast(track); if( via ) - Draw3DViaHole( via ); + draw3DViaHole( via ); } // Draw pads holes (vertical cylinders) for( const MODULE* module = pcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) - Draw3DPadHole( pad ); + if( pad->GetAttribute () != PAD_HOLE_NOT_PLATED ) + draw3DPadHole( pad ); } } - glEndList(); + glEndList(); // Build the body board: - glNewList( aBodyOnlyList, GL_COMPILE ); + glNewList( aBodyOnlyList, GL_COMPILE ); if( isRealisticMode() ) { - setGLEpoxyColor( 0.95 ); + setGLEpoxyColor( 1.00 ); } else { @@ -862,10 +923,10 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, // are drawn from zpos - copper_thickness/2 to zpos + copper_thickness // therefore substrate position is copper_thickness/2 to // substrate_height - copper_thickness/2 - zpos += (copper_thickness + epsilon) / 2.0; + zpos += (copper_thickness + epsilon) / 2.0f; board_thickness -= copper_thickness + epsilon; - glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( F_Cu ) ); + glNormal3f( 0.0f, 0.0f, Get3DLayer_Z_Orientation( F_Cu ) ); KI_POLYGON_SET currLayerPolyset; KI_POLYGON_SET polysetHoles; @@ -883,7 +944,7 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, if( bufferPcbOutlines.GetCornersCount() ) { - Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness/2.0, + Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0, board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures ); } @@ -891,7 +952,7 @@ void EDA_3D_CANVAS::BuildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList, } -void EDA_3D_CANVAS::BuildTechLayers3DView( wxString* aErrorMessages, bool aShowWarnings ) +void EDA_3D_CANVAS::buildTechLayers3DView( wxString* aErrorMessages, bool aShowWarnings ) { BOARD* pcb = GetBoard(); bool useTextures = isRealisticMode() && isEnabled( FL_RENDER_TEXTURES ); @@ -1016,7 +1077,7 @@ void EDA_3D_CANVAS::BuildTechLayers3DView( wxString* aErrorMessages, bool aShowW if( !pad->IsOnLayer( layer ) ) continue; - BuildPadShapeThickOutlineAsPolygon( pad, bufferPolys, + buildPadShapeThickOutlineAsPolygon( pad, bufferPolys, linewidth, segcountforcircle, correctionFactor ); } } @@ -1110,12 +1171,12 @@ void EDA_3D_CANVAS::BuildTechLayers3DView( wxString* aErrorMessages, bool aShowW /** - * Function BuildBoard3DAuxLayers + * Function buildBoard3DAuxLayers * Called by CreateDrawGL_List() * Fills the OpenGL GL_ID_BOARD draw list with items * on aux layers only */ -void EDA_3D_CANVAS::BuildBoard3DAuxLayers() +void EDA_3D_CANVAS::buildBoard3DAuxLayers() { const int segcountforcircle = 18; double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) ); @@ -1222,54 +1283,48 @@ void EDA_3D_CANVAS::CreateDrawGL_List( wxString* aErrorMessages, bool aShowWarni glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); // Create axis gl list (if it is not shown, the list will be not called - Draw3DAxis(); - - // Create grid gl list - if( ! m_glLists[GL_ID_GRID] ) - { - m_glLists[GL_ID_GRID] = glGenLists( 1 ); - glNewList( m_glLists[GL_ID_GRID], GL_COMPILE ); - - Draw3DGrid( GetPrm3DVisu().m_3D_Grid ); - glEndList(); - } + draw3DAxis(); // Create Board full gl lists: -// For testing purpose only, display calculation time to generate 3D data -// #define PRINT_CALCULATION_TIME - - -#ifdef PRINT_CALCULATION_TIME - unsigned strtime = GetRunningMicroSecs(); -#endif - if( ! m_glLists[GL_ID_BOARD] ) { + DBG( unsigned strtime = GetRunningMicroSecs() ); + m_glLists[GL_ID_BOARD] = glGenLists( 1 ); m_glLists[GL_ID_BODY] = glGenLists( 1 ); - BuildBoard3DView(m_glLists[GL_ID_BOARD], m_glLists[GL_ID_BODY], aErrorMessages, aShowWarnings ); + buildBoard3DView(m_glLists[GL_ID_BOARD], m_glLists[GL_ID_BODY], aErrorMessages, aShowWarnings ); CheckGLError( __FILE__, __LINE__ ); + + DBG( printf( " buildBoard3DView total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) ); } if( ! m_glLists[GL_ID_TECH_LAYERS] ) { + DBG( unsigned strtime = GetRunningMicroSecs() ); + m_glLists[GL_ID_TECH_LAYERS] = glGenLists( 1 ); glNewList( m_glLists[GL_ID_TECH_LAYERS], GL_COMPILE ); // when calling BuildTechLayers3DView, - // do not show warnings, which are the same as BuildBoard3DView - BuildTechLayers3DView( aErrorMessages, false ); + // do not show warnings, which are the same as buildBoard3DView + buildTechLayers3DView( aErrorMessages, false ); glEndList(); CheckGLError( __FILE__, __LINE__ ); + + DBG( printf( " buildTechLayers3DView total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) ); } if( ! m_glLists[GL_ID_AUX_LAYERS] ) { + DBG( unsigned strtime = GetRunningMicroSecs() ); + m_glLists[GL_ID_AUX_LAYERS] = glGenLists( 1 ); glNewList( m_glLists[GL_ID_AUX_LAYERS], GL_COMPILE ); - BuildBoard3DAuxLayers(); + buildBoard3DAuxLayers(); glEndList(); CheckGLError( __FILE__, __LINE__ ); + + DBG( printf( " buildBoard3DAuxLayers total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) ); } // draw modules 3D shapes @@ -1289,58 +1344,130 @@ void EDA_3D_CANVAS::CreateDrawGL_List( wxString* aErrorMessages, bool aShowWarni else m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] = 0; - BuildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT], - m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT], false ); - - CheckGLError( __FILE__, __LINE__ ); - - m_glLists[GL_ID_SHADOW_FRONT] = glGenLists( 1 ); - m_glLists[GL_ID_SHADOW_BACK] = glGenLists( 1 ); - m_glLists[GL_ID_SHADOW_BOARD] = glGenLists( 1 ); - - BuildShadowList( m_glLists[GL_ID_SHADOW_FRONT], m_glLists[GL_ID_SHADOW_BACK], - m_glLists[GL_ID_SHADOW_BOARD]); + buildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID_FRONT], + m_glLists[GL_ID_3DSHAPES_TRANSP_FRONT] ); CheckGLError( __FILE__, __LINE__ ); } + calcBBox(); -#ifdef PRINT_CALCULATION_TIME - unsigned endtime = GetRunningMicroSecs(); - wxString msg; - msg.Printf( "Built data %.1f ms", (double) (endtime - strtime) / 1000 ); - Parent()->SetStatusText( msg, 0 ); -#endif + // Create grid gl list + if( ! m_glLists[GL_ID_GRID] ) + { + m_glLists[GL_ID_GRID] = glGenLists( 1 ); + glNewList( m_glLists[GL_ID_GRID], GL_COMPILE ); + + draw3DGrid( GetPrm3DVisu().m_3D_Grid ); + + glEndList(); + } + + if( !m_glLists[GL_ID_SHADOW_FRONT] ) + m_glLists[GL_ID_SHADOW_FRONT] = glGenLists( 1 ); + + if( !m_glLists[GL_ID_SHADOW_BACK] ) + m_glLists[GL_ID_SHADOW_BACK] = glGenLists( 1 ); + + if( !m_glLists[GL_ID_SHADOW_BOARD] ) + m_glLists[GL_ID_SHADOW_BOARD] = glGenLists( 1 ); + + buildShadowList( m_glLists[GL_ID_SHADOW_FRONT], + m_glLists[GL_ID_SHADOW_BACK], + m_glLists[GL_ID_SHADOW_BOARD] ); + + CheckGLError( __FILE__, __LINE__ ); } -void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, - GLuint aTransparentList, bool aSideToLoad) +void EDA_3D_CANVAS::calcBBox() { -#ifdef PRINT_CALCULATION_TIME - unsigned strtime = GetRunningMicroSecs(); -#endif - // This lists are used to just load once of each filename model - std::vector model_parsers_list; - std::vector model_filename_list; + BOARD* pcb = GetBoard(); + + m_fastAABBox.Reset(); + + for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) + { + CBBOX tmpFastAABBox; + + // Compute the transformation matrix for this module based on translation, rotation and orientation. + float zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() ); + wxPoint pos = module->GetPosition(); + + glm::mat4 fullTransformMatrix; + fullTransformMatrix = glm::translate( glm::mat4(), S3D_VERTEX( (float)(pos.x * GetPrm3DVisu().m_BiuTo3Dunits), + (float)(-pos.y * GetPrm3DVisu().m_BiuTo3Dunits), + zpos ) ); + + if( module->GetOrientation() ) + fullTransformMatrix = glm::rotate( fullTransformMatrix, + (float)(module->GetOrientation() / 10.0f), + S3D_VERTEX( 0.0f, 0.0f, 1.0f ) ); + + if( module->IsFlipped() ) + { + fullTransformMatrix = glm::rotate( fullTransformMatrix, 180.0f, S3D_VERTEX( 0.0f, 1.0f, 0.0f ) ); + fullTransformMatrix = glm::rotate( fullTransformMatrix, 180.0f, S3D_VERTEX( 0.0f, 0.0f, 1.0f ) ); + } + + // Compute a union bounding box for all the shapes of the model + + S3D_MASTER* shape3D = module->Models(); + + for( ; shape3D; shape3D = shape3D->Next() ) + { + if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) + tmpFastAABBox.Union( shape3D->getFastAABBox() ); + } + + tmpFastAABBox.ApplyTransformationAA( fullTransformMatrix ); + + m_fastAABBox.Union( tmpFastAABBox ); + } + + // Create a board bounding box based on board size + wxSize brd_size = getBoardSize(); + wxPoint brd_center_pos = getBoardCenter(); + + float xsize = brd_size.x; + float ysize = brd_size.y; + + float scale = GetPrm3DVisu().m_BiuTo3Dunits; + float xmin = (brd_center_pos.x - xsize / 2.0) * scale; + float xmax = (brd_center_pos.x + xsize / 2.0) * scale; + float ymin = (brd_center_pos.y - ysize / 2.0) * scale; + float ymax = (brd_center_pos.y + ysize / 2.0) * scale; + + float zmin = GetPrm3DVisu().GetLayerZcoordBIU( B_Adhes ) * scale; + float zmax = GetPrm3DVisu().GetLayerZcoordBIU( F_Adhes ) * scale; + + m_boardAABBox = CBBOX( S3D_VERTEX(xmin, ymin, zmin), + S3D_VERTEX(xmax, ymax, zmax) ); + + // Add BB board with BB models and scale it a bit + m_fastAABBox.Union( m_boardAABBox ); + m_fastAABBox_Shadow = m_fastAABBox; + m_fastAABBox_Shadow.Scale( SHADOW_BOUNDING_BOX_SCALE ); +} + + +void EDA_3D_CANVAS::buildFootprintShape3DList( GLuint aOpaqueList, + GLuint aTransparentList ) +{ + DBG( unsigned strtime = GetRunningMicroSecs() ); + + // clean the parser list if it have any already loaded files + m_model_parsers_list.clear(); + m_model_filename_list.clear(); BOARD* pcb = GetBoard(); for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) - Read3DComponentShape( module, model_parsers_list, model_filename_list ); + read3DComponentShape( module ); -#ifdef PRINT_CALCULATION_TIME - { - unsigned endtime = GetRunningMicroSecs(); - wxString msg; - msg.Printf( " Read3DComponentShape total time %.1f ms", (double) (endtime - strtime) / 1000 ); - DBG( printf( "%s\n", (const char*)msg.c_str() ) ); - } -#endif + DBG( printf( " read3DComponentShape total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) ); -#ifdef PRINT_CALCULATION_TIME - strtime = GetRunningMicroSecs(); -#endif + DBG( strtime = GetRunningMicroSecs() ); bool useMaterial = g_Parm_3D_Visu.GetFlag( FL_RENDER_MATERIAL ); @@ -1354,8 +1481,9 @@ void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, bool loadOpaqueObjects = true; for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) - Render3DComponentShape( module, loadOpaqueObjects, - !loadOpaqueObjects, aSideToLoad ); + render3DComponentShape( module, loadOpaqueObjects, + !loadOpaqueObjects ); + glEndList(); @@ -1363,8 +1491,8 @@ void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, bool loadTransparentObjects = true; for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) - Render3DComponentShape( module, !loadTransparentObjects, - loadTransparentObjects, aSideToLoad ); + render3DComponentShape( module, !loadTransparentObjects, + loadTransparentObjects ); glEndList(); } @@ -1374,56 +1502,60 @@ void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, glNewList( aOpaqueList, GL_COMPILE ); for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) - Render3DComponentShape( module, false, false, aSideToLoad ); + render3DComponentShape( module, false, false ); glEndList(); } -#ifdef PRINT_CALCULATION_TIME - { - unsigned endtime = GetRunningMicroSecs(); - wxString msg; - msg.Printf( " Render3DComponentShape total time %.1f ms", (double) (endtime - strtime) / 1000 ); - DBG( printf( "%s\n", (const char*)msg.c_str() ) ); - } -#endif + DBG( printf( " render3DComponentShape total time %f ms\n", (double) (GetRunningMicroSecs() - strtime) / 1000.0 ) ); } -bool EDA_3D_CANVAS::Read3DComponentShape( MODULE* module, - std::vector& model_parsers_list, - std::vector& model_filename_list ) +bool EDA_3D_CANVAS::read3DComponentShape( MODULE* module ) { - S3D_MASTER* shape3D = module->Models(); - - for( ; shape3D; shape3D = shape3D->Next() ) + if( module ) { - if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) + S3D_MASTER* shape3D = module->Models(); + + for( ; shape3D; shape3D = shape3D->Next() ) { - bool found = false; - - unsigned int i; - wxString shape_filename = shape3D->GetShape3DFullFilename(); - - // Search for already loaded files - for( i = 0; i < model_filename_list.size(); i++ ) + if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) { - if( shape_filename.Cmp(model_filename_list[i]) == 0 ) + bool found = false; + + unsigned int i; + wxString shape_filename = shape3D->GetShape3DFullFilename(); + + // Search for already loaded files + for( i = 0; i < m_model_filename_list.size(); i++ ) { - found = true; - break; + if( shape_filename.Cmp(m_model_filename_list[i]) == 0 ) + { + found = true; + break; + } } - } - if( found == false ) - { - shape3D->ReadData(); - model_filename_list.push_back( shape_filename ); - model_parsers_list.push_back( shape3D->m_parser ); - } - else - { - DBG( printf( " Read3DComponentShape reusing %s\n", (const char*)shape_filename.c_str() ) ); - shape3D->m_parser = model_parsers_list[i]; + if( found == false ) + { + // Create a new parser + S3D_MODEL_PARSER *newParser = S3D_MODEL_PARSER::Create( shape3D, shape3D->GetShape3DExtension() ); + + if( newParser ) + { + // Read file + if( shape3D->ReadData( newParser ) == 0 ) + { + // Store this couple filename / parsed file + m_model_filename_list.push_back( shape_filename ); + m_model_parsers_list.push_back( newParser ); + } + } + } + else + { + // Reusing file + shape3D->m_parser = m_model_parsers_list[i]; + } } } } @@ -1432,12 +1564,10 @@ bool EDA_3D_CANVAS::Read3DComponentShape( MODULE* module, } -void EDA_3D_CANVAS::Render3DComponentShape( MODULE* module, +void EDA_3D_CANVAS::render3DComponentShape( MODULE* module, bool aIsRenderingJustNonTransparentObjects, - bool aIsRenderingJustTransparentObjects, - bool aSideToLoad ) + bool aIsRenderingJustTransparentObjects ) { - // Read from disk and draws the footprint 3D shapes if exists double zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() ); glPushMatrix(); @@ -1449,12 +1579,12 @@ void EDA_3D_CANVAS::Render3DComponentShape( MODULE* module, zpos ); if( module->GetOrientation() ) - glRotatef( (double) module->GetOrientation() / 10.0, 0.0, 0.0, 1.0 ); + glRotatef( (double) module->GetOrientation() / 10.0, 0.0f, 0.0f, 1.0f ); if( module->IsFlipped() ) { - glRotatef( 180.0, 0.0, 1.0, 0.0 ); - glRotatef( 180.0, 0.0, 0.0, 1.0 ); + glRotatef( 180.0f, 0.0f, 1.0f, 0.0f ); + glRotatef( 180.0f, 0.0f, 0.0f, 1.0f ); } S3D_MASTER* shape3D = module->Models(); @@ -1464,9 +1594,27 @@ void EDA_3D_CANVAS::Render3DComponentShape( MODULE* module, if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) { glPushMatrix(); + shape3D->Render( aIsRenderingJustNonTransparentObjects, aIsRenderingJustTransparentObjects ); + + if( isEnabled( FL_RENDER_SHOW_MODEL_BBOX ) ) + { + // Set the alpha current color to opaque + float currentColor[4]; + glGetFloatv( GL_CURRENT_COLOR,currentColor ); + currentColor[3] = 1.0f; + glColor4fv( currentColor ); + + CBBOX thisBBox = shape3D->getBBox(); + thisBBox.GLdebug(); + } + glPopMatrix(); + + // Debug AABBox + //thisBBox = shape3D->getfastAABBox(); + //thisBBox.GLdebug(); } } diff --git a/3d-viewer/3d_draw_basic_functions.cpp b/3d-viewer/3d_draw_basic_functions.cpp index 142cc00d17..1cfc738353 100644 --- a/3d-viewer/3d_draw_basic_functions.cpp +++ b/3d-viewer/3d_draw_basic_functions.cpp @@ -36,7 +36,7 @@ #include // 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, diff --git a/3d-viewer/3d_draw_helper_functions.cpp b/3d-viewer/3d_draw_helper_functions.cpp index 7c76995f50..4b83a55f37 100644 --- a/3d-viewer/3d_draw_helper_functions.cpp +++ b/3d-viewer/3d_draw_helper_functions.cpp @@ -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, diff --git a/3d-viewer/3d_frame.cpp b/3d-viewer/3d_frame.cpp index 8238590638..a9814e7470 100644 --- a/3d-viewer/3d_frame.cpp +++ b/3d-viewer/3d_frame.cpp @@ -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: diff --git a/3d-viewer/3d_material.cpp b/3d-viewer/3d_material.cpp index bff1b5c26e..e2c1b58d09 100644 --- a/3d-viewer/3d_material.cpp +++ b/3d-viewer/3d_material.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * 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 ); diff --git a/3d-viewer/3d_material.h b/3d-viewer/3d_material.h index 62b75bd21b..5ffedca7ae 100644 --- a/3d-viewer/3d_material.h +++ b/3d-viewer/3d_material.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * 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 ); diff --git a/3d-viewer/3d_mesh_model.cpp b/3d-viewer/3d_mesh_model.cpp index 985b2914d0..64a679bf6d 100644 --- a/3d-viewer/3d_mesh_model.cpp +++ b/3d-viewer/3d_mesh_model.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * 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 #include <3d_mesh_model.h> #include +#include + #include + +#ifdef __WXMAC__ +# ifdef __DARWIN__ +# include +# else +# include +# endif +#else +# include +#endif #ifdef USE_OPENMP #include #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() diff --git a/3d-viewer/3d_mesh_model.h b/3d-viewer/3d_mesh_model.h index d05f4849aa..0c139552c9 100644 --- a/3d-viewer/3d_mesh_model.h +++ b/3d-viewer/3d_mesh_model.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * 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 -#include -#include -#include -#include #include -#include -#include -#ifdef __WXMAC__ -# ifdef __DARWIN__ -# include -# else -# include -# endif -#else -# include -#endif -#include +#include +#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 > m_CoordIndex; std::vector< std::vector > 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 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 > m_InvalidCoordIndexes; //!TODO: check for invalid CoordIndex in file and remove the index and the same material index + std::vector< std::vector > 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 ); }; diff --git a/3d-viewer/3d_read_mesh.cpp b/3d-viewer/3d_read_mesh.cpp index d7ffbe116d..c3e651017b 100644 --- a/3d-viewer/3d_read_mesh.cpp +++ b/3d-viewer/3d_read_mesh.cpp @@ -1,6 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * + * Copyright (C) 2015 Mario Luzeiro * Copyright (C) 2015 Jean-Pierre Charras, jp.charras@wanadoo.fr * Copyright (C) 2011 Wayne Stambaugh * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors. @@ -32,14 +33,14 @@ #include #include #include - +#include #include <3d_viewer.h> #include #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 ); - } -} \ No newline at end of file +} + + +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 ); +} diff --git a/3d-viewer/3d_struct.h b/3d-viewer/3d_struct.h index f62d7b79b7..bd8a9345be 100644 --- a/3d-viewer/3d_struct.h +++ b/3d-viewer/3d_struct.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2011 Wayne Stambaugh * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors. @@ -34,54 +34,12 @@ #include #include #include <3d_material.h> -#include +#include <3d_types.h> +#include -/** - * @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 diff --git a/3d-viewer/3d_toolbar.cpp b/3d-viewer/3d_toolbar.cpp index 0c2b6edfd6..055148baeb 100644 --- a/3d-viewer/3d_toolbar.cpp +++ b/3d-viewer/3d_toolbar.cpp @@ -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 ) ); diff --git a/3d-viewer/3d_types.h b/3d-viewer/3d_types.h new file mode 100644 index 0000000000..693b7ad571 --- /dev/null +++ b/3d-viewer/3d_types.h @@ -0,0 +1,107 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Mario Luzeiro + * 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 +#include // 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 diff --git a/3d-viewer/3d_viewer_id.h b/3d-viewer/3d_viewer_id.h index da948141db..522675e601 100644 --- a/3d-viewer/3d_viewer_id.h +++ b/3d-viewer/3d_viewer_id.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, diff --git a/3d-viewer/CBBox.cpp b/3d-viewer/CBBox.cpp new file mode 100644 index 0000000000..23c1856a99 --- /dev/null +++ b/3d-viewer/CBBox.cpp @@ -0,0 +1,278 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Mario Luzeiro + * 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 +# else +# include +# endif +#else +# include +#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(); +} diff --git a/3d-viewer/CBBox.h b/3d-viewer/CBBox.h new file mode 100644 index 0000000000..bf14b18f76 --- /dev/null +++ b/3d-viewer/CBBox.h @@ -0,0 +1,182 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2015 Mario Luzeiro + * 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 +#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 diff --git a/3d-viewer/CImage.cpp b/3d-viewer/CImage.cpp index 2e0cd7de8f..0315d65e55 100644 --- a/3d-viewer/CImage.cpp +++ b/3d-viewer/CImage.cpp @@ -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 // Used for save an image to disk +#include // 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(); } - diff --git a/3d-viewer/CImage.h b/3d-viewer/CImage.h index 75f28cafa5..9e46cd2d49 100644 --- a/3d-viewer/CImage.h +++ b/3d-viewer/CImage.h @@ -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 +#include +/// 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 diff --git a/3d-viewer/CMakeLists.txt b/3d-viewer/CMakeLists.txt index 2259b61f46..0fae97ae2e 100644 --- a/3d-viewer/CMakeLists.txt +++ b/3d-viewer/CMakeLists.txt @@ -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}) diff --git a/3d-viewer/info3d_visu.cpp b/3d-viewer/info3d_visu.cpp index b74d6ce025..f140ced0c3 100644 --- a/3d-viewer/info3d_visu.cpp +++ b/3d-viewer/info3d_visu.cpp @@ -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 ); + } } diff --git a/3d-viewer/info3d_visu.h b/3d-viewer/info3d_visu.h index c36e52f07c..e5f4d1c7fc 100644 --- a/3d-viewer/info3d_visu.h +++ b/3d-viewer/info3d_visu.h @@ -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 }; diff --git a/3d-viewer/modelparsers.h b/3d-viewer/modelparsers.h index 7c2f3fee16..7fd8c8108f 100644 --- a/3d-viewer/modelparsers.h +++ b/3d-viewer/modelparsers.h @@ -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; }; diff --git a/3d-viewer/vrml_aux.cpp b/3d-viewer/vrml_aux.cpp index 7611c4d580..1b2bcefdf1 100644 --- a/3d-viewer/vrml_aux.cpp +++ b/3d-viewer/vrml_aux.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * 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& dst_vector ) +int ParseVertexList( FILE* File, std::vector& 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& 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 ); diff --git a/3d-viewer/vrml_aux.h b/3d-viewer/vrml_aux.h index 718ad72cc0..d0b2c0dd34 100644 --- a/3d-viewer/vrml_aux.h +++ b/3d-viewer/vrml_aux.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * 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 -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 diff --git a/3d-viewer/vrml_v1_modelparser.cpp b/3d-viewer/vrml_v1_modelparser.cpp index dc140c2211..52aca1ebfc 100644 --- a/3d-viewer/vrml_v1_modelparser.cpp +++ b/3d-viewer/vrml_v1_modelparser.cpp @@ -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; } diff --git a/3d-viewer/vrml_v2_modelparser.cpp b/3d-viewer/vrml_v2_modelparser.cpp index f84a702604..e74b4ea9b8 100644 --- a/3d-viewer/vrml_v2_modelparser.cpp +++ b/3d-viewer/vrml_v2_modelparser.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 Mario Luzeiro + * Copyright (C) 2014-2015 Mario Luzeiro * Copyright (C) 2013 Tuomas Vaherkoski * Copyright (C) 2012 Jean-Pierre Charras, jp.charras@wanadoo.fr * Copyright (C) 2011 Wayne Stambaugh @@ -39,7 +39,7 @@ #include "modelparsers.h" #include "vrml_aux.h" -#define BUFLINE_SIZE 32 +#define BUFLINE_SIZE 1024 /** * Trace mask used to enable or disable the trace output of the VRML V2 parser code. @@ -58,6 +58,7 @@ VRML2_MODEL_PARSER::VRML2_MODEL_PARSER( S3D_MODEL_PARSER* aModelParser ) m_file = NULL; m_normalPerVertex = true; colorPerVertex = true; + m_debugSpacer = ""; } @@ -65,25 +66,83 @@ VRML2_MODEL_PARSER::~VRML2_MODEL_PARSER() { } +void VRML2_MODEL_PARSER::debug_enter() +{ + m_debugSpacer.Append(' '); +} + +void VRML2_MODEL_PARSER::debug_exit() +{ + m_debugSpacer.RemoveLast(); +} bool VRML2_MODEL_PARSER::Load( const wxString& aFilename ) { - char text[BUFLINE_SIZE]; - - wxLogTrace( traceVrmlV2Parser, wxT( "Loading: %s" ), GetChars( aFilename ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Loading: %s" ), GetChars( aFilename ) ); + debug_enter(); m_file = wxFopen( aFilename, wxT( "rt" ) ); if( m_file == NULL ) { - wxLogTrace( traceVrmlV2Parser, wxT( "Failed to open file: %s" ), GetChars( aFilename ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Failed to open file: %s" ), GetChars( aFilename ) ); return false; } + m_Filename = aFilename; + // Switch the locale to standard C (needed to print floating point numbers) LOCALE_IO toggle; - m_ModelParser->childs.clear(); + loadFileModel( NULL ); + + fclose( m_file ); + + debug_exit(); + return true; +} + + +bool VRML2_MODEL_PARSER::Load( const wxString& aFilename, S3D_MESH *aTransformationModel ) +{ + if( aTransformationModel ) + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Loading: %s" ), GetChars( aFilename ) ); + debug_enter(); + + m_file = wxFopen( aFilename, wxT( "rt" ) ); + + if( m_file == NULL ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Failed to open file: %s" ), GetChars( aFilename ) ); + return false; + } + + m_Filename = aFilename; + + // Switch the locale to standard C (needed to print floating point numbers) + LOCALE_IO toggle; + + loadFileModel( aTransformationModel ); + + fclose( m_file ); + + debug_exit(); + return true; + } + + debug_exit(); + return false; +} + + +int VRML2_MODEL_PARSER::loadFileModel( S3D_MESH *aTransformationModel ) +{ + char text[BUFLINE_SIZE]; + + debug_enter(); while( GetNextTag( m_file, text, sizeof(text) ) ) { @@ -95,49 +154,125 @@ bool VRML2_MODEL_PARSER::Load( const wxString& aFilename ) if( strcmp( text, "Transform" ) == 0 ) { m_model = new S3D_MESH(); - m_ModelParser->childs.push_back( m_model ); - if( read_Transform() == 0) + S3D_MESH* save_ptr = m_model; + + if( read_Transform() == 0 ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); - //wxLogTrace( traceVrmlV2Parser, wxT( " m_CoordIndex.size: %u" ), (unsigned int)m_model->m_CoordIndex.size() ); + m_model = save_ptr; + + if( ((m_model->m_Point.size() == 0) || (m_model->m_CoordIndex.size() == 0)) && + (m_model->childs.size() == 0) ) + { + delete m_model; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "loadFileModel: skipping model with no points or childs" ) ); + } + else + { + if( aTransformationModel ) + { + m_model->m_translation = aTransformationModel->m_translation; + m_model->m_rotation = aTransformationModel->m_rotation; + m_model->m_scale = aTransformationModel->m_scale; + } + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "loadFileModel: Add model with %lu points, %lu coordIndex, %lu childs." ), + m_model->m_Point.size(), + m_model->m_CoordIndex.size(), + m_model->childs.size() ); + m_ModelParser->childs.push_back( m_model ); + } + } + else + { + delete m_model; } } else if( strcmp( text, "DEF" ) == 0 ) { m_model = new S3D_MESH(); - m_ModelParser->childs.push_back( m_model ); + + S3D_MESH* save_ptr = m_model; if( read_DEF() == 0 ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); - //wxLogTrace( traceVrmlV2Parser, wxT( " m_CoordIndex.size: %u" ), (unsigned int)m_model->m_CoordIndex.size() ); + m_model = save_ptr; + + if( ((m_model->m_Point.size() == 0) || (m_model->m_CoordIndex.size() == 0)) && + (m_model->childs.size() == 0) ) + { + delete m_model; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "loadFileModel: skipping model with no points or childs" ) ); + } + else + { + if( aTransformationModel ) + { + m_model->m_translation = aTransformationModel->m_translation; + m_model->m_rotation = aTransformationModel->m_rotation; + m_model->m_scale = aTransformationModel->m_scale; + } + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "loadFileModel: Add model with %lu points, %lu coordIndex, %lu childs." ), + m_model->m_Point.size(), + m_model->m_CoordIndex.size(), + m_model->childs.size() ); + m_ModelParser->childs.push_back( m_model ); + } + } + else + { + delete m_model; } } else if( strcmp( text, "Shape" ) == 0 ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " Shape" ) ); - m_model = new S3D_MESH(); - m_ModelParser->childs.push_back( m_model ); + + S3D_MESH* save_ptr = m_model; if( read_Shape() == 0 ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); - //wxLogTrace( traceVrmlV2Parser, wxT( " m_CoordIndex.size: %u" ), (unsigned int)m_model->m_CoordIndex.size() ); + m_model = save_ptr; + + if( ((m_model->m_Point.size() == 0) || (m_model->m_CoordIndex.size() == 0)) && + (m_model->childs.size() == 0) ) + { + delete m_model; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "loadFileModel: skipping model with no points or childs" ) ); + } + else + { + if( aTransformationModel ) + { + m_model->m_translation = aTransformationModel->m_translation; + m_model->m_rotation = aTransformationModel->m_rotation; + m_model->m_scale = aTransformationModel->m_scale; + } + + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "loadFileModel: Add model with %lu points, %lu coordIndex, %lu childs." ), + m_model->m_Point.size(), + m_model->m_CoordIndex.size(), + m_model->childs.size() ); + + m_ModelParser->childs.push_back( m_model ); + } + } + else + { + delete m_model; } } } - fclose( m_file ); - - return true; + debug_exit(); + return 0; } int VRML2_MODEL_PARSER::read_Transform() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_Transform" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform" ) ); + + debug_enter(); char text[BUFLINE_SIZE]; @@ -150,17 +285,50 @@ int VRML2_MODEL_PARSER::read_Transform() if( *text == '}' ) { - break; + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform exit" ) ); + return 0; } - if( strcmp( text, "translation" ) == 0 ) + if( strcmp( text, "Transform" ) == 0 ) { - parseVertex( m_file, m_model->m_translation ); + m_model = new S3D_MESH(); - //wxLogTrace( traceVrmlV2Parser, wxT( " translation (%f,%f,%f)" ), - // m_model->m_translation.x, - // m_model->m_translation.y, - // m_model->m_translation.z ); + S3D_MESH* save_ptr = m_model; + + if( read_Transform() == 0 ) + { + m_model = save_ptr; + + if( ((m_model->m_Point.size() == 0) || (m_model->m_CoordIndex.size() == 0)) && + (m_model->childs.size() == 0) ) + { + delete m_model; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: skipping model with no points or childs" ) ); + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: Add child model with %lu points, %lu coordIndex, %lu childs." ), + m_model->m_Point.size(), + m_model->m_CoordIndex.size(), + m_model->childs.size() ); + + m_ModelParser->childs.push_back( m_model ); + } + } + else + { + delete m_model; + } + } + else if( strcmp( text, "translation" ) == 0 ) + { + ParseVertex( m_file, m_model->m_translation ); + + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "translation (%f,%f,%f)" ), + m_model->m_translation.x, + m_model->m_translation.y, + m_model->m_translation.z ); } else if( strcmp( text, "rotation" ) == 0 ) { @@ -174,39 +342,41 @@ int VRML2_MODEL_PARSER::read_Transform() m_model->m_rotation[2] = 0.0f; m_model->m_rotation[3] = 0.0f; - wxLogTrace( traceVrmlV2Parser, wxT( " rotation failed, setting to zeros" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "rotation failed, setting to zeros" ) ); } else { m_model->m_rotation[3] = m_model->m_rotation[3] * 180.0f / 3.14f; // !TODO: use constants or functions } - //wxLogTrace( traceVrmlV2Parser, wxT( " rotation (%f,%f,%f,%f)" ), - // m_model->m_rotation[0], - // m_model->m_rotation[1], - // m_model->m_rotation[2], - // m_model->m_rotation[3] ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "rotation (%f,%f,%f,%f)" ), + m_model->m_rotation[0], + m_model->m_rotation[1], + m_model->m_rotation[2], + m_model->m_rotation[3] ); } else if( strcmp( text, "scale" ) == 0 ) { - parseVertex( m_file, m_model->m_scale ); + ParseVertex( m_file, m_model->m_scale ); - //wxLogTrace( traceVrmlV2Parser, wxT( " scale (%f,%f,%f)" ), m_model->m_scale.x, m_model->m_scale.y, m_model->m_scale.z ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "scale (%f,%f,%f)" ), m_model->m_scale.x, m_model->m_scale.y, m_model->m_scale.z ); } else if( strcmp( text, "scaleOrientation" ) == 0 ) { - // this m_scaleOrientation is not implemented, but it will be parsed - if( fscanf( m_file, "%f %f %f %f", &m_model->m_scaleOrientation[0], - &m_model->m_scaleOrientation[1], - &m_model->m_scaleOrientation[2], - &m_model->m_scaleOrientation[3] ) != 4 ) - { - m_model->m_scaleOrientation[0] = 0.0f; - m_model->m_scaleOrientation[1] = 0.0f; - m_model->m_scaleOrientation[2] = 0.0f; - m_model->m_scaleOrientation[3] = 0.0f; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "scaleOrientation is not implemented, but it will be parsed" ) ); - wxLogTrace( traceVrmlV2Parser, wxT( " scaleOrientation failed, setting to zeros" ) ); + glm::vec4 vecDummy; + if( fscanf( m_file, "%f %f %f %f", &vecDummy[0], + &vecDummy[1], + &vecDummy[2], + &vecDummy[3] ) != 4 ) + { + vecDummy[0] = 0.0f; + vecDummy[1] = 0.0f; + vecDummy[2] = 0.0f; + vecDummy[3] = 0.0f; + + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "scaleOrientation failed, setting to zeros" ) ); } //wxLogTrace( traceVrmlV2Parser, wxT( " scaleOrientation (%f,%f,%f,%f)" ), @@ -217,9 +387,11 @@ int VRML2_MODEL_PARSER::read_Transform() } else if( strcmp( text, "center" ) == 0 ) { - parseVertex( m_file, m_model->m_center ); + // this is not used + glm::vec3 vecDummy; + ParseVertex( m_file, vecDummy ); - //wxLogTrace( traceVrmlV2Parser, wxT( " center (%f,%f,%f)" ), m_model->m_center.x, m_model->m_center.y, m_model->m_center.z ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "center is not implemented (%f,%f,%f)" ), vecDummy.x, vecDummy.y, vecDummy.z ); } else if( strcmp( text, "children" ) == 0 ) { @@ -244,21 +416,52 @@ int VRML2_MODEL_PARSER::read_Transform() } else if( strcmp( text, "Group" ) == 0 ) { - // skip + // Keep looking for things in a transform + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Group" ) ); + read_Transform(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Transform Group exit" ) ); + //return ret; + } + else if( strcmp( text, "Inline" ) == 0 ) + { + read_Inline(); } else if( strcmp( text, "Shape" ) == 0 ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " Shape" ) ); - + // Save the pointer S3D_MESH* parent = m_model; S3D_MESH* new_mesh_model = new S3D_MESH(); - m_model->childs.push_back( new_mesh_model ); - + // Assign the current pointer m_model = new_mesh_model; - read_Shape(); + S3D_MESH* save_ptr = m_model; + + if( read_Shape() == 0 ) + { + m_model = save_ptr; + + if( ((m_model->m_Point.size() == 0) || (m_model->m_CoordIndex.size() == 0)) && + (m_model->childs.size() == 0) ) + { + delete m_model; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: Shape, skipping model with no points or childs" ) ); + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: Shape, Add child model with %lu points, %lu coordIndex, %lu childs." ), + m_model->m_Point.size(), + m_model->m_CoordIndex.size(), + m_model->childs.size() ); + + parent->childs.push_back( m_model ); + } + } + else + { + delete m_model; + } m_model = parent; } @@ -266,26 +469,175 @@ int VRML2_MODEL_PARSER::read_Transform() { read_DEF(); } + else if( strcmp( text, "USE" ) == 0 ) + { + char useLabel[BUFLINE_SIZE]; + + if( GetNextTag( m_file, useLabel, sizeof(useLabel) ) ) + { + // Check if a ',' is at the end and remove it + if( useLabel[strlen(useLabel) - 1] == ',' ) + { + useLabel[strlen(useLabel) - 1] = 0; + } + + std::string strUseLabel = useLabel; + + // Look for it in our group map. + VRML2_DEF_GROUP_MAP::iterator groupIt; + + groupIt = m_defGroupMap.find( strUseLabel ); + + // Checf if not previously defined. + if( groupIt == m_defGroupMap.end() ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "USE: group %s not previously defined " + "in a DEF section." ), strUseLabel ); + return -1; + } + + S3D_MESH* ptrModel = groupIt->second; + + if( ((ptrModel->m_Point.size() == 0) || (ptrModel->m_CoordIndex.size() == 0)) && + (ptrModel->childs.size() == 0) ) + { + // !TODO: delete in the end + //delete ptrModel; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: USE %s, skipping model with no points or childs" ), useLabel ); + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: USE %s Add child model with %lu points, %lu coordIndex, %lu childs." ), + useLabel, + ptrModel->m_Point.size(), + ptrModel->m_CoordIndex.size(), + ptrModel->childs.size() ); + + m_model->childs.push_back( ptrModel ); + } + } + else + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: USE Failed to get the label name" ) ); + return -1; + } + } else { - wxLogTrace( traceVrmlV2Parser, wxT( " %s NotImplemented" ), text ); - read_NotImplemented( m_file, '}' ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform: %s NotImplemented" ), text ); + Read_NotImplemented( m_file, '}' ); } } - return 0; + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Transform failed" ) ); + return -1; +} + + +int VRML2_MODEL_PARSER::read_Inline() +{ + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Inline" ) ); + debug_enter(); + + char text[BUFLINE_SIZE]; + + while( GetNextTag( m_file, text, sizeof(text) ) ) + { + if( *text == ']' ) + continue; + + if( *text == '}' ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Inline exit" ) ); + return 0; + } + + if( strcmp( text, "url" ) == 0 ) + { + if( GetString( m_file, text, sizeof(text) ) ) + { + wxString filename; + filename = filename.FromUTF8( text ); + + #ifdef __WINDOWS__ + filename.Replace( wxT( "/" ), wxT( "\\" ) ); + #else + filename.Replace( wxT( "\\" ), wxT( "/" ) ); + #endif + + bool fileExists = false; + + if( wxFileName::FileExists( filename ) ) + { + fileExists = true; + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "URL Failed to open file as a full path: \"%s\", will try now a relative path..." ), filename ); + + #ifdef __WINDOWS__ + filename = m_Filename.GetPath() + '\\' + filename; + #else + filename = m_Filename.GetPath() + '/' + filename; + #endif + + + if( wxFileName::FileExists( filename ) ) + { + fileExists = true; + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "URL Failed to open file: \"%s\"" ), filename ); + } + } + + if( fileExists ) + { + // Will now create a new parser and set the default + // transfomation model to apply on the root + VRML2_MODEL_PARSER *newParser = new VRML2_MODEL_PARSER( this->m_ModelParser ); + newParser->Load( filename, m_model ); + delete newParser; + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "URL Failed to open file: %s" ), text ); + } + } + else + { + // If fail get url text, exit with failure + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "URL failed read url string" ) ); + break; + } + } + } + + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Inline failed" ) ); + return -1; } int VRML2_MODEL_PARSER::read_DEF_Coordinate() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_DEF_Coordinate" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF_Coordinate" ) ); + debug_enter(); char text[BUFLINE_SIZE]; // Get the name of the definition. if( !GetNextTag( m_file, text, sizeof(text) ) ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF_Coordinate failed to get next tag" ) ); return -1; + } std::string coordinateName = text; @@ -295,7 +647,11 @@ int VRML2_MODEL_PARSER::read_DEF_Coordinate() continue; if( *text == '}' ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF_Coordinate exit" ) ); return 0; + } if( strcmp( text, "Coordinate" ) == 0 ) { @@ -304,25 +660,29 @@ int VRML2_MODEL_PARSER::read_DEF_Coordinate() if( retVal == 0 ) m_defCoordinateMap.insert( std::make_pair( coordinateName, m_model->m_Point ) ); + debug_exit(); return retVal; } } - wxLogTrace( traceVrmlV2Parser, wxT( " read_DEF_Coordinate failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF_Coordinate failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_DEF() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_DEF" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF" ) ); + debug_enter(); char text[BUFLINE_SIZE]; char tagName[BUFLINE_SIZE]; if( !GetNextTag( m_file, tagName, sizeof(tagName) ) ) { - wxLogTrace( traceVrmlV2Parser, wxT( " DEF failed GetNextTag first" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "DEF failed GetNextTag first" ) ); return -1; } @@ -330,18 +690,23 @@ int VRML2_MODEL_PARSER::read_DEF() { if( *text == ']' ) { - wxLogTrace( traceVrmlV2Parser, wxT( " skipping %c" ), *text ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "skipping %c" ), *text ); continue; } if( *text == '}' ) { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF exit" ) ); return 0; } if( strcmp( text, "Transform" ) == 0 ) { - return read_Transform(); + int ret = read_Transform(); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF exit after Transform, please check and validate" ) ); + return ret; } else if( strcmp( text, "children" ) == 0 ) { @@ -361,37 +726,113 @@ int VRML2_MODEL_PARSER::read_DEF() } else if( strcmp( text, "Shape" ) == 0 ) { - S3D_MESH* parent = m_model; - S3D_MESH* new_mesh_model = new S3D_MESH(); - m_model->childs.push_back( new_mesh_model ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Shape" ) ); + // Save the pointer + S3D_MESH* parent = m_model; + + S3D_MESH* new_mesh_model = new S3D_MESH(); + + // Assign the current pointer m_model = new_mesh_model; - read_Shape(); + + S3D_MESH* save_ptr = m_model; + + if( read_Shape() == 0 ) + { + m_model = save_ptr; + + if( ((m_model->m_Point.size() == 0) || (m_model->m_CoordIndex.size() == 0)) && + (m_model->childs.size() == 0) ) + { + delete m_model; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF: Shape, skipping model with no points or childs" ) ); + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF: Shape, Add child model with %lu points, %lu coordIndex, %lu childs." ), + m_model->m_Point.size(), + m_model->m_CoordIndex.size(), + m_model->childs.size() ); + + parent->childs.push_back( m_model ); + } + } + else + { + delete m_model; + } + m_model = parent; } + else if( strcmp( text, "IndexedFaceSet" ) == 0 ) + { + read_IndexedFaceSet(); + } + else if( strcmp( text, "Group" ) == 0 ) + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Group %s" ), tagName ); + + // Save the pointer + S3D_MESH* parent = m_model; + + S3D_MESH* new_mesh_model = new S3D_MESH(); + + // Assign the current pointer + m_model = new_mesh_model; + + // It will be the same as read a new Transform + if( read_Transform() == 0 ) + { + std::string groupName = tagName; + //m_defGroupMap.insert( std::make_pair( groupName, new_mesh_model ) ); + m_defGroupMap[groupName] = new_mesh_model; + + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Group %s: inserted model with %lu points, %lu coordIndex, %lu childs." ), + tagName, + new_mesh_model->m_Point.size(), + new_mesh_model->m_CoordIndex.size(), + new_mesh_model->childs.size() ); + } + else + { + delete m_model; + } + + // Restore current model pointer + m_model = parent; + + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_DEF %s Group exit" ), tagName ); + return 0; + } else { - wxLogTrace( traceVrmlV2Parser, wxT( " DEF %s %s NotImplemented, skipping." ), tagName, text ); - read_NotImplemented( m_file, '}' ); - - return -1; + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "DEF %s %s NotImplemented, skipping." ), tagName, text ); + Read_NotImplemented( m_file, '}' ); } } - wxLogTrace( traceVrmlV2Parser, wxT( " DEF failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "DEF failed" ) ); return -1; } -int VRML2_MODEL_PARSER::read_USE() +int VRML2_MODEL_PARSER::read_IndexedFaceSet_USE() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_USE" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedFaceSet_USE" ) ); + debug_enter(); char text[BUFLINE_SIZE]; // Get the name of the definition. if( !GetNextTag( m_file, text, sizeof(text) ) ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedFaceSet_USE failed to get next tag" ) ); return -1; + } std::string coordinateName = text; @@ -402,19 +843,22 @@ int VRML2_MODEL_PARSER::read_USE() // Not previously defined. if( coordinate == m_defCoordinateMap.end() ) { - wxLogTrace( traceVrmlV2Parser, wxT( "USE: coordinate %s not previously defined " + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "USE: coordinate %s not previously defined " "in a DEF section." ), text ); return -1; } m_model->m_Point = coordinate->second; + debug_exit(); return 0; } int VRML2_MODEL_PARSER::read_Shape() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_Shape" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Shape" ) ); + debug_enter(); char text[BUFLINE_SIZE]; @@ -427,6 +871,8 @@ int VRML2_MODEL_PARSER::read_Shape() if( *text == '}' ) { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Shape exit" ) ); return 0; } @@ -441,8 +887,7 @@ int VRML2_MODEL_PARSER::read_Shape() } else if( strcmp( text, "geometry" ) == 0 ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " \"geometry\" key word not supported." ) ); - // skip + read_geometry(); } else if( strcmp( text, "IndexedFaceSet" ) == 0 ) { @@ -454,19 +899,76 @@ int VRML2_MODEL_PARSER::read_Shape() } else { - wxLogTrace( traceVrmlV2Parser, wxT( " %s NotImplemented" ), text ); - read_NotImplemented( m_file, '}' ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "%s NotImplemented" ), text ); + Read_NotImplemented( m_file, '}' ); } } - wxLogTrace( traceVrmlV2Parser, wxT( " Shape failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Shape failed" ) ); + return -1; +} + + +int VRML2_MODEL_PARSER::read_geometry() +{ + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_geometry" ) ); + debug_enter(); + + char text[BUFLINE_SIZE]; + char tagName[BUFLINE_SIZE]; + tagName[0] = 0; + + while( GetNextTag( m_file, text, sizeof(text) ) ) + { + if( *text == ']' ) + { + continue; + } + + if( *text == '}' ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_geometry exit" ) ); + return 0; + } + + if( strcmp( text, "DEF" ) == 0 ) + { + if( !GetNextTag( m_file, tagName, sizeof(tagName) ) ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "DEF failed GetNextTag first" ) ); + return -1; + } + } + else if( strcmp( text, "IndexedFaceSet" ) == 0 ) + { + int ret = read_IndexedFaceSet(); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_geometry exit, after IndexedFaceSet" ) ); + return ret; + } + else + { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_geometry: %s NotImplemented" ), text ); + int ret = Read_NotImplemented( m_file, '}' ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_geometry exit, after %s" ), text); + return ret; + } + } + + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_geometry failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_Appearance() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_Appearance" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Appearance" ) ); + debug_enter(); char text[BUFLINE_SIZE]; @@ -479,6 +981,8 @@ int VRML2_MODEL_PARSER::read_Appearance() if( *text == '}' ) { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Appearance exit" ) ); return 0; } @@ -488,14 +992,16 @@ int VRML2_MODEL_PARSER::read_Appearance() } } - wxLogTrace( traceVrmlV2Parser, wxT( " Appearance failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Appearance failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_material() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_material" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_material" ) ); + debug_enter(); S3D_MATERIAL* material = NULL; char text[BUFLINE_SIZE]; @@ -511,7 +1017,9 @@ int VRML2_MODEL_PARSER::read_material() if( strcmp( text, "Material" ) == 0 ) { - return read_Material(); + int ret = read_Material(); + debug_exit(); + return ret; } } else if( strcmp( text, "DEF" ) == 0 ) @@ -529,7 +1037,9 @@ int VRML2_MODEL_PARSER::read_material() { if( strcmp( text, "Material" ) == 0 ) { - return read_Material(); + int ret = read_Material(); + debug_exit(); + return ret; } } } @@ -546,23 +1056,26 @@ int VRML2_MODEL_PARSER::read_material() if( material->m_Name == mat_name ) { m_model->m_Materials = material; + debug_exit(); return 0; } } - wxLogTrace( traceVrmlV2Parser, wxT( " read_material error: material not found" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_material error: material not found" ) ); } } } - wxLogTrace( traceVrmlV2Parser, wxT( " failed material" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "failed material" ) ); return -1; } int VRML2_MODEL_PARSER::read_Material() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_Material" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Material" ) ); + debug_enter(); char text[BUFLINE_SIZE]; glm::vec3 vertex; @@ -576,17 +1089,19 @@ int VRML2_MODEL_PARSER::read_Material() if( *text == '}' ) { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Material exit" ) ); return 0; } if( strcmp( text, "diffuseColor" ) == 0 ) { - parseVertex( m_file, vertex ); + ParseVertex( m_file, vertex ); m_model->m_Materials->m_DiffuseColor.push_back( vertex ); } else if( strcmp( text, "emissiveColor" ) == 0 ) { - parseVertex( m_file, vertex ); + ParseVertex( m_file, vertex ); if( m_Master->m_use_modelfile_emissiveColor == true ) { @@ -595,7 +1110,7 @@ int VRML2_MODEL_PARSER::read_Material() } else if( strcmp( text, "specularColor" ) == 0 ) { - parseVertex( m_file, vertex ); + ParseVertex( m_file, vertex ); if( m_Master->m_use_modelfile_specularColor == true ) { @@ -605,7 +1120,7 @@ int VRML2_MODEL_PARSER::read_Material() else if( strcmp( text, "ambientIntensity" ) == 0 ) { float ambientIntensity; - parseFloat( m_file, &ambientIntensity ); + ParseFloat( m_file, &ambientIntensity ); if( m_Master->m_use_modelfile_ambientIntensity == true ) { @@ -616,7 +1131,7 @@ int VRML2_MODEL_PARSER::read_Material() else if( strcmp( text, "transparency" ) == 0 ) { float transparency; - parseFloat( m_file, &transparency ); + ParseFloat( m_file, &transparency ); if( m_Master->m_use_modelfile_transparency == true ) { @@ -626,7 +1141,7 @@ int VRML2_MODEL_PARSER::read_Material() else if( strcmp( text, "shininess" ) == 0 ) { float shininess; - parseFloat( m_file, &shininess ); + ParseFloat( m_file, &shininess ); // VRML value is normalized and openGL expects a value 0 - 128 if( m_Master->m_use_modelfile_shininess == true ) @@ -637,14 +1152,16 @@ int VRML2_MODEL_PARSER::read_Material() } } - wxLogTrace( traceVrmlV2Parser, wxT( " Material failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "Material failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_IndexedFaceSet() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_IndexedFaceSet" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedFaceSet" ) ); + debug_enter(); char text[BUFLINE_SIZE]; @@ -660,6 +1177,8 @@ int VRML2_MODEL_PARSER::read_IndexedFaceSet() if( *text == '}' ) { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedFaceSet exit" ) ); return 0; } @@ -712,18 +1231,20 @@ int VRML2_MODEL_PARSER::read_IndexedFaceSet() } else if( strcmp( text, "USE" ) == 0 ) { - read_USE(); + read_IndexedFaceSet_USE(); } } - wxLogTrace( traceVrmlV2Parser, wxT( " IndexedFaceSet failed %s" ), text ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "IndexedFaceSet failed %s" ), text ); return -1; } int VRML2_MODEL_PARSER::read_IndexedLineSet() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_IndexedLineSet" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedLineSet" ) ); + debug_enter(); char text[BUFLINE_SIZE]; @@ -733,7 +1254,11 @@ int VRML2_MODEL_PARSER::read_IndexedLineSet() continue; if( *text == '}' ) + { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedLineSet exit" ) ); return 0; + } if( strcmp( text, "Coordinate" ) == 0 ) read_Coordinate(); @@ -743,13 +1268,16 @@ int VRML2_MODEL_PARSER::read_IndexedLineSet() read_DEF_Coordinate(); } + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_IndexedLineSet failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_colorIndex() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_colorIndex" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_colorIndex" ) ); + debug_enter(); m_model->m_MaterialIndex.clear(); @@ -781,15 +1309,16 @@ int VRML2_MODEL_PARSER::read_colorIndex() } } - //wxLogTrace( traceVrmlV2Parser, wxT( " read_colorIndex m_MaterialIndex.size: %u" ), (unsigned int)m_model->m_MaterialIndex.size() ); - + //wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_colorIndex m_MaterialIndex.size: %u" ), (unsigned int)m_model->m_MaterialIndex.size() ); + debug_exit(); return 0; } int VRML2_MODEL_PARSER::read_NormalIndex() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_NormalIndex" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_NormalIndex" ) ); + debug_enter(); m_model->m_NormalIndex.clear(); @@ -813,15 +1342,16 @@ int VRML2_MODEL_PARSER::read_NormalIndex() } } - //wxLogTrace( traceVrmlV2Parser, wxT( " read_NormalIndex m_NormalIndex.size: %u" ), (unsigned int)m_model->m_NormalIndex.size() ); - + //wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_NormalIndex m_NormalIndex.size: %u" ), (unsigned int)m_model->m_NormalIndex.size() ); + debug_exit(); return 0; } int VRML2_MODEL_PARSER::read_coordIndex() { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_coordIndex" ) ); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_coordIndex" ) ); + debug_enter(); m_model->m_CoordIndex.clear(); @@ -845,14 +1375,17 @@ int VRML2_MODEL_PARSER::read_coordIndex() } } - //wxLogTrace( traceVrmlV2Parser, wxT( " read_coordIndex m_CoordIndex.size: %u" ), (unsigned int)m_model->m_CoordIndex.size() ); - + //wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_coordIndex m_CoordIndex.size: %u" ), (unsigned int)m_model->m_CoordIndex.size() ); + debug_exit(); return 0; } int VRML2_MODEL_PARSER::read_Color() { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Color" ) ); + debug_enter(); + char text[BUFLINE_SIZE]; while( GetNextTag( m_file, text, sizeof(text) ) ) @@ -864,22 +1397,28 @@ int VRML2_MODEL_PARSER::read_Color() if( *text == '}' ) { + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Color exit" ) ); return 0; } if( strcmp( text, "color" ) == 0 ) { - parseVertexList( m_file, m_model->m_Materials->m_DiffuseColor ); + ParseVertexList( m_file, m_model->m_Materials->m_DiffuseColor ); } } - //wxLogTrace( traceVrmlV2Parser, wxT( " read_Color failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Color failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_Normal() { + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Normal" ) ); + debug_enter(); + char text[BUFLINE_SIZE]; while( GetNextTag( m_file, text, sizeof(text) ) ) @@ -891,11 +1430,14 @@ int VRML2_MODEL_PARSER::read_Normal() if( *text == '}' ) { + // Debug //if( m_normalPerVertex == false ) - // wxLogTrace( traceVrmlV2Parser, wxT( " read_Normal m_PerFaceNormalsNormalized.size: %u" ), (unsigned int)m_model->m_PerFaceNormalsNormalized.size() ); + // wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Normal m_PerFaceNormalsNormalized.size: %u" ), (unsigned int)m_model->m_PerFaceNormalsNormalized.size() ); //else - // wxLogTrace( traceVrmlV2Parser, wxT( " read_Normal m_PerVertexNormalsNormalized.size: %u" ), (unsigned int)m_model->m_PerVertexNormalsNormalized.size() ); + // wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Normal m_PerVertexNormalsNormalized.size: %u" ), (unsigned int)m_model->m_PerVertexNormalsNormalized.size() ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Normal exit" ) ); return 0; } @@ -903,22 +1445,25 @@ int VRML2_MODEL_PARSER::read_Normal() { if( m_normalPerVertex == false ) { - parseVertexList( m_file, m_model->m_PerFaceNormalsNormalized ); + ParseVertexList( m_file, m_model->m_PerFaceNormalsNormalized ); } else { - parseVertexList( m_file, m_model->m_PerVertexNormalsNormalized ); + ParseVertexList( m_file, m_model->m_PerVertexNormalsNormalized ); } } } - wxLogTrace( traceVrmlV2Parser, wxT( " read_Normal failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Normal failed" ) ); return -1; } int VRML2_MODEL_PARSER::read_Coordinate() { + debug_enter(); + char text[BUFLINE_SIZE]; while( GetNextTag( m_file, text, sizeof(text) ) ) @@ -930,17 +1475,20 @@ int VRML2_MODEL_PARSER::read_Coordinate() if( *text == '}' ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_Coordinate m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Coordinate exit" ) ); + //wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Coordinate m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); return 0; } if( strcmp( text, "point" ) == 0 ) { - parseVertexList( m_file, m_model->m_Point ); + ParseVertexList( m_file, m_model->m_Point ); } } - wxLogTrace( traceVrmlV2Parser, wxT( " read_Coordinate failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_Coordinate failed" ) ); return -1; } @@ -950,6 +1498,8 @@ int VRML2_MODEL_PARSER::read_Coordinate() */ int VRML2_MODEL_PARSER::read_CoordinateDef() { + debug_enter(); + char text[BUFLINE_SIZE]; while( GetNextTag( m_file, text, sizeof(text) ) ) @@ -959,14 +1509,17 @@ int VRML2_MODEL_PARSER::read_CoordinateDef() if( *text == '}' ) { - //wxLogTrace( traceVrmlV2Parser, wxT( " read_CoordinateDef m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_CoordinateDef exit" ) ); + //wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_CoordinateDef m_Point.size: %u" ), (unsigned int)m_model->m_Point.size() ); return 0; } if( strcmp( text, "point" ) == 0 ) - parseVertexList( m_file, m_model->m_Point ); + ParseVertexList( m_file, m_model->m_Point ); } - wxLogTrace( traceVrmlV2Parser, wxT( " read_CoordinateDef failed" ) ); + debug_exit(); + wxLogTrace( traceVrmlV2Parser, m_debugSpacer + wxT( "read_CoordinateDef failed" ) ); return -1; } diff --git a/3d-viewer/vrmlmodelparser.cpp b/3d-viewer/vrmlmodelparser.cpp index 436fe0775c..f9aeac5bdf 100644 --- a/3d-viewer/vrmlmodelparser.cpp +++ b/3d-viewer/vrmlmodelparser.cpp @@ -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; } diff --git a/3d-viewer/x3dmodelparser.cpp b/3d-viewer/x3dmodelparser.cpp index 5efef44217..780d228f35 100644 --- a/3d-viewer/x3dmodelparser.cpp +++ b/3d-viewer/x3dmodelparser.cpp @@ -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; + } + } }