@weasel-js/renderer 0.0.0-stage → 1.10.0
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/LICENSE +21 -0
- package/README.md +61 -2
- package/dist/chunk-43YL7HZV.js +11 -0
- package/dist/chunk-43YL7HZV.js.map +1 -0
- package/dist/chunk-LFD47OV2.js +1487 -0
- package/dist/chunk-LFD47OV2.js.map +1 -0
- package/dist/chunk-Q4SIHV7Q.js +178 -0
- package/dist/chunk-Q4SIHV7Q.js.map +1 -0
- package/dist/imageCache-DYcWftY8.d.ts +329 -0
- package/dist/index.d.ts +1062 -0
- package/dist/index.js +4268 -0
- package/dist/index.js.map +1 -0
- package/dist/mesh.d.ts +241 -0
- package/dist/mesh.js +603 -0
- package/dist/mesh.js.map +1 -0
- package/dist/paintKinds-BmPAT51k.d.ts +314 -0
- package/dist/patterns-builtin.d.ts +110 -0
- package/dist/patterns-builtin.js +28 -0
- package/dist/patterns-builtin.js.map +1 -0
- package/dist/test-seams.d.ts +79 -0
- package/dist/test-seams.js +4 -0
- package/dist/test-seams.js.map +1 -0
- package/dist/testing/glRecorder.d.ts +33 -0
- package/dist/testing/glRecorder.js +158 -0
- package/dist/testing/glRecorder.js.map +1 -0
- package/dist/testing/vertexUploads.d.ts +28 -0
- package/dist/testing/vertexUploads.js +48 -0
- package/dist/testing/vertexUploads.js.map +1 -0
- package/package.json +71 -4
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Path } from '@weasel-js/geom';
|
|
2
|
+
import { Mesh } from '@weasel-js/geom/tessellate';
|
|
3
|
+
export { F as FLOATS_PER_VERTEX, _ as __setImageLoaderForTests, k as _resetImageCacheForTests, l as _resetPatternSpecCacheForTests, m as _resetTextureRegistryForTests } from './imageCache-DYcWftY8.js';
|
|
4
|
+
export { _ as _resetPaintDrawKindsForTests, t as _resetProgramRegistryForTests } from './paintKinds-BmPAT51k.js';
|
|
5
|
+
import '@weasel-js/paint';
|
|
6
|
+
import '@weasel-js/registry';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The tessellated Mesh for `path`, cached by Path identity — different Path
|
|
10
|
+
* objects with the same coords are distinct cache entries. A mesh built under
|
|
11
|
+
* another default open-fill rule is rebuilt. Bypassed whenever
|
|
12
|
+
* `DrawContext.flattenTolerance` is set.
|
|
13
|
+
*/
|
|
14
|
+
declare function getMesh(path: Path): Mesh;
|
|
15
|
+
/** Test helper. Do not call from product code. */
|
|
16
|
+
declare function _resetCacheForTests(): void;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A stroke's marker commands, cached per path. The placed head is a fresh
|
|
20
|
+
* `Path`, and the fill cache keys on path identity — so rebuilding it every
|
|
21
|
+
* frame would re-tessellate and re-upload every head every frame.
|
|
22
|
+
*
|
|
23
|
+
* Keyed on value, so a painter that builds a new stroke object every frame
|
|
24
|
+
* still hits: the resolved lengths, the flatten tolerance, the registry's
|
|
25
|
+
* generation, the marker refs and whatever fields each head declares it reads.
|
|
26
|
+
* A head that does not declare them may read any field, so for it the stroke
|
|
27
|
+
* as the command carried it — before any `{ px }` length was resolved — joins
|
|
28
|
+
* the key by identity. Paint is applied over the cached geometry, so a new
|
|
29
|
+
* paint reuses the heads.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** Test helper. Do not call from product code. */
|
|
33
|
+
declare function _resetMarkerCommandCacheForTests(): void;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Tessellated glyph outlines, in em space. Em space is unit-scale and
|
|
37
|
+
* baseline-relative, so the same glyph of the same face is the same triangles
|
|
38
|
+
* at every size, position, and zoom: tessellate once and pay only a
|
|
39
|
+
* scale-and-translate per occurrence.
|
|
40
|
+
*
|
|
41
|
+
* Flatten tolerance: an error of `T` em shows up as `T × fontSize × viewScale`
|
|
42
|
+
* screen pixels. At 1/4096 em, a glyph would have to reach ~4000 screen pixels
|
|
43
|
+
* tall before the flattening error covered a single pixel.
|
|
44
|
+
*
|
|
45
|
+
* Eviction is wholesale rather than LRU because the refill cost is bounded by
|
|
46
|
+
* what is actually on screen.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/** Test helper. Do not call from product code. */
|
|
50
|
+
declare function _resetOutlineMeshCacheForTests(): void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Tessellated glyph *outlines' strokes*, in em space: the sibling of
|
|
54
|
+
* `outlineMeshCache`.
|
|
55
|
+
*
|
|
56
|
+
* A stroke's em-space mesh depends on `strokeWidth / fontSize`, so the width is
|
|
57
|
+
* in the key, and a document that animates stroke width or font size will miss
|
|
58
|
+
* every frame. The width is quantized before it reaches the key: neighboring
|
|
59
|
+
* sub-quantum widths would otherwise each get their own entry and evict each
|
|
60
|
+
* other.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Test helper. Do not call from product code. */
|
|
64
|
+
declare function _resetOutlineStrokeMeshCacheForTests(): void;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Tessellated stroke ribbons for scene paths, keyed on `Path` identity.
|
|
68
|
+
*
|
|
69
|
+
* The sibling of `cache.ts` (fills) and `outlineStrokeMeshCache.ts` (glyph
|
|
70
|
+
* ribbons in em space), and it inherits their contract: identity, not content.
|
|
71
|
+
* A `Path` rebuilt with equal coords is a distinct entry.
|
|
72
|
+
*
|
|
73
|
+
* Design: `docs/superpowers/specs/2026-08-15-stroke-ribbon-cache-design.md`.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/** Test helper. Do not call from product code. */
|
|
77
|
+
declare function _resetStrokeMeshCacheForTests(): void;
|
|
78
|
+
|
|
79
|
+
export { _resetCacheForTests, _resetMarkerCommandCacheForTests, _resetOutlineMeshCacheForTests, _resetOutlineStrokeMeshCacheForTests, _resetStrokeMeshCacheForTests, getMesh };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FLOATS_PER_VERTEX, __setImageLoaderForTests, _resetCacheForTests, _resetImageCacheForTests, _resetMarkerCommandCacheForTests, _resetOutlineMeshCacheForTests, _resetOutlineStrokeMeshCacheForTests, _resetPaintDrawKindsForTests, _resetPatternSpecCacheForTests, _resetProgramRegistryForTests, _resetStrokeMeshCacheForTests, getMesh } from './chunk-LFD47OV2.js';
|
|
2
|
+
export { _resetTextureRegistryForTests } from './chunk-Q4SIHV7Q.js';
|
|
3
|
+
//# sourceMappingURL=test-seams.js.map
|
|
4
|
+
//# sourceMappingURL=test-seams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"test-seams.js"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy-based recording WebGL2 context for unit tests.
|
|
3
|
+
*
|
|
4
|
+
* Records every method call as { name, args, result } so tests can assert
|
|
5
|
+
* against the call sequence. Returns synthetic handles for object creation
|
|
6
|
+
* (createShader/Program/Buffer/etc.); reports truthy for *Parameter status
|
|
7
|
+
* queries (i.e. assumes shader/program compilation succeeded). NOT a renderer
|
|
8
|
+
* correctness check: it sees the call sequence, never a pixel.
|
|
9
|
+
*/
|
|
10
|
+
interface GLCall {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly args: readonly unknown[];
|
|
13
|
+
readonly result: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** What the recorded context reports about itself. */
|
|
16
|
+
interface GLRecorderOptions {
|
|
17
|
+
/** Reported as `gl.drawingBufferWidth`. Default 800. */
|
|
18
|
+
drawingBufferWidth?: number;
|
|
19
|
+
/** Reported as `gl.drawingBufferHeight`. Default 600. */
|
|
20
|
+
drawingBufferHeight?: number;
|
|
21
|
+
/** Returned by `gl.getContextAttributes()`. Default `{ stencil: true }`. */
|
|
22
|
+
contextAttributes?: Partial<WebGLContextAttributes>;
|
|
23
|
+
}
|
|
24
|
+
/** A stand-in context and the calls made on it, oldest first. */
|
|
25
|
+
interface GLRecorder {
|
|
26
|
+
readonly gl: WebGL2RenderingContext;
|
|
27
|
+
readonly calls: GLCall[];
|
|
28
|
+
reset(): void;
|
|
29
|
+
}
|
|
30
|
+
/** A WebGL2 stand-in that records every call and draws nothing. */
|
|
31
|
+
declare function makeGLRecorder(options?: GLRecorderOptions): GLRecorder;
|
|
32
|
+
|
|
33
|
+
export { type GLCall, type GLRecorder, type GLRecorderOptions, makeGLRecorder };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// src/testing/glRecorder.ts
|
|
2
|
+
var GL_CONSTANTS = {
|
|
3
|
+
// Shader / program
|
|
4
|
+
VERTEX_SHADER: 35633,
|
|
5
|
+
FRAGMENT_SHADER: 35632,
|
|
6
|
+
COMPILE_STATUS: 35713,
|
|
7
|
+
LINK_STATUS: 35714,
|
|
8
|
+
// Buffer targets
|
|
9
|
+
ARRAY_BUFFER: 34962,
|
|
10
|
+
ELEMENT_ARRAY_BUFFER: 34963,
|
|
11
|
+
STATIC_DRAW: 35044,
|
|
12
|
+
// Types
|
|
13
|
+
FLOAT: 5126,
|
|
14
|
+
UNSIGNED_INT: 5125,
|
|
15
|
+
// Primitives
|
|
16
|
+
TRIANGLES: 4,
|
|
17
|
+
// Errors / state
|
|
18
|
+
NO_ERROR: 0,
|
|
19
|
+
DEPTH_TEST: 2929,
|
|
20
|
+
BLEND: 3042,
|
|
21
|
+
STENCIL_TEST: 2960,
|
|
22
|
+
CULL_FACE: 2884,
|
|
23
|
+
UNPACK_FLIP_Y_WEBGL: 37440,
|
|
24
|
+
UNPACK_PREMULTIPLY_ALPHA_WEBGL: 37441,
|
|
25
|
+
SCISSOR_TEST: 3089,
|
|
26
|
+
MAX_TEXTURE_SIZE: 3379,
|
|
27
|
+
// Blend factors
|
|
28
|
+
SRC_ALPHA: 770,
|
|
29
|
+
ONE_MINUS_SRC_ALPHA: 771,
|
|
30
|
+
DST_ALPHA: 772,
|
|
31
|
+
ONE_MINUS_DST_ALPHA: 773,
|
|
32
|
+
ZERO: 0,
|
|
33
|
+
ONE: 1,
|
|
34
|
+
// Buffer bits
|
|
35
|
+
COLOR_BUFFER_BIT: 16384,
|
|
36
|
+
STENCIL_BUFFER_BIT: 1024,
|
|
37
|
+
DEPTH_BUFFER_BIT: 256,
|
|
38
|
+
// Stencil ops
|
|
39
|
+
KEEP: 7680,
|
|
40
|
+
REPLACE: 7681,
|
|
41
|
+
INVERT: 5386,
|
|
42
|
+
// Compare funcs
|
|
43
|
+
ALWAYS: 519,
|
|
44
|
+
NEVER: 512,
|
|
45
|
+
EQUAL: 514,
|
|
46
|
+
NOTEQUAL: 517,
|
|
47
|
+
// Color masks
|
|
48
|
+
FRONT_AND_BACK: 1032,
|
|
49
|
+
// Misc constants used in step 1
|
|
50
|
+
COLOR_WRITEMASK: 3107,
|
|
51
|
+
// Textures (step 3)
|
|
52
|
+
TEXTURE_2D: 3553,
|
|
53
|
+
TEXTURE0: 33984,
|
|
54
|
+
RGBA: 6408,
|
|
55
|
+
UNSIGNED_BYTE: 5121,
|
|
56
|
+
TEXTURE_MIN_FILTER: 10241,
|
|
57
|
+
TEXTURE_MAG_FILTER: 10240,
|
|
58
|
+
LINEAR: 9729,
|
|
59
|
+
NEAREST: 9728,
|
|
60
|
+
TEXTURE_WRAP_S: 10242,
|
|
61
|
+
TEXTURE_WRAP_T: 10243,
|
|
62
|
+
CLAMP_TO_EDGE: 33071,
|
|
63
|
+
// Wrap modes (step 4)
|
|
64
|
+
REPEAT: 10497,
|
|
65
|
+
MIRRORED_REPEAT: 33648,
|
|
66
|
+
// Mipmap minification filter
|
|
67
|
+
LINEAR_MIPMAP_LINEAR: 9987,
|
|
68
|
+
// Framebuffers and renderbuffers (offscreen effect passes). Every one of
|
|
69
|
+
// these has to be here before a test names it: an absent ALL-CAPS property
|
|
70
|
+
// reads as 0 through the proxy, so `expect(args[0]).toBe(gl.FRAMEBUFFER)`
|
|
71
|
+
// would compare 0 against 0 and pass over a renderer that bound nothing.
|
|
72
|
+
FRAMEBUFFER: 36160,
|
|
73
|
+
RENDERBUFFER: 36161,
|
|
74
|
+
FRAMEBUFFER_BINDING: 36006,
|
|
75
|
+
RENDERBUFFER_BINDING: 36007,
|
|
76
|
+
COLOR_ATTACHMENT0: 36064,
|
|
77
|
+
DEPTH_STENCIL_ATTACHMENT: 33306,
|
|
78
|
+
DEPTH24_STENCIL8: 35056,
|
|
79
|
+
RGBA8: 32856,
|
|
80
|
+
FRAMEBUFFER_COMPLETE: 36053
|
|
81
|
+
};
|
|
82
|
+
function syntheticHandle(name, seq) {
|
|
83
|
+
return { __id: `${name}_${seq}` };
|
|
84
|
+
}
|
|
85
|
+
function snapshot(value) {
|
|
86
|
+
return ArrayBuffer.isView(value) && !(value instanceof DataView) ? value.slice() : value;
|
|
87
|
+
}
|
|
88
|
+
function makeGLRecorder(options = {}) {
|
|
89
|
+
const calls = [];
|
|
90
|
+
const {
|
|
91
|
+
drawingBufferWidth = 800,
|
|
92
|
+
drawingBufferHeight = 600,
|
|
93
|
+
contextAttributes = { stencil: true }
|
|
94
|
+
} = options;
|
|
95
|
+
const DATA_PROPERTIES = {
|
|
96
|
+
drawingBufferWidth,
|
|
97
|
+
drawingBufferHeight
|
|
98
|
+
};
|
|
99
|
+
const handler = (name) => (...args) => {
|
|
100
|
+
let result = void 0;
|
|
101
|
+
switch (name) {
|
|
102
|
+
case "createShader":
|
|
103
|
+
case "createProgram":
|
|
104
|
+
case "createBuffer":
|
|
105
|
+
case "createVertexArray":
|
|
106
|
+
case "createTexture":
|
|
107
|
+
case "createFramebuffer":
|
|
108
|
+
case "createRenderbuffer":
|
|
109
|
+
result = syntheticHandle(name, calls.length);
|
|
110
|
+
break;
|
|
111
|
+
case "getUniformLocation":
|
|
112
|
+
case "getAttribLocation":
|
|
113
|
+
result = calls.length;
|
|
114
|
+
break;
|
|
115
|
+
case "getShaderParameter":
|
|
116
|
+
case "getProgramParameter":
|
|
117
|
+
result = true;
|
|
118
|
+
break;
|
|
119
|
+
case "getShaderInfoLog":
|
|
120
|
+
case "getProgramInfoLog":
|
|
121
|
+
result = "";
|
|
122
|
+
break;
|
|
123
|
+
case "getContextAttributes":
|
|
124
|
+
result = { ...contextAttributes };
|
|
125
|
+
break;
|
|
126
|
+
case "getError":
|
|
127
|
+
result = 0;
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
result = void 0;
|
|
131
|
+
}
|
|
132
|
+
calls.push({ name, args: args.map(snapshot), result });
|
|
133
|
+
return result;
|
|
134
|
+
};
|
|
135
|
+
const gl = new Proxy(
|
|
136
|
+
{},
|
|
137
|
+
{
|
|
138
|
+
get(_, prop) {
|
|
139
|
+
if (typeof prop !== "string") return void 0;
|
|
140
|
+
if (prop in DATA_PROPERTIES) return DATA_PROPERTIES[prop];
|
|
141
|
+
if (prop in GL_CONSTANTS) return GL_CONSTANTS[prop];
|
|
142
|
+
if (/^[A-Z_0-9]+$/.test(prop)) return 0;
|
|
143
|
+
return handler(prop);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
return {
|
|
148
|
+
gl,
|
|
149
|
+
calls,
|
|
150
|
+
reset() {
|
|
151
|
+
calls.length = 0;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { makeGLRecorder };
|
|
157
|
+
//# sourceMappingURL=glRecorder.js.map
|
|
158
|
+
//# sourceMappingURL=glRecorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/glRecorder.ts"],"names":[],"mappings":"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","file":"glRecorder.js","sourcesContent":["/**\n * Proxy-based recording WebGL2 context for unit tests.\n *\n * Records every method call as { name, args, result } so tests can assert\n * against the call sequence. Returns synthetic handles for object creation\n * (createShader/Program/Buffer/etc.); reports truthy for *Parameter status\n * queries (i.e. assumes shader/program compilation succeeded). NOT a renderer\n * correctness check: it sees the call sequence, never a pixel.\n */\n\nexport interface GLCall {\n readonly name: string;\n readonly args: readonly unknown[];\n readonly result: unknown;\n}\n\n/** What the recorded context reports about itself. */\nexport interface GLRecorderOptions {\n /** Reported as `gl.drawingBufferWidth`. Default 800. */\n drawingBufferWidth?: number;\n /** Reported as `gl.drawingBufferHeight`. Default 600. */\n drawingBufferHeight?: number;\n /** Returned by `gl.getContextAttributes()`. Default `{ stencil: true }`. */\n contextAttributes?: Partial<WebGLContextAttributes>;\n}\n\n/** A stand-in context and the calls made on it, oldest first. */\nexport interface GLRecorder {\n readonly gl: WebGL2RenderingContext;\n readonly calls: GLCall[];\n reset(): void;\n}\n\nconst GL_CONSTANTS: Readonly<Record<string, number>> = {\n // Shader / program\n VERTEX_SHADER: 0x8B31,\n FRAGMENT_SHADER: 0x8B30,\n COMPILE_STATUS: 0x8B81,\n LINK_STATUS: 0x8B82,\n // Buffer targets\n ARRAY_BUFFER: 0x8892,\n ELEMENT_ARRAY_BUFFER: 0x8893,\n STATIC_DRAW: 0x88E4,\n // Types\n FLOAT: 0x1406,\n UNSIGNED_INT: 0x1405,\n // Primitives\n TRIANGLES: 0x0004,\n // Errors / state\n NO_ERROR: 0,\n DEPTH_TEST: 0x0B71,\n BLEND: 0x0BE2,\n STENCIL_TEST: 0x0B90,\n CULL_FACE: 0x0B44,\n UNPACK_FLIP_Y_WEBGL: 0x9240,\n UNPACK_PREMULTIPLY_ALPHA_WEBGL: 0x9241,\n SCISSOR_TEST: 0x0C11,\n MAX_TEXTURE_SIZE: 0x0D33,\n // Blend factors\n SRC_ALPHA: 0x0302,\n ONE_MINUS_SRC_ALPHA: 0x0303,\n DST_ALPHA: 0x0304,\n ONE_MINUS_DST_ALPHA: 0x0305,\n ZERO: 0,\n ONE: 1,\n // Buffer bits\n COLOR_BUFFER_BIT: 0x00004000,\n STENCIL_BUFFER_BIT: 0x00000400,\n DEPTH_BUFFER_BIT: 0x00000100,\n // Stencil ops\n KEEP: 0x1E00,\n REPLACE: 0x1E01,\n INVERT: 0x150A,\n // Compare funcs\n ALWAYS: 0x0207,\n NEVER: 0x0200,\n EQUAL: 0x0202,\n NOTEQUAL: 0x0205,\n // Color masks\n FRONT_AND_BACK: 0x0408,\n // Misc constants used in step 1\n COLOR_WRITEMASK: 0x0C23,\n // Textures (step 3)\n TEXTURE_2D: 0x0DE1,\n TEXTURE0: 0x84C0,\n RGBA: 0x1908,\n UNSIGNED_BYTE: 0x1401,\n TEXTURE_MIN_FILTER: 0x2801,\n TEXTURE_MAG_FILTER: 0x2800,\n LINEAR: 0x2601,\n NEAREST: 0x2600,\n TEXTURE_WRAP_S: 0x2802,\n TEXTURE_WRAP_T: 0x2803,\n CLAMP_TO_EDGE: 0x812F,\n // Wrap modes (step 4)\n REPEAT: 0x2901,\n MIRRORED_REPEAT: 0x8370,\n // Mipmap minification filter\n LINEAR_MIPMAP_LINEAR: 0x2703,\n // Framebuffers and renderbuffers (offscreen effect passes). Every one of\n // these has to be here before a test names it: an absent ALL-CAPS property\n // reads as 0 through the proxy, so `expect(args[0]).toBe(gl.FRAMEBUFFER)`\n // would compare 0 against 0 and pass over a renderer that bound nothing.\n FRAMEBUFFER: 0x8D40,\n RENDERBUFFER: 0x8D41,\n FRAMEBUFFER_BINDING: 0x8CA6,\n RENDERBUFFER_BINDING: 0x8CA7,\n COLOR_ATTACHMENT0: 0x8CE0,\n DEPTH_STENCIL_ATTACHMENT: 0x821A,\n DEPTH24_STENCIL8: 0x88F0,\n RGBA8: 0x8058,\n FRAMEBUFFER_COMPLETE: 0x8CD5,\n};\n\nfunction syntheticHandle(name: string, seq: number): { __id: string } {\n return { __id: `${name}_${seq}` };\n}\n\n/**\n * Copy typed-array arguments as they are recorded.\n *\n * A caller is entitled to reuse the array it uploads from — the text ring\n * packs every draw through one scratch buffer — so storing the reference\n * records a value that later frames overwrite. A test reading it back then\n * compares two frames and sees the same numbers twice, which passes.\n */\nfunction snapshot(value: unknown): unknown {\n return ArrayBuffer.isView(value) && !(value instanceof DataView)\n ? (value as unknown as { slice(): unknown }).slice()\n : value;\n}\n\n/** A WebGL2 stand-in that records every call and draws nothing. */\nexport function makeGLRecorder(options: GLRecorderOptions = {}): GLRecorder {\n const calls: GLCall[] = [];\n const {\n drawingBufferWidth = 800,\n drawingBufferHeight = 600,\n contextAttributes = { stencil: true },\n } = options;\n\n // Read as data, not called. The Proxy below hands back a recording function\n // for every lowercase property, so without this `drawingBufferHeight` is a\n // function and every y-flip computed from it is NaN — silently.\n const DATA_PROPERTIES: Readonly<Record<string, unknown>> = {\n drawingBufferWidth,\n drawingBufferHeight,\n };\n\n const handler = (name: string) => (...args: unknown[]) => {\n let result: unknown = undefined;\n switch (name) {\n case 'createShader':\n case 'createProgram':\n case 'createBuffer':\n case 'createVertexArray':\n case 'createTexture':\n case 'createFramebuffer':\n case 'createRenderbuffer':\n result = syntheticHandle(name, calls.length);\n break;\n case 'getUniformLocation':\n case 'getAttribLocation':\n result = calls.length;\n break;\n case 'getShaderParameter':\n case 'getProgramParameter':\n result = true;\n break;\n case 'getShaderInfoLog':\n case 'getProgramInfoLog':\n result = '';\n break;\n case 'getContextAttributes':\n result = { ...contextAttributes };\n break;\n case 'getError':\n result = 0;\n break;\n default:\n result = undefined;\n }\n calls.push({ name, args: args.map(snapshot), result });\n return result;\n };\n\n const gl = new Proxy(\n {},\n {\n get(_, prop: string | symbol) {\n if (typeof prop !== 'string') return undefined;\n if (prop in DATA_PROPERTIES) return DATA_PROPERTIES[prop];\n if (prop in GL_CONSTANTS) return GL_CONSTANTS[prop];\n if (/^[A-Z_0-9]+$/.test(prop)) return 0; // unknown all-caps constant → 0\n return handler(prop);\n },\n },\n ) as unknown as WebGL2RenderingContext;\n\n return {\n gl,\n calls,\n reset() {\n calls.length = 0;\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { GLRecorder } from './glRecorder.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read vertex geometry back out of a `GLRecorder`, with each upload's
|
|
5
|
+
* floats-per-vertex taken from the `vertexAttribPointer` recorded for that same
|
|
6
|
+
* buffer object.
|
|
7
|
+
*
|
|
8
|
+
* A ring slot configures its attributes once, so a frame after the first
|
|
9
|
+
* records no pointer calls at all — hence a tracker that remembers what it has
|
|
10
|
+
* learned. Ask it for `uploads()` after each frame and it carries the strides
|
|
11
|
+
* across `recorder.reset()`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** One vertex buffer upload. */
|
|
15
|
+
interface VertexUpload {
|
|
16
|
+
/** Floats per vertex. */
|
|
17
|
+
stride: number;
|
|
18
|
+
data: Float32Array;
|
|
19
|
+
}
|
|
20
|
+
/** Reads vertex uploads out of a recorder, remembering each buffer's stride. */
|
|
21
|
+
interface UploadTracker {
|
|
22
|
+
/** Every vertex upload recorded since the last `recorder.reset()`. */
|
|
23
|
+
uploads(): VertexUpload[];
|
|
24
|
+
}
|
|
25
|
+
/** A tracker over `recorder`; keep one across frames. */
|
|
26
|
+
declare function makeUploadTracker(recorder: GLRecorder): UploadTracker;
|
|
27
|
+
|
|
28
|
+
export { type UploadTracker, type VertexUpload, makeUploadTracker };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/testing/vertexUploads.ts
|
|
2
|
+
var ARRAY_BUFFER = 34962;
|
|
3
|
+
function payload(call) {
|
|
4
|
+
const data = call.name === "bufferData" ? call.args[1] : call.args[2];
|
|
5
|
+
if (!(data instanceof Float32Array)) return null;
|
|
6
|
+
if (call.name !== "bufferSubData") return data;
|
|
7
|
+
const srcOffset = typeof call.args[3] === "number" ? call.args[3] : 0;
|
|
8
|
+
const length = typeof call.args[4] === "number" ? call.args[4] : data.length - srcOffset;
|
|
9
|
+
return data.subarray(srcOffset, srcOffset + length);
|
|
10
|
+
}
|
|
11
|
+
function makeUploadTracker(recorder) {
|
|
12
|
+
const strides = /* @__PURE__ */ new Map();
|
|
13
|
+
return {
|
|
14
|
+
uploads() {
|
|
15
|
+
const out = [];
|
|
16
|
+
const pending = [];
|
|
17
|
+
let bound = null;
|
|
18
|
+
for (const call of recorder.calls) {
|
|
19
|
+
if (call.name === "bindBuffer") {
|
|
20
|
+
if (call.args[0] === ARRAY_BUFFER) bound = call.args[1];
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (call.name === "vertexAttribPointer") {
|
|
24
|
+
const bytes = call.args[4];
|
|
25
|
+
strides.set(bound, bytes === 0 ? 2 : bytes / 4);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (call.name !== "bufferData" && call.name !== "bufferSubData") continue;
|
|
29
|
+
const data = payload(call);
|
|
30
|
+
if (data) pending.push({ buffer: bound, data });
|
|
31
|
+
}
|
|
32
|
+
for (const { buffer, data } of pending) {
|
|
33
|
+
const stride = strides.get(buffer);
|
|
34
|
+
if (stride === void 0) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
"vertexUploads: a vertex buffer was written with no vertexAttribPointer ever recorded for it \u2014 call uploads() on the frame that creates the buffer, before resetting the recorder."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
out.push({ stride, data });
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { makeUploadTracker };
|
|
47
|
+
//# sourceMappingURL=vertexUploads.js.map
|
|
48
|
+
//# sourceMappingURL=vertexUploads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/vertexUploads.ts"],"names":[],"mappings":";AAaA,IAAM,YAAA,GAAe,KAAA;AAqBrB,SAAS,QAAQ,IAAA,EAAmC;AAClD,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,KAAS,YAAA,GAAe,IAAA,CAAK,KAAK,CAAC,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA;AACpE,EAAA,IAAI,EAAE,IAAA,YAAgB,YAAA,CAAA,EAAe,OAAO,IAAA;AAC5C,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,eAAA,EAAiB,OAAO,IAAA;AAC1C,EAAA,MAAM,SAAA,GAAY,OAAO,IAAA,CAAK,IAAA,CAAK,CAAC,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,GAAI,CAAA;AACpE,EAAA,MAAM,MAAA,GAAS,OAAO,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,MAAA,GAAS,SAAA;AAC/E,EAAA,OAAO,IAAA,CAAK,QAAA,CAAS,SAAA,EAAW,SAAA,GAAY,MAAM,CAAA;AACpD;AAGO,SAAS,kBAAkB,QAAA,EAAqC;AAErE,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAqB;AAEzC,EAAA,OAAO;AAAA,IACL,OAAA,GAA0B;AACxB,MAAA,MAAM,MAAsB,EAAC;AAC7B,MAAA,MAAM,UAAqD,EAAC;AAC5D,MAAA,IAAI,KAAA,GAAiB,IAAA;AAIrB,MAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,KAAA,EAAO;AACjC,QAAA,IAAI,IAAA,CAAK,SAAS,YAAA,EAAc;AAC9B,UAAA,IAAI,IAAA,CAAK,KAAK,CAAC,CAAA,KAAM,cAAc,KAAA,GAAQ,IAAA,CAAK,KAAK,CAAC,CAAA;AACtD,UAAA;AAAA,QACF;AACA,QAAA,IAAI,IAAA,CAAK,SAAS,qBAAA,EAAuB;AAEvC,UAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA;AACzB,UAAA,OAAA,CAAQ,IAAI,KAAA,EAAO,KAAA,KAAU,CAAA,GAAI,CAAA,GAAI,QAAQ,CAAC,CAAA;AAC9C,UAAA;AAAA,QACF;AACA,QAAA,IAAI,IAAA,CAAK,IAAA,KAAS,YAAA,IAAgB,IAAA,CAAK,SAAS,eAAA,EAAiB;AACjE,QAAA,MAAM,IAAA,GAAO,QAAQ,IAAI,CAAA;AACzB,QAAA,IAAI,MAAM,OAAA,CAAQ,IAAA,CAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAM,CAAA;AAAA,MAChD;AAEA,MAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,IAAA,EAAK,IAAK,OAAA,EAAS;AACtC,QAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AACjC,QAAA,IAAI,WAAW,MAAA,EAAW;AACxB,UAAA,MAAM,IAAI,KAAA;AAAA,YACR;AAAA,WAGF;AAAA,QACF;AACA,QAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,CAAA;AAAA,MAC3B;AACA,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,GACF;AACF","file":"vertexUploads.js","sourcesContent":["/**\n * Read vertex geometry back out of a `GLRecorder`, with each upload's\n * floats-per-vertex taken from the `vertexAttribPointer` recorded for that same\n * buffer object.\n *\n * A ring slot configures its attributes once, so a frame after the first\n * records no pointer calls at all — hence a tracker that remembers what it has\n * learned. Ask it for `uploads()` after each frame and it carries the strides\n * across `recorder.reset()`.\n */\n\nimport type { GLCall, GLRecorder } from './glRecorder';\n\nconst ARRAY_BUFFER = 0x8892;\n\n/** One vertex buffer upload. */\nexport interface VertexUpload {\n /** Floats per vertex. */\n stride: number;\n data: Float32Array;\n}\n\n/** Reads vertex uploads out of a recorder, remembering each buffer's stride. */\nexport interface UploadTracker {\n /** Every vertex upload recorded since the last `recorder.reset()`. */\n uploads(): VertexUpload[];\n}\n\n/**\n * The floats an upload actually sent. `bufferSubData(target, offset, src,\n * srcOffset, length)` hands GL a *window* into a scratch array the batch\n * reuses across frames, so reading the recorded argument whole compares live\n * vertices against stale ones.\n */\nfunction payload(call: GLCall): Float32Array | null {\n const data = call.name === 'bufferData' ? call.args[1] : call.args[2];\n if (!(data instanceof Float32Array)) return null;\n if (call.name !== 'bufferSubData') return data;\n const srcOffset = typeof call.args[3] === 'number' ? call.args[3] : 0;\n const length = typeof call.args[4] === 'number' ? call.args[4] : data.length - srcOffset;\n return data.subarray(srcOffset, srcOffset + length);\n}\n\n/** A tracker over `recorder`; keep one across frames. */\nexport function makeUploadTracker(recorder: GLRecorder): UploadTracker {\n // Keyed on the recorder's synthetic buffer handle, which is a stable object.\n const strides = new Map<unknown, number>();\n\n return {\n uploads(): VertexUpload[] {\n const out: VertexUpload[] = [];\n const pending: { buffer: unknown; data: Float32Array }[] = [];\n let bound: unknown = null;\n\n // Two passes: a buffer's attribute layout can be recorded either before\n // its first upload (the ring) or after it (every other draw path).\n for (const call of recorder.calls) {\n if (call.name === 'bindBuffer') {\n if (call.args[0] === ARRAY_BUFFER) bound = call.args[1];\n continue;\n }\n if (call.name === 'vertexAttribPointer') {\n // Byte stride; 0 means tightly packed, which for a_position is a vec2.\n const bytes = call.args[4] as number;\n strides.set(bound, bytes === 0 ? 2 : bytes / 4);\n continue;\n }\n if (call.name !== 'bufferData' && call.name !== 'bufferSubData') continue;\n const data = payload(call);\n if (data) pending.push({ buffer: bound, data });\n }\n\n for (const { buffer, data } of pending) {\n const stride = strides.get(buffer);\n if (stride === undefined) {\n throw new Error(\n 'vertexUploads: a vertex buffer was written with no vertexAttribPointer ' +\n 'ever recorded for it — call uploads() on the frame that creates the ' +\n 'buffer, before resetting the recorder.',\n );\n }\n out.push({ stride, data });\n }\n return out;\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/renderer",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.10.0",
|
|
4
|
+
"description": "A WebGL2 renderer for draw commands: batched path fills and strokes, MSDF and outline text, images and sprites, gradients, patterns, registered shader programs, and full-screen effects. No scene graph, no React.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./mesh": {
|
|
17
|
+
"import": "./dist/mesh.js",
|
|
18
|
+
"types": "./dist/mesh.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./patterns-builtin": {
|
|
21
|
+
"import": "./dist/patterns-builtin.js",
|
|
22
|
+
"types": "./dist/patterns-builtin.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./testing/glRecorder": {
|
|
25
|
+
"import": "./dist/testing/glRecorder.js",
|
|
26
|
+
"types": "./dist/testing/glRecorder.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./testing/vertexUploads": {
|
|
29
|
+
"import": "./dist/testing/vertexUploads.js",
|
|
30
|
+
"types": "./dist/testing/vertexUploads.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./test-seams": {
|
|
33
|
+
"import": "./dist/test-seams.js",
|
|
34
|
+
"types": "./dist/test-seams.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@weasel-js/geom": "1.10.0",
|
|
40
|
+
"@weasel-js/paint": "1.10.0",
|
|
41
|
+
"@weasel-js/registry": "1.10.0",
|
|
42
|
+
"@weasel-js/stroke": "1.10.0",
|
|
43
|
+
"@weasel-js/text": "1.10.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@weasel-js/font": "1.10.0"
|
|
47
|
+
},
|
|
48
|
+
"author": "orochi235",
|
|
49
|
+
"homepage": "https://orochi235.github.io/weasel/",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/orochi235/weasel.git",
|
|
53
|
+
"directory": "packages/renderer"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/orochi235/weasel/issues"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=22"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist",
|
|
63
|
+
"README.md",
|
|
64
|
+
"LICENSE"
|
|
65
|
+
],
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "tsup"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public",
|
|
71
|
+
"provenance": true
|
|
72
|
+
}
|
|
73
|
+
}
|