xbintsc 0.5.32 → 0.5.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/README.zh-CN.md +10 -8
- package/dist/scripts/check-version.d.ts +27 -0
- package/dist/scripts/check-version.js +71 -0
- package/dist/scripts/check-version.js.map +1 -0
- package/dist/scripts/package-platform.d.ts +58 -0
- package/dist/scripts/package-platform.js +142 -0
- package/dist/scripts/package-platform.js.map +1 -0
- package/dist/scripts/verify-platform-package.d.ts +34 -0
- package/dist/scripts/verify-platform-package.js +161 -0
- package/dist/scripts/verify-platform-package.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/main.js +3 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +29 -4
- package/dist/src/driver/runtime-lib.js +68 -10
- package/dist/src/driver/runtime-lib.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/index.js +18 -5
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/media/index.js +4 -3
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/src/parser/context.d.ts +41 -0
- package/dist/src/parser/context.js +89 -4
- package/dist/src/parser/context.js.map +1 -1
- package/dist/src/parser/literals.js +6 -12
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/driver/platform-package.test.d.ts +1 -0
- package/dist/tests/driver/platform-package.test.js +49 -0
- package/dist/tests/driver/platform-package.test.js.map +1 -0
- package/dist/tests/driver/runtime-lib.test.js +51 -4
- package/dist/tests/driver/runtime-lib.test.js.map +1 -1
- package/dist/tests/e2e/gui-audio.test.d.ts +14 -0
- package/dist/tests/e2e/gui-audio.test.js +287 -0
- package/dist/tests/e2e/gui-audio.test.js.map +1 -0
- package/dist/tests/e2e/gui-browser.test.js +65 -0
- package/dist/tests/e2e/gui-browser.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-args.test.d.ts +6 -0
- package/dist/tests/e2e/gui-canvas-args.test.js +217 -0
- package/dist/tests/e2e/gui-canvas-args.test.js.map +1 -0
- package/dist/tests/e2e/gui-canvas.test.js.map +1 -1
- package/dist/tests/e2e/gui-dom.test.js +215 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -1
- package/dist/tests/e2e/gui-events.test.js +112 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -1
- package/dist/tests/e2e/gui-helpers.d.ts +7 -0
- package/dist/tests/e2e/gui-helpers.js +1 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +78 -0
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-style.test.js +55 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.js +258 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-3d.test.d.ts +4 -0
- package/dist/tests/e2e/gui-webgl2-3d.test.js +264 -0
- package/dist/tests/e2e/gui-webgl2-3d.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.js +262 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.d.ts +6 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.js +395 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.d.ts +4 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.js +105 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.js +112 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.js +45 -1
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -1
- package/dist/tests/extensions/gui-index.test.js +1 -0
- package/dist/tests/extensions/gui-index.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +1 -0
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +30 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/platform-tarball.test.d.ts +1 -0
- package/dist/tests/platform-tarball.test.js +111 -0
- package/dist/tests/platform-tarball.test.js.map +1 -0
- package/dist/tests/version.test.js +6 -0
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/contributing.md +11 -0
- package/doc/ai/extensions.md +7 -4
- package/doc/ai/troubleshooting.md +7 -5
- package/doc/ai/zh-CN/contributing.md +9 -0
- package/doc/ai/zh-CN/extensions.md +4 -2
- package/doc/ai/zh-CN/troubleshooting.md +5 -3
- package/doc/gui/api.md +99 -22
- package/doc/gui/build.md +11 -4
- package/doc/gui/canvas.md +49 -18
- package/doc/gui/dom.md +57 -7
- package/doc/gui/media.md +4 -0
- package/doc/gui/webgl.md +105 -46
- package/doc/gui.md +7 -3
- package/doc/npm-package.md +55 -27
- package/doc/requirements.md +6 -2
- package/doc/zh-CN/gui/api.md +84 -14
- package/doc/zh-CN/gui/build.md +7 -2
- package/doc/zh-CN/gui/canvas.md +44 -19
- package/doc/zh-CN/gui/dom.md +48 -4
- package/doc/zh-CN/gui/media.md +3 -0
- package/doc/zh-CN/gui/webgl.md +22 -16
- package/doc/zh-CN/gui.md +3 -2
- package/doc/zh-CN/npm-package.md +44 -23
- package/doc/zh-CN/requirements.md +4 -1
- package/package.json +17 -1
- package/runtime/ext_gui/audio.cpp +365 -153
- package/runtime/ext_gui/audio_buffer.cpp +166 -0
- package/runtime/ext_gui/audio_buffer.h +37 -0
- package/runtime/ext_gui/audio_decode.cpp +219 -0
- package/runtime/ext_gui/audio_decode.h +39 -0
- package/runtime/ext_gui/audio_device.cpp +87 -0
- package/runtime/ext_gui/audio_effects.cpp +163 -0
- package/runtime/ext_gui/audio_effects.h +25 -0
- package/runtime/ext_gui/audio_internal.h +30 -0
- package/runtime/ext_gui/audio_mixer.cpp +494 -0
- package/runtime/ext_gui/audio_mixer.h +238 -0
- package/runtime/ext_gui/audio_param.cpp +104 -0
- package/runtime/ext_gui/audio_param_object.cpp +155 -0
- package/runtime/ext_gui/browser.cpp +45 -50
- package/runtime/ext_gui/browser_abort.cpp +249 -0
- package/runtime/ext_gui/browser_dialogs.cpp +76 -0
- package/runtime/ext_gui/browser_media.cpp +176 -0
- package/runtime/ext_gui/browser_navigation.cpp +130 -0
- package/runtime/ext_gui/canvas.cpp +88 -30
- package/runtime/ext_gui/canvas.h +74 -9
- package/runtime/ext_gui/canvas_image_data.cpp +143 -0
- package/runtime/ext_gui/canvas_internal.h +8 -5
- package/runtime/ext_gui/canvas_pattern.cpp +90 -0
- package/runtime/ext_gui/canvas_raster.cpp +31 -9
- package/runtime/ext_gui/canvas_style.cpp +4 -2
- package/runtime/ext_gui/css_selector.cpp +21 -3
- package/runtime/ext_gui/dom.h +4 -0
- package/runtime/ext_gui/dom_api.cpp +1 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +120 -114
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +57 -2
- package/runtime/ext_gui/dom_api_canvas_image.cpp +239 -0
- package/runtime/ext_gui/dom_api_canvas_paths.cpp +179 -0
- package/runtime/ext_gui/dom_api_computed_style.cpp +124 -0
- package/runtime/ext_gui/dom_api_dataset.cpp +154 -0
- package/runtime/ext_gui/dom_api_document.cpp +58 -5
- package/runtime/ext_gui/dom_api_events.cpp +93 -17
- package/runtime/ext_gui/dom_api_internal.h +71 -2
- package/runtime/ext_gui/dom_api_mutation.cpp +159 -0
- package/runtime/ext_gui/dom_api_node.cpp +40 -19
- package/runtime/ext_gui/dom_api_node_read.cpp +37 -1
- package/runtime/ext_gui/dom_api_path2d.cpp +358 -0
- package/runtime/ext_gui/dom_api_proto.cpp +35 -0
- package/runtime/ext_gui/dom_api_style.cpp +223 -13
- package/runtime/ext_gui/dom_api_webgl.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +151 -36
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +3 -3
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +6 -2
- package/runtime/ext_gui/dom_api_webgl_compressed.cpp +167 -0
- package/runtime/ext_gui/dom_api_webgl_framebuffer.cpp +160 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +4 -4
- package/runtime/ext_gui/dom_api_webgl_source.cpp +161 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +169 -23
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +276 -236
- package/runtime/ext_gui/dom_api_webgl_ubo.cpp +81 -0
- package/runtime/ext_gui/gui.cpp +103 -14
- package/runtime/ext_gui/gui_engine.h +56 -4
- package/runtime/ext_gui/gui_events.cpp +80 -9
- package/runtime/ext_gui/image_bitmap.cpp +28 -0
- package/runtime/ext_gui/image_bitmap.h +26 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +136 -0
- package/runtime/ext_gui/listener_options.h +43 -0
- package/runtime/ext_gui/media.cpp +32 -0
- package/runtime/ext_gui/media.h +13 -0
- package/runtime/ext_gui/media_api.h +23 -0
- package/runtime/ext_gui/paint.cpp +28 -0
- package/runtime/ext_gui/paint.h +4 -0
- package/runtime/ext_gui/webgl.h +152 -18
- package/runtime/ext_gui/webgl_blit.cpp +95 -0
- package/runtime/ext_gui/webgl_buffer.cpp +178 -263
- package/runtime/ext_gui/webgl_buffer_objects.cpp +270 -0
- package/runtime/ext_gui/webgl_clear.cpp +142 -0
- package/runtime/ext_gui/webgl_compressed.cpp +180 -0
- package/runtime/ext_gui/webgl_context.cpp +241 -156
- package/runtime/ext_gui/webgl_draw.cpp +68 -3
- package/runtime/ext_gui/webgl_draw_buffers.cpp +75 -0
- package/runtime/ext_gui/webgl_glsl.h +40 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +6 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +18 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +20 -11
- package/runtime/ext_gui/webgl_glsl_scan_block.cpp +126 -0
- package/runtime/ext_gui/webgl_glsl_tokens.h +28 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +71 -19
- package/runtime/ext_gui/webgl_program_blocks.cpp +58 -0
- package/runtime/ext_gui/webgl_program_internal.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +13 -1
- package/runtime/ext_gui/webgl_state.cpp +228 -0
- package/runtime/ext_gui/webgl_texture.cpp +144 -17
- package/runtime/ext_gui/webgl_texture_3d.cpp +215 -0
- package/runtime/ext_gui/webgl_uniform_block.h +31 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +58 -5
- package/runtime/ext_gui/window.cpp +14 -65
- package/runtime/ext_gui/window_events.cpp +125 -0
- package/runtime/ext_media/decode_audio.cpp +308 -0
- package/runtime/ext_media/media_bridge.c +2 -0
- package/runtime/rt.h +43 -0
- package/runtime/rt_internal.h +4 -0
- package/runtime/xt_array_buffer.c +30 -0
- package/runtime/xt_builtins.c +0 -21
- package/runtime/xt_containers/access.inc +94 -2
- package/runtime/xt_containers/objects.inc +29 -31
- package/runtime/xt_typed_array/elements.inc +13 -0
- package/scripts/build-media.ts +14 -6
- package/scripts/build-runtime.ts +21 -16
- package/scripts/check-version.ts +39 -9
- package/scripts/package-platform.ts +183 -0
- package/scripts/set-platform-version.ts +62 -0
- package/scripts/verify-platform-package.ts +182 -0
- package/src/cli/main.ts +5 -1
- package/src/driver/runtime-lib.ts +73 -9
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/index.ts +18 -5
- package/src/extensions/media/index.ts +4 -3
- package/src/parser/context.ts +99 -4
- package/src/parser/literals.ts +6 -12
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — the `addEventListener` options bag.
|
|
3
|
+
*
|
|
4
|
+
* Element and window listeners accept the standard third argument:
|
|
5
|
+
* `capture` / `once` / `passive` (a boolean third argument is the legacy
|
|
6
|
+
* `capture` spelling) and `signal` (an `AbortSignal`; an aborted signal means
|
|
7
|
+
* the listener must not run again). Both delivery sites parse it here so the
|
|
8
|
+
* two paths cannot drift apart.
|
|
9
|
+
*/
|
|
10
|
+
#ifndef XT_GUI_LISTENER_OPTIONS_H
|
|
11
|
+
#define XT_GUI_LISTENER_OPTIONS_H
|
|
12
|
+
|
|
13
|
+
#include "gui_engine.h"
|
|
14
|
+
|
|
15
|
+
struct XtGuiListenerOptions {
|
|
16
|
+
bool capture = false;
|
|
17
|
+
bool once = false;
|
|
18
|
+
bool passive = false;
|
|
19
|
+
xt_value signal = XT_UNDEFINED;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** True when `signal` is an already-aborted `AbortSignal`. */
|
|
23
|
+
inline bool xt_gui_signal_aborted(xt_value signal) {
|
|
24
|
+
if (!XT_IS_OBJECT(signal)) return false;
|
|
25
|
+
xt_value aborted = xt_object_get_cstr(signal, "aborted");
|
|
26
|
+
return XT_IS_UNDEFINED(aborted) ? false : (xt_truthy(aborted) != 0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
inline XtGuiListenerOptions xt_gui_listener_options(xt_value options) {
|
|
30
|
+
XtGuiListenerOptions parsed;
|
|
31
|
+
if (XT_IS_OBJECT(options)) {
|
|
32
|
+
parsed.capture = xt_truthy(xt_object_get_cstr(options, "capture")) != 0;
|
|
33
|
+
parsed.once = xt_truthy(xt_object_get_cstr(options, "once")) != 0;
|
|
34
|
+
parsed.passive = xt_truthy(xt_object_get_cstr(options, "passive")) != 0;
|
|
35
|
+
xt_value signal = xt_object_get_cstr(options, "signal");
|
|
36
|
+
if (XT_IS_OBJECT(signal)) parsed.signal = signal;
|
|
37
|
+
} else if (XT_IS_BOOL(options)) {
|
|
38
|
+
parsed.capture = xt_truthy(options) != 0;
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#endif /* XT_GUI_LISTENER_OPTIONS_H */
|
|
@@ -55,6 +55,38 @@ void xt_media_shutdown() {
|
|
|
55
55
|
if (g_api != nullptr && g_api->shutdown != nullptr) g_api->shutdown();
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
bool xt_media_decode_audio(const uint8_t* data, size_t size, DecodedAudio* out,
|
|
59
|
+
std::string* error) {
|
|
60
|
+
if (g_api == nullptr || g_api->decode_audio == nullptr) {
|
|
61
|
+
if (error) {
|
|
62
|
+
*error = "cannot decode this audio format; enable the 'media' extension (pass --ext media)";
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
XtMediaAudioBuffer decoded = {0, 0, 0, nullptr};
|
|
67
|
+
char message[kErrorSize] = {0};
|
|
68
|
+
if (g_api->decode_audio(data, size, &decoded, message, sizeof(message)) == 0 ||
|
|
69
|
+
decoded.samples == nullptr) {
|
|
70
|
+
if (decoded.samples != nullptr && g_api->free_audio != nullptr) {
|
|
71
|
+
g_api->free_audio(decoded.samples);
|
|
72
|
+
}
|
|
73
|
+
if (error) *error = message[0] != '\0' ? message : "cannot decode audio data";
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if (decoded.channels <= 0 || decoded.frames < 0 || decoded.sample_rate <= 0) {
|
|
77
|
+
if (g_api->free_audio != nullptr) g_api->free_audio(decoded.samples);
|
|
78
|
+
if (error) *error = "decoder produced an empty audio buffer";
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
out->channels = decoded.channels;
|
|
82
|
+
out->sample_rate = decoded.sample_rate;
|
|
83
|
+
out->frames = static_cast<uint32_t>(decoded.frames);
|
|
84
|
+
size_t count = static_cast<size_t>(decoded.frames) * static_cast<size_t>(decoded.channels);
|
|
85
|
+
out->interleaved.assign(decoded.samples, decoded.samples + count);
|
|
86
|
+
if (g_api->free_audio != nullptr) g_api->free_audio(decoded.samples);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
58
90
|
} // namespace xtgui
|
|
59
91
|
|
|
60
92
|
extern "C" void xt_media_install(const XtMediaApi* api) { g_api = api; }
|
package/runtime/ext_gui/media.h
CHANGED
|
@@ -35,11 +35,24 @@
|
|
|
35
35
|
#include <memory>
|
|
36
36
|
#include <string>
|
|
37
37
|
|
|
38
|
+
#include "audio_decode.h"
|
|
38
39
|
#include "image.h"
|
|
39
40
|
#include "media_api.h"
|
|
40
41
|
|
|
41
42
|
namespace xtgui {
|
|
42
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Decode an in-memory audio file (`decodeAudioData`).
|
|
46
|
+
*
|
|
47
|
+
* The engine has its own WAV decoder (`audio_decode.cpp`); this entry point is
|
|
48
|
+
* the fallback for compressed containers and codecs, which only the optional
|
|
49
|
+
* `media` extension can decode. Without that extension it fails with a message
|
|
50
|
+
* naming the extension. Implemented in `media.cpp`, which forwards to the
|
|
51
|
+
* backend table installed by the media bridge.
|
|
52
|
+
*/
|
|
53
|
+
bool xt_media_decode_audio(const uint8_t* data, size_t size, DecodedAudio* out,
|
|
54
|
+
std::string* error);
|
|
55
|
+
|
|
43
56
|
/** DOM events a media element may fire after `tick()`. */
|
|
44
57
|
enum MediaEvent {
|
|
45
58
|
kMediaEventLoadedMetadata = 1 << 0,
|
|
@@ -40,10 +40,30 @@ typedef XtMediaPlayerHandle (*XtMediaByIdFn)(uint64_t id);
|
|
|
40
40
|
/** Tear down every decoder and process-wide media state. */
|
|
41
41
|
typedef void (*XtMediaShutdownFn)(void);
|
|
42
42
|
|
|
43
|
+
/** Interleaved float PCM returned by the memory decoder.
|
|
44
|
+
*
|
|
45
|
+
* `samples` is allocated by the backend and must be released with the table's
|
|
46
|
+
* `free_audio` entry point (both archives use the same static CRT). */
|
|
47
|
+
typedef struct XtMediaAudioBuffer {
|
|
48
|
+
int channels;
|
|
49
|
+
int sample_rate;
|
|
50
|
+
int frames;
|
|
51
|
+
float *samples;
|
|
52
|
+
} XtMediaAudioBuffer;
|
|
53
|
+
|
|
54
|
+
/** Decode an in-memory audio file (`decodeAudioData`). Returns 1 on success and
|
|
55
|
+
* fills `out`; on failure returns 0 and copies a message into `error`. */
|
|
56
|
+
typedef int (*XtMediaDecodeAudioFn)(const unsigned char *data, size_t size,
|
|
57
|
+
XtMediaAudioBuffer *out, char *error, size_t error_size);
|
|
58
|
+
/** Release the `samples` a successful `decode_audio` allocated. */
|
|
59
|
+
typedef void (*XtMediaFreeAudioFn)(void *samples);
|
|
60
|
+
|
|
43
61
|
typedef struct XtMediaApi {
|
|
44
62
|
XtMediaOpenFn open;
|
|
45
63
|
XtMediaByIdFn by_id;
|
|
46
64
|
XtMediaShutdownFn shutdown;
|
|
65
|
+
XtMediaDecodeAudioFn decode_audio;
|
|
66
|
+
XtMediaFreeAudioFn free_audio;
|
|
47
67
|
} XtMediaApi;
|
|
48
68
|
|
|
49
69
|
/** Install a decoder table. Implemented by the GUI engine; called once by the
|
|
@@ -57,6 +77,9 @@ XtMediaPlayerHandle xt_media_backend_open(const char *path, char *error,
|
|
|
57
77
|
size_t error_size, void *audio_sink);
|
|
58
78
|
XtMediaPlayerHandle xt_media_backend_by_id(uint64_t id);
|
|
59
79
|
void xt_media_backend_shutdown(void);
|
|
80
|
+
int xt_media_backend_decode_audio(const unsigned char *data, size_t size,
|
|
81
|
+
XtMediaAudioBuffer *out, char *error, size_t error_size);
|
|
82
|
+
void xt_media_backend_free_audio(void *samples);
|
|
60
83
|
|
|
61
84
|
#ifdef __cplusplus
|
|
62
85
|
}
|
|
@@ -246,6 +246,34 @@ void xt_paint_build(const LayoutBox *root, DisplayList &out, float viewportWidth
|
|
|
246
246
|
paintBox(root, out, none, chain, viewportWidth, viewportHeight);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
void xt_paint_translate(DisplayList &list, float dx, float dy) {
|
|
250
|
+
if (dx == 0.0f && dy == 0.0f) return;
|
|
251
|
+
for (PaintRect &rect : list.rects) {
|
|
252
|
+
rect.x += dx;
|
|
253
|
+
rect.y += dy;
|
|
254
|
+
}
|
|
255
|
+
for (PaintText &text : list.texts) {
|
|
256
|
+
text.x += dx;
|
|
257
|
+
text.baseline += dy;
|
|
258
|
+
}
|
|
259
|
+
for (PaintImage &image : list.images) {
|
|
260
|
+
image.x += dx;
|
|
261
|
+
image.y += dy;
|
|
262
|
+
}
|
|
263
|
+
for (PaintOp &op : list.ops) {
|
|
264
|
+
op.clip.x += dx;
|
|
265
|
+
op.clip.y += dy;
|
|
266
|
+
}
|
|
267
|
+
for (ClipPathGeometry &path : list.clip_paths) {
|
|
268
|
+
for (ClipTriangle &triangle : path.triangles) {
|
|
269
|
+
for (int i = 0; i < 3; i++) {
|
|
270
|
+
triangle.x[i] += dx;
|
|
271
|
+
triangle.y[i] += dy;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
249
277
|
std::string DisplayList::dump() const {
|
|
250
278
|
std::string text;
|
|
251
279
|
char buffer[320];
|
package/runtime/ext_gui/paint.h
CHANGED
|
@@ -140,6 +140,10 @@ struct DisplayList {
|
|
|
140
140
|
void xt_paint_build(const LayoutBox *root, DisplayList &out, float viewportWidth = 0.0f,
|
|
141
141
|
float viewportHeight = 0.0f);
|
|
142
142
|
|
|
143
|
+
/** Shift every shape and clip in `list` by `(dx, dy)`. Used for page scroll:
|
|
144
|
+
* the layout stays at document coordinates and painting moves the viewport. */
|
|
145
|
+
void xt_paint_translate(DisplayList &list, float dx, float dy);
|
|
146
|
+
|
|
143
147
|
} // namespace xtgui
|
|
144
148
|
|
|
145
149
|
#endif /* XT_GUI_PAINT_H */
|
package/runtime/ext_gui/webgl.h
CHANGED
|
@@ -33,11 +33,13 @@
|
|
|
33
33
|
#include "webgl_constants.h"
|
|
34
34
|
#include "webgl2_constants.h"
|
|
35
35
|
#include "webgl_glsl.h"
|
|
36
|
+
#include "webgl_uniform_block.h"
|
|
36
37
|
|
|
37
38
|
namespace xtgui {
|
|
38
39
|
|
|
39
40
|
constexpr int kWebGLMaxAttribs = 16;
|
|
40
41
|
constexpr int kWebGLMaxTextureUnits = 16;
|
|
42
|
+
constexpr int kWebGLMaxDrawBuffers = 4;
|
|
41
43
|
|
|
42
44
|
struct WebGLShader {
|
|
43
45
|
uint32_t id = 0;
|
|
@@ -64,6 +66,7 @@ struct WebGLProgram {
|
|
|
64
66
|
bool linked = false;
|
|
65
67
|
std::string log;
|
|
66
68
|
std::vector<WebGLUniform> uniforms;
|
|
69
|
+
std::vector<WebGLUniformBlock> blocks;
|
|
67
70
|
std::vector<GlslUniformDecl> attribs;
|
|
68
71
|
std::unordered_map<std::string, int> attrib_locations; // name -> location
|
|
69
72
|
std::unordered_map<std::string, int> attrib_bindings; // bindAttribLocation overrides
|
|
@@ -87,6 +90,8 @@ struct WebGLBuffer {
|
|
|
87
90
|
SDL_GPUBuffer *gpu = nullptr;
|
|
88
91
|
uint32_t capacity = 0;
|
|
89
92
|
bool dirty = true;
|
|
93
|
+
/** `bufferData` usage hint, reported by `getBufferParameter`. */
|
|
94
|
+
int usage = GL_STATIC_DRAW;
|
|
90
95
|
};
|
|
91
96
|
|
|
92
97
|
struct WebGLTexture {
|
|
@@ -94,9 +99,20 @@ struct WebGLTexture {
|
|
|
94
99
|
int width = 0;
|
|
95
100
|
int height = 0;
|
|
96
101
|
int levels = 1;
|
|
102
|
+
/** The binding target this texture was created for. */
|
|
103
|
+
int target = GL_TEXTURE_2D;
|
|
104
|
+
/** Layers for a cube/2D-array texture, depth for a 3D texture. */
|
|
105
|
+
int layers = 1;
|
|
97
106
|
SDL_GPUTexture *gpu = nullptr;
|
|
98
107
|
SDL_GPUTextureFormat format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
99
|
-
|
|
108
|
+
/** Depth(-stencil) formats can only be depth attachments. */
|
|
109
|
+
bool depth = false;
|
|
110
|
+
/** Block-compressed textures are sample-only, with one mip level. */
|
|
111
|
+
bool compressed = false;
|
|
112
|
+
/** Usage flags the current `gpu` texture was created with. */
|
|
113
|
+
uint32_t usage = 0;
|
|
114
|
+
bool as_target = false; // bound as a colour attachment
|
|
115
|
+
bool as_depth_target = false; // bound as a depth attachment
|
|
100
116
|
bool has_mipmaps = false;
|
|
101
117
|
int min_filter = 0;
|
|
102
118
|
int mag_filter = 0;
|
|
@@ -117,11 +133,16 @@ struct WebGLRenderbuffer {
|
|
|
117
133
|
|
|
118
134
|
struct WebGLFramebuffer {
|
|
119
135
|
uint32_t id = 0;
|
|
120
|
-
uint32_t
|
|
136
|
+
uint32_t color_textures[kWebGLMaxDrawBuffers] = {};
|
|
137
|
+
/** Layer rendered to for an array/cube colour attachment. */
|
|
138
|
+
int color_layers[kWebGLMaxDrawBuffers] = {};
|
|
139
|
+
/** `COLOR_ATTACHMENTi` or `NONE` per draw-buffer slot. */
|
|
140
|
+
int draw_buffers[kWebGLMaxDrawBuffers] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE};
|
|
141
|
+
uint32_t depth_texture = 0;
|
|
121
142
|
uint32_t depth_renderbuffer = 0;
|
|
122
143
|
int width = 0;
|
|
123
144
|
int height = 0;
|
|
124
|
-
SDL_GPUTexture *depth = nullptr; // owned when no renderbuffer supplies one
|
|
145
|
+
SDL_GPUTexture *depth = nullptr; // owned when no renderbuffer/texture supplies one
|
|
125
146
|
};
|
|
126
147
|
|
|
127
148
|
/** Per-attribute array state. */
|
|
@@ -138,9 +159,7 @@ struct WebGLAttribState {
|
|
|
138
159
|
float current[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
|
139
160
|
};
|
|
140
161
|
|
|
141
|
-
/** A WebGL 2 vertex-array object
|
|
142
|
-
* SDL_GPU has no VAO concept, so binding one restores this state into the live
|
|
143
|
-
* `attribs_` array. */
|
|
162
|
+
/** A WebGL 2 vertex-array object; binding one restores this state. */
|
|
144
163
|
struct WebGLVertexArray {
|
|
145
164
|
uint32_t id = 0;
|
|
146
165
|
WebGLAttribState attribs[kWebGLMaxAttribs];
|
|
@@ -165,6 +184,17 @@ struct WebGLSync {
|
|
|
165
184
|
uint32_t id = 0;
|
|
166
185
|
};
|
|
167
186
|
|
|
187
|
+
/** One face's stencil test and update state. */
|
|
188
|
+
struct WebGLStencilFace {
|
|
189
|
+
int func = GL_ALWAYS;
|
|
190
|
+
int ref = 0;
|
|
191
|
+
uint32_t value_mask = 0xFFFFFFFFu; // compare mask
|
|
192
|
+
uint32_t write_mask = 0xFFFFFFFFu;
|
|
193
|
+
int fail = GL_KEEP;
|
|
194
|
+
int zfail = GL_KEEP;
|
|
195
|
+
int zpass = GL_KEEP;
|
|
196
|
+
};
|
|
197
|
+
|
|
168
198
|
/** The fixed-function state a pipeline depends on. */
|
|
169
199
|
struct WebGLDrawState {
|
|
170
200
|
bool blend = false;
|
|
@@ -177,10 +207,19 @@ struct WebGLDrawState {
|
|
|
177
207
|
bool depth_test = false;
|
|
178
208
|
bool depth_write = true;
|
|
179
209
|
int depth_func = GL_LESS;
|
|
210
|
+
bool stencil = false;
|
|
211
|
+
WebGLStencilFace stencil_front;
|
|
212
|
+
WebGLStencilFace stencil_back;
|
|
180
213
|
bool cull = false;
|
|
181
214
|
int cull_face = GL_BACK;
|
|
182
215
|
int front_face = GL_CCW;
|
|
183
216
|
bool color_mask[4] = {true, true, true, true};
|
|
217
|
+
/** Attachment formats of the bound target; pipelines are format-specific. */
|
|
218
|
+
int color_formats[kWebGLMaxDrawBuffers] = {
|
|
219
|
+
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
|
|
220
|
+
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM};
|
|
221
|
+
int color_target_count = 1;
|
|
222
|
+
int depth_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT;
|
|
184
223
|
};
|
|
185
224
|
|
|
186
225
|
class WebGLContext {
|
|
@@ -195,11 +234,15 @@ class WebGLContext {
|
|
|
195
234
|
/** Resize the drawing buffer; GL semantics discard its contents. */
|
|
196
235
|
void resize(int width, int height);
|
|
197
236
|
|
|
198
|
-
/** End the
|
|
199
|
-
* frame, before the page's own render pass samples the colour texture). */
|
|
237
|
+
/** End the pass and submit (once per frame, before sampling). */
|
|
200
238
|
void submit();
|
|
201
239
|
SDL_GPUTexture *color_texture();
|
|
202
240
|
bool lost() const { return lost_; }
|
|
241
|
+
/** Lose/restore the GPU device, dropping every WebGL object. */
|
|
242
|
+
void lose_context();
|
|
243
|
+
void restore_context();
|
|
244
|
+
/** `drawingBufferStorage`: fix the size across canvas resizes. */
|
|
245
|
+
void drawing_buffer_storage(int width, int height);
|
|
203
246
|
|
|
204
247
|
/* -- object lookups ---------------------------------------------------- */
|
|
205
248
|
WebGLShader *shader(uint32_t id);
|
|
@@ -223,10 +266,20 @@ class WebGLContext {
|
|
|
223
266
|
void color_mask(bool r, bool g, bool b, bool a);
|
|
224
267
|
void depth_mask(bool write) { state_.depth_write = write; }
|
|
225
268
|
void depth_func(int func) { state_.depth_func = func; }
|
|
269
|
+
void stencil_func(int func, int ref, uint32_t mask);
|
|
270
|
+
void stencil_func_separate(int face, int func, int ref, uint32_t mask);
|
|
271
|
+
void stencil_op(int fail, int zfail, int zpass);
|
|
272
|
+
void stencil_op_separate(int face, int fail, int zfail, int zpass);
|
|
273
|
+
void stencil_mask(uint32_t mask);
|
|
274
|
+
void stencil_mask_separate(int face, uint32_t mask);
|
|
275
|
+
const WebGLStencilFace &stencil_face(int face) const;
|
|
276
|
+
int stencil_reference() const; // the value the GPU test sees
|
|
226
277
|
void blend_func(int src, int dst);
|
|
227
278
|
void blend_func_separate(int src_rgb, int dst_rgb, int src_alpha, int dst_alpha);
|
|
228
279
|
void blend_equation(int mode);
|
|
229
280
|
void blend_equation_separate(int rgb, int alpha);
|
|
281
|
+
void blend_color(float r, float g, float b, float a);
|
|
282
|
+
void blend_color_value(float out[4]) const;
|
|
230
283
|
void cull_face(int mode);
|
|
231
284
|
void front_face(int mode);
|
|
232
285
|
void viewport(int x, int y, int w, int h);
|
|
@@ -261,8 +314,7 @@ class WebGLContext {
|
|
|
261
314
|
int attrib_location(uint32_t program, const std::string &name);
|
|
262
315
|
void bind_attrib_location(uint32_t program, int index, const std::string &name);
|
|
263
316
|
|
|
264
|
-
/* Uniform uploads
|
|
265
|
-
* (the DOM layer wraps it in the `WebGLUniformLocation` handle). */
|
|
317
|
+
/* Uniform uploads; `location` indexes the program's uniform table. */
|
|
266
318
|
void uniform_floats(uint32_t program, int location, int components, const double *values,
|
|
267
319
|
int count);
|
|
268
320
|
void uniform_ints(uint32_t program, int location, int components, const int *values, int count);
|
|
@@ -314,6 +366,12 @@ class WebGLContext {
|
|
|
314
366
|
void delete_sync(uint32_t id);
|
|
315
367
|
bool is_sync(uint32_t id) const;
|
|
316
368
|
uint32_t uniform_block_index(uint32_t program, const std::string &name) const;
|
|
369
|
+
WebGLUniformBlock *uniform_block(uint32_t program, uint32_t index);
|
|
370
|
+
int uniform_block_parameter(uint32_t program, uint32_t index, int pname) const;
|
|
371
|
+
std::string uniform_block_name(uint32_t program, uint32_t index) const;
|
|
372
|
+
void uniform_block_binding(uint32_t program, uint32_t index, int binding);
|
|
373
|
+
void bind_buffer_base(int target, int index, uint32_t buffer, uint32_t offset, uint32_t size);
|
|
374
|
+
uint32_t uniform_buffer_binding(int index) const;
|
|
317
375
|
|
|
318
376
|
/* -- textures ---------------------------------------------------------- */
|
|
319
377
|
uint32_t create_texture();
|
|
@@ -324,18 +382,50 @@ class WebGLContext {
|
|
|
324
382
|
int tex_parameter_value(uint32_t id, int pname);
|
|
325
383
|
bool tex_image_rgba(uint32_t id, int width, int height, const uint8_t *rgba);
|
|
326
384
|
bool tex_sub_image_rgba(uint32_t id, int x, int y, int width, int height, const uint8_t *rgba);
|
|
385
|
+
/** Level-0 upload; `pixels` is tightly packed RGBA or expanded already. */
|
|
386
|
+
bool tex_image_format(uint32_t id, int width, int height, SDL_GPUTextureFormat format,
|
|
387
|
+
const uint8_t *pixels, int layer = -1);
|
|
388
|
+
bool tex_sub_image_format(uint32_t id, int x, int y, int width, int height,
|
|
389
|
+
const uint8_t *pixels, int layer = 0);
|
|
327
390
|
bool generate_mipmap(uint32_t id);
|
|
328
|
-
/**
|
|
329
|
-
* The backend always allocates the full mip chain, so `levels` is a hint. */
|
|
391
|
+
/** `texStorage2D`; the backend allocates the full mip chain. */
|
|
330
392
|
bool tex_storage_2d(uint32_t id, int levels, int width, int height);
|
|
393
|
+
bool tex_storage_format(uint32_t id, int levels, int width, int height,
|
|
394
|
+
SDL_GPUTextureFormat format);
|
|
395
|
+
/** Allocate (and optionally upload) a 3D or 2D-array texture. */
|
|
396
|
+
bool tex_storage_3d(uint32_t id, int levels, int width, int height, int depth,
|
|
397
|
+
SDL_GPUTextureFormat format, int target);
|
|
398
|
+
bool tex_image_3d(uint32_t id, int width, int height, int depth,
|
|
399
|
+
SDL_GPUTextureFormat format, const uint8_t *pixels, int target);
|
|
400
|
+
bool tex_sub_image_3d(uint32_t id, int x, int y, int z, int width, int height, int depth,
|
|
401
|
+
const uint8_t *pixels);
|
|
402
|
+
/** Upload a block-compressed region. */
|
|
403
|
+
bool tex_image_compressed(uint32_t id, int width, int height, SDL_GPUTextureFormat format,
|
|
404
|
+
int x, int y, int region_width, int region_height,
|
|
405
|
+
const uint8_t *data, uint32_t size);
|
|
406
|
+
/** Whether the device can sample `internalformat` (compressed formats). */
|
|
407
|
+
bool supports_texture_format(int internalformat);
|
|
331
408
|
int texture_width(uint32_t id);
|
|
409
|
+
int texture_height(uint32_t id);
|
|
410
|
+
/** The SDL_GPU format of a texture (RGBA8 before `texImage2D`). */
|
|
411
|
+
int texture_format(uint32_t id);
|
|
332
412
|
|
|
333
413
|
/* -- framebuffers ------------------------------------------------------ */
|
|
334
414
|
uint32_t create_framebuffer();
|
|
335
415
|
void delete_framebuffer(uint32_t id);
|
|
336
|
-
void bind_framebuffer(uint32_t id);
|
|
337
|
-
|
|
416
|
+
void bind_framebuffer(int target, uint32_t id);
|
|
417
|
+
uint32_t bound_read_framebuffer_id() const { return read_framebuffer_; }
|
|
418
|
+
bool blit_framebuffer(const int source[4], const int destination[4], int mask, int filter);
|
|
419
|
+
bool framebuffer_texture(uint32_t framebuffer, uint32_t texture,
|
|
420
|
+
int attachment = GL_COLOR_ATTACHMENT0);
|
|
421
|
+
bool framebuffer_texture_layer(uint32_t framebuffer, uint32_t texture, int attachment,
|
|
422
|
+
int layer);
|
|
338
423
|
bool framebuffer_status(uint32_t id);
|
|
424
|
+
/** WebGL 2 `drawBuffers` / `readBuffer`. */
|
|
425
|
+
void draw_buffers(int count, const int *buffers);
|
|
426
|
+
void read_buffer(int mode) { read_buffer_ = mode; }
|
|
427
|
+
int read_buffer_value() const { return read_buffer_; }
|
|
428
|
+
int draw_buffer_value(int index);
|
|
339
429
|
uint32_t create_renderbuffer();
|
|
340
430
|
void delete_renderbuffer(uint32_t id);
|
|
341
431
|
void bind_renderbuffer(uint32_t id) { bound_renderbuffer_ = id; }
|
|
@@ -357,6 +447,9 @@ class WebGLContext {
|
|
|
357
447
|
std::string string_parameter(int pname);
|
|
358
448
|
uint32_t bound_buffer(int target) const;
|
|
359
449
|
uint32_t bound_texture(int unit) const;
|
|
450
|
+
uint32_t bound_cube_texture(int unit) const;
|
|
451
|
+
uint32_t bound_array_texture(int unit) const;
|
|
452
|
+
uint32_t bound_3d_texture(int unit) const;
|
|
360
453
|
uint32_t current_program_id() const { return current_program_; }
|
|
361
454
|
uint32_t bound_framebuffer_id() const { return bound_framebuffer_; }
|
|
362
455
|
uint32_t bound_renderbuffer_id() const { return bound_renderbuffer_; }
|
|
@@ -377,9 +470,24 @@ class WebGLContext {
|
|
|
377
470
|
void ensure_command();
|
|
378
471
|
void end_pass();
|
|
379
472
|
void flush_uploads();
|
|
380
|
-
void begin_pass(bool clear_color, bool clear_depth);
|
|
473
|
+
void begin_pass(bool clear_color, bool clear_depth, bool clear_stencil);
|
|
474
|
+
/** Scissored depth/stencil clear via a masked fullscreen triangle. */
|
|
475
|
+
void scissored_clear(int mask);
|
|
476
|
+
/** The 1×1 texture a scissored colour clear blits from. */
|
|
477
|
+
SDL_GPUTexture *clear_color_texture();
|
|
478
|
+
SDL_GPUTexture *framebuffer_color(uint32_t id);
|
|
479
|
+
void framebuffer_size(uint32_t id, int *width, int *height);
|
|
480
|
+
/** Release every GPU handle this context owns, keeping the CPU-side object
|
|
481
|
+
* table. Used by the destructor and by `lose_context`. */
|
|
482
|
+
void release_gpu_resources();
|
|
381
483
|
SDL_GPUTexture *target_color();
|
|
382
484
|
SDL_GPUTexture *target_depth();
|
|
485
|
+
int target_color_format();
|
|
486
|
+
int target_depth_format();
|
|
487
|
+
/** The texture rendered to for draw-buffer slot `slot`, or null. */
|
|
488
|
+
SDL_GPUTexture *draw_color_texture(int slot);
|
|
489
|
+
int draw_color_format(int slot);
|
|
490
|
+
int draw_color_layer(int slot);
|
|
383
491
|
SDL_GPUTexture *ensure_texture_gpu(WebGLTexture *texture, bool as_target);
|
|
384
492
|
SDL_GPUSampler *sampler_for(WebGLTexture *texture);
|
|
385
493
|
SDL_GPUBuffer *ensure_buffer_gpu(WebGLBuffer *buffer);
|
|
@@ -415,15 +523,22 @@ class WebGLContext {
|
|
|
415
523
|
SDL_GPUTexture *depth_ = nullptr;
|
|
416
524
|
SDL_GPUTexture *fallback_texture_ = nullptr;
|
|
417
525
|
SDL_GPUSampler *fallback_sampler_ = nullptr;
|
|
526
|
+
/** 1×1 RGBA8 source for a scissored colour clear. */
|
|
527
|
+
SDL_GPUTexture *clear_texture_ = nullptr;
|
|
528
|
+
/** Internal program/buffer for a scissored depth/stencil clear. */
|
|
529
|
+
uint32_t clear_program_ = 0;
|
|
530
|
+
uint32_t clear_buffer_ = 0;
|
|
418
531
|
|
|
419
532
|
float clear_color_[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
420
533
|
float clear_depth_ = 1.0f;
|
|
421
534
|
int clear_stencil_ = 0;
|
|
535
|
+
float blend_color_[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
536
|
+
/** Set by `drawingBufferStorage`; canvas resizes then leave the size. */
|
|
537
|
+
bool fixed_storage_ = false;
|
|
422
538
|
WebGLDrawState state_;
|
|
423
539
|
int viewport_[4] = {0, 0, 0, 0};
|
|
424
540
|
int scissor_box_[4] = {0, 0, 0, 0};
|
|
425
541
|
bool scissor_test_ = false;
|
|
426
|
-
bool stencil_test_ = false;
|
|
427
542
|
|
|
428
543
|
std::unordered_map<uint32_t, std::unique_ptr<WebGLShader>> shaders_;
|
|
429
544
|
std::unordered_map<uint32_t, std::unique_ptr<WebGLProgram>> programs_;
|
|
@@ -435,16 +550,27 @@ class WebGLContext {
|
|
|
435
550
|
std::unordered_map<uint32_t, std::unique_ptr<WebGLSampler>> samplers_;
|
|
436
551
|
std::unordered_map<uint32_t, std::unique_ptr<WebGLQuery>> queries_;
|
|
437
552
|
std::unordered_map<uint32_t, std::unique_ptr<WebGLSync>> syncs_;
|
|
438
|
-
/** GPU buffers
|
|
439
|
-
* attributes, expanded index data); released with the context. */
|
|
553
|
+
/** GPU buffers for transient draws (constant attributes, expanded indices). */
|
|
440
554
|
std::vector<SDL_GPUBuffer *> temp_buffers_;
|
|
441
555
|
|
|
442
556
|
uint32_t current_program_ = 0;
|
|
443
557
|
uint32_t bound_array_ = 0;
|
|
444
558
|
uint32_t bound_element_ = 0;
|
|
559
|
+
uint32_t bound_uniform_ = 0;
|
|
560
|
+
uint32_t bound_transform_feedback_ = 0;
|
|
445
561
|
uint32_t bound_framebuffer_ = 0;
|
|
562
|
+
uint32_t read_framebuffer_ = 0;
|
|
563
|
+
int read_buffer_ = GL_BACK;
|
|
564
|
+
int default_draw_buffers_[kWebGLMaxDrawBuffers] = {GL_BACK, GL_NONE, GL_NONE, GL_NONE};
|
|
446
565
|
uint32_t bound_renderbuffer_ = 0;
|
|
566
|
+
WebGLUniformBinding uniform_bindings_[16];
|
|
447
567
|
uint32_t bound_textures_[kWebGLMaxTextureUnits] = {};
|
|
568
|
+
uint32_t bound_cube_textures_[kWebGLMaxTextureUnits] = {};
|
|
569
|
+
uint32_t bound_array_textures_[kWebGLMaxTextureUnits] = {};
|
|
570
|
+
uint32_t bound_3d_textures_[kWebGLMaxTextureUnits] = {};
|
|
571
|
+
/** The target of the most recent `bindTexture` on each unit, so the existing
|
|
572
|
+
* per-unit entry points operate on the object the page just bound. */
|
|
573
|
+
int active_texture_target_[kWebGLMaxTextureUnits] = {};
|
|
448
574
|
uint32_t bound_samplers_[kWebGLMaxTextureUnits] = {};
|
|
449
575
|
uint32_t bound_vertex_array_ = 0;
|
|
450
576
|
WebGLVertexArray default_vertex_array_;
|
|
@@ -461,6 +587,14 @@ class WebGLContext {
|
|
|
461
587
|
* a `<canvas>`). */
|
|
462
588
|
WebGLContext *xt_webgl_by_id(uint64_t id);
|
|
463
589
|
|
|
590
|
+
/** Map a WebGL internal format to the SDL_GPU texture format the engine uses
|
|
591
|
+
* (RGBA8 for formats without a special backend representation). */
|
|
592
|
+
SDL_GPUTextureFormat webgl_storage_format(int internalformat);
|
|
593
|
+
|
|
594
|
+
/** Map a WebGL compressed-texture internal format to its SDL_GPU format, or
|
|
595
|
+
* `SDL_GPU_TEXTUREFORMAT_INVALID` for anything else. */
|
|
596
|
+
SDL_GPUTextureFormat webgl_compressed_format(int internalformat);
|
|
597
|
+
|
|
464
598
|
} // namespace xtgui
|
|
465
599
|
|
|
466
600
|
#endif /* XT_GUI_WEBGL_H */
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — `blitFramebuffer`.
|
|
3
|
+
*
|
|
4
|
+
* SDL_GPU's blit copies a colour texture region to another colour texture, so
|
|
5
|
+
* the colour bit maps directly. Depth/stencil blits are not supported by the
|
|
6
|
+
* backend; those bits are ignored (the call is still accepted, like a driver
|
|
7
|
+
* that cannot expand the blit). Sources must be single-sampled, which is what
|
|
8
|
+
* this engine allocates today.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#include "webgl.h"
|
|
12
|
+
|
|
13
|
+
#include <algorithm>
|
|
14
|
+
#include <cstring>
|
|
15
|
+
|
|
16
|
+
#include "gui_internal.h"
|
|
17
|
+
|
|
18
|
+
namespace xtgui {
|
|
19
|
+
|
|
20
|
+
bool WebGLContext::blit_framebuffer(const int source[4], const int destination[4], int mask,
|
|
21
|
+
int filter) {
|
|
22
|
+
if ((mask & GL_COLOR_BUFFER_BIT) == 0) return true;
|
|
23
|
+
end_pass();
|
|
24
|
+
ensure_command();
|
|
25
|
+
if (cmd_ == nullptr) return false;
|
|
26
|
+
SDL_GPUTexture *source_texture = framebuffer_color(read_framebuffer_);
|
|
27
|
+
SDL_GPUTexture *destination_texture = framebuffer_color(bound_framebuffer_);
|
|
28
|
+
if (source_texture == nullptr || destination_texture == nullptr ||
|
|
29
|
+
source_texture == destination_texture) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
int source_width = 0;
|
|
33
|
+
int source_height = 0;
|
|
34
|
+
int destination_width = 0;
|
|
35
|
+
int destination_height = 0;
|
|
36
|
+
framebuffer_size(read_framebuffer_, &source_width, &source_height);
|
|
37
|
+
framebuffer_size(bound_framebuffer_, &destination_width, &destination_height);
|
|
38
|
+
if (source_width <= 0 || source_height <= 0 || destination_width <= 0 ||
|
|
39
|
+
destination_height <= 0) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
int sx0 = source[0];
|
|
43
|
+
int sy0 = source[1];
|
|
44
|
+
int sx1 = source[2];
|
|
45
|
+
int sy1 = source[3];
|
|
46
|
+
int dx0 = destination[0];
|
|
47
|
+
int dy0 = destination[1];
|
|
48
|
+
int dx1 = destination[2];
|
|
49
|
+
int dy1 = destination[3];
|
|
50
|
+
if (sx1 < sx0) std::swap(sx0, sx1);
|
|
51
|
+
if (sy1 < sy0) std::swap(sy0, sy1);
|
|
52
|
+
if (dx1 < dx0) std::swap(dx0, dx1);
|
|
53
|
+
if (dy1 < dy0) std::swap(dy0, dy1);
|
|
54
|
+
sx0 = std::max(0, std::min(sx0, source_width));
|
|
55
|
+
sx1 = std::max(0, std::min(sx1, source_width));
|
|
56
|
+
sy0 = std::max(0, std::min(sy0, source_height));
|
|
57
|
+
sy1 = std::max(0, std::min(sy1, source_height));
|
|
58
|
+
dx0 = std::max(0, std::min(dx0, destination_width));
|
|
59
|
+
dx1 = std::max(0, std::min(dx1, destination_width));
|
|
60
|
+
dy0 = std::max(0, std::min(dy0, destination_height));
|
|
61
|
+
dy1 = std::max(0, std::min(dy1, destination_height));
|
|
62
|
+
if (sx1 <= sx0 || sy1 <= sy0 || dx1 <= dx0 || dy1 <= dy0) return true;
|
|
63
|
+
|
|
64
|
+
SDL_GPUBlitRegion source_region;
|
|
65
|
+
memset(&source_region, 0, sizeof(source_region));
|
|
66
|
+
source_region.texture = source_texture;
|
|
67
|
+
source_region.x = (Uint32)sx0;
|
|
68
|
+
/* GL's origin is bottom-left; SDL's regions are top-down. */
|
|
69
|
+
source_region.y = (Uint32)(source_height - sy1);
|
|
70
|
+
source_region.w = (Uint32)(sx1 - sx0);
|
|
71
|
+
source_region.h = (Uint32)(sy1 - sy0);
|
|
72
|
+
|
|
73
|
+
SDL_GPUBlitRegion destination_region;
|
|
74
|
+
memset(&destination_region, 0, sizeof(destination_region));
|
|
75
|
+
destination_region.texture = destination_texture;
|
|
76
|
+
destination_region.x = (Uint32)dx0;
|
|
77
|
+
destination_region.y = (Uint32)(destination_height - dy1);
|
|
78
|
+
destination_region.w = (Uint32)(dx1 - dx0);
|
|
79
|
+
destination_region.h = (Uint32)(dy1 - dy0);
|
|
80
|
+
|
|
81
|
+
SDL_GPUBlitInfo info;
|
|
82
|
+
memset(&info, 0, sizeof(info));
|
|
83
|
+
info.source = source_region;
|
|
84
|
+
info.destination = destination_region;
|
|
85
|
+
/* A blit only writes the destination rectangle; everything outside it keeps
|
|
86
|
+
* its previous contents, as `blitFramebuffer` requires. DONT_CARE lets a
|
|
87
|
+
* backend (Metal's MTLLoadActionDontCare) discard the attachment and leave
|
|
88
|
+
* those pixels undefined, so load it. */
|
|
89
|
+
info.load_op = SDL_GPU_LOADOP_LOAD;
|
|
90
|
+
info.filter = filter == GL_LINEAR ? SDL_GPU_FILTER_LINEAR : SDL_GPU_FILTER_NEAREST;
|
|
91
|
+
SDL_BlitGPUTexture(cmd_, &info);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
} // namespace xtgui
|