MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
InkPress.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "GlyphAtlas.hpp"
5
7
8struct GlyphQuad;
9
10/**
11 * @brief Policy controlling TextBuffer reuse behaviour in repress().
12 */
13enum class RedrawPolicy : uint8_t {
14 Clip, ///< Replace content. Truncate to existing budget bounds if text exceeds them.
15 Fit ///< Replace content. Reallocate GPU texture if text exceeds existing budget.
16};
17
18/**
19 * @brief Result of an impress() call.
20 *
21 * Ok and Overflow are both success states from the caller's perspective --
22 * the text was composited in both cases. Overflow additionally signals that
23 * the vertical budget was exceeded, the texture was reallocated, and all
24 * previous content has been cleared. The caller is responsible for
25 * rebuilding the full accumulated string if continuity is required.
26 */
27enum class ImpressResult : uint8_t {
28 Ok, ///< Run composited at cursor. No GPU state change.
29 Overflow ///< Vertical budget exceeded. Texture reallocated. Previous content cleared.
30};
31
32/**
33 * @brief Construction parameters for press().
34 *
35 * Atlas and render bounds are fixed at press() time and owned by the
36 * resulting TextBuffer. repress() and impress() read them from the buffer
37 * and do not accept a PressParams argument.
38 *
39 * budget_h controls the pre-allocated texture height. When zero the
40 * framework applies a k_grow_height_multiplier heuristic over the initial
41 * content height to reduce early vertical reallocation under growing text.
42 * Set to a concrete value to skip the heuristic and allocate exactly.
43 *
44 * Width is always allocated to render_bounds.x -- the layout engine wraps
45 * at that boundary, so no content can ever exceed it and a narrower
46 * horizontal allocation serves no purpose.
47 */
49 /// @brief Glyph atlas to use. Null selects the TypeFaceFoundry default at call time.
50 GlyphAtlas* atlas { nullptr };
51
52 /// @brief RGBA color applied to all glyphs.
53 glm::vec4 color { 1.F, 1.F, 1.F, 1.F };
54
55 /// @brief Hard render bounds in pixels.
56 /// impress() wraps at x and returns Overflow when y is exhausted.
57 glm::uvec2 render_bounds { 1280, 720 };
58
59 /// @brief Initial vertical budget in pixels. Zero applies the grow heuristic.
60 uint32_t budget_h { 0 };
61};
62
63/**
64 * @brief Write glyph quads into a caller-provided RGBA8 pixel buffer.
65 *
66 * Applies coverage-multiplied alpha blend per glyph cell. The destination
67 * buffer must be row-major RGBA8 with stride == buf_w * 4 bytes. Quads
68 * that fall outside [0, buf_w) x [0, buf_h) are clipped per pixel.
69 *
70 * The typical usage pattern is:
71 * @code
72 * auto layout = lay_out(text, atlas, 0.F, 0.F, wrap_w);
73 * for (auto& q : layout.quads) { ... } // per-character transforms
74 * rasterize_quads(layout.quads, atlas, color, pixels, w, h);
75 * @endcode
76 *
77 * @param quads Quads produced by lay_out(), optionally mutated by the caller.
78 * @param atlas Source atlas for coverage bitmaps.
79 * @param color RGBA glyph color in [0, 1].
80 * @param dst Destination RGBA8 buffer. Stride is buf_w * 4 bytes.
81 * @param buf_w Buffer width in pixels.
82 * @param buf_h Buffer height in pixels.
83 */
84MAYAFLUX_API void rasterize_quads(
85 std::span<const GlyphQuad> quads,
86 GlyphAtlas& atlas,
87 glm::vec4 color,
88 uint8_t* dst,
89 uint32_t buf_w,
90 uint32_t buf_h);
91
92/**
93 * @brief Rasterize a mutated quad span into an existing TextBuffer.
94 *
95 * Clears the buffer's pixel region, rasterizes @p quads via rasterize_quads(),
96 * and marks the buffer dirty for GPU upload. The scratch pixel buffer is
97 * thread-local and reused across calls, so no heap allocation occurs after
98 * the first call at a given buffer size.
99 *
100 * Typical usage:
101 * @code
102 * auto layout = Portal::Text::create_layout(text, 0.F, 0.F, wrap_w);
103 * // ... per-quad mutation ...
104 * Portal::Text::ink_quads(text_buf, layout->quads, color);
105 * @endcode
106 *
107 * @param target TextBuffer to write into. Dimensions are read from the buffer.
108 * @param quads Quads produced by create_layout(), optionally mutated by the caller.
109 * @param color RGBA glyph color in [0, 1].
110 */
111MAYAFLUX_API void ink_quads(
112 const std::shared_ptr<Buffers::TextBuffer>& target,
113 std::span<const GlyphQuad> quads,
114 glm::vec4 color);
115
116/**
117 * @brief Composite a UTF-8 string into a new TextBuffer.
118 *
119 * The returned TextBuffer has width == params.render_bounds.x and height
120 * equal to either the explicit params.budget_h or the heuristic initial
121 * allocation, whichever is larger than the content height.
122 *
123 * @param text UTF-8 string to composite.
124 * @param params Construction parameters. Default produces a growing buffer
125 * at 1280x720 render bounds using the default atlas.
126 * @return Initialized TextBuffer, or nullptr on failure.
127 */
128[[nodiscard]] MAYAFLUX_API std::shared_ptr<Buffers::TextBuffer> press(
129 std::string_view text,
130 const PressParams& params = {});
131
132/**
133 * @brief Re-composite a UTF-8 string into an existing TextBuffer.
134 *
135 * Always clears the buffer before compositing. Render bounds and atlas are
136 * read from the target buffer. When the target has a pre-allocated vertical
137 * budget the compositing bounds are the budget dimensions, so no VKImage
138 * rebuild occurs as long as content fits.
139 *
140 * @param target Existing TextBuffer to write into.
141 * @param text UTF-8 string to composite.
142 * @param color RGBA glyph color.
143 * @param policy Controls reallocation behaviour when text exceeds budget.
144 * @return True on success.
145 */
146MAYAFLUX_API bool repress(
147 const std::shared_ptr<Buffers::TextBuffer>& target,
148 std::string_view text,
149 glm::vec4 color = { 1.F, 1.F, 1.F, 1.F },
151
152/**
153 * @brief Append a UTF-8 string into an existing TextBuffer at the current cursor.
154 *
155 * Does not clear existing content. Composites the new run into the
156 * pre-allocated budget region and advances the cursor. No VKImage
157 * reallocation occurs while the run fits within the vertical budget.
158 *
159 * When the run would push the cursor past the vertical budget the texture
160 * is grown by k_grow_height_multiplier, the full accumulated text is
161 * recomposited, and ImpressResult::Overflow is returned. The caller is
162 * responsible for rebuilding prior content after an overflow if accumulated
163 * state is not sufficient.
164 *
165 * When the cursor would exceed render_bounds_h the run is rejected and
166 * ImpressResult::Overflow is returned without reallocation.
167 *
168 * The atlas is always the TypeFaceFoundry default. If a non-default atlas
169 * was used at press() time, impress() will use the default instead. Mixing
170 * atlases on the same TextBuffer is undefined behaviour.
171 *
172 * @param target Existing TextBuffer to append into.
173 * @param text UTF-8 string to composite.
174 * @param color RGBA glyph color.
175 * @return ImpressResult::Ok or ImpressResult::Overflow.
176 */
177MAYAFLUX_API ImpressResult impress(
178 const std::shared_ptr<Buffers::TextBuffer>& target,
179 std::string_view text,
180 glm::vec4 color = { 1.F, 1.F, 1.F, 1.F });
181
182} // namespace MayaFlux::Portal::Text
std::optional< glm::vec3 > color
Rasterizes and packs glyphs from a FontFace into a TextureContainer.
ImpressResult impress(const std::shared_ptr< Buffers::TextBuffer > &target, std::string_view text, glm::vec4 color)
Append a UTF-8 string into an existing TextBuffer at the current cursor.
Definition InkPress.cpp:338
void rasterize_quads(std::span< const GlyphQuad > quads, GlyphAtlas &atlas, glm::vec4 color, uint8_t *dst, uint32_t buf_w, uint32_t buf_h)
Write glyph quads into a caller-provided RGBA8 pixel buffer.
Definition InkPress.cpp:147
RedrawPolicy
Policy controlling TextBuffer reuse behaviour in repress().
Definition InkPress.hpp:13
@ Fit
Replace content. Reallocate GPU texture if text exceeds existing budget.
@ Clip
Replace content. Truncate to existing budget bounds if text exceeds them.
ImpressResult
Result of an impress() call.
Definition InkPress.hpp:27
@ Overflow
Vertical budget exceeded. Texture reallocated. Previous content cleared.
@ Ok
Run composited at cursor. No GPU state change.
void ink_quads(const std::shared_ptr< Buffers::TextBuffer > &target, std::span< const GlyphQuad > quads, glm::vec4 color)
Rasterize a mutated quad span into an existing TextBuffer.
Definition InkPress.cpp:203
bool repress(const std::shared_ptr< Buffers::TextBuffer > &target, std::string_view text, glm::vec4 color, RedrawPolicy policy)
Re-composite a UTF-8 string into an existing TextBuffer.
Definition InkPress.cpp:264
std::shared_ptr< Buffers::TextBuffer > press(std::string_view text, const PressParams &params)
Composite a UTF-8 string into a new TextBuffer.
Definition InkPress.cpp:234
GlyphAtlas * atlas
Glyph atlas to use. Null selects the TypeFaceFoundry default at call time.
Definition InkPress.hpp:50
glm::vec4 color
RGBA color applied to all glyphs.
Definition InkPress.hpp:53
uint32_t budget_h
Initial vertical budget in pixels. Zero applies the grow heuristic.
Definition InkPress.hpp:60
glm::uvec2 render_bounds
Hard render bounds in pixels.
Definition InkPress.hpp:57
Construction parameters for press().
Definition InkPress.hpp:48