@aethervtt/shard-render 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.
Files changed (170) hide show
  1. package/dist/ablation.d.ts +74 -0
  2. package/dist/ablation.js +117 -0
  3. package/dist/assets.d.ts +3 -0
  4. package/dist/assets.js +43 -2
  5. package/dist/atmosphere-nodes.d.ts +9 -0
  6. package/dist/atmosphere-nodes.js +157 -30
  7. package/dist/atmosphere-plugin.js +8 -2
  8. package/dist/atmosphere-shaders.js +17 -5
  9. package/dist/baseline/atmosphere.d.ts +16 -0
  10. package/dist/baseline/atmosphere.js +301 -0
  11. package/dist/baseline/data-texture.d.ts +36 -0
  12. package/dist/baseline/data-texture.js +181 -0
  13. package/dist/baseline/environment.d.ts +14 -0
  14. package/dist/baseline/environment.js +368 -0
  15. package/dist/baseline/exposure.d.ts +25 -0
  16. package/dist/baseline/exposure.js +133 -0
  17. package/dist/baseline/lights.d.ts +33 -0
  18. package/dist/baseline/lights.js +133 -0
  19. package/dist/baseline/textures.d.ts +97 -0
  20. package/dist/baseline/textures.js +203 -0
  21. package/dist/camera.d.ts +2 -0
  22. package/dist/camera.js +4 -0
  23. package/dist/crowd.d.ts +21 -0
  24. package/dist/crowd.js +121 -0
  25. package/dist/culling-shaders.js +21 -2
  26. package/dist/culling.d.ts +11 -2
  27. package/dist/culling.js +44 -18
  28. package/dist/cutaway-plugin.d.ts +48 -0
  29. package/dist/cutaway-plugin.js +364 -0
  30. package/dist/cutaway.d.ts +27 -0
  31. package/dist/cutaway.js +49 -0
  32. package/dist/data-store.d.ts +69 -0
  33. package/dist/data-store.js +105 -0
  34. package/dist/debug-shaders.js +17 -3
  35. package/dist/debug-views.js +4 -2
  36. package/dist/decals-plugin.d.ts +5 -0
  37. package/dist/decals-plugin.js +54 -0
  38. package/dist/decals.d.ts +69 -0
  39. package/dist/decals.js +326 -0
  40. package/dist/deferred-shaders.js +2 -0
  41. package/dist/deferred.js +28 -4
  42. package/dist/deform.d.ts +5 -4
  43. package/dist/deform.js +4 -9
  44. package/dist/describe-plugin.d.ts +4 -2
  45. package/dist/describe-plugin.js +75 -3
  46. package/dist/display-nodes.js +37 -13
  47. package/dist/dynamic-resolution.d.ts +2 -0
  48. package/dist/dynamic-resolution.js +6 -1
  49. package/dist/environment-plugin.js +17 -2
  50. package/dist/environment-state.d.ts +7 -3
  51. package/dist/environment-state.js +20 -9
  52. package/dist/environment.js +7 -1
  53. package/dist/features.d.ts +49 -0
  54. package/dist/features.js +106 -0
  55. package/dist/foliage-budget.d.ts +64 -0
  56. package/dist/foliage-budget.js +108 -0
  57. package/dist/foliage-path.d.ts +19 -0
  58. package/dist/foliage-path.js +7 -0
  59. package/dist/foliage-shaders.d.ts +11 -0
  60. package/dist/foliage-shaders.js +504 -0
  61. package/dist/foliage.d.ts +194 -0
  62. package/dist/foliage.js +1027 -0
  63. package/dist/forward.d.ts +38 -2
  64. package/dist/forward.js +608 -186
  65. package/dist/fxaa.js +12 -2
  66. package/dist/gizmos-plugin.js +7 -0
  67. package/dist/gizmos.d.ts +3 -3
  68. package/dist/gizmos.js +11 -13
  69. package/dist/gpu-assets.d.ts +58 -4
  70. package/dist/gpu-assets.js +191 -8
  71. package/dist/graph.d.ts +45 -0
  72. package/dist/graph.js +169 -19
  73. package/dist/health.d.ts +58 -0
  74. package/dist/health.js +112 -0
  75. package/dist/index.d.ts +40 -11
  76. package/dist/index.js +343 -9
  77. package/dist/instances.d.ts +119 -8
  78. package/dist/instances.js +387 -78
  79. package/dist/interior-plugin.d.ts +121 -0
  80. package/dist/interior-plugin.js +465 -0
  81. package/dist/interior.d.ts +24 -0
  82. package/dist/interior.js +13 -0
  83. package/dist/layers.d.ts +35 -0
  84. package/dist/layers.js +49 -0
  85. package/dist/lens-plugin.d.ts +43 -0
  86. package/dist/lens-plugin.js +304 -0
  87. package/dist/lens.d.ts +41 -0
  88. package/dist/lens.js +99 -0
  89. package/dist/lights.d.ts +50 -5
  90. package/dist/lights.js +101 -22
  91. package/dist/material-pipelines.d.ts +37 -4
  92. package/dist/material-pipelines.js +102 -5
  93. package/dist/materials.d.ts +23 -0
  94. package/dist/materials.js +44 -1
  95. package/dist/outline-plugin.d.ts +48 -0
  96. package/dist/outline-plugin.js +529 -0
  97. package/dist/outline.d.ts +15 -0
  98. package/dist/outline.js +42 -0
  99. package/dist/overlay-registry.d.ts +3 -1
  100. package/dist/overlay-registry.js +3 -1
  101. package/dist/overlays.js +6 -2
  102. package/dist/perf-overlay.d.ts +9 -0
  103. package/dist/perf-overlay.js +125 -0
  104. package/dist/picking.d.ts +17 -0
  105. package/dist/picking.js +40 -11
  106. package/dist/pixel-perfect-plugin.js +10 -2
  107. package/dist/plugin.d.ts +69 -7
  108. package/dist/plugin.js +223 -25
  109. package/dist/post-common.d.ts +22 -2
  110. package/dist/post-common.js +82 -2
  111. package/dist/post-nodes.d.ts +7 -1
  112. package/dist/post-nodes.js +235 -111
  113. package/dist/post-plugin.js +5 -3
  114. package/dist/post-scene.d.ts +130 -0
  115. package/dist/post-scene.js +164 -0
  116. package/dist/post-shaders.js +85 -62
  117. package/dist/post.js +11 -1
  118. package/dist/projection.d.ts +24 -0
  119. package/dist/projection.js +87 -0
  120. package/dist/readback.d.ts +1 -0
  121. package/dist/readback.js +1 -0
  122. package/dist/render-scale.js +1 -0
  123. package/dist/ribbons-plugin.d.ts +5 -0
  124. package/dist/ribbons-plugin.js +59 -0
  125. package/dist/ribbons.d.ts +44 -0
  126. package/dist/ribbons.js +288 -0
  127. package/dist/scenario.d.ts +70 -0
  128. package/dist/scenario.js +125 -0
  129. package/dist/screen-effects.d.ts +97 -0
  130. package/dist/screen-effects.js +192 -0
  131. package/dist/shaders.d.ts +13 -0
  132. package/dist/shaders.js +189 -34
  133. package/dist/shadow-catcher.d.ts +9 -0
  134. package/dist/shadow-catcher.js +133 -0
  135. package/dist/shadows.d.ts +27 -2
  136. package/dist/shadows.js +100 -20
  137. package/dist/standard-fields.d.ts +1 -0
  138. package/dist/standard-fields.js +5 -0
  139. package/dist/standard.js +18 -0
  140. package/dist/stats.d.ts +45 -1
  141. package/dist/stats.js +91 -3
  142. package/dist/surface-model.d.ts +57 -0
  143. package/dist/surface-model.js +289 -0
  144. package/dist/surface-shaders.d.ts +3 -0
  145. package/dist/surface-shaders.js +160 -0
  146. package/dist/surface.d.ts +40 -0
  147. package/dist/surface.js +86 -0
  148. package/dist/target.d.ts +1 -13
  149. package/dist/target.js +1 -26
  150. package/dist/testing.d.ts +11 -0
  151. package/dist/testing.js +39 -1
  152. package/dist/tier.d.ts +13 -0
  153. package/dist/tier.js +14 -0
  154. package/dist/timer.d.ts +18 -1
  155. package/dist/timer.js +73 -20
  156. package/dist/variants.d.ts +37 -0
  157. package/dist/variants.js +104 -0
  158. package/dist/vfx-draw.d.ts +37 -0
  159. package/dist/vfx-draw.js +291 -0
  160. package/dist/vfx-state.d.ts +42 -0
  161. package/dist/vfx-state.js +81 -0
  162. package/dist/vfx.d.ts +69 -0
  163. package/dist/vfx.js +103 -0
  164. package/dist/view-visibility-plugin.d.ts +61 -0
  165. package/dist/view-visibility-plugin.js +267 -0
  166. package/dist/view-visibility.d.ts +28 -0
  167. package/dist/view-visibility.js +46 -0
  168. package/dist/view.d.ts +29 -1
  169. package/dist/view.js +57 -34
  170. package/package.json +23 -11
