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.
@@ -5581,14 +5581,96 @@ var slimSkinGeometries = {
5581
5581
 
5582
5582
  // src/skin/scene/SkinObject.ts
5583
5583
  var import_ts_deepmerge7 = __toESM(require_dist());
5584
+
5585
+ // src/skin/SkinTextures.ts
5586
+ import { DataTexture, DoubleSide as DoubleSide2, MeshBasicMaterial as MeshBasicMaterial3, SRGBColorSpace as SRGBColorSpace3 } from "three";
5587
+ var SkinTextures = class {
5588
+ static async get(src, legacy) {
5589
+ const image = await ImageLoader.getData(src);
5590
+ const scale = image.width / 64;
5591
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width && image.height !== image.width / 2) {
5592
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; expected 64x64 or 64x32, or an integer-scaled equivalent`);
5593
+ }
5594
+ const isLegacy = legacy ?? image.height === image.width / 2;
5595
+ if (!isLegacy && image.height !== image.width) {
5596
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; non-legacy skins must be square`);
5597
+ }
5598
+ const slim = !isLegacy && this.isSlim(image, scale);
5599
+ const key = `skin:${serializeImageKey({ src })}:${isLegacy}`;
5600
+ const material = Caching.materialCache.get(key, () => {
5601
+ const pixels = isLegacy ? this.normalizeLegacy(image, scale) : new Uint8Array(image.data);
5602
+ const texture = Textures.initTextureProps(new DataTexture(pixels, image.width, image.width));
5603
+ texture.colorSpace = SRGBColorSpace3;
5604
+ texture.flipY = true;
5605
+ texture.needsUpdate = true;
5606
+ return new MeshBasicMaterial3({ map: texture, transparent: true, side: DoubleSide2, alphaTest: 0.5 });
5607
+ });
5608
+ return { material, slim, legacy: isLegacy };
5609
+ }
5610
+ static isSlim(image, scale) {
5611
+ for (const [x, y] of [[46, 52], [54, 20]]) {
5612
+ for (let row = y * scale; row < (y + 12) * scale; row++) {
5613
+ for (let column = x * scale; column < (x + 1) * scale; column++) {
5614
+ if (image.data[(row * image.width + column) * 4 + 3] !== 0) return false;
5615
+ }
5616
+ }
5617
+ }
5618
+ return true;
5619
+ }
5620
+ static normalizeLegacy(image, scale) {
5621
+ const pixels = new Uint8Array(image.width * image.width * 4);
5622
+ pixels.set(image.data.subarray(0, image.width * image.width / 2 * 4));
5623
+ for (const [sx, sy, dx, dy, width, height] of [
5624
+ [4, 16, 20, 48, 4, 4],
5625
+ [8, 16, 24, 48, 4, 4],
5626
+ [0, 20, 24, 52, 4, 12],
5627
+ [4, 20, 20, 52, 4, 12],
5628
+ [8, 20, 16, 52, 4, 12],
5629
+ [12, 20, 28, 52, 4, 12],
5630
+ [44, 16, 36, 48, 4, 4],
5631
+ [48, 16, 40, 48, 4, 4],
5632
+ [40, 20, 40, 52, 4, 12],
5633
+ [44, 20, 36, 52, 4, 12],
5634
+ [48, 20, 32, 52, 4, 12],
5635
+ [52, 20, 44, 52, 4, 12]
5636
+ ]) {
5637
+ for (let y = 0; y < height * scale; y++) {
5638
+ for (let x = 0; x < width * scale; x++) {
5639
+ const source = ((sy * scale + y) * image.width + sx * scale + x) * 4;
5640
+ const target = ((dy * scale + y) * image.width + (dx + width) * scale - 1 - x) * 4;
5641
+ pixels.set(image.data.subarray(source, source + 4), target);
5642
+ }
5643
+ }
5644
+ }
5645
+ let clearHat = true;
5646
+ for (let y = 0; y < 32 * scale; y++) {
5647
+ for (let x = 32 * scale; x < image.width; x++) {
5648
+ if (pixels[(y * image.width + x) * 4 + 3] < 128) clearHat = false;
5649
+ }
5650
+ }
5651
+ for (let y = 0; y < image.width; y++) {
5652
+ for (let x = 0; x < image.width; x++) {
5653
+ const alpha = (y * image.width + x) * 4 + 3;
5654
+ if (x < 32 * scale && y < 16 * scale || y >= 16 * scale && y < 32 * scale || x >= 16 * scale && x < 48 * scale && y >= 48 * scale) {
5655
+ pixels[alpha] = 255;
5656
+ } else if (clearHat && x >= 32 * scale && y < 32 * scale) {
5657
+ pixels[alpha] = 0;
5658
+ }
5659
+ }
5660
+ }
5661
+ return pixels;
5662
+ }
5663
+ };
5664
+
5665
+ // src/skin/scene/SkinObject.ts
5584
5666
  var SkinObject = class extends SceneObject {
5585
5667
  constructor(options) {
5586
5668
  super();
5587
5669
  this.slim = false;
5588
- this.legacy = false;
5589
- this.skinTextureWidth = 64;
5590
- this.skinTextureHeight = 64;
5670
+ this.detectedSlim = false;
5671
+ this.skinLoad = 0;
5591
5672
  this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5673
+ this.slim = this.options.slim ?? false;
5592
5674
  }
5593
5675
  async init() {
5594
5676
  this.createMeshes();
@@ -5597,15 +5679,13 @@ var SkinObject = class extends SceneObject {
5597
5679
  }
5598
5680
  createMeshes() {
5599
5681
  console.log("#createMeshes");
5600
- const mat = Materials.MISSING_TEXTURE;
5682
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5601
5683
  {
5602
5684
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5603
5685
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5604
5686
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5605
- if (!this.legacy) {
5606
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5607
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5608
- }
5687
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5688
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5609
5689
  }
5610
5690
  {
5611
5691
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5648,21 +5728,30 @@ var SkinObject = class extends SceneObject {
5648
5728
  }
5649
5729
  console.log("#createMeshes done");
5650
5730
  }
5651
- setSkinTexture(src) {
5731
+ async setSkinTexture(src) {
5652
5732
  if (typeof src === "undefined") return;
5653
- const mat = Materials.getImage({
5654
- texture: { src },
5655
- transparent: true
5656
- });
5657
- for (let part of SKIN_PARTS) {
5658
- let mesh = this.getMeshByName(part);
5733
+ this.skinTextureSrc = src;
5734
+ const load = ++this.skinLoad;
5735
+ const texture = await SkinTextures.get(src, this.options.legacy);
5736
+ if (load !== this.skinLoad) return;
5737
+ this.skinMaterial = texture.material;
5738
+ this.detectedSlim = texture.slim;
5739
+ this.updateSlim(this.options.slim ?? this.detectedSlim);
5740
+ for (const part of SKIN_PARTS) {
5741
+ const mesh = this.getMeshByName(part);
5659
5742
  if (mesh) {
5660
- mesh.material = mat;
5743
+ mesh.material = texture.material;
5661
5744
  }
5662
5745
  }
5746
+ this.notifyDirty();
5663
5747
  }
5664
5748
  //TODO: cape
5749
+ /** Select the arm model, or pass undefined to use texture detection. */
5665
5750
  setSlim(slim) {
5751
+ this.options.slim = slim;
5752
+ this.updateSlim(slim ?? this.detectedSlim);
5753
+ }
5754
+ updateSlim(slim) {
5666
5755
  if (slim === this.slim) return;
5667
5756
  this.slim = slim;
5668
5757
  for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
@@ -5676,17 +5765,22 @@ var SkinObject = class extends SceneObject {
5676
5765
  if (rightArm) rightArm.position.x -= offset;
5677
5766
  this.notifyDirty();
5678
5767
  }
5679
- setLegacy(legacy) {
5680
- if (legacy !== this.legacy) {
5681
- }
5682
- this.legacy = legacy;
5768
+ /** Select the texture layout, or pass undefined to detect it from image dimensions. */
5769
+ async setLegacy(legacy) {
5770
+ if (legacy === this.options.legacy) return;
5771
+ this.options.legacy = legacy;
5772
+ if (this.skinTextureSrc) await this.setSkinTexture(this.skinTextureSrc);
5773
+ }
5774
+ dispose() {
5775
+ this.skinLoad++;
5776
+ super.dispose();
5683
5777
  }
5684
5778
  //TODO: layer toggles
5685
5779
  getBoxGeometry(part) {
5686
5780
  console.log("slim", this.slim);
5687
5781
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5688
5782
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5689
- return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [this.skinTextureWidth, this.skinTextureHeight]);
5783
+ return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [64, 64]);
5690
5784
  }
5691
5785
  };
5692
5786
 
@@ -5799,10 +5893,10 @@ var MineRenderScene = class _MineRenderScene extends Scene2 {
5799
5893
  this.dirty = true;
5800
5894
  const obj = new SkinObject(options);
5801
5895
  obj.scene = this;
5802
- await obj.init();
5803
5896
  if (skin) {
5804
- obj.setSkinTexture(skin);
5897
+ await obj.setSkinTexture(skin);
5805
5898
  }
5899
+ await obj.init();
5806
5900
  parent.add(obj);
5807
5901
  return obj;
5808
5902
  }
@@ -5815,7 +5909,7 @@ function isMineRenderScene(obj) {
5815
5909
  }
5816
5910
 
5817
5911
  // src/renderer/Renderer.ts
5818
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector39, WebGLRenderer } from "three";
5912
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace4, Vector3 as Vector39, WebGLRenderer } from "three";
5819
5913
  var import_ts_deepmerge9 = __toESM(require_dist());
5820
5914
  import Stats from "stats.js";
5821
5915
  import { EffectComposer, RenderPass } from "postprocessing";
@@ -6569,7 +6663,7 @@ var Renderer = class _Renderer {
6569
6663
  renderer.setClearColor(0, 0);
6570
6664
  renderer.shadowMap.enabled = true;
6571
6665
  renderer.shadowMap.type = PCFSoftShadowMap;
6572
- renderer.outputColorSpace = SRGBColorSpace3;
6666
+ renderer.outputColorSpace = SRGBColorSpace4;
6573
6667
  renderer.setSize(this.viewWidth, this.viewHeight);
6574
6668
  return renderer;
6575
6669
  }
@@ -7276,6 +7370,7 @@ export {
7276
7370
  SchematicParser,
7277
7371
  SkinObject,
7278
7372
  SkinPart,
7373
+ SkinTextures,
7279
7374
  Skins,
7280
7375
  StructureParser,
7281
7376
  TextureAtlas,