xbintsc 0.3.25 → 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.
Files changed (154) hide show
  1. package/README.md +33 -0
  2. package/dist/src/cli/main.js +124 -30
  3. package/dist/src/cli/main.js.map +1 -1
  4. package/dist/src/codegen/generator/calls/access.js +8 -1
  5. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  6. package/dist/src/codegen/generator/state.js +20 -0
  7. package/dist/src/codegen/generator/state.js.map +1 -1
  8. package/dist/src/codegen/generator/tables.d.ts +6 -0
  9. package/dist/src/codegen/generator/tables.js +38 -0
  10. package/dist/src/codegen/generator/tables.js.map +1 -1
  11. package/dist/src/driver/bundler/commonjs.d.ts +52 -0
  12. package/dist/src/driver/bundler/commonjs.js +493 -0
  13. package/dist/src/driver/bundler/commonjs.js.map +1 -0
  14. package/dist/src/driver/bundler/graph.js +14 -0
  15. package/dist/src/driver/bundler/graph.js.map +1 -1
  16. package/dist/src/driver/bundler/merge.js +14 -0
  17. package/dist/src/driver/bundler/merge.js.map +1 -1
  18. package/dist/src/driver/bundler/types.d.ts +8 -0
  19. package/dist/src/driver/compiler.d.ts +8 -1
  20. package/dist/src/driver/compiler.js +73 -5
  21. package/dist/src/driver/compiler.js.map +1 -1
  22. package/dist/src/driver/config.d.ts +53 -0
  23. package/dist/src/driver/config.js +141 -0
  24. package/dist/src/driver/config.js.map +1 -0
  25. package/dist/src/driver/icon.d.ts +62 -0
  26. package/dist/src/driver/icon.js +151 -0
  27. package/dist/src/driver/icon.js.map +1 -0
  28. package/dist/src/driver/index.d.ts +4 -0
  29. package/dist/src/driver/index.js +4 -0
  30. package/dist/src/driver/index.js.map +1 -1
  31. package/dist/src/driver/mac-bundle.d.ts +41 -0
  32. package/dist/src/driver/mac-bundle.js +123 -0
  33. package/dist/src/driver/mac-bundle.js.map +1 -0
  34. package/dist/src/driver/win-icon.d.ts +27 -0
  35. package/dist/src/driver/win-icon.js +80 -0
  36. package/dist/src/driver/win-icon.js.map +1 -0
  37. package/dist/src/parser/statements.js +17 -4
  38. package/dist/src/parser/statements.js.map +1 -1
  39. package/dist/tests/cli/main.test.js +46 -1
  40. package/dist/tests/cli/main.test.js.map +1 -1
  41. package/dist/tests/driver/config.test.d.ts +1 -0
  42. package/dist/tests/driver/config.test.js +124 -0
  43. package/dist/tests/driver/config.test.js.map +1 -0
  44. package/dist/tests/driver/icon.test.d.ts +1 -0
  45. package/dist/tests/driver/icon.test.js +421 -0
  46. package/dist/tests/driver/icon.test.js.map +1 -0
  47. package/dist/tests/driver/modules.test.js +109 -0
  48. package/dist/tests/driver/modules.test.js.map +1 -1
  49. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  50. package/dist/tests/e2e/fetch.test.js +272 -0
  51. package/dist/tests/e2e/fetch.test.js.map +1 -0
  52. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  53. package/dist/tests/e2e/gui-dom.test.js +102 -0
  54. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  55. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  56. package/dist/tests/e2e/gui-events.test.js +60 -0
  57. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  58. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  59. package/dist/tests/e2e/gui-helpers.js +74 -0
  60. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  61. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  62. package/dist/tests/e2e/gui-layout.test.js +88 -0
  63. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  64. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  65. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  66. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  67. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  68. package/dist/tests/e2e/gui-paint.test.js +111 -0
  69. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  70. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  71. package/dist/tests/e2e/gui-script.test.js +78 -0
  72. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  73. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  74. package/dist/tests/e2e/gui-style.test.js +175 -0
  75. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  76. package/dist/tests/e2e/icon.test.d.ts +7 -0
  77. package/dist/tests/e2e/icon.test.js +80 -0
  78. package/dist/tests/e2e/icon.test.js.map +1 -0
  79. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  80. package/dist/tests/e2e/npm-modules.test.js +47 -1
  81. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  82. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  83. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  84. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  85. package/dist/tests/parser/statements.test.js +11 -0
  86. package/dist/tests/parser/statements.test.js.map +1 -1
  87. package/package.json +1 -1
  88. package/runtime/ext_gui/css.cpp +4 -517
  89. package/runtime/ext_gui/css_internal.h +27 -0
  90. package/runtime/ext_gui/css_match.cpp +195 -0
  91. package/runtime/ext_gui/css_selector.cpp +207 -0
  92. package/runtime/ext_gui/css_sheet.cpp +129 -0
  93. package/runtime/ext_gui/dom.cpp +7 -403
  94. package/runtime/ext_gui/dom_api.cpp +63 -1146
  95. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  96. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  97. package/runtime/ext_gui/dom_api_internal.h +135 -0
  98. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  99. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  100. package/runtime/ext_gui/dom_api_proto.cpp +130 -0
  101. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  102. package/runtime/ext_gui/dom_internal.h +39 -0
  103. package/runtime/ext_gui/dom_parse.cpp +348 -0
  104. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  105. package/runtime/ext_gui/gui.cpp +56 -286
  106. package/runtime/ext_gui/gui_events.cpp +294 -0
  107. package/runtime/ext_gui/gui_internal.h +29 -0
  108. package/runtime/ext_gui/layout.cpp +6 -597
  109. package/runtime/ext_gui/layout_flex.cpp +200 -0
  110. package/runtime/ext_gui/layout_flow.cpp +191 -0
  111. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  112. package/runtime/ext_gui/layout_inline.cpp +181 -0
  113. package/runtime/ext_gui/layout_internal.h +20 -0
  114. package/runtime/ext_gui/renderer.cpp +15 -679
  115. package/runtime/ext_gui/renderer_image.cpp +233 -0
  116. package/runtime/ext_gui/renderer_internal.h +112 -0
  117. package/runtime/ext_gui/renderer_shaders.h +108 -0
  118. package/runtime/ext_gui/renderer_text.cpp +342 -0
  119. package/runtime/ext_gui/style.cpp +12 -660
  120. package/runtime/ext_gui/style_internal.h +33 -0
  121. package/runtime/ext_gui/style_print.cpp +113 -0
  122. package/runtime/ext_gui/style_ua.cpp +98 -0
  123. package/runtime/ext_gui/style_values.cpp +468 -0
  124. package/runtime/rt.h +6 -0
  125. package/runtime/rt_internal.h +4 -0
  126. package/runtime/xt_builtins.c +1 -0
  127. package/runtime/xt_containers/access.inc +32 -1
  128. package/runtime/xt_fetch/buffer.inc +64 -0
  129. package/runtime/xt_fetch/headers.inc +312 -0
  130. package/runtime/xt_fetch/request.inc +386 -0
  131. package/runtime/xt_fetch/response.inc +107 -0
  132. package/runtime/xt_fetch/socket.inc +72 -0
  133. package/runtime/xt_fetch/url.inc +108 -0
  134. package/runtime/xt_fetch.c +39 -0
  135. package/runtime/xt_stdlib2/set.inc +1 -1
  136. package/runtime/xt_typed_array.c +614 -0
  137. package/src/cli/main.ts +137 -29
  138. package/src/codegen/generator/calls/access.ts +9 -1
  139. package/src/codegen/generator/state.ts +20 -0
  140. package/src/codegen/generator/tables.ts +40 -0
  141. package/src/driver/bundler/commonjs.ts +553 -0
  142. package/src/driver/bundler/graph.ts +14 -0
  143. package/src/driver/bundler/merge.ts +15 -0
  144. package/src/driver/bundler/types.ts +8 -0
  145. package/src/driver/compiler.ts +83 -5
  146. package/src/driver/config.ts +173 -0
  147. package/src/driver/icon.ts +184 -0
  148. package/src/driver/index.ts +30 -0
  149. package/src/driver/mac-bundle.ts +156 -0
  150. package/src/driver/win-icon.ts +96 -0
  151. package/src/parser/statements.ts +17 -4
  152. package/dist/tests/e2e/gui.test.d.ts +0 -12
  153. package/dist/tests/e2e/gui.test.js +0 -702
  154. package/dist/tests/e2e/gui.test.js.map +0 -1
