@swf2es/native 0.0.0-stage → 0.1.1
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 +202 -0
- package/LICENSE.third-party +313 -0
- package/README.md +489 -2
- package/dist/atf/binary.d.ts +2 -0
- package/dist/atf/binary.d.ts.map +1 -0
- package/dist/atf/binary.js +4 -0
- package/dist/atf/binary.js.map +1 -0
- package/dist/atf/index.d.ts +27 -0
- package/dist/atf/index.d.ts.map +1 -0
- package/dist/atf/index.js +158 -0
- package/dist/atf/index.js.map +1 -0
- package/dist/atf/jxr.d.ts +22 -0
- package/dist/atf/jxr.d.ts.map +1 -0
- package/dist/atf/jxr.js +60 -0
- package/dist/atf/jxr.js.map +1 -0
- package/dist/atf/parse.d.ts +65 -0
- package/dist/atf/parse.d.ts.map +1 -0
- package/dist/atf/parse.js +204 -0
- package/dist/atf/parse.js.map +1 -0
- package/dist/audio/binary.d.ts +2 -0
- package/dist/audio/binary.d.ts.map +1 -0
- package/dist/audio/binary.js +4 -0
- package/dist/audio/binary.js.map +1 -0
- package/dist/audio/index.d.ts +21 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +73 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/base64.d.ts +3 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/base64.js +10 -0
- package/dist/base64.js.map +1 -0
- package/dist/compress/binary.d.ts +2 -0
- package/dist/compress/binary.d.ts.map +1 -0
- package/dist/compress/binary.js +4 -0
- package/dist/compress/binary.js.map +1 -0
- package/dist/compress/index.d.ts +59 -0
- package/dist/compress/index.d.ts.map +1 -0
- package/dist/compress/index.js +146 -0
- package/dist/compress/index.js.map +1 -0
- package/dist/instance.d.ts +25 -0
- package/dist/instance.d.ts.map +1 -0
- package/dist/instance.js +50 -0
- package/dist/instance.js.map +1 -0
- package/dist/mp3/binary.d.ts +2 -0
- package/dist/mp3/binary.d.ts.map +1 -0
- package/dist/mp3/binary.js +4 -0
- package/dist/mp3/binary.js.map +1 -0
- package/dist/mp3/index.d.ts +20 -0
- package/dist/mp3/index.d.ts.map +1 -0
- package/dist/mp3/index.js +49 -0
- package/dist/mp3/index.js.map +1 -0
- package/dist/render/binary.d.ts +2 -0
- package/dist/render/binary.d.ts.map +1 -0
- package/dist/render/binary.js +4 -0
- package/dist/render/binary.js.map +1 -0
- package/dist/render/bitmap-kernel.d.ts +118 -0
- package/dist/render/bitmap-kernel.d.ts.map +1 -0
- package/dist/render/bitmap-kernel.js +592 -0
- package/dist/render/bitmap-kernel.js.map +1 -0
- package/dist/render/draw-kernel.d.ts +79 -0
- package/dist/render/draw-kernel.d.ts.map +1 -0
- package/dist/render/draw-kernel.js +205 -0
- package/dist/render/draw-kernel.js.map +1 -0
- package/dist/render/dxt-encoder.d.ts +19 -0
- package/dist/render/dxt-encoder.d.ts.map +1 -0
- package/dist/render/dxt-encoder.js +95 -0
- package/dist/render/dxt-encoder.js.map +1 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +11 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/lines.d.ts +55 -0
- package/dist/render/lines.d.ts.map +1 -0
- package/dist/render/lines.js +123 -0
- package/dist/render/lines.js.map +1 -0
- package/dist/render/module.d.ts +11 -0
- package/dist/render/module.d.ts.map +1 -0
- package/dist/render/module.js +27 -0
- package/dist/render/module.js.map +1 -0
- package/dist/render/pixel-ops.d.ts +77 -0
- package/dist/render/pixel-ops.d.ts.map +1 -0
- package/dist/render/pixel-ops.js +236 -0
- package/dist/render/pixel-ops.js.map +1 -0
- package/dist/render/tessellator.d.ts +90 -0
- package/dist/render/tessellator.d.ts.map +1 -0
- package/dist/render/tessellator.js +251 -0
- package/dist/render/tessellator.js.map +1 -0
- package/package.json +53 -3
- package/src/atf/index.ts +212 -0
- package/src/atf/jxr.ts +83 -0
- package/src/atf/parse.ts +263 -0
- package/src/audio/index.ts +93 -0
- package/src/base64.ts +10 -0
- package/src/compress/index.ts +225 -0
- package/src/instance.ts +53 -0
- package/src/mp3/index.ts +71 -0
- package/src/render/bitmap-kernel.ts +856 -0
- package/src/render/draw-kernel.ts +268 -0
- package/src/render/dxt-encoder.ts +121 -0
- package/src/render/index.ts +37 -0
- package/src/render/lines.ts +161 -0
- package/src/render/module.ts +30 -0
- package/src/render/pixel-ops.ts +356 -0
- package/src/render/tessellator.ts +367 -0
- package/src/webassembly.d.ts +22 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { LineBuilder } from "./lines.js";
|
|
2
|
+
import { renderInstance, renderModule } from "./module.js";
|
|
3
|
+
/**
|
|
4
|
+
* The commands of a contour layer() takes, each followed by its
|
|
5
|
+
* coordinates: MOVE x y and LINE x y; CURVE cx cy x y, a quadratic from
|
|
6
|
+
* the pen; CUBIC c1x c1y c2x c2y x y. The pen starts each contour at 0, 0.
|
|
7
|
+
* Curves are flattened to within 0.02 of the curve, in at most 256 chords;
|
|
8
|
+
* repeated points are dropped, and contours of fewer than three points left out.
|
|
9
|
+
*/
|
|
10
|
+
export const PATH_MOVE = 1;
|
|
11
|
+
export const PATH_LINE = 2;
|
|
12
|
+
export const PATH_CURVE = 3;
|
|
13
|
+
export const PATH_CUBIC = 4;
|
|
14
|
+
/** What root.zig takes of one fill; it rejects more too. */
|
|
15
|
+
const MOST_CONTOURS = 100000;
|
|
16
|
+
const MOST_POINTS = 1000000;
|
|
17
|
+
/** A rule root.zig rejects, for a fill whose arrays already show it would reject them. */
|
|
18
|
+
const REJECTED = 2;
|
|
19
|
+
/** The Int32s of root.zig's Layer, and of each fill's Range after it. */
|
|
20
|
+
const LAYER = 5;
|
|
21
|
+
const RANGE = 5;
|
|
22
|
+
/**
|
|
23
|
+
* Synchronous double-precision tessellator. It compiles the render module
|
|
24
|
+
* as it is made, and throws where the host refuses it. A fill it refuses
|
|
25
|
+
* (not finite, malformed, too large, or out of memory) is null.
|
|
26
|
+
*/
|
|
27
|
+
export class Tessellator {
|
|
28
|
+
instance = null;
|
|
29
|
+
limit;
|
|
30
|
+
keep;
|
|
31
|
+
bands;
|
|
32
|
+
lines;
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.limit = options.memoryLimit ?? 128 << 20;
|
|
35
|
+
this.keep = options.retainMemory ?? 8 << 20;
|
|
36
|
+
this.bands = options.bands ?? false;
|
|
37
|
+
if (!Number.isInteger(this.limit) ||
|
|
38
|
+
this.limit < 0 ||
|
|
39
|
+
this.limit > 128 << 20 ||
|
|
40
|
+
!Number.isInteger(this.keep) ||
|
|
41
|
+
this.keep < 0 ||
|
|
42
|
+
this.keep > 128 << 20) {
|
|
43
|
+
throw new RangeError("invalid tessellator memory limit");
|
|
44
|
+
}
|
|
45
|
+
renderModule();
|
|
46
|
+
this.lines = new LineBuilder({
|
|
47
|
+
memoryLimit: this.limit,
|
|
48
|
+
retainMemory: this.keep,
|
|
49
|
+
bands: this.bands,
|
|
50
|
+
});
|
|
51
|
+
this.tessellate = Object.assign(this.fill, { layer: this.layer, lines: this.lines });
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Current retained Wasm capacity, the line builder's included. Arena reset
|
|
55
|
+
* alone does not shrink this memory.
|
|
56
|
+
*/
|
|
57
|
+
get capacity() {
|
|
58
|
+
return (this.instance?.memory.buffer.byteLength ?? 0) + this.lines.capacity;
|
|
59
|
+
}
|
|
60
|
+
dispose() {
|
|
61
|
+
this.instance = null;
|
|
62
|
+
this.lines.dispose();
|
|
63
|
+
}
|
|
64
|
+
/** The instance, made on first use, its arena reset; filling by the bands alone where `bands`. */
|
|
65
|
+
arena(bands) {
|
|
66
|
+
this.instance ??= renderInstance(() => {
|
|
67
|
+
throw new Error("tessellation allocation failed");
|
|
68
|
+
});
|
|
69
|
+
const x = this.instance;
|
|
70
|
+
x.reset();
|
|
71
|
+
x.setLimit(this.limit);
|
|
72
|
+
x.bandsOnly(Number(bands));
|
|
73
|
+
return x;
|
|
74
|
+
}
|
|
75
|
+
/** A call that threw: a trapped instance is never used again. */
|
|
76
|
+
failed() {
|
|
77
|
+
// In particular, longjmp unwinds through a throwing import: never resume that C instance. The
|
|
78
|
+
// line builder's instance is its own.
|
|
79
|
+
this.instance = null;
|
|
80
|
+
}
|
|
81
|
+
/** An instance grown past what is kept, let go. */
|
|
82
|
+
trim() {
|
|
83
|
+
if ((this.instance?.memory.buffer.byteLength ?? 0) > this.keep) {
|
|
84
|
+
this.instance = null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** One fill. The module checks the coordinates; only the arrays' lengths are looked at here. */
|
|
88
|
+
fill = (contours, nonZero) => this.fillBy(contours, nonZero, this.bands);
|
|
89
|
+
/** One fill, by the bands alone where `bands`; again so in a new instance where libtess2 trapped. */
|
|
90
|
+
fillBy(contours, nonZero, bands) {
|
|
91
|
+
if (contours.length > MOST_CONTOURS) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
let count = 0;
|
|
95
|
+
for (const points of contours) {
|
|
96
|
+
if (points.length % 2 !== 0) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
count += points.length / 2;
|
|
100
|
+
}
|
|
101
|
+
if (count > MOST_POINTS) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
if (count === 0) {
|
|
105
|
+
return { vertices: new Float64Array(), indices: new Uint16Array() };
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const x = this.arena(bands);
|
|
109
|
+
// One allocation: coordinates, then contours' ends.
|
|
110
|
+
const coordAt = x.alloc(count * 16 + contours.length * 4);
|
|
111
|
+
if (!coordAt) {
|
|
112
|
+
throw new Error("tessellation input allocation failed");
|
|
113
|
+
}
|
|
114
|
+
const endsAt = coordAt + count * 16;
|
|
115
|
+
const coords = new Float64Array(x.memory.buffer, coordAt, count * 2);
|
|
116
|
+
const ends = new Uint32Array(x.memory.buffer, endsAt, contours.length);
|
|
117
|
+
let at = 0;
|
|
118
|
+
for (let i = 0; i < contours.length; i++) {
|
|
119
|
+
coords.set(contours[i], at);
|
|
120
|
+
at += contours[i].length;
|
|
121
|
+
ends[i] = at / 2;
|
|
122
|
+
}
|
|
123
|
+
if (x.run(coordAt, count, endsAt, contours.length, Number(nonZero)) !== 0) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
// Growth can detach the input views. Cached geometry owns fresh copies of the final views.
|
|
127
|
+
const vertices = new Float64Array(x.memory.buffer, x.vertices(), x.vertexCount() * 2).slice();
|
|
128
|
+
const source = new Uint32Array(x.memory.buffer, x.indices(), x.triangleCount() * 3);
|
|
129
|
+
const indices = vertices.length / 2 <= 0x10000 ? new Uint16Array(source) : source.slice();
|
|
130
|
+
return { vertices, indices };
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
this.failed();
|
|
134
|
+
return bands ? null : this.fillBy(contours, nonZero, true);
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
this.trim();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Each fill flattened and tessellated, as `fill` would make its polygons, in one call and one copy out. */
|
|
141
|
+
layer = (fills, nonZero) => this.layerBy(fills, nonZero, this.bands);
|
|
142
|
+
/** The layer, by the bands alone where `bands`; again so in a new instance where libtess2 trapped. */
|
|
143
|
+
layerBy(fills, nonZero, bands) {
|
|
144
|
+
let length = 0;
|
|
145
|
+
let contours = 0;
|
|
146
|
+
const rules = new Uint8Array(fills.length);
|
|
147
|
+
for (let i = 0; i < fills.length; i++) {
|
|
148
|
+
const fill = fills[i];
|
|
149
|
+
if (fill.length > MOST_CONTOURS) {
|
|
150
|
+
rules[i] = REJECTED;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
for (let j = 0; j < fill.length; j++) {
|
|
154
|
+
length += fill[j].length;
|
|
155
|
+
}
|
|
156
|
+
rules[i] = Number(nonZero[i]);
|
|
157
|
+
contours += fill.length;
|
|
158
|
+
}
|
|
159
|
+
let ranges;
|
|
160
|
+
let vertices;
|
|
161
|
+
let indices;
|
|
162
|
+
try {
|
|
163
|
+
// One allocation: commands, contours' ends, each fill's last contour, then rules.
|
|
164
|
+
const x = this.arena(bands);
|
|
165
|
+
const commandAt = x.alloc(length * 8 + contours * 4 + fills.length * 5);
|
|
166
|
+
if (!commandAt) {
|
|
167
|
+
throw new Error("tessellation input allocation failed");
|
|
168
|
+
}
|
|
169
|
+
const endsAt = commandAt + length * 8;
|
|
170
|
+
const fillsAt = endsAt + contours * 4;
|
|
171
|
+
const rulesAt = fillsAt + fills.length * 4;
|
|
172
|
+
const commands = new Float64Array(x.memory.buffer, commandAt, length);
|
|
173
|
+
const ends = new Uint32Array(x.memory.buffer, endsAt, contours);
|
|
174
|
+
const lasts = new Uint32Array(x.memory.buffer, fillsAt, fills.length);
|
|
175
|
+
new Uint8Array(x.memory.buffer, rulesAt, fills.length).set(rules);
|
|
176
|
+
let at = 0;
|
|
177
|
+
let contour = 0;
|
|
178
|
+
for (let i = 0; i < fills.length; i++) {
|
|
179
|
+
if (rules[i] !== REJECTED) {
|
|
180
|
+
const fill = fills[i];
|
|
181
|
+
for (let j = 0; j < fill.length; j++) {
|
|
182
|
+
commands.set(fill[j], at);
|
|
183
|
+
at += fill[j].length;
|
|
184
|
+
ends[contour++] = at;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
lasts[i] = contour;
|
|
188
|
+
}
|
|
189
|
+
const head = x.layer(commandAt, length, endsAt, contours, fillsAt, rulesAt, fills.length);
|
|
190
|
+
if (head === 0) {
|
|
191
|
+
// The layer's own output did not fit: a call a fill.
|
|
192
|
+
return fills.length === 1
|
|
193
|
+
? [null]
|
|
194
|
+
: fills.map((fill, i) => this.alone(fill, nonZero[i], bands));
|
|
195
|
+
}
|
|
196
|
+
// The one copy out, its ranges read before a retry resets the arena.
|
|
197
|
+
const buffer = x.memory.buffer;
|
|
198
|
+
ranges = new Int32Array(buffer, head, LAYER + fills.length * RANGE).slice();
|
|
199
|
+
vertices = new Float64Array(buffer, ranges[0], ranges[2] * 2).slice();
|
|
200
|
+
indices =
|
|
201
|
+
ranges[4] === 2
|
|
202
|
+
? new Uint16Array(buffer, ranges[1], ranges[3]).slice()
|
|
203
|
+
: new Uint32Array(buffer, ranges[1], ranges[3]).slice();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
this.failed();
|
|
207
|
+
if (bands) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
// libtess2 trapped: each fill in a fresh instance, and one that traps alone again by the
|
|
211
|
+
// bands, which never trap.
|
|
212
|
+
return fills.length === 1
|
|
213
|
+
? this.layerBy(fills, nonZero, true)
|
|
214
|
+
: fills.map((fill, i) => this.alone(fill, nonZero[i], false));
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
this.trim();
|
|
218
|
+
}
|
|
219
|
+
const out = new Array(fills.length);
|
|
220
|
+
for (let i = 0; i < fills.length; i++) {
|
|
221
|
+
const range = LAYER + i * RANGE;
|
|
222
|
+
const status = ranges[range];
|
|
223
|
+
if (status === 0) {
|
|
224
|
+
const vertexStart = ranges[range + 1];
|
|
225
|
+
const indexStart = ranges[range + 3];
|
|
226
|
+
out[i] = {
|
|
227
|
+
vertices: vertices.subarray(vertexStart * 2, (vertexStart + ranges[range + 2]) * 2),
|
|
228
|
+
indices: indices.subarray(indexStart, indexStart + ranges[range + 4]),
|
|
229
|
+
indexOffset: vertexStart,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
// Running out may be the layer's memory, where the fill alone fits.
|
|
234
|
+
out[i] = status === -1 && fills.length > 1 ? this.alone(fills[i], nonZero[i], bands) : null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return out;
|
|
238
|
+
}
|
|
239
|
+
/** One fill's commands as a layer of its own, in a fresh arena. */
|
|
240
|
+
alone(contours, nonZero, bands) {
|
|
241
|
+
const geometry = this.layerBy([contours], [nonZero], bands)?.[0] ?? null;
|
|
242
|
+
return geometry && { vertices: geometry.vertices, indices: geometry.indices };
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Use as RenderView's fillTessellator. A fill alone takes its contours
|
|
246
|
+
* flattened already; a layer takes them as path commands; and a layer's
|
|
247
|
+
* lines take the layer as the player packs it (`lines`).
|
|
248
|
+
*/
|
|
249
|
+
tessellate;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=tessellator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tessellator.js","sourceRoot":"","sources":["../../src/render/tessellator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swf2es/native",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "swf2es's WebAssembly modules: bitmap kernels, MP3, ADPCM and Nellymoser decoding, zlib and LZMA, fill and line tessellation, and ATF textures",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"swf",
|
|
7
|
+
"flash",
|
|
8
|
+
"webassembly",
|
|
9
|
+
"zlib",
|
|
10
|
+
"lzma",
|
|
11
|
+
"mp3",
|
|
12
|
+
"tessellation"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://swf2es.github.io/swf2es/",
|
|
15
|
+
"bugs": "https://github.com/swf2es/swf2es/issues",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/swf2es/swf2es.git",
|
|
19
|
+
"directory": "packages/native"
|
|
20
|
+
},
|
|
21
|
+
"license": "Apache-2.0 AND Zlib AND LicenseRef-LZMA-SDK-Public-Domain AND CC0-1.0 AND SGI-B-2.0 AND BSD-2-Clause AND MIT AND W3C-20150513",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
"./atf": {
|
|
25
|
+
"types": "./dist/atf/index.d.ts",
|
|
26
|
+
"default": "./dist/atf/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./audio": {
|
|
29
|
+
"types": "./dist/audio/index.d.ts",
|
|
30
|
+
"default": "./dist/audio/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./compress": {
|
|
33
|
+
"types": "./dist/compress/index.d.ts",
|
|
34
|
+
"default": "./dist/compress/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./mp3": {
|
|
37
|
+
"types": "./dist/mp3/index.d.ts",
|
|
38
|
+
"default": "./dist/mp3/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./render": {
|
|
41
|
+
"types": "./dist/render/index.d.ts",
|
|
42
|
+
"default": "./dist/render/index.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"!dist/**/.tsbuildinfo",
|
|
48
|
+
"src/**/*.ts",
|
|
49
|
+
"!src/**/binary.ts",
|
|
50
|
+
"LICENSE.third-party"
|
|
51
|
+
],
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build:wasm": "node build.ts",
|
|
54
|
+
"check:wasm": "node build.ts --check"
|
|
55
|
+
}
|
|
6
56
|
}
|
package/src/atf/index.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// ATF textures for Stage3D: the header and blocks (parse.ts), and each
|
|
2
|
+
// level decoded into what a desktop GPU takes, as Flash Player picks it on
|
|
3
|
+
// the desktop: RGB888 and RGBA8888's JPEG XR images as BGRA, and the block
|
|
4
|
+
// compressed formats as S3TC, DXT1 or DXT5, rebuilt from their LZMA'd
|
|
5
|
+
// indices and JPEG XR endpoint images, or copied where they are raw.
|
|
6
|
+
import { DONE, lzmaDecode } from "../compress/index.js";
|
|
7
|
+
import { decodeJxr, JXR_BGR, JXR_BGRA, JXR_GRAY, JXR_RGB565, type JxrImage } from "./jxr.js";
|
|
8
|
+
import {
|
|
9
|
+
ATF_COMPRESSED,
|
|
10
|
+
ATF_COMPRESSED_ALPHA,
|
|
11
|
+
ATF_COMPRESSED_LOSSY,
|
|
12
|
+
ATF_COMPRESSED_LOSSY_ALPHA,
|
|
13
|
+
ATF_RAW_COMPRESSED,
|
|
14
|
+
ATF_RAW_COMPRESSED_ALPHA,
|
|
15
|
+
ATF_RGB888,
|
|
16
|
+
type AtfBlocks,
|
|
17
|
+
AtfError,
|
|
18
|
+
type AtfHeader,
|
|
19
|
+
readAtfBlocks,
|
|
20
|
+
} from "./parse.js";
|
|
21
|
+
|
|
22
|
+
export { jxrMemoryInUse, jxrTraps } from "./jxr.js";
|
|
23
|
+
export * from "./parse.js";
|
|
24
|
+
|
|
25
|
+
/** What a level decodes to: BGRA pixels, or S3TC blocks. */
|
|
26
|
+
export type AtfEncoding = "bgra" | "dxt1" | "dxt5";
|
|
27
|
+
|
|
28
|
+
export interface AtfImage {
|
|
29
|
+
face: number;
|
|
30
|
+
level: number;
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
/**
|
|
34
|
+
* BGRA's top-down rows of 4 bytes a pixel, alpha straight; DXT1's 8 bytes
|
|
35
|
+
* a 4x4 block, DXT5's 16, the blocks in rows from the top, each at least
|
|
36
|
+
* one block however small the level.
|
|
37
|
+
*/
|
|
38
|
+
bytes: Uint8Array;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The encoding an ATF of `format` decodes to. */
|
|
42
|
+
export function atfEncoding(format: number): AtfEncoding {
|
|
43
|
+
switch (format) {
|
|
44
|
+
case ATF_COMPRESSED:
|
|
45
|
+
case ATF_RAW_COMPRESSED:
|
|
46
|
+
case ATF_COMPRESSED_LOSSY:
|
|
47
|
+
return "dxt1";
|
|
48
|
+
case ATF_COMPRESSED_ALPHA:
|
|
49
|
+
case ATF_RAW_COMPRESSED_ALPHA:
|
|
50
|
+
case ATF_COMPRESSED_LOSSY_ALPHA:
|
|
51
|
+
return "dxt5";
|
|
52
|
+
default:
|
|
53
|
+
return "bgra";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Every level the ATF holds, of every face, decoded: a level that is absent,
|
|
59
|
+
* or whose blocks for the desktop are empty, is left out. Throws AtfError
|
|
60
|
+
* (`decode`, #3677) for a block that does not decode or is not the size its
|
|
61
|
+
* level needs.
|
|
62
|
+
*/
|
|
63
|
+
export function decodeAtf(data: Uint8Array, header: AtfHeader): AtfImage[] {
|
|
64
|
+
const faces = readAtfBlocks(data, header);
|
|
65
|
+
const images: AtfImage[] = [];
|
|
66
|
+
|
|
67
|
+
for (let face = 0; face < faces.length; face++) {
|
|
68
|
+
const levels = faces[face];
|
|
69
|
+
for (let level = 0; level < levels.length; level++) {
|
|
70
|
+
const blocks = levels[level];
|
|
71
|
+
const width = Math.max(1, header.width >> level);
|
|
72
|
+
const height = Math.max(1, header.height >> level);
|
|
73
|
+
const bytes = blocks && decodeLevel(header.format, blocks, width, height);
|
|
74
|
+
if (bytes) {
|
|
75
|
+
images.push({ face, level, width, height, bytes });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return images;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function corrupt(what: string): never {
|
|
84
|
+
throw new AtfError("decode", `ATF ${what} does not decode`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** A level's image for the desktop; null where its blocks for it are all empty. */
|
|
88
|
+
function decodeLevel(
|
|
89
|
+
format: number,
|
|
90
|
+
blocks: AtfBlocks,
|
|
91
|
+
width: number,
|
|
92
|
+
height: number,
|
|
93
|
+
): Uint8Array | null {
|
|
94
|
+
const across = Math.max(1, width >> 2);
|
|
95
|
+
const down = Math.max(1, height >> 2);
|
|
96
|
+
switch (format) {
|
|
97
|
+
case ATF_RGB888:
|
|
98
|
+
return blocks[0].length === 0 ? null : bgra(blocks[0], width, height, false);
|
|
99
|
+
case ATF_COMPRESSED:
|
|
100
|
+
case ATF_COMPRESSED_LOSSY:
|
|
101
|
+
return empty(blocks, 2) ? null : dxt1(blocks, across, down);
|
|
102
|
+
case ATF_COMPRESSED_ALPHA:
|
|
103
|
+
case ATF_COMPRESSED_LOSSY_ALPHA:
|
|
104
|
+
return empty(blocks, 4) ? null : dxt5(blocks, across, down);
|
|
105
|
+
case ATF_RAW_COMPRESSED:
|
|
106
|
+
case ATF_RAW_COMPRESSED_ALPHA:
|
|
107
|
+
if (blocks[0].length === 0) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Raw blocks are the GPU's, as they are.
|
|
112
|
+
if (blocks[0].length !== across * down * (format === ATF_RAW_COMPRESSED ? 8 : 16)) {
|
|
113
|
+
corrupt("raw blocks");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return blocks[0].slice();
|
|
117
|
+
default:
|
|
118
|
+
return blocks[0].length === 0 ? null : bgra(blocks[0], width, height, true);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Whether the first `n` blocks, the desktop's, are all empty. */
|
|
123
|
+
function empty(blocks: AtfBlocks, n: number): boolean {
|
|
124
|
+
for (let i = 0; i < n; i++) {
|
|
125
|
+
if (blocks[i].length !== 0) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** An image of `format` exactly `width` by `height`. */
|
|
134
|
+
function image(block: Uint8Array, format: number, width: number, height: number): JxrImage {
|
|
135
|
+
// jxrlib refuses an image larger than the level's before it allocates for it.
|
|
136
|
+
const decoded = block.length === 0 ? null : decodeJxr(block, format, Math.max(width, height));
|
|
137
|
+
if (!decoded || decoded.width !== width || decoded.height !== height) {
|
|
138
|
+
corrupt("JPEG XR image");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return decoded;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** RGB888's or RGBA8888's image as BGRA. */
|
|
145
|
+
function bgra(block: Uint8Array, width: number, height: number, alpha: boolean): Uint8Array {
|
|
146
|
+
return image(block, alpha ? JXR_BGRA : JXR_BGR, width, height).pixels;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** An LZMA block, its 5 property bytes first, decoded to exactly `size` bytes. */
|
|
150
|
+
function lzma(block: Uint8Array, size: number): Uint8Array {
|
|
151
|
+
const decoded = lzmaDecode(block, 0, 5, size);
|
|
152
|
+
if (decoded.status !== DONE || decoded.bytes.length !== size) {
|
|
153
|
+
corrupt("LZMA block");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return decoded.bytes;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* DXT1 from Compressed's first two blocks: each 4x4 block's 2-bit indices,
|
|
161
|
+
* 4 bytes a block, LZMA'd, and its two RGB565 endpoints as an image a pixel
|
|
162
|
+
* a block, the first endpoints above the second (Adobe's dds2atf).
|
|
163
|
+
*/
|
|
164
|
+
function dxt1(blocks: AtfBlocks, across: number, down: number): Uint8Array {
|
|
165
|
+
const count = across * down;
|
|
166
|
+
const indices = lzma(blocks[0], count * 4);
|
|
167
|
+
const colors = image(blocks[1], JXR_RGB565, across, down * 2).pixels;
|
|
168
|
+
const out = new Uint8Array(count * 8);
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < count; i++) {
|
|
171
|
+
const o = i * 8;
|
|
172
|
+
const c = i * 2;
|
|
173
|
+
const d = (count + i) * 2;
|
|
174
|
+
out[o] = colors[c];
|
|
175
|
+
out[o + 1] = colors[c + 1];
|
|
176
|
+
out[o + 2] = colors[d];
|
|
177
|
+
out[o + 3] = colors[d + 1];
|
|
178
|
+
out.set(indices.subarray(i * 4, i * 4 + 4), o + 4);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* DXT5 from CompressedAlpha's first four blocks: the alpha indices, 6 bytes
|
|
186
|
+
* a block, LZMA'd; the alpha endpoints as an 8-bit grey image, the first
|
|
187
|
+
* above the second; then the colour indices and endpoints as DXT1's.
|
|
188
|
+
*/
|
|
189
|
+
function dxt5(blocks: AtfBlocks, across: number, down: number): Uint8Array {
|
|
190
|
+
const count = across * down;
|
|
191
|
+
const alphaIndices = lzma(blocks[0], count * 6);
|
|
192
|
+
const alphas = image(blocks[1], JXR_GRAY, across, down * 2).pixels;
|
|
193
|
+
const indices = lzma(blocks[2], count * 4);
|
|
194
|
+
const colors = image(blocks[3], JXR_RGB565, across, down * 2).pixels;
|
|
195
|
+
const out = new Uint8Array(count * 16);
|
|
196
|
+
|
|
197
|
+
for (let i = 0; i < count; i++) {
|
|
198
|
+
const o = i * 16;
|
|
199
|
+
const c = i * 2;
|
|
200
|
+
const d = (count + i) * 2;
|
|
201
|
+
out[o] = alphas[i];
|
|
202
|
+
out[o + 1] = alphas[count + i];
|
|
203
|
+
out.set(alphaIndices.subarray(i * 6, i * 6 + 6), o + 2);
|
|
204
|
+
out[o + 8] = colors[c];
|
|
205
|
+
out[o + 9] = colors[c + 1];
|
|
206
|
+
out[o + 10] = colors[d];
|
|
207
|
+
out[o + 11] = colors[d + 1];
|
|
208
|
+
out.set(indices.subarray(i * 4, i * 4 + 4), o + 12);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return out;
|
|
212
|
+
}
|
package/src/atf/jxr.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// JPEG XR images through jxrlib, synchronously, in one module that imports
|
|
2
|
+
// nothing, kept as compress's is (instance.ts). Each call copies its input
|
|
3
|
+
// into the module's memory, decodes in an arena reset first, and copies
|
|
4
|
+
// the pixels out. jxrlib is not memory safe on corrupt input: it may read
|
|
5
|
+
// past its tables, write through null pointers into the bottom of the
|
|
6
|
+
// stack, or trap, all within its instance. So an instance that refused an
|
|
7
|
+
// image, or trapped, is let go, and the next image starts in a new one:
|
|
8
|
+
// nothing a corrupt image did reaches another.
|
|
9
|
+
import { KeptInstance } from "../instance.js";
|
|
10
|
+
import { binary } from "./binary.js";
|
|
11
|
+
|
|
12
|
+
interface Exports {
|
|
13
|
+
memory: WebAssembly.Memory;
|
|
14
|
+
reset(): void;
|
|
15
|
+
alloc(n: number): number;
|
|
16
|
+
decodeImage(input: number, length: number, format: number, limit: number): number;
|
|
17
|
+
resultPointer(): number;
|
|
18
|
+
resultWidth(): number;
|
|
19
|
+
resultHeight(): number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The pixel formats ATF's images hold, as jxr.c numbers them, and their bytes a pixel out: 24-bit pixels come out as BGRA. */
|
|
23
|
+
export const JXR_BGR = 0;
|
|
24
|
+
export const JXR_BGRA = 1;
|
|
25
|
+
export const JXR_RGB565 = 2;
|
|
26
|
+
export const JXR_GRAY = 3;
|
|
27
|
+
const BYTES = [4, 4, 2, 1];
|
|
28
|
+
|
|
29
|
+
/** An image's pixels: top-down rows of its format's bytes, unpadded. */
|
|
30
|
+
export interface JxrImage {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
pixels: Uint8Array;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const kept = new KeptInstance<Exports>(binary);
|
|
37
|
+
let traps = 0;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The JPEG XR file `data`, which must hold `format` and be at most `limit`
|
|
41
|
+
* pixels a side; null where it does not, is corrupt, or cannot have the
|
|
42
|
+
* memory it needs, and so where the module cannot be instantiated.
|
|
43
|
+
*/
|
|
44
|
+
export function decodeJxr(data: Uint8Array, format: number, limit: number): JxrImage | null {
|
|
45
|
+
try {
|
|
46
|
+
return kept.call((x) => {
|
|
47
|
+
x.reset();
|
|
48
|
+
const at = x.alloc(data.length);
|
|
49
|
+
if (at !== 0) {
|
|
50
|
+
new Uint8Array(x.memory.buffer, at, data.length).set(data);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (at === 0 || x.decodeImage(at, data.length, format, limit) !== 0) {
|
|
54
|
+
kept.drop();
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const width = x.resultWidth();
|
|
59
|
+
const height = x.resultHeight();
|
|
60
|
+
const n = width * height * BYTES[format];
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
width,
|
|
64
|
+
height,
|
|
65
|
+
pixels: new Uint8Array(x.memory.buffer, x.resultPointer(), n).slice(),
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
} catch {
|
|
69
|
+
// A trap, which let the instance go, or a host that refused the module or its memory.
|
|
70
|
+
traps++;
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** How many calls have thrown, for the fuzzer: each was refused. */
|
|
76
|
+
export function jxrTraps(): number {
|
|
77
|
+
return traps;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The module's memory now, for measuring: 0 when no instance is kept. */
|
|
81
|
+
export function jxrMemoryInUse(): number {
|
|
82
|
+
return kept.memory;
|
|
83
|
+
}
|