minecraft-renderer 0.1.43 → 0.1.45
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.
- package/dist/mesher.js +35 -35
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +61 -61
- package/dist/minecraft-renderer.js +59 -59
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +458 -458
- package/package.json +1 -1
- package/src/graphicsBackend/appViewer.ts +19 -7
- package/src/graphicsBackend/types.ts +5 -1
- package/src/index.ts +33 -0
- package/src/lib/ui/newStats.ts +16 -2
- package/src/lib/worldrendererCommon.ts +2 -2
- package/src/mesher-shared/models.ts +28 -11
- package/src/mesher-shared/vertexShading.ts +35 -0
- package/src/three/entities.ts +22 -6
- package/src/three/graphicsBackendBase.ts +28 -20
- package/src/three/graphicsBackendOffThread.ts +1 -2
- package/src/three/menuBackground/activeView.ts +19 -0
- package/src/three/menuBackground/classic.ts +148 -0
- package/src/three/menuBackground/config.ts +23 -0
- package/src/three/menuBackground/defaultOptions.ts +141 -0
- package/src/three/menuBackground/futuristic.ts +859 -0
- package/src/three/menuBackground/index.ts +36 -0
- package/src/three/menuBackground/renderer.ts +97 -0
- package/src/three/menuBackground/shared.ts +3 -0
- package/src/three/menuBackground/types.ts +37 -0
- package/src/three/menuBackground/worldBlocks.ts +144 -0
- package/src/three/modules/rain.ts +21 -3
- package/src/three/waypointSprite.ts +108 -106
- package/src/three/worldRendererThree.ts +9 -12
- package/src/wasm-mesher/bridge/render-from-wasm.ts +57 -12
- package/src/three/panorama.ts +0 -312
- package/src/three/panoramaShared.ts +0 -2
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
import * as THREE from 'three'
|
|
3
3
|
import { createCanvas } from '../lib/utils'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Limits label texture resolution on high-DPR devices (sprite still sizes in screen px via Three.js;
|
|
7
|
+
* main win is fewer canvas pixels / less GPU memory — especially on iOS).
|
|
8
|
+
*/
|
|
9
|
+
const LABEL_CANVAS_MAX_DEVICE_PIXEL_RATIO = 1
|
|
10
|
+
|
|
11
|
+
/** Distance label repaints when this bucket (meters) changes — fewer canvas uploads while moving. */
|
|
12
|
+
const DISTANCE_LABEL_STEP_M = 10
|
|
13
|
+
|
|
5
14
|
// Centralized visual configuration (in screen pixels)
|
|
6
15
|
export const WAYPOINT_CONFIG = {
|
|
7
16
|
// Target size in screen pixels (this controls the final sprite size)
|
|
@@ -60,9 +69,8 @@ export function createWaypointSprite (options: {
|
|
|
60
69
|
visualScale?: number,
|
|
61
70
|
opacity?: number,
|
|
62
71
|
}): WaypointSprite {
|
|
63
|
-
|
|
72
|
+
let displayColor = options.color ?? 0xFF_00_00
|
|
64
73
|
const depthTest = options.depthTest ?? false
|
|
65
|
-
const labelYOffset = options.labelYOffset ?? 1.5
|
|
66
74
|
|
|
67
75
|
// Get visual scale from options, metadata, server metadata, or default
|
|
68
76
|
// Priority: options.visualScale > metadata.visualScale > window.serverMetadata?.waypointVisualScale > DEFAULT
|
|
@@ -78,61 +86,87 @@ export function createWaypointSprite (options: {
|
|
|
78
86
|
?? (typeof window === 'undefined' ? undefined : (window as any).serverMetadata?.waypointOpacity)
|
|
79
87
|
?? WAYPOINT_CONFIG.DEFAULT_OPACITY
|
|
80
88
|
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
const labelCanvas = createCanvas(getLabelCanvasSize(), getLabelCanvasSize())
|
|
90
|
+
drawCombinedOntoCanvas(labelCanvas, displayColor, options.label ?? '', '0m', visualScale)
|
|
91
|
+
|
|
92
|
+
const labelTexture = new THREE.CanvasTexture(labelCanvas)
|
|
93
|
+
labelTexture.anisotropy = 1
|
|
94
|
+
labelTexture.magFilter = THREE.LinearFilter
|
|
95
|
+
labelTexture.minFilter = THREE.LinearFilter
|
|
96
|
+
const material = new THREE.SpriteMaterial({
|
|
97
|
+
map: labelTexture,
|
|
98
|
+
transparent: true,
|
|
99
|
+
opacity: 1,
|
|
100
|
+
depthTest,
|
|
101
|
+
depthWrite: false,
|
|
102
|
+
})
|
|
103
|
+
const sprite = new THREE.Sprite(material)
|
|
104
|
+
sprite.position.set(0, 0, 0)
|
|
83
105
|
sprite.renderOrder = 10
|
|
84
106
|
sprite.material.opacity = opacity
|
|
85
107
|
let currentLabel = options.label ?? ''
|
|
86
108
|
|
|
87
|
-
// Performance optimization: cache distance text to avoid unnecessary updates
|
|
88
109
|
let lastDistanceText = '0m'
|
|
89
|
-
let
|
|
110
|
+
let lastDistanceBucket = Number.NaN
|
|
90
111
|
|
|
91
|
-
// Offscreen arrow (detached by default)
|
|
92
112
|
let arrowSprite: THREE.Sprite | undefined
|
|
113
|
+
let arrowCanvas: OffscreenCanvas | undefined
|
|
114
|
+
let arrowCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | undefined
|
|
115
|
+
let arrowTexture: THREE.CanvasTexture | undefined
|
|
93
116
|
let arrowParent: THREE.Object3D | null = null
|
|
94
117
|
let arrowEnabled = WAYPOINT_CONFIG.ARROW.enabledDefault
|
|
95
118
|
|
|
96
|
-
// Group for easy add/remove
|
|
97
119
|
const group = new THREE.Group()
|
|
98
120
|
group.add(sprite)
|
|
99
121
|
|
|
100
|
-
// Initial position
|
|
101
122
|
const { x, y, z } = options.position
|
|
102
123
|
group.position.set(x, y, z)
|
|
103
124
|
|
|
125
|
+
function refreshLabelTexture () {
|
|
126
|
+
labelTexture.needsUpdate = true
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function paintArrowOnCanvas () {
|
|
130
|
+
if (!arrowCanvas || !arrowCtx) return
|
|
131
|
+
const size = arrowCanvas.width
|
|
132
|
+
arrowCtx.clearRect(0, 0, size, size)
|
|
133
|
+
arrowCtx.beginPath()
|
|
134
|
+
arrowCtx.moveTo(size * 0.15, size * 0.5)
|
|
135
|
+
arrowCtx.lineTo(size * 0.85, size * 0.5)
|
|
136
|
+
arrowCtx.lineTo(size * 0.5, size * 0.15)
|
|
137
|
+
arrowCtx.closePath()
|
|
138
|
+
const colorHex = `#${displayColor.toString(16).padStart(6, '0')}`
|
|
139
|
+
arrowCtx.lineWidth = 6
|
|
140
|
+
arrowCtx.strokeStyle = 'black'
|
|
141
|
+
arrowCtx.stroke()
|
|
142
|
+
arrowCtx.fillStyle = colorHex
|
|
143
|
+
arrowCtx.fill()
|
|
144
|
+
if (arrowTexture) arrowTexture.needsUpdate = true
|
|
145
|
+
}
|
|
146
|
+
|
|
104
147
|
function setColor (newColor: number) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
148
|
+
displayColor = newColor
|
|
149
|
+
lastDistanceText = '0m'
|
|
150
|
+
lastDistanceBucket = 0
|
|
151
|
+
drawCombinedOntoCanvas(labelCanvas, displayColor, currentLabel, '0m', visualScale)
|
|
152
|
+
refreshLabelTexture()
|
|
153
|
+
if (arrowSprite) paintArrowOnCanvas()
|
|
111
154
|
}
|
|
112
155
|
|
|
113
156
|
function setLabel (newLabel?: string) {
|
|
114
157
|
currentLabel = newLabel ?? ''
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const mat = sprite.material
|
|
118
|
-
mat.map?.dispose()
|
|
119
|
-
mat.map = texture
|
|
120
|
-
mat.needsUpdate = true
|
|
158
|
+
drawCombinedOntoCanvas(labelCanvas, displayColor, currentLabel, lastDistanceText, visualScale)
|
|
159
|
+
refreshLabelTexture()
|
|
121
160
|
}
|
|
122
161
|
|
|
123
162
|
function updateDistanceText (label: string, distanceText: string) {
|
|
124
|
-
// Performance optimization: only update if distance text actually changed
|
|
125
163
|
if (distanceText === lastDistanceText) {
|
|
126
164
|
return
|
|
127
165
|
}
|
|
128
166
|
lastDistanceText = distanceText
|
|
129
167
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const mat = sprite.material
|
|
133
|
-
mat.map?.dispose()
|
|
134
|
-
mat.map = texture
|
|
135
|
-
mat.needsUpdate = true
|
|
168
|
+
drawCombinedOntoCanvas(labelCanvas, displayColor, label, distanceText, visualScale)
|
|
169
|
+
refreshLabelTexture()
|
|
136
170
|
}
|
|
137
171
|
|
|
138
172
|
function setVisible (visible: boolean) {
|
|
@@ -143,7 +177,6 @@ export function createWaypointSprite (options: {
|
|
|
143
177
|
group.position.set(nx, ny, nz)
|
|
144
178
|
}
|
|
145
179
|
|
|
146
|
-
// Keep constant pixel size on screen using global config
|
|
147
180
|
function updateScaleScreenPixels (
|
|
148
181
|
cameraPosition: THREE.Vector3,
|
|
149
182
|
cameraFov: number,
|
|
@@ -152,7 +185,6 @@ export function createWaypointSprite (options: {
|
|
|
152
185
|
) {
|
|
153
186
|
const vFovRad = cameraFov * Math.PI / 180
|
|
154
187
|
const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * distance
|
|
155
|
-
// Use configured target screen size with visual scale multiplier
|
|
156
188
|
const scale = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.TARGET_SCREEN_PX * visualScale / viewportHeightPx)
|
|
157
189
|
sprite.scale.set(scale, scale, 1)
|
|
158
190
|
}
|
|
@@ -160,28 +192,15 @@ export function createWaypointSprite (options: {
|
|
|
160
192
|
function ensureArrow () {
|
|
161
193
|
if (arrowSprite) return
|
|
162
194
|
const size = 128
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
ctx.closePath()
|
|
173
|
-
|
|
174
|
-
// Use waypoint color for arrow
|
|
175
|
-
const colorHex = `#${color.toString(16).padStart(6, '0')}`
|
|
176
|
-
ctx.lineWidth = 6
|
|
177
|
-
ctx.strokeStyle = 'black'
|
|
178
|
-
ctx.stroke()
|
|
179
|
-
ctx.fillStyle = colorHex
|
|
180
|
-
ctx.fill()
|
|
181
|
-
|
|
182
|
-
const texture = new THREE.CanvasTexture(canvas)
|
|
183
|
-
const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false, opacity })
|
|
184
|
-
arrowSprite = new THREE.Sprite(material)
|
|
195
|
+
arrowCanvas = createCanvas(size, size)
|
|
196
|
+
arrowCtx = arrowCanvas.getContext('2d')!
|
|
197
|
+
paintArrowOnCanvas()
|
|
198
|
+
arrowTexture = new THREE.CanvasTexture(arrowCanvas)
|
|
199
|
+
arrowTexture.anisotropy = 1
|
|
200
|
+
arrowTexture.magFilter = THREE.LinearFilter
|
|
201
|
+
arrowTexture.minFilter = THREE.LinearFilter
|
|
202
|
+
const matTex = new THREE.SpriteMaterial({ map: arrowTexture, transparent: true, depthTest: false, depthWrite: false, opacity })
|
|
203
|
+
arrowSprite = new THREE.Sprite(matTex)
|
|
185
204
|
arrowSprite.renderOrder = 12
|
|
186
205
|
arrowSprite.visible = false
|
|
187
206
|
if (arrowParent) arrowParent.add(arrowSprite)
|
|
@@ -306,9 +325,8 @@ export function createWaypointSprite (options: {
|
|
|
306
325
|
return false
|
|
307
326
|
}
|
|
308
327
|
|
|
309
|
-
function computeDistance (
|
|
310
|
-
|
|
311
|
-
return group.position.length()
|
|
328
|
+
function computeDistance (cameraPosition: THREE.Vector3): number {
|
|
329
|
+
return cameraPosition.distanceTo(group.position)
|
|
312
330
|
}
|
|
313
331
|
|
|
314
332
|
function updateForCamera (
|
|
@@ -318,17 +336,14 @@ export function createWaypointSprite (options: {
|
|
|
318
336
|
viewportHeightPx: number
|
|
319
337
|
): boolean {
|
|
320
338
|
const distance = computeDistance(cameraPosition)
|
|
321
|
-
// Keep constant pixel size
|
|
322
339
|
updateScaleScreenPixels(cameraPosition, camera.fov, distance, viewportHeightPx)
|
|
323
340
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
updateDistanceText(currentLabel, `${roundedDistance}m`)
|
|
341
|
+
const bucket = Math.round(distance / DISTANCE_LABEL_STEP_M) * DISTANCE_LABEL_STEP_M
|
|
342
|
+
if (bucket !== lastDistanceBucket) {
|
|
343
|
+
lastDistanceBucket = bucket
|
|
344
|
+
updateDistanceText(currentLabel, `${Math.max(0, bucket)}m`)
|
|
329
345
|
}
|
|
330
346
|
|
|
331
|
-
// Update arrow and visibility
|
|
332
347
|
const onScreen = updateOffscreenArrow(camera, viewportWidthPx, viewportHeightPx)
|
|
333
348
|
setVisible(onScreen)
|
|
334
349
|
return onScreen
|
|
@@ -339,7 +354,6 @@ export function createWaypointSprite (options: {
|
|
|
339
354
|
mat.map?.dispose()
|
|
340
355
|
mat.dispose()
|
|
341
356
|
if (arrowSprite) {
|
|
342
|
-
// Remove arrow from parent before disposing
|
|
343
357
|
if (arrowSprite.parent) {
|
|
344
358
|
arrowSprite.parent.remove(arrowSprite)
|
|
345
359
|
}
|
|
@@ -347,6 +361,10 @@ export function createWaypointSprite (options: {
|
|
|
347
361
|
am.map?.dispose()
|
|
348
362
|
am.dispose()
|
|
349
363
|
}
|
|
364
|
+
arrowSprite = undefined
|
|
365
|
+
arrowCanvas = undefined
|
|
366
|
+
arrowCtx = undefined
|
|
367
|
+
arrowTexture = undefined
|
|
350
368
|
}
|
|
351
369
|
|
|
352
370
|
return {
|
|
@@ -365,41 +383,46 @@ export function createWaypointSprite (options: {
|
|
|
365
383
|
}
|
|
366
384
|
|
|
367
385
|
// Internal helpers
|
|
368
|
-
function
|
|
369
|
-
const
|
|
370
|
-
const
|
|
371
|
-
|
|
386
|
+
function computeLabelCanvasLineScale (): number {
|
|
387
|
+
const dpr = globalThis.devicePixelRatio || 1
|
|
388
|
+
const effectiveDpr = Math.min(dpr, LABEL_CANVAS_MAX_DEVICE_PIXEL_RATIO)
|
|
389
|
+
return WAYPOINT_CONFIG.CANVAS_SCALE * effectiveDpr
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function getLabelCanvasSize (): number {
|
|
393
|
+
return Math.round(WAYPOINT_CONFIG.CANVAS_SIZE * computeLabelCanvasLineScale())
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function drawCombinedOntoCanvas (
|
|
397
|
+
canvas: OffscreenCanvas,
|
|
398
|
+
color: number,
|
|
399
|
+
id: string,
|
|
400
|
+
distance: string,
|
|
401
|
+
visualScale: number
|
|
402
|
+
): void {
|
|
403
|
+
const size = canvas.width
|
|
404
|
+
const scale = computeLabelCanvasLineScale()
|
|
372
405
|
const ctx = canvas.getContext('2d')!
|
|
373
406
|
|
|
374
|
-
// Clear canvas
|
|
375
407
|
ctx.clearRect(0, 0, size, size)
|
|
376
408
|
|
|
377
|
-
// Draw dot with visual scale applied
|
|
378
409
|
const centerX = size / 2
|
|
379
410
|
const dotY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DOT_Y)
|
|
380
|
-
const
|
|
381
|
-
const
|
|
411
|
+
const innerRadius = Math.round(size * 0.05 * visualScale)
|
|
412
|
+
const outlinePad = Math.max(2, Math.round(4 * scale * visualScale))
|
|
413
|
+
const dotRadius = innerRadius + outlinePad
|
|
382
414
|
|
|
383
|
-
// Outer border (black)
|
|
384
415
|
ctx.beginPath()
|
|
385
|
-
ctx.arc(centerX, dotY,
|
|
386
|
-
ctx.fillStyle = 'black'
|
|
387
|
-
ctx.fill()
|
|
388
|
-
|
|
389
|
-
// Inner circle (colored)
|
|
390
|
-
ctx.beginPath()
|
|
391
|
-
ctx.arc(centerX, dotY, radius, 0, Math.PI * 2)
|
|
416
|
+
ctx.arc(centerX, dotY, dotRadius, 0, Math.PI * 2)
|
|
392
417
|
ctx.fillStyle = `#${color.toString(16).padStart(6, '0')}`
|
|
393
418
|
ctx.fill()
|
|
394
419
|
|
|
395
|
-
// Text properties
|
|
396
420
|
ctx.textAlign = 'center'
|
|
397
421
|
ctx.textBaseline = 'middle'
|
|
398
422
|
|
|
399
|
-
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
ctx.font = `bold ${nameFontPx}px mojangles`
|
|
423
|
+
const nameFontPx = Math.round(size * 0.08 * visualScale)
|
|
424
|
+
const distanceFontPx = Math.round(size * 0.06 * visualScale)
|
|
425
|
+
ctx.font = `800 ${nameFontPx}px mojangles`
|
|
403
426
|
ctx.lineWidth = Math.max(2, Math.round(3 * scale * visualScale))
|
|
404
427
|
const nameY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.NAME_Y)
|
|
405
428
|
|
|
@@ -408,8 +431,7 @@ function drawCombinedCanvas (color: number, id: string, distance: string, visual
|
|
|
408
431
|
ctx.fillStyle = 'white'
|
|
409
432
|
ctx.fillText(id, centerX, nameY)
|
|
410
433
|
|
|
411
|
-
|
|
412
|
-
ctx.font = `bold ${distanceFontPx}px mojangles`
|
|
434
|
+
ctx.font = `800 ${distanceFontPx}px mojangles`
|
|
413
435
|
ctx.lineWidth = Math.max(2, Math.round(2 * scale * visualScale))
|
|
414
436
|
const distanceY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DISTANCE_Y)
|
|
415
437
|
|
|
@@ -417,26 +439,6 @@ function drawCombinedCanvas (color: number, id: string, distance: string, visual
|
|
|
417
439
|
ctx.strokeText(distance, centerX, distanceY)
|
|
418
440
|
ctx.fillStyle = '#CCCCCC'
|
|
419
441
|
ctx.fillText(distance, centerX, distanceY)
|
|
420
|
-
|
|
421
|
-
return canvas
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
function createCombinedSprite (color: number, id: string, distance: string, depthTest: boolean, visualScale = 1): THREE.Sprite {
|
|
425
|
-
const canvas = drawCombinedCanvas(color, id, distance, visualScale)
|
|
426
|
-
const texture = new THREE.CanvasTexture(canvas)
|
|
427
|
-
texture.anisotropy = 1
|
|
428
|
-
texture.magFilter = THREE.LinearFilter
|
|
429
|
-
texture.minFilter = THREE.LinearFilter
|
|
430
|
-
const material = new THREE.SpriteMaterial({
|
|
431
|
-
map: texture,
|
|
432
|
-
transparent: true,
|
|
433
|
-
opacity: 1,
|
|
434
|
-
depthTest,
|
|
435
|
-
depthWrite: false,
|
|
436
|
-
})
|
|
437
|
-
const sprite = new THREE.Sprite(material)
|
|
438
|
-
sprite.position.set(0, 0, 0)
|
|
439
|
-
return sprite
|
|
440
442
|
}
|
|
441
443
|
|
|
442
444
|
export const WaypointHelpers = {
|
|
@@ -9,7 +9,7 @@ import { renderSign } from '../sign-renderer'
|
|
|
9
9
|
import { DisplayWorldOptions, GraphicsInitOptions } from '../graphicsBackend/types'
|
|
10
10
|
import { chunkPos, sectionPos } from '../lib/simpleUtils'
|
|
11
11
|
import { WorldRendererCommon } from '../lib/worldrendererCommon'
|
|
12
|
-
import { addNewStat } from '../lib/ui/newStats'
|
|
12
|
+
import { addNewStat, MC_RENDERER_DEBUG_OVERLAY_CLASS } from '../lib/ui/newStats'
|
|
13
13
|
import { MesherGeometryOutput } from '../mesher-shared/shared'
|
|
14
14
|
import { ItemSpecificContextProperties } from '../playerState/types'
|
|
15
15
|
import { setBlockPosition } from '../mesher-shared/standaloneRenderer'
|
|
@@ -387,7 +387,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
387
387
|
if ((prop === 'x' || prop === 'y' || prop === 'z') && typeof value === 'number' && Math.abs(value) > WORLD_COORD_THRESHOLD) {
|
|
388
388
|
warnOnce()
|
|
389
389
|
}
|
|
390
|
-
;(target as any)[prop] = value
|
|
390
|
+
; (target as any)[prop] = value
|
|
391
391
|
return true
|
|
392
392
|
},
|
|
393
393
|
get(target, prop, receiver) {
|
|
@@ -701,22 +701,19 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
701
701
|
addDebugOverlay() {
|
|
702
702
|
if (this.debugOverlayAdded) return
|
|
703
703
|
this.debugOverlayAdded = true
|
|
704
|
-
const pane = addNewStat('debug-overlay')
|
|
704
|
+
const pane = addNewStat('debug-overlay', 80, 0, undefined, { className: MC_RENDERER_DEBUG_OVERLAY_CLASS })
|
|
705
705
|
setInterval(() => {
|
|
706
706
|
pane.setVisibility(this.displayAdvancedStats)
|
|
707
707
|
if (this.displayAdvancedStats) {
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
}
|
|
708
|
+
const formatFull = (num: number) => new Intl.NumberFormat('en-US', {}).format(num)
|
|
709
|
+
const formatCompact = (num: number) => new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(num)
|
|
711
710
|
let text = ''
|
|
712
|
-
text += `
|
|
713
|
-
text += `
|
|
714
|
-
text += `
|
|
715
|
-
text += `F: ${formatBigNumber(this.tilesRendered)} `
|
|
716
|
-
text += `B: ${formatBigNumber(this.blocksRendered)} `
|
|
711
|
+
text += `TE: ${formatFull(this.renderer.info.memory.textures)} `
|
|
712
|
+
text += `F: ${formatCompact(this.tilesRendered)} `
|
|
713
|
+
text += `B: ${formatCompact(this.blocksRendered)} `
|
|
717
714
|
text += `MEM: ${this.chunkMeshManager.getEstimatedMemoryUsage().total} `
|
|
718
715
|
const poolStats = this.chunkMeshManager.getStats()
|
|
719
|
-
text += `POOL: ${poolStats.activeCount}/${poolStats.poolSize}
|
|
716
|
+
text += `POOL: ${poolStats.activeCount}/${poolStats.poolSize}`
|
|
720
717
|
pane.updateText(text)
|
|
721
718
|
this.backendInfoReport = text
|
|
722
719
|
}
|
|
@@ -13,6 +13,8 @@ import { elemFaces, buildRotationMatrix, matmul3, matmulmat3, vecadd3, vecsub3 }
|
|
|
13
13
|
import type { ExportedWorldGeometry, ExportedSection } from '../../three/worldGeometryExport'
|
|
14
14
|
import type { MesherGeometryOutput } from '../../mesher-shared/shared'
|
|
15
15
|
import type { World } from '../../mesher-shared/world'
|
|
16
|
+
import { resolveBlockPropertiesForMeshing } from '../../mesher-shared/models'
|
|
17
|
+
import { getSideShading, vertexLightFromAo } from '../../mesher-shared/vertexShading'
|
|
16
18
|
|
|
17
19
|
// Handle both default and named export
|
|
18
20
|
const worldBlockProvider = (worldBlockProviderModule as any).default || worldBlockProviderModule
|
|
@@ -134,6 +136,18 @@ export function extractColumnHeightmap(
|
|
|
134
136
|
return out
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
function computeMesherVertexLight(
|
|
140
|
+
world: World | undefined,
|
|
141
|
+
ao: number,
|
|
142
|
+
cornerLight15: number,
|
|
143
|
+
faceDir: [number, number, number]
|
|
144
|
+
): number {
|
|
145
|
+
const shadingTheme = world?.config.shadingTheme ?? 'high-contrast'
|
|
146
|
+
const cardinalLight = world?.config.cardinalLight ?? 'default'
|
|
147
|
+
const sideShading = getSideShading(faceDir, shadingTheme, cardinalLight)
|
|
148
|
+
return vertexLightFromAo(ao, cornerLight15, sideShading, shadingTheme)
|
|
149
|
+
}
|
|
150
|
+
|
|
137
151
|
/**
|
|
138
152
|
* Get or create cached block model with precomputed matrices
|
|
139
153
|
*/
|
|
@@ -141,10 +155,32 @@ function getCachedBlockModel(
|
|
|
141
155
|
blockStateId: number,
|
|
142
156
|
version: string,
|
|
143
157
|
blockProvider: WorldBlockProvider,
|
|
144
|
-
PrismarineBlock: any
|
|
158
|
+
PrismarineBlock: any,
|
|
159
|
+
world?: World,
|
|
160
|
+
blockPos?: { x: number, y: number, z: number }
|
|
145
161
|
): CachedBlockModel | null {
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
const usePreflat = !!(world?.preflat && blockPos)
|
|
163
|
+
let blockName: string
|
|
164
|
+
let blockProps: Record<string, unknown>
|
|
165
|
+
if (usePreflat) {
|
|
166
|
+
const resolved = resolveBlockPropertiesForMeshing(
|
|
167
|
+
world,
|
|
168
|
+
new Vec3(blockPos!.x, blockPos!.y, blockPos!.z),
|
|
169
|
+
blockProvider,
|
|
170
|
+
blockStateId,
|
|
171
|
+
PrismarineBlock
|
|
172
|
+
)
|
|
173
|
+
blockName = resolved.name
|
|
174
|
+
blockProps = resolved.properties
|
|
175
|
+
} else {
|
|
176
|
+
const blockObj = PrismarineBlock.fromStateId(blockStateId, 1)
|
|
177
|
+
blockName = blockObj.name
|
|
178
|
+
blockProps = blockObj.getProperties()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const cacheKey = usePreflat
|
|
182
|
+
? `${version}:${blockStateId}:${blockName}:${JSON.stringify(blockProps)}`
|
|
183
|
+
: `${version}:${blockStateId}`
|
|
148
184
|
if (!(globalThis as any).__wasmBlockModelCache) {
|
|
149
185
|
(globalThis as any).__wasmBlockModelCache = new Map()
|
|
150
186
|
}
|
|
@@ -156,11 +192,13 @@ function getCachedBlockModel(
|
|
|
156
192
|
|
|
157
193
|
try {
|
|
158
194
|
const blockObj = PrismarineBlock.fromStateId(blockStateId, 1)
|
|
159
|
-
|
|
160
|
-
|
|
195
|
+
if (!usePreflat) {
|
|
196
|
+
blockName = blockObj.name
|
|
197
|
+
blockProps = blockObj.getProperties()
|
|
198
|
+
}
|
|
161
199
|
|
|
162
200
|
const models = blockProvider.getAllResolvedModels0_1(
|
|
163
|
-
{ name: blockName, properties: blockProps },
|
|
201
|
+
{ name: blockName, properties: blockProps as Record<string, string | number | boolean> },
|
|
164
202
|
false
|
|
165
203
|
)
|
|
166
204
|
|
|
@@ -505,7 +543,14 @@ export function renderWasmOutputToGeometry(
|
|
|
505
543
|
}
|
|
506
544
|
}
|
|
507
545
|
|
|
508
|
-
const cachedModel = getCachedBlockModel(
|
|
546
|
+
const cachedModel = getCachedBlockModel(
|
|
547
|
+
blockStateId,
|
|
548
|
+
version,
|
|
549
|
+
blockProvider,
|
|
550
|
+
PrismarineBlock,
|
|
551
|
+
world,
|
|
552
|
+
{ x: bx, y: by, z: bz }
|
|
553
|
+
)
|
|
509
554
|
if (!cachedModel) continue
|
|
510
555
|
|
|
511
556
|
if (false) {
|
|
@@ -654,10 +699,9 @@ export function renderWasmOutputToGeometry(
|
|
|
654
699
|
// But WASM light calculation seems to return 0.0, so we need to handle that
|
|
655
700
|
// In the test case, TypeScript gets baseLight = 1.0 (full brightness)
|
|
656
701
|
// So we should use 1.0 as the base light value when WASM returns 0
|
|
657
|
-
const
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
const light = (ao + 1) / 4 * (cornerLightResult / 15)
|
|
702
|
+
const cornerLight15 = (lightValues[cornerIdx] ?? 1) * 15
|
|
703
|
+
const faceDir = transformedDir as [number, number, number]
|
|
704
|
+
const light = computeMesherVertexLight(world, ao, cornerLight15, faceDir)
|
|
661
705
|
|
|
662
706
|
colors.push(tint[0] * light, tint[1] * light, tint[2] * light)
|
|
663
707
|
|
|
@@ -907,7 +951,8 @@ export function renderWasmOutputToGeometry(
|
|
|
907
951
|
}
|
|
908
952
|
|
|
909
953
|
if (doAO) {
|
|
910
|
-
|
|
954
|
+
const faceDir = transformedDirI as [number, number, number]
|
|
955
|
+
light = computeMesherVertexLight(world, ao, cornerLightResult, faceDir)
|
|
911
956
|
}
|
|
912
957
|
|
|
913
958
|
colors.push(tint[0] * light!, tint[1] * light!, tint[2] * light!)
|