@@ -0,0 +1,69 @@
1
+ import { type GpuContext } from '@aethervtt/shard-gpu';
2
+ /** Texels per row of a data texture (the baseline rewrite's loaders read the same). */
3
+ export declare const DATA_WIDTH = 1024;
4
+ export interface DataStoreOptions {
5
+ label: string;
6
+ /** Initial size in bytes. Default 256. */
7
+ size?: number;
8
+ /**
9
+ * Buffer usages beyond STORAGE (full tier) or UNIFORM (a baseline uniform block): a GPU pass that
10
+ * writes it, a readback. Data textures ignore it.
11
+ */
12
+ usage?: GPUBufferUsageFlags;
13
+ /** How baseline shaders read it: a data texture (default), or a uniform block. */
14
+ kind?: 'texture' | 'uniform';
15
+ }
16
+ /**
17
+ * Loads the baseline tier's data textures, once. The render plugin does it as it opens a baseline
18
+ * device, before anything makes a DataStore; so does code that makes one on its own device.
19
+ */
20
+ export declare function loadDataTextures(): Promise<void>;
21
+ /**
22
+ * The layout entry a DataStore of `kind` binds with on this device's tier, for layouts made
23
+ * before (or without) the store: storage on the full tier, a data texture or a uniform block on
24
+ * baseline.
25
+ */
26
+ export declare function dataEntry(gpu: GpuContext, binding: number, visibility: GPUShaderStageFlags, kind?: 'texture' | 'uniform', type?: GPUBufferBindingType): GPUBindGroupLayoutEntry;
27
+ /**
28
+ * Forgets the data textures `owner` made on `gpu` (an app's render plugin, as it disposes): the
29
+ * ledger destroys their textures, so they must not flush again.
30
+ */
31
+ export declare function releaseDataStores(gpu: GpuContext, owner: string): void;
32
+ /** Uploads what every baseline data texture of `gpu` was written this frame. Before the submit. */
33
+ export declare function flushDataStores(gpu: GpuContext): void;
34
+ /**
35
+ * A binding of indexed engine data that a vertex or fragment shader reads. Same calls as
36
+ * GpuBuffer: `ensureCapacity`, `write`, `version` (bumps when bind groups must be rebuilt); plus
37
+ * the layout entry and resource of whichever form the tier binds.
38
+ */
39
+ export declare class DataStore {
40
+ readonly label: string;
41
+ readonly kind: 'texture' | 'uniform';
42
+ /** Who its GPU objects count against (`gpu.owner` when it was made). */
43
+ readonly owner: string;
44
+ /** The texture form: the baseline tier's `@data` binding. */
45
+ readonly textured: boolean;
46
+ private readonly gpu;
47
+ private readonly buffer;
48
+ private readonly texture;
49
+ constructor(gpu: GpuContext, options: DataStoreOptions);
50
+ /** Bumps whenever the GPU object changes: bind groups made on the old one rebuild. */
51
+ get version(): number;
52
+ get byteLength(): number;
53
+ /**
54
+ * The buffer, on the tiers that bind one (full, and baseline uniform blocks): for full-tier
55
+ * passes that read or write it as storage (GPU culling).
56
+ */
57
+ get gpuBuffer(): GPUBuffer;
58
+ /** Grows to at least `bytes`. Returns true if the GPU object was replaced. */
59
+ ensureCapacity(bytes: number): boolean;
60
+ /** Writes a TypedArray (or a slice of it, in elements) at a byte offset, growing if needed. */
61
+ write(data: ArrayBufferView & ArrayLike<number>, byteOffset?: number, start?: number, count?: number): void;
62
+ /** The bind group layout entry for this binding on this tier. */
63
+ layoutEntry(binding: number, visibility: GPUShaderStageFlags, type?: GPUBufferBindingType): GPUBindGroupLayoutEntry;
64
+ /** What the bind group binds. Rebuild bind groups when `version` changes. */
65
+ resource(): GPUBindingResource;
66
+ /** Uploads the rows written since the last flush (data textures; the rest write through). */
67
+ flush(): void;
68
+ destroy(): void;
69
+ }
@@ -0,0 +1,105 @@
1
+ import { ShardError } from "@aethervtt/shard-core";
2
+ import { GpuBuffer } from "@aethervtt/shard-gpu";
3
+ import { DATA_TEXTURE_WIDTH } from "@aethervtt/shard-shader";
4
+ const DATA_WIDTH = DATA_TEXTURE_WIDTH;
5
+ let dataTextures;
6
+ async function loadDataTextures() {
7
+ dataTextures ??= await import("./baseline/data-texture.js");
8
+ }
9
+ function dataEntry(gpu, binding, visibility, kind = "texture", type = "read-only-storage") {
10
+ if (gpu.tier !== "baseline") return { binding, visibility, buffer: { type } };
11
+ if (kind === "uniform") return { binding, visibility, buffer: { type: "uniform" } };
12
+ return { binding, visibility, texture: { sampleType: "uint", viewDimension: "2d" } };
13
+ }
14
+ function releaseDataStores(gpu, owner) {
15
+ dataTextures?.releaseDataTextures(gpu, owner);
16
+ }
17
+ function flushDataStores(gpu) {
18
+ dataTextures?.flushDataTextures(gpu);
19
+ }
20
+ class DataStore {
21
+ label;
22
+ kind;
23
+ /** Who its GPU objects count against (`gpu.owner` when it was made). */
24
+ owner;
25
+ /** The texture form: the baseline tier's `@data` binding. */
26
+ textured;
27
+ gpu;
28
+ buffer;
29
+ texture;
30
+ constructor(gpu, options) {
31
+ this.gpu = gpu;
32
+ this.label = options.label;
33
+ this.owner = gpu.owner;
34
+ this.kind = options.kind ?? "texture";
35
+ const size = align16(Math.max(16, options.size ?? 256));
36
+ this.textured = gpu.tier === "baseline" && this.kind === "texture";
37
+ if (this.textured) {
38
+ if (!dataTextures) {
39
+ throw new ShardError(
40
+ "render/data-textures-not-loaded",
41
+ `DataStore "${options.label}" needs the baseline tier's data textures, which aren't loaded`,
42
+ { hint: "Await loadDataTextures() before making DataStores on a baseline device." }
43
+ );
44
+ }
45
+ this.texture = new dataTextures.DataTexture(gpu, options.label, size);
46
+ return;
47
+ }
48
+ this.buffer = new GpuBuffer(gpu, {
49
+ label: options.label,
50
+ usage: (gpu.tier === "baseline" ? GPUBufferUsage.UNIFORM : GPUBufferUsage.STORAGE) | (options.usage ?? 0),
51
+ size
52
+ });
53
+ }
54
+ /** Bumps whenever the GPU object changes: bind groups made on the old one rebuild. */
55
+ get version() {
56
+ return this.buffer ? this.buffer.version : this.texture.currentVersion;
57
+ }
58
+ get byteLength() {
59
+ return this.buffer ? this.buffer.byteLength : this.texture.size;
60
+ }
61
+ /**
62
+ * The buffer, on the tiers that bind one (full, and baseline uniform blocks): for full-tier
63
+ * passes that read or write it as storage (GPU culling).
64
+ */
65
+ get gpuBuffer() {
66
+ if (!this.buffer) throw new Error(`${this.label} is a data texture on this tier`);
67
+ return this.buffer.buffer;
68
+ }
69
+ /** Grows to at least `bytes`. Returns true if the GPU object was replaced. */
70
+ ensureCapacity(bytes) {
71
+ return this.buffer ? this.buffer.ensureCapacity(bytes) : this.texture.ensureCapacity(bytes);
72
+ }
73
+ /** Writes a TypedArray (or a slice of it, in elements) at a byte offset, growing if needed. */
74
+ write(data, byteOffset = 0, start = 0, count) {
75
+ if (this.buffer) this.buffer.write(data, byteOffset, start, count);
76
+ else this.texture.write(data, byteOffset, start, count);
77
+ }
78
+ /** The bind group layout entry for this binding on this tier. */
79
+ layoutEntry(binding, visibility, type = "read-only-storage") {
80
+ return dataEntry(this.gpu, binding, visibility, this.kind, type);
81
+ }
82
+ /** What the bind group binds. Rebuild bind groups when `version` changes. */
83
+ resource() {
84
+ return this.buffer ? { buffer: this.buffer.buffer } : this.texture.resource();
85
+ }
86
+ /** Uploads the rows written since the last flush (data textures; the rest write through). */
87
+ flush() {
88
+ this.texture?.flush();
89
+ }
90
+ destroy() {
91
+ this.buffer?.destroy();
92
+ this.texture?.destroy();
93
+ }
94
+ }
95
+ function align16(n) {
96
+ return n + 15 & ~15;
97
+ }
98
+ export {
99
+ DATA_WIDTH,
100
+ DataStore,
101
+ dataEntry,
102
+ flushDataStores,
103
+ loadDataTextures,
104
+ releaseDataStores
105
+ };
@@ -37,7 +37,7 @@ struct Line {
37
37
  bits: u32,
38
38
  }
