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.
- package/README.md +16 -10
- package/dist/src/binder/references.js +14 -1
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.d.ts +1 -0
- package/dist/src/codegen/generator/module.js +54 -0
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +6 -4
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/css.d.ts +26 -0
- package/dist/src/extensions/gui/css.js +100 -0
- package/dist/src/extensions/gui/css.js.map +1 -0
- package/dist/src/extensions/gui/html.js +9 -2
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +16 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +16 -0
- package/dist/src/extensions/gui/three.js +22 -0
- package/dist/src/extensions/gui/three.js.map +1 -0
- package/dist/src/extensions/media/index.d.ts +6 -5
- package/dist/src/extensions/media/index.js +12 -14
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/tests/e2e/compile-builtins.test.js +24 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +23 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-browser.test.js +1 -1
- package/dist/tests/e2e/gui-browser.test.js.map +1 -1
- package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
- package/dist/tests/e2e/gui-effects.test.js +262 -0
- package/dist/tests/e2e/gui-effects.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
- package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
- package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.js +48 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +5 -4
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
- package/dist/tests/e2e/gui-webgl.test.js +179 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2.test.js +238 -0
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +41 -0
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +7 -3
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/doc/ai/extensions.md +29 -9
- package/doc/ai/troubleshooting.md +12 -8
- package/doc/ai/zh-CN/extensions.md +26 -8
- package/doc/ai/zh-CN/troubleshooting.md +10 -6
- package/doc/gui/api.md +3 -2
- package/doc/gui/build.md +72 -16
- package/doc/gui/canvas.md +11 -3
- package/doc/gui/dom.md +33 -18
- package/doc/gui/known-issues.md +57 -24
- package/doc/gui/layout.md +18 -0
- package/doc/gui/media.md +17 -13
- package/doc/gui/rendering.md +50 -3
- package/doc/gui/webgl.md +256 -0
- package/doc/gui.md +108 -17
- package/doc/npm-package.md +6 -4
- package/doc/requirements.md +18 -9
- package/doc/zh-CN/gui/api.md +3 -2
- package/doc/zh-CN/gui/build.md +64 -15
- package/doc/zh-CN/gui/canvas.md +9 -2
- package/doc/zh-CN/gui/dom.md +20 -7
- package/doc/zh-CN/gui/known-issues.md +45 -19
- package/doc/zh-CN/gui/layout.md +14 -0
- package/doc/zh-CN/gui/media.md +15 -11
- package/doc/zh-CN/gui/rendering.md +41 -4
- package/doc/zh-CN/gui/webgl.md +115 -0
- package/doc/zh-CN/gui.md +89 -14
- package/doc/zh-CN/npm-package.md +9 -6
- package/doc/zh-CN/requirements.md +12 -6
- package/llms.txt +2 -0
- package/package.json +1 -1
- package/runtime/ext_gui/browser.cpp +39 -13
- package/runtime/ext_gui/canvas.cpp +3 -18
- package/runtime/ext_gui/canvas_internal.h +10 -0
- package/runtime/ext_gui/canvas_raster.cpp +60 -0
- package/runtime/ext_gui/clip_values.cpp +246 -0
- package/runtime/ext_gui/css.cpp +94 -0
- package/runtime/ext_gui/css.h +22 -1
- package/runtime/ext_gui/css_match.cpp +3 -0
- package/runtime/ext_gui/css_selector.cpp +9 -0
- package/runtime/ext_gui/css_sheet.cpp +89 -45
- package/runtime/ext_gui/document.cpp +4 -1
- package/runtime/ext_gui/document.h +2 -0
- package/runtime/ext_gui/dom.h +16 -0
- package/runtime/ext_gui/dom_api.cpp +1 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
- package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
- package/runtime/ext_gui/dom_api_internal.h +259 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
- package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
- package/runtime/ext_gui/effect_values.cpp +312 -0
- package/runtime/ext_gui/gradient_values.cpp +476 -0
- package/runtime/ext_gui/grid_values.cpp +230 -0
- package/runtime/ext_gui/gui_canvas.cpp +50 -2
- package/runtime/ext_gui/gui_engine.h +27 -0
- package/runtime/ext_gui/gui_events.cpp +4 -1
- package/runtime/ext_gui/gui_media.cpp +1 -1
- package/runtime/ext_gui/gui_webgl.cpp +83 -0
- package/runtime/ext_gui/layout.cpp +21 -0
- package/runtime/ext_gui/layout_flow.cpp +81 -4
- package/runtime/ext_gui/layout_flow_internal.h +31 -0
- package/runtime/ext_gui/layout_grid.cpp +374 -0
- package/runtime/ext_gui/media.h +1 -1
- package/runtime/ext_gui/media_api.h +2 -2
- package/runtime/ext_gui/media_query.cpp +211 -0
- package/runtime/ext_gui/paint.cpp +111 -77
- package/runtime/ext_gui/paint.h +33 -3
- package/runtime/ext_gui/paint_background.cpp +229 -0
- package/runtime/ext_gui/paint_clip.cpp +268 -0
- package/runtime/ext_gui/paint_effects.cpp +324 -0
- package/runtime/ext_gui/paint_internal.h +85 -0
- package/runtime/ext_gui/renderer.cpp +8 -31
- package/runtime/ext_gui/renderer_clip.cpp +196 -0
- package/runtime/ext_gui/renderer_image.cpp +13 -8
- package/runtime/ext_gui/renderer_internal.h +15 -8
- package/runtime/ext_gui/renderer_text.cpp +6 -31
- package/runtime/ext_gui/style.cpp +343 -20
- package/runtime/ext_gui/style.h +144 -3
- package/runtime/ext_gui/style_print.cpp +134 -1
- package/runtime/ext_gui/style_values.cpp +152 -126
- package/runtime/ext_gui/style_values_internal.h +35 -0
- package/runtime/ext_gui/webgl.h +466 -0
- package/runtime/ext_gui/webgl2_constants.h +274 -0
- package/runtime/ext_gui/webgl_buffer.cpp +565 -0
- package/runtime/ext_gui/webgl_constants.h +317 -0
- package/runtime/ext_gui/webgl_context.cpp +466 -0
- package/runtime/ext_gui/webgl_draw.cpp +495 -0
- package/runtime/ext_gui/webgl_glsl.h +125 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
- package/runtime/ext_gui/webgl_msl.cpp +62 -0
- package/runtime/ext_gui/webgl_msl.h +33 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
- package/runtime/ext_gui/webgl_program_internal.h +18 -0
- package/runtime/ext_gui/webgl_shader.cpp +582 -0
- package/runtime/ext_gui/webgl_texture.cpp +293 -0
- package/runtime/ext_gui/webgl_uniform.cpp +167 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +9 -3
- package/runtime/rt_internal.h +1 -0
- package/runtime/xt_containers/access.inc +8 -0
- package/runtime/xt_regex/api.inc +2 -0
- package/runtime/xt_regex/matcher.inc +16 -3
- package/runtime/xt_regex/parser.inc +8 -2
- package/runtime/xt_regex/types.inc +3 -0
- package/runtime/xt_stdlib2/regexp-match.inc +60 -21
- package/runtime/xt_stdlib2/regexp.inc +1 -0
- package/runtime/xt_typed_array.c +1 -1
- package/scripts/build-gui.ts +90 -3
- package/scripts/build-media.ts +323 -58
- package/scripts/setup-vs-toolchain.ps1 +152 -0
- package/src/binder/references.ts +13 -1
- package/src/codegen/generator/module.ts +50 -0
- package/src/codegen/generator/statements/variables.ts +6 -3
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/css.ts +113 -0
- package/src/extensions/gui/html.ts +9 -2
- package/src/extensions/gui/index.ts +16 -2
- package/src/extensions/gui/three.ts +25 -0
- 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(),
|
|
281
|
-
|
|
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 ¤t = 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.
|
|
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 (
|
|
325
|
-
|
|
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,
|
|
345
|
-
|
|
346
|
-
geometry->op_counts[index] =
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
/** Push
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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 (
|
|
311
|
-
|
|
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);
|