212 lines
7.6 KiB
JavaScript
212 lines
7.6 KiB
JavaScript
import _extends from '@babel/runtime/helpers/esm/extends';
|
|
import { useThree, useFrame } from '@react-three/fiber';
|
|
import * as React from 'react';
|
|
import * as THREE from 'three';
|
|
import { AxisArrow } from './AxisArrow.js';
|
|
import { AxisRotator } from './AxisRotator.js';
|
|
import { PlaneSlider } from './PlaneSlider.js';
|
|
import { ScalingSphere } from './ScalingSphere.js';
|
|
import { context } from './context.js';
|
|
import { calculateScaleFactor } from '../../core/calculateScaleFactor.js';
|
|
|
|
const mL0 = /* @__PURE__ */new THREE.Matrix4();
|
|
const mW0 = /* @__PURE__ */new THREE.Matrix4();
|
|
const mP = /* @__PURE__ */new THREE.Matrix4();
|
|
const mPInv = /* @__PURE__ */new THREE.Matrix4();
|
|
const mW = /* @__PURE__ */new THREE.Matrix4();
|
|
const mL = /* @__PURE__ */new THREE.Matrix4();
|
|
const mL0Inv = /* @__PURE__ */new THREE.Matrix4();
|
|
const mdL = /* @__PURE__ */new THREE.Matrix4();
|
|
const mG = /* @__PURE__ */new THREE.Matrix4();
|
|
const bb = /* @__PURE__ */new THREE.Box3();
|
|
const bbObj = /* @__PURE__ */new THREE.Box3();
|
|
const vCenter = /* @__PURE__ */new THREE.Vector3();
|
|
const vSize = /* @__PURE__ */new THREE.Vector3();
|
|
const vAnchorOffset = /* @__PURE__ */new THREE.Vector3();
|
|
const vPosition = /* @__PURE__ */new THREE.Vector3();
|
|
const vScale = /* @__PURE__ */new THREE.Vector3();
|
|
const xDir = /* @__PURE__ */new THREE.Vector3(1, 0, 0);
|
|
const yDir = /* @__PURE__ */new THREE.Vector3(0, 1, 0);
|
|
const zDir = /* @__PURE__ */new THREE.Vector3(0, 0, 1);
|
|
const PivotControls = /* @__PURE__ */React.forwardRef(({
|
|
enabled = true,
|
|
matrix,
|
|
onDragStart,
|
|
onDrag,
|
|
onDragEnd,
|
|
autoTransform = true,
|
|
anchor,
|
|
disableAxes = false,
|
|
disableSliders = false,
|
|
disableRotations = false,
|
|
disableScaling = false,
|
|
activeAxes = [true, true, true],
|
|
offset = [0, 0, 0],
|
|
rotation = [0, 0, 0],
|
|
scale = 1,
|
|
lineWidth = 4,
|
|
fixed = false,
|
|
translationLimits,
|
|
rotationLimits,
|
|
scaleLimits,
|
|
depthTest = true,
|
|
axisColors = ['#ff2060', '#20df80', '#2080ff'],
|
|
hoveredColor = '#ffff40',
|
|
annotations = false,
|
|
annotationsClass,
|
|
opacity = 1,
|
|
visible = true,
|
|
userData,
|
|
children,
|
|
...props
|
|
}, fRef) => {
|
|
const invalidate = useThree(state => state.invalidate);
|
|
const parentRef = React.useRef(null);
|
|
const ref = React.useRef(null);
|
|
const gizmoRef = React.useRef(null);
|
|
const childrenRef = React.useRef(null);
|
|
const translation = React.useRef([0, 0, 0]);
|
|
const cameraScale = React.useRef(new THREE.Vector3(1, 1, 1));
|
|
const gizmoScale = React.useRef(new THREE.Vector3(1, 1, 1));
|
|
React.useLayoutEffect(() => {
|
|
if (!anchor) return;
|
|
childrenRef.current.updateWorldMatrix(true, true);
|
|
mPInv.copy(childrenRef.current.matrixWorld).invert();
|
|
bb.makeEmpty();
|
|
childrenRef.current.traverse(obj => {
|
|
if (!obj.geometry) return;
|
|
if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
|
|
mL.copy(obj.matrixWorld).premultiply(mPInv);
|
|
bbObj.copy(obj.geometry.boundingBox);
|
|
bbObj.applyMatrix4(mL);
|
|
bb.union(bbObj);
|
|
});
|
|
vCenter.copy(bb.max).add(bb.min).multiplyScalar(0.5);
|
|
vSize.copy(bb.max).sub(bb.min).multiplyScalar(0.5);
|
|
vAnchorOffset.copy(vSize).multiply(new THREE.Vector3(...anchor)).add(vCenter);
|
|
vPosition.set(...offset).add(vAnchorOffset);
|
|
gizmoRef.current.position.copy(vPosition);
|
|
invalidate();
|
|
});
|
|
const config = React.useMemo(() => ({
|
|
onDragStart: props => {
|
|
mL0.copy(ref.current.matrix);
|
|
mW0.copy(ref.current.matrixWorld);
|
|
onDragStart && onDragStart(props);
|
|
invalidate();
|
|
},
|
|
onDrag: mdW => {
|
|
mP.copy(parentRef.current.matrixWorld);
|
|
mPInv.copy(mP).invert();
|
|
// After applying the delta
|
|
mW.copy(mW0).premultiply(mdW);
|
|
mL.copy(mW).premultiply(mPInv);
|
|
mL0Inv.copy(mL0).invert();
|
|
mdL.copy(mL).multiply(mL0Inv);
|
|
if (autoTransform) {
|
|
ref.current.matrix.copy(mL);
|
|
}
|
|
onDrag && onDrag(mL, mdL, mW, mdW);
|
|
invalidate();
|
|
},
|
|
onDragEnd: () => {
|
|
if (onDragEnd) onDragEnd();
|
|
invalidate();
|
|
},
|
|
translation,
|
|
translationLimits,
|
|
rotationLimits,
|
|
axisColors,
|
|
hoveredColor,
|
|
opacity,
|
|
scale,
|
|
lineWidth,
|
|
fixed,
|
|
depthTest,
|
|
userData,
|
|
annotations,
|
|
annotationsClass
|
|
}), [onDragStart, onDrag, onDragEnd, translation, translationLimits, rotationLimits, scaleLimits, depthTest, scale, lineWidth, fixed, ...axisColors, hoveredColor, opacity, userData, autoTransform, annotations, annotationsClass]);
|
|
const vec = new THREE.Vector3();
|
|
useFrame(state => {
|
|
if (fixed) {
|
|
const sf = calculateScaleFactor(gizmoRef.current.getWorldPosition(vec), scale, state.camera, state.size);
|
|
cameraScale.current.setScalar(sf);
|
|
}
|
|
if (matrix && matrix instanceof THREE.Matrix4) {
|
|
ref.current.matrix = matrix;
|
|
}
|
|
// Update gizmo scale in accordance with matrix changes
|
|
// Without this, there might be noticable turbulences if scaling happens fast enough
|
|
ref.current.updateWorldMatrix(true, true);
|
|
mG.makeRotationFromEuler(gizmoRef.current.rotation).setPosition(gizmoRef.current.position).premultiply(ref.current.matrixWorld);
|
|
gizmoScale.current.setFromMatrixScale(mG);
|
|
vScale.copy(cameraScale.current).divide(gizmoScale.current);
|
|
if (Math.abs(gizmoRef.current.scale.x - vScale.x) > 1e-4 || Math.abs(gizmoRef.current.scale.y - vScale.y) > 1e-4 || Math.abs(gizmoRef.current.scale.z - vScale.z) > 1e-4) {
|
|
gizmoRef.current.scale.copy(vScale);
|
|
state.invalidate();
|
|
}
|
|
});
|
|
React.useImperativeHandle(fRef, () => ref.current, []);
|
|
return /*#__PURE__*/React.createElement(context.Provider, {
|
|
value: config
|
|
}, /*#__PURE__*/React.createElement("group", {
|
|
ref: parentRef
|
|
}, /*#__PURE__*/React.createElement("group", _extends({
|
|
ref: ref,
|
|
matrix: matrix,
|
|
matrixAutoUpdate: false
|
|
}, props), /*#__PURE__*/React.createElement("group", {
|
|
visible: visible,
|
|
ref: gizmoRef,
|
|
position: offset,
|
|
rotation: rotation
|
|
}, enabled && /*#__PURE__*/React.createElement(React.Fragment, null, !disableAxes && activeAxes[0] && /*#__PURE__*/React.createElement(AxisArrow, {
|
|
axis: 0,
|
|
direction: xDir
|
|
}), !disableAxes && activeAxes[1] && /*#__PURE__*/React.createElement(AxisArrow, {
|
|
axis: 1,
|
|
direction: yDir
|
|
}), !disableAxes && activeAxes[2] && /*#__PURE__*/React.createElement(AxisArrow, {
|
|
axis: 2,
|
|
direction: zDir
|
|
}), !disableSliders && activeAxes[0] && activeAxes[1] && /*#__PURE__*/React.createElement(PlaneSlider, {
|
|
axis: 2,
|
|
dir1: xDir,
|
|
dir2: yDir
|
|
}), !disableSliders && activeAxes[0] && activeAxes[2] && /*#__PURE__*/React.createElement(PlaneSlider, {
|
|
axis: 1,
|
|
dir1: zDir,
|
|
dir2: xDir
|
|
}), !disableSliders && activeAxes[2] && activeAxes[1] && /*#__PURE__*/React.createElement(PlaneSlider, {
|
|
axis: 0,
|
|
dir1: yDir,
|
|
dir2: zDir
|
|
}), !disableRotations && activeAxes[0] && activeAxes[1] && /*#__PURE__*/React.createElement(AxisRotator, {
|
|
axis: 2,
|
|
dir1: xDir,
|
|
dir2: yDir
|
|
}), !disableRotations && activeAxes[0] && activeAxes[2] && /*#__PURE__*/React.createElement(AxisRotator, {
|
|
axis: 1,
|
|
dir1: zDir,
|
|
dir2: xDir
|
|
}), !disableRotations && activeAxes[2] && activeAxes[1] && /*#__PURE__*/React.createElement(AxisRotator, {
|
|
axis: 0,
|
|
dir1: yDir,
|
|
dir2: zDir
|
|
}), !disableScaling && activeAxes[0] && /*#__PURE__*/React.createElement(ScalingSphere, {
|
|
axis: 0,
|
|
direction: xDir
|
|
}), !disableScaling && activeAxes[1] && /*#__PURE__*/React.createElement(ScalingSphere, {
|
|
axis: 1,
|
|
direction: yDir
|
|
}), !disableScaling && activeAxes[2] && /*#__PURE__*/React.createElement(ScalingSphere, {
|
|
axis: 2,
|
|
direction: zDir
|
|
}))), /*#__PURE__*/React.createElement("group", {
|
|
ref: childrenRef
|
|
}, children))));
|
|
});
|
|
|
|
export { PivotControls };
|