minerender 2.1.0-beta.5 → 2.1.0-beta.6

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 (43) hide show
  1. package/dist/browser/esm/Materials.mjs +3 -2
  2. package/dist/browser/esm/Materials.mjs.map +1 -1
  3. package/dist/browser/esm/assets/Fonts.mjs +31 -4
  4. package/dist/browser/esm/assets/Fonts.mjs.map +1 -1
  5. package/dist/browser/esm/assets/_fonts/Unihex.mjs +166 -0
  6. package/dist/browser/esm/assets/_fonts/Unihex.mjs.map +1 -0
  7. package/dist/browser/esm/assets/source/HostedAssetSource.mjs +12 -1
  8. package/dist/browser/esm/assets/source/HostedAssetSource.mjs.map +1 -1
  9. package/dist/browser/esm/assets/source/parser/AssetParsers.mjs +1 -0
  10. package/dist/browser/esm/assets/source/parser/AssetParsers.mjs.map +1 -1
  11. package/dist/browser/esm/cache/Caching.mjs +2 -0
  12. package/dist/browser/esm/cache/Caching.mjs.map +1 -1
  13. package/dist/browser/esm/entity/scene/EntityAnimationPlayer.mjs +62 -11
  14. package/dist/browser/esm/entity/scene/EntityAnimationPlayer.mjs.map +1 -1
  15. package/dist/browser/esm/entity/scene/EntityObject.mjs +53 -20
  16. package/dist/browser/esm/entity/scene/EntityObject.mjs.map +1 -1
  17. package/dist/browser/esm/env/browser/section.worker.mjs +5 -3
  18. package/dist/browser/esm/env/browser/section.worker.mjs.map +1 -1
  19. package/dist/browser/esm/gui/GuiText.mjs +4 -3
  20. package/dist/browser/esm/gui/GuiText.mjs.map +1 -1
  21. package/dist/browser/esm/index.browser.d.mts +52 -10
  22. package/dist/browser/esm/model/scene/ModelObject.mjs +4 -0
  23. package/dist/browser/esm/model/scene/ModelObject.mjs.map +1 -1
  24. package/dist/browser/esm/util/model.mjs +7 -7
  25. package/dist/browser/esm/util/model.mjs.map +1 -1
  26. package/dist/browser/esm/world/SectionGeometry.mjs +5 -3
  27. package/dist/browser/esm/world/SectionGeometry.mjs.map +1 -1
  28. package/dist/browser/esm/world/SectionMesh.mjs +4 -0
  29. package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
  30. package/dist/browser/esm/world/SectionModels.mjs +2 -2
  31. package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
  32. package/dist/browser/index.d.ts +52 -10
  33. package/dist/browser/index.js +382 -73
  34. package/dist/browser/index.js.map +1 -1
  35. package/dist/bundle.js +425 -73
  36. package/dist/bundle.js.map +1 -1
  37. package/dist/node/index.d.mts +52 -10
  38. package/dist/node/index.d.ts +52 -10
  39. package/dist/node/index.js +387 -73
  40. package/dist/node/index.js.map +1 -1
  41. package/dist/node/index.mjs +386 -73
  42. package/dist/node/index.mjs.map +1 -1
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/model/scene/ModelObject.ts"],"sourcesContent":["import { SceneObject } from \"../../renderer/SceneObject\";\nimport { ItemModel, Model, TextureAsset, TripleArray } from \"../Model\";\nimport { Materials } from \"../../Materials\";\nimport { Maybe, toRadians } from \"../../util/util\";\nimport { UVMapper } from \"../../UVMapper\";\nimport { TextureAtlas } from \"../../texture/TextureAtlas\";\nimport { BoxGeometry, BoxHelper, BufferAttribute, Color, DoubleSide, EdgesGeometry, Euler, FrontSide, InstancedMesh, LineBasicMaterial, LineSegments, Material, Matrix4, Mesh, MeshBasicMaterial, MeshStandardMaterial, ShaderMaterial } from \"three\";\nimport { mergeBufferGeometries } from \"../../three/BufferGeometryUtils\";\nimport { SceneObjectOptions } from \"../../renderer/SceneObjectOptions\";\nimport { addBox3WireframeToObject, addWireframeToMesh, addWireframeToObject, applyElementRotation } from \"../../util/model\";\nimport { merge } from \"../../util/_internal/merge\";\nimport type { BufferGeometry, Texture } from \"three\";\nimport { BlockObject } from \"../block/scene/BlockObject\";\nimport { prefix } from \"../../util/log\";\nimport { CUBE_FACES } from \"../../CubeFace\";\nimport { DisplayPosition } from \"../DisplayPosition\";\nimport { DisplayTransforms } from \"../DisplayTransforms\";\nimport { ModelCulling } from \"../ModelCulling\";\nimport type { MineRenderScene } from \"../../renderer/MineRenderScene\";\nimport { SpecialItems } from \"../SpecialItems\";\nimport { EntityObject } from \"../../entity/scene/EntityObject\";\nimport { GuiLight } from \"../GuiLight\";\nimport { ItemTints } from \"../ItemTints\";\nimport { ItemGlint } from \"../ItemGlint\";\n\n\nconst p = prefix(\"ModelObject\");\n\n//TODO: might want to abstract this out into a generic model, and create a separate class for Block models\n/** Builds render geometry from a merged Java model. Create it through {@link MineRenderScene.addModel}. */\nexport class ModelObject extends SceneObject {\n\n public readonly isModelObject: true = true;\n\n public static readonly DEFAULT_OPTIONS: ModelObjectOptions = merge({}, SceneObject.DEFAULT_OPTIONS, <ModelObjectOptions>{});\n public readonly options: ModelObjectOptions;\n\n protected atlas?: TextureAtlas;\n private atlasMaterial?: Material;\n private atlasTexture?: Texture;\n private unsubscribeAtlas?: () => void;\n private readonly specialMaterials = new Map<Material, Material>();\n private readonly geometries = new Set<BufferGeometry>();\n private readonly hasGlint: boolean;\n private glint?: ItemGlint;\n\n public blockParent: Maybe<BlockObject>;\n\n private meshesCreated: boolean = false;\n\n constructor(readonly originalModel: Model, options?: Partial<ModelObjectOptions>) {\n super(options);\n this.options = merge({}, ModelObject.DEFAULT_OPTIONS, options ?? {});\n const item = originalModel as ItemModel;\n const specialType = item.special?.type.replace(/^minecraft:/, \"\");\n this.hasGlint = !item.parts && (!item.special || specialType === \"shield\" || specialType === \"trident\") && ItemGlint.enabled(item.components, item.itemId);\n if (item.special || item.parts || this.hasGlint) this.options.instanceMeshes = false;\n if (this.options.tints) this.options.tints = { ...this.options.tints };\n this.addEventListener(\"added\", () => this.updateAnimationSubscription());\n this.addEventListener(\"removed\", () => this.updateAnimationSubscription());\n }\n\n async init(): Promise<void> {\n const parts = (this.originalModel as ItemModel).parts;\n if (parts) {\n try {\n for (const part of parts) {\n const object = new ModelObject(part, { ...this.options, instanceMeshes: false });\n this.add(object);\n await object.init();\n }\n let order = 0;\n this.iterateAllMeshes(mesh => {\n mesh.renderOrder = order++;\n // Keep composite children in one render pass so their declared order is retained.\n for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {\n material.transparent = true;\n }\n });\n } catch (error) {\n this.disposeAndRemoveAllChildren();\n throw error;\n }\n this.notifyDirty();\n return;\n }\n this.options.tints = await ItemTints.get(this.originalModel, this.options.tints);\n const special = (this.originalModel as ItemModel).special;\n if (special) {\n const parts = await SpecialItems.getParts(special, this.originalModel.key?.root, (this.originalModel as ItemModel).components);\n // A separate display node preserves zero scales without decomposing a singular matrix.\n // Use SceneObject so disposal reaches the parts.\n const display = new SceneObject();\n if (this.options.displayPosition) {\n const transform = DisplayTransforms.getTransform(this.originalModel.display, this.options.displayPosition);\n display.position.copy(transform.position);\n display.quaternion.copy(transform.quaternion);\n display.scale.copy(transform.scale);\n }\n this.add(display);\n const offset = new Matrix4().makeTranslation(-8, -8, -8);\n try {\n const targets: { mesh: Mesh; parent?: Mesh }[] = [];\n for (const part of parts) {\n const object = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe, tints: part.tints, faces: part.faces });\n object.matrix.multiplyMatrices(offset, part.transform).decompose(object.position, object.quaternion, object.scale);\n display.add(object);\n await object.init(part.material);\n object.iterateAllMeshes(mesh => {\n const source = mesh.material as MeshBasicMaterial;\n let material = this.specialMaterials.get(source);\n if (!material) {\n const front = this.options.displayPosition === DisplayPosition.GUI &&\n (this.originalModel as ItemModel).gui_light === GuiLight.FRONT;\n material = SpecialItems.createMaterial(source, !front);\n // Entity geometry already contains the inward faces used by vanilla's translucent draw.\n if (part.material) material.side = FrontSide;\n this.specialMaterials.set(source, material);\n }\n mesh.material = material;\n });\n for (const [name, rotation] of Object.entries(part.rotations)) {\n object.getGroupByName(name)?.rotation.set(...rotation, \"ZYX\");\n }\n for (const [name, position] of Object.entries(part.positions ?? {})) {\n object.getGroupByName(name)?.position.set(...position);\n }\n if (this.hasGlint) {\n if (special.type === \"shield\" || special.type === \"minecraft:shield\") {\n const mesh = object.getMeshByName(\"plate\", \"main\")!;\n const layers = Object.keys(part.model.layers!);\n if (part.model.layers!.pattern_base) targets.push({ mesh: object.getMeshByName(\"handle\", \"main\")! });\n // Follow the final plate draw so GUI and composite ordering keeps glint above the patterns.\n targets.push({ mesh, parent: object.getMeshByName(\"plate\", layers[layers.length - 1])! });\n } else {\n object.iterateAllMeshes(mesh => targets.push({ mesh }));\n }\n }\n }\n if (targets.length) {\n this.glint = await ItemGlint.create(this, undefined, this.originalModel.key?.root, targets);\n this.updateAnimationSubscription();\n }\n } catch (error) {\n this.disposeAndRemoveAllChildren();\n throw error;\n }\n this.notifyDirty();\n return;\n }\n try {\n // Load the atlas before creating geometry so every pass uses the mapped UVs.\n await this.loadTextures();\n this.createMeshes();\n this.applyTextures();\n if (this.hasGlint && this.atlasTexture) {\n this.glint = await ItemGlint.create(this, this.atlasTexture, this.originalModel.key?.root);\n this.updateAnimationSubscription();\n }\n } catch (error) {\n this.disposeAndRemoveAllChildren();\n throw error;\n }\n }\n\n public get textureAtlas(): Maybe<TextureAtlas> {\n return this.atlas;\n }\n\n public get isOpaqueFullCube(): boolean {\n return !this.options.displayPosition && ModelCulling.isOpaqueFullCube(this.atlas);\n }\n\n //TODO: support for replacing textures\n\n protected async loadTextures(): Promise<void> {\n this.atlas = await UVMapper.getAtlas(this.originalModel);\n }\n\n\n protected createMeshes(force: boolean = false) {\n if (this.meshesCreated && !force) return;\n\n const mat = Materials.MISSING_TEXTURE;\n const displayTransform = this.options.displayPosition\n ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : undefined;\n\n let allGeos: BufferGeometry[] = [];\n\n if (this.atlas) {\n if (this.atlas.model.elements) {\n this.atlas.model.elements?.forEach(el => {\n const elGeo = this._getBoxGeometryFromElement(el).clone();\n this.geometries.add(elGeo);\n if (this.options.cullMask) {\n const indices = Array.from(elGeo.getIndex()!.array);\n elGeo.setIndex(indices.filter((_, index) => {\n const face = CUBE_FACES[Math.floor(index / 6)];\n const direction = CUBE_FACES.findIndex(name => name === el.faces[face]?.cullface);\n return direction < 0 || !(this.options.cullMask! & (1 << direction));\n }));\n elGeo.clearGroups();\n }\n if (this.options.uvLockRotation) {\n UVMapper.lockUvs(elGeo, el.faces, this.atlas!, new Euler(...this.options.uvLockRotation));\n }\n UVMapper.setAtlasUvBounds(elGeo, el.faces, this.atlas!);\n if (this.options.tints) {\n const colors = new Float32Array(elGeo.getAttribute(\"position\").count * 3).fill(1);\n for (const [faceIndex, faceName] of CUBE_FACES.entries()) {\n const tintIndex = el.faces[faceName]?.tintindex;\n if (tintIndex === undefined || tintIndex < 0) continue;\n const tint = this.options.tints[tintIndex];\n if (tint === undefined) continue;\n const color = new Color(tint);\n for (let vertex = 0; vertex < 4; vertex++) {\n color.toArray(colors, (faceIndex * 4 + vertex) * 3);\n }\n }\n elGeo.setAttribute(\"color\", new BufferAttribute(colors, 3));\n }\n\n // elGeo.applyMatrix4(new THREE.Matrix4().makeTranslation(-8,-8,-8));\n\n\n elGeo.applyMatrix4(new Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));\n elGeo.applyMatrix4(new Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));\n\n if (el.rotation) {\n applyElementRotation(el.rotation, elGeo);\n }\n if (this.hasGlint) ItemGlint.mapUvs(elGeo, el.faces, this.atlas!, (this.originalModel as ItemModel).itemId, this.options.displayPosition);\n\n elGeo.applyMatrix4(new Matrix4().makeTranslation(-8, -8, -8));\n if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);\n\n if (this.options.mergeMeshes) {\n allGeos.push(elGeo);\n } else {\n const mesh = this.createAndAddMesh(undefined, undefined, elGeo, mat);\n if (this.options.wireframe) {\n addWireframeToMesh(elGeo, mesh);\n }\n }\n });\n } else {\n console.debug(p, this.atlas.model, \"has no elements\")\n }\n } else {\n console.debug(p, \"Missing atlas for\", this);\n }\n\n if (this.options.mergeMeshes) {\n let combinedGeo: BufferGeometry;\n if (allGeos.length > 0) {\n // if (this.options.wireframe) {\n // allGeos.push(new BoxGeometry(16, 16, 16, 1, 1, 1))\n // }\n\n combinedGeo = mergeBufferGeometries(allGeos);\n for (const geometry of allGeos) {\n this.geometries.delete(geometry);\n }\n } else {\n combinedGeo = new BoxGeometry(16, 16, 16);\n if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);\n }\n this.geometries.add(combinedGeo);\n combinedGeo.computeBoundingBox();\n // combinedGeo.translate(-8, -8, -8);\n // TODO: cache the combined geometry\n let mesh: Mesh;\n if (this.options.instanceMeshes) {\n mesh = this.createInstancedMesh(undefined, combinedGeo, mat, this.options.maxInstanceCount || 50);\n this.add(mesh);\n this._isInstanced = true;\n //TODO\n } else {\n mesh = this.createAndAddMesh(undefined, undefined, combinedGeo, mat)\n }\n if (this.options.wireframe) {\n addWireframeToMesh(combinedGeo, mesh, 0x0000ff, 4);\n addBox3WireframeToObject(combinedGeo.boundingBox!, mesh, 0x00ffff, 3);\n }\n }\n\n if (this.options.wireframe) {\n addWireframeToObject(this, 0x00ff00, 3)\n }\n\n this.meshesCreated = true;\n }\n\n\n protected applyTextures() {\n if (this.atlas) {\n const mat = Materials.createShadedCanvasMaterial(this.atlas.image.canvas as HTMLCanvasElement, this.atlas.hasTranslucency, false, true);\n mat.side = this.atlas.hasTransparency ? DoubleSide : FrontSide;\n this.atlasMaterial = mat;\n this.atlasTexture = (mat as ShaderMaterial).uniforms?.map?.value ?? (mat as MeshBasicMaterial).map;\n if (this.options.displayPosition === DisplayPosition.GUI &&\n (this.originalModel as ItemModel).gui_light === GuiLight.FRONT && (mat as ShaderMaterial).uniforms?.SHADE) {\n (mat as ShaderMaterial).uniforms.SHADE.value = false;\n }\n this.iterateAllMeshes(mesh => {\n if (mesh.geometry.hasAttribute(\"color\")) mat.vertexColors = true;\n mesh.material = mat;\n });\n this.updateAnimationSubscription();\n }\n }\n\n private updateAnimationSubscription(): void {\n let root: ModelObject = this;\n while (root.parent && isModelObject(root.parent)) root = root.parent;\n const active = !!root.parent && (!this.isInstanced || this.instanceCounter > 0);\n this.glint?.updateSubscription(active);\n if (active && this.atlas?.hasAnimation && this.atlasTexture) {\n if (!this.unsubscribeAtlas) {\n this.atlasTexture.needsUpdate = true;\n this.unsubscribeAtlas = this.atlas.subscribe(() => {\n this.atlasTexture!.needsUpdate = true;\n this.traverseAncestors(parent => {\n if ((parent as MineRenderScene).isMineRenderScene) (parent as MineRenderScene).dirty = true;\n });\n this.notifyDirty();\n });\n }\n } else {\n this.unsubscribeAtlas?.();\n this.unsubscribeAtlas = undefined;\n }\n for (const child of this.children) {\n if (isModelObject(child)) child.updateAnimationSubscription();\n }\n }\n\n nextInstance() {\n const reference = super.nextInstance();\n this.updateAnimationSubscription();\n return reference;\n }\n\n removeInstanceAt(index: number): void {\n super.removeInstanceAt(index);\n this.updateAnimationSubscription();\n }\n\n public disposeAndRemoveAllChildren(): void {\n this.glint?.dispose();\n this.glint = undefined;\n this.unsubscribeAtlas?.();\n this.unsubscribeAtlas = undefined;\n this.atlasTexture?.dispose();\n this.atlasMaterial?.dispose();\n this.atlasTexture = undefined;\n this.atlasMaterial = undefined;\n for (const material of this.specialMaterials.values()) material.dispose();\n this.specialMaterials.clear();\n for (const geometry of this.geometries) geometry.dispose();\n this.geometries.clear();\n super.disposeAndRemoveAllChildren();\n }\n\n}\n\n/** Model settings passed to `scene.addModel(model, options)` or the ModelObject constructor. */\nexport interface ModelObjectOptions extends SceneObjectOptions {\n /** Minecraft display pose applied around the model center, before scene transforms. */\n displayPosition?: DisplayPosition;\n /** Quarter-turn block rotation in radians to compensate when locking UVs. */\n uvLockRotation?: TripleArray;\n /** sRGB 0xRRGGBB colors by face tint index, overriding automatic item or block preview colors. */\n tints?: Record<number, number>;\n /** Hidden neighbor directions in CUBE_FACES order, before the model's block rotation. */\n cullMask?: number;\n}\n\nexport function isModelObject(obj: any): obj is ModelObject {\n return (<ModelObject>obj).isModelObject;\n}\n"],"mappings":"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","names":["parts"]}
1
+ {"version":3,"sources":["../../../../../src/model/scene/ModelObject.ts"],"sourcesContent":["import { SceneObject } from \"../../renderer/SceneObject\";\nimport { ItemModel, Model, TextureAsset, TripleArray } from \"../Model\";\nimport { Materials } from \"../../Materials\";\nimport { Maybe, toRadians } from \"../../util/util\";\nimport { UVMapper } from \"../../UVMapper\";\nimport { TextureAtlas } from \"../../texture/TextureAtlas\";\nimport { BoxGeometry, BoxHelper, BufferAttribute, Color, DoubleSide, EdgesGeometry, Euler, FrontSide, InstancedMesh, LineBasicMaterial, LineSegments, Material, Matrix4, Mesh, MeshBasicMaterial, MeshStandardMaterial, ShaderMaterial } from \"three\";\nimport { mergeBufferGeometries } from \"../../three/BufferGeometryUtils\";\nimport { SceneObjectOptions } from \"../../renderer/SceneObjectOptions\";\nimport { addBox3WireframeToObject, addWireframeToMesh, addWireframeToObject, applyElementRotation } from \"../../util/model\";\nimport { merge } from \"../../util/_internal/merge\";\nimport type { BufferGeometry, Texture } from \"three\";\nimport { BlockObject } from \"../block/scene/BlockObject\";\nimport { prefix } from \"../../util/log\";\nimport { CUBE_FACES } from \"../../CubeFace\";\nimport { DisplayPosition } from \"../DisplayPosition\";\nimport { DisplayTransforms } from \"../DisplayTransforms\";\nimport { ModelCulling } from \"../ModelCulling\";\nimport type { MineRenderScene } from \"../../renderer/MineRenderScene\";\nimport { SpecialItems } from \"../SpecialItems\";\nimport { EntityObject } from \"../../entity/scene/EntityObject\";\nimport { GuiLight } from \"../GuiLight\";\nimport { ItemTints } from \"../ItemTints\";\nimport { ItemGlint } from \"../ItemGlint\";\n\n\nconst p = prefix(\"ModelObject\");\n\n//TODO: might want to abstract this out into a generic model, and create a separate class for Block models\n/** Builds render geometry from a merged Java model. Create it through {@link MineRenderScene.addModel}. */\nexport class ModelObject extends SceneObject {\n\n public readonly isModelObject: true = true;\n\n public static readonly DEFAULT_OPTIONS: ModelObjectOptions = merge({}, SceneObject.DEFAULT_OPTIONS, <ModelObjectOptions>{});\n public readonly options: ModelObjectOptions;\n\n protected atlas?: TextureAtlas;\n private atlasMaterial?: Material;\n private atlasTexture?: Texture;\n private unsubscribeAtlas?: () => void;\n private readonly specialMaterials = new Map<Material, Material>();\n private readonly geometries = new Set<BufferGeometry>();\n private readonly hasGlint: boolean;\n private glint?: ItemGlint;\n\n public blockParent: Maybe<BlockObject>;\n\n private meshesCreated: boolean = false;\n\n constructor(readonly originalModel: Model, options?: Partial<ModelObjectOptions>) {\n super(options);\n this.options = merge({}, ModelObject.DEFAULT_OPTIONS, options ?? {});\n const item = originalModel as ItemModel;\n const specialType = item.special?.type.replace(/^minecraft:/, \"\");\n this.hasGlint = !item.parts && (!item.special || specialType === \"shield\" || specialType === \"trident\") && ItemGlint.enabled(item.components, item.itemId);\n if (item.special || item.parts || this.hasGlint) this.options.instanceMeshes = false;\n if (this.options.tints) this.options.tints = { ...this.options.tints };\n this.addEventListener(\"added\", () => this.updateAnimationSubscription());\n this.addEventListener(\"removed\", () => this.updateAnimationSubscription());\n }\n\n async init(): Promise<void> {\n const parts = (this.originalModel as ItemModel).parts;\n if (parts) {\n try {\n for (const part of parts) {\n const object = new ModelObject(part, { ...this.options, instanceMeshes: false });\n this.add(object);\n await object.init();\n }\n let order = 0;\n this.iterateAllMeshes(mesh => {\n mesh.renderOrder = order++;\n // Keep composite children in one render pass so their declared order is retained.\n for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {\n material.transparent = true;\n }\n });\n } catch (error) {\n this.disposeAndRemoveAllChildren();\n throw error;\n }\n this.notifyDirty();\n return;\n }\n this.options.tints = await ItemTints.get(this.originalModel, this.options.tints);\n const special = (this.originalModel as ItemModel).special;\n if (special) {\n const parts = await SpecialItems.getParts(special, this.originalModel.key?.root, (this.originalModel as ItemModel).components);\n // A separate display node preserves zero scales without decomposing a singular matrix.\n // Use SceneObject so disposal reaches the parts.\n const display = new SceneObject();\n if (this.options.displayPosition) {\n const transform = DisplayTransforms.getTransform(this.originalModel.display, this.options.displayPosition);\n display.position.copy(transform.position);\n display.quaternion.copy(transform.quaternion);\n display.scale.copy(transform.scale);\n }\n this.add(display);\n const offset = new Matrix4().makeTranslation(-8, -8, -8);\n try {\n const targets: { mesh: Mesh; parent?: Mesh }[] = [];\n for (const part of parts) {\n const object = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe, tints: part.tints, faces: part.faces });\n object.matrix.multiplyMatrices(offset, part.transform).decompose(object.position, object.quaternion, object.scale);\n display.add(object);\n await object.init(part.material);\n object.iterateAllMeshes(mesh => {\n const source = mesh.material as MeshBasicMaterial;\n let material = this.specialMaterials.get(source);\n if (!material) {\n const front = this.options.displayPosition === DisplayPosition.GUI &&\n (this.originalModel as ItemModel).gui_light === GuiLight.FRONT;\n material = SpecialItems.createMaterial(source, !front);\n // Entity geometry already contains the inward faces used by vanilla's translucent draw.\n if (part.material) material.side = FrontSide;\n this.specialMaterials.set(source, material);\n }\n mesh.material = material;\n });\n for (const [name, rotation] of Object.entries(part.rotations)) {\n object.getGroupByName(name)?.rotation.set(...rotation, \"ZYX\");\n }\n for (const [name, position] of Object.entries(part.positions ?? {})) {\n object.getGroupByName(name)?.position.set(...position);\n }\n if (this.hasGlint) {\n if (special.type === \"shield\" || special.type === \"minecraft:shield\") {\n const mesh = object.getMeshByName(\"plate\", \"main\")!;\n const layers = Object.keys(part.model.layers!);\n if (part.model.layers!.pattern_base) targets.push({ mesh: object.getMeshByName(\"handle\", \"main\")! });\n // Follow the final plate draw so GUI and composite ordering keeps glint above the patterns.\n targets.push({ mesh, parent: object.getMeshByName(\"plate\", layers[layers.length - 1])! });\n } else {\n object.iterateAllMeshes(mesh => targets.push({ mesh }));\n }\n }\n }\n if (targets.length) {\n this.glint = await ItemGlint.create(this, undefined, this.originalModel.key?.root, targets);\n this.updateAnimationSubscription();\n }\n } catch (error) {\n this.disposeAndRemoveAllChildren();\n throw error;\n }\n this.notifyDirty();\n return;\n }\n try {\n // Load the atlas before creating geometry so every pass uses the mapped UVs.\n await this.loadTextures();\n this.createMeshes();\n this.applyTextures();\n if (this.hasGlint && this.atlasTexture) {\n this.glint = await ItemGlint.create(this, this.atlasTexture, this.originalModel.key?.root);\n this.updateAnimationSubscription();\n }\n } catch (error) {\n this.disposeAndRemoveAllChildren();\n throw error;\n }\n }\n\n public get textureAtlas(): Maybe<TextureAtlas> {\n return this.atlas;\n }\n\n public get isOpaqueFullCube(): boolean {\n return !this.options.displayPosition && ModelCulling.isOpaqueFullCube(this.atlas);\n }\n\n //TODO: support for replacing textures\n\n protected async loadTextures(): Promise<void> {\n this.atlas = await UVMapper.getAtlas(this.originalModel);\n }\n\n\n protected createMeshes(force: boolean = false) {\n if (this.meshesCreated && !force) return;\n\n const mat = Materials.MISSING_TEXTURE;\n const displayTransform = this.options.displayPosition\n ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : undefined;\n\n let allGeos: BufferGeometry[] = [];\n\n if (this.atlas) {\n if (this.atlas.model.elements) {\n this.atlas.model.elements?.forEach(el => {\n const elGeo = this._getBoxGeometryFromElement(el).clone();\n this.geometries.add(elGeo);\n elGeo.setAttribute(\"shade\", new BufferAttribute(\n new Float32Array(elGeo.getAttribute(\"position\").count).fill(!(this.originalModel as ItemModel).itemId && el.shade === false ? 0 : 1), 1));\n if (this.options.cullMask) {\n const indices = Array.from(elGeo.getIndex()!.array);\n elGeo.setIndex(indices.filter((_, index) => {\n const face = CUBE_FACES[Math.floor(index / 6)];\n const direction = CUBE_FACES.findIndex(name => name === el.faces[face]?.cullface);\n return direction < 0 || !(this.options.cullMask! & (1 << direction));\n }));\n elGeo.clearGroups();\n }\n if (this.options.uvLockRotation) {\n UVMapper.lockUvs(elGeo, el.faces, this.atlas!, new Euler(...this.options.uvLockRotation));\n }\n UVMapper.setAtlasUvBounds(elGeo, el.faces, this.atlas!);\n if (this.options.tints) {\n const colors = new Float32Array(elGeo.getAttribute(\"position\").count * 3).fill(1);\n for (const [faceIndex, faceName] of CUBE_FACES.entries()) {\n const tintIndex = el.faces[faceName]?.tintindex;\n if (tintIndex === undefined || tintIndex < 0) continue;\n const tint = this.options.tints[tintIndex];\n if (tint === undefined) continue;\n const color = new Color(tint);\n for (let vertex = 0; vertex < 4; vertex++) {\n color.toArray(colors, (faceIndex * 4 + vertex) * 3);\n }\n }\n elGeo.setAttribute(\"color\", new BufferAttribute(colors, 3));\n }\n\n // elGeo.applyMatrix4(new THREE.Matrix4().makeTranslation(-8,-8,-8));\n\n\n elGeo.applyMatrix4(new Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));\n elGeo.applyMatrix4(new Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));\n\n if (el.rotation) {\n applyElementRotation(el.rotation, elGeo);\n }\n if (this.hasGlint) ItemGlint.mapUvs(elGeo, el.faces, this.atlas!, (this.originalModel as ItemModel).itemId, this.options.displayPosition);\n\n elGeo.applyMatrix4(new Matrix4().makeTranslation(-8, -8, -8));\n if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);\n\n if (this.options.mergeMeshes) {\n allGeos.push(elGeo);\n } else {\n const mesh = this.createAndAddMesh(undefined, undefined, elGeo, mat);\n if (this.options.wireframe) {\n addWireframeToMesh(elGeo, mesh);\n }\n }\n });\n } else {\n console.debug(p, this.atlas.model, \"has no elements\")\n }\n } else {\n console.debug(p, \"Missing atlas for\", this);\n }\n\n if (this.options.mergeMeshes) {\n let combinedGeo: BufferGeometry;\n if (allGeos.length > 0) {\n // if (this.options.wireframe) {\n // allGeos.push(new BoxGeometry(16, 16, 16, 1, 1, 1))\n // }\n\n combinedGeo = mergeBufferGeometries(allGeos);\n for (const geometry of allGeos) {\n this.geometries.delete(geometry);\n }\n } else {\n combinedGeo = new BoxGeometry(16, 16, 16);\n if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);\n }\n this.geometries.add(combinedGeo);\n combinedGeo.computeBoundingBox();\n // combinedGeo.translate(-8, -8, -8);\n // TODO: cache the combined geometry\n let mesh: Mesh;\n if (this.options.instanceMeshes) {\n mesh = this.createInstancedMesh(undefined, combinedGeo, mat, this.options.maxInstanceCount || 50);\n this.add(mesh);\n this._isInstanced = true;\n //TODO\n } else {\n mesh = this.createAndAddMesh(undefined, undefined, combinedGeo, mat)\n }\n if (this.options.wireframe) {\n addWireframeToMesh(combinedGeo, mesh, 0x0000ff, 4);\n addBox3WireframeToObject(combinedGeo.boundingBox!, mesh, 0x00ffff, 3);\n }\n }\n\n if (this.options.wireframe) {\n addWireframeToObject(this, 0x00ff00, 3)\n }\n\n this.meshesCreated = true;\n }\n\n\n protected applyTextures() {\n if (this.atlas) {\n const mat = Materials.createShadedCanvasMaterial(this.atlas.image.canvas as HTMLCanvasElement, this.atlas.hasTranslucency, false, true);\n mat.side = this.atlas.hasTransparency ? DoubleSide : FrontSide;\n this.atlasMaterial = mat;\n this.atlasTexture = (mat as ShaderMaterial).uniforms?.map?.value ?? (mat as MeshBasicMaterial).map;\n if (this.options.displayPosition === DisplayPosition.GUI &&\n (this.originalModel as ItemModel).gui_light === GuiLight.FRONT && (mat as ShaderMaterial).uniforms?.SHADE) {\n (mat as ShaderMaterial).uniforms.SHADE.value = false;\n }\n this.iterateAllMeshes(mesh => {\n if (mesh.geometry.hasAttribute(\"color\")) mat.vertexColors = true;\n mesh.material = mat;\n });\n this.updateAnimationSubscription();\n }\n }\n\n private updateAnimationSubscription(): void {\n let root: ModelObject = this;\n while (root.parent && isModelObject(root.parent)) root = root.parent;\n const active = !!root.parent && (!this.isInstanced || this.instanceCounter > 0);\n this.glint?.updateSubscription(active);\n if (active && this.atlas?.hasAnimation && this.atlasTexture) {\n if (!this.unsubscribeAtlas) {\n this.atlasTexture.needsUpdate = true;\n this.unsubscribeAtlas = this.atlas.subscribe(() => {\n this.atlasTexture!.needsUpdate = true;\n this.traverseAncestors(parent => {\n if ((parent as MineRenderScene).isMineRenderScene) (parent as MineRenderScene).dirty = true;\n });\n this.notifyDirty();\n });\n }\n } else {\n this.unsubscribeAtlas?.();\n this.unsubscribeAtlas = undefined;\n }\n for (const child of this.children) {\n if (isModelObject(child)) child.updateAnimationSubscription();\n }\n }\n\n nextInstance() {\n const reference = super.nextInstance();\n this.updateAnimationSubscription();\n return reference;\n }\n\n removeInstanceAt(index: number): void {\n super.removeInstanceAt(index);\n this.updateAnimationSubscription();\n }\n\n public disposeAndRemoveAllChildren(): void {\n this.glint?.dispose();\n this.glint = undefined;\n this.unsubscribeAtlas?.();\n this.unsubscribeAtlas = undefined;\n this.atlasTexture?.dispose();\n this.atlasMaterial?.dispose();\n this.atlasTexture = undefined;\n this.atlasMaterial = undefined;\n for (const material of this.specialMaterials.values()) material.dispose();\n this.specialMaterials.clear();\n for (const geometry of this.geometries) geometry.dispose();\n this.geometries.clear();\n super.disposeAndRemoveAllChildren();\n }\n\n}\n\n/** Model settings passed to `scene.addModel(model, options)` or the ModelObject constructor. */\nexport interface ModelObjectOptions extends SceneObjectOptions {\n /** Minecraft display pose applied around the model center, before scene transforms. */\n displayPosition?: DisplayPosition;\n /** Quarter-turn block rotation in radians to compensate when locking UVs. */\n uvLockRotation?: TripleArray;\n /** sRGB 0xRRGGBB colors by face tint index, overriding automatic item or block preview colors. */\n tints?: Record<number, number>;\n /** Hidden neighbor directions in CUBE_FACES order, before the model's block rotation. */\n cullMask?: number;\n}\n\nexport function isModelObject(obj: any): obj is ModelObject {\n return (<ModelObject>obj).isModelObject;\n}\n"],"mappings":"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","names":["parts"]}
@@ -17,13 +17,13 @@ function applyElementRotation(rotation, geometry) {
17
17
  break;
18
18
  }
