minecraft-renderer 0.1.0
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/README.md +297 -0
- package/dist/index.html +83 -0
- package/dist/static/image/arrow.6f27b59f.png +0 -0
- package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
- package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
- package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
- package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
- package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
- package/dist/static/js/365.f05233ab.js +8462 -0
- package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
- package/dist/static/js/async/738.efa27644.js +1 -0
- package/dist/static/js/index.092ec5be.js +56 -0
- package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
- package/dist/static/js/lib-react.5c9129e0.js +2 -0
- package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
- package/package.json +104 -0
- package/src/assets/destroy_stage_0.png +0 -0
- package/src/assets/destroy_stage_1.png +0 -0
- package/src/assets/destroy_stage_2.png +0 -0
- package/src/assets/destroy_stage_3.png +0 -0
- package/src/assets/destroy_stage_4.png +0 -0
- package/src/assets/destroy_stage_5.png +0 -0
- package/src/assets/destroy_stage_6.png +0 -0
- package/src/assets/destroy_stage_7.png +0 -0
- package/src/assets/destroy_stage_8.png +0 -0
- package/src/assets/destroy_stage_9.png +0 -0
- package/src/examples/README.md +146 -0
- package/src/examples/appViewerExample.ts +205 -0
- package/src/examples/initialMenuStart.ts +161 -0
- package/src/graphicsBackend/appViewer.ts +297 -0
- package/src/graphicsBackend/config.ts +119 -0
- package/src/graphicsBackend/index.ts +10 -0
- package/src/graphicsBackend/playerState.ts +61 -0
- package/src/graphicsBackend/types.ts +143 -0
- package/src/index.ts +97 -0
- package/src/lib/DebugGui.ts +190 -0
- package/src/lib/animationController.ts +85 -0
- package/src/lib/buildSharedConfig.mjs +1 -0
- package/src/lib/cameraBobbing.ts +94 -0
- package/src/lib/canvas2DOverlay.example.ts +361 -0
- package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
- package/src/lib/canvas2DOverlay.ts +381 -0
- package/src/lib/cleanupDecorator.ts +29 -0
- package/src/lib/createPlayerObject.ts +55 -0
- package/src/lib/frameTimingCollector.ts +164 -0
- package/src/lib/guiRenderer.ts +283 -0
- package/src/lib/items.ts +140 -0
- package/src/lib/mesherlogReader.ts +131 -0
- package/src/lib/moreBlockDataGenerated.json +714 -0
- package/src/lib/preflatMap.json +1741 -0
- package/src/lib/simpleUtils.ts +40 -0
- package/src/lib/smoothSwitcher.ts +168 -0
- package/src/lib/spiral.ts +29 -0
- package/src/lib/ui/newStats.ts +120 -0
- package/src/lib/utils/proxy.ts +23 -0
- package/src/lib/utils/skins.ts +63 -0
- package/src/lib/utils.ts +76 -0
- package/src/lib/workerProxy.ts +342 -0
- package/src/lib/worldrendererCommon.ts +1088 -0
- package/src/mesher/mesher.ts +253 -0
- package/src/mesher/models.ts +769 -0
- package/src/mesher/modelsGeometryCommon.ts +142 -0
- package/src/mesher/shared.ts +80 -0
- package/src/mesher/standaloneRenderer.ts +270 -0
- package/src/mesher/test/a.ts +3 -0
- package/src/mesher/test/mesherTester.ts +76 -0
- package/src/mesher/test/playground.ts +19 -0
- package/src/mesher/test/test-perf.ts +74 -0
- package/src/mesher/test/tests.test.ts +56 -0
- package/src/mesher/world.ts +294 -0
- package/src/mesher/worldConstants.ts +1 -0
- package/src/modules/index.ts +11 -0
- package/src/modules/starfield.ts +313 -0
- package/src/modules/types.ts +110 -0
- package/src/playerState/playerState.ts +78 -0
- package/src/playerState/types.ts +36 -0
- package/src/playground/allEntitiesDebug.ts +170 -0
- package/src/playground/baseScene.ts +587 -0
- package/src/playground/mobileControls.tsx +268 -0
- package/src/playground/playground.html +83 -0
- package/src/playground/playground.ts +11 -0
- package/src/playground/playgroundUi.tsx +140 -0
- package/src/playground/reactUtils.ts +71 -0
- package/src/playground/scenes/allEntities.ts +13 -0
- package/src/playground/scenes/entities.ts +37 -0
- package/src/playground/scenes/floorRandom.ts +33 -0
- package/src/playground/scenes/frequentUpdates.ts +148 -0
- package/src/playground/scenes/geometryExport.ts +142 -0
- package/src/playground/scenes/index.ts +12 -0
- package/src/playground/scenes/lightingStarfield.ts +40 -0
- package/src/playground/scenes/main.ts +313 -0
- package/src/playground/scenes/railsCobweb.ts +14 -0
- package/src/playground/scenes/rotationIssue.ts +7 -0
- package/src/playground/scenes/slabsOptimization.ts +16 -0
- package/src/playground/scenes/transparencyIssue.ts +11 -0
- package/src/playground/shared.ts +79 -0
- package/src/resourcesManager/index.ts +5 -0
- package/src/resourcesManager/resourcesManager.ts +314 -0
- package/src/shims/minecraftData.ts +41 -0
- package/src/sign-renderer/index.html +21 -0
- package/src/sign-renderer/index.ts +216 -0
- package/src/sign-renderer/noop.js +1 -0
- package/src/sign-renderer/playground.ts +38 -0
- package/src/sign-renderer/tests.test.ts +69 -0
- package/src/sign-renderer/vite.config.ts +10 -0
- package/src/three/appShared.ts +75 -0
- package/src/three/bannerRenderer.ts +275 -0
- package/src/three/cameraShake.ts +120 -0
- package/src/three/cinimaticScript.ts +350 -0
- package/src/three/documentRenderer.ts +491 -0
- package/src/three/entities.ts +1580 -0
- package/src/three/entity/EntityMesh.ts +707 -0
- package/src/three/entity/animations.js +171 -0
- package/src/three/entity/armorModels.json +204 -0
- package/src/three/entity/armorModels.ts +36 -0
- package/src/three/entity/entities.json +6230 -0
- package/src/three/entity/exportedModels.js +38 -0
- package/src/three/entity/externalTextures.json +1 -0
- package/src/three/entity/models/allay.obj +325 -0
- package/src/three/entity/models/arrow.obj +60 -0
- package/src/three/entity/models/axolotl.obj +509 -0
- package/src/three/entity/models/blaze.obj +601 -0
- package/src/three/entity/models/boat.obj +417 -0
- package/src/three/entity/models/camel.obj +1061 -0
- package/src/three/entity/models/cat.obj +509 -0
- package/src/three/entity/models/chicken.obj +371 -0
- package/src/three/entity/models/cod.obj +371 -0
- package/src/three/entity/models/creeper.obj +279 -0
- package/src/three/entity/models/dolphin.obj +371 -0
- package/src/three/entity/models/ender_dragon.obj +2993 -0
- package/src/three/entity/models/enderman.obj +325 -0
- package/src/three/entity/models/endermite.obj +187 -0
- package/src/three/entity/models/fox.obj +463 -0
- package/src/three/entity/models/frog.obj +739 -0
- package/src/three/entity/models/ghast.obj +463 -0
- package/src/three/entity/models/goat.obj +601 -0
- package/src/three/entity/models/guardian.obj +1015 -0
- package/src/three/entity/models/horse.obj +1061 -0
- package/src/three/entity/models/llama.obj +509 -0
- package/src/three/entity/models/minecart.obj +233 -0
- package/src/three/entity/models/parrot.obj +509 -0
- package/src/three/entity/models/piglin.obj +739 -0
- package/src/three/entity/models/pillager.obj +371 -0
- package/src/three/entity/models/rabbit.obj +555 -0
- package/src/three/entity/models/sheep.obj +555 -0
- package/src/three/entity/models/shulker.obj +141 -0
- package/src/three/entity/models/sniffer.obj +693 -0
- package/src/three/entity/models/spider.obj +509 -0
- package/src/three/entity/models/tadpole.obj +95 -0
- package/src/three/entity/models/turtle.obj +371 -0
- package/src/three/entity/models/vex.obj +325 -0
- package/src/three/entity/models/villager.obj +509 -0
- package/src/three/entity/models/warden.obj +463 -0
- package/src/three/entity/models/witch.obj +647 -0
- package/src/three/entity/models/wolf.obj +509 -0
- package/src/three/entity/models/zombie_villager.obj +463 -0
- package/src/three/entity/objModels.js +1 -0
- package/src/three/fireworks.ts +661 -0
- package/src/three/fireworksRenderer.ts +434 -0
- package/src/three/globals.d.ts +7 -0
- package/src/three/graphicsBackend.ts +274 -0
- package/src/three/graphicsBackendOffThread.ts +107 -0
- package/src/three/hand.ts +89 -0
- package/src/three/holdingBlock.ts +926 -0
- package/src/three/index.ts +20 -0
- package/src/three/itemMesh.ts +427 -0
- package/src/three/modules.d.ts +14 -0
- package/src/three/panorama.ts +308 -0
- package/src/three/panoramaShared.ts +1 -0
- package/src/three/renderSlot.ts +82 -0
- package/src/three/skyboxRenderer.ts +406 -0
- package/src/three/starField.ts +13 -0
- package/src/three/threeJsMedia.ts +731 -0
- package/src/three/threeJsMethods.ts +15 -0
- package/src/three/threeJsParticles.ts +160 -0
- package/src/three/threeJsSound.ts +95 -0
- package/src/three/threeJsUtils.ts +90 -0
- package/src/three/waypointSprite.ts +435 -0
- package/src/three/waypoints.ts +163 -0
- package/src/three/world/cursorBlock.ts +172 -0
- package/src/three/world/vr.ts +257 -0
- package/src/three/worldGeometryExport.ts +259 -0
- package/src/three/worldGeometryHandler.ts +279 -0
- package/src/three/worldRendererThree.ts +1381 -0
- package/src/worldView/index.ts +6 -0
- package/src/worldView/types.ts +66 -0
- package/src/worldView/worldView.ts +424 -0
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
import { Vec3 } from 'vec3'
|
|
2
|
+
import worldBlockProvider, { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider'
|
|
3
|
+
import legacyJson from '../lib/preflatMap.json'
|
|
4
|
+
import { BlockType } from '../../../playground/shared'
|
|
5
|
+
import { World, BlockModelPartsResolved, WorldBlock as Block, WorldBlock, worldColumnKey } from './world'
|
|
6
|
+
import { BlockElement, buildRotationMatrix, elemFaces, matmul3, matmulmat3, vecadd3, vecsub3 } from './modelsGeometryCommon'
|
|
7
|
+
import { INVISIBLE_BLOCKS } from './worldConstants'
|
|
8
|
+
import { MesherGeometryOutput, HighestBlockInfo } from './shared'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
let blockProvider: WorldBlockProvider
|
|
12
|
+
|
|
13
|
+
const tints: any = {}
|
|
14
|
+
let needTiles = false
|
|
15
|
+
|
|
16
|
+
let tintsData
|
|
17
|
+
try {
|
|
18
|
+
tintsData = require('esbuild-data').tints
|
|
19
|
+
} catch (err) {
|
|
20
|
+
tintsData = require('minecraft-data/minecraft-data/data/pc/1.16.2/tints.json')
|
|
21
|
+
}
|
|
22
|
+
for (const key of Object.keys(tintsData)) {
|
|
23
|
+
tints[key] = prepareTints(tintsData[key])
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type Tiles = {
|
|
27
|
+
[blockPos: string]: BlockType
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function prepareTints (tints) {
|
|
31
|
+
const map = new Map()
|
|
32
|
+
const defaultValue = tintToGl(tints.default)
|
|
33
|
+
for (let { keys, color } of tints.data) {
|
|
34
|
+
color = tintToGl(color)
|
|
35
|
+
for (const key of keys) {
|
|
36
|
+
map.set(`${key}`, color)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return new Proxy(map, {
|
|
40
|
+
get (target, key) {
|
|
41
|
+
return target.has(key) ? target.get(key) : defaultValue
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks)
|
|
47
|
+
export function preflatBlockCalculation (block: Block, world: World, position: Vec3) {
|
|
48
|
+
const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0]
|
|
49
|
+
if (!type) return
|
|
50
|
+
switch (type) {
|
|
51
|
+
case 'directional': {
|
|
52
|
+
const isSolidConnection = !block.name.includes('redstone') && !block.name.includes('tripwire')
|
|
53
|
+
const neighbors = [
|
|
54
|
+
world.getBlock(position.offset(0, 0, 1)),
|
|
55
|
+
world.getBlock(position.offset(0, 0, -1)),
|
|
56
|
+
world.getBlock(position.offset(1, 0, 0)),
|
|
57
|
+
world.getBlock(position.offset(-1, 0, 0))
|
|
58
|
+
]
|
|
59
|
+
// set needed props to true: east:'false',north:'false',south:'false',west:'false'
|
|
60
|
+
const props = {}
|
|
61
|
+
let changed = false
|
|
62
|
+
for (const [i, neighbor] of neighbors.entries()) {
|
|
63
|
+
const isConnectedToSolid = isSolidConnection ? (neighbor && !neighbor.transparent) : false
|
|
64
|
+
if (isConnectedToSolid || neighbor?.name === block.name) {
|
|
65
|
+
props[['south', 'north', 'east', 'west'][i]] = 'true'
|
|
66
|
+
changed = true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return changed ? props : undefined
|
|
70
|
+
}
|
|
71
|
+
// case 'gate_in_wall': {}
|
|
72
|
+
case 'block_snowy': {
|
|
73
|
+
const aboveIsSnow = world.getBlock(position.offset(0, 1, 0))?.name === 'snow'
|
|
74
|
+
if (aboveIsSnow) {
|
|
75
|
+
return {
|
|
76
|
+
snowy: `${aboveIsSnow}`
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
case 'door': {
|
|
83
|
+
// upper half matches lower in
|
|
84
|
+
const { half } = block.getProperties()
|
|
85
|
+
if (half === 'upper') {
|
|
86
|
+
// copy other properties
|
|
87
|
+
const lower = world.getBlock(position.offset(0, -1, 0))
|
|
88
|
+
if (lower?.name === block.name) {
|
|
89
|
+
return {
|
|
90
|
+
...lower.getProperties(),
|
|
91
|
+
half: 'upper'
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function tintToGl (tint) {
|
|
100
|
+
const r = (tint >> 16) & 0xff
|
|
101
|
+
const g = (tint >> 8) & 0xff
|
|
102
|
+
const b = tint & 0xff
|
|
103
|
+
return [r / 255, g / 255, b / 255]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getLiquidRenderHeight (world: World, block: WorldBlock | null, type: number, pos: Vec3, isWater: boolean, isRealWater: boolean) {
|
|
107
|
+
if ((isWater && !isRealWater) || (block && isBlockWaterlogged(block))) return 8 / 9
|
|
108
|
+
if (!block || block.type !== type) return 1 / 9
|
|
109
|
+
if (block.metadata === 0) { // source block
|
|
110
|
+
const blockAbove = world.getBlock(pos.offset(0, 1, 0))
|
|
111
|
+
if (blockAbove && blockAbove.type === type) return 1
|
|
112
|
+
return 8 / 9
|
|
113
|
+
}
|
|
114
|
+
return ((block.metadata >= 8 ? 8 : 7 - block.metadata) + 1) / 9
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
const isCube = (block: Block) => {
|
|
119
|
+
if (!block || block.transparent) return false
|
|
120
|
+
if (block.isCube) return true
|
|
121
|
+
if (!block.models?.length || block.models.length !== 1) return false
|
|
122
|
+
// all variants
|
|
123
|
+
return block.models[0].every(v => v.elements.every(e => {
|
|
124
|
+
return e.from[0] === 0 && e.from[1] === 0 && e.from[2] === 0 && e.to[0] === 16 && e.to[1] === 16 && e.to[2] === 16
|
|
125
|
+
}))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const getVec = (v: Vec3, dir: Vec3) => {
|
|
129
|
+
for (const coord of ['x', 'y', 'z']) {
|
|
130
|
+
if (Math.abs(dir[coord]) > 0) v[coord] = 0
|
|
131
|
+
}
|
|
132
|
+
return v.plus(dir)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, type: number, biome: string, water: boolean, attr: MesherGeometryOutput, isRealWater: boolean) {
|
|
136
|
+
const heights: number[] = []
|
|
137
|
+
for (let z = -1; z <= 1; z++) {
|
|
138
|
+
for (let x = -1; x <= 1; x++) {
|
|
139
|
+
const pos = cursor.offset(x, 0, z)
|
|
140
|
+
heights.push(getLiquidRenderHeight(world, world.getBlock(pos), type, pos, water, isRealWater))
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const cornerHeights = [
|
|
144
|
+
Math.max(Math.max(heights[0], heights[1]), Math.max(heights[3], heights[4])),
|
|
145
|
+
Math.max(Math.max(heights[1], heights[2]), Math.max(heights[4], heights[5])),
|
|
146
|
+
Math.max(Math.max(heights[3], heights[4]), Math.max(heights[6], heights[7])),
|
|
147
|
+
Math.max(Math.max(heights[4], heights[5]), Math.max(heights[7], heights[8]))
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
// eslint-disable-next-line guard-for-in
|
|
151
|
+
for (const face in elemFaces) {
|
|
152
|
+
const { dir, corners, mask1, mask2 } = elemFaces[face]
|
|
153
|
+
const isUp = dir[1] === 1
|
|
154
|
+
|
|
155
|
+
const neighborPos = cursor.offset(...dir as [number, number, number])
|
|
156
|
+
const neighbor = world.getBlock(neighborPos)
|
|
157
|
+
if (!neighbor) continue
|
|
158
|
+
if (neighbor.type === type || (water && (neighbor.name === 'water' || isBlockWaterlogged(neighbor)))) continue
|
|
159
|
+
if (isCube(neighbor) && !isUp) continue
|
|
160
|
+
|
|
161
|
+
let tint = [1, 1, 1]
|
|
162
|
+
if (water) {
|
|
163
|
+
let m = 1 // Fake lighting to improve lisibility
|
|
164
|
+
if (Math.abs(dir[0]) > 0) m = 0.6
|
|
165
|
+
else if (Math.abs(dir[2]) > 0) m = 0.8
|
|
166
|
+
tint = tints.water[biome]
|
|
167
|
+
tint = [tint[0] * m, tint[1] * m, tint[2] * m]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (needTiles) {
|
|
171
|
+
const tiles = attr.tiles as Tiles
|
|
172
|
+
tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= {
|
|
173
|
+
block: 'water',
|
|
174
|
+
faces: [],
|
|
175
|
+
}
|
|
176
|
+
tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({
|
|
177
|
+
face,
|
|
178
|
+
neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`,
|
|
179
|
+
side: 0, // todo
|
|
180
|
+
textureIndex: 0,
|
|
181
|
+
// texture: eFace.texture.name,
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const { u } = texture
|
|
186
|
+
const { v } = texture
|
|
187
|
+
const { su } = texture
|
|
188
|
+
const { sv } = texture
|
|
189
|
+
|
|
190
|
+
// Get base light value for the face
|
|
191
|
+
const baseLight = world.getLight(neighborPos, undefined, undefined, water ? 'water' : 'lava') / 15
|
|
192
|
+
|
|
193
|
+
for (const pos of corners) {
|
|
194
|
+
const height = cornerHeights[pos[2] * 2 + pos[0]]
|
|
195
|
+
const OFFSET = 0.0001
|
|
196
|
+
attr.t_positions!.push(
|
|
197
|
+
(pos[0] ? 1 - OFFSET : OFFSET) + (cursor.x & 15) - 8,
|
|
198
|
+
(pos[1] ? height - OFFSET : OFFSET) + (cursor.y & 15) - 8,
|
|
199
|
+
(pos[2] ? 1 - OFFSET : OFFSET) + (cursor.z & 15) - 8
|
|
200
|
+
)
|
|
201
|
+
attr.t_normals!.push(...dir)
|
|
202
|
+
attr.t_uvs!.push(pos[3] * su + u, pos[4] * sv * (pos[1] ? 1 : height) + v)
|
|
203
|
+
|
|
204
|
+
let cornerLightResult = baseLight
|
|
205
|
+
if (world.config.smoothLighting) {
|
|
206
|
+
const dx = pos[0] * 2 - 1
|
|
207
|
+
const dy = pos[1] * 2 - 1
|
|
208
|
+
const dz = pos[2] * 2 - 1
|
|
209
|
+
const cornerDir: [number, number, number] = [dx, dy, dz]
|
|
210
|
+
const side1Dir: [number, number, number] = [dx * mask1[0], dy * mask1[1], dz * mask1[2]]
|
|
211
|
+
const side2Dir: [number, number, number] = [dx * mask2[0], dy * mask2[1], dz * mask2[2]]
|
|
212
|
+
|
|
213
|
+
const dirVec = new Vec3(...dir as [number, number, number])
|
|
214
|
+
|
|
215
|
+
const side1LightDir = getVec(new Vec3(...side1Dir), dirVec)
|
|
216
|
+
const side1Light = world.getLight(cursor.plus(side1LightDir)) / 15
|
|
217
|
+
const side2DirLight = getVec(new Vec3(...side2Dir), dirVec)
|
|
218
|
+
const side2Light = world.getLight(cursor.plus(side2DirLight)) / 15
|
|
219
|
+
const cornerLightDir = getVec(new Vec3(...cornerDir), dirVec)
|
|
220
|
+
const cornerLight = world.getLight(cursor.plus(cornerLightDir)) / 15
|
|
221
|
+
// interpolate
|
|
222
|
+
const lights = [side1Light, side2Light, cornerLight, baseLight]
|
|
223
|
+
cornerLightResult = lights.reduce((acc, cur) => acc + cur, 0) / lights.length
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Apply light value to tint
|
|
227
|
+
attr.t_colors!.push(tint[0] * cornerLightResult, tint[1] * cornerLightResult, tint[2] * cornerLightResult)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const identicalCull = (currentElement: BlockElement, neighbor: Block, direction: Vec3) => {
|
|
233
|
+
const dirStr = `${direction.x},${direction.y},${direction.z}`
|
|
234
|
+
const lookForOppositeSide = {
|
|
235
|
+
'0,1,0': 'down',
|
|
236
|
+
'0,-1,0': 'up',
|
|
237
|
+
'1,0,0': 'east',
|
|
238
|
+
'-1,0,0': 'west',
|
|
239
|
+
'0,0,1': 'south',
|
|
240
|
+
'0,0,-1': 'north',
|
|
241
|
+
}[dirStr]!
|
|
242
|
+
const elemCompareForm = {
|
|
243
|
+
'0,1,0': (e: BlockElement) => `${e.from[0]},${e.from[2]}:${e.to[0]},${e.to[2]}`,
|
|
244
|
+
'0,-1,0': (e: BlockElement) => `${e.to[0]},${e.to[2]}:${e.from[0]},${e.from[2]}`,
|
|
245
|
+
'1,0,0': (e: BlockElement) => `${e.from[2]},${e.from[1]}:${e.to[2]},${e.to[1]}`,
|
|
246
|
+
'-1,0,0': (e: BlockElement) => `${e.to[2]},${e.to[1]}:${e.from[2]},${e.from[1]}`,
|
|
247
|
+
'0,0,1': (e: BlockElement) => `${e.from[1]},${e.from[2]}:${e.to[1]},${e.to[2]}`,
|
|
248
|
+
'0,0,-1': (e: BlockElement) => `${e.to[1]},${e.to[2]}:${e.from[1]},${e.from[2]}`,
|
|
249
|
+
}[dirStr]!
|
|
250
|
+
const elementEdgeValidator = {
|
|
251
|
+
'0,1,0': (e: BlockElement) => currentElement.from[1] === 0 && e.to[2] === 16,
|
|
252
|
+
'0,-1,0': (e: BlockElement) => currentElement.from[1] === 0 && e.to[2] === 16,
|
|
253
|
+
'1,0,0': (e: BlockElement) => currentElement.from[0] === 0 && e.to[1] === 16,
|
|
254
|
+
'-1,0,0': (e: BlockElement) => currentElement.from[0] === 0 && e.to[1] === 16,
|
|
255
|
+
'0,0,1': (e: BlockElement) => currentElement.from[2] === 0 && e.to[0] === 16,
|
|
256
|
+
'0,0,-1': (e: BlockElement) => currentElement.from[2] === 0 && e.to[0] === 16,
|
|
257
|
+
}[dirStr]!
|
|
258
|
+
const useVar = 0
|
|
259
|
+
const models = neighbor.models?.map(m => m[useVar] ?? m[0]) ?? []
|
|
260
|
+
// TODO we should support it! rewrite with optimizing general pipeline
|
|
261
|
+
if (models.some(m => m.x || m.y || m.z)) return
|
|
262
|
+
return models.every(model => {
|
|
263
|
+
return (model.elements ?? []).every(element => {
|
|
264
|
+
// todo check alfa on texture
|
|
265
|
+
return !!(element.faces[lookForOppositeSide]?.cullface && elemCompareForm(currentElement) === elemCompareForm(element) && elementEdgeValidator(element))
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let needSectionRecomputeOnChange = false
|
|
271
|
+
|
|
272
|
+
function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO: boolean, attr: MesherGeometryOutput, globalMatrix: any, globalShift: any, block: Block, biome: string) {
|
|
273
|
+
const position = cursor
|
|
274
|
+
// const key = `${position.x},${position.y},${position.z}`
|
|
275
|
+
// if (!globalThis.allowedBlocks.includes(key)) return
|
|
276
|
+
const cullIfIdentical = block.name.includes('glass') || block.name.includes('ice')
|
|
277
|
+
|
|
278
|
+
// eslint-disable-next-line guard-for-in
|
|
279
|
+
for (const face in element.faces) {
|
|
280
|
+
const eFace = element.faces[face]
|
|
281
|
+
const { corners, mask1, mask2, side } = elemFaces[face]
|
|
282
|
+
const dir = matmul3(globalMatrix, elemFaces[face].dir)
|
|
283
|
+
|
|
284
|
+
if (eFace.cullface) {
|
|
285
|
+
const neighbor = world.getBlock(cursor.plus(new Vec3(...dir)), blockProvider, {})
|
|
286
|
+
if (neighbor) {
|
|
287
|
+
if (cullIfIdentical && neighbor.stateId === block.stateId) continue
|
|
288
|
+
if (!neighbor.transparent && (isCube(neighbor) || identicalCull(element, neighbor, new Vec3(...dir)))) continue
|
|
289
|
+
} else {
|
|
290
|
+
needSectionRecomputeOnChange = true
|
|
291
|
+
// continue
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const minx = element.from[0]
|
|
296
|
+
const miny = element.from[1]
|
|
297
|
+
const minz = element.from[2]
|
|
298
|
+
const maxx = element.to[0]
|
|
299
|
+
const maxy = element.to[1]
|
|
300
|
+
const maxz = element.to[2]
|
|
301
|
+
|
|
302
|
+
const texture = eFace.texture as any
|
|
303
|
+
const { u } = texture
|
|
304
|
+
const { v } = texture
|
|
305
|
+
const { su } = texture
|
|
306
|
+
const { sv } = texture
|
|
307
|
+
|
|
308
|
+
const ndx = Math.floor(attr.positions.length / 3)
|
|
309
|
+
|
|
310
|
+
let tint = [1, 1, 1]
|
|
311
|
+
if (eFace.tintindex !== undefined) {
|
|
312
|
+
if (eFace.tintindex === 0) {
|
|
313
|
+
if (block.name === 'redstone_wire') {
|
|
314
|
+
tint = tints.redstone[`${block.getProperties().power}`]
|
|
315
|
+
} else if (block.name === 'birch_leaves' ||
|
|
316
|
+
block.name === 'spruce_leaves' ||
|
|
317
|
+
block.name === 'lily_pad') {
|
|
318
|
+
tint = tints.constant[block.name]
|
|
319
|
+
} else if (block.name.includes('leaves') || block.name === 'vine') {
|
|
320
|
+
tint = tints.foliage[biome]
|
|
321
|
+
} else {
|
|
322
|
+
tint = tints.grass[biome]
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// UV rotation
|
|
328
|
+
let r = eFace.rotation || 0
|
|
329
|
+
if (face === 'down') {
|
|
330
|
+
r += 180
|
|
331
|
+
}
|
|
332
|
+
const uvcs = Math.cos(r * Math.PI / 180)
|
|
333
|
+
const uvsn = -Math.sin(r * Math.PI / 180)
|
|
334
|
+
|
|
335
|
+
let localMatrix = null as any
|
|
336
|
+
let localShift = null as any
|
|
337
|
+
|
|
338
|
+
if (element.rotation && !needTiles) {
|
|
339
|
+
// Rescale support for block model rotations
|
|
340
|
+
localMatrix = buildRotationMatrix(
|
|
341
|
+
element.rotation.axis,
|
|
342
|
+
element.rotation.angle
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
localShift = vecsub3(
|
|
346
|
+
element.rotation.origin,
|
|
347
|
+
matmul3(
|
|
348
|
+
localMatrix,
|
|
349
|
+
element.rotation.origin
|
|
350
|
+
)
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
// Apply rescale if specified
|
|
354
|
+
if (element.rotation.rescale) {
|
|
355
|
+
const FIT_TO_BLOCK_SCALE_MULTIPLIER = 2 - Math.sqrt(2)
|
|
356
|
+
const angleRad = element.rotation.angle * Math.PI / 180
|
|
357
|
+
const scale = Math.abs(Math.sin(angleRad)) * FIT_TO_BLOCK_SCALE_MULTIPLIER
|
|
358
|
+
|
|
359
|
+
// Get axis vector components (1 for the rotation axis, 0 for others)
|
|
360
|
+
const axisX = element.rotation.axis === 'x' ? 1 : 0
|
|
361
|
+
const axisY = element.rotation.axis === 'y' ? 1 : 0
|
|
362
|
+
const axisZ = element.rotation.axis === 'z' ? 1 : 0
|
|
363
|
+
|
|
364
|
+
// Create scale matrix: scale = (1 - axisComponent) * scaleFactor + 1
|
|
365
|
+
const scaleMatrix = [
|
|
366
|
+
[(1 - axisX) * scale + 1, 0, 0],
|
|
367
|
+
[0, (1 - axisY) * scale + 1, 0],
|
|
368
|
+
[0, 0, (1 - axisZ) * scale + 1]
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
// Apply scaling to the transformation matrix
|
|
372
|
+
localMatrix = matmulmat3(localMatrix, scaleMatrix)
|
|
373
|
+
|
|
374
|
+
// Recalculate shift with the new matrix
|
|
375
|
+
localShift = vecsub3(
|
|
376
|
+
element.rotation.origin,
|
|
377
|
+
matmul3(
|
|
378
|
+
localMatrix,
|
|
379
|
+
element.rotation.origin
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const aos: number[] = []
|
|
386
|
+
const neighborPos = position.plus(new Vec3(...dir))
|
|
387
|
+
// 10%
|
|
388
|
+
const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15
|
|
389
|
+
for (const pos of corners) {
|
|
390
|
+
let vertex = [
|
|
391
|
+
(pos[0] ? maxx : minx),
|
|
392
|
+
(pos[1] ? maxy : miny),
|
|
393
|
+
(pos[2] ? maxz : minz)
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
if (!needTiles) { // 10%
|
|
397
|
+
vertex = vecadd3(matmul3(localMatrix, vertex), localShift)
|
|
398
|
+
vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift)
|
|
399
|
+
vertex = vertex.map(v => v / 16)
|
|
400
|
+
|
|
401
|
+
attr.positions.push(
|
|
402
|
+
vertex[0] + (cursor.x & 15) - 8,
|
|
403
|
+
vertex[1] + (cursor.y & 15) - 8,
|
|
404
|
+
vertex[2] + (cursor.z & 15) - 8
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
attr.normals.push(...dir)
|
|
408
|
+
|
|
409
|
+
const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5
|
|
410
|
+
const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5
|
|
411
|
+
attr.uvs.push(baseu * su + u, basev * sv + v)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
let light = 1
|
|
415
|
+
const { smoothLighting } = world.config
|
|
416
|
+
// const smoothLighting = true
|
|
417
|
+
if (doAO) {
|
|
418
|
+
const dx = pos[0] * 2 - 1
|
|
419
|
+
const dy = pos[1] * 2 - 1
|
|
420
|
+
const dz = pos[2] * 2 - 1
|
|
421
|
+
const cornerDir = matmul3(globalMatrix, [dx, dy, dz])
|
|
422
|
+
const side1Dir = matmul3(globalMatrix, [dx * mask1[0], dy * mask1[1], dz * mask1[2]])
|
|
423
|
+
const side2Dir = matmul3(globalMatrix, [dx * mask2[0], dy * mask2[1], dz * mask2[2]])
|
|
424
|
+
const side1 = world.getBlock(cursor.offset(...side1Dir))
|
|
425
|
+
const side2 = world.getBlock(cursor.offset(...side2Dir))
|
|
426
|
+
const corner = world.getBlock(cursor.offset(...cornerDir))
|
|
427
|
+
|
|
428
|
+
let cornerLightResult = baseLight * 15
|
|
429
|
+
|
|
430
|
+
if (smoothLighting) {
|
|
431
|
+
const dirVec = new Vec3(...dir)
|
|
432
|
+
const getVec = (v: Vec3) => {
|
|
433
|
+
for (const coord of ['x', 'y', 'z']) {
|
|
434
|
+
if (Math.abs(dirVec[coord]) > 0) v[coord] = 0
|
|
435
|
+
}
|
|
436
|
+
return v.plus(dirVec)
|
|
437
|
+
}
|
|
438
|
+
const side1LightDir = getVec(new Vec3(...side1Dir))
|
|
439
|
+
const side1Light = world.getLight(cursor.plus(side1LightDir))
|
|
440
|
+
const side2DirLight = getVec(new Vec3(...side2Dir))
|
|
441
|
+
const side2Light = world.getLight(cursor.plus(side2DirLight))
|
|
442
|
+
const cornerLightDir = getVec(new Vec3(...cornerDir))
|
|
443
|
+
const cornerLight = world.getLight(cursor.plus(cornerLightDir))
|
|
444
|
+
// interpolate
|
|
445
|
+
const lights = [side1Light, side2Light, cornerLight, baseLight * 15]
|
|
446
|
+
cornerLightResult = lights.reduce((acc, cur) => acc + cur, 0) / lights.length
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const side1Block = world.shouldMakeAo(side1) ? 1 : 0
|
|
450
|
+
const side2Block = world.shouldMakeAo(side2) ? 1 : 0
|
|
451
|
+
const cornerBlock = world.shouldMakeAo(corner) ? 1 : 0
|
|
452
|
+
|
|
453
|
+
// TODO: correctly interpolate ao light based on pos (evaluate once for each corner of the block)
|
|
454
|
+
|
|
455
|
+
const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock))
|
|
456
|
+
// todo light should go upper on lower blocks
|
|
457
|
+
light = (ao + 1) / 4 * (cornerLightResult / 15)
|
|
458
|
+
aos.push(ao)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (!needTiles) {
|
|
462
|
+
attr.colors.push(tint[0] * light, tint[1] * light, tint[2] * light)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const lightWithColor = [baseLight * tint[0], baseLight * tint[1], baseLight * tint[2]] as [number, number, number]
|
|
467
|
+
|
|
468
|
+
if (needTiles) {
|
|
469
|
+
const tiles = attr.tiles as Tiles
|
|
470
|
+
tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= {
|
|
471
|
+
block: block.name,
|
|
472
|
+
faces: [],
|
|
473
|
+
}
|
|
474
|
+
const needsOnlyOneFace = false
|
|
475
|
+
const isTilesEmpty = tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.length < 1
|
|
476
|
+
if (isTilesEmpty || !needsOnlyOneFace) {
|
|
477
|
+
tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({
|
|
478
|
+
face,
|
|
479
|
+
side,
|
|
480
|
+
textureIndex: eFace.texture.tileIndex,
|
|
481
|
+
neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`,
|
|
482
|
+
light: baseLight,
|
|
483
|
+
tint: lightWithColor,
|
|
484
|
+
//@ts-expect-error debug prop
|
|
485
|
+
texture: eFace.texture.debugName || block.name,
|
|
486
|
+
} satisfies BlockType['faces'][number])
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (!needTiles) {
|
|
491
|
+
if (doAO && aos[0] + aos[3] >= aos[1] + aos[2]) {
|
|
492
|
+
attr.indices[attr.indicesCount++] = ndx
|
|
493
|
+
attr.indices[attr.indicesCount++] = ndx + 3
|
|
494
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
495
|
+
attr.indices[attr.indicesCount++] = ndx
|
|
496
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
497
|
+
attr.indices[attr.indicesCount++] = ndx + 3
|
|
498
|
+
} else {
|
|
499
|
+
attr.indices[attr.indicesCount++] = ndx
|
|
500
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
501
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
502
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
503
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
504
|
+
attr.indices[attr.indicesCount++] = ndx + 3
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const ALWAYS_WATERLOGGED = new Set([
|
|
511
|
+
'seagrass',
|
|
512
|
+
'tall_seagrass',
|
|
513
|
+
'kelp',
|
|
514
|
+
'kelp_plant',
|
|
515
|
+
'bubble_column'
|
|
516
|
+
])
|
|
517
|
+
const isBlockWaterlogged = (block: Block) => {
|
|
518
|
+
return block.getProperties().waterlogged === true || block.getProperties().waterlogged === 'true' || ALWAYS_WATERLOGGED.has(block.name)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
let unknownBlockModel: BlockModelPartsResolved
|
|
522
|
+
export function getSectionGeometry (sx: number, sy: number, sz: number, world: World) {
|
|
523
|
+
let delayedRender = [] as Array<() => void>
|
|
524
|
+
|
|
525
|
+
const attr: MesherGeometryOutput = {
|
|
526
|
+
sectionYNumber: (sy - world.config.worldMinY) >> 4,
|
|
527
|
+
chunkKey: worldColumnKey(sx, sz),
|
|
528
|
+
sectionStartY: sy,
|
|
529
|
+
sectionEndY: sy + 16,
|
|
530
|
+
sectionStartX: sx,
|
|
531
|
+
sectionEndX: sx + 16,
|
|
532
|
+
sectionStartZ: sz,
|
|
533
|
+
sectionEndZ: sz + 16,
|
|
534
|
+
sx: sx + 8,
|
|
535
|
+
sy: sy + 8,
|
|
536
|
+
sz: sz + 8,
|
|
537
|
+
positions: [],
|
|
538
|
+
normals: [],
|
|
539
|
+
colors: [],
|
|
540
|
+
uvs: [],
|
|
541
|
+
t_positions: [],
|
|
542
|
+
t_normals: [],
|
|
543
|
+
t_colors: [],
|
|
544
|
+
t_uvs: [],
|
|
545
|
+
indices: [],
|
|
546
|
+
indicesCount: 0, // Track current index position
|
|
547
|
+
using32Array: true,
|
|
548
|
+
tiles: {},
|
|
549
|
+
// todo this can be removed here
|
|
550
|
+
heads: {},
|
|
551
|
+
signs: {},
|
|
552
|
+
banners: {},
|
|
553
|
+
// isFull: true,
|
|
554
|
+
hadErrors: false,
|
|
555
|
+
blocksCount: 0
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const cursor = new Vec3(0, 0, 0)
|
|
559
|
+
for (cursor.y = sy; cursor.y < sy + 16; cursor.y++) {
|
|
560
|
+
for (cursor.z = sz; cursor.z < sz + 16; cursor.z++) {
|
|
561
|
+
for (cursor.x = sx; cursor.x < sx + 16; cursor.x++) {
|
|
562
|
+
let block = world.getBlock(cursor, blockProvider, attr)!
|
|
563
|
+
if (INVISIBLE_BLOCKS.has(block.name)) continue
|
|
564
|
+
if ((block.name.includes('_sign') || block.name === 'sign') && !world.config.disableBlockEntityTextures) {
|
|
565
|
+
const key = `${cursor.x},${cursor.y},${cursor.z}`
|
|
566
|
+
const props: any = block.getProperties()
|
|
567
|
+
const facingRotationMap = {
|
|
568
|
+
'north': 2,
|
|
569
|
+
'south': 0,
|
|
570
|
+
'west': 1,
|
|
571
|
+
'east': 3
|
|
572
|
+
}
|
|
573
|
+
const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('wall_hanging_sign')
|
|
574
|
+
const isHanging = block.name.endsWith('hanging_sign')
|
|
575
|
+
attr.signs[key] = {
|
|
576
|
+
isWall,
|
|
577
|
+
isHanging,
|
|
578
|
+
rotation: isWall ? facingRotationMap[props.facing] : +props.rotation
|
|
579
|
+
}
|
|
580
|
+
} else if (block.name === 'player_head' || block.name === 'player_wall_head') {
|
|
581
|
+
const key = `${cursor.x},${cursor.y},${cursor.z}`
|
|
582
|
+
const props: any = block.getProperties()
|
|
583
|
+
const facingRotationMap = {
|
|
584
|
+
'north': 0,
|
|
585
|
+
'south': 2,
|
|
586
|
+
'west': 3,
|
|
587
|
+
'east': 1
|
|
588
|
+
}
|
|
589
|
+
const isWall = block.name === 'player_wall_head'
|
|
590
|
+
attr.heads[key] = {
|
|
591
|
+
isWall,
|
|
592
|
+
rotation: isWall ? facingRotationMap[props.facing] : +props.rotation
|
|
593
|
+
}
|
|
594
|
+
} else if (block.name.includes('_banner') && !world.config.disableBlockEntityTextures) {
|
|
595
|
+
const key = `${cursor.x},${cursor.y},${cursor.z}`
|
|
596
|
+
const props: any = block.getProperties()
|
|
597
|
+
const facingRotationMap = {
|
|
598
|
+
'north': 2,
|
|
599
|
+
'south': 0,
|
|
600
|
+
'west': 1,
|
|
601
|
+
'east': 3
|
|
602
|
+
}
|
|
603
|
+
const isWall = block.name.endsWith('_wall_banner')
|
|
604
|
+
attr.banners[key] = {
|
|
605
|
+
isWall,
|
|
606
|
+
blockName: block.name, // Pass block name for base color extraction
|
|
607
|
+
rotation: isWall ? facingRotationMap[props.facing] : (props.rotation === undefined ? 0 : +props.rotation)
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const biome = block.biome.name
|
|
611
|
+
|
|
612
|
+
if (world.preflat) { // 10% perf
|
|
613
|
+
const patchProperties = preflatBlockCalculation(block, world, cursor)
|
|
614
|
+
if (patchProperties) {
|
|
615
|
+
block._originalProperties ??= block._properties
|
|
616
|
+
block._properties = { ...block._originalProperties, ...patchProperties }
|
|
617
|
+
if (block.models && JSON.stringify(block._originalProperties) !== JSON.stringify(block._properties)) {
|
|
618
|
+
// recompute models
|
|
619
|
+
block.models = undefined
|
|
620
|
+
block = world.getBlock(cursor, blockProvider, attr)!
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
block._properties = block._originalProperties ?? block._properties
|
|
624
|
+
block._originalProperties = undefined
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const isWaterlogged = isBlockWaterlogged(block)
|
|
629
|
+
if (block.name === 'water' || isWaterlogged) {
|
|
630
|
+
const pos = cursor.clone()
|
|
631
|
+
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
632
|
+
delayedRender.push(() => {
|
|
633
|
+
renderLiquid(world, pos, blockProvider.getTextureInfo('water_still'), block.type, biome, true, attr, !isWaterlogged)
|
|
634
|
+
})
|
|
635
|
+
attr.blocksCount++
|
|
636
|
+
} else if (block.name === 'lava') {
|
|
637
|
+
renderLiquid(world, cursor, blockProvider.getTextureInfo('lava_still'), block.type, biome, false, attr, false)
|
|
638
|
+
attr.blocksCount++
|
|
639
|
+
}
|
|
640
|
+
if (block.name !== 'water' && block.name !== 'lava' && !INVISIBLE_BLOCKS.has(block.name)) {
|
|
641
|
+
// cache
|
|
642
|
+
let { models } = block
|
|
643
|
+
|
|
644
|
+
models ??= unknownBlockModel
|
|
645
|
+
|
|
646
|
+
const firstForceVar = world.config.debugModelVariant?.[0]
|
|
647
|
+
let part = 0
|
|
648
|
+
for (const modelVars of models ?? []) {
|
|
649
|
+
const pos = cursor.clone()
|
|
650
|
+
// const variantRuntime = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), modelVars.length)
|
|
651
|
+
const variantRuntime = 0
|
|
652
|
+
const useVariant = world.config.debugModelVariant?.[part] ?? firstForceVar ?? variantRuntime
|
|
653
|
+
part++
|
|
654
|
+
const model = modelVars[useVariant] ?? modelVars[0]
|
|
655
|
+
if (!model) continue
|
|
656
|
+
|
|
657
|
+
// #region 10%
|
|
658
|
+
let globalMatrix = null as any
|
|
659
|
+
let globalShift = null as any
|
|
660
|
+
for (const axis of ['x', 'y', 'z'] as const) {
|
|
661
|
+
if (axis in model) {
|
|
662
|
+
globalMatrix = globalMatrix ?
|
|
663
|
+
matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0))) :
|
|
664
|
+
buildRotationMatrix(axis, -(model[axis] ?? 0))
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (globalMatrix) {
|
|
668
|
+
globalShift = [8, 8, 8]
|
|
669
|
+
globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
|
|
670
|
+
}
|
|
671
|
+
// #endregion
|
|
672
|
+
|
|
673
|
+
for (const element of model.elements ?? []) {
|
|
674
|
+
const ao = model.ao ?? block.boundingBox !== 'empty'
|
|
675
|
+
if (block.transparent) {
|
|
676
|
+
const pos = cursor.clone()
|
|
677
|
+
delayedRender.push(() => {
|
|
678
|
+
renderElement(world, pos, element, ao, attr, globalMatrix, globalShift, block, biome)
|
|
679
|
+
})
|
|
680
|
+
} else {
|
|
681
|
+
// 60%
|
|
682
|
+
renderElement(world, cursor, element, ao, attr, globalMatrix, globalShift, block, biome)
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (part > 0) attr.blocksCount++
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
for (const render of delayedRender) {
|
|
693
|
+
render()
|
|
694
|
+
}
|
|
695
|
+
delayedRender = []
|
|
696
|
+
|
|
697
|
+
let ndx = attr.positions.length / 3
|
|
698
|
+
for (let i = 0; i < attr.t_positions!.length / 12; i++) {
|
|
699
|
+
attr.indices[attr.indicesCount++] = ndx
|
|
700
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
701
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
702
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
703
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
704
|
+
attr.indices[attr.indicesCount++] = ndx + 3
|
|
705
|
+
// back face
|
|
706
|
+
attr.indices[attr.indicesCount++] = ndx
|
|
707
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
708
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
709
|
+
attr.indices[attr.indicesCount++] = ndx + 2
|
|
710
|
+
attr.indices[attr.indicesCount++] = ndx + 3
|
|
711
|
+
attr.indices[attr.indicesCount++] = ndx + 1
|
|
712
|
+
ndx += 4
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
attr.positions.push(...attr.t_positions!)
|
|
716
|
+
attr.normals.push(...attr.t_normals!)
|
|
717
|
+
attr.colors.push(...attr.t_colors!)
|
|
718
|
+
attr.uvs.push(...attr.t_uvs!)
|
|
719
|
+
|
|
720
|
+
delete attr.t_positions
|
|
721
|
+
delete attr.t_normals
|
|
722
|
+
delete attr.t_colors
|
|
723
|
+
delete attr.t_uvs
|
|
724
|
+
|
|
725
|
+
attr.positions = new Float32Array(attr.positions) as any
|
|
726
|
+
attr.normals = new Float32Array(attr.normals) as any
|
|
727
|
+
attr.colors = new Float32Array(attr.colors) as any
|
|
728
|
+
attr.uvs = new Float32Array(attr.uvs) as any
|
|
729
|
+
attr.using32Array = arrayNeedsUint32(attr.indices)
|
|
730
|
+
if (attr.using32Array) {
|
|
731
|
+
attr.indices = new Uint32Array(attr.indices)
|
|
732
|
+
} else {
|
|
733
|
+
attr.indices = new Uint16Array(attr.indices)
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if (needTiles) {
|
|
737
|
+
delete attr.positions
|
|
738
|
+
delete attr.normals
|
|
739
|
+
delete attr.colors
|
|
740
|
+
delete attr.uvs
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return attr
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// copied from three.js
|
|
747
|
+
function arrayNeedsUint32 (array) {
|
|
748
|
+
|
|
749
|
+
// assumes larger values usually on last
|
|
750
|
+
|
|
751
|
+
for (let i = array.length - 1; i >= 0; -- i) {
|
|
752
|
+
|
|
753
|
+
if (array[i] >= 65_535) return true // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
|
|
754
|
+
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
return false
|
|
758
|
+
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
export const setBlockStatesData = (blockstatesModels, blocksAtlas: any, _needTiles = false, useUnknownBlockModel = true, version = 'latest') => {
|
|
762
|
+
blockProvider = worldBlockProvider(blockstatesModels, blocksAtlas, version)
|
|
763
|
+
globalThis.blockProvider = blockProvider
|
|
764
|
+
if (useUnknownBlockModel) {
|
|
765
|
+
unknownBlockModel = blockProvider.getAllResolvedModels0_1({ name: 'unknown', properties: {} })
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
needTiles = _needTiles
|
|
769
|
+
}
|