minerender 2.1.0-alpha.67 → 2.1.0-alpha.69

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.
@@ -258,7 +258,8 @@ var init_Caching = __esm({
258
258
  this.entityModelCache,
259
259
  this.entityTextureCache,
260
260
  this.entityAnimationCache,
261
- this.blockEntityIndexCache
261
+ this.blockEntityIndexCache,
262
+ this.fontCache
262
263
  ];
263
264
  }
264
265
  static clear() {
@@ -305,6 +306,7 @@ var init_Caching = __esm({
305
306
  _Caching.entityTextureCache = _Caching.createAssetCache();
306
307
  _Caching.entityAnimationCache = _Caching.createAssetCache();
307
308
  _Caching.blockEntityIndexCache = _Caching.createAssetCache();
309
+ _Caching.fontCache = _Caching.createAssetCache();
308
310
  Caching = _Caching;
309
311
  }
310
312
  });
@@ -4247,8 +4249,8 @@ var init_EntityObject = __esm({
4247
4249
  // src/three/BufferGeometryUtils.js
4248
4250
  import {
4249
4251
  BufferAttribute as BufferAttribute4,
4250
- BufferGeometry as BufferGeometry2,
4251
- Float32BufferAttribute as Float32BufferAttribute4,
4252
+ BufferGeometry as BufferGeometry4,
4253
+ Float32BufferAttribute as Float32BufferAttribute6,
4252
4254
  InterleavedBuffer,
4253
4255
  InterleavedBufferAttribute,
4254
4256
  TriangleFanDrawMode,
@@ -4267,7 +4269,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
4267
4269
  const attributes = {};
4268
4270
  const morphAttributes = {};
4269
4271
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
4270
- const mergedGeometry = new BufferGeometry2();
4272
+ const mergedGeometry = new BufferGeometry4();
4271
4273
  let offset = 0;
4272
4274
  for (let i = 0; i < geometries.length; ++i) {
4273
4275
  const geometry = geometries[i];
@@ -4776,8 +4778,8 @@ function computeMorphedAttributes(object) {
4776
4778
  }
4777
4779
  }
4778
4780
  }
4779
- const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
4780
- const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
4781
+ const morphedPositionAttribute = new Float32BufferAttribute6(modifiedPosition, 3);
4782
+ const morphedNormalAttribute = new Float32BufferAttribute6(modifiedNormal, 3);
4781
4783
  return {
4782
4784
  positionAttribute,
4783
4785
  normalAttribute,
@@ -5027,7 +5029,7 @@ var init_ItemTints = __esm({
5027
5029
  });
5028
5030
 
5029
5031
  // src/model/scene/ModelObject.ts
5030
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler7, Matrix4 as Matrix49 } from "three";
5032
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color9, Euler as Euler7, Matrix4 as Matrix49 } from "three";
5031
5033
  function isModelObject(obj) {
5032
5034
  return obj.isModelObject;
5033
5035
  }
@@ -5141,7 +5143,7 @@ var init_ModelObject = __esm({
5141
5143
  if (tintIndex === void 0 || tintIndex < 0) continue;
5142
5144
  const tint = this.options.tints[tintIndex];
5143
5145
  if (tint === void 0) continue;
5144
- const color = new Color8(tint);
5146
+ const color = new Color9(tint);
5145
5147
  for (let vertex = 0; vertex < 4; vertex++) {
5146
5148
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
5147
5149
  }
@@ -5270,7 +5272,7 @@ var init_fluidBlocks = __esm({
5270
5272
  });
5271
5273
 
5272
5274
  // src/model/fluid/FluidGeometry.ts
5273
- import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
5275
+ import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute7 } from "three";
5274
5276
  function getBlockFluidState(key, state) {
5275
5277
  const rule = key && fluidRules[key.toNamespacedString()];
5276
5278
  if (rule) return {
@@ -5288,7 +5290,7 @@ function ownHeight(sample) {
5288
5290
  return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
5289
5291
  }
5290
5292
  function createFluidGeometry(kind, sample) {
5291
- const geometry = new BufferGeometry4();
5293
+ const geometry = new BufferGeometry6();
5292
5294
  const positions = [], normals = [], uvs = [], indices = [];
5293
5295
  const self = sample(0, 0, 0);
5294
5296
  const height = (x, z) => {
@@ -5387,9 +5389,9 @@ function createFluidGeometry(kind, sample) {
5387
5389
  1
5388
5390
  );
5389
5391
  }
5390
- geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
5391
- geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
5392
- geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
5392
+ geometry.setAttribute("position", new Float32BufferAttribute7(positions, 3));
5393
+ geometry.setAttribute("normal", new Float32BufferAttribute7(normals, 3));
5394
+ geometry.setAttribute("uv", new Float32BufferAttribute7(uvs, 2));
5393
5395
  geometry.setIndex(indices);
5394
5396
  return geometry;
5395
5397
  }
@@ -5409,7 +5411,7 @@ __export(FluidModelObject_exports, {
5409
5411
  FluidModelObject: () => FluidModelObject,
5410
5412
  sampleFluid: () => sampleFluid
5411
5413
  });
5412
- import { BufferAttribute as BufferAttribute6, Color as Color9, DoubleSide as DoubleSide3 } from "three";
5414
+ import { BufferAttribute as BufferAttribute6, Color as Color10, DoubleSide as DoubleSide4 } from "three";
5413
5415
  function sampleFluid(kind, sample) {
5414
5416
  const cells = [];
5415
5417
  const key = [];
@@ -5460,7 +5462,7 @@ var init_FluidModelObject = __esm({
5460
5462
  }
5461
5463
  }
5462
5464
  geometry.clearGroups();
5463
- const color = new Color9(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
5465
+ const color = new Color10(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
5464
5466
  const colors = new Float32Array(geometry.getAttribute("position").count * 3);
5465
5467
  for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
5466
5468
  geometry.setAttribute("color", new BufferAttribute6(colors, 3));
@@ -5477,7 +5479,7 @@ var init_FluidModelObject = __esm({
5477
5479
  super.applyTextures();
5478
5480
  this.iterateAllMeshes((mesh) => {
5479
5481
  const material = mesh.material;
5480
- material.side = DoubleSide3;
5482
+ material.side = DoubleSide4;
5481
5483
  material.forceSinglePass = true;
5482
5484
  material.depthWrite = !material.transparent;
5483
5485
  });
@@ -5731,6 +5733,101 @@ var BlockEntities = class {
5731
5733
  // src/assets/index.ts
5732
5734
  init_BlockStates();
5733
5735
  init_Entities();
5736
+
5737
+ // src/assets/Fonts.ts
5738
+ init_AssetKey();
5739
+ init_AssetLoader();
5740
+ init_AssetParsers();
5741
+ init_ModelTextures();
5742
+ init_Caching();
5743
+ var Fonts = class {
5744
+ static async get(key = "minecraft:default") {
5745
+ const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
5746
+ return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
5747
+ }
5748
+ static relatedKey(assetType, id, origin) {
5749
+ const key = AssetKey.parse(assetType, id);
5750
+ key.root = origin.root;
5751
+ return key;
5752
+ }
5753
+ static async load(key, parents) {
5754
+ const serialized = key.serialize();
5755
+ if (parents.includes(serialized)) throw new Error(`Cyclic font reference: ${key.toNamespacedString()}`);
5756
+ const stack = await AssetLoader.getAll(key, "json" /* JSON */);
5757
+ if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
5758
+ const glyphs = /* @__PURE__ */ new Map();
5759
+ for (const asset of stack) {
5760
+ for (const provider of asset.providers) {
5761
+ if (provider.filter?.uniform || provider.filter?.jp) continue;
5762
+ let provided;
5763
+ switch (provider.type) {
5764
+ case "bitmap":
5765
+ case "minecraft:bitmap":
5766
+ provided = await this.bitmap(provider, key);
5767
+ break;
5768
+ case "space":
5769
+ case "minecraft:space":
5770
+ provided = new Map(Object.entries(provider.advances).map(([character, advance]) => [
5771
+ character,
5772
+ { x: 0, y: 0, width: 0, height: 0, scale: 1, ascent: 0, advance }
5773
+ ]));
5774
+ break;
5775
+ case "reference":
5776
+ case "minecraft:reference":
5777
+ provided = (await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized])).glyphs;
5778
+ break;
5779
+ default:
5780
+ continue;
5781
+ }
5782
+ for (const [character, glyph] of provided) {
5783
+ if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
5784
+ }
5785
+ }
5786
+ }
5787
+ return { glyphs };
5788
+ }
5789
+ static async bitmap(provider, fontKey) {
5790
+ const rows = provider.chars.map((row) => [...row]);
5791
+ const columns = rows[0]?.length;
5792
+ if (!columns || rows.some((row) => row.length !== columns)) {
5793
+ throw new Error(`Invalid character grid in font ${fontKey.toNamespacedString()}`);
5794
+ }
5795
+ const key = this.relatedKey("textures", provider.file, fontKey);
5796
+ const image = await ModelTextures.get(key);
5797
+ if (!image) throw new Error(`Could not load font texture ${key.toNamespacedString()}`);
5798
+ const width = Math.floor(image.width / columns), height = Math.floor(image.height / rows.length);
5799
+ if (!width || !height) throw new Error(`Font texture ${key.toNamespacedString()} is smaller than its character grid`);
5800
+ const scale = (provider.height ?? 8) / height;
5801
+ const pixels = image.data.getImageData(0, 0, image.width, image.height).data;
5802
+ const glyphs = /* @__PURE__ */ new Map();
5803
+ rows.forEach((row, rowIndex) => row.forEach((character, columnIndex) => {
5804
+ if (character === "\0") return;
5805
+ const x = columnIndex * width, y = rowIndex * height;
5806
+ let occupiedWidth = 0;
5807
+ for (let column = width - 1; column >= 0 && !occupiedWidth; column--) {
5808
+ for (let row2 = 0; row2 < height; row2++) {
5809
+ if (pixels[((y + row2) * image.width + x + column) * 4 + 3] !== 0) {
5810
+ occupiedWidth = column + 1;
5811
+ break;
5812
+ }
5813
+ }
5814
+ }
5815
+ glyphs.set(character, {
5816
+ image: image.data.canvas,
5817
+ x,
5818
+ y,
5819
+ width,
5820
+ height,
5821
+ scale,
5822
+ ascent: provider.ascent,
5823
+ advance: Math.floor(occupiedWidth * scale + 0.5) + 1
5824
+ });
5825
+ }));
5826
+ return glyphs;
5827
+ }
5828
+ };
5829
+
5830
+ // src/assets/index.ts
5734
5831
  init_ModelTextures();
5735
5832
  init_Models();
5736
5833
  init_source();
@@ -8729,7 +8826,137 @@ function copyDataTexture(source) {
8729
8826
 
8730
8827
  // src/gui/GuiHelper.ts
8731
8828
  init_AssetKey();
8829
+
8830
+ // src/gui/GuiText.ts
8831
+ import { BufferGeometry as BufferGeometry2, Color as Color8, Float32BufferAttribute as Float32BufferAttribute4 } from "three";
8832
+ async function layoutGuiText(text, options = {}) {
8833
+ const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
8834
+ if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
8835
+ throw new Error("Text wrap width and line height must be positive");
8836
+ }
8837
+ const font = await Fonts.get(options.font);
8838
+ const runs = typeof text === "string" ? [{ text }] : text;
8839
+ const glyphs = [], lineWidths = [];
8840
+ let line = [], width = 0;
8841
+ let trailingNewline = false;
8842
+ const finishLine = (entries) => {
8843
+ let x = 0;
8844
+ for (const entry of entries) {
8845
+ glyphs.push({ ...entry, x, y: lineWidths.length * lineHeight });
8846
+ x += entry.advance;
8847
+ }
8848
+ lineWidths.push(x);
8849
+ };
8850
+ for (const run of runs) {
8851
+ const style = {
8852
+ color: run.color ?? options.color ?? 16777215,
8853
+ bold: run.bold ?? options.bold ?? false,
8854
+ italic: run.italic ?? options.italic ?? false
8855
+ };
8856
+ for (const character of run.text.replace(/\r\n?/g, "\n")) {
8857
+ trailingNewline = character === "\n";
8858
+ if (character === "\n") {
8859
+ finishLine(line);
8860
+ line = [];
8861
+ width = 0;
8862
+ continue;
8863
+ }
8864
+ const glyph = font.glyphs.get(character);
8865
+ const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
8866
+ line.push({ character, glyph, advance, style, x: 0, y: 0 });
8867
+ width += advance;
8868
+ while (width > maxWidth && line.length > 1) {
8869
+ let space = -1;
8870
+ for (let i = 0; i < line.length; i++) if (line[i].character === " ") space = i;
8871
+ const split = space >= 0 ? space : line.length - 1;
8872
+ if (split > 0) finishLine(line.slice(0, split));
8873
+ line = line.slice(split + (space >= 0 ? 1 : 0));
8874
+ width = line.reduce((sum, entry) => sum + entry.advance, 0);
8875
+ }
8876
+ }
8877
+ }
8878
+ if (line.length || !lineWidths.length || trailingNewline) finishLine(line);
8879
+ return { glyphs, lineWidths, width: Math.max(0, ...lineWidths), height: lineWidths.length * lineHeight };
8880
+ }
8881
+ function createGuiTextGeometry(layout, shadow = true) {
8882
+ const batches = [];
8883
+ for (const isShadow of shadow ? [true, false] : [false]) {
8884
+ let batch;
8885
+ for (const entry of layout.glyphs) {
8886
+ const { glyph, style } = entry;
8887
+ if (glyph && !glyph.image) continue;
8888
+ if (!batch || batch.image !== glyph?.image) {
8889
+ batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
8890
+ batches.push(batch);
8891
+ }
8892
+ const color = new Color8(isShadow ? (style.color & 16579836) >> 2 : style.color);
8893
+ const offset = isShadow ? 1 : 0;
8894
+ const top = glyph ? 7 - glyph.ascent : 0;
8895
+ const height = glyph ? glyph.height * glyph.scale : 8;
8896
+ const width = glyph ? glyph.width * glyph.scale : 5;
8897
+ const shear = (y) => style.italic ? 1 - 0.25 * y : 0;
8898
+ const quad = (left, upper, right, lower, boldOffset) => {
8899
+ const base = batch.positions.length / 3;
8900
+ const x = entry.x + offset + boldOffset, y = entry.y + offset;
8901
+ batch.positions.push(
8902
+ x + left + shear(upper),
8903
+ -y - upper,
8904
+ 0,
8905
+ x + right + shear(upper),
8906
+ -y - upper,
8907
+ 0,
8908
+ x + left + shear(lower),
8909
+ -y - lower,
8910
+ 0,
8911
+ x + right + shear(lower),
8912
+ -y - lower,
8913
+ 0
8914
+ );
8915
+ const u0 = glyph ? glyph.x / glyph.image.width : 0;
8916
+ const u1 = glyph ? (glyph.x + glyph.width) / glyph.image.width : 1;
8917
+ const v0 = glyph ? 1 - glyph.y / glyph.image.height : 1;
8918
+ const v1 = glyph ? 1 - (glyph.y + glyph.height) / glyph.image.height : 0;
8919
+ batch.uvs.push(u0, v0, u1, v0, u0, v1, u1, v1);
8920
+ for (let i = 0; i < 4; i++) batch.colors.push(color.r, color.g, color.b);
8921
+ batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
8922
+ };
8923
+ for (const boldOffset of style.bold ? [0, 1] : [0]) {
8924
+ if (glyph) quad(0, top, width, top + height, boldOffset);
8925
+ else {
8926
+ quad(0, 0, 5, 1, boldOffset);
8927
+ quad(0, 7, 5, 8, boldOffset);
8928
+ quad(0, 1, 1, 7, boldOffset);
8929
+ quad(4, 1, 5, 7, boldOffset);
8930
+ }
8931
+ }
8932
+ }
8933
+ }
8934
+ return batches.map(({ image, positions, uvs, colors, indices }) => ({ image, geometry: new BufferGeometry2().setAttribute("position", new Float32BufferAttribute4(positions, 3)).setAttribute("uv", new Float32BufferAttribute4(uvs, 2)).setAttribute("color", new Float32BufferAttribute4(colors, 3)).setIndex(indices) }));
8935
+ }
8936
+
8937
+ // src/gui/GuiHelper.ts
8732
8938
  var GuiHelper = class {
8939
+ /** Sizes a tooltip around supplied text; the first entry is its title. */
8940
+ static async tooltip(lines, options = {}) {
8941
+ if (!lines.length) return [];
8942
+ const { position = [0, 0], titleGap = 2, lineHeight = 10, shadow = true, ...style } = options;
8943
+ const textOptions = { ...style, lineHeight, shadow };
8944
+ const layouts = await Promise.all(lines.map((line) => layoutGuiText(line, textOptions)));
8945
+ const width = Math.max(...layouts.map((layout) => layout.width));
8946
+ const height = layouts.reduce((sum, layout) => sum + layout.height, 0) - 2 + (lines.length > 1 ? titleGap : 0);
8947
+ const layers = ["background", "frame"].map((part) => ({
8948
+ name: `tooltip-${part}`,
8949
+ texture: `minecraft:gui/sprites/tooltip/${part}`,
8950
+ position: [position[0] - 12, position[1] - 12],
8951
+ size: [width + 24, height + 24]
8952
+ }));
8953
+ let y = position[1];
8954
+ lines.forEach((text, index) => {
8955
+ layers.push({ ...textOptions, name: `tooltip-line-${index}`, text, position: [position[0], y] });
8956
+ y += layouts[index].height + (index === 0 ? titleGap : 0);
8957
+ });
8958
+ return layers;
8959
+ }
8733
8960
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
8734
8961
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
8735
8962
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
@@ -8793,6 +9020,85 @@ var GuiHelper = class {
8793
9020
  }
8794
9021
  };
8795
9022
 
9023
+ // src/gui/GuiTextureGeometry.ts
9024
+ import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute5, PlaneGeometry } from "three";
9025
+ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
9026
+ if (crop || !scaling || scaling.type === "stretch") {
9027
+ const [x, y, w, h] = crop ?? [0, 0, imageWidth, imageHeight];
9028
+ const geometry = new PlaneGeometry(width, height);
9029
+ const uv = geometry.getAttribute("uv");
9030
+ for (let i = 0; i < uv.count; i++) {
9031
+ uv.setXY(
9032
+ i,
9033
+ (x + uv.getX(i) * w) / imageWidth,
9034
+ 1 - (y + (1 - uv.getY(i)) * h) / imageHeight
9035
+ );
9036
+ }
9037
+ return geometry;
9038
+ }
9039
+ const sw = scaling.width, sh = scaling.height;
9040
+ if (![sw, sh].every((value) => Number.isInteger(value) && value > 0)) {
9041
+ throw new Error("GUI sprite dimensions must be positive integers");
9042
+ }
9043
+ if (![width, height].every((value) => Number.isFinite(value) && value >= 0)) {
9044
+ throw new Error("GUI output dimensions must be finite and nonnegative");
9045
+ }
9046
+ const positions = [], uvs = [], normals = [], indices = [];
9047
+ function quad(x, y, w, h, u, v, uw, vh) {
9048
+ if (w <= 0 || h <= 0) return;
9049
+ const index = positions.length / 3;
9050
+ const left = x - width / 2, top = height / 2 - y;
9051
+ positions.push(left, top, 0, left + w, top, 0, left, top - h, 0, left + w, top - h, 0);
9052
+ uvs.push(
9053
+ u / sw,
9054
+ 1 - v / sh,
9055
+ (u + uw) / sw,
9056
+ 1 - v / sh,
9057
+ u / sw,
9058
+ 1 - (v + vh) / sh,
9059
+ (u + uw) / sw,
9060
+ 1 - (v + vh) / sh
9061
+ );
9062
+ normals.push(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1);
9063
+ indices.push(index, index + 2, index + 1, index + 2, index + 3, index + 1);
9064
+ }
9065
+ function tile(x, y, w, h, u, v, tw, th) {
9066
+ for (let dy = 0; dy < h; dy += th) {
9067
+ for (let dx = 0; dx < w; dx += tw) {
9068
+ const cw = Math.min(tw, w - dx), ch = Math.min(th, h - dy);
9069
+ quad(x + dx, y + dy, cw, ch, u, v, cw, ch);
9070
+ }
9071
+ }
9072
+ }
9073
+ if (scaling.type === "tile") {
9074
+ tile(0, 0, width, height, 0, 0, sw, sh);
9075
+ } else {
9076
+ let segments = function(size, sourceSize, start, end) {
9077
+ if (size === sourceSize) return [[0, size, 0, sourceSize]];
9078
+ start = Math.min(start, Math.floor(size / 2));
9079
+ end = Math.min(end, Math.floor(size / 2));
9080
+ return [
9081
+ [0, start, 0, start],
9082
+ [start, size - start - end, start, sourceSize - start - end],
9083
+ [size - end, end, sourceSize - end, end]
9084
+ ];
9085
+ };
9086
+ const border = typeof scaling.border === "number" ? { left: scaling.border, top: scaling.border, right: scaling.border, bottom: scaling.border } : scaling.border;
9087
+ if (!border || typeof scaling.border === "number" && scaling.border <= 0 || ![border.left, border.top, border.right, border.bottom].every((value) => Number.isInteger(value) && value >= 0) || border.left + border.right >= sw || border.top + border.bottom >= sh) {
9088
+ throw new Error("GUI nine-slice borders must be nonnegative integers with a nonempty center");
9089
+ }
9090
+ const columns = segments(width, sw, border.left, border.right);
9091
+ const rows = segments(height, sh, border.top, border.bottom);
9092
+ for (const [y, h, v, vh] of rows) {
9093
+ for (const [x, w, u, uw] of columns) {
9094
+ if (w <= 0 || h <= 0) continue;
9095
+ (scaling.stretch_inner ? quad : tile)(x, y, w, h, u, v, uw, vh);
9096
+ }
9097
+ }
9098
+ }
9099
+ return new BufferGeometry3().setAttribute("position", new Float32BufferAttribute5(positions, 3)).setAttribute("normal", new Float32BufferAttribute5(normals, 3)).setAttribute("uv", new Float32BufferAttribute5(uvs, 2)).setIndex(indices);
9100
+ }
9101
+
8796
9102
  // src/gui/scene/GuiObject.ts
8797
9103
  init_AssetKey();
8798
9104
  init_ModelTextures();
@@ -8803,7 +9109,7 @@ init_Materials();
8803
9109
  init_ModelObject();
8804
9110
  init_DisplayPosition();
8805
9111
  init_GuiLight();
8806
- import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh6, PlaneGeometry, Vector2 as Vector23 } from "three";
9112
+ import { Box2, Box3 as Box32, DoubleSide as DoubleSide3, Group, Matrix4 as Matrix410, Mesh as Mesh6, MeshBasicMaterial as MeshBasicMaterial5, Vector2 as Vector23 } from "three";
8807
9113
  var GuiObject = class extends SceneObject {
8808
9114
  constructor(textureLayers, options) {
8809
9115
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -8813,6 +9119,7 @@ var GuiObject = class extends SceneObject {
8813
9119
  this.bounds = new Box2();
8814
9120
  this.geometries = /* @__PURE__ */ new Set();
8815
9121
  this.ownedMaterials = /* @__PURE__ */ new Set();
9122
+ this.textMaterials = /* @__PURE__ */ new Map();
8816
9123
  this.initialized = false;
8817
9124
  }
8818
9125
  async init() {
@@ -8821,6 +9128,43 @@ var GuiObject = class extends SceneObject {
8821
9128
  let depth = 0;
8822
9129
  for (const [index, layer] of this.textureLayers.entries()) {
8823
9130
  const [x, y] = layer.position ?? [0, 0];
9131
+ if ("text" in layer) {
9132
+ const layout = await layoutGuiText(layer.text, layer);
9133
+ const group = new Group();
9134
+ group.name = `group:${layer.name ?? index}`;
9135
+ group.position.set(x, -y, depth);
9136
+ const [width2, height2] = layer.size ?? [layout.width, layout.height];
9137
+ group.scale.set(layout.width ? width2 / layout.width : 1, height2 / layout.height, 1);
9138
+ this.add(group);
9139
+ const parts = createGuiTextGeometry(layout, layer.shadow);
9140
+ const bounds = new Box32();
9141
+ for (const [partIndex, { image: image2, geometry: geometry2 }] of parts.entries()) {
9142
+ this.geometries.add(geometry2);
9143
+ geometry2.computeBoundingBox();
9144
+ bounds.union(geometry2.boundingBox);
9145
+ let material2 = this.textMaterials.get(image2);
9146
+ if (!material2) {
9147
+ material2 = image2 ? Materials.createGuiCanvasMaterial(image2) : new MeshBasicMaterial5({ transparent: true, depthWrite: false, side: DoubleSide3, toneMapped: false });
9148
+ material2.vertexColors = true;
9149
+ this.textMaterials.set(image2, material2);
9150
+ this.ownedMaterials.add(material2);
9151
+ }
9152
+ const mesh2 = new Mesh6(geometry2, material2);
9153
+ mesh2.name = `mesh:${layer.name ?? index}:${partIndex}`;
9154
+ mesh2.renderOrder = index + partIndex / (parts.length + 1) * 0.5;
9155
+ group.add(mesh2);
9156
+ }
9157
+ group.updateMatrix();
9158
+ bounds.applyMatrix4(group.matrix);
9159
+ this.bounds.expandByPoint(new Vector23(x, y));
9160
+ this.bounds.expandByPoint(new Vector23(x + width2, y + height2));
9161
+ if (!bounds.isEmpty()) {
9162
+ this.bounds.expandByPoint(new Vector23(bounds.min.x, -bounds.max.y));
9163
+ this.bounds.expandByPoint(new Vector23(bounds.max.x, -bounds.min.y));
9164
+ }
9165
+ depth += 0.01;
9166
+ continue;
9167
+ }
8824
9168
  if ("item" in layer) {
8825
9169
  const [width2, height2] = layer.size ?? [16, 16];
8826
9170
  const item = await this.createItem(layer, index);
@@ -8844,18 +9188,10 @@ var GuiObject = class extends SceneObject {
8844
9188
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
8845
9189
  const material = await this.loadMaterial(key);
8846
9190
  const image = material.map.image;
8847
- const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
8848
- const [width, height] = layer.size ?? [cropWidth, cropHeight];
8849
- const geometry = new PlaneGeometry(width, height);
9191
+ const scaling = layer.crop ? void 0 : (await ModelTextures.getMeta(key))?.gui?.scaling;
9192
+ const [width, height] = layer.size ?? (layer.crop ? layer.crop.slice(2) : scaling && scaling.type !== "stretch" ? [scaling.width, scaling.height] : [image.width, image.height]);
9193
+ const geometry = createGuiTextureGeometry(width, height, image.width, image.height, layer.crop, scaling);
8850
9194
  this.geometries.add(geometry);
8851
- const uv = geometry.getAttribute("uv");
8852
- for (let i = 0; i < uv.count; i++) {
8853
- uv.setXY(
8854
- i,
8855
- (cropX + uv.getX(i) * cropWidth) / image.width,
8856
- 1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
8857
- );
8858
- }
8859
9195
  const mesh = new Mesh6(geometry, material);
8860
9196
  mesh.name = `mesh:${layer.name ?? index}`;
8861
9197
  mesh.position.set(x + width / 2, -y - height / 2, depth);
@@ -8920,10 +9256,11 @@ var GuiObject = class extends SceneObject {
8920
9256
  for (const geometry of this.geometries) geometry.dispose();
8921
9257
  this.geometries.clear();
8922
9258
  for (const material of this.ownedMaterials) {
8923
- material.map.dispose();
9259
+ material.map?.dispose();
8924
9260
  material.dispose();
8925
9261
  }
8926
9262
  this.ownedMaterials.clear();
9263
+ this.textMaterials.clear();
8927
9264
  this.bounds.makeEmpty();
8928
9265
  this.initialized = false;
8929
9266
  super.disposeAndRemoveAllChildren();
@@ -12489,7 +12826,7 @@ init_util();
12489
12826
  init_Caching();
12490
12827
  init_CacheKey();
12491
12828
  init_MineRenderError();
12492
- import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12829
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide5, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12493
12830
 
12494
12831
  // src/skin/SkinImage.ts
12495
12832
  init_Caching();
@@ -12574,7 +12911,7 @@ var SkinTextures = class {
12574
12911
  texture.colorSpace = SRGBColorSpace6;
12575
12912
  texture.flipY = true;
12576
12913
  texture.needsUpdate = true;
12577
- return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
12914
+ return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide5 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
12578
12915
  }
12579
12916
  static isSlim(image, scale) {
12580
12917
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -14782,8 +15119,8 @@ init_Model();
14782
15119
  // src/world/SectionMesh.ts
14783
15120
  init_CanvasCompat();
14784
15121
  init_Materials();
14785
- import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh9 } from "three";
14786
- var SectionMesh = class _SectionMesh extends Group {
15122
+ import { BufferGeometry as BufferGeometry8, Float32BufferAttribute as Float32BufferAttribute8, Group as Group2, Mesh as Mesh9 } from "three";
15123
+ var SectionMesh = class _SectionMesh extends Group2 {
14787
15124
  constructor() {
14788
15125
  super(...arguments);
14789
15126
  this.ownedMeshes = [];
@@ -14856,11 +15193,11 @@ var SectionMesh = class _SectionMesh extends Group {
14856
15193
  for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
14857
15194
  }
14858
15195
  }
14859
- const geometry = new BufferGeometry6();
14860
- geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
14861
- geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
14862
- geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
14863
- geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
15196
+ const geometry = new BufferGeometry8();
15197
+ geometry.setAttribute("position", new Float32BufferAttribute8(positions, 3));
15198
+ geometry.setAttribute("normal", new Float32BufferAttribute8(normals, 3));
15199
+ geometry.setAttribute("uv", new Float32BufferAttribute8(uvs, 2));
15200
+ geometry.setAttribute("color", new Float32BufferAttribute8(colors, 3));
14864
15201
  geometry.setIndex(indices);
14865
15202
  geometry.computeBoundingBox();
14866
15203
  geometry.computeBoundingSphere();
@@ -15114,6 +15451,7 @@ export {
15114
15451
  EntityObject,
15115
15452
  Env,
15116
15453
  FluidModelObject,
15454
+ Fonts,
15117
15455
  Geometries,
15118
15456
  GuiHelper,
15119
15457
  GuiLight,
@@ -15185,6 +15523,8 @@ export {
15185
15523
  computeTangents,
15186
15524
  createCanvas,
15187
15525
  createFluidGeometry,
15526
+ createGuiTextGeometry,
15527
+ createGuiTextureGeometry,
15188
15528
  createImage,
15189
15529
  entityAnimationTime,
15190
15530
  estimateBytesUsed,
@@ -15213,6 +15553,7 @@ export {
15213
15553
  isTransformable,
15214
15554
  isTripleArray,
15215
15555
  isVector3,
15556
+ layoutGuiText,
15216
15557
  md5,
15217
15558
  mergeBufferAttributes,
15218
15559
  mergeBufferGeometries,