Loading...
Searching...
No Matches
ImageLoader.hpp
1#pragma once
2#include <Gfx/Graph/Node.hpp>
3#include <Gfx/Graph/NodeRenderer.hpp>
4#include <Gfx/Graph/RenderList.hpp>
5#include <Gfx/Graph/TextureLoader.hpp>
6
7#include <halp/controls.hpp>
8#include <halp/file_port.hpp>
9#include <halp/meta.hpp>
10#include <halp/texture.hpp>
11
12#include <QImage>
13
14namespace Threedim
15{
16
17// Lightweight LDR image-to-GPU-texture loader. Sibling to BufferLoader
18// but for 2D textures. Sits alongside the main OpenImageIO-backed
19// ImageLoader in a sibling plug-in, usable when OIIO isn't linked in
20// and the image is a plain QImage-supported format (PNG / JPG / BMP /
21// …). HDR formats (.hdr / .exr) require the OIIO path.
22//
23// Primary use: feeds the pure-shader cubemap pipeline
24// ImageLoader(path) → cubemap_from_source → SceneResourceRoute(Skybox)
25// superseding the bespoke equirect/cross/strip code in CubemapLoader.
27{
28public:
29 halp_meta(name, "Image loader (LDR)")
30 halp_meta(category, "Visuals")
31 halp_meta(c_name, "image_loader_ldr")
32 halp_meta(authors, "ossia team")
33 halp_meta(
34 manual_url,
35 "https://ossia.io/score-docs/processes/image-loader.html")
36 halp_meta(description,
37 "Loads a 2D image file (PNG / JPG / BMP / …) to a GPU RGBA8 texture")
38 halp_meta(uuid, "e6b2c1d8-3f45-4a92-8b17-9c4e0d5a6f3b")
39
40 struct ins
41 {
42 // File-port boilerplate — same pattern as SplatLoader's obj_t.
43 // process() runs on the file-load thread, decodes the image,
44 // returns a lambda that stages the result onto the node from the
45 // execution thread.
46 struct image_t : halp::file_port<"Image", halp::mmap_file_view>
47 {
48 halp_meta(extensions,
49 "Images (*.png *.jpg *.jpeg *.bmp *.tga *.webp *.tif *.tiff)");
50 static std::function<void(ImageLoader&)> process(file_type data)
51 {
52 // Decode through the shared gfx loader: RGBA8888 canonicalization and
53 // the footer-less TGA fallback in one place.
54 QImage img;
55 if(!data.bytes.empty())
56 {
57 if(auto dec = score::gfx::decodeImageFromMemory(
58 QByteArray::fromRawData(data.bytes.data(), data.bytes.size()), {}))
59 img = std::move(dec->image);
60 }
61 if(img.isNull() && !data.filename.empty())
62 {
63 if(auto dec = score::gfx::decodeImageFromPath(
64 QString::fromUtf8(data.filename.data())))
65 img = std::move(dec->image);
66 }
67 return [img = std::move(img)](ImageLoader& self) mutable {
68 self.m_pendingImage = std::move(img);
69 self.m_changed = true;
70 };
71 }
72 } image;
73 } inputs;
74
75 struct
76 {
77 halp::gpu_texture_output<"Texture"> texture;
78 } outputs;
79
80 void init(score::gfx::RenderList& renderer, QRhiResourceUpdateBatch& res);
81 void update(
82 score::gfx::RenderList& renderer, QRhiResourceUpdateBatch& res,
84 void release(score::gfx::RenderList& r);
85 void runInitialPasses(
86 score::gfx::RenderList& renderer, QRhiCommandBuffer& commands,
87 QRhiResourceUpdateBatch*& res, score::gfx::Edge& edge);
88
89 void operator()() { }
90
91 QImage m_pendingImage;
92 // Persistent CPU copy of the last successfully uploaded image. Kept
93 // alive across RenderList rebuilds (resize) so that init() can
94 // re-upload to the freshly allocated QRhiTexture without needing the
95 // user to re-trigger the file-port. Without it, release() drops m_tex and
96 // update() clears m_pendingImage, so the next init() has nothing to upload
97 // and the texture port stays bound to the empty placeholder for the rest of
98 // the session.
99 QImage m_keptImage;
100 QRhiTexture* m_tex{};
101 bool m_changed{};
102};
103
104}
Definition ImageLoader.hpp:27
List of nodes to be rendered to an output.
Definition RenderList.hpp:30
Definition ImageLoader.hpp:47
Definition ImageLoader.hpp:41
Connection between two score::gfx::Port.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:103