chore: auto-commit (43 archivos)

- .mcp.json
- bash/functions/infra/write_mcp_jupyter_config.md
- bash/functions/infra/write_mcp_jupyter_config.sh
- cpp/CMakeLists.txt
- cpp/apps/chart_demo
- cpp/apps/shaders_lab
- cpp/functions/gfx/gl_framebuffer.cpp
- cpp/functions/gfx/gl_framebuffer.h
- cpp/functions/gfx/gl_framebuffer.md
- cpp/functions/gfx/mesh_gpu.md
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 17:28:47 +02:00
parent a2efdcf003
commit fd5787c55f
44 changed files with 3924 additions and 64 deletions
+82
View File
@@ -0,0 +1,82 @@
---
group: mesh-3d
description: "Carga, parse y upload a GPU de meshes 3D (OBJ, GLB/glTF 2.0). Flujo CPU→GPU para apps ImGui."
---
# mesh-3d — Capability Group
Cluster de funciones para cargar geometria 3D desde disco o memoria (CPU) y subirla a GPU con OpenGL. El flujo canonico es: **loader → `fn::gfx::Mesh` → `mesh_gpu_upload`**.
## Funciones
| ID | Firma corta | Que hace |
|---|---|---|
| `gltf_load_mesh_cpp_gfx` | `Mesh gltf_load_mesh_from_file(path)` | Carga primer mesh de un GLB 2.0. Genera normales si faltan. |
| `mesh_obj_load_cpp_gfx` | `Mesh mesh_obj_load(path); Mesh mesh_obj_parse(buf, len)` | Carga/parsea Wavefront .obj. Genera normales por face si faltan. |
| `mesh_gpu_cpp_gfx` | `MeshGpu mesh_gpu_upload(mesh); void mesh_gpu_destroy(gpu)` | Sube `fn::gfx::Mesh` CPU a VAO+VBO+EBO OpenGL. |
## Struct compartido
```cpp
// cpp/functions/gfx/mesh_obj_load.h
namespace fn::gfx {
struct Mesh {
std::vector<float> positions; // xyz stride=3
std::vector<float> normals; // xyz stride=3, mismo length que positions
std::vector<uint32_t> indices; // tri-list, multiplo de 3
};
}
```
## Ejemplo canonico end-to-end
```cpp
#include "gfx/gltf_load_mesh.h" // gltf_load_mesh_from_file
#include "gfx/mesh_obj_load.h" // Mesh (struct)
#include "gfx/mesh_gpu.h" // mesh_gpu_upload, mesh_gpu_destroy
// -- Cargar desde GLB (ej. output de TripoSR/trimesh) --
auto cpu = fn::gfx::gltf_load_mesh_from_file("model.glb");
if (cpu.positions.empty()) {
fprintf(stderr, "load failed: %s\n", fn::gfx::gltf_load_last_error());
return;
}
// -- Alternativamente desde OBJ --
// auto cpu = fn::gfx::mesh_obj_load("model.obj");
// -- Subir a GPU (requiere contexto GL activo) --
auto gpu = fn::gfx::mesh_gpu_upload(cpu);
if (!gpu.ok()) return;
// -- Render --
glUseProgram(prog);
glBindVertexArray(gpu.vao);
glDrawElements(GL_TRIANGLES, gpu.index_count, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// -- Cleanup --
fn::gfx::mesh_gpu_destroy(gpu);
```
## Shader esperado (layout)
```glsl
#version 330 core
layout(location = 0) in vec3 a_pos;
layout(location = 1) in vec3 a_normal;
```
## Fronteras
- Sin texturas/UV — mesh viewer usa color uniforme o shading por normal.
- Sin animaciones ni skinning.
- `gltf_load_mesh`: solo GLB binario (no .gltf+.bin separado, no data-URI base64). Solo primer mesh/primitive.
- `mesh_obj_load`: solo tris y quads; N-gons ignorados.
- `mesh_gpu`: asume contexto OpenGL 3.3+ activo. Sin streaming (GL_STATIC_DRAW).
## Prerequisitos
- `mesh_gpu_upload` requiere contexto GL activo (llama a `glGenVertexArrays`, etc.).
- `gltf_load_mesh` requiere `cpp/vendor/nlohmann/json.hpp`.
- `mesh_obj_load` solo stdlib — sin dependencias extra.