nowActiveHotspots.every((hotspot) => { // Some special cases const gamestates = gamestateSelectors.forState(store.getState()); if (isActive({ cast: hotspot, gamestates })) { const { type, cursorShapeWhenActive, } = hotspot; if (wasMouseUpped && type >= 5 && type <= 8) { dispatch(gameActions.setOpenHandCursor()); return false; } else if (wasMouseDowned || wasMouseMoved) { if (type >= 5 && type <= 8) { const currentCursor = gameSelectors.morpheusCursor(store.getState()); if (currentCursor !== 10009) { dispatch(gameActions.setOpenHandCursor()); } return false; } else if (cursorShapeWhenActive) { dispatch(gameActions.setCursor(cursorShapeWhenActive)); return false; } } } return true; });
return (dispatch, getState) => { const scene3D = panoSelectors.panoScene3D(getState()); const canvas = panoSelectors.canvas(getState()); const { width, height } = gameSelectors.dimensions(getState()); const camera = createCamera({ width, height }); const renderer = createRenderer({ canvas, width, height }); positionCamera({ camera, vector3: { z: -0.09 }, }); startRenderLoop({ scene3D, camera, renderer, }); return Promise.resolve({ camera, renderer, }); };
return (dispatch, getState) => { const panoCastData = panoSelectors.panoCastData(getState()); if (panoCastData) { const { width, height } = gameSelectors.dimensions(getState()); const nextStartAngle = sceneSelectors.nextSceneStartAngle(getState()); const { fileName } = panoCastData; const asset = getAssetUrl(`${fileName}.png`); const geometries = createGeometries(); const { material, promise: promiseMaterial } = createMaterial(asset); const object3D = createObject3D({ material, geometries, startAngle: nextStartAngle, }); const scene3D = createScene(object3D); return promiseMaterial .then(() => ({ object3D, scene3D, canvas: createCanvas({ width, height }), })); } return Promise.resolve(); };
function updateState({ clientX, clientY }) { const state = store.getState(); const inputEnabled = inputSelectors.enabled(state); if (!inputEnabled) { return; } const location = gameSelectors.location(state); const hotspots = castSelectorForScene.special.hotspotData(state); const isCurrent = sceneSelectors.currentSceneData(state) === scene; const isExiting = castSelectorForScene.isExiting(state); const acceptsMouseEvents = isCurrent && !isExiting; if (!acceptsMouseEvents) { return; } const nowActiveHotspots = []; const left = clientX - location.x; const top = clientY - location.y; // Update cursor location dispatch(gameActions.setCursorLocation({ top, left })); const newWidth = gameSelectors.width(store.getState()); const newHeight = gameSelectors.height(store.getState()); if (width !== newWidth || height !== newHeight) { width = newWidth; height = newHeight; const onScreenAspectRatio = newWidth / newHeight; if (onScreenAspectRatio > ORIGINAL_ASPECT_RATIO) { const adjustedHeight = width / ORIGINAL_ASPECT_RATIO; clipHeight = adjustedHeight - height; clipWidth = 0; widthScaler = width / ORIGINAL_WIDTH; heightScaler = adjustedHeight / ORIGINAL_HEIGHT; } else { const adjustedWidth = height * ORIGINAL_ASPECT_RATIO; clipWidth = adjustedWidth - width; clipHeight = 0; widthScaler = adjustedWidth / ORIGINAL_WIDTH; heightScaler = height / ORIGINAL_HEIGHT; } } const adjustedClickPos = { top: (top + (clipHeight / 2)) / heightScaler, left: (left + (clipWidth / 2)) / widthScaler, }; each(hotspots, (hotspot) => { const { rectTop, rectBottom, rectLeft, rectRight, } = hotspot; if (adjustedClickPos.top > rectTop && adjustedClickPos.top < rectBottom && adjustedClickPos.left > rectLeft && adjustedClickPos.left < rectRight) { nowActiveHotspots.push(hotspot); } }); // Update our state // logger.info('Handling mouse event', JSON.stringify({ // nowActiveHotspots, // wasMouseUpped, // wasMouseMoved, // wasMouseDowned, // adjustedClickPos, // originalClickPos: { // top, // left, // }, // }, null, 2)); // Events for hotspots we have left handleHotspotDispatches({ type: 'MouseOver', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: nowActiveHotspots, }); handleHotspotDispatches({ type: 'MouseLeave', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: difference(wasActiveHotspots, nowActiveHotspots), }); // Events for hotspots we have entered handleHotspotDispatches({ type: 'MouseEnter', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: difference(nowActiveHotspots, wasActiveHotspots), }); // User initiated event inside a hotspot so could be valid if (!mouseDown && wasMouseDowned && nowActiveHotspots.length) { mouseDown = true; handleHotspotDispatches({ type: 'MouseDown', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: nowActiveHotspots, }); } if (wasMouseMoved) { handleHotspotDispatches({ type: 'MouseMove', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: nowActiveHotspots, }); } if (wasMouseMoved && mouseDown) { handleHotspotDispatches({ type: 'MouseStillDown', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: nowActiveHotspots, }); } // User pressed and released mouse button inside a valid hotspot // TODO: debounce?? if (wasMouseUpped && nowActiveHotspots.length) { mouseDown = false; handleHotspotDispatches({ type: 'MouseUp', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: nowActiveHotspots, }); handleHotspotDispatches({ type: 'MouseClick', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: nowActiveHotspots, }); } handleHotspotDispatches({ type: 'MouseNone', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: difference(hotspots, nowActiveHotspots), }); handleHotspotDispatches({ type: 'Always', top: adjustedClickPos.top, left: adjustedClickPos.left, hotspots: hotspots .filter(h => h.castId === 0), }); nowActiveHotspots.every((hotspot) => { // Some special cases const gamestates = gamestateSelectors.forState(store.getState()); if (isActive({ cast: hotspot, gamestates })) { const { type, cursorShapeWhenActive, } = hotspot; if (wasMouseUpped && type >= 5 && type <= 8) { dispatch(gameActions.setOpenHandCursor()); return false; } else if (wasMouseDowned || wasMouseMoved) { if (type >= 5 && type <= 8) { const currentCursor = gameSelectors.morpheusCursor(store.getState()); if (currentCursor !== 10009) { dispatch(gameActions.setOpenHandCursor()); } return false; } else if (cursorShapeWhenActive) { dispatch(gameActions.setCursor(cursorShapeWhenActive)); return false; } } } return true; }); wasActiveHotspots = nowActiveHotspots; wasMouseMoved = false; wasMouseUpped = false; wasMouseDowned = false; dispatch(castActionsForScene.special.update(scene)); }