19
19
  if (rotation.rescale) {
20
- if (Math.abs(rotation.angle) === 22.5) {
21
- const s = 1 / Math.cos(0.39269909262657166);
22
- geometry.scale(s, 1, s);
23
- } else {
24
- const s = 1 / Math.cos(0.7853981852531433);
25
- geometry.scale(s, 1, s);
26
- }
20
+ const angle = toRadians(rotation.angle);
21
+ const s = 1 / Math.max(Math.abs(Math.cos(angle)), Math.abs(Math.sin(angle)));
22
+ geometry.scale(
23
+ rotation.axis === Axis.X ? 1 : s,
24
+ rotation.axis === Axis.Y ? 1 : s,
25
+ rotation.axis === Axis.Z ? 1 : s
26
+ );
27
27
  }
28
28
  geometry.translate(origin.x, origin.y, origin.z);
29
29
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/util/model.ts"],"sourcesContent":["/// https://stackoverflow.com/questions/42812861/three-js-pivot-point/42866733#42866733\n// obj - your object (THREE.Object3D or derived)\n// point - the point of rotation (THREE.Vector3)\n// axis - the axis of rotation (normalized THREE.Vector3)\n// theta - radian value of rotation\nimport { ElementRotation } from \"../model/ModelElement\";\nimport type { BufferGeometry } from \"three\";\nimport { Axis } from \"../Axis\";\nimport { toRadians } from \"./util\";\nimport { AxesHelper, Box3, BoxGeometry, EdgesGeometry, LineBasicMaterial, LineSegments, Matrix4, Mesh, Object3D, Quaternion, Vector3, Vector4 } from \"three\";\n\nfunction rotateAboutPoint(obj: Object3D, point: Vector3, axis: Vector3, theta: number) {\n obj.position.sub(point); // remove the offset\n obj.position.applyAxisAngle(axis, theta); // rotate the POSITION\n obj.position.add(point); // re-add the offset\n\n obj.rotateOnAxis(axis, theta); // rotate the OBJECT\n}\n\n/** Rotates geometry in place around the element's origin. The supplied angle is in degrees. */\nexport function applyElementRotation(rotation: ElementRotation, geometry: BufferGeometry) {\n const origin = new Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);\n // origin.multiplyScalar(0.0625);\n\n\n // let axisVector: Vector3;\n // let inverseAxisVector: Vector3;\n // switch (rotation.axis) {\n // case Axis.X:\n // axisVector = new Vector3(1, 0, 0);\n // inverseAxisVector = new Vector3(0, 1, 1);\n // break;\n // case Axis.Y:\n // axisVector = new Vector3(0, 1, 0);\n // inverseAxisVector = new Vector3(1, 0, 1);\n // break;\n // case Axis.Z:\n // axisVector = new Vector3(0, 0, 1);\n // inverseAxisVector = new Vector3(1, 1, 0);\n // break;\n // }\n // const quat = new Quaternion().setFromAxisAngle(axisVector, (rotation.angle*0.017453292));\n // if (rotation.rescale) {\n // if (Math.abs(rotation.angle) === 22.5) {\n // inverseAxisVector.multiplyScalar(1.0 / Math.cos(0.39269909262657166) - 1.0)\n // }else {\n // inverseAxisVector.multiplyScalar(1.0 / Math.cos(0.7853981852531433) - 1.0)\n // }\n //\n // inverseAxisVector.add(new Vector3(1, 1, 1));\n // }else{\n // inverseAxisVector.set(1, 1, 1);\n // }\n\n // Vector4 vec4 = new Vector4(geometry.getAttribute(\"position\").)\n\n\n // subtract origin\n geometry.translate(-origin.x, -origin.y, -origin.z);\n // apply rotation\n switch (rotation.axis) {\n case Axis.X:\n geometry.rotateX(toRadians(rotation.angle));\n break;\n case Axis.Y:\n geometry.rotateY(toRadians(rotation.angle));\n break;\n case Axis.Z:\n geometry.rotateZ(toRadians(rotation.angle));\n break;\n }\n\n\n // if (rotation.rescale) {\n // console.log(\"angle\", Math.abs(rotation.angle) )\n // if (Math.abs(rotation.angle) === 22.5) {\n // const s = 2;\n // geometry.scale(s, s, s);\n // }else{\n // const s = 2;\n // geometry.scale(s, s, s);\n // }\n // }\n if (rotation.rescale) {\n //TODO: y height seems a bit too tall (1 pixel)\n if (Math.abs(rotation.angle) === 22.5) {\n const s = 1.0 / Math.cos(0.39269909262657166);\n geometry.scale(s, 1, s);\n }else {\n const s = 1.0 / Math.cos(0.7853981852531433);\n geometry.scale(s, 1, s);\n }\n }\n\n // add back origin\n geometry.translate(origin.x, origin.y, origin.z);\n\n\n}\n\n/** Rotates an object around a local axis by an angle in degrees. */\nexport function applyGenericRotation(axis: Axis, rotation: number, obj: Object3D) {\n\n\n // obj.position.sub(new Vector3(8,8,8).add(obj.position))\n //\n // switch (axis) {\n // case Axis.X:\n // obj.position.applyAxisAngle(new Vector3(1, 0, 0), toRadians(rotation));\n // break;\n // case Axis.Y:\n // obj.position.applyAxisAngle(new Vector3(0, 1, 0), toRadians(rotation));\n // break;\n // case Axis.Z:\n // obj.position.applyAxisAngle(new Vector3(0, 0, 1), toRadians(rotation));\n // break;\n // }\n //\n // obj.position.add(new Vector3(8,8,8).add(obj.position))\n\n switch (axis) {\n case Axis.X:\n obj.rotateOnAxis(new Vector3(1, 0, 0), toRadians(rotation));\n break;\n case Axis.Y:\n obj.rotateOnAxis(new Vector3(0, 1, 0), toRadians(rotation));\n break;\n case Axis.Z:\n obj.rotateOnAxis(new Vector3(0, 0, 1), toRadians(rotation));\n break;\n }\n\n // subtract origin\n // obj.translateX(-8);\n // obj.translateZ(-8);\n // obj.translateY(-8);\n // // apply rotation\n // switch (axis) {\n // case Axis.X:\n // obj.rotateX(toRadians(rotation));\n // // matrix.makeRotationX(toRadians(rotation));\n // break;\n // case Axis.Y:\n // obj.rotateY(toRadians(rotation));\n // // matrix.makeRotationY(toRadians(rotation));\n // break;\n // case Axis.Z:\n // obj.rotateZ(toRadians(rotation));\n // // matrix.makeRotationZ(toRadians(rotation));\n // break;\n // }\n // // add back origin\n // obj.translateX(8);\n // obj.translateZ(8);\n // obj.translateY(8);\n\n // obj.applyMatrix4(matrix);\n}\n\nexport function addBox3WireframeToObject(box: Box3, obj: Object3D, color: number = 0xffffff, w: number = 2) {\n let size = new Vector3();\n box.getSize(size);\n\n let boxGeo = new BoxGeometry(size.x, size.y, size.z, 1, 1, 1);\n // boxGeo.translate(box.min.x, box.min.y, box.min.z);\n let wireGeo = new EdgesGeometry(boxGeo);\n let wireMat = new LineBasicMaterial({ color: color, linewidth: w, })\n let wireframe = new LineSegments(wireGeo, wireMat);\n obj.add(wireframe);\n\n let axes = new AxesHelper(1);\n obj.add(axes);\n}\n\n\nexport function addWireframeToObject(obj: Object3D, color: number = 0xffffff, w: number = 2) {\n let boxGeo = new BoxGeometry(16, 16, 16, 1, 1, 1);\n let wireGeo = new EdgesGeometry(boxGeo);\n let wireMat = new LineBasicMaterial({ color: color, linewidth: w, })\n let wireframe = new LineSegments(wireGeo, wireMat);\n obj.add(wireframe);\n\n let axes = new AxesHelper(1);\n obj.add(axes);\n}\n\n/** Adds edge and axis helpers to a mesh and returns a function that disposes their resources. */\nexport function addWireframeToMesh(geo: BufferGeometry, mesh: Mesh, color: number = 0xffffff, w: number = 2) {\n let wireGeo = new EdgesGeometry(geo);\n let wireMat = new LineBasicMaterial({ color: color, linewidth: w, })\n let wireframe = new LineSegments(wireGeo, wireMat);\n mesh.add(wireframe);\n\n let axes = new AxesHelper(1);\n mesh.add(axes);\n\n return () => {\n wireGeo.dispose();\n wireMat.dispose();\n axes.dispose();\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/util/model.ts"],"sourcesContent":["/// https://stackoverflow.com/questions/42812861/three-js-pivot-point/42866733#42866733\n// obj - your object (THREE.Object3D or derived)\n// point - the point of rotation (THREE.Vector3)\n// axis - the axis of rotation (normalized THREE.Vector3)\n// theta - radian value of rotation\nimport { ElementRotation } from \"../model/ModelElement\";\nimport type { BufferGeometry } from \"three\";\nimport { Axis } from \"../Axis\";\nimport { toRadians } from \"./util\";\nimport { AxesHelper, Box3, BoxGeometry, EdgesGeometry, LineBasicMaterial, LineSegments, Matrix4, Mesh, Object3D, Quaternion, Vector3, Vector4 } from \"three\";\n\nfunction rotateAboutPoint(obj: Object3D, point: Vector3, axis: Vector3, theta: number) {\n obj.position.sub(point); // remove the offset\n obj.position.applyAxisAngle(axis, theta); // rotate the POSITION\n obj.position.add(point); // re-add the offset\n\n obj.rotateOnAxis(axis, theta); // rotate the OBJECT\n}\n\n/** Rotates geometry in place around the element's origin. The supplied angle is in degrees. */\nexport function applyElementRotation(rotation: ElementRotation, geometry: BufferGeometry) {\n const origin = new Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);\n // origin.multiplyScalar(0.0625);\n\n\n // let axisVector: Vector3;\n // let inverseAxisVector: Vector3;\n // switch (rotation.axis) {\n // case Axis.X:\n // axisVector = new Vector3(1, 0, 0);\n // inverseAxisVector = new Vector3(0, 1, 1);\n // break;\n // case Axis.Y:\n // axisVector = new Vector3(0, 1, 0);\n // inverseAxisVector = new Vector3(1, 0, 1);\n // break;\n // case Axis.Z:\n // axisVector = new Vector3(0, 0, 1);\n // inverseAxisVector = new Vector3(1, 1, 0);\n // break;\n // }\n // const quat = new Quaternion().setFromAxisAngle(axisVector, (rotation.angle*0.017453292));\n // if (rotation.rescale) {\n // if (Math.abs(rotation.angle) === 22.5) {\n // inverseAxisVector.multiplyScalar(1.0 / Math.cos(0.39269909262657166) - 1.0)\n // }else {\n // inverseAxisVector.multiplyScalar(1.0 / Math.cos(0.7853981852531433) - 1.0)\n // }\n //\n // inverseAxisVector.add(new Vector3(1, 1, 1));\n // }else{\n // inverseAxisVector.set(1, 1, 1);\n // }\n\n // Vector4 vec4 = new Vector4(geometry.getAttribute(\"position\").)\n\n\n // subtract origin\n geometry.translate(-origin.x, -origin.y, -origin.z);\n // apply rotation\n switch (rotation.axis) {\n case Axis.X:\n geometry.rotateX(toRadians(rotation.angle));\n break;\n case Axis.Y:\n geometry.rotateY(toRadians(rotation.angle));\n break;\n case Axis.Z:\n geometry.rotateZ(toRadians(rotation.angle));\n break;\n }\n\n\n // if (rotation.rescale) {\n // console.log(\"angle\", Math.abs(rotation.angle) )\n // if (Math.abs(rotation.angle) === 22.5) {\n // const s = 2;\n // geometry.scale(s, s, s);\n // }else{\n // const s = 2;\n // geometry.scale(s, s, s);\n // }\n // }\n if (rotation.rescale) {\n // As in vanilla 1.21.6+, the element keeps its unrotated size along the nearest grid axis.\n const angle = toRadians(rotation.angle);\n const s = 1 / Math.max(Math.abs(Math.cos(angle)), Math.abs(Math.sin(angle)));\n geometry.scale(\n rotation.axis === Axis.X ? 1 : s,\n rotation.axis === Axis.Y ? 1 : s,\n rotation.axis === Axis.Z ? 1 : s\n );\n }\n\n // add back origin\n geometry.translate(origin.x, origin.y, origin.z);\n\n\n}\n\n/** Rotates an object around a local axis by an angle in degrees. */\nexport function applyGenericRotation(axis: Axis, rotation: number, obj: Object3D) {\n\n\n // obj.position.sub(new Vector3(8,8,8).add(obj.position))\n //\n // switch (axis) {\n // case Axis.X:\n // obj.position.applyAxisAngle(new Vector3(1, 0, 0), toRadians(rotation));\n // break;\n // case Axis.Y:\n // obj.position.applyAxisAngle(new Vector3(0, 1, 0), toRadians(rotation));\n // break;\n // case Axis.Z:\n // obj.position.applyAxisAngle(new Vector3(0, 0, 1), toRadians(rotation));\n // break;\n // }\n //\n // obj.position.add(new Vector3(8,8,8).add(obj.position))\n\n switch (axis) {\n case Axis.X:\n obj.rotateOnAxis(new Vector3(1, 0, 0), toRadians(rotation));\n break;\n case Axis.Y:\n obj.rotateOnAxis(new Vector3(0, 1, 0), toRadians(rotation));\n break;\n case Axis.Z:\n obj.rotateOnAxis(new Vector3(0, 0, 1), toRadians(rotation));\n break;\n }\n\n // subtract origin\n // obj.translateX(-8);\n // obj.translateZ(-8);\n // obj.translateY(-8);\n // // apply rotation\n // switch (axis) {\n // case Axis.X:\n // obj.rotateX(toRadians(rotation));\n // // matrix.makeRotationX(toRadians(rotation));\n // break;\n // case Axis.Y:\n // obj.rotateY(toRadians(rotation));\n // // matrix.makeRotationY(toRadians(rotation));\n // break;\n // case Axis.Z:\n // obj.rotateZ(toRadians(rotation));\n // // matrix.makeRotationZ(toRadians(rotation));\n // break;\n // }\n // // add back origin\n // obj.translateX(8);\n // obj.translateZ(8);\n // obj.translateY(8);\n\n // obj.applyMatrix4(matrix);\n}\n\nexport function addBox3WireframeToObject(box: Box3, obj: Object3D, color: number = 0xffffff, w: number = 2) {\n let size = new Vector3();\n box.getSize(size);\n\n let boxGeo = new BoxGeometry(size.x, size.y, size.z, 1, 1, 1);\n // boxGeo.translate(box.min.x, box.min.y, box.min.z);\n let wireGeo = new EdgesGeometry(boxGeo);\n let wireMat = new LineBasicMaterial({ color: color, linewidth: w, })\n let wireframe = new LineSegments(wireGeo, wireMat);\n obj.add(wireframe);\n\n let axes = new AxesHelper(1);\n obj.add(axes);\n}\n\n\nexport function addWireframeToObject(obj: Object3D, color: number = 0xffffff, w: number = 2) {\n let boxGeo = new BoxGeometry(16, 16, 16, 1, 1, 1);\n let wireGeo = new EdgesGeometry(boxGeo);\n let wireMat = new LineBasicMaterial({ color: color, linewidth: w, })\n let wireframe = new LineSegments(wireGeo, wireMat);\n obj.add(wireframe);\n\n let axes = new AxesHelper(1);\n obj.add(axes);\n}\n\n/** Adds edge and axis helpers to a mesh and returns a function that disposes their resources. */\nexport function addWireframeToMesh(geo: BufferGeometry, mesh: Mesh, color: number = 0xffffff, w: number = 2) {\n let wireGeo = new EdgesGeometry(geo);\n let wireMat = new LineBasicMaterial({ color: color, linewidth: w, })\n let wireframe = new LineSegments(wireGeo, wireMat);\n mesh.add(wireframe);\n\n let axes = new AxesHelper(1);\n mesh.add(axes);\n\n return () => {\n wireGeo.dispose();\n wireMat.dispose();\n axes.dispose();\n };\n}\n"],"mappings":"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","names":[]}
@@ -21,7 +21,7 @@ function buildSectionGeometry(input) {
21
21
  const cornerBrightness = ambientOcclusion ? new Float32Array(4) : void 0;
22
22
  for (const template of templateData) {
23
23
  const { quads } = template;
24
- if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads || template.biomeTint && template.biomeTint.length !== quads) {
24
+ if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads || template.shade && template.shade.length !== quads * 4 || template.biomeTint && template.biomeTint.length !== quads) {
25
25
  throw new RangeError("Section template arrays do not match its quad count");
26
26
  }
27
27
  }
