minerender 2.1.0-alpha.27 → 2.1.0-alpha.28

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.
@@ -5535,14 +5535,96 @@ var slimSkinGeometries = {
5535
5535
 
5536
5536
  // src/skin/scene/SkinObject.ts
5537
5537
  var import_ts_deepmerge7 = __toESM(require_dist());
5538
+
5539
+ // src/skin/SkinTextures.ts
5540
+ import { DataTexture, DoubleSide as DoubleSide2, MeshBasicMaterial as MeshBasicMaterial3, SRGBColorSpace as SRGBColorSpace3 } from "three";
5541
+ var SkinTextures = class {
5542
+ static async get(src, legacy) {
5543
+ const image = await ImageLoader.getData(src);
5544
+ const scale = image.width / 64;
5545
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width && image.height !== image.width / 2) {
5546
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; expected 64x64 or 64x32, or an integer-scaled equivalent`);
5547
+ }
5548
+ const isLegacy = legacy ?? image.height === image.width / 2;
5549
+ if (!isLegacy && image.height !== image.width) {
5550
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; non-legacy skins must be square`);
5551
+ }
5552
+ const slim = !isLegacy && this.isSlim(image, scale);
5553
+ const key = `skin:${serializeImageKey({ src })}:${isLegacy}`;
5554
+ const material = Caching.materialCache.get(key, () => {
5555
+ const pixels = isLegacy ? this.normalizeLegacy(image, scale) : new Uint8Array(image.data);
5556
+ const texture = Textures.initTextureProps(new DataTexture(pixels, image.width, image.width));
5557
+ texture.colorSpace = SRGBColorSpace3;
5558
+ texture.flipY = true;
5559
+ texture.needsUpdate = true;
5560
+ return new MeshBasicMaterial3({ map: texture, transparent: true, side: DoubleSide2, alphaTest: 0.5 });
5561
+ });
5562
+ return { material, slim, legacy: isLegacy };
5563
+ }
5564
+ static isSlim(image, scale) {
5565
+ for (const [x, y] of [[46, 52], [54, 20]]) {
5566
+ for (let row = y * scale; row < (y + 12) * scale; row++) {
5567
+ for (let column = x * scale; column < (x + 1) * scale; column++) {
5568
+ if (image.data[(row * image.width + column) * 4 + 3] !== 0) return false;
5569
+ }
5570
+ }
5571
+ }
5572
+ return true;
5573
+ }
5574
+ static normalizeLegacy(image, scale) {
5575
+ const pixels = new Uint8Array(image.width * image.width * 4);
5576
+ pixels.set(image.data.subarray(0, image.width * image.width / 2 * 4));
5577
+ for (const [sx, sy, dx, dy, width, height] of [
5578
+ [4, 16, 20, 48, 4, 4],
5579
+ [8, 16, 24, 48, 4, 4],
5580
+ [0, 20, 24, 52, 4, 12],
5581
+ [4, 20, 20, 52, 4, 12],
5582
+ [8, 20, 16, 52, 4, 12],
5583
+ [12, 20, 28, 52, 4, 12],
5584
+ [44, 16, 36, 48, 4, 4],
5585
+ [48, 16, 40, 48, 4, 4],
5586
+ [40, 20, 40, 52, 4, 12],
5587
+ [44, 20, 36, 52, 4, 12],
5588
+ [48, 20, 32, 52, 4, 12],
5589
+ [52, 20, 44, 52, 4, 12]
5590
+ ]) {
5591
+ for (let y = 0; y < height * scale; y++) {
5592
+ for (let x = 0; x < width * scale; x++) {
5593
+ const source = ((sy * scale + y) * image.width + sx * scale + x) * 4;
5594
+ const target = ((dy * scale + y) * image.width + (dx + width) * scale - 1 - x) * 4;
5595
+ pixels.set(image.data.subarray(source, source + 4), target);
5596
+ }
5597
+ }
5598
+ }
5599
+ let clearHat = true;
5600
+ for (let y = 0; y < 32 * scale; y++) {
5601
+ for (let x = 32 * scale; x < image.width; x++) {
5602
+ if (pixels[(y * image.width + x) * 4 + 3] < 128) clearHat = false;
5603
+ }
5604
+ }
5605
+ for (let y = 0; y < image.width; y++) {
5606
+ for (let x = 0; x < image.width; x++) {
5607
+ const alpha = (y * image.width + x) * 4 + 3;
5608
+ if (x < 32 * scale && y < 16 * scale || y >= 16 * scale && y < 32 * scale || x >= 16 * scale && x < 48 * scale && y >= 48 * scale) {
5609
+ pixels[alpha] = 255;
5610
+ } else if (clearHat && x >= 32 * scale && y < 32 * scale) {
5611
+ pixels[alpha] = 0;
5612
+ }
5613
+ }
5614
+ }
5615
+ return pixels;
5616
+ }
5617
+ };
5618
+
5619
+ // src/skin/scene/SkinObject.ts
5538
5620
  var SkinObject = class extends SceneObject {
5539
5621
  constructor(options) {
5540
5622
  super();
5541
5623
  this.slim = false;
5542
- this.legacy = false;
5543
- this.skinTextureWidth = 64;
5544
- this.skinTextureHeight = 64;
5624
+ this.detectedSlim = false;
5625
+ this.skinLoad = 0;
5545
5626
  this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5627
+ this.slim = this.options.slim ?? false;
5546
5628
  }
5547
5629
  async init() {
5548
5630
  this.createMeshes();
@@ -5551,15 +5633,13 @@ var SkinObject = class extends SceneObject {
5551
5633
  }
5552
5634
  createMeshes() {
5553
5635
  console.log("#createMeshes");
5554
- const mat = Materials.MISSING_TEXTURE;
5636
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5555
5637
  {
5556
5638
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5557
5639
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5558
5640
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5559
- if (!this.legacy) {
5560
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5561
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5562
- }
5641
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5642
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5563
5643
  }
5564
5644
  {
5565
5645
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5602,21 +5682,30 @@ var SkinObject = class extends SceneObject {
5602
5682
  }
5603
5683
  console.log("#createMeshes done");
5604
5684
  }
5605
- setSkinTexture(src) {
5685
+ async setSkinTexture(src) {
5606
5686
  if (typeof src === "undefined") return;
5607
- const mat = Materials.getImage({
5608
- texture: { src },
5609
- transparent: true
5610
- });
5611
- for (let part of SKIN_PARTS) {
5612
- let mesh = this.getMeshByName(part);
5687
+ this.skinTextureSrc = src;
5688
+ const load = ++this.skinLoad;
5689
+ const texture = await SkinTextures.get(src, this.options.legacy);
5690
+ if (load !== this.skinLoad) return;
5691
+ this.skinMaterial = texture.material;
5692
+ this.detectedSlim = texture.slim;
5693
+ this.updateSlim(this.options.slim ?? this.detectedSlim);
5694
+ for (const part of SKIN_PARTS) {
5695
+ const mesh = this.getMeshByName(part);
5613
5696
  if (mesh) {
5614
- mesh.material = mat;
5697
+ mesh.material = texture.material;
5615
5698
  }
5616
5699
  }
5700
+ this.notifyDirty();
5617
5701
  }
5618
5702
  //TODO: cape
5703
+ /** Select the arm model, or pass undefined to use texture detection. */
5619
5704
  setSlim(slim) {
5705
+ this.options.slim = slim;
5706
+ this.updateSlim(slim ?? this.detectedSlim);
5707
+ }
5708
+ updateSlim(slim) {
5620
5709
  if (slim === this.slim) return;
5621
5710
  this.slim = slim;
5622
5711
  for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
@@ -5630,17 +5719,22 @@ var SkinObject = class extends SceneObject {
5630
5719
  if (rightArm) rightArm.position.x -= offset;
5631
5720
  this.notifyDirty();
5632
5721
  }
5633
- setLegacy(legacy) {
5634
- if (legacy !== this.legacy) {
5635
- }
5636
- this.legacy = legacy;
5722
+ /** Select the texture layout, or pass undefined to detect it from image dimensions. */
5723
+ async setLegacy(legacy) {
5724
+ if (legacy === this.options.legacy) return;
5725
+ this.options.legacy = legacy;
5726
+ if (this.skinTextureSrc) await this.setSkinTexture(this.skinTextureSrc);
5727
+ }
5728
+ dispose() {
5729
+ this.skinLoad++;
5730
+ super.dispose();
5637
5731
  }
5638
5732
  //TODO: layer toggles
5639
5733
  getBoxGeometry(part) {
5640
5734
  console.log("slim", this.slim);
5641
5735
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5642
5736
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5643
- return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [this.skinTextureWidth, this.skinTextureHeight]);
5737
+ return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [64, 64]);
5644
5738
  }
5645
5739
  };
5646
5740
 
@@ -5750,10 +5844,10 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5750
5844
  this.dirty = true;
5751
5845
  const obj = new SkinObject(options);
5752
5846
  obj.scene = this;
5753
- await obj.init();
5754
5847
  if (skin) {
5755
- obj.setSkinTexture(skin);
5848
+ await obj.setSkinTexture(skin);
5756
5849
  }
5850
+ await obj.init();
5757
5851
  parent.add(obj);
5758
5852
  return obj;
5759
5853
  }
@@ -5768,7 +5862,7 @@ function isMineRenderScene(obj) {
5768
5862
  }
5769
5863
 
5770
5864
  // src/renderer/Renderer.ts
5771
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector39, WebGLRenderer } from "three";
5865
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace4, Vector3 as Vector39, WebGLRenderer } from "three";
5772
5866
  var import_ts_deepmerge9 = __toESM(require_dist());
5773
5867
  import Stats from "stats.js";
5774
5868
  import { EffectComposer, RenderPass } from "postprocessing";
@@ -6483,7 +6577,7 @@ var _Renderer = class _Renderer {
6483
6577
  renderer.setClearColor(0, 0);
6484
6578
  renderer.shadowMap.enabled = true;
6485
6579
  renderer.shadowMap.type = PCFSoftShadowMap;
6486
- renderer.outputColorSpace = SRGBColorSpace3;
6580
+ renderer.outputColorSpace = SRGBColorSpace4;
6487
6581
  renderer.setSize(this.viewWidth, this.viewHeight);
6488
6582
  return renderer;
6489
6583
  }
@@ -7228,6 +7322,7 @@ export {
7228
7322
  SchematicParser,
7229
7323
  SkinObject,
7230
7324
  SkinPart,
7325
+ SkinTextures,
7231
7326
  Skins,
7232
7327
  StructureParser,
7233
7328
  TextureAtlas,