minerender 2.1.0-alpha.132 → 2.1.0-alpha.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/browser/esm/Materials.mjs +3 -2
  2. package/dist/browser/esm/Materials.mjs.map +1 -1
  3. package/dist/browser/esm/assets/Fonts.mjs +31 -4
  4. package/dist/browser/esm/assets/Fonts.mjs.map +1 -1
  5. package/dist/browser/esm/assets/_fonts/Unihex.mjs +166 -0
  6. package/dist/browser/esm/assets/_fonts/Unihex.mjs.map +1 -0
  7. package/dist/browser/esm/assets/source/HostedAssetSource.mjs +12 -1
  8. package/dist/browser/esm/assets/source/HostedAssetSource.mjs.map +1 -1
  9. package/dist/browser/esm/assets/source/parser/AssetParsers.mjs +1 -0
  10. package/dist/browser/esm/assets/source/parser/AssetParsers.mjs.map +1 -1
  11. package/dist/browser/esm/cache/Caching.mjs +2 -0
  12. package/dist/browser/esm/cache/Caching.mjs.map +1 -1
  13. package/dist/browser/esm/env/browser/section.worker.mjs +5 -3
  14. package/dist/browser/esm/env/browser/section.worker.mjs.map +1 -1
  15. package/dist/browser/esm/gui/GuiText.mjs +4 -3
  16. package/dist/browser/esm/gui/GuiText.mjs.map +1 -1
  17. package/dist/browser/esm/index.browser.d.mts +25 -4
  18. package/dist/browser/esm/model/scene/ModelObject.mjs +4 -0
  19. package/dist/browser/esm/model/scene/ModelObject.mjs.map +1 -1
  20. package/dist/browser/esm/world/SectionGeometry.mjs +5 -3
  21. package/dist/browser/esm/world/SectionGeometry.mjs.map +1 -1
  22. package/dist/browser/esm/world/SectionMesh.mjs +4 -0
  23. package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
  24. package/dist/browser/esm/world/SectionModels.mjs +2 -2
  25. package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
  26. package/dist/browser/index.d.ts +25 -4
  27. package/dist/browser/index.js +263 -38
  28. package/dist/browser/index.js.map +1 -1
  29. package/dist/bundle.js +306 -38
  30. package/dist/bundle.js.map +1 -1
  31. package/dist/node/index.d.mts +25 -4
  32. package/dist/node/index.d.ts +25 -4
  33. package/dist/node/index.js +267 -38
  34. package/dist/node/index.js.map +1 -1
  35. package/dist/node/index.mjs +267 -38
  36. package/dist/node/index.mjs.map +1 -1
  37. package/package.json +1 -1
@@ -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
  }
@@ -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. Unsupported Unihex and TrueType providers are skipped. */
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
- provided = (await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized])).glyphs;
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]);
@@ -8023,6 +8237,7 @@ async function layoutGuiText(text2, options = {}) {
8023
8237
  }
8024
8238
  const font = await Fonts.get(options.font);
8025
8239
  const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
8240
+ await font.resolve?.(runs.map((run) => run.text).join(""));
8026
8241
  const glyphs = [], lineWidths = [];
8027
8242
  let line = [], width = 0;
8028
8243
  let trailingNewline = false;
@@ -8049,7 +8264,7 @@ async function layoutGuiText(text2, options = {}) {
8049
8264
  continue;
8050
8265
  }
8051
8266
  const glyph = font.glyphs.get(character);
8052
- const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
8267
+ const advance = (glyph?.advance ?? 6) + (style.bold ? glyph?.boldOffset ?? 1 : 0);
8053
8268
  line.push({ character, glyph, advance, style, x: 0, y: 0 });
8054
8269
  width += advance;
