xbintsc 0.5.45 → 0.5.52
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/AGENTS.md +1 -1
- package/README.md +5 -4
- package/README.zh-CN.md +4 -3
- package/dist/src/cli/extensions.d.ts +24 -0
- package/dist/src/cli/extensions.js +62 -0
- package/dist/src/cli/extensions.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/help.js +3 -1
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hints.js +8 -3
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +21 -28
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +2 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/driver/build-key.d.ts +2 -0
- package/dist/src/driver/build-key.js +1 -0
- package/dist/src/driver/build-key.js.map +1 -1
- package/dist/src/driver/compiler.js +61 -8
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +4 -0
- package/dist/src/driver/config.js +2 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/link-features.d.ts +37 -0
- package/dist/src/driver/link-features.js +123 -0
- package/dist/src/driver/link-features.js.map +1 -0
- package/dist/src/driver/options.d.ts +10 -0
- package/dist/src/driver/runtime-objects.d.ts +5 -0
- package/dist/src/driver/runtime-objects.js +20 -1
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/usage.d.ts +23 -0
- package/dist/src/driver/usage.js +353 -0
- package/dist/src/driver/usage.js.map +1 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/catalog.js +1 -2
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/features.d.ts +34 -0
- package/dist/src/extensions/gui/features.js +165 -0
- package/dist/src/extensions/gui/features.js.map +1 -0
- package/dist/src/extensions/gui/index.js +10 -4
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/link-feature.d.ts +70 -0
- package/dist/src/extensions/link-feature.js +18 -0
- package/dist/src/extensions/link-feature.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +24 -4
- package/dist/src/extensions/registry.js +26 -3
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tests/cli/hints.test.js +5 -7
- package/dist/tests/cli/hints.test.js.map +1 -1
- package/dist/tests/driver/link-features.test.js +105 -0
- package/dist/tests/driver/link-features.test.js.map +1 -0
- package/dist/tests/driver/usage.test.d.ts +1 -0
- package/dist/tests/driver/usage.test.js +88 -0
- package/dist/tests/driver/usage.test.js.map +1 -0
- package/dist/tests/e2e/gui-audio.test.js +4 -4
- package/dist/tests/e2e/gui-audio.test.js.map +1 -1
- package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
- package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
- package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
- package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
- package/dist/tests/e2e/gui-css-features.test.js +270 -0
- package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.js +92 -11
- package/dist/tests/e2e/gui-effects.test.js.map +1 -1
- package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
- package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
- package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
- package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
- package/dist/tests/e2e/gui-font-face.test.js +142 -0
- package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
- package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
- package/dist/tests/e2e/gui-fonts.test.js +150 -0
- package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +10 -1
- package/dist/tests/e2e/gui-helpers.js +6 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +7 -3
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
- package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media.test.js +9 -9
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-paint.test.js +5 -2
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
- package/dist/tests/e2e/gui-shaping.test.js +47 -0
- package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
- package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
- package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
- package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.js +3 -2
- package/dist/tests/e2e/gui-transform.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
- package/dist/tests/extensions/gui-features.test.d.ts +1 -0
- package/dist/tests/extensions/gui-features.test.js +175 -0
- package/dist/tests/extensions/gui-features.test.js.map +1 -0
- package/doc/ai/cli.md +5 -1
- package/doc/ai/extensions.md +56 -26
- package/doc/ai/troubleshooting.md +10 -7
- package/doc/ai/zh-CN/cli.md +5 -1
- package/doc/ai/zh-CN/extensions.md +48 -22
- package/doc/ai/zh-CN/troubleshooting.md +6 -5
- package/doc/gui/animation.md +39 -9
- package/doc/gui/api.md +2 -1
- package/doc/gui/build.md +137 -19
- package/doc/gui/canvas.md +1 -1
- package/doc/gui/dom.md +20 -4
- package/doc/gui/known-issues.md +63 -26
- package/doc/gui/layout.md +31 -8
- package/doc/gui/media.md +13 -7
- package/doc/gui/rendering.md +114 -39
- package/doc/gui/runtime.md +5 -0
- package/doc/gui/webgl.md +24 -6
- package/doc/gui.md +110 -47
- package/doc/implemented/cli.md +2 -0
- package/doc/implemented/extensions.md +9 -3
- package/doc/npm-package.md +4 -4
- package/doc/xbintsc.config.schema.json +10 -0
- package/doc/zh-CN/gui/animation.md +33 -10
- package/doc/zh-CN/gui/api.md +2 -1
- package/doc/zh-CN/gui/build.md +110 -16
- package/doc/zh-CN/gui/canvas.md +1 -1
- package/doc/zh-CN/gui/dom.md +16 -3
- package/doc/zh-CN/gui/known-issues.md +45 -15
- package/doc/zh-CN/gui/layout.md +23 -6
- package/doc/zh-CN/gui/media.md +11 -6
- package/doc/zh-CN/gui/rendering.md +84 -26
- package/doc/zh-CN/gui/runtime.md +3 -0
- package/doc/zh-CN/gui/webgl.md +3 -3
- package/doc/zh-CN/gui.md +92 -41
- package/doc/zh-CN/implemented/cli.md +2 -0
- package/doc/zh-CN/implemented/extensions.md +9 -3
- package/doc/zh-CN/npm-package.md +4 -3
- package/package.json +7 -7
- package/runtime/ext_gui/animation_values.cpp +425 -0
- package/runtime/ext_gui/animation_values.h +64 -0
- package/runtime/ext_gui/browser.cpp +22 -15
- package/runtime/ext_gui/browser_loop.cpp +13 -1
- package/runtime/ext_gui/canvas.h +1 -1
- package/runtime/ext_gui/canvas_raster.cpp +1 -1
- package/runtime/ext_gui/canvas_text.cpp +1 -1
- package/runtime/ext_gui/css.cpp +172 -21
- package/runtime/ext_gui/css.h +75 -4
- package/runtime/ext_gui/css_match.cpp +4 -0
- package/runtime/ext_gui/css_sheet.cpp +218 -2
- package/runtime/ext_gui/document.cpp +42 -192
- package/runtime/ext_gui/document.h +25 -12
- package/runtime/ext_gui/document_animation.cpp +428 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
- package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
- package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
- package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
- package/runtime/ext_gui/dom_api_style.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
- package/runtime/ext_gui/effect_values.cpp +245 -21
- package/runtime/ext_gui/gpu_bridge.c +28 -0
- package/runtime/ext_gui/gpu_feature.cpp +30 -0
- package/runtime/ext_gui/gpu_shader.cpp +22 -0
- package/runtime/ext_gui/gpu_shader_api.h +50 -0
- package/runtime/ext_gui/gradient_values.cpp +24 -0
- package/runtime/ext_gui/grid_values.cpp +23 -0
- package/runtime/ext_gui/gui.cpp +6 -37
- package/runtime/ext_gui/gui_canvas.cpp +14 -6
- package/runtime/ext_gui/gui_cursor.cpp +50 -0
- package/runtime/ext_gui/gui_engine.h +1 -18
- package/runtime/ext_gui/gui_events.cpp +19 -6
- package/runtime/ext_gui/gui_internal.h +3 -0
- package/runtime/ext_gui/gui_webgl.cpp +25 -10
- package/runtime/ext_gui/image_api.cpp +18 -0
- package/runtime/ext_gui/image_api.h +43 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
- package/runtime/ext_gui/image_bridge.c +22 -0
- package/runtime/ext_gui/image_feature.cpp +107 -0
- package/runtime/ext_gui/inline_svg.cpp +95 -8
- package/runtime/ext_gui/inline_svg.h +5 -1
- package/runtime/ext_gui/layout.cpp +15 -9
- package/runtime/ext_gui/layout.h +8 -2
- package/runtime/ext_gui/layout_flex.cpp +134 -29
- package/runtime/ext_gui/layout_flow.cpp +58 -7
- package/runtime/ext_gui/layout_flow_internal.h +39 -4
- package/runtime/ext_gui/layout_grid.cpp +31 -0
- package/runtime/ext_gui/layout_inline.cpp +26 -2
- package/runtime/ext_gui/layout_vertical.cpp +196 -0
- package/runtime/ext_gui/media.cpp +4 -2
- package/runtime/ext_gui/media.h +3 -3
- package/runtime/ext_gui/media_api.h +7 -6
- package/runtime/ext_gui/paint.cpp +67 -9
- package/runtime/ext_gui/paint.h +61 -8
- package/runtime/ext_gui/paint_backdrop.cpp +211 -0
- package/runtime/ext_gui/paint_background.cpp +175 -97
- package/runtime/ext_gui/paint_effects.cpp +12 -6
- package/runtime/ext_gui/paint_internal.h +27 -0
- package/runtime/ext_gui/paint_outline.cpp +44 -0
- package/runtime/ext_gui/paint_shadow.cpp +368 -0
- package/runtime/ext_gui/renderer.cpp +15 -7
- package/runtime/ext_gui/renderer.h +11 -2
- package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
- package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
- package/runtime/ext_gui/renderer_gradient.cpp +51 -17
- package/runtime/ext_gui/renderer_image.cpp +19 -7
- package/runtime/ext_gui/renderer_internal.h +21 -0
- package/runtime/ext_gui/renderer_layer.cpp +37 -6
- package/runtime/ext_gui/renderer_text.cpp +2 -1
- package/runtime/ext_gui/stb_truetype.h +5077 -0
- package/runtime/ext_gui/style.cpp +62 -8
- package/runtime/ext_gui/style.h +111 -4
- package/runtime/ext_gui/style_cascade.cpp +83 -0
- package/runtime/ext_gui/style_internal.h +13 -1
- package/runtime/ext_gui/style_length.cpp +92 -0
- package/runtime/ext_gui/style_print.cpp +83 -2
- package/runtime/ext_gui/style_svg.cpp +40 -0
- package/runtime/ext_gui/style_text.cpp +302 -0
- package/runtime/ext_gui/style_ui.cpp +150 -0
- package/runtime/ext_gui/style_values.cpp +76 -62
- package/runtime/ext_gui/style_values_internal.h +23 -0
- package/runtime/ext_gui/text.cpp +27 -499
- package/runtime/ext_gui/text.h +18 -9
- package/runtime/ext_gui/text_api.h +45 -0
- package/runtime/ext_gui/text_bridge.c +23 -0
- package/runtime/ext_gui/text_cache.cpp +12 -3
- package/runtime/ext_gui/text_font_db.cpp +427 -0
- package/runtime/ext_gui/text_font_paths.cpp +250 -0
- package/runtime/ext_gui/text_font_paths.h +39 -0
- package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
- package/runtime/ext_gui/text_font_sfnt.h +44 -0
- package/runtime/ext_gui/text_fonts.cpp +348 -0
- package/runtime/ext_gui/text_fonts.h +78 -0
- package/runtime/ext_gui/text_fonts_internal.h +77 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
- package/runtime/ext_gui/text_hb.cpp +438 -0
- package/runtime/ext_gui/text_stb.cpp +369 -0
- package/runtime/ext_gui/transform.cpp +107 -9
- package/runtime/ext_gui/transform.h +5 -0
- package/runtime/ext_gui/webgl_api.cpp +19 -0
- package/runtime/ext_gui/webgl_api.h +53 -0
- package/runtime/ext_gui/webgl_bridge.c +25 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
- package/runtime/ext_gui/webgl_feature.cpp +82 -0
- package/runtime/ext_gui/webgl_feature.h +28 -0
- package/runtime/ext_gui/webgl_msl.cpp +41 -0
- package/runtime/ext_gui/webgl_msl.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +40 -32
- package/runtime/ext_gui/window.cpp +7 -7
- package/runtime/ext_media/decode_audio.cpp +1 -1
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +7 -7
- package/scripts/build-gui.ts +97 -98
- package/scripts/check-file-length.ts +1 -0
- package/scripts/gui-build-options.ts +122 -0
- package/src/cli/extensions.ts +72 -0
- package/src/cli/help.ts +3 -1
- package/src/cli/hints.ts +9 -3
- package/src/cli/main.ts +21 -27
- package/src/diagnostics/diagnostic.ts +2 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/compiler.ts +63 -8
- package/src/driver/config.ts +6 -0
- package/src/driver/link-features.ts +163 -0
- package/src/driver/options.ts +10 -0
- package/src/driver/runtime-objects.ts +26 -1
- package/src/driver/usage.ts +376 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/catalog.ts +1 -2
- package/src/extensions/gui/features.ts +166 -0
- package/src/extensions/gui/index.ts +10 -4
- package/src/extensions/link-feature.ts +72 -0
- package/src/extensions/registry.ts +45 -4
- package/src/index.ts +3 -2
- package/dist/src/extensions/media/index.d.ts +0 -28
- package/dist/src/extensions/media/index.js +0 -59
- package/dist/src/extensions/media/index.js.map +0 -1
- package/dist/tests/extensions/media.test.js +0 -63
- package/dist/tests/extensions/media.test.js.map +0 -1
- package/src/extensions/media/index.ts +0 -65
- /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — CSS `outline` painting.
|
|
3
|
+
*
|
|
4
|
+
* Outline is a focus ring: drawn outside the border box, unaffected by layout,
|
|
5
|
+
* with an optional offset. The engine has one radius, so the four edge
|
|
6
|
+
* rectangles are square; the ring still follows the box's `border-radius` only
|
|
7
|
+
* approximately (documented).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "paint_internal.h"
|
|
11
|
+
|
|
12
|
+
namespace xtgui {
|
|
13
|
+
namespace paint_detail {
|
|
14
|
+
|
|
15
|
+
void addOutline(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
16
|
+
const FilterChain &chain, const PaintClip &clip, float viewportWidth,
|
|
17
|
+
float viewportHeight) {
|
|
18
|
+
if (style.outline_style == BorderStyle::None || !style.has_outline_color) return;
|
|
19
|
+
float width = resolveLength(style.outline_width, box.width, style.font_size, viewportWidth,
|
|
20
|
+
viewportHeight);
|
|
21
|
+
if (width <= 0.0f) return;
|
|
22
|
+
float offset = resolveLength(style.outline_offset, box.width, style.font_size, viewportWidth,
|
|
23
|
+
viewportHeight);
|
|
24
|
+
float x = box.x - offset;
|
|
25
|
+
float y = box.y - offset;
|
|
26
|
+
float outer_width = box.width + offset * 2.0f;
|
|
27
|
+
float outer_height = box.height + offset * 2.0f;
|
|
28
|
+
if (outer_width <= 0.0f || outer_height <= 0.0f) return;
|
|
29
|
+
Color color = filterColor(chain, style.outline_color);
|
|
30
|
+
if (color.a <= 0.0f) return;
|
|
31
|
+
|
|
32
|
+
addRectFiltered(out, x, y, outer_width, width, 0.0f, color, clip, box.world, chain);
|
|
33
|
+
addRectFiltered(out, x, y + outer_height - width, outer_width, width, 0.0f, color, clip,
|
|
34
|
+
box.world, chain);
|
|
35
|
+
float side_height = outer_height - width * 2.0f;
|
|
36
|
+
if (side_height > 0.0f) {
|
|
37
|
+
addRectFiltered(out, x, y + width, width, side_height, 0.0f, color, clip, box.world, chain);
|
|
38
|
+
addRectFiltered(out, x + outer_width - width, y + width, width, side_height, 0.0f, color, clip,
|
|
39
|
+
box.world, chain);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
} // namespace paint_detail
|
|
44
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — CSS shadows with a real Gaussian blur.
|
|
3
|
+
*
|
|
4
|
+
* `box-shadow` and a blurred `text-shadow` are convolutions of a shape mask
|
|
5
|
+
* with a Gaussian kernel, which a stack of a few offset copies cannot express.
|
|
6
|
+
* The paint pass therefore rasterises the silhouette (a rounded rectangle, or
|
|
7
|
+
* the glyph coverage of a text run), applies a separable Gaussian on the CPU,
|
|
8
|
+
* and emits the result as one tinted image quad. The texture is cached by the
|
|
9
|
+
* shape/blur key, so a static document rasterises each shadow once and an
|
|
10
|
+
* animated colour only changes the quad's tint.
|
|
11
|
+
*
|
|
12
|
+
* CSS defines the blur radius as twice the standard deviation:
|
|
13
|
+
* `sigma = blur / 2` (https://drafts.fxtf.org/css-backgrounds/#shadow-blur).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include "paint_internal.h"
|
|
17
|
+
|
|
18
|
+
#include <algorithm>
|
|
19
|
+
#include <cmath>
|
|
20
|
+
#include <cstdio>
|
|
21
|
+
#include <deque>
|
|
22
|
+
#include <memory>
|
|
23
|
+
#include <string>
|
|
24
|
+
#include <unordered_map>
|
|
25
|
+
#include <vector>
|
|
26
|
+
|
|
27
|
+
#include "text.h"
|
|
28
|
+
|
|
29
|
+
namespace xtgui {
|
|
30
|
+
namespace paint_detail {
|
|
31
|
+
|
|
32
|
+
namespace {
|
|
33
|
+
|
|
34
|
+
constexpr float kTextShadowScale = 2.0f;
|
|
35
|
+
constexpr size_t kMaxCachedShadows = 48;
|
|
36
|
+
|
|
37
|
+
std::unordered_map<std::string, std::shared_ptr<const PaintBitmap>> g_shadow_cache;
|
|
38
|
+
std::deque<std::string> g_shadow_order;
|
|
39
|
+
|
|
40
|
+
std::shared_ptr<const PaintBitmap> cachedShadow(const std::string &key) {
|
|
41
|
+
auto found = g_shadow_cache.find(key);
|
|
42
|
+
if (found == g_shadow_cache.end()) return nullptr;
|
|
43
|
+
return found->second;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void rememberShadow(const std::string &key, std::shared_ptr<const PaintBitmap> bitmap) {
|
|
47
|
+
if (g_shadow_cache.size() >= kMaxCachedShadows && !g_shadow_order.empty()) {
|
|
48
|
+
g_shadow_cache.erase(g_shadow_order.front());
|
|
49
|
+
g_shadow_order.pop_front();
|
|
50
|
+
}
|
|
51
|
+
g_shadow_cache[key] = bitmap;
|
|
52
|
+
g_shadow_order.push_back(key);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
float clamp01(float value) { return value < 0.0f ? 0.0f : (value > 1.0f ? 1.0f : value); }
|
|
56
|
+
|
|
57
|
+
/** Separable Gaussian on the alpha channel of an RGBA mask. `sigma` is in
|
|
58
|
+
* bitmap pixels. The RGB channels stay white: the image shader multiplies them
|
|
59
|
+
* by the shadow colour and blends with the alpha. */
|
|
60
|
+
void blurAlpha(std::vector<unsigned char> &pixels, int width, int height, float sigma) {
|
|
61
|
+
if (sigma <= 0.05f || width <= 0 || height <= 0) return;
|
|
62
|
+
int radius = (int)std::ceil(sigma * 3.0f);
|
|
63
|
+
if (radius < 1) radius = 1;
|
|
64
|
+
if (radius > 512) radius = 512;
|
|
65
|
+
std::vector<float> kernel((size_t)radius * 2 + 1);
|
|
66
|
+
float total = 0.0f;
|
|
67
|
+
for (int i = -radius; i <= radius; i++) {
|
|
68
|
+
float weight = std::exp(-(float)(i * i) / (2.0f * sigma * sigma));
|
|
69
|
+
kernel[(size_t)(i + radius)] = weight;
|
|
70
|
+
total += weight;
|
|
71
|
+
}
|
|
72
|
+
for (float &weight : kernel) weight /= total;
|
|
73
|
+
|
|
74
|
+
const size_t count = (size_t)width * (size_t)height;
|
|
75
|
+
std::vector<float> source(count);
|
|
76
|
+
for (size_t i = 0; i < count; i++) source[i] = (float)pixels[i * 4 + 3] / 255.0f;
|
|
77
|
+
std::vector<float> horizontal(count);
|
|
78
|
+
|
|
79
|
+
for (int y = 0; y < height; y++) {
|
|
80
|
+
const size_t row = (size_t)y * (size_t)width;
|
|
81
|
+
for (int x = 0; x < width; x++) {
|
|
82
|
+
float sum = 0.0f;
|
|
83
|
+
for (int k = -radius; k <= radius; k++) {
|
|
84
|
+
int sample = x + k;
|
|
85
|
+
if (sample < 0) sample = 0;
|
|
86
|
+
if (sample >= width) sample = width - 1;
|
|
87
|
+
sum += source[row + (size_t)sample] * kernel[(size_t)(k + radius)];
|
|
88
|
+
}
|
|
89
|
+
horizontal[row + (size_t)x] = sum;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
std::vector<float> vertical(count);
|
|
93
|
+
for (int y = 0; y < height; y++) {
|
|
94
|
+
for (int x = 0; x < width; x++) {
|
|
95
|
+
float sum = 0.0f;
|
|
96
|
+
for (int k = -radius; k <= radius; k++) {
|
|
97
|
+
int sample = y + k;
|
|
98
|
+
if (sample < 0) sample = 0;
|
|
99
|
+
if (sample >= height) sample = height - 1;
|
|
100
|
+
sum += horizontal[(size_t)sample * (size_t)width + (size_t)x] *
|
|
101
|
+
kernel[(size_t)(k + radius)];
|
|
102
|
+
}
|
|
103
|
+
vertical[(size_t)y * (size_t)width + (size_t)x] = sum;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (size_t i = 0; i < count; i++) {
|
|
107
|
+
float value = vertical[i];
|
|
108
|
+
value = clamp01(value);
|
|
109
|
+
pixels[i * 4 + 3] = (unsigned char)(value * 255.0f + 0.5f);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Signed distance to a rounded rectangle; negative inside. */
|
|
114
|
+
float roundedRectDistance(float px, float py, float x, float y, float width, float height,
|
|
115
|
+
float radius) {
|
|
116
|
+
float half_w = width * 0.5f;
|
|
117
|
+
float half_h = height * 0.5f;
|
|
118
|
+
float cx = x + half_w;
|
|
119
|
+
float cy = y + half_h;
|
|
120
|
+
if (radius > half_w) radius = half_w;
|
|
121
|
+
if (radius > half_h) radius = half_h;
|
|
122
|
+
float qx = std::fabs(px - cx) - (half_w - radius);
|
|
123
|
+
float qy = std::fabs(py - cy) - (half_h - radius);
|
|
124
|
+
float outside_x = qx > 0.0f ? qx : 0.0f;
|
|
125
|
+
float outside_y = qy > 0.0f ? qy : 0.0f;
|
|
126
|
+
float inside = std::min(std::max(qx, qy), 0.0f);
|
|
127
|
+
return inside + std::sqrt(outside_x * outside_x + outside_y * outside_y) - radius;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
void fillRoundedMask(std::vector<unsigned char> &pixels, int width, int height, float x, float y,
|
|
131
|
+
float box_width, float box_height, float radius, bool invert) {
|
|
132
|
+
pixels.assign((size_t)width * (size_t)height * 4u, 0);
|
|
133
|
+
for (int py = 0; py < height; py++) {
|
|
134
|
+
for (int px = 0; px < width; px++) {
|
|
135
|
+
float distance =
|
|
136
|
+
roundedRectDistance((float)px + 0.5f, (float)py + 0.5f, x, y, box_width, box_height,
|
|
137
|
+
radius);
|
|
138
|
+
float coverage = clamp01(0.5f - distance);
|
|
139
|
+
if (invert) coverage = 1.0f - coverage;
|
|
140
|
+
unsigned char *texel = &pixels[((size_t)py * (size_t)width + (size_t)px) * 4u];
|
|
141
|
+
texel[0] = 255;
|
|
142
|
+
texel[1] = 255;
|
|
143
|
+
texel[2] = 255;
|
|
144
|
+
texel[3] = (unsigned char)(coverage * 255.0f + 0.5f);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
std::string floatKey(float value) {
|
|
150
|
+
char buffer[32];
|
|
151
|
+
std::snprintf(buffer, sizeof(buffer), "%.3f", (double)value);
|
|
152
|
+
return buffer;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
} // namespace
|
|
156
|
+
|
|
157
|
+
/** Append a bitmap-backed image op without running the filter chain again (the
|
|
158
|
+
* shadow colour already carries it). */
|
|
159
|
+
void addBitmapImage(DisplayList &out, std::shared_ptr<const PaintBitmap> bitmap, float x, float y,
|
|
160
|
+
const Color &color, const Matrix2D &transform, const PaintClip &clip) {
|
|
161
|
+
if (color.a <= 0.0f || bitmap == nullptr || bitmap->width <= 0 || bitmap->height <= 0) return;
|
|
162
|
+
PaintImage image;
|
|
163
|
+
image.x = x;
|
|
164
|
+
image.y = y;
|
|
165
|
+
image.width = (float)bitmap->width / bitmap->scale;
|
|
166
|
+
image.height = (float)bitmap->height / bitmap->scale;
|
|
167
|
+
image.transform = transform;
|
|
168
|
+
image.tint = color;
|
|
169
|
+
image.bitmap = std::move(bitmap);
|
|
170
|
+
out.images.push_back(std::move(image));
|
|
171
|
+
out.ops.push_back(PaintOp{PaintKind::Image, (uint32_t)(out.images.size() - 1), clip});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
std::shared_ptr<const PaintBitmap> textShadowMask(const std::string &text, const FontSpec &font,
|
|
175
|
+
float blur) {
|
|
176
|
+
if (text.empty() || blur <= 0.0f) return nullptr;
|
|
177
|
+
char key_buffer[160];
|
|
178
|
+
std::snprintf(key_buffer, sizeof(key_buffer), "ts:%.2f:%.0f:%d:%d:%.3f:", (double)blur,
|
|
179
|
+
(double)font.pixel_size, font.weight, font.italic ? 1 : 0,
|
|
180
|
+
(double)font.letter_spacing);
|
|
181
|
+
std::string key = key_buffer + font.family + "|" + text;
|
|
182
|
+
if (std::shared_ptr<const PaintBitmap> cached = cachedShadow(key)) return cached;
|
|
183
|
+
|
|
184
|
+
Font *logical = xt_text_resolve(font);
|
|
185
|
+
if (logical == nullptr) return nullptr;
|
|
186
|
+
const ShapedRun *shaped = xt_text_shape_cached(text, logical, font.letter_spacing);
|
|
187
|
+
if (shaped == nullptr || shaped->glyphs.empty()) return nullptr;
|
|
188
|
+
|
|
189
|
+
const float scale = kTextShadowScale;
|
|
190
|
+
struct RasterGlyph {
|
|
191
|
+
GlyphImage image;
|
|
192
|
+
float x = 0.0f;
|
|
193
|
+
float baseline_y = 0.0f;
|
|
194
|
+
};
|
|
195
|
+
std::vector<RasterGlyph> glyphs;
|
|
196
|
+
glyphs.reserve(shaped->glyphs.size());
|
|
197
|
+
float pen_x = 0.0f;
|
|
198
|
+
float min_x = 1e9f, min_y = 1e9f, max_x = -1e9f, max_y = -1e9f;
|
|
199
|
+
for (const ShapedGlyph &glyph : shaped->glyphs) {
|
|
200
|
+
if (glyph.glyph != 0) {
|
|
201
|
+
Font *face = glyph.font != nullptr ? glyph.font : logical;
|
|
202
|
+
Font *scaled = xt_text_scale(face, font.pixel_size * scale);
|
|
203
|
+
if (scaled == nullptr) scaled = face;
|
|
204
|
+
GlyphImage image;
|
|
205
|
+
if (xt_text_rasterize(scaled, glyph.glyph, image) && image.width > 0 &&
|
|
206
|
+
image.height > 0) {
|
|
207
|
+
RasterGlyph entry;
|
|
208
|
+
entry.image = std::move(image);
|
|
209
|
+
entry.x = (pen_x + glyph.x_offset) * scale + (float)entry.image.left;
|
|
210
|
+
entry.baseline_y = -(float)entry.image.top;
|
|
211
|
+
glyphs.push_back(std::move(entry));
|
|
212
|
+
const RasterGlyph &added = glyphs.back();
|
|
213
|
+
min_x = std::min(min_x, added.x / scale);
|
|
214
|
+
max_x = std::max(max_x, (added.x + (float)added.image.width) / scale);
|
|
215
|
+
min_y = std::min(min_y, added.baseline_y / scale);
|
|
216
|
+
max_y = std::max(max_y, (added.baseline_y + (float)added.image.height) / scale);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
pen_x += glyph.x_advance;
|
|
220
|
+
}
|
|
221
|
+
if (glyphs.empty() || min_x > max_x) return nullptr;
|
|
222
|
+
|
|
223
|
+
float sigma = blur * 0.5f;
|
|
224
|
+
float padding = std::ceil(sigma * 3.0f) + 2.0f;
|
|
225
|
+
int width = (int)std::ceil((max_x - min_x + padding * 2.0f) * scale);
|
|
226
|
+
int height = (int)std::ceil((max_y - min_y + padding * 2.0f) * scale);
|
|
227
|
+
if (width < 1) width = 1;
|
|
228
|
+
if (height < 1) height = 1;
|
|
229
|
+
if ((long long)width * height > 16 * 1024 * 1024) return nullptr;
|
|
230
|
+
|
|
231
|
+
auto bitmap = std::make_shared<PaintBitmap>();
|
|
232
|
+
bitmap->width = width;
|
|
233
|
+
bitmap->height = height;
|
|
234
|
+
bitmap->scale = scale;
|
|
235
|
+
bitmap->key = key;
|
|
236
|
+
bitmap->pixels.assign((size_t)width * (size_t)height * 4u, 0);
|
|
237
|
+
const float origin_x = min_x - padding;
|
|
238
|
+
const float origin_y = min_y - padding;
|
|
239
|
+
bitmap->origin_x = origin_x;
|
|
240
|
+
bitmap->origin_y = origin_y;
|
|
241
|
+
for (const RasterGlyph &glyph : glyphs) {
|
|
242
|
+
int offset_x = (int)std::lround((glyph.x / scale - origin_x) * scale);
|
|
243
|
+
int offset_y = (int)std::lround((glyph.baseline_y / scale - origin_y) * scale);
|
|
244
|
+
const GlyphImage &image = glyph.image;
|
|
245
|
+
for (int row = 0; row < image.height; row++) {
|
|
246
|
+
int y = offset_y + row;
|
|
247
|
+
if (y < 0 || y >= height) continue;
|
|
248
|
+
for (int column = 0; column < image.width; column++) {
|
|
249
|
+
int x = offset_x + column;
|
|
250
|
+
if (x < 0 || x >= width) continue;
|
|
251
|
+
unsigned char coverage = image.pixels[(size_t)row * (size_t)image.width + (size_t)column];
|
|
252
|
+
if (coverage == 0) continue;
|
|
253
|
+
unsigned char *texel = &bitmap->pixels[((size_t)y * (size_t)width + (size_t)x) * 4u];
|
|
254
|
+
texel[0] = 255;
|
|
255
|
+
texel[1] = 255;
|
|
256
|
+
texel[2] = 255;
|
|
257
|
+
texel[3] = std::max(texel[3], coverage);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
blurAlpha(bitmap->pixels, width, height, sigma * scale);
|
|
262
|
+
rememberShadow(key, bitmap);
|
|
263
|
+
return bitmap;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
void addBoxShadows(DisplayList &out, const LayoutBox &box, const XtStyle &style,
|
|
267
|
+
const FilterChain &chain, const PaintClip &clip, bool inset,
|
|
268
|
+
float viewportWidth, float viewportHeight) {
|
|
269
|
+
for (size_t index = style.box_shadow.size(); index-- > 0;) {
|
|
270
|
+
const BoxShadow &shadow = style.box_shadow[index];
|
|
271
|
+
if (shadow.inset != inset) continue;
|
|
272
|
+
float dx = resolveLength(shadow.dx, 0.0f, style.font_size, viewportWidth, viewportHeight);
|
|
273
|
+
float dy = resolveLength(shadow.dy, 0.0f, style.font_size, viewportWidth, viewportHeight);
|
|
274
|
+
float blur = resolveLength(shadow.blur, 0.0f, style.font_size, viewportWidth, viewportHeight);
|
|
275
|
+
float spread = resolveLength(shadow.spread, 0.0f, style.font_size, viewportWidth,
|
|
276
|
+
viewportHeight);
|
|
277
|
+
if (blur < 0.0f) blur = 0.0f;
|
|
278
|
+
Color color = shadow.has_color ? filterColor(chain, shadow.color) : filterColor(chain, style.color);
|
|
279
|
+
if (color.a <= 0.0f) continue;
|
|
280
|
+
|
|
281
|
+
if (!inset && blur <= 0.0f) {
|
|
282
|
+
/* No blur: the silhouette is the box itself, expanded by `spread` and
|
|
283
|
+
* moved by the offset. A rounded rectangle is exact here. */
|
|
284
|
+
float x = box.x + dx - spread;
|
|
285
|
+
float y = box.y + dy - spread;
|
|
286
|
+
float width = box.width + spread * 2.0f;
|
|
287
|
+
float height = box.height + spread * 2.0f;
|
|
288
|
+
float radius = box.border_radius + spread;
|
|
289
|
+
addRect(out, x, y, width, height, radius, color, clip, box.world);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const float scale = 1.0f;
|
|
294
|
+
const float padding = std::ceil(blur * 1.5f) + 2.0f;
|
|
295
|
+
const std::string key =
|
|
296
|
+
std::string("bs:") + (inset ? "i:" : "o:") + floatKey(box.width) + ":" +
|
|
297
|
+
floatKey(box.height) + ":" + floatKey(box.border_radius) + ":" + floatKey(blur) +
|
|
298
|
+
":" + floatKey(spread) + ":" + floatKey(box.border_left) + ":" +
|
|
299
|
+
floatKey(box.border_right) + ":" + floatKey(box.border_top) + ":" +
|
|
300
|
+
floatKey(box.border_bottom) + ":" + floatKey(dx) + ":" + floatKey(dy);
|
|
301
|
+
|
|
302
|
+
std::shared_ptr<const PaintBitmap> bitmap = cachedShadow(key);
|
|
303
|
+
if (bitmap == nullptr) {
|
|
304
|
+
auto generated = std::make_shared<PaintBitmap>();
|
|
305
|
+
generated->scale = scale;
|
|
306
|
+
generated->key = key;
|
|
307
|
+
if (!inset) {
|
|
308
|
+
float shadow_width = std::max(0.0f, box.width + spread * 2.0f);
|
|
309
|
+
float shadow_height = std::max(0.0f, box.height + spread * 2.0f);
|
|
310
|
+
float radius = std::max(0.0f, box.border_radius + spread);
|
|
311
|
+
generated->width = std::max(1, (int)std::ceil(shadow_width + padding * 2.0f));
|
|
312
|
+
generated->height = std::max(1, (int)std::ceil(shadow_height + padding * 2.0f));
|
|
313
|
+
if ((long long)generated->width * generated->height > 16 * 1024 * 1024) continue;
|
|
314
|
+
fillRoundedMask(generated->pixels, generated->width, generated->height, padding, padding,
|
|
315
|
+
shadow_width, shadow_height, radius, false);
|
|
316
|
+
blurAlpha(generated->pixels, generated->width, generated->height, blur * 0.5f);
|
|
317
|
+
} else {
|
|
318
|
+
/* Inset: the mask is the *outside* of the (spread-shrunk) border box,
|
|
319
|
+
* blurred and then cropped to the padding box. */
|
|
320
|
+
float padding_box_width =
|
|
321
|
+
std::max(0.0f, box.width - box.border_left - box.border_right);
|
|
322
|
+
float padding_box_height =
|
|
323
|
+
std::max(0.0f, box.height - box.border_top - box.border_bottom);
|
|
324
|
+
float shape_local_x = padding + spread - box.border_left + dx;
|
|
325
|
+
float shape_local_y = padding + spread - box.border_top + dy;
|
|
326
|
+
float shape_width = std::max(0.0f, box.width - spread * 2.0f);
|
|
327
|
+
float shape_height = std::max(0.0f, box.height - spread * 2.0f);
|
|
328
|
+
float radius = std::max(0.0f, box.border_radius - spread);
|
|
329
|
+
generated->width = std::max(1, (int)std::ceil(padding_box_width + padding * 2.0f));
|
|
330
|
+
generated->height = std::max(1, (int)std::ceil(padding_box_height + padding * 2.0f));
|
|
331
|
+
if ((long long)generated->width * generated->height > 16 * 1024 * 1024) continue;
|
|
332
|
+
fillRoundedMask(generated->pixels, generated->width, generated->height, shape_local_x,
|
|
333
|
+
shape_local_y, shape_width, shape_height, radius, true);
|
|
334
|
+
blurAlpha(generated->pixels, generated->width, generated->height, blur * 0.5f);
|
|
335
|
+
/* Crop to the padding box: an inner shadow never paints over the
|
|
336
|
+
* border. */
|
|
337
|
+
const float left = padding;
|
|
338
|
+
const float top = padding;
|
|
339
|
+
const float right = padding + padding_box_width;
|
|
340
|
+
const float bottom = padding + padding_box_height;
|
|
341
|
+
for (int py = 0; py < generated->height; py++) {
|
|
342
|
+
for (int px = 0; px < generated->width; px++) {
|
|
343
|
+
if ((float)px >= left && (float)px < right && (float)py >= top &&
|
|
344
|
+
(float)py < bottom)
|
|
345
|
+
continue;
|
|
346
|
+
generated->pixels[((size_t)py * (size_t)generated->width + (size_t)px) * 4u + 3] = 0;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
rememberShadow(key, generated);
|
|
351
|
+
bitmap = generated;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
float image_x = 0.0f;
|
|
355
|
+
float image_y = 0.0f;
|
|
356
|
+
if (!inset) {
|
|
357
|
+
image_x = box.x + dx - spread - padding;
|
|
358
|
+
image_y = box.y + dy - spread - padding;
|
|
359
|
+
} else {
|
|
360
|
+
image_x = box.x + box.border_left - padding;
|
|
361
|
+
image_y = box.y + box.border_top - padding;
|
|
362
|
+
}
|
|
363
|
+
addBitmapImage(out, bitmap, image_x, image_y, color, box.world, clip);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
} // namespace paint_detail
|
|
368
|
+
} // namespace xtgui
|
|
@@ -329,11 +329,17 @@ void xt_gui_build_runs(XtGuiGeometry *shapes, XtGuiGeometry *texts, XtGuiGeometr
|
|
|
329
329
|
uint32_t cursor[3] = {0, 0, 0};
|
|
330
330
|
for (const xtgui::PaintOp &op : list.ops) {
|
|
331
331
|
if (op.kind == xtgui::PaintKind::LayerBegin ||
|
|
332
|
-
op.kind == xtgui::PaintKind::LayerEnd
|
|
332
|
+
op.kind == xtgui::PaintKind::LayerEnd ||
|
|
333
|
+
op.kind == xtgui::PaintKind::Backdrop) {
|
|
333
334
|
XtGuiDrawRun marker;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
335
|
+
if (op.kind == xtgui::PaintKind::Backdrop) {
|
|
336
|
+
marker.pipeline = XtGuiDrawRun::Backdrop;
|
|
337
|
+
marker.backdrop = op.index;
|
|
338
|
+
} else {
|
|
339
|
+
marker.pipeline = op.kind == xtgui::PaintKind::LayerBegin ? XtGuiDrawRun::LayerBegin
|
|
340
|
+
: XtGuiDrawRun::LayerEnd;
|
|
341
|
+
marker.layer = op.kind == xtgui::PaintKind::LayerBegin ? op.index : 0;
|
|
342
|
+
}
|
|
337
343
|
shapes->runs.push_back(marker);
|
|
338
344
|
continue;
|
|
339
345
|
}
|
|
@@ -410,8 +416,7 @@ void drawRuns(SDL_GPURenderPass *pass, const std::vector<XtGuiDrawRun> &runs, si
|
|
|
410
416
|
};
|
|
411
417
|
for (size_t i = begin; i < end && i < runs.size(); i++) {
|
|
412
418
|
const XtGuiDrawRun &run = runs[i];
|
|
413
|
-
if (run.pipeline
|
|
414
|
-
continue;
|
|
419
|
+
if (run.pipeline >= XtGuiDrawRun::LayerBegin) continue;
|
|
415
420
|
if (run.count == 0) continue;
|
|
416
421
|
SDL_Rect scissor;
|
|
417
422
|
scissor.x = 0;
|
|
@@ -488,7 +493,10 @@ void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPUTexture *swapchain,
|
|
|
488
493
|
* compiled at run time on the SPIR-V/MSL backends. Everywhere else (or if
|
|
489
494
|
* that compilation failed) the ordinary single pass still paints the
|
|
490
495
|
* unblended content rather than dropping it. */
|
|
491
|
-
|
|
496
|
+
const bool needs_layers = !list.layers.empty();
|
|
497
|
+
const bool needs_backdrop = !list.backdrops.empty();
|
|
498
|
+
if ((needs_layers || needs_backdrop) && layerRendererReady(g_device) &&
|
|
499
|
+
(!needs_backdrop || backdropRendererReady(g_device))) {
|
|
492
500
|
if (drawLayeredScene(cmd, swapchain, clear_color, shapes, texts, images, list, viewport_width,
|
|
493
501
|
viewport_height, pixel_density))
|
|
494
502
|
return;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - a shape pipeline that draws every `PaintRect` as triangles, using a
|
|
6
6
|
* rounded-rectangle distance field for antialiased fills;
|
|
7
7
|
* - a text pipeline that draws glyphs as textured quads from a shared
|
|
8
|
-
* grayscale glyph atlas (
|
|
8
|
+
* grayscale glyph atlas (stb_truetype rasterises, this file packs/upload);
|
|
9
9
|
* - an image pipeline that draws `PaintImage` quads sampling per-file RGBA
|
|
10
10
|
* textures decoded by `image.*`.
|
|
11
11
|
*
|
|
@@ -35,7 +35,14 @@ struct DisplayList;
|
|
|
35
35
|
struct XtGuiDrawRun {
|
|
36
36
|
/** `LayerBegin`/`LayerEnd` are zero-count markers around a
|
|
37
37
|
* `mix-blend-mode` group; `layer` indexes `DisplayList::layers`. */
|
|
38
|
-
enum Pipeline {
|
|
38
|
+
enum Pipeline {
|
|
39
|
+
Shape = 0,
|
|
40
|
+
Text = 1,
|
|
41
|
+
Image = 2,
|
|
42
|
+
LayerBegin = 3,
|
|
43
|
+
LayerEnd = 4,
|
|
44
|
+
Backdrop = 5
|
|
45
|
+
};
|
|
39
46
|
int pipeline = Shape;
|
|
40
47
|
uint32_t first = 0;
|
|
41
48
|
uint32_t count = 0;
|
|
@@ -45,6 +52,8 @@ struct XtGuiDrawRun {
|
|
|
45
52
|
float clip_height = 0;
|
|
46
53
|
SDL_GPUTexture *texture = nullptr;
|
|
47
54
|
uint32_t layer = 0;
|
|
55
|
+
/** `Backdrop` runs: index into `DisplayList::backdrops`. */
|
|
56
|
+
uint32_t backdrop = 0;
|
|
48
57
|
};
|
|
49
58
|
|
|
50
59
|
/** Per-window GPU geometry (vertex buffer + draw range). */
|