@@ -112,6 +112,7 @@ function buildSectionGeometry(input) {
112
112
  }
113
113
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
114
114
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
115
+ const shade = new Float32Array(faces * 4).fill(1);
115
116
  const outputIndices = new Uint32Array(faces * 6);
116
117
  const blockIndices = new Uint16Array(faces);
117
118
  let vertex = 0, indexOffset = 0;
@@ -141,6 +142,7 @@ function buildSectionGeometry(input) {
141
142
  normals[vertex * 3] = template.normals[source * 3];
142
143
  normals[vertex * 3 + 1] = template.normals[source * 3 + 1];
143
144
  normals[vertex * 3 + 2] = template.normals[source * 3 + 2];
145
+ shade[vertex] = template.shade?.[source] ?? 1;
144
146
  uvs[vertex * 2] = mapU(template.uvs[source * 2]);
145
147
  uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
146
148
  uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);
@@ -193,11 +195,11 @@ function buildSectionGeometry(input) {
193
195
  indexOffset += 6;
194
196
  }
195
197
  }
196
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
198
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, shade, indices: outputIndices, blockIndices };
197
199
  });
198
200
  }
199
201
  function sectionGeometryTransferables(pages) {
200
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer, page.blockIndices.buffer]);
202
+ return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.shade.buffer, page.indices.buffer, page.blockIndices.buffer]);
201
203
  }
