minecraft-renderer 0.1.98 → 0.1.100
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/mesherWasm.js +170 -170
- package/dist/minecraft-renderer.js +1 -1
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +52 -52
- package/package.json +1 -1
- package/src/three/entities.ts +8 -2
- package/src/wasm-mesher/bridge/geometryIndices.ts +17 -0
- package/src/wasm-mesher/bridge/render-from-wasm.ts +3 -4
- package/src/wasm-mesher/tests/geometryIndices.test.ts +71 -0
- package/src/wasm-mesher/worker/mesherWasm.ts +5 -5
package/package.json
CHANGED
package/src/three/entities.ts
CHANGED
|
@@ -240,12 +240,18 @@ function getUsernameTexture(
|
|
|
240
240
|
const iconSize = fontSize * 0.85
|
|
241
241
|
const iconAreaWidth = voiceState ? iconSize + padding * 2.5 : 0
|
|
242
242
|
|
|
243
|
-
|
|
243
|
+
// The nametag sprite is anchored (and thus centered above the player) at the
|
|
244
|
+
// midpoint of this canvas. Mirroring the icon's width as a second, unpainted
|
|
245
|
+
// margin on the right moves that midpoint to align with the *text's* own
|
|
246
|
+
// center instead of the icon+text bounding box's center — otherwise the
|
|
247
|
+
// icon's extra width on the left alone drags the whole sprite's anchor left,
|
|
248
|
+
// which visually reads as the text drifting right of the player.
|
|
249
|
+
const canvas = createCanvas(iconAreaWidth * 2 + textWidth, height)
|
|
244
250
|
const ctx = canvas.getContext('2d')
|
|
245
251
|
if (!ctx) throw new Error('Could not get 2d context')
|
|
246
252
|
|
|
247
253
|
ctx.fillStyle = nameTagBackgroundColor
|
|
248
|
-
ctx.fillRect(0, 0,
|
|
254
|
+
ctx.fillRect(0, 0, iconAreaWidth + textWidth, canvas.height)
|
|
249
255
|
if (voiceState) {
|
|
250
256
|
drawVoiceStateIcon(ctx, voiceState, iconAreaWidth / 2, canvas.height / 2, iconSize)
|
|
251
257
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
export function createGeometryIndexArray(indices: readonly number[]): Uint16Array | Uint32Array {
|
|
3
|
+
let using32Array = false
|
|
4
|
+
for (let index = 0; index < indices.length; index++) {
|
|
5
|
+
if (indices[index] > 65535) {
|
|
6
|
+
using32Array = true
|
|
7
|
+
break
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return using32Array ? new Uint32Array(indices) : new Uint16Array(indices)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function appendGeometryIndices(target: number[], source: readonly number[], vertexOffset: number): void {
|
|
14
|
+
for (let index = 0; index < source.length; index++) {
|
|
15
|
+
target.push(source[index] + vertexOffset)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -19,6 +19,7 @@ import { resolveBlockPropertiesForMeshing } from '../../mesher-shared/blockPrope
|
|
|
19
19
|
import { isSemiTransparentBlockName } from '../../mesher-shared/models'
|
|
20
20
|
import { faceIsCulled } from '../../mesher-shared/faceOcclusion'
|
|
21
21
|
import { buildShaderCubesFromWords, getShaderCubeResources, tryBuildShaderCubeInstances } from './shaderCubeBridge'
|
|
22
|
+
import { appendGeometryIndices } from './geometryIndices'
|
|
22
23
|
import { getSideShading, vertexLightFromAo } from '../../mesher-shared/vertexShading'
|
|
23
24
|
import tintsJson from 'minecraft-data/minecraft-data/data/pc/1.16.2/tints.json'
|
|
24
25
|
|
|
@@ -986,10 +987,8 @@ export function renderWasmOutputToGeometry(
|
|
|
986
987
|
blendSkyLights = liquidSkyLights.concat(blockBlendSkyLights)
|
|
987
988
|
blendBlockLights = liquidBlockLights.concat(blockBlendBlockLights)
|
|
988
989
|
blendUvs = liquidUvs.concat(blockBlendUvs)
|
|
989
|
-
blendIndices
|
|
990
|
-
|
|
991
|
-
blendIndices.push(idx + liquidVertexCount)
|
|
992
|
-
}
|
|
990
|
+
appendGeometryIndices(blendIndices, liquidIndices, 0)
|
|
991
|
+
appendGeometryIndices(blendIndices, blockBlendIndices, liquidVertexCount)
|
|
993
992
|
}
|
|
994
993
|
|
|
995
994
|
const shaderCubes = buildShaderCubesFromWords(shaderWordBuffer)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { expect, test } from 'vitest'
|
|
3
|
+
import { appendGeometryIndices, createGeometryIndexArray } from '../bridge/geometryIndices'
|
|
4
|
+
|
|
5
|
+
function expectSameValues(actual: ArrayLike<number>, expected: ArrayLike<number>): void {
|
|
6
|
+
expect(actual.length).toBe(expected.length)
|
|
7
|
+
let firstMismatch = -1
|
|
8
|
+
for (let index = 0; index < expected.length; index++) {
|
|
9
|
+
if (actual[index] !== expected[index]) {
|
|
10
|
+
firstMismatch = index
|
|
11
|
+
break
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
expect(firstMismatch, 'First differing index; -1 means all values match').toBe(-1)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test('creates lossless index buffers without depending on argument count', () => {
|
|
18
|
+
const cases: Array<{ input: number[]; using32Array: boolean }> = [
|
|
19
|
+
{ input: [], using32Array: false },
|
|
20
|
+
{ input: [0, 65535, 7], using32Array: false },
|
|
21
|
+
{ input: [0, 65536, 7], using32Array: true }
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
for (const { input, using32Array } of cases) {
|
|
25
|
+
const inputBefore = input.slice()
|
|
26
|
+
const result = createGeometryIndexArray(input)
|
|
27
|
+
expect(result).toBeInstanceOf(using32Array ? Uint32Array : Uint16Array)
|
|
28
|
+
expect(Array.from(result)).toEqual(inputBefore)
|
|
29
|
+
expect(input).toEqual(inputBefore)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const source = new Array<number>(1_000_000).fill(65535)
|
|
33
|
+
source[0] = 0
|
|
34
|
+
source[500_000] = 123
|
|
35
|
+
const sourceBeforeSmall = source.slice()
|
|
36
|
+
const smallValues = createGeometryIndexArray(source)
|
|
37
|
+
expect(smallValues).toBeInstanceOf(Uint16Array)
|
|
38
|
+
expectSameValues(smallValues, sourceBeforeSmall)
|
|
39
|
+
expectSameValues(source, sourceBeforeSmall)
|
|
40
|
+
|
|
41
|
+
source[source.length - 1] = 65536
|
|
42
|
+
const sourceBeforeLarge = source.slice()
|
|
43
|
+
const largeValue = createGeometryIndexArray(source)
|
|
44
|
+
expect(largeValue).toBeInstanceOf(Uint32Array)
|
|
45
|
+
expectSameValues(largeValue, sourceBeforeLarge)
|
|
46
|
+
expectSameValues(source, sourceBeforeLarge)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('appends large liquid indices before rebased block indices', () => {
|
|
50
|
+
const liquidIndices = new Array<number>(1_000_000).fill(0)
|
|
51
|
+
liquidIndices[0] = 2
|
|
52
|
+
liquidIndices[liquidIndices.length - 1] = 1
|
|
53
|
+
const blockBlendIndices = [0, 2, 1]
|
|
54
|
+
const liquidVertexCount = 3
|
|
55
|
+
const blendIndices: number[] = []
|
|
56
|
+
const liquidIndicesBefore = liquidIndices.slice()
|
|
57
|
+
const blockBlendIndicesBefore = blockBlendIndices.slice()
|
|
58
|
+
|
|
59
|
+
appendGeometryIndices(blendIndices, liquidIndices, 0)
|
|
60
|
+
appendGeometryIndices(blendIndices, blockBlendIndices, liquidVertexCount)
|
|
61
|
+
|
|
62
|
+
expect(blendIndices.length).toBe(liquidIndicesBefore.length + blockBlendIndicesBefore.length)
|
|
63
|
+
expectSameValues(blendIndices.slice(0, liquidIndicesBefore.length), liquidIndicesBefore)
|
|
64
|
+
expect(blendIndices.slice(liquidIndicesBefore.length)).toEqual([3, 5, 4])
|
|
65
|
+
expect(blockBlendIndices).toEqual(blockBlendIndicesBefore)
|
|
66
|
+
expectSameValues(liquidIndices, liquidIndicesBefore)
|
|
67
|
+
|
|
68
|
+
const snapshot = blendIndices.slice()
|
|
69
|
+
appendGeometryIndices(blendIndices, [], liquidVertexCount)
|
|
70
|
+
expectSameValues(blendIndices, snapshot)
|
|
71
|
+
})
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Vec3 } from 'vec3'
|
|
3
3
|
import { convertChunkToWasm, getBlockMeta, type ChunkConversionResult } from '../bridge/convertChunk'
|
|
4
4
|
import { extractColumnHeightmap, splitColumnWasmOutputToSections } from '../bridge/render-from-wasm'
|
|
5
|
+
import { createGeometryIndexArray } from '../bridge/geometryIndices'
|
|
5
6
|
import { setBlockStatesData as setMesherData } from '../../mesher-shared/models'
|
|
6
7
|
import { defaultMesherConfig, type MesherGeometryOutput, SECTION_HEIGHT } from '../../mesher-shared/shared'
|
|
7
8
|
import { SHADER_CUBES_FORMAT_VERSION } from '../../mesher-shared/shaderCubeFormat'
|
|
@@ -1493,8 +1494,8 @@ function processColumnTick() {
|
|
|
1493
1494
|
const hasLegacyMesh = hasOpaqueMesh || hasBlendMesh
|
|
1494
1495
|
const hasShaderCubes = (exported?.shaderCubes?.count ?? 0) > 0
|
|
1495
1496
|
if (exported && (hasLegacyMesh || hasShaderCubes)) {
|
|
1496
|
-
const
|
|
1497
|
-
const using32Array =
|
|
1497
|
+
const indices = createGeometryIndexArray(exported.geometry.indices)
|
|
1498
|
+
const using32Array = indices instanceof Uint32Array
|
|
1498
1499
|
geometry = {
|
|
1499
1500
|
sectionYNumber: (sy - (config?.worldMinY || 0)) >> 4,
|
|
1500
1501
|
chunkKey: worldColumnKey(sx, sz),
|
|
@@ -1513,7 +1514,7 @@ function processColumnTick() {
|
|
|
1513
1514
|
skyLights: new Float32Array(exported.geometry.skyLights),
|
|
1514
1515
|
blockLights: new Float32Array(exported.geometry.blockLights),
|
|
1515
1516
|
uvs: new Float32Array(exported.geometry.uvs),
|
|
1516
|
-
indices
|
|
1517
|
+
indices,
|
|
1517
1518
|
indicesCount: exported.geometry.indices.length,
|
|
1518
1519
|
using32Array,
|
|
1519
1520
|
tiles: {},
|
|
@@ -1537,7 +1538,6 @@ function processColumnTick() {
|
|
|
1537
1538
|
}
|
|
1538
1539
|
}
|
|
1539
1540
|
if (exported.blendGeometry && hasBlendMesh) {
|
|
1540
|
-
const blendMax = Math.max(...exported.blendGeometry.indices)
|
|
1541
1541
|
geometry.blend = {
|
|
1542
1542
|
positions: new Float32Array(exported.blendGeometry.positions),
|
|
1543
1543
|
normals: new Float32Array(exported.blendGeometry.normals),
|
|
@@ -1545,7 +1545,7 @@ function processColumnTick() {
|
|
|
1545
1545
|
skyLights: new Float32Array(exported.blendGeometry.skyLights),
|
|
1546
1546
|
blockLights: new Float32Array(exported.blendGeometry.blockLights),
|
|
1547
1547
|
uvs: new Float32Array(exported.blendGeometry.uvs),
|
|
1548
|
-
indices:
|
|
1548
|
+
indices: createGeometryIndexArray(exported.blendGeometry.indices)
|
|
1549
1549
|
}
|
|
1550
1550
|
}
|
|
1551
1551
|
transferable = [
|