34#include "../common_ogl/ogl_utils.h"
35#include "../3d_math.h"
52 GLuint* aIdxOut,
const glm::vec4& aColor )
64 for(
unsigned int i = 0; i < 8; ++i )
65 aVtxOut[i].m_color = aVtxOut[i].m_cad_color = glm::clamp( aColor * 255.0f, 0.0f, 255.0f );
67 #define bbox_line( vtx_a, vtx_b )\
68 do { *aIdxOut++ = vtx_a + aIdxOffset; \
69 *aIdxOut++ = vtx_b + aIdxOffset; } while( 0 )
92 wxLogTrace(
m_logTrace, wxT(
"MODEL_3D::MODEL_3D %u meshes %u materials" ),
96 auto start_time = std::chrono::high_resolution_clock::now();
106 glGenBuffers( 6, buffers );
114 wxASSERT( a3DModel.
m_Meshes !=
nullptr );
144 std::vector<VERTEX> m_vertices;
145 std::vector<GLuint> m_indices;
148 std::vector<MESH_GROUP> mesh_groups(
m_materials.size() );
150 for(
unsigned int mesh_i = 0; mesh_i < a3DModel.
m_MeshesSize; ++mesh_i )
173 const unsigned int vtx_offset = mesh_group.m_vertices.size();
174 mesh_group.m_vertices.resize( mesh_group.m_vertices.size() + mesh.
m_VertexSize );
178 glm::vec3 avg_color = material.
m_Diffuse;
182 for(
unsigned int vtx_i = 0; vtx_i < mesh.
m_VertexSize; ++vtx_i )
186 VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
189 vtx_out.
m_nrm = glm::clamp( glm::vec4( mesh.
m_Normals[vtx_i], 1.0f ) * 127.0f,
197 avg_color = ( avg_color + mesh.
m_Color[vtx_i] ) * 0.5f;
200 glm::clamp( glm::vec4( mesh.
m_Color[vtx_i],
206 1 ) * 255.0f, 0.0f, 255.0f );
216 glm::clamp( glm::vec4( material.
m_Diffuse,
233 { avg_color, 1.0f } );
244 const unsigned int idx_offset = mesh_group.m_indices.size();
247 if( use_idx_count % 3 != 0 )
249 wxLogTrace(
m_logTrace, wxT(
" index count %u not multiple of 3, truncating" ),
250 static_cast<unsigned int>( use_idx_count ) );
251 use_idx_count = ( use_idx_count / 3 ) * 3;
254 mesh_group.m_indices.resize( mesh_group.m_indices.size() + use_idx_count );
256 for(
unsigned int idx_i = 0; idx_i < use_idx_count; ++idx_i )
260 wxLogTrace(
m_logTrace, wxT(
" index %u out of range (%u)" ),
261 static_cast<unsigned int>( mesh.
m_FaceIdx[idx_i] ),
267 mesh_group.m_indices[idx_offset + idx_i] = mesh.
m_FaceIdx[idx_i] + vtx_offset;
274 { 0.0f, 1.0f, 0.0f, 1.0f } );
279 glBufferData( GL_ARRAY_BUFFER,
sizeof(
VERTEX ) * bbox_tmp_vertices.size(),
280 bbox_tmp_vertices.data(), GL_STATIC_DRAW );
284 if( bbox_tmp_vertices.size() <= std::numeric_limits<GLushort>::max() )
288 auto u16buf = std::make_unique<GLushort[]>( bbox_tmp_indices.size() );
290 for(
unsigned int i = 0; i < bbox_tmp_indices.size(); ++i )
291 u16buf[i] =
static_cast<GLushort
>( bbox_tmp_indices[i] );
293 glBufferData( GL_ELEMENT_ARRAY_BUFFER,
sizeof( GLushort ) * bbox_tmp_indices.size(),
294 u16buf.get(), GL_STATIC_DRAW );
299 glBufferData( GL_ELEMENT_ARRAY_BUFFER,
sizeof( GLuint ) * bbox_tmp_indices.size(),
300 bbox_tmp_indices.data(), GL_STATIC_DRAW );
304 unsigned int total_vertex_count = 0;
305 unsigned int total_index_count = 0;
307 for(
const MESH_GROUP& mg : mesh_groups )
309 total_vertex_count += mg.m_vertices.size();
310 total_index_count += mg.m_indices.size();
313 wxLogTrace(
m_logTrace, wxT(
" total %u vertices, %u indices" ),
314 total_vertex_count, total_index_count );
317 glBufferData( GL_ARRAY_BUFFER,
sizeof(
VERTEX ) * total_vertex_count,
318 nullptr, GL_STATIC_DRAW );
320 unsigned int idx_size = 0;
322 if( total_vertex_count <= std::numeric_limits<GLushort>::max() )
325 idx_size =
sizeof( GLushort );
330 idx_size =
sizeof( GLuint );
335 auto tmp_idx = std::make_unique<GLuint[]>( ( idx_size * total_index_count + 8 ) /
sizeof( GLuint ) );
337 unsigned int prev_vtx_count = 0;
338 unsigned int idx_offset = 0;
339 unsigned int vtx_offset = 0;
341 for(
unsigned int mg_i = 0; mg_i < mesh_groups.size (); ++mg_i )
343 MESH_GROUP& mg = mesh_groups[mg_i];
345 uintptr_t tmp_idx_ptr =
reinterpret_cast<uintptr_t
>( tmp_idx.get() );
349 GLushort* idx_out =
reinterpret_cast<GLushort*
>( tmp_idx_ptr + idx_offset );
351 for( GLuint idx : mg.m_indices )
352 *idx_out++ =
static_cast<GLushort
>( idx + prev_vtx_count );
356 GLuint* idx_out =
reinterpret_cast<GLuint*
>( tmp_idx_ptr + idx_offset );
358 for( GLuint idx : mg.m_indices )
359 *idx_out++ =
static_cast<GLuint
>( idx + prev_vtx_count );
362 glBufferSubData( GL_ARRAY_BUFFER, vtx_offset, mg.m_vertices.size() *
sizeof(
VERTEX ),
363 mg.m_vertices.data() );
368 prev_vtx_count += mg.m_vertices.size();
369 idx_offset += mg.m_indices.size() * idx_size;
370 vtx_offset += mg.m_vertices.size() *
sizeof(
VERTEX );
374 glBufferData( GL_ELEMENT_ARRAY_BUFFER, idx_size * total_index_count, tmp_idx.get(),
377 glBindBuffer( GL_ARRAY_BUFFER, 0 );
378 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
380 auto end_time = std::chrono::high_resolution_clock::now();
382 wxLogTrace(
m_logTrace, wxT(
" loaded in %u ms\n" ),
383 (
unsigned int)std::chrono::duration_cast<std::chrono::milliseconds> (
384 end_time - start_time).count() );
390 glEnableClientState( GL_VERTEX_ARRAY );
391 glEnableClientState( GL_NORMAL_ARRAY );
393 if( aUseColorInformation )
395 glEnableClientState( GL_COLOR_ARRAY );
396 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
397 glEnable( GL_COLOR_MATERIAL );
400 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
406 glDisable( GL_COLOR_MATERIAL );
407 glDisableClientState( GL_VERTEX_ARRAY );
408 glDisableClientState( GL_NORMAL_ARRAY );
409 glDisableClientState( GL_COLOR_ARRAY );
410 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
412 glBindBuffer( GL_ARRAY_BUFFER, 0 );
413 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
417void MODEL_3D::Draw(
bool aTransparent,
float aOpacity,
bool aUseSelectedMaterial,
418 const SFVEC3F& aSelectionColor,
419 const glm::mat4 *aModelWorldMatrix,
420 const SFVEC3F *aCameraWorldPos )
const
422 if( aOpacity <= FLT_EPSILON )
426 throw std::runtime_error(
"The OpenGL context no longer exists: unable to draw" );
431 glVertexPointer( 3, GL_FLOAT,
sizeof(
VERTEX ),
432 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_pos ) ) );
434 glNormalPointer( GL_BYTE,
sizeof(
VERTEX ),
435 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_nrm ) ) );
437 glColorPointer( 4, GL_UNSIGNED_BYTE,
sizeof(
VERTEX ),
438 reinterpret_cast<const void*
>(
m_materialMode == MATERIAL_MODE::CAD_MODE
439 ? offsetof(
VERTEX, m_cad_color )
440 : offsetof(
VERTEX, m_color ) ) );
442 glTexCoordPointer( 2, GL_FLOAT,
sizeof(
VERTEX ),
443 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_tex_uv ) ) );
447 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (
const float*)¶m.x );
449 std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
453 if( aModelWorldMatrix && aCameraWorldPos )
457 std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
462 if( mat.m_render_idx_count == 0 )
467 if( ( mat.IsTransparent() != aTransparent )
468 && ( aOpacity >= 1.0f )
474 const BBOX_3D& bBox = mat.m_bbox;
476 const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f );
478 const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld );
480 materialsSorted.emplace_back( &mat, distanceToCamera );
484 std::sort( materialsSorted.begin(), materialsSorted.end(),
485 [&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
486 std::pair<const MODEL_3D::MATERIAL*, float>& b )
488 bool aInsideB = a.first->m_bbox.Inside( b.first->m_bbox );
489 bool bInsideA = b.first->m_bbox.Inside( a.first->m_bbox );
492 if( aInsideB != bInsideA )
495 if( a.second != b.second )
496 return a.second > b.second;
498 return a.first > b.first;
501 for(
const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
503 materialsToRender.push_back( mat.first );
513 if( mat.m_render_idx_count == 0 )
518 if( ( mat.IsTransparent() != aTransparent )
519 && ( aOpacity >= 1.0f )
525 materialsToRender.push_back( &mat );
533 case MATERIAL_MODE::NORMAL:
534 OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
537 case MATERIAL_MODE::DIFFUSE_ONLY:
541 case MATERIAL_MODE::CAD_MODE:
543 aUseSelectedMaterial, aSelectionColor );
551 reinterpret_cast<const void*
>(
552 static_cast<uintptr_t
>( mat->m_render_idx_buffer_offset ) ) );
559 if( glDeleteBuffers )
572 throw std::runtime_error(
"The OpenGL context no longer exists: unable to draw bbox" );
577 glVertexPointer( 3, GL_FLOAT,
sizeof(
VERTEX ),
578 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_pos ) ) );
580 glColorPointer( 4, GL_UNSIGNED_BYTE,
sizeof(
VERTEX ),
581 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_color ) ) );
584 reinterpret_cast<const void*
>( 0 ) );
591 throw std::runtime_error(
"The OpenGL context no longer exists: unable to draw bboxes" );
596 glVertexPointer( 3, GL_FLOAT,
sizeof(
VERTEX ),
597 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_pos ) ) );
599 glColorPointer( 4, GL_UNSIGNED_BYTE,
sizeof(
VERTEX ),
600 reinterpret_cast<const void*
>( offsetof(
VERTEX, m_color ) ) );
606 reinterpret_cast<const void*
>(
MATERIAL_MODE
Render 3d model shape materials mode.
SFVEC3F MaterialDiffuseToColorCAD(const SFVEC3F &aDiffuseColor)
#define bbox_line(vtx_a, vtx_b)
void DrawBbox() const
Draw main bounding box of the model.
bool m_have_opaque_meshes
static void EndDrawMulti()
Cleanup render states after drawing multiple models.
GLenum m_index_buffer_type
MODEL_3D(const S3DMODEL &a3DModel, MATERIAL_MODE aMaterialMode)
Load a 3D model.
std::vector< MATERIAL > m_materials
static void MakeBbox(const BBOX_3D &aBox, unsigned int aIdxOffset, VERTEX *aVtxOut, GLuint *aIdxOut, const glm::vec4 &aColor)
void Draw(bool aTransparent, float aOpacity, bool aUseSelectedMaterial, const SFVEC3F &aSelectionColor, const glm::mat4 *aModelWorldMatrix, const SFVEC3F *aCameraWorldPos) const
Render the model into the current context.
static void BeginDrawMulti(bool aUseColorInformation)
Set some basic render states before drawing multiple models.
GLuint m_bbox_index_buffer
static constexpr unsigned int bbox_idx_count
MATERIAL_MODE m_materialMode
void DrawBboxes() const
Draw individual bounding boxes of each mesh.
static const wxChar * m_logTrace
bool m_have_transparent_meshes
std::vector< BBOX_3D > m_meshes_bbox
individual bbox for each mesh
GLenum m_bbox_index_buffer_type
static constexpr unsigned int bbox_vtx_count
BBOX_3D m_model_bbox
global bounding box for this model
GLuint m_bbox_vertex_buffer
void OglSetDiffuseMaterial(const SFVEC3F &aMaterialDiffuse, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Sets only the diffuse color and keep other parameters with default values.
void OglSetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Set OpenGL materials.
Manage a bounding box defined by two SFVEC3F min max points.
void Union(const SFVEC3F &aPoint)
Recalculate the bounding box adding a point.
SFVEC3F GetCenter() const
Return the center point of the bounding box.
const SFVEC3F & Min() const
Return the minimum vertex pointer.
const SFVEC3F & Max() const
Return the maximum vertex pointer.
bool IsInitialized() const
Check if this bounding box is already initialized.
bool IsTransparent() const
unsigned int m_render_idx_count
BBOX_3D m_bbox
bounding box for this material group, used for transparent material ordering
unsigned int m_render_idx_buffer_offset
Store the a model based on meshes and materials.
SMATERIAL * m_Materials
The materials list of this model.
unsigned int m_MeshesSize
Number of meshes in the array.
SMESH * m_Meshes
The meshes list of this model.
unsigned int m_MaterialsSize
Number of materials in the material array.
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Per-vertex normal/color/texcoors structure.
unsigned int * m_FaceIdx
Triangle Face Indexes.
SFVEC3F * m_Normals
Vertex normals array.
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
unsigned int m_VertexSize
Number of vertex in the arrays.
SFVEC2F * m_Texcoords
Vertex texture coordinates array, can be NULL.
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
SFVEC3F * m_Color
Vertex color array, can be NULL.
SFVEC3F * m_Positions
Vertex position array.