minecraft-renderer 0.1.78 → 0.1.80

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 (200) hide show
  1. package/README.md +29 -25
  2. package/dist/mesher.js +36 -36
  3. package/dist/mesher.js.map +4 -4
  4. package/dist/mesherWasm.js +217 -217
  5. package/dist/minecraft-renderer.js +32 -32
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +415 -415
  8. package/package.json +5 -2
  9. package/src/bundler/bundlePrepare.ts +3 -8
  10. package/src/graphicsBackend/appViewer.ts +10 -7
  11. package/src/graphicsBackend/config.ts +1 -5
  12. package/src/graphicsBackend/playerState.ts +35 -34
  13. package/src/graphicsBackend/preloadWorkers.ts +43 -41
  14. package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
  15. package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
  16. package/src/graphicsBackend/types.ts +2 -2
  17. package/src/index.ts +6 -27
  18. package/src/lib/DebugGui.ts +34 -31
  19. package/src/lib/animationController.ts +9 -9
  20. package/src/lib/bakeLegacyLight.ts +1 -6
  21. package/src/lib/bindAbortableListener.test.ts +32 -12
  22. package/src/lib/bindAbortableListener.ts +14 -6
  23. package/src/lib/blockEntityLightRegistry.ts +11 -20
  24. package/src/lib/blockEntityLighting.test.ts +1 -6
  25. package/src/lib/blockEntityLighting.ts +5 -5
  26. package/src/lib/buildSharedConfig.mjs +4 -4
  27. package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
  28. package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
  29. package/src/lib/cameraBobbing.ts +1 -1
  30. package/src/lib/canvas2DOverlay.example.ts +13 -33
  31. package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
  32. package/src/lib/canvas2DOverlay.ts +28 -47
  33. package/src/lib/cleanupDecorator.ts +2 -2
  34. package/src/lib/createPlayerObject.test.ts +2 -7
  35. package/src/lib/createPlayerObject.ts +18 -25
  36. package/src/lib/frameTimingCollector.ts +2 -5
  37. package/src/lib/guiRenderer.ts +57 -42
  38. package/src/lib/items.ts +15 -9
  39. package/src/lib/mesherlogReader.ts +5 -6
  40. package/src/lib/simpleUtils.ts +5 -5
  41. package/src/lib/skyLight.ts +3 -3
  42. package/src/lib/smoothSwitcher.ts +11 -18
  43. package/src/lib/ui/newStats.ts +10 -12
  44. package/src/lib/utils/proxy.ts +7 -1
  45. package/src/lib/utils/skins.ts +4 -4
  46. package/src/lib/utils.ts +1 -1
  47. package/src/lib/workerMessageSanitize.ts +5 -12
  48. package/src/lib/workerProxy.ts +52 -42
  49. package/src/lib/workerSyncOps.test.ts +58 -41
  50. package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
  51. package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
  52. package/src/lib/worldrendererCommon.ts +338 -211
  53. package/src/mesher-legacy/mesher.ts +9 -4
  54. package/src/mesher-legacy/test/a.ts +1 -1
  55. package/src/mesher-legacy/test/mesherTester.ts +2 -2
  56. package/src/mesher-legacy/test/playground.ts +1 -1
  57. package/src/mesher-legacy/test/run/test-js.ts +1 -1
  58. package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
  59. package/src/mesher-legacy/test/test-perf.ts +1 -1
  60. package/src/mesher-legacy/test/tests.test.ts +2 -2
  61. package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
  62. package/src/mesher-shared/blockEntityMetadata.ts +28 -19
  63. package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
  64. package/src/mesher-shared/computeHeightmap.ts +2 -4
  65. package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
  66. package/src/mesher-shared/faceOcclusion.ts +324 -0
  67. package/src/mesher-shared/models.ts +80 -131
  68. package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
  69. package/src/mesher-shared/shared.ts +46 -46
  70. package/src/mesher-shared/standaloneRenderer.ts +40 -44
  71. package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
  72. package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
  73. package/src/mesher-shared/vertexShading.ts +2 -11
  74. package/src/mesher-shared/world.ts +19 -19
  75. package/src/mesher-shared/worldLighting.test.ts +2 -2
  76. package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
  77. package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
  78. package/src/performanceMonitor/index.ts +1 -5
  79. package/src/performanceMonitor/types.ts +1 -1
  80. package/src/playerState/playerState.ts +55 -50
  81. package/src/playerState/types.ts +2 -8
  82. package/src/playground/allEntitiesDebug.ts +19 -16
  83. package/src/playground/baseScene.ts +29 -32
  84. package/src/playground/mobileControls.tsx +133 -129
  85. package/src/playground/playground.html +76 -73
  86. package/src/playground/playground.ts +14 -1
  87. package/src/playground/playgroundUi.tsx +100 -74
  88. package/src/playground/reactUtils.ts +3 -7
  89. package/src/playground/scenes/entities.ts +10 -7
  90. package/src/playground/scenes/frequentUpdates.ts +5 -5
  91. package/src/playground/scenes/geometryExport.ts +6 -20
  92. package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
  93. package/src/playground/scenes/index.ts +1 -1
  94. package/src/playground/scenes/lightingStarfield.ts +18 -12
  95. package/src/playground/scenes/main.ts +15 -11
  96. package/src/playground/scenes/partialBlockCulling.ts +31 -0
  97. package/src/playground/scenes/railsCobweb.ts +1 -1
  98. package/src/playground/scenes/rotationIssue.ts +1 -1
  99. package/src/playground/scenes/slabsOptimization.ts +1 -2
  100. package/src/playground/scenes/transparencyIssue.ts +1 -1
  101. package/src/playground/shared.ts +2 -2
  102. package/src/resourcesManager/resourcesManager.ts +29 -54
  103. package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
  104. package/src/shims/minecraftData.ts +70 -24
  105. package/src/sign-renderer/index.html +10 -12
  106. package/src/sign-renderer/index.ts +29 -29
  107. package/src/sign-renderer/playground.ts +22 -15
  108. package/src/sign-renderer/tests.test.ts +16 -13
  109. package/src/sign-renderer/vite.config.ts +2 -2
  110. package/src/three/appShared.ts +46 -25
  111. package/src/three/bannerRenderer.ts +33 -61
  112. package/src/three/cameraShake.ts +15 -6
  113. package/src/three/chunkMeshManager.ts +329 -301
  114. package/src/three/cinimaticScript.ts +26 -15
  115. package/src/three/cubeDrawSpans.ts +27 -37
  116. package/src/three/cubeMultiDraw.ts +9 -22
  117. package/src/three/documentRenderer.ts +15 -18
  118. package/src/three/entities.ts +175 -150
  119. package/src/three/entity/EntityMesh.ts +114 -108
  120. package/src/three/entity/animations.js +3 -3
  121. package/src/three/entity/armorModels.ts +15 -15
  122. package/src/three/entity/gltfAnimationUtils.ts +2 -5
  123. package/src/three/fireworks.ts +34 -32
  124. package/src/three/fireworksRenderer.ts +32 -29
  125. package/src/three/globalBlockBuffer.ts +174 -99
  126. package/src/three/globalLegacyBuffer.ts +465 -136
  127. package/src/three/graphicsBackendBase.ts +19 -25
  128. package/src/three/graphicsBackendOffThread.ts +12 -15
  129. package/src/three/hand.ts +21 -21
  130. package/src/three/handLegacy.ts +3 -13
  131. package/src/three/holdingBlock.ts +116 -79
  132. package/src/three/holdingBlockFactory.ts +1 -4
  133. package/src/three/holdingBlockItemIdentity.test.ts +25 -17
  134. package/src/three/holdingBlockItemIdentity.ts +9 -6
  135. package/src/three/holdingBlockLegacy.ts +113 -132
  136. package/src/three/itemMesh.ts +20 -29
  137. package/src/three/legacyMultiDraw.ts +93 -0
  138. package/src/three/legacySectionCull.ts +8 -14
  139. package/src/three/menuBackground/activeView.ts +1 -4
  140. package/src/three/menuBackground/assetUrl.ts +1 -1
  141. package/src/three/menuBackground/classic.ts +4 -12
  142. package/src/three/menuBackground/gpuPreference.ts +1 -3
  143. package/src/three/menuBackground/index.ts +2 -11
  144. package/src/three/menuBackground/renderer.ts +1 -5
  145. package/src/three/menuBackground/types.ts +1 -4
  146. package/src/three/menuBackground/v2.ts +196 -96
  147. package/src/three/menuBackground/v2Meta.ts +3 -3
  148. package/src/three/menuBackground/worldBlocks.ts +37 -35
  149. package/src/three/modules/blockBreakParticles.ts +59 -28
  150. package/src/three/modules/cameraBobbing.ts +3 -6
  151. package/src/three/modules/index.ts +1 -1
  152. package/src/three/modules/rain.ts +10 -23
  153. package/src/three/modules/sciFiWorldReveal.ts +11 -25
  154. package/src/three/modules/starfield.ts +7 -13
  155. package/src/three/renderSlot.ts +28 -16
  156. package/src/three/rendererModuleSystem.ts +1 -3
  157. package/src/three/sceneOrigin.ts +96 -33
  158. package/src/three/sectionRaycastAabb.ts +30 -18
  159. package/src/three/shaderCubeMesh.ts +6 -17
  160. package/src/three/shaders/cubeBlockShader.ts +85 -96
  161. package/src/three/shaders/legacyBlockShader.ts +21 -43
  162. package/src/three/shaders/textureIndexMapping.ts +89 -95
  163. package/src/three/shaders/tintPalette.ts +156 -170
  164. package/src/three/signTextureCache.ts +9 -12
  165. package/src/three/skyboxRenderer.ts +62 -70
  166. package/src/three/tests/chunkMeshManagerLegacy.test.ts +133 -25
  167. package/src/three/tests/cubeDrawSpans.test.ts +55 -25
  168. package/src/three/tests/globalBlockBuffer.test.ts +217 -0
  169. package/src/three/tests/globalLegacyBuffer.test.ts +460 -58
  170. package/src/three/tests/legacyMultiDraw.test.ts +88 -0
  171. package/src/three/tests/pr3PerFrameCpuCuts.test.ts +370 -0
  172. package/src/three/tests/signTextureCache.test.ts +4 -4
  173. package/src/three/threeJsMedia.ts +55 -72
  174. package/src/three/threeJsParticles.ts +32 -41
  175. package/src/three/threeJsSound.ts +3 -3
  176. package/src/three/threeJsUtils.ts +3 -3
  177. package/src/three/threeWorker.ts +2 -2
  178. package/src/three/waypointSprite.ts +55 -82
  179. package/src/three/waypoints.ts +20 -23
  180. package/src/three/world/cursorBlock.ts +25 -12
  181. package/src/three/world/vr.ts +11 -17
  182. package/src/three/worldGeometryExport.ts +15 -34
  183. package/src/three/worldRendererThree.ts +131 -133
  184. package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
  185. package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
  186. package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
  187. package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
  188. package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
  189. package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
  190. package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +17 -4
  191. package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
  192. package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
  193. package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
  194. package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
  195. package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
  196. package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
  197. package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
  198. package/src/worldView/worldView.spiral.test.ts +1 -1
  199. package/src/worldView/worldView.ts +34 -39
  200. package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
