@aethervtt/shard-text 0.0.1 → 0.2.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/dist/fallback-font.d.ts +7 -0
- package/dist/fallback-font.js +48 -0
- package/dist/importer.js +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/plugin.js +14 -1
- package/dist/render.d.ts +4 -3
- package/dist/render.js +9 -10
- package/dist/shaders.js +2 -2
- package/package.json +9 -9
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Font } from './font.js';
|
|
2
|
+
/**
|
|
3
|
+
* The engine's built-in fallback font (0061): printable ASCII from the gizmo label atlas (Inter at
|
|
4
|
+
* 13 px), what a font that failed to load draws with. Its coverage stands in for the distance field,
|
|
5
|
+
* so it reads cleanly near 13 px and softens when much larger; other characters show '?'.
|
|
6
|
+
*/
|
|
7
|
+
export declare function builtinFont(): Font;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { LABEL_FONT, labelAtlas } from "@aethervtt/shard-render";
|
|
2
|
+
import { Font } from "./font.js";
|
|
3
|
+
function builtinFont() {
|
|
4
|
+
const f = LABEL_FONT;
|
|
5
|
+
const em = 13;
|
|
6
|
+
const atlas = labelAtlas();
|
|
7
|
+
const pixels = new Uint8Array(f.width * f.height * 4);
|
|
8
|
+
for (let i = 0; i < atlas.length; i++) {
|
|
9
|
+
const c = atlas[i];
|
|
10
|
+
pixels[i * 4] = c;
|
|
11
|
+
pixels[i * 4 + 1] = c;
|
|
12
|
+
pixels[i * 4 + 2] = c;
|
|
13
|
+
pixels[i * 4 + 3] = 255;
|
|
14
|
+
}
|
|
15
|
+
const glyph = (code) => {
|
|
16
|
+
const index = code - 32;
|
|
17
|
+
const col = index % f.columns;
|
|
18
|
+
const row = Math.floor(index / f.columns);
|
|
19
|
+
if (code === 32) return { u: code, a: f.advances[index] / em };
|
|
20
|
+
return {
|
|
21
|
+
u: code,
|
|
22
|
+
a: f.advances[index] / em,
|
|
23
|
+
b: [0, -(f.cellHeight - f.baseline) / em, f.cellWidth / em, f.baseline / em],
|
|
24
|
+
r: [col * f.cellWidth, row * f.cellHeight, f.cellWidth, f.cellHeight]
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const glyphs = [];
|
|
28
|
+
for (let code = 32; code < 127; code++) glyphs.push(glyph(code));
|
|
29
|
+
const json = {
|
|
30
|
+
version: 1,
|
|
31
|
+
name: "shard-fallback",
|
|
32
|
+
size: em,
|
|
33
|
+
range: 1,
|
|
34
|
+
unitsPerEm: 1e3,
|
|
35
|
+
ascent: f.baseline / em,
|
|
36
|
+
descent: -(f.cellHeight - f.baseline) / em,
|
|
37
|
+
lineGap: 0,
|
|
38
|
+
pages: [{ width: f.width, height: f.height }],
|
|
39
|
+
glyphs,
|
|
40
|
+
notdef: { ...glyph(63), u: -1 },
|
|
41
|
+
kerning: [],
|
|
42
|
+
charset: "custom"
|
|
43
|
+
};
|
|
44
|
+
return Font.fromMetrics(json, { pixels: [pixels] });
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
builtinFont
|
|
48
|
+
};
|
package/dist/importer.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@aethervtt/shard-core";
|
|
12
12
|
import { writeKtx2 } from "@aethervtt/shard-texture";
|
|
13
13
|
import { buildFont } from "./build.js";
|
|
14
|
+
import { builtinFont } from "./fallback-font.js";
|
|
14
15
|
import { Font } from "./font.js";
|
|
15
16
|
import { FontSource } from "./source.js";
|
|
16
17
|
const FontImportSettings = defineSchema(
|
|
@@ -181,7 +182,9 @@ const FontAssetType = defineAssetType("Font", {
|
|
|
181
182
|
update: (existing, next) => {
|
|
182
183
|
existing.copyFrom(next);
|
|
183
184
|
existing.linker?.link();
|
|
184
|
-
}
|
|
185
|
+
},
|
|
186
|
+
// A font that failed to load draws with the built-in one (0061).
|
|
187
|
+
fallback: () => builtinFont()
|
|
185
188
|
});
|
|
186
189
|
export {
|
|
187
190
|
FontAssetType,
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { type PackItem, type PackResult, packRects, SkylinePacker } from '@aethe
|
|
|
2
2
|
export { buildFont, type FontBuild, type FontBuildOptions, fontFromBytes } from './build.js';
|
|
3
3
|
export { type CharsetName, charsetCodepoints } from './charset.js';
|
|
4
4
|
export { Localized, SCREEN_CORNERS, ScreenText, TEXT_ALIGNS, Text } from './components.js';
|
|
5
|
+
export { builtinFont } from './fallback-font.js';
|
|
5
6
|
export { Font, type FontLoadOptions, type FontMetricsJson, FontPage, GLYPH_PADDING, Glyph, type GlyphJson, RUNTIME_PAGE_SIZE, } from './font.js';
|
|
6
7
|
export { atlasLabel, FontAssetType, FontImporter, FontImportSettings, type FontImportSettingsValue, FontStore, Fonts, } from './importer.js';
|
|
7
8
|
export { hasGposKerning, readGposKerning } from './kerning.js';
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { packRects, SkylinePacker } from "@aethervtt/shard-texture";
|
|
|
2
2
|
import { buildFont, fontFromBytes } from "./build.js";
|
|
3
3
|
import { charsetCodepoints } from "./charset.js";
|
|
4
4
|
import { Localized, SCREEN_CORNERS, ScreenText, TEXT_ALIGNS, Text } from "./components.js";
|
|
5
|
+
import { builtinFont } from "./fallback-font.js";
|
|
5
6
|
import {
|
|
6
7
|
Font,
|
|
7
8
|
FontPage,
|
|
@@ -105,6 +106,7 @@ export {
|
|
|
105
106
|
atlasLabel,
|
|
106
107
|
blitMsdf,
|
|
107
108
|
buildFont,
|
|
109
|
+
builtinFont,
|
|
108
110
|
charsetCodepoints,
|
|
109
111
|
colorEdgesSimple,
|
|
110
112
|
describeText,
|
package/dist/plugin.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Last } from "@aethervtt/shard-core";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
addRenderFeatures,
|
|
4
|
+
Gpu,
|
|
5
|
+
Graph,
|
|
6
|
+
RenderDescribers,
|
|
7
|
+
RenderSet,
|
|
8
|
+
Shaders
|
|
9
|
+
} from "@aethervtt/shard-render";
|
|
3
10
|
import { definePlugin } from "@aethervtt/shard-runtime";
|
|
4
11
|
import * as componentsModule from "./components.js";
|
|
5
12
|
import * as importerModule from "./importer.js";
|
|
@@ -33,6 +40,12 @@ const textPlugin = definePlugin({
|
|
|
33
40
|
for (const [path, source] of Object.entries(TEXT_SHADERS))
|
|
34
41
|
shaders.register(path, source, `engine:${path}`);
|
|
35
42
|
const graph = world.resource(Graph);
|
|
43
|
+
addRenderFeatures(world, {
|
|
44
|
+
name: "text",
|
|
45
|
+
description: "MSDF text in the world and on screen.",
|
|
46
|
+
nodes: ["text", "text/screen"],
|
|
47
|
+
baseline: { strategy: "Glyph and text records in data textures" }
|
|
48
|
+
});
|
|
36
49
|
graph.addNode("text", textNode(world));
|
|
37
50
|
graph.addNode("text/screen", screenTextNode(world));
|
|
38
51
|
world.initResource(RenderDescribers).set("text", (w) => describeText(w));
|
package/dist/render.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Entity, type World } from '@aethervtt/shard-core';
|
|
2
2
|
import { GpuBuffer, type GpuContext } from '@aethervtt/shard-gpu';
|
|
3
|
-
import { type NodeDescriptor } from '@aethervtt/shard-render';
|
|
3
|
+
import { DataStore, type NodeDescriptor } from '@aethervtt/shard-render';
|
|
4
4
|
import type { Font, FontPage } from './font.js';
|
|
5
5
|
import { TextLayout } from './layout.js';
|
|
6
6
|
interface TextState {
|
|
@@ -44,8 +44,9 @@ export declare class TextStore {
|
|
|
44
44
|
textCount: number;
|
|
45
45
|
readonly groups: GlyphGroup[];
|
|
46
46
|
groupCount: number;
|
|
47
|
-
|
|
48
|
-
readonly
|
|
47
|
+
/** Storage on the full tier, data textures on baseline (0064). */
|
|
48
|
+
readonly glyphBuffer: DataStore;
|
|
49
|
+
readonly textBuffer: DataStore;
|
|
49
50
|
/** Layouts redone this frame, and characters nothing could draw. */
|
|
50
51
|
relayouts: number;
|
|
51
52
|
missing: number;
|
package/dist/render.js
CHANGED
|
@@ -6,6 +6,8 @@ import { GpuBuffer } from "@aethervtt/shard-gpu";
|
|
|
6
6
|
import {
|
|
7
7
|
ComputedVisibility,
|
|
8
8
|
cameraOf,
|
|
9
|
+
DataStore,
|
|
10
|
+
dataEntry,
|
|
9
11
|
GpuAssetsResource,
|
|
10
12
|
RenderPhase,
|
|
11
13
|
Shaders,
|
|
@@ -42,6 +44,7 @@ class TextStore {
|
|
|
42
44
|
textCount = 0;
|
|
43
45
|
groups = [];
|
|
44
46
|
groupCount = 0;
|
|
47
|
+
/** Storage on the full tier, data textures on baseline (0064). */
|
|
45
48
|
glyphBuffer;
|
|
46
49
|
textBuffer;
|
|
47
50
|
/** Layouts redone this frame, and characters nothing could draw. */
|
|
@@ -53,9 +56,8 @@ class TextStore {
|
|
|
53
56
|
nextIndex = 0;
|
|
54
57
|
dirtyGlyphs = true;
|
|
55
58
|
constructor(gpu) {
|
|
56
|
-
|
|
57
|
-
this.
|
|
58
|
-
this.textBuffer = new GpuBuffer(gpu, { label: "text/records", usage: storage, size: 4096 });
|
|
59
|
+
this.glyphBuffer = new DataStore(gpu, { label: "text/glyphs", size: 4096 });
|
|
60
|
+
this.textBuffer = new DataStore(gpu, { label: "text/records", size: 4096 });
|
|
59
61
|
}
|
|
60
62
|
beginFrame() {
|
|
61
63
|
this.frame++;
|
|
@@ -329,10 +331,7 @@ function caches(ctx) {
|
|
|
329
331
|
}),
|
|
330
332
|
data: gpu.layouts.bindGroupLayout({
|
|
331
333
|
label: "text/data",
|
|
332
|
-
entries: [
|
|
333
|
-
{ binding: 0, visibility: V | F, buffer: { type: "read-only-storage" } },
|
|
334
|
-
{ binding: 1, visibility: V | F, buffer: { type: "read-only-storage" } }
|
|
335
|
-
]
|
|
334
|
+
entries: [dataEntry(gpu, 0, V | F), dataEntry(gpu, 1, V | F)]
|
|
336
335
|
}),
|
|
337
336
|
page: gpu.layouts.bindGroupLayout({
|
|
338
337
|
label: "text/page",
|
|
@@ -434,11 +433,11 @@ function drawText(ctx, space) {
|
|
|
434
433
|
group(
|
|
435
434
|
ctx,
|
|
436
435
|
"text/data",
|
|
437
|
-
`${idOf(store.glyphBuffer
|
|
436
|
+
`${idOf(store.glyphBuffer)}:${store.glyphBuffer.version}/${idOf(store.textBuffer)}:${store.textBuffer.version}`,
|
|
438
437
|
c.layouts.data,
|
|
439
438
|
() => [
|
|
440
|
-
{ binding: 0, resource:
|
|
441
|
-
{ binding: 1, resource:
|
|
439
|
+
{ binding: 0, resource: store.glyphBuffer.resource() },
|
|
440
|
+
{ binding: 1, resource: store.textBuffer.resource() }
|
|
442
441
|
]
|
|
443
442
|
)
|
|
444
443
|
);
|
package/dist/shaders.js
CHANGED
|
@@ -41,8 +41,8 @@ struct TextRecord {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
@group(0) @binding(0) var<uniform> text_view: TextView;
|
|
44
|
-
@group(1) @binding(0) var<storage, read> glyphs: array<Glyph>;
|
|
45
|
-
@group(1) @binding(1) var<storage, read> texts: array<TextRecord>;
|
|
44
|
+
@data @group(1) @binding(0) var<storage, read> glyphs: array<Glyph>;
|
|
45
|
+
@data @group(1) @binding(1) var<storage, read> texts: array<TextRecord>;
|
|
46
46
|
@group(2) @binding(0) var atlas: texture_2d<f32>;
|
|
47
47
|
@group(2) @binding(1) var atlas_sampler: sampler;
|
|
48
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aethervtt/shard-text",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@aethervtt/shard-assets": "0.0
|
|
20
|
-
"@aethervtt/shard-core": "0.0
|
|
21
|
-
"@aethervtt/shard-gpu": "0.0
|
|
22
|
-
"@aethervtt/shard-render": "0.0
|
|
23
|
-
"@aethervtt/shard-runtime": "0.0
|
|
24
|
-
"@aethervtt/shard-texture": "0.0
|
|
25
|
-
"@aethervtt/shard-transform": "0.0
|
|
19
|
+
"@aethervtt/shard-assets": "0.2.0",
|
|
20
|
+
"@aethervtt/shard-core": "0.2.0",
|
|
21
|
+
"@aethervtt/shard-gpu": "0.2.0",
|
|
22
|
+
"@aethervtt/shard-render": "0.2.0",
|
|
23
|
+
"@aethervtt/shard-runtime": "0.2.0",
|
|
24
|
+
"@aethervtt/shard-texture": "0.2.0",
|
|
25
|
+
"@aethervtt/shard-transform": "0.2.0",
|
|
26
26
|
"opentype.js": "^2.0.0"
|
|
27
27
|
},
|
|
28
28
|
"repository": {
|
|
@@ -35,6 +35,6 @@
|
|
|
35
35
|
"provenance": true
|
|
36
36
|
},
|
|
37
37
|
"shard": {
|
|
38
|
-
"buildSha": "
|
|
38
|
+
"buildSha": "32c22a3944ed23f5d1baa90bf7cc9fae724f5fd8"
|
|
39
39
|
}
|
|
40
40
|
}
|