39
39
 
40
- @group(1) @binding(0) var<storage, read> lines: array<Line>;
40
+ @data @group(1) @binding(0) var<storage, read> lines: array<Line>;
41
41
 
42
42
  struct LineOutput {
43
43
  @builtin(position) clip: vec4f,
@@ -112,7 +112,7 @@ struct Glyph {
112
112
  _pad1: u32,
113
113
  }
114
114
 
115
- @group(1) @binding(1) var<storage, read> glyphs: array<Glyph>;
115
+ @data @group(1) @binding(1) var<storage, read> glyphs: array<Glyph>;
116
116
  @group(1) @binding(3) var atlas: texture_2d<f32>;
117
117
 
118
118
  struct GlyphOutput {
@@ -167,11 +167,21 @@ struct PickOutput {
167
167
  import shard::view::view;
168
168
  import shard::mesh::{ instance_at, mesh_vertex_at };
169
169
  import shard::pick::types::PickOutput;
170
+ @if(CUTAWAY) import shard::cutaway::cutaway_clip;
170
171
 
171
172
  struct PickVertex {
172
173
  @builtin(position) clip: vec4f,
173
174
  @location(0) normal: vec3f,
174
175
  @location(1) @interpolate(flat) entity: u32,
176
+ /**
177
+ * Clip z and w, interpolated perspective-correct: z / w is the surface's own depth. The
178
+ * fragment's position.z includes the depth bias ground bands draw with (0057), which would move
179
+ * a picked point toward the camera.
180
+ */
181
+ @location(2) zw: vec2f,
182
+ /** Where cutaways (0070) test the surface. */
183
+ @if(CUTAWAY) @location(3) world: vec3f,
184
+ @if(CUTAWAY) @location(4) @interpolate(flat) flags: u32,
175
185
  }
176
186
 
177
187
  @vertex fn vs(
@@ -190,14 +200,18 @@ struct PickVertex {
190
200
  out.clip = view.viewProjNoJitter * vec4f(m.world_position, 1.0);
191
201
  out.normal = m.world_normal;
192
202
  out.entity = inst.entity;
203
+ out.zw = out.clip.zw;
204
+ @if(CUTAWAY) out.world = m.world_position;
205
+ @if(CUTAWAY) out.flags = m.flags;
193
206
  return out;
194
207
  }
195
208
 
196
209
  @fragment fn fs(in: PickVertex, @builtin(front_facing) front: bool) -> PickOutput {
210
+ @if(CUTAWAY) cutaway_clip(in.world, in.clip.xy, in.flags);
197
211
  var out: PickOutput;
198
212
  out.id = in.entity;
199
213
  let n = normalize(in.normal);
200
- out.normal = vec4f(select(-n, n, front), in.clip.z);
214
+ out.normal = vec4f(select(-n, n, front), in.zw.x / in.zw.y);
201
215
  return out;
202
216
  }`
203
217
  };
@@ -161,8 +161,10 @@ function describeLighting(world) {
161
161
  })),
162
162
  clusters: {
163
163
  grid: [16, 9, 24],
164
- maxLightsPerCluster: pv.clusters.latest.maxLightsPerCluster,
165
- overflows: pv.clusters.latest.overflows
164
+ // GPU clustering's stats; baseline bins on the CPU and drops lights past its budget.
165
+ maxLightsPerCluster: pv.clusters?.latest.maxLightsPerCluster ?? null,
166
+ overflows: pv.clusters?.latest.overflows ?? 0,
167
+ baselineLights: pv.baseline ? { packed: pv.baseline.count, dropped: pv.baseline.dropped } : null
166
168
  },
167
169
  cascades: pv.cascades.count,
168
170
  cascadeSplits: [...pv.cascades.splits.subarray(0, pv.cascades.count)]
@@ -0,0 +1,5 @@
1
+ import { VfxRenderer } from './vfx-draw.js';
2
+ export declare const DecalGpu: import("@aethervtt/shard-core").ResourceDef<{
3
+ renderer?: VfxRenderer;
4
+ }>;
5
+ export declare const decalsPlugin: import("@aethervtt/shard-runtime").Plugin;
@@ -0,0 +1,54 @@
1
+ import { defineResource, defineSystem, Last, PostUpdate } from "@aethervtt/shard-core";
2
+ import { definePlugin, FrameDemand } from "@aethervtt/shard-runtime";
3
+ import { TransformSystems } from "@aethervtt/shard-transform";
4
+ import { Decals, describeDecals, updateDecals } from "./decals.js";
5
+ import { addRenderFeatures } from "./features.js";
6
+ import { Graph, RenderDescribers, RenderSet, Shaders } from "./plugin.js";
7
+ import { registerShaders } from "./shaders.js";
8
+ import { DecalsPath } from "./vfx.js";
9
+ import { VFX_SHADERS, VfxRenderer } from "./vfx-draw.js";
10
+ import { computeVisibility } from "./visibility.js";
11
+ const DecalGpu = defineResource("render/DecalGpu", {
12
+ init: () => ({})
13
+ });
14
+ const prune = defineSystem({
15
+ name: "render/decals-prune",
16
+ run: (_, world) => world.resource(DecalGpu).renderer?.prune(world)
17
+ });
18
+ const decalsPlugin = definePlugin({
19
+ name: "render/decals",
20
+ dependencies: ["render/forward"],
21
+ provides: [Decals, DecalGpu, updateDecals],
22
+ build(app) {
23
+ app.world.initResource(DecalsPath);
24
+ app.world.initResource(Decals);
25
+ app.world.initResource(DecalGpu);
26
+ app.addSystems(PostUpdate, updateDecals.after(TransformSystems, computeVisibility));
27
+ app.addSystems(Last, prune.inSet(RenderSet.Prepare));
28
+ },
29
+ ready(app) {
30
+ const w = app.world, renderer = new VfxRenderer(w.resource(Decals).records, true);
31
+ w.resource(DecalGpu).renderer = renderer;
32
+ registerShaders(w.resource(Shaders), VFX_SHADERS);
33
+ addRenderFeatures(w, {
34
+ name: "render/decals",
35
+ description: "Clipped rigid-mesh projected decals.",
36
+ nodes: ["decals"],
37
+ baseline: { strategy: "CPU projection and the same vertex/fragment passes" }
38
+ });
39
+ w.resource(Graph).addNode("decals", renderer.node());
40
+ w.initResource(RenderDescribers).set("decals", describeDecals);
41
+ },
42
+ dispose(app) {
43
+ app.world.resource(DecalGpu).renderer?.dispose();
44
+ const s = app.world.resource(Decals);
45
+ s.records.length = 0;
46
+ s.receivers.length = 0;
47
+ s.receiverByEntity.clear();
48
+ app.world.tryResource(FrameDemand)?.set("render/decals", false);
49
+ }
50
+ });
51
+ export {
52
+ DecalGpu,
53
+ decalsPlugin
54
+ };
@@ -0,0 +1,69 @@
1
+ import { type Entity, type World } from '@aethervtt/shard-core';
2
+ import type { Mesh } from '@aethervtt/shard-mesh';
3
+ import { type VfxRecord } from './vfx-state.js';
4
+ export declare const DECAL_TRIANGLE_BUDGET = 32768;
5
+ export interface DecalRange {
6
+ start: number;
7
+ count: number;
8
+ entity: Entity;
9
+ layers: number;
10
+ }
11
+ interface Receiver {
12
+ entity: Entity;
13
+ matrix: Float64Array;
14
+ mesh: Mesh | undefined;
15
+ version: number;
16
+ mask: number;
17
+ visible: boolean;
18
+ unsupported: boolean;
19
+ layers: number;
20
+ seen: number;
21
+ }
22
+ export interface DecalRecord extends VfxRecord {
23
+ inverse: Float64Array;
24
+ settings: Float64Array;
25
+ geometryCount: number;
26
+ receiverRevision: number;
27
+ rebuilds: number;
28
+ ranges: DecalRange[];
29
+ clipA: Float64Array;
30
+ clipB: Float64Array;
31
+ worldTriangle: Float64Array;
32
+ }
33
+ export declare const Decals: import("@aethervtt/shard-core").ResourceDef<{
34
+ records: DecalRecord[];
35
+ receivers: Receiver[];
36
+ receiverByEntity: Map<number, Receiver>;
37
+ frame: number;
38
+ revision: number;
39
+ rejected: number;
40
+ }>;
41
+ /** Clips a convex polygon against one axis-aligned half-space. Scratch fits a clipped triangle. */
42
+ export declare function clipPlane(input: Float64Array, count: number, output: Float64Array, axis: number, sign: number, half: number): number;
43
+ /** Cold projection work. Output is all-or-nothing on budget/unsupported errors. */
44
+ export declare function projectDecal(r: DecalRecord, receivers: readonly Receiver[]): void;
45
+ export declare const updateDecals: import("@aethervtt/shard-core").SystemDef<{
46
+ q: import("@aethervtt/shard-core").Query;
47
+ receivers: import("@aethervtt/shard-core").Query;
48
+ }>;
49
+ export declare function describeDecals(world: World): {
50
+ rejected: number;
51
+ error: string | null;
52
+ receivers: number;
53
+ records: {
54
+ entity: number;
55
+ kind: "beam" | "decal" | "trail";
56
+ vertices: number;
57
+ age: number;
58
+ opacity: number;
59
+ error: string | null;
60
+ visible: boolean;
61
+ texture: string;
62
+ playing: boolean;
63
+ paused: boolean;
64
+ cpuBytes: number;
65
+ rebuilds: number;
66
+ triangles: number;
67
+ }[];
68
+ };
69
+ export {};