202
204
  export {
203
205
  buildSectionGeometry,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/world/SectionGeometry.ts"],"sourcesContent":["import { buildFluidQuads, fluidKindOf } from \"../model/fluid/FluidQuads\";\nimport type { FluidKind, FluidQuads } from \"../model/fluid/FluidQuads\";\nimport { quadAmbientOcclusion, sectionAmbientOcclusionMask } from \"./_light/AmbientOcclusion\";\nimport { fluidLightLevel, LIGHT_SAMPLE_OFFSETS, lightBrightness, quadLightIndex } from \"./_light/FaceLight\";\n\n/** Static model geometry as quads: four vertices per quad, in quad order. */\nexport interface SectionTemplateData {\n quads: number;\n positions: Float32Array;\n normals: Float32Array;\n uvs: Float32Array;\n uvBounds: Float32Array;\n colors: Float32Array;\n indices: Uint16Array;\n cullFaces: Uint8Array;\n biomeTint?: Uint8Array;\n atlas: number;\n layer: number;\n ambientOcclusion?: boolean;\n}\n\n/** The pixel dimensions and animation state of a source atlas. */\nexport interface SectionAtlasSize {\n width: number;\n height: number;\n animated: boolean;\n}\n\n/** One fluid kind's sprite rectangles in atlas pixels and its linear-light vertex tint. */\nexport interface SectionFluidKind {\n atlas: number;\n still: [x: number, y: number, width: number, height: number];\n flow: [x: number, y: number, width: number, height: number];\n tint: [r: number, g: number, b: number];\n}\n\n/** Fluid cells of the section plus a one-cell shell, 18×18×18, x fastest, then z, then y. */\nexport interface SectionFluidInput {\n /** Bit 128 marks a surface rendered elsewhere; the cell still supplies neighbor fluid samples. */\n cells: Uint8Array;\n /** Linear RGB per section cell, indexed by (x + 16z + 256y) * 3. Omission uses the water kind's tint. */\n waterTints?: Float32Array;\n water?: SectionFluidKind;\n lava?: SectionFluidKind;\n}\n\n/** Section placements and their shared templates, ready for geometry building. */\nexport interface SectionGeometryInput {\n count: number;\n indices: Uint16Array;\n templates: Uint16Array;\n cullMasks: Uint8Array;\n /** Linear RGB per placement; three NaN values preserve the template's colors. */\n biomeTints?: Float32Array;\n templateData: SectionTemplateData[];\n atlases: SectionAtlasSize[];\n maxAtlasSize: number;\n fluids?: SectionFluidInput;\n /** Saved brightness levels for an 18×18×18 neighborhood; 255 means unknown/full brightness. */\n light?: Uint8Array;\n /** Minimum brightness for known light levels, from 0 to 1. */\n ambientLight?: number;\n /** Opaque full cubes in an 18×18×18 neighborhood, stored as zero or one. */\n ambientOcclusion?: Uint8Array;\n}\n\n/** Merged quads and source-atlas placements for one atlas page. */\nexport interface SectionGeometryPage {\n layer: number;\n width: number;\n height: number;\n placements: { atlas: number; x: number; y: number }[];\n positions: Float32Array;\n normals: Float32Array;\n uvs: Float32Array;\n uvBounds: Float32Array;\n colors: Float32Array;\n indices: Uint32Array;\n /** Owning section cell for each quad; each quad contributes two consecutive triangles. */\n blockIndices: Uint16Array;\n}\n\n/** Builds section-local geometry from visible quads, with bounded atlas pages per layer. */\nexport function buildSectionGeometry(input: SectionGeometryInput): SectionGeometryPage[] {\n const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;\n if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError(\"Section atlas size must be a positive integer\");\n if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError(\"Section entry count exceeds its arrays\");\n if (biomeTints && biomeTints.length !== count * 3) throw new RangeError(\"Section biome tints must contain RGB for each placement\");\n if (fluids && fluids.cells.length !== 5832) throw new RangeError(\"Section fluid cells must cover an 18×18×18 neighborhood\");\n if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError(\"Section water tints must contain RGB for 4096 cells\");\n if (light && (light.length !== 5832 || light.some(level => level > 15 && level !== 255))) {\n throw new RangeError(\"Section light must cover an 18×18×18 neighborhood with levels from 0 to 15 or 255\");\n }\n if (ambientLight !== undefined && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {\n throw new RangeError(\"Section ambient light must be a number from 0 to 1\");\n }\n if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some(value => value > 1))) {\n throw new RangeError(\"Section ambient occlusion must cover an 18×18×18 neighborhood with zero or one per cell\");\n }\n const cornerBrightness = ambientOcclusion ? new Float32Array(4) : undefined;\n for (const template of templateData) {\n const { quads } = template;\n if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 ||\n template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 ||\n template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads ||\n (template.biomeTint && template.biomeTint.length !== quads)) {\n throw new RangeError(\"Section template arrays do not match its quad count\");\n }\n }\n const visible: number[] = [];\n const visibleAtlases = new Map<number, Set<number>>();\n for (let entry = 0; entry < count; entry++) {\n const template = templateData[templates[entry]];\n if (!template.cullFaces.some(direction => !(cullMasks[entry] & direction))) continue;\n visible.push(entry);\n if (!visibleAtlases.has(template.layer)) visibleAtlases.set(template.layer, new Set());\n visibleAtlases.get(template.layer)!.add(template.atlas);\n }\n const pages: {\n layer: number; placements: SectionGeometryPage[\"placements\"]; entries: number[];\n fluids: { quads: FluidQuads; x: number; y: number; z: number; data: SectionFluidKind; tint: ArrayLike<number> }[];\n x: number; y: number; rowHeight: number; width: number; height: number;\n }[] = [];\n const locations = new Map<number, { page: number; x: number; y: number }>();\n for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a], [b]) => a - b)) {\n const firstPage = pages.length;\n for (const atlas of [...layerAtlases].sort((a, b) => Number(atlases[a].animated) - Number(atlases[b].animated) ||\n (atlases[a].animated ? a - b : atlases[b].height - atlases[a].height))) {\n const { width, height, animated } = atlases[atlas];\n if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError(\"Model atlas exceeds the section atlas size limit\");\n let selected = -1;\n for (let i = firstPage; !animated && i < pages.length; i++) {\n const page = pages[i];\n const nextRow = page.x + width > maxAtlasSize;\n if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;\n if (nextRow) {\n page.y += page.rowHeight;\n page.x = 0;\n page.rowHeight = 0;\n }\n selected = i;\n break;\n }\n if (selected < 0) {\n selected = pages.length;\n pages.push({ layer, placements: [], entries: [], fluids: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 });\n }\n const page = pages[selected];\n page.placements.push({ atlas, x: page.x, y: page.y });\n locations.set(atlas, { page: selected, x: page.x, y: page.y });\n page.x += width;\n page.rowHeight = Math.max(page.rowHeight, height);\n page.width = Math.max(page.width, page.x);\n page.height = Math.max(page.height, page.y + height);\n }\n }\n for (const entry of visible) pages[locations.get(templateData[templates[entry]].atlas)!.page].entries.push(entry);\n\n if (fluids) {\n const fluidPages = new Map<FluidKind, (typeof pages)[number]>();\n for (let y = 0; y < 16; y++) for (let z = 0; z < 16; z++) for (let x = 0; x < 16; x++) {\n const byte = fluids.cells[(y + 1) * 324 + (z + 1) * 18 + x + 1];\n const fluid = fluidKindOf(byte);\n if (!fluid || (byte & 128)) continue;\n const data = fluids[fluid];\n if (!data) throw new RangeError(\"Section fluid input lacks the atlas for a present fluid\");\n const quads = buildFluidQuads(fluid, (dx, dy, dz) => {\n const cell = fluids.cells[(y + 1 + dy) * 324 + (z + 1 + dz) * 18 + x + 1 + dx];\n return { fluid: fluidKindOf(cell), level: cell & 15, solid: !!(cell & 64) };\n });\n if (!quads.sprites.length) continue;\n if (!fluidPages.has(fluid)) {\n const { width, height } = atlases[data.atlas];\n if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError(\"Model atlas exceeds the section atlas size limit\");\n fluidPages.set(fluid, { layer: 2, placements: [{ atlas: data.atlas, x: 0, y: 0 }], entries: [], fluids: [],\n x: 0, y: 0, rowHeight: 0, width, height });\n }\n const tintIndex = (x + z * 16 + y * 256) * 3;\n const tint = fluid === \"water\" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;\n fluidPages.get(fluid)!.fluids.push({ quads, x, y, z, data, tint });\n }\n pages.push(...[...fluidPages.values()].sort((a, b) => Number(atlases[a.placements[0].atlas].animated) -\n Number(atlases[b.placements[0].atlas].animated) || a.placements[0].atlas - b.placements[0].atlas));\n }\n\n return pages.map(page => {\n let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);\n for (const entry of page.entries) {\n const template = templateData[templates[entry]];\n for (let quad = 0; quad < template.quads; quad++) {\n if (!(cullMasks[entry] & template.cullFaces[quad])) faces++;\n }\n }\n const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);\n const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);\n const outputIndices = new Uint32Array(faces * 6);\n const blockIndices = new Uint16Array(faces);\n let vertex = 0, indexOffset = 0;\n for (const entry of page.entries) {\n const template = templateData[templates[entry]];\n const atlas = atlases[template.atlas];\n const placement = locations.get(template.atlas)!;\n const mapU = (u: number) => (placement.x + u * atlas.width) / page.width;\n const mapV = (v: number) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;\n const offsetX = (indices[entry] % 16) * 16;\n const offsetY = Math.floor(indices[entry] / 256) * 16;\n const offsetZ = (Math.floor(indices[entry] / 16) % 16) * 16;\n const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;\n const ambientMask = ambientOcclusion && template.ambientOcclusion !== false\n ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;\n for (let quad = 0; quad < template.quads; quad++) {\n if (cullMasks[entry] & template.cullFaces[quad]) continue;\n blockIndices[indexOffset / 6] = indices[entry];\n if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness!);\n const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[\n quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;\n const tint = biomeTints && template.biomeTint?.[quad] && !Number.isNaN(biomeTints[entry * 3]) ? entry * 3 : undefined;\n const start = vertex;\n for (let corner = 0; corner < 4; corner++, vertex++) {\n const source = quad * 4 + corner;\n positions[vertex * 3] = template.positions[source * 3] + offsetX;\n positions[vertex * 3 + 1] = template.positions[source * 3 + 1] + offsetY;\n positions[vertex * 3 + 2] = template.positions[source * 3 + 2] + offsetZ;\n normals[vertex * 3] = template.normals[source * 3];\n normals[vertex * 3 + 1] = template.normals[source * 3 + 1];\n normals[vertex * 3 + 2] = template.normals[source * 3 + 2];\n uvs[vertex * 2] = mapU(template.uvs[source * 2]);\n uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);\n uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);\n uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);\n uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);\n uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);\n const factor = brightness * (ambientMask ? cornerBrightness![corner] : 1);\n colors[vertex * 3] = (tint === undefined ? template.colors[source * 3] : biomeTints![tint]) * factor;\n colors[vertex * 3 + 1] = (tint === undefined ? template.colors[source * 3 + 1] : biomeTints![tint + 1]) * factor;\n colors[vertex * 3 + 2] = (tint === undefined ? template.colors[source * 3 + 2] : biomeTints![tint + 2]) * factor;\n }\n for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];\n }\n }\n for (const { quads, x, y, z, data, tint } of page.fluids) {\n const atlas = atlases[data.atlas];\n const placement = page.placements[0];\n const mapU = (u: number) => (placement.x + u * atlas.width) / page.width;\n const mapV = (v: number) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;\n const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;\n for (let quad = 0; quad < quads.sprites.length; quad++) {\n blockIndices[indexOffset / 6] = x + z * 16 + y * 256;\n const rect = quads.sprites[quad] === 0 ? data.still : data.flow;\n const brightness = light ? lightBrightness(fluidLightLevel(light[lightIndex],\n light[lightIndex + (quads.normals[quad * 12 + 1] < 0 ? -324 : 324)]), ambientLight) : 1;\n const start = vertex;\n for (let corner = 0; corner < 4; corner++, vertex++) {\n const source = quad * 4 + corner;\n positions[vertex * 3] = quads.positions[source * 3] + x * 16;\n positions[vertex * 3 + 1] = quads.positions[source * 3 + 1] + y * 16;\n positions[vertex * 3 + 2] = quads.positions[source * 3 + 2] + z * 16;\n normals[vertex * 3] = quads.normals[source * 3];\n normals[vertex * 3 + 1] = quads.normals[source * 3 + 1];\n normals[vertex * 3 + 2] = quads.normals[source * 3 + 2];\n uvs[vertex * 2] = mapU((rect[0] + quads.uvs[source * 2] * rect[2]) / atlas.width);\n uvs[vertex * 2 + 1] = mapV(1 - (rect[1] + (1 - quads.uvs[source * 2 + 1]) * rect[3]) / atlas.height);\n uvBounds.set([mapU(rect[0] / atlas.width), mapV(1 - (rect[1] + rect[3]) / atlas.height),\n mapU((rect[0] + rect[2]) / atlas.width), mapV(1 - rect[1] / atlas.height)], vertex * 4);\n colors[vertex * 3] = tint[0] * brightness;\n colors[vertex * 3 + 1] = tint[1] * brightness;\n colors[vertex * 3 + 2] = tint[2] * brightness;\n }\n outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);\n indexOffset += 6;\n }\n }\n return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };\n });\n}\n\n/** Returns the buffers behind each page's typed arrays for transfer to another thread. */\nexport function sectionGeometryTransferables(pages: readonly SectionGeometryPage[]): ArrayBuffer[] {\n return pages.flatMap(page => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer, page.blockIndices.buffer]);\n}\n"],"mappings":"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","names":["page"]}
