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.
Files changed (194) 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.d.ts +2 -1
  15. package/dist/src/driver/bundler/graph.js +32 -3
  16. package/dist/src/driver/bundler/graph.js.map +1 -1
  17. package/dist/src/driver/bundler/merge.d.ts +2 -1
  18. package/dist/src/driver/bundler/merge.js +16 -2
  19. package/dist/src/driver/bundler/merge.js.map +1 -1
  20. package/dist/src/driver/bundler/types.d.ts +8 -0
  21. package/dist/src/driver/compiler.d.ts +8 -1
  22. package/dist/src/driver/compiler.js +75 -7
  23. package/dist/src/driver/compiler.js.map +1 -1
  24. package/dist/src/driver/config.d.ts +53 -0
  25. package/dist/src/driver/config.js +141 -0
  26. package/dist/src/driver/config.js.map +1 -0
  27. package/dist/src/driver/icon.d.ts +62 -0
  28. package/dist/src/driver/icon.js +151 -0
  29. package/dist/src/driver/icon.js.map +1 -0
  30. package/dist/src/driver/index.d.ts +4 -0
  31. package/dist/src/driver/index.js +4 -0
  32. package/dist/src/driver/index.js.map +1 -1
  33. package/dist/src/driver/mac-bundle.d.ts +41 -0
  34. package/dist/src/driver/mac-bundle.js +123 -0
  35. package/dist/src/driver/mac-bundle.js.map +1 -0
  36. package/dist/src/driver/win-icon.d.ts +27 -0
  37. package/dist/src/driver/win-icon.js +80 -0
  38. package/dist/src/driver/win-icon.js.map +1 -0
  39. package/dist/src/extensions/gui/html.d.ts +25 -0
  40. package/dist/src/extensions/gui/html.js +203 -0
  41. package/dist/src/extensions/gui/html.js.map +1 -0
  42. package/dist/src/extensions/gui/index.js +11 -0
  43. package/dist/src/extensions/gui/index.js.map +1 -1
  44. package/dist/src/extensions/registry.d.ts +29 -0
  45. package/dist/src/extensions/registry.js +14 -0
  46. package/dist/src/extensions/registry.js.map +1 -1
  47. package/dist/src/index.d.ts +1 -1
  48. package/dist/src/index.js.map +1 -1
  49. package/dist/src/lexer/scanner/identifiers.js +4 -12
  50. package/dist/src/lexer/scanner/identifiers.js.map +1 -1
  51. package/dist/src/parser/statements.js +17 -4
  52. package/dist/src/parser/statements.js.map +1 -1
  53. package/dist/tests/cli/main.test.js +46 -1
  54. package/dist/tests/cli/main.test.js.map +1 -1
  55. package/dist/tests/driver/bundler-resolve.test.d.ts +1 -0
  56. package/dist/tests/driver/bundler-resolve.test.js +230 -0
  57. package/dist/tests/driver/bundler-resolve.test.js.map +1 -0
  58. package/dist/tests/driver/config.test.d.ts +1 -0
  59. package/dist/tests/driver/config.test.js +124 -0
  60. package/dist/tests/driver/config.test.js.map +1 -0
  61. package/dist/tests/driver/icon.test.d.ts +1 -0
  62. package/dist/tests/driver/icon.test.js +421 -0
  63. package/dist/tests/driver/icon.test.js.map +1 -0
  64. package/dist/tests/driver/modules.test.js +177 -0
  65. package/dist/tests/driver/modules.test.js.map +1 -1
  66. package/dist/tests/e2e/fetch.test.d.ts +12 -0
  67. package/dist/tests/e2e/fetch.test.js +272 -0
  68. package/dist/tests/e2e/fetch.test.js.map +1 -0
  69. package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
  70. package/dist/tests/e2e/gui-dom.test.js +102 -0
  71. package/dist/tests/e2e/gui-dom.test.js.map +1 -0
  72. package/dist/tests/e2e/gui-events.test.d.ts +5 -0
  73. package/dist/tests/e2e/gui-events.test.js +60 -0
  74. package/dist/tests/e2e/gui-events.test.js.map +1 -0
  75. package/dist/tests/e2e/gui-helpers.d.ts +31 -0
  76. package/dist/tests/e2e/gui-helpers.js +74 -0
  77. package/dist/tests/e2e/gui-helpers.js.map +1 -0
  78. package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
  79. package/dist/tests/e2e/gui-layout.test.js +88 -0
  80. package/dist/tests/e2e/gui-layout.test.js.map +1 -0
  81. package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
  82. package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
  83. package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
  84. package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
  85. package/dist/tests/e2e/gui-paint.test.js +111 -0
  86. package/dist/tests/e2e/gui-paint.test.js.map +1 -0
  87. package/dist/tests/e2e/gui-script.test.d.ts +5 -0
  88. package/dist/tests/e2e/gui-script.test.js +78 -0
  89. package/dist/tests/e2e/gui-script.test.js.map +1 -0
  90. package/dist/tests/e2e/gui-style.test.d.ts +5 -0
  91. package/dist/tests/e2e/gui-style.test.js +175 -0
  92. package/dist/tests/e2e/gui-style.test.js.map +1 -0
  93. package/dist/tests/e2e/icon.test.d.ts +7 -0
  94. package/dist/tests/e2e/icon.test.js +80 -0
  95. package/dist/tests/e2e/icon.test.js.map +1 -0
  96. package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
  97. package/dist/tests/e2e/npm-modules.test.js +47 -1
  98. package/dist/tests/e2e/npm-modules.test.js.map +1 -1
  99. package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
  100. package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
  101. package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
  102. package/dist/tests/extensions/gui-index.test.d.ts +1 -0
  103. package/dist/tests/extensions/gui-index.test.js +49 -0
  104. package/dist/tests/extensions/gui-index.test.js.map +1 -0
  105. package/dist/tests/extensions/gui.test.d.ts +1 -0
  106. package/dist/tests/extensions/gui.test.js +177 -0
  107. package/dist/tests/extensions/gui.test.js.map +1 -0
  108. package/dist/tests/extensions/registry.test.js +36 -0
  109. package/dist/tests/extensions/registry.test.js.map +1 -1
  110. package/dist/tests/parser/statements.test.js +11 -0
  111. package/dist/tests/parser/statements.test.js.map +1 -1
  112. package/dist/tests/public-api.test.d.ts +1 -0
  113. package/dist/tests/public-api.test.js +31 -0
  114. package/dist/tests/public-api.test.js.map +1 -0
  115. package/package.json +1 -1
  116. package/runtime/ext_gui/css.cpp +4 -517
  117. package/runtime/ext_gui/css_internal.h +27 -0
  118. package/runtime/ext_gui/css_match.cpp +195 -0
  119. package/runtime/ext_gui/css_selector.cpp +207 -0
  120. package/runtime/ext_gui/css_sheet.cpp +129 -0
  121. package/runtime/ext_gui/document.cpp +90 -0
  122. package/runtime/ext_gui/document.h +23 -0
  123. package/runtime/ext_gui/dom.cpp +43 -403
  124. package/runtime/ext_gui/dom.h +7 -0
  125. package/runtime/ext_gui/dom_api.cpp +164 -0
  126. package/runtime/ext_gui/dom_api.h +12 -0
  127. package/runtime/ext_gui/dom_api_document.cpp +96 -0
  128. package/runtime/ext_gui/dom_api_events.cpp +123 -0
  129. package/runtime/ext_gui/dom_api_internal.h +135 -0
  130. package/runtime/ext_gui/dom_api_node.cpp +329 -0
  131. package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
  132. package/runtime/ext_gui/dom_api_proto.cpp +130 -0
  133. package/runtime/ext_gui/dom_api_style.cpp +192 -0
  134. package/runtime/ext_gui/dom_internal.h +39 -0
  135. package/runtime/ext_gui/dom_parse.cpp +348 -0
  136. package/runtime/ext_gui/dom_serialize.cpp +54 -0
  137. package/runtime/ext_gui/gui.cpp +61 -245
  138. package/runtime/ext_gui/gui_engine.h +54 -0
  139. package/runtime/ext_gui/gui_events.cpp +294 -0
  140. package/runtime/ext_gui/gui_internal.h +29 -0
  141. package/runtime/ext_gui/layout.cpp +6 -597
  142. package/runtime/ext_gui/layout_flex.cpp +200 -0
  143. package/runtime/ext_gui/layout_flow.cpp +191 -0
  144. package/runtime/ext_gui/layout_flow_internal.h +149 -0
  145. package/runtime/ext_gui/layout_inline.cpp +181 -0
  146. package/runtime/ext_gui/layout_internal.h +20 -0
  147. package/runtime/ext_gui/renderer.cpp +15 -679
  148. package/runtime/ext_gui/renderer_image.cpp +233 -0
  149. package/runtime/ext_gui/renderer_internal.h +112 -0
  150. package/runtime/ext_gui/renderer_shaders.h +108 -0
  151. package/runtime/ext_gui/renderer_text.cpp +342 -0
  152. package/runtime/ext_gui/script.cpp +63 -0
  153. package/runtime/ext_gui/style.cpp +12 -660
  154. package/runtime/ext_gui/style_internal.h +33 -0
  155. package/runtime/ext_gui/style_print.cpp +113 -0
  156. package/runtime/ext_gui/style_ua.cpp +98 -0
  157. package/runtime/ext_gui/style_values.cpp +468 -0
  158. package/runtime/ext_gui/window.cpp +60 -0
  159. package/runtime/rt.h +6 -0
  160. package/runtime/rt_internal.h +4 -0
  161. package/runtime/xt_builtins.c +1 -0
  162. package/runtime/xt_containers/access.inc +32 -1
  163. package/runtime/xt_fetch/buffer.inc +64 -0
  164. package/runtime/xt_fetch/headers.inc +312 -0
  165. package/runtime/xt_fetch/request.inc +386 -0
  166. package/runtime/xt_fetch/response.inc +107 -0
  167. package/runtime/xt_fetch/socket.inc +72 -0
  168. package/runtime/xt_fetch/url.inc +108 -0
  169. package/runtime/xt_fetch.c +39 -0
  170. package/runtime/xt_stdlib2/set.inc +1 -1
  171. package/runtime/xt_typed_array.c +614 -0
  172. package/src/cli/main.ts +137 -29
  173. package/src/codegen/generator/calls/access.ts +9 -1
  174. package/src/codegen/generator/state.ts +20 -0
  175. package/src/codegen/generator/tables.ts +40 -0
  176. package/src/driver/bundler/commonjs.ts +553 -0
  177. package/src/driver/bundler/graph.ts +35 -2
  178. package/src/driver/bundler/merge.ts +18 -1
  179. package/src/driver/bundler/types.ts +8 -0
  180. package/src/driver/compiler.ts +85 -7
  181. package/src/driver/config.ts +173 -0
  182. package/src/driver/icon.ts +184 -0
  183. package/src/driver/index.ts +30 -0
  184. package/src/driver/mac-bundle.ts +156 -0
  185. package/src/driver/win-icon.ts +96 -0
  186. package/src/extensions/gui/html.ts +236 -0
  187. package/src/extensions/gui/index.ts +11 -0
  188. package/src/extensions/registry.ts +39 -0
  189. package/src/index.ts +1 -1
  190. package/src/lexer/scanner/identifiers.ts +4 -11
  191. package/src/parser/statements.ts +17 -4
  192. package/dist/tests/e2e/gui.test.d.ts +0 -12
  193. package/dist/tests/e2e/gui.test.js +0 -493
  194. 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
