diff --git a/React360/React360.js b/React360/React360.js index 3fb61f7b2..2914328c7 100755 --- a/React360/React360.js +++ b/React360/React360.js @@ -12,6 +12,7 @@ import bundleFromLocation from './js/bundleFromLocation'; import createRootView from './js/createRootView'; import Location from './js/Compositor/Location'; +import * as Math from './js/Utils/Math'; import Module from './js/Modules/Module'; import RCTBaseView from './js/Views/BaseView'; import ReactInstance from './js/ReactInstance'; @@ -27,6 +28,7 @@ import {ReactNativeContext} from './js/ReactNativeContext'; export {bundleFromLocation}; export {createRootView}; export {Location}; +export {Math}; export {Module}; export {RCTBaseView}; export {ReactNativeContext}; diff --git a/React360/js/ReactInstance.js b/React360/js/ReactInstance.js index 314492e93..0a10ac222 100755 --- a/React360/js/ReactInstance.js +++ b/React360/js/ReactInstance.js @@ -65,6 +65,7 @@ export type React360Options = { customOverlay?: OverlayInterface, customViews?: Array, executor?: ReactExecutor, + frame?: number => mixed, fullScreen?: boolean, nativeModules?: Array, }; @@ -84,6 +85,7 @@ export default class ReactInstance { _events: Array; _focused2DSurface: null | Surface; _frameData: ?VRFrameData; + _frameHook: ?(number) => mixed; _lastFrameTime: number; _looping: boolean; _needsResize: boolean; @@ -126,6 +128,7 @@ export default class ReactInstance { this._nextFrame = null; this._lastFrameTime = 0; this._focused2DSurface = null; + this._frameHook = options.frame; if (options.fullScreen) { parent.style.position = 'fixed'; @@ -315,6 +318,9 @@ export default class ReactInstance { audioModule._setCameraParameters(this._cameraPosition, this._cameraQuat); audioModule.frame(delta); } + if (this._frameHook) { + this._frameHook(frameStart); + } this.compositor.frame(delta); const cursorVis = this.compositor.getCursorVisibility(); if ( @@ -529,4 +535,20 @@ export default class ReactInstance { getAssetURL(localPath: string): string { return this._assetRoot + localPath; } + + /** + * Get the current camera position as a 3-dimensional vector. Changing the + * values of this array can have unexpected effects. + */ + getCameraPosition(): Vec3 { + return this._cameraPosition; + } + + /** + * Get the current camera rotation as a quaternion. Changing the values of + * this array can have unexpected effects. + */ + getCameraQuaternion(): Quaternion { + return this._cameraQuat; + } } diff --git a/Samples/HeadlockedSurfaces/client.js b/Samples/HeadlockedSurfaces/client.js new file mode 100755 index 000000000..be77c846a --- /dev/null +++ b/Samples/HeadlockedSurfaces/client.js @@ -0,0 +1,38 @@ +import {Math as VRMath, ReactInstance, Surface} from 'react-360-web'; + +function init(bundle, parent, options = {}) { + const horizontalPanel = new Surface(300, 300, Surface.SurfaceShape.Flat); + const hvPanel = new Surface(300, 300, Surface.SurfaceShape.Flat); + + horizontalPanel.setAngle(0, -0.5); + + const cameraDirection = [0, 0, -1]; + + const r360 = new ReactInstance(bundle, parent, { + fullScreen: true, + frame: () => { + const cameraQuat = r360.getCameraQuaternion(); + cameraDirection[0] = 0; + cameraDirection[1] = 0; + cameraDirection[2] = -1; + // cameraDirection will point out from the view of the camera, + // we can use it to compute surface angles + VRMath.rotateByQuaternion(cameraDirection, cameraQuat); + const cx = cameraDirection[0]; + const cy = cameraDirection[1]; + const cz = cameraDirection[2]; + const horizAngle = Math.atan2(cx, -cz); + const vertAngle = Math.asin(cy / Math.sqrt(cx * cx + cy * cy + cz * cz)); + horizontalPanel.setAngle(horizAngle, -0.5); + hvPanel.setAngle(horizAngle, vertAngle); + }, + ...options, + }); + + r360.renderToSurface(r360.createRoot('HorizontalPanel'), horizontalPanel); + r360.renderToSurface(r360.createRoot('HVPanel'), hvPanel); + + r360.compositor.setBackground('./static_assets/360_world.jpg'); +} + +window.React360 = {init}; diff --git a/Samples/HeadlockedSurfaces/index.html b/Samples/HeadlockedSurfaces/index.html new file mode 100644 index 000000000..42ea76542 --- /dev/null +++ b/Samples/HeadlockedSurfaces/index.html @@ -0,0 +1,17 @@ + + + Headlocked Surfaces Sample + + + + +
+ + + + diff --git a/Samples/HeadlockedSurfaces/index.js b/Samples/HeadlockedSurfaces/index.js new file mode 100755 index 000000000..03ff75eb9 --- /dev/null +++ b/Samples/HeadlockedSurfaces/index.js @@ -0,0 +1,32 @@ +import * as React from 'react'; +import {AppRegistry, StyleSheet, Text, View} from 'react-360'; + +const HorizontalPanel = () => ( + + {'Follows Horizontally'} + +); + +const HVPanel = () => ( + + {'Follows Horizontally\nand Vertically'} + +); + +const styles = StyleSheet.create({ + panel: { + width: 300, + height: 300, + backgroundColor: 'rgba(255, 255, 255, 0.8)', + justifyContent: 'center', + alignItems: 'center', + }, + panelText: { + color: '#000000', + fontSize: 30, + textAlign: 'center', + } +}); + +AppRegistry.registerComponent('HorizontalPanel', () => HorizontalPanel); +AppRegistry.registerComponent('HVPanel', () => HVPanel);