minerender 2.1.0-alpha.42 → 2.1.0-alpha.43

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.
@@ -1072,6 +1072,8 @@ declare class SceneObject extends Object3D<Object3DEventMap & {
1072
1072
  get instanceCounter(): number;
1073
1073
  protected constructInstanceReference(i: number): InstanceReference<SceneObject>;
1074
1074
  nextInstance(): InstanceReference<SceneObject>;
1075
+ /** Returns the live reference for a raycast hit on this object's instance mesh. */
1076
+ getInstanceReference(mesh: Object3D, index: number): Maybe<InstanceReference<SceneObject>>;
1075
1077
  isInstanceActive(index: number, reference: InstanceReference<Instanceable>): boolean;
1076
1078
  removeInstanceAt(index: number): void;
1077
1079
  private growInstances;
@@ -1623,17 +1625,21 @@ declare class SceneInspector {
1623
1625
  protected readonly raycaster: Raycaster;
1624
1626
  private readonly mouse;
1625
1627
  private selectedObject?;
1628
+ private pointer?;
1629
+ private readonly listeners;
1626
1630
  constructor(renderer: Renderer);
1627
1631
  protected init(): void;
1632
+ dispose(): void;
1628
1633
  findMeshChildren(from: Object3D, out?: Mesh[]): Mesh<three.BufferGeometry<three.NormalBufferAttributes>, three.Material | three.Material[], three.Object3DEventMap>[];
1629
- onClick(event: any): void;
1634
+ onClick(event: MouseEvent): void;
1630
1635
  appendTo(el: HTMLElement): void;
1631
1636
  protected handleRaycasterObjects(intersections: Intersection[]): void;
1632
- selectObject(targetObject: Object3D, targetIntersection?: Intersection): void;
1633
- protected redraw(targetObject: Object3D, targetIntersection?: Intersection): void;
1634
- protected addControls(object: Object3D, intersection?: Intersection): void;
1637
+ private getIntersectionInstance;
1638
+ selectObject(targetObject: Object3D, targetIntersection?: Intersection, instance?: Maybe<InstanceReference<SceneObject>>): void;
1639
+ protected redraw(targetObject: Object3D, targetIntersection?: Intersection, instance?: InstanceReference<SceneObject>): void;
1640
+ protected addControls(object: Object3D, intersection?: Intersection, instance?: InstanceReference<SceneObject>): void;
1635
1641
  protected addInfoLine(name: string, id: string, value: any): HTMLElement;
1636
- protected addObjectControls(target: Object3D, intersection: Maybe<Intersection>, container: HTMLElement): void;
1642
+ protected addObjectControls(target: Object3D, intersection: Maybe<Intersection>, container: HTMLElement, instance?: InstanceReference<SceneObject>): void;
1637
1643
  protected buttonControl(name: string, id: string, click: () => void): HTMLElement;
1638
1644
  protected selectControl(name: string, id: string, options: string[], change: (v: string) => void): HTMLElement;
1639
1645
  protected toggleControl(name: string, id: string, val: boolean, change: (v: boolean) => void): HTMLElement;
@@ -1072,6 +1072,8 @@ declare class SceneObject extends Object3D<Object3DEventMap & {
1072
1072
  get instanceCounter(): number;
1073
1073
  protected constructInstanceReference(i: number): InstanceReference<SceneObject>;
1074
1074
  nextInstance(): InstanceReference<SceneObject>;
1075
+ /** Returns the live reference for a raycast hit on this object's instance mesh. */
1076
+ getInstanceReference(mesh: Object3D, index: number): Maybe<InstanceReference<SceneObject>>;
1075
1077
  isInstanceActive(index: number, reference: InstanceReference<Instanceable>): boolean;
1076
1078
  removeInstanceAt(index: number): void;
1077
1079
  private growInstances;
@@ -1623,17 +1625,21 @@ declare class SceneInspector {
1623
1625
  protected readonly raycaster: Raycaster;
1624
1626
  private readonly mouse;
1625
1627
  private selectedObject?;
1628
+ private pointer?;
1629
+ private readonly listeners;
1626
1630
  constructor(renderer: Renderer);
1627
1631
  protected init(): void;
1632
+ dispose(): void;
1628
1633
  findMeshChildren(from: Object3D, out?: Mesh[]): Mesh<three.BufferGeometry<three.NormalBufferAttributes>, three.Material | three.Material[], three.Object3DEventMap>[];
1629
- onClick(event: any): void;
1634
+ onClick(event: MouseEvent): void;
1630
1635
  appendTo(el: HTMLElement): void;
1631
1636
  protected handleRaycasterObjects(intersections: Intersection[]): void;
1632
- selectObject(targetObject: Object3D, targetIntersection?: Intersection): void;
1633
- protected redraw(targetObject: Object3D, targetIntersection?: Intersection): void;
1634
- protected addControls(object: Object3D, intersection?: Intersection): void;
1637
+ private getIntersectionInstance;
1638
+ selectObject(targetObject: Object3D, targetIntersection?: Intersection, instance?: Maybe<InstanceReference<SceneObject>>): void;
1639
+ protected redraw(targetObject: Object3D, targetIntersection?: Intersection, instance?: InstanceReference<SceneObject>): void;
1640
+ protected addControls(object: Object3D, intersection?: Intersection, instance?: InstanceReference<SceneObject>): void;
1635
1641
  protected addInfoLine(name: string, id: string, value: any): HTMLElement;
1636
- protected addObjectControls(target: Object3D, intersection: Maybe<Intersection>, container: HTMLElement): void;
1642
+ protected addObjectControls(target: Object3D, intersection: Maybe<Intersection>, container: HTMLElement, instance?: InstanceReference<SceneObject>): void;
1637
1643
  protected buttonControl(name: string, id: string, click: () => void): HTMLElement;
1638
1644
  protected selectControl(name: string, id: string, options: string[], change: (v: string) => void): HTMLElement;
1639
1645
  protected toggleControl(name: string, id: string, val: boolean, change: (v: boolean) => void): HTMLElement;
@@ -3213,6 +3213,10 @@ var _SceneObject = class _SceneObject extends import_three10.Object3D {
3213
3213
  this.setMatrixAt(index, new import_three10.Matrix4());
3214
3214
  return reference;
3215
3215
  }
3216
+ /** Returns the live reference for a raycast hit on this object's instance mesh. */
3217
+ getInstanceReference(mesh, index) {
3218
+ return mesh === this.instanceMesh ? this.instanceReferences.get(index) : void 0;
3219
+ }
3216
3220
  isInstanceActive(index, reference) {
3217
3221
  return this.instanceReferences.get(index) === reference;
3218
3222
  }
@@ -3295,9 +3299,9 @@ var _SceneObject = class _SceneObject extends import_three10.Object3D {
3295
3299
  }
3296
3300
  getRotationAt(index, euler = new import_three10.Euler()) {
3297
3301
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3298
- const matrix = this.getMatrixAt(index);
3299
- euler.setFromRotationMatrix(matrix);
3300
- return euler;
3302
+ const rotation = new import_three10.Quaternion();
3303
+ this.getMatrixAt(index).decompose(new import_three10.Vector3(), rotation, new import_three10.Vector3());
3304
+ return euler.setFromQuaternion(rotation);
3301
3305
  }
3302
3306
  setScaleAt(index, scale) {
3303
3307
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
@@ -3553,11 +3557,12 @@ var GuiObject = class extends SceneObject {
3553
3557
  // src/inspector/SceneInspector.ts
3554
3558
  var import_three14 = require("three");
3555
3559
  var p7 = prefix("SceneInspector");
3556
- var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3560
+ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
3557
3561
  var SceneInspector = class {
3558
3562
  constructor(renderer) {
3559
3563
  this.renderer = renderer;
3560
3564
  this.mouse = new import_three14.Vector2();
3565
+ this.listeners = new AbortController();
3561
3566
  this.objectInfoContainer = document.createElement("div");
3562
3567
  this.objectControlsContainer = document.createElement("div");
3563
3568
  this.raycaster = new import_three14.Raycaster();
@@ -3567,13 +3572,44 @@ var SceneInspector = class {
3567
3572
  this.objectInfoContainer.classList.add("minerender-inspector", "minerender-object-info");
3568
3573
  this.objectControlsContainer.classList.add("minerender-inspector", "minerender-object-controls");
3569
3574
  this.objectInfoContainer.innerHTML = help;
3570
- document.addEventListener("click", this.onClick.bind(this), {
3571
- passive: true
3572
- });
3575
+ const canvas = this.renderer.renderer.domElement;
3576
+ const options = { signal: this.listeners.signal };
3577
+ canvas.addEventListener("pointerdown", (event) => {
3578
+ this.pointer = event.button === 0 && (event.ctrlKey || event.metaKey) ? event : void 0;
3579
+ }, options);
3580
+ canvas.addEventListener("pointermove", (event) => {
3581
+ if (this.pointer?.pointerId === event.pointerId && Math.hypot(event.clientX - this.pointer.clientX, event.clientY - this.pointer.clientY) > 5) {
3582
+ this.pointer = void 0;
3583
+ }
3584
+ }, options);
3585
+ canvas.addEventListener("pointerup", (event) => {
3586
+ const start = this.pointer;
3587
+ this.pointer = void 0;
3588
+ if (start?.pointerId === event.pointerId && Math.hypot(event.clientX - start.clientX, event.clientY - start.clientY) <= 5) {
3589
+ this.onClick(event);
3590
+ }
3591
+ }, options);
3592
+ canvas.addEventListener("pointercancel", () => {
3593
+ this.pointer = void 0;
3594
+ }, options);
3595
+ canvas.addEventListener("pointerleave", () => {
3596
+ this.pointer = void 0;
3597
+ }, options);
3598
+ canvas.addEventListener("contextmenu", (event) => {
3599
+ if (this.pointer?.ctrlKey) event.preventDefault();
3600
+ }, options);
3601
+ }
3602
+ dispose() {
3603
+ this.listeners.abort();
3604
+ this.pointer = void 0;
3605
+ this.selectedObject = void 0;
3606
+ this.objectInfoContainer.remove();
3607
+ this.objectControlsContainer.remove();
3573
3608
  }
3574
3609
  findMeshChildren(from, out = []) {
3610
+ if (!from.visible) return out;
3575
3611
  for (let c of from.children) {
3576
- if (isMesh(c)) {
3612
+ if (c.visible && isMesh(c)) {
3577
3613
  out.push(c);
3578
3614
  }
3579
3615
  this.findMeshChildren(c, out);
@@ -3581,50 +3617,43 @@ var SceneInspector = class {
3581
3617
  return out;
3582
3618
  }
3583
3619
  onClick(event) {
3584
- if (event.target?.nodeName !== "CANVAS") return;
3585
- if (!event.ctrlKey) return;
3586
- setTimeout(() => {
3587
- this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
3588
- this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
3589
- this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
3590
- let start = Date.now();
3591
- let targets = this.findMeshChildren(this.renderer.scene);
3592
- const intersects = this.raycaster.intersectObjects(targets, false);
3593
- console.debug("Raycast took " + (Date.now() - start) + "ms for " + targets.length + " possible targets with " + intersects.length + " results");
3594
- if (intersects.length > 0) {
3595
- this.handleRaycasterObjects(intersects);
3596
- }
3597
- });
3620
+ const canvas = this.renderer.renderer.domElement;
3621
+ if (event.target !== canvas || event.button !== 0 || !(event.ctrlKey || event.metaKey)) return;
3622
+ const rect = canvas.getBoundingClientRect();
3623
+ const x = event.clientX - rect.left, y = event.clientY - rect.top;
3624
+ if (rect.width <= 0 || rect.height <= 0 || x < 0 || y < 0 || x >= rect.width || y >= rect.height) return;
3625
+ this.mouse.set(x / rect.width * 2 - 1, 1 - y / rect.height * 2);
3626
+ this.renderer.camera.updateWorldMatrix(true, false);
3627
+ this.renderer.scene.updateMatrixWorld(true);
3628
+ this.raycaster.setFromCamera(this.mouse, this.renderer.camera);
3629
+ this.handleRaycasterObjects(this.raycaster.intersectObjects(this.findMeshChildren(this.renderer.scene), false));
3598
3630
  }
3599
3631
  appendTo(el) {
3600
3632
  el.append(this.objectInfoContainer);
3601
3633
  el.append(this.objectControlsContainer);
3602
3634
  }
3603
3635
  handleRaycasterObjects(intersections) {
3604
- console.debug(intersections);
3605
- const firstIntersection = intersections[0];
3606
- if (firstIntersection && firstIntersection.object) {
3607
- const firstObject = firstIntersection.object;
3608
- let targetIntersection = void 0;
3609
- let targetObject = void 0;
3610
- const firstSceneObjectIntersection = intersections.find((i) => i.object && i.object.parent && isSceneObject(i.object.parent));
3611
- if (firstSceneObjectIntersection && firstSceneObjectIntersection.object) {
3612
- targetIntersection = firstSceneObjectIntersection;
3613
- targetObject = firstSceneObjectIntersection.object;
3614
- } else {
3615
- targetIntersection = firstIntersection;
3616
- targetObject = firstObject;
3636
+ const hit = intersections[0];
3637
+ if (!hit) return;
3638
+ const instance = this.getIntersectionInstance(hit);
3639
+ this.selectObject(instance?.instanceable ?? hit.object, hit, instance);
3640
+ }
3641
+ getIntersectionInstance(hit) {
3642
+ if (hit?.instanceId === void 0) return void 0;
3643
+ for (let parent = hit.object.parent; parent; parent = parent.parent) {
3644
+ if (isSceneObject(parent)) {
3645
+ const instance = parent.getInstanceReference(hit.object, hit.instanceId);
3646
+ if (instance) return instance;
3617
3647
  }
3618
- if (!targetIntersection || !targetObject) return;
3619
- this.selectObject(targetObject, targetIntersection);
3620
3648
  }
3649
+ return void 0;
3621
3650
  }
3622
- selectObject(targetObject, targetIntersection) {
3651
+ selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
3623
3652
  this.selectedObject = targetObject;
3624
3653
  console.log(p7, "selected", targetObject);
3625
- this.redraw(targetObject, targetIntersection);
3654
+ this.redraw(targetObject, targetIntersection, instance);
3626
3655
  }
3627
- redraw(targetObject, targetIntersection) {
3656
+ redraw(targetObject, targetIntersection, instance) {
3628
3657
  this.objectInfoContainer.innerHTML = help;
3629
3658
  if (targetIntersection) {
3630
3659
  this.addInfoLine("Distance", "D", targetIntersection.distance);
@@ -3637,8 +3666,8 @@ var SceneInspector = class {
3637
3666
  if (isSceneObject(targetObject.parent)) {
3638
3667
  }
3639
3668
  }
3640
- if ("atlas" in targetObject) {
3641
- const atlas = targetObject["atlas"];
3669
+ const atlas = "atlas" in targetObject ? targetObject["atlas"] : void 0;
3670
+ if (atlas?.image.canvas) {
3642
3671
  const img = atlas.image.canvas;
3643
3672
  img.style.width = "100px";
3644
3673
  img.style.height = "100px";
@@ -3647,28 +3676,31 @@ var SceneInspector = class {
3647
3676
  this.objectInfoContainer.prepend(img);
3648
3677
  }
3649
3678
  this.objectControlsContainer.innerHTML = "";
3650
- this.addControls(targetObject, targetIntersection);
3679
+ this.addControls(targetObject, targetIntersection, instance);
3651
3680
  }
3652
- addControls(object, intersection) {
3681
+ addControls(object, intersection, instance) {
3653
3682
  const container = document.createElement("div");
3654
3683
  container.append(this.separator("Select Parent/Child"));
3655
3684
  if (object.parent) {
3656
3685
  container.append(this.buttonControl("Select Parent " + object.parent.constructor.name + " " + object.parent.name, "P", () => {
3657
- this.selectObject(object.parent, intersection);
3686
+ this.selectObject(object.parent, intersection, instance);
3658
3687
  }));
3659
3688
  }
3660
3689
  if (object.children.length > 0) {
3661
3690
  let i = 1;
3662
3691
  for (let child of object.children) {
3663
3692
  container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
3664
- this.selectObject(child, intersection);
3693
+ this.selectObject(child, intersection, instance);
3665
3694
  }));
3666
3695
  }
3667
3696
  }
3668
3697
  container.append(this.separator());
3669
- container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
3698
+ const selectedInstance = instance && (object === instance.instanceable || object === intersection?.object) ? instance : void 0;
3699
+ if (!selectedInstance) {
3700
+ container.append(this.toggleControl("Visibility", "V", object.visible, (v) => object.visible = v));
3701
+ }
3670
3702
  container.append(this.separator("Mesh"));
3671
- this.addObjectControls(object, intersection, container);
3703
+ this.addObjectControls(object, intersection, container, selectedInstance);
3672
3704
  container.append(this.separator());
3673
3705
  this.objectControlsContainer.append(container);
3674
3706
  }
@@ -3680,78 +3712,26 @@ var SceneInspector = class {
3680
3712
  this.objectInfoContainer.append(document.createElement("br"));
3681
3713
  return el;
3682
3714
  }
3683
- addObjectControls(target, intersection, container) {
3715
+ addObjectControls(target, intersection, container, instance) {
3684
3716
  const posRange = 16 * 16;
3685
3717
  const rotRange = 360;
3686
3718
  const scaleRange = 4;
3687
- if (typeof intersection !== "undefined" && typeof intersection.instanceId !== "undefined" && isSceneObject(target) && target.isInstanced) {
3688
- const scObj = target;
3689
- container.append(this.separator("Position"));
3690
- let pos = scObj.getPositionAt(intersection.instanceId);
3691
- container.append(this.rangeControl("X Position", "X", -posRange + pos.x, posRange + pos.x, pos.x, 1, (v) => {
3692
- pos = scObj.getPositionAt(intersection.instanceId);
3693
- pos.x = v;
3694
- scObj.setPositionAt(intersection.instanceId, pos);
3695
- }));
3696
- container.append(this.rangeControl("Y Position", "Y", -posRange + pos.y, posRange + pos.y, pos.y, 1, (v) => {
3697
- pos = scObj.getPositionAt(intersection.instanceId);
3698
- pos.y = v;
3699
- scObj.setPositionAt(intersection.instanceId, pos);
3700
- }));
3701
- container.append(this.rangeControl("Z Position", "Z", -posRange + pos.z, posRange + pos.z, pos.z, 1, (v) => {
3702
- pos = scObj.getPositionAt(intersection.instanceId);
3703
- pos.z = v;
3704
- scObj.setPositionAt(intersection.instanceId, pos);
3705
- }));
3706
- container.append(this.separator("Rotation"));
3707
- let rot = scObj.getRotationAt(intersection.instanceId);
3708
- container.append(this.rangeControl("X Rotation", "X", 0, rotRange, Math.round(toDegrees(rot.x)), 1, (v) => {
3709
- rot = scObj.getRotationAt(intersection.instanceId);
3710
- rot.x = toRadians(v);
3711
- scObj.setRotationAt(intersection.instanceId, rot);
3712
- }));
3713
- container.append(this.rangeControl("Y Rotation", "Y", 0, rotRange, Math.round(toDegrees(rot.y)), 1, (v) => {
3714
- rot = scObj.getRotationAt(intersection.instanceId);
3715
- rot.y = toRadians(v);
3716
- scObj.setRotationAt(intersection.instanceId, rot);
3717
- }));
3718
- container.append(this.rangeControl("Z Rotation", "Z", 0, rotRange, Math.round(toDegrees(rot.z)), 1, (v) => {
3719
- rot = scObj.getRotationAt(intersection.instanceId);
3720
- rot.z = toRadians(v);
3721
- scObj.setRotationAt(intersection.instanceId, rot);
3722
- }));
3723
- container.append(this.separator("Scale"));
3724
- let scl = scObj.getScale();
3725
- container.append(this.rangeControl("X Scale", "X", 0, scaleRange, scl.x, 0.1, (v) => {
3726
- scl = scObj.getScaleAt(intersection.instanceId);
3727
- scl.x = v;
3728
- scObj.setScaleAt(intersection.instanceId, scl);
3729
- }));
3730
- container.append(this.rangeControl("Y Scale", "Y", 0, scaleRange, scl.y, 0.1, (v) => {
3731
- scl = scObj.getScaleAt(intersection.instanceId);
3732
- scl.y = v;
3733
- scObj.setScaleAt(intersection.instanceId, scl);
3734
- }));
3735
- container.append(this.rangeControl("Z Scale", "Z", 0, scaleRange, scl.z, 0.1, (v) => {
3736
- scl = scObj.getScaleAt(intersection.instanceId);
3737
- scl.z = v;
3738
- scObj.setScaleAt(intersection.instanceId, scl);
3739
- }));
3740
- } else if (isTransformable(target)) {
3741
- const parent = target;
3719
+ const transform = instance ?? (isTransformable(target) ? target : void 0);
3720
+ if (transform) {
3721
+ const parent = transform;
3742
3722
  container.append(this.separator("Position"));
3743
3723
  let pos = parent.getPosition();
3744
- container.append(this.rangeControl("X Position", "X", -posRange, posRange, pos.x, 1, (v) => {
3724
+ container.append(this.rangeControl("X Position", "X", pos.x - posRange, pos.x + posRange, pos.x, 1, (v) => {
3745
3725
  pos = parent.getPosition();
3746
3726
  pos.x = v;
3747
3727
  parent.setPosition(pos);
3748
3728
  }));
3749
- container.append(this.rangeControl("Y Position", "Y", -posRange, posRange, pos.y, 1, (v) => {
3729
+ container.append(this.rangeControl("Y Position", "Y", pos.y - posRange, pos.y + posRange, pos.y, 1, (v) => {
3750
3730
  pos = parent.getPosition();
3751
3731
  pos.y = v;
3752
3732
  parent.setPosition(pos);
3753
3733
  }));
3754
- container.append(this.rangeControl("Z Position", "Z", -posRange, posRange, pos.z, 1, (v) => {
3734
+ container.append(this.rangeControl("Z Position", "Z", pos.z - posRange, pos.z + posRange, pos.z, 1, (v) => {
3755
3735
  pos = parent.getPosition();
3756
3736
  pos.z = v;
3757
3737
  parent.setPosition(pos);
@@ -3840,6 +3820,7 @@ var SceneInspector = class {
3840
3820
  toggle.checked = val;
3841
3821
  toggle.addEventListener("change", (e) => {
3842
3822
  change(toggle.checked);
3823
+ this.renderer.scene.dirty = true;
3843
3824
  });
3844
3825
  label.append(toggle);
3845
3826
  label.append(document.createElement("br"));
@@ -3852,7 +3833,6 @@ var SceneInspector = class {
3852
3833
  label.setAttribute("title", name);
3853
3834
  labelText.style.width = "18%";
3854
3835
  labelText.style.display = "inline-block";
3855
- labelText.innerText = `${id} (${val})`;
3856
3836
  const range = document.createElement("input");
3857
3837
  range.setAttribute("type", "range");
3858
3838
  range.style.width = "80%";
@@ -3860,8 +3840,10 @@ var SceneInspector = class {
3860
3840
  range.min = `${min}`;
3861
3841
  range.step = `${step}`;
3862
3842
  range.value = `${val}`;
3843
+ labelText.innerText = `${id} (${range.value})`;
3863
3844
  const onChange = () => {
3864
3845
  change(parseFloat(range.value));
3846
+ this.renderer.scene.dirty = true;
3865
3847
  labelText.innerText = `${id} (${range.value})`;
3866
3848
  };
3867
3849
  range.addEventListener("input", onChange);