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.
package/dist/bundle.js CHANGED
@@ -41421,7 +41421,8 @@ void main() {
41421
41421
  this.entityModelCache,
41422
41422
  this.entityTextureCache,
41423
41423
  this.entityAnimationCache,
41424
- this.blockEntityIndexCache
41424
+ this.blockEntityIndexCache,
41425
+ this.fontCache
41425
41426
  ];
41426
41427
  }
41427
41428
  static clear() {
@@ -41468,6 +41469,7 @@ void main() {
41468
41469
  _Caching.entityTextureCache = _Caching.createAssetCache();
41469
41470
  _Caching.entityAnimationCache = _Caching.createAssetCache();
41470
41471
  _Caching.blockEntityIndexCache = _Caching.createAssetCache();
41472
+ _Caching.fontCache = _Caching.createAssetCache();
41471
41473
  Caching = _Caching;
41472
41474
  }
41473
41475
  });
@@ -93313,6 +93315,7 @@ ${shader.fragmentShader}`.replace(
93313
93315
  EntityObject: () => EntityObject,
93314
93316
  Env: () => Env,
93315
93317
  FluidModelObject: () => FluidModelObject,
93318
+ Fonts: () => Fonts,
93316
93319
  Geometries: () => Geometries,
93317
93320
  GuiHelper: () => GuiHelper,
93318
93321
  GuiLight: () => GuiLight,
@@ -93384,6 +93387,8 @@ ${shader.fragmentShader}`.replace(
93384
93387
  computeTangents: () => computeTangents,
93385
93388
  createCanvas: () => createCanvas,
93386
93389
  createFluidGeometry: () => createFluidGeometry,
93390
+ createGuiTextGeometry: () => createGuiTextGeometry,
93391
+ createGuiTextureGeometry: () => createGuiTextureGeometry,
93387
93392
  createImage: () => createImage,
93388
93393
  entityAnimationTime: () => entityAnimationTime,
93389
93394
  estimateBytesUsed: () => estimateBytesUsed,
@@ -93412,6 +93417,7 @@ ${shader.fragmentShader}`.replace(
93412
93417
  isTransformable: () => isTransformable,
93413
93418
  isTripleArray: () => isTripleArray,
93414
93419
  isVector3: () => isVector3,
93420
+ layoutGuiText: () => layoutGuiText,
93415
93421
  md5: () => md5,
93416
93422
  mergeBufferAttributes: () => mergeBufferAttributes,
93417
93423
  mergeBufferGeometries: () => mergeBufferGeometries,
@@ -93759,6 +93765,104 @@ ${shader.fragmentShader}`.replace(
93759
93765
  // src/assets/index.ts
93760
93766
  init_BlockStates();
93761
93767
  init_Entities();
93768
+
93769
+ // src/assets/Fonts.ts
93770
+ init_dirname();
93771
+ init_buffer2();
93772
+ init_process2();
93773
+ init_AssetKey();
93774
+ init_AssetLoader();
93775
+ init_AssetParsers();
93776
+ init_ModelTextures();
93777
+ init_Caching();
93778
+ var Fonts = class {
93779
+ static async get(key = "minecraft:default") {
93780
+ const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
93781
+ return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
93782
+ }
93783
+ static relatedKey(assetType, id, origin) {
93784
+ const key = AssetKey.parse(assetType, id);
93785
+ key.root = origin.root;
93786
+ return key;
93787
+ }
93788
+ static async load(key, parents) {
93789
+ const serialized = key.serialize();
93790
+ if (parents.includes(serialized)) throw new Error(`Cyclic font reference: ${key.toNamespacedString()}`);
93791
+ const stack = await AssetLoader.getAll(key, "json" /* JSON */);
93792
+ if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
93793
+ const glyphs = /* @__PURE__ */ new Map();
93794
+ for (const asset of stack) {
93795
+ for (const provider of asset.providers) {
93796
+ if (provider.filter?.uniform || provider.filter?.jp) continue;
93797
+ let provided;
93798
+ switch (provider.type) {
93799
+ case "bitmap":
93800
+ case "minecraft:bitmap":
93801
+ provided = await this.bitmap(provider, key);
93802
+ break;
93803
+ case "space":
93804
+ case "minecraft:space":
93805
+ provided = new Map(Object.entries(provider.advances).map(([character, advance]) => [
93806
+ character,
93807
+ { x: 0, y: 0, width: 0, height: 0, scale: 1, ascent: 0, advance }
93808
+ ]));
93809
+ break;
93810
+ case "reference":
93811
+ case "minecraft:reference":
93812
+ provided = (await this.load(this.relatedKey("font", provider.id, key), [...parents, serialized])).glyphs;
93813
+ break;
93814
+ default:
93815
+ continue;
93816
+ }
93817
+ for (const [character, glyph] of provided) {
93818
+ if (character !== "\0" && !glyphs.has(character)) glyphs.set(character, glyph);
93819
+ }
93820
+ }
93821
+ }
93822
+ return { glyphs };
93823
+ }
93824
+ static async bitmap(provider, fontKey) {
93825
+ const rows = provider.chars.map((row) => [...row]);
93826
+ const columns = rows[0]?.length;
93827
+ if (!columns || rows.some((row) => row.length !== columns)) {
93828
+ throw new Error(`Invalid character grid in font ${fontKey.toNamespacedString()}`);
93829
+ }
93830
+ const key = this.relatedKey("textures", provider.file, fontKey);
93831
+ const image = await ModelTextures.get(key);
93832
+ if (!image) throw new Error(`Could not load font texture ${key.toNamespacedString()}`);
93833
+ const width = Math.floor(image.width / columns), height = Math.floor(image.height / rows.length);
93834
+ if (!width || !height) throw new Error(`Font texture ${key.toNamespacedString()} is smaller than its character grid`);
93835
+ const scale = (provider.height ?? 8) / height;
93836
+ const pixels = image.data.getImageData(0, 0, image.width, image.height).data;
93837
+ const glyphs = /* @__PURE__ */ new Map();
93838
+ rows.forEach((row, rowIndex) => row.forEach((character, columnIndex) => {
93839
+ if (character === "\0") return;
93840
+ const x4 = columnIndex * width, y5 = rowIndex * height;
93841
+ let occupiedWidth = 0;
93842
+ for (let column = width - 1; column >= 0 && !occupiedWidth; column--) {
93843
+ for (let row2 = 0; row2 < height; row2++) {
93844
+ if (pixels[((y5 + row2) * image.width + x4 + column) * 4 + 3] !== 0) {
93845
+ occupiedWidth = column + 1;
93846
+ break;
93847
+ }
93848
+ }
93849
+ }
93850
+ glyphs.set(character, {
93851
+ image: image.data.canvas,
93852
+ x: x4,
93853
+ y: y5,
93854
+ width,
93855
+ height,
93856
+ scale,
93857
+ ascent: provider.ascent,
93858
+ advance: Math.floor(occupiedWidth * scale + 0.5) + 1
93859
+ });
93860
+ }));
93861
+ return glyphs;
93862
+ }
93863
+ };
93864
+
93865
+ // src/assets/index.ts
93762
93866
  init_ModelTextures();
93763
93867
  init_Models();
93764
93868
  init_source();
@@ -96789,7 +96893,140 @@ property list uchar int vertex_index
96789
96893
  init_buffer2();
96790
96894
  init_process2();
96791
96895
  init_AssetKey();
96896
+
96897
+ // src/gui/GuiText.ts
96898
+ init_dirname();
96899
+ init_buffer2();
96900
+ init_process2();
96901
+ init_three_module();
96902
+ async function layoutGuiText(text, options = {}) {
96903
+ const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
96904
+ if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
96905
+ throw new Error("Text wrap width and line height must be positive");
96906
+ }
96907
+ const font = await Fonts.get(options.font);
96908
+ const runs = typeof text === "string" ? [{ text }] : text;
96909
+ const glyphs = [], lineWidths = [];
96910
+ let line = [], width = 0;
96911
+ let trailingNewline = false;
96912
+ const finishLine = (entries) => {
96913
+ let x4 = 0;
96914
+ for (const entry of entries) {
96915
+ glyphs.push({ ...entry, x: x4, y: lineWidths.length * lineHeight });
96916
+ x4 += entry.advance;
96917
+ }
96918
+ lineWidths.push(x4);
96919
+ };
96920
+ for (const run of runs) {
96921
+ const style = {
96922
+ color: run.color ?? options.color ?? 16777215,
96923
+ bold: run.bold ?? options.bold ?? false,
96924
+ italic: run.italic ?? options.italic ?? false
96925
+ };
96926
+ for (const character of run.text.replace(/\r\n?/g, "\n")) {
96927
+ trailingNewline = character === "\n";
96928
+ if (character === "\n") {
96929
+ finishLine(line);
96930
+ line = [];
96931
+ width = 0;
96932
+ continue;
96933
+ }
96934
+ const glyph = font.glyphs.get(character);
96935
+ const advance = (glyph?.advance ?? 6) + (style.bold ? 1 : 0);
96936
+ line.push({ character, glyph, advance, style, x: 0, y: 0 });
96937
+ width += advance;
96938
+ while (width > maxWidth && line.length > 1) {
96939
+ let space = -1;
96940
+ for (let i4 = 0; i4 < line.length; i4++) if (line[i4].character === " ") space = i4;
96941
+ const split = space >= 0 ? space : line.length - 1;
96942
+ if (split > 0) finishLine(line.slice(0, split));
96943
+ line = line.slice(split + (space >= 0 ? 1 : 0));
96944
+ width = line.reduce((sum, entry) => sum + entry.advance, 0);
96945
+ }
96946
+ }
96947
+ }
96948
+ if (line.length || !lineWidths.length || trailingNewline) finishLine(line);
96949
+ return { glyphs, lineWidths, width: Math.max(0, ...lineWidths), height: lineWidths.length * lineHeight };
96950
+ }
96951
+ function createGuiTextGeometry(layout, shadow = true) {
96952
+ const batches = [];
96953
+ for (const isShadow of shadow ? [true, false] : [false]) {
96954
+ let batch;
96955
+ for (const entry of layout.glyphs) {
96956
+ const { glyph, style } = entry;
96957
+ if (glyph && !glyph.image) continue;
96958
+ if (!batch || batch.image !== glyph?.image) {
96959
+ batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
96960
+ batches.push(batch);
96961
+ }
96962
+ const color2 = new Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
96963
+ const offset = isShadow ? 1 : 0;
96964
+ const top = glyph ? 7 - glyph.ascent : 0;
96965
+ const height = glyph ? glyph.height * glyph.scale : 8;
96966
+ const width = glyph ? glyph.width * glyph.scale : 5;
96967
+ const shear = (y5) => style.italic ? 1 - 0.25 * y5 : 0;
96968
+ const quad = (left, upper, right, lower, boldOffset) => {
96969
+ const base = batch.positions.length / 3;
96970
+ const x4 = entry.x + offset + boldOffset, y5 = entry.y + offset;
96971
+ batch.positions.push(
96972
+ x4 + left + shear(upper),
96973
+ -y5 - upper,
96974
+ 0,
96975
+ x4 + right + shear(upper),
96976
+ -y5 - upper,
96977
+ 0,
96978
+ x4 + left + shear(lower),
96979
+ -y5 - lower,
96980
+ 0,
96981
+ x4 + right + shear(lower),
96982
+ -y5 - lower,
96983
+ 0
96984
+ );
96985
+ const u0 = glyph ? glyph.x / glyph.image.width : 0;
96986
+ const u1 = glyph ? (glyph.x + glyph.width) / glyph.image.width : 1;
96987
+ const v0 = glyph ? 1 - glyph.y / glyph.image.height : 1;
96988
+ const v1 = glyph ? 1 - (glyph.y + glyph.height) / glyph.image.height : 0;
96989
+ batch.uvs.push(u0, v0, u1, v0, u0, v1, u1, v1);
96990
+ for (let i4 = 0; i4 < 4; i4++) batch.colors.push(color2.r, color2.g, color2.b);
96991
+ batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
96992
+ };
96993
+ for (const boldOffset of style.bold ? [0, 1] : [0]) {
96994
+ if (glyph) quad(0, top, width, top + height, boldOffset);
96995
+ else {
96996
+ quad(0, 0, 5, 1, boldOffset);
96997
+ quad(0, 7, 5, 8, boldOffset);
96998
+ quad(0, 1, 1, 7, boldOffset);
96999
+ quad(4, 1, 5, 7, boldOffset);
97000
+ }
97001
+ }
97002
+ }
97003
+ }
97004
+ return batches.map(({ image, positions, uvs, colors, indices }) => ({ image, geometry: new BufferGeometry().setAttribute("position", new Float32BufferAttribute(positions, 3)).setAttribute("uv", new Float32BufferAttribute(uvs, 2)).setAttribute("color", new Float32BufferAttribute(colors, 3)).setIndex(indices) }));
97005
+ }
97006
+
97007
+ // src/gui/GuiHelper.ts
96792
97008
  var GuiHelper = class {
97009
+ /** Sizes a tooltip around supplied text; the first entry is its title. */
97010
+ static async tooltip(lines, options = {}) {
97011
+ if (!lines.length) return [];
97012
+ const { position = [0, 0], titleGap = 2, lineHeight = 10, shadow = true, ...style } = options;
97013
+ const textOptions = { ...style, lineHeight, shadow };
97014
+ const layouts = await Promise.all(lines.map((line) => layoutGuiText(line, textOptions)));
97015
+ const width = Math.max(...layouts.map((layout) => layout.width));
97016
+ const height = layouts.reduce((sum, layout) => sum + layout.height, 0) - 2 + (lines.length > 1 ? titleGap : 0);
97017
+ const layers = ["background", "frame"].map((part) => ({
97018
+ name: `tooltip-${part}`,
97019
+ texture: `minecraft:gui/sprites/tooltip/${part}`,
97020
+ position: [position[0] - 12, position[1] - 12],
97021
+ size: [width + 24, height + 24]
97022
+ }));
97023
+ let y5 = position[1];
97024
+ lines.forEach((text, index) => {
97025
+ layers.push({ ...textOptions, name: `tooltip-line-${index}`, text, position: [position[0], y5] });
97026
+ y5 += layouts[index].height + (index === 0 ? titleGap : 0);
97027
+ });
97028
+ return layers;
97029
+ }
96793
97030
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
96794
97031
  const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
96795
97032
  return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
@@ -96858,6 +97095,88 @@ property list uchar int vertex_index
96858
97095
  init_buffer2();
96859
97096
  init_process2();
96860
97097
 
97098
+ // src/gui/GuiTextureGeometry.ts
97099
+ init_dirname();
97100
+ init_buffer2();
97101
+ init_process2();
97102
+ init_three_module();
97103
+ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
97104
+ if (crop || !scaling || scaling.type === "stretch") {
97105
+ const [x4, y5, w4, h5] = crop ?? [0, 0, imageWidth, imageHeight];
97106
+ const geometry = new PlaneGeometry(width, height);
97107
+ const uv = geometry.getAttribute("uv");
97108
+ for (let i4 = 0; i4 < uv.count; i4++) {
97109
+ uv.setXY(
97110
+ i4,
97111
+ (x4 + uv.getX(i4) * w4) / imageWidth,
97112
+ 1 - (y5 + (1 - uv.getY(i4)) * h5) / imageHeight
97113
+ );
97114
+ }
97115
+ return geometry;
97116
+ }
97117
+ const sw = scaling.width, sh = scaling.height;
97118
+ if (![sw, sh].every((value) => Number.isInteger(value) && value > 0)) {
97119
+ throw new Error("GUI sprite dimensions must be positive integers");
97120
+ }
97121
+ if (![width, height].every((value) => Number.isFinite(value) && value >= 0)) {
97122
+ throw new Error("GUI output dimensions must be finite and nonnegative");
97123
+ }
97124
+ const positions = [], uvs = [], normals = [], indices = [];
97125
+ function quad(x4, y5, w4, h5, u4, v5, uw, vh) {
97126
+ if (w4 <= 0 || h5 <= 0) return;
97127
+ const index = positions.length / 3;
97128
+ const left = x4 - width / 2, top = height / 2 - y5;
97129
+ positions.push(left, top, 0, left + w4, top, 0, left, top - h5, 0, left + w4, top - h5, 0);
97130
+ uvs.push(
97131
+ u4 / sw,
97132
+ 1 - v5 / sh,
97133
+ (u4 + uw) / sw,
97134
+ 1 - v5 / sh,
97135
+ u4 / sw,
97136
+ 1 - (v5 + vh) / sh,
97137
+ (u4 + uw) / sw,
97138
+ 1 - (v5 + vh) / sh
97139
+ );
97140
+ normals.push(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1);
97141
+ indices.push(index, index + 2, index + 1, index + 2, index + 3, index + 1);
97142
+ }
97143
+ function tile(x4, y5, w4, h5, u4, v5, tw, th) {
97144
+ for (let dy = 0; dy < h5; dy += th) {
97145
+ for (let dx = 0; dx < w4; dx += tw) {
97146
+ const cw = Math.min(tw, w4 - dx), ch = Math.min(th, h5 - dy);
97147
+ quad(x4 + dx, y5 + dy, cw, ch, u4, v5, cw, ch);
97148
+ }
97149
+ }
97150
+ }
97151
+ if (scaling.type === "tile") {
97152
+ tile(0, 0, width, height, 0, 0, sw, sh);
97153
+ } else {
97154
+ let segments = function(size, sourceSize, start, end) {
97155
+ if (size === sourceSize) return [[0, size, 0, sourceSize]];
97156
+ start = Math.min(start, Math.floor(size / 2));
97157
+ end = Math.min(end, Math.floor(size / 2));
97158
+ return [
97159
+ [0, start, 0, start],
97160
+ [start, size - start - end, start, sourceSize - start - end],
97161
+ [size - end, end, sourceSize - end, end]
97162
+ ];
97163
+ };
97164
+ const border2 = typeof scaling.border === "number" ? { left: scaling.border, top: scaling.border, right: scaling.border, bottom: scaling.border } : scaling.border;
97165
+ if (!border2 || typeof scaling.border === "number" && scaling.border <= 0 || ![border2.left, border2.top, border2.right, border2.bottom].every((value) => Number.isInteger(value) && value >= 0) || border2.left + border2.right >= sw || border2.top + border2.bottom >= sh) {
97166
+ throw new Error("GUI nine-slice borders must be nonnegative integers with a nonempty center");
97167
+ }
97168
+ const columns = segments(width, sw, border2.left, border2.right);
97169
+ const rows = segments(height, sh, border2.top, border2.bottom);
97170
+ for (const [y5, h5, v5, vh] of rows) {
97171
+ for (const [x4, w4, u4, uw] of columns) {
97172
+ if (w4 <= 0 || h5 <= 0) continue;
97173
+ (scaling.stretch_inner ? quad : tile)(x4, y5, w4, h5, u4, v5, uw, vh);
97174
+ }
97175
+ }
97176
+ }
97177
+ return new BufferGeometry().setAttribute("position", new Float32BufferAttribute(positions, 3)).setAttribute("normal", new Float32BufferAttribute(normals, 3)).setAttribute("uv", new Float32BufferAttribute(uvs, 2)).setIndex(indices);
97178
+ }
97179
+
96861
97180
  // src/gui/scene/index.ts
96862
97181
  init_dirname();
96863
97182
  init_buffer2();
@@ -96886,6 +97205,7 @@ property list uchar int vertex_index
96886
97205
  this.bounds = new Box2();
96887
97206
  this.geometries = /* @__PURE__ */ new Set();
96888
97207
  this.ownedMaterials = /* @__PURE__ */ new Set();
97208
+ this.textMaterials = /* @__PURE__ */ new Map();
96889
97209
  this.initialized = false;
96890
97210
  }
