UNPKG

@react-three/csg

Version:

Constructive solid geometry for React

153 lines (140 loc) 5.01 kB
import _extends from '@babel/runtime/helpers/esm/extends'; import * as React from 'react'; import { extend } from '@react-three/fiber'; import { Evaluator, ADDITION, Brush, SUBTRACTION, REVERSE_SUBTRACTION, DIFFERENCE, INTERSECTION } from 'three-bvh-csg'; const TYPES = { subtraction: SUBTRACTION, reverseSubtraction: REVERSE_SUBTRACTION, addition: ADDITION, difference: DIFFERENCE, intersection: INTERSECTION }; function dispose(geometry) { geometry.dispose(); geometry.attributes = {}; geometry.groups = []; geometry.boundsTree = geometry.index = geometry.boundingBox = geometry.boundingSphere = null; geometry.drawRange = { start: 0, count: Infinity }; } function resolve(op) { let currentOp = null; if (op instanceof Brush) { op.updateMatrixWorld(); currentOp = op; } else { op.traverse(obj => { obj.updateMatrixWorld(); if (!currentOp && obj instanceof Brush) currentOp = obj; }); } return currentOp; } const csgContext = /*#__PURE__*/React.createContext(null); const Geometry = /*#__PURE__*/React.forwardRef(({ children, computeVertexNormals = false, useGroups = false, consolidateGroups = false, showOperations = false }, fref) => { const geo = React.useRef(null); const operations = React.useRef(null); const ev = React.useMemo(() => Object.assign(new Evaluator(), { useGroups, consolidateGroups }), [useGroups, consolidateGroups]); const update = React.useCallback(() => { try { const ops = operations.current.children.slice(); if (ops.length > 0) { // Dispose old geometry dispose(geo.current); // Set the ops groups matrix to identiy operations.current.matrixWorld.identity(); let root = resolve(ops.shift()); if (root) { var _geo$current, _geo$current$__r3f, _geo$current$__r3f$pa, _geo$current$__r3f$pa2; while (ops.length) { const op = resolve(ops.shift()); if (op) root = ev.evaluate(root, op, TYPES[op.operator] || ADDITION); } ; geo.current.boundsTree = root.geometry.boundsTree; geo.current.index = root.geometry.index; geo.current.attributes = root.geometry.attributes; geo.current.groups = root.geometry.groups; geo.current.drawRange = root.geometry.drawRange; if (ev.useGroups && (_geo$current = geo.current) != null && (_geo$current$__r3f = _geo$current.__r3f) != null && (_geo$current$__r3f$pa = _geo$current$__r3f.parent) != null && (_geo$current$__r3f$pa2 = _geo$current$__r3f$pa.object) != null && _geo$current$__r3f$pa2.material) geo.current.__r3f.parent.object.material = root.material; if (computeVertexNormals) geo.current.computeVertexNormals(); } } } catch (e) { console.log(e); } }, [computeVertexNormals, ev]); const api = React.useMemo(() => ({ computeVertexNormals, showOperations, useGroups, consolidateGroups, update }), [computeVertexNormals, showOperations, useGroups, consolidateGroups]); React.useLayoutEffect(() => void update()); React.useImperativeHandle(fref, () => ({ geometry: geo.current, operations: operations.current, ...api }), [api]); return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("group", { matrixAutoUpdate: false, ref: operations }, /*#__PURE__*/React.createElement(csgContext.Provider, { value: api }, children)), /*#__PURE__*/React.createElement("bufferGeometry", { ref: geo })); }); const Base = /*#__PURE__*/React.forwardRef(({ showOperation = false, operator = 'addition', ...props }, fref) => { extend({ Brush: Brush }); const { showOperations } = React.useContext(csgContext); return /*#__PURE__*/React.createElement("brush", _extends({ operator: operator, raycast: () => null, visible: showOperation || showOperations, ref: fref }, props)); }); const Addition = /*#__PURE__*/React.forwardRef((props, fref) => /*#__PURE__*/React.createElement(Base, _extends({ ref: fref, operator: "addition" }, props))); const Subtraction = /*#__PURE__*/React.forwardRef((props, fref) => /*#__PURE__*/React.createElement(Base, _extends({ ref: fref, operator: "subtraction" }, props))); const ReverseSubtraction = /*#__PURE__*/React.forwardRef((props, fref) => /*#__PURE__*/React.createElement(Base, _extends({ ref: fref, operator: "reverseSubtraction" }, props))); const Difference = /*#__PURE__*/React.forwardRef((props, fref) => /*#__PURE__*/React.createElement(Base, _extends({ ref: fref, operator: "difference" }, props))); const Intersection = /*#__PURE__*/React.forwardRef((props, fref) => /*#__PURE__*/React.createElement(Base, _extends({ ref: fref, operator: "intersection" }, props))); function useCSG() { return React.useContext(csgContext); } export { Addition, Base, Difference, Geometry, Intersection, ReverseSubtraction, Subtraction, useCSG };