xbintsc 0.5.32 → 0.5.37

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 (222) hide show
  1. package/README.md +10 -7
  2. package/README.zh-CN.md +10 -8
  3. package/dist/scripts/check-version.d.ts +27 -0
  4. package/dist/scripts/check-version.js +71 -0
  5. package/dist/scripts/check-version.js.map +1 -0
  6. package/dist/scripts/package-platform.d.ts +58 -0
  7. package/dist/scripts/package-platform.js +142 -0
  8. package/dist/scripts/package-platform.js.map +1 -0
  9. package/dist/scripts/verify-platform-package.d.ts +34 -0
  10. package/dist/scripts/verify-platform-package.js +161 -0
  11. package/dist/scripts/verify-platform-package.js.map +1 -0
  12. package/dist/src/cli/help.d.ts +1 -1
  13. package/dist/src/cli/main.js +3 -1
  14. package/dist/src/cli/main.js.map +1 -1
  15. package/dist/src/driver/runtime-lib.d.ts +29 -4
  16. package/dist/src/driver/runtime-lib.js +68 -10
  17. package/dist/src/driver/runtime-lib.js.map +1 -1
  18. package/dist/src/driver/version.d.ts +1 -1
  19. package/dist/src/driver/version.js +1 -1
  20. package/dist/src/extensions/gui/index.js +18 -5
  21. package/dist/src/extensions/gui/index.js.map +1 -1
  22. package/dist/src/extensions/media/index.js +4 -3
  23. package/dist/src/extensions/media/index.js.map +1 -1
  24. package/dist/src/parser/context.d.ts +41 -0
  25. package/dist/src/parser/context.js +89 -4
  26. package/dist/src/parser/context.js.map +1 -1
  27. package/dist/src/parser/literals.js +6 -12
  28. package/dist/src/parser/literals.js.map +1 -1
  29. package/dist/tests/driver/platform-package.test.d.ts +1 -0
  30. package/dist/tests/driver/platform-package.test.js +49 -0
  31. package/dist/tests/driver/platform-package.test.js.map +1 -0
  32. package/dist/tests/driver/runtime-lib.test.js +51 -4
  33. package/dist/tests/driver/runtime-lib.test.js.map +1 -1
  34. package/dist/tests/e2e/gui-audio.test.d.ts +14 -0
  35. package/dist/tests/e2e/gui-audio.test.js +287 -0
  36. package/dist/tests/e2e/gui-audio.test.js.map +1 -0
  37. package/dist/tests/e2e/gui-browser.test.js +65 -0
  38. package/dist/tests/e2e/gui-browser.test.js.map +1 -1
  39. package/dist/tests/e2e/gui-canvas-args.test.d.ts +6 -0
  40. package/dist/tests/e2e/gui-canvas-args.test.js +217 -0
  41. package/dist/tests/e2e/gui-canvas-args.test.js.map +1 -0
  42. package/dist/tests/e2e/gui-canvas.test.js.map +1 -1
  43. package/dist/tests/e2e/gui-dom.test.js +215 -0
  44. package/dist/tests/e2e/gui-dom.test.js.map +1 -1
  45. package/dist/tests/e2e/gui-events.test.js +112 -0
  46. package/dist/tests/e2e/gui-events.test.js.map +1 -1
  47. package/dist/tests/e2e/gui-helpers.d.ts +7 -0
  48. package/dist/tests/e2e/gui-helpers.js +1 -0
  49. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  50. package/dist/tests/e2e/gui-media.test.js +78 -0
  51. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  52. package/dist/tests/e2e/gui-style.test.js +55 -0
  53. package/dist/tests/e2e/gui-style.test.js.map +1 -1
  54. package/dist/tests/e2e/gui-webgl.test.js +258 -0
  55. package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
  56. package/dist/tests/e2e/gui-webgl2-3d.test.d.ts +4 -0
  57. package/dist/tests/e2e/gui-webgl2-3d.test.js +264 -0
  58. package/dist/tests/e2e/gui-webgl2-3d.test.js.map +1 -0
  59. package/dist/tests/e2e/gui-webgl2-blit.test.d.ts +10 -0
  60. package/dist/tests/e2e/gui-webgl2-blit.test.js +262 -0
  61. package/dist/tests/e2e/gui-webgl2-blit.test.js.map +1 -0
  62. package/dist/tests/e2e/gui-webgl2-formats.test.d.ts +6 -0
  63. package/dist/tests/e2e/gui-webgl2-formats.test.js +395 -0
  64. package/dist/tests/e2e/gui-webgl2-formats.test.js.map +1 -0
  65. package/dist/tests/e2e/gui-webgl2-mrt.test.d.ts +4 -0
  66. package/dist/tests/e2e/gui-webgl2-mrt.test.js +105 -0
  67. package/dist/tests/e2e/gui-webgl2-mrt.test.js.map +1 -0
  68. package/dist/tests/e2e/gui-webgl2-ubo.test.d.ts +8 -0
  69. package/dist/tests/e2e/gui-webgl2-ubo.test.js +112 -0
  70. package/dist/tests/e2e/gui-webgl2-ubo.test.js.map +1 -0
  71. package/dist/tests/e2e/gui-webgl2.test.js +45 -1
  72. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -1
  73. package/dist/tests/extensions/gui-index.test.js +1 -0
  74. package/dist/tests/extensions/gui-index.test.js.map +1 -1
  75. package/dist/tests/extensions/media.test.js +1 -0
  76. package/dist/tests/extensions/media.test.js.map +1 -1
  77. package/dist/tests/parser/expressions.test.js +30 -0
  78. package/dist/tests/parser/expressions.test.js.map +1 -1
  79. package/dist/tests/platform-tarball.test.d.ts +1 -0
  80. package/dist/tests/platform-tarball.test.js +111 -0
  81. package/dist/tests/platform-tarball.test.js.map +1 -0
  82. package/dist/tests/version.test.js +6 -0
  83. package/dist/tests/version.test.js.map +1 -1
  84. package/doc/ai/contributing.md +11 -0
  85. package/doc/ai/extensions.md +7 -4
  86. package/doc/ai/troubleshooting.md +7 -5
  87. package/doc/ai/zh-CN/contributing.md +9 -0
  88. package/doc/ai/zh-CN/extensions.md +4 -2
  89. package/doc/ai/zh-CN/troubleshooting.md +5 -3
  90. package/doc/gui/api.md +99 -22
  91. package/doc/gui/build.md +11 -4
  92. package/doc/gui/canvas.md +49 -18
  93. package/doc/gui/dom.md +57 -7
  94. package/doc/gui/media.md +4 -0
  95. package/doc/gui/webgl.md +105 -46
  96. package/doc/gui.md +7 -3
  97. package/doc/npm-package.md +55 -27
  98. package/doc/requirements.md +6 -2
  99. package/doc/zh-CN/gui/api.md +84 -14
  100. package/doc/zh-CN/gui/build.md +7 -2
  101. package/doc/zh-CN/gui/canvas.md +44 -19
  102. package/doc/zh-CN/gui/dom.md +48 -4
  103. package/doc/zh-CN/gui/media.md +3 -0
  104. package/doc/zh-CN/gui/webgl.md +22 -16
  105. package/doc/zh-CN/gui.md +3 -2
  106. package/doc/zh-CN/npm-package.md +44 -23
  107. package/doc/zh-CN/requirements.md +4 -1
  108. package/package.json +17 -1
  109. package/runtime/ext_gui/audio.cpp +365 -153
  110. package/runtime/ext_gui/audio_buffer.cpp +166 -0
  111. package/runtime/ext_gui/audio_buffer.h +37 -0
  112. package/runtime/ext_gui/audio_decode.cpp +219 -0
  113. package/runtime/ext_gui/audio_decode.h +39 -0
  114. package/runtime/ext_gui/audio_device.cpp +87 -0
  115. package/runtime/ext_gui/audio_effects.cpp +163 -0
  116. package/runtime/ext_gui/audio_effects.h +25 -0
  117. package/runtime/ext_gui/audio_internal.h +30 -0
  118. package/runtime/ext_gui/audio_mixer.cpp +494 -0
  119. package/runtime/ext_gui/audio_mixer.h +238 -0
  120. package/runtime/ext_gui/audio_param.cpp +104 -0
  121. package/runtime/ext_gui/audio_param_object.cpp +155 -0
  122. package/runtime/ext_gui/browser.cpp +45 -50
  123. package/runtime/ext_gui/browser_abort.cpp +249 -0
  124. package/runtime/ext_gui/browser_dialogs.cpp +76 -0
  125. package/runtime/ext_gui/browser_media.cpp +176 -0
  126. package/runtime/ext_gui/browser_navigation.cpp +130 -0
  127. package/runtime/ext_gui/canvas.cpp +88 -30
  128. package/runtime/ext_gui/canvas.h +74 -9
  129. package/runtime/ext_gui/canvas_image_data.cpp +143 -0
  130. package/runtime/ext_gui/canvas_internal.h +8 -5
  131. package/runtime/ext_gui/canvas_pattern.cpp +90 -0
  132. package/runtime/ext_gui/canvas_raster.cpp +31 -9
  133. package/runtime/ext_gui/canvas_style.cpp +4 -2
  134. package/runtime/ext_gui/css_selector.cpp +21 -3
  135. package/runtime/ext_gui/dom.h +4 -0
  136. package/runtime/ext_gui/dom_api.cpp +1 -0
  137. package/runtime/ext_gui/dom_api_canvas.cpp +120 -114
  138. package/runtime/ext_gui/dom_api_canvas_extra.cpp +57 -2
  139. package/runtime/ext_gui/dom_api_canvas_image.cpp +239 -0
  140. package/runtime/ext_gui/dom_api_canvas_paths.cpp +179 -0
  141. package/runtime/ext_gui/dom_api_computed_style.cpp +124 -0
  142. package/runtime/ext_gui/dom_api_dataset.cpp +154 -0
  143. package/runtime/ext_gui/dom_api_document.cpp +58 -5
  144. package/runtime/ext_gui/dom_api_events.cpp +93 -17
  145. package/runtime/ext_gui/dom_api_internal.h +71 -2
  146. package/runtime/ext_gui/dom_api_mutation.cpp +159 -0
  147. package/runtime/ext_gui/dom_api_node.cpp +40 -19
  148. package/runtime/ext_gui/dom_api_node_read.cpp +37 -1
  149. package/runtime/ext_gui/dom_api_path2d.cpp +358 -0
  150. package/runtime/ext_gui/dom_api_proto.cpp +35 -0
  151. package/runtime/ext_gui/dom_api_style.cpp +223 -13
  152. package/runtime/ext_gui/dom_api_webgl.cpp +7 -0
  153. package/runtime/ext_gui/dom_api_webgl2.cpp +151 -36
  154. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +3 -3
  155. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +6 -2
  156. package/runtime/ext_gui/dom_api_webgl_compressed.cpp +167 -0
  157. package/runtime/ext_gui/dom_api_webgl_framebuffer.cpp +160 -0
  158. package/runtime/ext_gui/dom_api_webgl_shader.cpp +4 -4
  159. package/runtime/ext_gui/dom_api_webgl_source.cpp +161 -0
  160. package/runtime/ext_gui/dom_api_webgl_state.cpp +169 -23
  161. package/runtime/ext_gui/dom_api_webgl_texture.cpp +276 -236
  162. package/runtime/ext_gui/dom_api_webgl_ubo.cpp +81 -0
  163. package/runtime/ext_gui/gui.cpp +103 -14
  164. package/runtime/ext_gui/gui_engine.h +56 -4
  165. package/runtime/ext_gui/gui_events.cpp +80 -9
  166. package/runtime/ext_gui/image_bitmap.cpp +28 -0
  167. package/runtime/ext_gui/image_bitmap.h +26 -0
  168. package/runtime/ext_gui/image_bitmap_browser.cpp +136 -0
  169. package/runtime/ext_gui/listener_options.h +43 -0
  170. package/runtime/ext_gui/media.cpp +32 -0
  171. package/runtime/ext_gui/media.h +13 -0
  172. package/runtime/ext_gui/media_api.h +23 -0
  173. package/runtime/ext_gui/paint.cpp +28 -0
  174. package/runtime/ext_gui/paint.h +4 -0
  175. package/runtime/ext_gui/webgl.h +152 -18
  176. package/runtime/ext_gui/webgl_blit.cpp +95 -0
  177. package/runtime/ext_gui/webgl_buffer.cpp +178 -263
  178. package/runtime/ext_gui/webgl_buffer_objects.cpp +270 -0
  179. package/runtime/ext_gui/webgl_clear.cpp +142 -0
  180. package/runtime/ext_gui/webgl_compressed.cpp +180 -0
  181. package/runtime/ext_gui/webgl_context.cpp +241 -156
  182. package/runtime/ext_gui/webgl_draw.cpp +68 -3
  183. package/runtime/ext_gui/webgl_draw_buffers.cpp +75 -0
  184. package/runtime/ext_gui/webgl_glsl.h +40 -0
  185. package/runtime/ext_gui/webgl_glsl_compile.cpp +6 -0
  186. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +18 -0
  187. package/runtime/ext_gui/webgl_glsl_scan.cpp +20 -11
  188. package/runtime/ext_gui/webgl_glsl_scan_block.cpp +126 -0
  189. package/runtime/ext_gui/webgl_glsl_tokens.h +28 -0
  190. package/runtime/ext_gui/webgl_pipeline.cpp +71 -19
  191. package/runtime/ext_gui/webgl_program_blocks.cpp +58 -0
  192. package/runtime/ext_gui/webgl_program_internal.h +6 -0
  193. package/runtime/ext_gui/webgl_shader.cpp +13 -1
  194. package/runtime/ext_gui/webgl_state.cpp +228 -0
  195. package/runtime/ext_gui/webgl_texture.cpp +144 -17
  196. package/runtime/ext_gui/webgl_texture_3d.cpp +215 -0
  197. package/runtime/ext_gui/webgl_uniform_block.h +31 -0
  198. package/runtime/ext_gui/webgl_webgl2.cpp +58 -5
  199. package/runtime/ext_gui/window.cpp +14 -65
  200. package/runtime/ext_gui/window_events.cpp +125 -0
  201. package/runtime/ext_media/decode_audio.cpp +308 -0
  202. package/runtime/ext_media/media_bridge.c +2 -0
  203. package/runtime/rt.h +43 -0
  204. package/runtime/rt_internal.h +4 -0
  205. package/runtime/xt_array_buffer.c +30 -0
  206. package/runtime/xt_builtins.c +0 -21
  207. package/runtime/xt_containers/access.inc +94 -2
  208. package/runtime/xt_containers/objects.inc +29 -31
  209. package/runtime/xt_typed_array/elements.inc +13 -0
  210. package/scripts/build-media.ts +14 -6
  211. package/scripts/build-runtime.ts +21 -16
  212. package/scripts/check-version.ts +39 -9
  213. package/scripts/package-platform.ts +183 -0
  214. package/scripts/set-platform-version.ts +62 -0
  215. package/scripts/verify-platform-package.ts +182 -0
  216. package/src/cli/main.ts +5 -1
  217. package/src/driver/runtime-lib.ts +73 -9
  218. package/src/driver/version.ts +1 -1
  219. package/src/extensions/gui/index.ts +18 -5
  220. package/src/extensions/media/index.ts +4 -3
  221. package/src/parser/context.ts +99 -4
  222. package/src/parser/literals.ts +6 -12
