minerender 2.1.0-alpha.132 → 2.1.0-alpha.133
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/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/gui/GuiText.mjs +4 -3
- package/dist/browser/esm/gui/GuiText.mjs.map +1 -1
- package/dist/browser/esm/index.browser.d.mts +23 -4
- package/dist/browser/index.d.ts +23 -4
- package/dist/browser/index.js +245 -31
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +288 -31
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +23 -4
- package/dist/node/index.d.ts +23 -4
- package/dist/node/index.js +249 -31
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +249 -31
- 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,
|
|
@@ -1408,6 +1412,7 @@ var init_AssetParsers = __esm({
|
|
|
1408
1412
|
AssetParser2["IMAGE"] = "image";
|
|
1409
1413
|
AssetParser2["LIST"] = "list";
|
|
1410
1414
|
AssetParser2["JSON"] = "json";
|
|
1415
|
+
AssetParser2["BINARY"] = "binary";
|
|
1411
1416
|
return AssetParser2;
|
|
1412
1417
|
})(AssetParser || {});
|
|
1413
1418
|
}
|
|
@@ -2878,7 +2883,7 @@ var init_parser = __esm({
|
|
|
2878
2883
|
});
|
|
2879
2884
|
|
|
2880
2885
|
// src/assets/source/HostedAssetSource.ts
|
|
2881
|
-
var p3, DEFAULT_OPTIONS, HostedAssetSource;
|
|
2886
|
+
var BINARY_TIMEOUT, p3, DEFAULT_OPTIONS, HostedAssetSource;
|
|
2882
2887
|
var init_HostedAssetSource = __esm({
|
|
2883
2888
|
"src/assets/source/HostedAssetSource.ts"() {
|
|
2884
2889
|
init_AssetSource();
|
|
@@ -2891,6 +2896,7 @@ var init_HostedAssetSource = __esm({
|
|
|
2891
2896
|
init_AssetLoader();
|
|
2892
2897
|
init_parser();
|
|
2893
2898
|
init_merge();
|
|
2899
|
+
BINARY_TIMEOUT = 6e4;
|
|
2894
2900
|
p3 = prefix("HostedAssetSource");
|
|
2895
2901
|
DEFAULT_OPTIONS = {
|
|
2896
2902
|
retryDefaults: true
|
|
@@ -2961,6 +2967,17 @@ var init_HostedAssetSource = __esm({
|
|
|
2961
2967
|
}
|
|
2962
2968
|
};
|
|
2963
2969
|
}
|
|
2970
|
+
static {
|
|
2971
|
+
this.BINARY = {
|
|
2972
|
+
config(request) {
|
|
2973
|
+
request.timeout = BINARY_TIMEOUT;
|
|
2974
|
+
request.responseType = "arraybuffer";
|
|
2975
|
+
},
|
|
2976
|
+
parse(response) {
|
|
2977
|
+
return { data: new Uint8Array(response.data) };
|
|
2978
|
+
}
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2964
2981
|
static {
|
|
2965
2982
|
this.PARSER_MAP = /* @__PURE__ */ new Map([
|
|
2966
2983
|
["model" /* MODEL */, _HostedAssetSource.MODEL],
|
|
@@ -2969,7 +2986,8 @@ var init_HostedAssetSource = __esm({
|
|
|
2969
2986
|
["nbt" /* NBT */, _HostedAssetSource.NBT],
|
|
2970
2987
|
["image" /* IMAGE */, _HostedAssetSource.IMAGE],
|
|
2971
2988
|
["list" /* LIST */, _HostedAssetSource.LIST],
|
|
2972
|
-
["json" /* JSON */, _HostedAssetSource.JSON]
|
|
2989
|
+
["json" /* JSON */, _HostedAssetSource.JSON],
|
|
2990
|
+
["binary" /* BINARY */, _HostedAssetSource.BINARY]
|
|
2973
2991
|
]);
|
|
2974
2992
|
}
|
|
2975
2993
|
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
@@ -4855,6 +4873,178 @@ var init_Entities = __esm({
|
|
|
4855
4873
|
}
|
|
4856
4874
|
});
|
|
4857
4875
|
|
|
4876
|
+
// src/assets/_fonts/Unihex.ts
|
|
4877
|
+
var Unihex_exports = {};
|
|
4878
|
+
__export(Unihex_exports, {
|
|
4879
|
+
loadUnihex: () => loadUnihex
|
|
4880
|
+
});
|
|
4881
|
+
import { TextWriter, Uint8ArrayReader, ZipReader as ZipReader2 } from "@zip.js/zip.js";
|
|
4882
|
+
function readHex(text2, filename, glyphs) {
|
|
4883
|
+
const lines = text2.split("\n");
|
|
4884
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
4885
|
+
lines.forEach((line, index) => {
|
|
4886
|
+
const match = /^([0-9A-F]{4,6}):([0-9A-F]+)$/.exec(line);
|
|
4887
|
+
if (!match || ![32, 64, 96, 128].includes(match[2].length)) {
|
|
4888
|
+
throw new Error(`Invalid Unihex record in ${filename} at line ${index + 1}`);
|
|
4889
|
+
}
|
|
4890
|
+
const codepoint = parseInt(match[1], 16);
|
|
4891
|
+
if (codepoint > 1114111) throw new Error(`Invalid Unihex codepoint in ${filename} at line ${index + 1}`);
|
|
4892
|
+
const bitWidth = match[2].length / 4;
|
|
4893
|
+
const rowLength = bitWidth / 4;
|
|
4894
|
+
const rows = new Uint32Array(GLYPH_HEIGHT);
|
|
4895
|
+
let mask = 0;
|
|
4896
|
+
for (let y = 0; y < GLYPH_HEIGHT; y++) {
|
|
4897
|
+
rows[y] = parseInt(match[2].slice(y * rowLength, (y + 1) * rowLength), 16);
|
|
4898
|
+
mask |= rows[y];
|
|
4899
|
+
}
|
|
4900
|
+
let left = 0, right = bitWidth;
|
|
4901
|
+
if (mask) {
|
|
4902
|
+
while (!(mask >>> bitWidth - left - 1 & 1)) left++;
|
|
4903
|
+
right = bitWidth - 1;
|
|
4904
|
+
while (!(mask >>> bitWidth - right - 1 & 1)) right--;
|
|
4905
|
+
}
|
|
4906
|
+
glyphs.set(codepoint, { rows, bitWidth, left, right });
|
|
4907
|
+
});
|
|
4908
|
+
}
|
|
4909
|
+
async function parseUnihex(key) {
|
|
4910
|
+
try {
|
|
4911
|
+
const asset2 = await AssetLoader.get(key, "binary" /* BINARY */);
|
|
4912
|
+
if (!asset2) throw new Error(`Could not load Unihex archive ${key.toNamespacedString()}`);
|
|
4913
|
+
const records = /* @__PURE__ */ new Map();
|
|
4914
|
+
const reader = new ZipReader2(new Uint8ArrayReader(asset2.data), { useWebWorkers: false, useCompressionStream: false });
|
|
4915
|
+
try {
|
|
4916
|
+
for (const entry of await reader.getEntries()) {
|
|
4917
|
+
if (!entry.directory && entry.filename.endsWith(".hex")) {
|
|
4918
|
+
readHex(await entry.getData(new TextWriter(), { checkSignature: true }), entry.filename, records);
|
|
4919
|
+
}
|
|
4920
|
+
}
|
|
4921
|
+
} finally {
|
|
4922
|
+
await reader.close();
|
|
4923
|
+
}
|
|
4924
|
+
const indices = new Int32Array(1114112).fill(-1);
|
|
4925
|
+
const rows = new Uint32Array(records.size * GLYPH_HEIGHT), metrics = new Uint8Array(records.size * 3);
|
|
4926
|
+
let index = 0;
|
|
4927
|
+
for (const [codepoint, record] of records) {
|
|
4928
|
+
indices[codepoint] = index;
|
|
4929
|
+
rows.set(record.rows, index * GLYPH_HEIGHT);
|
|
4930
|
+
metrics.set([record.bitWidth, record.left, record.right], index * 3);
|
|
4931
|
+
index++;
|
|
4932
|
+
}
|
|
4933
|
+
return { indices, rows, metrics };
|
|
4934
|
+
} catch (error) {
|
|
4935
|
+
console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
|
|
4936
|
+
return void 0;
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
async function loadUnihex(provider, fontKey, characters) {
|
|
4940
|
+
const origin = new AssetKey(DEFAULT_NAMESPACE, "", void 0, void 0, "assets", "", fontKey.root);
|
|
4941
|
+
const key = AssetKey.parse("font", provider.hex_file, origin);
|
|
4942
|
+
key.assetType = void 0;
|
|
4943
|
+
const glyphs = /* @__PURE__ */ new Map();
|
|
4944
|
+
let overrides;
|
|
4945
|
+
try {
|
|
4946
|
+
overrides = (provider.size_overrides ?? []).map((override) => {
|
|
4947
|
+
const from = override.from.codePointAt(0), to = override.to.codePointAt(0);
|
|
4948
|
+
if ([...override.from].length !== 1 || [...override.to].length !== 1 || from >= to || !Number.isInteger(override.left) || !Number.isInteger(override.right) || override.right < override.left) {
|
|
4949
|
+
throw new Error(`Invalid Unihex size override in font ${fontKey.toNamespacedString()}`);
|
|
4950
|
+
}
|
|
4951
|
+
return { ...override, from, to };
|
|
4952
|
+
});
|
|
4953
|
+
} catch (error) {
|
|
4954
|
+
console.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
|
|
4955
|
+
return glyphs;
|
|
4956
|
+
}
|
|
4957
|
+
const file = await Caching.unihexCache.get(key.serialize(), () => parseUnihex(key));
|
|
4958
|
+
if (!file) return glyphs;
|
|
4959
|
+
let atlas = atlases.get(provider);
|
|
4960
|
+
if (!atlas) {
|
|
4961
|
+
atlas = new UnihexAtlas();
|
|
4962
|
+
atlases.set(provider, atlas);
|
|
4963
|
+
}
|
|
4964
|
+
for (const character of characters) {
|
|
4965
|
+
const codepoint = character.codePointAt(0), index = file.indices[codepoint];
|
|
4966
|
+
if (index < 0) continue;
|
|
4967
|
+
const record = {
|
|
4968
|
+
rows: file.rows.subarray(index * GLYPH_HEIGHT, (index + 1) * GLYPH_HEIGHT),
|
|
4969
|
+
bitWidth: file.metrics[index * 3],
|
|
4970
|
+
left: file.metrics[index * 3 + 1],
|
|
4971
|
+
right: file.metrics[index * 3 + 2]
|
|
4972
|
+
};
|
|
4973
|
+
const override = overrides.find((range) => codepoint >= range.from && codepoint <= range.to);
|
|
4974
|
+
if (override) {
|
|
4975
|
+
record.left = override.left;
|
|
4976
|
+
record.right = override.right;
|
|
4977
|
+
}
|
|
4978
|
+
const width = record.right - record.left + 1;
|
|
4979
|
+
let rendered;
|
|
4980
|
+
const render = () => rendered ??= atlas.draw(record);
|
|
4981
|
+
glyphs.set(character, {
|
|
4982
|
+
get image() {
|
|
4983
|
+
return render().image;
|
|
4984
|
+
},
|
|
4985
|
+
get x() {
|
|
4986
|
+
return render().x;
|
|
4987
|
+
},
|
|
4988
|
+
get y() {
|
|
4989
|
+
return render().y;
|
|
4990
|
+
},
|
|
4991
|
+
width,
|
|
4992
|
+
height: GLYPH_HEIGHT,
|
|
4993
|
+
scale: 0.5,
|
|
4994
|
+
ascent: 7,
|
|
4995
|
+
advance: Math.floor(width / 2) + 1,
|
|
4996
|
+
boldOffset: 0.5,
|
|
4997
|
+
shadowOffset: 0.5
|
|
4998
|
+
});
|
|
4999
|
+
}
|
|
5000
|
+
return glyphs;
|
|
5001
|
+
}
|
|
5002
|
+
var ATLAS_SIZE, GLYPH_HEIGHT, UnihexAtlas, atlases;
|
|
5003
|
+
var init_Unihex = __esm({
|
|
5004
|
+
"src/assets/_fonts/Unihex.ts"() {
|
|
5005
|
+
init_AssetKey();
|
|
5006
|
+
init_AssetLoader();
|
|
5007
|
+
init_Assets();
|
|
5008
|
+
init_Caching();
|
|
5009
|
+
init_AssetParsers();
|
|
5010
|
+
init_CanvasCompat();
|
|
5011
|
+
ATLAS_SIZE = 512;
|
|
5012
|
+
GLYPH_HEIGHT = 16;
|
|
5013
|
+
UnihexAtlas = class {
|
|
5014
|
+
constructor() {
|
|
5015
|
+
this.x = 0;
|
|
5016
|
+
this.y = 0;
|
|
5017
|
+
}
|
|
5018
|
+
draw(glyph) {
|
|
5019
|
+
const width = glyph.right - glyph.left + 1;
|
|
5020
|
+
if (this.image && this.x + width > this.image.width) {
|
|
5021
|
+
this.x = 0;
|
|
5022
|
+
this.y += GLYPH_HEIGHT;
|
|
5023
|
+
}
|
|
5024
|
+
if (!this.image || this.y + GLYPH_HEIGHT > this.image.height || width > this.image.width) {
|
|
5025
|
+
this.image = createCanvas2(Math.max(ATLAS_SIZE, width), ATLAS_SIZE);
|
|
5026
|
+
this.x = 0;
|
|
5027
|
+
this.y = 0;
|
|
5028
|
+
}
|
|
5029
|
+
const context = this.image.getContext("2d");
|
|
5030
|
+
const pixels = context.createImageData(width, GLYPH_HEIGHT);
|
|
5031
|
+
for (let y = 0; y < GLYPH_HEIGHT; y++) {
|
|
5032
|
+
for (let x = 0; x < width; x++) {
|
|
5033
|
+
const column = glyph.left + x;
|
|
5034
|
+
if (column < 0 || column >= glyph.bitWidth || !(glyph.rows[y] >>> glyph.bitWidth - column - 1 & 1)) continue;
|
|
5035
|
+
pixels.data.fill(255, (y * width + x) * 4, (y * width + x + 1) * 4);
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
const result = { image: this.image, x: this.x, y: this.y };
|
|
5039
|
+
context.putImageData(pixels, this.x, this.y);
|
|
5040
|
+
this.x += width;
|
|
5041
|
+
return result;
|
|
5042
|
+
}
|
|
5043
|
+
};
|
|
5044
|
+
atlases = /* @__PURE__ */ new WeakMap();
|
|
5045
|
+
}
|
|
5046
|
+
});
|
|
5047
|
+
|
|
4858
5048
|
// src/assets/Fonts.ts
|
|
4859
5049
|
var Fonts;
|
|
4860
5050
|
var init_Fonts = __esm({
|
|
@@ -4865,7 +5055,7 @@ var init_Fonts = __esm({
|
|
|
4865
5055
|
init_ModelTextures();
|
|
4866
5056
|
init_Caching();
|
|
4867
5057
|
Fonts = class {
|
|
4868
|
-
/** Combines font definitions in source-priority order.
|
|
5058
|
+
/** Combines font definitions in source-priority order. TrueType providers are skipped. */
|
|
4869
5059
|
static async get(key = "minecraft:default") {
|
|
4870
5060
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
4871
5061
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -4881,6 +5071,7 @@ var init_Fonts = __esm({
|
|
|
4881
5071
|
const stack = await AssetLoader.getAll(key, "json" /* JSON */);
|
|
4882
5072
|
if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
|
|
4883
5073
|
const glyphs = /* @__PURE__ */ new Map();
|
|
5074
|
+
const providers = [];
|
|
4884
5075
|
for (const asset2 of stack) {
|
|
4885
5076
|
for (const provider of asset2.providers) {
|
|
4886
5077
|
if (provider.filter?.uniform || provider.filter?.jp) continue;
|
|
@@ -4899,17 +5090,43 @@ var init_Fonts = __esm({
|
|
|
4899
5090
|
break;
|
|
4900
5091
|
case "reference":
|
|
4901
5092
|
case "minecraft:reference":
|
|
4902
|
-
|
|
5093
|
+
const reference = await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized]);
|
|
5094
|
+
if (reference.resolve) {
|
|
5095
|
+
providers.push(async (characters) => {
|
|
5096
|
+
await reference.resolve(characters);
|
|
5097
|
+
return reference.glyphs;
|
|
5098
|
+
});
|
|
5099
|
+
continue;
|
|
5100
|
+
}
|
|
5101
|
+
provided = reference.glyphs;
|
|
4903
5102
|
break;
|
|
5103
|
+
case "unihex":
|
|
5104
|
+
case "minecraft:unihex":
|
|
5105
|
+
providers.push(async (characters) => (await Promise.resolve().then(() => (init_Unihex(), Unihex_exports))).loadUnihex(provider, key, characters));
|
|
5106
|
+
continue;
|
|
4904
5107
|
default:
|
|
4905
5108
|
continue;
|
|
4906
5109
|
}
|
|
4907
|
-
for (const [character, glyph] of provided) {
|
|
5110
|
+
if (providers.every((provider2) => provider2 instanceof Map)) for (const [character, glyph] of provided) {
|
|
4908
5111
|
if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
|
|
4909
5112
|
}
|
|
5113
|
+
providers.push(provided);
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
5116
|
+
return { glyphs, resolve: providers.every((provider) => provider instanceof Map) ? void 0 : async (characters) => {
|
|
5117
|
+
const remaining = new Set([...characters].filter((character) => character !== "\0" && character !== "\n" && character !== "\r" && !glyphs.has(character)));
|
|
5118
|
+
for (const provider of providers) {
|
|
5119
|
+
if (!remaining.size) break;
|
|
5120
|
+
const provided = provider instanceof Map ? provider : await provider([...remaining].join(""));
|
|
5121
|
+
for (const character of remaining) {
|
|
5122
|
+
const glyph = provided.get(character);
|
|
5123
|
+
if (glyph) {
|
|
5124
|
+
glyphs.set(character, glyph);
|
|
5125
|
+
remaining.delete(character);
|
|
5126
|
+
}
|
|
5127
|
+
}
|
|
4910
5128
|
}
|
|
4911
|
-
}
|
|
4912
|
-
return { glyphs };
|
|
5129
|
+
} };
|
|
4913
5130
|
}
|
|
4914
5131
|
static async bitmap(provider, fontKey) {
|
|
4915
5132
|
const rows = provider.chars.map((row) => [...row]);
|
|
@@ -8147,6 +8364,7 @@ async function layoutGuiText(text2, options = {}) {
|
|
|
8147
8364
|
}
|
|
8148
8365
|
const font = await Fonts.get(options.font);
|
|
8149
8366
|
const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
|
|
8367
|
+
await font.resolve?.(runs.map((run) => run.text).join(""));
|
|
8150
8368
|
const glyphs = [], lineWidths = [];
|
|
8151
8369
|
let line = [], width = 0;
|
|
8152
8370
|
let trailingNewline = false;
|
|
@@ -8173,7 +8391,7 @@ async function layoutGuiText(text2, options = {}) {
|
|
|
8173
8391
|
continue;
|
|
8174
8392
|
}
|
|
8175
8393
|
const glyph = font.glyphs.get(character);
|
|
8176
|
-
const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
|
|
8394
|
+
const advance = (glyph?.advance ?? 6) + (style.bold ? glyph?.boldOffset ?? 1 : 0);
|
|
8177
8395
|
line.push({ character, glyph, advance, style, x: 0, y: 0 });
|
|
8178
8396
|
width += advance;
|
|
8179
8397
|
while (width > maxWidth && line.length > 1) {
|
|
@@ -8201,7 +8419,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
8201
8419
|
batches.push(batch);
|
|
8202
8420
|
}
|
|
8203
8421
|
const color2 = new Color8(isShadow ? (style.color & 16579836) >> 2 : style.color);
|
|
8204
|
-
const offset = isShadow ? 1 : 0;
|
|
8422
|
+
const offset = isShadow ? glyph?.shadowOffset ?? 1 : 0;
|
|
8205
8423
|
const top = glyph ? 7 - glyph.ascent : 0;
|
|
8206
8424
|
const height = glyph ? glyph.height * glyph.scale : 8;
|
|
8207
8425
|
const width = glyph ? glyph.width * glyph.scale : 5;
|
|
@@ -8231,7 +8449,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
8231
8449
|
for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
|
|
8232
8450
|
batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
|
|
8233
8451
|
};
|
|
8234
|
-
for (const boldOffset of style.bold ? [0, 1] : [0]) {
|
|
8452
|
+
for (const boldOffset of style.bold ? [0, glyph?.boldOffset ?? 1] : [0]) {
|
|
8235
8453
|
if (glyph) quad(0, top, width, top + height, boldOffset);
|
|
8236
8454
|
else {
|
|
8237
8455
|
quad(0, 0, 5, 1, boldOffset);
|
|
@@ -18854,7 +19072,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18854
19072
|
|
|
18855
19073
|
// src/world/SectionGeometry.ts
|
|
18856
19074
|
function buildSectionGeometry(input) {
|
|
18857
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
19075
|
+
const { count, indices, templates, cullMasks, templateData, atlases: atlases2, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
18858
19076
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18859
19077
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18860
19078
|
if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
|
|
@@ -18889,8 +19107,8 @@ function buildSectionGeometry(input) {
|
|
|
18889
19107
|
const locations = /* @__PURE__ */ new Map();
|
|
18890
19108
|
for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a], [b]) => a - b)) {
|
|
18891
19109
|
const firstPage = pages.length;
|
|
18892
|
-
for (const atlas of [...layerAtlases].sort((a, b) => Number(
|
|
18893
|
-
const { width, height, animated } =
|
|
19110
|
+
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))) {
|
|
19111
|
+
const { width, height, animated } = atlases2[atlas];
|
|
18894
19112
|
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
18895
19113
|
let selected = -1;
|
|
18896
19114
|
for (let i = firstPage; !animated && i < pages.length; i++) {
|
|
@@ -18933,7 +19151,7 @@ function buildSectionGeometry(input) {
|
|
|
18933
19151
|
});
|
|
18934
19152
|
if (!quads.sprites.length) continue;
|
|
18935
19153
|
if (!fluidPages.has(fluid)) {
|
|
18936
|
-
const { width, height } =
|
|
19154
|
+
const { width, height } = atlases2[data.atlas];
|
|
18937
19155
|
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
18938
19156
|
fluidPages.set(fluid, {
|
|
18939
19157
|
layer: 2,
|
|
@@ -18951,7 +19169,7 @@ function buildSectionGeometry(input) {
|
|
|
18951
19169
|
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
18952
19170
|
fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
|
|
18953
19171
|
}
|
|
18954
|
-
pages.push(...[...fluidPages.values()].sort((a, b) => Number(
|
|
19172
|
+
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));
|
|
18955
19173
|
}
|
|
18956
19174
|
return pages.map((page) => {
|
|
18957
19175
|
let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);
|
|
@@ -18968,7 +19186,7 @@ function buildSectionGeometry(input) {
|
|
|
18968
19186
|
let vertex = 0, indexOffset = 0;
|
|
18969
19187
|
for (const entry of page.entries) {
|
|
18970
19188
|
const template = templateData[templates[entry]];
|
|
18971
|
-
const atlas =
|
|
19189
|
+
const atlas = atlases2[template.atlas];
|
|
18972
19190
|
const placement = locations.get(template.atlas);
|
|
18973
19191
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
18974
19192
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
@@ -19007,7 +19225,7 @@ function buildSectionGeometry(input) {
|
|
|
19007
19225
|
}
|
|
19008
19226
|
}
|
|
19009
19227
|
for (const { quads, x, y, z, data, tint } of page.fluids) {
|
|
19010
|
-
const atlas =
|
|
19228
|
+
const atlas = atlases2[data.atlas];
|
|
19011
19229
|
const placement = page.placements[0];
|
|
19012
19230
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
19013
19231
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
@@ -19109,7 +19327,7 @@ var templateCache = /* @__PURE__ */ new WeakMap();
|
|
|
19109
19327
|
var WATER_TINT = new Color12(4159204).toArray();
|
|
19110
19328
|
function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
19111
19329
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
19112
|
-
const
|
|
19330
|
+
const atlases2 = [];
|
|
19113
19331
|
const atlasIds = /* @__PURE__ */ new Map();
|
|
19114
19332
|
const templateIds = /* @__PURE__ */ new Map();
|
|
19115
19333
|
const input = {
|
|
@@ -19132,9 +19350,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19132
19350
|
if (id === void 0) {
|
|
19133
19351
|
let atlas = atlasIds.get(template.atlas);
|
|
19134
19352
|
if (atlas === void 0) {
|
|
19135
|
-
atlas =
|
|
19353
|
+
atlas = atlases2.length;
|
|
19136
19354
|
atlasIds.set(template.atlas, atlas);
|
|
19137
|
-
|
|
19355
|
+
atlases2.push(template.atlas);
|
|
19138
19356
|
input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });
|
|
19139
19357
|
}
|
|
19140
19358
|
let data = templateCache.get(template);
|
|
@@ -19193,9 +19411,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19193
19411
|
if (!atlas) continue;
|
|
19194
19412
|
let id = atlasIds.get(atlas);
|
|
19195
19413
|
if (id === void 0) {
|
|
19196
|
-
id =
|
|
19414
|
+
id = atlases2.length;
|
|
19197
19415
|
atlasIds.set(atlas, id);
|
|
19198
|
-
|
|
19416
|
+
atlases2.push(atlas);
|
|
19199
19417
|
input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });
|
|
19200
19418
|
}
|
|
19201
19419
|
input.fluids[kind] = {
|
|
@@ -19206,7 +19424,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19206
19424
|
};
|
|
19207
19425
|
}
|
|
19208
19426
|
}
|
|
19209
|
-
return { input, atlases };
|
|
19427
|
+
return { input, atlases: atlases2 };
|
|
19210
19428
|
}
|
|
19211
19429
|
var SectionMesh = class _SectionMesh extends Group3 {
|
|
19212
19430
|
constructor() {
|
|
@@ -19221,23 +19439,23 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19221
19439
|
}
|
|
19222
19440
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
19223
19441
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
19224
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19225
|
-
return this.fromPages(buildSectionGeometry(input),
|
|
19442
|
+
const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19443
|
+
return this.fromPages(buildSectionGeometry(input), atlases2);
|
|
19226
19444
|
}
|
|
19227
19445
|
/** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
|
|
19228
19446
|
static async buildAsync(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
19229
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19447
|
+
const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
19230
19448
|
const worker = SectionWorker.shared();
|
|
19231
19449
|
const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
|
|
19232
|
-
return this.fromPages(pages,
|
|
19450
|
+
return this.fromPages(pages, atlases2);
|
|
19233
19451
|
}
|
|
19234
|
-
static fromPages(pages,
|
|
19452
|
+
static fromPages(pages, atlases2) {
|
|
19235
19453
|
const section = new _SectionMesh();
|
|
19236
19454
|
for (const page of pages) {
|
|
19237
19455
|
const canvas = createCanvas2(page.width, page.height);
|
|
19238
19456
|
const context = canvas.getContext("2d");
|
|
19239
19457
|
for (const { atlas, x, y } of page.placements) {
|
|
19240
|
-
context.drawImage(
|
|
19458
|
+
context.drawImage(atlases2[atlas].image.canvas, x, y);
|
|
19241
19459
|
}
|
|
19242
19460
|
const geometry = new BufferGeometry9();
|
|
19243
19461
|
geometry.setAttribute("position", new Float32BufferAttribute10(page.positions.buffer, 3));
|
|
@@ -19248,7 +19466,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19248
19466
|
geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
|
|
19249
19467
|
geometry.computeBoundingBox();
|
|
19250
19468
|
geometry.computeBoundingSphere();
|
|
19251
|
-
const transparent = page.layer === 2 ?
|
|
19469
|
+
const transparent = page.layer === 2 ? atlases2[page.placements[0].atlas].hasTranslucency : page.layer === 1;
|
|
19252
19470
|
const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
|
|
19253
19471
|
material.side = FrontSide4;
|
|
19254
19472
|
if (page.layer === 2) {
|
|
@@ -19263,7 +19481,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19263
19481
|
section.blockIndices.set(mesh, page.blockIndices);
|
|
19264
19482
|
const unsubscribe = [];
|
|
19265
19483
|
for (const { atlas: id, x, y } of page.placements) {
|
|
19266
|
-
const atlas =
|
|
19484
|
+
const atlas = atlases2[id];
|
|
19267
19485
|
if (!atlas.hasAnimation) continue;
|
|
19268
19486
|
unsubscribe.push(atlas.subscribe(() => {
|
|
19269
19487
|
context.clearRect(x, y, atlas.image.width, atlas.image.height);
|