From d5b635027e5d3a5e33c38f36e4a88720ee411ea1 Mon Sep 17 00:00:00 2001 From: Mario Luzeiro Date: Thu, 2 Mar 2023 22:29:08 +0000 Subject: [PATCH] 3D-Viewer: sort models and material models when rendering in transparent Also enables transparency on model preview and small optimizations fixes Fixes https://gitlab.com/kicad/code/kicad/-/issues/14005 (cherry picked from commit 7bc976f3f4293fbdf18d8d0579c6996b0e20c766) --- .../3d_model_viewer/eda_3d_model_viewer.cpp | 8 + 3d-viewer/3d_rendering/opengl/3d_model.cpp | 113 ++++++- 3d-viewer/3d_rendering/opengl/3d_model.h | 19 +- .../3d_rendering/opengl/render_3d_opengl.cpp | 304 ++++++++++++++---- .../3d_rendering/opengl/render_3d_opengl.h | 48 ++- .../raytracing/shapes2D/bbox_2d.cpp | 10 + .../raytracing/shapes2D/bbox_2d.h | 8 + .../raytracing/shapes3D/bbox_3d.cpp | 10 + .../raytracing/shapes3D/bbox_3d.h | 8 + 9 files changed, 431 insertions(+), 97 deletions(-) diff --git a/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp b/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp index 29fa52ae2d..4e3d375d52 100644 --- a/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp +++ b/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp @@ -330,8 +330,16 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event ) m_ogl_3dmodel->BeginDrawMulti( true ); m_ogl_3dmodel->DrawOpaque( false ); + + glDepthMask( GL_FALSE ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + m_ogl_3dmodel->DrawTransparent( 1.0f, false ); + glDisable( GL_BLEND ); + glDepthMask( GL_TRUE ); + m_ogl_3dmodel->EndDrawMulti(); glPopMatrix(); diff --git a/3d-viewer/3d_rendering/opengl/3d_model.cpp b/3d-viewer/3d_rendering/opengl/3d_model.cpp index e84b3e2b70..8cad4339d1 100644 --- a/3d-viewer/3d_rendering/opengl/3d_model.cpp +++ b/3d-viewer/3d_rendering/opengl/3d_model.cpp @@ -27,13 +27,14 @@ * @file c_ogl_3dmodel.cpp * @brief */ +#include #include #include // Must be included first #include "3d_model.h" -#include "opengl_utils.h" #include "../common_ogl/ogl_utils.h" #include "../3d_math.h" +#include #include #include #include @@ -177,9 +178,11 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode ) // use material color for mesh bounding box or some sort of average vertex color. glm::vec3 avg_color = material.m_Diffuse; + BBOX_3D &mesh_bbox = m_meshes_bbox[mesh_i]; + for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i ) { - m_meshes_bbox[mesh_i].Union( mesh.m_Positions[vtx_i] ); + mesh_bbox.Union( mesh.m_Positions[vtx_i] ); VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i]; @@ -222,16 +225,19 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode ) } } - if( m_meshes_bbox[mesh_i].IsInitialized() ) + if( mesh_bbox.IsInitialized() ) { // generate geometry for the bounding box - MakeBbox( m_meshes_bbox[mesh_i], ( mesh_i + 1 ) * bbox_vtx_count, + MakeBbox( mesh_bbox, ( mesh_i + 1 ) * bbox_vtx_count, &bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count], &bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count], { avg_color, 1.0f } ); // bump the outer bounding box - m_model_bbox.Union( m_meshes_bbox[mesh_i] ); + m_model_bbox.Union( mesh_bbox ); + + // add to the material group + material.m_bbox.Union( mesh_bbox ); } @@ -410,7 +416,9 @@ void MODEL_3D::EndDrawMulti() void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial, - SFVEC3F& aSelectionColor ) const + const SFVEC3F& aSelectionColor, + const glm::mat4 *aModelWorldMatrix, + const SFVEC3F *aCameraWorldPos ) const { if( aOpacity <= FLT_EPSILON ) return; @@ -439,27 +447,102 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)¶m.x ); - for( const MODEL_3D::MATERIAL& mat : m_materials ) + std::vector materialsToRender; + + materialsToRender.reserve( m_materials.size() ); + + if( aModelWorldMatrix && aCameraWorldPos ) { - if( ( mat.IsTransparent() != aTransparent ) + // Sort Material groups + + std::vector> materialsSorted; + + // Calculate the distance to the camera for each material group + for( const MODEL_3D::MATERIAL& mat : m_materials ) + { + if( mat.m_render_idx_count == 0 ) + { + continue; + } + + if( ( mat.IsTransparent() != aTransparent ) && ( aOpacity >= 1.0f ) && m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY ) - { - continue; + { + continue; + } + + const BBOX_3D& bBox = mat.m_bbox; + const SFVEC3F& bBoxCenter = bBox.GetCenter(); + const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f ); + + const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld ); + + materialsSorted.emplace_back( &mat, distanceToCamera ); } + // Sort from back to front + std::sort( materialsSorted.begin(), materialsSorted.end(), + [&]( std::pair& a, + std::pair& b ) { + // If A is inside B, then A is rendered first + if( b.first->m_bbox.Inside( a.first->m_bbox ) ) + { + return true; + } + else + { + if( a.first->m_bbox.Inside( b.first->m_bbox ) ) + { + return false; + } + } + + return a.second > b.second; + } ); + + for( const std::pair& mat : materialsSorted ) + { + materialsToRender.push_back( mat.first ); + } + } + else + { + for( const MODEL_3D::MATERIAL& mat : m_materials ) + { + // There is at least one default material created in case a mesh has no declared materials. + // Most meshes have a material, so usually the first material will have nothing to render and is skip. + // See S3D::GetModel for more details. + if( mat.m_render_idx_count == 0 ) + { + continue; + } + + if( ( mat.IsTransparent() != aTransparent ) + && ( aOpacity >= 1.0f ) + && m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY ) + { + continue; + } + + materialsToRender.push_back( &mat ); + } + } + + for( const MODEL_3D::MATERIAL* mat : materialsToRender ) + { switch( m_materialMode ) { case MATERIAL_MODE::NORMAL: - OglSetMaterial( mat, aOpacity, aUseSelectedMaterial, aSelectionColor ); + OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor ); break; case MATERIAL_MODE::DIFFUSE_ONLY: - OglSetDiffuseMaterial( mat.m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor ); + OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor ); break; case MATERIAL_MODE::CAD_MODE: - OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat.m_Diffuse ), aOpacity, + OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity, aUseSelectedMaterial, aSelectionColor ); break; @@ -467,9 +550,9 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria break; } - glDrawElements( GL_TRIANGLES, mat.m_render_idx_count, m_index_buffer_type, + glDrawElements( GL_TRIANGLES, mat->m_render_idx_count, m_index_buffer_type, reinterpret_cast( - static_cast( mat.m_render_idx_buffer_offset ) ) ); + static_cast( mat->m_render_idx_buffer_offset ) ) ); } } diff --git a/3d-viewer/3d_rendering/opengl/3d_model.h b/3d-viewer/3d_rendering/opengl/3d_model.h index baf93483d9..1663e35ab5 100644 --- a/3d-viewer/3d_rendering/opengl/3d_model.h +++ b/3d-viewer/3d_rendering/opengl/3d_model.h @@ -54,7 +54,7 @@ public: */ void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const { - Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor ); + Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr ); } /** @@ -63,9 +63,19 @@ public: void DrawTransparent( float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const { - Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor ); + Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr ); } + /** + * Render the model into the current context. + * if aModelWorldMatrix and aCameraWorldPos is provided, + * it renders the material groups sorted. + */ + void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial, + const SFVEC3F& aSelectionColor, + const glm::mat4 *aModelWorldMatrix, + const SFVEC3F *aCameraWorldPos ) const; + /** * Return true if have opaque meshes to render. */ @@ -136,6 +146,8 @@ private: unsigned int m_render_idx_buffer_offset = 0; unsigned int m_render_idx_count = 0; + BBOX_3D m_bbox; ///< bounding box for this material group, used for transparent material ordering + MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { } bool IsTransparent() const { return m_Transparency > FLT_EPSILON; } }; @@ -159,9 +171,6 @@ private: static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut, GLuint* aIdxOut, const glm::vec4& aColor ); - - void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial, - SFVEC3F& aSelectionColor ) const; }; #endif // _MODEL_3D_H_ diff --git a/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp b/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp index a5495d2390..e6c1cb067a 100644 --- a/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp +++ b/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp @@ -22,14 +22,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include // Must be included first +#include "plugins/3dapi/xv3d_types.h" #include "render_3d_opengl.h" #include "opengl_utils.h" #include "common_ogl/ogl_utils.h" #include #include <3d_math.h> +#include #include // for KiROUND +#include +#include #include #include @@ -858,9 +863,12 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter, glPopMatrix(); } + glm::mat4 cameraViewMatrix; + + glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) ); + // Render 3D Models (Non-transparent) - render3dModels( false, false ); - render3dModels( true, false ); + renderOpaqueModels( cameraViewMatrix ); // Display board body if( m_boardAdapter.m_Cfg->m_Render.show_board_body ) @@ -922,8 +930,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter, glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT ); glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA ); - render3dModels( false, true ); - render3dModels( true, true ); + renderTransparentModels( cameraViewMatrix ); glDisable( GL_BLEND ); OglResetTextureState(); @@ -1143,14 +1150,15 @@ void RENDER_3D_OPENGL::renderSolderMaskLayer( PCB_LAYER_ID aLayerID, float aZPos } -void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly, - bool aRenderSelectedOnly ) +void RENDER_3D_OPENGL::get3dModelsSelected( std::list &aDstRenderList, + bool aGetTop, bool aGetBot, bool aRenderTransparentOnly, + bool aRenderSelectedOnly ) { + wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) ); + if( !m_boardAdapter.GetBoard() ) return; - MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly ); - // Go for all footprints for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() ) { @@ -1175,54 +1183,52 @@ void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRende { if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) ) { - if( aRenderTopOrBot == !fp->IsFlipped() ) - renderFootprint( fp, aRenderTransparentOnly, highlight ); + const bool isFlipped = fp->IsFlipped(); + + if( ( aGetTop == !isFlipped ) || + ( aGetBot == isFlipped ) ) + get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly, highlight ); } } } - - MODEL_3D::EndDrawMulti(); } -void RENDER_3D_OPENGL::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly ) -{ - if( m_boardAdapter.m_IsBoardView ) - render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true ); - - render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false ); -} - - -void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly, - bool aIsSelected ) +void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list &aDstRenderList, + const FOOTPRINT* aFootprint, bool aRenderTransparentOnly, + bool aIsSelected ) { if( !aFootprint->Models().empty() ) { const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() ); - SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color ); - - - glPushMatrix(); VECTOR2I pos = aFootprint->GetPosition(); - glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(), - zpos ); + glm::mat4 fpMatrix( 1.0f ); + + fpMatrix = glm::translate( fpMatrix, + SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(), + -pos.y * m_boardAdapter.BiuTo3dUnits(), + zpos ) ); if( !aFootprint->GetOrientation().IsZero() ) - glRotated( aFootprint->GetOrientation().AsDegrees(), 0.0, 0.0, 1.0 ); + { + fpMatrix = glm::rotate( fpMatrix, + (float) aFootprint->GetOrientation().AsRadians(), + SFVEC3F( 0.0f, 0.0f, 1.0f ) ); + } if( aFootprint->IsFlipped() ) { - glRotatef( 180.0f, 0.0f, 1.0f, 0.0f ); - glRotatef( 180.0f, 0.0f, 0.0f, 1.0f ); + fpMatrix = glm::rotate( fpMatrix, glm::pi(), SFVEC3F( 0.0f, 1.0f, 0.0f ) ); + fpMatrix = glm::rotate( fpMatrix, glm::pi(), SFVEC3F( 0.0f, 0.0f, 1.0f ) ); } - double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB; + const double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * + UNITS3D_TO_UNITSPCB; - glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor, - modelunit_to_3d_units_factor ); + fpMatrix = glm::scale( fpMatrix, + SFVEC3F( modelunit_to_3d_units_factor ) ); // Get the list of model files for this model for( const FP_3DMODEL& sM : aFootprint->Models() ) @@ -1243,66 +1249,232 @@ void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRende if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) || ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) ) { - glPushMatrix(); + glm::mat4 modelworldMatrix = fpMatrix; - std::vector key = { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z, - sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z, - sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z }; + const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z ); + const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z ); + const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z ); + + std::vector key = { offset.x, offset.y, offset.z, + rotation.x, rotation.y, rotation.z, + scale.x, scale.y, scale.z }; auto it = m_3dModelMatrixMap.find( key ); if( it != m_3dModelMatrixMap.end() ) { - glMultMatrixf( glm::value_ptr( it->second ) ); + modelworldMatrix *= it->second; } else { - glm::mat4 mtx( 1 ); - mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } ); - mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } ); - mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ), { 0.0f, 1.0f, 0.0f } ); - mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ), { 1.0f, 0.0f, 0.0f } ); - mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } ); + glm::mat4 mtx( 1.0f ); + mtx = glm::translate( mtx, offset ); + mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } ); + mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } ); + mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } ); + mtx = glm::scale( mtx, scale ); m_3dModelMatrixMap[ key ] = mtx; - glMultMatrixf( glm::value_ptr( mtx ) ); + modelworldMatrix *= mtx; } - if( aRenderTransparentOnly ) { - modelPtr->DrawTransparent( sM.m_Opacity, - aFootprint->IsSelected() || aIsSelected, - selColor ); + aDstRenderList.emplace_back( modelworldMatrix, + modelPtr, + sM.m_Opacity, + true, + aFootprint->IsSelected() || aIsSelected ); } else { - modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected, selColor ); + aDstRenderList.emplace_back( modelworldMatrix, + modelPtr, + 1.0f, + false, + aFootprint->IsSelected() || aIsSelected ); } + } + } + } + } +} - if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox ) - { - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glDisable( GL_LIGHTING ); +void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix ) +{ + const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color ); - glLineWidth( 1 ); - modelPtr->DrawBboxes(); + glPushMatrix(); - glLineWidth( 4 ); - modelPtr->DrawBbox(); + std::list renderList; - glEnable( GL_LIGHTING ); - glDisable( GL_BLEND ); - } + if( m_boardAdapter.m_IsBoardView ) + { + renderList.clear(); - glPopMatrix(); + get3dModelsSelected( renderList, true, true, false, true ); + + if( !renderList.empty() ) + { + MODEL_3D::BeginDrawMulti( false ); + + for( const MODELTORENDER& mtr : renderList ) + { + renderModel( aCameraViewMatrix, mtr, selColor, nullptr ); + } + + MODEL_3D::EndDrawMulti(); + } + } + + renderList.clear(); + get3dModelsSelected( renderList, true, true, false, false ); + + if( !renderList.empty() ) + { + MODEL_3D::BeginDrawMulti( true ); + + for( const MODELTORENDER& mtr : renderList ) + { + renderModel( aCameraViewMatrix, mtr, selColor, nullptr ); + } + + MODEL_3D::EndDrawMulti(); + } + + glPopMatrix(); +} + + +void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix ) +{ + const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color ); + + std::list renderListModels; // do not clear it until this function returns + + if( m_boardAdapter.m_IsBoardView ) + { + // Get Transparent Selected + get3dModelsSelected( renderListModels, true, true, true, true ); + } + + // Get Transparent Not Selected + get3dModelsSelected( renderListModels, true, true, true, false ); + + if( renderListModels.empty() ) + return; + + std::vector> transparentModelList; + + transparentModelList.reserve( renderListModels.size() ); + + // Calculate the distance to the camera for each model + const SFVEC3F &cameraPos = m_camera.GetPos(); + + for( const MODELTORENDER& mtr : renderListModels ) + { + const BBOX_3D& bBox = mtr.m_model->GetBBox(); + const SFVEC3F& bBoxCenter = bBox.GetCenter(); + const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f ); + + const float distanceToCamera = glm::length( cameraPos - bBoxWorld ); + + transparentModelList.emplace_back( &mtr, distanceToCamera ); + } + + // Sort from back to front + std::sort( transparentModelList.begin(), transparentModelList.end(), + [&]( std::pair& a, + std::pair& b ) { + return a.second > b.second; + } ); + + // Start rendering calls + glPushMatrix(); + + bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected && + m_boardAdapter.m_IsBoardView ); + + MODEL_3D::BeginDrawMulti( isUsingColorInformation ); + + for( const std::pair& mtr : transparentModelList ) + { + if( m_boardAdapter.m_IsBoardView ) + { + // Toggle between using model color or the select color + if( !isUsingColorInformation && !mtr.first->m_isSelected ) + { + isUsingColorInformation = true; + + glEnableClientState( GL_COLOR_ARRAY ); + glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + glEnable( GL_COLOR_MATERIAL ); + } + else + { + if( isUsingColorInformation && mtr.first->m_isSelected ) + { + isUsingColorInformation = false; + + glDisableClientState( GL_COLOR_ARRAY ); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + glDisable( GL_COLOR_MATERIAL ); } } } - glPopMatrix(); + // Render model, sort each individuall material group + // by passing cameraPos + renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos ); + } + + MODEL_3D::EndDrawMulti(); + + glPopMatrix(); +} + + +void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix, + const MODELTORENDER &aModelToRender, + const SFVEC3F &aSelColor, + const SFVEC3F *aCameraWorldPos ) +{ + const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat; + + glLoadMatrixf( glm::value_ptr( modelviewMatrix ) ); + + aModelToRender.m_model->Draw( aModelToRender.m_isTransparent, + aModelToRender.m_opacity, + aModelToRender.m_isSelected, + aSelColor, + &aModelToRender.m_modelWorldMat, + aCameraWorldPos ); + + if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox ) + { + const bool wasBlendEnabled = glIsEnabled( GL_BLEND ); + + if( !wasBlendEnabled ) + { + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + + glDisable( GL_LIGHTING ); + + glLineWidth( 1 ); + aModelToRender.m_model->DrawBboxes(); + + glLineWidth( 4 ); + aModelToRender.m_model->DrawBbox(); + + glEnable( GL_LIGHTING ); + + if( !wasBlendEnabled ) + { + glDisable( GL_BLEND ); + } } } diff --git a/3d-viewer/3d_rendering/opengl/render_3d_opengl.h b/3d-viewer/3d_rendering/opengl/render_3d_opengl.h index 3c2ae1d002..667ed49ad9 100644 --- a/3d-viewer/3d_rendering/opengl/render_3d_opengl.h +++ b/3d-viewer/3d_rendering/opengl/render_3d_opengl.h @@ -129,18 +129,44 @@ private: */ void load3dModels( REPORTER* aStatusReporter ); - /** - * @param aRenderTopOrBot true will render Top, false will render bottom - * @param aRenderTransparentOnly true will render only the transparent objects, false will - * render opaque - */ - void render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly ); + struct MODELTORENDER + { + glm::mat4 m_modelWorldMat; + const MODEL_3D* m_model; + float m_opacity; + bool m_isTransparent; + bool m_isSelected; - void render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly, - bool aRenderSelectedOnly ); + MODELTORENDER( glm::mat4 aModelWorldMat, + const MODEL_3D* aNodel, + float aOpacity, + bool aIsTransparent, + bool aIsSelected ) : + m_modelWorldMat( std::move( aModelWorldMat ) ), + m_model( aNodel ), + m_opacity( aOpacity ), + m_isTransparent( aIsTransparent ), + m_isSelected( aIsSelected ) + { + } + }; - void renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly, - bool aIsSelected ); + void renderOpaqueModels( const glm::mat4 &aCameraViewMatrix ); + void renderTransparentModels( const glm::mat4 &aCameraViewMatrix ); + + void renderModel( const glm::mat4 &aCameraViewMatrix, + const MODELTORENDER &aModelToRender, + const SFVEC3F &aSelColor, + const SFVEC3F *aCameraWorldPos ); + + + void get3dModelsSelected( std::list &aDstRenderList, + bool aGetTop, bool aGetBot, bool aRenderTransparentOnly, + bool aRenderSelectedOnly ); + + void get3dModelsFromFootprint( std::list &aDstRenderList, + const FOOTPRINT* aFootprint, bool aRenderTransparentOnly, + bool aIsSelected ); void setLightFront( bool enabled ); void setLightTop( bool enabled ); @@ -210,7 +236,7 @@ private: // Caches std::map< wxString, MODEL_3D* > m_3dModelMap; - std::map< std::vector, glm::mat4 > m_3dModelMatrixMap; + std::map< std::vector, glm::mat4 > m_3dModelMatrixMap; BOARD_ITEM* m_currentRollOverItem; diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.cpp b/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.cpp index 023c29f4e6..f29ad1aa1e 100644 --- a/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.cpp +++ b/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.cpp @@ -229,6 +229,16 @@ bool BBOX_2D::Inside( const SFVEC2F& aPoint ) const } +bool BBOX_2D::Inside( const BBOX_2D& aBBox ) const +{ + wxASSERT( IsInitialized() ); + wxASSERT( aBBox.IsInitialized() ); + + return Inside( aBBox.Min() ) && + Inside( aBBox.Max() ); +} + + float BBOX_2D::Area() const { SFVEC2F extent = GetExtent(); diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.h b/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.h index 1fd83b282b..974d1a497a 100644 --- a/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.h +++ b/3d-viewer/3d_rendering/raytracing/shapes2D/bbox_2d.h @@ -132,6 +132,14 @@ public: */ bool Inside( const SFVEC2F& aPoint ) const; + /** + * Check if a bounding box is inside this bounding box. + * + * @param aBBox the bounding box to test if it is inside + * @return true if aBBox is smaller and all points are inside + */ + bool Inside( const BBOX_2D& aBBox ) const; + /** * Calculate the area of a bounding box. * diff --git a/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.cpp b/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.cpp index 400c2533ec..81f8de85d6 100644 --- a/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.cpp +++ b/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.cpp @@ -238,6 +238,16 @@ bool BBOX_3D::Inside( const SFVEC3F& aPoint ) const } +bool BBOX_3D::Inside( const BBOX_3D& aBBox ) const +{ + wxASSERT( IsInitialized() ); + wxASSERT( aBBox.IsInitialized() ); + + return Inside( aBBox.Min() ) && + Inside( aBBox.Max() ); +} + + float BBOX_3D::Volume() const { wxASSERT( IsInitialized() ); diff --git a/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.h b/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.h index 8342bdfb78..aa9e0ece1d 100644 --- a/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.h +++ b/3d-viewer/3d_rendering/raytracing/shapes3D/bbox_3d.h @@ -125,6 +125,14 @@ public: */ bool Inside( const SFVEC3F& aPoint ) const; + /** + * Check if a bounding box is inside this bounding box. + * + * @param aBBox the bounding box to test if it is inside + * @return true if aBBox is smaller and all points are inside + */ + bool Inside( const BBOX_3D& aBBox ) const; + /** * Apply a transformation matrix to the box points. *