diff --git a/components/ARBox.js b/components/ARBox.js index b53350c..3abe7a8 100644 --- a/components/ARBox.js +++ b/components/ARBox.js @@ -10,14 +10,17 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARBox = createArComponent('addBox', { - shape: PropTypes.shape({ - width: PropTypes.number, - height: PropTypes.number, - length: PropTypes.number, - chamfer: PropTypes.number, - }), - material, -}); +const ARBox = createArComponent( + { props: { shape: { type: 'box' } } }, + { + shape: PropTypes.shape({ + width: PropTypes.number, + height: PropTypes.number, + length: PropTypes.number, + chamfer: PropTypes.number + }), + material + } +); export default ARBox; diff --git a/components/ARCapsule.js b/components/ARCapsule.js index b74df95..cd0c5de 100644 --- a/components/ARCapsule.js +++ b/components/ARCapsule.js @@ -10,12 +10,15 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARCapsule = createArComponent('addCapsule', { - shape: PropTypes.shape({ - capR: PropTypes.number, - height: PropTypes.number, - }), - material, -}); +const ARCapsule = createArComponent( + { props: { shape: { type: 'capsule' } } }, + { + shape: PropTypes.shape({ + capR: PropTypes.number, + height: PropTypes.number + }), + material + } +); export default ARCapsule; diff --git a/components/ARCone.js b/components/ARCone.js index 01eef2b..4efd046 100644 --- a/components/ARCone.js +++ b/components/ARCone.js @@ -10,13 +10,16 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARCone = createArComponent('addCone', { - shape: PropTypes.shape({ - topR: PropTypes.number, - bottomR: PropTypes.number, - height: PropTypes.number, - }), - material, -}); +const ARCone = createArComponent( + { props: { shape: { type: 'cone' } } }, + { + shape: PropTypes.shape({ + topR: PropTypes.number, + bottomR: PropTypes.number, + height: PropTypes.number + }), + material + } +); export default ARCone; diff --git a/components/ARCylinder.js b/components/ARCylinder.js index ccbd188..bc42bbd 100644 --- a/components/ARCylinder.js +++ b/components/ARCylinder.js @@ -10,12 +10,15 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARCylinder = createArComponent('addCylinder', { - shape: PropTypes.shape({ - radius: PropTypes.number, - height: PropTypes.number, - }), - material, -}); +const ARCylinder = createArComponent( + { props: { shape: { type: 'cylinder' } } }, + { + shape: PropTypes.shape({ + radius: PropTypes.number, + height: PropTypes.number + }), + material + } +); export default ARCylinder; diff --git a/components/ARGroup.js b/components/ARGroup.js index 87fbba1..c4b6fc5 100644 --- a/components/ARGroup.js +++ b/components/ARGroup.js @@ -7,6 +7,6 @@ import createArComponent from './lib/createArComponent'; -const ARBox = createArComponent('addGroup', {}); +const ARBox = createArComponent({}, {}); export default ARBox; diff --git a/components/ARLight.js b/components/ARLight.js index 0328e0e..9907cc2 100644 --- a/components/ARLight.js +++ b/components/ARLight.js @@ -1,28 +1,33 @@ import PropTypes from 'prop-types'; - +import { NativeModules } from 'react-native'; import { categoryBitMask, color, lightType, shadowMode } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARLight = createArComponent('addLight', { - type: lightType, - color, - temperature: PropTypes.number, - intensity: PropTypes.number, - attenuationStartDistance: PropTypes.number, - attenuationEndDistance: PropTypes.number, - spotInnerAngle: PropTypes.number, - spotOuterAngle: PropTypes.number, - castsShadow: PropTypes.bool, - shadowRadius: PropTypes.number, - shadowColor: color, - // shadowMapSize: PropTypes.number, - shadowSampleCount: PropTypes.number, - shadowMode, - shadowBias: PropTypes.number, - orthographicScale: PropTypes.number, - zFar: PropTypes.number, - zNear: PropTypes.number, - lightCategoryBitMask: categoryBitMask, -}); +const ARLight = createArComponent( + { + mount: NativeModules.ARGeosManager.addLight + }, + { + type: lightType, + color, + temperature: PropTypes.number, + intensity: PropTypes.number, + attenuationStartDistance: PropTypes.number, + attenuationEndDistance: PropTypes.number, + spotInnerAngle: PropTypes.number, + spotOuterAngle: PropTypes.number, + castsShadow: PropTypes.bool, + shadowRadius: PropTypes.number, + shadowColor: color, + // shadowMapSize: PropTypes.number, + shadowSampleCount: PropTypes.number, + shadowMode, + shadowBias: PropTypes.number, + orthographicScale: PropTypes.number, + zFar: PropTypes.number, + zNear: PropTypes.number, + lightCategoryBitMask: categoryBitMask + } +); export default ARLight; diff --git a/components/ARPlane.js b/components/ARPlane.js index 10cbe90..cf8901f 100644 --- a/components/ARPlane.js +++ b/components/ARPlane.js @@ -10,16 +10,19 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARPlane = createArComponent('addPlane', { - shape: PropTypes.shape({ - width: PropTypes.number, - height: PropTypes.number, - cornerRadius: PropTypes.number, - cornerSegmentCount: PropTypes.number, - widthSegmentCount: PropTypes.number, - heightSegmentCount: PropTypes.number, - }), - material, -}); +const ARPlane = createArComponent( + { props: { shape: { type: 'plane' } } }, + { + shape: PropTypes.shape({ + width: PropTypes.number, + height: PropTypes.number, + cornerRadius: PropTypes.number, + cornerSegmentCount: PropTypes.number, + widthSegmentCount: PropTypes.number, + heightSegmentCount: PropTypes.number + }), + material + } +); export default ARPlane; diff --git a/components/ARPyramid.js b/components/ARPyramid.js index 90f47ac..b5afe83 100644 --- a/components/ARPyramid.js +++ b/components/ARPyramid.js @@ -10,13 +10,16 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARPyramid = createArComponent('addPyramid', { - shape: PropTypes.shape({ - width: PropTypes.number, - length: PropTypes.number, - height: PropTypes.number, - }), - material, -}); +const ARPyramid = createArComponent( + { props: { shape: { type: 'pyramid' } } }, + { + shape: PropTypes.shape({ + width: PropTypes.number, + length: PropTypes.number, + height: PropTypes.number + }), + material + } +); export default ARPyramid; diff --git a/components/ARShape.js b/components/ARShape.js index 91e951f..2511a08 100644 --- a/components/ARShape.js +++ b/components/ARShape.js @@ -3,17 +3,20 @@ import PropTypes from 'prop-types'; import { chamferMode, material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARShape = createArComponent('addShape', { - shape: PropTypes.shape({ - extrusion: PropTypes.number, - pathSvg: PropTypes.string, - pathFlatness: PropTypes.number, - chamferMode, - chamferRadius: PropTypes.number, - chamferProfilePathSvg: PropTypes.string, - chamferProfilePathFlatness: PropTypes.number, - }), - material, -}); +const ARShape = createArComponent( + { props: { shape: { type: 'shape' } } }, + { + shape: PropTypes.shape({ + extrusion: PropTypes.number, + pathSvg: PropTypes.string, + pathFlatness: PropTypes.number, + chamferMode, + chamferRadius: PropTypes.number, + chamferProfilePathSvg: PropTypes.string, + chamferProfilePathFlatness: PropTypes.number + }), + material + } +); export default ARShape; diff --git a/components/ARSphere.js b/components/ARSphere.js index 31e3126..7112a6c 100644 --- a/components/ARSphere.js +++ b/components/ARSphere.js @@ -10,11 +10,14 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARSphere = createArComponent('addSphere', { - shape: PropTypes.shape({ - radius: PropTypes.number, - }), - material, -}); +const ARSphere = createArComponent( + { props: { shape: { type: 'sphere' } } }, + { + shape: PropTypes.shape({ + radius: PropTypes.number + }), + material + } +); export default ARSphere; diff --git a/components/ARText.js b/components/ARText.js index 207d0ab..80690ba 100644 --- a/components/ARText.js +++ b/components/ARText.js @@ -13,7 +13,7 @@ import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; const ARText = createArComponent( - { mount: NativeModules.ARTextManager.mount, pick: ['id', 'text', 'font'] }, + { mount: NativeModules.ARTextManager.mount }, { text: PropTypes.string, font: PropTypes.shape({ diff --git a/components/ARTorus.js b/components/ARTorus.js index 07c926e..39664b2 100644 --- a/components/ARTorus.js +++ b/components/ARTorus.js @@ -10,12 +10,15 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARTorus = createArComponent('addTorus', { - shape: PropTypes.shape({ - ringR: PropTypes.number, - pipeR: PropTypes.number, - }), - material, -}); +const ARTorus = createArComponent( + { props: { shape: { type: 'torus' } } }, + { + shape: PropTypes.shape({ + ringR: PropTypes.number, + pipeR: PropTypes.number + }), + material + } +); export default ARTorus; diff --git a/components/ARTube.js b/components/ARTube.js index ba203bb..779279d 100644 --- a/components/ARTube.js +++ b/components/ARTube.js @@ -10,13 +10,16 @@ import PropTypes from 'prop-types'; import { material } from './lib/propTypes'; import createArComponent from './lib/createArComponent'; -const ARTube = createArComponent('addTube', { - shape: PropTypes.shape({ - innerR: PropTypes.number, - outerR: PropTypes.number, - height: PropTypes.number, - }), - material, -}); +const ARTube = createArComponent( + { props: { shape: { type: 'tube' } } }, + { + shape: PropTypes.shape({ + innerR: PropTypes.number, + outerR: PropTypes.number, + height: PropTypes.number + }), + material + } +); export default ARTube; diff --git a/components/lib/createArComponent.js b/components/lib/createArComponent.js index 2155296..b627538 100644 --- a/components/lib/createArComponent.js +++ b/components/lib/createArComponent.js @@ -7,19 +7,21 @@ import isEmpty from 'lodash/isEmpty'; import keys from 'lodash/keys'; import pick from 'lodash/pick'; import some from 'lodash/some'; +import merge from 'lodash/merge'; import { castsShadow, categoryBitMask, + constraint, eulerAngles, opacity, orientation, + physicsBody, position, renderingOrder, rotation, scale, - constraint, - transition, + transition } from './propTypes'; import addAnimatedSupport from './addAnimatedSupport'; import generateId from './generateId'; @@ -31,11 +33,11 @@ const { ARGeosManager } = NativeModules; const PROP_TYPES_IMMUTABLE = { id: PropTypes.string, - frame: PropTypes.string, + frame: PropTypes.string }; const MOUNT_UNMOUNT_ANIMATION_PROPS = { propsOnMount: PropTypes.any, - propsOnUnMount: PropTypes.any, + propsOnUnMount: PropTypes.any }; const PROP_TYPES_NODE = { position, @@ -49,6 +51,7 @@ const PROP_TYPES_NODE = { renderingOrder, opacity, constraint, + physicsBody }; const NODE_PROPS = keys(PROP_TYPES_NODE); @@ -64,15 +67,27 @@ the property will be updated on scenekit, instead of beeing remounted. this excludes at the moment: model, font, text, (???) * */ -export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { +export default ( + customMountConfig, + propTypes = {}, + nonUpdateablePropKeys = [] +) => { + const defaultMontConfig = { + mount: ARGeosManager.mount + }; + const mountConfig = { + ...defaultMontConfig, + ...customMountConfig + }; + const allPropTypes = { ...MOUNT_UNMOUNT_ANIMATION_PROPS, ...PROP_TYPES_IMMUTABLE, ...PROP_TYPES_NODE, - ...propTypes, + ...propTypes }; // any custom props (material, shape, ...) - const nonNodePropKeys = keys(propTypes); + const nonNodePropKeys = [...keys(propTypes), ...keys(mountConfig.props)]; const parseMaterials = props => ({ ...props, @@ -80,26 +95,24 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { ? { shadowColor: processColor(props.shadowColor) } : {}), ...(props.color ? { color: processColor(props.color) } : {}), - ...(props.material ? { material: processMaterial(props.material) } : {}), + ...(props.material ? { material: processMaterial(props.material) } : {}) }); const getNonNodeProps = props => parseMaterials(pick(props, nonNodePropKeys)); - const mountFunc = - typeof mountConfig === 'string' - ? ARGeosManager[mountConfig] - : mountConfig.mount; + const mount = (id, passedProps, parentId) => { + const props = merge({}, mountConfig.props, passedProps); - const mount = (id, props, parentId) => { if (DEBUG) console.log(`[${id}] [${new Date().getTime()}] mount`, props); - return mountFunc( + + return mountConfig.mount( getNonNodeProps(props), { id, - ...pick(props, NODE_PROPS), + ...pick(props, NODE_PROPS) }, props.frame, - parentId, + parentId ); }; @@ -124,7 +137,7 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { if (propsOnMount) { const fullPropsOnMount = { ...props, ...propsOnMount }; const { - transition: transitionOnMount = { duration: 0 }, + transition: transitionOnMount = { duration: 0 } } = fullPropsOnMount; this.doPendingTimers(); @@ -144,7 +157,7 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { componentWillUpdate(props) { const changedKeys = filter( keys(this.props), - key => key !== 'children' && !isDeepEqual(props[key], this.props[key]), + key => key !== 'children' && !isDeepEqual(props[key], this.props[key]) ); if (isEmpty(changedKeys)) { return; @@ -152,14 +165,14 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { if (__DEV__) { const nonAllowedUpdates = filter(changedKeys, k => - IMMUTABLE_PROPS.includes(k), + IMMUTABLE_PROPS.includes(k) ); if (nonAllowedUpdates.length > 0) { throw new Error( `[${this .identifier}] prop can't be updated: '${nonAllowedUpdates.join( - ', ', - )}'`, + ', ' + )}'` ); } } @@ -168,7 +181,7 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { if (DEBUG) console.log( `[${this.identifier}] need to remount node because of `, - changedKeys, + changedKeys ); this.mountWithProps({ ...this.props, ...props }); } else { @@ -179,9 +192,9 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { // always inclue transition transition: { ...this.props.transition, - ...props.transition, + ...props.transition }, - ...parseMaterials(pick(props, changedKeys)), + ...parseMaterials(pick(props, changedKeys)) }; update(this.identifier, propsToupdate).catch(() => { // sometimes calls are out of order, so this node has been unmounted @@ -217,7 +230,7 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { callback.call(this); delete TIMERS[this.identifier]; }, duration), - callback, + callback }; } @@ -232,7 +245,7 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { } getChildContext() { return { - arkitParentId: this.identifier, + arkitParentId: this.identifier }; } @@ -243,10 +256,10 @@ export default (mountConfig, propTypes = {}, nonUpdateablePropKeys = []) => { } }; ARComponent.childContextTypes = { - arkitParentId: PropTypes.string, + arkitParentId: PropTypes.string }; ARComponent.contextTypes = { - arkitParentId: PropTypes.string, + arkitParentId: PropTypes.string }; const ARComponentAnimated = addAnimatedSupport(ARComponent); diff --git a/components/lib/propTypes.js b/components/lib/propTypes.js index d993e0f..75a323a 100644 --- a/components/lib/propTypes.js +++ b/components/lib/propTypes.js @@ -6,90 +6,95 @@ const ARKitManager = NativeModules.ARKitManager; const animatableNumber = PropTypes.oneOfType([ PropTypes.number, - PropTypes.object, + PropTypes.object ]); export const deprecated = (propType, hint = null) => ( props, propName, - componentName, + componentName ) => { if (props[propName]) { console.warn( `Prop \`${propName}\` supplied to` + - ` \`${componentName}\` is deprecated. ${hint}`, + ` \`${componentName}\` is deprecated. ${hint}` ); } return PropTypes.checkPropTypes( { [propName]: propType }, props, propName, - componentName, + componentName ); }; export const position = PropTypes.shape({ x: animatableNumber, y: animatableNumber, - z: animatableNumber, + z: animatableNumber }); export const scale = animatableNumber; export const categoryBitMask = PropTypes.number; export const transition = PropTypes.shape({ - duration: PropTypes.number, + duration: PropTypes.number }); export const planeDetection = PropTypes.oneOf( - values(ARKitManager.ARPlaneDetection), + values(ARKitManager.ARPlaneDetection) ); export const eulerAngles = PropTypes.shape({ x: animatableNumber, y: animatableNumber, - z: animatableNumber, + z: animatableNumber }); export const rotation = PropTypes.shape({ x: animatableNumber, y: animatableNumber, z: animatableNumber, - w: animatableNumber, + w: animatableNumber }); export const orientation = PropTypes.shape({ x: animatableNumber, y: animatableNumber, z: animatableNumber, - w: animatableNumber, + w: animatableNumber +}); + +export const physicsBody = PropTypes.shape({ + mass: PropTypes.number, + type: PropTypes.oneOf(values(ARKitManager.PhysicsBodyType)) }); export const textureTranslation = PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, - z: PropTypes.number, + z: PropTypes.number }); export const textureRotation = PropTypes.shape({ angle: PropTypes.number, x: PropTypes.number, y: PropTypes.number, - z: PropTypes.number, + z: PropTypes.number }); export const textureScale = PropTypes.shape({ x: PropTypes.number, y: PropTypes.number, - z: PropTypes.number, + z: PropTypes.number }); export const shaders = PropTypes.shape({ [ARKitManager.ShaderModifierEntryPoint.Geometry]: PropTypes.string, [ARKitManager.ShaderModifierEntryPoint.Surface]: PropTypes.string, [ARKitManager.ShaderModifierEntryPoint.LightingModel]: PropTypes.string, - [ARKitManager.ShaderModifierEntryPoint.Fragment]: PropTypes.string, + [ARKitManager.ShaderModifierEntryPoint.Fragment]: PropTypes.string }); export const lightingModel = PropTypes.oneOf( - values(ARKitManager.LightingModel), + values(ARKitManager.LightingModel) ); export const castsShadow = PropTypes.bool; @@ -102,7 +107,7 @@ export const fillMode = PropTypes.oneOf(values(ARKitManager.FillMode)); export const lightType = PropTypes.oneOf(values(ARKitManager.LightType)); export const shadowMode = PropTypes.oneOf(values(ARKitManager.ShadowMode)); export const colorBufferWriteMask = PropTypes.oneOf( - values(ARKitManager.ColorMask), + values(ARKitManager.ColorMask) ); export const opacity = animatableNumber; @@ -120,7 +125,7 @@ export const materialProperty = PropTypes.shape({ wrap: wrapMode, translation: textureTranslation, scale: textureScale, - rotation: textureRotation, + rotation: textureRotation }); export const material = PropTypes.shape({ @@ -139,10 +144,10 @@ export const material = PropTypes.shape({ doubleSided: PropTypes.bool, litPerPixel: PropTypes.bool, transparency: PropTypes.number, - fillMode, + fillMode }); const detectionImage = PropTypes.shape({ - resourceGroupName: PropTypes.string, + resourceGroupName: PropTypes.string }); export const detectionImages = PropTypes.arrayOf(detectionImage); diff --git a/ios/RCTARKit.m b/ios/RCTARKit.m index 36105fe..a1f0948 100644 --- a/ios/RCTARKit.m +++ b/ios/RCTARKit.m @@ -11,7 +11,7 @@ @import CoreLocation; -@interface RCTARKit () { +@interface RCTARKit () { RCTARKitResolve _resolve; } @@ -48,7 +48,9 @@ + (instancetype)sharedInstance { dispatch_once_on_main_thread(&onceToken, ^{ if (instance == nil) { + ARSCNView *arView = [[ARSCNView alloc] init]; + instance = [[self alloc] initWithARView:arView]; } }); @@ -64,10 +66,10 @@ - (bool)isMounted { - (instancetype)initWithARView:(ARSCNView *)arView { if ((self = [super init])) { self.arView = arView; - // delegates arView.delegate = self; arView.session.delegate = self; + arView.scene.physicsWorld.contactDelegate = self; UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapFrom:)]; tapGestureRecognizer.numberOfTapsRequired = 1; @@ -157,7 +159,8 @@ - (BOOL)debug { - (void)setDebug:(BOOL)debug { if (debug) { self.arView.showsStatistics = YES; - self.arView.debugOptions = ARSCNDebugOptionShowWorldOrigin | ARSCNDebugOptionShowFeaturePoints; + + self.arView.debugOptions = ARSCNDebugOptionShowWorldOrigin | ARSCNDebugOptionShowFeaturePoints | SCNDebugOptionShowPhysicsShapes; } else { self.arView.showsStatistics = NO; self.arView.debugOptions = SCNDebugOptionNone; @@ -572,6 +575,7 @@ - (void)removeRendererDelegates:(id) delegate { NSLog(@"removed, number of renderer delegates %d", [self.rendererDelegates count]); } - (void)renderer:(id )renderer willUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor { + } @@ -736,7 +740,19 @@ - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event } } } +#pragma mark - SCNPhysicsContactDelegate +- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact { + +} + +- (void)physicsWorld:(SCNPhysicsWorld *)world didUpdateContact:(SCNPhysicsContact *)contact { + +} + +- (void)physicsWorld:(SCNPhysicsWorld *)world didEndContact:(SCNPhysicsContact *)contact { + +} #pragma mark - dealloc diff --git a/ios/RCTARKit.xcodeproj/project.pbxproj b/ios/RCTARKit.xcodeproj/project.pbxproj index 78c04cc..08c9efd 100644 --- a/ios/RCTARKit.xcodeproj/project.pbxproj +++ b/ios/RCTARKit.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 10ED47A71F38BC01004DF043 /* DeviceMotion.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED47A61F38BC00004DF043 /* DeviceMotion.m */; }; 10FEF6141F774C9000EC21AE /* RCTARKitIO.m in Sources */ = {isa = PBXBuildFile; fileRef = 10FEF6101F774C8F00EC21AE /* RCTARKitIO.m */; }; 10FEF6151F774C9000EC21AE /* RCTARKitNodes.m in Sources */ = {isa = PBXBuildFile; fileRef = 10FEF6121F774C9000EC21AE /* RCTARKitNodes.m */; }; + B12E5F312070241D00D423F4 /* Switcher.m in Sources */ = {isa = PBXBuildFile; fileRef = B12E5F302070241D00D423F4 /* Switcher.m */; }; B1990B221FCEEBD60001AE2F /* color-grabber.m in Sources */ = {isa = PBXBuildFile; fileRef = B1990B211FCEEBD60001AE2F /* color-grabber.m */; }; B1CEA29F204C14090025C1B8 /* RCTARKitSpriteView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1CEA29E204C14090025C1B8 /* RCTARKitSpriteView.m */; }; B1CEA2A3204C160D0025C1B8 /* RCTARKitSpriteViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B1CEA2A2204C160D0025C1B8 /* RCTARKitSpriteViewManager.m */; }; @@ -61,6 +62,8 @@ 10FEF6121F774C9000EC21AE /* RCTARKitNodes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTARKitNodes.m; sourceTree = ""; }; 10FEF6131F774C9000EC21AE /* RCTARKitDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTARKitDelegate.h; sourceTree = ""; }; 134814201AA4EA6300B7C361 /* libRCTARKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTARKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B12E5F302070241D00D423F4 /* Switcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Switcher.m; path = "../../../../../../panter/archilogic/react-native-arkit/ios/Switcher.m"; sourceTree = ""; }; + B12E5F322070245700D423F4 /* Switcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Switcher.h; sourceTree = ""; }; B14C36631F960C500047CB67 /* PocketSVG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PocketSVG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B14C36651F960C6E0047CB67 /* PocketSVG.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PocketSVG.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B1990B201FCEEBD60001AE2F /* color-grabber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "color-grabber.h"; sourceTree = ""; }; @@ -112,6 +115,8 @@ 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( + B12E5F322070245700D423F4 /* Switcher.h */, + B12E5F302070241D00D423F4 /* Switcher.m */, B1990B1F1FCEEBD60001AE2F /* color-grabber */, 106999E21F3EC2FB00032829 /* components */, 10ED47A51F38BC00004DF043 /* DeviceMotion.h */, @@ -218,6 +223,7 @@ 10062C831F127572009AE974 /* RCTARKitManager.m in Sources */, B1CEA29F204C14090025C1B8 /* RCTARKitSpriteView.m in Sources */, B1CEA2A3204C160D0025C1B8 /* RCTARKitSpriteViewManager.m in Sources */, + B12E5F312070241D00D423F4 /* Switcher.m in Sources */, 10ED47A71F38BC01004DF043 /* DeviceMotion.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/RCTARKitManager.m b/ios/RCTARKitManager.m index c41ef7f..d3fa4cc 100644 --- a/ios/RCTARKitManager.m +++ b/ios/RCTARKitManager.m @@ -132,6 +132,11 @@ - (NSDictionary *)constantsToExport @"GravityAndHeading": @(ARWorldAlignmentGravityAndHeading), @"Camera": @(ARWorldAlignmentCamera), }, + @"PhysicsBodyType": @{ + @"Static": @(SCNPhysicsBodyTypeStatic), + @"Dynamic": @(SCNPhysicsBodyTypeDynamic), + @"Kinematic": @(SCNPhysicsBodyTypeKinematic), + }, @"FillMode": @{ @"Fill": [@(SCNFillModeFill) stringValue], @"Lines": [@(SCNFillModeLines) stringValue], diff --git a/ios/RCTConvert+ARKit.h b/ios/RCTConvert+ARKit.h index 60beee7..724f5da 100644 --- a/ios/RCTConvert+ARKit.h +++ b/ios/RCTConvert+ARKit.h @@ -23,6 +23,7 @@ + (SCNVector4)SCNVector4:(id)json; + (SCNNode *)SCNNode:(id)json; ++ (SCNGeometry *)SCNGeometry:(id)json; + (SCNBox *)SCNBox:(id)json; + (SCNSphere *)SCNSphere:(id)json; + (SCNCylinder *)SCNCylinder:(id)json; diff --git a/ios/RCTConvert+ARKit.m b/ios/RCTConvert+ARKit.m index b648e99..a19010c 100644 --- a/ios/RCTConvert+ARKit.m +++ b/ios/RCTConvert+ARKit.m @@ -8,6 +8,7 @@ #import "RCTConvert+ARKit.h" #import "SVGBezierPath.h" +#import "Switcher.h" @implementation RCTConvert (ARKit) @@ -53,6 +54,76 @@ + (void)addMaterials:(SCNGeometry *)geometry json:(id)json sides:(int) sides { for (int i = 0; i < sides; i++) [materials addObject: material]; geometry.materials = materials; +} + ++ (SCNGeometry *)SCNGeometry:(id)json { + + if(!json[@"shape"]) { + return nil; + } + NSDictionary *shape = json[@"shape"]; + if(!shape[@"type"]) { + return nil; + } + + __block SCNGeometry* geometry; + + + NSString *type = shape[@"type"]; + + + [Switcher switchOnString:type using:@{ + @"sphere": + ^{ + geometry = [self SCNSphere:json]; + }, + @"box": + ^{ + geometry = [self SCNBox:json]; + }, + @"cylinder": + ^{ + geometry = [self SCNCylinder:json]; + }, + @"capuse": + ^{ + geometry = [self SCNCapsule:json]; + }, + @"cone": + ^{ + geometry = [self SCNCone:json]; + }, + @"shape": + ^{ + geometry = [self SCNShape:json]; + }, + @"plane": + ^{ + geometry = [self SCNPlane:json]; + }, + @"pyramid": + ^{ + geometry = [self SCNPyramid:json]; + }, + @"torus": + ^{ + geometry = [self SCNTorus:json]; + }, + @"tube": + ^{ + geometry = [self SCNTube:json]; + } + } withDefault: + ^{ + + } + ]; + return geometry; + + + + + } + (SCNBox *)SCNBox:(id)json { @@ -172,6 +243,23 @@ + (SCNPlane *)SCNPlane:(id)json { return geometry; } ++ (SCNPhysicsBody *)SCNPhysicsBody:(id)json { + SCNPhysicsBodyType type = [json[@"type"] integerValue]; + SCNPhysicsShape * shape = nil; + if(json[@"shape"]) { + SCNGeometry * geometry = [self SCNGeometry:json]; + shape = [SCNPhysicsShape shapeWithGeometry:geometry options:nil]; + } + + SCNPhysicsBody* body = [SCNPhysicsBody bodyWithType:type shape:shape]; + if(json[@"mass"]) { + body.mass = [json[@"mass"] floatValue]; + } + + + return body; +} + + (SVGBezierPath *)svgStringToBezier:(NSString *)pathString { NSArray * paths = [SVGBezierPath pathsFromSVGString:pathString]; SVGBezierPath * fullPath; @@ -431,7 +519,10 @@ + (void)setMaterialProperties:(SCNMaterial *)material properties:(id)json { } + (void)setNodeProperties:(SCNNode *)node properties:(id)json { - + if(json[@"physicsBody"]) { + node.physicsBody = [self SCNPhysicsBody:json[@"physicsBody"]]; + + } if (json[@"categoryBitMask"]) { node.categoryBitMask = [json[@"categoryBitMask"] integerValue]; } @@ -462,7 +553,7 @@ + (void)setNodeProperties:(SCNNode *)node properties:(id)json { } if (json[@"scale"]) { - + CGFloat scale = [json[@"scale"] floatValue]; node.scale = SCNVector3Make(scale, scale, scale); diff --git a/ios/Switcher.h b/ios/Switcher.h new file mode 100644 index 0000000..fb9a587 --- /dev/null +++ b/ios/Switcher.h @@ -0,0 +1,18 @@ +// +// Switcher.h +// RCTARKit +// +// Created by Marco Wettstein on 31.03.18. +// Copyright © 2018 HippoAR. All rights reserved. +// + + +typedef void (^CaseBlock)(); + +@interface Switcher : NSObject + ++ (void)switchOnString:(NSString *)tString + using:(NSDictionary *)tCases + withDefault:(CaseBlock)tDefaultBlock; + +@end diff --git a/ios/Switcher.m b/ios/Switcher.m new file mode 100644 index 0000000..38119d5 --- /dev/null +++ b/ios/Switcher.m @@ -0,0 +1,27 @@ +// +// Switcher.m +// RCTARKit +// +// Created by Marco Wettstein on 31.03.18. +// Copyright © 2018 HippoAR. All rights reserved. +// + +#import +#import "Switcher.h" + + +@implementation Switcher + ++ (void)switchOnString:(NSString *)tString + using:(NSDictionary *)tCases + withDefault:(CaseBlock)tDefaultBlock +{ + CaseBlock blockToExecute = tCases[tString]; + if (blockToExecute) { + blockToExecute(); + } else { + tDefaultBlock(); + } +} + +@end diff --git a/ios/components/ARGeosManager.m b/ios/components/ARGeosManager.m index d5d7d9e..2410882 100644 --- a/ios/components/ARGeosManager.m +++ b/ios/components/ARGeosManager.m @@ -9,79 +9,23 @@ #import "ARGeosManager.h" #import "RCTARKitNodes.h" -@implementation ARGeosManager - -RCT_EXPORT_MODULE() - - -RCT_EXPORT_METHOD(addBox:(SCNBox *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject ) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} - -RCT_EXPORT_METHOD(addGroup:(id)bla node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} -RCT_EXPORT_METHOD(addSphere:(SCNSphere *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} - -RCT_EXPORT_METHOD(addCylinder:(SCNCylinder *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} - -RCT_EXPORT_METHOD(addCone:(SCNCone *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} -RCT_EXPORT_METHOD(addPyramid:(SCNPyramid *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} +@implementation ARGeosManager -RCT_EXPORT_METHOD(addTube:(SCNTube *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} +RCT_EXPORT_MODULE() -RCT_EXPORT_METHOD(addTorus:(SCNTorus *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} -RCT_EXPORT_METHOD(addCapsule:(SCNCapsule *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} -RCT_EXPORT_METHOD(addPlane:(SCNPlane *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; +RCT_EXPORT_METHOD(mount:(SCNGeometry *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject ) { + [self addNodeWithGeometry:node geometry:geometry frame:frame parentId:parentId]; resolve(nil); } -RCT_EXPORT_METHOD(addShape:(SCNShape *)geometry node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - node.geometry = geometry; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; - resolve(nil); -} RCT_EXPORT_METHOD(addLight:(SCNLight *)light node:(SCNNode *)node frame:(NSString *)frame parentId:(NSString *)parentId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { node.light = light; - [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; + [self addNodeWithGeometry:node geometry:nil frame:frame parentId:parentId]; resolve(nil); } @@ -101,5 +45,21 @@ @implementation ARGeosManager } } +- (void)addNodeWithGeometry:(SCNNode *)node geometry:(SCNGeometry *)geometry frame:(NSString *)frame parentId:(NSString *)parentId { + if(geometry) { + node.geometry = geometry; + // usually, scenekit will use the same geometry for physicsshape, + // if you assign a physicsBody without a shape. + // but because we create SCNNode and the geometry indipendently, scenekit will know the geometry, so we add it here manually + if(node.physicsBody && ! node.physicsBody.physicsShape) { + node.physicsBody.physicsShape = [SCNPhysicsShape shapeWithGeometry:geometry options:nil]; + } + } + [[RCTARKitNodes sharedInstance] addNodeToScene:node inReferenceFrame:frame withParentId:parentId]; + +} + @end + +