1fa82447c2
Genera cubo procedural in-line (mesh_obj_parse de string), permite cargar .obj desde un text input absoluto. Botones: Reload cube, Wireframe toggle, Load .obj. Status line con tris count y instrucciones (drag to orbit, wheel to zoom). issue 0029
109 lines
3.2 KiB
C++
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
|