@aethervtt/shard-render 0.0.1

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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/assets.d.ts +104 -0
  4. package/dist/assets.js +213 -0
  5. package/dist/atmosphere-model.d.ts +96 -0
  6. package/dist/atmosphere-model.js +370 -0
  7. package/dist/atmosphere-nodes.d.ts +55 -0
  8. package/dist/atmosphere-nodes.js +780 -0
  9. package/dist/atmosphere-plugin.d.ts +5 -0
  10. package/dist/atmosphere-plugin.js +42 -0
  11. package/dist/atmosphere-shaders.d.ts +7 -0
  12. package/dist/atmosphere-shaders.js +595 -0
  13. package/dist/atmosphere-state.d.ts +72 -0
  14. package/dist/atmosphere-state.js +18 -0
  15. package/dist/atmosphere.d.ts +191 -0
  16. package/dist/atmosphere.js +950 -0
  17. package/dist/camera.d.ts +83 -0
  18. package/dist/camera.js +163 -0
  19. package/dist/clusters.d.ts +68 -0
  20. package/dist/clusters.js +288 -0
  21. package/dist/culling-shaders.d.ts +2 -0
  22. package/dist/culling-shaders.js +203 -0
  23. package/dist/culling.d.ts +84 -0
  24. package/dist/culling.js +498 -0
  25. package/dist/debug-shaders.d.ts +3 -0
  26. package/dist/debug-shaders.js +207 -0
  27. package/dist/debug-views.d.ts +60 -0
  28. package/dist/debug-views.js +197 -0
  29. package/dist/deferred-plugin.d.ts +5 -0
  30. package/dist/deferred-plugin.js +20 -0
  31. package/dist/deferred-shaders.d.ts +2 -0
  32. package/dist/deferred-shaders.js +151 -0
  33. package/dist/deferred.d.ts +22 -0
  34. package/dist/deferred.js +296 -0
  35. package/dist/deform.d.ts +80 -0
  36. package/dist/deform.js +213 -0
  37. package/dist/describe-plugin.d.ts +5 -0
  38. package/dist/describe-plugin.js +19 -0
  39. package/dist/display-nodes.d.ts +5 -0
  40. package/dist/display-nodes.js +189 -0
  41. package/dist/dynamic-resolution.d.ts +47 -0
  42. package/dist/dynamic-resolution.js +191 -0
  43. package/dist/environment-plugin.d.ts +6 -0
  44. package/dist/environment-plugin.js +44 -0
  45. package/dist/environment-shaders.d.ts +2 -0
  46. package/dist/environment-shaders.js +260 -0
  47. package/dist/environment-state.d.ts +71 -0
  48. package/dist/environment-state.js +144 -0
  49. package/dist/environment.d.ts +70 -0
  50. package/dist/environment.js +529 -0
  51. package/dist/forward.d.ts +123 -0
  52. package/dist/forward.js +1216 -0
  53. package/dist/fxaa.d.ts +2 -0
  54. package/dist/fxaa.js +65 -0
  55. package/dist/gizmo-font.d.ts +21 -0
  56. package/dist/gizmo-font.js +132 -0
  57. package/dist/gizmos-plugin.d.ts +5 -0
  58. package/dist/gizmos-plugin.js +34 -0
  59. package/dist/gizmos.d.ts +156 -0
  60. package/dist/gizmos.js +772 -0
  61. package/dist/gpu-assets.d.ts +114 -0
  62. package/dist/gpu-assets.js +494 -0
  63. package/dist/graph.d.ts +204 -0
  64. package/dist/graph.js +417 -0
  65. package/dist/index.d.ts +53 -0
  66. package/dist/index.js +540 -0
  67. package/dist/instances.d.ts +349 -0
  68. package/dist/instances.js +1335 -0
  69. package/dist/large-world.d.ts +13 -0
  70. package/dist/large-world.js +20 -0
  71. package/dist/lights.d.ts +160 -0
  72. package/dist/lights.js +468 -0
  73. package/dist/material-noise.d.ts +19 -0
  74. package/dist/material-noise.js +7 -0
  75. package/dist/material-pipelines.d.ts +46 -0
  76. package/dist/material-pipelines.js +166 -0
  77. package/dist/materials.d.ts +108 -0
  78. package/dist/materials.js +219 -0
  79. package/dist/noise.d.ts +76 -0
  80. package/dist/noise.js +286 -0
  81. package/dist/overlay-registry.d.ts +18 -0
  82. package/dist/overlay-registry.js +30 -0
  83. package/dist/overlays.d.ts +35 -0
  84. package/dist/overlays.js +344 -0
  85. package/dist/paths.d.ts +20 -0
  86. package/dist/paths.js +46 -0
  87. package/dist/picking-plugin.d.ts +2 -0
  88. package/dist/picking-plugin.js +20 -0
  89. package/dist/picking.d.ts +94 -0
  90. package/dist/picking.js +456 -0
  91. package/dist/pixel-perfect-plugin.d.ts +9 -0
  92. package/dist/pixel-perfect-plugin.js +135 -0
  93. package/dist/pixel-perfect.d.ts +27 -0
  94. package/dist/pixel-perfect.js +70 -0
  95. package/dist/plugin.d.ts +111 -0
  96. package/dist/plugin.js +182 -0
  97. package/dist/pool.d.ts +19 -0
  98. package/dist/pool.js +43 -0
  99. package/dist/post-common.d.ts +51 -0
  100. package/dist/post-common.js +148 -0
  101. package/dist/post-nodes.d.ts +39 -0
  102. package/dist/post-nodes.js +849 -0
  103. package/dist/post-plugin.d.ts +5 -0
  104. package/dist/post-plugin.js +26 -0
  105. package/dist/post-shaders.d.ts +8 -0
  106. package/dist/post-shaders.js +698 -0
  107. package/dist/post.d.ts +175 -0
  108. package/dist/post.js +453 -0
  109. package/dist/readback.d.ts +4 -0
  110. package/dist/readback.js +95 -0
  111. package/dist/render-scale.d.ts +53 -0
  112. package/dist/render-scale.js +63 -0
  113. package/dist/shaders.d.ts +122 -0
  114. package/dist/shaders.js +1168 -0
  115. package/dist/shadows.d.ts +119 -0
  116. package/dist/shadows.js +562 -0
  117. package/dist/skin-asset.d.ts +26 -0
  118. package/dist/skin-asset.js +25 -0
  119. package/dist/skinning-plugin.d.ts +5 -0
  120. package/dist/skinning-plugin.js +16 -0
  121. package/dist/skinning.d.ts +19 -0
  122. package/dist/skinning.js +343 -0
  123. package/dist/standard-fields.d.ts +67 -0
  124. package/dist/standard-fields.js +73 -0
  125. package/dist/standard.d.ts +7 -0
  126. package/dist/standard.js +37 -0
  127. package/dist/stats.d.ts +25 -0
  128. package/dist/stats.js +18 -0
  129. package/dist/target.d.ts +55 -0
  130. package/dist/target.js +70 -0
  131. package/dist/testing.d.ts +34 -0
  132. package/dist/testing.js +126 -0
  133. package/dist/timer.d.ts +28 -0
  134. package/dist/timer.js +136 -0
  135. package/dist/view.d.ts +117 -0
  136. package/dist/view.js +389 -0
  137. package/dist/visibility.d.ts +10 -0
  138. package/dist/visibility.js +84 -0
  139. package/package.json +49 -0
