This commit is contained in:
ninja
2025-12-15 23:22:33 +08:00
parent 019570564b
commit 8782765fbc
809 changed files with 118753 additions and 18289 deletions

View File

@@ -0,0 +1,273 @@
/***********************************************************************************************************************
*
* 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.
*
***********************************************************************************************************************/
#define INITIALIZE_A3D_API
#include <A3DSDKIncludes.h>
#include <hoops_license.h>
#include "../common.hpp"
#include <iostream>
#include <map>
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "application/application.h"
#include "application/camera.h"
#include "application/render/mesh.h"
#include "application/render/shader.h"
#include "application/render/vao.h"
#include "model/exchange.h"
#include "utils/properties.h"
#include "utils/bounding_box.h"
#include "utils/geometry.h"
static auto const exchange_bin_dir = _T(HOOPS_BINARY_DIRECTORY);
/*! Check if the file is valid.
* \param [in] file_path The path to the model file.
* \return true if the file is valid, else false. */
bool is_file_valid(const std::string& file_path, bool read = true) {
if (FILE* file = fopen(file_path.c_str(), read ? "r" : "w")) {
fclose(file);
return true;
}
else {
return false;
}
}
/*! Manage the input command line arguments.
* If no model file provided, open the default one (_micro engine.prc).
* If `--dump_model_tree` option used, dump the model tree.
* Finally create the resulting tree dump in the given output file.
* \param argc The number of arguments.
* \param argv The argument values.
* \return the file to open and the xml file (tree dump) to create. */
std::pair<std::string, std::string> manage_input_arguments(int argc, char** argv) {
std::string filename = std::string(SAMPLES_DATA_DIRECTORY) + "/prc/_micro engine.prc";
std::string xmlfile;
if (argc < 2) {
std::cout << "Using file: " << filename << std::endl;
}
else {
bool dump_tree = false;
for (auto i = 1; i < argc; ++i) {
if(strcmp(argv[i], "--dump_model_tree") == 0) {
dump_tree = true;
continue;
}
if (!is_file_valid(argv[i], !dump_tree)) {
std::cout << "Invalid file provided. ";
dump_tree = false;
}
else {
if (dump_tree)
{
xmlfile = argv[i];
dump_tree = false;
}
else
{
filename = argv[i];
std::cout << "Valid file provided. ";
}
}
}
}
std::cout << "Using file: " << filename << std::endl;
return { filename, xmlfile };
}
int main(int argc, char** argv)
{
//--------------------------------------------------------------------------
// Command line arguments
//--------------------------------------------------------------------------
// CAD file can be configured as a parameter,
// if none is provided or the one provided does not exist,
// we go back to the Micro Engine PRC file available in the package.
// `--dump_model_tree` option and the output xml file are optional
if (argc > 4)
{
std::cout << "Usage:" << std::endl << argv[0] << " [input CAD file] --dump_model_tree [output XML file]" << std::endl;
return -1;
}
auto inputs = manage_input_arguments(argc, argv);
std::string input_file = inputs.first;
std::string model_tree_file = inputs.second;
//--------------------------------------------------------------------------
// Initialize HOOPS EXCHANGE
//--------------------------------------------------------------------------
A3DSDKHOOPSExchangeLoader loader(exchange_bin_dir, HOOPS_LICENSE);
CHECK_RET(loader.m_eSDKStatus);
//--------------------------------------------------------------------------
// Initialize OpenGL window
//--------------------------------------------------------------------------
Application application;
std::string displayTitle = "TS3D Mesh Viewer : ";
displayTitle.append(input_file);
application.launch(utils::properties::screen_width, utils::properties::screen_height, displayTitle);
application.display();
//--------------------------------------------------------------------------
// Load the input file
//--------------------------------------------------------------------------
A3DAsmModelFile* model_file = nullptr;
auto const load_status = model::exchange::load_model(input_file.c_str(), model_file);
if (A3D_SUCCESS != load_status && A3D_LOAD_MISSING_COMPONENTS != load_status)
{
std::cout << "input_file = " << input_file << std::endl;
std::cout << "ERROR::MODELFILE::FILE_NOT_SUCCESSFULLY_READ: " << load_status << std::endl;
return -1;
}
std::cout << input_file << " loaded \n";
//--------------------------------------------------------------------------
// Dump Tree if asked
//--------------------------------------------------------------------------
if (!model_tree_file.empty())
model::exchange::tree::print(model_file, input_file, model_tree_file);
//--------------------------------------------------------------------------
// Retrieve meshes from the model
//--------------------------------------------------------------------------
// Collect the leaves of the model: the parts with their associated graphical contexts (A3DMiscCascadedAttributes) and transformations
std::vector<he::structure::Part> model_leaves;
model::exchange::collect_leaves(model_file, model_leaves);
// transfer mesh data
std::vector<Mesh> meshs;
std::vector<Mesh> transparent_meshs;
utils::geometry::BoundingBox bounding_box;
for (const auto& leaf : model_leaves)
{
// For each leaf, retrieve the representation items that contain the geometry (brep and polybrep only)
std::vector<A3DRiRepresentationItem*> ri_list;
leaf.ri_list(ri_list);
for (const auto& context : leaf.get_contexts())
{
// Process the different contexts of the leaf (same geometry, with different graphic style and transformation)
const auto& graphical_context_data = std::get<1>(context);
if (graphical_context_data.m_bShow == A3D_FALSE || graphical_context_data.m_bRemoved == A3D_TRUE)
continue;
const auto& graphical_context = std::get<0>(context);
const auto& transformations = std::get<2>(context);
for (const auto ri : ri_list)
{
// For each representation item containing the geometry in the leaf,
// fill one buffer if the ri is unicolor,
// or multiple buffers, in case it contains multiple graphic styles (color, material, texture).
// These buffers contain the vertices, the indices, the bounding box and the graphic style (color, material, texture).
std::vector<utils::geometry::BufferData> buffer_data_array = model::exchange::geometry::prepare_render_buffer(ri, graphical_context);
if (buffer_data_array.empty())
continue;
for (const auto& buffer_data : buffer_data_array)
{
// Add the bounding box for the camera
bounding_box.add_boxes(buffer_data.mesh_box, transformations);
// Add the computed information in the list of meshs
utils::properties::style::Graphics graphics = buffer_data.graphics;
auto& container = graphics.has_transparency() ? transparent_meshs : meshs;
for (const auto& placement : transformations)
{
container.emplace_back(buffer_data, placement, graphics);
}
}
}
}
}
if (meshs.empty())
{
std::cout << "ERROR::MODELFILE::NO_MESH_FOUND: " << load_status << std::endl;
return 1;
}
//--------------------------------------------------------------------------
// Sort meshes
//--------------------------------------------------------------------------
Mesh::sort_by_style(meshs);
//--------------------------------------------------------------------------
// Camera and shader setting
//--------------------------------------------------------------------------
application.compute_camera(bounding_box);
Shader shader_program("default.vert", "default.frag");
//--------------------------------------------------------------------------
// Drawing loop
//--------------------------------------------------------------------------
bool first_style = true;
while (!application.should_close())
{
glm::vec3 translation = (application.camera.up + application.camera.right - application.camera.front) * (application.camera.max_bbx_length * 0.5f);
glm::vec3 light_pos = application.camera.position + translation;
shader_program.add_light_properties(light_pos);
shader_program.update_projection_matrix(application.compute_projection_matrix());
shader_program.update_view_matrix(application.compute_view_matrix());
shader_program.set_vec3("view_position", application.camera.position);
application.clear();
first_style = true;
application.set_blending(false);
for (auto& model : meshs)
{
shader_program.update_mesh_style(model.style, first_style);
shader_program.update_model_matrix(model.placement);
model.draw();
}
if (transparent_meshs.size())
{
std::map<float, Mesh> sorted;
application.set_blending(true);
for (const auto& model : transparent_meshs)
{
float d1 = glm::length(application.camera.position - model.box.min);
float d2 = glm::length(application.camera.position - model.box.max);
sorted[d1 < d2 ? d1 : d2] = model;
}
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it)
{
shader_program.update_mesh_style(it->second.style, first_style);
shader_program.update_model_matrix(it->second.placement);
it->second.draw();
}
}
application.display();
}
return 0;
}