@react-three/csg
Version:
Constructive solid geometry for React
187 lines (169 loc) • 6.41 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var _extends = require('@babel/runtime/helpers/extends');
var React = require('react');
var fiber = require('@react-three/fiber');
var threeBvhCsg = require('three-bvh-csg');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
var React__namespace = /*#__PURE__*/_interopNamespace(React);
const TYPES = {
subtraction: threeBvhCsg.SUBTRACTION,
reverseSubtraction: threeBvhCsg.REVERSE_SUBTRACTION,
addition: threeBvhCsg.ADDITION,
difference: threeBvhCsg.DIFFERENCE,
intersection: threeBvhCsg.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 threeBvhCsg.Brush) {
op.updateMatrixWorld();
currentOp = op;
} else {
op.traverse(obj => {
obj.updateMatrixWorld();
if (!currentOp && obj instanceof threeBvhCsg.Brush) currentOp = obj;
});
}
return currentOp;
}
const csgContext = /*#__PURE__*/React__namespace.createContext(null);
const Geometry = /*#__PURE__*/React__namespace.forwardRef(({
children,
computeVertexNormals = false,
useGroups = false,
consolidateGroups = false,
showOperations = false
}, fref) => {
const geo = React__namespace.useRef(null);
const operations = React__namespace.useRef(null);
const ev = React__namespace.useMemo(() => Object.assign(new threeBvhCsg.Evaluator(), {
useGroups,
consolidateGroups
}), [useGroups, consolidateGroups]);
const update = React__namespace.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] || threeBvhCsg.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__namespace.useMemo(() => ({
computeVertexNormals,
showOperations,
useGroups,
consolidateGroups,
update
}), [computeVertexNormals, showOperations, useGroups, consolidateGroups]);
React__namespace.useLayoutEffect(() => void update());
React__namespace.useImperativeHandle(fref, () => ({
geometry: geo.current,
operations: operations.current,
...api
}), [api]);
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("group", {
matrixAutoUpdate: false,
ref: operations
}, /*#__PURE__*/React__namespace.createElement(csgContext.Provider, {
value: api
}, children)), /*#__PURE__*/React__namespace.createElement("bufferGeometry", {
ref: geo
}));
});
const Base = /*#__PURE__*/React__namespace.forwardRef(({
showOperation = false,
operator = 'addition',
...props
}, fref) => {
fiber.extend({
Brush: threeBvhCsg.Brush
});
const {
showOperations
} = React__namespace.useContext(csgContext);
return /*#__PURE__*/React__namespace.createElement("brush", _extends__default["default"]({
operator: operator,
raycast: () => null,
visible: showOperation || showOperations,
ref: fref
}, props));
});
const Addition = /*#__PURE__*/React__namespace.forwardRef((props, fref) => /*#__PURE__*/React__namespace.createElement(Base, _extends__default["default"]({
ref: fref,
operator: "addition"
}, props)));
const Subtraction = /*#__PURE__*/React__namespace.forwardRef((props, fref) => /*#__PURE__*/React__namespace.createElement(Base, _extends__default["default"]({
ref: fref,
operator: "subtraction"
}, props)));
const ReverseSubtraction = /*#__PURE__*/React__namespace.forwardRef((props, fref) => /*#__PURE__*/React__namespace.createElement(Base, _extends__default["default"]({
ref: fref,
operator: "reverseSubtraction"
}, props)));
const Difference = /*#__PURE__*/React__namespace.forwardRef((props, fref) => /*#__PURE__*/React__namespace.createElement(Base, _extends__default["default"]({
ref: fref,
operator: "difference"
}, props)));
const Intersection = /*#__PURE__*/React__namespace.forwardRef((props, fref) => /*#__PURE__*/React__namespace.createElement(Base, _extends__default["default"]({
ref: fref,
operator: "intersection"
}, props)));
function useCSG() {
return React__namespace.useContext(csgContext);
}
exports.Addition = Addition;
exports.Base = Base;
exports.Difference = Difference;
exports.Geometry = Geometry;
exports.Intersection = Intersection;
exports.ReverseSubtraction = ReverseSubtraction;
exports.Subtraction = Subtraction;
exports.useCSG = useCSG;