package/dist/view.js ADDED
@@ -0,0 +1,389 @@
1
+ import {
2
+ affine,
3
+ defineComponent,
4
+ defineResource,
5
+ defineSystem,
6
+ frustum,
7
+ mat4,
8
+ t,
9
+ vec3
10
+ } from "@aethervtt/shard-core";
11
+ import { LogResource, Time } from "@aethervtt/shard-runtime";
12
+ import { GlobalTransform } from "@aethervtt/shard-transform";
13
+ import { RenderTargets } from "./assets.js";
14
+ import { Camera3d, Exposure, exposureScale } from "./camera.js";
15
+ import { createDrawList } from "./instances.js";
16
+ import {
17
+ PixelPerfect,
18
+ PixelPerfectPath,
19
+ pixelPerfectLayout
20
+ } from "./pixel-perfect.js";
21
+ import { Views, Window } from "./plugin.js";
22
+ import {
23
+ antialiasingOf,
24
+ CORE_EFFECTS,
25
+ createPostSettings,
26
+ extractPost,
27
+ PostEffect,
28
+ PostFeatures,
29
+ postAliases
30
+ } from "./post.js";
31
+ import { RenderScale, scaledSize } from "./render-scale.js";
32
+ const TONEMAP_CURVES = ["aces", "agx", "pbr-neutral", "reinhard", "none"];
33
+ const DEFAULT_CURVE = "agx";
34
+ const Tonemapping = defineComponent(
35
+ "render/Tonemapping",
36
+ {
37
+ curve: t.enum(TONEMAP_CURVES, {
38
+ default: DEFAULT_CURVE,
39
+ description: "How HDR becomes display color. agx: saturated highlights (glows, lava, neon) keep their hue; aces: punchy filmic contrast; pbr-neutral: faithful product colors (Khronos); reinhard: simple, soft; none: clamp only, for measuring."
40
+ }),
41
+ dither: t.bool({ default: true, description: "Adds \xB11 LSB noise against banding." })
42
+ },
43
+ {
44
+ description: "Tonemapping for a camera. Without it, cameras use the default curve with dithering."
45
+ }
46
+ );
47
+ const RenderPath = defineComponent(
48
+ "render/RenderPath",
49
+ {
50
+ mode: t.enum(["forward", "deferred"], {
51
+ description: "forward: simpler, supports MSAA, fine up to a few hundred lights. deferred: lights each pixel once (heavy overdraw, many lights) and gives G-buffer effects; anti-alias with FXAA or TAA."
52
+ })
53
+ },
54
+ {
55
+ description: "How a camera shades opaque geometry. Materials work in both; custom-lit and transparent ones always draw forward."
56
+ }
57
+ );
58
+ const DeferredPath = defineResource("render/DeferredPath", {
59
+ description: "Present when the deferred path (deferredPlugin) is installed."
60
+ });
61
+ const Cameras = defineResource("render/Cameras", {
62
+ description: "Per-camera render data by entity, extracted each frame.",
63
+ init: () => /* @__PURE__ */ new Map()
64
+ });
65
+ const ViewSettings = defineResource("render/ViewSettings", {
66
+ description: "Render settings shared by all views: the default MSAA sample count, and the display density past which it is skipped.",
67
+ init: () => ({ msaa: 4, msaaMaxPixelRatio: 1.5 })
68
+ });
69
+ const scratchProj = mat4.create();
70
+ const scratchSnap = affine.create();
71
+ const scratchView = affine.create();
72
+ const NO_MSAA_ALIASES = Object.freeze({
73
+ "scene-color": "hdr",
74
+ "scene-depth": "depth",
75
+ ldr: "view-target",
76
+ display: "view-target"
77
+ });
78
+ const MSAA_ALIASES = Object.freeze({ ldr: "view-target", display: "view-target" });
79
+ const SCALED_NO_MSAA_ALIASES = Object.freeze({
80
+ "scene-color": "hdr",
81
+ "scene-depth": "depth",
82
+ ldr: "display"
83
+ });
84
+ const SCALED_MSAA_ALIASES = Object.freeze({ ldr: "display" });
85
+ function isScaled(cam) {
86
+ return cam.width !== cam.displayWidth || cam.height !== cam.displayHeight;
87
+ }
88
+ function viewAliases(cam) {
89
+ if (isScaled(cam)) return cam.msaa > 1 ? SCALED_MSAA_ALIASES : SCALED_NO_MSAA_ALIASES;
90
+ return cam.msaa > 1 ? MSAA_ALIASES : NO_MSAA_ALIASES;
91
+ }
92
+ const reportedEffects = /* @__PURE__ */ new WeakMap();
93
+ const reportedDeferred = /* @__PURE__ */ new WeakSet();
94
+ function warnMissingDeferred(world) {
95
+ if (reportedDeferred.has(world)) return;
96
+ reportedDeferred.add(world);
97
+ world.tryResource(LogResource)?.log(
98
+ "warn",
99
+ "A camera asks for RenderPath deferred, but deferredPlugin isn't installed; it renders forward",
100
+ {
101
+ code: "render/feature-missing",
102
+ hint: "Add deferredPlugin from '@aethervtt/shard-render' (forwardPlugin includes it)."
103
+ }
104
+ );
105
+ }
106
+ const reportedPixel = /* @__PURE__ */ new WeakSet();
107
+ function warnMissingPixelPerfect(world) {
108
+ if (reportedPixel.has(world)) return;
109
+ reportedPixel.add(world);
110
+ world.tryResource(LogResource)?.log(
111
+ "warn",
112
+ "A camera has PixelPerfect, but pixelPerfectPlugin isn't installed; it renders at full resolution",
113
+ {
114
+ code: "render/feature-missing",
115
+ hint: "Add pixelPerfectPlugin from '@aethervtt/shard-render' (forwardPlugin includes it)."
116
+ }
117
+ );
118
+ }
119
+ function warnMissingEffects(world, missing) {
120
+ const reported = reportedEffects.get(world) ?? 0;
121
+ const fresh = missing & ~reported;
122
+ if (fresh === 0) return;
123
+ reportedEffects.set(world, reported | fresh);
124
+ const names = Object.entries(PostEffect).filter(([, bit]) => (fresh & bit) !== 0).map(([name]) => name);
125
+ const plugin = fresh & PostEffect.Fxaa && fresh === PostEffect.Fxaa ? "fxaaPlugin" : "postPlugin";
126
+ world.tryResource(LogResource)?.log(
127
+ "warn",
128
+ `A camera asks for ${names.join(", ")}, but ${plugin} isn't installed; it renders without them`,
129
+ {
130
+ code: "render/feature-missing",
131
+ hint: `Add ${plugin} from '@aethervtt/shard-render' (forwardPlugin includes it).`
132
+ }
133
+ );
134
+ }
135
+ const extractCameras = defineSystem({
136
+ name: "render/extract-cameras",
137
+ description: "Turns Camera3d entities into render views with matrices, frustums, and exposure.",
138
+ setup: (world) => ({ q: world.query({ with: [Camera3d, GlobalTransform, Exposure] }) }),
139
+ run: ({ q }, world) => {
140
+ const cameras = world.resource(Cameras);
141
+ const views = world.resource(Views).list;
142
+ const window = world.tryResource(Window);
143
+ const targets = world.resource(RenderTargets);
144
+ const settings = world.resource(ViewSettings);
145
+ const scale = world.tryResource(RenderScale);
146
+ if (scale) scale.windowViews = 0;
147
+ const delta = world.resource(Time).delta;
148
+ const installed = world.tryResource(PostFeatures)?.effects ?? CORE_EFFECTS;
149
+ const deferredInstalled = world.hasResource(DeferredPath);
150
+ const pixelInstalled = world.hasResource(PixelPerfectPath);
151
+ for (const table of q.tables) {
152
+ const projection = table.column(Camera3d, "projection");
153
+ const fovY = table.column(Camera3d, "fovY");
154
+ const near = table.column(Camera3d, "near");
155
+ const far = table.column(Camera3d, "far");
156
+ const orthoHeight = table.column(Camera3d, "orthoHeight");
157
+ const order = table.column(Camera3d, "order");
158
+ const clear = table.column(Camera3d, "clearColor");
159
+ const target = table.column(Camera3d, "target");
160
+ const active = table.column(Camera3d, "active");
161
+ const g = table.column(GlobalTransform, "matrix");
162
+ const ev = table.column(Exposure, "ev100");
163
+ const path = table.has(RenderPath) ? table.column(RenderPath, "mode") : void 0;
164
+ const hasTonemap = table.has(Tonemapping);
165
+ const curve = hasTonemap ? table.column(Tonemapping, "curve") : void 0;
166
+ const dither = hasTonemap ? table.column(Tonemapping, "dither") : void 0;
167
+ if (table.has(PixelPerfect) && !pixelInstalled) warnMissingPixelPerfect(world);
168
+ const pixel = pixelInstalled && table.has(PixelPerfect);
169
+ const ppu = pixel ? table.column(PixelPerfect, "pixelsPerUnit") : void 0;
170
+ const snap = pixel ? table.column(PixelPerfect, "snap") : void 0;
171
+ for (let i = 0; i < table.count; i++) {
172
+ if (active[i] === 0) {
173
+ const idle = cameras.get(table.entities[i]);
174
+ if (idle) idle.frames = 0;
175
+ continue;
176
+ }
177
+ const shown = target[i] ? targets.get(target[i]) : window;
178
+ if (!shown) continue;
179
+ let rt = shown;
180
+ const entity = table.entities[i];
181
+ let cam = cameras.get(entity);
182
+ if (!cam) {
183
+ cam = {
184
+ entity,
185
+ view: mat4.create(),
186
+ proj: mat4.create(),
187
+ viewProj: mat4.create(),
188
+ viewProjNoJitter: mat4.create(),
189
+ invViewProj: mat4.create(),
190
+ prevViewProj: mat4.create(),
191
+ position: vec3.create(),
192
+ forward: vec3.create(0, 0, -1),
193
+ frustum: frustum.create(),
194
+ orthographic: false,
195
+ near: 0.1,
196
+ far: 0,
197
+ fovY: 1,
198
+ orthoHeight: 10,
199
+ aspect: 1,
200
+ width: 1,
201
+ height: 1,
202
+ displayWidth: 1,
203
+ displayHeight: 1,
204
+ pixelRatio: 1,
205
+ exposure: 1,
206
+ ev100: 0,
207
+ clear: { r: 0, g: 0, b: 0, a: 1 },
208
+ msaa: 1,
209
+ curve: 1,
210
+ dither: true,
211
+ draws: createDrawList(),
212
+ transparent: createDrawList(),
213
+ forwardOnly: createDrawList(),
214
+ deferred: false,
215
+ gbufferDebug: -1,
216
+ lodState: new Uint8Array(0),
217
+ lodCapacity: 0,
218
+ frozenFrustum: void 0,
219
+ frozenPosition: void 0,
220
+ frames: 0,
221
+ debug: 0,
222
+ post: createPostSettings(),
223
+ pixelPerfect: void 0
224
+ };
225
+ cameras.set(entity, cam);
226
+ }
227
+ cam.orthographic = projection[i] !== 0;
228
+ let height = orthoHeight[i];
229
+ cam.pixelPerfect = void 0;
230
+ if (ppu && cam.orthographic) {
231
+ const p = pixelPerfectLayout(world, entity, shown, height, ppu[i], snap[i] !== 0);
232
+ rt = p.target;
233
+ height = p.height / p.pixelsPerUnit;
234
+ cam.pixelPerfect = p;
235
+ }
236
+ cam.displayWidth = rt.width;
237
+ cam.displayHeight = rt.height;
238
+ cam.pixelRatio = rt.pixelRatio ?? 1;
239
+ cam.width = rt.width;
240
+ cam.height = rt.height;
241
+ if (scale && !cam.pixelPerfect && rt.renderScale) {
242
+ cam.width = scaledSize(rt.width, scale.scale);
243
+ cam.height = scaledSize(rt.height, scale.scale);
244
+ scale.windowViews++;
245
+ }
246
+ const aspect = cam.width / Math.max(1, cam.height);
247
+ cam.aspect = aspect;
248
+ cam.near = near[i];
249
+ cam.fovY = fovY[i] * Math.PI / 180;
250
+ cam.orthoHeight = height;
251
+ if (!cam.orthographic) {
252
+ mat4.perspectiveReversedZ(scratchProj, cam.fovY, aspect, near[i]);
253
+ cam.far = 0;
254
+ } else {
255
+ const h = height / 2;
256
+ mat4.orthographicReversedZ(scratchProj, -h * aspect, h * aspect, -h, h, near[i], far[i]);
257
+ cam.far = far[i];
258
+ }
259
+ const wantsDeferred = path ? path[i] === 1 : false;
260
+ cam.deferred = wantsDeferred && deferredInstalled;
261
+ if (wantsDeferred && !deferredInstalled) warnMissingDeferred(world);
262
+ const missing = extractPost(table, i, cam, delta, true, installed);
263
+ if (missing !== 0) warnMissingEffects(world, missing);
264
+ const world_ = g.subarray(i * 12, i * 12 + 12);
265
+ if (cam.pixelPerfect?.snap) {
266
+ scratchSnap.set(world_);
267
+ const u = cam.pixelPerfect.pixelsPerUnit;
268
+ scratchSnap[3] = Math.round(scratchSnap[3] * u) / u;
269
+ scratchSnap[7] = Math.round(scratchSnap[7] * u) / u;
270
+ affine.invert(scratchView, scratchSnap);
271
+ } else {
272
+ affine.invert(scratchView, world_);
273
+ }
274
+ affine.toMat4(cam.view, scratchView);
275
+ if (cam.frames > 0) mat4.copy(cam.prevViewProj, cam.viewProjNoJitter);
276
+ mat4.multiply(cam.viewProjNoJitter, scratchProj, cam.view);
277
+ if (cam.frames === 0) mat4.copy(cam.prevViewProj, cam.viewProjNoJitter);
278
+ const jitter = cam.post.jitter;
279
+ if (cam.post.effects & PostEffect.Taa) {
280
+ const k = cam.frames % 8 + 1;
281
+ jitter[0] = halton(k, 2) - 0.5;
282
+ jitter[1] = halton(k, 3) - 0.5;
283
+ const jx = 2 * jitter[0] / cam.width;
284
+ const jy = -2 * jitter[1] / cam.height;
285
+ if (cam.orthographic) {
286
+ scratchProj[12] = scratchProj[12] + jx;
287
+ scratchProj[13] = scratchProj[13] + jy;
288
+ } else {
289
+ scratchProj[8] = scratchProj[8] - jx;
290
+ scratchProj[9] = scratchProj[9] - jy;
291
+ }
292
+ } else {
293
+ jitter[0] = 0;
294
+ jitter[1] = 0;
295
+ }
296
+ mat4.copy(cam.proj, scratchProj);
297
+ mat4.multiply(cam.viewProj, scratchProj, cam.view);
298
+ mat4.invert(cam.invViewProj, cam.viewProj);
299
+ frustum.fromViewProjection(cam.frustum, cam.viewProj);
300
+ affine.getTranslationAt(cam.position, g, i * 12);
301
+ const o = i * 12;
302
+ const fx = -g[o + 2];
303
+ const fy = -g[o + 6];
304
+ const fz = -g[o + 10];
305
+ const fl = Math.sqrt(fx * fx + fy * fy + fz * fz) || 1;
306
+ cam.forward[0] = fx / fl;
307
+ cam.forward[1] = fy / fl;
308
+ cam.forward[2] = fz / fl;
309
+ cam.ev100 = ev[i];
310
+ cam.exposure = exposureScale(ev[i]);
311
+ const c = i * 4;
312
+ cam.clear = { r: clear[c], g: clear[c + 1], b: clear[c + 2], a: clear[c + 3] };
313
+ const aa = antialiasingOf(table, i);
314
+ const dense = settings.msaaMaxPixelRatio > 0 && cam.pixelRatio >= settings.msaaMaxPixelRatio;
315
+ cam.msaa = cam.deferred ? 1 : aa < 0 ? dense ? 1 : settings.msaa : aa === 3 ? 4 : 1;
316
+ cam.curve = curve ? curve[i] : TONEMAP_CURVES.indexOf(DEFAULT_CURVE);
317
+ cam.dither = dither ? dither[i] !== 0 : true;
318
+ cam.frames++;
319
+ const view = {
320
+ name: `camera:${entity}`,
321
+ target: rt,
322
+ order: order[i],
323
+ data: { camera: cam }
324
+ };
325
+ if (isScaled(cam)) {
326
+ view.width = cam.width;
327
+ view.height = cam.height;
328
+ }
329
+ view.aliases = postAliases(cam, viewAliases(cam));
330
+ views.push(view);
331
+ if (cam.pixelPerfect) {
332
+ views.push({
333
+ name: `pixel-perfect:${entity}`,
334
+ target: shown,
335
+ order: order[i] + 0.5,
336
+ data: { upscale: cam.pixelPerfect }
337
+ });
338
+ }
339
+ }
340
+ }
341
+ }
342
+ });
343
+ function translateRight(m, x, y, z) {
344
+ for (let r = 0; r < 4; r++) m[12 + r] = m[r] * x + m[4 + r] * y + m[8 + r] * z + m[12 + r];
345
+ }
346
+ function shiftCameraHistory(cam, x, y, z) {
347
+ translateRight(cam.viewProjNoJitter, -x, -y, -z);
348
+ translateRight(cam.prevViewProj, -x, -y, -z);
349
+ const fp = cam.frozenPosition;
350
+ if (fp) {
351
+ fp[0] = fp[0] + x;
352
+ fp[1] = fp[1] + y;
353
+ fp[2] = fp[2] + z;
354
+ }
355
+ const ff = cam.frozenFrustum;
356
+ if (ff) {
357
+ for (let p = 0; p < ff.length; p += 4) {
358
+ ff[p + 3] = ff[p + 3] - (ff[p] * x + ff[p + 1] * y + ff[p + 2] * z);
359
+ }
360
+ }
361
+ }
362
+ function halton(k, base) {
363
+ let f = 1;
364
+ let r = 0;
365
+ let i = k;
366
+ while (i > 0) {
367
+ f /= base;
368
+ r += f * (i % base);
369
+ i = Math.floor(i / base);
370
+ }
371
+ return r;
372
+ }
373
+ function cameraOf(view) {
374
+ return view.data.camera;
375
+ }
376
+ export {
377
+ Cameras,
378
+ DEFAULT_CURVE,
379
+ DeferredPath,
380
+ RenderPath,
381
+ TONEMAP_CURVES,
382
+ Tonemapping,
383
+ ViewSettings,
384
+ cameraOf,
385
+ extractCameras,
386
+ isScaled,
387
+ shiftCameraHistory,
388
+ viewAliases
389
+ };
@@ -0,0 +1,10 @@
1
+ export declare const ComputedVisibility: import("@aethervtt/shard-core").ComponentDef<{
2
+ readonly visible: import("@aethervtt/shard-core").FieldType<boolean, "u8">;
3
+ }>;
4
+ export declare const Visibility: import("@aethervtt/shard-core").ComponentDef<{
5
+ readonly mode: import("@aethervtt/shard-core").FieldType<"hidden" | "inherit" | "visible", "u8">;
6
+ }>;
7
+ /** Roots take their own mode; children resolve 'inherit' from the parent, depth-first. */
8
+ export declare const computeVisibility: import("@aethervtt/shard-core").SystemDef<{
9
+ roots: import("@aethervtt/shard-core").Query;
10
+ }>;
@@ -0,0 +1,84 @@
1
+ import {
2
+ ChildOf,
3
+ Children,
4
+ defineComponent,
5
+ defineSystem,
6
+ t
7
+ } from "@aethervtt/shard-core";
8
+ const ComputedVisibility = defineComponent(
9
+ "render/ComputedVisibility",
10
+ {
11
+ visible: t.bool({
12
+ default: true,
13
+ readonly: true,
14
+ description: "Final visibility after inheritance."
15
+ })
16
+ },
17
+ {
18
+ description: "Computed from Visibility and the parent chain each frame. Do not write.",
19
+ serialize: false
20
+ }
21
+ );
22
+ const Visibility = defineComponent(
23
+ "render/Visibility",
24
+ {
25
+ mode: t.enum(["inherit", "visible", "hidden"], {
26
+ description: "'inherit' follows the parent; 'visible' shows even under a hidden parent; 'hidden' hides this and inheriting children."
27
+ })
28
+ },
29
+ {
30
+ description: "Whether this entity (and inheriting children) is drawn.",
31
+ requires: [ComputedVisibility]
32
+ }
33
+ );
34
+ const MODE_VISIBLE = 1;
35
+ const MODE_HIDDEN = 2;
36
+ const computeVisibility = defineSystem({
37
+ name: "render/compute-visibility",
38
+ description: "Resolves Visibility modes through the hierarchy into ComputedVisibility.",
39
+ setup: (world) => ({ roots: world.query({ with: [Visibility], without: [ChildOf] }) }),
40
+ run: ({ roots }, world) => {
41
+ for (const table of roots.tables) {
42
+ const modes = table.column(Visibility, "mode");
43
+ const out = table.column(ComputedVisibility, "visible");
44
+ const children = table.has(Children) ? table.column(Children, "entities") : void 0;
45
+ for (let i = 0; i < table.count; i++) {
46
+ const visible = modes[i] !== MODE_HIDDEN;
47
+ const value = visible ? 1 : 0;
48
+ if (out[i] !== value) {
49
+ out[i] = value;
50
+ table.markChanged(ComputedVisibility, i);
51
+ }
52
+ const list = children?.[i];
53
+ if (list) walk(world, list, visible);
54
+ }
55
+ }
56
+ }
57
+ });
58
+ function walk(world, list, parentVisible) {
59
+ for (let k = 0; k < list.length; k++) {
60
+ const child = list[k];
61
+ if (child === null || child === void 0) continue;
62
+ const table = world.entityTableUnchecked(child);
63
+ const row = world.entityRowUnchecked(child);
64
+ let visible = parentVisible;
65
+ if (table.has(Visibility)) {
66
+ const mode = table.column(Visibility, "mode")[row];
67
+ visible = mode === MODE_HIDDEN ? false : mode === MODE_VISIBLE ? true : parentVisible;
68
+ const out = table.column(ComputedVisibility, "visible");
69
+ if (out[row] !== (visible ? 1 : 0)) {
70
+ out[row] = visible ? 1 : 0;
71
+ table.markChanged(ComputedVisibility, row);
72
+ }
73
+ }
74
+ if (table.has(Children)) {
75
+ const grandchildren = table.column(Children, "entities")[row];
76
+ if (grandchildren) walk(world, grandchildren, visible);
77
+ }
78
+ }
79
+ }
80
+ export {
81
+ ComputedVisibility,
82
+ Visibility,
83
+ computeVisibility
84
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@aethervtt/shard-render",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./testing": {
13
+ "types": "./dist/testing.d.ts",
14
+ "default": "./dist/testing.js"
15
+ },
16
+ "./noise": {
17
+ "types": "./dist/noise.d.ts",
18
+ "default": "./dist/noise.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "LICENSE",
24
+ "README.md"
25
+ ],
26
+ "dependencies": {
27
+ "@aethervtt/shard-assets": "0.0.1",
28
+ "@aethervtt/shard-core": "0.0.1",
29
+ "@aethervtt/shard-gpu": "0.0.1",
30
+ "@aethervtt/shard-mesh": "0.0.1",
31
+ "@aethervtt/shard-noise": "0.0.1",
32
+ "@aethervtt/shard-runtime": "0.0.1",
33
+ "@aethervtt/shard-shader": "0.0.1",
34
+ "@aethervtt/shard-texture": "0.0.1",
35
+ "@aethervtt/shard-transform": "0.0.1"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/aethervtt/shard.git",
40
+ "directory": "packages/render"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public",
44
+ "provenance": true
45
+ },
46
+ "shard": {
47
+ "buildSha": "d6c5c6aef4675575c878b02cf2c8f738b4190229"
48
+ }
49
+ }