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,167 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — compressed-texture WebGL bindings.
|
|
3
|
+
*
|
|
4
|
+
* `getExtension` publishes the S3TC/ASTC enum objects only when the device can
|
|
5
|
+
* sample the format, and `compressedTexImage2D` / `compressedTexSubImage2D`
|
|
6
|
+
* hand the tightly packed blocks to `webgl_compressed.cpp`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "dom_api_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
#include "webgl.h"
|
|
15
|
+
|
|
16
|
+
#define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
|
|
17
|
+
|
|
18
|
+
namespace domapi {
|
|
19
|
+
namespace {
|
|
20
|
+
|
|
21
|
+
xtgui::WebGLContext *context_of(xt_value self) { return webgl_live_context(self); }
|
|
22
|
+
|
|
23
|
+
uint32_t texture_argument(xt_value value) { return webgl_object_id(value, "__xt_gl_texture"); }
|
|
24
|
+
|
|
25
|
+
std::vector<uint8_t> compressed_bytes(int32_t argc, xt_value *argv, int32_t data_index,
|
|
26
|
+
int32_t offset_index, int32_t length_index) {
|
|
27
|
+
std::vector<uint8_t> bytes = webgl_bytes(xt_arg(argc, argv, data_index));
|
|
28
|
+
const uint32_t offset = (uint32_t)webgl_number(argc, argv, offset_index, 0.0);
|
|
29
|
+
uint32_t length = (uint32_t)webgl_number(argc, argv, length_index, (double)bytes.size());
|
|
30
|
+
if (offset > bytes.size()) return std::vector<uint8_t>();
|
|
31
|
+
if (length > bytes.size() - offset) length = (uint32_t)bytes.size() - offset;
|
|
32
|
+
return std::vector<uint8_t>(bytes.begin() + offset, bytes.begin() + offset + length);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void add_constant(xt_value object, const char *name, int value) {
|
|
36
|
+
xt_object_set(object, xt_string_from_cstr(name), xt_number((double)value));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
} // namespace
|
|
40
|
+
|
|
41
|
+
METHOD(webgl_compressed_tex_image_2d) {
|
|
42
|
+
(void)env;
|
|
43
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
44
|
+
if (context == nullptr) return XT_UNDEFINED;
|
|
45
|
+
const uint32_t texture = context->bound_texture(0);
|
|
46
|
+
if (texture == 0) return XT_UNDEFINED;
|
|
47
|
+
const int level = webgl_int(argc, argv, 1, 0);
|
|
48
|
+
if (level != 0) return XT_UNDEFINED;
|
|
49
|
+
const int internalformat = webgl_int(argc, argv, 2, 0);
|
|
50
|
+
const SDL_GPUTextureFormat format = xtgui::webgl_compressed_format(internalformat);
|
|
51
|
+
if (format == SDL_GPU_TEXTUREFORMAT_INVALID) {
|
|
52
|
+
context->set_error(GL_INVALID_ENUM);
|
|
53
|
+
return XT_UNDEFINED;
|
|
54
|
+
}
|
|
55
|
+
const int width = webgl_int(argc, argv, 3, 0);
|
|
56
|
+
const int height = webgl_int(argc, argv, 4, 0);
|
|
57
|
+
const std::vector<uint8_t> data = compressed_bytes(argc, argv, 6, 7, 8);
|
|
58
|
+
context->tex_image_compressed(texture, width, height, format, 0, 0, width, height,
|
|
59
|
+
data.empty() ? nullptr : data.data(), (uint32_t)data.size());
|
|
60
|
+
return XT_UNDEFINED;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
METHOD(webgl_compressed_tex_sub_image_2d) {
|
|
64
|
+
(void)env;
|
|
65
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
66
|
+
if (context == nullptr) return XT_UNDEFINED;
|
|
67
|
+
const uint32_t texture = context->bound_texture(0);
|
|
68
|
+
if (texture == 0) return XT_UNDEFINED;
|
|
69
|
+
const int internalformat = webgl_int(argc, argv, 6, 0);
|
|
70
|
+
const SDL_GPUTextureFormat format = xtgui::webgl_compressed_format(internalformat);
|
|
71
|
+
if (format == SDL_GPU_TEXTUREFORMAT_INVALID) {
|
|
72
|
+
context->set_error(GL_INVALID_ENUM);
|
|
73
|
+
return XT_UNDEFINED;
|
|
74
|
+
}
|
|
75
|
+
const int x = webgl_int(argc, argv, 2, 0);
|
|
76
|
+
const int y = webgl_int(argc, argv, 3, 0);
|
|
77
|
+
const int width = webgl_int(argc, argv, 4, 0);
|
|
78
|
+
const int height = webgl_int(argc, argv, 5, 0);
|
|
79
|
+
const std::vector<uint8_t> data = compressed_bytes(argc, argv, 7, 8, 9);
|
|
80
|
+
context->tex_image_compressed(texture, context->texture_width(texture),
|
|
81
|
+
context->texture_height(texture), format, x, y, width, height,
|
|
82
|
+
data.empty() ? nullptr : data.data(), (uint32_t)data.size());
|
|
83
|
+
return XT_UNDEFINED;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** `getExtension` for the compressed-texture families; returns null when the
|
|
87
|
+
* device cannot sample the representative format, and undefined when `name` is
|
|
88
|
+
* not a compressed-texture extension. */
|
|
89
|
+
xt_value webgl_compressed_extension(const std::string &name, xtgui::WebGLContext *context) {
|
|
90
|
+
struct CompressedConstant {
|
|
91
|
+
const char *name;
|
|
92
|
+
int value;
|
|
93
|
+
};
|
|
94
|
+
static const CompressedConstant kS3tc[] = {
|
|
95
|
+
{"COMPRESSED_RGB_S3TC_DXT1_EXT", 0x83F0},
|
|
96
|
+
{"COMPRESSED_RGBA_S3TC_DXT1_EXT", 0x83F1},
|
|
97
|
+
{"COMPRESSED_RGBA_S3TC_DXT3_EXT", 0x83F2},
|
|
98
|
+
{"COMPRESSED_RGBA_S3TC_DXT5_EXT", 0x83F3},
|
|
99
|
+
};
|
|
100
|
+
static const CompressedConstant kS3tcSrgb[] = {
|
|
101
|
+
{"COMPRESSED_SRGB_S3TC_DXT1_EXT", 0x8C4C},
|
|
102
|
+
{"COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", 0x8C4D},
|
|
103
|
+
{"COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", 0x8C4E},
|
|
104
|
+
{"COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", 0x8C4F},
|
|
105
|
+
};
|
|
106
|
+
static const CompressedConstant kAstc[] = {
|
|
107
|
+
{"COMPRESSED_RGBA_ASTC_4x4_KHR", 0x93B0},
|
|
108
|
+
{"COMPRESSED_RGBA_ASTC_5x4_KHR", 0x93B1},
|
|
109
|
+
{"COMPRESSED_RGBA_ASTC_5x5_KHR", 0x93B2},
|
|
110
|
+
{"COMPRESSED_RGBA_ASTC_6x5_KHR", 0x93B3},
|
|
111
|
+
{"COMPRESSED_RGBA_ASTC_6x6_KHR", 0x93B4},
|
|
112
|
+
{"COMPRESSED_RGBA_ASTC_8x5_KHR", 0x93B5},
|
|
113
|
+
{"COMPRESSED_RGBA_ASTC_8x6_KHR", 0x93B6},
|
|
114
|
+
{"COMPRESSED_RGBA_ASTC_8x8_KHR", 0x93B7},
|
|
115
|
+
{"COMPRESSED_RGBA_ASTC_10x5_KHR", 0x93B8},
|
|
116
|
+
{"COMPRESSED_RGBA_ASTC_10x6_KHR", 0x93B9},
|
|
117
|
+
{"COMPRESSED_RGBA_ASTC_10x8_KHR", 0x93BA},
|
|
118
|
+
{"COMPRESSED_RGBA_ASTC_10x10_KHR", 0x93BB},
|
|
119
|
+
{"COMPRESSED_RGBA_ASTC_12x10_KHR", 0x93BC},
|
|
120
|
+
{"COMPRESSED_RGBA_ASTC_12x12_KHR", 0x93BD},
|
|
121
|
+
};
|
|
122
|
+
static const CompressedConstant kAstcSrgb[] = {
|
|
123
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", 0x93D0},
|
|
124
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR", 0x93D1},
|
|
125
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR", 0x93D2},
|
|
126
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", 0x93D3},
|
|
127
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR", 0x93D4},
|
|
128
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR", 0x93D5},
|
|
129
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR", 0x93D6},
|
|
130
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR", 0x93D7},
|
|
131
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR", 0x93D8},
|
|
132
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR", 0x93D9},
|
|
133
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR", 0x93DA},
|
|
134
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR", 0x93DB},
|
|
135
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR", 0x93DC},
|
|
136
|
+
{"COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR", 0x93DD},
|
|
137
|
+
};
|
|
138
|
+
if (context == nullptr) return XT_NULL;
|
|
139
|
+
xt_value object = xt_object_new();
|
|
140
|
+
int representative = 0;
|
|
141
|
+
const CompressedConstant *table = kS3tc;
|
|
142
|
+
size_t count = sizeof(kS3tc) / sizeof(kS3tc[0]);
|
|
143
|
+
if (name == "WEBGL_compressed_texture_s3tc") {
|
|
144
|
+
representative = 0x83F1;
|
|
145
|
+
} else if (name == "WEBGL_compressed_texture_s3tc_srgb") {
|
|
146
|
+
table = kS3tcSrgb;
|
|
147
|
+
count = sizeof(kS3tcSrgb) / sizeof(kS3tcSrgb[0]);
|
|
148
|
+
representative = 0x8C4D;
|
|
149
|
+
} else if (name == "WEBGL_compressed_texture_astc") {
|
|
150
|
+
table = kAstc;
|
|
151
|
+
count = sizeof(kAstc) / sizeof(kAstc[0]);
|
|
152
|
+
representative = 0x93B0;
|
|
153
|
+
} else {
|
|
154
|
+
return XT_UNDEFINED;
|
|
155
|
+
}
|
|
156
|
+
if (!context->supports_texture_format(representative)) return XT_NULL;
|
|
157
|
+
for (size_t i = 0; i < count; i++) add_constant(object, table[i].name, table[i].value);
|
|
158
|
+
if (name == "WEBGL_compressed_texture_astc") {
|
|
159
|
+
/* The ASTC extension publishes both LDR and sRGB enums. */
|
|
160
|
+
for (size_t i = 0; i < sizeof(kAstcSrgb) / sizeof(kAstcSrgb[0]); i++) {
|
|
161
|
+
add_constant(object, kAstcSrgb[i].name, kAstcSrgb[i].value);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return object;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
} // namespace domapi
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — WebGL framebuffer, renderbuffer and readback bindings.
|
|
3
|
+
*
|
|
4
|
+
* Textures live in `dom_api_webgl_texture.cpp`; this unit owns the objects that
|
|
5
|
+
* render into them, plus `readPixels`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "dom_api_internal.h"
|
|
9
|
+
|
|
10
|
+
#include <cstring>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
#include "dom_api_webgl_rt.h"
|
|
15
|
+
#include "webgl.h"
|
|
16
|
+
|
|
17
|
+
#define METHOD(name) xt_value name(xt_value self, xt_value env, int32_t argc, xt_value *argv)
|
|
18
|
+
|
|
19
|
+
namespace domapi {
|
|
20
|
+
namespace {
|
|
21
|
+
|
|
22
|
+
xtgui::WebGLContext *context_of(xt_value self) { return webgl_live_context(self); }
|
|
23
|
+
|
|
24
|
+
uint32_t texture_argument(xt_value value) { return webgl_object_id(value, "__xt_gl_texture"); }
|
|
25
|
+
|
|
26
|
+
} // namespace
|
|
27
|
+
|
|
28
|
+
/* -- framebuffers and renderbuffers -------------------------------------- */
|
|
29
|
+
|
|
30
|
+
METHOD(webgl_create_framebuffer) {
|
|
31
|
+
(void)env;
|
|
32
|
+
(void)argc;
|
|
33
|
+
(void)argv;
|
|
34
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
35
|
+
if (context == nullptr) return XT_NULL;
|
|
36
|
+
return webgl_make_object(self, "__xt_gl_framebuffer", context->create_framebuffer(),
|
|
37
|
+
"framebuffer");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
METHOD(webgl_delete_framebuffer) {
|
|
41
|
+
(void)env;
|
|
42
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
43
|
+
if (context != nullptr) {
|
|
44
|
+
context->delete_framebuffer(webgl_object_id(xt_arg(argc, argv, 0), "__xt_gl_framebuffer"));
|
|
45
|
+
}
|
|
46
|
+
return XT_UNDEFINED;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
METHOD(webgl_bind_framebuffer) {
|
|
50
|
+
(void)env;
|
|
51
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
52
|
+
if (context != nullptr) {
|
|
53
|
+
context->bind_framebuffer(webgl_int(argc, argv, 0, GL_FRAMEBUFFER),
|
|
54
|
+
webgl_object_id(xt_arg(argc, argv, 1), "__xt_gl_framebuffer"));
|
|
55
|
+
}
|
|
56
|
+
return XT_UNDEFINED;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
METHOD(webgl_framebuffer_texture_2d) {
|
|
60
|
+
(void)env;
|
|
61
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
62
|
+
if (context != nullptr) {
|
|
63
|
+
/* WebGL's first argument is the target (`FRAMEBUFFER`), not the object:
|
|
64
|
+
* the texture attaches to the currently bound framebuffer. */
|
|
65
|
+
context->framebuffer_texture(context->bound_framebuffer_id(),
|
|
66
|
+
texture_argument(xt_arg(argc, argv, 3)),
|
|
67
|
+
webgl_int(argc, argv, 1, GL_COLOR_ATTACHMENT0));
|
|
68
|
+
}
|
|
69
|
+
return XT_UNDEFINED;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
METHOD(webgl_check_framebuffer_status) {
|
|
73
|
+
(void)env;
|
|
74
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
75
|
+
if (context == nullptr) return xt_number(GL_FRAMEBUFFER_COMPLETE);
|
|
76
|
+
const uint32_t framebuffer = context->bound_framebuffer_id();
|
|
77
|
+
if (framebuffer == 0) return xt_number(GL_FRAMEBUFFER_COMPLETE);
|
|
78
|
+
return xt_number(context->framebuffer_status(framebuffer) ? GL_FRAMEBUFFER_COMPLETE
|
|
79
|
+
: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
METHOD(webgl_create_renderbuffer) {
|
|
83
|
+
(void)env;
|
|
84
|
+
(void)argc;
|
|
85
|
+
(void)argv;
|
|
86
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
87
|
+
if (context == nullptr) return XT_NULL;
|
|
88
|
+
return webgl_make_object(self, "__xt_gl_renderbuffer", context->create_renderbuffer(),
|
|
89
|
+
"renderbuffer");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
METHOD(webgl_delete_renderbuffer) {
|
|
93
|
+
(void)env;
|
|
94
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
95
|
+
if (context != nullptr) {
|
|
96
|
+
context->delete_renderbuffer(webgl_object_id(xt_arg(argc, argv, 0), "__xt_gl_renderbuffer"));
|
|
97
|
+
}
|
|
98
|
+
return XT_UNDEFINED;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
METHOD(webgl_bind_renderbuffer) {
|
|
102
|
+
(void)env;
|
|
103
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
104
|
+
if (context != nullptr) {
|
|
105
|
+
context->bind_renderbuffer(webgl_object_id(xt_arg(argc, argv, 1), "__xt_gl_renderbuffer"));
|
|
106
|
+
}
|
|
107
|
+
return XT_UNDEFINED;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
METHOD(webgl_renderbuffer_storage) {
|
|
111
|
+
(void)env;
|
|
112
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
113
|
+
if (context != nullptr) {
|
|
114
|
+
context->renderbuffer_storage(context->bound_renderbuffer_id(), webgl_int(argc, argv, 3, 0),
|
|
115
|
+
webgl_int(argc, argv, 4, 0), false);
|
|
116
|
+
}
|
|
117
|
+
return XT_UNDEFINED;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
METHOD(webgl_framebuffer_renderbuffer) {
|
|
121
|
+
(void)env;
|
|
122
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
123
|
+
if (context != nullptr) {
|
|
124
|
+
context->framebuffer_renderbuffer(
|
|
125
|
+
context->bound_framebuffer_id(),
|
|
126
|
+
webgl_object_id(xt_arg(argc, argv, 3), "__xt_gl_renderbuffer"));
|
|
127
|
+
}
|
|
128
|
+
return XT_UNDEFINED;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
METHOD(webgl_get_renderbuffer_parameter) {
|
|
132
|
+
(void)env;
|
|
133
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
134
|
+
if (context == nullptr) return xt_number(0);
|
|
135
|
+
xtgui::WebGLRenderbuffer *renderbuffer = context->renderbuffer(context->bound_renderbuffer_id());
|
|
136
|
+
if (renderbuffer == nullptr) return xt_number(0);
|
|
137
|
+
const int pname = webgl_int(argc, argv, 1, 0);
|
|
138
|
+
if (pname == GL_RENDERBUFFER_WIDTH) return xt_number(renderbuffer->width);
|
|
139
|
+
if (pname == GL_RENDERBUFFER_HEIGHT) return xt_number(renderbuffer->height);
|
|
140
|
+
return xt_number(0);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
METHOD(webgl_read_pixels) {
|
|
144
|
+
(void)env;
|
|
145
|
+
xtgui::WebGLContext *context = context_of(self);
|
|
146
|
+
if (context == nullptr) return XT_UNDEFINED;
|
|
147
|
+
const int x = webgl_int(argc, argv, 0, 0);
|
|
148
|
+
const int y = webgl_int(argc, argv, 1, 0);
|
|
149
|
+
const int width = webgl_int(argc, argv, 2, 0);
|
|
150
|
+
const int height = webgl_int(argc, argv, 3, 0);
|
|
151
|
+
const int format = webgl_int(argc, argv, 4, GL_RGBA);
|
|
152
|
+
const int type = webgl_int(argc, argv, 5, GL_UNSIGNED_BYTE);
|
|
153
|
+
if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) return XT_UNDEFINED;
|
|
154
|
+
std::vector<uint8_t> pixels((size_t)width * height * 4);
|
|
155
|
+
if (!context->read_pixels(x, y, width, height, pixels.data())) return XT_UNDEFINED;
|
|
156
|
+
webgl_write_bytes(xt_arg(argc, argv, 6), pixels.data(), pixels.size());
|
|
157
|
+
return XT_UNDEFINED;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
} // namespace domapi
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
namespace domapi {
|
|
15
15
|
namespace {
|
|
16
16
|
|
|
17
|
-
xtgui::WebGLContext *context_of(xt_value self) { return
|
|
17
|
+
xtgui::WebGLContext *context_of(xt_value self) { return webgl_live_context(self); }
|
|
18
18
|
|
|
19
19
|
xt_value shader_argument(xt_value value) {
|
|
20
20
|
return webgl_object_id(value, "__xt_gl_shader");
|
|
@@ -295,7 +295,7 @@ METHOD(webgl_get_uniform) {
|
|
|
295
295
|
namespace {
|
|
296
296
|
|
|
297
297
|
void uniform_scalars(xt_value self, int32_t argc, xt_value *argv, int components, bool integer) {
|
|
298
|
-
xtgui::WebGLContext *context =
|
|
298
|
+
xtgui::WebGLContext *context = webgl_live_context(self);
|
|
299
299
|
if (context == nullptr) return;
|
|
300
300
|
uint32_t program = 0;
|
|
301
301
|
int location = 0;
|
|
@@ -312,7 +312,7 @@ void uniform_scalars(xt_value self, int32_t argc, xt_value *argv, int components
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
void uniform_vectors(xt_value self, int32_t argc, xt_value *argv, int components, bool integer) {
|
|
315
|
-
xtgui::WebGLContext *context =
|
|
315
|
+
xtgui::WebGLContext *context = webgl_live_context(self);
|
|
316
316
|
if (context == nullptr) return;
|
|
317
317
|
uint32_t program = 0;
|
|
318
318
|
int location = 0;
|
|
@@ -400,7 +400,7 @@ METHOD(webgl_uniform4iv) {
|
|
|
400
400
|
namespace {
|
|
401
401
|
|
|
402
402
|
void uniform_matrix(xt_value self, int32_t argc, xt_value *argv, int dimensions) {
|
|
403
|
-
xtgui::WebGLContext *context =
|
|
403
|
+
xtgui::WebGLContext *context = webgl_live_context(self);
|
|
404
404
|
if (context == nullptr) return;
|
|
405
405
|
uint32_t program = 0;
|
|
406
406
|
int location = 0;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — WebGL pixel sources.
|
|
3
|
+
*
|
|
4
|
+
* Decodes the things `texImage2D` accepts (`<img>`, `<canvas>`, `<video>`,
|
|
5
|
+
* `ImageData` and `ImageBitmap`) into tightly packed RGBA8, and converts the
|
|
6
|
+
* RGBA/RGB/LUMINANCE families to that layout.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "dom_api_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <cstring>
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include "dom_api_webgl_rt.h"
|
|
16
|
+
#include "image.h"
|
|
17
|
+
#include "image_bitmap.h"
|
|
18
|
+
#include "webgl.h"
|
|
19
|
+
|
|
20
|
+
namespace domapi {
|
|
21
|
+
namespace {
|
|
22
|
+
|
|
23
|
+
void flip_rows(std::vector<uint8_t> *pixels, int width, int height) {
|
|
24
|
+
const size_t stride = (size_t)width * 4;
|
|
25
|
+
std::vector<uint8_t> row(stride);
|
|
26
|
+
for (int y = 0; y < height / 2; y++) {
|
|
27
|
+
uint8_t *top = pixels->data() + (size_t)y * stride;
|
|
28
|
+
uint8_t *bottom = pixels->data() + (size_t)(height - 1 - y) * stride;
|
|
29
|
+
memcpy(row.data(), top, stride);
|
|
30
|
+
memcpy(top, bottom, stride);
|
|
31
|
+
memcpy(bottom, row.data(), stride);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
} // namespace
|
|
36
|
+
|
|
37
|
+
void webgl_convert_pixels(const uint8_t *source, int count, int format, bool premultiply,
|
|
38
|
+
std::vector<uint8_t> *out) {
|
|
39
|
+
out->assign((size_t)count * 4, 255);
|
|
40
|
+
for (int i = 0; i < count; i++) {
|
|
41
|
+
uint8_t r = 0;
|
|
42
|
+
uint8_t g = 0;
|
|
43
|
+
uint8_t b = 0;
|
|
44
|
+
uint8_t a = 255;
|
|
45
|
+
switch (format) {
|
|
46
|
+
case GL_RGBA:
|
|
47
|
+
r = source[i * 4 + 0];
|
|
48
|
+
g = source[i * 4 + 1];
|
|
49
|
+
b = source[i * 4 + 2];
|
|
50
|
+
a = source[i * 4 + 3];
|
|
51
|
+
break;
|
|
52
|
+
case GL_RGB:
|
|
53
|
+
r = source[i * 3 + 0];
|
|
54
|
+
g = source[i * 3 + 1];
|
|
55
|
+
b = source[i * 3 + 2];
|
|
56
|
+
break;
|
|
57
|
+
case GL_LUMINANCE_ALPHA:
|
|
58
|
+
r = g = b = source[i * 2 + 0];
|
|
59
|
+
a = source[i * 2 + 1];
|
|
60
|
+
break;
|
|
61
|
+
case GL_ALPHA:
|
|
62
|
+
a = source[i];
|
|
63
|
+
r = g = b = 0;
|
|
64
|
+
break;
|
|
65
|
+
case GL_LUMINANCE:
|
|
66
|
+
default:
|
|
67
|
+
r = g = b = source[i];
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
if (premultiply) {
|
|
71
|
+
r = (uint8_t)((r * a + 127) / 255);
|
|
72
|
+
g = (uint8_t)((g * a + 127) / 255);
|
|
73
|
+
b = (uint8_t)((b * a + 127) / 255);
|
|
74
|
+
}
|
|
75
|
+
(*out)[(size_t)i * 4 + 0] = r;
|
|
76
|
+
(*out)[(size_t)i * 4 + 1] = g;
|
|
77
|
+
(*out)[(size_t)i * 4 + 2] = b;
|
|
78
|
+
(*out)[(size_t)i * 4 + 3] = a;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/** Decode a DOM source into top-down RGBA8. */
|
|
84
|
+
bool webgl_read_source(xt_value source, int *width, int *height, std::vector<uint8_t> *rgba,
|
|
85
|
+
bool premultiply) {
|
|
86
|
+
if (XT_IS_OBJECT(source)) {
|
|
87
|
+
xt_value bitmap_id = xt_object_get_cstr(source, "__xt_bitmap");
|
|
88
|
+
if (XT_IS_NUMBER(bitmap_id)) {
|
|
89
|
+
const xtgui::Image *bitmap =
|
|
90
|
+
xtgui::xt_image_bitmap_get((uint64_t)xt_to_number(bitmap_id));
|
|
91
|
+
if (bitmap == nullptr || bitmap->width <= 0 || bitmap->height <= 0) return false;
|
|
92
|
+
*width = bitmap->width;
|
|
93
|
+
*height = bitmap->height;
|
|
94
|
+
if (premultiply) {
|
|
95
|
+
webgl_convert_pixels(bitmap->pixels.data(), bitmap->width * bitmap->height, GL_RGBA, true,
|
|
96
|
+
rgba);
|
|
97
|
+
} else {
|
|
98
|
+
*rgba = bitmap->pixels;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
XtGuiWindow *win = nullptr;
|
|
104
|
+
xtgui::Node *node = resolve_node(source, &win);
|
|
105
|
+
const xtgui::Image *image = nullptr;
|
|
106
|
+
std::vector<uint8_t> owned;
|
|
107
|
+
if (node != nullptr && node->isElement() && node->isTag("img")) {
|
|
108
|
+
const std::string *src = node->attr("src");
|
|
109
|
+
if (src != nullptr) image = xtgui::xt_image_load(*src);
|
|
110
|
+
} else if (node != nullptr && node->isElement() && node->isTag("video")) {
|
|
111
|
+
xtgui::MediaPlayer *player = xt_gui_media_player(win, node);
|
|
112
|
+
if (player != nullptr) image = player->frame();
|
|
113
|
+
} else if (node != nullptr && node->isElement() && node->isTag("canvas")) {
|
|
114
|
+
if (xtgui::Canvas2D *canvas = xt_gui_canvas_find(win, node)) {
|
|
115
|
+
image = &canvas->image();
|
|
116
|
+
} else if (xtgui::WebGLContext *context = xt_gui_webgl_find(win, node)) {
|
|
117
|
+
owned.resize((size_t)context->width() * context->height() * 4);
|
|
118
|
+
if (!context->read_pixels(0, 0, context->width(), context->height(), owned.data())) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
/* `readPixels` is GL-ordered (bottom-up); textures are stored top-down. */
|
|
122
|
+
flip_rows(&owned, context->width(), context->height());
|
|
123
|
+
*width = context->width();
|
|
124
|
+
*height = context->height();
|
|
125
|
+
rgba->swap(owned);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
} else if (XT_IS_OBJECT(source) && !xt_is_array_buffer(source)) {
|
|
129
|
+
xt_value data = xt_object_get_cstr(source, "data");
|
|
130
|
+
xt_value width_value = xt_object_get_cstr(source, "width");
|
|
131
|
+
xt_value height_value = xt_object_get_cstr(source, "height");
|
|
132
|
+
if (XT_IS_OBJECT(data) && XT_IS_NUMBER(width_value) && XT_IS_NUMBER(height_value)) {
|
|
133
|
+
const int w = (int)xt_to_number(width_value);
|
|
134
|
+
const int h = (int)xt_to_number(height_value);
|
|
135
|
+
const std::vector<uint8_t> bytes = webgl_bytes(data);
|
|
136
|
+
if (w <= 0 || h <= 0 || bytes.size() < (size_t)w * h * 4) return false;
|
|
137
|
+
webgl_convert_pixels(bytes.data(), w * h, GL_RGBA, premultiply, rgba);
|
|
138
|
+
*width = w;
|
|
139
|
+
*height = h;
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
/* `new Image()` is a plain object with a `src`. */
|
|
143
|
+
xt_value src = xt_object_get_cstr(source, "src");
|
|
144
|
+
if (XT_IS_STRING(src)) {
|
|
145
|
+
const char *path = xt_string_data(xt_to_string(src));
|
|
146
|
+
if (path != nullptr && path[0] != '\0') image = xtgui::xt_image_load(path);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (image == nullptr || image->width <= 0 || image->height <= 0) return false;
|
|
150
|
+
*width = image->width;
|
|
151
|
+
*height = image->height;
|
|
152
|
+
if (premultiply) {
|
|
153
|
+
webgl_convert_pixels(image->pixels.data(), image->width * image->height, GL_RGBA, true, rgba);
|
|
154
|
+
} else {
|
|
155
|
+
*rgba = image->pixels;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
} // namespace domapi
|