1
+ {"version":3,"sources":["../../../../src/world/SectionGeometry.ts"],"sourcesContent":["import { buildFluidQuads, fluidKindOf } from \"../model/fluid/FluidQuads\";\nimport type { FluidKind, FluidQuads } from \"../model/fluid/FluidQuads\";\nimport { quadAmbientOcclusion, sectionAmbientOcclusionMask } from \"./_light/AmbientOcclusion\";\nimport { fluidLightLevel, LIGHT_SAMPLE_OFFSETS, lightBrightness, quadLightIndex } from \"./_light/FaceLight\";\n\n/** Static model geometry as quads: four vertices per quad, in quad order. */\nexport interface SectionTemplateData {\n quads: number;\n positions: Float32Array;\n normals: Float32Array;\n uvs: Float32Array;\n uvBounds: Float32Array;\n colors: Float32Array;\n shade?: Float32Array;\n indices: Uint16Array;\n cullFaces: Uint8Array;\n biomeTint?: Uint8Array;\n atlas: number;\n layer: number;\n ambientOcclusion?: boolean;\n}\n\n/** The pixel dimensions and animation state of a source atlas. */\nexport interface SectionAtlasSize {\n width: number;\n height: number;\n animated: boolean;\n}\n\n/** One fluid kind's sprite rectangles in atlas pixels and its linear-light vertex tint. */\nexport interface SectionFluidKind {\n atlas: number;\n still: [x: number, y: number, width: number, height: number];\n flow: [x: number, y: number, width: number, height: number];\n tint: [r: number, g: number, b: number];\n}\n\n/** Fluid cells of the section plus a one-cell shell, 18×18×18, x fastest, then z, then y. */\nexport interface SectionFluidInput {\n /** Bit 128 marks a surface rendered elsewhere; the cell still supplies neighbor fluid samples. */\n cells: Uint8Array;\n /** Linear RGB per section cell, indexed by (x + 16z + 256y) * 3. Omission uses the water kind's tint. */\n waterTints?: Float32Array;\n water?: SectionFluidKind;\n lava?: SectionFluidKind;\n}\n\n/** Section placements and their shared templates, ready for geometry building. */\nexport interface SectionGeometryInput {\n count: number;\n indices: Uint16Array;\n templates: Uint16Array;\n cullMasks: Uint8Array;\n /** Linear RGB per placement; three NaN values preserve the template's colors. */\n biomeTints?: Float32Array;\n templateData: SectionTemplateData[];\n atlases: SectionAtlasSize[];\n maxAtlasSize: number;\n fluids?: SectionFluidInput;\n /** Saved brightness levels for an 18×18×18 neighborhood; 255 means unknown/full brightness. */\n light?: Uint8Array;\n /** Minimum brightness for known light levels, from 0 to 1. */\n ambientLight?: number;\n /** Opaque full cubes in an 18×18×18 neighborhood, stored as zero or one. */\n ambientOcclusion?: Uint8Array;\n}\n\n/** Merged quads and source-atlas placements for one atlas page. */\nexport interface SectionGeometryPage {\n layer: number;\n width: number;\n height: number;\n placements: { atlas: number; x: number; y: number }[];\n positions: Float32Array;\n normals: Float32Array;\n uvs: Float32Array;\n uvBounds: Float32Array;\n colors: Float32Array;\n shade: Float32Array;\n indices: Uint32Array;\n /** Owning section cell for each quad; each quad contributes two consecutive triangles. */\n blockIndices: Uint16Array;\n}\n\n/** Builds section-local geometry from visible quads, with bounded atlas pages per layer. */\nexport function buildSectionGeometry(input: SectionGeometryInput): SectionGeometryPage[] {\n const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;\n if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError(\"Section atlas size must be a positive integer\");\n if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError(\"Section entry count exceeds its arrays\");\n if (biomeTints && biomeTints.length !== count * 3) throw new RangeError(\"Section biome tints must contain RGB for each placement\");\n if (fluids && fluids.cells.length !== 5832) throw new RangeError(\"Section fluid cells must cover an 18×18×18 neighborhood\");\n if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError(\"Section water tints must contain RGB for 4096 cells\");\n if (light && (light.length !== 5832 || light.some(level => level > 15 && level !== 255))) {\n throw new RangeError(\"Section light must cover an 18×18×18 neighborhood with levels from 0 to 15 or 255\");\n }\n if (ambientLight !== undefined && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {\n throw new RangeError(\"Section ambient light must be a number from 0 to 1\");\n }\n if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some(value => value > 1))) {\n throw new RangeError(\"Section ambient occlusion must cover an 18×18×18 neighborhood with zero or one per cell\");\n }\n const cornerBrightness = ambientOcclusion ? new Float32Array(4) : undefined;\n for (const template of templateData) {\n const { quads } = template;\n if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 ||\n template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 ||\n template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads ||\n (template.shade && template.shade.length !== quads * 4) ||\n (template.biomeTint && template.biomeTint.length !== quads)) {\n throw new RangeError(\"Section template arrays do not match its quad count\");\n }\n }\n const visible: number[] = [];\n const visibleAtlases = new Map<number, Set<number>>();\n for (let entry = 0; entry < count; entry++) {\n const template = templateData[templates[entry]];\n if (!template.cullFaces.some(direction => !(cullMasks[entry] & direction))) continue;\n visible.push(entry);\n if (!visibleAtlases.has(template.layer)) visibleAtlases.set(template.layer, new Set());\n visibleAtlases.get(template.layer)!.add(template.atlas);\n }\n const pages: {\n layer: number; placements: SectionGeometryPage[\"placements\"]; entries: number[];\n fluids: { quads: FluidQuads; x: number; y: number; z: number; data: SectionFluidKind; tint: ArrayLike<number> }[];\n x: number; y: number; rowHeight: number; width: number; height: number;\n }[] = [];\n const locations = new Map<number, { page: number; x: number; y: number }>();\n for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a], [b]) => a - b)) {\n const firstPage = pages.length;\n for (const atlas of [...layerAtlases].sort((a, b) => Number(atlases[a].animated) - Number(atlases[b].animated) ||\n (atlases[a].animated ? a - b : atlases[b].height - atlases[a].height))) {\n const { width, height, animated } = atlases[atlas];\n if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError(\"Model atlas exceeds the section atlas size limit\");\n let selected = -1;\n for (let i = firstPage; !animated && i < pages.length; i++) {\n const page = pages[i];\n const nextRow = page.x + width > maxAtlasSize;\n if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;\n if (nextRow) {\n page.y += page.rowHeight;\n page.x = 0;\n page.rowHeight = 0;\n }\n selected = i;\n break;\n }\n if (selected < 0) {\n selected = pages.length;\n pages.push({ layer, placements: [], entries: [], fluids: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 });\n }\n const page = pages[selected];\n page.placements.push({ atlas, x: page.x, y: page.y });\n locations.set(atlas, { page: selected, x: page.x, y: page.y });\n page.x += width;\n page.rowHeight = Math.max(page.rowHeight, height);\n page.width = Math.max(page.width, page.x);\n page.height = Math.max(page.height, page.y + height);\n }\n }\n for (const entry of visible) pages[locations.get(templateData[templates[entry]].atlas)!.page].entries.push(entry);\n\n if (fluids) {\n const fluidPages = new Map<FluidKind, (typeof pages)[number]>();\n for (let y = 0; y < 16; y++) for (let z = 0; z < 16; z++) for (let x = 0; x < 16; x++) {\n const byte = fluids.cells[(y + 1) * 324 + (z + 1) * 18 + x + 1];\n const fluid = fluidKindOf(byte);\n if (!fluid || (byte & 128)) continue;\n const data = fluids[fluid];\n if (!data) throw new RangeError(\"Section fluid input lacks the atlas for a present fluid\");\n const quads = buildFluidQuads(fluid, (dx, dy, dz) => {\n const cell = fluids.cells[(y + 1 + dy) * 324 + (z + 1 + dz) * 18 + x + 1 + dx];\n return { fluid: fluidKindOf(cell), level: cell & 15, solid: !!(cell & 64) };\n });\n if (!quads.sprites.length) continue;\n if (!fluidPages.has(fluid)) {\n const { width, height } = atlases[data.atlas];\n if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError(\"Model atlas exceeds the section atlas size limit\");\n fluidPages.set(fluid, { layer: 2, placements: [{ atlas: data.atlas, x: 0, y: 0 }], entries: [], fluids: [],\n x: 0, y: 0, rowHeight: 0, width, height });\n }\n const tintIndex = (x + z * 16 + y * 256) * 3;\n const tint = fluid === \"water\" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;\n fluidPages.get(fluid)!.fluids.push({ quads, x, y, z, data, tint });\n }\n pages.push(...[...fluidPages.values()].sort((a, b) => Number(atlases[a.placements[0].atlas].animated) -\n Number(atlases[b.placements[0].atlas].animated) || a.placements[0].atlas - b.placements[0].atlas));\n }\n\n return pages.map(page => {\n let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);\n for (const entry of page.entries) {\n const template = templateData[templates[entry]];\n for (let quad = 0; quad < template.quads; quad++) {\n if (!(cullMasks[entry] & template.cullFaces[quad])) faces++;\n }\n }\n const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);\n const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);\n const shade = new Float32Array(faces * 4).fill(1);\n const outputIndices = new Uint32Array(faces * 6);\n const blockIndices = new Uint16Array(faces);\n let vertex = 0, indexOffset = 0;\n for (const entry of page.entries) {\n const template = templateData[templates[entry]];\n const atlas = atlases[template.atlas];\n const placement = locations.get(template.atlas)!;\n const mapU = (u: number) => (placement.x + u * atlas.width) / page.width;\n const mapV = (v: number) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;\n const offsetX = (indices[entry] % 16) * 16;\n const offsetY = Math.floor(indices[entry] / 256) * 16;\n const offsetZ = (Math.floor(indices[entry] / 16) % 16) * 16;\n const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;\n const ambientMask = ambientOcclusion && template.ambientOcclusion !== false\n ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;\n for (let quad = 0; quad < template.quads; quad++) {\n if (cullMasks[entry] & template.cullFaces[quad]) continue;\n blockIndices[indexOffset / 6] = indices[entry];\n if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness!);\n const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[\n quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;\n const tint = biomeTints && template.biomeTint?.[quad] && !Number.isNaN(biomeTints[entry * 3]) ? entry * 3 : undefined;\n const start = vertex;\n for (let corner = 0; corner < 4; corner++, vertex++) {\n const source = quad * 4 + corner;\n positions[vertex * 3] = template.positions[source * 3] + offsetX;\n positions[vertex * 3 + 1] = template.positions[source * 3 + 1] + offsetY;\n positions[vertex * 3 + 2] = template.positions[source * 3 + 2] + offsetZ;\n normals[vertex * 3] = template.normals[source * 3];\n normals[vertex * 3 + 1] = template.normals[source * 3 + 1];\n normals[vertex * 3 + 2] = template.normals[source * 3 + 2];\n shade[vertex] = template.shade?.[source] ?? 1;\n uvs[vertex * 2] = mapU(template.uvs[source * 2]);\n uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);\n uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);\n uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);\n uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);\n uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);\n const factor = brightness * (ambientMask ? cornerBrightness![corner] : 1);\n colors[vertex * 3] = (tint === undefined ? template.colors[source * 3] : biomeTints![tint]) * factor;\n colors[vertex * 3 + 1] = (tint === undefined ? template.colors[source * 3 + 1] : biomeTints![tint + 1]) * factor;\n colors[vertex * 3 + 2] = (tint === undefined ? template.colors[source * 3 + 2] : biomeTints![tint + 2]) * factor;\n }\n for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];\n }\n }\n for (const { quads, x, y, z, data, tint } of page.fluids) {\n const atlas = atlases[data.atlas];\n const placement = page.placements[0];\n const mapU = (u: number) => (placement.x + u * atlas.width) / page.width;\n const mapV = (v: number) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;\n const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;\n for (let quad = 0; quad < quads.sprites.length; quad++) {\n blockIndices[indexOffset / 6] = x + z * 16 + y * 256;\n const rect = quads.sprites[quad] === 0 ? data.still : data.flow;\n const brightness = light ? lightBrightness(fluidLightLevel(light[lightIndex],\n light[lightIndex + (quads.normals[quad * 12 + 1] < 0 ? -324 : 324)]), ambientLight) : 1;\n const start = vertex;\n for (let corner = 0; corner < 4; corner++, vertex++) {\n const source = quad * 4 + corner;\n positions[vertex * 3] = quads.positions[source * 3] + x * 16;\n positions[vertex * 3 + 1] = quads.positions[source * 3 + 1] + y * 16;\n positions[vertex * 3 + 2] = quads.positions[source * 3 + 2] + z * 16;\n normals[vertex * 3] = quads.normals[source * 3];\n normals[vertex * 3 + 1] = quads.normals[source * 3 + 1];\n normals[vertex * 3 + 2] = quads.normals[source * 3 + 2];\n uvs[vertex * 2] = mapU((rect[0] + quads.uvs[source * 2] * rect[2]) / atlas.width);\n uvs[vertex * 2 + 1] = mapV(1 - (rect[1] + (1 - quads.uvs[source * 2 + 1]) * rect[3]) / atlas.height);\n uvBounds.set([mapU(rect[0] / atlas.width), mapV(1 - (rect[1] + rect[3]) / atlas.height),\n mapU((rect[0] + rect[2]) / atlas.width), mapV(1 - rect[1] / atlas.height)], vertex * 4);\n colors[vertex * 3] = tint[0] * brightness;\n colors[vertex * 3 + 1] = tint[1] * brightness;\n colors[vertex * 3 + 2] = tint[2] * brightness;\n }\n outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);\n indexOffset += 6;\n }\n }\n return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, shade, indices: outputIndices, blockIndices };\n });\n}\n\n/** Returns the buffers behind each page's typed arrays for transfer to another thread. */\nexport function sectionGeometryTransferables(pages: readonly SectionGeometryPage[]): ArrayBuffer[] {\n return pages.flatMap(page => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.shade.buffer, page.indices.buffer, page.blockIndices.buffer]);\n}\n"],"mappings":"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","names":["page"]}
@@ -51,6 +51,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
51
51
  uvs: new Float32Array(quads * 8),
