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 );
|
||||
|
||||
m_ogl_3dmodel->BeginDrawMulti();
|
||||
|
||||
m_ogl_3dmodel->Draw_opaque();
|
||||
m_ogl_3dmodel->Draw_transparent();
|
||||
|
||||
m_ogl_3dmodel->EndDrawMulti();
|
||||
|
||||
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,
|
||||
bool aRenderTransparentOnly )
|
||||
{
|
||||
C_OGL_3DMODEL::BeginDrawMulti();
|
||||
|
||||
// Go for all 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() ) )
|
||||
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 );
|
||||
|
||||
// Get the list of model files for this model
|
||||
auto sM = module->Models().begin();
|
||||
auto eM = module->Models().end();
|
||||
|
||||
while( sM != eM )
|
||||
for (auto& sM : module->Models ())
|
||||
{
|
||||
if( !sM->m_Filename.empty() )
|
||||
if( !sM.m_Filename.empty() )
|
||||
{
|
||||
// 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
|
||||
const C_OGL_3DMODEL *modelPtr = m_3dmodel_map[ sM->m_Filename ];
|
||||
|
||||
if( modelPtr )
|
||||
if( const C_OGL_3DMODEL *modelPtr = cache_i->second )
|
||||
{
|
||||
if( ( (!aRenderTransparentOnly) && modelPtr->Have_opaque() ) ||
|
||||
( aRenderTransparentOnly && modelPtr->Have_transparent() ) )
|
||||
{
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef( sM->m_Offset.x, sM->m_Offset.y, sM->m_Offset.z );
|
||||
|
||||
glRotatef( -sM->m_Rotation.z, 0.0f, 0.0f, 1.0f );
|
||||
glRotatef( -sM->m_Rotation.y, 0.0f, 1.0f, 0.0f );
|
||||
glRotatef( -sM->m_Rotation.x, 1.0f, 0.0f, 0.0f );
|
||||
|
||||
glScalef( sM->m_Scale.x, sM->m_Scale.y, sM->m_Scale.z );
|
||||
// FIXME: don't do this over and over again unless the
|
||||
// values have changed. cache the matrix somewhere.
|
||||
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 } );
|
||||
glMultMatrixf( glm::value_ptr( mtx ) );
|
||||
|
||||
if( aRenderTransparentOnly )
|
||||
modelPtr->Draw_transparent();
|
||||
|
@ -1160,17 +1161,16 @@ void C3D_RENDER_OGL_LEGACY::render_3D_module( const MODULE* module,
|
|||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glLineWidth( 1 );
|
||||
modelPtr->Draw_bboxes();
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
|
||||
glColor4f( 0.0f, 1.0f, 0.0f, 1.0f );
|
||||
glLineWidth( 1 );
|
||||
modelPtr->Draw_bboxes();
|
||||
|
||||
glLineWidth( 4 );
|
||||
modelPtr->Draw_bbox();
|
||||
|
||||
glEnable( GL_LIGHTING );
|
||||
glDisable( GL_BLEND );
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
@ -1178,8 +1178,6 @@ void C3D_RENDER_OGL_LEGACY::render_3D_module( const MODULE* module,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
++sM;
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* 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) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
|
@ -27,357 +28,461 @@
|
|||
* @brief
|
||||
*/
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include "c_ogl_3dmodel.h"
|
||||
#include "ogl_legacy_utils.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "../3d_math.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,
|
||||
MATERIAL_MODE aMaterialMode )
|
||||
{
|
||||
m_ogl_idx_list_meshes = 0;
|
||||
m_ogl_idx_list_opaque = 0;
|
||||
m_ogl_idx_list_transparent = 0;
|
||||
m_nr_meshes = 0;
|
||||
m_meshs_bbox = NULL;
|
||||
wxLogTrace( m_logTrace, wxT( "C_OGL_3DMODEL::C_OGL_3DMODEL %u meshes %u materials" ),
|
||||
static_cast<unsigned int>( a3DModel.m_MeshesSize ),
|
||||
static_cast<unsigned int>( a3DModel.m_MaterialsSize ) );
|
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Validate a3DModel pointers
|
||||
wxASSERT( a3DModel.m_Materials != NULL );
|
||||
wxASSERT( a3DModel.m_Meshes != NULL );
|
||||
wxASSERT( a3DModel.m_Materials != nullptr );
|
||||
wxASSERT( a3DModel.m_Meshes != nullptr );
|
||||
wxASSERT( a3DModel.m_MaterialsSize > 0 );
|
||||
wxASSERT( a3DModel.m_MeshesSize > 0 );
|
||||
|
||||
if( (a3DModel.m_Materials != NULL) && (a3DModel.m_Meshes != NULL) &&
|
||||
(a3DModel.m_MaterialsSize > 0) && (a3DModel.m_MeshesSize > 0) )
|
||||
m_material_mode = aMaterialMode;
|
||||
|
||||
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
|
||||
m_ogl_idx_list_meshes = glGenLists( a3DModel.m_MeshesSize );
|
||||
|
||||
// Render each mesh of the model
|
||||
// /////////////////////////////////////////////////////////////////////
|
||||
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
||||
{
|
||||
if( glIsList( m_ogl_idx_list_meshes + mesh_i ) )
|
||||
const auto& mesh = a3DModel.m_Meshes[mesh_i];
|
||||
|
||||
// silently ignore meshes that have invalid material references
|
||||
// or invalid geometry.
|
||||
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 )
|
||||
{
|
||||
const SMESH &mesh = a3DModel.m_Meshes[mesh_i];
|
||||
m_meshes_bbox[mesh_i].Union( mesh.m_Positions[vtx_i] );
|
||||
|
||||
// Validate the mesh pointers
|
||||
wxASSERT( mesh.m_Positions != NULL );
|
||||
wxASSERT( mesh.m_FaceIdx != NULL );
|
||||
wxASSERT( mesh.m_Normals != NULL );
|
||||
auto& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
|
||||
|
||||
if( (mesh.m_Positions != NULL) &&
|
||||
(mesh.m_Normals != NULL) &&
|
||||
(mesh.m_FaceIdx != NULL) &&
|
||||
(mesh.m_FaceIdxSize > 0) && (mesh.m_VertexSize > 0) )
|
||||
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 )
|
||||
{
|
||||
SFVEC4F *pColorRGBA = NULL;
|
||||
avg_color = ( avg_color + mesh.m_Color[vtx_i] ) * 0.5f;
|
||||
|
||||
// Create the bbox for this mesh
|
||||
// /////////////////////////////////////////////////////////
|
||||
m_meshs_bbox[mesh_i].Reset();
|
||||
vtx_out.m_color =
|
||||
glm::clamp( glm::vec4( mesh.m_Color[vtx_i],
|
||||
1 - material.m_Transparency ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
|
||||
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 );
|
||||
vtx_out.m_cad_color =
|
||||
glm::clamp( glm::vec4( MaterialDiffuseToColorCAD( mesh.m_Color[vtx_i] ),
|
||||
1 ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
}
|
||||
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];
|
||||
// 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.
|
||||
|
||||
// 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 );
|
||||
}
|
||||
// if there are no vertex colors, use material color instead.
|
||||
vtx_out.m_color =
|
||||
glm::clamp( glm::vec4( material.m_Diffuse,
|
||||
1 - material.m_Transparency ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
|
||||
// Load an RGBA array
|
||||
glColorPointer( 4, GL_FLOAT, 0, pColorRGBA );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
vtx_out.m_cad_color =
|
||||
glm::clamp( glm::vec4 ( MaterialDiffuseToColorCAD( material.m_Diffuse ),
|
||||
1 ) * 255.0f,
|
||||
0.0f, 255.0f );
|
||||
}
|
||||
}
|
||||
|
||||
if( mesh.m_Texcoords != NULL )
|
||||
if( m_meshes_bbox[mesh_i].IsInitialized() )
|
||||
{
|
||||
// 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] );
|
||||
}
|
||||
|
||||
|
||||
// append indices of this mesh to the mesh group.
|
||||
const unsigned int idx_offset = mesh_group.m_indices.size();
|
||||
unsigned int use_idx_count = mesh.m_FaceIdxSize;
|
||||
|
||||
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()
|
||||
{
|
||||
glEnableClientState( GL_VERTEX_ARRAY );
|
||||
glEnableClientState( GL_NORMAL_ARRAY );
|
||||
glEnableClientState( GL_COLOR_ARRAY );
|
||||
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
|
||||
|
||||
void C_OGL_3DMODEL::EndDrawMulti()
|
||||
{
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
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 );
|
||||
}
|
||||
|
||||
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
|
||||
|
||||
void C_OGL_3DMODEL::Draw( bool aTransparent ) const
|
||||
{
|
||||
switch( aMaterialMode )
|
||||
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( a3DModel.m_Materials[mesh.m_MaterialIdx] );
|
||||
OGL_SetMaterial( mat );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
||||
OGL_SetDiffuseOnlyMaterial(
|
||||
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse );
|
||||
OGL_SetDiffuseOnlyMaterial( mat.m_Diffuse );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::CAD_MODE:
|
||||
OGL_SetDiffuseOnlyMaterial(
|
||||
MaterialDiffuseToColorCAD(
|
||||
a3DModel.m_Materials[mesh.m_MaterialIdx].m_Diffuse ) );
|
||||
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 ) );
|
||||
}
|
||||
|
||||
// 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;
|
||||
// EndDrawMulti();
|
||||
}
|
||||
}
|
||||
}// for each mesh
|
||||
|
||||
|
||||
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];
|
||||
|
||||
if( mesh.m_MaterialIdx < a3DModel.m_MaterialsSize )
|
||||
{
|
||||
const SMATERIAL &material = a3DModel.m_Materials[mesh.m_MaterialIdx];
|
||||
|
||||
if( material.m_Transparency == 0.0f )
|
||||
{
|
||||
have_opaque_meshes = true; // Flag that we have at least one opaque mesh
|
||||
glCallList( m_ogl_idx_list_meshes + mesh_i );
|
||||
}
|
||||
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
|
||||
{
|
||||
m_ogl_idx_list_opaque = 0;
|
||||
}
|
||||
|
||||
// Create the main bbox
|
||||
// /////////////////////////////////////////////////////////////////////
|
||||
m_model_bbox.Reset();
|
||||
|
||||
for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
|
||||
m_model_bbox.Union( m_meshs_bbox[mesh_i] );
|
||||
|
||||
glFlush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C_OGL_3DMODEL::Draw_opaque() const
|
||||
{
|
||||
if( glIsList( m_ogl_idx_list_opaque ) )
|
||||
glCallList( m_ogl_idx_list_opaque );
|
||||
}
|
||||
|
||||
|
||||
void C_OGL_3DMODEL::Draw_transparent() const
|
||||
{
|
||||
if( glIsList( m_ogl_idx_list_transparent ) )
|
||||
glCallList( m_ogl_idx_list_transparent );
|
||||
}
|
||||
|
||||
|
||||
C_OGL_3DMODEL::~C_OGL_3DMODEL()
|
||||
{
|
||||
if( glIsList( m_ogl_idx_list_opaque ) )
|
||||
glDeleteLists( m_ogl_idx_list_opaque, 1 );
|
||||
|
||||
if( glIsList( m_ogl_idx_list_transparent ) )
|
||||
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;
|
||||
glDeleteBuffers( 1, &m_vertex_buffer );
|
||||
glDeleteBuffers( 1, &m_index_buffer );
|
||||
glDeleteBuffers( 1, &m_bbox_vertex_buffer );
|
||||
glDeleteBuffers( 1, &m_bbox_index_buffer );
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
for( unsigned int mesh_i = 0; mesh_i < m_nr_meshes; ++mesh_i )
|
||||
OGL_draw_bbox( m_meshs_bbox[mesh_i] );
|
||||
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 ) ) );
|
||||
|
||||
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.
|
||||
*
|
||||
* Copyright (C) 2020 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
|
@ -30,6 +31,7 @@
|
|||
#ifndef _C_OGL_3DMODEL_H_
|
||||
#define _C_OGL_3DMODEL_H_
|
||||
|
||||
#include <vector>
|
||||
#include <plugins/3dapi/c3dmodel.h>
|
||||
#include "../../common_ogl/openGL_includes.h"
|
||||
#include "../3d_render_raytracing/shapes3D/cbbox.h"
|
||||
|
@ -51,22 +53,22 @@ public:
|
|||
/**
|
||||
* @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
|
||||
*/
|
||||
void Draw_transparent() const;
|
||||
void Draw_transparent() const { Draw( true ); }
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
bool Have_transparent() const;
|
||||
bool Have_transparent() const { return m_have_transparent_meshes; }
|
||||
|
||||
/**
|
||||
* @brief Draw_bbox - draw main bounding box of the model
|
||||
|
@ -84,14 +86,76 @@ public:
|
|||
*/
|
||||
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:
|
||||
GLuint m_ogl_idx_list_opaque; ///< display list for rendering opaque meshes
|
||||
GLuint m_ogl_idx_list_transparent; ///< display list for rendering transparent meshes
|
||||
GLuint m_ogl_idx_list_meshes; ///< display lists for all meshes.
|
||||
unsigned int m_nr_meshes; ///< number of meshes of this model
|
||||
static const wxChar *m_logTrace;
|
||||
|
||||
// the material mode that was used to generate the rendering data.
|
||||
// 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_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_
|
||||
|
|
Loading…
Reference in New Issue