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.
@@ -296,6 +296,9 @@ var init_Caching = __esm({
296
296
  static {
297
297
  this.blockEntityIndexCache = _Caching.createAssetCache();
298
298
  }
299
+ static {
300
+ this.fontCache = _Caching.createAssetCache();
301
+ }
299
302
  static createAssetCache() {
300
303
  return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
301
304
  }
@@ -322,7 +325,8 @@ var init_Caching = __esm({
322
325
  this.entityModelCache,
323
326
  this.entityTextureCache,
324
327
  this.entityAnimationCache,
325
- this.blockEntityIndexCache
328
+ this.blockEntityIndexCache,
329
+ this.fontCache
326
330
  ];
327
331
  }
328
332
  static clear() {
@@ -4335,8 +4339,8 @@ var init_EntityObject = __esm({
4335
4339
  // src/three/BufferGeometryUtils.js
4336
4340
  import {
4337
4341
  BufferAttribute as BufferAttribute4,
4338
- BufferGeometry as BufferGeometry2,
4339
- Float32BufferAttribute as Float32BufferAttribute4,
4342
+ BufferGeometry as BufferGeometry4,
4343
+ Float32BufferAttribute as Float32BufferAttribute6,
4340
4344
  InterleavedBuffer,
4341
4345
  InterleavedBufferAttribute,
4342
4346
  TriangleFanDrawMode,
@@ -4355,7 +4359,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
4355
4359
  const attributes = {};
4356
4360
  const morphAttributes = {};
4357
4361
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
4358
- const mergedGeometry = new BufferGeometry2();
4362
+ const mergedGeometry = new BufferGeometry4();
4359
4363
  let offset = 0;
4360
4364
  for (let i = 0; i < geometries.length; ++i) {
4361
4365
  const geometry = geometries[i];
@@ -4864,8 +4868,8 @@ function computeMorphedAttributes(object) {
4864
4868
  }
4865
4869
  }
4866
4870
  }
4867
- const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
4868
- const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
4871
+ const morphedPositionAttribute = new Float32BufferAttribute6(modifiedPosition, 3);
4872
+ const morphedNormalAttribute = new Float32BufferAttribute6(modifiedNormal, 3);
4869
4873
  return {
4870
4874
  positionAttribute,
4871
4875
  normalAttribute,
@@ -5115,7 +5119,7 @@ var init_ItemTints = __esm({
5115
5119
  });
5116
5120
 
5117
5121
  // src/model/scene/ModelObject.ts
5118
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler7, Matrix4 as Matrix49 } from "three";
5122
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color9, Euler as Euler7, Matrix4 as Matrix49 } from "three";
5119
5123
  function isModelObject(obj) {
5120
5124
  return obj.isModelObject;
5121
5125
  }
@@ -5232,7 +5236,7 @@ var init_ModelObject = __esm({
5232
5236
  if (tintIndex === void 0 || tintIndex < 0) continue;
5233
5237
  const tint = this.options.tints[tintIndex];
5234
5238
  if (tint === void 0) continue;
5235
- const color = new Color8(tint);
5239
+ const color = new Color9(tint);
5236
5240
  for (let vertex = 0; vertex < 4; vertex++) {
5237
5241
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
5238
5242
  }
@@ -5359,7 +5363,7 @@ var init_fluidBlocks = __esm({
5359
5363
  });
5360
5364
 
5361
5365
  // src/model/fluid/FluidGeometry.ts
5362
- import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
5366
+ import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute7 } from "three";
5363
5367
  function getBlockFluidState(key, state) {
5364
5368
  const rule = key && fluidRules[key.toNamespacedString()];
5365
5369
  if (rule) return {
@@ -5377,7 +5381,7 @@ function ownHeight(sample) {
5377
5381
  return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
5378
5382
  }
5379
5383
  function createFluidGeometry(kind, sample) {
5380
- const geometry = new BufferGeometry4();
5384
+ const geometry = new BufferGeometry6();
5381
5385
  const positions = [], normals = [], uvs = [], indices = [];
5382
5386
  const self = sample(0, 0, 0);
5383
5387
  const height = (x, z) => {
@@ -5476,9 +5480,9 @@ function createFluidGeometry(kind, sample) {
5476
5480
  1
5477
5481
  );
5478
5482
  }
5479
- geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
5480
- geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
5481
- geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
5483
+ geometry.setAttribute("position", new Float32BufferAttribute7(positions, 3));
5484
+ geometry.setAttribute("normal", new Float32BufferAttribute7(normals, 3));
5485
+ geometry.setAttribute("uv", new Float32BufferAttribute7(uvs, 2));
5482
5486
  geometry.setIndex(indices);
5483
5487
  return geometry;
5484
5488
  }
@@ -5498,7 +5502,7 @@ __export(FluidModelObject_exports, {
5498
5502
  FluidModelObject: () => FluidModelObject,
5499
5503
  sampleFluid: () => sampleFluid
5500
5504
  });
5501
- import { BufferAttribute as BufferAttribute6, Color as Color9, DoubleSide as DoubleSide3 } from "three";
5505
+ import { BufferAttribute as BufferAttribute6, Color as Color10, DoubleSide as DoubleSide4 } from "three";
5502
5506
  function sampleFluid(kind, sample) {
5503
5507
  const cells = [];
5504
5508
  const key = [];
@@ -5549,7 +5553,7 @@ var init_FluidModelObject = __esm({
5549
5553
  }
5550
5554
  }
5551
5555
  geometry.clearGroups();
5552
- const color = new Color9(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
5556
+ const color = new Color10(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
5553
5557
  const colors = new Float32Array(geometry.getAttribute("position").count * 3);
5554
5558
  for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
5555
5559
  geometry.setAttribute("color", new BufferAttribute6(colors, 3));
@@ -5566,7 +5570,7 @@ var init_FluidModelObject = __esm({
5566
5570
  super.applyTextures();
5567
5571
  this.iterateAllMeshes((mesh) => {
5568
5572
  const material = mesh.material;
5569
- material.side = DoubleSide3;
5573
+ material.side = DoubleSide4;
5570
5574
  material.forceSinglePass = true;
5571
5575
  material.depthWrite = !material.transparent;
5572
5576
  });
@@ -5782,6 +5786,101 @@ var BlockEntities = class {
5782
5786
  // src/assets/index.ts
5783
5787
  init_BlockStates();
5784
5788
  init_Entities();
5789
+
5790
+ // src/assets/Fonts.ts
5791
+ init_AssetKey();
5792
+ init_AssetLoader();
5793
+ init_AssetParsers();
5794
+ init_ModelTextures();
5795
+ init_Caching();
5796
+ var Fonts = class {
5797
+ static async get(key = "minecraft:default") {
5798
+ const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
5799
+ return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
5800
+ }
5801
+ static relatedKey(assetType, id, origin) {
5802
+ const key = AssetKey.parse(assetType, id);
5803
+ key.root = origin.root;
5804
+ return key;
5805
+ }
5806
+ static async load(key, parents) {
5807
+ const serialized = key.serialize();
5808
+ if (parents.includes(serialized)) throw new Error(`Cyclic font reference: ${key.toNamespacedString()}`);
5809
+ const stack = await AssetLoader.getAll(key, "json" /* JSON */);
5810
+ if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
5811
+ const glyphs = /* @__PURE__ */ new Map();
5812
+ for (const asset of stack) {
5813
+ for (const provider of asset.providers) {
5814
+ if (provider.filter?.uniform || provider.filter?.jp) continue;
5815
+ let provided;
5816
+ switch (provider.type) {
5817
+ case "bitmap":
5818
+ case "minecraft:bitmap":
5819
+ provided = await this.bitmap(provider, key);
5820
+ break;
5821
+ case "space":
5822
+ case "minecraft:space":
5823
+ provided = new Map(Object.entries(provider.advances).map(([character, advance]) => [
5824
+ character,
5825
+ { x: 0, y: 0, width: 0, height: 0, scale: 1, ascent: 0, advance }
5826
+ ]));
5827
+ break;
5828
+ case "reference":
5829
+ case "minecraft:reference":
5830
+ provided = (await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized])).glyphs;
5831
+ break;
5832
+ default:
5833
+ continue;
5834
+ }
5835
+ for (const [character, glyph] of provided) {
5836
+ if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
5837
+ }
5838
+ }
5839
+ }
5840
+ return { glyphs };
5841
+ }
5842
+ static async bitmap(provider, fontKey) {
5843
+ const rows = provider.chars.map((row) => [...row]);
5844
+ const columns = rows[0]?.length;
5845
+ if (!columns || rows.some((row) => row.length !== columns)) {
5846
+ throw new Error(`Invalid character grid in font ${fontKey.toNamespacedString()}`);
5847
+ }
5848
+ const key = this.relatedKey("textures", provider.file, fontKey);
5849
+ const image = await ModelTextures.get(key);
5850
+ if (!image) throw new Error(`Could not load font texture ${key.toNamespacedString()}`);
5851
+ const width = Math.floor(image.width / columns), height = Math.floor(image.height / rows.length);
5852
+ if (!width || !height) throw new Error(`Font texture ${key.toNamespacedString()} is smaller than its character grid`);
5853
+ const scale = (provider.height ?? 8) / height;
5854
+ const pixels = image.data.getImageData(0, 0, image.width, image.height).data;
5855
+ const glyphs = /* @__PURE__ */ new Map();
5856
+ rows.forEach((row, rowIndex) => row.forEach((character, columnIndex) => {
5857
+ if (character === "\0") return;
5858
+ const x = columnIndex * width, y = rowIndex * height;
5859
+ let occupiedWidth = 0;
5860
+ for (let column = width - 1; column >= 0 && !occupiedWidth; column--) {
5861
+ for (let row2 = 0; row2 < height; row2++) {
5862
+ if (pixels[((y + row2) * image.width + x + column) * 4 + 3] !== 0) {
5863
+ occupiedWidth = column + 1;
5864
+ break;
5865
+ }
5866
+ }
5867
+ }
5868
+ glyphs.set(character, {
5869
+ image: image.data.canvas,
5870
+ x,
5871
+ y,
5872
+ width,
5873
+ height,
5874
+ scale,
5875
+ ascent: provider.ascent,
5876
+ advance: Math.floor(occupiedWidth * scale + 0.5) + 1
5877
+ });
5878
+ }));
5879
+ return glyphs;
5880
+ }
5881
+ };
5882
+
5883
+ // src/assets/index.ts
5785
5884
  init_ModelTextures();
5786
5885
  init_Models();
5787
5886
  init_source();
@@ -8780,7 +8879,137 @@ function copyDataTexture(source) {
8780
8879
 
8781
8880
  // src/gui/GuiHelper.ts
8782
8881
  init_AssetKey();
8882
+
8883
+ // src/gui/GuiText.ts
8884
+ import { BufferGeometry as BufferGeometry2, Color as Color8, Float32BufferAttribute as Float32BufferAttribute4 } from "three";
8885
+ async function layoutGuiText(text, options = {}) {
8886
+ const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
8887
+ if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
8888
+ throw new Error("Text wrap width and line height must be positive");
8889
+ }
8890
+ const font = await Fonts.get(options.font);
8891
+ const runs = typeof text === "string" ? [{ text }] : text;
8892
+ const glyphs = [], lineWidths = [];
8893
+ let line = [], width = 0;
8894
+ let trailingNewline = false;
8895
+ const finishLine = (entries) => {
8896
+ let x = 0;
8897
+ for (const entry of entries) {
8898
+ glyphs.push({ ...entry, x, y: lineWidths.length * lineHeight });
8899
+ x += entry.advance;
8900
+ }
8901
+ lineWidths.push(x);
8902
+ };
8903
+ for (const run of runs) {
8904
+ const style = {
8905
+ color: run.color ?? options.color ?? 16777215,
8906
+ bold: run.bold ?? options.bold ?? false,
8907
+ italic: run.italic ?? options.italic ?? false
8908
+ };
8909
+ for (const character of run.text.replace(/\r\n?/g, "\n")) {
8910
+ trailingNewline = character === "\n";
8911
+ if (character === "\n") {
8912
+ finishLine(line);
8913
+ line = [];
8914
+ width = 0;
8915
+ continue;
8916
+ }
8917
+ const glyph = font.glyphs.get(character);
8918
+ const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
8919
+ line.push({ character, glyph, advance, style, x: 0, y: 0 });
8920
+ width += advance;
8921
+ while (width > maxWidth && line.length > 1) {
8922
+ let space = -1;
8923
+ for (let i = 0; i < line.length; i++) if (line[i].character === " ") space = i;
8924
+ const split = space >= 0 ? space : line.length - 1;
8925
+ if (split > 0) finishLine(line.slice(0, split));
8926
+ line = line.slice(split + (space >= 0 ? 1 : 0));
8927
+ width = line.reduce((sum, entry) => sum + entry.advance, 0);
8928
+ }
8929
+ }
8930
+ }
8931
+ if (line.length || !lineWidths.length || trailingNewline) finishLine(line);
8932
+ return { glyphs, lineWidths, width: Math.max(0, ...lineWidths), height: lineWidths.length * lineHeight };
8933
+ }
8934
+ function createGuiTextGeometry(layout, shadow = true) {
8935
+ const batches = [];
8936
+ for (const isShadow of shadow ? [true, false] : [false]) {
8937
+ let batch;
8938
+ for (const entry of layout.glyphs) {
8939
+ const { glyph, style } = entry;
8940
+ if (glyph && !glyph.image) continue;
8941
+ if (!batch || batch.image !== glyph?.image) {
8942
+ batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
8943
+ batches.push(batch);
8944
+ }
8945
+ const color = new Color8(isShadow ? (style.color & 16579836) >> 2 : style.color);
8946
+ const offset = isShadow ? 1 : 0;
8947
+ const top = glyph ? 7 - glyph.ascent : 0;
8948
+ const height = glyph ? glyph.height * glyph.scale : 8;
8949
+ const width = glyph ? glyph.width * glyph.scale : 5;
8950
+ const shear = (y) => style.italic ? 1 - 0.25 * y : 0;
8951
+ const quad = (left, upper, right, lower, boldOffset) => {
8952
+ const base = batch.positions.length / 3;
8953
+ const x = entry.x + offset + boldOffset, y = entry.y + offset;
8954
+ batch.positions.push(
8955
+ x + left + shear(upper),
8956
+ -y - upper,
8957
+ 0,
8958
+ x + right + shear(upper),
8959
+ -y - upper,
8960
+ 0,
8961
+ x + left + shear(lower),
8962
+ -y - lower,
8963
+ 0,
8964
+ x + right + shear(lower),
8965
+ -y - lower,
8966
+ 0
8967
+ );
8968
+ const u0 = glyph ? glyph.x / glyph.image.width : 0;
8969
+ const u1 = glyph ? (glyph.x + glyph.width) / glyph.image.width : 1;
8970
+ const v0 = glyph ? 1 - glyph.y / glyph.image.height : 1;
8971
+ const v1 = glyph ? 1 - (glyph.y + glyph.height) / glyph.image.height : 0;
8972
+ batch.uvs.push(u0, v0, u1, v0, u0, v1, u1, v1);
8973
+ for (let i = 0; i < 4; i++) batch.colors.push(color.r, color.g, color.b);
8974
+ batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
8975
+ };
8976
+ for (const boldOffset of style.bold ? [0, 1] : [0]) {
8977
+ if (glyph) quad(0, top, width, top + height, boldOffset);
8978
+ else {
8979
+ quad(0, 0, 5, 1, boldOffset);
8980
+ quad(0, 7, 5, 8, boldOffset);
8981
+ quad(0, 1, 1, 7, boldOffset);
8982
+ quad(4, 1, 5, 7, boldOffset);
8983
+ }
8984
+ }
8985
+ }
8986
+ }
8987
+ 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) }));
8988
+ }
8989
+
8990
+ // src/gui/GuiHelper.ts
8783
8991
  var GuiHelper = class {
8992
+ /** Sizes a tooltip around supplied text; the first entry is its title. */
8993
+ static async tooltip(lines, options = {}) {
8994
+ if (!lines.length) return [];
8995
+ const { position = [0, 0], titleGap = 2, lineHeight = 10, shadow = true, ...style } = options;
8996
+ const textOptions = { ...style, lineHeight, shadow };
8997
+ const layouts = await Promise.all(lines.map((line) => layoutGuiText(line, textOptions)));
8998
+ const width = Math.max(...layouts.map((layout) => layout.width));
8999
+ const height = layouts.reduce((sum, layout) => sum + layout.height, 0) - 2 + (lines.length > 1 ? titleGap : 0);
9000
+ const layers = ["background", "frame"].map((part) => ({
9001
+ name: `tooltip-${part}`,
9002
+ texture: `minecraft:gui/sprites/tooltip/${part}`,
9003
+ position: [position[0] - 12, position[1] - 12],
9004
+ size: [width + 24, height + 24]
9005
+ }));
9006
+ let y = position[1];
9007
+ lines.forEach((text, index) => {
9008
+ layers.push({ ...textOptions, name: `tooltip-line-${index}`, text, position: [position[0], y] });
9009
+ y += layouts[index].height + (index === 0 ? titleGap : 0);
9010
+ });
9011
+ return layers;
9012
+ }
8784
9013
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
8785
9014
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
8786
9015
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
@@ -8844,6 +9073,85 @@ var GuiHelper = class {
8844
9073
  }
8845
9074
  };
8846
9075
 
9076
+ // src/gui/GuiTextureGeometry.ts
9077
+ import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute5, PlaneGeometry } from "three";
9078
+ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
9079
+ if (crop || !scaling || scaling.type === "stretch") {
9080
+ const [x, y, w, h] = crop ?? [0, 0, imageWidth, imageHeight];
9081
+ const geometry = new PlaneGeometry(width, height);
9082
+ const uv = geometry.getAttribute("uv");
9083
+ for (let i = 0; i < uv.count; i++) {
9084
+ uv.setXY(
9085
+ i,
9086
+ (x + uv.getX(i) * w) / imageWidth,
9087
+ 1 - (y + (1 - uv.getY(i)) * h) / imageHeight
9088
+ );
9089
+ }
9090
+ return geometry;
9091
+ }
9092
+ const sw = scaling.width, sh = scaling.height;
9093
+ if (![sw, sh].every((value) => Number.isInteger(value) && value > 0)) {
9094
+ throw new Error("GUI sprite dimensions must be positive integers");
9095
+ }
9096
+ if (![width, height].every((value) => Number.isFinite(value) && value >= 0)) {
9097
+ throw new Error("GUI output dimensions must be finite and nonnegative");
9098
+ }
9099
+ const positions = [], uvs = [], normals = [], indices = [];
9100
+ function quad(x, y, w, h, u, v, uw, vh) {
9101
+ if (w <= 0 || h <= 0) return;
9102
+ const index = positions.length / 3;
9103
+ const left = x - width / 2, top = height / 2 - y;
9104
+ positions.push(left, top, 0, left + w, top, 0, left, top - h, 0, left + w, top - h, 0);
9105
+ uvs.push(
9106
+ u / sw,
9107
+ 1 - v / sh,
9108
+ (u + uw) / sw,
9109
+ 1 - v / sh,
9110
+ u / sw,
9111
+ 1 - (v + vh) / sh,
9112
+ (u + uw) / sw,
9113
+ 1 - (v + vh) / sh
9114
+ );
9115
+ normals.push(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1);
9116
+ indices.push(index, index + 2, index + 1, index + 2, index + 3, index + 1);
9117
+ }
9118
+ function tile(x, y, w, h, u, v, tw, th) {
9119
+ for (let dy = 0; dy < h; dy += th) {
9120
+ for (let dx = 0; dx < w; dx += tw) {
9121
+ const cw = Math.min(tw, w - dx), ch = Math.min(th, h - dy);
9122
+ quad(x + dx, y + dy, cw, ch, u, v, cw, ch);
9123
+ }
9124
+ }
9125
+ }
9126
+ if (scaling.type === "tile") {
9127
+ tile(0, 0, width, height, 0, 0, sw, sh);
9128
+ } else {
9129
+ let segments = function(size, sourceSize, start, end) {
9130
+ if (size === sourceSize) return [[0, size, 0, sourceSize]];
9131
+ start = Math.min(start, Math.floor(size / 2));
9132
+ end = Math.min(end, Math.floor(size / 2));
9133
+ return [
9134
+ [0, start, 0, start],
9135
+ [start, size - start - end, start, sourceSize - start - end],
9136
+ [size - end, end, sourceSize - end, end]
9137
+ ];
9138
+ };
9139
+ const border = typeof scaling.border === "number" ? { left: scaling.border, top: scaling.border, right: scaling.border, bottom: scaling.border } : scaling.border;
9140
+ 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) {
9141
+ throw new Error("GUI nine-slice borders must be nonnegative integers with a nonempty center");
9142
+ }
9143
+ const columns = segments(width, sw, border.left, border.right);
9144
+ const rows = segments(height, sh, border.top, border.bottom);
9145
+ for (const [y, h, v, vh] of rows) {
9146
+ for (const [x, w, u, uw] of columns) {
9147
+ if (w <= 0 || h <= 0) continue;
9148
+ (scaling.stretch_inner ? quad : tile)(x, y, w, h, u, v, uw, vh);
9149
+ }
9150
+ }
9151
+ }
9152
+ return new BufferGeometry3().setAttribute("position", new Float32BufferAttribute5(positions, 3)).setAttribute("normal", new Float32BufferAttribute5(normals, 3)).setAttribute("uv", new Float32BufferAttribute5(uvs, 2)).setIndex(indices);
9153
+ }
9154
+
8847
9155
  // src/gui/scene/GuiObject.ts
8848
9156
  init_AssetKey();
8849
9157
  init_ModelTextures();
@@ -8854,7 +9162,7 @@ init_Materials();
8854
9162
  init_ModelObject();
8855
9163
  init_DisplayPosition();
8856
9164
  init_GuiLight();
8857
- import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh6, PlaneGeometry, Vector2 as Vector23 } from "three";
9165
+ import { Box2, Box3 as Box32, DoubleSide as DoubleSide3, Group, Matrix4 as Matrix410, Mesh as Mesh6, MeshBasicMaterial as MeshBasicMaterial5, Vector2 as Vector23 } from "three";
8858
9166
  var GuiObject = class extends SceneObject {
8859
9167
  constructor(textureLayers, options) {
8860
9168
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -8864,6 +9172,7 @@ var GuiObject = class extends SceneObject {
8864
9172
  this.bounds = new Box2();
8865
9173
  this.geometries = /* @__PURE__ */ new Set();
8866
9174
  this.ownedMaterials = /* @__PURE__ */ new Set();
9175
+ this.textMaterials = /* @__PURE__ */ new Map();
8867
9176
  this.initialized = false;
8868
9177
  }
8869
9178
  async init() {
@@ -8872,6 +9181,43 @@ var GuiObject = class extends SceneObject {
8872
9181
  let depth = 0;
8873
9182
  for (const [index, layer] of this.textureLayers.entries()) {
8874
9183
  const [x, y] = layer.position ?? [0, 0];
9184
+ if ("text" in layer) {
9185
+ const layout = await layoutGuiText(layer.text, layer);
9186
+ const group = new Group();
9187
+ group.name = `group:${layer.name ?? index}`;
9188
+ group.position.set(x, -y, depth);
9189
+ const [width2, height2] = layer.size ?? [layout.width, layout.height];
9190
+ group.scale.set(layout.width ? width2 / layout.width : 1, height2 / layout.height, 1);
9191
+ this.add(group);
9192
+ const parts = createGuiTextGeometry(layout, layer.shadow);
9193
+ const bounds = new Box32();
9194
+ for (const [partIndex, { image: image2, geometry: geometry2 }] of parts.entries()) {
9195
+ this.geometries.add(geometry2);
9196
+ geometry2.computeBoundingBox();
9197
+ bounds.union(geometry2.boundingBox);
9198
+ let material2 = this.textMaterials.get(image2);
9199
+ if (!material2) {
9200
+ material2 = image2 ? Materials.createGuiCanvasMaterial(image2) : new MeshBasicMaterial5({ transparent: true, depthWrite: false, side: DoubleSide3, toneMapped: false });
9201
+ material2.vertexColors = true;
9202
+ this.textMaterials.set(image2, material2);
9203
+ this.ownedMaterials.add(material2);
9204
+ }
9205
+ const mesh2 = new Mesh6(geometry2, material2);
9206
+ mesh2.name = `mesh:${layer.name ?? index}:${partIndex}`;
9207
+ mesh2.renderOrder = index + partIndex / (parts.length + 1) * 0.5;
9208
+ group.add(mesh2);
9209
+ }
9210
+ group.updateMatrix();
9211
+ bounds.applyMatrix4(group.matrix);
9212
+ this.bounds.expandByPoint(new Vector23(x, y));
9213
+ this.bounds.expandByPoint(new Vector23(x + width2, y + height2));
9214
+ if (!bounds.isEmpty()) {
9215
+ this.bounds.expandByPoint(new Vector23(bounds.min.x, -bounds.max.y));
9216
+ this.bounds.expandByPoint(new Vector23(bounds.max.x, -bounds.min.y));
9217
+ }
9218
+ depth += 0.01;
9219
+ continue;
9220
+ }
8875
9221
  if ("item" in layer) {
8876
9222
  const [width2, height2] = layer.size ?? [16, 16];
8877
9223
  const item = await this.createItem(layer, index);
@@ -8895,18 +9241,10 @@ var GuiObject = class extends SceneObject {
8895
9241
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
8896
9242
  const material = await this.loadMaterial(key);
8897
9243
  const image = material.map.image;
8898
- const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
8899
- const [width, height] = layer.size ?? [cropWidth, cropHeight];
8900
- const geometry = new PlaneGeometry(width, height);
9244
+ const scaling = layer.crop ? void 0 : (await ModelTextures.getMeta(key))?.gui?.scaling;
9245
+ const [width, height] = layer.size ?? (layer.crop ? layer.crop.slice(2) : scaling && scaling.type !== "stretch" ? [scaling.width, scaling.height] : [image.width, image.height]);
9246
+ const geometry = createGuiTextureGeometry(width, height, image.width, image.height, layer.crop, scaling);
8901
9247
  this.geometries.add(geometry);
8902
- const uv = geometry.getAttribute("uv");
8903
- for (let i = 0; i < uv.count; i++) {
8904
- uv.setXY(
8905
- i,
8906
- (cropX + uv.getX(i) * cropWidth) / image.width,
8907
- 1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
8908
- );
8909
- }
8910
9248
  const mesh = new Mesh6(geometry, material);
8911
9249
  mesh.name = `mesh:${layer.name ?? index}`;
8912
9250
  mesh.position.set(x + width / 2, -y - height / 2, depth);
@@ -8971,10 +9309,11 @@ var GuiObject = class extends SceneObject {
8971
9309
  for (const geometry of this.geometries) geometry.dispose();
8972
9310
  this.geometries.clear();
8973
9311
  for (const material of this.ownedMaterials) {
8974
- material.map.dispose();
9312
+ material.map?.dispose();
8975
9313
  material.dispose();
8976
9314
  }
8977
9315
  this.ownedMaterials.clear();
9316
+ this.textMaterials.clear();
8978
9317
  this.bounds.makeEmpty();
8979
9318
  this.initialized = false;
8980
9319
  super.disposeAndRemoveAllChildren();
@@ -12541,7 +12880,7 @@ init_util();
12541
12880
  init_Caching();
12542
12881
  init_CacheKey();
12543
12882
  init_MineRenderError();
12544
- import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12883
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide5, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12545
12884
 
12546
12885
  // src/skin/SkinImage.ts
12547
12886
  init_Caching();
@@ -12626,7 +12965,7 @@ var SkinTextures = class {
12626
12965
  texture.colorSpace = SRGBColorSpace6;
12627
12966
  texture.flipY = true;
12628
12967
  texture.needsUpdate = true;
12629
- return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
12968
+ return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide5 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
12630
12969
  }
12631
12970
  static isSlim(image, scale) {
12632
12971
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -14836,8 +15175,8 @@ init_Model();
14836
15175
  // src/world/SectionMesh.ts
14837
15176
  init_CanvasCompat();
14838
15177
  init_Materials();
14839
- import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh9 } from "three";
14840
- var SectionMesh = class _SectionMesh extends Group {
15178
+ import { BufferGeometry as BufferGeometry8, Float32BufferAttribute as Float32BufferAttribute8, Group as Group2, Mesh as Mesh9 } from "three";
15179
+ var SectionMesh = class _SectionMesh extends Group2 {
14841
15180
  constructor() {
14842
15181
  super(...arguments);
14843
15182
  this.ownedMeshes = [];
@@ -14910,11 +15249,11 @@ var SectionMesh = class _SectionMesh extends Group {
14910
15249
  for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
14911
15250
  }
14912
15251
  }
14913
- const geometry = new BufferGeometry6();
14914
- geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
14915
- geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
14916
- geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
14917
- geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
15252
+ const geometry = new BufferGeometry8();
15253
+ geometry.setAttribute("position", new Float32BufferAttribute8(positions, 3));
15254
+ geometry.setAttribute("normal", new Float32BufferAttribute8(normals, 3));
15255
+ geometry.setAttribute("uv", new Float32BufferAttribute8(uvs, 2));
15256
+ geometry.setAttribute("color", new Float32BufferAttribute8(colors, 3));
14918
15257
  geometry.setIndex(indices);
14919
15258
  geometry.computeBoundingBox();
14920
15259
  geometry.computeBoundingSphere();
@@ -15166,6 +15505,7 @@ export {
15166
15505
  EntityObject,
15167
15506
  Env,
15168
15507
  FluidModelObject,
15508
+ Fonts,
15169
15509
  Geometries,
15170
15510
  GuiHelper,
15171
15511
  GuiLight,
@@ -15239,6 +15579,8 @@ export {
15239
15579
  computeTangents,
15240
15580
  createCanvas2 as createCanvas,
15241
15581
  createFluidGeometry,
15582
+ createGuiTextGeometry,
15583
+ createGuiTextureGeometry,
15242
15584
  createImage,
15243
15585
  entityAnimationTime,
15244
15586
  estimateBytesUsed,
@@ -15267,6 +15609,7 @@ export {
15267
15609
  isTransformable,
15268
15610
  isTripleArray,
15269
15611
  isVector3,
15612
+ layoutGuiText,
15270
15613
  md5,
15271
15614
  mergeBufferAttributes,
15272
15615
  mergeBufferGeometries,