// Demo de gl_texture_load (cpp/functions/gfx/gl_texture_load.{h,cpp}). // Carga assets/sample.png y lo muestra con ImGui::Image. Sliders para tint // RGB que se aplican como modulacion (ImGui::Image acepta tint_col). // // Limitacion: el "zoom UV" se simula moviendo uv0/uv1 (que ImGui::Image acepta // nativamente). Asi evitamos compilar un shader custom adicional para la demo. #include "demos.h" #include "demo.h" #include "gfx/gl_texture_load.h" #include "gfx/gl_loader.h" #include #include #include namespace gallery { namespace { struct TextureState { fn::GlTexture tex{}; bool tried_load = false; std::string_view err; char err_buf[256] = {0}; float tint[3] = {1.0f, 1.0f, 1.0f}; float zoom = 1.0f; // 1.0 = sin zoom; >1 hace UV mas pequeno }; TextureState& state() { static TextureState s; return s; } // Resuelve un path para el asset. Probamos varios candidatos relativos al cwd // del binario (puede lanzarse desde build/ o desde la raiz del repo). const char* resolve_sample_path() { static const char* candidates[] = { "assets/sample.png", "apps/primitives_gallery/assets/sample.png", "cpp/apps/primitives_gallery/assets/sample.png", "../cpp/apps/primitives_gallery/assets/sample.png", "../../cpp/apps/primitives_gallery/assets/sample.png", "../../../cpp/apps/primitives_gallery/assets/sample.png", nullptr, }; for (int i = 0; candidates[i]; i++) { FILE* f = std::fopen(candidates[i], "rb"); if (f) { std::fclose(f); return candidates[i]; } } return candidates[0]; // devolver el primer candidato para que el error sea mas descriptivo } } // namespace void demo_gl_texture() { demo_header("gl_texture_load", "v1.0.0", "Carga PNG/JPG/HDR desde disco a una textura GL lista para sampler2D. " "Vendorea stb_image (cpp/vendor/stb/). Demo: assets/sample.png " "(damero 256x256), tint RGB modulando ImGui::Image, zoom UV."); auto& s = state(); if (!s.tried_load) { // Asegurar simbolos GL resueltos (Linux no-op, Windows wglGetProcAddress). fn::gfx::gl_loader_init(); const char* path = resolve_sample_path(); s.tex = fn::gl_texture_load(path, /*flip_y=*/true, /*srgb=*/false); if (!s.tex.ok()) { std::snprintf(s.err_buf, sizeof(s.err_buf), "no se pudo cargar '%s': %s", path, fn::gl_texture_last_error()); } s.tried_load = true; } if (!s.tex.ok()) { ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s", s.err_buf); ImGui::TextWrapped( "El binario busca el PNG en varios paths relativos al cwd. " "Lanzar desde la raiz del repo o desde cpp/build/ deberia funcionar."); return; } section("Texture info"); ImGui::Text("size: %d x %d px", s.tex.w, s.tex.h); ImGui::Text("channels: %d (forzado a RGBA en upload)", s.tex.channels); ImGui::Text("gl_id: %u", (unsigned)s.tex.id); section("Tint + zoom"); ImGui::SliderFloat3("tint RGB", s.tint, 0.0f, 2.0f, "%.2f"); ImGui::SliderFloat("zoom UV", &s.zoom, 0.25f, 4.0f, "%.2fx"); section("Preview"); // Calcular UVs centradas con zoom: 1.0 = (0,0)-(1,1), 2.0 = (0.25,0.25)-(0.75,0.75) float u_half = 0.5f / (s.zoom > 0.001f ? s.zoom : 0.001f); ImVec2 uv0(0.5f - u_half, 0.5f - u_half); ImVec2 uv1(0.5f + u_half, 0.5f + u_half); ImVec4 tint(s.tint[0], s.tint[1], s.tint[2], 1.0f); // Conversion GLuint -> ImTextureID. ImGui::Image acepta cualquier id de // textura del backend; en imgui_impl_opengl3 es directamente el GLuint. ImTextureID tid = (ImTextureID)(intptr_t)s.tex.id; ImGui::ImageWithBg(tid, ImVec2(384.0f, 384.0f), uv0, uv1, ImVec4(0, 0, 0, 0), tint); code_block( "#include \"gfx/gl_texture_load.h\"\n\n" "auto tex = fn::gl_texture_load(\"assets/sample.png\");\n" "if (!tex.ok()) {\n" " fprintf(stderr, \"%s\\n\", fn::gl_texture_last_error());\n" " return 1;\n" "}\n" "// uso en shader:\n" "glUseProgram(prog);\n" "fn::gl_texture_bind_uniform(prog, \"u_tex\", tex, /*unit=*/0);\n" "glDrawArrays(GL_TRIANGLES, 0, 6);\n\n" "// o en ImGui directamente:\n" "ImGui::Image((ImTextureID)(intptr_t)tex.id, ImVec2(w, h));" ); } } // namespace gallery