52
52
  uvBounds: new Float32Array(quads * 16),
53
53
  colors: new Float32Array(quads * 12),
54
+ shade: new Float32Array(quads * 4),
54
55
  indices: new Uint16Array(quads * 6),
55
56
  cullFaces: new Uint8Array(template.cullFaces),
56
57
  biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
@@ -62,6 +63,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
62
63
  const uv = template.geometry.getAttribute("uv");
63
64
  const bounds = template.geometry.getAttribute("uvBounds");
64
65
  const color = template.geometry.getAttribute("color");
66
+ const shade = template.geometry.getAttribute("shade");
65
67
  for (let vertex = 0; vertex < quads * 4; vertex++) {
66
68
  data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
67
69
  data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
@@ -73,6 +75,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
73
75
  bounds?.getW(vertex) ?? 1
74
76
  ], vertex * 4);
75
77
  data.colors.set([color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1], vertex * 3);
78
+ data.shade[vertex] = shade?.getX(vertex) ?? 1;
76
79
  }
77
80
  for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - 4 * Math.floor(i2 / 6);
78
81
  templateCache.set(template, data);
@@ -144,6 +147,7 @@ var SectionMesh = class _SectionMesh extends Group {
144
147
  geometry.setAttribute("uv", new Float32BufferAttribute(page.uvs.buffer, 2));
145
148
  geometry.setAttribute("uvBounds", new Float32BufferAttribute(page.uvBounds.buffer, 4));
146
149
  geometry.setAttribute("color", new Float32BufferAttribute(page.colors.buffer, 3));
150
+ geometry.setAttribute("shade", new Float32BufferAttribute(page.shade.buffer, 1));
147
151
  geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
148
152
  geometry.computeBoundingBox();
149
153
  geometry.computeBoundingSphere();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/world/SectionMesh.ts"],"sourcesContent":["import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, FrontSide, Group, Material, Mesh, MeshBasicMaterial, ShaderMaterial, Texture, Uint32BufferAttribute } from \"three\";\nimport { createCanvas } from \"../canvas/CanvasCompat\";\nimport { Materials } from \"../Materials\";\nimport type { MineRenderScene } from \"../renderer/MineRenderScene\";\nimport { TextureAtlas } from \"../texture/TextureAtlas\";\nimport { buildSectionGeometry, SectionGeometryInput, SectionGeometryPage, SectionTemplateData } from \"./SectionGeometry\";\nimport { SectionWorker } from \"./SectionWorker\";\nimport type { Intersection } from \"three\";\n\n/** Shared quad geometry and atlas data prepared for section merging. */\nexport interface SectionMeshTemplate {\n geometry: BufferGeometry;\n atlas: TextureAtlas;\n cullFaces: Uint8Array;\n /** Quads that accept a placement's biome tint, stored as zero or one. */\n biomeTint?: Uint8Array;\n occludes: boolean;\n /** Whether the model permits corner shading from neighboring full cubes. */\n ambientOcclusion?: boolean;\n layer: 0 | 1;\n}\n\n/** One block placement in a section, with its storage index and hidden-face mask. */\nexport interface SectionMeshEntry {\n index: number;\n template: SectionMeshTemplate;\n cullMask: number;\n /** Linear RGB replacing automatic biome colors on eligible quads. */\n biomeTint?: readonly [number, number, number];\n}\n\n/** Fluid cells for one section and the shared atlases of the kinds present. */\nexport interface SectionFluids {\n cells: Uint8Array;\n /** Linear RGB per section cell, indexed by (x + 16z + 256y) * 3. */\n waterTints?: Float32Array;\n water?: TextureAtlas;\n lava?: TextureAtlas;\n}\n\nconst templateCache = new WeakMap<SectionMeshTemplate, SectionTemplateData>();\nconst WATER_TINT = new Color(0x3f76e4).toArray() as [number, number, number];\n\nfunction toInput(entries: readonly SectionMeshEntry[], maxAtlasSize: number, fluids?: SectionFluids,\n lighting?: Pick<SectionGeometryInput, \"light\" | \"ambientLight\" | \"ambientOcclusion\">): { input: SectionGeometryInput; atlases: TextureAtlas[] } {\n if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError(\"Section atlas size must be a positive integer\");\n const atlases: TextureAtlas[] = [];\n const atlasIds = new Map<TextureAtlas, number>();\n const templateIds = new Map<SectionMeshTemplate, number>();\n const input: SectionGeometryInput = {\n count: entries.length, indices: new Uint16Array(entries.length), templates: new Uint16Array(entries.length),\n cullMasks: new Uint8Array(entries.length), templateData: [], atlases: [], maxAtlasSize, ...lighting\n };\n for (let i = 0; i < entries.length; i++) {\n const { index, template, cullMask, biomeTint } = entries[i];\n if (biomeTint) {\n input.biomeTints ??= new Float32Array(entries.length * 3).fill(NaN);\n input.biomeTints.set(biomeTint, i * 3);\n }\n let id = templateIds.get(template);\n if (id === undefined) {\n let atlas = atlasIds.get(template.atlas);\n if (atlas === undefined) {\n atlas = atlases.length;\n atlasIds.set(template.atlas, atlas);\n atlases.push(template.atlas);\n input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });\n }\n let data = templateCache.get(template);\n if (!data) {\n const indices = template.geometry.getIndex()!;\n const position = template.geometry.getAttribute(\"position\");\n const quads = indices.count / 6;\n if (indices.count % 6 !== 0 || position.count !== quads * 4) {\n throw new RangeError(\"Section template geometry must hold four vertices and six indices per quad\");\n }\n data = {\n quads, positions: new Float32Array(quads * 12), normals: new Float32Array(quads * 12), uvs: new Float32Array(quads * 8),\n uvBounds: new Float32Array(quads * 16), colors: new Float32Array(quads * 12), indices: new Uint16Array(quads * 6),\n cullFaces: new Uint8Array(template.cullFaces), biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : undefined, atlas: 0, layer: template.layer, ambientOcclusion: template.ambientOcclusion\n };\n const normal = template.geometry.getAttribute(\"normal\");\n const uv = template.geometry.getAttribute(\"uv\");\n const bounds = template.geometry.getAttribute(\"uvBounds\");\n const color = template.geometry.getAttribute(\"color\");\n for (let vertex = 0; vertex < quads * 4; vertex++) {\n data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);\n data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);\n data.uvs.set([uv.getX(vertex), uv.getY(vertex)], vertex * 2);\n data.uvBounds.set([bounds?.getX(vertex) ?? 0, bounds?.getY(vertex) ?? 0,\n bounds?.getZ(vertex) ?? 1, bounds?.getW(vertex) ?? 1], vertex * 4);\n data.colors.set([color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1], vertex * 3);\n }\n for (let i = 0; i < data.indices.length; i++) data.indices[i] = indices.getX(i) - 4 * Math.floor(i / 6);\n templateCache.set(template, data);\n }\n id = input.templateData.length;\n templateIds.set(template, id);\n // Atlas IDs belong to each build; cached buffers can be shared across concurrent builds.\n input.templateData.push({ ...data, atlas });\n }\n input.indices[i] = index;\n input.templates[i] = id;\n input.cullMasks[i] = cullMask;\n }\n if (fluids) {\n input.fluids = { cells: fluids.cells, waterTints: fluids.waterTints };\n for (const kind of [\"water\", \"lava\"] as const) {\n const atlas = fluids[kind];\n if (!atlas) continue;\n let id = atlasIds.get(atlas);\n if (id === undefined) {\n id = atlases.length;\n atlasIds.set(atlas, id);\n atlases.push(atlas);\n input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });\n }\n input.fluids[kind] = {\n atlas: id, still: [...atlas.positions.still, ...atlas.sizes.still],\n flow: [...atlas.positions.flow, ...atlas.sizes.flow], tint: kind === \"water\" ? WATER_TINT : [1, 1, 1]\n };\n }\n }\n return { input, atlases };\n}\n\n/** Merged terrain geometry and atlas pages for one 16×16×16 section. Owns its generated render resources. */\nexport class SectionMesh extends Group {\n\n private readonly ownedMeshes: { mesh: Mesh<BufferGeometry, Material>; texture?: Texture; unsubscribe: (() => void)[] }[] = [];\n private readonly blockIndices = new Map<Mesh, Uint16Array>();\n\n /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */\n public getBlockIndex(hit: Intersection): number | undefined {\n if (hit.faceIndex === undefined || hit.faceIndex === null) return undefined;\n return this.blockIndices.get(hit.object as Mesh)?.[Math.floor(hit.faceIndex / 2)];\n }\n\n /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */\n public static build(entries: readonly SectionMeshEntry[], maxAtlasSize = 2048, fluids?: SectionFluids,\n lighting?: Pick<SectionGeometryInput, \"light\" | \"ambientLight\" | \"ambientOcclusion\">): SectionMesh {\n const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);\n return this.fromPages(buildSectionGeometry(input), atlases);\n }\n\n /** Builds section-local meshes in a browser worker when available, with synchronous fallback. */\n public static async buildAsync(entries: readonly SectionMeshEntry[], maxAtlasSize = 2048, fluids?: SectionFluids,\n lighting?: Pick<SectionGeometryInput, \"light\" | \"ambientLight\" | \"ambientOcclusion\">): Promise<SectionMesh> {\n const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);\n const worker = SectionWorker.shared();\n const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);\n return this.fromPages(pages, atlases);\n }\n\n private static fromPages(pages: SectionGeometryPage[], atlases: TextureAtlas[]): SectionMesh {\n const section = new SectionMesh();\n for (const page of pages) {\n const canvas = createCanvas(page.width, page.height);\n const context = canvas.getContext(\"2d\") as CanvasRenderingContext2D;\n for (const { atlas, x, y } of page.placements) {\n context.drawImage(atlases[atlas].image.canvas as CanvasImageSource, x, y);\n }\n const geometry = new BufferGeometry();\n // Passing buffers keeps Three's typed attributes from copying the builder's arrays.\n geometry.setAttribute(\"position\", new Float32BufferAttribute(page.positions.buffer, 3));\n geometry.setAttribute(\"normal\", new Float32BufferAttribute(page.normals.buffer, 3));\n geometry.setAttribute(\"uv\", new Float32BufferAttribute(page.uvs.buffer, 2));\n geometry.setAttribute(\"uvBounds\", new Float32BufferAttribute(page.uvBounds.buffer, 4));\n geometry.setAttribute(\"color\", new Float32BufferAttribute(page.colors.buffer, 3));\n geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));\n geometry.computeBoundingBox();\n geometry.computeBoundingSphere();\n const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;\n const material = Materials.createShadedCanvasMaterial(canvas as HTMLCanvasElement, transparent, false, true);\n material.side = FrontSide;\n if (page.layer === 2) {\n material.side = DoubleSide;\n material.forceSinglePass = true;\n material.depthWrite = !material.transparent;\n }\n material.vertexColors = true;\n const texture = (material as ShaderMaterial).uniforms?.map?.value ?? (material as MeshBasicMaterial).map;\n const mesh = new Mesh(geometry, material);\n section.add(mesh);\n section.blockIndices.set(mesh, page.blockIndices);\n const unsubscribe: (() => void)[] = [];\n for (const { atlas: id, x, y } of page.placements) {\n const atlas = atlases[id];\n if (!atlas.hasAnimation) continue;\n unsubscribe.push(atlas.subscribe(() => {\n context.clearRect(x, y, atlas.image.width, atlas.image.height);\n context.drawImage(atlas.image.canvas as CanvasImageSource, x, y);\n texture.needsUpdate = true;\n section.traverseAncestors(parent => {\n if ((parent as MineRenderScene).isMineRenderScene) (parent as MineRenderScene).dirty = true;\n });\n }));\n }\n section.ownedMeshes.push({ mesh, texture, unsubscribe });\n }\n return section;\n }\n\n public dispose(): void {\n for (const { mesh, texture, unsubscribe } of this.ownedMeshes.splice(0)) {\n for (const stop of unsubscribe) stop();\n mesh.removeFromParent();\n mesh.geometry.dispose();\n mesh.material.dispose();\n texture?.dispose();\n }\n this.blockIndices.clear();\n this.removeFromParent();\n super.dispose();\n }\n\n}\n"],"mappings":"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","names":["i"]}
