minerender 2.1.0-alpha.26 → 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.
@@ -5506,7 +5506,41 @@ var baseSkinCoordinates = {
5506
5506
  var classicSkinTextureCoordinates = {
5507
5507
  ...baseSkinCoordinates
5508
5508
  };
5509
- var slimSkinTextureCoordinates = { ...baseSkinCoordinates };
5509
+ var slimSkinTextureCoordinates = {
5510
+ ...baseSkinCoordinates,
5511
+ leftArm: {
5512
+ ...baseSkinCoordinates.leftArm,
5513
+ west: { uv: [39, 52, 43, 64] },
5514
+ north: { uv: [36, 52, 39, 64] },
5515
+ south: { uv: [43, 52, 46, 64] },
5516
+ up: { uv: [39, 52, 36, 48] },
5517
+ down: { uv: [42, 48, 39, 52] }
5518
+ },
5519
+ rightArm: {
5520
+ ...baseSkinCoordinates.rightArm,
5521
+ west: { uv: [47, 20, 51, 32] },
5522
+ north: { uv: [44, 20, 47, 32] },
5523
+ south: { uv: [51, 20, 54, 32] },
5524
+ up: { uv: [47, 20, 44, 16] },
5525
+ down: { uv: [50, 16, 47, 20] }
5526
+ },
5527
+ leftSleeve: {
5528
+ ...baseSkinCoordinates.leftSleeve,
5529
+ west: { uv: [55, 52, 59, 64] },
5530
+ north: { uv: [52, 52, 55, 64] },
5531
+ south: { uv: [59, 52, 62, 64] },
5532
+ up: { uv: [55, 52, 52, 48] },
5533
+ down: { uv: [58, 48, 55, 52], rotation: 180 }
5534
+ },
5535
+ rightSleeve: {
5536
+ ...baseSkinCoordinates.rightSleeve,
5537
+ west: { uv: [47, 36, 51, 48] },
5538
+ north: { uv: [44, 36, 47, 48] },
5539
+ south: { uv: [51, 36, 54, 48] },
5540
+ up: { uv: [47, 36, 44, 32] },
5541
+ down: { uv: [50, 32, 47, 36], rotation: 180 }
5542
+ }
5543
+ };
5510
5544
 
5511
5545
  // src/skin/SkinGeometries.ts
5512
5546
  var box8inner = [8, 8, 8];
@@ -5547,14 +5581,96 @@ var slimSkinGeometries = {
5547
5581
 
5548
5582
  // src/skin/scene/SkinObject.ts
5549
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
5550
5666
  var SkinObject = class extends SceneObject {
5551
5667
  constructor(options) {
5552
5668
  super();
5553
5669
  this.slim = false;
5554
- this.legacy = false;
5555
- this.skinTextureWidth = 64;
5556
- this.skinTextureHeight = 64;
5670
+ this.detectedSlim = false;
5671
+ this.skinLoad = 0;
5557
5672
  this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5673
+ this.slim = this.options.slim ?? false;
5558
5674
  }
5559
5675
  async init() {
5560
5676
  this.createMeshes();
@@ -5563,15 +5679,13 @@ var SkinObject = class extends SceneObject {
5563
5679
  }
5564
5680
  createMeshes() {
5565
5681
  console.log("#createMeshes");
5566
- const mat = Materials.MISSING_TEXTURE;
5682
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5567
5683
  {
5568
5684
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5569
5685
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5570
5686
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5571
- if (!this.legacy) {
5572
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5573
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5574
- }
5687
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5688
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5575
5689
  }
5576
5690
  {
5577
5691
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5614,46 +5728,59 @@ var SkinObject = class extends SceneObject {
5614
5728
  }
5615
5729
  console.log("#createMeshes done");
5616
5730
  }
5617
- setSkinTexture(src) {
5731
+ async setSkinTexture(src) {
5618
5732
  if (typeof src === "undefined") return;
5619
5733
  this.skinTextureSrc = src;
5620
- const mat = Materials.getImage({
5621
- texture: { src },
5622
- transparent: true
5623
- });
5624
- for (let part of SKIN_PARTS) {
5625
- let mesh = this.getMeshByName(part);
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);
5626
5742
  if (mesh) {
5627
- mesh.material = mat;
5743
+ mesh.material = texture.material;
5628
5744
  }
5629
5745
  }
5746
+ this.notifyDirty();
5630
5747
  }
5631
5748
  //TODO: cape
5749
+ /** Select the arm model, or pass undefined to use texture detection. */
5632
5750
  setSlim(slim) {
5633
- console.log("#setSlim");
5634
- const changed = slim !== this.slim;
5751
+ this.options.slim = slim;
5752
+ this.updateSlim(slim ?? this.detectedSlim);
5753
+ }
5754
+ updateSlim(slim) {
5755
+ if (slim === this.slim) return;
5635
5756
  this.slim = slim;
5636
- if (changed) {
5637
- this.createMeshes();
5638
- }
5639
- if (changed) {
5640
- if (this.skinTextureSrc) {
5641
- this.setSkinTexture(this.skinTextureSrc);
5642
- }
5643
- }
5644
- console.log("#setSlim done");
5757
+ for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
5758
+ const mesh = this.getMeshByName(part);
5759
+ if (mesh) mesh.geometry = this.getBoxGeometry(part);
5760
+ }
5761
+ const offset = slim ? 0.5 : -0.5;
5762
+ const leftArm = this.getGroupByName("leftArm" /* LEFT_ARM */);
5763
+ const rightArm = this.getGroupByName("rightArm" /* RIGHT_ARM */);
5764
+ if (leftArm) leftArm.position.x += offset;
5765
+ if (rightArm) rightArm.position.x -= offset;
5766
+ this.notifyDirty();
5645
5767
  }
5646
- setLegacy(legacy) {
5647
- if (legacy !== this.legacy) {
5648
- }
5649
- 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();
5650
5777
  }
5651
5778
  //TODO: layer toggles
5652
5779
  getBoxGeometry(part) {
5653
5780
  console.log("slim", this.slim);
5654
5781
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5655
5782
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5656
- 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]);
5657
5784
  }
5658
5785
  };
5659
5786
 
@@ -5766,10 +5893,10 @@ var MineRenderScene = class _MineRenderScene extends Scene2 {
5766
5893
  this.dirty = true;
5767
5894
  const obj = new SkinObject(options);
5768
5895
  obj.scene = this;
5769
- await obj.init();
5770
5896
  if (skin) {
5771
- obj.setSkinTexture(skin);
5897
+ await obj.setSkinTexture(skin);
5772
5898
  }
5899
+ await obj.init();
5773
5900
  parent.add(obj);
5774
5901
  return obj;
5775
5902
  }
@@ -5782,7 +5909,7 @@ function isMineRenderScene(obj) {
5782
5909
  }
5783
5910
 
5784
5911
  // src/renderer/Renderer.ts
5785
- 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";
5786
5913
  var import_ts_deepmerge9 = __toESM(require_dist());
5787
5914
  import Stats from "stats.js";
5788
5915
  import { EffectComposer, RenderPass } from "postprocessing";
@@ -6536,7 +6663,7 @@ var Renderer = class _Renderer {
6536
6663
  renderer.setClearColor(0, 0);
6537
6664
  renderer.shadowMap.enabled = true;
6538
6665
  renderer.shadowMap.type = PCFSoftShadowMap;
6539
- renderer.outputColorSpace = SRGBColorSpace3;
6666
+ renderer.outputColorSpace = SRGBColorSpace4;
6540
6667
  renderer.setSize(this.viewWidth, this.viewHeight);
6541
6668
  return renderer;
6542
6669
  }
@@ -7243,6 +7370,7 @@ export {
7243
7370
  SchematicParser,
7244
7371
  SkinObject,
7245
7372
  SkinPart,
7373
+ SkinTextures,
7246
7374
  Skins,
7247
7375
  StructureParser,
7248
7376
  TextureAtlas,