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.
@@ -5460,7 +5460,41 @@ var baseSkinCoordinates = {
5460
5460
  var classicSkinTextureCoordinates = {
5461
5461
  ...baseSkinCoordinates
5462
5462
  };
5463
- var slimSkinTextureCoordinates = { ...baseSkinCoordinates };
5463
+ var slimSkinTextureCoordinates = {
5464
+ ...baseSkinCoordinates,
5465
+ leftArm: {
5466
+ ...baseSkinCoordinates.leftArm,
5467
+ west: { uv: [39, 52, 43, 64] },
5468
+ north: { uv: [36, 52, 39, 64] },
5469
+ south: { uv: [43, 52, 46, 64] },
5470
+ up: { uv: [39, 52, 36, 48] },
5471
+ down: { uv: [42, 48, 39, 52] }
5472
+ },
5473
+ rightArm: {
5474
+ ...baseSkinCoordinates.rightArm,
5475
+ west: { uv: [47, 20, 51, 32] },
5476
+ north: { uv: [44, 20, 47, 32] },
5477
+ south: { uv: [51, 20, 54, 32] },
5478
+ up: { uv: [47, 20, 44, 16] },
5479
+ down: { uv: [50, 16, 47, 20] }
5480
+ },
5481
+ leftSleeve: {
5482
+ ...baseSkinCoordinates.leftSleeve,
5483
+ west: { uv: [55, 52, 59, 64] },
5484
+ north: { uv: [52, 52, 55, 64] },
5485
+ south: { uv: [59, 52, 62, 64] },
5486
+ up: { uv: [55, 52, 52, 48] },
5487
+ down: { uv: [58, 48, 55, 52], rotation: 180 }
5488
+ },
5489
+ rightSleeve: {
5490
+ ...baseSkinCoordinates.rightSleeve,
5491
+ west: { uv: [47, 36, 51, 48] },
5492
+ north: { uv: [44, 36, 47, 48] },
5493
+ south: { uv: [51, 36, 54, 48] },
5494
+ up: { uv: [47, 36, 44, 32] },
5495
+ down: { uv: [50, 32, 47, 36], rotation: 180 }
5496
+ }
5497
+ };
5464
5498
 
5465
5499
  // src/skin/SkinGeometries.ts
5466
5500
  var box8inner = [8, 8, 8];
@@ -5501,14 +5535,96 @@ var slimSkinGeometries = {
5501
5535
 
5502
5536
  // src/skin/scene/SkinObject.ts
5503
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
5504
5620
  var SkinObject = class extends SceneObject {
5505
5621
  constructor(options) {
5506
5622
  super();
5507
5623
  this.slim = false;
5508
- this.legacy = false;
5509
- this.skinTextureWidth = 64;
5510
- this.skinTextureHeight = 64;
5624
+ this.detectedSlim = false;
5625
+ this.skinLoad = 0;
5511
5626
  this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5627
+ this.slim = this.options.slim ?? false;
5512
5628
  }
5513
5629
  async init() {
5514
5630
  this.createMeshes();
@@ -5517,15 +5633,13 @@ var SkinObject = class extends SceneObject {
5517
5633
  }
5518
5634
  createMeshes() {
5519
5635
  console.log("#createMeshes");
5520
- const mat = Materials.MISSING_TEXTURE;
5636
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5521
5637
  {
5522
5638
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5523
5639
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5524
5640
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5525
- if (!this.legacy) {
5526
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5527
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5528
- }
5641
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5642
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5529
5643
  }
5530
5644
  {
5531
5645
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5568,46 +5682,59 @@ var SkinObject = class extends SceneObject {
5568
5682
  }
5569
5683
  console.log("#createMeshes done");
5570
5684
  }
5571
- setSkinTexture(src) {
5685
+ async setSkinTexture(src) {
5572
5686
  if (typeof src === "undefined") return;
5573
5687
  this.skinTextureSrc = src;
5574
- const mat = Materials.getImage({
5575
- texture: { src },
5576
- transparent: true
5577
- });
5578
- for (let part of SKIN_PARTS) {
5579
- let mesh = this.getMeshByName(part);
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);
5580
5696
  if (mesh) {
5581
- mesh.material = mat;
5697
+ mesh.material = texture.material;
5582
5698
  }
5583
5699
  }
5700
+ this.notifyDirty();
5584
5701
  }
5585
5702
  //TODO: cape
5703
+ /** Select the arm model, or pass undefined to use texture detection. */
5586
5704
  setSlim(slim) {
5587
- console.log("#setSlim");
5588
- const changed = slim !== this.slim;
5705
+ this.options.slim = slim;
5706
+ this.updateSlim(slim ?? this.detectedSlim);
5707
+ }
5708
+ updateSlim(slim) {
5709
+ if (slim === this.slim) return;
5589
5710
  this.slim = slim;
5590
- if (changed) {
5591
- this.createMeshes();
5592
- }
5593
- if (changed) {
5594
- if (this.skinTextureSrc) {
5595
- this.setSkinTexture(this.skinTextureSrc);
5596
- }
5597
- }
5598
- console.log("#setSlim done");
5711
+ for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
5712
+ const mesh = this.getMeshByName(part);
5713
+ if (mesh) mesh.geometry = this.getBoxGeometry(part);
5714
+ }
5715
+ const offset = slim ? 0.5 : -0.5;
5716
+ const leftArm = this.getGroupByName("leftArm" /* LEFT_ARM */);
5717
+ const rightArm = this.getGroupByName("rightArm" /* RIGHT_ARM */);
5718
+ if (leftArm) leftArm.position.x += offset;
5719
+ if (rightArm) rightArm.position.x -= offset;
5720
+ this.notifyDirty();
5599
5721
  }
5600
- setLegacy(legacy) {
5601
- if (legacy !== this.legacy) {
5602
- }
5603
- 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();
5604
5731
  }
5605
5732
  //TODO: layer toggles
5606
5733
  getBoxGeometry(part) {
5607
5734
  console.log("slim", this.slim);
5608
5735
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5609
5736
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5610
- 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]);
5611
5738
  }
5612
5739
  };
5613
5740
 
@@ -5717,10 +5844,10 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5717
5844
  this.dirty = true;
5718
5845
  const obj = new SkinObject(options);
5719
5846
  obj.scene = this;
5720
- await obj.init();
5721
5847
  if (skin) {
5722
- obj.setSkinTexture(skin);
5848
+ await obj.setSkinTexture(skin);
5723
5849
  }
5850
+ await obj.init();
5724
5851
  parent.add(obj);
5725
5852
  return obj;
5726
5853
  }
@@ -5735,7 +5862,7 @@ function isMineRenderScene(obj) {
5735
5862
  }
5736
5863
 
5737
5864
  // src/renderer/Renderer.ts
5738
- 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";
5739
5866
  var import_ts_deepmerge9 = __toESM(require_dist());
5740
5867
  import Stats from "stats.js";
5741
5868
  import { EffectComposer, RenderPass } from "postprocessing";
@@ -6450,7 +6577,7 @@ var _Renderer = class _Renderer {
6450
6577
  renderer.setClearColor(0, 0);
6451
6578
  renderer.shadowMap.enabled = true;
6452
6579
  renderer.shadowMap.type = PCFSoftShadowMap;
6453
- renderer.outputColorSpace = SRGBColorSpace3;
6580
+ renderer.outputColorSpace = SRGBColorSpace4;
6454
6581
  renderer.setSize(this.viewWidth, this.viewHeight);
6455
6582
  return renderer;
6456
6583
  }
@@ -7195,6 +7322,7 @@ export {
7195
7322
  SchematicParser,
7196
7323
  SkinObject,
7197
7324
  SkinPart,
7325
+ SkinTextures,
7198
7326
  Skins,
7199
7327
  StructureParser,
7200
7328
  TextureAtlas,