xbintsc 0.5.37 → 0.5.38
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/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/state.js +1 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +1 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/deferred.d.ts +63 -0
- package/dist/src/driver/bundler/deferred.js +279 -0
- package/dist/src/driver/bundler/deferred.js.map +1 -0
- package/dist/src/driver/bundler/merge.js +214 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.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/html.js +89 -13
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +1 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +4 -3
- package/dist/src/extensions/gui/three.js +4 -3
- package/dist/src/extensions/gui/three.js.map +1 -1
- package/dist/tests/e2e/gui-script-import-order.test.d.ts +10 -0
- package/dist/tests/e2e/gui-script-import-order.test.js +161 -0
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js +108 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js.map +1 -0
- package/dist/tests/e2e/url.test.d.ts +6 -0
- package/dist/tests/e2e/url.test.js +114 -0
- package/dist/tests/e2e/url.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +22 -10
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/doc/gui/webgl.md +20 -10
- package/doc/gui-scripts.md +19 -19
- package/doc/gui.md +10 -8
- package/doc/implemented/fetch.md +5 -0
- package/doc/implemented/modules.md +13 -0
- package/doc/implemented/stdlib.md +17 -0
- package/doc/unimplemented/deviations.md +1 -0
- package/doc/zh-CN/gui/webgl.md +3 -3
- package/doc/zh-CN/gui-scripts.md +14 -13
- package/doc/zh-CN/gui.md +7 -6
- package/doc/zh-CN/implemented/fetch.md +4 -0
- package/doc/zh-CN/implemented/modules.md +10 -0
- package/doc/zh-CN/implemented/stdlib.md +15 -0
- package/doc/zh-CN/unimplemented/deviations.md +1 -0
- package/package.json +7 -7
- package/runtime/ext_gui/dom_api_webgl.cpp +10 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +33 -1
- package/runtime/ext_gui/gui_engine.h +2 -0
- package/runtime/ext_gui/script.cpp +31 -0
- package/runtime/ext_gui/webgl_glsl.h +3 -0
- package/runtime/ext_gui/webgl_glsl_unroll.cpp +283 -0
- package/runtime/ext_gui/webgl_msl.cpp +4 -0
- package/runtime/ext_gui/webgl_shader.cpp +12 -6
- package/runtime/rt.h +3 -0
- package/runtime/xt_fetch/async.inc +60 -0
- package/runtime/xt_url_object.c +463 -0
- package/src/codegen/generator/state.ts +1 -0
- package/src/codegen/generator/tables.ts +1 -0
- package/src/driver/bundler/deferred.ts +351 -0
- package/src/driver/bundler/merge.ts +219 -2
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +91 -15
- package/src/extensions/gui/index.ts +1 -0
- package/src/extensions/gui/three.ts +4 -3
package/doc/gui/webgl.md
CHANGED
|
@@ -23,8 +23,11 @@ display.
|
|
|
23
23
|
Both **WebGL 1.0** and **WebGL 2.0** are available. A canvas keeps the first
|
|
24
24
|
context kind it asks for: after `getContext("webgl2")` a later
|
|
25
25
|
`getContext("webgl")` answers `null`, and the other way round. A WebGL 2 context
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
has its own `WebGL2RenderingContext` prototype (with a copy of the WebGL 1
|
|
27
|
+
constants and methods), so `gl instanceof WebGL2RenderingContext` is true while
|
|
28
|
+
`gl instanceof WebGLRenderingContext` is false, like a browser — libraries such
|
|
29
|
+
as three.js use exactly that check to pick their WebGL 2 path. `gl.constructor.name`
|
|
30
|
+
reports the type as well.
|
|
28
31
|
|
|
29
32
|
## How a frame reaches the screen
|
|
30
33
|
|
|
@@ -54,8 +57,9 @@ format, so the engine ships two statically linked translators:
|
|
|
54
57
|
|
|
55
58
|
- **glslang** compiles the rewritten GLSL to SPIR-V, which the Vulkan backend
|
|
56
59
|
consumes directly;
|
|
57
|
-
- **SPIRV-Cross** cross-compiles that same SPIR-V to Metal Shading Language
|
|
58
|
-
which the Metal backend
|
|
60
|
+
- **SPIRV-Cross** cross-compiles that same SPIR-V to Metal Shading Language 2.0
|
|
61
|
+
text (needed for arrays of textures/samplers), which the Metal backend
|
|
62
|
+
compiles at run time.
|
|
59
63
|
|
|
60
64
|
Both live in `gui.a` / `gui.lib`; the Metal path reuses the SPIR-V module rather
|
|
61
65
|
than growing a second GLSL front end, so both backends accept exactly the same
|
|
@@ -96,9 +100,13 @@ reflected offsets; `uniform1i` on a sampler stores the texture unit. The block
|
|
|
96
100
|
is pushed with the dynamic uniform-buffer API on every draw.
|
|
97
101
|
|
|
98
102
|
Limits of the translator: struct-typed uniforms, user uniform blocks, uniform
|
|
99
|
-
arrays whose size is not resolved by the preprocessor,
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
arrays whose size is not resolved by the preprocessor, and a sampler array
|
|
104
|
+
indexed by a non-constant expression are rejected (the link/shader info log
|
|
105
|
+
says so). A `#pragma unroll_loop_start` loop is expanded before rewriting, so
|
|
106
|
+
the `sampler2D shadowMap[ NUM_DIR_LIGHT_SHADOWS ]` / `shadowMap[ i ]` shape
|
|
107
|
+
three.js emits becomes constant-indexed. Shader code inside `#ifdef` is fine;
|
|
108
|
+
non-sampler uniform declarations are moved to the enclosing top-level position
|
|
109
|
+
so the block stays unconditional.
|
|
102
110
|
|
|
103
111
|
### GLSL ES 3.00 (WebGL 2)
|
|
104
112
|
|
|
@@ -299,9 +307,11 @@ same assertions as the SPIR-V one.
|
|
|
299
307
|
|
|
300
308
|
## three.js
|
|
301
309
|
|
|
302
|
-
The
|
|
303
|
-
|
|
304
|
-
|
|
310
|
+
The shader rewriter expands three.js's `#pragma unroll_loop_start` loops into
|
|
311
|
+
constant indices (its sampler arrays would otherwise fail Vulkan GLSL), and the
|
|
312
|
+
`.js` asset loader keeps the renderer's own unroller out of the way.
|
|
313
|
+
`WebGLRenderer` runs unchanged on this engine's real WebGL 2 backend, so **no
|
|
314
|
+
Canvas2D fallback is bundled any more**. Verified with three.js r160 through SDL_GPU:
|
|
305
315
|
`MeshBasicMaterial`, `MeshStandardMaterial` and `MeshPhongMaterial`,
|
|
306
316
|
`CanvasTexture`, linear fog, ambient/directional/point/spot/hemisphere lights,
|
|
307
317
|
`Sprite`, `Line`, `Points` and `InstancedMesh`.
|
package/doc/gui-scripts.md
CHANGED
|
@@ -155,17 +155,18 @@ export default __html;
|
|
|
155
155
|
### 2b. External `<script src>`
|
|
156
156
|
|
|
157
157
|
`<script src="./app.ts">` is read relative to the HTML file, parsed, and split:
|
|
158
|
-
its top-level `import`/`export … from` statements are
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
its top-level `import`/`export … from` statements are removed from the body, and
|
|
159
|
+
the remaining statements are wrapped in the script function. Relative imports
|
|
160
|
+
are **deferred**, like a browser module script: the loader emits a synthetic
|
|
161
|
+
`__xt_deferred_module` marker and the generated script calls the module wrapper
|
|
162
|
+
at `loadHTML` time. The bundler wraps the whole local import graph in functions
|
|
163
|
+
that return their exports (memoised by `__xt_defer`), so top-level module code
|
|
164
|
+
runs after the document exists and two scripts importing the same module share
|
|
165
|
+
one instance. Bare specifiers (`gui`, a package) stay eager.
|
|
166
|
+
|
|
167
|
+
A missing `src` file is still a clear error (turned into a bundler diagnostic),
|
|
168
|
+
and `src` URLs (`https://…`, `data:…`, `//host`) are left untouched — they are
|
|
169
|
+
not compile-time assets and never run.
|
|
169
170
|
|
|
170
171
|
`src` URLs (`https://…`, `data:…`, `//host`) are left untouched — they are not
|
|
171
172
|
compile-time assets and never run.
|
|
@@ -302,11 +303,11 @@ legacy `target` field over the handle.
|
|
|
302
303
|
- **M9b** ✅ — gui `.html` loader (`src/extensions/gui/html.ts`), the
|
|
303
304
|
`__registerScript` builtin, the script registry (`runtime/ext_gui/script.cpp`),
|
|
304
305
|
`loadHTML` execution and `DOMContentLoaded`/`load`; e2e coverage.
|
|
305
|
-
- **M9c** ✅ — `<script src>` files are read
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
306
|
+
- **M9c** ✅ — `<script src>` files are read and their body is wrapped and
|
|
307
|
+
registered; relative imports are deferred and evaluated by a memoised
|
|
308
|
+
module wrapper at `loadHTML` time, so the import graph sees a parsed
|
|
309
|
+
document and shares one instance per module. Missing files surface as
|
|
310
|
+
diagnostics. All scripts run in document order. e2e coverage.
|
|
310
311
|
- **M9d** *(optional)* — detect inline HTML in template literals passed to
|
|
311
312
|
`win.loadHTML(...)` and transform them too (fragile; deferred).
|
|
312
313
|
- **M10 — polish** ✅ — `requestAnimationFrame`/`cancelAnimationFrame` on the
|
|
@@ -330,9 +331,8 @@ legacy `target` field over the handle.
|
|
|
330
331
|
network fetches) do not run. Documented.
|
|
331
332
|
- **Template-literal HTML** passed to `win.loadHTML(…)` is not transformed in
|
|
332
333
|
M9b (only imported assets are). M9d addresses this if needed.
|
|
333
|
-
- **
|
|
334
|
-
|
|
335
|
-
is possible later.
|
|
334
|
+
- **Top-level `await`** inside a deferred `<script src>` module is not
|
|
335
|
+
supported: the module body is wrapped in a synchronous init function.
|
|
336
336
|
- **Assets.** `<script src>` is resolved relative to the HTML asset; URL `src`
|
|
337
337
|
values are ignored. There is no fetch/network loading.
|
|
338
338
|
|
package/doc/gui.md
CHANGED
|
@@ -219,10 +219,11 @@ engine were Rust.
|
|
|
219
219
|
registered through the `__registerScript` builtin and replaced by
|
|
220
220
|
`<script data-xt-id="<hash>">` markers; `win.loadHTML` runs the matching
|
|
221
221
|
functions after parsing and fires `DOMContentLoaded` then `load`.
|
|
222
|
-
- **M9c** ✅ — `<script src>` files are read relative to the HTML
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
- **M9c** ✅ — `<script src>` files are read relative to the HTML and their
|
|
223
|
+
body is wrapped/registered; relative imports are deferred to `loadHTML`
|
|
224
|
+
through a memoised module wrapper, so imported modules see the parsed
|
|
225
|
+
document and share state. Missing files become diagnostics. Everything
|
|
226
|
+
runs in document order.
|
|
226
227
|
10. **M10 — polish** ✅
|
|
227
228
|
- `win.requestAnimationFrame(fn)` / `win.cancelAnimationFrame(id)`; callbacks
|
|
228
229
|
run at the top of each frame with the frame timestamp and may mutate the
|
|
@@ -387,10 +388,11 @@ engine were Rust.
|
|
|
387
388
|
bodies into AOT functions registered at startup and run by `win.loadHTML`
|
|
388
389
|
(before first layout; `DOMContentLoaded` then `load`). Unit tests in
|
|
389
390
|
`tests/extensions/gui.test.ts`, e2e in `tests/e2e/gui-*.test.ts`.
|
|
390
|
-
- **M9c** ✅ external `<script src>` files are read
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
caught by `loadGraph`
|
|
391
|
+
- **M9c** ✅ external `<script src>` files are read and their body
|
|
392
|
+
wrapped/registered; relative imports are deferred to `loadHTML` through a
|
|
393
|
+
memoised module wrapper (so module-level DOM work sees the parsed document),
|
|
394
|
+
while missing files are diagnostics. Loader errors are caught by `loadGraph`
|
|
395
|
+
and reported as build errors.
|
|
394
396
|
- **M10** ✅ `requestAnimationFrame`/`cancelAnimationFrame` on window handles
|
|
395
397
|
(callbacks run with the frame timestamp before layout each frame) plus
|
|
396
398
|
`offsetWidth`/`offsetHeight`/`contains` on element handles; e2e coverage in
|
package/doc/implemented/fetch.md
CHANGED
|
@@ -13,6 +13,11 @@ Location: `runtime/xt_fetch.c`, `runtime/xt_fetch/async.inc`, `runtime/xt_async_
|
|
|
13
13
|
exchange, up to 20 redirects, and a 301/302/303 switches POST to GET.
|
|
14
14
|
- It accepts `http://` URLs only — `https://` rejects with a `TypeError` because
|
|
15
15
|
no TLS backend is linked.
|
|
16
|
+
- A reference with **no scheme** (a relative path) and `file://` URLs read a
|
|
17
|
+
local file, so a compiled program can load an asset from disk without an HTTP
|
|
18
|
+
server. Relative paths resolve against the working directory; `GET` / `HEAD`
|
|
19
|
+
are supported. On Windows the standard `file:///C:/dir/file` spelling and
|
|
20
|
+
`file://C:/dir/file` / `file://C:\dir\file` all name the same file.
|
|
16
21
|
- Options: `method`, `headers` (plain object or `Headers`), `body` and `redirect`
|
|
17
22
|
(`follow` / `manual` / `error`).
|
|
18
23
|
- The resolved `Response`-shaped object exposes `ok` / `status` / `statusText` /
|
|
@@ -19,6 +19,19 @@ Location: `src/parser/parser.ts` (syntax), `src/driver/modules.ts` (bundling),
|
|
|
19
19
|
- Imported bindings and namespace members are snapshots at module-evaluation time (no live bindings) — see [Unimplemented: module system](../unimplemented/modules.md).
|
|
20
20
|
- Type-only imports and re-exports (`import type { T } from "..."`, `import { type T } from "..."`, `export type { T } from "..."`) are erased. They are **not** module edges: the target is not loaded or bundled, and a type-only cycle between modules is not a circular dependency. Use a side-effect import (`import "./mod"`) when a module must be evaluated without binding a name.
|
|
21
21
|
|
|
22
|
+
## Deferred evaluation
|
|
23
|
+
|
|
24
|
+
- The `gui` `.html` asset loader marks relative `<script src>` imports with a
|
|
25
|
+
synthetic `__xt_deferred_module` binding. The bundler then wraps that module
|
|
26
|
+
and its local import graph in functions that return their exports, and the
|
|
27
|
+
generated script calls them after `loadHTML` (`__xt_defer` memoises each
|
|
28
|
+
module). This matches a browser module script, where the graph is evaluated
|
|
29
|
+
once the document exists.
|
|
30
|
+
- Modules also reachable through a normal (non-marker) import stay eager and get
|
|
31
|
+
a thin wrapper over their already-initialised exports.
|
|
32
|
+
- The wrapper body is synchronous: top-level `await` inside a deferred script
|
|
33
|
+
module is not supported.
|
|
34
|
+
|
|
22
35
|
## import.meta
|
|
23
36
|
|
|
24
37
|
- `import.meta.url` / `.dirname` / `.filename`, resolved from the running executable's path.
|
|
@@ -55,6 +55,23 @@ own pages: [Collections](./collections.md), [Typed arrays and binary data](./typ
|
|
|
55
55
|
- `Symbol(description)` primitives (`XT_OBJECT_KIND_SYMBOL`), the 13 well-known symbols (`Symbol.iterator`, `Symbol.asyncIterator`, `Symbol.match`, ...), `Symbol.for` / `Symbol.keyFor` global registry, `symbol.description` / `toString()` / `valueOf()`.
|
|
56
56
|
- Symbols are valid property keys (`Object.getOwnPropertySymbols`, symbol keyed `get`/`set`/`in`/`delete`), are skipped by `Object.keys` / `values` / `entries` / `for...in` / `JSON.stringify`, and print as `Symbol(desc)`.
|
|
57
57
|
|
|
58
|
+
## URL
|
|
59
|
+
|
|
60
|
+
- `URL` is implemented in `runtime/xt_url_object.c`: `new URL(input)` and
|
|
61
|
+
`new URL(input, base)` (the base may be another `URL`), resolving relative
|
|
62
|
+
references against a hierarchical `scheme://authority/path` base.
|
|
63
|
+
- A reference with **no scheme is a filesystem path**: `new URL("./model.glb")`
|
|
64
|
+
resolves against the working directory and yields a `file:` URL (an explicit
|
|
65
|
+
base is still honoured, so `new URL("./x", import.meta.url)` works too).
|
|
66
|
+
- Read-only `href`, `protocol`, `origin`, `host`, `hostname`, `port`,
|
|
67
|
+
`pathname`, `search`, `hash`, `searchParams` and `toString()` / `toJSON()`;
|
|
68
|
+
absolute inputs are kept as written, except that the Windows spellings of a
|
|
69
|
+
`file:` URL (`file://C:/dir` and `file://C:\dir`) are canonicalized to
|
|
70
|
+
`file:///C:/dir`, matching Node.
|
|
71
|
+
- Not a full WHATWG parser: path percent-encoding, IDNA, setters and live
|
|
72
|
+
`searchParams` synchronisation are not implemented — see
|
|
73
|
+
[Runtime deviations](../unimplemented/deviations.md).
|
|
74
|
+
|
|
58
75
|
## URLSearchParams
|
|
59
76
|
|
|
60
77
|
- `URLSearchParams` is implemented in `runtime/xt_url.c`.
|
|
@@ -8,6 +8,7 @@ These features **compile and run**, but the result does not fully match ECMAScri
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| RegExp byte-oriented matching | The engine matches UTF-8 bytes: literal multi-byte text works, but `.` and character classes consume one byte per repetition (`\d` / `\w` stay ASCII). Offsets returned by `exec` / `search` / replacement callbacks are converted to UTF-16 code units |
|
|
10
10
|
| Global RegExp `lastIndex` | `test` / `exec` do not advance or honour a caller-set `lastIndex` for `/g` / `/y` regexes |
|
|
11
|
+
| `URL` parser | Read-only WHATWG subset: no path percent-encoding, IDNA, setters or live `searchParams`; a reference with no scheme resolves against the working directory as a `file:` URL |
|
|
11
12
|
| String `normalize` | Not implemented |
|
|
12
13
|
| First-class built-in methods | Implemented as unbound method values (see [Functions](./functions.md)); `fn.toString()` returns a placeholder rather than source text |
|
|
13
14
|
| `for...in` | Enumerates own keys of objects / arrays / strings; does not include prototype-chain properties |
|
package/doc/zh-CN/gui/webgl.md
CHANGED
|
@@ -16,7 +16,7 @@ if (gl == null) {
|
|
|
16
16
|
|
|
17
17
|
2D 上下文把图形光栅化到 CPU 位图再上传为纹理;WebGL 上下文则**在 GPU 上渲染**:顶点变换、光照、纹理采样、深度测试与混合全部在 SDL_GPU 管线中执行(Windows/Linux 上是 Vulkan,macOS 上是 Metal)。页面直接合成该上下文的颜色纹理,因此显示时不需要把像素读回 CPU。
|
|
18
18
|
|
|
19
|
-
同时提供 **WebGL 1.0** 与 **WebGL 2.0**。一个 canvas 会固定为它第一次申请的上下文类型:先调用 `getContext("webgl2")` 之后,`getContext("webgl")` 返回 `null`,反之亦然。WebGL 2
|
|
19
|
+
同时提供 **WebGL 1.0** 与 **WebGL 2.0**。一个 canvas 会固定为它第一次申请的上下文类型:先调用 `getContext("webgl2")` 之后,`getContext("webgl")` 返回 `null`,反之亦然。WebGL 2 上下文拥有自己的 `WebGL2RenderingContext` 原型(其中复制了 WebGL 1 的常量与方法),因此 `gl instanceof WebGL2RenderingContext` 为真,而 `gl instanceof WebGLRenderingContext` 为假,与浏览器一致——three.js 等库正是据此选择 WebGL 2 路径。`gl.constructor.name` 也会报告对应类型名。
|
|
20
20
|
|
|
21
21
|
## 一帧如何到达屏幕
|
|
22
22
|
|
|
@@ -53,7 +53,7 @@ SDL_GPU 不能在运行时编译 GLSL,且每个后端只消费自己的格式
|
|
|
53
53
|
| `gl_FragData[0]` | `xt_FragColor` |
|
|
54
54
|
| 缺少 `#version` / `#version 100` | `#version 310 es` |
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
实现限制:结构体 uniform、用户 uniform 块、预处理阶段无法确定长度的 uniform 数组,以及用非常量表达式索引的采样器数组会被拒绝(shader/link info log 会说明)。`#pragma unroll_loop_start` 循环会在改写前展开,因此 three.js 生成的 `sampler2D shadowMap[ NUM_DIR_LIGHT_SHADOWS ]` / `shadowMap[ i ]` 会变成常量索引。`#ifdef` 内的着色器代码可用;非采样器 uniform 声明会被移动到顶层,保证块保持无条件。两个阶段的非采样器 uniform 会合并成同一个块,并在每个阶段各声明一次(顶点 set 1、片元 set 3),与 SDL_GPU 的 Vulkan 描述符布局一致。在 Metal 上同一批声明会变成 `[[buffer(0)]]` 与 `[[texture(N)]]`/`[[sampler(N)]]`,正是 SDL_GPU Metal 后端绑定的槽位。`uniformMatrix4fv` 按列主序写入反射出的偏移;对采样器调用 `uniform1i` 时记录纹理单元。每次绘制都用动态 uniform 缓冲接口推送该块。
|
|
57
57
|
|
|
58
58
|
翻译器的限制:结构体 uniform、用户 uniform 块、预处理后仍无法确定长度的 uniform 数组、采样器数组与采样器类型不匹配的声明会被拒绝(着色器/链接日志会说明)。`#ifdef` 内的代码没问题;非采样器 uniform 声明会被移到外层顶层位置,保证块是无条件的。
|
|
59
59
|
|
|
@@ -116,6 +116,6 @@ transform feedback(入口为空操作)与 MSAA/采样缓冲(SDL_GPU 的 Me
|
|
|
116
116
|
|
|
117
117
|
## three.js
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
着色器改写器会把 three.js 的 `#pragma unroll_loop_start` 循环展开为常量索引(否则其采样器数组无法通过 Vulkan GLSL),`.js` 资源加载器则避免渲染器自带的展开器重复处理。`WebGLRenderer` 在本引擎真正的 WebGL 2 后端上原样运行,**不再打包 Canvas2D 回退**。已用 three.js r160 通过 SDL_GPU 验证:`MeshBasicMaterial`、`MeshStandardMaterial`、`MeshPhongMaterial`、`CanvasTexture`、线性雾、环境光/平行光/点光/聚光/半球光、`Sprite`、`Line`、`Points` 与 `InstancedMesh`。
|
|
120
120
|
|
|
121
121
|
本引擎子集之外的能力仍无法模拟:transform feedback 与 MSAA;立方体贴图/环境贴图、深度纹理、HDR/浮点渲染目标与压缩纹理已经可用。需要这些能力的场景无法正确渲染;此前 Canvas2D 回退能显示的内容现在全部走 GPU。
|
package/doc/zh-CN/gui-scripts.md
CHANGED
|
@@ -146,15 +146,16 @@ export default __html;
|
|
|
146
146
|
### 2b. 外部 `<script src>`
|
|
147
147
|
|
|
148
148
|
`<script src="./app.ts">` 相对 HTML 文件读取、解析并拆分:其顶层
|
|
149
|
-
`import`/`export … from`
|
|
150
|
-
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
`import`/`export … from` 语句从主体中移除,其余语句被包装进脚本函数。相对
|
|
150
|
+
import 会像浏览器的模块脚本一样**延迟**:loader 生成一个合成的
|
|
151
|
+
`__xt_deferred_module` 标记,生成的脚本在 `loadHTML` 时调用模块包装函数。
|
|
152
|
+
bundler 把整个本地 import 图包装成返回各自导出的函数(由 `__xt_defer`
|
|
153
|
+
记忆化),因此模块顶层代码在文档就绪后才运行,且两个脚本导入同一模块时共享
|
|
154
|
+
同一个实例。裸说明符(`gui`、npm 包)仍然立即加载。
|
|
155
|
+
|
|
156
|
+
缺失的 `src` 文件仍会抛出清晰的错误(被转换为 bundler 诊断);
|
|
157
|
+
`src` URL(`https://…`、`data:…`、`//host`)保持原样 —— 它们不是编译期资产,
|
|
158
|
+
永不运行。
|
|
158
159
|
|
|
159
160
|
`src` URL(`https://…`、`data:…`、`//host`)保持原样 —— 它们不是编译期资产,
|
|
160
161
|
永不运行。
|
|
@@ -283,10 +284,10 @@ Event 的 `target` 是句柄,其描述符(`toString`)与同一 `div#id.cla
|
|
|
283
284
|
- **M9b** ✅ —— gui `.html` 加载器(`src/extensions/gui/html.ts`)、
|
|
284
285
|
`__registerScript` 内置函数、脚本注册表(`runtime/ext_gui/script.cpp`)、
|
|
285
286
|
`loadHTML` 执行与 `DOMContentLoaded`/`load`;e2e 覆盖。
|
|
286
|
-
- **M9c** ✅ —— 读取 `<script src>`
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
覆盖。
|
|
287
|
+
- **M9c** ✅ —— 读取 `<script src>` 文件,其主体被包装并注册;相对 import
|
|
288
|
+
通过带记忆化的模块包装函数延迟到 `loadHTML` 求值,因此 import 图能看到
|
|
289
|
+
已解析的文档,且同一模块只实例化一次。缺失文件作为诊断浮现。所有脚本按
|
|
290
|
+
文档顺序运行。e2e 覆盖。
|
|
290
291
|
- **M9d** *(可选)* —— 检测传给 `win.loadHTML(...)` 的模板字面量中的内联
|
|
291
292
|
HTML 并同样转换它们(脆弱;推迟)。
|
|
292
293
|
- **M10 — 打磨** ✅ —— 窗口上的
|
package/doc/zh-CN/gui.md
CHANGED
|
@@ -167,9 +167,10 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
|
|
|
167
167
|
`__registerScript` 内置函数注册,并替换为
|
|
168
168
|
`<script data-xt-id="<hash>">` 标记;`win.loadHTML` 在解析后运行匹配的
|
|
169
169
|
函数并触发 `DOMContentLoaded` 然后是 `load`。
|
|
170
|
-
- **M9c** ✅ —— `<script src>` 文件相对 HTML
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
- **M9c** ✅ —— `<script src>` 文件相对 HTML 读取,其主体被包装/注册;
|
|
171
|
+
相对 import 通过带记忆化的模块包装函数延迟到 `loadHTML` 求值,因此被导入
|
|
172
|
+
模块能看到已解析的文档并共享状态。缺失文件会成为诊断。一切都按文档顺序
|
|
173
|
+
运行。
|
|
173
174
|
10. **M10 — 打磨** ✅
|
|
174
175
|
- `win.requestAnimationFrame(fn)` / `win.cancelAnimationFrame(id)`;回调
|
|
175
176
|
在每帧顶部以帧时间戳运行,并可修改 DOM
|
|
@@ -317,9 +318,9 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
|
|
|
317
318
|
编译为启动时注册、由 `win.loadHTML` 运行的 AOT 函数(在首次布局之前;
|
|
318
319
|
`DOMContentLoaded` 然后是 `load`)。`tests/extensions/gui.test.ts` 中的单元
|
|
319
320
|
测试,`tests/e2e/gui-*.test.ts` 中的 e2e。
|
|
320
|
-
- **M9c** ✅ 外部 `<script src>`
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
- **M9c** ✅ 外部 `<script src>` 文件被读取,其主体被包装/注册;相对 import
|
|
322
|
+
通过带记忆化的模块包装函数延迟到 `loadHTML`(模块级 DOM 工作因此能看到已解析
|
|
323
|
+
文档);缺失文件会成为诊断。加载器错误被 `loadGraph` 捕获并报告为构建错误。
|
|
323
324
|
- **M10** ✅ 窗口句柄上的 `requestAnimationFrame`/`cancelAnimationFrame`
|
|
324
325
|
(回调在每帧布局之前以帧时间戳运行),以及元素句柄上的
|
|
325
326
|
`offsetWidth`/`offsetHeight`/`contains`;e2e 覆盖在
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
- 全局 `fetch(input, init)` 是 HTTP/1.1 客户端。阻塞的套接字交换(`getaddrinfo`、connect、send、receive)运行在异步 I/O 工作线程池上,因此进行中的请求**不会**卡住事件循环:定时器、套接字与其他 `await` 继续运行,promise 在 reactor 派发完成结果时 settle。
|
|
8
8
|
- 重定向在主线程上处理:每一跳是一次 offload 交换,最多 20 次;301/302/303 会把 POST 改成 GET。
|
|
9
9
|
- 只接受 `http://` URL —— 由于未链接 TLS 后端,`https://` 会以 `TypeError` 拒绝。
|
|
10
|
+
- **没有协议的引用**(相对路径)与 `file://` URL 会读取本地文件,因此编译后的程序
|
|
11
|
+
无需 HTTP 服务即可加载磁盘资源。相对路径相对工作目录解析;支持 `GET` / `HEAD`。
|
|
12
|
+
在 Windows 上,标准写法 `file:///C:/dir/file` 与 `file://C:/dir/file` /
|
|
13
|
+
`file://C:\dir\file` 都指向同一个文件。
|
|
10
14
|
- 选项:`method`、`headers`(普通对象或 `Headers`)、`body` 与 `redirect`(`follow` / `manual` / `error`)。
|
|
11
15
|
- 解析出的 `Response` 形状对象暴露 `ok` / `status` / `statusText` / `url` / `headers` 以及 `text()` / `json()` / `arrayBuffer()` / `bytes()` / `clone()`。响应体在 promise settle 前已完整缓冲;不支持流式响应体。
|
|
12
16
|
- `Headers` 大小写不敏感,提供 `get` / `has` / `set` / `append` / `delete` / `keys` / `values` / `entries` / `forEach` / `getSetCookie`。
|
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
- 导入绑定与命名空间成员是模块求值时的快照(无实时绑定)—— 见[未实现:模块系统](../unimplemented/modules.md)。
|
|
20
20
|
- 纯类型导入与再导出(`import type { T } from "..."`、`import { type T } from "..."`、`export type { T } from "..."`)会被擦除,**不构成模块依赖边**:目标模块不会被加载或打包,模块之间的纯类型循环也不属于循环依赖。若需要仅求值一个模块而不绑定名字,请使用副作用导入(`import "./mod"`)。
|
|
21
21
|
|
|
22
|
+
## 延迟求值
|
|
23
|
+
|
|
24
|
+
- `gui` 的 `.html` 资产加载器用合成的 `__xt_deferred_module` 绑定标记相对的
|
|
25
|
+
`<script src>` import。bundler 会把该模块及其本地 import 图包装成返回各自
|
|
26
|
+
导出的函数,生成的脚本在 `loadHTML` 之后调用它们(`__xt_defer` 对每个模块
|
|
27
|
+
做记忆化)。这与浏览器的模块脚本一致:文档就绪后才求值 import 图。
|
|
28
|
+
- 同时被普通(非标记)import 引用的模块保持立即求值,并获得一个返回已初始化
|
|
29
|
+
导出的薄包装。
|
|
30
|
+
- 包装体是同步的:延迟脚本模块中的顶层 `await` 不受支持。
|
|
31
|
+
|
|
22
32
|
## import.meta
|
|
23
33
|
|
|
24
34
|
- `import.meta.url` / `.dirname` / `.filename`,由正在运行的可执行文件路径解析。
|
|
@@ -53,6 +53,21 @@
|
|
|
53
53
|
- `Symbol(description)` 原始值(`XT_OBJECT_KIND_SYMBOL`)、13 个著名符号(`Symbol.iterator`、`Symbol.asyncIterator`、`Symbol.match` 等)、`Symbol.for` / `Symbol.keyFor` 全局注册表、`symbol.description` / `toString()` / `valueOf()`。
|
|
54
54
|
- symbol 可作为属性键(`Object.getOwnPropertySymbols`,symbol 键的 `get`/`set`/`in`/`delete`),会被 `Object.keys` / `values` / `entries` / `for...in` / `JSON.stringify` 跳过,打印为 `Symbol(desc)`。
|
|
55
55
|
|
|
56
|
+
## URL
|
|
57
|
+
|
|
58
|
+
- `URL` 实现在 `runtime/xt_url_object.c`:支持 `new URL(input)` 与
|
|
59
|
+
`new URL(input, base)`(base 也可以是另一个 `URL`),并按层级式
|
|
60
|
+
`scheme://authority/path` base 解析相对引用。
|
|
61
|
+
- **没有协议的引用按文件路径处理**:`new URL("./model.glb")` 相对工作目录解析,
|
|
62
|
+
得到 `file:` URL(显式 base 仍然生效,因此 `new URL("./x", import.meta.url)`
|
|
63
|
+
也可用)。
|
|
64
|
+
- 只读属性 `href`、`protocol`、`origin`、`host`、`hostname`、`port`、
|
|
65
|
+
`pathname`、`search`、`hash`、`searchParams` 以及 `toString()` / `toJSON()`;
|
|
66
|
+
绝对输入按原样保留,但 `file:` URL 的 Windows 写法(`file://C:/dir` 与
|
|
67
|
+
`file://C:\dir`)会规范化为 `file:///C:/dir`,与 Node 一致。
|
|
68
|
+
- 不是完整的 WHATWG 解析器:未实现路径百分号编码、IDNA、setter 与
|
|
69
|
+
`searchParams` 的实时同步 —— 见[运行时偏差](../unimplemented/deviations.md)。
|
|
70
|
+
|
|
56
71
|
## URLSearchParams
|
|
57
72
|
|
|
58
73
|
- `URLSearchParams` 实现在 `runtime/xt_url.c`。
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| 正则按字节匹配 | 引擎按 UTF-8 字节匹配:多字节字面量仍可匹配,但 `.` 与字符类每次只消费一个字节(`\d`/`\w` 仍是 ASCII)。`exec` / `search` / 替换回调返回的偏移会转换为 UTF-16 码元 |
|
|
10
10
|
| 全局正则 `lastIndex` | `/g`、`/y` 正则的 `test` / `exec` 不推进也不读取调用方设置的 `lastIndex` |
|
|
11
|
+
| `URL` 解析器 | 只读 WHATWG 子集:未实现路径百分号编码、IDNA、setter 与 `searchParams` 实时联动;无协议引用按工作目录解析为 `file:` URL |
|
|
11
12
|
| `String.normalize` | 未实现 |
|
|
12
13
|
| 内置方法一等公民 | 以未绑定方法值实现(见[函数](./functions.md));`fn.toString()` 返回占位字符串而非源码文本 |
|
|
13
14
|
| `for...in` | 枚举对象 / 数组 / 字符串的自身键;不含原型链属性 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xbintsc",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.38",
|
|
4
4
|
"description": "xbintsc - a TypeScript binary compiler (TypeScript -> LLVM IR -> native binary)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -72,12 +72,12 @@
|
|
|
72
72
|
"vitest": "^2.1.8"
|
|
73
73
|
},
|
|
74
74
|
"optionalDependencies": {
|
|
75
|
-
"@xbintsc/linux-x64": "0.5.
|
|
76
|
-
"@xbintsc/linux-arm64": "0.5.
|
|
77
|
-
"@xbintsc/darwin-x64": "0.5.
|
|
78
|
-
"@xbintsc/darwin-arm64": "0.5.
|
|
79
|
-
"@xbintsc/win32-x64": "0.5.
|
|
80
|
-
"@xbintsc/win32-arm64": "0.5.
|
|
75
|
+
"@xbintsc/linux-x64": "0.5.38",
|
|
76
|
+
"@xbintsc/linux-arm64": "0.5.38",
|
|
77
|
+
"@xbintsc/darwin-x64": "0.5.38",
|
|
78
|
+
"@xbintsc/darwin-arm64": "0.5.38",
|
|
79
|
+
"@xbintsc/win32-x64": "0.5.38",
|
|
80
|
+
"@xbintsc/win32-arm64": "0.5.38"
|
|
81
81
|
},
|
|
82
82
|
"engines": {
|
|
83
83
|
"node": ">=22"
|
|
@@ -223,6 +223,16 @@ xt_value webgl_proto() {
|
|
|
223
223
|
define_getter(proto, "canvas", (void *)webgl_canvas_get);
|
|
224
224
|
define_getter(proto, "drawingBufferWidth", (void *)webgl_drawing_buffer_width_get);
|
|
225
225
|
define_getter(proto, "drawingBufferHeight", (void *)webgl_drawing_buffer_height_get);
|
|
226
|
+
/* `gl.constructor.name` is how three.js tells a WebGL 2 context from a
|
|
227
|
+
* WebGL 1 one. A host-type value from `xt_browser_type` later replaces this
|
|
228
|
+
* with the real constructor (and its `prototype`), but the context must
|
|
229
|
+
* answer the name even when the page never read the global. */
|
|
230
|
+
{
|
|
231
|
+
xt_value constructor = xt_object_new();
|
|
232
|
+
xt_object_set(constructor, xt_string_from_cstr("name"),
|
|
233
|
+
xt_string_from_cstr("WebGLRenderingContext"));
|
|
234
|
+
xt_object_set(proto, xt_string_from_cstr("constructor"), constructor);
|
|
235
|
+
}
|
|
226
236
|
g_webgl_proto = proto;
|
|
227
237
|
return proto;
|
|
228
238
|
}
|
|
@@ -121,12 +121,44 @@ xt_value uint_array(const unsigned int *values, int count) {
|
|
|
121
121
|
xt_value webgl2_proto() {
|
|
122
122
|
xt_gc_add_root(&g_webgl2_proto);
|
|
123
123
|
if (XT_IS_OBJECT(g_webgl2_proto)) return g_webgl2_proto;
|
|
124
|
-
|
|
124
|
+
/* WebGL 2 shares the WebGL 1 surface but not its prototype: in a browser
|
|
125
|
+
* `gl2 instanceof WebGLRenderingContext` is false, which is how three.js and
|
|
126
|
+
* other libraries detect WebGL 2. Copy the WebGL 1 members instead of
|
|
127
|
+
* inheriting the WebGL 1 prototype. */
|
|
128
|
+
xt_value webgl1 = webgl_proto();
|
|
129
|
+
xt_value proto = xt_object_new();
|
|
130
|
+
xt_value keys = xt_object_keys(webgl1);
|
|
131
|
+
const double count = xt_to_number(xt_array_length(keys));
|
|
132
|
+
for (int32_t i = 0; i < (int32_t)count; i++) {
|
|
133
|
+
xt_value key = xt_array_get(keys, xt_number((double)i));
|
|
134
|
+
const char *name = xt_string_data(key);
|
|
135
|
+
if (name == nullptr) continue;
|
|
136
|
+
/* `constructor` gets the WebGL 2 name below. The three host getters are
|
|
137
|
+
* accessors, not values: reading them here would run them against the
|
|
138
|
+
* WebGL 1 prototype and copy `undefined`. Reinstall them as accessors. */
|
|
139
|
+
if (strcmp(name, "constructor") == 0 || strcmp(name, "canvas") == 0 ||
|
|
140
|
+
strcmp(name, "drawingBufferWidth") == 0 || strcmp(name, "drawingBufferHeight") == 0) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
xt_object_set(proto, key, xt_object_get(webgl1, key));
|
|
144
|
+
}
|
|
145
|
+
xt_object_define_getter(proto, xt_string_from_cstr("canvas"),
|
|
146
|
+
xt_closure_new((void *)webgl_canvas_get, 0, nullptr));
|
|
147
|
+
xt_object_define_getter(proto, xt_string_from_cstr("drawingBufferWidth"),
|
|
148
|
+
xt_closure_new((void *)webgl_drawing_buffer_width_get, 0, nullptr));
|
|
149
|
+
xt_object_define_getter(proto, xt_string_from_cstr("drawingBufferHeight"),
|
|
150
|
+
xt_closure_new((void *)webgl_drawing_buffer_height_get, 0, nullptr));
|
|
125
151
|
#define XT_WEBGL2_CONSTANT(name, value) \
|
|
126
152
|
xt_object_set(proto, xt_string_from_cstr(#name), xt_number((double)(value)));
|
|
127
153
|
XT_WEBGL2_CONSTANTS(XT_WEBGL2_CONSTANT)
|
|
128
154
|
#undef XT_WEBGL2_CONSTANT
|
|
129
155
|
for (const MethodEntry &method : kMethods) define_method(proto, method.name, method.fn);
|
|
156
|
+
{
|
|
157
|
+
xt_value constructor = xt_object_new();
|
|
158
|
+
xt_object_set(constructor, xt_string_from_cstr("name"),
|
|
159
|
+
xt_string_from_cstr("WebGL2RenderingContext"));
|
|
160
|
+
xt_object_set(proto, xt_string_from_cstr("constructor"), constructor);
|
|
161
|
+
}
|
|
130
162
|
g_webgl2_proto = proto;
|
|
131
163
|
return proto;
|
|
132
164
|
}
|
|
@@ -24,6 +24,8 @@ xt_value xt_gui_run(int32_t argc, xt_value *argv);
|
|
|
24
24
|
xt_value xt_gui_quit(int32_t argc, xt_value *argv);
|
|
25
25
|
/** `__registerScript(id, fn)`: record an AOT-compiled `<script>` body. */
|
|
26
26
|
xt_value xt_register_script(int32_t argc, xt_value *argv);
|
|
27
|
+
/** `__xt_defer(id, init)`: evaluate a deferred module once and cache its exports. */
|
|
28
|
+
xt_value xt_gui_defer_module(int32_t argc, xt_value *argv);
|
|
27
29
|
/** Which SDL_GPU backend the device is using (`"vulkan"`, `"direct3d12"`,
|
|
28
30
|
* `"metal"`, …), or `""` before the device exists. */
|
|
29
31
|
const char *xt_gui_driver(void);
|
|
@@ -25,6 +25,14 @@ static std::unordered_map<std::string, xt_value> &script_registry() {
|
|
|
25
25
|
return registry;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** Deferred module id -> its exports object. A `<script src>`'s imports are
|
|
29
|
+
* evaluated on first use (after `loadHTML`) and then shared by every script
|
|
30
|
+
* that imports the same module. */
|
|
31
|
+
static std::unordered_map<std::string, xt_value> &deferred_registry() {
|
|
32
|
+
static std::unordered_map<std::string, xt_value> registry;
|
|
33
|
+
return registry;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
extern "C" xt_value xt_register_script(int32_t argc, xt_value *argv) {
|
|
29
37
|
if (argc >= 2) {
|
|
30
38
|
xt_value id_value = xt_to_string(xt_arg(argc, argv, 0));
|
|
@@ -42,6 +50,29 @@ extern "C" xt_value xt_register_script(int32_t argc, xt_value *argv) {
|
|
|
42
50
|
|
|
43
51
|
void xt_gui_script_gc_scan(void) {
|
|
44
52
|
for (const auto &entry : script_registry()) xt_gc_mark_value(entry.second);
|
|
53
|
+
for (const auto &entry : deferred_registry()) xt_gc_mark_value(entry.second);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** `__xt_defer(id, init)`: evaluate `init` once and return its exports. The
|
|
57
|
+
* placeholder is published before the call so a cyclic import sees the same
|
|
58
|
+
* object instead of recursing. */
|
|
59
|
+
extern "C" xt_value xt_gui_defer_module(int32_t argc, xt_value *argv) {
|
|
60
|
+
if (argc < 2) return XT_UNDEFINED;
|
|
61
|
+
xt_value id_value = xt_to_string(xt_arg(argc, argv, 0));
|
|
62
|
+
const char *id = xt_string_data(id_value);
|
|
63
|
+
if (id == nullptr) return XT_UNDEFINED;
|
|
64
|
+
std::unordered_map<std::string, xt_value> ®istry = deferred_registry();
|
|
65
|
+
auto found = registry.find(std::string(id));
|
|
66
|
+
if (found != registry.end()) return found->second;
|
|
67
|
+
xt_gc_register_root_provider(xt_gui_script_gc_scan);
|
|
68
|
+
xt_value exports = xt_object_new();
|
|
69
|
+
registry[std::string(id)] = exports;
|
|
70
|
+
xt_value init = xt_arg(argc, argv, 1);
|
|
71
|
+
if (XT_IS_FUNCTION(init)) {
|
|
72
|
+
exports = xt_call_with_this(init, XT_UNDEFINED, 0, nullptr);
|
|
73
|
+
registry[std::string(id)] = exports;
|
|
74
|
+
}
|
|
75
|
+
return exports;
|
|
45
76
|
}
|
|
46
77
|
|
|
47
78
|
/** Collect `data-xt-id` markers from `<script>` elements, in document order. */
|
|
@@ -126,6 +126,9 @@ struct GlslLinkLayout {
|
|
|
126
126
|
std::vector<GlslUniformDecl> block_members;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
/** Expand three.js's `#pragma unroll_loop_start` loops into constant indices. */
|
|
130
|
+
std::string unroll_glsl_pragmas(const std::string &source);
|
|
131
|
+
|
|
129
132
|
/** Scan `source` for the declarations WebGL needs to know about. */
|
|
130
133
|
void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info);
|
|
131
134
|
|