fad4006f60
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
147 lines
5.2 KiB
Markdown
147 lines
5.2 KiB
Markdown
---
|
|
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).
|