UNPKG

react-native-filament

Version:

A real-time physically based 3D rendering engine for React Native

131 lines (118 loc) 5.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useApplyTransformations = useApplyTransformations; var _react = require("react"); var _useFilamentContext = require("../useFilamentContext"); var _helper = require("../../utilities/helper"); var _useWorkletEffect = require("../useWorkletEffect"); var _reactNativeWorkletsCore = require("react-native-worklets-core"); /** * Takes the next entity from the context and applies all transformations from the next * transformation context to it */ function useApplyTransformations({ to: entity, transformProps, aabb }) { const { translate: position, scale, rotate, transformToUnitCube, multiplyWithCurrentTransform = true } = transformProps ?? {}; const { transformManager } = (0, _useFilamentContext.useFilamentContext)(); // TODO: multiplying current transformations is a bit problematic with react. // E.g. in strict mode or concurrent rendering our effects can be called multiple times. // Running an effect multiple times with transformation multiplication can lead to unexpected results. const prevScale = (0, _react.useRef)(null); const prevRotate = (0, _react.useRef)(null); const prevPosition = (0, _react.useRef)(null); (0, _react.useEffect)(() => { if (entity == null) return; if (transformToUnitCube && aabb != null) { transformManager.transformToUnitCube(entity, aabb); } if (!(0, _helper.isWorkletSharedValue)(scale) && Array.isArray(scale) && (prevScale.current == null || !(0, _helper.areFloat3Equal)(scale, prevScale.current))) { transformManager.setEntityScale(entity, scale, multiplyWithCurrentTransform); prevScale.current = scale; } if (!(0, _helper.isWorkletSharedValue)(rotate) && Array.isArray(rotate) && (prevRotate.current == null || !(0, _helper.areFloat3Equal)(rotate, prevRotate.current))) { const [x, y, z] = rotate; transformManager.setEntityRotation(entity, x, [1, 0, 0], multiplyWithCurrentTransform); // Rotation across axis is one operation so we need to always multiply the remaining rotations: transformManager.setEntityRotation(entity, y, [0, 1, 0], true); transformManager.setEntityRotation(entity, z, [0, 0, 1], true); prevRotate.current = rotate; } if (!(0, _helper.isWorkletSharedValue)(position) && Array.isArray(position) && (prevPosition.current == null || !(0, _helper.areFloat3Equal)(position, prevPosition.current))) { transformManager.setEntityPosition(entity, position, multiplyWithCurrentTransform); prevPosition.current = position; } }, [aabb, entity, multiplyWithCurrentTransform, position, prevPosition, prevRotate, prevScale, rotate, scale, transformManager, transformToUnitCube]); const prevScaleShared = (0, _react.useRef)((0, _helper.isWorkletSharedValue)(scale) ? _reactNativeWorkletsCore.Worklets.createSharedValue(null) : null); const prevRotateShared = (0, _react.useRef)((0, _helper.isWorkletSharedValue)(rotate) ? _reactNativeWorkletsCore.Worklets.createSharedValue(null) : null); const prevPositionShared = (0, _react.useRef)((0, _helper.isWorkletSharedValue)(position) ? _reactNativeWorkletsCore.Worklets.createSharedValue(null) : null); // Effects for when a transform option is a shared value (SRT) (0, _useWorkletEffect.useWorkletEffect)(() => { 'worklet'; if (entity == null) return; const unsubscribers = []; // Generic handler for worklet transform values const createTransformHandler = (value, prevValueShared, updater) => { 'worklet'; if (value == null || !(0, _helper.isWorkletSharedValue)(value) || Array.isArray(value)) return null; const unsubscribe = value.addListener(() => { 'worklet'; // Check if value has changed to avoid duplicate applications in strict mode if (prevValueShared !== null && prevValueShared !== void 0 && prevValueShared.value && (0, _helper.areFloat3Equal)(value.value, prevValueShared.value)) { return; } updater(value.value); // Update previous value tracker if (prevValueShared) { prevValueShared.value = [value.value[0], value.value[1], value.value[2]]; } }); unsubscribers.push(unsubscribe); return value; }; // Set up handlers for each transform type const scaleHandler = createTransformHandler(scale, prevScaleShared.current, newScale => { 'worklet'; transformManager.setEntityScale(entity, [newScale[0], newScale[1], newScale[2]], multiplyWithCurrentTransform); }); const rotateHandler = createTransformHandler(rotate, prevRotateShared.current, newRotate => { 'worklet'; const [x, y, z] = newRotate; transformManager.setEntityRotation(entity, x, [1, 0, 0], multiplyWithCurrentTransform); // Rotation across axis is one operation so we need to always multiply the remaining rotations: transformManager.setEntityRotation(entity, y, [0, 1, 0], true); transformManager.setEntityRotation(entity, z, [0, 0, 1], true); }); const positionHandler = createTransformHandler(position, prevPositionShared.current, newPosition => { 'worklet'; transformManager.setEntityPosition(entity, newPosition, multiplyWithCurrentTransform); }); // Trigger initial values in order: scale -> rotation -> position if (scaleHandler) { scaleHandler.value = [scaleHandler.value[0], scaleHandler.value[1], scaleHandler.value[2]]; } if (rotateHandler) { rotateHandler.value = [rotateHandler.value[0], rotateHandler.value[1], rotateHandler.value[2]]; } if (positionHandler) { positionHandler.value = [positionHandler.value[0], positionHandler.value[1], positionHandler.value[2]]; } return () => { 'worklet'; unsubscribers.forEach(unsubscribe => unsubscribe()); }; }); } //# sourceMappingURL=useApplyTransformations.js.map