@multiplekex/shallot 0.2.4 → 0.2.5
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/package.json +1 -1
- package/src/extras/arrows/index.ts +3 -3
- package/src/extras/caustic.ts +37 -0
- package/src/extras/gradient/index.ts +63 -69
- package/src/extras/index.ts +3 -0
- package/src/extras/lines/index.ts +3 -3
- package/src/extras/skylab/index.ts +314 -0
- package/src/extras/text/font.ts +69 -14
- package/src/extras/text/index.ts +8 -5
- package/src/extras/text/sdf.ts +13 -2
- package/src/extras/water.ts +64 -0
- package/src/standard/defaults.ts +2 -0
- package/src/standard/index.ts +2 -0
- package/src/standard/raster/index.ts +517 -0
- package/src/standard/{render → raytracing}/bvh/blas.ts +3 -3
- package/src/standard/{render → raytracing}/bvh/tlas.ts +3 -0
- package/src/standard/{render → raytracing}/depth.ts +9 -9
- package/src/standard/raytracing/index.ts +380 -0
- package/src/standard/{render → raytracing}/instance.ts +3 -0
- package/src/standard/raytracing/shaders.ts +815 -0
- package/src/standard/{render → raytracing}/triangle.ts +1 -1
- package/src/standard/render/camera.ts +88 -80
- package/src/standard/render/index.ts +68 -208
- package/src/standard/render/indirect.ts +9 -10
- package/src/standard/render/mesh/index.ts +35 -166
- package/src/standard/render/overlay.ts +4 -4
- package/src/standard/render/pass.ts +1 -1
- package/src/standard/render/postprocess.ts +75 -50
- package/src/standard/render/scene.ts +28 -16
- package/src/standard/render/surface/compile.ts +6 -8
- package/src/standard/render/surface/noise.ts +15 -2
- package/src/standard/render/surface/shaders.ts +257 -0
- package/src/standard/render/surface/structs.ts +13 -6
- package/src/standard/render/forward/index.ts +0 -259
- package/src/standard/render/forward/raster.ts +0 -228
- package/src/standard/render/shaders.ts +0 -484
- package/src/standard/render/surface/wgsl.ts +0 -573
- /package/src/standard/{render → raytracing}/bvh/radix.ts +0 -0
- /package/src/standard/{render → raytracing}/bvh/structs.ts +0 -0
- /package/src/standard/{render → raytracing}/bvh/traverse.ts +0 -0
- /package/src/standard/{render → raytracing}/intersection.ts +0 -0
- /package/src/standard/{render → raytracing}/ray.ts +0 -0
package/src/extras/text/font.ts
CHANGED
|
@@ -82,7 +82,10 @@ function parseHead(r: Reader, table: TableEntry): { unitsPerEm: number; indexToL
|
|
|
82
82
|
return { unitsPerEm, indexToLocFormat };
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function parseHhea(
|
|
85
|
+
function parseHhea(
|
|
86
|
+
r: Reader,
|
|
87
|
+
table: TableEntry
|
|
88
|
+
): { ascender: number; descender: number; lineGap: number; numHMetrics: number } {
|
|
86
89
|
seek(r, table.offset + 4);
|
|
87
90
|
const ascender = i16(r);
|
|
88
91
|
const descender = i16(r);
|
|
@@ -92,7 +95,12 @@ function parseHhea(r: Reader, table: TableEntry): { ascender: number; descender:
|
|
|
92
95
|
return { ascender, descender, lineGap, numHMetrics };
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
function parseHmtx(
|
|
98
|
+
function parseHmtx(
|
|
99
|
+
r: Reader,
|
|
100
|
+
table: TableEntry,
|
|
101
|
+
numHMetrics: number,
|
|
102
|
+
numGlyphs: number
|
|
103
|
+
): { advances: Uint16Array } {
|
|
96
104
|
const advances = new Uint16Array(numGlyphs);
|
|
97
105
|
seek(r, table.offset);
|
|
98
106
|
|
|
@@ -114,7 +122,12 @@ function parseMaxp(r: Reader, table: TableEntry): number {
|
|
|
114
122
|
return u16(r);
|
|
115
123
|
}
|
|
116
124
|
|
|
117
|
-
function parseLoca(
|
|
125
|
+
function parseLoca(
|
|
126
|
+
r: Reader,
|
|
127
|
+
table: TableEntry,
|
|
128
|
+
numGlyphs: number,
|
|
129
|
+
indexToLocFormat: number
|
|
130
|
+
): Uint32Array {
|
|
118
131
|
const offsets = new Uint32Array(numGlyphs + 1);
|
|
119
132
|
seek(r, table.offset);
|
|
120
133
|
|
|
@@ -210,7 +223,8 @@ function parseCmap(r: Reader, table: TableEntry): Map<number, number> {
|
|
|
210
223
|
if (rangeOffset === 0) {
|
|
211
224
|
glyphId = (c + delta) & 0xffff;
|
|
212
225
|
} else {
|
|
213
|
-
const glyphIdOffset =
|
|
226
|
+
const glyphIdOffset =
|
|
227
|
+
idRangeOffsetPos + i * 2 + rangeOffset + (c - start) * 2;
|
|
214
228
|
seek(r, glyphIdOffset);
|
|
215
229
|
glyphId = u16(r);
|
|
216
230
|
if (glyphId !== 0) {
|
|
@@ -291,7 +305,12 @@ const REPEAT = 8;
|
|
|
291
305
|
const X_SAME = 16;
|
|
292
306
|
const Y_SAME = 32;
|
|
293
307
|
|
|
294
|
-
function parseGlyph(
|
|
308
|
+
function parseGlyph(
|
|
309
|
+
r: Reader,
|
|
310
|
+
glyfOffset: number,
|
|
311
|
+
loca: Uint32Array,
|
|
312
|
+
glyphId: number
|
|
313
|
+
): { path: string; bounds: [number, number, number, number] } | null {
|
|
295
314
|
const start = loca[glyphId];
|
|
296
315
|
const end = loca[glyphId + 1];
|
|
297
316
|
if (start === end) return null;
|
|
@@ -372,7 +391,11 @@ function parseGlyph(r: Reader, glyfOffset: number, loca: Uint32Array, glyphId: n
|
|
|
372
391
|
while (firstOn < points.length && !points[firstOn].on) firstOn++;
|
|
373
392
|
|
|
374
393
|
if (firstOn === points.length) {
|
|
375
|
-
const mid = {
|
|
394
|
+
const mid = {
|
|
395
|
+
x: (points[0].x + points[1].x) / 2,
|
|
396
|
+
y: (points[0].y + points[1].y) / 2,
|
|
397
|
+
on: true,
|
|
398
|
+
};
|
|
376
399
|
points.unshift(mid);
|
|
377
400
|
firstOn = 0;
|
|
378
401
|
}
|
|
@@ -412,17 +435,28 @@ function parseGlyph(r: Reader, glyfOffset: number, loca: Uint32Array, glyphId: n
|
|
|
412
435
|
return { path, bounds: [xMin, yMin, xMax, yMax] };
|
|
413
436
|
}
|
|
414
437
|
|
|
415
|
-
function parseCompositeGlyph(
|
|
438
|
+
function parseCompositeGlyph(
|
|
439
|
+
r: Reader,
|
|
440
|
+
glyfOffset: number,
|
|
441
|
+
loca: Uint32Array
|
|
442
|
+
): { path: string; bounds: [number, number, number, number] } | null {
|
|
416
443
|
let path = "";
|
|
417
|
-
let xMin = Infinity,
|
|
444
|
+
let xMin = Infinity,
|
|
445
|
+
yMin = Infinity,
|
|
446
|
+
xMax = -Infinity,
|
|
447
|
+
yMax = -Infinity;
|
|
418
448
|
let hasMore = true;
|
|
419
449
|
|
|
420
450
|
while (hasMore) {
|
|
421
451
|
const flags = u16(r);
|
|
422
452
|
const glyphIndex = u16(r);
|
|
423
453
|
|
|
424
|
-
let dx = 0,
|
|
425
|
-
|
|
454
|
+
let dx = 0,
|
|
455
|
+
dy = 0;
|
|
456
|
+
let a = 1,
|
|
457
|
+
b = 0,
|
|
458
|
+
c = 0,
|
|
459
|
+
d = 1;
|
|
426
460
|
|
|
427
461
|
if (flags & 1) {
|
|
428
462
|
dx = i16(r);
|
|
@@ -464,7 +498,15 @@ function parseCompositeGlyph(r: Reader, glyfOffset: number, loca: Uint32Array):
|
|
|
464
498
|
return { path, bounds: [xMin, yMin, xMax, yMax] };
|
|
465
499
|
}
|
|
466
500
|
|
|
467
|
-
function transformPath(
|
|
501
|
+
function transformPath(
|
|
502
|
+
path: string,
|
|
503
|
+
a: number,
|
|
504
|
+
b: number,
|
|
505
|
+
c: number,
|
|
506
|
+
d: number,
|
|
507
|
+
dx: number,
|
|
508
|
+
dy: number
|
|
509
|
+
): string {
|
|
468
510
|
return path.replace(/(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)/g, (_, x, y) => {
|
|
469
511
|
const nx = parseFloat(x) * a + parseFloat(y) * b + dx;
|
|
470
512
|
const ny = parseFloat(x) * c + parseFloat(y) * d + dy;
|
|
@@ -485,7 +527,15 @@ export function parseFont(buffer: ArrayBuffer): Font {
|
|
|
485
527
|
const glyfTable = tables.get("glyf");
|
|
486
528
|
const kernTable = tables.get("kern");
|
|
487
529
|
|
|
488
|
-
if (
|
|
530
|
+
if (
|
|
531
|
+
!headTable ||
|
|
532
|
+
!hheaTable ||
|
|
533
|
+
!hmtxTable ||
|
|
534
|
+
!maxpTable ||
|
|
535
|
+
!cmapTable ||
|
|
536
|
+
!locaTable ||
|
|
537
|
+
!glyfTable
|
|
538
|
+
) {
|
|
489
539
|
throw new Error("Missing required font tables");
|
|
490
540
|
}
|
|
491
541
|
|
|
@@ -497,14 +547,19 @@ export function parseFont(buffer: ArrayBuffer): Font {
|
|
|
497
547
|
const cmap = parseCmap(r, cmapTable);
|
|
498
548
|
const kern = kernTable ? parseKern(r, kernTable) : new Map<number, number>();
|
|
499
549
|
|
|
500
|
-
const glyphCache = new Map<
|
|
550
|
+
const glyphCache = new Map<
|
|
551
|
+
number,
|
|
552
|
+
{ path: string; bounds: [number, number, number, number] } | null
|
|
553
|
+
>();
|
|
501
554
|
const glyfOffset = glyfTable.offset;
|
|
502
555
|
|
|
503
556
|
function getGlyphId(char: string): number {
|
|
504
557
|
return cmap.get(char.codePointAt(0) ?? 0) ?? 0;
|
|
505
558
|
}
|
|
506
559
|
|
|
507
|
-
function getGlyph(
|
|
560
|
+
function getGlyph(
|
|
561
|
+
glyphId: number
|
|
562
|
+
): { path: string; bounds: [number, number, number, number] } | null {
|
|
508
563
|
if (glyphCache.has(glyphId)) return glyphCache.get(glyphId)!;
|
|
509
564
|
const glyph = parseGlyph(r, glyfOffset, loca, glyphId);
|
|
510
565
|
glyphCache.set(glyphId, glyph);
|
package/src/extras/text/index.ts
CHANGED
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
type Draw,
|
|
22
22
|
type SharedPassContext,
|
|
23
23
|
} from "../../standard/render";
|
|
24
|
-
import {
|
|
25
|
-
import { SCENE_STRUCT_WGSL } from "../../standard/render/
|
|
24
|
+
import { Z_FORMAT } from "../../standard/render/scene";
|
|
25
|
+
import { SCENE_STRUCT_WGSL } from "../../standard/render/surface/structs";
|
|
26
26
|
import { Transform } from "../../standard/transforms";
|
|
27
27
|
|
|
28
28
|
const MAX_GLYPHS = 50000;
|
|
@@ -366,7 +366,7 @@ function layoutText(text: string, atlas: GlyphAtlas, fontSize: number): LayoutRe
|
|
|
366
366
|
if (!metrics) continue;
|
|
367
367
|
|
|
368
368
|
if (prevChar) {
|
|
369
|
-
cursorX += atlas.font.kerning(prevChar, char) / atlas.font.unitsPerEm * scale;
|
|
369
|
+
cursorX += (atlas.font.kerning(prevChar, char) / atlas.font.unitsPerEm) * scale;
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
const glyphW = metrics.glyphWidth * scale;
|
|
@@ -579,7 +579,7 @@ function createTextPipeline(
|
|
|
579
579
|
cullMode: "none",
|
|
580
580
|
},
|
|
581
581
|
depthStencil: {
|
|
582
|
-
format:
|
|
582
|
+
format: Z_FORMAT,
|
|
583
583
|
depthCompare: "less",
|
|
584
584
|
depthWriteEnabled: false,
|
|
585
585
|
},
|
|
@@ -669,6 +669,8 @@ interface PendingGlyph {
|
|
|
669
669
|
a: number;
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
+
let glyphsByFont: PendingGlyph[][] = [];
|
|
673
|
+
|
|
672
674
|
const TextSystem: System = {
|
|
673
675
|
group: "draw",
|
|
674
676
|
|
|
@@ -681,7 +683,8 @@ const TextSystem: System = {
|
|
|
681
683
|
const { atlases, staging, ranges } = text;
|
|
682
684
|
const stagingU32 = new Uint32Array(staging.buffer);
|
|
683
685
|
|
|
684
|
-
|
|
686
|
+
while (glyphsByFont.length < atlases.length) glyphsByFont.push([]);
|
|
687
|
+
for (let i = 0; i < atlases.length; i++) glyphsByFont[i].length = 0;
|
|
685
688
|
|
|
686
689
|
for (const eid of state.query([Text, Transform])) {
|
|
687
690
|
if (!Text.visible[eid]) continue;
|
package/src/extras/text/sdf.ts
CHANGED
|
@@ -340,14 +340,25 @@ export class SDFGenerator {
|
|
|
340
340
|
const segments = segmentPath(path, this.curveSubdivisions);
|
|
341
341
|
if (segments.length === 0) return;
|
|
342
342
|
if (segments.length > this.maxSegments) {
|
|
343
|
-
console.warn(
|
|
343
|
+
console.warn(
|
|
344
|
+
`Too many segments (${segments.length}), truncating to ${this.maxSegments}`
|
|
345
|
+
);
|
|
344
346
|
segments.length = this.maxSegments;
|
|
345
347
|
}
|
|
346
348
|
|
|
347
349
|
const [xMin, yMin, xMax, yMax] = bounds;
|
|
348
350
|
const maxDist = Math.max(xMax - xMin, yMax - yMin) / 2;
|
|
349
351
|
|
|
350
|
-
const uniformData = new Float32Array([
|
|
352
|
+
const uniformData = new Float32Array([
|
|
353
|
+
xMin,
|
|
354
|
+
yMin,
|
|
355
|
+
xMax,
|
|
356
|
+
yMax,
|
|
357
|
+
maxDist,
|
|
358
|
+
this.exponent,
|
|
359
|
+
0,
|
|
360
|
+
0,
|
|
361
|
+
]);
|
|
351
362
|
this.device.queue.writeBuffer(this.uniformBuffer, 0, uniformData);
|
|
352
363
|
|
|
353
364
|
const segmentData = new Float32Array(segments.length * 4);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { surface } from "../standard/render/surface";
|
|
2
|
+
import type { MeshData } from "../standard/render/mesh";
|
|
3
|
+
|
|
4
|
+
const SEED1 = "vec2(127.1, 311.7)";
|
|
5
|
+
const SEED2 = "vec2(269.5, 183.3)";
|
|
6
|
+
|
|
7
|
+
export const Water = surface({
|
|
8
|
+
fragment: `
|
|
9
|
+
let p = (*surface).worldPos.xz * 3.0;
|
|
10
|
+
let t = scene.time;
|
|
11
|
+
let t1 = vec2(t * 0.6, t * 0.4);
|
|
12
|
+
let t2 = vec2(t * 0.5, t * 0.7);
|
|
13
|
+
let eps = 0.1;
|
|
14
|
+
|
|
15
|
+
let h = (value2d(p + t1, ${SEED1}) + value2d(p - t2, ${SEED2})) * 0.5;
|
|
16
|
+
let hx = (value2d(p + vec2(eps, 0.0) + t1, ${SEED1}) + value2d(p + vec2(eps, 0.0) - t2, ${SEED2})) * 0.5;
|
|
17
|
+
let hz = (value2d(p + vec2(0.0, eps) + t1, ${SEED1}) + value2d(p + vec2(0.0, eps) - t2, ${SEED2})) * 0.5;
|
|
18
|
+
|
|
19
|
+
let dx = (hx - h) / eps;
|
|
20
|
+
let dz = (hz - h) / eps;
|
|
21
|
+
(*surface).normal = normalize(vec3(-dx * 0.015, 1.0, -dz * 0.015));`,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export function createSubdividedPlane(subdivisions: number = 32): MeshData {
|
|
25
|
+
const segments = subdivisions;
|
|
26
|
+
const vertexCount = (segments + 1) * (segments + 1);
|
|
27
|
+
const indexCount = segments * segments * 6;
|
|
28
|
+
|
|
29
|
+
const vertices = new Float32Array(vertexCount * 6);
|
|
30
|
+
const indices = new Uint16Array(indexCount);
|
|
31
|
+
|
|
32
|
+
let vi = 0;
|
|
33
|
+
for (let z = 0; z <= segments; z++) {
|
|
34
|
+
for (let x = 0; x <= segments; x++) {
|
|
35
|
+
const u = x / segments;
|
|
36
|
+
const v = z / segments;
|
|
37
|
+
vertices[vi++] = u - 0.5;
|
|
38
|
+
vertices[vi++] = 0;
|
|
39
|
+
vertices[vi++] = v - 0.5;
|
|
40
|
+
vertices[vi++] = 0;
|
|
41
|
+
vertices[vi++] = 1;
|
|
42
|
+
vertices[vi++] = 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let ii = 0;
|
|
47
|
+
for (let z = 0; z < segments; z++) {
|
|
48
|
+
for (let x = 0; x < segments; x++) {
|
|
49
|
+
const topLeft = z * (segments + 1) + x;
|
|
50
|
+
const topRight = topLeft + 1;
|
|
51
|
+
const bottomLeft = (z + 1) * (segments + 1) + x;
|
|
52
|
+
const bottomRight = bottomLeft + 1;
|
|
53
|
+
|
|
54
|
+
indices[ii++] = topLeft;
|
|
55
|
+
indices[ii++] = bottomLeft;
|
|
56
|
+
indices[ii++] = topRight;
|
|
57
|
+
indices[ii++] = topRight;
|
|
58
|
+
indices[ii++] = bottomLeft;
|
|
59
|
+
indices[ii++] = bottomRight;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { vertices, indices, vertexCount, indexCount };
|
|
64
|
+
}
|
package/src/standard/defaults.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { TransformsPlugin } from "./transforms";
|
|
|
3
3
|
import { InputPlugin } from "./input";
|
|
4
4
|
import { ComputePlugin, initCanvas } from "./compute";
|
|
5
5
|
import { RenderPlugin } from "./render";
|
|
6
|
+
import { RasterPlugin } from "./raster";
|
|
6
7
|
import { ActivityPlugin, spinnerDark } from "./activity";
|
|
7
8
|
import { shallotDark } from "./loading";
|
|
8
9
|
|
|
@@ -12,6 +13,7 @@ export const DEFAULT_PLUGINS: readonly Plugin[] = [
|
|
|
12
13
|
InputPlugin,
|
|
13
14
|
ComputePlugin,
|
|
14
15
|
RenderPlugin,
|
|
16
|
+
RasterPlugin,
|
|
15
17
|
];
|
|
16
18
|
|
|
17
19
|
StateBuilder.defaultPlugins = DEFAULT_PLUGINS;
|