/*********************************************************************************************************************** * * Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc. * The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret * as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event * of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized * employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the * scope and manner of such use. * ***********************************************************************************************************************/ #include #include "representation_item.h" #include "../../utils/properties.h" #include "../../utils/bounding_box.h" #include "../../utils/geometry.h" #include "../../model/exchange.h" namespace he { namespace geometry { RepresentationItem::RepresentationItem(A3DRiRepresentationItem* rep_item, const A3DMiscCascadedAttributes* cascaded_attributes) : Entity() { A3D_INITIALIZE_DATA(A3DMeshData, mesh_data); // for each representation item list, we compute a mesh based on triangle only. status = A3DRiComputeMesh(rep_item, cascaded_attributes, &mesh_data, nullptr); if (status != A3D_SUCCESS) { A3DRWParamsTessellationData tess_params; A3D_INITIALIZE_DATA(A3DRWParamsTessellationData, tess_params); tess_params.m_eTessellationLevelOfDetail = kA3DTessLODMedium; A3DRiRepresentationItemComputeTessellation(rep_item, &tess_params); status = A3DRiComputeMesh(rep_item, cascaded_attributes, &mesh_data, nullptr); } } RepresentationItem::~RepresentationItem() { A3DRiComputeMesh(nullptr, nullptr, &mesh_data, nullptr); } bool RepresentationItem::is_unicolor() const { return mesh_data.m_puiStyleIndexPerFace == nullptr; } void RepresentationItem::prepare_render_buffer(std::vector & buffer_data_array) { if (is_unicolor()) { utils::geometry::BufferData buffer_data; build_one_buffer(buffer_data); buffer_data_array.push_back(buffer_data); } else { build_buffer_per_style(buffer_data_array); } } void RepresentationItem::build_one_buffer(utils::geometry::BufferData& buffer_data) const { buffer_data.vertices.reserve(mesh_data.m_uiCoordSize / 3); // For each mesh, we create model buffer, and store graphical information, and all positions // associated to it. for (A3DUns32 vertex_i = 0; vertex_i < mesh_data.m_uiCoordSize; vertex_i+=3) { utils::geometry::Vertex vertex; vertex.position = glm::vec3(mesh_data.m_pdCoords[vertex_i], mesh_data.m_pdCoords[vertex_i + 1], mesh_data.m_pdCoords[vertex_i + 2]); vertex.normal = glm::vec3(mesh_data.m_pdNormals[vertex_i], mesh_data.m_pdNormals[vertex_i + 1], mesh_data.m_pdNormals[vertex_i + 2]); buffer_data.mesh_box.add_point(vertex.position); buffer_data.vertices.push_back(vertex); } // Count the total number of indices size_t indiceCount = 0; for (A3DUns32 face_i = 0; face_i < mesh_data.m_uiFaceSize; ++face_i) { indiceCount += mesh_data.m_puiTriangleCountPerFace[face_i]; } indiceCount *= 3; // 3 indices per triangle buffer_data.indices.reserve(indiceCount); for (A3DUns32 vertex_i = 0; vertex_i < indiceCount; vertex_i++) buffer_data.indices.push_back(mesh_data.m_puiVertexIndicesPerFace[vertex_i]); buffer_data.graphics = model::exchange::convert_style(mesh_data.m_uiStyleIndex); } void RepresentationItem::build_buffer_per_style(std::vector & buffers_data) const { int idx = 0; // sort face by style, and create one buffer data per style std::map> style_face_indices; std::vector> vertex_indices_per_face(mesh_data.m_uiFaceSize); A3DUns32 vertex_index = 0; for (A3DUns32 f = 0; f < mesh_data.m_uiFaceSize; f++) { const A3DUns32 triangle_count = mesh_data.m_puiTriangleCountPerFace[f]; if (triangle_count == 0) continue; A3DUns32 face_style = mesh_data.m_puiStyleIndexPerFace[f]; style_face_indices[face_style].push_back(f); // Store vertex indices per face const A3DUns32 start_index = vertex_index; const A3DUns32 end_index = vertex_index + (triangle_count * 3); for (A3DUns32 v = start_index; v < end_index; ++v) { vertex_indices_per_face[f].push_back(mesh_data.m_puiVertexIndicesPerFace[v]); } vertex_index = end_index; } // for each mesh, we create OnpenGL model (buffer), and store graphical information, and all positions // associated to it. for (auto iter = style_face_indices.begin(); iter != style_face_indices.end(); ++iter) { utils::geometry::BufferData buffer_data; buffer_data.graphics = model::exchange::convert_style(iter->first); idx = 0; for (auto& f : iter->second) { // for each face A3DUns32 triangle_count = mesh_data.m_puiTriangleCountPerFace[f]; const std::vector& vertex_indices = vertex_indices_per_face[f]; std::vector vertices; utils::geometry::BoundingBox box; utils::geometry::Vertex vertex; for (A3DUns32 t = 0; t < triangle_count; t++) { // for each triangle for (A3DUns32 v = 0; v < 3; v++) { const uint32_t indice = vertex_indices[t * 3 + v] * 3; vertex.position = glm::vec3(mesh_data.m_pdCoords[indice], mesh_data.m_pdCoords[indice + 1], mesh_data.m_pdCoords[indice + 2]); vertex.normal = glm::vec3(mesh_data.m_pdNormals[indice], mesh_data.m_pdNormals[indice + 1], mesh_data.m_pdNormals[indice + 2]); buffer_data.mesh_box.add_point(vertex.position); buffer_data.vertices.push_back(vertex); buffer_data.indices.push_back(idx++); } } } buffers_data.push_back(buffer_data); } } } }