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/browser/index.js
CHANGED
|
@@ -286,6 +286,7 @@ var init_Caching = __esm({
|
|
|
286
286
|
this.entityAnimationCache,
|
|
287
287
|
this.blockEntityIndexCache,
|
|
288
288
|
this.fontCache,
|
|
289
|
+
this.unihexCache,
|
|
289
290
|
this.bannerPatternCache,
|
|
290
291
|
this.mineRenderDataCache,
|
|
291
292
|
this.usernameUuidCache,
|
|
@@ -339,6 +340,7 @@ var init_Caching = __esm({
|
|
|
339
340
|
_Caching.entityTextureCache = _Caching.createAssetCache();
|
|
340
341
|
_Caching.entityAnimationCache = _Caching.createAssetCache();
|
|
341
342
|
_Caching.blockEntityIndexCache = _Caching.createAssetCache();
|
|
343
|
+
_Caching.unihexCache = _Caching.createAssetCache();
|
|
342
344
|
_Caching.fontCache = _Caching.createAssetCache();
|
|
343
345
|
_Caching.bannerPatternCache = _Caching.createAssetCache();
|
|
344
346
|
_Caching.mineRenderDataCache = _Caching.createAssetCache();
|
|
@@ -1055,6 +1057,7 @@ var init_Materials = __esm({
|
|
|
1055
1057
|
static createShadedCanvasMaterial(canvas, transparent = false, shade = false, boundUvs = false) {
|
|
1056
1058
|
const vertShader = `
|
|
1057
1059
|
uniform bool SHADE;
|
|
1060
|
+
attribute float shade;
|
|
1058
1061
|
|
|
1059
1062
|
// Keep MSAA edge pixels from sampling outside the face's atlas region.
|
|
1060
1063
|
#if __VERSION__ >= 300
|
|
@@ -1077,7 +1080,7 @@ var init_Materials = __esm({
|
|
|
1077
1080
|
void main()
|
|
1078
1081
|
{
|
|
1079
1082
|
|
|
1080
|
-
if (SHADE) {
|
|
1083
|
+
if (SHADE && shade > 0.5) {
|
|
1081
1084
|
|
|
1082
1085
|
#ifdef USE_INSTANCING
|
|
1083
1086
|
vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
|
|
@@ -1186,7 +1189,7 @@ var init_Materials = __esm({
|
|
|
1186
1189
|
side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
|
|
1187
1190
|
alphaTest: 0.5
|
|
1188
1191
|
});
|
|
1189
|
-
Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
|
|
1192
|
+
Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });
|
|
1190
1193
|
return material;
|
|
1191
1194
|
} catch (e) {
|
|
1192
1195
|
console.warn(e);
|
|
@@ -1351,6 +1354,7 @@ var init_AssetParsers = __esm({
|
|
|
1351
1354
|
AssetParser2["IMAGE"] = "image";
|
|
1352
1355
|
AssetParser2["LIST"] = "list";
|
|
1353
1356
|
AssetParser2["JSON"] = "json";
|
|
1357
|
+
AssetParser2["BINARY"] = "binary";
|
|
1354
1358
|
return AssetParser2;
|
|
1355
1359
|
})(AssetParser || {});
|
|
1356
1360
|
}
|
|
@@ -2631,13 +2635,13 @@ function applyElementRotation(rotation, geometry) {
|
|
|
2631
2635
|
break;
|
|
2632
2636
|
}
|
|
2633
2637
|
if (rotation.rescale) {
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2638
|
+
const angle = toRadians(rotation.angle);
|
|
2639
|
+
const s = 1 / Math.max(Math.abs(Math.cos(angle)), Math.abs(Math.sin(angle)));
|
|
2640
|
+
geometry.scale(
|
|
2641
|
+
rotation.axis === "x" /* X */ ? 1 : s,
|
|
2642
|
+
rotation.axis === "y" /* Y */ ? 1 : s,
|
|
2643
|
+
rotation.axis === "z" /* Z */ ? 1 : s
|
|
2644
|
+
);
|
|
2641
2645
|
}
|
|
2642
2646
|
geometry.translate(origin.x, origin.y, origin.z);
|
|
2643
2647
|
}
|
|
@@ -2821,7 +2825,7 @@ var init_parser = __esm({
|
|
|
2821
2825
|
});
|
|
2822
2826
|
|
|
2823
2827
|
// src/assets/source/HostedAssetSource.ts
|
|
2824
|
-
var p4, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
|
|
2828
|
+
var BINARY_TIMEOUT, p4, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
|
|
2825
2829
|
var init_HostedAssetSource = __esm({
|
|
2826
2830
|
"src/assets/source/HostedAssetSource.ts"() {
|
|
2827
2831
|
init_AssetSource();
|
|
@@ -2834,6 +2838,7 @@ var init_HostedAssetSource = __esm({
|
|
|
2834
2838
|
init_AssetLoader();
|
|
2835
2839
|
init_parser();
|
|
2836
2840
|
init_merge();
|
|
2841
|
+
BINARY_TIMEOUT = 6e4;
|
|
2837
2842
|
p4 = prefix("HostedAssetSource");
|
|
2838
2843
|
DEFAULT_OPTIONS = {
|
|
2839
2844
|
retryDefaults: true
|
|
@@ -2974,6 +2979,15 @@ var init_HostedAssetSource = __esm({
|
|
|
2974
2979
|
return response.data;
|
|
2975
2980
|
}
|
|
2976
2981
|
};
|
|
2982
|
+
_HostedAssetSource.BINARY = {
|
|
2983
|
+
config(request) {
|
|
2984
|
+
request.timeout = BINARY_TIMEOUT;
|
|
2985
|
+
request.responseType = "arraybuffer";
|
|
2986
|
+
},
|
|
2987
|
+
parse(response) {
|
|
2988
|
+
return { data: new Uint8Array(response.data) };
|
|
2989
|
+
}
|
|
2990
|
+
};
|
|
2977
2991
|
_HostedAssetSource.PARSER_MAP = /* @__PURE__ */ new Map([
|
|
2978
2992
|
["model" /* MODEL */, _HostedAssetSource.MODEL],
|
|
2979
2993
|
["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
|
|
@@ -2981,7 +2995,8 @@ var init_HostedAssetSource = __esm({
|
|
|
2981
2995
|
["nbt" /* NBT */, _HostedAssetSource.NBT],
|
|
2982
2996
|
["image" /* IMAGE */, _HostedAssetSource.IMAGE],
|
|
2983
2997
|
["list" /* LIST */, _HostedAssetSource.LIST],
|
|
2984
|
-
["json" /* JSON */, _HostedAssetSource.JSON]
|
|
2998
|
+
["json" /* JSON */, _HostedAssetSource.JSON],
|
|
2999
|
+
["binary" /* BINARY */, _HostedAssetSource.BINARY]
|
|
2985
3000
|
]);
|
|
2986
3001
|
HostedAssetSource = _HostedAssetSource;
|
|
2987
3002
|
}
|
|
@@ -4762,6 +4777,178 @@ var init_Entities = __esm({
|
|
|
4762
4777
|
}
|
|
4763
4778
|
});
|
|
4764
4779
|
|
|
4780
|
+
// src/assets/_fonts/Unihex.ts
|
|
4781
|
+
var Unihex_exports = {};
|
|
4782
|
+
__export(Unihex_exports, {
|
|
4783
|
+
loadUnihex: () => loadUnihex
|
|
4784
|
+
});
|
|
4785
|
+
function readHex(text2, filename, glyphs) {
|
|
4786
|
+
const lines = text2.split("\n");
|
|
4787
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
4788
|
+
lines.forEach((line, index) => {
|
|
4789
|
+
const match = /^([0-9A-F]{4,6}):([0-9A-F]+)$/.exec(line);
|
|
4790
|
+
if (!match || ![32, 64, 96, 128].includes(match[2].length)) {
|
|
4791
|
+
throw new Error(`Invalid Unihex record in ${filename} at line ${index + 1}`);
|
|
4792
|
+
}
|
|
4793
|
+
const codepoint = parseInt(match[1], 16);
|
|
4794
|
+
if (codepoint > 1114111) throw new Error(`Invalid Unihex codepoint in ${filename} at line ${index + 1}`);
|
|
4795
|
+
const bitWidth = match[2].length / 4;
|
|
4796
|
+
const rowLength = bitWidth / 4;
|
|
4797
|
+
const rows = new Uint32Array(GLYPH_HEIGHT);
|
|
4798
|
+
let mask = 0;
|
|
4799
|
+
for (let y = 0; y < GLYPH_HEIGHT; y++) {
|
|
4800
|
+
rows[y] = parseInt(match[2].slice(y * rowLength, (y + 1) * rowLength), 16);
|
|
4801
|
+
mask |= rows[y];
|
|
4802
|
+
}
|
|
4803
|
+
let left = 0, right = bitWidth;
|
|
4804
|
+
if (mask) {
|
|
4805
|
+
while (!(mask >>> bitWidth - left - 1 & 1)) left++;
|
|
4806
|
+
right = bitWidth - 1;
|
|
4807
|
+
while (!(mask >>> bitWidth - right - 1 & 1)) right--;
|
|
4808
|
+
}
|
|
4809
|
+
glyphs.set(codepoint, { rows, bitWidth, left, right });
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
async function parseUnihex(key) {
|
|
4813
|
+
try {
|
|
4814
|
+
const asset2 = await AssetLoader.get(key, "binary" /* BINARY */);
|
|
4815
|
+
if (!asset2) throw new Error(`Could not load Unihex archive ${key.toNamespacedString()}`);
|
|
4816
|
+
const records = /* @__PURE__ */ new Map();
|
|
4817
|
+
const reader = new import_zip2.ZipReader(new import_zip2.Uint8ArrayReader(asset2.data), { useWebWorkers: false, useCompressionStream: false });
|
|
4818
|
+
try {
|
|
4819
|
+
for (const entry of await reader.getEntries()) {
|
|
4820
|
+
if (!entry.directory && entry.filename.endsWith(".hex")) {
|
|
4821
|
+
readHex(await entry.getData(new import_zip2.TextWriter(), { checkSignature: true }), entry.filename, records);
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
} finally {
|
|
4825
|
+
await reader.close();
|
|
4826
|
+
}
|
|
4827
|
+
const indices = new Int32Array(1114112).fill(-1);
|
|
4828
|
+
const rows = new Uint32Array(records.size * GLYPH_HEIGHT), metrics = new Uint8Array(records.size * 3);
|
|
4829
|
+
let index = 0;
|
|
4830
|
+
for (const [codepoint, record] of records) {
|
|
4831
|
+
indices[codepoint] = index;
|
|
4832
|
+
rows.set(record.rows, index * GLYPH_HEIGHT);
|
|
4833
|
+
metrics.set([record.bitWidth, record.left, record.right], index * 3);
|
|
4834
|
+
index++;
|
|
4835
|
+
}
|
|
4836
|
+
return { indices, rows, metrics };
|
|
4837
|
+
} catch (error) {
|
|
4838
|
+
console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
|
|
4839
|
+
return void 0;
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4842
|
+
async function loadUnihex(provider, fontKey, characters) {
|
|
4843
|
+
const origin = new AssetKey(DEFAULT_NAMESPACE, "", void 0, void 0, "assets", "", fontKey.root);
|
|
4844
|
+
const key = AssetKey.parse("font", provider.hex_file, origin);
|
|
4845
|
+
key.assetType = void 0;
|
|
4846
|
+
const glyphs = /* @__PURE__ */ new Map();
|
|
4847
|
+
let overrides;
|
|
4848
|
+
try {
|
|
4849
|
+
overrides = (provider.size_overrides ?? []).map((override) => {
|
|
4850
|
+
const from = override.from.codePointAt(0), to = override.to.codePointAt(0);
|
|
4851
|
+
if ([...override.from].length !== 1 || [...override.to].length !== 1 || from >= to || !Number.isInteger(override.left) || !Number.isInteger(override.right) || override.right < override.left) {
|
|
4852
|
+
throw new Error(`Invalid Unihex size override in font ${fontKey.toNamespacedString()}`);
|
|
4853
|
+
}
|
|
4854
|
+
return { ...override, from, to };
|
|
4855
|
+
});
|
|
4856
|
+
} catch (error) {
|
|
4857
|
+
console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
|
|
4858
|
+
return glyphs;
|
|
4859
|
+
}
|
|
4860
|
+
const file = await Caching.unihexCache.get(key.serialize(), () => parseUnihex(key));
|
|
4861
|
+
if (!file) return glyphs;
|
|
4862
|
+
let atlas = atlases.get(provider);
|
|
4863
|
+
if (!atlas) {
|
|
4864
|
+
atlas = new UnihexAtlas();
|
|
4865
|
+
atlases.set(provider, atlas);
|
|
4866
|
+
}
|
|
4867
|
+
for (const character of characters) {
|
|
4868
|
+
const codepoint = character.codePointAt(0), index = file.indices[codepoint];
|
|
4869
|
+
if (index < 0) continue;
|
|
4870
|
+
const record = {
|
|
4871
|
+
rows: file.rows.subarray(index * GLYPH_HEIGHT, (index + 1) * GLYPH_HEIGHT),
|
|
4872
|
+
bitWidth: file.metrics[index * 3],
|
|
4873
|
+
left: file.metrics[index * 3 + 1],
|
|
4874
|
+
right: file.metrics[index * 3 + 2]
|
|
4875
|
+
};
|
|
4876
|
+
const override = overrides.find((range) => codepoint >= range.from && codepoint <= range.to);
|
|
4877
|
+
if (override) {
|
|
4878
|
+
record.left = override.left;
|
|
4879
|
+
record.right = override.right;
|
|
4880
|
+
}
|
|
4881
|
+
const width = record.right - record.left + 1;
|
|
4882
|
+
let rendered;
|
|
4883
|
+
const render = () => rendered ?? (rendered = atlas.draw(record));
|
|
4884
|
+
glyphs.set(character, {
|
|
4885
|
+
get image() {
|
|
4886
|
+
return render().image;
|
|
4887
|
+
},
|
|
4888
|
+
get x() {
|
|
4889
|
+
return render().x;
|
|
4890
|
+
},
|
|
4891
|
+
get y() {
|
|
4892
|
+
return render().y;
|
|
4893
|
+
},
|
|
4894
|
+
width,
|
|
4895
|
+
height: GLYPH_HEIGHT,
|
|
4896
|
+
scale: 0.5,
|
|
4897
|
+
ascent: 7,
|
|
4898
|
+
advance: Math.floor(width / 2) + 1,
|
|
4899
|
+
boldOffset: 0.5,
|
|
4900
|
+
shadowOffset: 0.5
|
|
4901
|
+
});
|
|
4902
|
+
}
|
|
4903
|
+
return glyphs;
|
|
4904
|
+
}
|
|
4905
|
+
var import_zip2, ATLAS_SIZE, GLYPH_HEIGHT, UnihexAtlas, atlases;
|
|
4906
|
+
var init_Unihex = __esm({
|
|
4907
|
+
"src/assets/_fonts/Unihex.ts"() {
|
|
4908
|
+
import_zip2 = require("@zip.js/zip.js");
|
|
4909
|
+
init_AssetKey();
|
|
4910
|
+
init_AssetLoader();
|
|
4911
|
+
init_Assets();
|
|
4912
|
+
init_Caching();
|
|
4913
|
+
init_AssetParsers();
|
|
4914
|
+
init_CanvasCompat();
|
|
4915
|
+
ATLAS_SIZE = 512;
|
|
4916
|
+
GLYPH_HEIGHT = 16;
|
|
4917
|
+
UnihexAtlas = class {
|
|
4918
|
+
constructor() {
|
|
4919
|
+
this.x = 0;
|
|
4920
|
+
this.y = 0;
|
|
4921
|
+
}
|
|
4922
|
+
draw(glyph) {
|
|
4923
|
+
const width = glyph.right - glyph.left + 1;
|
|
4924
|
+
if (this.image && this.x + width > this.image.width) {
|
|
4925
|
+
this.x = 0;
|
|
4926
|
+
this.y += GLYPH_HEIGHT;
|
|
4927
|
+
}
|
|
4928
|
+
if (!this.image || this.y + GLYPH_HEIGHT > this.image.height || width > this.image.width) {
|
|
4929
|
+
this.image = createCanvas(Math.max(ATLAS_SIZE, width), ATLAS_SIZE);
|
|
4930
|
+
this.x = 0;
|
|
4931
|
+
this.y = 0;
|
|
4932
|
+
}
|
|
4933
|
+
const context = this.image.getContext("2d");
|
|
4934
|
+
const pixels = context.createImageData(width, GLYPH_HEIGHT);
|
|
4935
|
+
for (let y = 0; y < GLYPH_HEIGHT; y++) {
|
|
4936
|
+
for (let x = 0; x < width; x++) {
|
|
4937
|
+
const column = glyph.left + x;
|
|
4938
|
+
if (column < 0 || column >= glyph.bitWidth || !(glyph.rows[y] >>> glyph.bitWidth - column - 1 & 1)) continue;
|
|
4939
|
+
pixels.data.fill(255, (y * width + x) * 4, (y * width + x + 1) * 4);
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4942
|
+
const result = { image: this.image, x: this.x, y: this.y };
|
|
4943
|
+
context.putImageData(pixels, this.x, this.y);
|
|
4944
|
+
this.x += width;
|
|
4945
|
+
return result;
|
|
4946
|
+
}
|
|
4947
|
+
};
|
|
4948
|
+
atlases = /* @__PURE__ */ new WeakMap();
|
|
4949
|
+
}
|
|
4950
|
+
});
|
|
4951
|
+
|
|
4765
4952
|
// src/assets/Fonts.ts
|
|
4766
4953
|
var Fonts;
|
|
4767
4954
|
var init_Fonts = __esm({
|
|
@@ -4772,7 +4959,7 @@ var init_Fonts = __esm({
|
|
|
4772
4959
|
init_ModelTextures();
|
|
4773
4960
|
init_Caching();
|
|
4774
4961
|
Fonts = class {
|
|
4775
|
-
/** Combines font definitions in source-priority order.
|
|
4962
|
+
/** Combines font definitions in source-priority order. TrueType providers are skipped. */
|
|
4776
4963
|
static async get(key = "minecraft:default") {
|
|
4777
4964
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
4778
4965
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -4788,6 +4975,7 @@ var init_Fonts = __esm({
|
|
|
4788
4975
|
const stack = await AssetLoader.getAll(key, "json" /* JSON */);
|
|
4789
4976
|
if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
|
|
4790
4977
|
const glyphs = /* @__PURE__ */ new Map();
|
|
4978
|
+
const providers = [];
|
|
4791
4979
|
for (const asset2 of stack) {
|
|
4792
4980
|
for (const provider of asset2.providers) {
|
|
4793
4981
|
if (provider.filter?.uniform || provider.filter?.jp) continue;
|
|
@@ -4806,17 +4994,43 @@ var init_Fonts = __esm({
|
|
|
4806
4994
|
break;
|
|
4807
4995
|
case "reference":
|
|
4808
4996
|
case "minecraft:reference":
|
|
4809
|
-
|
|
4997
|
+
const reference = await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized]);
|
|
4998
|
+
if (reference.resolve) {
|
|
4999
|
+
providers.push(async (characters) => {
|
|
5000
|
+
await reference.resolve(characters);
|
|
5001
|
+
return reference.glyphs;
|
|
5002
|
+
});
|
|
5003
|
+
continue;
|
|
5004
|
+
}
|
|
5005
|
+
provided = reference.glyphs;
|
|
4810
5006
|
break;
|
|
5007
|
+
case "unihex":
|
|
5008
|
+
case "minecraft:unihex":
|
|
5009
|
+
providers.push(async (characters) => (await Promise.resolve().then(() => (init_Unihex(), Unihex_exports))).loadUnihex(provider, key, characters));
|
|
5010
|
+
continue;
|
|
4811
5011
|
default:
|
|
4812
5012
|
continue;
|
|
4813
5013
|
}
|
|
4814
|
-
for (const [character, glyph] of provided) {
|
|
5014
|
+
if (providers.every((provider2) => provider2 instanceof Map)) for (const [character, glyph] of provided) {
|
|
4815
5015
|
if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
|
|
4816
5016
|
}
|
|
5017
|
+
providers.push(provided);
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
return { glyphs, resolve: providers.every((provider) => provider instanceof Map) ? void 0 : async (characters) => {
|
|
5021
|
+
const remaining = new Set([...characters].filter((character) => character !== "\0" && character !== "\n" && character !== "\r" && !glyphs.has(character)));
|
|
5022
|
+
for (const provider of providers) {
|
|
5023
|
+
if (!remaining.size) break;
|
|
5024
|
+
const provided = provider instanceof Map ? provider : await provider([...remaining].join(""));
|
|
5025
|
+
for (const character of remaining) {
|
|
5026
|
+
const glyph = provided.get(character);
|
|
5027
|
+
if (glyph) {
|
|
5028
|
+
glyphs.set(character, glyph);
|
|
5029
|
+
remaining.delete(character);
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
4817
5032
|
}
|
|
4818
|
-
}
|
|
4819
|
-
return { glyphs };
|
|
5033
|
+
} };
|
|
4820
5034
|
}
|
|
4821
5035
|
static async bitmap(provider, fontKey) {
|
|
4822
5036
|
const rows = provider.chars.map((row) => [...row]);
|
|
@@ -4909,6 +5123,13 @@ var init_EntityAnimation = __esm({
|
|
|
4909
5123
|
});
|
|
4910
5124
|
|
|
4911
5125
|
// src/entity/scene/EntityAnimationPlayer.ts
|
|
5126
|
+
function validateAnimationWeights(weights, count) {
|
|
5127
|
+
const values = Array.from(weights);
|
|
5128
|
+
if (values.length !== count || values.some((weight) => !Number.isFinite(weight) || weight < 0)) {
|
|
5129
|
+
throw new Error("Animation weights must match the clip count and contain only finite nonnegative numbers");
|
|
5130
|
+
}
|
|
5131
|
+
return values;
|
|
5132
|
+
}
|
|
4912
5133
|
var import_three11, ZERO, EntityAnimationPlayer;
|
|
4913
5134
|
var init_EntityAnimationPlayer = __esm({
|
|
4914
5135
|
"src/entity/scene/EntityAnimationPlayer.ts"() {
|
|
@@ -4918,12 +5139,20 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
4918
5139
|
EntityAnimationPlayer = class {
|
|
4919
5140
|
constructor() {
|
|
4920
5141
|
this.parts = [];
|
|
5142
|
+
this._animations = [];
|
|
5143
|
+
this._weights = [];
|
|
5144
|
+
this.loops = [];
|
|
4921
5145
|
this._time = 0;
|
|
4922
|
-
this.loop = false;
|
|
4923
5146
|
this.speed = 1;
|
|
4924
5147
|
}
|
|
4925
5148
|
get animation() {
|
|
4926
|
-
return this.
|
|
5149
|
+
return this._animations[0];
|
|
5150
|
+
}
|
|
5151
|
+
get animations() {
|
|
5152
|
+
return this._animations.slice();
|
|
5153
|
+
}
|
|
5154
|
+
get weights() {
|
|
5155
|
+
return this._weights.slice();
|
|
4927
5156
|
}
|
|
4928
5157
|
get time() {
|
|
4929
5158
|
return this._time;
|
|
@@ -4933,10 +5162,20 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
4933
5162
|
* without them, the current pose is used. Stopping restores the pose from before playback.
|
|
4934
5163
|
*/
|
|
4935
5164
|
play(layers, animation, options = {}, poses) {
|
|
5165
|
+
this.playAnimations(layers, [animation], options, poses);
|
|
5166
|
+
}
|
|
5167
|
+
/**
|
|
5168
|
+
* Starts clips on matching parts with a shared clock. Weighted offsets add to the supplied baked poses
|
|
5169
|
+
* or, without poses, to each animated part's pose when playback starts.
|
|
5170
|
+
*/
|
|
5171
|
+
playAnimations(layers, animations, options = {}, poses) {
|
|
5172
|
+
const weights = validateAnimationWeights(options.weights ?? animations.map(() => 1), animations.length);
|
|
4936
5173
|
this.stop();
|
|
4937
|
-
this.
|
|
5174
|
+
this._animations = animations.slice();
|
|
5175
|
+
this._weights = weights;
|
|
5176
|
+
if (!animations.length) return;
|
|
4938
5177
|
this._time = options.time ?? 0;
|
|
4939
|
-
this.
|
|
5178
|
+
this.loops = animations.map((animation) => options.loop ?? animation.loop);
|
|
4940
5179
|
this.speed = options.speed ?? 1;
|
|
4941
5180
|
for (const layer of layers) {
|
|
4942
5181
|
const objects = [];
|
|
@@ -4945,7 +5184,8 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
4945
5184
|
if (poses.has(object4)) objects.push(object4);
|
|
4946
5185
|
});
|
|
4947
5186
|
} else {
|
|
4948
|
-
|
|
5187
|
+
const bones = new Set(animations.flatMap((animation) => Object.keys(animation.bones)));
|
|
5188
|
+
for (const bone of bones) {
|
|
4949
5189
|
const object4 = layer.getObjectByName(`group:${bone}`);
|
|
4950
5190
|
if (object4) objects.push(object4);
|
|
4951
5191
|
}
|
|
@@ -4969,7 +5209,7 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
4969
5209
|
}
|
|
4970
5210
|
/** Restores the poses from before playback. Returns whether an animation was active. */
|
|
4971
5211
|
stop() {
|
|
4972
|
-
if (!this.
|
|
5212
|
+
if (!this._animations.length) return false;
|
|
4973
5213
|
for (const part of this.parts) {
|
|
4974
5214
|
part.object.position.copy(part.position);
|
|
4975
5215
|
part.object.rotation.copy(part.rotation);
|
|
@@ -4981,12 +5221,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
4981
5221
|
/** Forgets the animation without touching the parts, for parts that no longer exist. */
|
|
4982
5222
|
clear() {
|
|
4983
5223
|
this.parts = [];
|
|
4984
|
-
this.
|
|
5224
|
+
this._animations = [];
|
|
5225
|
+
this._weights = [];
|
|
5226
|
+
this.loops = [];
|
|
4985
5227
|
this._time = 0;
|
|
4986
5228
|
}
|
|
4987
5229
|
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
4988
5230
|
setTime(seconds) {
|
|
4989
|
-
if (!this.
|
|
5231
|
+
if (!this._animations.length) return false;
|
|
4990
5232
|
this._time = seconds;
|
|
4991
5233
|
this.apply();
|
|
4992
5234
|
return true;
|
|
@@ -4995,8 +5237,30 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
4995
5237
|
advance(deltaSeconds) {
|
|
4996
5238
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
4997
5239
|
}
|
|
5240
|
+
/** Changes weights in clip order and reapplies the current time without restarting playback. */
|
|
5241
|
+
setWeights(weights) {
|
|
5242
|
+
if (!this._animations.length) return false;
|
|
5243
|
+
const validated = validateAnimationWeights(weights, this._animations.length);
|
|
5244
|
+
this._weights = validated;
|
|
5245
|
+
this.apply();
|
|
5246
|
+
return true;
|
|
5247
|
+
}
|
|
4998
5248
|
apply() {
|
|
4999
|
-
const pose =
|
|
5249
|
+
const pose = /* @__PURE__ */ Object.create(null);
|
|
5250
|
+
for (let i = 0; i < this._animations.length; i++) {
|
|
5251
|
+
const weight = this._weights[i];
|
|
5252
|
+
if (weight === 0) continue;
|
|
5253
|
+
const sampled = sampleEntityAnimation(this._animations[i], this._time, this.loops[i]);
|
|
5254
|
+
for (const [bone, channels] of Object.entries(sampled)) {
|
|
5255
|
+
const blended = pose[bone] ?? (pose[bone] = {});
|
|
5256
|
+
for (const channel of ENTITY_ANIMATION_CHANNELS) {
|
|
5257
|
+
const value = channels[channel];
|
|
5258
|
+
if (!value) continue;
|
|
5259
|
+
const target = blended[channel] ?? (blended[channel] = [0, 0, 0]);
|
|
5260
|
+
for (let axis = 0; axis < 3; axis++) target[axis] += value[axis] * weight;
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5000
5264
|
for (const part of this.parts) {
|
|
5001
5265
|
const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone] ?? {};
|
|
5002
5266
|
part.object.position.set(part.basePosition.x + position[0], part.basePosition.y + position[1], part.basePosition.z + position[2]);
|
|
@@ -5616,7 +5880,7 @@ var init_EntityObject = __esm({
|
|
|
5616
5880
|
for (const geometry of this.geometries) geometry.dispose();
|
|
5617
5881
|
this.geometries.clear();
|
|
5618
5882
|
for (const dispose of this.disposeWireframes.splice(0)) dispose();
|
|
5619
|
-
for (const player of this.animationPlayers.splice(0)) player.clear();
|
|
5883
|
+
for (const { player } of this.animationPlayers.splice(0)) player.clear();
|
|
5620
5884
|
this.partPoses.clear();
|
|
5621
5885
|
super.disposeAndRemoveAllChildren();
|
|
5622
5886
|
}
|
|
@@ -5651,15 +5915,31 @@ var init_EntityObject = __esm({
|
|
|
5651
5915
|
//<editor-fold desc="ANIMATION">
|
|
5652
5916
|
/** The first active clip, until playback is stopped or the object is disposed. */
|
|
5653
5917
|
get animation() {
|
|
5654
|
-
return this.animationPlayers[0]?.animation;
|
|
5918
|
+
return this.animationPlayers[0]?.player.animation;
|
|
5655
5919
|
}
|
|
5656
|
-
/** Clips playing together,
|
|
5920
|
+
/** Clips playing together, in the order passed to {@link playAnimations}. */
|
|
5657
5921
|
get activeAnimations() {
|
|
5658
|
-
|
|
5922
|
+
const animations = [];
|
|
5923
|
+
for (const { player, indices } of this.animationPlayers) {
|
|
5924
|
+
player.animations.forEach((animation, i) => {
|
|
5925
|
+
animations[indices[i]] = animation;
|
|
5926
|
+
});
|
|
5927
|
+
}
|
|
5928
|
+
return animations;
|
|
5929
|
+
}
|
|
5930
|
+
/** Weights of the active clips, in the same order as {@link activeAnimations}. */
|
|
5931
|
+
get animationWeights() {
|
|
5932
|
+
const weights = [];
|
|
5933
|
+
for (const { player, indices } of this.animationPlayers) {
|
|
5934
|
+
player.weights.forEach((weight, i) => {
|
|
5935
|
+
weights[indices[i]] = weight;
|
|
5936
|
+
});
|
|
5937
|
+
}
|
|
5938
|
+
return weights;
|
|
5659
5939
|
}
|
|
5660
5940
|
/** Seconds since the animation started, before looping. */
|
|
5661
5941
|
get animationTime() {
|
|
5662
|
-
return this.animationPlayers[0]?.time ?? 0;
|
|
5942
|
+
return this.animationPlayers[0]?.player.time ?? 0;
|
|
5663
5943
|
}
|
|
5664
5944
|
/**
|
|
5665
5945
|
* Plays a clip from {@link Entities.getAnimations}, replacing all active clips.
|
|
@@ -5670,42 +5950,59 @@ var init_EntityObject = __esm({
|
|
|
5670
5950
|
playAnimation(animation, options) {
|
|
5671
5951
|
this.playAnimations([animation], options);
|
|
5672
5952
|
}
|
|
5673
|
-
/**
|
|
5953
|
+
/**
|
|
5954
|
+
* Plays clips with a shared clock, adding their weighted offsets within each geometry layer.
|
|
5955
|
+
* Weights default to 1 and are not normalized. Selected layers without their own clip follow `main`.
|
|
5956
|
+
*/
|
|
5674
5957
|
playAnimations(animations, options) {
|
|
5675
|
-
const
|
|
5676
|
-
const selections =
|
|
5958
|
+
const weights = validateAnimationWeights(options?.weights ?? animations.map(() => 1), animations.length);
|
|
5959
|
+
const selections = /* @__PURE__ */ new Map();
|
|
5960
|
+
animations.forEach((animation, index) => {
|
|
5677
5961
|
const layer = animation.layer ?? "main";
|
|
5678
|
-
if (targets.has(layer)) throw new Error(`Multiple animations target layer "${layer}"`);
|
|
5679
|
-
targets.add(layer);
|
|
5680
5962
|
const names = Object.keys(this.entityLayers).filter((name) => name.split("#")[0] === layer);
|
|
5681
5963
|
if (!names.length) throw new Error(`Entity ${this.entity.id} has no selected animation layer "${layer}"`);
|
|
5682
|
-
|
|
5964
|
+
let selection = selections.get(layer);
|
|
5965
|
+
if (!selection) selections.set(layer, selection = { animations: [], names, indices: [] });
|
|
5966
|
+
selection.animations.push(animation);
|
|
5967
|
+
selection.indices.push(index);
|
|
5683
5968
|
});
|
|
5684
|
-
const main = selections.
|
|
5685
|
-
if (main) main.names.push(...Object.keys(this.entityLayers).filter((name) => !
|
|
5969
|
+
const main = selections.get("main");
|
|
5970
|
+
if (main) main.names.push(...Object.keys(this.entityLayers).filter((name) => !selections.has(name.split("#")[0])));
|
|
5686
5971
|
this.createMeshes();
|
|
5687
5972
|
this.stopAnimation();
|
|
5688
|
-
for (const {
|
|
5973
|
+
for (const { animations: clips, names, indices } of selections.values()) {
|
|
5689
5974
|
const player = new EntityAnimationPlayer();
|
|
5690
|
-
player.
|
|
5691
|
-
|
|
5975
|
+
player.playAnimations(
|
|
5976
|
+
names.map((name) => this.getLayerGroup(name)),
|
|
5977
|
+
clips,
|
|
5978
|
+
{ ...options, weights: indices.map((index) => weights[index]) },
|
|
5979
|
+
this.partPoses
|
|
5980
|
+
);
|
|
5981
|
+
this.animationPlayers.push({ player, indices });
|
|
5692
5982
|
}
|
|
5693
5983
|
this.notifyDirty();
|
|
5694
5984
|
}
|
|
5985
|
+
/** Changes weights in active clip order, notifying the scene without restarting the shared clock. Has no effect without an animation. */
|
|
5986
|
+
setAnimationWeights(weights) {
|
|
5987
|
+
if (!this.animationPlayers.length) return;
|
|
5988
|
+
const values = validateAnimationWeights(weights, this.activeAnimations.length);
|
|
5989
|
+
for (const { player, indices } of this.animationPlayers) player.setWeights(indices.map((index) => values[index]));
|
|
5990
|
+
this.notifyDirty();
|
|
5991
|
+
}
|
|
5695
5992
|
/** Stops all clips and restores the poses from before playback. */
|
|
5696
5993
|
stopAnimation() {
|
|
5697
5994
|
const players = this.animationPlayers.splice(0);
|
|
5698
|
-
for (const player of players) player.stop();
|
|
5995
|
+
for (const { player } of players) player.stop();
|
|
5699
5996
|
if (players.length) this.notifyDirty();
|
|
5700
5997
|
}
|
|
5701
5998
|
/** Poses the object at an explicit time in seconds. Has no effect without an animation. */
|
|
5702
5999
|
setAnimationTime(seconds) {
|
|
5703
|
-
for (const player of this.animationPlayers) player.setTime(seconds);
|
|
6000
|
+
for (const { player } of this.animationPlayers) player.setTime(seconds);
|
|
5704
6001
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
5705
6002
|
}
|
|
5706
6003
|
/** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
|
|
5707
6004
|
advanceAnimation(deltaSeconds) {
|
|
5708
|
-
for (const player of this.animationPlayers) player.advance(deltaSeconds);
|
|
6005
|
+
for (const { player } of this.animationPlayers) player.advance(deltaSeconds);
|
|
5709
6006
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
5710
6007
|
}
|
|
5711
6008
|
//</editor-fold>
|
|
@@ -7940,6 +8237,7 @@ async function layoutGuiText(text2, options = {}) {
|
|
|
7940
8237
|
}
|
|
7941
8238
|
const font = await Fonts.get(options.font);
|
|
7942
8239
|
const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
|
|
8240
|
+
await font.resolve?.(runs.map((run) => run.text).join(""));
|
|
7943
8241
|
const glyphs = [], lineWidths = [];
|
|
7944
8242
|
let line = [], width = 0;
|
|
7945
8243
|
let trailingNewline = false;
|
|
@@ -7966,7 +8264,7 @@ async function layoutGuiText(text2, options = {}) {
|
|
|
7966
8264
|
continue;
|
|
7967
8265
|
}
|
|
7968
8266
|
const glyph = font.glyphs.get(character);
|
|
7969
|
-
const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
|
|
8267
|
+
const advance = (glyph?.advance ?? 6) + (style.bold ? glyph?.boldOffset ?? 1 : 0);
|
|
7970
8268
|
line.push({ character, glyph, advance, style, x: 0, y: 0 });
|
|
7971
8269
|
width += advance;
|
|
7972
8270
|
while (width > maxWidth && line.length > 1) {
|
|
@@ -7994,7 +8292,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
7994
8292
|
batches.push(batch);
|
|
7995
8293
|
}
|
|
7996
8294
|
const color2 = new import_three20.Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
|
|
7997
|
-
const offset = isShadow ? 1 : 0;
|
|
8295
|
+
const offset = isShadow ? glyph?.shadowOffset ?? 1 : 0;
|
|
7998
8296
|
const top = glyph ? 7 - glyph.ascent : 0;
|
|
7999
8297
|
const height = glyph ? glyph.height * glyph.scale : 8;
|
|
8000
8298
|
const width = glyph ? glyph.width * glyph.scale : 5;
|
|
@@ -8024,7 +8322,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
8024
8322
|
for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
|
|
8025
8323
|
batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
|
|
8026
8324
|
};
|
|
8027
|
-
for (const boldOffset of style.bold ? [0, 1] : [0]) {
|
|
8325
|
+
for (const boldOffset of style.bold ? [0, glyph?.boldOffset ?? 1] : [0]) {
|
|
8028
8326
|
if (glyph) quad(0, top, width, top + height, boldOffset);
|
|
8029
8327
|
else {
|
|
8030
8328
|
quad(0, 0, 5, 1, boldOffset);
|
|
@@ -9795,6 +10093,10 @@ var init_ModelObject = __esm({
|
|
|
9795
10093
|
this.atlas.model.elements?.forEach((el) => {
|
|
9796
10094
|
const elGeo = this._getBoxGeometryFromElement(el).clone();
|
|
9797
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
|
+
));
|
|
9798
10100
|
if (this.options.cullMask) {
|
|
9799
10101
|
const indices = Array.from(elGeo.getIndex().array);
|
|
9800
10102
|
elGeo.setIndex(indices.filter((_, index) => {
|
|
@@ -11299,6 +11601,7 @@ __export(index_browser_exports, {
|
|
|
11299
11601
|
toRadians: () => toRadians,
|
|
11300
11602
|
toTrianglesDrawMode: () => toTrianglesDrawMode,
|
|
11301
11603
|
trimCanvas: () => trimCanvas,
|
|
11604
|
+
validateAnimationWeights: () => validateAnimationWeights,
|
|
11302
11605
|
yieldToEventLoop: () => yieldToEventLoop
|
|
11303
11606
|
});
|
|
11304
11607
|
module.exports = __toCommonJS(index_browser_exports);
|
|
@@ -17666,9 +17969,9 @@ function cached(map, key, load) {
|
|
|
17666
17969
|
function compactQuads(geometry, keep) {
|
|
17667
17970
|
const quads = keep.flatMap((kept, index) => kept ? [index] : []);
|
|
17668
17971
|
const compact = new import_three41.BufferGeometry();
|
|
17669
|
-
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 })) {
|
|
17670
17973
|
const source2 = geometry.getAttribute(name);
|
|
17671
|
-
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;
|
|
17672
17975
|
const values = new Float32Array(quads.length * 4 * size);
|
|
17673
17976
|
for (let q = 0; q < quads.length; q++) {
|
|
17674
17977
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
@@ -18916,7 +19219,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18916
19219
|
|
|
18917
19220
|
// src/world/SectionGeometry.ts
|
|
18918
19221
|
function buildSectionGeometry(input) {
|
|
18919
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
19222
|
+
const { count, indices, templates, cullMasks, templateData, atlases: atlases2, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
18920
19223
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18921
19224
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18922
19225
|
if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
|
|
@@ -18934,7 +19237,7 @@ function buildSectionGeometry(input) {
|
|
|
18934
19237
|
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18935
19238
|
for (const template of templateData) {
|
|
18936
19239
|
const { quads } = template;
|
|
18937
|
-
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) {
|
|
18938
19241
|
throw new RangeError("Section template arrays do not match its quad count");
|
|
18939
19242
|
}
|
|
18940
19243
|
}
|
|
@@ -18951,8 +19254,8 @@ function buildSectionGeometry(input) {
|
|
|
18951
19254
|
const locations = /* @__PURE__ */ new Map();
|
|
18952
19255
|
for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a], [b]) => a - b)) {
|
|
18953
19256
|
const firstPage = pages.length;
|
|
18954
|
-
for (const atlas of [...layerAtlases].sort((a, b) => Number(
|
|
18955
|
-
const { width, height, animated } =
|
|
19257
|
+
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))) {
|
|
19258
|
+
const { width, height, animated } = atlases2[atlas];
|
|
18956
19259
|
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
18957
19260
|
let selected = -1;
|
|
18958
19261
|
for (let i = firstPage; !animated && i < pages.length; i++) {
|
|
@@ -18995,7 +19298,7 @@ function buildSectionGeometry(input) {
|
|
|
18995
19298
|
});
|
|
18996
19299
|
if (!quads.sprites.length) continue;
|
|
18997
19300
|
if (!fluidPages.has(fluid)) {
|
|
18998
|
-
const { width, height } =
|
|
19301
|
+
const { width, height } = atlases2[data.atlas];
|
|
18999
19302
|
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
19000
19303
|
fluidPages.set(fluid, {
|
|
19001
19304
|
layer: 2,
|
|
@@ -19013,7 +19316,7 @@ function buildSectionGeometry(input) {
|
|
|
19013
19316
|
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
19014
19317
|
fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
|
|
19015
19318
|
}
|
|
19016
|
-
pages.push(...[...fluidPages.values()].sort((a, b) => Number(
|
|
19319
|
+
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));
|
|
19017
19320
|
}
|
|
19018
19321
|
return pages.map((page) => {
|
|
19019
19322
|
let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);
|
|
@@ -19025,12 +19328,13 @@ function buildSectionGeometry(input) {
|
|
|
19025
19328
|
}
|
|
19026
19329
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
19027
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);
|
|
19028
19332
|
const outputIndices = new Uint32Array(faces * 6);
|
|
19029
19333
|
const blockIndices = new Uint16Array(faces);
|
|
19030
19334
|
let vertex = 0, indexOffset = 0;
|
|
19031
19335
|
for (const entry of page.entries) {
|
|
19032
19336
|
const template = templateData[templates[entry]];
|
|
19033
|
-
const atlas =
|
|
19337
|
+
const atlas = atlases2[template.atlas];
|
|
19034
19338
|
const placement = locations.get(template.atlas);
|
|
19035
19339
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
19036
19340
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
@@ -19054,6 +19358,7 @@ function buildSectionGeometry(input) {
|
|
|
19054
19358
|
normals[vertex * 3] = template.normals[source * 3];
|
|
19055
19359
|
normals[vertex * 3 + 1] = template.normals[source * 3 + 1];
|
|
19056
19360
|
normals[vertex * 3 + 2] = template.normals[source * 3 + 2];
|
|
19361
|
+
shade[vertex] = template.shade?.[source] ?? 1;
|
|
19057
19362
|
uvs[vertex * 2] = mapU(template.uvs[source * 2]);
|
|
19058
19363
|
uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
|
|
19059
19364
|
uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);
|
|
@@ -19069,7 +19374,7 @@ function buildSectionGeometry(input) {
|
|
|
19069
19374
|
}
|
|
19070
19375
|
}
|
|
19071
19376
|
for (const { quads, x, y, z, data, tint } of page.fluids) {
|
|
19072
|
-
const atlas =
|
|
19377
|
+
const atlas = atlases2[data.atlas];
|
|
19073
19378
|
const placement = page.placements[0];
|
|
19074
19379
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
19075
19380
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
@@ -19106,11 +19411,11 @@ function buildSectionGeometry(input) {
|
|
|
19106
19411
|
indexOffset += 6;
|
|
19107
19412
|
}
|
|
19108
19413
|
}
|
|
19109
|
-
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 };
|
|
19110
19415
|
});
|
|
19111
19416
|
}
|
|
19112
19417
|
function sectionGeometryTransferables(pages) {
|
|
19113
|
-
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]);
|
|
19114
19419
|
}
|
|
19115
19420
|
|
|
19116
19421
|
// src/world/SectionWorker.ts
|
|
@@ -19170,7 +19475,7 @@ var templateCache = /* @__PURE__ */ new WeakMap();
|
|
|
19170
19475
|
var WATER_TINT = new import_three46.Color(4159204).toArray();
|
|
19171
19476
|
function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
19172
19477
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
19173
|
-
const
|
|
19478
|
+
const atlases2 = [];
|
|
19174
19479
|
const atlasIds = /* @__PURE__ */ new Map();
|
|
19175
19480
|
const templateIds = /* @__PURE__ */ new Map();
|
|
19176
19481
|
const input = {
|
|
@@ -19193,9 +19498,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19193
19498
|
if (id === void 0) {
|
|
19194
19499
|
let atlas = atlasIds.get(template.atlas);
|
|
19195
19500
|
if (atlas === void 0) {
|
|
19196
|
-
atlas =
|
|
19501
|
+
atlas = atlases2.length;
|
|
19197
19502
|
atlasIds.set(template.atlas, atlas);
|
|
19198
|
-
|
|
19503
|
+
atlases2.push(template.atlas);
|
|
19199
19504
|
input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });
|
|
19200
19505
|
}
|
|
19201
19506
|
let data = templateCache.get(template);
|
|
@@ -19213,6 +19518,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19213
19518
|
uvs: new Float32Array(quads * 8),
|
|
19214
19519
|
uvBounds: new Float32Array(quads * 16),
|
|
19215
19520
|
colors: new Float32Array(quads * 12),
|
|
19521
|
+
shade: new Float32Array(quads * 4),
|
|
19216
19522
|
indices: new Uint16Array(quads * 6),
|
|
19217
19523
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
19218
19524
|
biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
|
|
@@ -19224,6 +19530,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19224
19530
|
const uv = template.geometry.getAttribute("uv");
|
|
19225
19531
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
19226
19532
|
const color2 = template.geometry.getAttribute("color");
|
|
19533
|
+
const shade = template.geometry.getAttribute("shade");
|
|
19227
19534
|
for (let vertex = 0; vertex < quads * 4; vertex++) {
|
|
19228
19535
|
data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
|
|
19229
19536
|
data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
|
|
@@ -19235,6 +19542,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19235
19542
|
bounds?.getW(vertex) ?? 1
|
|
19236
19543
|
], vertex * 4);
|
|
19237
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;
|
|
19238
19546
|
}
|
|
19239
19547
|
for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - 4 * Math.floor(i2 / 6);
|
|
19240
19548
|
templateCache.set(template, data);
|
|
@@ -19254,9 +19562,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19254
19562
|
if (!atlas) continue;
|
|
19255
19563
|
let id = atlasIds.get(atlas);
|
|
19256
19564
|
if (id === void 0) {
|
|
19257
|
-
id =
|
|
19565
|
+
id = atlases2.length;
|
|
19258
19566
|
atlasIds.set(atlas, id);
|
|
19259
|
-
|
|
19567
|
+
atlases2.push(atlas);
|
|
19260
19568
|
input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });
|
|
19261
19569
|
}
|
|
19262
19570
|
input.fluids[kind] = {
|
|
@@ -19267,7 +19575,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19267
19575
|
};
|
|
19268
19576
|
}
|
|
19269
19577
|
}
|
|
19270
|
-
return { input, atlases };
|
|
19578
|
+
return { input, atlases: atlases2 };
|
|
19271
19579
|
}
|
|
19272
19580
|
var SectionMesh = class _SectionMesh extends import_three46.Group {
|
|
19273
19581
|
constructor() {
|
|
@@ -19282,23 +19590,23 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
|
|
|
19282
19590
|
}
|
|
19283
19591
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
19284
19592
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
19285
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19286
|
-
return this.fromPages(buildSectionGeometry(input),
|
|
19593
|
+
const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19594
|
+
return this.fromPages(buildSectionGeometry(input), atlases2);
|
|
19287
19595
|
}
|
|
19288
19596
|
/** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
|
|
19289
19597
|
static async buildAsync(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
19290
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19598
|
+
const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19291
19599
|
const worker = SectionWorker.shared();
|
|
19292
19600
|
const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
|
|
19293
|
-
return this.fromPages(pages,
|
|
19601
|
+
return this.fromPages(pages, atlases2);
|
|
19294
19602
|
}
|
|
19295
|
-
static fromPages(pages,
|
|
19603
|
+
static fromPages(pages, atlases2) {
|
|
19296
19604
|
const section = new _SectionMesh();
|
|
19297
19605
|
for (const page of pages) {
|
|
19298
19606
|
const canvas = createCanvas(page.width, page.height);
|
|
19299
19607
|
const context = canvas.getContext("2d");
|
|
19300
19608
|
for (const { atlas, x, y } of page.placements) {
|
|
19301
|
-
context.drawImage(
|
|
19609
|
+
context.drawImage(atlases2[atlas].image.canvas, x, y);
|
|
19302
19610
|
}
|
|
19303
19611
|
const geometry = new import_three46.BufferGeometry();
|
|
19304
19612
|
geometry.setAttribute("position", new import_three46.Float32BufferAttribute(page.positions.buffer, 3));
|
|
@@ -19306,10 +19614,11 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
|
|
|
19306
19614
|
geometry.setAttribute("uv", new import_three46.Float32BufferAttribute(page.uvs.buffer, 2));
|
|
19307
19615
|
geometry.setAttribute("uvBounds", new import_three46.Float32BufferAttribute(page.uvBounds.buffer, 4));
|
|
19308
19616
|
geometry.setAttribute("color", new import_three46.Float32BufferAttribute(page.colors.buffer, 3));
|
|
19617
|
+
geometry.setAttribute("shade", new import_three46.Float32BufferAttribute(page.shade.buffer, 1));
|
|
19309
19618
|
geometry.setIndex(new import_three46.Uint32BufferAttribute(page.indices.buffer, 1));
|
|
19310
19619
|
geometry.computeBoundingBox();
|
|
19311
19620
|
geometry.computeBoundingSphere();
|
|
19312
|
-
const transparent = page.layer === 2 ?
|
|
19621
|
+
const transparent = page.layer === 2 ? atlases2[page.placements[0].atlas].hasTranslucency : page.layer === 1;
|
|
19313
19622
|
const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
|
|
19314
19623
|
material.side = import_three46.FrontSide;
|
|
19315
19624
|
if (page.layer === 2) {
|
|
@@ -19324,7 +19633,7 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
|
|
|
19324
19633
|
section.blockIndices.set(mesh, page.blockIndices);
|
|
19325
19634
|
const unsubscribe = [];
|
|
19326
19635
|
for (const { atlas: id, x, y } of page.placements) {
|
|
19327
|
-
const atlas =
|
|
19636
|
+
const atlas = atlases2[id];
|
|
19328
19637
|
if (!atlas.hasAnimation) continue;
|
|
19329
19638
|
unsubscribe.push(atlas.subscribe(() => {
|
|
19330
19639
|
context.clearRect(x, y, atlas.image.width, atlas.image.height);
|