Files
primitives_gallery/demos_mesh.cpp
T
2026-05-11 16:28:44 +02:00

109 lines
3.2 KiB
C++

// Demo del primitivo viz/mesh_viewer.
// Genera un cubo procedural in-line, lo sube al GPU, y permite cargar un
// .obj desde un path ingresado en un text input.
#include "demos.h"
#include "demo.h"
#include "viz/mesh_viewer.h"
#include "gfx/mesh_obj_load.h"
#include "gfx/mesh_gpu.h"
#include "core/orbit_camera.h"
#include <imgui.h>
#include <cstring>
#include <string>
namespace gallery {
namespace {
const char* kCubeObj =
"v -1 -1 -1\nv 1 -1 -1\nv 1 1 -1\nv -1 1 -1\n"
"v -1 -1 1\nv 1 -1 1\nv 1 1 1\nv -1 1 1\n"
"f 4 3 2 1\n" // back (-Z) — winding for outward normal
"f 5 6 7 8\n" // front (+Z)
"f 1 2 6 5\n" // bottom (-Y)
"f 8 7 3 4\n" // top (+Y)
"f 5 8 4 1\n" // left (-X)
"f 2 3 7 6\n"; // right (+X)
struct State {
fn::gfx::MeshGpu mesh{};
fn::core::OrbitCamera cam{};
char path[512] = "";
std::string status;
bool wireframe = false;
bool initialized = false;
};
State& state() {
static State s;
return s;
}
void load_cube() {
auto& s = state();
if (s.mesh.ok()) fn::gfx::mesh_gpu_destroy(s.mesh);
auto cpu = fn::gfx::mesh_obj_parse(kCubeObj, std::strlen(kCubeObj));
s.mesh = fn::gfx::mesh_gpu_upload(cpu);
s.status = s.mesh.ok()
? ("loaded cube: " + std::to_string(s.mesh.index_count / 3) + " tris")
: "cube upload failed";
}
void load_from_path() {
auto& s = state();
if (!s.path[0]) { s.status = "path is empty"; return; }
auto cpu = fn::gfx::mesh_obj_load(s.path);
if (cpu.positions.empty()) { s.status = "parse/read failed"; return; }
if (s.mesh.ok()) fn::gfx::mesh_gpu_destroy(s.mesh);
s.mesh = fn::gfx::mesh_gpu_upload(cpu);
s.status = s.mesh.ok()
? ("loaded: " + std::to_string(s.mesh.index_count / 3) + " tris")
: "upload failed";
}
} // namespace
void demo_mesh_viewer() {
demo_header("mesh_viewer", "v1.0.0",
"Visualizador 3D para inspeccion de geometria. Composicion de "
"mesh_obj_load (parser .obj puro) + mesh_gpu (upload VAO/VBO/EBO) + "
"orbit_camera (drag/wheel) + mesh_viewer (FBO + ImGui::Image + Lambert).");
auto& s = state();
if (!s.initialized) {
load_cube();
s.initialized = true;
}
// Controls row.
if (ImGui::Button("Reload cube")) load_cube();
ImGui::SameLine();
ImGui::Checkbox("Wireframe", &s.wireframe);
ImGui::SameLine();
ImGui::TextDisabled("|");
ImGui::SameLine();
ImGui::SetNextItemWidth(360);
ImGui::InputTextWithHint("##obj_path", "absolute path to .obj", s.path, sizeof(s.path));
ImGui::SameLine();
if (ImGui::Button("Load .obj")) load_from_path();
ImGui::TextDisabled("status: %s | tris: %d | drag to orbit, wheel to zoom",
s.status.c_str(),
s.mesh.ok() ? s.mesh.index_count / 3 : 0);
ImGui::Separator();
fn::viz::MeshViewerConfig cfg{};
cfg.mesh = &s.mesh;
cfg.cam = &s.cam;
cfg.size = ImVec2(-1.0f, 480.0f);
cfg.color = IM_COL32(160, 200, 255, 255);
cfg.wireframe = s.wireframe;
fn::viz::mesh_viewer("##gallery_mesh_viewer", cfg);
}
} // namespace gallery