@@ -0,0 +1,215 @@
1
+ /*
2
+ * xbintsc GUI engine — 3D and 2D-array texture storage and uploads.
3
+ *
4
+ * SDL_GPU treats a 3D texture and a 2D-array as layered textures. Uploads are
5
+ * performed one slice at a time because SDL's multi-slice transfer stride is
6
+ * not usable for small 3D textures on the Metal backend.
7
+ */
8
+
9
+ #include "webgl.h"
10
+
11
+ #include <cstring>
12
+ #include <vector>
13
+
14
+ #include "gui_internal.h"
15
+
16
+ namespace xtgui {
17
+ namespace {
18
+
19
+ int texel_bytes(SDL_GPUTextureFormat format) {
20
+ if (format == SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT) return 8;
21
+ if (format == SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT) return 16;
22
+ return 4;
23
+ }
24
+
25
+ /** Upload a whole 3D/2D-array volume. Each slice is uploaded separately:
26
+ * SDL's multi-slice transfer stride is not usable for a 2-layer 3D texture on
27
+ * the Metal backend. */
28
+ bool upload_volume(SDL_GPUDevice *device, SDL_GPUCommandBuffer *cmd, SDL_GPUTexture *gpu,
29
+ int width, int height, int depth, const uint8_t *pixels,
30
+ int bytes_per_texel, bool is_3d) {
31
+ const uint32_t slice_bytes = (uint32_t)(width * height * bytes_per_texel);
32
+ const uint32_t bytes = slice_bytes * (uint32_t)depth;
33
+ if (bytes == 0) return true;
34
+ std::vector<uint8_t> zeros;
35
+ if (pixels == nullptr) {
36
+ zeros.assign(bytes, 0);
37
+ pixels = zeros.data();
38
+ }
39
+ SDL_GPUTransferBufferCreateInfo info;
40
+ memset(&info, 0, sizeof(info));
41
+ info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
42
+ info.size = bytes;
43
+ SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &info);
44
+ if (transfer == nullptr) return false;
45
+ void *mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
46
+ if (mapped == nullptr) {
47
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
48
+ return false;
49
+ }
50
+ memcpy(mapped, pixels, bytes);
51
+ SDL_UnmapGPUTransferBuffer(device, transfer);
52
+ SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
53
+ for (int slice = 0; slice < depth; slice++) {
54
+ SDL_GPUTextureTransferInfo source;
55
+ memset(&source, 0, sizeof(source));
56
+ source.transfer_buffer = transfer;
57
+ source.offset = (Uint32)slice * slice_bytes;
58
+ source.pixels_per_row = (Uint32)width;
59
+ source.rows_per_layer = (Uint32)height;
60
+ SDL_GPUTextureRegion region;
61
+ memset(&region, 0, sizeof(region));
62
+ region.texture = gpu;
63
+ region.layer = is_3d ? 0 : (Uint32)slice;
64
+ region.z = is_3d ? (Uint32)slice : 0;
65
+ region.w = (Uint32)width;
66
+ region.h = (Uint32)height;
67
+ region.d = 1;
68
+ SDL_UploadToGPUTexture(copy, &source, &region, false);
69
+ }
70
+ SDL_EndGPUCopyPass(copy);
71
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
72
+ return true;
73
+ }
74
+
75
+ /** Upload a sub-volume of a 3D/2D-array texture, one slice at a time. */
76
+ bool upload_sub_volume(SDL_GPUDevice *device, SDL_GPUCommandBuffer *cmd, SDL_GPUTexture *gpu,
77
+ int x, int y, int z, int width, int height, int depth,
78
+ const uint8_t *pixels, int bytes_per_texel, bool is_3d) {
79
+ const uint32_t slice_bytes = (uint32_t)(width * height * bytes_per_texel);
80
+ const uint32_t bytes = slice_bytes * (uint32_t)depth;
81
+ if (bytes == 0 || pixels == nullptr) return false;
82
+ SDL_GPUTransferBufferCreateInfo info;
83
+ memset(&info, 0, sizeof(info));
84
+ info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
85
+ info.size = bytes;
86
+ SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &info);
87
+ if (transfer == nullptr) return false;
88
+ void *mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
89
+ if (mapped == nullptr) {
90
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
91
+ return false;
92
+ }
93
+ memcpy(mapped, pixels, bytes);
94
+ SDL_UnmapGPUTransferBuffer(device, transfer);
95
+ SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
96
+ for (int slice = 0; slice < depth; slice++) {
97
+ SDL_GPUTextureTransferInfo source;
98
+ memset(&source, 0, sizeof(source));
99
+ source.transfer_buffer = transfer;
100
+ source.offset = (Uint32)slice * slice_bytes;
101
+ source.pixels_per_row = (Uint32)width;
102
+ source.rows_per_layer = (Uint32)height;
103
+ SDL_GPUTextureRegion region;
104
+ memset(&region, 0, sizeof(region));
105
+ region.texture = gpu;
106
+ region.layer = is_3d ? 0 : (Uint32)(z + slice);
107
+ region.z = is_3d ? (Uint32)(z + slice) : 0;
108
+ region.x = (Uint32)x;
109
+ region.y = (Uint32)y;
110
+ region.w = (Uint32)width;
111
+ region.h = (Uint32)height;
112
+ region.d = 1;
113
+ SDL_UploadToGPUTexture(copy, &source, &region, false);
114
+ }
115
+ SDL_EndGPUCopyPass(copy);
116
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
117
+ return true;
118
+ }
119
+
120
+ } // namespace
121
+
122
+ bool WebGLContext::tex_storage_3d(uint32_t id, int levels, int width, int height, int depth,
123
+ SDL_GPUTextureFormat format, int target) {
124
+ (void)levels;
125
+ WebGLTexture *record = texture(id);
126
+ if (record == nullptr || width <= 0 || height <= 0 || depth <= 0) {
127
+ set_error(GL_INVALID_VALUE);
128
+ return false;
129
+ }
130
+ end_pass();
131
+ ensure_command();
132
+ if (record->gpu != nullptr) {
133
+ submit();
134
+ SDL_WaitForGPUIdle(guidev::g_device);
135
+ SDL_ReleaseGPUTexture(guidev::g_device, record->gpu);
136
+ record->gpu = nullptr;
137
+ record->usage = 0;
138
+ }
139
+ record->width = width;
140
+ record->height = height;
141
+ record->layers = depth;
142
+ record->format = format;
143
+ record->depth = false;
144
+ record->compressed = false;
145
+ record->target = target == GL_TEXTURE_3D ? GL_TEXTURE_3D : GL_TEXTURE_2D_ARRAY;
146
+ record->has_mipmaps = false;
147
+ if (record->sampler != nullptr && guidev::g_device != nullptr) {
148
+ SDL_ReleaseGPUSampler(guidev::g_device, record->sampler);
149
+ record->sampler = nullptr;
150
+ }
151
+ record->defined = true;
152
+ return ensure_texture_gpu(record, false) != nullptr;
153
+ }
154
+
155
+ bool WebGLContext::tex_image_3d(uint32_t id, int width, int height, int depth,
156
+ SDL_GPUTextureFormat format, const uint8_t *pixels,
157
+ int target) {
158
+ WebGLTexture *record = texture(id);
159
+ if (record == nullptr || width <= 0 || height <= 0 || depth <= 0) {
160
+ set_error(GL_INVALID_VALUE);
161
+ return false;
162
+ }
163
+ end_pass();
164
+ ensure_command();
165
+ if (cmd_ == nullptr) return false;
166
+ const int resolved_target = target == GL_TEXTURE_3D ? GL_TEXTURE_3D : GL_TEXTURE_2D_ARRAY;
167
+ if (record->gpu != nullptr &&
168
+ (record->width != width || record->height != height || record->layers != depth ||
169
+ record->format != format || record->target != resolved_target)) {
170
+ SDL_WaitForGPUIdle(guidev::g_device);
171
+ SDL_ReleaseGPUTexture(guidev::g_device, record->gpu);
172
+ record->gpu = nullptr;
173
+ record->usage = 0;
174
+ }
175
+ record->width = width;
176
+ record->height = height;
177
+ record->layers = depth;
178
+ record->format = format;
179
+ record->depth = false;
180
+ record->compressed = false;
181
+ record->target = resolved_target;
182
+ record->has_mipmaps = false;
183
+ if (record->sampler != nullptr) {
184
+ SDL_ReleaseGPUSampler(guidev::g_device, record->sampler);
185
+ record->sampler = nullptr;
186
+ }
187
+ if (ensure_texture_gpu(record, false) == nullptr) return false;
188
+ record->defined = true;
189
+ return upload_volume(guidev::g_device, cmd_, record->gpu, width, height, depth, pixels,
190
+ texel_bytes(format), resolved_target == GL_TEXTURE_3D);
191
+ }
192
+
193
+ bool WebGLContext::tex_sub_image_3d(uint32_t id, int x, int y, int z, int width, int height,
194
+ int depth, const uint8_t *pixels) {
195
+ WebGLTexture *record = texture(id);
196
+ if (record == nullptr || !record->defined || record->gpu == nullptr ||
197
+ (record->target != GL_TEXTURE_3D && record->target != GL_TEXTURE_2D_ARRAY)) {
198
+ set_error(GL_INVALID_OPERATION);
199
+ return false;
200
+ }
201
+ if (x < 0 || y < 0 || z < 0 || width <= 0 || height <= 0 || depth <= 0 ||
202
+ x + width > record->width || y + height > record->height ||
203
+ z + depth > record->layers) {
204
+ set_error(GL_INVALID_VALUE);
205
+ return false;
206
+ }
207
+ end_pass();
208
+ ensure_command();
209
+ if (cmd_ == nullptr) return false;
210
+ return upload_sub_volume(guidev::g_device, cmd_, record->gpu, x, y, z, width, height, depth,
211
+ pixels, texel_bytes(record->format),
212
+ record->target == GL_TEXTURE_3D);
213
+ }
214
+
215
+ } // namespace xtgui
@@ -0,0 +1,31 @@
1
+ /*
2
+ * xbintsc GUI engine — uniform-block bookkeeping shared by programs and draws.
3
+ */
4
+ #ifndef XT_GUI_WEBGL_UNIFORM_BLOCK_H
5
+ #define XT_GUI_WEBGL_UNIFORM_BLOCK_H
6
+
7
+ #include <cstdint>
8
+ #include <string>
9
+
10
+ namespace xtgui {
11
+
12
+ /** A user uniform block merged into the engine's single std140 block. */
13
+ struct WebGLUniformBlock {
14
+ std::string name;
15
+ std::string instance;
16
+ int binding = 0;
17
+ int base_offset = 0;
18
+ int data_size = 0;
19
+ int member_count = 0;
20
+ };
21
+
22
+ /** The buffer bound to one indexed uniform-buffer binding point. */
23
+ struct WebGLUniformBinding {
24
+ uint32_t buffer = 0;
25
+ uint32_t offset = 0;
26
+ uint32_t size = 0;
27
+ };
28
+
29
+ } // namespace xtgui
30
+
31
+ #endif /* XT_GUI_WEBGL_UNIFORM_BLOCK_H */
@@ -125,14 +125,67 @@ bool WebGLContext::is_sync(uint32_t id) const {
125
125
  return syncs_.find(id) != syncs_.end();
126
126
  }