1
+ {"version":3,"sources":["../../../../src/world/SectionMesh.ts"],"sourcesContent":["import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, FrontSide, Group, Material, Mesh, MeshBasicMaterial, ShaderMaterial, Texture, Uint32BufferAttribute } from \"three\";\nimport { createCanvas } from \"../canvas/CanvasCompat\";\nimport { Materials } from \"../Materials\";\nimport type { MineRenderScene } from \"../renderer/MineRenderScene\";\nimport { TextureAtlas } from \"../texture/TextureAtlas\";\nimport { buildSectionGeometry, SectionGeometryInput, SectionGeometryPage, SectionTemplateData } from \"./SectionGeometry\";\nimport { SectionWorker } from \"./SectionWorker\";\nimport type { Intersection } from \"three\";\n\n/** Shared quad geometry and atlas data prepared for section merging. */\nexport interface SectionMeshTemplate {\n geometry: BufferGeometry;\n atlas: TextureAtlas;\n cullFaces: Uint8Array;\n /** Quads that accept a placement's biome tint, stored as zero or one. */\n biomeTint?: Uint8Array;\n occludes: boolean;\n /** Whether the model permits corner shading from neighboring full cubes. */\n ambientOcclusion?: boolean;\n layer: 0 | 1;\n}\n\n/** One block placement in a section, with its storage index and hidden-face mask. */\nexport interface SectionMeshEntry {\n index: number;\n template: SectionMeshTemplate;\n cullMask: number;\n /** Linear RGB replacing automatic biome colors on eligible quads. */\n biomeTint?: readonly [number, number, number];\n}\n\n/** Fluid cells for one section and the shared atlases of the kinds present. */\nexport interface SectionFluids {\n cells: Uint8Array;\n /** Linear RGB per section cell, indexed by (x + 16z + 256y) * 3. */\n waterTints?: Float32Array;\n water?: TextureAtlas;\n lava?: TextureAtlas;\n}\n\nconst templateCache = new WeakMap<SectionMeshTemplate, SectionTemplateData>();\nconst WATER_TINT = new Color(0x3f76e4).toArray() as [number, number, number];\n\nfunction toInput(entries: readonly SectionMeshEntry[], maxAtlasSize: number, fluids?: SectionFluids,\n lighting?: Pick<SectionGeometryInput, \"light\" | \"ambientLight\" | \"ambientOcclusion\">): { input: SectionGeometryInput; atlases: TextureAtlas[] } {\n if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError(\"Section atlas size must be a positive integer\");\n const atlases: TextureAtlas[] = [];\n const atlasIds = new Map<TextureAtlas, number>();\n const templateIds = new Map<SectionMeshTemplate, number>();\n const input: SectionGeometryInput = {\n count: entries.length, indices: new Uint16Array(entries.length), templates: new Uint16Array(entries.length),\n cullMasks: new Uint8Array(entries.length), templateData: [], atlases: [], maxAtlasSize, ...lighting\n };\n for (let i = 0; i < entries.length; i++) {\n const { index, template, cullMask, biomeTint } = entries[i];\n if (biomeTint) {\n input.biomeTints ??= new Float32Array(entries.length * 3).fill(NaN);\n input.biomeTints.set(biomeTint, i * 3);\n }\n let id = templateIds.get(template);\n if (id === undefined) {\n let atlas = atlasIds.get(template.atlas);\n if (atlas === undefined) {\n atlas = atlases.length;\n atlasIds.set(template.atlas, atlas);\n atlases.push(template.atlas);\n input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });\n }\n let data = templateCache.get(template);\n if (!data) {\n const indices = template.geometry.getIndex()!;\n const position = template.geometry.getAttribute(\"position\");\n const quads = indices.count / 6;\n if (indices.count % 6 !== 0 || position.count !== quads * 4) {\n throw new RangeError(\"Section template geometry must hold four vertices and six indices per quad\");\n }\n data = {\n quads, positions: new Float32Array(quads * 12), normals: new Float32Array(quads * 12), uvs: new Float32Array(quads * 8),\n uvBounds: new Float32Array(quads * 16), colors: new Float32Array(quads * 12), shade: new Float32Array(quads * 4), indices: new Uint16Array(quads * 6),\n cullFaces: new Uint8Array(template.cullFaces), biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : undefined, atlas: 0, layer: template.layer, ambientOcclusion: template.ambientOcclusion\n };\n const normal = template.geometry.getAttribute(\"normal\");\n const uv = template.geometry.getAttribute(\"uv\");\n const bounds = template.geometry.getAttribute(\"uvBounds\");\n const color = template.geometry.getAttribute(\"color\");\n const shade = template.geometry.getAttribute(\"shade\");\n for (let vertex = 0; vertex < quads * 4; vertex++) {\n data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);\n data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);\n data.uvs.set([uv.getX(vertex), uv.getY(vertex)], vertex * 2);\n data.uvBounds.set([bounds?.getX(vertex) ?? 0, bounds?.getY(vertex) ?? 0,\n bounds?.getZ(vertex) ?? 1, bounds?.getW(vertex) ?? 1], vertex * 4);\n data.colors.set([color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1], vertex * 3);\n data.shade![vertex] = shade?.getX(vertex) ?? 1;\n }\n for (let i = 0; i < data.indices.length; i++) data.indices[i] = indices.getX(i) - 4 * Math.floor(i / 6);\n templateCache.set(template, data);\n }\n id = input.templateData.length;\n templateIds.set(template, id);\n // Atlas IDs belong to each build; cached buffers can be shared across concurrent builds.\n input.templateData.push({ ...data, atlas });\n }\n input.indices[i] = index;\n input.templates[i] = id;\n input.cullMasks[i] = cullMask;\n }\n if (fluids) {\n input.fluids = { cells: fluids.cells, waterTints: fluids.waterTints };\n for (const kind of [\"water\", \"lava\"] as const) {\n const atlas = fluids[kind];\n if (!atlas) continue;\n let id = atlasIds.get(atlas);\n if (id === undefined) {\n id = atlases.length;\n atlasIds.set(atlas, id);\n atlases.push(atlas);\n input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });\n }\n input.fluids[kind] = {\n atlas: id, still: [...atlas.positions.still, ...atlas.sizes.still],\n flow: [...atlas.positions.flow, ...atlas.sizes.flow], tint: kind === \"water\" ? WATER_TINT : [1, 1, 1]\n };\n }\n }\n return { input, atlases };\n}\n\n/** Merged terrain geometry and atlas pages for one 16×16×16 section. Owns its generated render resources. */\nexport class SectionMesh extends Group {\n\n private readonly ownedMeshes: { mesh: Mesh<BufferGeometry, Material>; texture?: Texture; unsubscribe: (() => void)[] }[] = [];\n private readonly blockIndices = new Map<Mesh, Uint16Array>();\n\n /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */\n public getBlockIndex(hit: Intersection): number | undefined {\n if (hit.faceIndex === undefined || hit.faceIndex === null) return undefined;\n return this.blockIndices.get(hit.object as Mesh)?.[Math.floor(hit.faceIndex / 2)];\n }\n\n /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */\n public static build(entries: readonly SectionMeshEntry[], maxAtlasSize = 2048, fluids?: SectionFluids,\n lighting?: Pick<SectionGeometryInput, \"light\" | \"ambientLight\" | \"ambientOcclusion\">): SectionMesh {\n const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);\n return this.fromPages(buildSectionGeometry(input), atlases);\n }\n\n /** Builds section-local meshes in a browser worker when available, with synchronous fallback. */\n public static async buildAsync(entries: readonly SectionMeshEntry[], maxAtlasSize = 2048, fluids?: SectionFluids,\n lighting?: Pick<SectionGeometryInput, \"light\" | \"ambientLight\" | \"ambientOcclusion\">): Promise<SectionMesh> {\n const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);\n const worker = SectionWorker.shared();\n const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);\n return this.fromPages(pages, atlases);\n }\n\n private static fromPages(pages: SectionGeometryPage[], atlases: TextureAtlas[]): SectionMesh {\n const section = new SectionMesh();\n for (const page of pages) {\n const canvas = createCanvas(page.width, page.height);\n const context = canvas.getContext(\"2d\") as CanvasRenderingContext2D;\n for (const { atlas, x, y } of page.placements) {\n context.drawImage(atlases[atlas].image.canvas as CanvasImageSource, x, y);\n }\n const geometry = new BufferGeometry();\n // Passing buffers keeps Three's typed attributes from copying the builder's arrays.\n geometry.setAttribute(\"position\", new Float32BufferAttribute(page.positions.buffer, 3));\n geometry.setAttribute(\"normal\", new Float32BufferAttribute(page.normals.buffer, 3));\n geometry.setAttribute(\"uv\", new Float32BufferAttribute(page.uvs.buffer, 2));\n geometry.setAttribute(\"uvBounds\", new Float32BufferAttribute(page.uvBounds.buffer, 4));\n geometry.setAttribute(\"color\", new Float32BufferAttribute(page.colors.buffer, 3));\n geometry.setAttribute(\"shade\", new Float32BufferAttribute(page.shade.buffer, 1));\n geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));\n geometry.computeBoundingBox();\n geometry.computeBoundingSphere();\n const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;\n const material = Materials.createShadedCanvasMaterial(canvas as HTMLCanvasElement, transparent, false, true);\n material.side = FrontSide;\n if (page.layer === 2) {\n material.side = DoubleSide;\n material.forceSinglePass = true;\n material.depthWrite = !material.transparent;\n }\n material.vertexColors = true;\n const texture = (material as ShaderMaterial).uniforms?.map?.value ?? (material as MeshBasicMaterial).map;\n const mesh = new Mesh(geometry, material);\n section.add(mesh);\n section.blockIndices.set(mesh, page.blockIndices);\n const unsubscribe: (() => void)[] = [];\n for (const { atlas: id, x, y } of page.placements) {\n const atlas = atlases[id];\n if (!atlas.hasAnimation) continue;\n unsubscribe.push(atlas.subscribe(() => {\n context.clearRect(x, y, atlas.image.width, atlas.image.height);\n context.drawImage(atlas.image.canvas as CanvasImageSource, x, y);\n texture.needsUpdate = true;\n section.traverseAncestors(parent => {\n if ((parent as MineRenderScene).isMineRenderScene) (parent as MineRenderScene).dirty = true;\n });\n }));\n }\n section.ownedMeshes.push({ mesh, texture, unsubscribe });\n }\n return section;\n }\n\n public dispose(): void {\n for (const { mesh, texture, unsubscribe } of this.ownedMeshes.splice(0)) {\n for (const stop of unsubscribe) stop();\n mesh.removeFromParent();\n mesh.geometry.dispose();\n mesh.material.dispose();\n texture?.dispose();\n }\n this.blockIndices.clear();\n this.removeFromParent();\n super.dispose();\n }\n\n}\n"],"mappings":"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","names":["i"]}
@@ -26,9 +26,9 @@ function cached(map, key, load) {
26
26
  function compactQuads(geometry, keep) {
27
27
  const quads = keep.flatMap((kept, index) => kept ? [index] : []);
28
28
  const compact = new BufferGeometry();
29
- for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3 })) {
29
+ for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3, shade: 1 })) {
30
30
  const source2 = geometry.getAttribute(name);
31
- const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : void 0;
31
+ const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : name === "shade" ? [1] : void 0;
32
32
  const values = new Float32Array(quads.length * 4 * size);
33
33
  for (let q = 0; q < quads.length; q++) {
34
34
  for (let vertex = 0; vertex < 4; vertex++) {