8055
8270
  while (width > maxWidth && line.length > 1) {
@@ -8077,7 +8292,7 @@ function createGuiTextGeometry(layout, shadow = true) {
8077
8292
  batches.push(batch);
8078
8293
  }
8079
8294
  const color2 = new import_three20.Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
8080
- const offset = isShadow ? 1 : 0;
8295
+ const offset = isShadow ? glyph?.shadowOffset ?? 1 : 0;
8081
8296
  const top = glyph ? 7 - glyph.ascent : 0;
8082
8297
  const height = glyph ? glyph.height * glyph.scale : 8;
8083
8298
  const width = glyph ? glyph.width * glyph.scale : 5;
@@ -8107,7 +8322,7 @@ function createGuiTextGeometry(layout, shadow = true) {
8107
8322
  for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
8108
8323
  batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
8109
8324
  };
8110
- for (const boldOffset of style.bold ? [0, 1] : [0]) {
8325
+ for (const boldOffset of style.bold ? [0, glyph?.boldOffset ?? 1] : [0]) {
8111
8326
  if (glyph) quad(0, top, width, top + height, boldOffset);
8112
8327
  else {
8113
8328
  quad(0, 0, 5, 1, boldOffset);
@@ -9878,6 +10093,10 @@ var init_ModelObject = __esm({
9878
10093
  this.atlas.model.elements?.forEach((el) => {
9879
10094
  const elGeo = this._getBoxGeometryFromElement(el).clone();
9880
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
+ ));
9881
10100
  if (this.options.cullMask) {
9882
10101
  const indices = Array.from(elGeo.getIndex().array);
9883
10102
  elGeo.setIndex(indices.filter((_, index) => {
@@ -17750,9 +17969,9 @@ function cached(map, key, load) {
17750
17969
  function compactQuads(geometry, keep) {
17751
17970
  const quads = keep.flatMap((kept, index) => kept ? [index] : []);
17752
17971
  const compact = new import_three41.BufferGeometry();
17753
- 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 })) {
17754
17973
  const source2 = geometry.getAttribute(name);
17755
- 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;
17756
17975
  const values = new Float32Array(quads.length * 4 * size);
17757
17976
  for (let q = 0; q < quads.length; q++) {
17758
17977
  for (let vertex = 0; vertex < 4; vertex++) {
@@ -19000,7 +19219,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
19000
19219
 
19001
19220
  // src/world/SectionGeometry.ts
19002
19221
  function buildSectionGeometry(input) {
19003
- 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;
19004
19223
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
19005
19224
  if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
19006
19225
  if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
@@ -19018,7 +19237,7 @@ function buildSectionGeometry(input) {
19018
19237
  const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
19019
19238
  for (const template of templateData) {
19020
19239
  const { quads } = template;
19021
- 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) {
19022
19241
  throw new RangeError("Section template arrays do not match its quad count");
19023
19242
  }
19024
19243
  }
@@ -19035,8 +19254,8 @@ function buildSectionGeometry(input) {
19035
19254
  const locations = /* @__PURE__ */ new Map();
19036
19255
  for (const [layer, layerAtlases] of [...visibleAtlases].sort(([a], [b]) => a - b)) {
19037
19256
  const firstPage = pages.length;
19038
- for (const atlas of [...layerAtlases].sort((a, b) => Number(atlases[a].animated) - Number(atlases[b].animated) || (atlases[a].animated ? a - b : atlases[b].height - atlases[a].height))) {
19039
- const { width, height, animated } = atlases[atlas];
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];
19040
19259
  if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
19041
19260
  let selected = -1;
19042
19261
  for (let i = firstPage; !animated && i < pages.length; i++) {
@@ -19079,7 +19298,7 @@ function buildSectionGeometry(input) {
19079
19298
  });
19080
19299
  if (!quads.sprites.length) continue;
19081
19300
  if (!fluidPages.has(fluid)) {
19082
- const { width, height } = atlases[data.atlas];
19301
+ const { width, height } = atlases2[data.atlas];
19083
19302
  if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
19084
19303
  fluidPages.set(fluid, {
19085
19304
  layer: 2,
@@ -19097,7 +19316,7 @@ function buildSectionGeometry(input) {
19097
19316
  const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
19098
19317
  fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
19099
19318
  }
19100
- pages.push(...[...fluidPages.values()].sort((a, b) => Number(atlases[a.placements[0].atlas].animated) - Number(atlases[b.placements[0].atlas].animated) || a.placements[0].atlas - b.placements[0].atlas));
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));
19101
19320
  }
19102
19321
  return pages.map((page) => {
19103
19322
  let faces = page.fluids.reduce((sum, fluid) => sum + fluid.quads.sprites.length, 0);
@@ -19109,12 +19328,13 @@ function buildSectionGeometry(input) {
19109
19328
  }
19110
19329
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
19111
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);
19112
19332
  const outputIndices = new Uint32Array(faces * 6);
19113
19333
  const blockIndices = new Uint16Array(faces);
19114
19334
  let vertex = 0, indexOffset = 0;
19115
19335
  for (const entry of page.entries) {
19116
19336
  const template = templateData[templates[entry]];
19117
- const atlas = atlases[template.atlas];
19337
+ const atlas = atlases2[template.atlas];
19118
19338
  const placement = locations.get(template.atlas);
19119
19339
  const mapU = (u) => (placement.x + u * atlas.width) / page.width;
19120
19340
  const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
@@ -19138,6 +19358,7 @@ function buildSectionGeometry(input) {
19138
19358
  normals[vertex * 3] = template.normals[source * 3];
19139
19359
  normals[vertex * 3 + 1] = template.normals[source * 3 + 1];
19140
19360
  normals[vertex * 3 + 2] = template.normals[source * 3 + 2];
19361
+ shade[vertex] = template.shade?.[source] ?? 1;
19141
19362
  uvs[vertex * 2] = mapU(template.uvs[source * 2]);
19142
19363
  uvs[vertex * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
19143
19364
  uvBounds[vertex * 4] = mapU(template.uvBounds[source * 4]);
@@ -19153,7 +19374,7 @@ function buildSectionGeometry(input) {
19153
19374
  }
19154
19375
  }
19155
19376
  for (const { quads, x, y, z, data, tint } of page.fluids) {
19156
- const atlas = atlases[data.atlas];
19377
+ const atlas = atlases2[data.atlas];
19157
19378
  const placement = page.placements[0];
19158
19379
  const mapU = (u) => (placement.x + u * atlas.width) / page.width;
19159
19380
  const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
@@ -19190,11 +19411,11 @@ function buildSectionGeometry(input) {
19190
19411
  indexOffset += 6;
19191
19412
  }
19192
19413
  }
19193
- 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 };
19194
19415
  });
19195
19416
  }
19196
19417
  function sectionGeometryTransferables(pages) {
19197
- 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]);
19198
19419
  }
19199
19420
 
19200
19421
  // src/world/SectionWorker.ts
@@ -19254,7 +19475,7 @@ var templateCache = /* @__PURE__ */ new WeakMap();
19254
19475
  var WATER_TINT = new import_three46.Color(4159204).toArray();
19255
19476
  function toInput(entries, maxAtlasSize, fluids, lighting) {
19256
19477
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
19257
- const atlases = [];
19478
+ const atlases2 = [];
19258
19479
  const atlasIds = /* @__PURE__ */ new Map();
19259
19480
  const templateIds = /* @__PURE__ */ new Map();
19260
19481
  const input = {
@@ -19277,9 +19498,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19277
19498
  if (id === void 0) {
19278
19499
  let atlas = atlasIds.get(template.atlas);
19279
19500
  if (atlas === void 0) {
19280
- atlas = atlases.length;
19501
+ atlas = atlases2.length;
19281
19502
  atlasIds.set(template.atlas, atlas);
19282
- atlases.push(template.atlas);
19503
+ atlases2.push(template.atlas);
19283
19504
  input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height, animated: template.atlas.hasAnimation });
19284
19505
  }
19285
19506
  let data = templateCache.get(template);
@@ -19297,6 +19518,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19297
19518
  uvs: new Float32Array(quads * 8),
19298
19519
  uvBounds: new Float32Array(quads * 16),
19299
19520
  colors: new Float32Array(quads * 12),
19521
+ shade: new Float32Array(quads * 4),
19300
19522
  indices: new Uint16Array(quads * 6),
19301
19523
  cullFaces: new Uint8Array(template.cullFaces),
19302
19524
  biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
@@ -19308,6 +19530,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19308
19530
  const uv = template.geometry.getAttribute("uv");
19309
19531
  const bounds = template.geometry.getAttribute("uvBounds");
19310
19532
  const color2 = template.geometry.getAttribute("color");
19533
+ const shade = template.geometry.getAttribute("shade");
19311
19534
  for (let vertex = 0; vertex < quads * 4; vertex++) {
19312
19535
  data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
19313
19536
  data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
@@ -19319,6 +19542,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19319
19542
  bounds?.getW(vertex) ?? 1
19320
19543
  ], vertex * 4);
19321
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;
19322
19546
  }
19323
19547
  for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - 4 * Math.floor(i2 / 6);
19324
19548
  templateCache.set(template, data);
@@ -19338,9 +19562,9 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19338
19562
  if (!atlas) continue;
19339
19563
  let id = atlasIds.get(atlas);
19340
19564
  if (id === void 0) {
19341
- id = atlases.length;
19565
+ id = atlases2.length;
19342
19566
  atlasIds.set(atlas, id);
19343
- atlases.push(atlas);
19567
+ atlases2.push(atlas);
19344
19568
  input.atlases.push({ width: atlas.image.width, height: atlas.image.height, animated: atlas.hasAnimation });
19345
19569
  }
19346
19570
  input.fluids[kind] = {
@@ -19351,7 +19575,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19351
19575
  };
19352
19576
  }
19353
19577
  }
19354
- return { input, atlases };
19578
+ return { input, atlases: atlases2 };
19355
19579
  }
19356
19580
  var SectionMesh = class _SectionMesh extends import_three46.Group {
19357
19581
  constructor() {
@@ -19366,23 +19590,23 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
19366
19590
  }
19367
19591
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
19368
19592
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
19369
- const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
19370
- return this.fromPages(buildSectionGeometry(input), atlases);
19593
+ const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
19594
+ return this.fromPages(buildSectionGeometry(input), atlases2);
19371
19595
  }
19372
19596
  /** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
19373
19597
  static async buildAsync(entries, maxAtlasSize = 2048, fluids, lighting) {
19374
- const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
19598
+ const { input, atlases: atlases2 } = toInput(entries, maxAtlasSize, fluids, lighting);
19375
19599
  const worker = SectionWorker.shared();
19376
19600
  const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
19377
- return this.fromPages(pages, atlases);
19601
+ return this.fromPages(pages, atlases2);
19378
19602
  }
19379
- static fromPages(pages, atlases) {
19603
+ static fromPages(pages, atlases2) {
19380
19604
  const section = new _SectionMesh();
19381
19605
  for (const page of pages) {
19382
19606
  const canvas = createCanvas(page.width, page.height);
19383
19607
  const context = canvas.getContext("2d");
19384
19608
  for (const { atlas, x, y } of page.placements) {
19385
- context.drawImage(atlases[atlas].image.canvas, x, y);
19609
+ context.drawImage(atlases2[atlas].image.canvas, x, y);
19386
19610
  }
19387
19611
  const geometry = new import_three46.BufferGeometry();
19388
19612
  geometry.setAttribute("position", new import_three46.Float32BufferAttribute(page.positions.buffer, 3));
@@ -19390,10 +19614,11 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
19390
19614
  geometry.setAttribute("uv", new import_three46.Float32BufferAttribute(page.uvs.buffer, 2));
19391
19615
  geometry.setAttribute("uvBounds", new import_three46.Float32BufferAttribute(page.uvBounds.buffer, 4));
19392
19616
  geometry.setAttribute("color", new import_three46.Float32BufferAttribute(page.colors.buffer, 3));
19617
+ geometry.setAttribute("shade", new import_three46.Float32BufferAttribute(page.shade.buffer, 1));
19393
19618
  geometry.setIndex(new import_three46.Uint32BufferAttribute(page.indices.buffer, 1));
19394
19619
  geometry.computeBoundingBox();
19395
19620
  geometry.computeBoundingSphere();
19396
- const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;
19621
+ const transparent = page.layer === 2 ? atlases2[page.placements[0].atlas].hasTranslucency : page.layer === 1;
19397
19622
  const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
19398
19623
  material.side = import_three46.FrontSide;
19399
19624
  if (page.layer === 2) {
@@ -19408,7 +19633,7 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
19408
19633
  section.blockIndices.set(mesh, page.blockIndices);
19409
19634
  const unsubscribe = [];
19410
19635
  for (const { atlas: id, x, y } of page.placements) {
19411
- const atlas = atlases[id];
19636
+ const atlas = atlases2[id];
19412
19637
  if (!atlas.hasAnimation) continue;
19413
19638
  unsubscribe.push(atlas.subscribe(() => {
19414
19639
  context.clearRect(x, y, atlas.image.width, atlas.image.height);