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
This commit is contained in:
parent
0f5ee38ee2
commit
7bc976f3f4
|
@ -330,8 +330,16 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||||
m_ogl_3dmodel->BeginDrawMulti( true );
|
m_ogl_3dmodel->BeginDrawMulti( true );
|
||||||
|
|
||||||
m_ogl_3dmodel->DrawOpaque( false );
|
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 );
|
m_ogl_3dmodel->DrawTransparent( 1.0f, false );
|
||||||
|
|
||||||
|
glDisable( GL_BLEND );
|
||||||
|
glDepthMask( GL_TRUE );
|
||||||
|
|
||||||
m_ogl_3dmodel->EndDrawMulti();
|
m_ogl_3dmodel->EndDrawMulti();
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
|
@ -27,13 +27,14 @@
|
||||||
* @file c_ogl_3dmodel.cpp
|
* @file c_ogl_3dmodel.cpp
|
||||||
* @brief
|
* @brief
|
||||||
*/
|
*/
|
||||||
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <gal/opengl/kiglew.h> // Must be included first
|
#include <gal/opengl/kiglew.h> // Must be included first
|
||||||
|
|
||||||
#include "3d_model.h"
|
#include "3d_model.h"
|
||||||
#include "opengl_utils.h"
|
|
||||||
#include "../common_ogl/ogl_utils.h"
|
#include "../common_ogl/ogl_utils.h"
|
||||||
#include "../3d_math.h"
|
#include "../3d_math.h"
|
||||||
|
#include <utility>
|
||||||
#include <wx/debug.h>
|
#include <wx/debug.h>
|
||||||
#include <wx/log.h>
|
#include <wx/log.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -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.
|
// use material color for mesh bounding box or some sort of average vertex color.
|
||||||
glm::vec3 avg_color = material.m_Diffuse;
|
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 )
|
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];
|
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
|
// 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_vertices[( mesh_i + 1 ) * bbox_vtx_count],
|
||||||
&bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
|
&bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
|
||||||
{ avg_color, 1.0f } );
|
{ avg_color, 1.0f } );
|
||||||
|
|
||||||
// bump the outer bounding box
|
// 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,
|
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 )
|
if( aOpacity <= FLT_EPSILON )
|
||||||
return;
|
return;
|
||||||
|
@ -439,8 +447,24 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||||
|
|
||||||
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)¶m.x );
|
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)¶m.x );
|
||||||
|
|
||||||
|
std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
|
||||||
|
|
||||||
|
materialsToRender.reserve( m_materials.size() );
|
||||||
|
|
||||||
|
if( aModelWorldMatrix && aCameraWorldPos )
|
||||||
|
{
|
||||||
|
// Sort Material groups
|
||||||
|
|
||||||
|
std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
|
||||||
|
|
||||||
|
// Calculate the distance to the camera for each material group
|
||||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||||
{
|
{
|
||||||
|
if( mat.m_render_idx_count == 0 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if( ( mat.IsTransparent() != aTransparent )
|
if( ( mat.IsTransparent() != aTransparent )
|
||||||
&& ( aOpacity >= 1.0f )
|
&& ( aOpacity >= 1.0f )
|
||||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||||
|
@ -448,18 +472,77 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||||
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<const MODEL_3D::MATERIAL*, float>& a,
|
||||||
|
std::pair<const MODEL_3D::MATERIAL*, float>& 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<const MODEL_3D::MATERIAL*, float>& 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 )
|
switch( m_materialMode )
|
||||||
{
|
{
|
||||||
case MATERIAL_MODE::NORMAL:
|
case MATERIAL_MODE::NORMAL:
|
||||||
OglSetMaterial( mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
case MATERIAL_MODE::DIFFUSE_ONLY:
|
||||||
OglSetDiffuseMaterial( mat.m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MATERIAL_MODE::CAD_MODE:
|
case MATERIAL_MODE::CAD_MODE:
|
||||||
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat.m_Diffuse ), aOpacity,
|
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity,
|
||||||
aUseSelectedMaterial, aSelectionColor );
|
aUseSelectedMaterial, aSelectionColor );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -467,9 +550,9 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||||
break;
|
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<const void*>(
|
reinterpret_cast<const void*>(
|
||||||
static_cast<uintptr_t>( mat.m_render_idx_buffer_offset ) ) );
|
static_cast<uintptr_t>( mat->m_render_idx_buffer_offset ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
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,
|
void DrawTransparent( float aOpacity, bool aUseSelectedMaterial,
|
||||||
SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
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.
|
* 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_buffer_offset = 0;
|
||||||
unsigned int m_render_idx_count = 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 ) { }
|
MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { }
|
||||||
bool IsTransparent() const { return m_Transparency > FLT_EPSILON; }
|
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,
|
static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut,
|
||||||
GLuint* aIdxOut, const glm::vec4& aColor );
|
GLuint* aIdxOut, const glm::vec4& aColor );
|
||||||
|
|
||||||
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
|
||||||
SFVEC3F& aSelectionColor ) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _MODEL_3D_H_
|
#endif // _MODEL_3D_H_
|
||||||
|
|
|
@ -22,14 +22,19 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <gal/opengl/kiglew.h> // Must be included first
|
#include <gal/opengl/kiglew.h> // Must be included first
|
||||||
|
|
||||||
|
#include "plugins/3dapi/xv3d_types.h"
|
||||||
#include "render_3d_opengl.h"
|
#include "render_3d_opengl.h"
|
||||||
#include "opengl_utils.h"
|
#include "opengl_utils.h"
|
||||||
#include "common_ogl/ogl_utils.h"
|
#include "common_ogl/ogl_utils.h"
|
||||||
#include <footprint.h>
|
#include <footprint.h>
|
||||||
#include <3d_math.h>
|
#include <3d_math.h>
|
||||||
|
#include <glm/geometric.hpp>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
#include <wx/log.h>
|
#include <wx/log.h>
|
||||||
|
|
||||||
#include <base_units.h>
|
#include <base_units.h>
|
||||||
|
@ -858,9 +863,12 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::mat4 cameraViewMatrix;
|
||||||
|
|
||||||
|
glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
|
||||||
|
|
||||||
// Render 3D Models (Non-transparent)
|
// Render 3D Models (Non-transparent)
|
||||||
render3dModels( false, false );
|
renderOpaqueModels( cameraViewMatrix );
|
||||||
render3dModels( true, false );
|
|
||||||
|
|
||||||
// Display board body
|
// Display board body
|
||||||
if( m_boardAdapter.m_Cfg->m_Render.show_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_SRC1_ALPHA, GL_CONSTANT );
|
||||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
|
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
|
||||||
|
|
||||||
render3dModels( false, true );
|
renderTransparentModels( cameraViewMatrix );
|
||||||
render3dModels( true, true );
|
|
||||||
|
|
||||||
glDisable( GL_BLEND );
|
glDisable( GL_BLEND );
|
||||||
OglResetTextureState();
|
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,
|
void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
|
||||||
|
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
|
||||||
bool aRenderSelectedOnly )
|
bool aRenderSelectedOnly )
|
||||||
{
|
{
|
||||||
|
wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
|
||||||
|
|
||||||
if( !m_boardAdapter.GetBoard() )
|
if( !m_boardAdapter.GetBoard() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
|
|
||||||
|
|
||||||
// Go for all footprints
|
// Go for all footprints
|
||||||
for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->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( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
|
||||||
{
|
{
|
||||||
if( aRenderTopOrBot == !fp->IsFlipped() )
|
const bool isFlipped = fp->IsFlipped();
|
||||||
renderFootprint( fp, aRenderTransparentOnly, highlight );
|
|
||||||
|
if( ( aGetTop == !isFlipped ) ||
|
||||||
|
( aGetBot == isFlipped ) )
|
||||||
|
get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly, highlight );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MODEL_3D::EndDrawMulti();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
|
||||||
void RENDER_3D_OPENGL::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly )
|
const FOOTPRINT* aFootprint, 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 )
|
bool aIsSelected )
|
||||||
{
|
{
|
||||||
if( !aFootprint->Models().empty() )
|
if( !aFootprint->Models().empty() )
|
||||||
{
|
{
|
||||||
const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
|
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();
|
VECTOR2I pos = aFootprint->GetPosition();
|
||||||
|
|
||||||
glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(),
|
glm::mat4 fpMatrix( 1.0f );
|
||||||
zpos );
|
|
||||||
|
fpMatrix = glm::translate( fpMatrix,
|
||||||
|
SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
|
||||||
|
-pos.y * m_boardAdapter.BiuTo3dUnits(),
|
||||||
|
zpos ) );
|
||||||
|
|
||||||
if( !aFootprint->GetOrientation().IsZero() )
|
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() )
|
if( aFootprint->IsFlipped() )
|
||||||
{
|
{
|
||||||
glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
|
fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
|
||||||
glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
|
fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), 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,
|
fpMatrix = glm::scale( fpMatrix,
|
||||||
modelunit_to_3d_units_factor );
|
SFVEC3F( modelunit_to_3d_units_factor ) );
|
||||||
|
|
||||||
// Get the list of model files for this model
|
// Get the list of model files for this model
|
||||||
for( const FP_3DMODEL& sM : aFootprint->Models() )
|
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 ) ||
|
if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
|
||||||
( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
|
( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
|
||||||
{
|
{
|
||||||
glPushMatrix();
|
glm::mat4 modelworldMatrix = fpMatrix;
|
||||||
|
|
||||||
std::vector<double> key = { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z,
|
const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
|
||||||
sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z,
|
const SFVEC3F rotation = SFVEC3F( 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 scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
|
||||||
|
|
||||||
|
std::vector<float> 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 );
|
auto it = m_3dModelMatrixMap.find( key );
|
||||||
|
|
||||||
if( it != m_3dModelMatrixMap.end() )
|
if( it != m_3dModelMatrixMap.end() )
|
||||||
{
|
{
|
||||||
glMultMatrixf( glm::value_ptr( it->second ) );
|
modelworldMatrix *= it->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
glm::mat4 mtx( 1 );
|
glm::mat4 mtx( 1.0f );
|
||||||
mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
|
mtx = glm::translate( mtx, offset );
|
||||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } );
|
mtx = glm::rotate( mtx, glm::radians( -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( -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::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
|
||||||
mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
|
mtx = glm::scale( mtx, scale );
|
||||||
m_3dModelMatrixMap[ key ] = mtx;
|
m_3dModelMatrixMap[ key ] = mtx;
|
||||||
|
|
||||||
glMultMatrixf( glm::value_ptr( mtx ) );
|
modelworldMatrix *= mtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( aRenderTransparentOnly )
|
if( aRenderTransparentOnly )
|
||||||
{
|
{
|
||||||
modelPtr->DrawTransparent( sM.m_Opacity,
|
aDstRenderList.emplace_back( modelworldMatrix,
|
||||||
aFootprint->IsSelected() || aIsSelected,
|
modelPtr,
|
||||||
selColor );
|
sM.m_Opacity,
|
||||||
|
true,
|
||||||
|
aFootprint->IsSelected() || aIsSelected );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected, selColor );
|
aDstRenderList.emplace_back( modelworldMatrix,
|
||||||
|
modelPtr,
|
||||||
|
1.0f,
|
||||||
|
false,
|
||||||
|
aFootprint->IsSelected() || aIsSelected );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
|
||||||
|
{
|
||||||
|
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
|
||||||
|
std::list<MODELTORENDER> renderList;
|
||||||
|
|
||||||
|
if( m_boardAdapter.m_IsBoardView )
|
||||||
|
{
|
||||||
|
renderList.clear();
|
||||||
|
|
||||||
|
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<MODELTORENDER> 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<std::pair<const MODELTORENDER *, float>> 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<const MODELTORENDER *, float>& a,
|
||||||
|
std::pair<const MODELTORENDER *, float>& 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<const MODELTORENDER *, float>& 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 )
|
if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox )
|
||||||
|
{
|
||||||
|
const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
|
||||||
|
|
||||||
|
if( !wasBlendEnabled )
|
||||||
{
|
{
|
||||||
glEnable( GL_BLEND );
|
glEnable( GL_BLEND );
|
||||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
}
|
||||||
|
|
||||||
glDisable( GL_LIGHTING );
|
glDisable( GL_LIGHTING );
|
||||||
|
|
||||||
glLineWidth( 1 );
|
glLineWidth( 1 );
|
||||||
modelPtr->DrawBboxes();
|
aModelToRender.m_model->DrawBboxes();
|
||||||
|
|
||||||
glLineWidth( 4 );
|
glLineWidth( 4 );
|
||||||
modelPtr->DrawBbox();
|
aModelToRender.m_model->DrawBbox();
|
||||||
|
|
||||||
glEnable( GL_LIGHTING );
|
glEnable( GL_LIGHTING );
|
||||||
|
|
||||||
|
if( !wasBlendEnabled )
|
||||||
|
{
|
||||||
glDisable( GL_BLEND );
|
glDisable( GL_BLEND );
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,17 +129,43 @@ private:
|
||||||
*/
|
*/
|
||||||
void load3dModels( REPORTER* aStatusReporter );
|
void load3dModels( REPORTER* aStatusReporter );
|
||||||
|
|
||||||
/**
|
struct MODELTORENDER
|
||||||
* @param aRenderTopOrBot true will render Top, false will render bottom
|
{
|
||||||
* @param aRenderTransparentOnly true will render only the transparent objects, false will
|
glm::mat4 m_modelWorldMat;
|
||||||
* render opaque
|
const MODEL_3D* m_model;
|
||||||
*/
|
float m_opacity;
|
||||||
void render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly );
|
bool m_isTransparent;
|
||||||
|
bool m_isSelected;
|
||||||
|
|
||||||
void render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
|
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 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<MODELTORENDER> &aDstRenderList,
|
||||||
|
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
|
||||||
bool aRenderSelectedOnly );
|
bool aRenderSelectedOnly );
|
||||||
|
|
||||||
void renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
void get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
|
||||||
|
const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||||
bool aIsSelected );
|
bool aIsSelected );
|
||||||
|
|
||||||
void setLightFront( bool enabled );
|
void setLightFront( bool enabled );
|
||||||
|
@ -210,7 +236,7 @@ private:
|
||||||
|
|
||||||
// Caches
|
// Caches
|
||||||
std::map< wxString, MODEL_3D* > m_3dModelMap;
|
std::map< wxString, MODEL_3D* > m_3dModelMap;
|
||||||
std::map< std::vector<double>, glm::mat4 > m_3dModelMatrixMap;
|
std::map< std::vector<float>, glm::mat4 > m_3dModelMatrixMap;
|
||||||
|
|
||||||
BOARD_ITEM* m_currentRollOverItem;
|
BOARD_ITEM* m_currentRollOverItem;
|
||||||
|
|
||||||
|
|
|
@ -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
|
float BBOX_2D::Area() const
|
||||||
{
|
{
|
||||||
SFVEC2F extent = GetExtent();
|
SFVEC2F extent = GetExtent();
|
||||||
|
|
|
@ -132,6 +132,14 @@ public:
|
||||||
*/
|
*/
|
||||||
bool Inside( const SFVEC2F& aPoint ) const;
|
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.
|
* Calculate the area of a bounding box.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
float BBOX_3D::Volume() const
|
||||||
{
|
{
|
||||||
wxASSERT( IsInitialized() );
|
wxASSERT( IsInitialized() );
|
||||||
|
|
|
@ -125,6 +125,14 @@ public:
|
||||||
*/
|
*/
|
||||||
bool Inside( const SFVEC3F& aPoint ) const;
|
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.
|
* Apply a transformation matrix to the box points.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue