---
id: "0026"
title: "C++ gl_texture_load"
status: completado
type: feature
domain:
  - cpp-stack
scope: multi-app
priority: alta
depends: []
blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: []
---
# 0026 — C++ gl_texture_load

## APP Metadata

| Campo | Valor |
|-------|-------|
| **ID** | 0026 |
| **Estado** | pendiente |
| **Prioridad** | alta |
| **Tipo** | feature — C++ gfx (cpp/functions/gfx) |

## Dependencias

Ninguna. Se compone con `gl_loader_cpp_gfx`, `gl_shader_cpp_gfx`, `shader_canvas_cpp_gfx`.

**Desbloquea:** shaders que toman imagenes externas (textura de ruido, foto, lookup tables). Base para `webcam_texture` (0036) y para nodos DAG futuros que usen sampler2D.

---

## Objetivo

Añadir una funcion impura al registry C++ que carga PNG/JPG/HDR desde disco y devuelve un `GLuint` listo para `glBindTexture` + `glUniform1i`. Vendorea **stb_image** (header-only, dominio publico) en `cpp/vendor/stb/`.

Mostrar el resultado en `primitives_gallery` como demo: un shader fullscreen que samplea una imagen cargada, con sliders para tint y zoom UV.

## Contexto

Actualmente `gl_shader_cpp_gfx` solo expone uniforms `u_resolution`, `u_time`, `u_mouse`, y `shaders_lab` puede pasar `u_params[16]` via `dag_uniforms`. No hay forma de meter una imagen al pipeline. Esto bloquea casos comunes:
- Texturas de ruido (perlin/bluenoise) precomputadas.
- Lookup tables para color grading.
- Imagenes de referencia para post-process.

## Arquitectura

```
cpp/
├── vendor/stb/
│   └── stb_image.h              # NEW (~10k LOC, public domain)
├── functions/gfx/
│   ├── gl_texture_load.h        # NEW
│   ├── gl_texture_load.cpp      # NEW
│   └── gl_texture_load.md       # NEW
└── apps/primitives_gallery/
    ├── demos_gl_texture.cpp     # NEW
    ├── demos.h                  # MOD
    ├── main.cpp                 # MOD
    └── CMakeLists.txt           # MOD
cpp/CMakeLists.txt               # MOD
```

### Pure core / impure shell

Funcion **impura** (`purity: impure`, `kind: function`): hace I/O de disco + crea recurso GPU.

### API propuesta

```cpp
namespace fn {

struct GlTexture {
    GLuint id = 0;
    int    w  = 0;
    int    h  = 0;
    int    channels = 0;
    bool   ok() const { return id != 0; }
};

// Carga desde disco (PNG/JPG/BMP/TGA via stb_image, HDR como float opcional).
// flip_y por defecto true para coincidir con UV de OpenGL.
// Devuelve GlTexture con id=0 si falla; usar gl_texture_last_error() para detalle.
GlTexture gl_texture_load(const char* path, bool flip_y = true, bool srgb = false);
GlTexture gl_texture_load_from_memory(const unsigned char* data, int size, bool flip_y = true, bool srgb = false);

void gl_texture_destroy(GlTexture& tex);
const char* gl_texture_last_error();

// Helper: bind a una texture unit y subir uniform sampler.
void gl_texture_bind_uniform(GLuint program, const char* name, const GlTexture& tex, int unit);
}
```

## Tareas

### Fase 1 — Vendor stb_image

- 1.1 Descargar `stb_image.h` (commit estable) a `cpp/vendor/stb/`. Crear `cpp/vendor/stb/stb_image_impl.cpp` con `#define STB_IMAGE_IMPLEMENTATION` antes del include, para evitar emitir el cuerpo en multiples TUs.
- 1.2 Añadirlo a `cpp/CMakeLists.txt` global.

### Fase 2 — gl_texture_load

- 2.1 Implementar `gl_texture_load.h/.cpp`. Usar `glGenTextures` + `glTexImage2D`. Filtros LINEAR_MIPMAP_LINEAR + LINEAR. Generar mipmaps con `glGenerateMipmap`.
- 2.2 Soporte para `srgb=true` (`GL_SRGB8_ALPHA8` como internal format).
- 2.3 Soporte HDR: si extension es `.hdr`, usar `stbi_loadf` y `GL_RGBA16F`.
- 2.4 `gl_texture_load.md` con frontmatter (`kind: function`, `purity: impure`, `error_type`, `uses_functions: [gl_loader_cpp_gfx]`).

### Fase 3 — Gallery demo

- 3.1 `demos_gl_texture.cpp` con `demo_gl_texture_load()`: carga `assets/sample.png` (un PNG de prueba, ej. patron damero). Renderiza un fullscreen quad con un shader que samplea la textura y aplica tint via uniforms. ImGui::Image con thumbnail al lado y info (w, h, channels).
- 3.2 Añadir `assets/sample.png` (256x256, ~10KB).
- 3.3 Registrar en `demos.h`, `main.cpp`, `CMakeLists.txt`.

### Fase 4 — Tests + docs

- 4.1 Test que carga un PNG embebido (in-memory) y verifica `tex.ok() && tex.w == ...`.
- 4.2 `./fn index` y verificar via `fn show gl_texture_load_cpp_gfx`.

## Ejemplo de uso

```cpp
auto tex = fn::gl_texture_load("assets/noise.png");
if (!tex.ok()) {
    std::fprintf(stderr, "error: %s\n", fn::gl_texture_last_error());
    return 1;
}
glUseProgram(prog);
fn::gl_texture_bind_uniform(prog, "u_noise", tex, 0);  // unit 0
glDrawArrays(GL_TRIANGLES, 0, 6);
```

## Decisiones de diseño

- **Vendoreado en `cpp/vendor/stb/`** sigue el patron actual de ImGui/ImPlot.
- **`flip_y=true` por defecto** porque la convencion en GLSL es V hacia arriba.
- **`srgb` opcional** — para texturas LDR de color, `GL_SRGB8_ALPHA8` da un gamma correcto sin tener que `pow(color, 2.2)` en el shader.

## Riesgos

- **Tamaño de imagenes**: cargar PNGs de 4K consume RAM/VRAM. Documentar limite practico (<= 8192 lado).
- **Driver no soporta sRGB**: documentar fallback a `GL_RGBA8`.
- **Codigo de stb_image lento**: aceptable para uso interactivo (no es hot path de cada frame).
