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,349 @@
1
+ import { Texture } from "../Texture.js"
2
+ import { Material } from "../Material.js"
3
+ import { Mesh } from "../Mesh.js"
4
+ import { Geometry } from "../Geometry.js"
5
+
6
+ /**
7
+ * SpriteSystem - Manages sprite entities for billboard rendering
8
+ *
9
+ * Handles:
10
+ * - Parsing sprite definitions (texture path, frames per row)
11
+ * - Loading and caching sprite textures
12
+ * - Computing UV transforms for sprite sheet frames
13
+ * - Animating sprites based on frame property
14
+ * - Creating sprite materials and meshes
15
+ */
16
+ class SpriteSystem {
17
+ constructor(engine) {
18
+ this.engine = engine
19
+
20
+ // Cache for loaded sprite textures: textureUrl -> Texture
21
+ this._textureCache = new Map()
22
+
23
+ // Cache for sprite materials: key -> Material
24
+ this._materialCache = new Map()
25
+
26
+ // Cache for sprite geometries: pivot -> Geometry
27
+ this._geometryCache = new Map()
28
+
29
+ // Active sprite entity tracking for animation
30
+ this._spriteEntities = new Map() // entityId -> spriteData
31
+ }
32
+
33
+ /**
34
+ * Parse a sprite definition string
35
+ * Format: "texture.png" or "texture.png|8" (texture|framesPerRow)
36
+ * @param {string} spriteString - Sprite definition
37
+ * @returns {{ url: string, framesPerRow: number }}
38
+ */
39
+ parseSprite(spriteString) {
40
+ if (!spriteString || typeof spriteString !== 'string') {
41
+ return null
42
+ }
43
+
44
+ const parts = spriteString.split('|')
45
+ return {
46
+ url: parts[0],
47
+ framesPerRow: parts.length > 1 ? parseInt(parts[1], 10) : 1
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Parse a frame animation string
53
+ * Format: integer frame OR "startFrame|endFrame|fps"
54
+ * @param {number|string} frame - Frame definition
55
+ * @returns {{ currentFrame: number, startFrame: number, endFrame: number, fps: number, isAnimated: boolean }}
56
+ */
57
+ parseFrame(frame) {
58
+ // Check for animated format first: "startFrame|endFrame|fps"
59
+ if (typeof frame === 'string' && frame.includes('|')) {
60
+ const parts = frame.split('|')
61
+ const start = parseInt(parts[0], 10) || 0
62
+ const end = parseInt(parts[1], 10) || start
63
+ const fps = parseFloat(parts[2]) || 30
64
+ return {
65
+ currentFrame: start,
66
+ startFrame: start,
67
+ endFrame: end,
68
+ fps,
69
+ isAnimated: true
70
+ }
71
+ }
72
+
73
+ // Single frame (number or numeric string)
74
+ if (typeof frame === 'number') {
75
+ return {
76
+ currentFrame: frame,
77
+ startFrame: frame,
78
+ endFrame: frame,
79
+ fps: 0,
80
+ isAnimated: false
81
+ }
82
+ }
83
+
84
+ if (typeof frame === 'string' && !isNaN(parseInt(frame, 10))) {
85
+ const f = parseInt(frame, 10)
86
+ return {
87
+ currentFrame: f,
88
+ startFrame: f,
89
+ endFrame: f,
90
+ fps: 0,
91
+ isAnimated: false
92
+ }
93
+ }
94
+
95
+ // Default: frame 0
96
+ return {
97
+ currentFrame: 0,
98
+ startFrame: 0,
99
+ endFrame: 0,
100
+ fps: 0,
101
+ isAnimated: false
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Compute UV offset and scale for a frame in a sprite sheet
107
+ * @param {number} frame - Frame index (0-based)
108
+ * @param {number} framesPerRow - Number of frames per row in the sheet
109
+ * @param {number} [totalFrames] - Optional total frames (for non-square sheets)
110
+ * @returns {{ offset: [number, number], scale: [number, number] }}
111
+ */
112
+ computeFrameUV(frame, framesPerRow, totalFrames = null) {
113
+ if (framesPerRow <= 1) {
114
+ // Single frame - full texture
115
+ return {
116
+ offset: [0, 0],
117
+ scale: [1, 1]
118
+ }
119
+ }
120
+
121
+ const col = frame % framesPerRow
122
+ const row = Math.floor(frame / framesPerRow)
123
+
124
+ // Calculate number of rows based on totalFrames or assume single row
125
+ // For sprite sheets like 256x32 with 8 frames, there's only 1 row
126
+ // so scaleY should be 1 (full height), not 1/8
127
+ const numRows = totalFrames ? Math.ceil(totalFrames / framesPerRow) : (row + 1)
128
+ const scaleX = 1.0 / framesPerRow
129
+ const scaleY = 1.0 / Math.max(1, numRows)
130
+
131
+ // X offset is straightforward: column * frame width
132
+ const xOffset = col * scaleX
133
+
134
+ // Y offset with flipY: top of image is at v=1, bottom at v=0
135
+ // For single-row sheets, yOffset is 0 and scaleY is 1
136
+ // For multi-row sheets, calculate based on row
137
+ const yOffset = row * scaleY
138
+
139
+ return {
140
+ offset: [xOffset, yOffset],
141
+ scale: [scaleX, scaleY]
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Get or load a sprite texture
147
+ * @param {string} url - Texture URL
148
+ * @returns {Promise<Texture>}
149
+ */
150
+ async loadTexture(url) {
151
+ if (this._textureCache.has(url)) {
152
+ return this._textureCache.get(url)
153
+ }
154
+
155
+ const texture = await Texture.fromImage(this.engine, url, {
156
+ srgb: true,
157
+ generateMips: true,
158
+ flipY: true
159
+ })
160
+
161
+ this._textureCache.set(url, texture)
162
+ return texture
163
+ }
164
+
165
+ /**
166
+ * Get or create a material for a sprite type
167
+ * @param {string} textureUrl - Texture URL
168
+ * @param {number} roughness - Roughness value (0-1)
169
+ * @param {string} pivot - Pivot mode
170
+ * @returns {Material}
171
+ */
172
+ async getSpriteMaterial(textureUrl, roughness = 0.7, pivot = 'center') {
173
+ const key = `sprite:${textureUrl}:${pivot}:r${roughness.toFixed(2)}`
174
+
175
+ if (this._materialCache.has(key)) {
176
+ return this._materialCache.get(key)
177
+ }
178
+
179
+ // Load sprite texture
180
+ const albedoTexture = await this.loadTexture(textureUrl)
181
+
182
+ // Create default textures for other slots
183
+ const normalTexture = await Texture.fromRGBA(this.engine, 0.5, 0.5, 1.0, 1.0) // Flat normal
184
+ const aoTexture = await Texture.fromRGBA(this.engine, 1.0, 1.0, 1.0, 1.0) // No AO
185
+ const rmTexture = await Texture.fromRGBA(this.engine, 0.0, roughness, 0.0, 1.0) // Roughness, no metallic
186
+ const emissionTexture = await Texture.fromRGBA(this.engine, 0.0, 0.0, 0.0, 1.0) // No emission
187
+
188
+ const material = new Material(
189
+ [albedoTexture, normalTexture, aoTexture, rmTexture, emissionTexture],
190
+ {
191
+ billboardMode: this._pivotToMode(pivot),
192
+ spriteRoughness: roughness
193
+ },
194
+ key,
195
+ this.engine
196
+ )
197
+
198
+ // Enable alpha hash for cutout transparency
199
+ material.alphaHash = true
200
+ material.alphaHashScale = 1.0
201
+
202
+ this._materialCache.set(key, material)
203
+ return material
204
+ }
205
+
206
+ /**
207
+ * Get or create billboard quad geometry for a pivot mode
208
+ * @param {string} pivot - Pivot mode: 'center', 'bottom', 'horizontal'
209
+ * @returns {Geometry}
210
+ */
211
+ getGeometry(pivot = 'center') {
212
+ if (this._geometryCache.has(pivot)) {
213
+ return this._geometryCache.get(pivot)
214
+ }
215
+
216
+ const geometry = Geometry.billboardQuad(this.engine, pivot)
217
+ this._geometryCache.set(pivot, geometry)
218
+ return geometry
219
+ }
220
+
221
+ /**
222
+ * Convert pivot string to billboard mode number
223
+ * @param {string} pivot - Pivot mode
224
+ * @returns {number}
225
+ */
226
+ _pivotToMode(pivot) {
227
+ switch (pivot) {
228
+ case 'center': return 1
229
+ case 'bottom': return 2
230
+ case 'horizontal': return 3
231
+ default: return 0
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Register a sprite entity for animation tracking
237
+ * @param {string} entityId - Entity ID
238
+ * @param {Object} entity - Entity object
239
+ */
240
+ registerEntity(entityId, entity) {
241
+ if (!entity.sprite) return
242
+
243
+ const spriteInfo = this.parseSprite(entity.sprite)
244
+ if (!spriteInfo) return
245
+
246
+ const frameInfo = this.parseFrame(entity.frame || 0)
247
+
248
+ this._spriteEntities.set(entityId, {
249
+ entity,
250
+ spriteInfo,
251
+ frameInfo,
252
+ animTime: 0
253
+ })
254
+ }
255
+
256
+ /**
257
+ * Unregister a sprite entity
258
+ * @param {string} entityId - Entity ID
259
+ */
260
+ unregisterEntity(entityId) {
261
+ this._spriteEntities.delete(entityId)
262
+ }
263
+
264
+ /**
265
+ * Update sprite animations
266
+ * @param {number} dt - Delta time in seconds
267
+ */
268
+ update(dt) {
269
+ for (const [entityId, data] of this._spriteEntities) {
270
+ const { entity, spriteInfo, frameInfo } = data
271
+
272
+ if (!frameInfo.isAnimated) continue
273
+
274
+ // Advance animation time
275
+ data.animTime += dt * frameInfo.fps
276
+
277
+ // Calculate current frame (loop by default)
278
+ const frameCount = frameInfo.endFrame - frameInfo.startFrame + 1
279
+ const frameOffset = Math.floor(data.animTime) % frameCount
280
+ frameInfo.currentFrame = frameInfo.startFrame + frameOffset
281
+
282
+ // Update entity's UV transform
283
+ const uv = this.computeFrameUV(frameInfo.currentFrame, spriteInfo.framesPerRow)
284
+ entity._uvTransform = [uv.offset[0], uv.offset[1], uv.scale[0], uv.scale[1]]
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Get instance data for a sprite entity
290
+ * @param {Object} entity - Entity with sprite properties
291
+ * @returns {{ uvTransform: [number, number, number, number], color: [number, number, number, number] }}
292
+ */
293
+ getSpriteInstanceData(entity) {
294
+ // If entity has pre-computed _uvTransform (from animation), use it
295
+ if (entity._uvTransform) {
296
+ return {
297
+ uvTransform: entity._uvTransform,
298
+ color: entity.color || [1, 1, 1, 1]
299
+ }
300
+ }
301
+
302
+ // Otherwise compute from sprite properties
303
+ const spriteInfo = this.parseSprite(entity.sprite)
304
+ if (!spriteInfo) {
305
+ return {
306
+ uvTransform: [0, 0, 1, 1],
307
+ color: entity.color || [1, 1, 1, 1]
308
+ }
309
+ }
310
+
311
+ const frameInfo = this.parseFrame(entity.frame || 0)
312
+ const uv = this.computeFrameUV(frameInfo.currentFrame, spriteInfo.framesPerRow)
313
+
314
+ return {
315
+ uvTransform: [uv.offset[0], uv.offset[1], uv.scale[0], uv.scale[1]],
316
+ color: entity.color || [1, 1, 1, 1]
317
+ }
318
+ }
319
+
320
+ /**
321
+ * Create a complete sprite asset (geometry + material + mesh)
322
+ * @param {string} spriteString - Sprite definition
323
+ * @param {string} pivot - Pivot mode
324
+ * @param {number} roughness - Roughness value
325
+ * @returns {Promise<{ geometry: Geometry, material: Material, mesh: Mesh }>}
326
+ */
327
+ async createSpriteAsset(spriteString, pivot = 'center', roughness = 0.7) {
328
+ const spriteInfo = this.parseSprite(spriteString)
329
+ if (!spriteInfo) return null
330
+
331
+ const geometry = this.getGeometry(pivot)
332
+ const material = await this.getSpriteMaterial(spriteInfo.url, roughness, pivot)
333
+ const mesh = new Mesh(this.engine, geometry, material)
334
+
335
+ return { geometry, material, mesh, spriteInfo }
336
+ }
337
+
338
+ /**
339
+ * Destroy and clean up resources
340
+ */
341
+ destroy() {
342
+ this._textureCache.clear()
343
+ this._materialCache.clear()
344
+ this._geometryCache.clear()
345
+ this._spriteEntities.clear()
346
+ }
347
+ }
348
+
349
+ export { SpriteSystem }