---
name: mesh_obj_load
kind: function
lang: cpp
domain: gfx
version: "1.0.0"
purity: pure
signature: "Mesh mesh_obj_parse(const char* obj_text, size_t len); Mesh mesh_obj_load(const char* path)"
description: "Parser minimal de Wavefront .obj — soporta v, vn, f (tris y quads). Genera normales por face si faltan. mesh_obj_parse es puro; mesh_obj_load es helper impuro que lee fichero y delega."
tags: [obj, mesh, parser, wavefront, loader, geometry, 3d]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [fstream, sstream, cmath]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/gfx/mesh_obj_load.cpp"
framework: opengl
params:
  - name: obj_text
    desc: "Buffer de texto .obj. Lineas reconocidas: v, vn, f. Comentarios con #. UTF-8 plano."
  - name: len
    desc: "Longitud del buffer en bytes"
  - name: path
    desc: "Ruta absoluta o relativa del .obj a leer (mesh_obj_load impuro)"
output: "Mesh con positions/normals (stride 3, mismo length) y indices (tri-list, multiplo de 3). Si no hay vn, normales por face (flat shading) y vertices duplicados por face. Mesh vacio si parse falla."
---

# mesh_obj_load

Parser pequeno de Wavefront `.obj` para inspeccion de geometria. KISS: cubre el subconjunto que la mayoria de exporters genera (Blender default, MeshLab, etc).

## Soporta

- `v x y z` — vertice (xyz; w opcional ignorado)
- `vn x y z` — normal
- `f a b c` y `f a b c d` — tris y quads (los quads se dividen en 2 tris)
- Indices `v`, `v/t`, `v//n`, `v/t/n` (vt se ignora; t no afecta)
- Indices 1-based positivos y negativos (relative-to-end, conforme spec)
- Lineas en blanco y comentarios con `#`

## NO soporta (en este issue)

- N-gons con mas de 4 vertices → silenciosamente descartados
- `vt` (coordenadas de textura) — el indice se parsea pero el dato se ignora
- `mtllib`, `usemtl`, `o`, `g`, `s` — se saltan
- Lineas de polilineas (`l`)
- Curvas, superficies, `vp`

## Generacion de normales

Si el `.obj` no tiene `vn` (o si alguna face no las referencia), se generan normales por face (flat shading). Esto duplica vertices entre faces que comparten posicion pero no normal — es el comportamiento esperado para inspeccion.

Cuando todas las faces tienen normales explicitas, se hace dedup `(v_idx, n_idx)` con un linear-scan simple. Para meshes inspeccion (<<100k verts unicos) es perf-OK; meshes mas grandes se beneficiarian de un hashmap.

## Errores

Si el archivo no tiene vertices o no tiene faces, devuelve `Mesh{}` (positions/indices vacios). El caller puede chequear con `mesh.positions.empty()`.

## Test inline (cubo)

```cpp
const char* obj =
    "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 1 2 3 4\nf 5 6 7 8\nf 1 2 6 5\n"
    "f 4 3 7 8\nf 1 4 8 5\nf 2 3 7 6\n";
Mesh m = mesh_obj_parse(obj, std::strlen(obj));
// 6 quads -> 12 tris -> 36 indices.
// Sin vn -> face normals -> 36 verts emitidos (duplicados por face).
assert(m.indices.size() == 36);
```
