Improve 3D viewer rendering performance
* Use GL vertex buffers and index buffers for 3D model rendering * Use material or average vertex color for bounding boxes instead of red * Reinstate bounding box rendering with GL vertex/index buffers * Use compact vertex/index data representation - 8-bit normals - 8-bit colors - 16-bit or 32-bit indices, depending on model size This should improve performance a bit on lower end GPUs with less memory and bandwidth. Fixes #4112
This commit is contained in:
parent
0dfdc37ae7
commit
ae6fbc9c60
|
@ -310,9 +310,13 @@ void C3D_MODEL_VIEWER::OnPaint( wxPaintEvent &event )
|
||||||
|
|
||||||
glTranslatef( -model_center.x, -model_center.y, -model_center.z );
|
glTranslatef( -model_center.x, -model_center.y, -model_center.z );
|
||||||
|
|
||||||
|
m_ogl_3dmodel->BeginDrawMulti();
|
||||||
|
|
||||||
m_ogl_3dmodel->Draw_opaque();
|
m_ogl_3dmodel->Draw_opaque();
|
||||||
m_ogl_3dmodel->Draw_transparent();
|
m_ogl_3dmodel->Draw_transparent();
|
||||||
|
|
||||||
|
m_ogl_3dmodel->EndDrawMulti();
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1079,6 +1079,8 @@ void C3D_RENDER_OGL_LEGACY::render_solder_mask_layer( PCB_LAYER_ID aLayerID,
|
||||||
void C3D_RENDER_OGL_LEGACY::render_3D_models( bool aRenderTopOrBot,
|
void C3D_RENDER_OGL_LEGACY::render_3D_models( bool aRenderTopOrBot,
|
||||||
bool aRenderTransparentOnly )
|
bool aRenderTransparentOnly )
|
||||||
{
|
{
|
||||||
|
C_OGL_3DMODEL::BeginDrawMulti();
|
||||||
|
|
||||||
// Go for all modules
|
// Go for all modules
|
||||||
for( auto module : m_boardAdapter.GetBoard()->Modules() )
|
for( auto module : m_boardAdapter.GetBoard()->Modules() )
|
||||||
{
|
{
|
||||||
|
@ -1088,6 +1090,8 @@ void C3D_RENDER_OGL_LEGACY::render_3D_models( bool aRenderTopOrBot,
|
||||||
|| ( !aRenderTopOrBot && module->IsFlipped() ) )
|
|| ( !aRenderTopOrBot && module->IsFlipped() ) )
|
||||||
render_3D_module( module, aRenderTransparentOnly );
|
render_3D_module( module, aRenderTransparentOnly );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
C_OGL_3DMODEL::EndDrawMulti();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1122,33 +1126,30 @@ void C3D_RENDER_OGL_LEGACY::render_3D_module( const MODULE* module,
|
||||||
modelunit_to_3d_units_factor );
|
modelunit_to_3d_units_factor );
|
||||||
|
|
||||||
// Get the list of model files for this model
|
// Get the list of model files for this model
|
||||||
auto sM = module->Models().begin();
|
for (auto& sM : module->Models ())
|
||||||
auto eM = module->Models().end();
|
|
||||||
|
|
||||||
while( sM != eM )
|
|
||||||
{
|
{
|
||||||
if( !sM->m_Filename.empty() )
|
if( !sM.m_Filename.empty() )
|
||||||
{
|
{
|
||||||
// Check if the model is present in our cache map
|
// Check if the model is present in our cache map
|
||||||
if( m_3dmodel_map.find( sM->m_Filename ) != m_3dmodel_map.end() )
|
auto cache_i = m_3dmodel_map.find( sM.m_Filename );
|
||||||
|
if( cache_i != m_3dmodel_map.end() )
|
||||||
{
|
{
|
||||||
// It is not present, try get it from cache
|
if( const C_OGL_3DMODEL *modelPtr = cache_i->second )
|
||||||
const C_OGL_3DMODEL *modelPtr = m_3dmodel_map[ sM->m_Filename ];
|
|
||||||
|
|
||||||
if( modelPtr )
|
|
||||||
{
|
{
|
||||||
if( ( (!aRenderTransparentOnly) && modelPtr->Have_opaque() ) ||
|
if( ( (!aRenderTransparentOnly) && modelPtr->Have_opaque() ) ||
|
||||||
( aRenderTransparentOnly && modelPtr->Have_transparent() ) )
|
( aRenderTransparentOnly && modelPtr->Have_transparent() ) )
|
||||||
{
|
{
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
glTranslatef( sM->m_Offset.x, sM->m_Offset.y, sM->m_Offset.z );
|
// FIXME: don't do this over and over again unless the
|
||||||
|
// values have changed. cache the matrix somewhere.
|
||||||
glRotatef( -sM->m_Rotation.z, 0.0f, 0.0f, 1.0f );
|
glm::mat4 mtx( 1 );
|
||||||
glRotatef( -sM->m_Rotation.y, 0.0f, 1.0f, 0.0f );
|
mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
|
||||||
glRotatef( -sM->m_Rotation.x, 1.0f, 0.0f, 0.0f );
|
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 } );
|
||||||
glScalef( sM->m_Scale.x, sM->m_Scale.y, sM->m_Scale.z );
|
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 } );
|
||||||
|
glMultMatrixf( glm::value_ptr( mtx ) );
|
||||||
|
|
||||||
if( aRenderTransparentOnly )
|
if( aRenderTransparentOnly )
|
||||||
modelPtr->Draw_transparent();
|
modelPtr->Draw_transparent();
|
||||||
|
@ -1160,17 +1161,16 @@ void C3D_RENDER_OGL_LEGACY::render_3D_module( const MODULE* module,
|
||||||
glEnable( GL_BLEND );
|
glEnable( GL_BLEND );
|
||||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||||
|
|
||||||
glLineWidth( 1 );
|
|
||||||
modelPtr->Draw_bboxes();
|
|
||||||
|
|
||||||
glDisable( GL_LIGHTING );
|
glDisable( GL_LIGHTING );
|
||||||
|
|
||||||
glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
|
glLineWidth( 1 );
|
||||||
|
modelPtr->Draw_bboxes();
|
||||||
|
|
||||||
glLineWidth( 4 );
|
glLineWidth( 4 );
|
||||||
modelPtr->Draw_bbox();
|
modelPtr->Draw_bbox();
|
||||||
|
|
||||||
glEnable( GL_LIGHTING );
|
glEnable( GL_LIGHTING );
|
||||||
|
glDisable( GL_BLEND );
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
@ -1178,8 +1178,6 @@ void C3D_RENDER_OGL_LEGACY::render_3D_module( const MODULE* module,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++sM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
|
||||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
|
@ -27,357 +28,461 @@
|
||||||
* @brief
|
* @brief
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
#include "c_ogl_3dmodel.h"
|
#include "c_ogl_3dmodel.h"
|
||||||
#include "ogl_legacy_utils.h"
|
#include "ogl_legacy_utils.h"
|
||||||
#include "../common_ogl/ogl_utils.h"
|
#include "../common_ogl/ogl_utils.h"
|
||||||
#include "../3d_math.h"
|
#include "../3d_math.h"
|
||||||
#include <wx/debug.h>
|
#include <wx/debug.h>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
const wxChar * C_OGL_3DMODEL::m_logTrace = wxT( "KI_TRACE_EDA_OGL_3DMODEL" );
|
||||||
|
|
||||||
|
void C_OGL_3DMODEL::MakeBbox( const CBBOX &aBox, unsigned int aIdxOffset,
|
||||||
|
VERTEX *aVtxOut, GLuint *aIdxOut,
|
||||||
|
const glm::vec4 &aColor )
|
||||||
|
{
|
||||||
|
aVtxOut[0].m_pos = { aBox.Min().x, aBox.Min().y, aBox.Min().z };
|
||||||
|
aVtxOut[1].m_pos = { aBox.Max().x, aBox.Min().y, aBox.Min().z };
|
||||||
|
aVtxOut[2].m_pos = { aBox.Max().x, aBox.Max().y, aBox.Min().z };
|
||||||
|
aVtxOut[3].m_pos = { aBox.Min().x, aBox.Max().y, aBox.Min().z };
|
||||||
|
|
||||||
|
aVtxOut[4].m_pos = { aBox.Min().x, aBox.Min().y, aBox.Max().z };
|
||||||
|
aVtxOut[5].m_pos = { aBox.Max().x, aBox.Min().y, aBox.Max().z };
|
||||||
|
aVtxOut[6].m_pos = { aBox.Max().x, aBox.Max().y, aBox.Max().z };
|
||||||
|
aVtxOut[7].m_pos = { aBox.Min().x, aBox.Max().y, aBox.Max().z };
|
||||||
|
|
||||||
|
for( unsigned int i = 0; i < 8; ++i )
|
||||||
|
aVtxOut[i].m_color = aVtxOut[i].m_cad_color = glm::clamp( aColor * 255.0f, 0.0f, 255.0f );
|
||||||
|
|
||||||
|
#define bbox_line( vtx_a, vtx_b )\
|
||||||
|
do { *aIdxOut++ = vtx_a + aIdxOffset; \
|
||||||
|
*aIdxOut++ = vtx_b + aIdxOffset; } while( 0 )
|
||||||
|
|
||||||
|
bbox_line( 0, 1 );
|
||||||
|
bbox_line( 1, 2 );
|
||||||
|
bbox_line( 2, 3 );
|
||||||
|
bbox_line( 3, 0 );
|
||||||
|
|
||||||
|
bbox_line( 4, 5 );
|
||||||
|
bbox_line( 5, 6 );
|
||||||
|
bbox_line( 6, 7 );
|
||||||
|
bbox_line( 7, 4 );
|
||||||
|
|
||||||
|
bbox_line( 0, 4 );
|
||||||
|
bbox_line( 1, 5 );
|
||||||
|
bbox_line( 2, 6 );
|
||||||
|
bbox_line( 3, 7 );
|
||||||
|
|
||||||
|
#undef bbox_line
|
||||||
|
}
|
||||||
|
|
||||||
C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel,
|
C_OGL_3DMODEL::C_OGL_3DMODEL( const S3DMODEL &a3DModel,
|
||||||
MATERIAL_MODE aMaterialMode )
|
MATERIAL_MODE aMaterialMode )
|
||||||
{
|
{
|
||||||
m_ogl_idx_list_meshes = 0;
|
wxLogTrace( m_logTrace, wxT( "C_OGL_3DMODEL::C_OGL_3DMODEL %u meshes %u materials" ),
|
||||||
m_ogl_idx_list_opaque = 0;
|
static_cast<unsigned int>( a3DModel.m_MeshesSize ),
|
||||||
m_ogl_idx_list_transparent = 0;
|
static_cast<unsigned int>( a3DModel.m_MaterialsSize ) );
|
||||||
m_nr_meshes = 0;
|
|
||||||
m_meshs_bbox = NULL;
|
auto start_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// Validate a3DModel pointers
|
// Validate a3DModel pointers
|
||||||
wxASSERT( a3DModel.m_Materials != NULL );
|
wxASSERT( a3DModel.m_Materials != nullptr );
|
||||||
wxASSERT( a3DModel.m_Meshes != NULL );
|
wxASSERT( a3DModel.m_Meshes != nullptr );
|
||||||
wxASSERT( a3DModel.m_MaterialsSize > 0 );
|
wxASSERT( a3DModel.m_MaterialsSize > 0 );
|
||||||
wxASSERT( a3DModel.m_MeshesSize > 0 );
|
wxASSERT( a3DModel.m_MeshesSize > 0 );
|
||||||
|
|
||||||
if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
|
m_material_mode = aMaterialMode;
|
||||||
(a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
|
|
||||||
|
if( a3DModel.m_Materials == nullptr || a3DModel.m_Meshes == nullptr
|
||||||
|
|| a3DModel.m_MaterialsSize == 0 || a3DModel.m_MeshesSize == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create empty bbox for each mesh. it will be updated when the vertices
|
||||||
|
// are copied.
|
||||||
|
m_meshes_bbox.resize( a3DModel.m_MeshesSize );
|
||||||
|
|
||||||
|
// copy materials for later use during rendering.
|
||||||
|
m_materials.reserve( a3DModel.m_MaterialsSize );
|
||||||
|
|
||||||
|
for( unsigned int i = 0; i < a3DModel.m_MaterialsSize; ++i )
|
||||||
|
m_materials.emplace_back( a3DModel.m_Materials[i] );
|
||||||
|
|
||||||
|
// build temporary vertex and index buffers for bounding boxes.
|
||||||
|
// the first box is the outer box.
|
||||||
|
std::vector<VERTEX> bbox_tmp_vertices( ( m_meshes_bbox.size() + 1 ) * bbox_vtx_count );
|
||||||
|
std::vector<GLuint> bbox_tmp_indices( ( m_meshes_bbox.size() + 1 ) * bbox_idx_count );
|
||||||
|
|
||||||
|
// group all meshes by material.
|
||||||
|
// for each material create a combined vertex and index buffer.
|
||||||
|
// some models might have many sub-meshes. so iterate over the
|
||||||
|
// input meshes only once.
|
||||||
|
struct MESH_GROUP
|
||||||
{
|
{
|
||||||
m_nr_meshes = a3DModel.m_MeshesSize;
|
std::vector<VERTEX> m_vertices;
|
||||||
|
std::vector<GLuint> m_indices;
|
||||||
|
};
|
||||||
|
|
||||||
m_meshs_bbox = new CBBOX[a3DModel.m_MeshesSize];
|
std::vector<MESH_GROUP> mesh_groups( m_materials.size() );
|
||||||
|
|
||||||
// Generate m_MeshesSize auxiliar lists to render the meshes
|
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
||||||
m_ogl_idx_list_meshes = glGenLists( a3DModel.m_MeshesSize );
|
{
|
||||||
|
const auto& mesh = a3DModel.m_Meshes[mesh_i];
|
||||||
|
|
||||||
// Render each mesh of the model
|
// silently ignore meshes that have invalid material references
|
||||||
// /////////////////////////////////////////////////////////////////////
|
// or invalid geometry.
|
||||||
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
if( mesh.m_MaterialIdx >= m_materials.size()
|
||||||
|
|| mesh.m_Positions == nullptr
|
||||||
|
|| mesh.m_FaceIdx == nullptr
|
||||||
|
|| mesh.m_Normals == nullptr
|
||||||
|
|| mesh.m_FaceIdxSize == 0
|
||||||
|
|| mesh.m_VertexSize == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& mesh_group = mesh_groups[mesh.m_MaterialIdx];
|
||||||
|
auto& material = m_materials[mesh.m_MaterialIdx];
|
||||||
|
|
||||||
|
if( material.IsTransparent() )
|
||||||
|
m_have_transparent_meshes = true;
|
||||||
|
else
|
||||||
|
m_have_opaque_meshes = true;
|
||||||
|
|
||||||
|
const unsigned int vtx_offset = mesh_group.m_vertices.size();
|
||||||
|
mesh_group.m_vertices.resize( mesh_group.m_vertices.size() + mesh.m_VertexSize );
|
||||||
|
|
||||||
|
// copy vertex data and update the bounding box.
|
||||||
|
// use material color for mesh bounding box or some sort of average
|
||||||
|
// vertex color.
|
||||||
|
glm::vec3 avg_color = material.m_Diffuse;
|
||||||
|
|
||||||
|
for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i )
|
||||||
{
|
{
|
||||||
if( glIsList( m_ogl_idx_list_meshes + mesh_i ) )
|
m_meshes_bbox[mesh_i].Union( mesh.m_Positions[vtx_i] );
|
||||||
|
|
||||||
|
auto& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
|
||||||
|
|
||||||
|
vtx_out.m_pos = mesh.m_Positions[vtx_i];
|
||||||
|
vtx_out.m_nrm = glm::clamp( glm::vec4( mesh.m_Normals[vtx_i], 1.0f ) * 127.0f,
|
||||||
|
-127.0f, 127.0f );
|
||||||
|
|
||||||
|
vtx_out.m_tex_uv = mesh.m_Texcoords != nullptr
|
||||||
|
? mesh.m_Texcoords[vtx_i]
|
||||||
|
: glm::vec2 (0);
|
||||||
|
|
||||||
|
if( mesh.m_Color != nullptr )
|
||||||
{
|
{
|
||||||
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
|
avg_color = ( avg_color + mesh.m_Color[vtx_i] ) * 0.5f;
|
||||||
|
|
||||||
// Validate the mesh pointers
|
vtx_out.m_color =
|
||||||
wxASSERT( mesh.m_Positions != NULL );
|
glm::clamp( glm::vec4( mesh.m_Color[vtx_i],
|
||||||
wxASSERT( mesh.m_FaceIdx != NULL );
|
1 - material.m_Transparency ) * 255.0f,
|
||||||
wxASSERT( mesh.m_Normals != NULL );
|
0.0f, 255.0f );
|
||||||
|
|
||||||
if( (mesh.m_Positions != NULL) &&
|
vtx_out.m_cad_color =
|
||||||
(mesh.m_Normals != NULL) &&
|
glm::clamp( glm::vec4( MaterialDiffuseToColorCAD( mesh.m_Color[vtx_i] ),
|
||||||
(mesh.m_FaceIdx != NULL) &&
|
1 ) * 255.0f,
|
||||||
(mesh.m_FaceIdxSize > 0) && (mesh.m_VertexSize > 0) )
|
0.0f, 255.0f );
|
||||||
{
|
|
||||||
SFVEC4F *pColorRGBA = NULL;
|
|
||||||
|
|
||||||
// Create the bbox for this mesh
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
m_meshs_bbox[mesh_i].Reset();
|
|
||||||
|
|
||||||
for( unsigned int vertex_i = 0;
|
|
||||||
vertex_i < mesh.m_VertexSize;
|
|
||||||
++vertex_i )
|
|
||||||
{
|
|
||||||
m_meshs_bbox[mesh_i].Union( mesh.m_Positions[vertex_i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we start with client state disabled
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
||||||
glDisableClientState( GL_COLOR_ARRAY );
|
|
||||||
|
|
||||||
|
|
||||||
// Enable arrays client states
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
glEnableClientState( GL_VERTEX_ARRAY );
|
|
||||||
glEnableClientState( GL_NORMAL_ARRAY );
|
|
||||||
|
|
||||||
glVertexPointer( 3, GL_FLOAT, 0, mesh.m_Positions );
|
|
||||||
glNormalPointer( GL_FLOAT, 0, mesh.m_Normals );
|
|
||||||
|
|
||||||
if( mesh.m_Color != NULL )
|
|
||||||
{
|
|
||||||
glEnableClientState( GL_COLOR_ARRAY );
|
|
||||||
|
|
||||||
float transparency = 0.0f;
|
|
||||||
|
|
||||||
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
|
|
||||||
transparency = a3DModel.m_Materials[mesh.m_MaterialIdx].m_Transparency;
|
|
||||||
|
|
||||||
if( ( transparency > FLT_EPSILON )
|
|
||||||
&& ( aMaterialMode == MATERIAL_MODE::NORMAL ) )
|
|
||||||
{
|
|
||||||
// Create a new array of RGBA colors
|
|
||||||
pColorRGBA = new SFVEC4F[mesh.m_VertexSize];
|
|
||||||
|
|
||||||
// Copy RGB array and add the Alpha value
|
|
||||||
for( unsigned int i = 0; i < mesh.m_VertexSize; ++i )
|
|
||||||
pColorRGBA[i] = SFVEC4F( mesh.m_Color[i],
|
|
||||||
1.0f - transparency );
|
|
||||||
|
|
||||||
// Load an RGBA array
|
|
||||||
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch( aMaterialMode )
|
|
||||||
{
|
|
||||||
case MATERIAL_MODE::NORMAL:
|
|
||||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
|
||||||
// load the original RGB color array
|
|
||||||
glColorPointer( 3, GL_FLOAT, 0, mesh.m_Color );
|
|
||||||
break;
|
|
||||||
case MATERIAL_MODE::CAD_MODE:
|
|
||||||
// Create a new array of RGBA colors
|
|
||||||
pColorRGBA = new SFVEC4F[mesh.m_VertexSize];
|
|
||||||
|
|
||||||
// Copy RGB array and add the Alpha value
|
|
||||||
for( unsigned int i = 0; i < mesh.m_VertexSize; ++i )
|
|
||||||
{
|
|
||||||
pColorRGBA[i] =
|
|
||||||
SFVEC4F( MaterialDiffuseToColorCAD( mesh.m_Color[i] ),
|
|
||||||
1.0f );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load an RGBA array
|
|
||||||
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( mesh.m_Texcoords != NULL )
|
|
||||||
{
|
|
||||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
||||||
glTexCoordPointer( 2, GL_FLOAT, 0, mesh.m_Texcoords );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile the display list to store triangles
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
glNewList( m_ogl_idx_list_meshes + mesh_i, GL_COMPILE );
|
|
||||||
|
|
||||||
// Set material properties
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
if( mesh.m_Color != NULL )
|
|
||||||
{
|
|
||||||
// This enables the use of the Color Pointer information
|
|
||||||
glEnable( GL_COLOR_MATERIAL );
|
|
||||||
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glDisable( GL_COLOR_MATERIAL );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
|
|
||||||
{
|
|
||||||
switch( aMaterialMode )
|
|
||||||
{
|
|
||||||
case MATERIAL_MODE::NORMAL:
|
|
||||||
OGL_SetMaterial( a3DModel.m_Materials[mesh.m_MaterialIdx] );
|
|
||||||
break;
|
|
||||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
|
||||||
OGL_SetDiffuseOnlyMaterial(
|
|
||||||
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse );
|
|
||||||
break;
|
|
||||||
case MATERIAL_MODE::CAD_MODE:
|
|
||||||
OGL_SetDiffuseOnlyMaterial(
|
|
||||||
MaterialDiffuseToColorCAD(
|
|
||||||
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse ) );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw mesh
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
glDrawElements( GL_TRIANGLES, mesh.m_FaceIdxSize,
|
|
||||||
GL_UNSIGNED_INT, mesh.m_FaceIdx );
|
|
||||||
|
|
||||||
glDisable( GL_COLOR_MATERIAL );
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
|
|
||||||
// Disable arrays client states
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
||||||
glDisableClientState( GL_COLOR_ARRAY );
|
|
||||||
glDisableClientState( GL_NORMAL_ARRAY );
|
|
||||||
glDisableClientState( GL_VERTEX_ARRAY );
|
|
||||||
|
|
||||||
glFlush();
|
|
||||||
|
|
||||||
delete [] pColorRGBA;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}// for each mesh
|
else
|
||||||
|
|
||||||
|
|
||||||
m_ogl_idx_list_opaque = glGenLists( 1 );
|
|
||||||
|
|
||||||
// Check if the generated list is valid
|
|
||||||
if( glIsList( m_ogl_idx_list_opaque ) )
|
|
||||||
{
|
|
||||||
bool have_opaque_meshes = false;
|
|
||||||
bool have_transparent_meshes = false;
|
|
||||||
|
|
||||||
// Compile the model display list
|
|
||||||
glNewList( m_ogl_idx_list_opaque, GL_COMPILE );
|
|
||||||
|
|
||||||
// Render each mesh display list (opaque first)
|
|
||||||
// /////////////////////////////////////////////////////////////////
|
|
||||||
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
|
||||||
{
|
{
|
||||||
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
|
// the mesh will be rendered with other meshes that might have
|
||||||
|
// vertex colors. thus, we can't enable/disable vertex colors
|
||||||
|
// for individual meshes during rendering.
|
||||||
|
|
||||||
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
|
// if there are no vertex colors, use material color instead.
|
||||||
{
|
vtx_out.m_color =
|
||||||
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
|
glm::clamp( glm::vec4( material.m_Diffuse,
|
||||||
|
1 - material.m_Transparency ) * 255.0f,
|
||||||
|
0.0f, 255.0f );
|
||||||
|
|
||||||
if( material.m_Transparency == 0.0f )
|
vtx_out.m_cad_color =
|
||||||
{
|
glm::clamp( glm::vec4 ( MaterialDiffuseToColorCAD( material.m_Diffuse ),
|
||||||
have_opaque_meshes = true; // Flag that we have at least one opaque mesh
|
1 ) * 255.0f,
|
||||||
glCallList( m_ogl_idx_list_meshes + mesh_i );
|
0.0f, 255.0f );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
have_transparent_meshes = true; // Flag that we found a transparent mesh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
|
|
||||||
if( !have_opaque_meshes )
|
|
||||||
{
|
|
||||||
// If we dont have opaque meshes, we can free the list
|
|
||||||
glDeleteLists( m_ogl_idx_list_opaque, 1 );
|
|
||||||
m_ogl_idx_list_opaque = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( have_transparent_meshes )
|
|
||||||
{
|
|
||||||
m_ogl_idx_list_transparent = glGenLists( 1 );
|
|
||||||
|
|
||||||
// Check if the generated list is valid
|
|
||||||
if( glIsList( m_ogl_idx_list_transparent ) )
|
|
||||||
{
|
|
||||||
// Compile the model display list
|
|
||||||
glNewList( m_ogl_idx_list_transparent, GL_COMPILE );
|
|
||||||
|
|
||||||
glEnable( GL_BLEND );
|
|
||||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
|
||||||
|
|
||||||
// Render each mesh display list
|
|
||||||
// /////////////////////////////////////////////////////////
|
|
||||||
for( unsigned mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
|
||||||
{
|
|
||||||
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
|
|
||||||
|
|
||||||
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
|
|
||||||
{
|
|
||||||
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
|
|
||||||
|
|
||||||
// Render the transparent mesh if it have a transparency value
|
|
||||||
if( material.m_Transparency != 0.0f )
|
|
||||||
glCallList( m_ogl_idx_list_meshes + mesh_i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glDisable( GL_BLEND );
|
|
||||||
|
|
||||||
glEndList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ogl_idx_list_transparent = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if( m_meshes_bbox[mesh_i].IsInitialized() )
|
||||||
{
|
{
|
||||||
m_ogl_idx_list_opaque = 0;
|
// generate geometry for the bounding box
|
||||||
|
MakeBbox( m_meshes_bbox[mesh_i], ( 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] );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the main bbox
|
|
||||||
// /////////////////////////////////////////////////////////////////////
|
|
||||||
m_model_bbox.Reset();
|
|
||||||
|
|
||||||
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
// append indices of this mesh to the mesh group.
|
||||||
m_model_bbox.Union( m_meshs_bbox[mesh_i] );
|
const unsigned int idx_offset = mesh_group.m_indices.size();
|
||||||
|
unsigned int use_idx_count = mesh.m_FaceIdxSize;
|
||||||
|
|
||||||
glFlush();
|
if( use_idx_count % 3 != 0 )
|
||||||
|
{
|
||||||
|
wxLogTrace( m_logTrace, wxT( " index count %u not multiple of 3, truncating" ),
|
||||||
|
static_cast<unsigned int>( use_idx_count ) );
|
||||||
|
use_idx_count = ( use_idx_count / 3 ) * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh_group.m_indices.resize( mesh_group.m_indices.size() + use_idx_count );
|
||||||
|
|
||||||
|
for( unsigned int idx_i = 0; idx_i < use_idx_count; ++idx_i )
|
||||||
|
{
|
||||||
|
if( mesh.m_FaceIdx[idx_i] >= mesh.m_VertexSize )
|
||||||
|
{
|
||||||
|
wxLogTrace( m_logTrace, wxT( " index %u out of range (%u)" ),
|
||||||
|
static_cast<unsigned int>( mesh.m_FaceIdx[idx_i] ),
|
||||||
|
static_cast<unsigned int>( mesh.m_VertexSize ) );
|
||||||
|
|
||||||
|
// FIXME: should skip this triangle
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh_group.m_indices[idx_offset + idx_i] = mesh.m_FaceIdx[idx_i] + vtx_offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate geometry for the outer bounding box
|
||||||
|
if( m_model_bbox.IsInitialized() )
|
||||||
|
MakeBbox( m_model_bbox, 0, &bbox_tmp_vertices[0], &bbox_tmp_indices[0],
|
||||||
|
{ 0.0f, 1.0f, 0.0f, 1.0f } );
|
||||||
|
|
||||||
|
// create bounding box buffers
|
||||||
|
glGenBuffers( 1, &m_bbox_vertex_buffer );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
|
||||||
|
glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * bbox_tmp_vertices.size(),
|
||||||
|
bbox_tmp_vertices.data(), GL_STATIC_DRAW );
|
||||||
|
|
||||||
|
glGenBuffers( 1, &m_bbox_index_buffer );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
|
||||||
|
|
||||||
|
if( bbox_tmp_vertices.size() <= std::numeric_limits<GLushort>::max() )
|
||||||
|
{
|
||||||
|
m_bbox_index_buffer_type = GL_UNSIGNED_SHORT;
|
||||||
|
|
||||||
|
auto u16buf = std::make_unique<GLushort[]>( bbox_tmp_indices.size() );
|
||||||
|
|
||||||
|
for( unsigned int i = 0; i < bbox_tmp_indices.size(); ++i )
|
||||||
|
u16buf[i] = static_cast<GLushort>( bbox_tmp_indices[i] );
|
||||||
|
|
||||||
|
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( GLushort ) * bbox_tmp_indices.size(),
|
||||||
|
u16buf.get(), GL_STATIC_DRAW );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_bbox_index_buffer_type = GL_UNSIGNED_INT;
|
||||||
|
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( GLuint ) * bbox_tmp_indices.size(),
|
||||||
|
bbox_tmp_indices.data(), GL_STATIC_DRAW );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// merge the mesh group geometry data.
|
||||||
|
unsigned int total_vertex_count = 0;
|
||||||
|
unsigned int total_index_count = 0;
|
||||||
|
|
||||||
|
for( auto& mg : mesh_groups )
|
||||||
|
{
|
||||||
|
total_vertex_count += mg.m_vertices.size();
|
||||||
|
total_index_count += mg.m_indices.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
wxLogTrace( m_logTrace, wxT( " total %u vertices, %u indices" ),
|
||||||
|
total_vertex_count, total_index_count );
|
||||||
|
|
||||||
|
glGenBuffers( 1, &m_vertex_buffer );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer );
|
||||||
|
glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * total_vertex_count,
|
||||||
|
nullptr, GL_STATIC_DRAW );
|
||||||
|
|
||||||
|
unsigned int idx_size = 0;
|
||||||
|
|
||||||
|
if( total_vertex_count <= std::numeric_limits<GLushort>::max() )
|
||||||
|
{
|
||||||
|
m_index_buffer_type = GL_UNSIGNED_SHORT;
|
||||||
|
idx_size = sizeof( GLushort );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_index_buffer_type = GL_UNSIGNED_INT;
|
||||||
|
idx_size = sizeof( GLuint );
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporary index buffer which will contain either GLushort or GLuint
|
||||||
|
// type indices. allocate with a bit of meadow at the end.
|
||||||
|
auto tmp_idx = std::make_unique<GLuint[]>(
|
||||||
|
( idx_size * total_index_count + 8 ) / sizeof( GLuint ) );
|
||||||
|
|
||||||
|
unsigned int prev_vtx_count = 0;
|
||||||
|
unsigned int idx_offset = 0;
|
||||||
|
unsigned int vtx_offset = 0;
|
||||||
|
|
||||||
|
for( unsigned int mg_i = 0; mg_i < mesh_groups.size (); ++mg_i )
|
||||||
|
{
|
||||||
|
auto& mg = mesh_groups[mg_i];
|
||||||
|
auto& mat = m_materials[mg_i];
|
||||||
|
|
||||||
|
if( m_index_buffer_type == GL_UNSIGNED_SHORT )
|
||||||
|
{
|
||||||
|
auto idx_out = reinterpret_cast<GLushort*>(
|
||||||
|
reinterpret_cast<uintptr_t>( tmp_idx.get() ) + idx_offset );
|
||||||
|
|
||||||
|
for( auto idx : mg.m_indices )
|
||||||
|
*idx_out++ = static_cast<GLushort>( idx + prev_vtx_count );
|
||||||
|
}
|
||||||
|
else if( m_index_buffer_type == GL_UNSIGNED_INT )
|
||||||
|
{
|
||||||
|
auto idx_out = reinterpret_cast<GLuint*>(
|
||||||
|
reinterpret_cast<uintptr_t>( tmp_idx.get() ) + idx_offset );
|
||||||
|
|
||||||
|
for( auto idx : mg.m_indices )
|
||||||
|
*idx_out++ = static_cast<GLuint>( idx + prev_vtx_count );
|
||||||
|
}
|
||||||
|
|
||||||
|
glBufferSubData( GL_ARRAY_BUFFER,
|
||||||
|
vtx_offset,
|
||||||
|
mg.m_vertices.size() * sizeof( VERTEX ),
|
||||||
|
mg.m_vertices.data() );
|
||||||
|
|
||||||
|
mat.m_render_idx_buffer_offset = idx_offset;
|
||||||
|
mat.m_render_idx_count = mg.m_indices.size();
|
||||||
|
|
||||||
|
prev_vtx_count += mg.m_vertices.size();
|
||||||
|
idx_offset += mg.m_indices.size() * idx_size;
|
||||||
|
vtx_offset += mg.m_vertices.size() * sizeof( VERTEX );
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenBuffers( 1, &m_index_buffer );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer );
|
||||||
|
glBufferData( GL_ELEMENT_ARRAY_BUFFER, idx_size * total_index_count,
|
||||||
|
tmp_idx.get(), GL_STATIC_DRAW );
|
||||||
|
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||||
|
|
||||||
|
auto end_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
wxLogTrace( m_logTrace, wxT( " loaded in %u ms\n" ),
|
||||||
|
(unsigned int)std::chrono::duration_cast<std::chrono::milliseconds> (
|
||||||
|
end_time - start_time).count() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void C_OGL_3DMODEL::BeginDrawMulti()
|
||||||
void C_OGL_3DMODEL::Draw_opaque() const
|
|
||||||
{
|
{
|
||||||
if( glIsList( m_ogl_idx_list_opaque ) )
|
glEnableClientState( GL_VERTEX_ARRAY );
|
||||||
glCallList( m_ogl_idx_list_opaque );
|
glEnableClientState( GL_NORMAL_ARRAY );
|
||||||
|
glEnableClientState( GL_COLOR_ARRAY );
|
||||||
|
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
|
||||||
|
glEnable( GL_COLOR_MATERIAL );
|
||||||
|
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void C_OGL_3DMODEL::EndDrawMulti()
|
||||||
void C_OGL_3DMODEL::Draw_transparent() const
|
|
||||||
{
|
{
|
||||||
if( glIsList( m_ogl_idx_list_transparent ) )
|
glDisable( GL_COLOR_MATERIAL );
|
||||||
glCallList( m_ogl_idx_list_transparent );
|
glDisableClientState( GL_VERTEX_ARRAY );
|
||||||
|
glDisableClientState( GL_NORMAL_ARRAY );
|
||||||
|
glDisableClientState( GL_COLOR_ARRAY );
|
||||||
|
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void C_OGL_3DMODEL::Draw( bool aTransparent ) const
|
||||||
|
{
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer );
|
||||||
|
|
||||||
|
glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
|
||||||
|
|
||||||
|
glNormalPointer( GL_BYTE, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_nrm ) ) );
|
||||||
|
|
||||||
|
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>(
|
||||||
|
m_material_mode == MATERIAL_MODE::CAD_MODE
|
||||||
|
? offsetof( VERTEX, m_cad_color )
|
||||||
|
: offsetof( VERTEX, m_color ) ) );
|
||||||
|
|
||||||
|
glTexCoordPointer( 2, GL_FLOAT, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_tex_uv ) ) );
|
||||||
|
|
||||||
|
// BeginDrawMulti();
|
||||||
|
|
||||||
|
for( auto& mat : m_materials )
|
||||||
|
{
|
||||||
|
if( mat.IsTransparent() != aTransparent )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch( m_material_mode )
|
||||||
|
{
|
||||||
|
case MATERIAL_MODE::NORMAL:
|
||||||
|
OGL_SetMaterial( mat );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATERIAL_MODE::DIFFUSE_ONLY:
|
||||||
|
OGL_SetDiffuseOnlyMaterial( mat.m_Diffuse );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MATERIAL_MODE::CAD_MODE:
|
||||||
|
OGL_SetDiffuseOnlyMaterial( MaterialDiffuseToColorCAD( mat.m_Diffuse ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawElements( GL_TRIANGLES, mat.m_render_idx_count, m_index_buffer_type,
|
||||||
|
reinterpret_cast<const void*>( mat.m_render_idx_buffer_offset ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndDrawMulti();
|
||||||
|
}
|
||||||
|
|
||||||
C_OGL_3DMODEL::~C_OGL_3DMODEL()
|
C_OGL_3DMODEL::~C_OGL_3DMODEL()
|
||||||
{
|
{
|
||||||
if( glIsList( m_ogl_idx_list_opaque ) )
|
glDeleteBuffers( 1, &m_vertex_buffer );
|
||||||
glDeleteLists( m_ogl_idx_list_opaque, 1 );
|
glDeleteBuffers( 1, &m_index_buffer );
|
||||||
|
glDeleteBuffers( 1, &m_bbox_vertex_buffer );
|
||||||
if( glIsList( m_ogl_idx_list_transparent ) )
|
glDeleteBuffers( 1, &m_bbox_index_buffer );
|
||||||
glDeleteLists( m_ogl_idx_list_transparent, 1 );
|
|
||||||
|
|
||||||
if( glIsList( m_ogl_idx_list_meshes ) )
|
|
||||||
glDeleteLists( m_ogl_idx_list_meshes, m_nr_meshes );
|
|
||||||
|
|
||||||
m_ogl_idx_list_meshes = 0;
|
|
||||||
m_ogl_idx_list_opaque = 0;
|
|
||||||
m_ogl_idx_list_transparent = 0;
|
|
||||||
|
|
||||||
delete[] m_meshs_bbox;
|
|
||||||
m_meshs_bbox = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void C_OGL_3DMODEL::Draw_bbox() const
|
void C_OGL_3DMODEL::Draw_bbox() const
|
||||||
{
|
{
|
||||||
OGL_draw_bbox( m_model_bbox );
|
glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
|
||||||
|
|
||||||
|
glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
|
||||||
|
|
||||||
|
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_color ) ) );
|
||||||
|
|
||||||
|
glDrawElements( GL_LINES, bbox_idx_count, m_bbox_index_buffer_type,
|
||||||
|
reinterpret_cast<const void*>( 0 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void C_OGL_3DMODEL::Draw_bboxes() const
|
void C_OGL_3DMODEL::Draw_bboxes() const
|
||||||
{
|
{
|
||||||
for( unsigned int mesh_i = 0; mesh_i < m_nr_meshes; ++mesh_i )
|
glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
|
||||||
OGL_draw_bbox( m_meshs_bbox[mesh_i] );
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
|
||||||
|
|
||||||
|
glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
|
||||||
|
|
||||||
|
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
|
||||||
|
reinterpret_cast<const void*>( offsetof( VERTEX, m_color ) ) );
|
||||||
|
|
||||||
|
unsigned int idx_size = m_bbox_index_buffer_type == GL_UNSIGNED_SHORT
|
||||||
|
? sizeof( GLushort ) : sizeof( GLuint );
|
||||||
|
|
||||||
|
glDrawElements( GL_LINES, bbox_idx_count * m_meshes_bbox.size(), m_bbox_index_buffer_type,
|
||||||
|
reinterpret_cast<const void*>( bbox_idx_count * idx_size ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool C_OGL_3DMODEL::Have_opaque() const
|
|
||||||
{
|
|
||||||
return glIsList( m_ogl_idx_list_opaque );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool C_OGL_3DMODEL::Have_transparent() const
|
|
||||||
{
|
|
||||||
return glIsList( m_ogl_idx_list_transparent );
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
|
||||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
#ifndef _C_OGL_3DMODEL_H_
|
#ifndef _C_OGL_3DMODEL_H_
|
||||||
#define _C_OGL_3DMODEL_H_
|
#define _C_OGL_3DMODEL_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <plugins/3dapi/c3dmodel.h>
|
#include <plugins/3dapi/c3dmodel.h>
|
||||||
#include "../../common_ogl/openGL_includes.h"
|
#include "../../common_ogl/openGL_includes.h"
|
||||||
#include "../3d_render_raytracing/shapes3D/cbbox.h"
|
#include "../3d_render_raytracing/shapes3D/cbbox.h"
|
||||||
|
@ -51,22 +53,22 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Draw_opaque - render the model into the current context
|
* @brief Draw_opaque - render the model into the current context
|
||||||
*/
|
*/
|
||||||
void Draw_opaque() const;
|
void Draw_opaque() const { Draw( false ); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draw_transparent - render the model into the current context
|
* @brief Draw_transparent - render the model into the current context
|
||||||
*/
|
*/
|
||||||
void Draw_transparent() const;
|
void Draw_transparent() const { Draw( true ); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Have_opaque - return true if have opaque meshs to render
|
* @brief Have_opaque - return true if have opaque meshs to render
|
||||||
*/
|
*/
|
||||||
bool Have_opaque() const;
|
bool Have_opaque() const { return m_have_opaque_meshes; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Have_transparent - return true if have transparent meshs to render
|
* @brief Have_transparent - return true if have transparent meshs to render
|
||||||
*/
|
*/
|
||||||
bool Have_transparent() const;
|
bool Have_transparent() const { return m_have_transparent_meshes; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draw_bbox - draw main bounding box of the model
|
* @brief Draw_bbox - draw main bounding box of the model
|
||||||
|
@ -84,14 +86,76 @@ public:
|
||||||
*/
|
*/
|
||||||
const CBBOX &GetBBox() const { return m_model_bbox; }
|
const CBBOX &GetBBox() const { return m_model_bbox; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief BeginDrawMulti - set some basic render states before drawing multiple models
|
||||||
|
*/
|
||||||
|
static void BeginDrawMulti();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief EndDrawMulti - cleanup render states after drawing multiple models
|
||||||
|
*/
|
||||||
|
static void EndDrawMulti();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLuint m_ogl_idx_list_opaque; ///< display list for rendering opaque meshes
|
static const wxChar *m_logTrace;
|
||||||
GLuint m_ogl_idx_list_transparent; ///< display list for rendering transparent meshes
|
|
||||||
GLuint m_ogl_idx_list_meshes; ///< display lists for all meshes.
|
// the material mode that was used to generate the rendering data.
|
||||||
unsigned int m_nr_meshes; ///< number of meshes of this model
|
// FIXME: this can be selected at run-time and does not require re-creation
|
||||||
|
// of the whole model objects.
|
||||||
|
MATERIAL_MODE m_material_mode;
|
||||||
|
|
||||||
CBBOX m_model_bbox; ///< global bounding box for this model
|
CBBOX m_model_bbox; ///< global bounding box for this model
|
||||||
CBBOX *m_meshs_bbox; ///< individual bbox for each mesh
|
std::vector<CBBOX> m_meshes_bbox; ///< individual bbox for each mesh
|
||||||
|
|
||||||
|
// unified vertex format for mesh rendering.
|
||||||
|
struct VERTEX
|
||||||
|
{
|
||||||
|
glm::vec3 m_pos;
|
||||||
|
glm::u8vec4 m_nrm; // only 3 components used
|
||||||
|
glm::u8vec4 m_color; // regular color
|
||||||
|
glm::u8vec4 m_cad_color; // "CAD" mode rendering color
|
||||||
|
glm::vec2 m_tex_uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
// vertex buffer and index buffers that include all the individual meshes
|
||||||
|
// lumped together.
|
||||||
|
GLuint m_vertex_buffer = 0;
|
||||||
|
GLuint m_index_buffer = 0;
|
||||||
|
GLenum m_index_buffer_type = GL_INVALID_ENUM;
|
||||||
|
|
||||||
|
// internal material definition
|
||||||
|
// all meshes are grouped by material for rendering purposes.
|
||||||
|
struct MATERIAL : SMATERIAL
|
||||||
|
{
|
||||||
|
unsigned int m_render_idx_buffer_offset = 0;
|
||||||
|
unsigned int m_render_idx_count = 0;
|
||||||
|
|
||||||
|
MATERIAL( const SMATERIAL &aOther ) : SMATERIAL( aOther ) { }
|
||||||
|
bool IsTransparent() const { return m_Transparency > FLT_EPSILON; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<MATERIAL> m_materials;
|
||||||
|
|
||||||
|
// a model can consist of transparent and opaque parts. remember which
|
||||||
|
// ones are present during initial buffer and data setup. use it later
|
||||||
|
// during rendering.
|
||||||
|
bool m_have_opaque_meshes = false;
|
||||||
|
bool m_have_transparent_meshes = false;
|
||||||
|
|
||||||
|
// vertex buffer and index buffer for the bounding boxes.
|
||||||
|
// the first box is always the outer box, followed by inner boxes (one for each mesh).
|
||||||
|
static constexpr unsigned int bbox_vtx_count = 8;
|
||||||
|
static constexpr unsigned int bbox_idx_count = 24;
|
||||||
|
|
||||||
|
GLuint m_bbox_vertex_buffer = 0;
|
||||||
|
GLuint m_bbox_index_buffer = 0;
|
||||||
|
GLenum m_bbox_index_buffer_type = GL_INVALID_ENUM;
|
||||||
|
|
||||||
|
static void MakeBbox( const CBBOX &aBox, unsigned int aIdxOffset,
|
||||||
|
VERTEX *aVtxOut, GLuint *aIdxOut,
|
||||||
|
const glm::vec4 &aColor );
|
||||||
|
|
||||||
|
void Draw( bool aTransparent ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _C_OGL_3DMODEL_H_
|
#endif // _C_OGL_3DMODEL_H_
|
||||||
|
|
Loading…
Reference in New Issue