Loading...
Searching...
No Matches
TextToTexture.hpp
1#pragma once
2#include <halp/controls.hpp>
3#include <halp/meta.hpp>
4#include <halp/texture.hpp>
5
6#include <QColor>
7#include <QFont>
8#include <QImage>
9#include <QPainter>
10
11#include <string>
12
13namespace Threedim
14{
15
16// Rasterize a text string into an RGBA texture via QPainter. Pipes into
17// any node that consumes halp::gpu_texture — most commonly
18// MaterialOverride (to show text on a mesh's base-color slot) or
19// Instancer / a billboard renderer (for text sprites).
20//
21// Re-renders only when a control (text / font / size / color / canvas
22// dimensions) changes — the update() hooks on each port fire recreate().
24{
25public:
26 halp_meta(name, "Text to Texture")
27 halp_meta(category, "Visuals/3D/Text")
28 halp_meta(c_name, "text_to_texture")
29 halp_meta(description, "Render text with configurable font, color and canvas dimensions into an RGBA texture.")
30 halp_meta(authors, "ossia team")
31 halp_meta(
32 manual_url,
33 "https://ossia.io/score-docs/processes/text-to-texture.html")
34 halp_meta(uuid, "5d3a9b2f-7e6c-4a8d-b1f4-9c2e3d5a7b8f")
35
36 struct ins
37 {
38 struct : halp::lineedit<"Text", "Hello, world">
39 {
40 void update(TextToTexture& self) { self.recreate(); }
41 } text;
42 struct : halp::lineedit<"Font family", "Sans">
43 {
44 void update(TextToTexture& self) { self.recreate(); }
45 } font_family;
46 struct : halp::spinbox_i32<"Font size", halp::irange{4, 512, 64}>
47 {
48 void update(TextToTexture& self) { self.recreate(); }
49 } font_size;
50 struct : halp::toggle<"Bold">
51 {
52 void update(TextToTexture& self) { self.recreate(); }
53 } bold;
54 struct : halp::toggle<"Italic">
55 {
56 void update(TextToTexture& self) { self.recreate(); }
57 } italic;
58
59 struct : halp::spinbox_i32<"Canvas width", halp::irange{16, 4096, 1024}>
60 {
61 void update(TextToTexture& self) { self.recreate(); }
62 } canvas_w;
63 struct : halp::spinbox_i32<"Canvas height", halp::irange{16, 4096, 256}>
64 {
65 void update(TextToTexture& self) { self.recreate(); }
66 } canvas_h;
67
68 // Colors are vec4 (r, g, b, a) in [0, 1]. The background defaults to
69 // transparent, so only the glyphs show.
70 struct : halp::hslider_f32<"Text R", halp::range{0., 1., 1.}> { void update(TextToTexture& s) { s.recreate(); } } fg_r;
71 struct : halp::hslider_f32<"Text G", halp::range{0., 1., 1.}> { void update(TextToTexture& s) { s.recreate(); } } fg_g;
72 struct : halp::hslider_f32<"Text B", halp::range{0., 1., 1.}> { void update(TextToTexture& s) { s.recreate(); } } fg_b;
73 struct : halp::hslider_f32<"Text A", halp::range{0., 1., 1.}> { void update(TextToTexture& s) { s.recreate(); } } fg_a;
74 struct : halp::hslider_f32<"BG R", halp::range{0., 1., 0.}> { void update(TextToTexture& s) { s.recreate(); } } bg_r;
75 struct : halp::hslider_f32<"BG G", halp::range{0., 1., 0.}> { void update(TextToTexture& s) { s.recreate(); } } bg_g;
76 struct : halp::hslider_f32<"BG B", halp::range{0., 1., 0.}> { void update(TextToTexture& s) { s.recreate(); } } bg_b;
77 struct : halp::hslider_f32<"BG A", halp::range{0., 1., 0.}> { void update(TextToTexture& s) { s.recreate(); } } bg_a;
78
79 // Text alignment inside the canvas: 0=left, 1=center, 2=right for h;
80 // 0=top, 1=center, 2=bottom for v.
81 struct : halp::spinbox_i32<"H align", halp::irange{0, 2, 1}>
82 { void update(TextToTexture& s) { s.recreate(); } } h_align;
83 struct : halp::spinbox_i32<"V align", halp::irange{0, 2, 1}>
84 { void update(TextToTexture& s) { s.recreate(); } } v_align;
85 } inputs;
86
87 struct
88 {
89 halp::texture_output<"Output", halp::rgba_texture> main;
90 } outputs;
91
92 void recreate()
93 {
94 const int w = inputs.canvas_w.value;
95 const int h = inputs.canvas_h.value;
96 if(w <= 0 || h <= 0)
97 return;
98
99 // Qt renders with premultiplied alpha; we output straight RGBA8.
100 // QImage::Format_RGBA8888 is non-premultiplied and matches what
101 // gpu_texture expects when upload-bound as RGBA8.
102 QImage img(w, h, QImage::Format_RGBA8888);
103 img.fill(QColor::fromRgbF(
104 inputs.bg_r.value, inputs.bg_g.value, inputs.bg_b.value,
105 inputs.bg_a.value));
106
107 QPainter p(&img);
108 p.setRenderHint(QPainter::Antialiasing, true);
109 p.setRenderHint(QPainter::TextAntialiasing, true);
110
111 QFont f(QString::fromStdString(inputs.font_family.value));
112 f.setPixelSize(inputs.font_size.value);
113 f.setBold(inputs.bold.value);
114 f.setItalic(inputs.italic.value);
115 p.setFont(f);
116 p.setPen(QColor::fromRgbF(
117 inputs.fg_r.value, inputs.fg_g.value, inputs.fg_b.value,
118 inputs.fg_a.value));
119
120 int flags = 0;
121 switch(inputs.h_align.value)
122 {
123 case 0: flags |= Qt::AlignLeft; break;
124 case 2: flags |= Qt::AlignRight; break;
125 default: flags |= Qt::AlignHCenter;
126 }
127 switch(inputs.v_align.value)
128 {
129 case 0: flags |= Qt::AlignTop; break;
130 case 2: flags |= Qt::AlignBottom; break;
131 default: flags |= Qt::AlignVCenter;
132 }
133 flags |= Qt::TextWordWrap;
134
135 p.drawText(
136 QRect(0, 0, w, h), flags,
137 QString::fromStdString(inputs.text.value));
138 p.end();
139
140 outputs.main.create(w, h);
141 std::memcpy(outputs.main.texture.bytes, img.constBits(), std::size_t(w) * h * 4);
142 outputs.main.upload();
143 }
144};
145
146}
Definition TextToTexture.hpp:24
Definition TextToTexture.hpp:37