@@ -0,0 +1,342 @@
1
+ /*
2
+ * xbintsc GUI engine — SDL_GPU 2D renderer: glyph atlas and text geometry.
3
+ */
4
+
5
+ #include "renderer_internal.h"
6
+
7
+ #include <algorithm>
8
+ #include <cstddef>
9
+ #include <cstdint>
10
+ #include <cstdio>
11
+ #include <cstring>
12
+
13
+ #include "text.h"
14
+
15
+ #include "renderer_shaders.h"
16
+
17
+ namespace xtgui {
18
+ namespace renderer_detail {
19
+
20
+ void pushGlyph(std::vector<TextVertex> &verts, float x, float y, float width, float height,
21
+ const GlyphEntry &entry, const xtgui::Color &color) {
22
+ const float corners_x[4] = {x, x + width, x + width, x};
23
+ const float corners_y[4] = {y, y, y + height, y + height};
24
+ const float u[4] = {entry.u0, entry.u1, entry.u1, entry.u0};
25
+ const float v[4] = {entry.v0, entry.v0, entry.v1, entry.v1};
26
+ TextVertex corners[4];
27
+ for (int i = 0; i < 4; i++) {
28
+ corners[i].x = corners_x[i];
29
+ corners[i].y = corners_y[i];
30
+ corners[i].u = u[i];
31
+ corners[i].v = v[i];
32
+ corners[i].r = color.r;
33
+ corners[i].g = color.g;
34
+ corners[i].b = color.b;
35
+ corners[i].a = color.a;
36
+ }
37
+ static const int order[6] = {0, 1, 2, 0, 2, 3};
38
+ for (int i = 0; i < 6; i++) verts.push_back(corners[order[i]]);
39
+ }
40
+
41
+ bool ensureAtlasTexture(SDL_GPUDevice *device) {
42
+ if (g_atlas_texture != nullptr) return true;
43
+ SDL_GPUTextureCreateInfo info;
44
+ memset(&info, 0, sizeof(info));
45
+ info.type = SDL_GPU_TEXTURETYPE_2D;
46
+ info.format = SDL_GPU_TEXTUREFORMAT_R8_UNORM;
47
+ info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
48
+ info.width = kAtlasSize;
49
+ info.height = kAtlasSize;
50
+ info.layer_count_or_depth = 1;
51
+ info.num_levels = 1;
52
+ info.sample_count = SDL_GPU_SAMPLECOUNT_1;
53
+ g_atlas_texture = SDL_CreateGPUTexture(device, &info);
54
+ if (g_atlas_texture == nullptr) {
55
+ fprintf(stderr, "xt_gui: glyph atlas creation failed: %s\n", SDL_GetError());
56
+ return false;
57
+ }
58
+ g_atlas_mirror.assign((size_t)kAtlasSize * kAtlasSize, 0);
59
+ return true;
60
+ }
61
+
62
+ void markAtlasDirty(int x, int y, int width, int height) {
63
+ if (!g_atlas_dirty) {
64
+ g_atlas_dirty_x0 = x;
65
+ g_atlas_dirty_y0 = y;
66
+ g_atlas_dirty_x1 = x + width;
67
+ g_atlas_dirty_y1 = y + height;
68
+ g_atlas_dirty = true;
69
+ return;
70
+ }
71
+ g_atlas_dirty_x0 = std::min(g_atlas_dirty_x0, x);
72
+ g_atlas_dirty_y0 = std::min(g_atlas_dirty_y0, y);
73
+ g_atlas_dirty_x1 = std::max(g_atlas_dirty_x1, x + width);
74
+ g_atlas_dirty_y1 = std::max(g_atlas_dirty_y1, y + height);
75
+ }
76
+
77
+ /** Rasterise + pack `glyph` if new. Returns true and fills `out` when the glyph
78
+ * has a bitmap; false for blank glyphs (space, missing) or a full atlas. */
79
+ bool ensureGlyph(SDL_GPUDevice *device, xtgui::Font *font, uint32_t glyph, GlyphEntry &out) {
80
+ GlyphKey key{font, glyph};
81
+ auto found = g_glyphs.find(key);
82
+ if (found != g_glyphs.end()) {
83
+ out = found->second;
84
+ return out.width > 0 && out.height > 0;
85
+ }
86
+
87
+ xtgui::GlyphImage image;
88
+ if (!xtgui::xt_text_rasterize(font, glyph, image) || image.width <= 0 || image.height <= 0) {
89
+ g_glyphs.emplace(key, GlyphEntry{});
90
+ return false;
91
+ }
92
+ if (!ensureAtlasTexture(device)) return false;
93
+
94
+ if (g_atlas_x + image.width > kAtlasSize) {
95
+ g_atlas_x = 0;
96
+ g_atlas_y += g_atlas_row_height + 1;
97
+ g_atlas_row_height = 0;
98
+ }
99
+ if (g_atlas_y + image.height > kAtlasSize) {
100
+ if (!g_atlas_full_logged) {
101
+ fprintf(stderr, "xt_gui: glyph atlas full; some glyphs will not be drawn\n");
102
+ g_atlas_full_logged = true;
103
+ }
104
+ g_glyphs.emplace(key, GlyphEntry{});
105
+ return false;
106
+ }
107
+
108
+ int px = g_atlas_x;
109
+ int py = g_atlas_y;
110
+ for (int row = 0; row < image.height; row++) {
111
+ std::memcpy(&g_atlas_mirror[(size_t)(py + row) * kAtlasSize + px],
112
+ image.pixels.data() + (size_t)row * image.width, (size_t)image.width);
113
+ }
114
+ markAtlasDirty(px, py, image.width, image.height);
115
+
116
+ GlyphEntry entry;
117
+ entry.u0 = (float)px / kAtlasSize;
118
+ entry.v0 = (float)py / kAtlasSize;
119
+ entry.u1 = (float)(px + image.width) / kAtlasSize;
120
+ entry.v1 = (float)(py + image.height) / kAtlasSize;
121
+ entry.width = image.width;
122
+ entry.height = image.height;
123
+ entry.left = image.left;
124
+ entry.top = image.top;
125
+ g_glyphs.emplace(key, entry);
126
+
127
+ g_atlas_x += image.width + 1;
128
+ g_atlas_row_height = std::max(g_atlas_row_height, image.height);
129
+ out = entry;
130
+ return true;
131
+ }
132
+
133
+ void flushAtlas(SDL_GPUDevice *device) {
134
+ if (!g_atlas_dirty || g_atlas_texture == nullptr) return;
135
+ g_atlas_dirty = false;
136
+ int x0 = g_atlas_dirty_x0;
137
+ int y0 = g_atlas_dirty_y0;
138
+ int width = g_atlas_dirty_x1 - g_atlas_dirty_x0;
139
+ int height = g_atlas_dirty_y1 - g_atlas_dirty_y0;
140
+ if (width <= 0 || height <= 0) return;
141
+
142
+ uint32_t bytes = (uint32_t)(width * height);
143
+ SDL_GPUTransferBufferCreateInfo transfer_info;
144
+ memset(&transfer_info, 0, sizeof(transfer_info));
145
+ transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
146
+ transfer_info.size = bytes;
147
+ SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &transfer_info);
148
+ if (transfer == nullptr) return;
149
+ unsigned char *mapped = (unsigned char *)SDL_MapGPUTransferBuffer(device, transfer, false);
150
+ if (mapped == nullptr) {
151
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
152
+ return;
153
+ }
154
+ for (int row = 0; row < height; row++) {
155
+ std::memcpy(mapped + (size_t)row * width,
156
+ &g_atlas_mirror[(size_t)(y0 + row) * kAtlasSize + x0], (size_t)width);
157
+ }
158
+ SDL_UnmapGPUTransferBuffer(device, transfer);
159
+
160
+ SDL_GPUCommandBuffer *cmd = SDL_AcquireGPUCommandBuffer(device);
161
+ if (cmd == nullptr) {
162
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
163
+ return;
164
+ }
165
+ SDL_GPUTextureTransferInfo source;
166
+ memset(&source, 0, sizeof(source));
167
+ source.transfer_buffer = transfer;
168
+ source.offset = 0;
169
+ source.pixels_per_row = (Uint32)width;
170
+ source.rows_per_layer = (Uint32)height;
171
+ SDL_GPUTextureRegion destination;
172
+ memset(&destination, 0, sizeof(destination));
173
+ destination.texture = g_atlas_texture;
174
+ destination.mip_level = 0;
175
+ destination.layer = 0;
176
+ destination.x = (Uint32)x0;
177
+ destination.y = (Uint32)y0;
178
+ destination.z = 0;
179
+ destination.w = (Uint32)width;
180
+ destination.h = (Uint32)height;
181
+ destination.d = 1;
182
+ SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
183
+ SDL_UploadToGPUTexture(copy, &source, &destination, false);
184
+ SDL_EndGPUCopyPass(copy);
185
+ SDL_SubmitGPUCommandBuffer(cmd);
186
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
187
+ }
188
+
189
+ SDL_GPUGraphicsPipeline *createTextPipeline(SDL_GPUDevice *device, SDL_Window *reference) {
190
+ SDL_GPUShaderCreateInfo vs_info;
191
+ memset(&vs_info, 0, sizeof(vs_info));
192
+ vs_info.code_size = strlen(kTextMSL);
193
+ vs_info.code = (const Uint8 *)kTextMSL;
194
+ vs_info.entrypoint = "vs_text";
195
+ vs_info.format = SDL_GPU_SHADERFORMAT_MSL;
196
+ vs_info.stage = SDL_GPU_SHADERSTAGE_VERTEX;
197
+ vs_info.num_uniform_buffers = 1;
198
+ SDL_GPUShader *vs = SDL_CreateGPUShader(device, &vs_info);
199
+
200
+ SDL_GPUShaderCreateInfo fs_info;
201
+ memset(&fs_info, 0, sizeof(fs_info));
202
+ fs_info.code_size = strlen(kTextMSL);
203
+ fs_info.code = (const Uint8 *)kTextMSL;
204
+ fs_info.entrypoint = "fs_text";
205
+ fs_info.format = SDL_GPU_SHADERFORMAT_MSL;
206
+ fs_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
207
+ fs_info.num_samplers = 1;
208
+ SDL_GPUShader *fs = SDL_CreateGPUShader(device, &fs_info);
209
+
210
+ if (vs == nullptr || fs == nullptr) {
211
+ fprintf(stderr, "xt_gui: text shader creation failed: %s\n", SDL_GetError());
212
+ if (vs != nullptr) SDL_ReleaseGPUShader(device, vs);
213
+ if (fs != nullptr) SDL_ReleaseGPUShader(device, fs);
214
+ return nullptr;
215
+ }
216
+
217
+ SDL_GPUVertexBufferDescription vb_desc;
218
+ memset(&vb_desc, 0, sizeof(vb_desc));
219
+ vb_desc.slot = 0;
220
+ vb_desc.pitch = sizeof(TextVertex);
221
+ vb_desc.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
222
+
223
+ SDL_GPUVertexAttribute attrs[3];
224
+ memset(attrs, 0, sizeof(attrs));
225
+ attrs[0] = {0, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, (Uint32)offsetof(TextVertex, x)};
226
+ attrs[1] = {1, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, (Uint32)offsetof(TextVertex, u)};
227
+ attrs[2] = {2, 0, SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, (Uint32)offsetof(TextVertex, r)};
228
+
229
+ SDL_GPUColorTargetDescription color_target;
230
+ memset(&color_target, 0, sizeof(color_target));
231
+ color_target.format = SDL_GetGPUSwapchainTextureFormat(device, reference);
232
+ color_target.blend_state.enable_blend = true;
233
+ color_target.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
234
+ color_target.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
235
+ color_target.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD;
236
+ color_target.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
237
+ color_target.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
238
+ color_target.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD;
239
+
240
+ SDL_GPUGraphicsPipelineCreateInfo info;
241
+ memset(&info, 0, sizeof(info));
242
+ info.vertex_shader = vs;
243
+ info.fragment_shader = fs;
244
+ info.vertex_input_state.vertex_buffer_descriptions = &vb_desc;
245
+ info.vertex_input_state.num_vertex_buffers = 1;
246
+ info.vertex_input_state.vertex_attributes = attrs;
247
+ info.vertex_input_state.num_vertex_attributes = 3;
248
+ info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
249
+ info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
250
+ info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;
251
+ info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
252
+ info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
253
+ info.target_info.color_target_descriptions = &color_target;
254
+ info.target_info.num_color_targets = 1;
255
+
256
+ SDL_GPUGraphicsPipeline *pipeline = SDL_CreateGPUGraphicsPipeline(device, &info);
257
+ SDL_ReleaseGPUShader(device, vs);
258
+ SDL_ReleaseGPUShader(device, fs);
259
+ if (pipeline == nullptr) {
260
+ fprintf(stderr, "xt_gui: text pipeline creation failed: %s\n", SDL_GetError());
261
+ }
262
+ return pipeline;
263
+ }
264
+
265
+ SDL_GPUSampler *createSampler(SDL_GPUDevice *device) {
266
+ SDL_GPUSamplerCreateInfo info;
267
+ memset(&info, 0, sizeof(info));
268
+ info.min_filter = SDL_GPU_FILTER_LINEAR;
269
+ info.mag_filter = SDL_GPU_FILTER_LINEAR;
270
+ info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
271
+ info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
272
+ info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
273
+ info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
274
+ SDL_GPUSampler *sampler = SDL_CreateGPUSampler(device, &info);
275
+ if (sampler == nullptr) {
276
+ fprintf(stderr, "xt_gui: glyph sampler creation failed: %s\n", SDL_GetError());
277
+ }
278
+ return sampler;
279
+ }
280
+
281
+ } // namespace renderer_detail
282
+ } // namespace xtgui
283
+
284
+ void xt_gui_text_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
285
+ const xtgui::DisplayList &list, float scale) {
286
+ using namespace xtgui::renderer_detail;
287
+ if (!g_text_ok) {
288
+ geometry->vertex_count = 0;
289
+ return;
290
+ }
291
+ if (scale <= 0.0f) scale = 1.0f;
292
+
293
+ std::vector<TextVertex> verts;
294
+ for (const xtgui::PaintText &run : list.texts) {
295
+ if (run.text.empty() || run.color.a <= 0.0f) continue;
296
+ xtgui::Font *logical = xtgui::xt_text_resolve(run.font);
297
+ if (logical == nullptr) continue;
298
+ xtgui::FontSpec raster_spec = run.font;
299
+ raster_spec.pixel_size = run.font.pixel_size * scale;
300
+ xtgui::Font *raster = xtgui::xt_text_resolve(raster_spec);
301
+ if (raster == nullptr) raster = logical;
302
+
303
+ std::vector<xtgui::ShapedGlyph> glyphs;
304
+ xtgui::xt_text_shape_run(run.text, logical, glyphs);
305
+ float pen_x = run.x;
306
+ for (const xtgui::ShapedGlyph &glyph : glyphs) {
307
+ if (glyph.glyph != 0) {
308
+ GlyphEntry entry;
309
+ if (ensureGlyph(device, raster, glyph.glyph, entry)) {
310
+ float quad_x = pen_x + glyph.x_offset + (float)entry.left / scale;
311
+ float quad_y = run.baseline + glyph.y_offset - (float)entry.top / scale;
312
+ float quad_w = (float)entry.width / scale;
313
+ float quad_h = (float)entry.height / scale;
314
+ pushGlyph(verts, quad_x, quad_y, quad_w, quad_h, entry, run.color);
315
+ }
316
+ }
317
+ pen_x += glyph.x_advance;
318
+ }
319
+ }
320
+ uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(TextVertex));
321
+ flushAtlas(device);
322
+ }
323
+
324
+ void xt_gui_text_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass, XtGuiGeometry *geometry,
325
+ float viewport_width, float viewport_height) {
326
+ using namespace xtgui::renderer_detail;
327
+ if (!g_text_ok || geometry->buffer == nullptr || geometry->vertex_count == 0) return;
328
+ if (g_atlas_texture == nullptr) return;
329
+ if (viewport_width <= 0.0f || viewport_height <= 0.0f) return;
330
+ SDL_BindGPUGraphicsPipeline(pass, g_text_pipeline);
331
+ SDL_GPUBufferBinding binding;
332
+ binding.buffer = geometry->buffer;
333
+ binding.offset = 0;
334
+ SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
335
+ SDL_GPUTextureSamplerBinding atlas_binding;
336
+ atlas_binding.texture = g_atlas_texture;
337
+ atlas_binding.sampler = g_sampler;
338
+ SDL_BindGPUFragmentSamplers(pass, 0, &atlas_binding, 1);
339
+ float viewport[2] = {viewport_width, viewport_height};
340
+ SDL_PushGPUVertexUniformData(cmd, 0, viewport, sizeof(viewport));
341
+ SDL_DrawGPUPrimitives(pass, geometry->vertex_count, 1, 0, 0);
342
+ }