+ }
@@ -0,0 +1,63 @@
1
+ /*
2
+ * xbintsc GUI engine — AOT `<script>` registry.
3
+ *
4
+ * xbintsc has no runtime interpreter, so `<script>` bodies are compiled ahead
5
+ * of time. The `.html` asset loader (see `src/extensions/gui/html.ts`) extracts
6
+ * each inline body, wraps it in a function `(window, document) => { ... }` and
7
+ * calls the `__registerScript(id, fn)` builtin at module initialization. This
8
+ * file keeps that registry and runs the matching functions once the document
9
+ * has been parsed.
10
+ */
11
+
12
+ #include "gui_engine.h"
13
+
14
+ #include <string>
15
+ #include <unordered_map>
16
+ #include <vector>
17
+
18
+ /** Script id -> AOT-compiled function value. Lives for the whole process (the
19
+ * runtime arena never reclaims, so storing `xt_value`s is safe). */
20
+ static std::unordered_map<std::string, xt_value> &script_registry() {
21
+ static std::unordered_map<std::string, xt_value> registry;
22
+ return registry;
23
+ }
24
+
25
+ extern "C" xt_value xt_register_script(int32_t argc, xt_value *argv) {
26
+ if (argc >= 2) {
27
+ xt_value id_value = xt_to_string(xt_arg(argc, argv, 0));
28
+ const char *id = xt_string_data(id_value);
29
+ xt_value fn = xt_arg(argc, argv, 1);
30
+ if (id != nullptr && XT_IS_FUNCTION(fn)) {
31
+ script_registry()[std::string(id)] = fn;
32
+ }
33
+ }
34
+ return XT_UNDEFINED;
35
+ }
36
+
37
+ /** Collect `data-xt-id` markers from `<script>` elements, in document order. */
38
+ static void collect_script_ids(const xtgui::Node *node, std::vector<std::string> &ids) {
39
+ if (node == nullptr) return;
40
+ if (node->isElement() && node->isTag("script")) {
41
+ const std::string *id = node->attr("data-xt-id");
42
+ if (id != nullptr && !id->empty()) ids.push_back(*id);
43
+ return;
44
+ }
45
+ for (const std::unique_ptr<xtgui::Node> &child : node->children) {
46
+ collect_script_ids(child.get(), ids);
47
+ }
48
+ }
49
+
50
+ void xt_gui_run_scripts(XtGuiWindow *win) {
51
+ if (win == nullptr || win->document == nullptr) return;
52
+ std::vector<std::string> ids;
53
+ collect_script_ids(win->document->root(), ids);
54
+ if (ids.empty()) return;
55
+ xt_value window_handle = win->object;
56
+ xt_value document_handle = xt_gui_document_handle(win);
57
+ for (const std::string &id : ids) {
58
+ auto it = script_registry().find(id);
59
+ if (it == script_registry().end()) continue;
60
+ xt_value args[2] = {window_handle, document_handle};
61
+ xt_call_with_this(it->second, XT_UNDEFINED, 2, args);
62
+ }
63
+ }