topazcube 0.1.31 → 0.1.35

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 (103) hide show
  1. package/LICENSE.txt +0 -0
  2. package/README.md +0 -0
  3. package/dist/Renderer.cjs +20844 -0
  4. package/dist/Renderer.cjs.map +1 -0
  5. package/dist/Renderer.js +20827 -0
  6. package/dist/Renderer.js.map +1 -0
  7. package/dist/client.cjs +91 -260
  8. package/dist/client.cjs.map +1 -1
  9. package/dist/client.js +68 -215
  10. package/dist/client.js.map +1 -1
  11. package/dist/server.cjs +165 -432
  12. package/dist/server.cjs.map +1 -1
  13. package/dist/server.js +117 -370
  14. package/dist/server.js.map +1 -1
  15. package/dist/terminal.cjs +113 -200
  16. package/dist/terminal.cjs.map +1 -1
  17. package/dist/terminal.js +50 -51
  18. package/dist/terminal.js.map +1 -1
  19. package/dist/utils-CRhi1BDa.cjs +259 -0
  20. package/dist/utils-CRhi1BDa.cjs.map +1 -0
  21. package/dist/utils-D7tXt6-2.js +260 -0
  22. package/dist/utils-D7tXt6-2.js.map +1 -0
  23. package/package.json +19 -15
  24. package/src/{client.ts → network/client.js} +170 -403
  25. package/src/{compress-browser.ts → network/compress-browser.js} +2 -4
  26. package/src/{compress-node.ts → network/compress-node.js} +8 -14
  27. package/src/{server.ts → network/server.js} +229 -317
  28. package/src/{terminal.js → network/terminal.js} +0 -0
  29. package/src/{topazcube.ts → network/topazcube.js} +2 -2
  30. package/src/network/utils.js +375 -0
  31. package/src/renderer/Camera.js +191 -0
  32. package/src/renderer/DebugUI.js +703 -0
  33. package/src/renderer/Geometry.js +1049 -0
  34. package/src/renderer/Material.js +64 -0
  35. package/src/renderer/Mesh.js +211 -0
  36. package/src/renderer/Node.js +112 -0
  37. package/src/renderer/Pipeline.js +645 -0
  38. package/src/renderer/Renderer.js +1496 -0
  39. package/src/renderer/Skin.js +792 -0
  40. package/src/renderer/Texture.js +584 -0
  41. package/src/renderer/core/AssetManager.js +394 -0
  42. package/src/renderer/core/CullingSystem.js +308 -0
  43. package/src/renderer/core/EntityManager.js +541 -0
  44. package/src/renderer/core/InstanceManager.js +343 -0
  45. package/src/renderer/core/ParticleEmitter.js +358 -0
  46. package/src/renderer/core/ParticleSystem.js +564 -0
  47. package/src/renderer/core/SpriteSystem.js +349 -0
  48. package/src/renderer/gltf.js +563 -0
  49. package/src/renderer/math.js +161 -0
  50. package/src/renderer/rendering/HistoryBufferManager.js +333 -0
  51. package/src/renderer/rendering/ProbeCapture.js +1495 -0
  52. package/src/renderer/rendering/ReflectionProbeManager.js +352 -0
  53. package/src/renderer/rendering/RenderGraph.js +2258 -0
  54. package/src/renderer/rendering/passes/AOPass.js +308 -0
  55. package/src/renderer/rendering/passes/AmbientCapturePass.js +593 -0
  56. package/src/renderer/rendering/passes/BasePass.js +101 -0
  57. package/src/renderer/rendering/passes/BloomPass.js +420 -0
  58. package/src/renderer/rendering/passes/CRTPass.js +724 -0
  59. package/src/renderer/rendering/passes/FogPass.js +445 -0
  60. package/src/renderer/rendering/passes/GBufferPass.js +730 -0
  61. package/src/renderer/rendering/passes/HiZPass.js +744 -0
  62. package/src/renderer/rendering/passes/LightingPass.js +753 -0
  63. package/src/renderer/rendering/passes/ParticlePass.js +841 -0
  64. package/src/renderer/rendering/passes/PlanarReflectionPass.js +456 -0
  65. package/src/renderer/rendering/passes/PostProcessPass.js +405 -0
  66. package/src/renderer/rendering/passes/ReflectionPass.js +157 -0
  67. package/src/renderer/rendering/passes/RenderPostPass.js +364 -0
  68. package/src/renderer/rendering/passes/SSGIPass.js +266 -0
  69. package/src/renderer/rendering/passes/SSGITilePass.js +305 -0
  70. package/src/renderer/rendering/passes/ShadowPass.js +2072 -0
  71. package/src/renderer/rendering/passes/TransparentPass.js +831 -0
  72. package/src/renderer/rendering/passes/VolumetricFogPass.js +715 -0
  73. package/src/renderer/rendering/shaders/ao.wgsl +182 -0
  74. package/src/renderer/rendering/shaders/bloom.wgsl +97 -0
  75. package/src/renderer/rendering/shaders/bloom_blur.wgsl +80 -0
  76. package/src/renderer/rendering/shaders/crt.wgsl +455 -0
  77. package/src/renderer/rendering/shaders/depth_copy.wgsl +17 -0
  78. package/src/renderer/rendering/shaders/geometry.wgsl +580 -0
  79. package/src/renderer/rendering/shaders/hiz_reduce.wgsl +114 -0
  80. package/src/renderer/rendering/shaders/light_culling.wgsl +204 -0
  81. package/src/renderer/rendering/shaders/lighting.wgsl +932 -0
  82. package/src/renderer/rendering/shaders/lighting_common.wgsl +143 -0
  83. package/src/renderer/rendering/shaders/particle_render.wgsl +672 -0
  84. package/src/renderer/rendering/shaders/particle_simulate.wgsl +440 -0
  85. package/src/renderer/rendering/shaders/postproc.wgsl +293 -0
  86. package/src/renderer/rendering/shaders/render_post.wgsl +289 -0
  87. package/src/renderer/rendering/shaders/shadow.wgsl +117 -0
  88. package/src/renderer/rendering/shaders/ssgi.wgsl +266 -0
  89. package/src/renderer/rendering/shaders/ssgi_accumulate.wgsl +114 -0
  90. package/src/renderer/rendering/shaders/ssgi_propagate.wgsl +132 -0
  91. package/src/renderer/rendering/shaders/volumetric_blur.wgsl +80 -0
  92. package/src/renderer/rendering/shaders/volumetric_composite.wgsl +80 -0
  93. package/src/renderer/rendering/shaders/volumetric_raymarch.wgsl +634 -0
  94. package/src/renderer/utils/BoundingSphere.js +439 -0
  95. package/src/renderer/utils/Frustum.js +281 -0
  96. package/src/renderer/utils/Raycaster.js +761 -0
  97. package/dist/client.d.cts +0 -211
  98. package/dist/client.d.ts +0 -211
  99. package/dist/server.d.cts +0 -120
  100. package/dist/server.d.ts +0 -120
  101. package/dist/terminal.d.cts +0 -64
  102. package/dist/terminal.d.ts +0 -64
  103. package/src/utils.ts +0 -403
