xbintsc 0.3.18 → 0.3.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/src/cli/main.js +124 -30
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -1
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/state.js +20 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +6 -0
- package/dist/src/codegen/generator/tables.js +38 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/commonjs.d.ts +52 -0
- package/dist/src/driver/bundler/commonjs.js +493 -0
- package/dist/src/driver/bundler/commonjs.js.map +1 -0
- package/dist/src/driver/bundler/graph.d.ts +2 -1
- package/dist/src/driver/bundler/graph.js +32 -3
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.d.ts +2 -1
- package/dist/src/driver/bundler/merge.js +16 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +8 -0
- package/dist/src/driver/compiler.d.ts +8 -1
- package/dist/src/driver/compiler.js +75 -7
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +53 -0
- package/dist/src/driver/config.js +141 -0
- package/dist/src/driver/config.js.map +1 -0
- package/dist/src/driver/icon.d.ts +62 -0
- package/dist/src/driver/icon.js +151 -0
- package/dist/src/driver/icon.js.map +1 -0
- package/dist/src/driver/index.d.ts +4 -0
- package/dist/src/driver/index.js +4 -0
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/mac-bundle.d.ts +41 -0
- package/dist/src/driver/mac-bundle.js +123 -0
- package/dist/src/driver/mac-bundle.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +27 -0
- package/dist/src/driver/win-icon.js +80 -0
- package/dist/src/driver/win-icon.js.map +1 -0
- package/dist/src/extensions/gui/html.d.ts +25 -0
- package/dist/src/extensions/gui/html.js +203 -0
- package/dist/src/extensions/gui/html.js.map +1 -0
- package/dist/src/extensions/gui/index.js +11 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/registry.d.ts +29 -0
- package/dist/src/extensions/registry.js +14 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.js +4 -12
- package/dist/src/lexer/scanner/identifiers.js.map +1 -1
- package/dist/src/parser/statements.js +17 -4
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/tests/cli/main.test.js +46 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/bundler-resolve.test.d.ts +1 -0
- package/dist/tests/driver/bundler-resolve.test.js +230 -0
- package/dist/tests/driver/bundler-resolve.test.js.map +1 -0
- package/dist/tests/driver/config.test.d.ts +1 -0
- package/dist/tests/driver/config.test.js +124 -0
- package/dist/tests/driver/config.test.js.map +1 -0
- package/dist/tests/driver/icon.test.d.ts +1 -0
- package/dist/tests/driver/icon.test.js +421 -0
- package/dist/tests/driver/icon.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +177 -0
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.d.ts +12 -0
- package/dist/tests/e2e/fetch.test.js +272 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -0
- package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
- package/dist/tests/e2e/gui-dom.test.js +102 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -0
- package/dist/tests/e2e/gui-events.test.d.ts +5 -0
- package/dist/tests/e2e/gui-events.test.js +60 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +31 -0
- package/dist/tests/e2e/gui-helpers.js +74 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
- package/dist/tests/e2e/gui-layout.test.js +88 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -0
- package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
- package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
- package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
- package/dist/tests/e2e/gui-paint.test.js +111 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.d.ts +5 -0
- package/dist/tests/e2e/gui-script.test.js +78 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -0
- package/dist/tests/e2e/gui-style.test.d.ts +5 -0
- package/dist/tests/e2e/gui-style.test.js +175 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -0
- package/dist/tests/e2e/icon.test.d.ts +7 -0
- package/dist/tests/e2e/icon.test.js +80 -0
- package/dist/tests/e2e/icon.test.js.map +1 -0
- package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
- package/dist/tests/e2e/npm-modules.test.js +47 -1
- package/dist/tests/e2e/npm-modules.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
- package/dist/tests/extensions/gui-index.test.d.ts +1 -0
- package/dist/tests/extensions/gui-index.test.js +49 -0
- package/dist/tests/extensions/gui-index.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.d.ts +1 -0
- package/dist/tests/extensions/gui.test.js +177 -0
- package/dist/tests/extensions/gui.test.js.map +1 -0
- package/dist/tests/extensions/registry.test.js +36 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/dist/tests/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/dist/tests/public-api.test.d.ts +1 -0
- package/dist/tests/public-api.test.js +31 -0
- package/dist/tests/public-api.test.js.map +1 -0
- package/package.json +1 -1
- package/runtime/ext_gui/css.cpp +4 -517
- package/runtime/ext_gui/css_internal.h +27 -0
- package/runtime/ext_gui/css_match.cpp +195 -0
- package/runtime/ext_gui/css_selector.cpp +207 -0
- package/runtime/ext_gui/css_sheet.cpp +129 -0
- package/runtime/ext_gui/document.cpp +90 -0
- package/runtime/ext_gui/document.h +23 -0
- package/runtime/ext_gui/dom.cpp +43 -403
- package/runtime/ext_gui/dom.h +7 -0
- package/runtime/ext_gui/dom_api.cpp +164 -0
- package/runtime/ext_gui/dom_api.h +12 -0
- package/runtime/ext_gui/dom_api_document.cpp +96 -0
- package/runtime/ext_gui/dom_api_events.cpp +123 -0
- package/runtime/ext_gui/dom_api_internal.h +135 -0
- package/runtime/ext_gui/dom_api_node.cpp +329 -0
- package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
- package/runtime/ext_gui/dom_api_proto.cpp +130 -0
- package/runtime/ext_gui/dom_api_style.cpp +192 -0
- package/runtime/ext_gui/dom_internal.h +39 -0
- package/runtime/ext_gui/dom_parse.cpp +348 -0
- package/runtime/ext_gui/dom_serialize.cpp +54 -0
- package/runtime/ext_gui/gui.cpp +61 -245
- package/runtime/ext_gui/gui_engine.h +54 -0
- package/runtime/ext_gui/gui_events.cpp +294 -0
- package/runtime/ext_gui/gui_internal.h +29 -0
- package/runtime/ext_gui/layout.cpp +6 -597
- package/runtime/ext_gui/layout_flex.cpp +200 -0
- package/runtime/ext_gui/layout_flow.cpp +191 -0
- package/runtime/ext_gui/layout_flow_internal.h +149 -0
- package/runtime/ext_gui/layout_inline.cpp +181 -0
- package/runtime/ext_gui/layout_internal.h +20 -0
- package/runtime/ext_gui/renderer.cpp +15 -679
- package/runtime/ext_gui/renderer_image.cpp +233 -0
- package/runtime/ext_gui/renderer_internal.h +112 -0
- package/runtime/ext_gui/renderer_shaders.h +108 -0
- package/runtime/ext_gui/renderer_text.cpp +342 -0
- package/runtime/ext_gui/script.cpp +63 -0
- package/runtime/ext_gui/style.cpp +12 -660
- package/runtime/ext_gui/style_internal.h +33 -0
- package/runtime/ext_gui/style_print.cpp +113 -0
- package/runtime/ext_gui/style_ua.cpp +98 -0
- package/runtime/ext_gui/style_values.cpp +468 -0
- package/runtime/ext_gui/window.cpp +60 -0
- package/runtime/rt.h +6 -0
- package/runtime/rt_internal.h +4 -0
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_containers/access.inc +32 -1
- package/runtime/xt_fetch/buffer.inc +64 -0
- package/runtime/xt_fetch/headers.inc +312 -0
- package/runtime/xt_fetch/request.inc +386 -0
- package/runtime/xt_fetch/response.inc +107 -0
- package/runtime/xt_fetch/socket.inc +72 -0
- package/runtime/xt_fetch/url.inc +108 -0
- package/runtime/xt_fetch.c +39 -0
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_typed_array.c +614 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/state.ts +20 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +35 -2
- package/src/driver/bundler/merge.ts +18 -1
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +85 -7
- package/src/driver/config.ts +173 -0
- package/src/driver/icon.ts +184 -0
- package/src/driver/index.ts +30 -0
- package/src/driver/mac-bundle.ts +156 -0
- package/src/driver/win-icon.ts +96 -0
- package/src/extensions/gui/html.ts +236 -0
- package/src/extensions/gui/index.ts +11 -0
- package/src/extensions/registry.ts +39 -0
- package/src/index.ts +1 -1
- package/src/lexer/scanner/identifiers.ts +4 -11
- package/src/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -493
- package/dist/tests/e2e/gui.test.js.map +0 -1
|
@@ -1,134 +1,26 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* xbintsc GUI engine — SDL_GPU 2D renderer
|
|
2
|
+
* xbintsc GUI engine — SDL_GPU 2D renderer: shared state, shape pipeline and
|
|
3
|
+
* the public geometry API.
|
|
4
|
+
*
|
|
5
|
+
* Text (glyph atlas) lives in `renderer_text.cpp` and image textures in
|
|
6
|
+
* `renderer_image.cpp`; both are declared in `renderer_internal.h`.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
|
-
#include "
|
|
9
|
+
#include "renderer_internal.h"
|
|
6
10
|
|
|
7
11
|
#include <algorithm>
|
|
8
12
|
#include <cstddef>
|
|
9
13
|
#include <cstdint>
|
|
10
14
|
#include <cstdio>
|
|
11
15
|
#include <cstring>
|
|
12
|
-
#include <functional>
|
|
13
|
-
#include <unordered_map>
|
|
14
|
-
#include <vector>
|
|
15
16
|
|
|
16
17
|
#include "paint.h"
|
|
17
|
-
#include "image.h"
|
|
18
18
|
#include "text.h"
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
#include "renderer_shaders.h"
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* 1 -> local (pixels, relative to the rectangle centre)
|
|
25
|
-
* 2 -> half (rectangle half extents, pixels)
|
|
26
|
-
* 3 -> radius (pixels)
|
|
27
|
-
* 4 -> colour
|
|
28
|
-
* The push constant is the viewport size in logical pixels. */
|
|
29
|
-
const char *const kFillMSL = R"MSL(
|
|
30
|
-
#include <metal_stdlib>
|
|
31
|
-
using namespace metal;
|
|
32
|
-
|
|
33
|
-
struct FillIn {
|
|
34
|
-
float2 position [[attribute(0)]];
|
|
35
|
-
float2 local [[attribute(1)]];
|
|
36
|
-
float2 halfsize [[attribute(2)]];
|
|
37
|
-
float radius [[attribute(3)]];
|
|
38
|
-
float4 color [[attribute(4)]];
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
struct FillOut {
|
|
42
|
-
float4 position [[position]];
|
|
43
|
-
float2 local;
|
|
44
|
-
float2 halfsize;
|
|
45
|
-
float radius;
|
|
46
|
-
float4 color;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
vertex FillOut vs_main(FillIn in [[stage_in]],
|
|
50
|
-
constant float2 &viewport [[buffer(0)]]) {
|
|
51
|
-
FillOut out;
|
|
52
|
-
float2 ndc = float2(in.position.x / viewport.x * 2.0 - 1.0,
|
|
53
|
-
1.0 - in.position.y / viewport.y * 2.0);
|
|
54
|
-
out.position = float4(ndc, 0.0, 1.0);
|
|
55
|
-
out.local = in.local;
|
|
56
|
-
out.halfsize = in.halfsize;
|
|
57
|
-
out.radius = in.radius;
|
|
58
|
-
out.color = in.color;
|
|
59
|
-
return out;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
fragment float4 fs_main(FillOut in [[stage_in]]) {
|
|
63
|
-
float2 d = abs(in.local) - in.halfsize + in.radius;
|
|
64
|
-
float dist = min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - in.radius;
|
|
65
|
-
float aa = max(fwidth(dist), 0.0001);
|
|
66
|
-
float alpha = clamp(0.5 - dist / aa, 0.0, 1.0);
|
|
67
|
-
return float4(in.color.rgb, in.color.a * alpha);
|
|
68
|
-
}
|
|
69
|
-
)MSL";
|
|
70
|
-
|
|
71
|
-
/* Glyph quads. Attributes:
|
|
72
|
-
* 0 -> position (pixels, viewport-relative)
|
|
73
|
-
* 1 -> uv (atlas coordinates in [0,1])
|
|
74
|
-
* 2 -> colour
|
|
75
|
-
* The fragment shader samples the single-channel atlas and modulates alpha. */
|
|
76
|
-
const char *const kTextMSL = R"MSL(
|
|
77
|
-
#include <metal_stdlib>
|
|
78
|
-
using namespace metal;
|
|
79
|
-
|
|
80
|
-
struct TextIn {
|
|
81
|
-
float2 position [[attribute(0)]];
|
|
82
|
-
float2 uv [[attribute(1)]];
|
|
83
|
-
float4 color [[attribute(2)]];
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
struct TextOut {
|
|
87
|
-
float4 position [[position]];
|
|
88
|
-
float2 uv;
|
|
89
|
-
float4 color;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
vertex TextOut vs_text(TextIn in [[stage_in]],
|
|
93
|
-
constant float2 &viewport [[buffer(0)]]) {
|
|
94
|
-
TextOut out;
|
|
95
|
-
float2 ndc = float2(in.position.x / viewport.x * 2.0 - 1.0,
|
|
96
|
-
1.0 - in.position.y / viewport.y * 2.0);
|
|
97
|
-
out.position = float4(ndc, 0.0, 1.0);
|
|
98
|
-
out.uv = in.uv;
|
|
99
|
-
out.color = in.color;
|
|
100
|
-
return out;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
fragment float4 fs_text(TextOut in [[stage_in]],
|
|
104
|
-
texture2d<float> atlas [[texture(0)]],
|
|
105
|
-
sampler samp [[sampler(0)]]) {
|
|
106
|
-
float coverage = atlas.sample(samp, in.uv).r;
|
|
107
|
-
return float4(in.color.rgb, in.color.a * coverage);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/* Image quads reuse the text vertex layout but sample an RGBA texture. */
|
|
111
|
-
fragment float4 fs_image(TextOut in [[stage_in]],
|
|
112
|
-
texture2d<float> tex [[texture(0)]],
|
|
113
|
-
sampler samp [[sampler(0)]]) {
|
|
114
|
-
float4 c = tex.sample(samp, in.uv);
|
|
115
|
-
return float4(c.rgb * in.color.rgb, c.a * in.color.a);
|
|
116
|
-
}
|
|
117
|
-
)MSL";
|
|
118
|
-
|
|
119
|
-
struct Vertex {
|
|
120
|
-
float x, y;
|
|
121
|
-
float lx, ly;
|
|
122
|
-
float hx, hy;
|
|
123
|
-
float radius;
|
|
124
|
-
float r, g, b, a;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
struct TextVertex {
|
|
128
|
-
float x, y;
|
|
129
|
-
float u, v;
|
|
130
|
-
float r, g, b, a;
|
|
131
|
-
};
|
|
22
|
+
namespace xtgui {
|
|
23
|
+
namespace renderer_detail {
|
|
132
24
|
|
|
133
25
|
SDL_GPUGraphicsPipeline *g_pipeline = nullptr;
|
|
134
26
|
SDL_GPUGraphicsPipeline *g_text_pipeline = nullptr;
|
|
@@ -136,40 +28,8 @@ SDL_GPUGraphicsPipeline *g_image_pipeline = nullptr;
|
|
|
136
28
|
SDL_GPUSampler *g_sampler = nullptr;
|
|
137
29
|
int g_renderer_failed = 0;
|
|
138
30
|
bool g_text_ok = false;
|
|
139
|
-
|
|
140
|
-
/* Image quads are batched by texture; textures are cached by source path. */
|
|
141
|
-
struct ImageBatch {
|
|
142
|
-
SDL_GPUTexture *texture = nullptr;
|
|
143
|
-
uint32_t first = 0;
|
|
144
|
-
uint32_t count = 0;
|
|
145
|
-
};
|
|
146
31
|
std::vector<ImageBatch> g_image_batches;
|
|
147
32
|
std::unordered_map<std::string, SDL_GPUTexture *> g_image_textures;
|
|
148
|
-
|
|
149
|
-
/* -- glyph atlas ---------------------------------------------------------- */
|
|
150
|
-
|
|
151
|
-
constexpr int kAtlasSize = 2048;
|
|
152
|
-
|
|
153
|
-
struct GlyphEntry {
|
|
154
|
-
float u0 = 0, v0 = 0, u1 = 0, v1 = 0;
|
|
155
|
-
int width = 0, height = 0, left = 0, top = 0;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
struct GlyphKey {
|
|
159
|
-
const void *font = nullptr;
|
|
160
|
-
uint32_t glyph = 0;
|
|
161
|
-
bool operator==(const GlyphKey &other) const {
|
|
162
|
-
return font == other.font && glyph == other.glyph;
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
struct GlyphKeyHash {
|
|
167
|
-
size_t operator()(const GlyphKey &key) const {
|
|
168
|
-
return std::hash<const void *>()(key.font) * 1099511628211ull ^
|
|
169
|
-
(size_t)(key.glyph * 2654435761u);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
33
|
SDL_GPUTexture *g_atlas_texture = nullptr;
|
|
174
34
|
std::vector<unsigned char> g_atlas_mirror;
|
|
175
35
|
std::unordered_map<GlyphKey, GlyphEntry, GlyphKeyHash> g_glyphs;
|
|
@@ -207,175 +67,6 @@ void pushRect(std::vector<Vertex> &verts, const xtgui::PaintRect &rect) {
|
|
|
207
67
|
for (int i = 0; i < 6; i++) verts.push_back(corners[order[i]]);
|
|
208
68
|
}
|
|
209
69
|
|
|
210
|
-
void pushGlyph(std::vector<TextVertex> &verts, float x, float y, float width, float height,
|
|
211
|
-
const GlyphEntry &entry, const xtgui::Color &color) {
|
|
212
|
-
const float corners_x[4] = {x, x + width, x + width, x};
|
|
213
|
-
const float corners_y[4] = {y, y, y + height, y + height};
|
|
214
|
-
const float u[4] = {entry.u0, entry.u1, entry.u1, entry.u0};
|
|
215
|
-
const float v[4] = {entry.v0, entry.v0, entry.v1, entry.v1};
|
|
216
|
-
TextVertex corners[4];
|
|
217
|
-
for (int i = 0; i < 4; i++) {
|
|
218
|
-
corners[i].x = corners_x[i];
|
|
219
|
-
corners[i].y = corners_y[i];
|
|
220
|
-
corners[i].u = u[i];
|
|
221
|
-
corners[i].v = v[i];
|
|
222
|
-
corners[i].r = color.r;
|
|
223
|
-
corners[i].g = color.g;
|
|
224
|
-
corners[i].b = color.b;
|
|
225
|
-
corners[i].a = color.a;
|
|
226
|
-
}
|
|
227
|
-
static const int order[6] = {0, 1, 2, 0, 2, 3};
|
|
228
|
-
for (int i = 0; i < 6; i++) verts.push_back(corners[order[i]]);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
bool ensureAtlasTexture(SDL_GPUDevice *device) {
|
|
232
|
-
if (g_atlas_texture != nullptr) return true;
|
|
233
|
-
SDL_GPUTextureCreateInfo info;
|
|
234
|
-
memset(&info, 0, sizeof(info));
|
|
235
|
-
info.type = SDL_GPU_TEXTURETYPE_2D;
|
|
236
|
-
info.format = SDL_GPU_TEXTUREFORMAT_R8_UNORM;
|
|
237
|
-
info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
|
238
|
-
info.width = kAtlasSize;
|
|
239
|
-
info.height = kAtlasSize;
|
|
240
|
-
info.layer_count_or_depth = 1;
|
|
241
|
-
info.num_levels = 1;
|
|
242
|
-
info.sample_count = SDL_GPU_SAMPLECOUNT_1;
|
|
243
|
-
g_atlas_texture = SDL_CreateGPUTexture(device, &info);
|
|
244
|
-
if (g_atlas_texture == nullptr) {
|
|
245
|
-
fprintf(stderr, "xt_gui: glyph atlas creation failed: %s\n", SDL_GetError());
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
g_atlas_mirror.assign((size_t)kAtlasSize * kAtlasSize, 0);
|
|
249
|
-
return true;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
void markAtlasDirty(int x, int y, int width, int height) {
|
|
253
|
-
if (!g_atlas_dirty) {
|
|
254
|
-
g_atlas_dirty_x0 = x;
|
|
255
|
-
g_atlas_dirty_y0 = y;
|
|
256
|
-
g_atlas_dirty_x1 = x + width;
|
|
257
|
-
g_atlas_dirty_y1 = y + height;
|
|
258
|
-
g_atlas_dirty = true;
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
g_atlas_dirty_x0 = std::min(g_atlas_dirty_x0, x);
|
|
262
|
-
g_atlas_dirty_y0 = std::min(g_atlas_dirty_y0, y);
|
|
263
|
-
g_atlas_dirty_x1 = std::max(g_atlas_dirty_x1, x + width);
|
|
264
|
-
g_atlas_dirty_y1 = std::max(g_atlas_dirty_y1, y + height);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/** Rasterise + pack `glyph` if new. Returns true and fills `out` when the glyph
|
|
268
|
-
* has a bitmap; false for blank glyphs (space, missing) or a full atlas. */
|
|
269
|
-
bool ensureGlyph(SDL_GPUDevice *device, xtgui::Font *font, uint32_t glyph, GlyphEntry &out) {
|
|
270
|
-
GlyphKey key{font, glyph};
|
|
271
|
-
auto found = g_glyphs.find(key);
|
|
272
|
-
if (found != g_glyphs.end()) {
|
|
273
|
-
out = found->second;
|
|
274
|
-
return out.width > 0 && out.height > 0;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
xtgui::GlyphImage image;
|
|
278
|
-
if (!xtgui::xt_text_rasterize(font, glyph, image) || image.width <= 0 || image.height <= 0) {
|
|
279
|
-
g_glyphs.emplace(key, GlyphEntry{});
|
|
280
|
-
return false;
|
|
281
|
-
}
|
|
282
|
-
if (!ensureAtlasTexture(device)) return false;
|
|
283
|
-
|
|
284
|
-
if (g_atlas_x + image.width > kAtlasSize) {
|
|
285
|
-
g_atlas_x = 0;
|
|
286
|
-
g_atlas_y += g_atlas_row_height + 1;
|
|
287
|
-
g_atlas_row_height = 0;
|
|
288
|
-
}
|
|
289
|
-
if (g_atlas_y + image.height > kAtlasSize) {
|
|
290
|
-
if (!g_atlas_full_logged) {
|
|
291
|
-
fprintf(stderr, "xt_gui: glyph atlas full; some glyphs will not be drawn\n");
|
|
292
|
-
g_atlas_full_logged = true;
|
|
293
|
-
}
|
|
294
|
-
g_glyphs.emplace(key, GlyphEntry{});
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
int px = g_atlas_x;
|
|
299
|
-
int py = g_atlas_y;
|
|
300
|
-
for (int row = 0; row < image.height; row++) {
|
|
301
|
-
std::memcpy(&g_atlas_mirror[(size_t)(py + row) * kAtlasSize + px],
|
|
302
|
-
image.pixels.data() + (size_t)row * image.width, (size_t)image.width);
|
|
303
|
-
}
|
|
304
|
-
markAtlasDirty(px, py, image.width, image.height);
|
|
305
|
-
|
|
306
|
-
GlyphEntry entry;
|
|
307
|
-
entry.u0 = (float)px / kAtlasSize;
|
|
308
|
-
entry.v0 = (float)py / kAtlasSize;
|
|
309
|
-
entry.u1 = (float)(px + image.width) / kAtlasSize;
|
|
310
|
-
entry.v1 = (float)(py + image.height) / kAtlasSize;
|
|
311
|
-
entry.width = image.width;
|
|
312
|
-
entry.height = image.height;
|
|
313
|
-
entry.left = image.left;
|
|
314
|
-
entry.top = image.top;
|
|
315
|
-
g_glyphs.emplace(key, entry);
|
|
316
|
-
|
|
317
|
-
g_atlas_x += image.width + 1;
|
|
318
|
-
g_atlas_row_height = std::max(g_atlas_row_height, image.height);
|
|
319
|
-
out = entry;
|
|
320
|
-
return true;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
void flushAtlas(SDL_GPUDevice *device) {
|
|
324
|
-
if (!g_atlas_dirty || g_atlas_texture == nullptr) return;
|
|
325
|
-
g_atlas_dirty = false;
|
|
326
|
-
int x0 = g_atlas_dirty_x0;
|
|
327
|
-
int y0 = g_atlas_dirty_y0;
|
|
328
|
-
int width = g_atlas_dirty_x1 - g_atlas_dirty_x0;
|
|
329
|
-
int height = g_atlas_dirty_y1 - g_atlas_dirty_y0;
|
|
330
|
-
if (width <= 0 || height <= 0) return;
|
|
331
|
-
|
|
332
|
-
uint32_t bytes = (uint32_t)(width * height);
|
|
333
|
-
SDL_GPUTransferBufferCreateInfo transfer_info;
|
|
334
|
-
memset(&transfer_info, 0, sizeof(transfer_info));
|
|
335
|
-
transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
|
336
|
-
transfer_info.size = bytes;
|
|
337
|
-
SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &transfer_info);
|
|
338
|
-
if (transfer == nullptr) return;
|
|
339
|
-
unsigned char *mapped = (unsigned char *)SDL_MapGPUTransferBuffer(device, transfer, false);
|
|
340
|
-
if (mapped == nullptr) {
|
|
341
|
-
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
for (int row = 0; row < height; row++) {
|
|
345
|
-
std::memcpy(mapped + (size_t)row * width,
|
|
346
|
-
&g_atlas_mirror[(size_t)(y0 + row) * kAtlasSize + x0], (size_t)width);
|
|
347
|
-
}
|
|
348
|
-
SDL_UnmapGPUTransferBuffer(device, transfer);
|
|
349
|
-
|
|
350
|
-
SDL_GPUCommandBuffer *cmd = SDL_AcquireGPUCommandBuffer(device);
|
|
351
|
-
if (cmd == nullptr) {
|
|
352
|
-
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
SDL_GPUTextureTransferInfo source;
|
|
356
|
-
memset(&source, 0, sizeof(source));
|
|
357
|
-
source.transfer_buffer = transfer;
|
|
358
|
-
source.offset = 0;
|
|
359
|
-
source.pixels_per_row = (Uint32)width;
|
|
360
|
-
source.rows_per_layer = (Uint32)height;
|
|
361
|
-
SDL_GPUTextureRegion destination;
|
|
362
|
-
memset(&destination, 0, sizeof(destination));
|
|
363
|
-
destination.texture = g_atlas_texture;
|
|
364
|
-
destination.mip_level = 0;
|
|
365
|
-
destination.layer = 0;
|
|
366
|
-
destination.x = (Uint32)x0;
|
|
367
|
-
destination.y = (Uint32)y0;
|
|
368
|
-
destination.z = 0;
|
|
369
|
-
destination.w = (Uint32)width;
|
|
370
|
-
destination.h = (Uint32)height;
|
|
371
|
-
destination.d = 1;
|
|
372
|
-
SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
|
|
373
|
-
SDL_UploadToGPUTexture(copy, &source, &destination, false);
|
|
374
|
-
SDL_EndGPUCopyPass(copy);
|
|
375
|
-
SDL_SubmitGPUCommandBuffer(cmd);
|
|
376
|
-
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
70
|
/** Upload `count` vertices (of `stride` bytes) into `geometry`, reusing or
|
|
380
71
|
* growing its GPU buffer. Does nothing when `count` is zero. */
|
|
381
72
|
void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *data,
|
|
@@ -432,255 +123,11 @@ void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *
|
|
|
432
123
|
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
433
124
|
}
|
|
434
125
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
memset(&vs_info, 0, sizeof(vs_info));
|
|
438
|
-
vs_info.code_size = strlen(kTextMSL);
|
|
439
|
-
vs_info.code = (const Uint8 *)kTextMSL;
|
|
440
|
-
vs_info.entrypoint = "vs_text";
|
|
441
|
-
vs_info.format = SDL_GPU_SHADERFORMAT_MSL;
|
|
442
|
-
vs_info.stage = SDL_GPU_SHADERSTAGE_VERTEX;
|
|
443
|
-
vs_info.num_uniform_buffers = 1;
|
|
444
|
-
SDL_GPUShader *vs = SDL_CreateGPUShader(device, &vs_info);
|
|
445
|
-
|
|
446
|
-
SDL_GPUShaderCreateInfo fs_info;
|
|
447
|
-
memset(&fs_info, 0, sizeof(fs_info));
|
|
448
|
-
fs_info.code_size = strlen(kTextMSL);
|
|
449
|
-
fs_info.code = (const Uint8 *)kTextMSL;
|
|
450
|
-
fs_info.entrypoint = "fs_text";
|
|
451
|
-
fs_info.format = SDL_GPU_SHADERFORMAT_MSL;
|
|
452
|
-
fs_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
|
|
453
|
-
fs_info.num_samplers = 1;
|
|
454
|
-
SDL_GPUShader *fs = SDL_CreateGPUShader(device, &fs_info);
|
|
455
|
-
|
|
456
|
-
if (vs == nullptr || fs == nullptr) {
|
|
457
|
-
fprintf(stderr, "xt_gui: text shader creation failed: %s\n", SDL_GetError());
|
|
458
|
-
if (vs != nullptr) SDL_ReleaseGPUShader(device, vs);
|
|
459
|
-
if (fs != nullptr) SDL_ReleaseGPUShader(device, fs);
|
|
460
|
-
return nullptr;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
SDL_GPUVertexBufferDescription vb_desc;
|
|
464
|
-
memset(&vb_desc, 0, sizeof(vb_desc));
|
|
465
|
-
vb_desc.slot = 0;
|
|
466
|
-
vb_desc.pitch = sizeof(TextVertex);
|
|
467
|
-
vb_desc.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
468
|
-
|
|
469
|
-
SDL_GPUVertexAttribute attrs[3];
|
|
470
|
-
memset(attrs, 0, sizeof(attrs));
|
|
471
|
-
attrs[0] = {0, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, (Uint32)offsetof(TextVertex, x)};
|
|
472
|
-
attrs[1] = {1, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, (Uint32)offsetof(TextVertex, u)};
|
|
473
|
-
attrs[2] = {2, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, (Uint32)offsetof(TextVertex, r)};
|
|
474
|
-
|
|
475
|
-
SDL_GPUColorTargetDescription color_target;
|
|
476
|
-
memset(&color_target, 0, sizeof(color_target));
|
|
477
|
-
color_target.format = SDL_GetGPUSwapchainTextureFormat(device, reference);
|
|
478
|
-
color_target.blend_state.enable_blend = true;
|
|
479
|
-
color_target.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
|
480
|
-
color_target.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
|
481
|
-
color_target.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD;
|
|
482
|
-
color_target.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
|
|
483
|
-
color_target.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
|
484
|
-
color_target.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD;
|
|
485
|
-
|
|
486
|
-
SDL_GPUGraphicsPipelineCreateInfo info;
|
|
487
|
-
memset(&info, 0, sizeof(info));
|
|
488
|
-
info.vertex_shader = vs;
|
|
489
|
-
info.fragment_shader = fs;
|
|
490
|
-
info.vertex_input_state.vertex_buffer_descriptions = &vb_desc;
|
|
491
|
-
info.vertex_input_state.num_vertex_buffers = 1;
|
|
492
|
-
info.vertex_input_state.vertex_attributes = attrs;
|
|
493
|
-
info.vertex_input_state.num_vertex_attributes = 3;
|
|
494
|
-
info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
|
495
|
-
info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
|
|
496
|
-
info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;
|
|
497
|
-
info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
|
|
498
|
-
info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
|
|
499
|
-
info.target_info.color_target_descriptions = &color_target;
|
|
500
|
-
info.target_info.num_color_targets = 1;
|
|
501
|
-
|
|
502
|
-
SDL_GPUGraphicsPipeline *pipeline = SDL_CreateGPUGraphicsPipeline(device, &info);
|
|
503
|
-
SDL_ReleaseGPUShader(device, vs);
|
|
504
|
-
SDL_ReleaseGPUShader(device, fs);
|
|
505
|
-
if (pipeline == nullptr) {
|
|
506
|
-
fprintf(stderr, "xt_gui: text pipeline creation failed: %s\n", SDL_GetError());
|
|
507
|
-
}
|
|
508
|
-
return pipeline;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
SDL_GPUSampler *createSampler(SDL_GPUDevice *device) {
|
|
512
|
-
SDL_GPUSamplerCreateInfo info;
|
|
513
|
-
memset(&info, 0, sizeof(info));
|
|
514
|
-
info.min_filter = SDL_GPU_FILTER_LINEAR;
|
|
515
|
-
info.mag_filter = SDL_GPU_FILTER_LINEAR;
|
|
516
|
-
info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
|
517
|
-
info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
|
518
|
-
info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
|
519
|
-
info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
|
520
|
-
SDL_GPUSampler *sampler = SDL_CreateGPUSampler(device, &info);
|
|
521
|
-
if (sampler == nullptr) {
|
|
522
|
-
fprintf(stderr, "xt_gui: glyph sampler creation failed: %s\n", SDL_GetError());
|
|
523
|
-
}
|
|
524
|
-
return sampler;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
SDL_GPUGraphicsPipeline *createImagePipeline(SDL_GPUDevice *device, SDL_Window *reference) {
|
|
528
|
-
SDL_GPUShaderCreateInfo vs_info;
|
|
529
|
-
memset(&vs_info, 0, sizeof(vs_info));
|
|
530
|
-
vs_info.code_size = strlen(kTextMSL);
|
|
531
|
-
vs_info.code = (const Uint8 *)kTextMSL;
|
|
532
|
-
vs_info.entrypoint = "vs_text";
|
|
533
|
-
vs_info.format = SDL_GPU_SHADERFORMAT_MSL;
|
|
534
|
-
vs_info.stage = SDL_GPU_SHADERSTAGE_VERTEX;
|
|
535
|
-
vs_info.num_uniform_buffers = 1;
|
|
536
|
-
SDL_GPUShader *vs = SDL_CreateGPUShader(device, &vs_info);
|
|
537
|
-
|
|
538
|
-
SDL_GPUShaderCreateInfo fs_info;
|
|
539
|
-
memset(&fs_info, 0, sizeof(fs_info));
|
|
540
|
-
fs_info.code_size = strlen(kTextMSL);
|
|
541
|
-
fs_info.code = (const Uint8 *)kTextMSL;
|
|
542
|
-
fs_info.entrypoint = "fs_image";
|
|
543
|
-
fs_info.format = SDL_GPU_SHADERFORMAT_MSL;
|
|
544
|
-
fs_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
|
|
545
|
-
fs_info.num_samplers = 1;
|
|
546
|
-
SDL_GPUShader *fs = SDL_CreateGPUShader(device, &fs_info);
|
|
547
|
-
|
|
548
|
-
if (vs == nullptr || fs == nullptr) {
|
|
549
|
-
fprintf(stderr, "xt_gui: image shader creation failed: %s\n", SDL_GetError());
|
|
550
|
-
if (vs != nullptr) SDL_ReleaseGPUShader(device, vs);
|
|
551
|
-
if (fs != nullptr) SDL_ReleaseGPUShader(device, fs);
|
|
552
|
-
return nullptr;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
SDL_GPUVertexBufferDescription vb_desc;
|
|
556
|
-
memset(&vb_desc, 0, sizeof(vb_desc));
|
|
557
|
-
vb_desc.slot = 0;
|
|
558
|
-
vb_desc.pitch = sizeof(TextVertex);
|
|
559
|
-
vb_desc.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
560
|
-
|
|
561
|
-
SDL_GPUVertexAttribute attrs[3];
|
|
562
|
-
memset(attrs, 0, sizeof(attrs));
|
|
563
|
-
attrs[0] = {0, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, (Uint32)offsetof(TextVertex, x)};
|
|
564
|
-
attrs[1] = {1, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, (Uint32)offsetof(TextVertex, u)};
|
|
565
|
-
attrs[2] = {2, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, (Uint32)offsetof(TextVertex, r)};
|
|
566
|
-
|
|
567
|
-
SDL_GPUColorTargetDescription color_target;
|
|
568
|
-
memset(&color_target, 0, sizeof(color_target));
|
|
569
|
-
color_target.format = SDL_GetGPUSwapchainTextureFormat(device, reference);
|
|
570
|
-
color_target.blend_state.enable_blend = true;
|
|
571
|
-
color_target.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
|
572
|
-
color_target.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
|
573
|
-
color_target.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD;
|
|
574
|
-
color_target.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
|
|
575
|
-
color_target.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
|
576
|
-
color_target.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD;
|
|
577
|
-
|
|
578
|
-
SDL_GPUGraphicsPipelineCreateInfo info;
|
|
579
|
-
memset(&info, 0, sizeof(info));
|
|
580
|
-
info.vertex_shader = vs;
|
|
581
|
-
info.fragment_shader = fs;
|
|
582
|
-
info.vertex_input_state.vertex_buffer_descriptions = &vb_desc;
|
|
583
|
-
info.vertex_input_state.num_vertex_buffers = 1;
|
|
584
|
-
info.vertex_input_state.vertex_attributes = attrs;
|
|
585
|
-
info.vertex_input_state.num_vertex_attributes = 3;
|
|
586
|
-
info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
|
587
|
-
info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
|
|
588
|
-
info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;
|
|
589
|
-
info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
|
|
590
|
-
info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
|
|
591
|
-
info.target_info.color_target_descriptions = &color_target;
|
|
592
|
-
info.target_info.num_color_targets = 1;
|
|
593
|
-
|
|
594
|
-
SDL_GPUGraphicsPipeline *pipeline = SDL_CreateGPUGraphicsPipeline(device, &info);
|
|
595
|
-
SDL_ReleaseGPUShader(device, vs);
|
|
596
|
-
SDL_ReleaseGPUShader(device, fs);
|
|
597
|
-
if (pipeline == nullptr) {
|
|
598
|
-
fprintf(stderr, "xt_gui: image pipeline creation failed: %s\n", SDL_GetError());
|
|
599
|
-
}
|
|
600
|
-
return pipeline;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
/** Decode `src` (cached) and upload it as an RGBA texture (cached by path). */
|
|
604
|
-
SDL_GPUTexture *ensureImageTexture(SDL_GPUDevice *device, const std::string &src) {
|
|
605
|
-
auto found = g_image_textures.find(src);
|
|
606
|
-
if (found != g_image_textures.end()) return found->second;
|
|
607
|
-
|
|
608
|
-
const xtgui::Image *image = xtgui::xt_image_load(src);
|
|
609
|
-
if (image == nullptr || image->width <= 0 || image->height <= 0) {
|
|
610
|
-
fprintf(stderr, "xt_gui: could not decode image '%s'\n", src.c_str());
|
|
611
|
-
g_image_textures.emplace(src, nullptr);
|
|
612
|
-
return nullptr;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
SDL_GPUTextureCreateInfo info;
|
|
616
|
-
memset(&info, 0, sizeof(info));
|
|
617
|
-
info.type = SDL_GPU_TEXTURETYPE_2D;
|
|
618
|
-
info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
619
|
-
info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
|
620
|
-
info.width = (Uint32)image->width;
|
|
621
|
-
info.height = (Uint32)image->height;
|
|
622
|
-
info.layer_count_or_depth = 1;
|
|
623
|
-
info.num_levels = 1;
|
|
624
|
-
info.sample_count = SDL_GPU_SAMPLECOUNT_1;
|
|
625
|
-
SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &info);
|
|
626
|
-
if (texture == nullptr) {
|
|
627
|
-
fprintf(stderr, "xt_gui: image texture creation failed: %s\n", SDL_GetError());
|
|
628
|
-
g_image_textures.emplace(src, nullptr);
|
|
629
|
-
return nullptr;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
uint32_t bytes = (uint32_t)(image->pixels.size());
|
|
633
|
-
SDL_GPUTransferBufferCreateInfo transfer_info;
|
|
634
|
-
memset(&transfer_info, 0, sizeof(transfer_info));
|
|
635
|
-
transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
|
636
|
-
transfer_info.size = bytes;
|
|
637
|
-
SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &transfer_info);
|
|
638
|
-
if (transfer == nullptr) {
|
|
639
|
-
SDL_ReleaseGPUTexture(device, texture);
|
|
640
|
-
g_image_textures.emplace(src, nullptr);
|
|
641
|
-
return nullptr;
|
|
642
|
-
}
|
|
643
|
-
void *mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
|
|
644
|
-
std::memcpy(mapped, image->pixels.data(), bytes);
|
|
645
|
-
SDL_UnmapGPUTransferBuffer(device, transfer);
|
|
646
|
-
|
|
647
|
-
SDL_GPUCommandBuffer *cmd = SDL_AcquireGPUCommandBuffer(device);
|
|
648
|
-
if (cmd == nullptr) {
|
|
649
|
-
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
650
|
-
SDL_ReleaseGPUTexture(device, texture);
|
|
651
|
-
g_image_textures.emplace(src, nullptr);
|
|
652
|
-
return nullptr;
|
|
653
|
-
}
|
|
654
|
-
SDL_GPUTextureTransferInfo source;
|
|
655
|
-
memset(&source, 0, sizeof(source));
|
|
656
|
-
source.transfer_buffer = transfer;
|
|
657
|
-
source.offset = 0;
|
|
658
|
-
source.pixels_per_row = (Uint32)image->width;
|
|
659
|
-
source.rows_per_layer = (Uint32)image->height;
|
|
660
|
-
SDL_GPUTextureRegion destination;
|
|
661
|
-
memset(&destination, 0, sizeof(destination));
|
|
662
|
-
destination.texture = texture;
|
|
663
|
-
destination.mip_level = 0;
|
|
664
|
-
destination.layer = 0;
|
|
665
|
-
destination.x = 0;
|
|
666
|
-
destination.y = 0;
|
|
667
|
-
destination.z = 0;
|
|
668
|
-
destination.w = (Uint32)image->width;
|
|
669
|
-
destination.h = (Uint32)image->height;
|
|
670
|
-
destination.d = 1;
|
|
671
|
-
SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
|
|
672
|
-
SDL_UploadToGPUTexture(copy, &source, &destination, false);
|
|
673
|
-
SDL_EndGPUCopyPass(copy);
|
|
674
|
-
SDL_SubmitGPUCommandBuffer(cmd);
|
|
675
|
-
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
676
|
-
|
|
677
|
-
g_image_textures.emplace(src, texture);
|
|
678
|
-
return texture;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
} // namespace
|
|
126
|
+
} // namespace renderer_detail
|
|
127
|
+
} // namespace xtgui
|
|
682
128
|
|
|
683
129
|
bool xt_gui_renderer_ensure(SDL_GPUDevice *device, SDL_Window *reference) {
|
|
130
|
+
using namespace xtgui::renderer_detail;
|
|
684
131
|
if (g_pipeline != nullptr) return true;
|
|
685
132
|
if (g_renderer_failed) return false;
|
|
686
133
|
if ((SDL_GetGPUShaderFormats(device) & SDL_GPU_SHADERFORMAT_MSL) == 0) {
|
|
@@ -776,6 +223,7 @@ bool xt_gui_renderer_ensure(SDL_GPUDevice *device, SDL_Window *reference) {
|
|
|
776
223
|
}
|
|
777
224
|
|
|
778
225
|
void xt_gui_renderer_destroy(SDL_GPUDevice *device) {
|
|
226
|
+
using namespace xtgui::renderer_detail;
|
|
779
227
|
if (g_pipeline != nullptr) {
|
|
780
228
|
SDL_ReleaseGPUGraphicsPipeline(device, g_pipeline);
|
|
781
229
|
g_pipeline = nullptr;
|
|
@@ -824,53 +272,16 @@ void xt_gui_geometry_destroy(SDL_GPUDevice *device, XtGuiGeometry *geometry) {
|
|
|
824
272
|
|
|
825
273
|
void xt_gui_geometry_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
826
274
|
const xtgui::DisplayList &list) {
|
|
275
|
+
using namespace xtgui::renderer_detail;
|
|
827
276
|
std::vector<Vertex> verts;
|
|
828
277
|
verts.reserve(list.rects.size() * 6);
|
|
829
278
|
for (const xtgui::PaintRect &rect : list.rects) pushRect(verts, rect);
|
|
830
279
|
uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(Vertex));
|
|
831
280
|
}
|
|
832
281
|
|
|
833
|
-
void xt_gui_text_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
834
|
-
const xtgui::DisplayList &list, float scale) {
|
|
835
|
-
if (!g_text_ok) {
|
|
836
|
-
geometry->vertex_count = 0;
|
|
837
|
-
return;
|
|
838
|
-
}
|
|
839
|
-
if (scale <= 0.0f) scale = 1.0f;
|
|
840
|
-
|
|
841
|
-
std::vector<TextVertex> verts;
|
|
842
|
-
for (const xtgui::PaintText &run : list.texts) {
|
|
843
|
-
if (run.text.empty() || run.color.a <= 0.0f) continue;
|
|
844
|
-
xtgui::Font *logical = xtgui::xt_text_resolve(run.font);
|
|
845
|
-
if (logical == nullptr) continue;
|
|
846
|
-
xtgui::FontSpec raster_spec = run.font;
|
|
847
|
-
raster_spec.pixel_size = run.font.pixel_size * scale;
|
|
848
|
-
xtgui::Font *raster = xtgui::xt_text_resolve(raster_spec);
|
|
849
|
-
if (raster == nullptr) raster = logical;
|
|
850
|
-
|
|
851
|
-
std::vector<xtgui::ShapedGlyph> glyphs;
|
|
852
|
-
xtgui::xt_text_shape_run(run.text, logical, glyphs);
|
|
853
|
-
float pen_x = run.x;
|
|
854
|
-
for (const xtgui::ShapedGlyph &glyph : glyphs) {
|
|
855
|
-
if (glyph.glyph != 0) {
|
|
856
|
-
GlyphEntry entry;
|
|
857
|
-
if (ensureGlyph(device, raster, glyph.glyph, entry)) {
|
|
858
|
-
float quad_x = pen_x + glyph.x_offset + (float)entry.left / scale;
|
|
859
|
-
float quad_y = run.baseline + glyph.y_offset - (float)entry.top / scale;
|
|
860
|
-
float quad_w = (float)entry.width / scale;
|
|
861
|
-
float quad_h = (float)entry.height / scale;
|
|
862
|
-
pushGlyph(verts, quad_x, quad_y, quad_w, quad_h, entry, run.color);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
pen_x += glyph.x_advance;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(TextVertex));
|
|
869
|
-
flushAtlas(device);
|
|
870
|
-
}
|
|
871
|
-
|
|
872
282
|
void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass,
|
|
873
283
|
XtGuiGeometry *geometry, float viewport_width, float viewport_height) {
|
|
284
|
+
using namespace xtgui::renderer_detail;
|
|
874
285
|
if (g_pipeline == nullptr || geometry->buffer == nullptr || geometry->vertex_count == 0) return;
|
|
875
286
|
if (viewport_width <= 0.0f || viewport_height <= 0.0f) return;
|
|
876
287
|
SDL_BindGPUGraphicsPipeline(pass, g_pipeline);
|
|
@@ -882,78 +293,3 @@ void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass,
|
|
|
882
293
|
SDL_PushGPUVertexUniformData(cmd, 0, viewport, sizeof(viewport));
|
|
883
294
|
SDL_DrawGPUPrimitives(pass, geometry->vertex_count, 1, 0, 0);
|
|
884
295
|
}
|
|
885
|
-
|
|
886
|
-
void xt_gui_text_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass, XtGuiGeometry *geometry,
|
|
887
|
-
float viewport_width, float viewport_height) {
|
|
888
|
-
if (!g_text_ok || geometry->buffer == nullptr || geometry->vertex_count == 0) return;
|
|
889
|
-
if (g_atlas_texture == nullptr) return;
|
|
890
|
-
if (viewport_width <= 0.0f || viewport_height <= 0.0f) return;
|
|
891
|
-
SDL_BindGPUGraphicsPipeline(pass, g_text_pipeline);
|
|
892
|
-
SDL_GPUBufferBinding binding;
|
|
893
|
-
binding.buffer = geometry->buffer;
|
|
894
|
-
binding.offset = 0;
|
|
895
|
-
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
|
|
896
|
-
SDL_GPUTextureSamplerBinding atlas_binding;
|
|
897
|
-
atlas_binding.texture = g_atlas_texture;
|
|
898
|
-
atlas_binding.sampler = g_sampler;
|
|
899
|
-
SDL_BindGPUFragmentSamplers(pass, 0, &atlas_binding, 1);
|
|
900
|
-
float viewport[2] = {viewport_width, viewport_height};
|
|
901
|
-
SDL_PushGPUVertexUniformData(cmd, 0, viewport, sizeof(viewport));
|
|
902
|
-
SDL_DrawGPUPrimitives(pass, geometry->vertex_count, 1, 0, 0);
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
void xt_gui_image_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
906
|
-
const xtgui::DisplayList &list) {
|
|
907
|
-
g_image_batches.clear();
|
|
908
|
-
if (g_image_pipeline == nullptr) {
|
|
909
|
-
geometry->vertex_count = 0;
|
|
910
|
-
return;
|
|
911
|
-
}
|
|
912
|
-
std::vector<TextVertex> verts;
|
|
913
|
-
verts.reserve(list.images.size() * 6);
|
|
914
|
-
xtgui::Color white{1.0f, 1.0f, 1.0f, 1.0f};
|
|
915
|
-
GlyphEntry full;
|
|
916
|
-
full.u0 = 0.0f;
|
|
917
|
-
full.v0 = 0.0f;
|
|
918
|
-
full.u1 = 1.0f;
|
|
919
|
-
full.v1 = 1.0f;
|
|
920
|
-
for (const xtgui::PaintImage &image : list.images) {
|
|
921
|
-
if (image.width <= 0.0f || image.height <= 0.0f) continue;
|
|
922
|
-
SDL_GPUTexture *texture = ensureImageTexture(device, image.src);
|
|
923
|
-
if (texture == nullptr) continue;
|
|
924
|
-
uint32_t first = (uint32_t)verts.size();
|
|
925
|
-
pushGlyph(verts, image.x, image.y, image.width, image.height, full, white);
|
|
926
|
-
g_image_batches.push_back(ImageBatch{texture, first, 6});
|
|
927
|
-
}
|
|
928
|
-
uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(TextVertex));
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
void xt_gui_image_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass, XtGuiGeometry *geometry,
|
|
932
|
-
float viewport_width, float viewport_height) {
|
|
933
|
-
if (g_image_pipeline == nullptr || g_sampler == nullptr) return;
|
|
934
|
-
if (geometry->buffer == nullptr || geometry->vertex_count == 0 || g_image_batches.empty()) return;
|
|
935
|
-
if (viewport_width <= 0.0f || viewport_height <= 0.0f) return;
|
|
936
|
-
SDL_BindGPUGraphicsPipeline(pass, g_image_pipeline);
|
|
937
|
-
SDL_GPUBufferBinding binding;
|
|
938
|
-
binding.buffer = geometry->buffer;
|
|
939
|
-
binding.offset = 0;
|
|
940
|
-
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
|
|
941
|
-
float viewport[2] = {viewport_width, viewport_height};
|
|
942
|
-
SDL_PushGPUVertexUniformData(cmd, 0, viewport, sizeof(viewport));
|
|
943
|
-
for (const ImageBatch &batch : g_image_batches) {
|
|
944
|
-
if (batch.texture == nullptr) continue;
|
|
945
|
-
SDL_GPUTextureSamplerBinding texture_binding;
|
|
946
|
-
texture_binding.texture = batch.texture;
|
|
947
|
-
texture_binding.sampler = g_sampler;
|
|
948
|
-
SDL_BindGPUFragmentSamplers(pass, 0, &texture_binding, 1);
|
|
949
|
-
SDL_DrawGPUPrimitives(pass, batch.count, 1, batch.first, 0);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
void xt_gui_image_textures_destroy(SDL_GPUDevice *device) {
|
|
954
|
-
for (auto &entry : g_image_textures) {
|
|
955
|
-
if (entry.second != nullptr) SDL_ReleaseGPUTexture(device, entry.second);
|
|
956
|
-
}
|
|
957
|
-
g_image_textures.clear();
|
|
958
|
-
g_image_batches.clear();
|
|
959
|
-
}
|