insomni 0.2.0-alpha.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.md +674 -0
- package/README.md +234 -0
- package/dist/advanced.d.mts +76 -0
- package/dist/advanced.mjs +81 -0
- package/dist/assemble-BT3CXbSx.mjs +1574 -0
- package/dist/camera-view-DHmMiKvP.d.mts +326 -0
- package/dist/frame-mHNdKRpF.mjs +135 -0
- package/dist/index-CmMZCMJT.d.mts +39 -0
- package/dist/index-DkJfpntS.d.mts +2417 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6612 -0
- package/dist/internal.d.mts +892 -0
- package/dist/internal.mjs +566 -0
- package/dist/logger-DSyBF3Y_.mjs +15 -0
- package/dist/particles.d.mts +816 -0
- package/dist/particles.mjs +4804 -0
- package/dist/pipeline-BWCAZTKx.mjs +470 -0
- package/dist/pipeline-DE3a1Pnk.d.mts +115 -0
- package/dist/reactivity-B7I0pvzm.mjs +191 -0
- package/dist/reactivity.d.mts +2 -0
- package/dist/reactivity.mjs +2 -0
- package/dist/renderer-DzZqd1bY.d.mts +4566 -0
- package/dist/root-CHradZKM.mjs +30 -0
- package/dist/shape-DfZP9Jdk.mjs +349 -0
- package/dist/space-CeDnj6eu.mjs +11240 -0
- package/dist/spatial-Bd3Ay8I2.d.mts +85 -0
- package/dist/spatial-hash-C1crBjTo.mjs +77 -0
- package/dist/spatial.d.mts +2 -0
- package/dist/spatial.mjs +121 -0
- package/dist/text-font-D7GGDtTK.d.mts +185 -0
- package/dist/text-ttf.d.mts +91 -0
- package/dist/text-ttf.mjs +298 -0
- package/dist/texture-dABoqFoP.mjs +131 -0
- package/dist/viewport.d.mts +2 -0
- package/dist/viewport.mjs +274 -0
- package/package.json +69 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { n as resolveRoot } from "./root-CHradZKM.mjs";
|
|
2
|
+
import { r as shapeText, t as measureBlockWidth } from "./shape-DfZP9Jdk.mjs";
|
|
3
|
+
import { r as Texture } from "./texture-dABoqFoP.mjs";
|
|
4
|
+
import { Font, MsdfGlyphAtlas as MsdfGlyphAtlas$1, loadFont, parseFont, parseFont as parseFont$1 } from "insomni-msdf-text";
|
|
5
|
+
//#region src/text/msdf-adapter.ts
|
|
6
|
+
var MsdfGlyphAtlas = class {
|
|
7
|
+
font;
|
|
8
|
+
_atlas;
|
|
9
|
+
_texture;
|
|
10
|
+
measureCache = /* @__PURE__ */ new Map();
|
|
11
|
+
measureCacheVersion = 0;
|
|
12
|
+
constructor(owner, font, options = {}) {
|
|
13
|
+
const device = resolveRoot(owner).device;
|
|
14
|
+
this.font = font;
|
|
15
|
+
this._atlas = new MsdfGlyphAtlas$1({
|
|
16
|
+
device,
|
|
17
|
+
font,
|
|
18
|
+
atlasSize: options.atlasSize,
|
|
19
|
+
atlasFontSize: options.atlasFontSize,
|
|
20
|
+
pxRange: options.pxRange,
|
|
21
|
+
label: options.label ?? `text-atlas:${font.family}`
|
|
22
|
+
});
|
|
23
|
+
this._texture = new Texture(this._atlas.texture, this._atlas.atlasSize, this._atlas.atlasSize);
|
|
24
|
+
}
|
|
25
|
+
get pxRange() {
|
|
26
|
+
return this._atlas.pxRange;
|
|
27
|
+
}
|
|
28
|
+
get atlasFontSize() {
|
|
29
|
+
return this._atlas.atlasFontSize;
|
|
30
|
+
}
|
|
31
|
+
get atlasSize() {
|
|
32
|
+
return this._atlas.atlasSize;
|
|
33
|
+
}
|
|
34
|
+
get texture() {
|
|
35
|
+
return this._texture;
|
|
36
|
+
}
|
|
37
|
+
get glyphCount() {
|
|
38
|
+
return this._atlas.glyphCount;
|
|
39
|
+
}
|
|
40
|
+
get destroyed() {
|
|
41
|
+
return this._atlas.destroyed;
|
|
42
|
+
}
|
|
43
|
+
get fillPercent() {
|
|
44
|
+
return this._atlas.fillPercent;
|
|
45
|
+
}
|
|
46
|
+
get version() {
|
|
47
|
+
return this._atlas.version;
|
|
48
|
+
}
|
|
49
|
+
getGlyph(codepoint) {
|
|
50
|
+
return this._atlas.getGlyph(codepoint);
|
|
51
|
+
}
|
|
52
|
+
getGlyphById(id) {
|
|
53
|
+
return this._atlas.getGlyphById(id);
|
|
54
|
+
}
|
|
55
|
+
measureText(text, options) {
|
|
56
|
+
const v = this._atlas.version;
|
|
57
|
+
if (this.measureCacheVersion !== v) {
|
|
58
|
+
this.measureCache.clear();
|
|
59
|
+
this.measureCacheVersion = v;
|
|
60
|
+
}
|
|
61
|
+
const simple = options.simple === true;
|
|
62
|
+
const lineHeight = options.lineHeight ?? options.fontSize * 1.2;
|
|
63
|
+
const key = `${options.fontSize}|${simple ? 1 : 0}|${options.maxWidth ?? -1}|${lineHeight}|${text}`;
|
|
64
|
+
const cached = this.measureCache.get(key);
|
|
65
|
+
if (cached !== void 0) return cached;
|
|
66
|
+
let metrics;
|
|
67
|
+
if (options.maxWidth === void 0) {
|
|
68
|
+
const width = measureBlockWidth(text, this.font, this, options.fontSize, simple);
|
|
69
|
+
let lineCount = 1;
|
|
70
|
+
if (!simple) {
|
|
71
|
+
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 10) lineCount++;
|
|
72
|
+
}
|
|
73
|
+
metrics = {
|
|
74
|
+
width: Math.max(0, width),
|
|
75
|
+
height: lineCount * lineHeight
|
|
76
|
+
};
|
|
77
|
+
} else {
|
|
78
|
+
const block = shapeText(text, this.font, this, 0, 0, {
|
|
79
|
+
fontSize: options.fontSize,
|
|
80
|
+
maxWidth: options.maxWidth,
|
|
81
|
+
lineHeight: options.lineHeight,
|
|
82
|
+
simple
|
|
83
|
+
});
|
|
84
|
+
const width = Number.isFinite(block.bbox.maxX) ? block.bbox.maxX - block.bbox.minX : 0;
|
|
85
|
+
metrics = {
|
|
86
|
+
width: Math.max(0, width),
|
|
87
|
+
height: block.height
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
this.measureCache.set(key, metrics);
|
|
91
|
+
return metrics;
|
|
92
|
+
}
|
|
93
|
+
preload(text) {
|
|
94
|
+
this._atlas.preload(text);
|
|
95
|
+
}
|
|
96
|
+
destroy() {
|
|
97
|
+
this._atlas.destroy();
|
|
98
|
+
this._texture.destroy();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/text/embedded-font.ts
|
|
103
|
+
/** Family name for the embedded subset (its `name` table was dropped by subsetting). */
|
|
104
|
+
const EMBEDDED_FONT_FAMILY = "Lato";
|
|
105
|
+
/** Base64-encoded Lato Regular subset TTF (Latin-1 + common punctuation). */
|
|
106
|
+
const EMBEDDED_FONT_B64 = "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DygPKA72DygPKA8oDygPKA8oDygAAQBeAAMACAAJAAsADQAOAA8AEAAhACIAJAAlACcAKwAsAC0AMAAxADIAMwA1ADYANwA4ADkAOgA7ADwAPQBCAEMARgBHAEkATABOAE8AUABRAFMAVwBYAFkAWgBcAGoAawBtAG4AcAByAHMAdwB5AHoAewCAAIEAggCDAIQAhQCHAJAAkgCTAJQAlQCWAJkAmgCbAJwAnQCeAKAAoQCiAKMApAClAKYAqACpAKoAqwCxALIAswC0ALUAtgC4AL4AIAAD/xwACP8cAAv/HAAO/3gAIf/IACT/yAAo/8gAMP/IADL/yAA1/0wAN/9MADj/hgA6/2gAPf9MAFf/fABY/8IAWv98AGr/HABr/3gAbf94AHD/HAB3/3gAev8cAHv/eACH/8gAkv/IAJP/yACU/8gAlf/IAJb/yACY/8gAnf9oACwAB/98AA3/TAAP/0wAEP98ABv/xAAc/8QAIAAeACL/fAAr/zoARP+6AEX/ugBG/7oATv/EAE//xABQ/7oAUf/EAFL/ugBT/8QAVv/EAHX/xACA/3wAgf98AIL/fACD/3wAhP98AIX/fACG/3wAp/+6AKj/ugCp/7oAqv+6AKv/ugCw/7oAsf/EALL/ugCz/7oAtP+6ALX/ugC2/7oAuP+6ALn/xAC6/8QAu//EALz/xAA3AAP+3gAI/t4AC/7eAA0ANgAO/zoADwA2ACD/zgAh/7AAJP+wACj/sAAw/7AAMv+wADX/VAA3/0oAOP9oADr/LAA9/0oARP/cAEX/3ABG/9wAUP/cAFL/3ABX/5QAWP+wAFr/lABq/t4Aa/86AG3/OgBw/t4Acv82AHP/NgB3/zoAef82AHr+3gB7/zoAh/+wAJL/sACT/7AAlP+wAJX/sACW/7AAmP+wAJ3/LACn/9wAqP/cAKn/3ACq/9wAq//cALD/3ACy/9wAs//cALT/3AC1/9wAtv/cALj/3AAmAAf/dgAN/wgAD/8IABD/dgAi/3YAK/9KAEL/zgBE/+IARf/iAEb/4gBQ/+IAUv/iAID/dgCB/3YAgv92AIP/dgCE/3YAhf92AIb/dgCg/84Aof/OAKL/zgCj/84ApP/OAKX/zgCm/84Ap//iAKj/4gCp/+IAqv/iAKv/4gCw/+IAsv/iALP/4gC0/+IAtf/iALb/4gC4/+IAEgAh/9IAJP/SACj/0gAw/9IAMv/SADX/zAA2/9YAh//SAJL/0gCT/9IAlP/SAJX/0gCW/9IAmP/SAJn/1gCa/9YAm//WAJz/1gBLAAf/fAAN/0wADv9MAA//TAAQ/3wAG/9gABz/YAAh/54AIv98ACT/ngAo/54AK/84ADD/ngAy/54AQv8GAET/LgBF/y4ARv8uAEj/RABO/2AAT/9gAFD/LgBR/2AAUv8uAFP/YABU/14AVv9gAFf/TABY/3QAWf9wAFr/TABb/4gAa/9MAG3/TAB1/2AAd/9MAHv/TACA/3wAgf98AIL/fACD/3wAhP98AIX/fACG/3wAh/+eAJL/ngCT/54AlP+eAJX/ngCW/54AmP+eAKD/BgCh/wYAov8GAKP/BgCk/wYApf8GAKb/BgCn/y4AqP8uAKn/LgCq/y4Aq/8uALD/LgCx/2AAsv8uALP/LgC0/y4Atf8uALb/LgC4/y4Auf9gALr/YAC7/2AAvP9gAFYAAwAwAAf/eAAIADAACwAwAA3/QAAO/5AAD/9AABD/eAAb/6gAHP+oACAAMAAh/8wAIv94ACT/zAAo/8wAK/9oADD/zAAy/8wAQv+MAET/jABF/4wARv+MAEf/4gBI/3gATv+oAE//qABQ/4wAUf+oAFL/jABT/6gAVP+WAFX/1gBW/6gAV//QAFn/zABa/9AAW/+uAGoAMABr/5AAbf+QAHAAMAByADoAcwA6AHX/qAB3/5AAeQA6AHoAMAB7/5AAgP94AIH/eACC/3gAg/94AIT/eACF/3gAhv94AIf/zACS/8wAk//MAJT/zACV/8wAlv/MAJj/zACg/4wAof+MAKL/jACj/4wApP+MAKX/jACm/4wAp/+MAKj/jACp/4wAqv+MAKv/jACw/4wAsf+oALL/jACz/4wAtP+MALX/jAC2/4wAuP+MALn/qAC6/6gAu/+oALz/qAA3AAMAMAAH/6IACAAwAAsAMAAN/4YADv/gAA//hgAQ/6IAIAAiACL/ogAr/5oAQv+oAET/4ABF/+AARv/gAEj/ngBQ/+AAUv/gAFT/0gBqADAAa//gAG3/4ABwADAAcgAwAHMAMAB3/+AAeQAwAHoAMAB7/+AAgP+iAIH/ogCC/6IAg/+iAIT/ogCF/6IAhv+iAKD/qACh/6gAov+oAKP/qACk/6gApf+oAKb/qACn/+AAqP/gAKn/4ACq/+AAq//gALD/4ACy/+AAs//gALT/4AC1/+AAtv/gALj/4AAnAA7/wgAh/+IAJP/iACj/4gAw/+IAMv/iAET/3ABF/9wARv/cAEf/zABQ/9wAUv/cAFX/rgBX/74AWP/IAFr/vgBr/8IAbf/CAHf/wgB7/8IAh//iAJL/4gCT/+IAlP/iAJX/4gCW/+IAmP/iAKf/3ACo/9wAqf/cAKr/3ACr/9wAsP/cALL/3ACz/9wAtP/cALX/3AC2/9wAuP/cACYADv+6ACAAIgAh/8YAJP/GACj/xgAw/8YAMv/GAET/2gBF/9oARv/aAFD/2gBS/9oAVP/kAFf/2ABa/9gAa/+6AG3/ugB3/7oAe/+6AIf/xgCS/8YAk//GAJT/xgCV/8YAlv/GAJj/xgCn/9oAqP/aAKn/2gCq/9oAq//aALD/2gCy/9oAs//aALT/2gC1/9oAtv/aALj/2gALAAMARAAIAEQACwBEAA3/fgAP/34AagBEAHAARAByAGQAcwBkAHkAZAB6AEQACgAN/3wAD/98AEL/2gCg/9oAof/aAKL/2gCj/9oApP/aAKX/2gCm/9oAAgAN/8IAD//CABEARP/EAEX/xABG/8QAUP/EAFL/xACn/8QAqP/EAKn/xACq/8QAq//EALD/xACy/8QAs//EALT/xAC1/8QAtv/EALj/xAAdAAf/rgAN/3wAD/98ABD/rgAi/64ARP/mAEX/5gBG/+YAUP/mAFL/5gCA/64Agf+uAIL/rgCD/64AhP+uAIX/rgCG/64Ap//mAKj/5gCp/+YAqv/mAKv/5gCw/+YAsv/mALP/5gC0/+YAtf/mALb/5gC4/+YAHQAh/9gAJP/YACj/2AAw/9gAMv/YAET/4ABF/+AARv/gAFD/4ABS/+AAh//YAJL/2ACT/9gAlP/YAJX/2ACW/9gAmP/YAKf/4ACo/+AAqf/gAKr/4ACr/+AAsP/gALL/4ACz/+AAtP/gALX/4AC2/+AAuP/gAA8AB/9IABD/SAAi/0gANwA6ADgAOgA6ACgAPQA6AID/SACB/0gAgv9IAIP/SACE/0gAhf9IAIb/SACdACgAOwAH/0oADf8cAA7/TgAP/xwAEP9KACH/0gAi/0oAJP/SACj/0gAw/9IAMv/SADcAMAA4ADAAOgAeAD0AMABC/8AARP+kAEX/pABG/6QAUP+kAFL/pABr/04Abf9OAHf/TgB7/04AgP9KAIH/SgCC/0oAg/9KAIT/SgCF/0oAhv9KAIf/0gCS/9IAk//SAJT/0gCV/9IAlv/SAJj/0gCdAB4AoP/AAKH/wACi/8AAo//AAKT/wACl/8AApv/AAKf/pACo/6QAqf+kAKr/pACr/6QAsP+kALL/pACz/6QAtP+kALX/pAC2/6QAuP+kABoAA/9OAAf/zAAI/04AC/9OAA3/eAAP/3gAEP/MACL/zAA1/0wAN/+QADj/4AA5/8IAOv9gADv/0gA9/5AAav9OAHD/TgB6/04AgP/MAIH/zACC/8wAg//MAIT/zACF/8wAhv/MAJ3/YAApAAP/SgAI/0oAC/9KAA7/zAAg/8gAIf/WACT/1gAo/9YAKwAyADD/1gAy/9YANf98ADb/yAA3/3gAOP+sADr/XAA9/3gAV/+uAFr/rgBq/0oAa//MAG3/zABw/0oAcv9IAHP/SAB3/8wAef9IAHr/SgB7/8wAh//WAJL/1gCT/9YAlP/WAJX/1gCW/9YAmP/WAJn/yACa/8gAm//IAJz/yACd/1wABQAO/2oAa/9qAG3/agB3/2oAe/9qAAwAB//IAA3/zgAP/84AEP/IACL/yACA/8gAgf/IAIL/yACD/8gAhP/IAIX/yACG/8gAVAADAB4AB/9cAAgAHgALAB4ADf9oAA7/YAAP/2gAEP9cABv/hgAc/4YAIAAiACH/sAAi/1wAJP+wACj/sAAr/zgAMP+wADL/sABC/4AARP9gAEX/YABG/2AASP9UAE7/hgBP/4YAUP9gAFH/hgBS/2AAU/+GAFT/gABW/4YAV/+cAFj/pABZ/3wAWv+cAGoAHgBr/2AAbf9gAHAAHgByADIAcwAyAHX/hgB3/2AAeQAyAHoAHgB7/2AAgP9cAIH/XACC/1wAg/9cAIT/XACF/1wAhv9cAIf/sACS/7AAk/+wAJT/sACV/7AAlv+wAJj/sACg/4AAof+AAKL/gACj/4AApP+AAKX/gACm/4AAp/9gAKj/YACp/2AAqv9gAKv/YACw/2AAsf+GALL/YACz/2AAtP9gALX/YAC2/2AAuP9gALn/hgC6/4YAu/+GALz/hgAcAAP/0gAH/9YACP/SAAr/2AAL/9IADf/IAA//yAAQ/9YAIv/WADX/ngA3/8wAOf/iADr/sAA7/7oAPf/MAD7/2ABe/9gAav/SAHD/0gB6/9IAgP/WAIH/1gCC/9YAg//WAIT/1gCF/9YAhv/WAJ3/sAAMAAP/uAAI/7gAC/+4AFf/4ABY//AAWv/gAGr/uABw/7gAcv+4AHP/uAB5/7gAev+4AA8AA/+kAAj/pAAK/+AAC/+kADf/jAA4/+AAPf+MAD7/4ABX/+YAWf/EAFr/5gBe/+AAav+kAHD/pAB6/6QAAQAAAAoAJAAyAAJERkxUAA5sYXRuAA4ABAAAAAD//wABAAAAAWxpZ2EACAAAAAEAAAABAAQABAAAAAEACAABABoAAQAIAAIABgAMAMQAAgBKAMUAAgBNAAEAAQBHAAA=";
|
|
107
|
+
/**
|
|
108
|
+
* Decode the embedded font bytes into an ArrayBuffer.
|
|
109
|
+
* Synchronous, allocation-only — no network, no I/O, SSR-safe.
|
|
110
|
+
*/
|
|
111
|
+
function decodeEmbeddedFont() {
|
|
112
|
+
return Uint8Array.from(atob(EMBEDDED_FONT_B64), (c) => c.charCodeAt(0)).buffer;
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/text/cpu-glyph-atlas.ts
|
|
116
|
+
var CpuGlyphAtlas = class {
|
|
117
|
+
font;
|
|
118
|
+
pxRange;
|
|
119
|
+
atlasFontSize;
|
|
120
|
+
atlasSize;
|
|
121
|
+
cache = /* @__PURE__ */ new Map();
|
|
122
|
+
/** Glyphs indexed by `atlasGlyphId`. Append-only; mirrors MsdfGlyphAtlas. */
|
|
123
|
+
_glyphList = [];
|
|
124
|
+
/** Bumps every time `_glyphList` grows. */
|
|
125
|
+
_version = 0;
|
|
126
|
+
measureCache = /* @__PURE__ */ new Map();
|
|
127
|
+
_destroyed = false;
|
|
128
|
+
constructor(font, options = {}) {
|
|
129
|
+
this.font = font;
|
|
130
|
+
this.atlasSize = options.atlasSize ?? 2048;
|
|
131
|
+
this.atlasFontSize = options.atlasFontSize ?? 64;
|
|
132
|
+
this.pxRange = options.pxRange ?? 8;
|
|
133
|
+
}
|
|
134
|
+
get version() {
|
|
135
|
+
return this._version;
|
|
136
|
+
}
|
|
137
|
+
get glyphCount() {
|
|
138
|
+
return this._glyphList.length;
|
|
139
|
+
}
|
|
140
|
+
get destroyed() {
|
|
141
|
+
return this._destroyed;
|
|
142
|
+
}
|
|
143
|
+
/** Always 0 — no shelf packer needed (no texture). */
|
|
144
|
+
get fillPercent() {
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* CPU atlas has no GPU texture. Throws if accessed so misuse is loud, not
|
|
149
|
+
* silent corruption. The SVG renderer never reads `texture` — it gates on
|
|
150
|
+
* `layer.atlas` and decodes via `getGlyphById` (`svg-renderer.ts:285`).
|
|
151
|
+
*/
|
|
152
|
+
get texture() {
|
|
153
|
+
throw new Error("CpuGlyphAtlas has no GPU texture — SVG/measure only; use SdfGlyphAtlas/MsdfGlyphAtlas for GPU rendering.");
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Return the glyph entry for `codepoint`, computing metrics from the font
|
|
157
|
+
* outline on first request. UVs are set to 0 (no texture).
|
|
158
|
+
*
|
|
159
|
+
* Mirrors `MsdfGlyphAtlas.getGlyph` (atlas.ts:133-232) with the
|
|
160
|
+
* shelf-packer, `generate()`, and UV-from-origin math removed.
|
|
161
|
+
*/
|
|
162
|
+
getGlyph(codepoint) {
|
|
163
|
+
const cached = this.cache.get(codepoint);
|
|
164
|
+
if (cached !== void 0) return cached;
|
|
165
|
+
const outline = this.font.getOutline(codepoint);
|
|
166
|
+
if (!outline) {
|
|
167
|
+
this.cache.set(codepoint, null);
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
if (outline.contours.length === 0) {
|
|
171
|
+
const entry = {
|
|
172
|
+
codepoint,
|
|
173
|
+
atlasGlyphId: this._glyphList.length,
|
|
174
|
+
uvMinX: 0,
|
|
175
|
+
uvMinY: 0,
|
|
176
|
+
uvMaxX: 0,
|
|
177
|
+
uvMaxY: 0,
|
|
178
|
+
pxRange: this.pxRange,
|
|
179
|
+
advance: outline.advance,
|
|
180
|
+
bearingX: 0,
|
|
181
|
+
bearingY: 0,
|
|
182
|
+
width: 0,
|
|
183
|
+
height: 0
|
|
184
|
+
};
|
|
185
|
+
this.cache.set(codepoint, entry);
|
|
186
|
+
this._glyphList.push(entry);
|
|
187
|
+
this._version++;
|
|
188
|
+
return entry;
|
|
189
|
+
}
|
|
190
|
+
const emPad = this.pxRange / this.atlasFontSize / 2;
|
|
191
|
+
const minX = outline.bbox.minX - emPad;
|
|
192
|
+
const minY = outline.bbox.minY - emPad;
|
|
193
|
+
const maxX = outline.bbox.maxX + emPad;
|
|
194
|
+
const maxY = outline.bbox.maxY + emPad;
|
|
195
|
+
const entry = {
|
|
196
|
+
codepoint,
|
|
197
|
+
atlasGlyphId: this._glyphList.length,
|
|
198
|
+
uvMinX: 0,
|
|
199
|
+
uvMinY: 0,
|
|
200
|
+
uvMaxX: 0,
|
|
201
|
+
uvMaxY: 0,
|
|
202
|
+
pxRange: this.pxRange,
|
|
203
|
+
advance: outline.advance,
|
|
204
|
+
bearingX: minX,
|
|
205
|
+
bearingY: maxY,
|
|
206
|
+
width: maxX - minX,
|
|
207
|
+
height: maxY - minY
|
|
208
|
+
};
|
|
209
|
+
this.cache.set(codepoint, entry);
|
|
210
|
+
this._glyphList.push(entry);
|
|
211
|
+
this._version++;
|
|
212
|
+
return entry;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Fetch a glyph by its `atlasGlyphId` (allocation order). O(1) array lookup.
|
|
216
|
+
* This is the decode contract: `svg-renderer.ts:512` calls this to reconstruct
|
|
217
|
+
* the original codepoint from a glyph-pack instance.
|
|
218
|
+
*/
|
|
219
|
+
getGlyphById(id) {
|
|
220
|
+
return this._glyphList[id];
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Verbatim copy of `msdf-adapter.ts:75-109` — depends only on `this.font`
|
|
224
|
+
* and `this` as the GlyphAtlas shaper arg (no GPU involvement).
|
|
225
|
+
*/
|
|
226
|
+
measureText(text, options) {
|
|
227
|
+
const simple = options.simple === true;
|
|
228
|
+
const lineHeight = options.lineHeight ?? options.fontSize * 1.2;
|
|
229
|
+
const key = `${options.fontSize}|${simple ? 1 : 0}|${options.maxWidth ?? -1}|${lineHeight}|${text}`;
|
|
230
|
+
const cached = this.measureCache.get(key);
|
|
231
|
+
if (cached !== void 0) return cached;
|
|
232
|
+
let metrics;
|
|
233
|
+
if (options.maxWidth === void 0) {
|
|
234
|
+
const width = measureBlockWidth(text, this.font, this, options.fontSize, simple);
|
|
235
|
+
let lineCount = 1;
|
|
236
|
+
if (!simple) {
|
|
237
|
+
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 10) lineCount++;
|
|
238
|
+
}
|
|
239
|
+
metrics = {
|
|
240
|
+
width: Math.max(0, width),
|
|
241
|
+
height: lineCount * lineHeight
|
|
242
|
+
};
|
|
243
|
+
} else {
|
|
244
|
+
const block = shapeText(text, this.font, this, 0, 0, {
|
|
245
|
+
fontSize: options.fontSize,
|
|
246
|
+
maxWidth: options.maxWidth,
|
|
247
|
+
lineHeight: options.lineHeight,
|
|
248
|
+
simple
|
|
249
|
+
});
|
|
250
|
+
const width = Number.isFinite(block.bbox.maxX) ? block.bbox.maxX - block.bbox.minX : 0;
|
|
251
|
+
metrics = {
|
|
252
|
+
width: Math.max(0, width),
|
|
253
|
+
height: block.height
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
this.measureCache.set(key, metrics);
|
|
257
|
+
return metrics;
|
|
258
|
+
}
|
|
259
|
+
/** Pre-warm the glyph cache for a string of text. No GPU work. */
|
|
260
|
+
preload(text) {
|
|
261
|
+
for (const ch of text) this.getGlyph(ch.codePointAt(0));
|
|
262
|
+
}
|
|
263
|
+
/** Clear caches and mark as destroyed. */
|
|
264
|
+
destroy() {
|
|
265
|
+
if (this._destroyed) return;
|
|
266
|
+
this._destroyed = true;
|
|
267
|
+
this.cache.clear();
|
|
268
|
+
this._glyphList.length = 0;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* Module-scope lazy singleton: parses the embedded Lato subset font ONCE and
|
|
273
|
+
* reuses the atlas across every `toSVG()` call. O(1) after first load.
|
|
274
|
+
*
|
|
275
|
+
* Do NOT destroy this instance — it is shared across all export calls.
|
|
276
|
+
*/
|
|
277
|
+
let _shared = null;
|
|
278
|
+
function sharedCpuGlyphAtlas() {
|
|
279
|
+
if (_shared === null) _shared = new CpuGlyphAtlas(parseFont$1(decodeEmbeddedFont(), { family: EMBEDDED_FONT_FAMILY }));
|
|
280
|
+
return _shared;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Create a non-singleton `CpuGlyphAtlas`, optionally with a custom font.
|
|
284
|
+
*
|
|
285
|
+
* - Pass `font` (an already-parsed `Font`) for zero-overhead construction.
|
|
286
|
+
* - Pass `fontBytes` (ArrayBuffer or Uint8Array) to parse on construction.
|
|
287
|
+
* - Pass neither to fall back to the embedded Lato subset (same font as the
|
|
288
|
+
* shared singleton, but a fresh atlas instance).
|
|
289
|
+
*/
|
|
290
|
+
function createCpuGlyphAtlas(opts = {}) {
|
|
291
|
+
let font;
|
|
292
|
+
if (opts.font !== void 0) font = opts.font;
|
|
293
|
+
else if (opts.fontBytes !== void 0) font = parseFont$1(opts.fontBytes);
|
|
294
|
+
else font = parseFont$1(decodeEmbeddedFont(), { family: EMBEDDED_FONT_FAMILY });
|
|
295
|
+
return new CpuGlyphAtlas(font, opts.options);
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
export { CpuGlyphAtlas, Font, MsdfGlyphAtlas, createCpuGlyphAtlas, loadFont, parseFont, sharedCpuGlyphAtlas };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { n as resolveRoot } from "./root-CHradZKM.mjs";
|
|
2
|
+
//#region src/shared/texture.ts
|
|
3
|
+
let _nextTextureId = 0;
|
|
4
|
+
/**
|
|
5
|
+
* Caller-owned GPU texture wrapper used by sprite APIs.
|
|
6
|
+
*
|
|
7
|
+
* `Layer`, `SpriteAtlas`, `GridAtlas`, and `Renderer2D` may retain references
|
|
8
|
+
* to a `Texture`, but none of them take ownership of it or destroy it on the caller's behalf.
|
|
9
|
+
*/
|
|
10
|
+
var Texture = class {
|
|
11
|
+
id;
|
|
12
|
+
gpuTexture;
|
|
13
|
+
view;
|
|
14
|
+
width;
|
|
15
|
+
height;
|
|
16
|
+
_destroyed = false;
|
|
17
|
+
constructor(gpuTexture, width, height) {
|
|
18
|
+
this.id = _nextTextureId++;
|
|
19
|
+
this.gpuTexture = gpuTexture;
|
|
20
|
+
this.view = gpuTexture.createView();
|
|
21
|
+
this.width = width;
|
|
22
|
+
this.height = height;
|
|
23
|
+
}
|
|
24
|
+
/** Sub-region by pixel coordinates. */
|
|
25
|
+
region(x, y, w, h) {
|
|
26
|
+
this.ensureAlive();
|
|
27
|
+
assertTextureRect(x, y, w, h, this.width, this.height);
|
|
28
|
+
return {
|
|
29
|
+
texture: this,
|
|
30
|
+
uvMin: [x / this.width, y / this.height],
|
|
31
|
+
uvMax: [(x + w) / this.width, (y + h) / this.height]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Sub-region by normalized UV coordinates. */
|
|
35
|
+
regionUV(u0, v0, u1, v1) {
|
|
36
|
+
this.ensureAlive();
|
|
37
|
+
return {
|
|
38
|
+
texture: this,
|
|
39
|
+
uvMin: [u0, v0],
|
|
40
|
+
uvMax: [u1, v1]
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
get destroyed() {
|
|
44
|
+
return this._destroyed;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Release the underlying GPU texture.
|
|
48
|
+
*
|
|
49
|
+
* Destroying a texture that is still referenced by a `Layer` is a caller error.
|
|
50
|
+
* Future sprite draws that still reference it will throw a clear runtime error.
|
|
51
|
+
*/
|
|
52
|
+
destroy() {
|
|
53
|
+
if (this._destroyed) return;
|
|
54
|
+
this._destroyed = true;
|
|
55
|
+
this.gpuTexture.destroy();
|
|
56
|
+
}
|
|
57
|
+
ensureAlive() {
|
|
58
|
+
if (this._destroyed) throw new Error("Texture has been destroyed.");
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var SpriteAtlas = class {
|
|
62
|
+
_regions;
|
|
63
|
+
constructor(texture, regions) {
|
|
64
|
+
this._regions = new Map(Object.entries(regions).map(([name, def]) => [name, texture.region(def.x, def.y, def.w, def.h)]));
|
|
65
|
+
}
|
|
66
|
+
region(name) {
|
|
67
|
+
const r = this._regions.get(name);
|
|
68
|
+
if (!r) throw new Error(`SpriteAtlas: region "${name}" not found.`);
|
|
69
|
+
return r;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var GridAtlas = class {
|
|
73
|
+
texture;
|
|
74
|
+
cellW;
|
|
75
|
+
cellH;
|
|
76
|
+
cols;
|
|
77
|
+
rows;
|
|
78
|
+
constructor(texture, options) {
|
|
79
|
+
this.texture = texture;
|
|
80
|
+
this.cellW = options.cell[0];
|
|
81
|
+
this.cellH = options.cell[1];
|
|
82
|
+
if (this.cellW <= 0 || this.cellH <= 0) throw new Error("GridAtlas cell dimensions must be positive.");
|
|
83
|
+
const maxCols = Math.floor(texture.width / this.cellW);
|
|
84
|
+
const maxRows = Math.floor(texture.height / this.cellH);
|
|
85
|
+
if (maxCols < 1 || maxRows < 1) throw new Error("GridAtlas cell dimensions must fit inside the texture.");
|
|
86
|
+
this.cols = options.cols ?? maxCols;
|
|
87
|
+
this.rows = options.rows ?? maxRows;
|
|
88
|
+
if (!Number.isInteger(this.cols) || !Number.isInteger(this.rows) || this.cols < 1 || this.rows < 1) throw new Error("GridAtlas rows and cols must be positive integers.");
|
|
89
|
+
if (this.cols > maxCols || this.rows > maxRows) throw new Error(`GridAtlas ${this.rows}x${this.cols} exceeds the ${maxRows}x${maxCols} grid that fits in this texture.`);
|
|
90
|
+
}
|
|
91
|
+
/** Get a frame by linear index, or by (row, col). */
|
|
92
|
+
frame(indexOrRow, col) {
|
|
93
|
+
const row = col === void 0 ? Math.floor(indexOrRow / this.cols) : indexOrRow;
|
|
94
|
+
const c = col === void 0 ? indexOrRow % this.cols : col;
|
|
95
|
+
if (!Number.isInteger(row) || !Number.isInteger(c) || row < 0 || row >= this.rows || c < 0 || c >= this.cols) throw new Error(`GridAtlas frame (${row}, ${c}) is out of bounds for a ${this.rows}x${this.cols} atlas.`);
|
|
96
|
+
return this.texture.region(c * this.cellW, row * this.cellH, this.cellW, this.cellH);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Load a texture from a URL or any ImageBitmapSource.
|
|
101
|
+
* The result is in premultiplied alpha format, matching the renderer's blend state.
|
|
102
|
+
*
|
|
103
|
+
* The returned `Texture` remains caller-owned. The renderer may cache per-texture bind groups
|
|
104
|
+
* while it is in use, but it will never destroy the texture for you.
|
|
105
|
+
*/
|
|
106
|
+
async function loadTexture(owner, src, options = {}) {
|
|
107
|
+
const device = resolveRoot(owner).device;
|
|
108
|
+
const bitmap = typeof src === "string" ? await createImageBitmap(await (await fetch(src)).blob()) : await createImageBitmap(src);
|
|
109
|
+
const width = bitmap.width;
|
|
110
|
+
const height = bitmap.height;
|
|
111
|
+
const format = options.format ?? "rgba8unorm";
|
|
112
|
+
const gpuTexture = device.createTexture({
|
|
113
|
+
label: options.label,
|
|
114
|
+
size: [width, height],
|
|
115
|
+
format,
|
|
116
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
|
|
117
|
+
});
|
|
118
|
+
device.queue.copyExternalImageToTexture({ source: bitmap }, {
|
|
119
|
+
texture: gpuTexture,
|
|
120
|
+
premultipliedAlpha: true
|
|
121
|
+
}, [width, height]);
|
|
122
|
+
bitmap.close();
|
|
123
|
+
return new Texture(gpuTexture, width, height);
|
|
124
|
+
}
|
|
125
|
+
function assertTextureRect(x, y, w, h, textureWidth, textureHeight) {
|
|
126
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(w) || !Number.isFinite(h)) throw new Error("Texture region coordinates must be finite.");
|
|
127
|
+
if (w <= 0 || h <= 0) throw new Error("Texture region dimensions must be positive.");
|
|
128
|
+
if (x < 0 || y < 0 || x + w > textureWidth || y + h > textureHeight) throw new Error(`Texture region (${x}, ${y}, ${w}, ${h}) is out of bounds for a ${textureWidth}x${textureHeight} texture.`);
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
export { loadTexture as i, SpriteAtlas as n, Texture as r, GridAtlas as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as ViewportLike, b as worldCullBounds, d as CameraPanBoundsOptions, f as CameraViewport, g as Viewport, h as PanBoundsMargins, m as PanBoundsMargin, p as CameraViewportOptions, u as CameraInternal, v as ZoomFactor, y as createViewport } from "./camera-view-DHmMiKvP.mjs";
|
|
2
|
+
export { CameraInternal, CameraPanBoundsOptions, CameraViewport, CameraViewportOptions, PanBoundsMargin, PanBoundsMargins, Viewport, ViewportLike, ZoomFactor, createViewport, worldCullBounds };
|