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
@@ -39,35 +39,6 @@ bool g_atlas_dirty = false;
39
39
  int g_atlas_dirty_x0 = 0, g_atlas_dirty_y0 = 0, g_atlas_dirty_x1 = 0, g_atlas_dirty_y1 = 0;
40
40
  bool g_atlas_full_logged = false;
41
41
 
42
- void pushRect(std::vector<Vertex> &verts, const xtgui::PaintRect &rect) {
43
- float hw = rect.width * 0.5f;
44
- float hh = rect.height * 0.5f;
45
- float cx = rect.x + hw;
46
- float cy = rect.y + hh;
47
- float radius = std::min(rect.radius, std::min(hw, hh));
48
-
49
- const float local_x[4] = {-hw, hw, hw, -hw};
50
- const float local_y[4] = {-hh, -hh, hh, hh};
51
- Vertex corners[4];
52
- for (int i = 0; i < 4; i++) {
53
- /* `local` keeps the distance-field coordinates in the box's own frame, so
54
- * a rotated/scaled shape still gets a rounded rectangle (the radius scales
55
- * with the matrix instead of staying circular). */
56
- rect.transform.apply(cx + local_x[i], cy + local_y[i], &corners[i].x, &corners[i].y);
57
- corners[i].lx = local_x[i];
58
- corners[i].ly = local_y[i];
59
- corners[i].hx = hw;
60
- corners[i].hy = hh;
61
- corners[i].radius = radius;
62
- corners[i].r = rect.color.r;
63
- corners[i].g = rect.color.g;
64
- corners[i].b = rect.color.b;
65
- corners[i].a = rect.color.a;
66
- }
67
- static const int order[6] = {0, 1, 2, 0, 2, 3};
68
- for (int i = 0; i < 6; i++) verts.push_back(corners[order[i]]);
69
- }
70
-
71
42
  /** Upload `count` vertices (of `stride` bytes) into `geometry`, reusing or
72
43
  * growing its GPU buffer. Does nothing when `count` is zero. */
73
44
  void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *data,
@@ -277,8 +248,14 @@ void xt_gui_geometry_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
277
248
  using namespace xtgui::renderer_detail;
278
249
  std::vector<Vertex> verts;
279
250
  verts.reserve(list.rects.size() * 6);
280
- geometry->op_counts.assign(list.rects.size(), 6);
281
- for (const xtgui::PaintRect &rect : list.rects) pushRect(verts, rect);
251
+ geometry->op_counts.assign(list.rects.size(), 0);
252
+ /* Walk painter order so each rectangle carries its op's clip path. */
253
+ for (const xtgui::PaintOp &op : list.ops) {
254
+ if (op.kind != xtgui::PaintKind::Rect || op.index >= list.rects.size()) continue;
255
+ uint32_t before = (uint32_t)verts.size();
256
+ pushShape(verts, list.rects[op.index], op.clip, list);
257
+ geometry->op_counts[op.index] = (uint32_t)verts.size() - before;
258
+ }
282
259
  uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(Vertex));
283
260
  }
284
261
 
