minerender 2.1.0-alpha.133 → 2.1.0-alpha.134
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/esm/Materials.mjs +3 -2
- package/dist/browser/esm/Materials.mjs.map +1 -1
- package/dist/browser/esm/env/browser/section.worker.mjs +5 -3
- package/dist/browser/esm/env/browser/section.worker.mjs.map +1 -1
- package/dist/browser/esm/index.browser.d.mts +2 -0
- package/dist/browser/esm/model/scene/ModelObject.mjs +4 -0
- package/dist/browser/esm/model/scene/ModelObject.mjs.map +1 -1
- package/dist/browser/esm/world/SectionGeometry.mjs +5 -3
- package/dist/browser/esm/world/SectionGeometry.mjs.map +1 -1
- package/dist/browser/esm/world/SectionMesh.mjs +4 -0
- package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
- package/dist/browser/esm/world/SectionModels.mjs +2 -2
- package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +18 -7
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +18 -7
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +2 -0
- package/dist/node/index.d.ts +2 -0
- package/dist/node/index.js +18 -7
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +18 -7
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -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++) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/world/SectionModels.ts"],"sourcesContent":["import { BufferAttribute, BufferGeometry, Euler, Matrix4, Mesh, Vector3 } from \"three\";\nimport { AssetKey } from \"../assets/AssetKey\";\nimport { Models } from \"../assets/Models\";\nimport { CUBE_FACES, CUBE_FACE_OFFSETS } from \"../CubeFace\";\nimport { BlockState, BlockStateVariant } from \"../model/block/BlockState\";\nimport { BlockStateProperties } from \"../model/block/BlockStateProperties\";\nimport { BlockStateResolver } from \"../model/block/BlockStateResolver\";\nimport { BlockTints } from \"../model/block/BlockTints\";\nimport { FluidKind } from \"../model/fluid/FluidGeometry\";\nimport { BlockModel, Model, TripleArray } from \"../model/Model\";\nimport { ModelCulling } from \"../model/ModelCulling\";\nimport { ModelObject } from \"../model/scene/ModelObject\";\nimport { TextureAtlas } from \"../texture/TextureAtlas\";\nimport { UVMapper } from \"../UVMapper\";\nimport { SectionMeshTemplate } from \"./SectionMesh\";\n\ninterface PreparedVariant {\n model: Model;\n atlas: TextureAtlas;\n rotation: Euler;\n}\n\ninterface PreparedState {\n state: BlockStateProperties;\n groups: (BlockStateVariant | BlockStateVariant[])[];\n choices: Map<BlockStateVariant, PreparedVariant>;\n}\n\n// Section meshes supply the material; templates only need the existing model geometry pipeline.\nclass SectionModel extends ModelObject {\n protected applyTextures() {}\n}\n\nfunction cached<T>(map: Map<string, Promise<T>>, key: string, load: () => Promise<T>): Promise<T> {\n let value = map.get(key);\n if (!value) {\n value = load().catch(error => { map.delete(key); throw error; });\n map.set(key, value);\n }\n return value;\n}\n\nfunction compactQuads(geometry: BufferGeometry, keep: boolean[]): BufferGeometry {\n const quads = keep.flatMap((kept, index) => kept ? [index] : []);\n const compact = new BufferGeometry();\n for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3 })) {\n const source = geometry.getAttribute(name);\n const defaults = name === \"uvBounds\" ? [0, 0, 1, 1] : name === \"color\" ? [1, 1, 1] : undefined;\n const values = new Float32Array(quads.length * 4 * size);\n for (let q = 0; q < quads.length; q++) {\n for (let vertex = 0; vertex < 4; vertex++) {\n for (let component = 0; component < size; component++) {\n values[(q * 4 + vertex) * size + component] = source\n ? source.getComponent(quads[q] * 4 + vertex, component) : defaults![component];\n }\n }\n }\n compact.setAttribute(name, new BufferAttribute(values, size));\n }\n const source = geometry.getIndex()!;\n const indices: number[] = [];\n for (let q = 0; q < quads.length; q++) {\n for (let k = 0; k < 6; k++) indices.push(source.getX(quads[q] * 6 + k) - quads[q] * 4 + q * 4);\n }\n compact.setIndex(indices);\n geometry.dispose();\n return compact;\n}\n\n/** Prepares and caches model geometry and fluid atlases for merged world sections. */\nexport class SectionModels {\n private states = new WeakMap<BlockState, Map<string, Promise<PreparedState | undefined>>>();\n private models = new WeakMap<Model, Map<string, Promise<SectionMeshTemplate>>>();\n private readonly templates = new Set<SectionMeshTemplate>();\n private readonly fluidAtlases = new Map<string, Promise<TextureAtlas>>();\n\n constructor(readonly maxAtlasSize = 2048) {\n if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError(\"maxAtlasSize must be a positive integer\");\n }\n\n /** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */\n public async get(blockState: BlockState, properties: BlockStateProperties = {},\n position?: Readonly<TripleArray>, biome?: string): Promise<SectionMeshTemplate[] | undefined> {\n const biomePosition: TripleArray | undefined = position ? [...position] : undefined;\n const prepared = await this.state(blockState, properties);\n if (!prepared) return undefined;\n return Promise.all(prepared.groups.map(async group => {\n const variant = BlockStateResolver.choose(group, biomePosition);\n const choice = prepared.choices.get(variant)!;\n const tints = await BlockTints.get(blockState.key, prepared.state, choice.model, undefined,\n () => BlockTints.getBiomeColor(blockState.key, biome, biomePosition));\n return this.template(variant, choice, tints);\n }));\n }\n\n /** Resolves shared templates; dynamic biome tints are supplied on section placements instead of cached geometry. */\n public async prepareState(blockState: BlockState, properties: BlockStateProperties = {},\n biomeColor?: number | (() => Promise<number | undefined>), dynamicBiomeTint = false):\n Promise<{ pick(position?: Readonly<TripleArray>): SectionMeshTemplate[]; biomeTint?: boolean } | undefined> {\n const prepared = await this.state(blockState, properties);\n if (!prepared) return undefined;\n let color: Promise<number | undefined> | undefined;\n const resolveColor = typeof biomeColor === \"function\" ? () => color ??= biomeColor() : biomeColor;\n const templates = new Map<BlockStateVariant, SectionMeshTemplate>();\n const source = dynamicBiomeTint && await BlockTints.biomeSource(blockState.key);\n await Promise.all([...prepared.choices].map(async ([variant, choice]) => {\n const tints = await BlockTints.get(blockState.key, prepared.state, choice.model, undefined, resolveColor);\n const biomeTints = source ? await BlockTints.get(blockState.key, prepared.state, choice.model, undefined, 0xffffff) : undefined;\n templates.set(variant, await this.template(variant, choice, tints, biomeTints));\n }));\n return {\n pick: (position?: Readonly<TripleArray>) => prepared.groups.map(group => templates.get(BlockStateResolver.choose(group, position))!),\n biomeTint: source ? [...templates.values()].some(template => template.biomeTint?.some(value => value === 1)) || undefined : undefined\n };\n }\n\n private async state(blockState: BlockState, properties: BlockStateProperties): Promise<PreparedState | undefined> {\n let states = this.states.get(blockState);\n if (!states) this.states.set(blockState, states = new Map());\n const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));\n return cached(states, key, () => this.prepare(blockState, properties));\n }\n\n /** Returns the shared still/flow atlas used by per-block fluid objects. */\n public fluidAtlas(kind: FluidKind, root?: string): Promise<TextureAtlas> {\n const key = new AssetKey(\"minecraft\", kind, \"models\", \"fluid\", \"assets\", \".json\", root);\n return cached(this.fluidAtlases, key.serialize(), async () => {\n const atlas = await UVMapper.getAtlas({\n key,\n textures: { still: `minecraft:block/${kind}_still`, flow: `minecraft:block/${kind}_flow` },\n elements: []\n });\n if (!atlas) throw new Error(`Missing ${kind} fluid atlas`);\n return atlas;\n });\n }\n\n private async prepare(blockState: BlockState, properties: BlockStateProperties): Promise<PreparedState | undefined> {\n const state = { ...await BlockStateResolver.defaults(blockState), ...properties };\n const groups = BlockStateResolver.matching(blockState, state);\n if (!groups.length) return undefined;\n const prepared = new Map<BlockStateVariant, PreparedVariant>();\n for (const group of groups) {\n const choices = Array.isArray(group) ? group : [group];\n if (!choices.length) return undefined;\n for (const variant of choices) {\n if (!variant.model) return undefined;\n const modelKey = AssetKey.parse(\"models\", variant.model);\n modelKey.root = blockState.key?.root;\n const model = await Models.getMerged(modelKey);\n if (!model?.elements?.length) return undefined;\n const atlas = await UVMapper.getAtlas(model);\n const rotation = BlockStateResolver.rotation(variant);\n if (!atlas\n || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return undefined;\n prepared.set(variant, { model, atlas, rotation });\n }\n }\n return { state, groups, choices: prepared };\n }\n\n private async template(variant: BlockStateVariant, { model, atlas, rotation }: PreparedVariant,\n tints?: Record<number, number>, biomeTints?: Record<number, number>): Promise<SectionMeshTemplate> {\n let models = this.models.get(model);\n if (!models) this.models.set(model, models = new Map());\n const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints, biomeTints]);\n return cached(models, key, async () => {\n const object = new SectionModel(model, {\n instanceMeshes: false, mergeMeshes: true, tints,\n uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0)\n ? [rotation.x, rotation.y, rotation.z] : undefined\n });\n await object.init();\n let geometry = (object.children[0] as Mesh).geometry;\n geometry.applyMatrix4(new Matrix4().makeRotationFromEuler(rotation));\n object.clear();\n const keep: boolean[] = [];\n const cullFaces: number[] = [];\n const biomeTint: number[] | undefined = biomeTints ? [] : undefined;\n for (const element of atlas.model.elements!) {\n for (const face of CUBE_FACES) {\n const data = element.faces[face];\n keep.push(data !== undefined);\n if (!data) continue;\n biomeTint?.push(Number(data.tintindex !== undefined && biomeTints?.[data.tintindex] !== undefined));\n const local = CUBE_FACES.findIndex(name => name === data.cullface);\n if (local < 0) {\n cullFaces.push(0);\n continue;\n }\n const normal = new Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);\n const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) =>\n Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);\n cullFaces.push(world < 0 ? 0 : 1 << world);\n }\n }\n geometry = compactQuads(geometry, keep);\n const template: SectionMeshTemplate = {\n geometry, atlas, cullFaces: new Uint8Array(cullFaces),\n biomeTint: biomeTint?.some(Boolean) ? new Uint8Array(biomeTint) : undefined,\n occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,\n layer: atlas.hasTranslucency ? 1 : 0, ambientOcclusion: (model as BlockModel).ambientocclusion !== false\n };\n this.templates.add(template);\n return template;\n });\n }\n\n /** Disposes prepared geometry and clears this world's template caches. */\n public clear(): void {\n for (const template of this.templates) template.geometry.dispose();\n this.templates.clear();\n this.states = new WeakMap();\n this.models = new WeakMap();\n this.fluidAtlases.clear();\n }\n}\n"],"mappings":";AAAA,SAAS,iBAAiB,gBAAuB,SAAe,eAAe;AAC/E,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,YAAY,yBAAyB;AAG9C,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAG3B,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB;AAgBzB,IAAM,eAAN,cAA2B,YAAY;AAAA,EACzB,gBAAgB;AAAA,EAAC;AAC/B;AAEA,SAAS,OAAU,KAA8B,KAAa,MAAoC;AAC9F,MAAI,QAAQ,IAAI,IAAI,GAAG;AACvB,MAAI,CAAC,OAAO;AACR,YAAQ,KAAK,EAAE,MAAM,WAAS;AAAE,UAAI,OAAO,GAAG;AAAG,YAAM;AAAA,IAAO,CAAC;AAC/D,QAAI,IAAI,KAAK,KAAK;AAAA,EACtB;AACA,SAAO;AACX;AAEA,SAAS,aAAa,UAA0B,MAAiC;AAC7E,QAAM,QAAQ,KAAK,QAAQ,CAAC,MAAM,UAAU,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;AAC/D,QAAM,UAAU,IAAI,eAAe;AACnC,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,GAAG,UAAU,GAAG,OAAO,EAAE,CAAC,GAAG;AACjG,UAAMA,UAAS,SAAS,aAAa,IAAI;AACzC,UAAM,WAAW,SAAS,aAAa,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,SAAS,UAAU,CAAC,GAAG,GAAG,CAAC,IAAI;AACrF,UAAM,SAAS,IAAI,aAAa,MAAM,SAAS,IAAI,IAAI;AACvD,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACnC,eAAS,SAAS,GAAG,SAAS,GAAG,UAAU;AACvC,iBAAS,YAAY,GAAG,YAAY,MAAM,aAAa;AACnD,kBAAQ,IAAI,IAAI,UAAU,OAAO,SAAS,IAAIA,UACxCA,QAAO,aAAa,MAAM,CAAC,IAAI,IAAI,QAAQ,SAAS,IAAI,SAAU,SAAS;AAAA,QACrF;AAAA,MACJ;AAAA,IACJ;AACA,YAAQ,aAAa,MAAM,IAAI,gBAAgB,QAAQ,IAAI,CAAC;AAAA,EAChE;AACA,QAAM,SAAS,SAAS,SAAS;AACjC,QAAM,UAAoB,CAAC;AAC3B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACnC,aAAS,IAAI,GAAG,IAAI,GAAG,IAAK,SAAQ,KAAK,OAAO,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC;AAAA,EACjG;AACA,UAAQ,SAAS,OAAO;AACxB,WAAS,QAAQ;AACjB,SAAO;AACX;AAGO,IAAM,gBAAN,MAAoB;AAAA,EAMvB,YAAqB,eAAe,MAAM;AAArB;AALrB,SAAQ,SAAS,oBAAI,QAAqE;AAC1F,SAAQ,SAAS,oBAAI,QAA0D;AAC/E,SAAiB,YAAY,oBAAI,IAAyB;AAC1D,SAAiB,eAAe,oBAAI,IAAmC;AAGnE,QAAI,CAAC,OAAO,UAAU,YAAY,KAAK,eAAe,EAAG,OAAM,IAAI,WAAW,yCAAyC;AAAA,EAC3H;AAAA;AAAA,EAGA,MAAa,IAAI,YAAwB,aAAmC,CAAC,GAC5D,UAAkC,OAA4D;AAC3G,UAAM,gBAAyC,WAAW,CAAC,GAAG,QAAQ,IAAI;AAC1E,UAAM,WAAW,MAAM,KAAK,MAAM,YAAY,UAAU;AACxD,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO,QAAQ,IAAI,SAAS,OAAO,IAAI,OAAM,UAAS;AAClD,YAAM,UAAU,mBAAmB,OAAO,OAAO,aAAa;AAC9D,YAAM,SAAS,SAAS,QAAQ,IAAI,OAAO;AAC3C,YAAM,QAAQ,MAAM,WAAW;AAAA,QAAI,WAAW;AAAA,QAAK,SAAS;AAAA,QAAO,OAAO;AAAA,QAAO;AAAA,QAC7E,MAAM,WAAW,cAAc,WAAW,KAAK,OAAO,aAAa;AAAA,MAAC;AACxE,aAAO,KAAK,SAAS,SAAS,QAAQ,KAAK;AAAA,IAC/C,CAAC,CAAC;AAAA,EACN;AAAA;AAAA,EAGA,MAAa,aAAa,YAAwB,aAAmC,CAAC,GAC5D,YAA2D,mBAAmB,OACQ;AAC5G,UAAM,WAAW,MAAM,KAAK,MAAM,YAAY,UAAU;AACxD,QAAI,CAAC,SAAU,QAAO;AACtB,QAAI;AACJ,UAAM,eAAe,OAAO,eAAe,aAAa,MAAM,kBAAU,WAAW,KAAI;AACvF,UAAM,YAAY,oBAAI,IAA4C;AAClE,UAAM,SAAS,oBAAoB,MAAM,WAAW,YAAY,WAAW,GAAG;AAC9E,UAAM,QAAQ,IAAI,CAAC,GAAG,SAAS,OAAO,EAAE,IAAI,OAAO,CAAC,SAAS,MAAM,MAAM;AACrE,YAAM,QAAQ,MAAM,WAAW,IAAI,WAAW,KAAK,SAAS,OAAO,OAAO,OAAO,QAAW,YAAY;AACxG,YAAM,aAAa,SAAS,MAAM,WAAW,IAAI,WAAW,KAAK,SAAS,OAAO,OAAO,OAAO,QAAW,QAAQ,IAAI;AACtH,gBAAU,IAAI,SAAS,MAAM,KAAK,SAAS,SAAS,QAAQ,OAAO,UAAU,CAAC;AAAA,IAClF,CAAC,CAAC;AACF,WAAO;AAAA,MACH,MAAM,CAAC,aAAqC,SAAS,OAAO,IAAI,WAAS,UAAU,IAAI,mBAAmB,OAAO,OAAO,QAAQ,CAAC,CAAE;AAAA,MACnI,WAAW,SAAS,CAAC,GAAG,UAAU,OAAO,CAAC,EAAE,KAAK,cAAY,SAAS,WAAW,KAAK,WAAS,UAAU,CAAC,CAAC,KAAK,SAAY;AAAA,IAChI;AAAA,EACJ;AAAA,EAEA,MAAc,MAAM,YAAwB,YAAsE;AAC9G,QAAI,SAAS,KAAK,OAAO,IAAI,UAAU;AACvC,QAAI,CAAC,OAAQ,MAAK,OAAO,IAAI,YAAY,SAAS,oBAAI,IAAI,CAAC;AAC3D,UAAM,MAAM,KAAK,UAAU,OAAO,QAAQ,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;AAC5F,WAAO,OAAO,QAAQ,KAAK,MAAM,KAAK,QAAQ,YAAY,UAAU,CAAC;AAAA,EACzE;AAAA;AAAA,EAGO,WAAW,MAAiB,MAAsC;AACrE,UAAM,MAAM,IAAI,SAAS,aAAa,MAAM,UAAU,SAAS,UAAU,SAAS,IAAI;AACtF,WAAO,OAAO,KAAK,cAAc,IAAI,UAAU,GAAG,YAAY;AAC1D,YAAM,QAAQ,MAAM,SAAS,SAAS;AAAA,QAClC;AAAA,QACA,UAAU,EAAE,OAAO,mBAAmB,IAAI,UAAU,MAAM,mBAAmB,IAAI,QAAQ;AAAA,QACzF,UAAU,CAAC;AAAA,MACf,CAAC;AACD,UAAI,CAAC,MAAO,OAAM,IAAI,MAAM,WAAW,IAAI,cAAc;AACzD,aAAO;AAAA,IACX,CAAC;AAAA,EACL;AAAA,EAEA,MAAc,QAAQ,YAAwB,YAAsE;AAChH,UAAM,QAAQ,EAAE,GAAG,MAAM,mBAAmB,SAAS,UAAU,GAAG,GAAG,WAAW;AAChF,UAAM,SAAS,mBAAmB,SAAS,YAAY,KAAK;AAC5D,QAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,UAAM,WAAW,oBAAI,IAAwC;AAC7D,eAAW,SAAS,QAAQ;AACxB,YAAM,UAAU,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACrD,UAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,iBAAW,WAAW,SAAS;AAC3B,YAAI,CAAC,QAAQ,MAAO,QAAO;AAC3B,cAAM,WAAW,SAAS,MAAM,UAAU,QAAQ,KAAK;AACvD,iBAAS,OAAO,WAAW,KAAK;AAChC,cAAM,QAAQ,MAAM,OAAO,UAAU,QAAQ;AAC7C,YAAI,CAAC,OAAO,UAAU,OAAQ,QAAO;AACrC,cAAM,QAAQ,MAAM,SAAS,SAAS,KAAK;AAC3C,cAAM,WAAW,mBAAmB,SAAS,OAAO;AACpD,YAAI,CAAC,SACE,MAAM,MAAM,QAAQ,KAAK,gBAAgB,MAAM,MAAM,SAAS,KAAK,aAAc,QAAO;AAC/F,iBAAS,IAAI,SAAS,EAAE,OAAO,OAAO,SAAS,CAAC;AAAA,MACpD;AAAA,IACJ;AACA,WAAO,EAAE,OAAO,QAAQ,SAAS,SAAS;AAAA,EAC9C;AAAA,EAEA,MAAc,SAAS,SAA4B,EAAE,OAAO,OAAO,SAAS,GACrD,OAAgC,YAAmE;AACtH,QAAI,SAAS,KAAK,OAAO,IAAI,KAAK;AAClC,QAAI,CAAC,OAAQ,MAAK,OAAO,IAAI,OAAO,SAAS,oBAAI,IAAI,CAAC;AACtD,UAAM,MAAM,KAAK,UAAU,CAAC,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,QAAQ,OAAO,UAAU,CAAC;AAClG,WAAO,OAAO,QAAQ,KAAK,YAAY;AACnC,YAAM,SAAS,IAAI,aAAa,OAAO;AAAA,QACnC,gBAAgB;AAAA,QAAO,aAAa;AAAA,QAAM;AAAA,QAC1C,gBAAgB,QAAQ,WAAW,SAAS,MAAM,KAAK,SAAS,MAAM,KAChE,CAAC,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC,IAAI;AAAA,MACjD,CAAC;AACD,YAAM,OAAO,KAAK;AAClB,UAAI,WAAY,OAAO,SAAS,CAAC,EAAW;AAC5C,eAAS,aAAa,IAAI,QAAQ,EAAE,sBAAsB,QAAQ,CAAC;AACnE,aAAO,MAAM;AACb,YAAM,OAAkB,CAAC;AACzB,YAAM,YAAsB,CAAC;AAC7B,YAAM,YAAkC,aAAa,CAAC,IAAI;AAC1D,iBAAW,WAAW,MAAM,MAAM,UAAW;AACzC,mBAAW,QAAQ,YAAY;AAC3B,gBAAM,OAAO,QAAQ,MAAM,IAAI;AAC/B,eAAK,KAAK,SAAS,MAAS;AAC5B,cAAI,CAAC,KAAM;AACX,qBAAW,KAAK,OAAO,KAAK,cAAc,UAAa,aAAa,KAAK,SAAS,MAAM,MAAS,CAAC;AAClG,gBAAM,QAAQ,WAAW,UAAU,UAAQ,SAAS,KAAK,QAAQ;AACjE,cAAI,QAAQ,GAAG;AACX,sBAAU,KAAK,CAAC;AAChB;AAAA,UACJ;AACA,gBAAM,SAAS,IAAI,QAAQ,GAAG,kBAAkB,KAAK,CAAC,EAAE,WAAW,QAAQ;AAC3E,gBAAM,QAAQ,kBAAkB,UAAU,CAAC,CAAC,GAAG,GAAG,CAAC,MAC/C,KAAK,IAAI,OAAO,IAAI,CAAC,IAAI,QAAQ,KAAK,IAAI,OAAO,IAAI,CAAC,IAAI,QAAQ,KAAK,IAAI,OAAO,IAAI,CAAC,IAAI,IAAI;AACnG,oBAAU,KAAK,QAAQ,IAAI,IAAI,KAAK,KAAK;AAAA,QAC7C;AAAA,MACJ;AACA,iBAAW,aAAa,UAAU,IAAI;AACtC,YAAM,WAAgC;AAAA,QAClC;AAAA,QAAU;AAAA,QAAO,WAAW,IAAI,WAAW,SAAS;AAAA,QACpD,WAAW,WAAW,KAAK,OAAO,IAAI,IAAI,WAAW,SAAS,IAAI;AAAA,QAClE,UAAU,aAAa,iBAAiB,KAAK,KAAK,aAAa,YAAY,IAAI,QAAQ,MAAM;AAAA,QAC7F,OAAO,MAAM,kBAAkB,IAAI;AAAA,QAAG,kBAAmB,MAAqB,qBAAqB;AAAA,MACvG;AACA,WAAK,UAAU,IAAI,QAAQ;AAC3B,aAAO;AAAA,IACX,CAAC;AAAA,EACL;AAAA;AAAA,EAGO,QAAc;AACjB,eAAW,YAAY,KAAK,UAAW,UAAS,SAAS,QAAQ;AACjE,SAAK,UAAU,MAAM;AACrB,SAAK,SAAS,oBAAI,QAAQ;AAC1B,SAAK,SAAS,oBAAI,QAAQ;AAC1B,SAAK,aAAa,MAAM;AAAA,EAC5B;AACJ;","names":["source"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/world/SectionModels.ts"],"sourcesContent":["import { BufferAttribute, BufferGeometry, Euler, Matrix4, Mesh, Vector3 } from \"three\";\nimport { AssetKey } from \"../assets/AssetKey\";\nimport { Models } from \"../assets/Models\";\nimport { CUBE_FACES, CUBE_FACE_OFFSETS } from \"../CubeFace\";\nimport { BlockState, BlockStateVariant } from \"../model/block/BlockState\";\nimport { BlockStateProperties } from \"../model/block/BlockStateProperties\";\nimport { BlockStateResolver } from \"../model/block/BlockStateResolver\";\nimport { BlockTints } from \"../model/block/BlockTints\";\nimport { FluidKind } from \"../model/fluid/FluidGeometry\";\nimport { BlockModel, Model, TripleArray } from \"../model/Model\";\nimport { ModelCulling } from \"../model/ModelCulling\";\nimport { ModelObject } from \"../model/scene/ModelObject\";\nimport { TextureAtlas } from \"../texture/TextureAtlas\";\nimport { UVMapper } from \"../UVMapper\";\nimport { SectionMeshTemplate } from \"./SectionMesh\";\n\ninterface PreparedVariant {\n model: Model;\n atlas: TextureAtlas;\n rotation: Euler;\n}\n\ninterface PreparedState {\n state: BlockStateProperties;\n groups: (BlockStateVariant | BlockStateVariant[])[];\n choices: Map<BlockStateVariant, PreparedVariant>;\n}\n\n// Section meshes supply the material; templates only need the existing model geometry pipeline.\nclass SectionModel extends ModelObject {\n protected applyTextures() {}\n}\n\nfunction cached<T>(map: Map<string, Promise<T>>, key: string, load: () => Promise<T>): Promise<T> {\n let value = map.get(key);\n if (!value) {\n value = load().catch(error => { map.delete(key); throw error; });\n map.set(key, value);\n }\n return value;\n}\n\nfunction compactQuads(geometry: BufferGeometry, keep: boolean[]): BufferGeometry {\n const quads = keep.flatMap((kept, index) => kept ? [index] : []);\n const compact = new BufferGeometry();\n for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3, shade: 1 })) {\n const source = geometry.getAttribute(name);\n const defaults = name === \"uvBounds\" ? [0, 0, 1, 1] : name === \"color\" ? [1, 1, 1] : name === \"shade\" ? [1] : undefined;\n const values = new Float32Array(quads.length * 4 * size);\n for (let q = 0; q < quads.length; q++) {\n for (let vertex = 0; vertex < 4; vertex++) {\n for (let component = 0; component < size; component++) {\n values[(q * 4 + vertex) * size + component] = source\n ? source.getComponent(quads[q] * 4 + vertex, component) : defaults![component];\n }\n }\n }\n compact.setAttribute(name, new BufferAttribute(values, size));\n }\n const source = geometry.getIndex()!;\n const indices: number[] = [];\n for (let q = 0; q < quads.length; q++) {\n for (let k = 0; k < 6; k++) indices.push(source.getX(quads[q] * 6 + k) - quads[q] * 4 + q * 4);\n }\n compact.setIndex(indices);\n geometry.dispose();\n return compact;\n}\n\n/** Prepares and caches model geometry and fluid atlases for merged world sections. */\nexport class SectionModels {\n private states = new WeakMap<BlockState, Map<string, Promise<PreparedState | undefined>>>();\n private models = new WeakMap<Model, Map<string, Promise<SectionMeshTemplate>>>();\n private readonly templates = new Set<SectionMeshTemplate>();\n private readonly fluidAtlases = new Map<string, Promise<TextureAtlas>>();\n\n constructor(readonly maxAtlasSize = 2048) {\n if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError(\"maxAtlasSize must be a positive integer\");\n }\n\n /** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */\n public async get(blockState: BlockState, properties: BlockStateProperties = {},\n position?: Readonly<TripleArray>, biome?: string): Promise<SectionMeshTemplate[] | undefined> {\n const biomePosition: TripleArray | undefined = position ? [...position] : undefined;\n const prepared = await this.state(blockState, properties);\n if (!prepared) return undefined;\n return Promise.all(prepared.groups.map(async group => {\n const variant = BlockStateResolver.choose(group, biomePosition);\n const choice = prepared.choices.get(variant)!;\n const tints = await BlockTints.get(blockState.key, prepared.state, choice.model, undefined,\n () => BlockTints.getBiomeColor(blockState.key, biome, biomePosition));\n return this.template(variant, choice, tints);\n }));\n }\n\n /** Resolves shared templates; dynamic biome tints are supplied on section placements instead of cached geometry. */\n public async prepareState(blockState: BlockState, properties: BlockStateProperties = {},\n biomeColor?: number | (() => Promise<number | undefined>), dynamicBiomeTint = false):\n Promise<{ pick(position?: Readonly<TripleArray>): SectionMeshTemplate[]; biomeTint?: boolean } | undefined> {\n const prepared = await this.state(blockState, properties);\n if (!prepared) return undefined;\n let color: Promise<number | undefined> | undefined;\n const resolveColor = typeof biomeColor === \"function\" ? () => color ??= biomeColor() : biomeColor;\n const templates = new Map<BlockStateVariant, SectionMeshTemplate>();\n const source = dynamicBiomeTint && await BlockTints.biomeSource(blockState.key);\n await Promise.all([...prepared.choices].map(async ([variant, choice]) => {\n const tints = await BlockTints.get(blockState.key, prepared.state, choice.model, undefined, resolveColor);\n const biomeTints = source ? await BlockTints.get(blockState.key, prepared.state, choice.model, undefined, 0xffffff) : undefined;\n templates.set(variant, await this.template(variant, choice, tints, biomeTints));\n }));\n return {\n pick: (position?: Readonly<TripleArray>) => prepared.groups.map(group => templates.get(BlockStateResolver.choose(group, position))!),\n biomeTint: source ? [...templates.values()].some(template => template.biomeTint?.some(value => value === 1)) || undefined : undefined\n };\n }\n\n private async state(blockState: BlockState, properties: BlockStateProperties): Promise<PreparedState | undefined> {\n let states = this.states.get(blockState);\n if (!states) this.states.set(blockState, states = new Map());\n const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));\n return cached(states, key, () => this.prepare(blockState, properties));\n }\n\n /** Returns the shared still/flow atlas used by per-block fluid objects. */\n public fluidAtlas(kind: FluidKind, root?: string): Promise<TextureAtlas> {\n const key = new AssetKey(\"minecraft\", kind, \"models\", \"fluid\", \"assets\", \".json\", root);\n return cached(this.fluidAtlases, key.serialize(), async () => {\n const atlas = await UVMapper.getAtlas({\n key,\n textures: { still: `minecraft:block/${kind}_still`, flow: `minecraft:block/${kind}_flow` },\n elements: []\n });\n if (!atlas) throw new Error(`Missing ${kind} fluid atlas`);\n return atlas;\n });\n }\n\n private async prepare(blockState: BlockState, properties: BlockStateProperties): Promise<PreparedState | undefined> {\n const state = { ...await BlockStateResolver.defaults(blockState), ...properties };\n const groups = BlockStateResolver.matching(blockState, state);\n if (!groups.length) return undefined;\n const prepared = new Map<BlockStateVariant, PreparedVariant>();\n for (const group of groups) {\n const choices = Array.isArray(group) ? group : [group];\n if (!choices.length) return undefined;\n for (const variant of choices) {\n if (!variant.model) return undefined;\n const modelKey = AssetKey.parse(\"models\", variant.model);\n modelKey.root = blockState.key?.root;\n const model = await Models.getMerged(modelKey);\n if (!model?.elements?.length) return undefined;\n const atlas = await UVMapper.getAtlas(model);\n const rotation = BlockStateResolver.rotation(variant);\n if (!atlas\n || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return undefined;\n prepared.set(variant, { model, atlas, rotation });\n }\n }\n return { state, groups, choices: prepared };\n }\n\n private async template(variant: BlockStateVariant, { model, atlas, rotation }: PreparedVariant,\n tints?: Record<number, number>, biomeTints?: Record<number, number>): Promise<SectionMeshTemplate> {\n let models = this.models.get(model);\n if (!models) this.models.set(model, models = new Map());\n const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints, biomeTints]);\n return cached(models, key, async () => {\n const object = new SectionModel(model, {\n instanceMeshes: false, mergeMeshes: true, tints,\n uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0)\n ? [rotation.x, rotation.y, rotation.z] : undefined\n });\n await object.init();\n let geometry = (object.children[0] as Mesh).geometry;\n geometry.applyMatrix4(new Matrix4().makeRotationFromEuler(rotation));\n object.clear();\n const keep: boolean[] = [];\n const cullFaces: number[] = [];\n const biomeTint: number[] | undefined = biomeTints ? [] : undefined;\n for (const element of atlas.model.elements!) {\n for (const face of CUBE_FACES) {\n const data = element.faces[face];\n keep.push(data !== undefined);\n if (!data) continue;\n biomeTint?.push(Number(data.tintindex !== undefined && biomeTints?.[data.tintindex] !== undefined));\n const local = CUBE_FACES.findIndex(name => name === data.cullface);\n if (local < 0) {\n cullFaces.push(0);\n continue;\n }\n const normal = new Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);\n const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) =>\n Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);\n cullFaces.push(world < 0 ? 0 : 1 << world);\n }\n }\n geometry = compactQuads(geometry, keep);\n const template: SectionMeshTemplate = {\n geometry, atlas, cullFaces: new Uint8Array(cullFaces),\n biomeTint: biomeTint?.some(Boolean) ? new Uint8Array(biomeTint) : undefined,\n occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,\n layer: atlas.hasTranslucency ? 1 : 0, ambientOcclusion: (model as BlockModel).ambientocclusion !== false\n };\n this.templates.add(template);\n return template;\n });\n }\n\n /** Disposes prepared geometry and clears this world's template caches. */\n public clear(): void {\n for (const template of this.templates) template.geometry.dispose();\n this.templates.clear();\n this.states = new WeakMap();\n this.models = new WeakMap();\n this.fluidAtlases.clear();\n }\n}\n"],"mappings":"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","names":["source"]}
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -3830,6 +3830,7 @@ interface SectionTemplateData {
|
|
|
3830
3830
|
uvs: Float32Array;
|
|
3831
3831
|
uvBounds: Float32Array;
|
|
3832
3832
|
colors: Float32Array;
|
|
3833
|
+
shade?: Float32Array;
|
|
3833
3834
|
indices: Uint16Array;
|
|
3834
3835
|
cullFaces: Uint8Array;
|
|
3835
3836
|
biomeTint?: Uint8Array;
|
|
@@ -3893,6 +3894,7 @@ interface SectionGeometryPage {
|
|
|
3893
3894
|
uvs: Float32Array;
|
|
3894
3895
|
uvBounds: Float32Array;
|
|
3895
3896
|
colors: Float32Array;
|
|
3897
|
+
shade: Float32Array;
|
|
3896
3898
|
indices: Uint32Array;
|
|
3897
3899
|
/** Owning section cell for each quad; each quad contributes two consecutive triangles. */
|
|
3898
3900
|
blockIndices: Uint16Array;
|
package/dist/browser/index.js
CHANGED
|
@@ -1057,6 +1057,7 @@ var init_Materials = __esm({
|
|
|
1057
1057
|
static createShadedCanvasMaterial(canvas, transparent = false, shade = false, boundUvs = false) {
|
|
1058
1058
|
const vertShader = `
|
|
1059
1059
|
uniform bool SHADE;
|
|
1060
|
+
attribute float shade;
|
|
1060
1061
|
|
|
1061
1062
|
// Keep MSAA edge pixels from sampling outside the face's atlas region.
|
|
1062
1063
|
#if __VERSION__ >= 300
|
|
@@ -1079,7 +1080,7 @@ var init_Materials = __esm({
|
|
|
1079
1080
|
void main()
|
|
1080
1081
|
{
|
|
1081
1082
|
|
|
1082
|
-
if (SHADE) {
|
|
1083
|
+
if (SHADE && shade > 0.5) {
|
|
1083
1084
|
|
|
1084
1085
|
#ifdef USE_INSTANCING
|
|
1085
1086
|
vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
|
|
@@ -1188,7 +1189,7 @@ var init_Materials = __esm({
|
|
|
1188
1189
|
side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
|
|
1189
1190
|
alphaTest: 0.5
|
|
1190
1191
|
});
|
|
1191
|
-
Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
|
|
1192
|
+
Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });
|
|
1192
1193
|
return material;
|
|
1193
1194
|
} catch (e) {
|
|
1194
1195
|
console.warn(e);
|
|
@@ -10092,6 +10093,10 @@ var init_ModelObject = __esm({
|
|
|
10092
10093
|
this.atlas.model.elements?.forEach((el) => {
|
|
10093
10094
|
const elGeo = this._getBoxGeometryFromElement(el).clone();
|
|
10094
10095
|
this.geometries.add(elGeo);
|
|
10096
|
+
elGeo.setAttribute("shade", new import_three27.BufferAttribute(
|
|
10097
|
+
new Float32Array(elGeo.getAttribute("position").count).fill(!this.originalModel.itemId && el.shade === false ? 0 : 1),
|
|
10098
|
+
1
|
|
10099
|
+
));
|
|
10095
10100
|
if (this.options.cullMask) {
|
|
10096
10101
|
const indices = Array.from(elGeo.getIndex().array);
|
|
10097
10102
|
elGeo.setIndex(indices.filter((_, index) => {
|
|
@@ -17964,9 +17969,9 @@ function cached(map, key, load) {
|
|
|
17964
17969
|
function compactQuads(geometry, keep) {
|
|
17965
17970
|
const quads = keep.flatMap((kept, index) => kept ? [index] : []);
|
|
17966
17971
|
const compact = new import_three41.BufferGeometry();
|
|
17967
|
-
for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3 })) {
|
|
17972
|
+
for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3, shade: 1 })) {
|
|
17968
17973
|
const source2 = geometry.getAttribute(name);
|
|
17969
|
-
const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : void 0;
|
|
17974
|
+
const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : name === "shade" ? [1] : void 0;
|
|
17970
17975
|
const values = new Float32Array(quads.length * 4 * size);
|
|
17971
17976
|
for (let q = 0; q < quads.length; q++) {
|
|
17972
17977
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
@@ -19232,7 +19237,7 @@ function buildSectionGeometry(input) {
|
|
|
19232
19237
|
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
19233
19238
|
for (const template of templateData) {
|
|
19234
19239
|
const { quads } = template;
|
|
19235
|
-
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) {
|
|
19240
|
+
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) {
|
|
19236
19241
|
throw new RangeError("Section template arrays do not match its quad count");
|
|
19237
19242
|
}
|
|
19238
19243
|
}
|
|
@@ -19323,6 +19328,7 @@ function buildSectionGeometry(input) {
|
|
|
19323
19328
|
}
|
|
19324
19329
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
19325
19330
|
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
19331
|
+
const shade = new Float32Array(faces * 4).fill(1);
|
|
19326
19332
|
const outputIndices = new Uint32Array(faces * 6);
|
|
19327
19333
|
const blockIndices = new Uint16Array(faces);
|
|
19328
19334
|
let vertex = 0, indexOffset = 0;
|
|
@@ -19352,6 +19358,7 @@ function buildSectionGeometry(input) {
|
|
|
19352
19358
|
normals[vertex * 3] = template.normals[source * 3];
|
|
19353
19359
|
normals[vertex * 3 + 1] = template.normals[source * 3 + 1];
|
|
19354
19360
|
normals[vertex * 3 + 2] = template.normals[source * 3 + 2];
|
|
19361
|
+
shade[vertex] = template.shade?.[source] ?? 1;
|
|
19355
19362
|
uvs[vertex * 2] = mapU(template.uvs[source * 2]);
|
|
19356
19363
|
uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
|
|
19357
19364
|
uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);
|
|
@@ -19404,11 +19411,11 @@ function buildSectionGeometry(input) {
|
|
|
19404
19411
|
indexOffset += 6;
|
|
19405
19412
|
}
|
|
19406
19413
|
}
|
|
19407
|
-
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
|
|
19414
|
+
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, shade, indices: outputIndices, blockIndices };
|
|
19408
19415
|
});
|
|
19409
19416
|
}
|
|
19410
19417
|
function sectionGeometryTransferables(pages) {
|
|
19411
|
-
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]);
|
|
19418
|
+
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]);
|
|
19412
19419
|
}
|
|
19413
19420
|
|
|
19414
19421
|
// src/world/SectionWorker.ts
|
|
@@ -19511,6 +19518,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19511
19518
|
uvs: new Float32Array(quads * 8),
|
|
19512
19519
|
uvBounds: new Float32Array(quads * 16),
|
|
19513
19520
|
colors: new Float32Array(quads * 12),
|
|
19521
|
+
shade: new Float32Array(quads * 4),
|
|
19514
19522
|
indices: new Uint16Array(quads * 6),
|
|
19515
19523
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
19516
19524
|
biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
|
|
@@ -19522,6 +19530,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19522
19530
|
const uv = template.geometry.getAttribute("uv");
|
|
19523
19531
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
19524
19532
|
const color2 = template.geometry.getAttribute("color");
|
|
19533
|
+
const shade = template.geometry.getAttribute("shade");
|
|
19525
19534
|
for (let vertex = 0; vertex < quads * 4; vertex++) {
|
|
19526
19535
|
data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
|
|
19527
19536
|
data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
|
|
@@ -19533,6 +19542,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19533
19542
|
bounds?.getW(vertex) ?? 1
|
|
19534
19543
|
], vertex * 4);
|
|
19535
19544
|
data.colors.set([color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1], vertex * 3);
|
|
19545
|
+
data.shade[vertex] = shade?.getX(vertex) ?? 1;
|
|
19536
19546
|
}
|
|
19537
19547
|
for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - 4 * Math.floor(i2 / 6);
|
|
19538
19548
|
templateCache.set(template, data);
|
|
@@ -19604,6 +19614,7 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
|
|
|
19604
19614
|
geometry.setAttribute("uv", new import_three46.Float32BufferAttribute(page.uvs.buffer, 2));
|
|
19605
19615
|
geometry.setAttribute("uvBounds", new import_three46.Float32BufferAttribute(page.uvBounds.buffer, 4));
|
|
19606
19616
|
geometry.setAttribute("color", new import_three46.Float32BufferAttribute(page.colors.buffer, 3));
|
|
19617
|
+
geometry.setAttribute("shade", new import_three46.Float32BufferAttribute(page.shade.buffer, 1));
|
|
19607
19618
|
geometry.setIndex(new import_three46.Uint32BufferAttribute(page.indices.buffer, 1));
|
|
19608
19619
|
geometry.computeBoundingBox();
|
|
19609
19620
|
geometry.computeBoundingSphere();
|