minerender 2.1.0-beta.5 → 2.1.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/esm/Materials.mjs +3 -2
- package/dist/browser/esm/Materials.mjs.map +1 -1
- package/dist/browser/esm/assets/Fonts.mjs +31 -4
- package/dist/browser/esm/assets/Fonts.mjs.map +1 -1
- package/dist/browser/esm/assets/_fonts/Unihex.mjs +166 -0
- package/dist/browser/esm/assets/_fonts/Unihex.mjs.map +1 -0
- package/dist/browser/esm/assets/source/HostedAssetSource.mjs +12 -1
- package/dist/browser/esm/assets/source/HostedAssetSource.mjs.map +1 -1
- package/dist/browser/esm/assets/source/parser/AssetParsers.mjs +1 -0
- package/dist/browser/esm/assets/source/parser/AssetParsers.mjs.map +1 -1
- package/dist/browser/esm/cache/Caching.mjs +2 -0
- package/dist/browser/esm/cache/Caching.mjs.map +1 -1
- package/dist/browser/esm/entity/scene/EntityAnimationPlayer.mjs +62 -11
- package/dist/browser/esm/entity/scene/EntityAnimationPlayer.mjs.map +1 -1
- package/dist/browser/esm/entity/scene/EntityObject.mjs +53 -20
- package/dist/browser/esm/entity/scene/EntityObject.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/gui/GuiText.mjs +4 -3
- package/dist/browser/esm/gui/GuiText.mjs.map +1 -1
- package/dist/browser/esm/index.browser.d.mts +52 -10
- 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/util/model.mjs +7 -7
- package/dist/browser/esm/util/model.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 +52 -10
- package/dist/browser/index.js +382 -73
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +425 -73
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +52 -10
- package/dist/node/index.d.ts +52 -10
- package/dist/node/index.js +387 -73
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +386 -73
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.mjs
CHANGED
|
@@ -309,6 +309,9 @@ var init_Caching = __esm({
|
|
|
309
309
|
static {
|
|
310
310
|
this.blockEntityIndexCache = _Caching.createAssetCache();
|
|
311
311
|
}
|
|
312
|
+
static {
|
|
313
|
+
this.unihexCache = _Caching.createAssetCache();
|
|
314
|
+
}
|
|
312
315
|
static {
|
|
313
316
|
this.fontCache = _Caching.createAssetCache();
|
|
314
317
|
}
|
|
@@ -351,6 +354,7 @@ var init_Caching = __esm({
|
|
|
351
354
|
this.entityAnimationCache,
|
|
352
355
|
this.blockEntityIndexCache,
|
|
353
356
|
this.fontCache,
|
|
357
|
+
this.unihexCache,
|
|
354
358
|
this.bannerPatternCache,
|
|
355
359
|
this.mineRenderDataCache,
|
|
356
360
|
this.usernameUuidCache,
|
|
@@ -1112,6 +1116,7 @@ var init_Materials = __esm({
|
|
|
1112
1116
|
static createShadedCanvasMaterial(canvas, transparent = false, shade = false, boundUvs = false) {
|
|
1113
1117
|
const vertShader = `
|
|
1114
1118
|
uniform bool SHADE;
|
|
1119
|
+
attribute float shade;
|
|
1115
1120
|
|
|
1116
1121
|
// Keep MSAA edge pixels from sampling outside the face's atlas region.
|
|
1117
1122
|
#if __VERSION__ >= 300
|
|
@@ -1134,7 +1139,7 @@ var init_Materials = __esm({
|
|
|
1134
1139
|
void main()
|
|
1135
1140
|
{
|
|
1136
1141
|
|
|
1137
|
-
if (SHADE) {
|
|
1142
|
+
if (SHADE && shade > 0.5) {
|
|
1138
1143
|
|
|
1139
1144
|
#ifdef USE_INSTANCING
|
|
1140
1145
|
vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
|
|
@@ -1243,7 +1248,7 @@ var init_Materials = __esm({
|
|
|
1243
1248
|
side: transparent ? DoubleSide : FrontSide,
|
|
1244
1249
|
alphaTest: 0.5
|
|
1245
1250
|
});
|
|
1246
|
-
Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
|
|
1251
|
+
Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });
|
|
1247
1252
|
return material;
|
|
1248
1253
|
} catch (e) {
|
|
1249
1254
|
console.warn(e);
|
|
@@ -1408,6 +1413,7 @@ var init_AssetParsers = __esm({
|
|
|
1408
1413
|
AssetParser2["IMAGE"] = "image";
|
|
1409
1414
|
AssetParser2["LIST"] = "list";
|
|
1410
1415
|
AssetParser2["JSON"] = "json";
|
|
1416
|
+
AssetParser2["BINARY"] = "binary";
|
|
1411
1417
|
return AssetParser2;
|
|
1412
1418
|
})(AssetParser || {});
|
|
1413
1419
|
}
|
|
@@ -2691,13 +2697,13 @@ function applyElementRotation(rotation, geometry) {
|
|
|
2691
2697
|
break;
|
|
2692
2698
|
}
|
|
2693
2699
|
if (rotation.rescale) {
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2700
|
+
const angle = toRadians(rotation.angle);
|
|
2701
|
+
const s = 1 / Math.max(Math.abs(Math.cos(angle)), Math.abs(Math.sin(angle)));
|
|
2702
|
+
geometry.scale(
|
|
2703
|
+
rotation.axis === "x" /* X */ ? 1 : s,
|
|
2704
|
+
rotation.axis === "y" /* Y */ ? 1 : s,
|
|
2705
|
+
rotation.axis === "z" /* Z */ ? 1 : s
|
|
2706
|
+
);
|
|
2701
2707
|
}
|
|
2702
2708
|
geometry.translate(origin.x, origin.y, origin.z);
|
|
2703
2709
|
}
|
|
@@ -2878,7 +2884,7 @@ var init_parser = __esm({
|
|
|
2878
2884
|
});
|
|
2879
2885
|
|
|
2880
2886
|
// src/assets/source/HostedAssetSource.ts
|
|
2881
|
-
var p3, DEFAULT_OPTIONS, HostedAssetSource;
|
|
2887
|
+
var BINARY_TIMEOUT, p3, DEFAULT_OPTIONS, HostedAssetSource;
|
|
2882
2888
|
var init_HostedAssetSource = __esm({
|
|
2883
2889
|
"src/assets/source/HostedAssetSource.ts"() {
|
|
2884
2890
|
init_AssetSource();
|
|
@@ -2891,6 +2897,7 @@ var init_HostedAssetSource = __esm({
|
|
|
2891
2897
|
init_AssetLoader();
|
|
2892
2898
|
init_parser();
|
|
2893
2899
|
init_merge();
|
|
2900
|
+
BINARY_TIMEOUT = 6e4;
|
|
2894
2901
|
p3 = prefix("HostedAssetSource");
|
|
2895
2902
|
DEFAULT_OPTIONS = {
|
|
2896
2903
|
retryDefaults: true
|
|
@@ -2961,6 +2968,17 @@ var init_HostedAssetSource = __esm({
|
|
|
2961
2968
|
}
|
|
2962
2969
|
};
|
|
2963
2970
|
}
|
|
2971
|
+
static {
|
|
2972
|
+
this.BINARY = {
|
|
2973
|
+
config(request) {
|
|
2974
|
+
request.timeout = BINARY_TIMEOUT;
|
|
2975
|
+
request.responseType = "arraybuffer";
|
|
2976
|
+
},
|
|
2977
|
+
parse(response) {
|
|
2978
|
+
return { data: new Uint8Array(response.data) };
|
|
2979
|
+
}
|
|
2980
|
+
};
|
|
2981
|
+
}
|
|
2964
2982
|
static {
|
|
2965
2983
|
this.PARSER_MAP = /* @__PURE__ */ new Map([
|
|
2966
2984
|
["model" /* MODEL */, _HostedAssetSource.MODEL],
|
|
@@ -2969,7 +2987,8 @@ var init_HostedAssetSource = __esm({
|
|
|
2969
2987
|
["nbt" /* NBT */, _HostedAssetSource.NBT],
|
|
2970
2988
|
["image" /* IMAGE */, _HostedAssetSource.IMAGE],
|
|
2971
2989
|
["list" /* LIST */, _HostedAssetSource.LIST],
|
|
2972
|
-
["json" /* JSON */, _HostedAssetSource.JSON]
|
|
2990
|
+
["json" /* JSON */, _HostedAssetSource.JSON],
|
|
2991
|
+
["binary" /* BINARY */, _HostedAssetSource.BINARY]
|
|
2973
2992
|
]);
|
|
2974
2993
|
}
|
|
2975
2994
|
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
@@ -4855,6 +4874,178 @@ var init_Entities = __esm({
|
|
|
4855
4874
|
}
|
|
4856
4875
|
});
|
|
4857
4876
|
|
|
4877
|
+
// src/assets/_fonts/Unihex.ts
|
|
4878
|
+
var Unihex_exports = {};
|
|
4879
|
+
__export(Unihex_exports, {
|
|
4880
|
+
loadUnihex: () => loadUnihex
|
|
4881
|
+
});
|
|
4882
|
+
import { TextWriter, Uint8ArrayReader, ZipReader as ZipReader2 } from "@zip.js/zip.js";
|
|
4883
|
+
function readHex(text2, filename, glyphs) {
|
|
4884
|
+
const lines = text2.split("\n");
|
|
4885
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
4886
|
+
lines.forEach((line, index) => {
|
|
4887
|
+
const match = /^([0-9A-F]{4,6}):([0-9A-F]+)$/.exec(line);
|
|
4888
|
+
if (!match || ![32, 64, 96, 128].includes(match[2].length)) {
|
|
4889
|
+
throw new Error(`Invalid Unihex record in ${filename} at line ${index + 1}`);
|
|
4890
|
+
}
|
|
4891
|
+
const codepoint = parseInt(match[1], 16);
|
|
4892
|
+
if (codepoint > 1114111) throw new Error(`Invalid Unihex codepoint in ${filename} at line ${index + 1}`);
|
|
4893
|
+
const bitWidth = match[2].length / 4;
|
|
4894
|
+
const rowLength = bitWidth / 4;
|
|
4895
|
+
const rows = new Uint32Array(GLYPH_HEIGHT);
|
|
4896
|
+
let mask = 0;
|
|
4897
|
+
for (let y = 0; y < GLYPH_HEIGHT; y++) {
|
|
4898
|
+
rows[y] = parseInt(match[2].slice(y * rowLength, (y + 1) * rowLength), 16);
|
|
4899
|
+
mask |= rows[y];
|
|
4900
|
+
}
|
|
4901
|
+
let left = 0, right = bitWidth;
|
|
4902
|
+
if (mask) {
|
|
4903
|
+
while (!(mask >>> bitWidth - left - 1 & 1)) left++;
|
|
4904
|
+
right = bitWidth - 1;
|
|
4905
|
+
while (!(mask >>> bitWidth - right - 1 & 1)) right--;
|
|
4906
|
+
}
|
|
4907
|
+
glyphs.set(codepoint, { rows, bitWidth, left, right });
|
|
4908
|
+
});
|
|
4909
|
+
}
|
|
4910
|
+
async function parseUnihex(key) {
|
|
4911
|
+
try {
|
|
4912
|
+
const asset2 = await AssetLoader.get(key, "binary" /* BINARY */);
|
|
4913
|
+
if (!asset2) throw new Error(`Could not load Unihex archive ${key.toNamespacedString()}`);
|
|
4914
|
+
const records = /* @__PURE__ */ new Map();
|
|
4915
|
+
const reader = new ZipReader2(new Uint8ArrayReader(asset2.data), { useWebWorkers: false, useCompressionStream: false });
|
|
4916
|
+
try {
|
|
4917
|
+
for (const entry of await reader.getEntries()) {
|
|
4918
|
+
if (!entry.directory && entry.filename.endsWith(".hex")) {
|
|
4919
|
+
readHex(await entry.getData(new TextWriter(), { checkSignature: true }), entry.filename, records);
|
|
4920
|
+
}
|
|
4921
|
+
}
|
|
4922
|
+
} finally {
|
|
4923
|
+
await reader.close();
|
|
4924
|
+
}
|
|
4925
|
+
const indices = new Int32Array(1114112).fill(-1);
|
|
4926
|
+
const rows = new Uint32Array(records.size * GLYPH_HEIGHT), metrics = new Uint8Array(records.size * 3);
|
|
4927
|
+
let index = 0;
|
|
4928
|
+
for (const [codepoint, record] of records) {
|
|
4929
|
+
indices[codepoint] = index;
|
|
4930
|
+
rows.set(record.rows, index * GLYPH_HEIGHT);
|
|
4931
|
+
metrics.set([record.bitWidth, record.left, record.right], index * 3);
|
|
4932
|
+
index++;
|
|
4933
|
+
}
|
|
4934
|
+
return { indices, rows, metrics };
|
|
4935
|
+
} catch (error) {
|
|
4936
|
+
console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
|
|
4937
|
+
return void 0;
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
async function loadUnihex(provider, fontKey, characters) {
|
|
4941
|
+
const origin = new AssetKey(DEFAULT_NAMESPACE, "", void 0, void 0, "assets", "", fontKey.root);
|
|
4942
|
+
const key = AssetKey.parse("font", provider.hex_file, origin);
|
|
4943
|
+
key.assetType = void 0;
|
|
4944
|
+
const glyphs = /* @__PURE__ */ new Map();
|
|
4945
|
+
let overrides;
|
|
4946
|
+
try {
|
|
4947
|
+
overrides = (provider.size_overrides ?? []).map((override) => {
|
|
4948
|
+
const from = override.from.codePointAt(0), to = override.to.codePointAt(0);
|
|
4949
|
+
if ([...override.from].length !== 1 || [...override.to].length !== 1 || from >= to || !Number.isInteger(override.left) || !Number.isInteger(override.right) || override.right < override.left) {
|
|
4950
|
+
throw new Error(`Invalid Unihex size override in font ${fontKey.toNamespacedString()}`);
|
|
4951
|
+
}
|
|
4952
|
+
return { ...override, from, to };
|
|
4953
|
+
});
|
|
4954
|
+
} catch (error) {
|
|
4955
|
+
console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
|
|
4956
|
+
return glyphs;
|
|
4957
|
+
}
|
|
4958
|
+
const file = await Caching.unihexCache.get(key.serialize(), () => parseUnihex(key));
|
|
4959
|
+
if (!file) return glyphs;
|
|
4960
|
+
let atlas = atlases.get(provider);
|
|
4961
|
+
if (!atlas) {
|
|
4962
|
+
atlas = new UnihexAtlas();
|
|
4963
|
+
atlases.set(provider, atlas);
|
|
4964
|
+
}
|
|
4965
|
+
for (const character of characters) {
|
|
4966
|
+
const codepoint = character.codePointAt(0), index = file.indices[codepoint];
|
|
4967
|
+
if (index < 0) continue;
|
|
4968
|
+
const record = {
|
|
4969
|
+
rows: file.rows.subarray(index * GLYPH_HEIGHT, (index + 1) * GLYPH_HEIGHT),
|
|
4970
|
+
bitWidth: file.metrics[index * 3],
|
|
4971
|
+
left: file.metrics[index * 3 + 1],
|
|
4972
|
+
right: file.metrics[index * 3 + 2]
|
|
4973
|
+
};
|
|
4974
|
+
const override = overrides.find((range) => codepoint >= range.from && codepoint <= range.to);
|
|
4975
|
+
if (override) {
|
|
4976
|
+
record.left = override.left;
|
|
4977
|
+
record.right = override.right;
|
|
4978
|
+
}
|
|
4979
|
+
const width = record.right - record.left + 1;
|
|
4980
|
+
let rendered;
|
|
4981
|
+
const render = () => rendered ??= atlas.draw(record);
|
|
4982
|
+
glyphs.set(character, {
|
|
4983
|
+
get image() {
|
|
4984
|
+
return render().image;
|
|
4985
|
+
},
|
|
4986
|
+
get x() {
|
|
4987
|
+
return render().x;
|
|
4988
|
+
},
|
|
4989
|
+
get y() {
|
|
4990
|
+
return render().y;
|
|
4991
|
+
},
|
|
4992
|
+
width,
|
|
4993
|
+
height: GLYPH_HEIGHT,
|
|
4994
|
+
scale: 0.5,
|
|
4995
|
+
ascent: 7,
|
|
4996
|
+
advance: Math.floor(width / 2) + 1,
|
|
4997
|
+
boldOffset: 0.5,
|
|
4998
|
+
shadowOffset: 0.5
|
|
4999
|
+
});
|
|
5000
|
+
}
|
|
5001
|
+
return glyphs;
|
|
5002
|
+
}
|
|
5003
|
+
var ATLAS_SIZE, GLYPH_HEIGHT, UnihexAtlas, atlases;
|
|
5004
|
+
var init_Unihex = __esm({
|
|
5005
|
+
"src/assets/_fonts/Unihex.ts"() {
|
|
5006
|
+
init_AssetKey();
|
|
5007
|
+
init_AssetLoader();
|
|
5008
|
+
init_Assets();
|
|
5009
|
+
init_Caching();
|
|
5010
|
+
init_AssetParsers();
|
|
5011
|
+
init_CanvasCompat();
|
|
5012
|
+
ATLAS_SIZE = 512;
|
|
5013
|
+
GLYPH_HEIGHT = 16;
|
|
5014
|
+
UnihexAtlas = class {
|
|
5015
|
+
constructor() {
|
|
5016
|
+
this.x = 0;
|
|
5017
|
+
this.y = 0;
|
|
5018
|
+
}
|
|
5019
|
+
draw(glyph) {
|
|
5020
|
+
const width = glyph.right - glyph.left + 1;
|
|
5021
|
+
if (this.image && this.x + width > this.image.width) {
|
|
5022
|
+
this.x = 0;
|
|
5023
|
+
this.y += GLYPH_HEIGHT;
|
|
5024
|
+
}
|
|
5025
|
+
if (!this.image || this.y + GLYPH_HEIGHT > this.image.height || width > this.image.width) {
|
|
5026
|
+
this.image = createCanvas2(Math.max(ATLAS_SIZE, width), ATLAS_SIZE);
|
|
5027
|
+
this.x = 0;
|
|
5028
|
+
this.y = 0;
|
|
5029
|
+
}
|
|
5030
|
+
const context = this.image.getContext("2d");
|
|
5031
|
+
const pixels = context.createImageData(width, GLYPH_HEIGHT);
|
|
5032
|
+
for (let y = 0; y < GLYPH_HEIGHT; y++) {
|
|
5033
|
+
for (let x = 0; x < width; x++) {
|
|
5034
|
+
const column = glyph.left + x;
|
|
5035
|
+
if (column < 0 || column >= glyph.bitWidth || !(glyph.rows[y] >>> glyph.bitWidth - column - 1 & 1)) continue;
|
|
5036
|
+
pixels.data.fill(255, (y * width + x) * 4, (y * width + x + 1) * 4);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
const result = { image: this.image, x: this.x, y: this.y };
|
|
5040
|
+
context.putImageData(pixels, this.x, this.y);
|
|
5041
|
+
this.x += width;
|
|
5042
|
+
return result;
|
|
5043
|
+
}
|
|
5044
|
+
};
|
|
5045
|
+
atlases = /* @__PURE__ */ new WeakMap();
|
|
5046
|
+
}
|
|
5047
|
+
});
|
|
5048
|
+
|
|
4858
5049
|
// src/assets/Fonts.ts
|
|
4859
5050
|
var Fonts;
|
|
4860
5051
|
var init_Fonts = __esm({
|
|
@@ -4865,7 +5056,7 @@ var init_Fonts = __esm({
|
|
|
4865
5056
|
init_ModelTextures();
|
|
4866
5057
|
init_Caching();
|
|
4867
5058
|
Fonts = class {
|
|
4868
|
-
/** Combines font definitions in source-priority order.
|
|
5059
|
+
/** Combines font definitions in source-priority order. TrueType providers are skipped. */
|
|
4869
5060
|
static async get(key = "minecraft:default") {
|
|
4870
5061
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
4871
5062
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -4881,6 +5072,7 @@ var init_Fonts = __esm({
|
|
|
4881
5072
|
const stack = await AssetLoader.getAll(key, "json" /* JSON */);
|
|
4882
5073
|
if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
|
|
4883
5074
|
const glyphs = /* @__PURE__ */ new Map();
|
|
5075
|
+
const providers = [];
|
|
4884
5076
|
for (const asset2 of stack) {
|
|
4885
5077
|
for (const provider of asset2.providers) {
|
|
4886
5078
|
if (provider.filter?.uniform || provider.filter?.jp) continue;
|
|
@@ -4899,17 +5091,43 @@ var init_Fonts = __esm({
|
|
|
4899
5091
|
break;
|
|
4900
5092
|
case "reference":
|
|
4901
5093
|
case "minecraft:reference":
|
|
4902
|
-
|
|
5094
|
+
const reference = await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized]);
|
|
5095
|
+
if (reference.resolve) {
|
|
5096
|
+
providers.push(async (characters) => {
|
|
5097
|
+
await reference.resolve(characters);
|
|
5098
|
+
return reference.glyphs;
|
|
5099
|
+
});
|
|
5100
|
+
continue;
|
|
5101
|
+
}
|
|
5102
|
+
provided = reference.glyphs;
|
|
4903
5103
|
break;
|
|
5104
|
+
case "unihex":
|
|
5105
|
+
case "minecraft:unihex":
|
|
5106
|
+
providers.push(async (characters) => (await Promise.resolve().then(() => (init_Unihex(), Unihex_exports))).loadUnihex(provider, key, characters));
|
|
5107
|
+
continue;
|
|
4904
5108
|
default:
|
|
4905
5109
|
continue;
|
|
4906
5110
|
}
|
|
4907
|
-
for (const [character, glyph] of provided) {
|
|
5111
|
+
if (providers.every((provider2) => provider2 instanceof Map)) for (const [character, glyph] of provided) {
|
|
4908
5112
|
if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
|
|
4909
5113
|
}
|
|
5114
|
+
providers.push(provided);
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
return { glyphs, resolve: providers.every((provider) => provider instanceof Map) ? void 0 : async (characters) => {
|
|
5118
|
+
const remaining = new Set([...characters].filter((character) => character !== "\0" && character !== "\n" && character !== "\r" && !glyphs.has(character)));
|
|
5119
|
+
for (const provider of providers) {
|
|
5120
|
+
if (!remaining.size) break;
|
|
5121
|
+
const provided = provider instanceof Map ? provider : await provider([...remaining].join(""));
|
|
5122
|
+
for (const character of remaining) {
|
|
5123
|
+
const glyph = provided.get(character);
|
|
5124
|
+
if (glyph) {
|
|
5125
|
+
glyphs.set(character, glyph);
|
|
5126
|
+
remaining.delete(character);
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
4910
5129
|
}
|
|
4911
|
-
}
|
|
4912
|
-
return { glyphs };
|
|
5130
|
+
} };
|
|
4913
5131
|
}
|
|
4914
5132
|
static async bitmap(provider, fontKey) {
|
|
4915
5133
|
const rows = provider.chars.map((row) => [...row]);
|
|
@@ -5003,6 +5221,13 @@ var init_EntityAnimation = __esm({
|
|
|
5003
5221
|
|
|
5004
5222
|
// src/entity/scene/EntityAnimationPlayer.ts
|
|
5005
5223
|
import { Euler as Euler3, Vector3 as Vector35 } from "three";
|
|
5224
|
+
function validateAnimationWeights(weights, count) {
|
|
5225
|
+
const values = Array.from(weights);
|
|
5226
|
+
if (values.length !== count || values.some((weight) => !Number.isFinite(weight) || weight < 0)) {
|
|
5227
|
+
throw new Error("Animation weights must match the clip count and contain only finite nonnegative numbers");
|
|
5228
|
+
}
|
|
5229
|
+
return values;
|
|
5230
|
+
}
|
|
5006
5231
|
var ZERO, EntityAnimationPlayer;
|
|
5007
5232
|
var init_EntityAnimationPlayer = __esm({
|
|
5008
5233
|
"src/entity/scene/EntityAnimationPlayer.ts"() {
|
|
@@ -5011,12 +5236,20 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
5011
5236
|
EntityAnimationPlayer = class {
|
|
5012
5237
|
constructor() {
|
|
5013
5238
|
this.parts = [];
|
|
5239
|
+
this._animations = [];
|
|
5240
|
+
this._weights = [];
|
|
5241
|
+
this.loops = [];
|
|
5014
5242
|
this._time = 0;
|
|
5015
|
-
this.loop = false;
|
|
5016
5243
|
this.speed = 1;
|
|
5017
5244
|
}
|
|
5018
5245
|
get animation() {
|
|
5019
|
-
return this.
|
|
5246
|
+
return this._animations[0];
|
|
5247
|
+
}
|
|
5248
|
+
get animations() {
|
|
5249
|
+
return this._animations.slice();
|
|
5250
|
+
}
|
|
5251
|
+
get weights() {
|
|
5252
|
+
return this._weights.slice();
|
|
5020
5253
|
}
|
|
5021
5254
|
get time() {
|
|
5022
5255
|
return this._time;
|
|
@@ -5026,10 +5259,20 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
5026
5259
|
* without them, the current pose is used. Stopping restores the pose from before playback.
|
|
5027
5260
|
*/
|
|
5028
5261
|
play(layers, animation, options = {}, poses) {
|
|
5262
|
+
this.playAnimations(layers, [animation], options, poses);
|
|
5263
|
+
}
|
|
5264
|
+
/**
|
|
5265
|
+
* Starts clips on matching parts with a shared clock. Weighted offsets add to the supplied baked poses
|
|
5266
|
+
* or, without poses, to each animated part's pose when playback starts.
|
|
5267
|
+
*/
|
|
5268
|
+
playAnimations(layers, animations, options = {}, poses) {
|
|
5269
|
+
const weights = validateAnimationWeights(options.weights ?? animations.map(() => 1), animations.length);
|
|
5029
5270
|
this.stop();
|
|
5030
|
-
this.
|
|
5271
|
+
this._animations = animations.slice();
|
|
5272
|
+
this._weights = weights;
|
|
5273
|
+
if (!animations.length) return;
|
|
5031
5274
|
this._time = options.time ?? 0;
|
|
5032
|
-
this.
|
|
5275
|
+
this.loops = animations.map((animation) => options.loop ?? animation.loop);
|
|
5033
5276
|
this.speed = options.speed ?? 1;
|
|
5034
5277
|
for (const layer of layers) {
|
|
5035
5278
|
const objects = [];
|
|
@@ -5038,7 +5281,8 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
5038
5281
|
if (poses.has(object4)) objects.push(object4);
|
|
5039
5282
|
});
|
|
5040
5283
|
} else {
|
|
5041
|
-
|
|
5284
|
+
const bones = new Set(animations.flatMap((animation) => Object.keys(animation.bones)));
|
|
5285
|
+
for (const bone of bones) {
|
|
5042
5286
|
const object4 = layer.getObjectByName(`group:${bone}`);
|
|
5043
5287
|
if (object4) objects.push(object4);
|
|
5044
5288
|
}
|
|
@@ -5062,7 +5306,7 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
5062
5306
|
}
|
|
5063
5307
|
/** Restores the poses from before playback. Returns whether an animation was active. */
|
|
5064
5308
|
stop() {
|
|
5065
|
-
if (!this.
|
|
5309
|
+
if (!this._animations.length) return false;
|
|
5066
5310
|
for (const part of this.parts) {
|
|
5067
5311
|
part.object.position.copy(part.position);
|
|
5068
5312
|
part.object.rotation.copy(part.rotation);
|
|
@@ -5074,12 +5318,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
5074
5318
|
/** Forgets the animation without touching the parts, for parts that no longer exist. */
|
|
5075
5319
|
clear() {
|
|
5076
5320
|
this.parts = [];
|
|
5077
|
-
this.
|
|
5321
|
+
this._animations = [];
|
|
5322
|
+
this._weights = [];
|
|
5323
|
+
this.loops = [];
|
|
5078
5324
|
this._time = 0;
|
|
5079
5325
|
}
|
|
5080
5326
|
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
5081
5327
|
setTime(seconds) {
|
|
5082
|
-
if (!this.
|
|
5328
|
+
if (!this._animations.length) return false;
|
|
5083
5329
|
this._time = seconds;
|
|
5084
5330
|
this.apply();
|
|
5085
5331
|
return true;
|
|
@@ -5088,8 +5334,30 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
5088
5334
|
advance(deltaSeconds) {
|
|
5089
5335
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
5090
5336
|
}
|
|
5337
|
+
/** Changes weights in clip order and reapplies the current time without restarting playback. */
|
|
5338
|
+
setWeights(weights) {
|
|
5339
|
+
if (!this._animations.length) return false;
|
|
5340
|
+
const validated = validateAnimationWeights(weights, this._animations.length);
|
|
5341
|
+
this._weights = validated;
|
|
5342
|
+
this.apply();
|
|
5343
|
+
return true;
|
|
5344
|
+
}
|
|
5091
5345
|
apply() {
|
|
5092
|
-
const pose =
|
|
5346
|
+
const pose = /* @__PURE__ */ Object.create(null);
|
|
5347
|
+
for (let i = 0; i < this._animations.length; i++) {
|
|
5348
|
+
const weight = this._weights[i];
|
|
5349
|
+
if (weight === 0) continue;
|
|
5350
|
+
const sampled = sampleEntityAnimation(this._animations[i], this._time, this.loops[i]);
|
|
5351
|
+
for (const [bone, channels] of Object.entries(sampled)) {
|
|
5352
|
+
const blended = pose[bone] ??= {};
|
|
5353
|
+
for (const channel of ENTITY_ANIMATION_CHANNELS) {
|
|
5354
|
+
const value = channels[channel];
|
|
5355
|
+
if (!value) continue;
|
|
5356
|
+
const target = blended[channel] ??= [0, 0, 0];
|
|
5357
|
+
for (let axis = 0; axis < 3; axis++) target[axis] += value[axis] * weight;
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
}
|
|
5093
5361
|
for (const part of this.parts) {
|
|
5094
5362
|
const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone] ?? {};
|
|
5095
5363
|
part.object.position.set(part.basePosition.x + position[0], part.basePosition.y + position[1], part.basePosition.z + position[2]);
|
|
@@ -5713,7 +5981,7 @@ var init_EntityObject = __esm({
|
|
|
5713
5981
|
for (const geometry of this.geometries) geometry.dispose();
|
|
5714
5982
|
this.geometries.clear();
|
|
5715
5983
|
for (const dispose of this.disposeWireframes.splice(0)) dispose();
|
|
5716
|
-
for (const player of this.animationPlayers.splice(0)) player.clear();
|
|
5984
|
+
for (const { player } of this.animationPlayers.splice(0)) player.clear();
|
|
5717
5985
|
this.partPoses.clear();
|
|
5718
5986
|
super.disposeAndRemoveAllChildren();
|
|
5719
5987
|
}
|
|
@@ -5748,15 +6016,31 @@ var init_EntityObject = __esm({
|
|
|
5748
6016
|
//<editor-fold desc="ANIMATION">
|
|
5749
6017
|
/** The first active clip, until playback is stopped or the object is disposed. */
|
|
5750
6018
|
get animation() {
|
|
5751
|
-
return this.animationPlayers[0]?.animation;
|
|
6019
|
+
return this.animationPlayers[0]?.player.animation;
|
|
5752
6020
|
}
|
|
5753
|
-
/** Clips playing together,
|
|
6021
|
+
/** Clips playing together, in the order passed to {@link playAnimations}. */
|
|
5754
6022
|
get activeAnimations() {
|
|
5755
|
-
|
|
6023
|
+
const animations = [];
|
|
6024
|
+
for (const { player, indices } of this.animationPlayers) {
|
|
6025
|
+
player.animations.forEach((animation, i) => {
|
|
6026
|
+
animations[indices[i]] = animation;
|
|
6027
|
+
});
|
|
6028
|
+
}
|
|
6029
|
+
return animations;
|
|
6030
|
+
}
|
|
6031
|
+
/** Weights of the active clips, in the same order as {@link activeAnimations}. */
|
|
6032
|
+
get animationWeights() {
|
|
6033
|
+
const weights = [];
|
|
6034
|
+
for (const { player, indices } of this.animationPlayers) {
|
|
6035
|
+
player.weights.forEach((weight, i) => {
|
|
6036
|
+
weights[indices[i]] = weight;
|
|
6037
|
+
});
|
|
6038
|
+
}
|
|
6039
|
+
return weights;
|
|
5756
6040
|
}
|
|
5757
6041
|
/** Seconds since the animation started, before looping. */
|
|
5758
6042
|
get animationTime() {
|
|
5759
|
-
return this.animationPlayers[0]?.time ?? 0;
|
|
6043
|
+
return this.animationPlayers[0]?.player.time ?? 0;
|
|
5760
6044
|
}
|
|
5761
6045
|
/**
|
|
5762
6046
|
* Plays a clip from {@link Entities.getAnimations}, replacing all active clips.
|
|
@@ -5767,42 +6051,59 @@ var init_EntityObject = __esm({
|
|
|
5767
6051
|
playAnimation(animation, options) {
|
|
5768
6052
|
this.playAnimations([animation], options);
|
|
5769
6053
|
}
|
|
5770
|
-
/**
|
|
6054
|
+
/**
|
|
6055
|
+
* Plays clips with a shared clock, adding their weighted offsets within each geometry layer.
|
|
6056
|
+
* Weights default to 1 and are not normalized. Selected layers without their own clip follow `main`.
|
|
6057
|
+
*/
|
|
5771
6058
|
playAnimations(animations, options) {
|
|
5772
|
-
const
|
|
5773
|
-
const selections =
|
|
6059
|
+
const weights = validateAnimationWeights(options?.weights ?? animations.map(() => 1), animations.length);
|
|
6060
|
+
const selections = /* @__PURE__ */ new Map();
|
|
6061
|
+
animations.forEach((animation, index) => {
|
|
5774
6062
|
const layer = animation.layer ?? "main";
|
|
5775
|
-
if (targets.has(layer)) throw new Error(`Multiple animations target layer "${layer}"`);
|
|
5776
|
-
targets.add(layer);
|
|
5777
6063
|
const names = Object.keys(this.entityLayers).filter((name) => name.split("#")[0] === layer);
|
|
5778
6064
|
if (!names.length) throw new Error(`Entity ${this.entity.id} has no selected animation layer "${layer}"`);
|
|
5779
|
-
|
|
6065
|
+
let selection = selections.get(layer);
|
|
6066
|
+
if (!selection) selections.set(layer, selection = { animations: [], names, indices: [] });
|
|
6067
|
+
selection.animations.push(animation);
|
|
6068
|
+
selection.indices.push(index);
|
|
5780
6069
|
});
|
|
5781
|
-
const main = selections.
|
|
5782
|
-
if (main) main.names.push(...Object.keys(this.entityLayers).filter((name) => !
|
|
6070
|
+
const main = selections.get("main");
|
|
6071
|
+
if (main) main.names.push(...Object.keys(this.entityLayers).filter((name) => !selections.has(name.split("#")[0])));
|
|
5783
6072
|
this.createMeshes();
|
|
5784
6073
|
this.stopAnimation();
|
|
5785
|
-
for (const {
|
|
6074
|
+
for (const { animations: clips, names, indices } of selections.values()) {
|
|
5786
6075
|
const player = new EntityAnimationPlayer();
|
|
5787
|
-
player.
|
|
5788
|
-
|
|
6076
|
+
player.playAnimations(
|
|
6077
|
+
names.map((name) => this.getLayerGroup(name)),
|
|
6078
|
+
clips,
|
|
6079
|
+
{ ...options, weights: indices.map((index) => weights[index]) },
|
|
6080
|
+
this.partPoses
|
|
6081
|
+
);
|
|
6082
|
+
this.animationPlayers.push({ player, indices });
|
|
5789
6083
|
}
|
|
5790
6084
|
this.notifyDirty();
|
|
5791
6085
|
}
|
|
6086
|
+
/** Changes weights in active clip order, notifying the scene without restarting the shared clock. Has no effect without an animation. */
|
|
6087
|
+
setAnimationWeights(weights) {
|
|
6088
|
+
if (!this.animationPlayers.length) return;
|
|
6089
|
+
const values = validateAnimationWeights(weights, this.activeAnimations.length);
|
|
6090
|
+
for (const { player, indices } of this.animationPlayers) player.setWeights(indices.map((index) => values[index]));
|
|
6091
|
+
this.notifyDirty();
|
|
6092
|
+
}
|
|
5792
6093
|
/** Stops all clips and restores the poses from before playback. */
|
|
5793
6094
|
stopAnimation() {
|
|
5794
6095
|
const players = this.animationPlayers.splice(0);
|
|
5795
|
-
for (const player of players) player.stop();
|
|
6096
|
+
for (const { player } of players) player.stop();
|
|
5796
6097
|
if (players.length) this.notifyDirty();
|
|
5797
6098
|
}
|
|
5798
6099
|
/** Poses the object at an explicit time in seconds. Has no effect without an animation. */
|
|
5799
6100
|
setAnimationTime(seconds) {
|
|
5800
|
-
for (const player of this.animationPlayers) player.setTime(seconds);
|
|
6101
|
+
for (const { player } of this.animationPlayers) player.setTime(seconds);
|
|
5801
6102
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
5802
6103
|
}
|
|
5803
6104
|
/** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
|
|
5804
6105
|
advanceAnimation(deltaSeconds) {
|
|
5805
|
-
for (const player of this.animationPlayers) player.advance(deltaSeconds);
|
|
6106
|
+
for (const { player } of this.animationPlayers) player.advance(deltaSeconds);
|
|
5806
6107
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
5807
6108
|
}
|
|
5808
6109
|
//</editor-fold>
|
|
@@ -8064,6 +8365,7 @@ async function layoutGuiText(text2, options = {}) {
|
|
|
8064
8365
|
}
|
|
8065
8366
|
const font = await Fonts.get(options.font);
|
|
8066
8367
|
const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
|
|
8368
|
+
await font.resolve?.(runs.map((run) => run.text).join(""));
|
|
8067
8369
|
const glyphs = [], lineWidths = [];
|
|
8068
8370
|
let line = [], width = 0;
|
|
8069
8371
|
let trailingNewline = false;
|
|
@@ -8090,7 +8392,7 @@ async function layoutGuiText(text2, options = {}) {
|
|
|
8090
8392
|
continue;
|
|
8091
8393
|
}
|
|
8092
8394
|
const glyph = font.glyphs.get(character);
|
|
8093
|
-
const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
|
|
8395
|
+
const advance = (glyph?.advance ?? 6) + (style.bold ? glyph?.boldOffset ?? 1 : 0);
|
|
8094
8396
|
line.push({ character, glyph, advance, style, x: 0, y: 0 });
|
|
8095
8397
|
width += advance;
|
|
8096
8398
|
while (width > maxWidth && line.length > 1) {
|
|
@@ -8118,7 +8420,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
8118
8420
|
batches.push(batch);
|
|
8119
8421
|
}
|
|
8120
8422
|
const color2 = new Color8(isShadow ? (style.color & 16579836) >> 2 : style.color);
|
|
8121
|
-
const offset = isShadow ? 1 : 0;
|
|
8423
|
+
const offset = isShadow ? glyph?.shadowOffset ?? 1 : 0;
|
|
8122
8424
|
const top = glyph ? 7 - glyph.ascent : 0;
|
|
8123
8425
|
const height = glyph ? glyph.height * glyph.scale : 8;
|
|
8124
8426
|
const width = glyph ? glyph.width * glyph.scale : 5;
|
|
@@ -8148,7 +8450,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
8148
8450
|
for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
|
|
8149
8451
|
batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
|
|
8150
8452
|
};
|
|
8151
|
-
for (const boldOffset of style.bold ? [0, 1] : [0]) {
|
|
8453
|
+
for (const boldOffset of style.bold ? [0, glyph?.boldOffset ?? 1] : [0]) {
|
|
8152
8454
|
if (glyph) quad(0, top, width, top + height, boldOffset);
|
|
8153
8455
|
else {
|
|
8154
8456
|
quad(0, 0, 5, 1, boldOffset);
|
|
@@ -9928,6 +10230,10 @@ var init_ModelObject = __esm({
|
|
|
9928
10230
|
this.atlas.model.elements?.forEach((el) => {
|
|
9929
10231
|
const elGeo = this._getBoxGeometryFromElement(el).clone();
|
|
9930
10232
|
this.geometries.add(elGeo);
|
|
10233
|
+
elGeo.setAttribute("shade", new BufferAttribute5(
|
|
10234
|
+
new Float32Array(elGeo.getAttribute("position").count).fill(!this.originalModel.itemId && el.shade === false ? 0 : 1),
|
|
10235
|
+
1
|
|
10236
|
+
));
|
|
9931
10237
|
if (this.options.cullMask) {
|
|
9932
10238
|
const indices = Array.from(elGeo.getIndex().array);
|
|
9933
10239
|
elGeo.setIndex(indices.filter((_, index) => {
|
|
@@ -17521,9 +17827,9 @@ function cached(map, key, load) {
|
|
|
17521
17827
|
function compactQuads(geometry, keep) {
|
|
17522
17828
|
const quads = keep.flatMap((kept, index) => kept ? [index] : []);
|
|
17523
17829
|
const compact = new BufferGeometry8();
|
|
17524
|
-
for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3 })) {
|
|
17830
|
+
for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3, shade: 1 })) {
|
|
17525
17831
|
const source2 = geometry.getAttribute(name);
|
|
17526
|
-
const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : void 0;
|
|
17832
|
+
const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : name === "shade" ? [1] : void 0;
|
|
17527
17833
|
const values = new Float32Array(quads.length * 4 * size);
|
|
17528
17834
|
for (let q = 0; q < quads.length; q++) {
|
|
17529
17835
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
@@ -18771,7 +19077,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18771
19077
|
|
|
18772
19078
|
// src/world/SectionGeometry.ts
|
|
18773
19079
|
function buildSectionGeometry(input) {
|
|
18774
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
19080
|
+
const { count, indices, templates, cullMasks, templateData, atlases: atlases2, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
18775
19081
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18776
19082
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18777
19083
|
if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
|
|
@@ -18789,7 +19095,7 @@ function buildSectionGeometry(input) {
|
|
|
18789
19095
|
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18790
19096
|
for (const template of templateData) {
|
|
18791
19097
|
const { quads } = template;
|
|
18792
|
-
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) {
|
|
19098
|
+
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) {
|
|
18793
19099
|
throw new RangeError("Section template arrays do not match its quad count");
|
|
18794
19100
|
}
|
|
18795
19101
|
}
|
|
@@ -18806,8 +19112,8 @@ function buildSectionGeometry(input) {
|
|
|
18806
19112
|
const locations = /* @__PURE__ */ new Map();
|
|
18807
19113
|
for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a], [b]) => a - b)) {
|
|
18808
19114
|
const firstPage = pages.length;
|
|
18809
|
-
for (const atlas of [...layerAtlases].sort((a, b) => Number(
|
|
18810
|
-
const { width, height, animated } =
|
|
19115
|
+
for (const atlas of [...layerAtlases].sort((a, b) => Number(atlases2[a].animated) - Number(atlases2[b].animated) || (atlases2[a].animated ? a - b : atlases2[b].height - atlases2[a].height))) {
|
|
19116
|
+
const { width, height, animated } = atlases2[atlas];
|
|
18811
19117
|
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
18812
19118
|
let selected = -1;
|
|
18813
19119
|
for (let i = firstPage; !animated && i < pages.length; i++) {
|
|
@@ -18850,7 +19156,7 @@ function buildSectionGeometry(input) {
|
|
|
18850
19156
|
});
|
|
18851
19157
|
if (!quads.sprites.length) continue;
|
|
18852
19158
|
if (!fluidPages.has(fluid)) {
|
|
18853
|
-
const { width, height } =
|
|
19159
|
+
const { width, height } = atlases2[data.atlas];
|
|
18854
19160
|
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
18855
19161
|
fluidPages.set(fluid, {
|
|
18856
19162
|
layer: 2,
|
|
@@ -18868,7 +19174,7 @@ function buildSectionGeometry(input) {
|
|
|
18868
19174
|
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
18869
19175
|
fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
|
|
18870
19176
|
}
|
|
18871
|
-
pages.push(...[...fluidPages.values()].sort((a, b) => Number(
|
|
19177
|
+
pages.push(...[...fluidPages.values()].sort((a, b) => Number(atlases2[a.placements[0].atlas].animated) - Number(atlases2[b.placements[0].atlas].animated) || a.placements[0].atlas - b.placements[0].atlas));
|
|
18872
19178
|
}
|
|
18873
19179
|
return pages.map((page) => {
|
|
18874
19180
|
let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);
|
|
@@ -18880,12 +19186,13 @@ function buildSectionGeometry(input) {
|
|
|
18880
19186
|
}
|
|
18881
19187
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
18882
19188
|
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
19189
|
+
const shade = new Float32Array(faces * 4).fill(1);
|
|
18883
19190
|
const outputIndices = new Uint32Array(faces * 6);
|
|
18884
19191
|
const blockIndices = new Uint16Array(faces);
|
|
18885
19192
|
let vertex = 0, indexOffset = 0;
|
|
18886
19193
|
for (const entry of page.entries) {
|
|
18887
19194
|
const template = templateData[templates[entry]];
|
|
18888
|
-
const atlas =
|
|
19195
|
+
const atlas = atlases2[template.atlas];
|
|
18889
19196
|
const placement = locations.get(template.atlas);
|
|
18890
19197
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
18891
19198
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
@@ -18909,6 +19216,7 @@ function buildSectionGeometry(input) {
|
|
|
18909
19216
|
normals[vertex * 3] = template.normals[source * 3];
|
|
18910
19217
|
normals[vertex * 3 + 1] = template.normals[source * 3 + 1];
|
|
18911
19218
|
normals[vertex * 3 + 2] = template.normals[source * 3 + 2];
|
|
19219
|
+
shade[vertex] = template.shade?.[source] ?? 1;
|
|
18912
19220
|
uvs[vertex * 2] = mapU(template.uvs[source * 2]);
|
|
18913
19221
|
uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
|
|
18914
19222
|
uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);
|
|
@@ -18924,7 +19232,7 @@ function buildSectionGeometry(input) {
|
|
|
18924
19232
|
}
|
|
18925
19233
|
}
|
|
18926
19234
|
for (const { quads, x, y, z, data, tint } of page.fluids) {
|
|
18927
|
-
const atlas =
|
|
19235
|
+
const atlas = atlases2[data.atlas];
|
|
18928
19236
|
const placement = page.placements[0];
|
|
18929
19237
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
18930
19238
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
@@ -18961,11 +19269,11 @@ function buildSectionGeometry(input) {
|
|
|
18961
19269
|
indexOffset += 6;
|
|
18962
19270
|
}
|
|
18963
19271
|
}
|
|
18964
|
-
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
|
|
19272
|
+
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, shade, indices: outputIndices, blockIndices };
|
|
18965
19273
|
});
|
|
18966
19274
|
}
|
|
18967
19275
|
function sectionGeometryTransferables(pages) {
|
|
18968
|
-
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]);
|
|
19276
|
+
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]);
|
|
18969
19277
|
}
|
|
18970
19278
|
|
|
18971
19279
|
// src/world/SectionWorker.ts
|
|
@@ -19026,7 +19334,7 @@ var templateCache = /* @__PURE__ */ new WeakMap();
|
|
|
19026
19334
|
var WATER_TINT = new Color12(4159204).toArray();
|
|
19027
19335
|
function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
19028
19336
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
19029
|
-
const
|
|
19337
|
+
const atlases2 = [];
|
|
19030
19338
|
const atlasIds = /* @__PURE__ */ new Map();
|
|
19031
19339
|
const templateIds = /* @__PURE__ */ new Map();
|
|
19032
19340
|
const input = {
|
|
@@ -19049,9 +19357,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19049
19357
|
if (id === void 0) {
|
|
19050
19358
|
let atlas = atlasIds.get(template.atlas);
|
|
19051
19359
|
if (atlas === void 0) {
|
|
19052
|
-
atlas =
|
|
19360
|
+
atlas = atlases2.length;
|
|
19053
19361
|
atlasIds.set(template.atlas, atlas);
|
|
19054
|
-
|
|
19362
|
+
atlases2.push(template.atlas);
|
|
19055
19363
|
input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });
|
|
19056
19364
|
}
|
|
19057
19365
|
let data = templateCache.get(template);
|
|
@@ -19069,6 +19377,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19069
19377
|
uvs: new Float32Array(quads * 8),
|
|
19070
19378
|
uvBounds: new Float32Array(quads * 16),
|
|
19071
19379
|
colors: new Float32Array(quads * 12),
|
|
19380
|
+
shade: new Float32Array(quads * 4),
|
|
19072
19381
|
indices: new Uint16Array(quads * 6),
|
|
19073
19382
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
19074
19383
|
biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
|
|
@@ -19080,6 +19389,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19080
19389
|
const uv = template.geometry.getAttribute("uv");
|
|
19081
19390
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
19082
19391
|
const color2 = template.geometry.getAttribute("color");
|
|
19392
|
+
const shade = template.geometry.getAttribute("shade");
|
|
19083
19393
|
for (let vertex = 0; vertex < quads * 4; vertex++) {
|
|
19084
19394
|
data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
|
|
19085
19395
|
data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
|
|
@@ -19091,6 +19401,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19091
19401
|
bounds?.getW(vertex) ?? 1
|
|
19092
19402
|
], vertex * 4);
|
|
19093
19403
|
data.colors.set([color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1], vertex * 3);
|
|
19404
|
+
data.shade[vertex] = shade?.getX(vertex) ?? 1;
|
|
19094
19405
|
}
|
|
19095
19406
|
for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - 4 * Math.floor(i2 / 6);
|
|
19096
19407
|
templateCache.set(template, data);
|
|
@@ -19110,9 +19421,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19110
19421
|
if (!atlas) continue;
|
|
19111
19422
|
let id = atlasIds.get(atlas);
|
|
19112
19423
|
if (id === void 0) {
|
|
19113
|
-
id =
|
|
19424
|
+
id = atlases2.length;
|
|
19114
19425
|
atlasIds.set(atlas, id);
|
|
19115
|
-
|
|
19426
|
+
atlases2.push(atlas);
|
|
19116
19427
|
input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });
|
|
19117
19428
|
}
|
|
19118
19429
|
input.fluids[kind] = {
|
|
@@ -19123,7 +19434,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19123
19434
|
};
|
|
19124
19435
|
}
|
|
19125
19436
|
}
|
|
19126
|
-
return { input, atlases };
|
|
19437
|
+
return { input, atlases: atlases2 };
|
|
19127
19438
|
}
|
|
19128
19439
|
var SectionMesh = class _SectionMesh extends Group3 {
|
|
19129
19440
|
constructor() {
|
|
@@ -19138,23 +19449,23 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19138
19449
|
}
|
|
19139
19450
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
19140
19451
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
19141
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19142
|
-
return this.fromPages(buildSectionGeometry(input),
|
|
19452
|
+
const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19453
|
+
return this.fromPages(buildSectionGeometry(input), atlases2);
|
|
19143
19454
|
}
|
|
19144
19455
|
/** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
|
|
19145
19456
|
static async buildAsync(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
19146
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19457
|
+
const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19147
19458
|
const worker = SectionWorker.shared();
|
|
19148
19459
|
const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
|
|
19149
|
-
return this.fromPages(pages,
|
|
19460
|
+
return this.fromPages(pages, atlases2);
|
|
19150
19461
|
}
|
|
19151
|
-
static fromPages(pages,
|
|
19462
|
+
static fromPages(pages, atlases2) {
|
|
19152
19463
|
const section = new _SectionMesh();
|
|
19153
19464
|
for (const page of pages) {
|
|
19154
19465
|
const canvas = createCanvas2(page.width, page.height);
|
|
19155
19466
|
const context = canvas.getContext("2d");
|
|
19156
19467
|
for (const { atlas, x, y } of page.placements) {
|
|
19157
|
-
context.drawImage(
|
|
19468
|
+
context.drawImage(atlases2[atlas].image.canvas, x, y);
|
|
19158
19469
|
}
|
|
19159
19470
|
const geometry = new BufferGeometry9();
|
|
19160
19471
|
geometry.setAttribute("position", new Float32BufferAttribute10(page.positions.buffer, 3));
|
|
@@ -19162,10 +19473,11 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19162
19473
|
geometry.setAttribute("uv", new Float32BufferAttribute10(page.uvs.buffer, 2));
|
|
19163
19474
|
geometry.setAttribute("uvBounds", new Float32BufferAttribute10(page.uvBounds.buffer, 4));
|
|
19164
19475
|
geometry.setAttribute("color", new Float32BufferAttribute10(page.colors.buffer, 3));
|
|
19476
|
+
geometry.setAttribute("shade", new Float32BufferAttribute10(page.shade.buffer, 1));
|
|
19165
19477
|
geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
|
|
19166
19478
|
geometry.computeBoundingBox();
|
|
19167
19479
|
geometry.computeBoundingSphere();
|
|
19168
|
-
const transparent = page.layer === 2 ?
|
|
19480
|
+
const transparent = page.layer === 2 ? atlases2[page.placements[0].atlas].hasTranslucency : page.layer === 1;
|
|
19169
19481
|
const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
|
|
19170
19482
|
material.side = FrontSide4;
|
|
19171
19483
|
if (page.layer === 2) {
|
|
@@ -19180,7 +19492,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19180
19492
|
section.blockIndices.set(mesh, page.blockIndices);
|
|
19181
19493
|
const unsubscribe = [];
|
|
19182
19494
|
for (const { atlas: id, x, y } of page.placements) {
|
|
19183
|
-
const atlas =
|
|
19495
|
+
const atlas = atlases2[id];
|
|
19184
19496
|
if (!atlas.hasAnimation) continue;
|
|
19185
19497
|
unsubscribe.push(atlas.subscribe(() => {
|
|
19186
19498
|
context.clearRect(x, y, atlas.image.width, atlas.image.height);
|
|
@@ -20523,6 +20835,7 @@ export {
|
|
|
20523
20835
|
toRadians,
|
|
20524
20836
|
toTrianglesDrawMode,
|
|
20525
20837
|
trimCanvas,
|
|
20838
|
+
validateAnimationWeights,
|
|
20526
20839
|
yieldToEventLoop
|
|
20527
20840
|
};
|
|
20528
20841
|
//# sourceMappingURL=index.mjs.map
|