@@ -0,0 +1,196 @@
1
+ /*
2
+ * xbintsc GUI engine — CPU geometry clipping for `clip-path`.
3
+ *
4
+ * Every painted shape is a convex quad. The paint pass leaves each clip path as
5
+ * a triangulated device-space polygon; clipping a convex quad by one triangle
6
+ * keeps it convex, so the result is emitted as a triangle fan. Clipping against
7
+ * a concave path is correct because its triangles partition the path.
8
+ */
9
+
10
+ #include "renderer_internal.h"
11
+
12
+ #include <algorithm>
13
+ #include <vector>
14
+
15
+ namespace xtgui {
16
+ namespace renderer_detail {
17
+
18
+ namespace {
19
+
20
+ float side(const ClipTriangle &triangle, int edge, float x, float y) {
21
+ int next = (edge + 1) % 3;
22
+ float ax = triangle.x[edge];
23
+ float ay = triangle.y[edge];
24
+ float bx = triangle.x[next];
25
+ float by = triangle.y[next];
26
+ return (bx - ax) * (y - ay) - (by - ay) * (x - ax);
27
+ }
28
+
29
+ bool triangleOrientation(const ClipTriangle &triangle, float *orientation) {
30
+ float cross = (triangle.x[1] - triangle.x[0]) * (triangle.y[2] - triangle.y[0]) -
31
+ (triangle.y[1] - triangle.y[0]) * (triangle.x[2] - triangle.x[0]);
32
+ if (cross > -0.00001f && cross < 0.00001f) return false;
33
+ *orientation = cross > 0.0f ? 1.0f : -1.0f;
34
+ return true;
35
+ }
36
+
37
+ template <typename V, typename Mix>
38
+ std::vector<V> clipToTriangle(const std::vector<V> &subject, const ClipTriangle &triangle,
39
+ Mix mix) {
40
+ float orientation = 0.0f;
41
+ if (!triangleOrientation(triangle, &orientation)) return std::vector<V>();
42
+ std::vector<V> out = subject;
43
+ for (int edge = 0; edge < 3 && !out.empty(); edge++) {
44
+ std::vector<V> input = out;
45
+ out.clear();
46
+ for (size_t i = 0; i < input.size(); i++) {
47
+ const V &current = input[i];
48
+ const V &previous = input[(i + input.size() - 1) % input.size()];
49
+ float currentSide = side(triangle, edge, current.x, current.y) * orientation;
50
+ float previousSide = side(triangle, edge, previous.x, previous.y) * orientation;
51
+ bool currentInside = currentSide >= -0.0001f;
52
+ bool previousInside = previousSide >= -0.0001f;
53
+ if (currentInside) {
54
+ if (!previousInside) {
55
+ float t = previousSide / (previousSide - currentSide);
56
+ out.push_back(mix(previous, current, t));
57
+ }
58
+ out.push_back(current);
59
+ } else if (previousInside) {
60
+ float t = previousSide / (previousSide - currentSide);
61
+ out.push_back(mix(previous, current, t));
62
+ }
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+
68
+ template <typename V>
69
+ void appendFan(const std::vector<V> &polygon, std::vector<V> *out) {
70
+ for (size_t i = 1; i + 1 < polygon.size(); i++) {
71
+ out->push_back(polygon[0]);
72
+ out->push_back(polygon[i]);
73
+ out->push_back(polygon[i + 1]);
74
+ }
75
+ }
76
+
77
+ const ClipPathGeometry *pathAt(const DisplayList &list, int index) {
78
+ if (index < 0 || (size_t)index >= list.clip_paths.size()) return nullptr;
79
+ return &list.clip_paths[(size_t)index];
80
+ }
81
+
82
+ template <typename V, typename Mix>
83
+ uint32_t appendClipped(std::vector<V> &out, const std::vector<V> &quad, const PaintClip &clip,
84
+ const DisplayList &list, Mix mix) {
85
+ if (clip.path_count <= 0) {
86
+ appendFan(quad, &out);
87
+ return 6;
88
+ }
89
+ const ClipPathGeometry *first = pathAt(list, clip.paths[0]);
90
+ if (first == nullptr || first->triangles.empty()) return 0;
91
+ uint32_t before = (uint32_t)out.size();
92
+ if (clip.path_count == 1) {
93
+ for (const ClipTriangle &triangle : first->triangles) {
94
+ std::vector<V> clipped = clipToTriangle(quad, triangle, mix);
95
+ if (clipped.size() >= 3) appendFan(clipped, &out);
96
+ }
97
+ } else {
98
+ const ClipPathGeometry *second = pathAt(list, clip.paths[1]);
99
+ if (second == nullptr || second->triangles.empty()) return 0;
100
+ for (const ClipTriangle &outer : first->triangles) {
101
+ std::vector<V> firstClip = clipToTriangle(quad, outer, mix);
102
+ if (firstClip.size() < 3) continue;
103
+ for (const ClipTriangle &inner : second->triangles) {
104
+ std::vector<V> secondClip = clipToTriangle(firstClip, inner, mix);
105
+ if (secondClip.size() >= 3) appendFan(secondClip, &out);
106
+ }
107
+ }
108
+ }
109
+ return (uint32_t)out.size() - before;
110
+ }
111
+
112
+ Vertex mixVertex(const Vertex &a, const Vertex &b, float t) {
113
+ Vertex out;
114
+ out.x = a.x + (b.x - a.x) * t;
115
+ out.y = a.y + (b.y - a.y) * t;
116
+ out.lx = a.lx + (b.lx - a.lx) * t;
117
+ out.ly = a.ly + (b.ly - a.ly) * t;
118
+ out.hx = a.hx + (b.hx - a.hx) * t;
119
+ out.hy = a.hy + (b.hy - a.hy) * t;
120
+ out.radius = a.radius + (b.radius - a.radius) * t;
121
+ out.r = a.r + (b.r - a.r) * t;
122
+ out.g = a.g + (b.g - a.g) * t;
123
+ out.b = a.b + (b.b - a.b) * t;
124
+ out.a = a.a + (b.a - a.a) * t;
125
+ return out;
126
+ }
127
+
128
+ TextVertex mixTextVertex(const TextVertex &a, const TextVertex &b, float t) {
129
+ TextVertex out;
130
+ out.x = a.x + (b.x - a.x) * t;
131
+ out.y = a.y + (b.y - a.y) * t;
132
+ out.u = a.u + (b.u - a.u) * t;
133
+ out.v = a.v + (b.v - a.v) * t;
134
+ out.r = a.r + (b.r - a.r) * t;
135
+ out.g = a.g + (b.g - a.g) * t;
136
+ out.b = a.b + (b.b - a.b) * t;
137
+ out.a = a.a + (b.a - a.a) * t;
138
+ return out;
139
+ }
140
+
141
+ } // namespace
142
+
143
+ uint32_t pushShape(std::vector<Vertex> &verts, const PaintRect &rect, const PaintClip &clip,
144
+ const DisplayList &list) {
145
+ float hw = rect.width * 0.5f;
146
+ float hh = rect.height * 0.5f;
147
+ float cx = rect.x + hw;
148
+ float cy = rect.y + hh;
149
+ float radius = std::min(rect.radius, std::min(hw, hh));
150
+ const float local_x[4] = {-hw, hw, hw, -hw};
151
+ const float local_y[4] = {-hh, -hh, hh, hh};
152
+ std::vector<Vertex> quad(4);
153
+ for (int i = 0; i < 4; i++) {
154
+ rect.transform.apply(cx + local_x[i], cy + local_y[i], &quad[i].x, &quad[i].y);
155
+ quad[i].lx = local_x[i];
156
+ quad[i].ly = local_y[i];
157
+ quad[i].hx = hw;
158
+ quad[i].hy = hh;
159
+ quad[i].radius = radius;
160
+ quad[i].r = rect.color.r;
161
+ quad[i].g = rect.color.g;
162
+ quad[i].b = rect.color.b;
163
+ quad[i].a = rect.color.a;
164
+ }
165
+ return appendClipped(verts, quad, clip, list, mixVertex);
166
+ }
167
+
168
+ uint32_t pushQuad(std::vector<TextVertex> &verts, const float corners_x[4],
169
+ const float corners_y[4], const float u[4], const float v[4],
170
+ const Color &color, const Matrix2D &transform, const PaintClip &clip,
171
+ const DisplayList &list) {
172
+ std::vector<TextVertex> quad(4);
173
+ for (int i = 0; i < 4; i++) {
174
+ transform.apply(corners_x[i], corners_y[i], &quad[i].x, &quad[i].y);
175
+ quad[i].u = u[i];
176
+ quad[i].v = v[i];
177
+ quad[i].r = color.r;
178
+ quad[i].g = color.g;
179
+ quad[i].b = color.b;
180
+ quad[i].a = color.a;
181
+ }
182
+ return appendClipped(verts, quad, clip, list, mixTextVertex);
183
+ }
184
+
185
+ uint32_t pushGlyph(std::vector<TextVertex> &verts, float x, float y, float width, float height,
186
+ const GlyphEntry &entry, const Color &color, const Matrix2D &transform,
187
+ const PaintClip &clip, const DisplayList &list) {
188
+ const float corners_x[4] = {x, x + width, x + width, x};
189
+ const float corners_y[4] = {y, y, y + height, y + height};
190
+ const float u[4] = {entry.u0, entry.u1, entry.u1, entry.u0};
191
+ const float v[4] = {entry.v0, entry.v0, entry.v1, entry.v1};
192
+ return pushQuad(verts, corners_x, corners_y, u, v, color, transform, clip, list);
193
+ }
194
+
195
+ } // namespace renderer_detail
196
+ } // namespace xtgui
@@ -13,6 +13,7 @@
13
13
  #include "image.h"
14
14
  #include "media.h"
15
15
  #include "svg.h"
16
+ #include "webgl.h"
16
17
 
17
18
  #include "renderer_shaders.h"
18
19
 
@@ -114,8 +115,12 @@ static SDL_GPUTexture *ensureMediaTexture(SDL_GPUDevice *device, uint64_t media_
114
115
  }
115
116
 
116
117
  /** Ensure the texture for `canvas_id` exists and holds the canvas's newest
117
- * pixels. Returns `nullptr` for an unknown or empty canvas. */
118
+ * pixels. A WebGL canvas already owns its colour target, so it is returned
119
+ * directly and nothing is copied through the CPU. */
118
120
  static SDL_GPUTexture *ensureCanvasTexture(SDL_GPUDevice *device, uint64_t canvas_id) {
121
+ if (xtgui::WebGLContext *webgl = xtgui::xt_webgl_by_id(canvas_id)) {
122
+ return webgl->color_texture();
123
+ }
119
124
  xtgui::Canvas2D *canvas = xtgui::xt_canvas_by_id(canvas_id);
120
125
  if (canvas == nullptr) return nullptr;
121
126
  const xtgui::Image &image = canvas->image();
@@ -315,14 +320,14 @@ void xt_gui_image_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
315
320
  if (scale <= 0.0f) scale = 1.0f;
316
321
  std::vector<TextVertex> verts;
317
322
  verts.reserve(list.images.size() * 6);
318
- xtgui::Color white{1.0f, 1.0f, 1.0f, 1.0f};
319
323
  GlyphEntry full;
320
324
  full.u0 = 0.0f;
321
325
  full.v0 = 0.0f;
322
326
  full.u1 = 1.0f;
323
327
  full.v1 = 1.0f;
324
- for (size_t index = 0; index < list.images.size(); index++) {
325
- const xtgui::PaintImage &image = list.images[index];
328
+ for (const xtgui::PaintOp &op : list.ops) {
329
+ if (op.kind != xtgui::PaintKind::Image || op.index >= list.images.size()) continue;
330
+ const xtgui::PaintImage &image = list.images[op.index];
326
331
  if (image.width <= 0.0f || image.height <= 0.0f) continue;
327
332
  /* Draw-time device pixels: an SVG (file or inline) is rasterised at this
328
333
  * size so it stays crisp on HiDPI and when scaled. */
@@ -341,10 +346,10 @@ void xt_gui_image_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
341
346
  texture = ensureImageTexture(device, image.src, pixel_width, pixel_height);
342
347
  }
343
348
  if (texture == nullptr) continue;
344
- pushGlyph(verts, image.x, image.y, image.width, image.height, full, white,
345
- image.transform);
346
- geometry->op_counts[index] = 6;
347
- geometry->op_textures[index] = texture;
349
+ uint32_t count = pushGlyph(verts, image.x, image.y, image.width, image.height, full,
350
+ image.tint, image.transform, op.clip, list);
351
+ geometry->op_counts[op.index] = count;
352
+ geometry->op_textures[op.index] = texture;
348
353
  }
349
354
  uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(TextVertex));
350
355
  }
@@ -79,14 +79,21 @@ extern bool g_atlas_full_logged;
79
79
 
80
80
  /* -- geometry helpers ----------------------------------------------------- */
81
81
 
82
- void pushRect(std::vector<Vertex> &verts, const xtgui::PaintRect &rect);
83
- void pushGlyph(std::vector<TextVertex> &verts, float x, float y, float width, float height,
84
- const GlyphEntry &entry, const xtgui::Color &color,
85
- const xtgui::Matrix2D &transform);
86
- /** Push a textured quad, applying a `transform` matrix to its four corners. */
87
- void pushQuad(std::vector<TextVertex> &verts, const float corners_x[4], const float corners_y[4],
88
- const float u[4], const float v[4], const xtgui::Color &color,
89
- const xtgui::Matrix2D &transform);
82
+ /** Push one rounded rectangle, clipped by the op's `clip-path` polygons (if
83
+ * any). Returns the number of vertices appended. */
84
+ uint32_t pushShape(std::vector<Vertex> &verts, const xtgui::PaintRect &rect,
85
+ const xtgui::PaintClip &clip, const xtgui::DisplayList &list);
86
+ /** Push one glyph quad, clipped by `clip-path`. */
87
+ uint32_t pushGlyph(std::vector<TextVertex> &verts, float x, float y, float width, float height,
88
+ const GlyphEntry &entry, const xtgui::Color &color,
89
+ const xtgui::Matrix2D &transform, const xtgui::PaintClip &clip,
90
+ const xtgui::DisplayList &list);
91
+ /** Push a textured quad, applying a `transform` matrix to its four corners and
92
+ * clipping it by `clip-path`. */
93
+ uint32_t pushQuad(std::vector<TextVertex> &verts, const float corners_x[4],
94
+ const float corners_y[4], const float u[4], const float v[4],
95
+ const xtgui::Color &color, const xtgui::Matrix2D &transform,
96
+ const xtgui::PaintClip &clip, const xtgui::DisplayList &list);
90
97
  void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *data,
91
98
  uint32_t count, uint32_t stride);
92
99
 
@@ -22,33 +22,6 @@ namespace renderer_detail {
22
22
  constexpr float kMinGlyphScale = 0.5f;
23
23
  constexpr float kMaxGlyphScale = 4.0f;
24
24
 
25
- void pushQuad(std::vector<TextVertex> &verts, const float corners_x[4], const float corners_y[4],
26
- const float u[4], const float v[4], const xtgui::Color &color,
27
- const xtgui::Matrix2D &transform) {
28
- TextVertex corners[4];
29
- for (int i = 0; i < 4; i++) {
30
- transform.apply(corners_x[i], corners_y[i], &corners[i].x, &corners[i].y);
31
- corners[i].u = u[i];
32
- corners[i].v = v[i];
33
- corners[i].r = color.r;
34
- corners[i].g = color.g;
35
- corners[i].b = color.b;
36
- corners[i].a = color.a;
37
- }
38
- static const int order[6] = {0, 1, 2, 0, 2, 3};
39
- for (int i = 0; i < 6; i++) verts.push_back(corners[order[i]]);
40
- }
41
-
42
- void pushGlyph(std::vector<TextVertex> &verts, float x, float y, float width, float height,
43
- const GlyphEntry &entry, const xtgui::Color &color,
44
- const xtgui::Matrix2D &transform) {
45
- const float corners_x[4] = {x, x + width, x + width, x};
46
- const float corners_y[4] = {y, y, y + height, y + height};
47
- const float u[4] = {entry.u0, entry.u1, entry.u1, entry.u0};
48
- const float v[4] = {entry.v0, entry.v0, entry.v1, entry.v1};
49
- pushQuad(verts, corners_x, corners_y, u, v, color, transform);
50
- }
51
-
52
25
  bool ensureAtlasTexture(SDL_GPUDevice *device) {
53
26
  if (g_atlas_texture != nullptr) return true;
54
27
  SDL_GPUTextureCreateInfo info;
@@ -307,8 +280,9 @@ void xt_gui_text_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
307
280
 
308
281
  std::vector<TextVertex> verts;
309
282
  geometry->op_counts.assign(list.texts.size(), 0);
310
- for (size_t index = 0; index < list.texts.size(); index++) {
311
- const xtgui::PaintText &run = list.texts[index];
283
+ for (const xtgui::PaintOp &op : list.ops) {
284
+ if (op.kind != xtgui::PaintKind::Text || op.index >= list.texts.size()) continue;
285
+ const xtgui::PaintText &run = list.texts[op.index];
312
286
  if (run.text.empty() || run.color.a <= 0.0f) continue;
313
287
  xtgui::Font *logical = xtgui::xt_text_resolve(run.font);
314
288
  if (logical == nullptr) continue;
@@ -341,12 +315,13 @@ void xt_gui_text_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
341
315
  float quad_y = run.baseline + glyph.y_offset - (float)entry.top / glyph_scale;
342
316
  float quad_w = (float)entry.width / glyph_scale;
343
317
  float quad_h = (float)entry.height / glyph_scale;
344
- pushGlyph(verts, quad_x, quad_y, quad_w, quad_h, entry, run.color, run.transform);
318
+ pushGlyph(verts, quad_x, quad_y, quad_w, quad_h, entry, run.color, run.transform,
319
+ op.clip, list);
345
320
  }
346
321
  }
347
322
  pen_x += glyph.x_advance;
348
323
  }
349
- geometry->op_counts[index] = (uint32_t)verts.size() - before;
324
+ geometry->op_counts[op.index] = (uint32_t)verts.size() - before;
350
325
  }
351
326
  uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(TextVertex));
352
327
  flushAtlas(device);