127
127
 
128
- uint32_t WebGLContext::uniform_block_index(uint32_t program, const std::string &name) const {
129
- (void)program;
130
- (void)name;
131
- /* Uniform blocks are not exposed; answering INVALID_INDEX makes a library
132
- * fall back to individual uniforms. */
128
+ uint32_t WebGLContext::uniform_block_index(uint32_t program_id,
129
+ const std::string &name) const {
130
+ auto found = programs_.find(program_id);
131
+ if (found == programs_.end()) return 0xFFFFFFFFu;
132
+ const std::vector<WebGLUniformBlock> &blocks = found->second->blocks;
133
+ for (size_t i = 0; i < blocks.size(); i++) {
134
+ if (blocks[i].name == name) return (uint32_t)i;
135
+ }
133
136
  return 0xFFFFFFFFu;
134
137
  }
135
138
 
139
+ WebGLUniformBlock *WebGLContext::uniform_block(uint32_t program_id, uint32_t index) {
140
+ auto found = programs_.find(program_id);
141
+ if (found == programs_.end() || index >= found->second->blocks.size()) return nullptr;
142
+ return &found->second->blocks[index];
143
+ }
144
+
145
+ int WebGLContext::uniform_block_parameter(uint32_t program_id, uint32_t index,
146
+ int pname) const {
147
+ auto found = programs_.find(program_id);
148
+ if (found == programs_.end() || index >= found->second->blocks.size()) return 0;
149
+ const WebGLUniformBlock &block = found->second->blocks[index];
150
+ switch (pname) {
151
+ case GL_UNIFORM_BLOCK_BINDING:
152
+ return block.binding;
153
+ case GL_UNIFORM_BLOCK_DATA_SIZE:
154
+ return block.data_size;
155
+ case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
156
+ return block.member_count;
157
+ case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
158
+ case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
159
+ return 1;
160
+ default:
161
+ return 0;
162
+ }
163
+ }
164
+
165
+ std::string WebGLContext::uniform_block_name(uint32_t program_id, uint32_t index) const {
166
+ auto found = programs_.find(program_id);
167
+ if (found == programs_.end() || index >= found->second->blocks.size()) return std::string();
168
+ return found->second->blocks[index].name;
169
+ }
170
+
171
+ void WebGLContext::uniform_block_binding(uint32_t program_id, uint32_t index, int binding) {
172
+ WebGLUniformBlock *block = uniform_block(program_id, index);
173
+ if (block != nullptr) block->binding = binding;
174
+ }
175
+
176
+ void WebGLContext::bind_buffer_base(int target, int index, uint32_t buffer_id,
177
+ uint32_t offset, uint32_t size) {
178
+ if (target != 0x8A11 || index < 0 || index >= 16) return; // GL_UNIFORM_BUFFER
179
+ uniform_bindings_[index].buffer = buffer_id;
180
+ uniform_bindings_[index].offset = offset;
181
+ uniform_bindings_[index].size = size;
182
+ }
183
+
184
+ uint32_t WebGLContext::uniform_buffer_binding(int index) const {
185
+ if (index < 0 || index >= 16) return 0;
186
+ return uniform_bindings_[index].buffer;
187
+ }
188
+
136
189
  /* -- sampler objects ----------------------------------------------------- */
137
190
 
138
191
  WebGLSampler *WebGLContext::sampler(uint32_t id) {
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  #include "gui_engine.h"
12
+ #include "listener_options.h"
12
13
 
13
14
  #include <algorithm>
14
15
 
@@ -18,6 +19,12 @@
18
19
 
19
20
  static xt_value g_window_proto = XT_UNDEFINED;
20
21
 
22
+ /** String value of a runtime value, as `std::string` ("" for null/undefined). */
23
+ static std::string window_string(xt_value value) {
24
+ const char *data = xt_string_data(xt_to_string(value));
25
+ return data != nullptr ? data : "";
26
+ }
27
+
21
28
  /* -- methods -------------------------------------------------------------- */
22
29
 
23
30
  static xt_value win_set_title(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
@@ -51,6 +58,9 @@ static xt_value win_load_html(xt_value self, xt_value env, int32_t argc, xt_valu
51
58
  XtGuiWindow *win = xt_gui_window_from_this(self);
52
59
  if (win != nullptr) {
53
60
  win->html = html;
61
+ /* A fresh document starts at the top of the page. */
62
+ win->scroll_x = 0.0f;
63
+ win->scroll_y = 0.0f;
54
64
  /* Fresh document: invalidate every previously handed-out handle, and drop
55
65
  * the decoders that belonged to the old tree. */
56
66
  xt_gui_handles_reset(win);
@@ -371,65 +381,6 @@ static xt_value win_cancel_animation_frame(xt_value self, xt_value env, int32_t
371
381
  return XT_UNDEFINED;
372
382
  }
373
383
 
374
- static xt_value win_on(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
375
- (void)env;
376
- if (argc >= 2) {
377
- xt_value name = xt_to_string(xt_arg(argc, argv, 0));
378
- xt_value fn = xt_arg(argc, argv, 1);
379
- if (XT_IS_FUNCTION(fn)) {
380
- xt_value listeners = xt_object_get_cstr(self, "__xt_gui_events");
381
- if (!XT_IS_OBJECT(listeners)) {
382
- listeners = xt_object_new();
383
- xt_object_set(self, xt_string_from_cstr("__xt_gui_events"), listeners);
384
- }
385
- xt_value array = xt_object_get(listeners, name);
386
- if (!XT_IS_ARRAY(array)) {
387
- array = xt_array_new(0, NULL);
388
- xt_object_set(listeners, name, array);
389
- }
390
- xt_array_push(array, fn);
391
- }
392
- }
393
- return self;
394
- }
395
-
396
- static xt_value win_off(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
397
- (void)env;
398
- if (argc >= 2) {
399
- xt_value listeners = xt_object_get_cstr(self, "__xt_gui_events");
400
- if (XT_IS_OBJECT(listeners)) {
401
- xt_value name = xt_to_string(xt_arg(argc, argv, 0));
402
- xt_value fn = xt_arg(argc, argv, 1);
403
- xt_value array = xt_object_get(listeners, name);
404
- if (XT_IS_ARRAY(array)) {
405
- xt_value kept = xt_array_new(0, NULL);
406
- int32_t count = (int32_t)xt_to_number(xt_array_length(array));
407
- for (int32_t i = 0; i < count; i++) {
408
- xt_value candidate = xt_array_get(array, xt_number((double)i));
409
- if (candidate != fn) xt_array_push(kept, candidate);
410
- }
411
- xt_object_set(listeners, name, kept);
412
- }
413
- }
414
- }
415
- return self;
416
- }
417
-
418
- /** Web spelling of 'on': 'window.addEventListener(type, fn, options?)'. The
419
- * optional 'options' argument ('capture'/'once') is accepted and ignored —
420
- * window-level delivery has no capture phase — so a document written against
421
- * the browser API compiles and behaves the same here. */
422
- static xt_value win_add_event_listener(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
423
- win_on(self, env, argc, argv);
424
- return XT_UNDEFINED;
425
- }
426
-
427
- /** Web spelling of 'off': 'window.removeEventListener(type, fn, options?)'. */
428
- static xt_value win_remove_event_listener(xt_value self, xt_value env, int32_t argc,
429
- xt_value *argv) {
430
- win_off(self, env, argc, argv);
431
- return XT_UNDEFINED;
432
- }
433
384
 
434
385
  /* -- input diagnostics ---------------------------------------------------- */
435
386
 
@@ -570,12 +521,10 @@ xt_value xt_gui_window_proto(void) {
570
521
  define_method(proto, "driver", (void *)win_driver);
571
522
  define_method(proto, "requestAnimationFrame", (void *)win_request_animation_frame);
572
523
  define_method(proto, "cancelAnimationFrame", (void *)win_cancel_animation_frame);
573
- define_method(proto, "on", (void *)win_on);
574
- define_method(proto, "off", (void *)win_off);
575
- /* Web spellings, so a document written against the browser API runs
576
- * unchanged under the engine. */
577
- define_method(proto, "addEventListener", (void *)win_add_event_listener);
578
- define_method(proto, "removeEventListener", (void *)win_remove_event_listener);
524
+ /* `on` / `off` and their Web spellings (`addEventListener` /
525
+ * `removeEventListener` with the listener options bag) live in
526
+ * `window_events.cpp`. */
527
+ xt_gui_install_window_events(proto);
579
528
  define_method(proto, "hitTest", (void *)win_hit_test);
580
529
  define_method(proto, "sendEvent", (void *)win_send_event);
581
530
  define_method(proto, "stats", (void *)win_stats);
@@ -0,0 +1,125 @@
1
+ /*
2
+ * xbintsc GUI engine — window-level event listeners.
3
+ *
4
+ * `win.on` / `win.off` keep their legacy behaviour (an event name plus a
5
+ * callback, delivered with the input payload); `win.addEventListener` /
6
+ * `win.removeEventListener` take the Web options bag (`capture`, `once`,
7
+ * `passive`, `signal`). Both register in the window's single listener vector, so
8
+ * a listener added through one spelling can be removed through the other, and
9
+ * `gui_events.cpp` delivers one merged batch.
10
+ */
11
+
12
+ #include "gui_engine.h"
13
+ #include "listener_options.h"
14
+
15
+ #include <algorithm>
16
+ #include <string>
17
+ #include <vector>
18
+
19
+ namespace {
20
+
21
+ std::string listener_string(xt_value value) {
22
+ const char *data = xt_string_data(xt_to_string(value));
23
+ return data != nullptr ? data : "";
24
+ }
25
+
26
+ void push_listener(XtGuiWindow *win, const std::string &type, xt_value fn, bool once, bool capture,
27
+ bool passive, xt_value signal) {
28
+ if (win == nullptr || !XT_IS_FUNCTION(fn)) return;
29
+ XtGuiWindowListener listener;
30
+ listener.type = type;
31
+ listener.fn = fn;
32
+ listener.once = once;
33
+ listener.capture = capture;
34
+ listener.passive = passive;
35
+ listener.signal = signal;
36
+ win->window_listeners.push_back(listener);
37
+ }
38
+
39
+ xt_value win_on(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
40
+ (void)env;
41
+ if (argc >= 2) {
42
+ XtGuiWindow *win = xt_gui_window_from_this(self);
43
+ xt_value fn = xt_arg(argc, argv, 1);
44
+ if (win != nullptr && XT_IS_FUNCTION(fn)) {
45
+ push_listener(win, listener_string(xt_arg(argc, argv, 0)), fn, false, false, false,
46
+ XT_UNDEFINED);
47
+ }
48
+ }
49
+ return self;
50
+ }
51
+
52
+ xt_value win_off(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
53
+ (void)env;
54
+ if (argc >= 2) {
55
+ XtGuiWindow *win = xt_gui_window_from_this(self);
56
+ if (win != nullptr) {
57
+ std::string type = listener_string(xt_arg(argc, argv, 0));
58
+ xt_value fn = xt_arg(argc, argv, 1);
59
+ std::vector<XtGuiWindowListener> &listeners = win->window_listeners;
60
+ listeners.erase(std::remove_if(listeners.begin(), listeners.end(),
61
+ [&](const XtGuiWindowListener &listener) {
62
+ return listener.type == type &&
63
+ xt_truthy(xt_seq(listener.fn, fn));
64
+ }),
65
+ listeners.end());
66
+ }
67
+ }
68
+ return self;
69
+ }
70
+
71
+ /** Web spelling of `on`: `window.addEventListener(type, fn, options?)`. Window
72
+ * delivery has no capture phase, but `capture` is part of listener identity so
73
+ * `removeEventListener(type, fn, true)` still matches the right entry. */
74
+ xt_value win_add_event_listener(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
75
+ (void)env;
76
+ if (argc < 2) return XT_UNDEFINED;
77
+ XtGuiWindow *win = xt_gui_window_from_this(self);
78
+ std::string type = listener_string(xt_arg(argc, argv, 0));
79
+ xt_value fn = xt_arg(argc, argv, 1);
80
+ XtGuiListenerOptions options = xt_gui_listener_options(xt_arg(argc, argv, 2));
81
+ if (win == nullptr || !XT_IS_FUNCTION(fn) || xt_gui_signal_aborted(options.signal)) {
82
+ return XT_UNDEFINED;
83
+ }
84
+ /* The DOM ignores a second registration of the same (type, fn, capture). */
85
+ for (const XtGuiWindowListener &existing : win->window_listeners) {
86
+ if (existing.type == type && existing.capture == options.capture &&
87
+ xt_truthy(xt_seq(existing.fn, fn))) {
88
+ return XT_UNDEFINED;
89
+ }
90
+ }
91
+ push_listener(win, type, fn, options.once, options.capture, options.passive, options.signal);
92
+ return XT_UNDEFINED;
93
+ }
94
+
95
+ /** Web spelling of `off`: `window.removeEventListener(type, fn, options?)`. */
96
+ xt_value win_remove_event_listener(xt_value self, xt_value env, int32_t argc, xt_value *argv) {
97
+ (void)env;
98
+ if (argc < 2) return XT_UNDEFINED;
99
+ XtGuiWindow *win = xt_gui_window_from_this(self);
100
+ if (win == nullptr) return XT_UNDEFINED;
101
+ std::string type = listener_string(xt_arg(argc, argv, 0));
102
+ xt_value fn = xt_arg(argc, argv, 1);
103
+ XtGuiListenerOptions options = xt_gui_listener_options(xt_arg(argc, argv, 2));
104
+ std::vector<XtGuiWindowListener> &listeners = win->window_listeners;
105
+ for (auto it = listeners.begin(); it != listeners.end(); ++it) {
106
+ if (it->type == type && it->capture == options.capture && xt_truthy(xt_seq(it->fn, fn))) {
107
+ listeners.erase(it);
108
+ return XT_UNDEFINED;
109
+ }
110
+ }
111
+ return XT_UNDEFINED;
112
+ }
113
+
114
+ } // namespace
115
+
116
+ void xt_gui_install_window_events(xt_value proto) {
117
+ xt_object_set(proto, xt_string_from_cstr("on"),
118
+ xt_closure_new((void *)win_on, 0, nullptr));
119
+ xt_object_set(proto, xt_string_from_cstr("off"),
120
+ xt_closure_new((void *)win_off, 0, nullptr));
121
+ xt_object_set(proto, xt_string_from_cstr("addEventListener"),
122
+ xt_closure_new((void *)win_add_event_listener, 0, nullptr));
123
+ xt_object_set(proto, xt_string_from_cstr("removeEventListener"),
124
+ xt_closure_new((void *)win_remove_event_listener, 0, nullptr));
125
+ }