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,270 @@
1
+ /*
2
+ * xbintsc GUI engine — WebGL buffer objects and vertex-attribute state.
3
+ *
4
+ * Uploads are recorded immediately: a copy pass cannot run inside a render
5
+ * pass, so a buffer update ends the open pass first. The next draw starts a
6
+ * new pass with `LOAD`, so the framebuffer keeps its contents.
7
+ */
8
+
9
+ #include "webgl.h"
10
+
11
+ #include <algorithm>
12
+ #include <cstring>
13
+
14
+ #include "gui_internal.h"
15
+
16
+ namespace xtgui {
17
+ namespace {
18
+
19
+ bool upload_transfer(SDL_GPUDevice *device, SDL_GPUCommandBuffer *cmd, SDL_GPUBuffer *buffer,
20
+ const void *bytes, uint32_t size) {
21
+ if (size == 0) return true;
22
+ SDL_GPUTransferBufferCreateInfo info;
23
+ memset(&info, 0, sizeof(info));
24
+ info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
25
+ info.size = size;
26
+ SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &info);
27
+ if (transfer == nullptr) return false;
28
+ void *mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
29
+ if (mapped == nullptr) {
30
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
31
+ return false;
32
+ }
33
+ memcpy(mapped, bytes, size);
34
+ SDL_UnmapGPUTransferBuffer(device, transfer);
35
+ SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
36
+ SDL_GPUTransferBufferLocation source;
37
+ memset(&source, 0, sizeof(source));
38
+ source.transfer_buffer = transfer;
39
+ SDL_GPUBufferRegion region;
40
+ memset(&region, 0, sizeof(region));
41
+ region.buffer = buffer;
42
+ region.size = size;
43
+ SDL_UploadToGPUBuffer(copy, &source, &region, false);
44
+ SDL_EndGPUCopyPass(copy);
45
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
46
+ return true;
47
+ }
48
+
49
+ } // namespace
50
+
51
+ /* -- buffers ------------------------------------------------------------- */
52
+
53
+ uint32_t WebGLContext::create_buffer() {
54
+ auto record = std::make_unique<WebGLBuffer>();
55
+ record->id = next_object_id_++;
56
+ const uint32_t id = record->id;
57
+ buffers_[id] = std::move(record);
58
+ return id;
59
+ }
60
+
61
+ void WebGLContext::delete_buffer(uint32_t id) {
62
+ auto found = buffers_.find(id);
63
+ if (found == buffers_.end()) return;
64
+ if (bound_array_ == id) bound_array_ = 0;
65
+ if (bound_element_ == id) bound_element_ = 0;
66
+ for (WebGLAttribState &attrib : attribs_) {
67
+ if (attrib.buffer == id) attrib.buffer = 0;
68
+ }
69
+ if (found->second->gpu != nullptr && guidev::g_device != nullptr) {
70
+ submit(); SDL_WaitForGPUIdle(guidev::g_device);
71
+ SDL_ReleaseGPUBuffer(guidev::g_device, found->second->gpu);
72
+ }
73
+ buffers_.erase(found);
74
+ }
75
+
76
+ void WebGLContext::bind_buffer(int target, uint32_t id) {
77
+ if (id != 0 && buffers_.find(id) == buffers_.end()) return;
78
+ if (target == GL_ARRAY_BUFFER) bound_array_ = id;
79
+ if (target == GL_ELEMENT_ARRAY_BUFFER) bound_element_ = id;
80
+ if (target == GL_COPY_READ_BUFFER) copy_read_buffer_ = id;
81
+ if (target == GL_COPY_WRITE_BUFFER) copy_write_buffer_ = id;
82
+ if (target == GL_UNIFORM_BUFFER) bound_uniform_ = id;
83
+ if (target == GL_TRANSFORM_FEEDBACK_BUFFER) bound_transform_feedback_ = id;
84
+ }
85
+
86
+ uint32_t WebGLContext::buffer_for_target(int target) const {
87
+ if (target == GL_ELEMENT_ARRAY_BUFFER) return bound_element_;
88
+ if (target == GL_ARRAY_BUFFER) return bound_array_;
89
+ if (target == GL_COPY_READ_BUFFER) return copy_read_buffer_;
90
+ if (target == GL_COPY_WRITE_BUFFER) return copy_write_buffer_;
91
+ if (target == GL_UNIFORM_BUFFER) return bound_uniform_;
92
+ if (target == GL_TRANSFORM_FEEDBACK_BUFFER) return bound_transform_feedback_;
93
+ return 0;
94
+ }
95
+
96
+ bool WebGLContext::copy_buffer_sub_data(int read_target, int write_target, uint32_t read_offset,
97
+ uint32_t write_offset, uint32_t size) {
98
+ WebGLBuffer *read_buffer = buffer(buffer_for_target(read_target));
99
+ WebGLBuffer *write_buffer = buffer(buffer_for_target(write_target));
100
+ if (read_buffer == nullptr || write_buffer == nullptr ||
101
+ read_offset + size > read_buffer->data.size() ||
102
+ write_offset + size > write_buffer->data.size()) {
103
+ set_error(GL_INVALID_VALUE);
104
+ return false;
105
+ }
106
+ if (size > 0) {
107
+ memmove(write_buffer->data.data() + write_offset,
108
+ read_buffer->data.data() + read_offset, size);
109
+ }
110
+ write_buffer->dirty = true;
111
+ return ensure_buffer_gpu(write_buffer) != nullptr || size == 0;
112
+ }
113
+
114
+ bool WebGLContext::get_buffer_sub_data(int target, uint32_t offset, uint8_t *out,
115
+ uint32_t size) {
116
+ WebGLBuffer *record = buffer(buffer_for_target(target));
117
+ if (record == nullptr || offset + size > record->data.size()) {
118
+ set_error(GL_INVALID_VALUE);
119
+ return false;
120
+ }
121
+ if (size > 0) memcpy(out, record->data.data() + offset, size);
122
+ return true;
123
+ }
124
+
125
+ SDL_GPUBuffer *WebGLContext::ensure_buffer_gpu(WebGLBuffer *buffer) {
126
+ if (buffer == nullptr || guidev::g_device == nullptr) return nullptr;
127
+ if (buffer->data.empty()) return nullptr;
128
+ end_pass();
129
+ ensure_command();
130
+ if (cmd_ == nullptr) return nullptr;
131
+ const uint32_t size = (uint32_t)buffer->data.size();
132
+ if (buffer->gpu == nullptr || buffer->capacity < size) {
133
+ if (buffer->gpu != nullptr) {
134
+ submit(); SDL_WaitForGPUIdle(guidev::g_device);
135
+ SDL_ReleaseGPUBuffer(guidev::g_device, buffer->gpu);
136
+ }
137
+ SDL_GPUBufferCreateInfo info;
138
+ memset(&info, 0, sizeof(info));
139
+ info.usage = SDL_GPU_BUFFERUSAGE_VERTEX | SDL_GPU_BUFFERUSAGE_INDEX;
140
+ info.size = size;
141
+ buffer->gpu = SDL_CreateGPUBuffer(guidev::g_device, &info);
142
+ buffer->capacity = size;
143
+ if (buffer->gpu == nullptr) {
144
+ set_error(GL_OUT_OF_MEMORY);
145
+ return nullptr;
146
+ }
147
+ }
148
+ if (buffer->dirty) {
149
+ /* Recreating the buffer above submitted the pending command buffer. */
150
+ ensure_command();
151
+ if (cmd_ == nullptr) return nullptr;
152
+ if (!upload_transfer(guidev::g_device, cmd_, buffer->gpu, buffer->data.data(), size)) {
153
+ set_error(GL_OUT_OF_MEMORY);
154
+ return nullptr;
155
+ }
156
+ buffer->dirty = false;
157
+ }
158
+ return buffer->gpu;
159
+ }
160
+
161
+ bool WebGLContext::buffer_data(uint32_t id, const uint8_t *bytes, uint32_t size, int usage) {
162
+ WebGLBuffer *record = buffer(id);
163
+ if (record == nullptr) {
164
+ set_error(GL_INVALID_OPERATION);
165
+ return false;
166
+ }
167
+ if (usage == GL_STREAM_DRAW || usage == GL_STATIC_DRAW || usage == GL_DYNAMIC_DRAW) {
168
+ record->usage = usage;
169
+ } else if (usage != 0) {
170
+ set_error(GL_INVALID_ENUM);
171
+ return false;
172
+ }
173
+ record->data.assign(size, 0);
174
+ if (bytes != nullptr && size > 0) memcpy(record->data.data(), bytes, size);
175
+ record->dirty = true;
176
+ return ensure_buffer_gpu(record) != nullptr || size == 0;
177
+ }
178
+
179
+ bool WebGLContext::buffer_sub_data(uint32_t id, uint32_t offset, const uint8_t *bytes,
180
+ uint32_t size) {
181
+ WebGLBuffer *record = buffer(id);
182
+ if (record == nullptr || offset > record->data.size() ||
183
+ offset + size > record->data.size()) {
184
+ set_error(GL_INVALID_VALUE);
185
+ return false;
186
+ }
187
+ memcpy(record->data.data() + offset, bytes, size);
188
+ record->dirty = true;
189
+ return ensure_buffer_gpu(record) != nullptr;
190
+ }
191
+
192
+ uint32_t WebGLContext::buffer_size(uint32_t id) {
193
+ WebGLBuffer *record = buffer(id);
194
+ return record != nullptr ? (uint32_t)record->data.size() : 0;
195
+ }
196
+
197
+ /* -- vertex attributes --------------------------------------------------- */
198
+
199
+ void WebGLContext::enable_attrib(int index, bool enabled) {
200
+ if (index < 0 || index >= kWebGLMaxAttribs) {
201
+ set_error(GL_INVALID_VALUE);
202
+ return;
203
+ }
204
+ attribs_[index].enabled = enabled;
205
+ }
206
+
207
+ bool WebGLContext::attrib_enabled(int index) const {
208
+ return index >= 0 && index < kWebGLMaxAttribs && attribs_[index].enabled;
209
+ }
210
+
211
+ void WebGLContext::attrib_pointer(int index, int size, int type, bool normalized, int stride,
212
+ int offset) {
213
+ if (index < 0 || index >= kWebGLMaxAttribs) {
214
+ set_error(GL_INVALID_VALUE);
215
+ return;
216
+ }
217
+ WebGLAttribState &attrib = attribs_[index];
218
+ attrib.buffer = bound_array_;
219
+ attrib.size = size;
220
+ attrib.type = type;
221
+ attrib.normalized = normalized;
222
+ attrib.integer = false;
223
+ attrib.stride = stride > 0 ? stride : 0;
224
+ attrib.offset = offset;
225
+ }
226
+
227
+ void WebGLContext::attrib_ipointer(int index, int size, int type, int stride, int offset) {
228
+ if (index < 0 || index >= kWebGLMaxAttribs) {
229
+ set_error(GL_INVALID_VALUE);
230
+ return;
231
+ }
232
+ WebGLAttribState &attrib = attribs_[index];
233
+ attrib.buffer = bound_array_;
234
+ attrib.size = size;
235
+ attrib.type = type;
236
+ attrib.normalized = false;
237
+ attrib.integer = true;
238
+ attrib.stride = stride > 0 ? stride : 0;
239
+ attrib.offset = offset;
240
+ }
241
+
242
+ void WebGLContext::attrib_divisor(int index, int divisor) {
243
+ if (index < 0 || index >= kWebGLMaxAttribs) {
244
+ set_error(GL_INVALID_VALUE);
245
+ return;
246
+ }
247
+ /* SDL 3.2's `instance_step_rate` is reserved and must be 0, so only the two
248
+ * rates WebGL programs use — per vertex (0) and per instance (1) — map onto
249
+ * the backend. A larger divisor is clamped. */
250
+ attribs_[index].divisor = divisor > 0 ? 1 : 0;
251
+ }
252
+
253
+ void WebGLContext::attrib_value(int index, int components, const float *values) {
254
+ if (index < 0 || index >= kWebGLMaxAttribs) return;
255
+ for (int i = 0; i < 4; i++) attribs_[index].current[i] = i < components ? values[i] : 0.0f;
256
+ if (components < 4) attribs_[index].current[3] = 1.0f;
257
+ }
258
+
259
+ void WebGLContext::attrib_state(int index, int *size, int *type, int *stride, bool *normalized,
260
+ float current[4]) const {
261
+ if (index < 0 || index >= kWebGLMaxAttribs) return;
262
+ const WebGLAttribState &attrib = attribs_[index];
263
+ *size = attrib.size;
264
+ *type = attrib.type;
265
+ *stride = attrib.stride;
266
+ *normalized = attrib.normalized;
267
+ for (int i = 0; i < 4; i++) current[i] = attrib.current[i];
268
+ }
269
+
270
+ } // namespace xtgui
@@ -0,0 +1,142 @@
1
+ /*
2
+ * xbintsc GUI engine — scissored clear.
3
+ *
4
+ * SDL_GPU render-pass clears ignore the scissor rectangle, but WebGL's `clear`
5
+ * honours it. A scissored colour clear is a blit from a 1×1 clear-colour
6
+ * texture into the scissor rectangle; depth and stencil are cleared by drawing
7
+ * a fullscreen triangle with colour writes masked off and depth/stencil writes
8
+ * enabled (depth test ALWAYS, stencil REPLACE).
9
+ *
10
+ * The internal program and buffer are ordinary engine objects, created lazily
11
+ * on the first scissored depth/stencil clear and kept for the context lifetime.
12
+ * The caller's state is saved and restored around the draw, so `clear` remains
13
+ * an API call that only changes the attachment contents.
14
+ */
15
+
16
+ #include "webgl.h"
17
+
18
+ #include <cstring>
19
+
20
+ #include "gui_internal.h"
21
+
22
+ namespace xtgui {
23
+ namespace {
24
+
25
+ const char *kClearVertexShader =
26
+ "attribute vec2 a_pos;\n"
27
+ "uniform float u_z;\n"
28
+ "void main() { gl_Position = vec4(a_pos, u_z, 1.0); }\n";
29
+
30
+ const char *kClearFragmentShader =
31
+ "precision mediump float;\n"
32
+ "void main() { gl_FragColor = vec4(0.0); }\n";
33
+
34
+ } // namespace
35
+
36
+ void WebGLContext::scissored_clear(int mask) {
37
+ if (guidev::g_device == nullptr) return;
38
+ const bool depth_bit = (mask & GL_DEPTH_BUFFER_BIT) != 0;
39
+ const bool stencil_bit = (mask & GL_STENCIL_BUFFER_BIT) != 0;
40
+ if (!depth_bit && !stencil_bit) return;
41
+
42
+ if (clear_program_ == 0) {
43
+ const uint32_t vs = create_shader(GL_VERTEX_SHADER);
44
+ shader_source(vs, kClearVertexShader);
45
+ const uint32_t fs = create_shader(GL_FRAGMENT_SHADER);
46
+ shader_source(fs, kClearFragmentShader);
47
+ if (compile_shader(vs) && compile_shader(fs)) {
48
+ const uint32_t program = create_program();
49
+ attach_shader(program, vs);
50
+ attach_shader(program, fs);
51
+ bind_attrib_location(program, 0, "a_pos");
52
+ if (link_program(program)) {
53
+ clear_program_ = program;
54
+ } else {
55
+ delete_program(program);
56
+ }
57
+ }
58
+ if (clear_program_ == 0) {
59
+ delete_shader(vs);
60
+ delete_shader(fs);
61
+ }
62
+ }
63
+ if (clear_program_ == 0) {
64
+ /* No shader backend: fall back to clearing the whole attachment rather than
65
+ * leaving the buffer untouched. */
66
+ begin_pass(false, depth_bit, stencil_bit);
67
+ return;
68
+ }
69
+ if (clear_buffer_ == 0) {
70
+ clear_buffer_ = create_buffer();
71
+ bind_buffer(GL_ARRAY_BUFFER, clear_buffer_);
72
+ const float vertices[6] = {-1.0f, -1.0f, 3.0f, -1.0f, -1.0f, 3.0f};
73
+ buffer_data(clear_buffer_, (const uint8_t *)vertices, (uint32_t)sizeof(vertices),
74
+ GL_DYNAMIC_DRAW);
75
+ }
76
+ if (clear_buffer_ == 0) {
77
+ begin_pass(false, depth_bit, stencil_bit);
78
+ return;
79
+ }
80
+
81
+ const WebGLDrawState saved_state = state_;
82
+ const uint32_t saved_program = current_program_;
83
+ const uint32_t saved_array = bound_array_;
84
+ int saved_viewport[4];
85
+ for (int i = 0; i < 4; i++) saved_viewport[i] = viewport_[i];
86
+ WebGLAttribState saved_attribs[kWebGLMaxAttribs];
87
+ memcpy(saved_attribs, attribs_, sizeof(attribs_));
88
+
89
+ state_.blend = false;
90
+ state_.cull = false;
91
+ for (bool &channel : state_.color_mask) channel = false;
92
+ state_.depth_test = depth_bit;
93
+ state_.depth_write = depth_bit;
94
+ state_.depth_func = GL_ALWAYS;
95
+ state_.stencil = stencil_bit;
96
+ if (stencil_bit) {
97
+ for (WebGLStencilFace *face : {&state_.stencil_front, &state_.stencil_back}) {
98
+ face->func = GL_ALWAYS;
99
+ face->ref = clear_stencil_;
100
+ face->value_mask = 0xFF;
101
+ face->write_mask = 0xFF;
102
+ face->fail = GL_KEEP;
103
+ face->zfail = GL_KEEP;
104
+ face->zpass = GL_REPLACE;
105
+ }
106
+ }
107
+ current_program_ = clear_program_;
108
+ int attrib = attrib_location(clear_program_, "a_pos");
109
+ if (attrib < 0 || attrib >= kWebGLMaxAttribs) attrib = 0;
110
+ attribs_[attrib] = WebGLAttribState();
111
+ attribs_[attrib].enabled = true;
112
+ attribs_[attrib].buffer = clear_buffer_;
113
+ attribs_[attrib].size = 2;
114
+ attribs_[attrib].type = GL_FLOAT;
115
+ attribs_[attrib].stride = 8;
116
+ attribs_[attrib].offset = 0;
117
+ int target_width = 0;
118
+ int target_height = 0;
119
+ framebuffer_size(bound_framebuffer_, &target_width, &target_height);
120
+ viewport_[0] = 0;
121
+ viewport_[1] = 0;
122
+ viewport_[2] = target_width;
123
+ viewport_[3] = target_height;
124
+
125
+ begin_pass(false, false, false);
126
+ if (pass_ != nullptr) {
127
+ const int z_location = uniform_location(clear_program_, "u_z");
128
+ if (z_location >= 0) {
129
+ const double depth = (double)clear_depth_;
130
+ uniform_floats(clear_program_, z_location, 1, &depth, 1);
131
+ }
132
+ draw_arrays(GL_TRIANGLES, 0, 3);
133
+ }
134
+
135
+ state_ = saved_state;
136
+ current_program_ = saved_program;
137
+ bound_array_ = saved_array;
138
+ memcpy(attribs_, saved_attribs, sizeof(attribs_));
139
+ for (int i = 0; i < 4; i++) viewport_[i] = saved_viewport[i];
140
+ }
141
+
142
+ } // namespace xtgui
@@ -0,0 +1,180 @@
1
+ /*
2
+ * xbintsc GUI engine — compressed textures (S3TC/BC and ASTC).
3
+ *
4
+ * SDL_GPU exposes block-compressed formats directly, so the engine only has to
5
+ * map the WebGL extension enum to the SDL one and upload the tightly packed
6
+ * blocks. Compressed textures are sample-only and get a single mip level.
7
+ */
8
+
9
+ #include "webgl.h"
10
+
11
+ #include <cstring>
12
+
13
+ #include "gui_internal.h"
14
+
15
+ namespace xtgui {
16
+ namespace {
17
+
18
+ bool upload_compressed(SDL_GPUDevice *device, SDL_GPUCommandBuffer *cmd, SDL_GPUTexture *gpu,
19
+ int x, int y, int width, int height, const uint8_t *data, uint32_t size) {
20
+ if (gpu == nullptr || data == nullptr || size == 0 || width <= 0 || height <= 0) return false;
21
+ SDL_GPUTransferBufferCreateInfo info;
22
+ memset(&info, 0, sizeof(info));
23
+ info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
24
+ info.size = size;
25
+ SDL_GPUTransferBuffer *transfer = SDL_CreateGPUTransferBuffer(device, &info);
26
+ if (transfer == nullptr) return false;
27
+ void *mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
28
+ if (mapped == nullptr) {
29
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
30
+ return false;
31
+ }
32
+ memcpy(mapped, data, size);
33
+ SDL_UnmapGPUTransferBuffer(device, transfer);
34
+ SDL_GPUTextureTransferInfo source;
35
+ memset(&source, 0, sizeof(source));
36
+ source.transfer_buffer = transfer;
37
+ source.pixels_per_row = (Uint32)width;
38
+ source.rows_per_layer = (Uint32)height;
39
+ SDL_GPUTextureRegion region;
40
+ memset(&region, 0, sizeof(region));
41
+ region.texture = gpu;
42
+ region.x = (Uint32)x;
43
+ region.y = (Uint32)y;
44
+ region.w = (Uint32)width;
45
+ region.h = (Uint32)height;
46
+ region.d = 1;
47
+ SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
48
+ SDL_UploadToGPUTexture(copy, &source, &region, false);
49
+ SDL_EndGPUCopyPass(copy);
50
+ SDL_ReleaseGPUTransferBuffer(device, transfer);
51
+ return true;
52
+ }
53
+
54
+ } // namespace
55
+
56
+ SDL_GPUTextureFormat webgl_compressed_format(int internalformat) {
57
+ switch (internalformat) {
58
+ /* WEBGL_compressed_texture_s3tc */
59
+ case 0x83F0: // COMPRESSED_RGB_S3TC_DXT1_EXT
60
+ case 0x83F1: // COMPRESSED_RGBA_S3TC_DXT1_EXT
61
+ return SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM;
62
+ case 0x83F2: // COMPRESSED_RGBA_S3TC_DXT3_EXT
63
+ return SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM;
64
+ case 0x83F3: // COMPRESSED_RGBA_S3TC_DXT5_EXT
65
+ return SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM;
66
+ /* WEBGL_compressed_texture_s3tc_srgb */
67
+ case 0x8C4C: // COMPRESSED_SRGB_S3TC_DXT1_EXT
68
+ case 0x8C4D: // COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
69
+ return SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB;
70
+ case 0x8C4E: // COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
71
+ return SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB;
72
+ case 0x8C4F: // COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
73
+ return SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB;
74
+ /* WEBGL_compressed_texture_astc (LDR) */
75
+ case 0x93B0:
76
+ return SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM;
77
+ case 0x93B1:
78
+ return SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM;
79
+ case 0x93B2:
80
+ return SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM;
81
+ case 0x93B3:
82
+ return SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM;
83
+ case 0x93B4:
84
+ return SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM;
85
+ case 0x93B5:
86
+ return SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM;
87
+ case 0x93B6:
88
+ return SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM;
89
+ case 0x93B7:
90
+ return SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM;
91
+ case 0x93B8:
92
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM;
93
+ case 0x93B9:
94
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM;
95
+ case 0x93BA:
96
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM;
97
+ case 0x93BB:
98
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM;
99
+ case 0x93BC:
100
+ return SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM;
101
+ case 0x93BD:
102
+ return SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM;
103
+ /* ASTC sRGB */
104
+ case 0x93D0:
105
+ return SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB;
106
+ case 0x93D1:
107
+ return SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB;
108
+ case 0x93D2:
109
+ return SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB;
110
+ case 0x93D3:
111
+ return SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB;
112
+ case 0x93D4:
113
+ return SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB;
114
+ case 0x93D5:
115
+ return SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB;
116
+ case 0x93D6:
117
+ return SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB;
118
+ case 0x93D7:
119
+ return SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB;
120
+ case 0x93D8:
121
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB;
122
+ case 0x93D9:
123
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB;
124
+ case 0x93DA:
125
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB;
126
+ case 0x93DB:
127
+ return SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB;
128
+ case 0x93DC:
129
+ return SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB;
130
+ case 0x93DD:
131
+ return SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB;
132
+ default:
133
+ return SDL_GPU_TEXTUREFORMAT_INVALID;
134
+ }
135
+ }
136
+
137
+ bool WebGLContext::supports_texture_format(int internalformat) {
138
+ const SDL_GPUTextureFormat format = webgl_compressed_format(internalformat);
139
+ if (format == SDL_GPU_TEXTUREFORMAT_INVALID || guidev::g_device == nullptr) return false;
140
+ return SDL_GPUTextureSupportsFormat(guidev::g_device, format, SDL_GPU_TEXTURETYPE_2D,
141
+ SDL_GPU_TEXTUREUSAGE_SAMPLER);
142
+ }
143
+
144
+ bool WebGLContext::tex_image_compressed(uint32_t id, int width, int height,
145
+ SDL_GPUTextureFormat format, int x, int y,
146
+ int region_width, int region_height,
147
+ const uint8_t *data, uint32_t size) {
148
+ WebGLTexture *record = texture(id);
149
+ if (record == nullptr || width <= 0 || height <= 0 || format == SDL_GPU_TEXTUREFORMAT_INVALID) {
150
+ set_error(GL_INVALID_VALUE);
151
+ return false;
152
+ }
153
+ end_pass();
154
+ ensure_command();
155
+ if (cmd_ == nullptr) return false;
156
+ if (record->gpu != nullptr &&
157
+ (record->width != width || record->height != height || record->format != format ||
158
+ !record->compressed)) {
159
+ SDL_WaitForGPUIdle(guidev::g_device);
160
+ SDL_ReleaseGPUTexture(guidev::g_device, record->gpu);
161
+ record->gpu = nullptr;
162
+ record->usage = 0;
163
+ }
164
+ record->width = width;
165
+ record->height = height;
166
+ record->format = format;
167
+ record->depth = false;
168
+ record->compressed = true;
169
+ record->has_mipmaps = false;
170
+ if (record->sampler != nullptr) {
171
+ SDL_ReleaseGPUSampler(guidev::g_device, record->sampler);
172
+ record->sampler = nullptr;
173
+ }
174
+ if (ensure_texture_gpu(record, false) == nullptr) return false;
175
+ record->defined = true;
176
+ return upload_compressed(guidev::g_device, cmd_, record->gpu, x, y, region_width, region_height,
177
+ data, size);
178
+ }
179
+
180
+ } // namespace xtgui