@@ -0,0 +1,352 @@
1
+ import { Texture } from "../Texture.js"
2
+ import { vec3 } from "../math.js"
3
+
4
+ /**
5
+ * ReflectionProbe - A single reflection probe with position and texture
6
+ */
7
+ class ReflectionProbe {
8
+ constructor(id, position, worldId = 'default') {
9
+ this.id = id
10
+ this.position = [...position]
11
+ this.worldId = worldId
12
+ this.texture = null
13
+ this.loaded = false
14
+ this.url = null
15
+ this.mipLevels = 6
16
+ }
17
+ }
18
+
19
+ /**
20
+ * ReflectionProbeManager - Manages loading, caching, and interpolating reflection probes
21
+ *
22
+ * Handles:
23
+ * - Loading probes from server by worldId/position
24
+ * - Finding closest probes to camera
25
+ * - Interpolating between probes
26
+ * - Uploading new captures to server
27
+ */
28
+ class ReflectionProbeManager {
29
+ constructor(engine) {
30
+ this.engine = engine
31
+
32
+ // All loaded probes: Map<probeId, ReflectionProbe>
33
+ this.probes = new Map()
34
+
35
+ // Probes indexed by world: Map<worldId, ReflectionProbe[]>
36
+ this.probesByWorld = new Map()
37
+
38
+ // Currently active probes for rendering (closest 2)
39
+ this.activeProbes = [null, null]
40
+ this.activeWeights = [1.0, 0.0]
41
+
42
+ // Base/fallback environment map (used when no probes available)
43
+ this.fallbackEnvironment = null
44
+
45
+ // Server configuration
46
+ this.serverBaseUrl = '/api/probes'
47
+
48
+ // Cache settings
49
+ this.maxCachedProbes = 10
50
+ this.loadingProbes = new Set() // URLs currently being loaded
51
+ }
52
+
53
+ /**
54
+ * Set fallback environment map
55
+ */
56
+ setFallbackEnvironment(envMap) {
57
+ this.fallbackEnvironment = envMap
58
+ }
59
+
60
+ /**
61
+ * Register a probe (from capture or loaded from server)
62
+ */
63
+ registerProbe(probe) {
64
+ this.probes.set(probe.id, probe)
65
+
66
+ // Index by world
67
+ if (!this.probesByWorld.has(probe.worldId)) {
68
+ this.probesByWorld.set(probe.worldId, [])
69
+ }
70
+ this.probesByWorld.get(probe.worldId).push(probe)
71
+
72
+ console.log(`ReflectionProbeManager: Registered probe ${probe.id} at [${probe.position.join(', ')}]`)
73
+ }
74
+
75
+ /**
76
+ * Load probe from URL
77
+ * @param {string} url - URL to HDR probe image
78
+ * @param {vec3} position - World position of probe
79
+ * @param {string} worldId - World identifier
80
+ * @returns {Promise<ReflectionProbe>}
81
+ */
82
+ async loadProbe(url, position, worldId = 'default') {
83
+ // Check if already loaded
84
+ const existingId = `${worldId}_${position.join('_')}`
85
+ if (this.probes.has(existingId)) {
86
+ return this.probes.get(existingId)
87
+ }
88
+
89
+ // Check if already loading
90
+ if (this.loadingProbes.has(url)) {
91
+ // Wait for existing load
92
+ await new Promise(resolve => {
93
+ const check = () => {
94
+ if (!this.loadingProbes.has(url)) {
95
+ resolve()
96
+ } else {
97
+ setTimeout(check, 100)
98
+ }
99
+ }
100
+ check()
101
+ })
102
+ return this.probes.get(existingId)
103
+ }
104
+
105
+ this.loadingProbes.add(url)
106
+
107
+ try {
108
+ // Load texture (supports HDR)
109
+ const texture = await Texture.fromImage(this.engine, url, {
110
+ flipY: false,
111
+ srgb: false,
112
+ generateMips: true,
113
+ addressMode: 'clamp-to-edge'
114
+ })
115
+
116
+ const probe = new ReflectionProbe(existingId, position, worldId)
117
+ probe.texture = texture
118
+ probe.url = url
119
+ probe.loaded = true
120
+
121
+ this.registerProbe(probe)
122
+
123
+ // Enforce cache limit
124
+ this._enforceeCacheLimit()
125
+
126
+ return probe
127
+ } catch (error) {
128
+ console.error(`ReflectionProbeManager: Failed to load probe from ${url}:`, error)
129
+ return null
130
+ } finally {
131
+ this.loadingProbes.delete(url)
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Load probes for a world from server
137
+ * @param {string} worldId - World identifier
138
+ * @returns {Promise<ReflectionProbe[]>}
139
+ */
140
+ async loadWorldProbes(worldId) {
141
+ try {
142
+ // Fetch probe manifest from server
143
+ const response = await fetch(`${this.serverBaseUrl}/${worldId}/manifest.json`)
144
+ if (!response.ok) {
145
+ console.warn(`ReflectionProbeManager: No probes found for world ${worldId}`)
146
+ return []
147
+ }
148
+
149
+ const manifest = await response.json()
150
+ const loadedProbes = []
151
+
152
+ for (const probeInfo of manifest.probes) {
153
+ const probe = await this.loadProbe(
154
+ `${this.serverBaseUrl}/${worldId}/${probeInfo.file}`,
155
+ probeInfo.position,
156
+ worldId
157
+ )
158
+ if (probe) {
159
+ loadedProbes.push(probe)
160
+ }
161
+ }
162
+
163
+ return loadedProbes
164
+ } catch (error) {
165
+ console.warn(`ReflectionProbeManager: Failed to load world probes for ${worldId}:`, error)
166
+ return []
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Find closest probes to a position
172
+ * @param {vec3} position - World position
173
+ * @param {string} worldId - World identifier
174
+ * @param {number} count - Number of probes to find (default 2)
175
+ * @returns {{ probes: ReflectionProbe[], weights: number[] }}
176
+ */
177
+ findClosestProbes(position, worldId = 'default', count = 2) {
178
+ const worldProbes = this.probesByWorld.get(worldId) || []
179
+
180
+ if (worldProbes.length === 0) {
181
+ return { probes: [], weights: [] }
182
+ }
183
+
184
+ // Calculate distances
185
+ const probesWithDistance = worldProbes
186
+ .filter(p => p.loaded && p.texture)
187
+ .map(probe => {
188
+ const dx = probe.position[0] - position[0]
189
+ const dy = probe.position[1] - position[1]
190
+ const dz = probe.position[2] - position[2]
191
+ const distSq = dx * dx + dy * dy + dz * dz
192
+ return { probe, distance: Math.sqrt(distSq) }
193
+ })
194
+ .sort((a, b) => a.distance - b.distance)
195
+
196
+ // Get closest N probes
197
+ const closest = probesWithDistance.slice(0, count)
198
+
199
+ if (closest.length === 0) {
200
+ return { probes: [], weights: [] }
201
+ }
202
+
203
+ if (closest.length === 1) {
204
+ return {
205
+ probes: [closest[0].probe],
206
+ weights: [1.0]
207
+ }
208
+ }
209
+
210
+ // Calculate interpolation weights based on inverse distance
211
+ const totalInvDist = closest.reduce((sum, p) => sum + 1.0 / Math.max(p.distance, 0.001), 0)
212
+ const weights = closest.map(p => (1.0 / Math.max(p.distance, 0.001)) / totalInvDist)
213
+
214
+ return {
215
+ probes: closest.map(p => p.probe),
216
+ weights
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Update active probes based on camera position
222
+ * @param {vec3} cameraPosition - Camera world position
223
+ * @param {string} worldId - Current world
224
+ */
225
+ updateActiveProbes(cameraPosition, worldId = 'default') {
226
+ const { probes, weights } = this.findClosestProbes(cameraPosition, worldId, 2)
227
+
228
+ this.activeProbes = [probes[0] || null, probes[1] || null]
229
+ this.activeWeights = [weights[0] || 1.0, weights[1] || 0.0]
230
+ }
231
+
232
+ /**
233
+ * Get active probe textures and weights for shader
234
+ * @returns {{ textures: [Texture, Texture], weights: [number, number] }}
235
+ */
236
+ getActiveProbeData() {
237
+ return {
238
+ textures: [
239
+ this.activeProbes[0]?.texture || this.fallbackEnvironment,
240
+ this.activeProbes[1]?.texture || this.fallbackEnvironment
241
+ ],
242
+ weights: this.activeWeights
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Upload a captured probe to server
248
+ * @param {Blob} probeData - HDR PNG blob
249
+ * @param {vec3} position - Capture position
250
+ * @param {string} worldId - World identifier
251
+ * @returns {Promise<boolean>} Success
252
+ */
253
+ async uploadProbe(probeData, position, worldId = 'default') {
254
+ try {
255
+ const formData = new FormData()
256
+ formData.append('probe', probeData, 'probe.png')
257
+ formData.append('position', JSON.stringify(position))
258
+ formData.append('worldId', worldId)
259
+
260
+ const response = await fetch(`${this.serverBaseUrl}/upload`, {
261
+ method: 'POST',
262
+ body: formData
263
+ })
264
+
265
+ if (!response.ok) {
266
+ throw new Error(`Upload failed: ${response.status}`)
267
+ }
268
+
269
+ const result = await response.json()
270
+ console.log(`ReflectionProbeManager: Uploaded probe to ${result.url}`)
271
+
272
+ // Load the uploaded probe
273
+ await this.loadProbe(result.url, position, worldId)
274
+
275
+ return true
276
+ } catch (error) {
277
+ console.error('ReflectionProbeManager: Failed to upload probe:', error)
278
+ return false
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Remove a probe
284
+ */
285
+ removeProbe(probeId) {
286
+ const probe = this.probes.get(probeId)
287
+ if (!probe) return
288
+
289
+ // Remove from world index
290
+ const worldProbes = this.probesByWorld.get(probe.worldId)
291
+ if (worldProbes) {
292
+ const idx = worldProbes.indexOf(probe)
293
+ if (idx >= 0) worldProbes.splice(idx, 1)
294
+ }
295
+
296
+ // Destroy texture
297
+ if (probe.texture?.texture) {
298
+ probe.texture.texture.destroy()
299
+ }
300
+
301
+ this.probes.delete(probeId)
302
+ }
303
+
304
+ /**
305
+ * Enforce cache limit by removing least recently used probes
306
+ */
307
+ _enforceeCacheLimit() {
308
+ if (this.probes.size <= this.maxCachedProbes) return
309
+
310
+ // Simple LRU: remove oldest probes not currently active
311
+ const toRemove = []
312
+ for (const [id, probe] of this.probes) {
313
+ if (probe !== this.activeProbes[0] && probe !== this.activeProbes[1]) {
314
+ toRemove.push(id)
315
+ if (this.probes.size - toRemove.length <= this.maxCachedProbes) {
316
+ break
317
+ }
318
+ }
319
+ }
320
+
321
+ for (const id of toRemove) {
322
+ this.removeProbe(id)
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Get statistics
328
+ */
329
+ getStats() {
330
+ return {
331
+ totalProbes: this.probes.size,
332
+ loadedProbes: [...this.probes.values()].filter(p => p.loaded).length,
333
+ worldCount: this.probesByWorld.size,
334
+ activeProbe0: this.activeProbes[0]?.id || 'none',
335
+ activeProbe1: this.activeProbes[1]?.id || 'none',
336
+ weights: this.activeWeights
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Destroy all resources
342
+ */
343
+ destroy() {
344
+ for (const [id] of this.probes) {
345
+ this.removeProbe(id)
346
+ }
347
+ this.probes.clear()
348
+ this.probesByWorld.clear()
349
+ }
350
+ }
351
+
352
+ export { ReflectionProbeManager, ReflectionProbe }