96891
97211
  async init() {
@@ -96894,6 +97214,43 @@ property list uchar int vertex_index
96894
97214
  let depth = 0;
96895
97215
  for (const [index, layer] of this.textureLayers.entries()) {
96896
97216
  const [x4, y5] = layer.position ?? [0, 0];
97217
+ if ("text" in layer) {
97218
+ const layout = await layoutGuiText(layer.text, layer);
97219
+ const group = new Group();
97220
+ group.name = `group:${layer.name ?? index}`;
97221
+ group.position.set(x4, -y5, depth);
97222
+ const [width2, height2] = layer.size ?? [layout.width, layout.height];
97223
+ group.scale.set(layout.width ? width2 / layout.width : 1, height2 / layout.height, 1);
97224
+ this.add(group);
97225
+ const parts = createGuiTextGeometry(layout, layer.shadow);
97226
+ const bounds = new Box3();
97227
+ for (const [partIndex, { image: image2, geometry: geometry2 }] of parts.entries()) {
97228
+ this.geometries.add(geometry2);
97229
+ geometry2.computeBoundingBox();
97230
+ bounds.union(geometry2.boundingBox);
97231
+ let material2 = this.textMaterials.get(image2);
97232
+ if (!material2) {
97233
+ material2 = image2 ? Materials.createGuiCanvasMaterial(image2) : new MeshBasicMaterial({ transparent: true, depthWrite: false, side: DoubleSide, toneMapped: false });
97234
+ material2.vertexColors = true;
97235
+ this.textMaterials.set(image2, material2);
97236
+ this.ownedMaterials.add(material2);
97237
+ }
97238
+ const mesh2 = new Mesh(geometry2, material2);
97239
+ mesh2.name = `mesh:${layer.name ?? index}:${partIndex}`;
97240
+ mesh2.renderOrder = index + partIndex / (parts.length + 1) * 0.5;
97241
+ group.add(mesh2);
97242
+ }
97243
+ group.updateMatrix();
97244
+ bounds.applyMatrix4(group.matrix);
97245
+ this.bounds.expandByPoint(new Vector2(x4, y5));
97246
+ this.bounds.expandByPoint(new Vector2(x4 + width2, y5 + height2));
97247
+ if (!bounds.isEmpty()) {
97248
+ this.bounds.expandByPoint(new Vector2(bounds.min.x, -bounds.max.y));
97249
+ this.bounds.expandByPoint(new Vector2(bounds.max.x, -bounds.min.y));
97250
+ }
97251
+ depth += 0.01;
97252
+ continue;
97253
+ }
96897
97254
  if ("item" in layer) {
96898
97255
  const [width2, height2] = layer.size ?? [16, 16];
96899
97256
  const item = await this.createItem(layer, index);
@@ -96917,18 +97274,10 @@ property list uchar int vertex_index
96917
97274
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
96918
97275
  const material = await this.loadMaterial(key);
96919
97276
  const image = material.map.image;
96920
- const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
96921
- const [width, height] = layer.size ?? [cropWidth, cropHeight];
96922
- const geometry = new PlaneGeometry(width, height);
97277
+ const scaling = layer.crop ? void 0 : (await ModelTextures.getMeta(key))?.gui?.scaling;
97278
+ const [width, height] = layer.size ?? (layer.crop ? layer.crop.slice(2) : scaling && scaling.type !== "stretch" ? [scaling.width, scaling.height] : [image.width, image.height]);
97279
+ const geometry = createGuiTextureGeometry(width, height, image.width, image.height, layer.crop, scaling);
96923
97280
  this.geometries.add(geometry);
96924
- const uv = geometry.getAttribute("uv");
96925
- for (let i4 = 0; i4 < uv.count; i4++) {
96926
- uv.setXY(
96927
- i4,
96928
- (cropX + uv.getX(i4) * cropWidth) / image.width,
96929
- 1 - (cropY + (1 - uv.getY(i4)) * cropHeight) / image.height
96930
- );
96931
- }
96932
97281
  const mesh = new Mesh(geometry, material);
96933
97282
  mesh.name = `mesh:${layer.name ?? index}`;
96934
97283
  mesh.position.set(x4 + width / 2, -y5 - height / 2, depth);
@@ -96993,10 +97342,11 @@ property list uchar int vertex_index
96993
97342
  for (const geometry of this.geometries) geometry.dispose();
96994
97343
  this.geometries.clear();
96995
97344
  for (const material of this.ownedMaterials) {
96996
- material.map.dispose();
97345
+ material.map?.dispose();
96997
97346
  material.dispose();
96998
97347
  }
96999
97348
  this.ownedMaterials.clear();
97349
+ this.textMaterials.clear();
97000
97350
  this.bounds.makeEmpty();
97001
97351
  this.initialized = false;
97002
97352
  super.disposeAndRemoveAllChildren();