@@ -25,22 +25,23 @@ export class SkyboxRenderer {
25
25
  private readonly brightnessAtPosition = 1
26
26
  debugGui: DebugGui
27
27
 
28
- constructor (private readonly scene: THREE.Scene, public defaultSkybox: boolean, public initialImage: string | null) {
29
- this.debugGui = new DebugGui('skybox_renderer', this, [
30
- 'temperature',
31
- 'worldTime',
32
- 'inWater',
33
- 'waterBreathing',
34
- 'fogOrangeness',
35
- 'brightnessAtPosition',
36
- 'distanceFactor'
37
- ], {
38
- brightnessAtPosition: { min: 0, max: 1, step: 0.01 },
39
- temperature: { min: 0, max: 1, step: 0.01 },
40
- worldTime: { min: 0, max: 24_000, step: 1 },
41
- fogOrangeness: { min: -1, max: 1, step: 0.01 },
42
- distanceFactor: { min: 0, max: 5, step: 0.01 },
43
- })
28
+ constructor(
29
+ private readonly scene: THREE.Scene,
30
+ public defaultSkybox: boolean,
31
+ public initialImage: string | null
32
+ ) {
33
+ this.debugGui = new DebugGui(
34
+ 'skybox_renderer',
35
+ this,
36
+ ['temperature', 'worldTime', 'inWater', 'waterBreathing', 'fogOrangeness', 'brightnessAtPosition', 'distanceFactor'],
37
+ {
38
+ brightnessAtPosition: { min: 0, max: 1, step: 0.01 },
39
+ temperature: { min: 0, max: 1, step: 0.01 },
40
+ worldTime: { min: 0, max: 24_000, step: 1 },
41
+ fogOrangeness: { min: -1, max: 1, step: 0.01 },
42
+ distanceFactor: { min: 0, max: 5, step: 0.01 }
43
+ }
44
+ )
44
45
 
45
46
  if (!initialImage) {
46
47
  this.createGradientSky()
@@ -48,13 +49,13 @@ export class SkyboxRenderer {
48
49
  // this.debugGui.activate()
49
50
  }
50
51
 
51
- async init () {
52
+ async init() {
52
53
  if (this.initialImage) {
53
54
  await this.setSkyboxImage(this.initialImage)
54
55
  }
55
56
  }
56
57
 
57
- async setSkyboxImage (imageUrl: string) {
58
+ async setSkyboxImage(imageUrl: string) {
58
59
  // Dispose old textures if they exist
59
60
  if (this.texture) {
60
61
  this.texture.dispose()
@@ -62,19 +63,16 @@ export class SkyboxRenderer {
62
63
 
63
64
  // Load the equirectangular texture
64
65
  const textureLoader = new THREE.TextureLoader()
65
- this.texture = await new Promise((resolve) => {
66
- textureLoader.load(
67
- imageUrl,
68
- (texture) => {
69
- texture.mapping = THREE.EquirectangularReflectionMapping
70
- texture.colorSpace = THREE.SRGBColorSpace
71
- // Keep pixelated look
72
- texture.minFilter = THREE.NearestFilter
73
- texture.magFilter = THREE.NearestFilter
74
- texture.needsUpdate = true
75
- resolve(texture)
76
- }
77
- )
66
+ this.texture = await new Promise(resolve => {
67
+ textureLoader.load(imageUrl, texture => {
68
+ texture.mapping = THREE.EquirectangularReflectionMapping
69
+ texture.colorSpace = THREE.SRGBColorSpace
70
+ // Keep pixelated look
71
+ texture.minFilter = THREE.NearestFilter
72
+ texture.magFilter = THREE.NearestFilter
73
+ texture.needsUpdate = true
74
+ resolve(texture)
75
+ })
78
76
  })
79
77
 
80
78
  // Create or update the skybox
@@ -100,7 +98,7 @@ export class SkyboxRenderer {
100
98
  }
101
99
  }
102
100
 
103
- update (cameraPosition: THREE.Vector3, newViewDistance: number) {
101
+ update(cameraPosition: THREE.Vector3, newViewDistance: number) {
104
102
  if (newViewDistance !== this.viewDistance) {
105
103
  this.viewDistance = newViewDistance
106
104
  this.updateSkyColors()
@@ -118,7 +116,7 @@ export class SkyboxRenderer {
118
116
  }
119
117
 
120
118
  // Update world time
121
- updateTime (timeOfDay: number, partialTicks = 0) {
119
+ updateTime(timeOfDay: number, partialTicks = 0) {
122
120
  if (this.debugGui.visible) return
123
121
  this.worldTime = timeOfDay
124
122
  this.partialTicks = partialTicks
@@ -126,20 +124,20 @@ export class SkyboxRenderer {
126
124
  }
127
125
 
128
126
  // Update view distance
129
- updateViewDistance (viewDistance: number) {
127
+ updateViewDistance(viewDistance: number) {
130
128
  this.viewDistance = viewDistance
131
129
  this.updateSkyColors()
132
130
  }
133
131
 
134
132
  // Update temperature (for biome support)
135
- updateTemperature (temperature: number) {
133
+ updateTemperature(temperature: number) {
136
134
  if (this.debugGui.visible) return
137
135
  this.temperature = temperature
138
136
  this.updateSkyColors()
139
137
  }
140
138
 
141
139
  // Update water state
142
- updateWaterState (inWater: boolean, waterBreathing: boolean) {
140
+ updateWaterState(inWater: boolean, waterBreathing: boolean) {
143
141
  if (this.debugGui.visible) return
144
142
  this.inWater = inWater
145
143
  this.waterBreathing = waterBreathing
@@ -147,13 +145,13 @@ export class SkyboxRenderer {
147
145
  }
148
146
 
149
147
  // Update default skybox setting
150
- updateDefaultSkybox (defaultSkybox: boolean) {
148
+ updateDefaultSkybox(defaultSkybox: boolean) {
151
149
  if (this.debugGui.visible) return
152
150
  this.defaultSkybox = defaultSkybox
153
151
  this.updateSkyColors()
154
152
  }
155
153
 
156
- private createGradientSky () {
154
+ private createGradientSky() {
157
155
  const size = 64
158
156
  const scale = 256 / size + 2
159
157
 
@@ -190,7 +188,7 @@ export class SkyboxRenderer {
190
188
  this.updateSkyColors()
191
189
  }
192
190
 
193
- private getFogColor (partialTicks = 0): THREE.Vector3 {
191
+ private getFogColor(partialTicks = 0): THREE.Vector3 {
194
192
  const angle = this.getCelestialAngle(partialTicks)
195
193
  let rotation = Math.cos(angle * Math.PI * 2) * 2 + 0.5
196
194
  rotation = Math.max(0, Math.min(1, rotation))
@@ -199,14 +197,14 @@ export class SkyboxRenderer {
199
197
  let y = 0.847_058_83
200
198
  let z = 1
201
199
 
202
- x *= (rotation * 0.94 + 0.06)
203
- y *= (rotation * 0.94 + 0.06)
204
- z *= (rotation * 0.91 + 0.09)
200
+ x *= rotation * 0.94 + 0.06
201
+ y *= rotation * 0.94 + 0.06
202
+ z *= rotation * 0.91 + 0.09
205
203
 
206
204
  return new THREE.Vector3(x, y, z)
207
205
  }
208
206
 
209
- private getSkyColor (x = 0, z = 0, partialTicks = 0): THREE.Vector3 {
207
+ private getSkyColor(x = 0, z = 0, partialTicks = 0): THREE.Vector3 {
210
208
  const angle = this.getCelestialAngle(partialTicks)
211
209
  let brightness = Math.cos(angle * 3.141_593 * 2) * 2 + 0.5
212
210
 
@@ -220,15 +218,11 @@ export class SkyboxRenderer {
220
218
  const green = ((rgb >> 8) & 0xff) / 255
221
219
  const blue = (rgb & 0xff) / 255
222
220
 
223
- return new THREE.Vector3(
224
- red * brightness,
225
- green * brightness,
226
- blue * brightness
227
- )
221
+ return new THREE.Vector3(red * brightness, green * brightness, blue * brightness)
228
222
  }
229
223
 
230
- private calculateCelestialAngle (time: number, partialTicks: number): number {
231
- const modTime = (time % 24_000)
224
+ private calculateCelestialAngle(time: number, partialTicks: number): number {
225
+ const modTime = time % 24_000
232
226
  let angle = (modTime + partialTicks) / 24_000 - 0.25
233
227
 
234
228
  if (angle < 0) {
@@ -238,21 +232,21 @@ export class SkyboxRenderer {
238
232
  angle--
239
233
  }
240
234
 
241
- angle = 1 - ((Math.cos(angle * Math.PI) + 1) / 2)
235
+ angle = 1 - (Math.cos(angle * Math.PI) + 1) / 2
242
236
  angle += (angle - angle) / 3
243
237
 
244
238
  return angle
245
239
  }
246
240
 
247
- private getCelestialAngle (partialTicks: number): number {
241
+ private getCelestialAngle(partialTicks: number): number {
248
242
  return this.calculateCelestialAngle(this.worldTime, partialTicks)
249
243
  }
250
244
 
251
- private getTemperature (x: number, z: number): number {
245
+ private getTemperature(x: number, z: number): number {
252
246
  return this.temperature
253
247
  }
254
248
 
255
- private getSkyColorByTemp (temperature: number): number {
249
+ private getSkyColorByTemp(temperature: number): number {
256
250
  temperature /= 3
257
251
  if (temperature < -1) temperature = -1
258
252
  if (temperature > 1) temperature = 1
@@ -262,17 +256,20 @@ export class SkyboxRenderer {
262
256
  // Orange is around hue 0.08-0.15, so we need to shift from blue-purple (0.62) toward orange
263
257
  // Use a more dramatic shift and also increase saturation for more noticeable effect
264
258
  const orangeHue = 0.12 // Orange hue value
265
- const hue = this.fogOrangeness > 0
266
- ? baseHue + (orangeHue - baseHue) * this.fogOrangeness * 0.8 // Blend toward orange
267
- : baseHue + this.fogOrangeness * 0.1 // Subtle shift for negative values
259
+ const hue =
260
+ this.fogOrangeness > 0
261
+ ? baseHue + (orangeHue - baseHue) * this.fogOrangeness * 0.8 // Blend toward orange
262
+ : baseHue + this.fogOrangeness * 0.1 // Subtle shift for negative values
268
263
  const saturation = 0.5 + temperature * 0.1 + Math.abs(this.fogOrangeness) * 0.3 // Increase saturation with orangeness
269
264
  const brightness = 1
270
265
 
271
266
  return this.hsbToRgb(hue, saturation, brightness)
272
267
  }
273
268
 
274
- private hsbToRgb (hue: number, saturation: number, brightness: number): number {
275
- let r = 0; let g = 0; let b = 0
269
+ private hsbToRgb(hue: number, saturation: number, brightness: number): number {
270
+ let r = 0
271
+ let g = 0
272
+ let b = 0
276
273
  if (saturation === 0) {
277
274
  r = g = b = Math.floor(brightness * 255 + 0.5)
278
275
  } else {
@@ -280,7 +277,7 @@ export class SkyboxRenderer {
280
277
  const f = h - Math.floor(h)
281
278
  const p = brightness * (1 - saturation)
282
279
  const q = brightness * (1 - saturation * f)
283
- const t = brightness * (1 - (saturation * (1 - f)))
280
+ const t = brightness * (1 - saturation * (1 - f))
284
281
  switch (Math.floor(h)) {
285
282
  case 0:
286
283
  r = Math.floor(brightness * 255 + 0.5)
@@ -314,10 +311,10 @@ export class SkyboxRenderer {
314
311
  break
315
312
  }
316
313
  }
317
- return 0xff_00_00_00 | (r << 16) | (g << 8) | (Math.trunc(b))
314
+ return 0xff_00_00_00 | (r << 16) | (g << 8) | Math.trunc(b)
318
315
  }
319
316
 
320
- private updateSkyColors () {
317
+ private updateSkyColors() {
321
318
  if (!this.skyMesh || !this.voidMesh) return
322
319
 
323
320
  // If default skybox is disabled, hide the skybox meshes
@@ -357,7 +354,7 @@ export class SkyboxRenderer {
357
354
 
358
355
  // Normal sky colors
359
356
  const viewDistance = this.viewDistance * 16
360
- const viewFactor = 1 - (0.25 + 0.75 * this.viewDistance / 32) ** 0.25
357
+ const viewFactor = 1 - (0.25 + (0.75 * this.viewDistance) / 32) ** 0.25
361
358
 
362
359
  const angle = this.getCelestialAngle(this.partialTicks)
363
360
  const skyColor = this.getSkyColor(0, 0, this.partialTicks)
@@ -375,16 +372,11 @@ export class SkyboxRenderer {
375
372
 
376
373
  this.scene.background = new THREE.Color(red, green, blue)
377
374
  this.scene.fog = new THREE.Fog(new THREE.Color(red, green, blue), 0.0025, viewDistance * this.distanceFactor)
378
-
379
375
  ;(this.skyMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(skyColor.x, skyColor.y, skyColor.z))
380
- ;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(
381
- skyColor.x * 0.2 + 0.04,
382
- skyColor.y * 0.2 + 0.04,
383
- skyColor.z * 0.6 + 0.1
384
- ))
376
+ ;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(skyColor.x * 0.2 + 0.04, skyColor.y * 0.2 + 0.04, skyColor.z * 0.6 + 0.1))
385
377
  }
386
378
 
387
- dispose () {
379
+ dispose() {
388
380
  if (this.texture) {
389
381
  this.texture.dispose()
390
382
  }
@@ -3,20 +3,16 @@ import { test, expect, vi } from 'vitest'
3
3
  import * as THREE from 'three'
4
4
 
5
5
  vi.mock('../entity/EntityMesh', () => ({
6
- getMesh: vi.fn(),
6
+ getMesh: vi.fn()
7
7
  }))
8
8
 
9
9
  import { ChunkMeshManager } from '../chunkMeshManager'
10
10
  import type { WorldRendererThree } from '../worldRendererThree'
11
11
  import type { MesherGeometryOutput } from '../../mesher-shared/shared'
12
+ import { renderWasmOutputToGeometry } from '../../wasm-mesher/bridge/render-from-wasm'
12
13
 
13
- function makeQuadArrays () {
14
- const positions = new Float32Array([
15
- -1, -1, -1,
16
- -1, 1, -1,
17
- -1, 1, 1,
18
- -1, -1, 1,
19
- ])
14
+ function makeQuadArrays() {
15
+ const positions = new Float32Array([-1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1])
20
16
  const colors = new Float32Array(12).fill(1)
21
17
  const skyLights = new Float32Array(4).fill(1)
22
18
  const blockLights = new Float32Array(4).fill(0)
@@ -25,7 +21,7 @@ function makeQuadArrays () {
25
21
  return { positions, colors, skyLights, blockLights, uvs, indices }
26
22
  }
27
23
 
28
- function makeBlendOnlyGeometry (): MesherGeometryOutput {
24
+ function makeBlendOnlyGeometry(): MesherGeometryOutput {
29
25
  const blend = makeQuadArrays()
30
26
  return {
31
27
  sectionYNumber: 0,
@@ -61,12 +57,12 @@ function makeBlendOnlyGeometry (): MesherGeometryOutput {
61
57
  skyLights: blend.skyLights,
62
58
  blockLights: blend.blockLights,
63
59
  uvs: blend.uvs,
64
- indices: blend.indices,
65
- },
60
+ indices: blend.indices
61
+ }
66
62
  }
67
63
  }
68
64
 
69
- function makeMixedGeometry (): MesherGeometryOutput {
65
+ function makeMixedGeometry(): MesherGeometryOutput {
70
66
  const opaque = makeQuadArrays()
71
67
  const blend = makeQuadArrays()
72
68
  return {
@@ -103,12 +99,12 @@ function makeMixedGeometry (): MesherGeometryOutput {
103
99
  skyLights: blend.skyLights,
104
100
  blockLights: blend.blockLights,
105
101
  uvs: blend.uvs,
106
- indices: blend.indices,
107
- },
102
+ indices: blend.indices
103
+ }
108
104
  }
109
105
  }
110
106
 
111
- function makeInvalidBlendGeometry (): MesherGeometryOutput {
107
+ function makeInvalidBlendGeometry(): MesherGeometryOutput {
112
108
  const geo = makeBlendOnlyGeometry()
113
109
  const blend = geo.blend!
114
110
  return {
@@ -116,33 +112,94 @@ function makeInvalidBlendGeometry (): MesherGeometryOutput {
116
112
  blend: {
117
113
  ...blend,
118
114
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 2, 0, 0]),
119
- indices: new Uint32Array([0, 1, 2, 0, 2, 1, 3]),
120
- },
115
+ indices: new Uint32Array([0, 1, 2, 0, 2, 1, 3])
116
+ }
121
117
  }
122
118
  }
123
119
 
124
120
  type ManagerOptions = {
125
121
  revealDefer?: boolean
122
+ shaderCubes?: boolean
123
+ finishedChunks?: Record<string, boolean>
124
+ }
125
+
126
+ function makeShaderCubeOnlyGeometry(): MesherGeometryOutput {
127
+ const block = {
128
+ position: [0, 0, 0] as [number, number, number],
129
+ block_state_id: 1,
130
+ visible_faces: (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5),
131
+ ao_data: Array.from({ length: 6 }, () => [3, 3, 3, 3]),
132
+ light_data: Array.from({ length: 6 }, () => [1, 1, 1, 1]),
133
+ light_combined: Array.from({ length: 6 }, () => [255, 255, 255, 255])
134
+ }
135
+ const out = renderWasmOutputToGeometry({ blocks: [block], block_count: 1, block_iterations: 0 }, '1.16.5', '0,0,0', { x: 8, y: 8, z: 8 }, undefined, {
136
+ shaderCubes: true
137
+ })
138
+ return {
139
+ sectionYNumber: 0,
140
+ chunkKey: '0,0',
141
+ sectionStartY: 0,
142
+ sectionEndY: 16,
143
+ sectionStartX: 0,
144
+ sectionEndX: 16,
145
+ sectionStartZ: 0,
146
+ sectionEndZ: 16,
147
+ sx: 8,
148
+ sy: 8,
149
+ sz: 8,
150
+ positions: new Float32Array(0),
151
+ normals: new Float32Array(0),
152
+ colors: new Float32Array(0),
153
+ skyLights: new Float32Array(0),
154
+ blockLights: new Float32Array(0),
155
+ uvs: new Float32Array(0),
156
+ indices: new Uint32Array(0),
157
+ indicesCount: 0,
158
+ using32Array: true,
159
+ tiles: {},
160
+ heads: {},
161
+ signs: {},
162
+ banners: {},
163
+ hadErrors: false,
164
+ blocksCount: 1,
165
+ shaderCubes: out.shaderCubes
166
+ }
167
+ }
168
+
169
+ function makeCullCamera(): THREE.PerspectiveCamera {
170
+ const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 1000)
171
+ camera.position.set(8, 8, 20)
172
+ camera.lookAt(8, 8, 8)
173
+ camera.updateMatrixWorld()
174
+ return camera
175
+ }
176
+
177
+ function drainCubeUploads(manager: ChunkMeshManager): void {
178
+ const gb = manager.globalBlockBuffer
179
+ if (!gb) return
180
+ while (gb.hasPendingUploads()) gb.uploadDirtyRange()
126
181
  }
127
182
 
128
- function createManager (opts: ManagerOptions = {}): ChunkMeshManager {
183
+ function createManager(opts: ManagerOptions = {}): ChunkMeshManager {
129
184
  const scene = new THREE.Scene()
130
185
  const material = new THREE.MeshBasicMaterial()
131
186
  const revealModule = opts.revealDefer
132
187
  ? {
133
- shouldDeferSectionGeometry: () => true,
134
- }
188
+ shouldDeferSectionGeometry: () => true
189
+ }
135
190
  : undefined
136
191
  const worldRenderer = {
137
- shaderCubeBlocksEnabled: () => false,
192
+ shaderCubeBlocksEnabled: () => opts.shaderCubes ?? false,
138
193
  getModule: (name: string) => (name === 'futuristicReveal' ? revealModule : undefined),
139
194
  sceneOrigin: {
140
195
  track: () => {},
141
196
  removeAndUntrack: () => {},
142
- removeAndUntrackAll: () => {},
197
+ removeAndUntrackAll: () => {}
143
198
  },
144
199
  blockEntities: {},
145
- worldRendererConfig: {},
200
+ worldRendererConfig: opts.shaderCubes ? { wasmMesher: true } : {},
201
+ displayOptions: { inWorldRenderingConfig: {} },
202
+ finishedChunks: opts.finishedChunks ?? (opts.shaderCubes ? { '0,0': true } : {})
146
203
  } as unknown as WorldRendererThree
147
204
  return new ChunkMeshManager(worldRenderer, scene, material, 256, 1)
148
205
  }
@@ -187,11 +244,13 @@ test('ChunkMeshManager: hidden section excluded from draw spans', () => {
187
244
  camera.updateMatrixWorld()
188
245
 
189
246
  manager.updateSectionCullAndSort(camera, 8, 8, 20)
190
- expect(manager.globalLegacyBlendBuffer?.mesh.geometry.groups.length).toBe(0)
247
+ expect(manager.globalLegacyBlendBuffer?.getVisibleIndexSpans().length).toBe(0)
191
248
 
192
249
  section.visible = true
250
+ const blendBuf = manager.globalLegacyBlendBuffer!
251
+ while (blendBuf.hasPendingUploads()) blendBuf.uploadDirtyRange()
193
252
  manager.updateSectionCullAndSort(camera, 8, 8, 20)
194
- expect(manager.globalLegacyBlendBuffer?.mesh.geometry.groups.length).toBeGreaterThan(0)
253
+ expect(manager.globalLegacyBlendBuffer?.getVisibleIndexSpans().length).toBeGreaterThan(0)
195
254
 
196
255
  manager.cleanupSection(key)
197
256
  manager.dispose()
@@ -284,3 +343,52 @@ test('ChunkMeshManager: mixed opaque and blend route to separate global buffers'
284
343
 
285
344
  manager.dispose()
286
345
  })
346
+
347
+ test('ChunkMeshManager: hidden cube section excluded from draw spans', () => {
348
+ const manager = createManager({ shaderCubes: true })
349
+ const key = '0,0,0'
350
+ manager.updateSection(key, makeShaderCubeOnlyGeometry())
351
+ const section = manager.sectionObjects[key]!
352
+ expect(manager.globalBlockBuffer?.hasSection(key)).toBe(true)
353
+ drainCubeUploads(manager)
354
+
355
+ const camera = makeCullCamera()
356
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
357
+ expect(manager.globalBlockBuffer?.getVisibleSpans().length).toBeGreaterThan(0)
358
+
359
+ section.visible = false
360
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
361
+ expect(manager.globalBlockBuffer?.getVisibleSpans().length).toBe(0)
362
+
363
+ section.visible = true
364
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
365
+ expect(manager.globalBlockBuffer?.getVisibleSpans().length).toBeGreaterThan(0)
366
+
367
+ manager.cleanupSection(key)
368
+ manager.dispose()
369
+ })
370
+
371
+ test('ChunkMeshManager: finishChunkDisplay reveals cube spans and marks cull dirty', () => {
372
+ const manager = createManager({ shaderCubes: true, finishedChunks: {} })
373
+ const key = '0,0,0'
374
+ manager.updateSection(key, makeShaderCubeOnlyGeometry())
375
+ expect(manager.sectionObjects[key]?.visible).toBe(false)
376
+ expect(manager.globalBlockBuffer?.hasSection(key)).toBe(true)
377
+
378
+ const camera = makeCullCamera()
379
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
380
+ expect(manager.globalBlockBuffer?.getVisibleSpans().length).toBe(0)
381
+
382
+ const markCullDirtySpy = vi.spyOn(manager, 'markCullDirty')
383
+ manager.finishChunkDisplay('0,0')
384
+ expect(manager.sectionObjects[key]?.visible).toBe(true)
385
+ expect(markCullDirtySpy).toHaveBeenCalled()
386
+
387
+ drainCubeUploads(manager)
388
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
389
+ expect(manager.globalBlockBuffer?.getVisibleSpans().length).toBeGreaterThan(0)
390
+
391
+ markCullDirtySpy.mockRestore()
392
+ manager.cleanupSection(key)
393
+ manager.dispose()
394
+ })
@@ -1,46 +1,76 @@
1
1
  //@ts-nocheck
2
2
  import { describe, expect, test } from 'vitest'
3
- import {
4
- buildVisibleCubeSpans,
5
- MAX_CUBE_SPANS,
6
- SPAN_GAP_TOLERANCE_FACES,
7
- } from '../cubeDrawSpans'
3
+ import { buildVisibleCubeSpans } from '../cubeDrawSpans'
8
4
 
9
5
  describe('buildVisibleCubeSpans', () => {
10
6
  test('contiguous slots merge into one span', () => {
11
- const spans = buildVisibleCubeSpans([
12
- { start: 0, count: 4 },
13
- { start: 4, count: 2 },
14
- ], 6)
7
+ const spans = buildVisibleCubeSpans(
8
+ [
9
+ { start: 0, count: 4 },
10
+ { start: 4, count: 2 }
11
+ ],
12
+ 6
13
+ )
15
14
  expect(spans.length).toBe(1)
16
15
  expect(spans[0]).toEqual({ start: 0, count: 6 })
17
16
  })
18
17
 
19
18
  test('scattered slots stay as multiple spans', () => {
20
- const gap = SPAN_GAP_TOLERANCE_FACES + 1
21
- const spans = buildVisibleCubeSpans([
22
- { start: 0, count: 1 },
23
- { start: 1 + gap, count: 1 },
24
- ], 1 + gap + 1)
19
+ const spans = buildVisibleCubeSpans(
20
+ [
21
+ { start: 0, count: 1 },
22
+ { start: 10, count: 1 }
23
+ ],
24
+ 11
25
+ )
25
26
  expect(spans.length).toBe(2)
26
27
  expect(spans[0]).toEqual({ start: 0, count: 1 })
27
- expect(spans[1]).toEqual({ start: 1 + gap, count: 1 })
28
+ expect(spans[1]).toEqual({ start: 10, count: 1 })
28
29
  })
29
30
 
30
31
  test('full draw when most faces visible', () => {
31
- const spans = buildVisibleCubeSpans([
32
- { start: 0, count: 3 },
33
- { start: 3, count: 3 },
34
- { start: 6, count: 2 },
35
- ], 8)
32
+ const spans = buildVisibleCubeSpans(
33
+ [
34
+ { start: 0, count: 3 },
35
+ { start: 3, count: 3 },
36
+ { start: 6, count: 2 }
37
+ ],
38
+ 8
39
+ )
36
40
  expect(spans.length).toBe(1)
37
41
  expect(spans[0]).toEqual({ start: 0, count: 8 })
38
42
  })
39
43
 
40
- test('caps at MAX_CUBE_SPANS with full coverage', () => {
41
- const visibleSectionCount = MAX_CUBE_SPANS + 5
42
- const padFaces = SPAN_GAP_TOLERANCE_FACES + 1
43
- const visibleSlots: Array<{ start: number, count: number }> = []
44
+ test('full draw blocked when canFullDraw is false', () => {
45
+ const spans = buildVisibleCubeSpans([{ start: 0, count: 6 }], 8, false)
46
+ expect(spans).toEqual([{ start: 0, count: 6 }])
47
+ })
48
+
49
+ test('carves pending interior range from full-draw span', () => {
50
+ const spans = buildVisibleCubeSpans([{ start: 0, count: 6 }], 8, true, undefined, [{ start: 2, end: 3 }])
51
+ expect(spans).toEqual([
52
+ { start: 0, count: 2 },
53
+ { start: 4, count: 4 }
54
+ ])
55
+ })
56
+
57
+ test('does not merge across interior gap', () => {
58
+ const spans = buildVisibleCubeSpans(
59
+ [
60
+ { start: 0, count: 1 },
61
+ { start: 2, count: 1 }
62
+ ],
63
+ 3
64
+ )
65
+ expect(spans.length).toBe(2)
66
+ expect(spans[0]).toEqual({ start: 0, count: 1 })
67
+ expect(spans[1]).toEqual({ start: 2, count: 1 })
68
+ })
69
+
70
+ test('does not cap span count when many scattered sections', () => {
71
+ const visibleSectionCount = 69
72
+ const padFaces = 10
73
+ const visibleSlots: Array<{ start: number; count: number }> = []
44
74
  let cursor = 0
45
75
 
46
76
  for (let i = 0; i < visibleSectionCount; i++) {
@@ -53,7 +83,7 @@ describe('buildVisibleCubeSpans', () => {
53
83
 
54
84
  const highWatermark = cursor
55
85
  const spans = buildVisibleCubeSpans(visibleSlots, highWatermark)
56
- expect(spans.length).toBe(MAX_CUBE_SPANS)
86
+ expect(spans.length).toBe(visibleSectionCount)
57
87
 
58
88
  const covered = new Set<number>()
59
89
  for (const span of spans) {