feat(gfx): añadir gl_texture_load_cpp_gfx

Funcion impura del registry que carga PNG/JPG/BMP/TGA/HDR a una textura
OpenGL lista para sampler2D. Composable con gl_loader, gl_shader,
shader_canvas. Genera mipmaps, soporta sRGB y HDR (RGBA16F).

API:
  GlTexture gl_texture_load(path, flip_y=true, srgb=false)
  GlTexture gl_texture_load_from_memory(data, size, ...)
  void      gl_texture_destroy(tex)
  const char* gl_texture_last_error()  // thread-local
  void      gl_texture_bind_uniform(prog, name, tex, unit)

Errores via thread_local string accesible por gl_texture_last_error().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 20:58:14 +02:00
parent fcbda2af2e
commit cb0591ff91
3 changed files with 303 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
---
name: gl_texture_load
kind: function
lang: cpp
domain: gfx
version: "1.0.0"
purity: impure
signature: "GlTexture gl_texture_load(const char* path, bool flip_y, bool srgb)"
description: "Carga PNG/JPG/BMP/TGA/HDR desde disco (o memoria) a una textura OpenGL lista para usar como sampler2D. Vendorea stb_image. Soporta sRGB (GL_SRGB8_ALPHA8) y HDR (GL_RGBA16F via stbi_loadf). Genera mipmaps automaticamente. flip_y=true por defecto coincide con la convencion UV de OpenGL."
tags: [opengl, texture, image, png, jpg, hdr, stb_image, gfx]
uses_functions: [gl_loader_cpp_gfx]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [stb_image.h, GL/gl.h, GL/glext.h]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/gfx/gl_texture_load.cpp"
framework: opengl
params:
- name: path
desc: "Ruta al archivo de imagen (PNG/JPG/BMP/TGA o .hdr para float). UTF-8."
- name: flip_y
desc: "Si es true, voltea verticalmente al cargar (convencion OpenGL: V hacia arriba). Default true."
- name: srgb
desc: "Si es true, sube como GL_SRGB8_ALPHA8 (gamma correcto sin pow(c, 2.2) en shader). Solo aplica a LDR. Default false."
output: "GlTexture con id=GLuint listo para glBindTexture, w/h/channels de la imagen original. Si falla, id=0 y ok()==false; usar gl_texture_last_error() para detalle."
---
# gl_texture_load
Funcion impura del registry C++ que carga una imagen desde disco (o memoria) y devuelve una textura OpenGL lista para samplear desde un shader. Vendorea [stb_image](https://github.com/nothings/stb) en `cpp/vendor/stb/`.
## API
```cpp
namespace fn {
struct GlTexture {
GLuint id = 0;
int w = 0;
int h = 0;
int channels = 0;
bool ok() const { return id != 0; }
};
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();
void gl_texture_bind_uniform(GLuint program, const char* name,
const GlTexture& tex, int unit);
} // namespace fn
```
## Uso
```cpp
#include "gfx/gl_texture_load.h"
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, /*unit=*/0);
glDrawArrays(GL_TRIANGLES, 0, 6);
// al destruir:
fn::gl_texture_destroy(tex);
```
## Comportamiento
- Forzamos 4 canales (RGBA) al decodificar via stb (`req_comp=4`), asi el upload a `glTexImage2D` siempre es regular.
- Filtros: `GL_LINEAR_MIPMAP_LINEAR` (min) + `GL_LINEAR` (mag). Mipmaps generados con `glGenerateMipmap`.
- Wrap: `GL_REPEAT` en S y T.
- HDR (`.hdr`): `stbi_loadf` + `GL_RGBA16F` (driver con GL 3.0+). En este caso `srgb` se ignora.
- sRGB (LDR + `srgb=true`): internal format `GL_SRGB8_ALPHA8`. El driver convierte a linear automaticamente al samplear.
- `flip_y=true` por defecto — la mayoria de PNGs vienen con (0,0) arriba; OpenGL espera (0,0) abajo.
## Errores
- En fallo, `id == 0` y `ok() == false`. El detalle (string de stb o "glGenTextures returned 0") se guarda en un `thread_local` accesible via `gl_texture_last_error()` hasta el siguiente `gl_texture_load*` en el mismo thread.
## Limites
- Tamano practico: <= 8192 px por lado (depende del driver — `GL_MAX_TEXTURE_SIZE`).
- No reentrante con la misma stb-flag global: stb usa una variable global para `flip_vertically`. Si dos threads cargan en paralelo, el resultado puede mezclar los flags. Para paralelo serio, serializar las llamadas o usar `stbi__ldr_to_hdr` directo con flag local.
## Composicion
Depende de `gl_loader_cpp_gfx` para los simbolos `glActiveTexture`, `glGenerateMipmap`, `glUseProgram`, `glGetUniformLocation`, `glUniform1i` (en Linux son simbolos directos via `GL_GLEXT_PROTOTYPES`; en Windows se resuelven con `wglGetProcAddress`).
Compone naturalmente con:
- `gl_shader_cpp_gfx` — para usar la textura en un fragment shader (uniform sampler2D).
- `shader_canvas_cpp_gfx` — un canvas full-screen que samplea la textura con uniforms de tint/zoom.
## Atribucion
stb_image v2.30 — public domain (MIT-0). Ver `cpp/vendor/stb/README.md`.