xbintsc 0.5.31 → 0.5.32

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 (181) hide show
  1. package/README.md +16 -10
  2. package/dist/src/binder/references.js +14 -1
  3. package/dist/src/binder/references.js.map +1 -1
  4. package/dist/src/cli/help.d.ts +1 -1
  5. package/dist/src/codegen/generator/module.d.ts +1 -0
  6. package/dist/src/codegen/generator/module.js +54 -0
  7. package/dist/src/codegen/generator/module.js.map +1 -1
  8. package/dist/src/codegen/generator/statements/variables.js +6 -4
  9. package/dist/src/codegen/generator/statements/variables.js.map +1 -1
  10. package/dist/src/driver/version.d.ts +1 -1
  11. package/dist/src/driver/version.js +1 -1
  12. package/dist/src/extensions/gui/css.d.ts +26 -0
  13. package/dist/src/extensions/gui/css.js +100 -0
  14. package/dist/src/extensions/gui/css.js.map +1 -0
  15. package/dist/src/extensions/gui/html.js +9 -2
  16. package/dist/src/extensions/gui/html.js.map +1 -1
  17. package/dist/src/extensions/gui/index.js +16 -2
  18. package/dist/src/extensions/gui/index.js.map +1 -1
  19. package/dist/src/extensions/gui/three.d.ts +16 -0
  20. package/dist/src/extensions/gui/three.js +22 -0
  21. package/dist/src/extensions/gui/three.js.map +1 -0
  22. package/dist/src/extensions/media/index.d.ts +6 -5
  23. package/dist/src/extensions/media/index.js +12 -14
  24. package/dist/src/extensions/media/index.js.map +1 -1
  25. package/dist/tests/e2e/compile-builtins.test.js +24 -0
  26. package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
  27. package/dist/tests/e2e/compile-objects-classes.test.js +23 -0
  28. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  29. package/dist/tests/e2e/gui-browser.test.js +1 -1
  30. package/dist/tests/e2e/gui-browser.test.js.map +1 -1
  31. package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
  32. package/dist/tests/e2e/gui-effects.test.js +262 -0
  33. package/dist/tests/e2e/gui-effects.test.js.map +1 -0
  34. package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
  35. package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
  36. package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
  37. package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
  38. package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
  39. package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
  40. package/dist/tests/e2e/gui-layout.test.js +48 -0
  41. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  42. package/dist/tests/e2e/gui-media.test.js +5 -4
  43. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  44. package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
  45. package/dist/tests/e2e/gui-webgl.test.js +179 -0
  46. package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
  47. package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
  48. package/dist/tests/e2e/gui-webgl2.test.js +238 -0
  49. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
  50. package/dist/tests/extensions/gui.test.js +41 -0
  51. package/dist/tests/extensions/gui.test.js.map +1 -1
  52. package/dist/tests/extensions/media.test.js +7 -3
  53. package/dist/tests/extensions/media.test.js.map +1 -1
  54. package/doc/ai/extensions.md +29 -9
  55. package/doc/ai/troubleshooting.md +12 -8
  56. package/doc/ai/zh-CN/extensions.md +26 -8
  57. package/doc/ai/zh-CN/troubleshooting.md +10 -6
  58. package/doc/gui/api.md +3 -2
  59. package/doc/gui/build.md +72 -16
  60. package/doc/gui/canvas.md +11 -3
  61. package/doc/gui/dom.md +33 -18
  62. package/doc/gui/known-issues.md +57 -24
  63. package/doc/gui/layout.md +18 -0
  64. package/doc/gui/media.md +17 -13
  65. package/doc/gui/rendering.md +50 -3
  66. package/doc/gui/webgl.md +256 -0
  67. package/doc/gui.md +108 -17
  68. package/doc/npm-package.md +6 -4
  69. package/doc/requirements.md +18 -9
  70. package/doc/zh-CN/gui/api.md +3 -2
  71. package/doc/zh-CN/gui/build.md +64 -15
  72. package/doc/zh-CN/gui/canvas.md +9 -2
  73. package/doc/zh-CN/gui/dom.md +20 -7
  74. package/doc/zh-CN/gui/known-issues.md +45 -19
  75. package/doc/zh-CN/gui/layout.md +14 -0
  76. package/doc/zh-CN/gui/media.md +15 -11
  77. package/doc/zh-CN/gui/rendering.md +41 -4
  78. package/doc/zh-CN/gui/webgl.md +115 -0
  79. package/doc/zh-CN/gui.md +89 -14
  80. package/doc/zh-CN/npm-package.md +9 -6
  81. package/doc/zh-CN/requirements.md +12 -6
  82. package/llms.txt +2 -0
  83. package/package.json +1 -1
  84. package/runtime/ext_gui/browser.cpp +39 -13
  85. package/runtime/ext_gui/canvas.cpp +3 -18
  86. package/runtime/ext_gui/canvas_internal.h +10 -0
  87. package/runtime/ext_gui/canvas_raster.cpp +60 -0
  88. package/runtime/ext_gui/clip_values.cpp +246 -0
  89. package/runtime/ext_gui/css.cpp +94 -0
  90. package/runtime/ext_gui/css.h +22 -1
  91. package/runtime/ext_gui/css_match.cpp +3 -0
  92. package/runtime/ext_gui/css_selector.cpp +9 -0
  93. package/runtime/ext_gui/css_sheet.cpp +89 -45
  94. package/runtime/ext_gui/document.cpp +4 -1
  95. package/runtime/ext_gui/document.h +2 -0
  96. package/runtime/ext_gui/dom.h +16 -0
  97. package/runtime/ext_gui/dom_api.cpp +1 -0
  98. package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
  99. package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
  100. package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
  101. package/runtime/ext_gui/dom_api_internal.h +259 -0
  102. package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
  103. package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
  104. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
  105. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
  106. package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
  107. package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
  108. package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
  109. package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
  110. package/runtime/ext_gui/effect_values.cpp +312 -0
  111. package/runtime/ext_gui/gradient_values.cpp +476 -0
  112. package/runtime/ext_gui/grid_values.cpp +230 -0
  113. package/runtime/ext_gui/gui_canvas.cpp +50 -2
  114. package/runtime/ext_gui/gui_engine.h +27 -0
  115. package/runtime/ext_gui/gui_events.cpp +4 -1
  116. package/runtime/ext_gui/gui_media.cpp +1 -1
  117. package/runtime/ext_gui/gui_webgl.cpp +83 -0
  118. package/runtime/ext_gui/layout.cpp +21 -0
  119. package/runtime/ext_gui/layout_flow.cpp +81 -4
  120. package/runtime/ext_gui/layout_flow_internal.h +31 -0
  121. package/runtime/ext_gui/layout_grid.cpp +374 -0
  122. package/runtime/ext_gui/media.h +1 -1
  123. package/runtime/ext_gui/media_api.h +2 -2
  124. package/runtime/ext_gui/media_query.cpp +211 -0
  125. package/runtime/ext_gui/paint.cpp +111 -77
  126. package/runtime/ext_gui/paint.h +33 -3
  127. package/runtime/ext_gui/paint_background.cpp +229 -0
  128. package/runtime/ext_gui/paint_clip.cpp +268 -0
  129. package/runtime/ext_gui/paint_effects.cpp +324 -0
  130. package/runtime/ext_gui/paint_internal.h +85 -0
  131. package/runtime/ext_gui/renderer.cpp +8 -31
  132. package/runtime/ext_gui/renderer_clip.cpp +196 -0
  133. package/runtime/ext_gui/renderer_image.cpp +13 -8
  134. package/runtime/ext_gui/renderer_internal.h +15 -8
  135. package/runtime/ext_gui/renderer_text.cpp +6 -31
  136. package/runtime/ext_gui/style.cpp +343 -20
  137. package/runtime/ext_gui/style.h +144 -3
  138. package/runtime/ext_gui/style_print.cpp +134 -1
  139. package/runtime/ext_gui/style_values.cpp +152 -126
  140. package/runtime/ext_gui/style_values_internal.h +35 -0
  141. package/runtime/ext_gui/webgl.h +466 -0
  142. package/runtime/ext_gui/webgl2_constants.h +274 -0
  143. package/runtime/ext_gui/webgl_buffer.cpp +565 -0
  144. package/runtime/ext_gui/webgl_constants.h +317 -0
  145. package/runtime/ext_gui/webgl_context.cpp +466 -0
  146. package/runtime/ext_gui/webgl_draw.cpp +495 -0
  147. package/runtime/ext_gui/webgl_glsl.h +125 -0
  148. package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
  149. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
  150. package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
  151. package/runtime/ext_gui/webgl_msl.cpp +62 -0
  152. package/runtime/ext_gui/webgl_msl.h +33 -0
  153. package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
  154. package/runtime/ext_gui/webgl_program_internal.h +18 -0
  155. package/runtime/ext_gui/webgl_shader.cpp +582 -0
  156. package/runtime/ext_gui/webgl_texture.cpp +293 -0
  157. package/runtime/ext_gui/webgl_uniform.cpp +167 -0
  158. package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
  159. package/runtime/ext_media/media.cpp +1 -1
  160. package/runtime/ext_media/media_bridge.c +9 -3
  161. package/runtime/rt_internal.h +1 -0
  162. package/runtime/xt_containers/access.inc +8 -0
  163. package/runtime/xt_regex/api.inc +2 -0
  164. package/runtime/xt_regex/matcher.inc +16 -3
  165. package/runtime/xt_regex/parser.inc +8 -2
  166. package/runtime/xt_regex/types.inc +3 -0
  167. package/runtime/xt_stdlib2/regexp-match.inc +60 -21
  168. package/runtime/xt_stdlib2/regexp.inc +1 -0
  169. package/runtime/xt_typed_array.c +1 -1
  170. package/scripts/build-gui.ts +90 -3
  171. package/scripts/build-media.ts +323 -58
  172. package/scripts/setup-vs-toolchain.ps1 +152 -0
  173. package/src/binder/references.ts +13 -1
  174. package/src/codegen/generator/module.ts +50 -0
  175. package/src/codegen/generator/statements/variables.ts +6 -3
  176. package/src/driver/version.ts +1 -1
  177. package/src/extensions/gui/css.ts +113 -0
  178. package/src/extensions/gui/html.ts +9 -2
  179. package/src/extensions/gui/index.ts +16 -2
  180. package/src/extensions/gui/three.ts +25 -0
  181. package/src/extensions/media/index.ts +13 -16
