@aethervtt/shard-text 0.0.1 → 0.1.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.
@@ -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 { Gpu, Graph, RenderDescribers, RenderSet, Shaders } from "@aethervtt/shard-render";
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
- readonly glyphBuffer: GpuBuffer;
48
- readonly textBuffer: GpuBuffer;
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
- const storage = GPUBufferUsage.STORAGE;
57
- this.glyphBuffer = new GpuBuffer(gpu, { label: "text/glyphs", usage: storage, size: 4096 });
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.buffer)}/${idOf(store.textBuffer.buffer)}`,
436
+ `${idOf(store.glyphBuffer)}:${store.glyphBuffer.version}/${idOf(store.textBuffer)}:${store.textBuffer.version}`,
438
437
  c.layouts.data,
439
438
  () => [
440
- { binding: 0, resource: { buffer: store.glyphBuffer.buffer } },
441
- { binding: 1, resource: { buffer: store.textBuffer.buffer } }
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.1",
3
+ "version": "0.1.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.1",
20
- "@aethervtt/shard-core": "0.0.1",
21
- "@aethervtt/shard-gpu": "0.0.1",
22
- "@aethervtt/shard-render": "0.0.1",
23
- "@aethervtt/shard-runtime": "0.0.1",
24
- "@aethervtt/shard-texture": "0.0.1",
25
- "@aethervtt/shard-transform": "0.0.1",
19
+ "@aethervtt/shard-assets": "0.1.0",
20
+ "@aethervtt/shard-core": "0.1.0",
21
+ "@aethervtt/shard-gpu": "0.1.0",
22
+ "@aethervtt/shard-render": "0.1.0",
23
+ "@aethervtt/shard-runtime": "0.1.0",
24
+ "@aethervtt/shard-texture": "0.1.0",
25
+ "@aethervtt/shard-transform": "0.1.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": "d6c5c6aef4675575c878b02cf2c8f738b4190229"
38
+ "buildSha": "8e14c9896f82a3554b156f1ffdd68f2cc3e7d78a"
39
39
  }
40
40
  }