// 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 #include #include 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