@@ -0,0 +1,495 @@
1
+ /*
2
+ * xbintsc GUI engine — WebGL draw calls.
3
+ *
4
+ * SDL_GPU has no dynamic state for blend/depth/rasterisation: those live in a
5
+ * `SDL_GPUGraphicsPipeline`. WebGL changes them with `glEnable`/`glDepthFunc`,
6
+ * so a pipeline is built lazily per (program, vertex layout, the subset of
7
+ * fixed-function state that matters) and cached on the program.
8
+ *
9
+ * A matrix attribute consumes several consecutive vertex locations; the
10
+ * pipeline spells out one `SDL_GPUVertexAttribute` per column, all reading the
11
+ * same vertex buffer binding.
12
+ */
13
+
14
+ #include "webgl.h"
15
+
16
+ #include <algorithm>
17
+ #include <cstring>
18
+ #include <string>
19
+ #include <vector>
20
+
21
+ #include "gui_internal.h"
22
+
23
+ namespace xtgui {
24
+ namespace {
25
+
26
+ int type_size(int type) {
27
+ switch (type) {
28
+ case GL_BYTE:
29
+ case GL_UNSIGNED_BYTE:
30
+ return 1;
31
+ case GL_SHORT:
32
+ case GL_UNSIGNED_SHORT:
33
+ return 2;
34
+ default:
35
+ return 4;
36
+ }
37
+ }
38
+
39
+ int components_of_type(const std::string &type) {
40
+ if (!type.empty() && type.back() >= '2' && type.back() <= '4') return type.back() - '0';
41
+ return 1;
42
+ }
43
+
44
+ SDL_GPUVertexElementFormat float_format(int size) {
45
+ switch (size) {
46
+ case 1:
47
+ return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
48
+ case 2:
49
+ return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
50
+ case 3:
51
+ return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
52
+ default:
53
+ return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
54
+ }
55
+ }
56
+
57
+ SDL_GPUVertexElementFormat format_of(int size, int type, bool normalized) {
58
+ if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
59
+ if (type == GL_FLOAT) return float_format(size);
60
+ if (type == GL_UNSIGNED_BYTE || type == GL_BYTE) {
61
+ const bool is_byte = type == GL_BYTE;
62
+ if (size == 2) {
63
+ return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2_NORM
64
+ : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2_NORM)
65
+ : (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2
66
+ : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2);
67
+ }
68
+ if (size == 4) {
69
+ return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4_NORM
70
+ : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM)
71
+ : (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4
72
+ : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4);
73
+ }
74
+ return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
75
+ }
76
+ if (type == GL_UNSIGNED_SHORT || type == GL_SHORT) {
77
+ const bool is_short = type == GL_SHORT;
78
+ if (size == 2) {
79
+ return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2_NORM
80
+ : SDL_GPU_VERTEXELEMENTFORMAT_USHORT2_NORM)
81
+ : (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2
82
+ : SDL_GPU_VERTEXELEMENTFORMAT_USHORT2);
83
+ }
84
+ if (size == 4) {
85
+ return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4_NORM
86
+ : SDL_GPU_VERTEXELEMENTFORMAT_USHORT4_NORM)
87
+ : (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4
88
+ : SDL_GPU_VERTEXELEMENTFORMAT_USHORT4);
89
+ }
90
+ return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
91
+ }
92
+ return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
93
+ }
94
+
95
+ /** `vertexAttribIPointer` formats: integer attributes keep their integer type
96
+ * in the shader (`in ivec3 …`). SDL has no 1- or 3-component byte/short
97
+ * integer formats, so only the sizes it can express are accepted. */
98
+ SDL_GPUVertexElementFormat int_format_of(int size, int type) {
99
+ if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
100
+ if (type == GL_INT) {
101
+ switch (size) {
102
+ case 1:
103
+ return SDL_GPU_VERTEXELEMENTFORMAT_INT;
104
+ case 2:
105
+ return SDL_GPU_VERTEXELEMENTFORMAT_INT2;
106
+ case 3:
107
+ return SDL_GPU_VERTEXELEMENTFORMAT_INT3;
108
+ default:
109
+ return SDL_GPU_VERTEXELEMENTFORMAT_INT4;
110
+ }
111
+ }
112
+ if (type == GL_UNSIGNED_INT) {
113
+ switch (size) {
114
+ case 1:
115
+ return SDL_GPU_VERTEXELEMENTFORMAT_UINT;
116
+ case 2:
117
+ return SDL_GPU_VERTEXELEMENTFORMAT_UINT2;
118
+ case 3:
119
+ return SDL_GPU_VERTEXELEMENTFORMAT_UINT3;
120
+ default:
121
+ return SDL_GPU_VERTEXELEMENTFORMAT_UINT4;
122
+ }
123
+ }
124
+ if (type == GL_SHORT && (size == 2 || size == 4)) {
125
+ return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2 : SDL_GPU_VERTEXELEMENTFORMAT_SHORT4;
126
+ }
127
+ if (type == GL_UNSIGNED_SHORT && (size == 2 || size == 4)) {
128
+ return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_USHORT2
129
+ : SDL_GPU_VERTEXELEMENTFORMAT_USHORT4;
130
+ }
131
+ if (type == GL_BYTE && (size == 2 || size == 4)) {
132
+ return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_BYTE4;
133
+ }
134
+ if (type == GL_UNSIGNED_BYTE && (size == 2 || size == 4)) {
135
+ return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4;
136
+ }
137
+ return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
138
+ }
139
+
140
+ /** A cache key covering everything (other than the program) that a
141
+ * `SDL_GPUGraphicsPipeline` bakes in. */
142
+ std::string pipeline_key(int mode, int index_size,
143
+ const std::vector<SDL_GPUVertexAttribute> &attrs,
144
+ const std::vector<SDL_GPUVertexBufferDescription> &buffers,
145
+ const WebGLDrawState &state) {
146
+ std::string key = std::to_string(mode) + "/" + std::to_string(index_size);
147
+ for (const SDL_GPUVertexAttribute &attr : attrs) {
148
+ key += "/" + std::to_string(attr.location) + ":" + std::to_string(attr.buffer_slot) + ":" +
149
+ std::to_string((int)attr.format) + ":" + std::to_string(attr.offset);
150
+ }
151
+ for (const SDL_GPUVertexBufferDescription &buffer : buffers) {
152
+ key += "|" + std::to_string(buffer.slot) + ":" + std::to_string(buffer.pitch) + ":" +
153
+ std::to_string((int)buffer.input_rate);
154
+ }
155
+ char state_key[160];
156
+ snprintf(state_key, sizeof(state_key), "|%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
157
+ (int)state.blend, state.blend_src_rgb, state.blend_dst_rgb, state.blend_src_alpha,
158
+ state.blend_dst_alpha, state.blend_eq_rgb, state.blend_eq_alpha, (int)state.depth_test,
159
+ (int)state.depth_write, state.depth_func, (int)state.cull, state.cull_face,
160
+ state.front_face, (int)state.color_mask[0]);
161
+ key += state_key;
162
+ key += std::to_string((int)state.color_mask[1]);
163
+ key += std::to_string((int)state.color_mask[2]);
164
+ key += std::to_string((int)state.color_mask[3]);
165
+ return key;
166
+ }
167
+
168
+ } // namespace
169
+
170
+ void WebGLContext::draw_arrays(int mode, int first, int count) {
171
+ if (count < 0) {
172
+ set_error(GL_INVALID_VALUE);
173
+ return;
174
+ }
175
+ draw(mode, first, count, 0, 0, 1);
176
+ }
177
+
178
+ void WebGLContext::draw_elements(int mode, int count, int type, int offset) {
179
+ if (count < 0) {
180
+ set_error(GL_INVALID_VALUE);
181
+ return;
182
+ }
183
+ if (type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE) {
184
+ set_error(GL_INVALID_ENUM);
185
+ return;
186
+ }
187
+ draw(mode, 0, count, type, offset, 1);
188
+ }
189
+
190
+ void WebGLContext::draw_arrays_instanced(int mode, int first, int count, int instances) {
191
+ if (count < 0 || instances < 0) {
192
+ set_error(GL_INVALID_VALUE);
193
+ return;
194
+ }
195
+ draw(mode, first, count, 0, 0, instances > 0 ? instances : 1);
196
+ }
197
+
198
+ void WebGLContext::draw_elements_instanced(int mode, int count, int type, int offset,
199
+ int instances) {
200
+ if (count < 0 || instances < 0) {
201
+ set_error(GL_INVALID_VALUE);
202
+ return;
203
+ }
204
+ if (type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE) {
205
+ set_error(GL_INVALID_ENUM);
206
+ return;
207
+ }
208
+ draw(mode, 0, count, type, offset, instances > 0 ? instances : 1);
209
+ }
210
+
211
+ void WebGLContext::draw_range_elements(int mode, int start, int end, int count, int type,
212
+ int offset) {
213
+ (void)start;
214
+ (void)end;
215
+ draw_elements(mode, count, type, offset);
216
+ }
217
+
218
+ void WebGLContext::draw(int mode, int first, int count, int index_type, int offset,
219
+ int instances) {
220
+ if (count <= 0) return;
221
+ WebGLProgram *program_ = program(current_program_);
222
+ if (program_ == nullptr || !program_->linked || program_->vs_shader == nullptr) {
223
+ set_error(GL_INVALID_OPERATION);
224
+ return;
225
+ }
226
+ if (mode != GL_POINTS && mode != GL_LINES && mode != GL_LINE_STRIP && mode != GL_TRIANGLES &&
227
+ mode != GL_TRIANGLE_STRIP && mode != GL_TRIANGLE_FAN && mode != GL_LINE_LOOP) {
228
+ set_error(GL_INVALID_ENUM);
229
+ return;
230
+ }
231
+ ensure_fallback();
232
+ end_pass();
233
+ ensure_command();
234
+
235
+ /* Expand source indices when the draw needs a primitive SDL_GPU lacks or a
236
+ * byte-sized index type. */
237
+ std::vector<uint32_t> expanded;
238
+ SDL_GPUBuffer *index_gpu = nullptr;
239
+ int index_size = 0;
240
+ int first_index = 0;
241
+ int draw_mode = mode;
242
+ const bool needs_expand =
243
+ mode == GL_TRIANGLE_FAN || mode == GL_LINE_LOOP || index_type == GL_UNSIGNED_BYTE;
244
+ if (needs_expand) {
245
+ std::vector<uint32_t> source;
246
+ source.reserve((size_t)count);
247
+ if (index_type != 0) {
248
+ WebGLBuffer *element = buffer(bound_element_);
249
+ if (element == nullptr || element->data.empty()) {
250
+ set_error(GL_INVALID_OPERATION);
251
+ return;
252
+ }
253
+ const int element_size = type_size(index_type);
254
+ for (int i = 0; i < count; i++) {
255
+ const size_t at = (size_t)offset + (size_t)i * element_size;
256
+ if (at + element_size > element->data.size()) {
257
+ source.push_back(0);
258
+ continue;
259
+ }
260
+ uint32_t value = element->data[at];
261
+ if (element_size >= 2) value |= (uint32_t)element->data[at + 1] << 8;
262
+ if (element_size >= 4) {
263
+ value |= (uint32_t)element->data[at + 2] << 16;
264
+ value |= (uint32_t)element->data[at + 3] << 24;
265
+ }
266
+ source.push_back(value);
267
+ }
268
+ } else {
269
+ for (int i = 0; i < count; i++) source.push_back((uint32_t)(first + i));
270
+ }
271
+ if (mode == GL_TRIANGLE_FAN) {
272
+ for (size_t i = 1; i + 1 < source.size(); i++) {
273
+ expanded.push_back(source[0]);
274
+ expanded.push_back(source[i]);
275
+ expanded.push_back(source[i + 1]);
276
+ }
277
+ draw_mode = GL_TRIANGLES;
278
+ } else if (mode == GL_LINE_LOOP) {
279
+ for (size_t i = 0; i < source.size(); i++) {
280
+ expanded.push_back(source[i]);
281
+ expanded.push_back(source[(i + 1) % source.size()]);
282
+ }
283
+ draw_mode = GL_LINES;
284
+ } else {
285
+ expanded = source;
286
+ draw_mode = mode;
287
+ }
288
+ index_size = 4;
289
+ if (!expanded.empty()) {
290
+ index_gpu = upload_temp_buffer(expanded.data(),
291
+ (uint32_t)(expanded.size() * sizeof(uint32_t)),
292
+ SDL_GPU_BUFFERUSAGE_INDEX);
293
+ if (index_gpu == nullptr) return;
294
+ }
295
+ } else if (index_type != 0) {
296
+ WebGLBuffer *element = buffer(bound_element_);
297
+ if (element == nullptr || element->data.empty()) {
298
+ set_error(GL_INVALID_OPERATION);
299
+ return;
300
+ }
301
+ index_gpu = ensure_buffer_gpu(element);
302
+ if (index_gpu == nullptr) return;
303
+ index_size = type_size(index_type) == 4 ? 4 : 2;
304
+ first_index = offset / index_size;
305
+ }
306
+
307
+ WebGLFramebuffer *framebuffer_ =
308
+ bound_framebuffer_ != 0 ? framebuffer(bound_framebuffer_) : nullptr;
309
+ const int target_width = framebuffer_ != nullptr ? framebuffer_->width : width_;
310
+ const int target_height = framebuffer_ != nullptr ? framebuffer_->height : height_;
311
+
312
+ std::vector<SDL_GPUVertexAttribute> attributes;
313
+ std::vector<SDL_GPUVertexBufferDescription> buffers;
314
+ std::vector<SDL_GPUBufferBinding> bindings;
315
+
316
+ for (const GlslUniformDecl &decl : program_->attribs) {
317
+ auto location_it = program_->attrib_locations.find(decl.name);
318
+ if (location_it == program_->attrib_locations.end()) continue;
319
+ const int base_location = location_it->second;
320
+ if (base_location < 0 || base_location >= kWebGLMaxAttribs) continue;
321
+ WebGLAttribState &attrib = attribs_[base_location];
322
+ const int slots = decl.type == "mat2" ? 2 : (decl.type == "mat3" ? 3 : (decl.type == "mat4" ? 4 : 1));
323
+ const int components = slots > 1 ? slots : (components_of_type(decl.type) > 4 ? 4
324
+ : components_of_type(decl.type));
325
+ const uint32_t slot = (uint32_t)buffers.size();
326
+ SDL_GPUVertexBufferDescription description;
327
+ memset(&description, 0, sizeof(description));
328
+ description.slot = slot;
329
+ description.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
330
+ SDL_GPUBufferBinding binding;
331
+ memset(&binding, 0, sizeof(binding));
332
+ if (!attrib.enabled) {
333
+ float values[4] = {attrib.current[0], attrib.current[1], attrib.current[2], attrib.current[3]};
334
+ binding.buffer = upload_temp_buffer(values, sizeof(values), SDL_GPU_BUFFERUSAGE_VERTEX);
335
+ description.pitch = 0;
336
+ if (binding.buffer == nullptr) continue;
337
+ for (int column = 0; column < slots; column++) {
338
+ SDL_GPUVertexAttribute attribute;
339
+ memset(&attribute, 0, sizeof(attribute));
340
+ attribute.location = (Uint32)(base_location + column);
341
+ attribute.buffer_slot = slot;
342
+ attribute.format = float_format(components);
343
+ attribute.offset = 0;
344
+ attributes.push_back(attribute);
345
+ }
346
+ buffers.push_back(description);
347
+ bindings.push_back(binding);
348
+ continue;
349
+ }
350
+ WebGLBuffer *buffer_ = buffer(attrib.buffer);
351
+ if (buffer_ == nullptr || buffer_->data.empty()) {
352
+ set_error(GL_INVALID_OPERATION);
353
+ return;
354
+ }
355
+ SDL_GPUVertexElementFormat format = attrib.integer
356
+ ? int_format_of(attrib.size, attrib.type)
357
+ : format_of(attrib.size, attrib.type, attrib.normalized);
358
+ if (format == SDL_GPU_VERTEXELEMENTFORMAT_INVALID) {
359
+ set_error(GL_INVALID_OPERATION);
360
+ return;
361
+ }
362
+ description.input_rate = attrib.divisor > 0 ? SDL_GPU_VERTEXINPUTRATE_INSTANCE
363
+ : SDL_GPU_VERTEXINPUTRATE_VERTEX;
364
+ const int stride =
365
+ attrib.stride > 0 ? attrib.stride : components * type_size(attrib.type) * slots;
366
+ description.pitch = (Uint32)stride;
367
+ SDL_GPUBuffer *gpu = ensure_buffer_gpu(buffer_);
368
+ if (gpu == nullptr) return;
369
+ binding.buffer = gpu;
370
+ binding.offset = 0;
371
+ for (int column = 0; column < slots; column++) {
372
+ SDL_GPUVertexAttribute attribute;
373
+ memset(&attribute, 0, sizeof(attribute));
374
+ attribute.location = (Uint32)(base_location + column);
375
+ attribute.buffer_slot = slot;
376
+ attribute.format = format;
377
+ attribute.offset = (Uint32)(attrib.offset + column * components * type_size(attrib.type));
378
+ attributes.push_back(attribute);
379
+ }
380
+ buffers.push_back(description);
381
+ bindings.push_back(binding);
382
+ }
383
+
384
+ begin_pass(false, false);
385
+ if (pass_ == nullptr) return;
386
+
387
+ SDL_GPUViewport viewport;
388
+ memset(&viewport, 0, sizeof(viewport));
389
+ viewport.x = (float)viewport_[0];
390
+ viewport.y = (float)(target_height - (viewport_[1] + viewport_[3]));
391
+ viewport.w = (float)std::max(1, viewport_[2]);
392
+ viewport.h = (float)std::max(1, viewport_[3]);
393
+ viewport.min_depth = 0.0f;
394
+ viewport.max_depth = 1.0f;
395
+ SDL_SetGPUViewport(pass_, &viewport);
396
+
397
+ SDL_Rect scissor;
398
+ scissor.x = 0;
399
+ scissor.y = 0;
400
+ scissor.w = target_width;
401
+ scissor.h = target_height;
402
+ if (scissor_test_ && scissor_box_[2] > 0 && scissor_box_[3] > 0) {
403
+ scissor.x = scissor_box_[0];
404
+ scissor.y = target_height - (scissor_box_[1] + scissor_box_[3]);
405
+ scissor.w = scissor_box_[2];
406
+ scissor.h = scissor_box_[3];
407
+ }
408
+ if (scissor.x < 0) {
409
+ scissor.w += scissor.x;
410
+ scissor.x = 0;
411
+ }
412
+ if (scissor.y < 0) {
413
+ scissor.h += scissor.y;
414
+ scissor.y = 0;
415
+ }
416
+ if (scissor.x + scissor.w > target_width) scissor.w = target_width - scissor.x;
417
+ if (scissor.y + scissor.h > target_height) scissor.h = target_height - scissor.y;
418
+ if (scissor.w < 0) scissor.w = 0;
419
+ if (scissor.h < 0) scissor.h = 0;
420
+ SDL_SetGPUScissor(pass_, &scissor);
421
+
422
+ const std::string key = pipeline_key(draw_mode, index_size, attributes, buffers, state_);
423
+ SDL_GPUGraphicsPipeline *pipeline = nullptr;
424
+ auto cached = program_->pipeline_cache.find(key);
425
+ if (cached != program_->pipeline_cache.end()) {
426
+ pipeline = cached->second;
427
+ } else {
428
+ pipeline = create_pipeline(program_, draw_mode, index_size, (int)attributes.size(),
429
+ (int)buffers.size(), attributes.data(), buffers.data(), key);
430
+ }
431
+ if (pipeline == nullptr) return;
432
+
433
+ SDL_BindGPUGraphicsPipeline(pass_, pipeline);
434
+ if (!bindings.empty()) {
435
+ SDL_BindGPUVertexBuffers(pass_, 0, bindings.data(), (Uint32)bindings.size());
436
+ }
437
+ if (index_size > 0) {
438
+ SDL_GPUBufferBinding binding;
439
+ binding.buffer = index_gpu;
440
+ binding.offset = 0;
441
+ SDL_BindGPUIndexBuffer(pass_, &binding,
442
+ index_size == 4 ? SDL_GPU_INDEXELEMENTSIZE_32BIT
443
+ : SDL_GPU_INDEXELEMENTSIZE_16BIT);
444
+ }
445
+ if (program_->vs_has_block && program_->block_size > 0) {
446
+ SDL_PushGPUVertexUniformData(cmd_, 0, program_->block.data(), (Uint32)program_->block.size());
447
+ }
448
+ if (program_->fs_has_block && program_->block_size > 0) {
449
+ SDL_PushGPUFragmentUniformData(cmd_, 0, program_->block.data(), (Uint32)program_->block.size());
450
+ }
451
+
452
+ auto bind_samplers = [&](const std::vector<int> &stage, bool vertex_stage) {
453
+ if (stage.empty()) return;
454
+ std::vector<SDL_GPUTextureSamplerBinding> sampler_bindings;
455
+ sampler_bindings.reserve(stage.size());
456
+ for (int uniform_index : stage) {
457
+ const WebGLUniform &uniform = program_->uniforms[(size_t)uniform_index];
458
+ const int unit =
459
+ uniform.unit >= 0 && uniform.unit < kWebGLMaxTextureUnits ? uniform.unit : 0;
460
+ WebGLTexture *sampled = texture(bound_textures_[unit]);
461
+ SDL_GPUTexture *gpu = sampled != nullptr ? ensure_texture_gpu(sampled, sampled->as_target)
462
+ : nullptr;
463
+ WebGLSampler *sampler_object = this->sampler(bound_samplers_[unit]);
464
+ SDL_GPUSampler *sampler = sampler_object != nullptr
465
+ ? sampler_gpu(sampler_object)
466
+ : (sampled != nullptr ? sampler_for(sampled) : nullptr);
467
+ if (gpu == nullptr || sampler == nullptr) {
468
+ gpu = fallback_texture_;
469
+ sampler = fallback_sampler_;
470
+ }
471
+ SDL_GPUTextureSamplerBinding texture_binding;
472
+ texture_binding.texture = gpu;
473
+ texture_binding.sampler = sampler;
474
+ sampler_bindings.push_back(texture_binding);
475
+ }
476
+ if (vertex_stage) {
477
+ SDL_BindGPUVertexSamplers(pass_, 0, sampler_bindings.data(),
478
+ (Uint32)sampler_bindings.size());
479
+ } else {
480
+ SDL_BindGPUFragmentSamplers(pass_, 0, sampler_bindings.data(),
481
+ (Uint32)sampler_bindings.size());
482
+ }
483
+ };
484
+ bind_samplers(program_->vs_sampler_uniforms, true);
485
+ bind_samplers(program_->fs_sampler_uniforms, false);
486
+
487
+ if (index_size > 0) {
488
+ SDL_DrawGPUIndexedPrimitives(pass_, (Uint32)count, (Uint32)instances, (Uint32)first_index, 0,
489
+ 0);
490
+ } else {
491
+ SDL_DrawGPUPrimitives(pass_, (Uint32)count, (Uint32)instances, (Uint32)first, 0);
492
+ }
493
+ }
494
+
495
+ } // namespace xtgui
@@ -0,0 +1,125 @@
1
+ /*
2
+ * xbintsc GUI engine — GLSL ES for WebGL.
3
+ *
4
+ * WebGL shaders reach `shaderSource` as GLSL ES 1.00/3.00 text, while SDL_GPU's
5
+ * Vulkan backend consumes SPIR-V. There is no GLSL compiler in SDL_GPU, so this
6
+ * module does two things:
7
+ *
8
+ * 1. rewrites a WebGL shader into Vulkan-flavoured GLSL ES 3.10
9
+ * (`attribute` -> `in`, `varying` -> in/out with explicit locations,
10
+ * `gl_FragColor` -> an output, non-sampler uniforms -> one std140 block,
11
+ * samplers -> explicit descriptor set/binding, `texture2D` -> `texture`);
12
+ * 2. compiles it with glslang and reflects the resulting SPIR-V, which yields
13
+ * the exact std140 offsets, array strides and matrix strides of the
14
+ * uniform block plus the active attributes and sampler bindings.
15
+ *
16
+ * Reflection is the source of truth for layout: the shader text may size an
17
+ * array with a macro, but glslang has already resolved it by the time we look
18
+ * at the block members.
19
+ */
20
+ #ifndef XT_GUI_WEBGL_GLSL_H
21
+ #define XT_GUI_WEBGL_GLSL_H
22
+
23
+ #include <cstdint>
24
+ #include <string>
25
+ #include <unordered_map>
26
+ #include <utility>
27
+ #include <vector>
28
+
29
+ namespace xtgui {
30
+
31
+ /** One `uniform` declaration found in a shader source. */
32
+ struct GlslUniformDecl {
33
+ std::string type; // `mat4`, `vec3`, `sampler2D`, …
34
+ std::string name;
35
+ std::string array; // `[4]` (raw text, may contain a macro)
36
+ std::string precision; // `highp` / `mediump` / `lowp` / empty
37
+ bool sampler = false;
38
+ /** Extra qualifiers (`layout(...)`) that were already present; empty for a
39
+ * WebGL 1 source. */
40
+ std::string extra;
41
+ };
42
+
43
+ /** Where one declaration sits in the source text, and what it declares. */
44
+ struct GlslDeclSite {
45
+ enum Kind { Uniform, Sampler, Attribute, Varying, FragmentOut };
46
+ Kind kind = Uniform;
47
+ size_t begin = 0; // byte offset of the first token (`layout` included)
48
+ size_t end = 0; // byte offset just past the `;`
49
+ GlslUniformDecl decl;
50
+ int existing_location = -1; // from a `layout(location = …)` qualifier
51
+ /** True when a preprocessor `#if`/`#ifdef` encloses the declaration. */
52
+ bool conditional = false;
53
+ };
54
+
55
+ /** The declarations a shader contributes to a program. */
56
+ struct GlslShaderInfo {
57
+ std::vector<GlslUniformDecl> uniforms; // non-sampler
58
+ std::vector<GlslUniformDecl> samplers;
59
+ std::vector<GlslUniformDecl> attributes; // vertex only
60
+ std::vector<GlslUniformDecl> varyings;
61
+ /** Every top-level declaration, in source order, for the rewriter. */
62
+ std::vector<GlslDeclSite> sites;
63
+ /** Active top-level `struct Name { … };` definitions, hoisted before the
64
+ * uniform block because the block may name those types (three.js lights). */
65
+ std::vector<std::pair<size_t, size_t>> structs;
66
+ /** The text of those definitions, shared across stages at link time. */
67
+ std::vector<std::string> struct_definitions;
68
+ /** True when the source writes `gl_FragColor` / `gl_FragData[0]`. */
69
+ bool legacy_fragment_output = false;
70
+ /** True when the source declared its own `out` variable (ES 3.00). */
71
+ bool has_fragment_output = false;
72
+ /** Byte offset of the first non-sampler uniform declaration (block insertion
73
+ * point); `npos` when the shader has none. */
74
+ size_t first_uniform_offset = std::string::npos;
75
+ /** A declaration this engine cannot translate (struct uniform, block, …). */
76
+ std::string unsupported;
77
+ };
78
+
79
+ /** Locations and bindings assigned at link time. */
80
+ struct GlslLinkLayout {
81
+ std::unordered_map<std::string, int> attributes; // name -> location
82
+ std::unordered_map<std::string, int> varyings; // name -> location
83
+ /** stage-local sampler binding: name -> binding index inside the stage. */
84
+ std::unordered_map<std::string, int> samplers;
85
+ /** Merged, declaration-ordered non-sampler uniforms (shared block members). */
86
+ std::vector<GlslUniformDecl> block_members;
87
+ };
88
+
89
+ /** Scan `source` for the declarations WebGL needs to know about. */
90
+ void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info);
91
+
92
+ /** Rewrite `source` into Vulkan GLSL ES 3.10 (`layout` added everywhere). */
93
+ std::string rewrite_glsl(const std::string &source, bool fragment, const GlslLinkLayout &layout,
94
+ const GlslShaderInfo &info);
95
+
96
+ /** Compile a rewritten shader to SPIR-V. Returns false and fills `log`. */
97
+ bool compile_glsl(const std::string &source, bool fragment, std::vector<uint32_t> *spirv,
98
+ std::string *log);
99
+
100
+ /** One std140 block member, reflected from SPIR-V. */
101
+ struct GlslBlockMember {
102
+ std::string name;
103
+ int gl_type = 0; // GL_FLOAT, GL_FLOAT_VEC4, GL_FLOAT_MAT4, GL_INT_VEC2, …
104
+ int components = 0; // 1..4
105
+ bool is_matrix = false;
106
+ int columns = 0; // matrix columns; 0 for non-matrix members
107
+ int rows = 0;
108
+ bool is_array = false;
109
+ int array_size = 1;
110
+ int offset = 0; // byte offset of the member in the block
111
+ int array_stride = 0; // byte stride between array elements
112
+ int matrix_stride = 0; // byte stride between matrix columns
113
+ int scalar_type = 0; // GL_FLOAT / GL_INT / GL_BOOL
114
+ };
115
+
116
+ /** Reflect the (single) uniform block of a compiled shader. */
117
+ bool reflect_uniform_block(const std::vector<uint32_t> &spirv, std::vector<GlslBlockMember> *out);
118
+
119
+ /** Reflect `in` variable locations (vertex attributes) from SPIR-V. */
120
+ bool reflect_attributes(const std::vector<uint32_t> &spirv,
121
+ std::unordered_map<std::string, int> *out);
122
+
123
+ } // namespace xtgui
124
+
125
+ #endif /* XT_GUI_WEBGL_GLSL_H */