From 24178b72fb8c854305f524ef694810e9625a8073 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 21 Apr 2015 21:55:52 -0700 Subject: [PATCH] Use lobby.js as starting point for avatarSelector.js --- examples/avatarSelector.js | 400 +++++++++++++++++++++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 examples/avatarSelector.js diff --git a/examples/avatarSelector.js b/examples/avatarSelector.js new file mode 100644 index 0000000000..41d6abbe2b --- /dev/null +++ b/examples/avatarSelector.js @@ -0,0 +1,400 @@ +// +// avatarSelector.js +// examples +// +// Created by David Rowe on 21 Apr 2015. +// Copyright 2015 High Fidelity, Inc. +// +// Based on lobby.js created by Stephen Birarda on 17 Oct 2014. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var panelWall = false; +var orbShell = false; +var descriptionText = false; +var showText = false; + +// used for formating the description text, in meters +var textWidth = 4; +var textHeight = .5; +var numberOfLines = 2; +var textMargin = 0.0625; +var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines; + +var avatarStickPosition = {}; + +var orbNaturalExtentsMin = { x: -1.230354, y: -1.22077, z: -1.210487 }; +var orbNaturalExtentsMax = { x: 1.230353, y: 1.229819, z: 1.210487 }; +var panelsNaturalExtentsMin = { x: -1.223182, y: -0.348487, z: 0.0451369 }; +var panelsNaturalExtentsMax = { x: 1.223039, y: 0.602978, z: 1.224298 }; + +var orbNaturalDimensions = Vec3.subtract(orbNaturalExtentsMax, orbNaturalExtentsMin); +var panelsNaturalDimensions = Vec3.subtract(panelsNaturalExtentsMax, panelsNaturalExtentsMin); + +var SCALING_FACTOR = 10; +var orbDimensions = Vec3.multiply(orbNaturalDimensions, SCALING_FACTOR); +var panelsDimensions = Vec3.multiply(panelsNaturalDimensions, SCALING_FACTOR); + +var orbNaturalCenter = Vec3.sum(orbNaturalExtentsMin, Vec3.multiply(orbNaturalDimensions, 0.5)); +var panelsNaturalCenter = Vec3.sum(panelsNaturalExtentsMin, Vec3.multiply(panelsNaturalDimensions, 0.5)); +var orbCenter = Vec3.multiply(orbNaturalCenter, SCALING_FACTOR); +var panelsCenter = Vec3.multiply(panelsNaturalCenter, SCALING_FACTOR); +var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter); + +var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8 }; + +var LOBBY_PANEL_WALL_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/PanelWallForInterface.fbx"; +var LOBBY_BLANK_PANEL_TEXTURE_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Texture.jpg"; +var LOBBY_SHELL_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/LobbyShellForInterface.fbx"; + +var droneSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.stereo.raw") +var currentDrone = null; + +var latinSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.stereo.raw") +var latinInjector = null; +var elevatorSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.stereo.raw") +var elevatorInjector = null; +var currentMuzakInjector = null; +var currentSound = null; + +function textOverlayPosition() { + var TEXT_DISTANCE_OUT = 6; + var TEXT_DISTANCE_DOWN = -2; + return Vec3.sum(Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), TEXT_DISTANCE_OUT)), + Vec3.multiply(Quat.getUp(Camera.orientation), TEXT_DISTANCE_DOWN)); +} + +var panelPlaceOrder = [ + 7, 8, 9, 10, 11, 12, 13, + 0, 1, 2, 3, 4, 5, 6, + 14, 15, 16, 17, 18, 19, 20 +]; + +// place index is 0-based +function placeIndexToPanelIndex(placeIndex) { + return panelPlaceOrder.indexOf(placeIndex) + 1; +} + +// Panel index is 1-based +function panelIndexToPlaceIndex(panelIndex) { + return panelPlaceOrder[panelIndex - 1]; +} + +var MAX_NUM_PANELS = 21; +var DRONE_VOLUME = 0.3; + +function drawLobby() { + if (!panelWall) { + print("Adding overlays for the lobby panel wall and orb shell."); + + var cameraEuler = Quat.safeEulerAngles(Camera.orientation); + var towardsMe = Quat.angleAxis(cameraEuler.y + 180, { x: 0, y: 1, z: 0 }); + + var orbPosition = Vec3.sum(Camera.position, Vec3.multiplyQbyV(towardsMe, ORB_SHIFT)); + + var panelWallProps = { + url: LOBBY_PANEL_WALL_URL, + position: Vec3.sum(orbPosition, Vec3.multiplyQbyV(towardsMe, panelsCenterShift)), + rotation: towardsMe, + dimensions: panelsDimensions + }; + + var orbShellProps = { + url: LOBBY_SHELL_URL, + position: orbPosition, + rotation: towardsMe, + dimensions: orbDimensions, + ignoreRayIntersection: true + }; + + var windowDimensions = Controller.getViewportDimensions(); + + var descriptionTextProps = { + position: textOverlayPosition(), + dimensions: { x: textWidth, y: textHeight }, + backgroundColor: { red: 0, green: 0, blue: 0 }, + color: { red: 255, green: 255, blue: 255 }, + topMargin: textMargin, + leftMargin: textMargin, + bottomMargin: textMargin, + rightMargin: textMargin, + text: "", + lineHeight: lineHeight, + alpha: 0.9, + backgroundAlpha: 0.9, + ignoreRayIntersection: true, + visible: false, + isFacingAvatar: true + }; + + avatarStickPosition = MyAvatar.position; + + panelWall = Overlays.addOverlay("model", panelWallProps); + orbShell = Overlays.addOverlay("model", orbShellProps); + descriptionText = Overlays.addOverlay("text3d", descriptionTextProps); + + if (droneSound.downloaded) { + // start the drone sound + if (!currentDrone) { + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + } else { + currentDrone.restart(); + } + } + + // start one of our muzak sounds + playRandomMuzak(); + } +} + +var places = {}; + +function changeLobbyTextures() { + var req = new XMLHttpRequest(); + req.open("GET", "https://metaverse.highfidelity.com/api/v1/places?limit=21", false); + req.send(); + + places = JSON.parse(req.responseText).data.places; + + var NUM_PANELS = places.length; + + var textureProp = { + textures: {} + }; + + for (var j = 0; j < NUM_PANELS; j++) { + var panelIndex = placeIndexToPanelIndex(j); + textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby; + }; + + Overlays.editOverlay(panelWall, textureProp); +} + +var MUZAK_VOLUME = 0.1; + +function playCurrentSound(secondOffset) { + if (currentSound == latinSound) { + if (!latinInjector) { + latinInjector = Audio.playSound(latinSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + } else { + latinInjector.restart(); + } + + currentMuzakInjector = latinInjector; + } else if (currentSound == elevatorSound) { + if (!elevatorInjector) { + elevatorInjector = Audio.playSound(elevatorSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + } else { + elevatorInjector.restart(); + } + + currentMuzakInjector = elevatorInjector; + } +} + +function playNextMuzak() { + if (panelWall) { + if (currentSound == latinSound) { + if (elevatorSound.downloaded) { + currentSound = elevatorSound; + } + } else if (currentSound == elevatorSound) { + if (latinSound.downloaded) { + currentSound = latinSound; + } + } + + playCurrentSound(0); + } +} + +function playRandomMuzak() { + currentSound = null; + + if (latinSound.downloaded && elevatorSound.downloaded) { + currentSound = Math.random() < 0.5 ? latinSound : elevatorSound; + } else if (latinSound.downloaded) { + currentSound = latinSound; + } else if (elevatorSound.downloaded) { + currentSound = elevatorSound; + } + + if (currentSound) { + // pick a random number of seconds from 0-10 to offset the muzak + var secondOffset = Math.random() * 10; + + playCurrentSound(secondOffset); + } else { + currentMuzakInjector = null; + } +} + +function cleanupLobby() { + toggleEnvironmentRendering(true); + + // for each of the 21 placeholder textures, set them back to default so the cached model doesn't have changed textures + var panelTexturesReset = {}; + panelTexturesReset["textures"] = {}; + + for (var j = 0; j < MAX_NUM_PANELS; j++) { + panelTexturesReset["textures"]["file" + (j + 1)] = LOBBY_BLANK_PANEL_TEXTURE_URL; + }; + + Overlays.editOverlay(panelWall, panelTexturesReset); + + Overlays.deleteOverlay(panelWall); + Overlays.deleteOverlay(orbShell); + Overlays.deleteOverlay(descriptionText); + + panelWall = false; + orbShell = false; + + if (currentDrone) { + currentDrone.stop(); + currentDrone = null + } + + if (currentMuzakInjector) { + currentMuzakInjector.stop(); + currentMuzakInjector = null; + } + + places = {}; + +} + +function actionStartEvent(event) { + if (panelWall) { + // we've got an action event and our panel wall is up + // check if we hit a panel and if we should jump there + var result = Overlays.findRayIntersection(event.actionRay); + if (result.intersects && result.overlayID == panelWall) { + + var panelName = result.extraInfo; + + var panelStringIndex = panelName.indexOf("Panel"); + if (panelStringIndex != -1) { + var panelIndex = parseInt(panelName.slice(5)); + var placeIndex = panelIndexToPlaceIndex(panelIndex); + if (placeIndex < places.length) { + var actionPlace = places[placeIndex]; + + print("Jumping to " + actionPlace.name + " at " + actionPlace.address + + " after click on panel " + panelIndex + " with place index " + placeIndex); + + Window.location = actionPlace.address; + maybeCleanupLobby(); + } + } + } + } +} + +function backStartEvent() { + if (!panelWall) { + toggleEnvironmentRendering(false); + drawLobby(); + changeLobbyTextures(); + } else { + cleanupLobby(); + } +} + +var CLEANUP_EPSILON_DISTANCE = 0.05; + +function maybeCleanupLobby() { + if (panelWall && Vec3.length(Vec3.subtract(avatarStickPosition, MyAvatar.position)) > CLEANUP_EPSILON_DISTANCE) { + cleanupLobby(); + } +} + +function toggleEnvironmentRendering(shouldRender) { + Scene.shouldRenderAvatars = shouldRender; + Scene.shouldRenderEntities = shouldRender; +} + +function handleLookAt(pickRay) { + if (panelWall && descriptionText) { + // we've got an action event and our panel wall is up + // check if we hit a panel and if we should jump there + var result = Overlays.findRayIntersection(pickRay); + if (result.intersects && result.overlayID == panelWall) { + var panelName = result.extraInfo; + var panelStringIndex = panelName.indexOf("Panel"); + if (panelStringIndex != -1) { + var panelIndex = parseInt(panelName.slice(5)); + var placeIndex = panelIndexToPlaceIndex(panelIndex); + if (placeIndex < places.length) { + var actionPlace = places[placeIndex]; + + if (actionPlace.description == "") { + Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText }); + } else { + // handle line wrapping + var allWords = actionPlace.description.split(" "); + var currentGoodLine = ""; + var currentTestLine = ""; + var formatedDescription = ""; + var wordsFormated = 0; + var currentTestWord = 0; + var wordsOnLine = 0; + while (wordsFormated < allWords.length) { + // first add the "next word" to the line and test it. + currentTestLine = currentGoodLine; + if (wordsOnLine > 0) { + currentTestLine += " " + allWords[currentTestWord]; + } else { + currentTestLine = allWords[currentTestWord]; + } + var lineLength = Overlays.textSize(descriptionText, currentTestLine).width; + if (lineLength < textWidth || wordsOnLine == 0) { + wordsFormated++; + currentTestWord++; + wordsOnLine++; + currentGoodLine = currentTestLine; + } else { + formatedDescription += currentGoodLine + "\n"; + wordsOnLine = 0; + currentGoodLine = ""; + currentTestLine = ""; + } + } + formatedDescription += currentGoodLine; + Overlays.editOverlay(descriptionText, { text: formatedDescription, visible: showText }); + } + } else { + Overlays.editOverlay(descriptionText, { text: "", visible: false }); + } + } + } + } +} + +function update(deltaTime) { + maybeCleanupLobby(); + if (panelWall) { + Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); + + // if the reticle is up then we may need to play the next muzak + if (currentMuzakInjector && !currentMuzakInjector.isPlaying) { + playNextMuzak(); + } + } +} + +function mouseMoveEvent(event) { + if (panelWall) { + var pickRay = Camera.computePickRay(event.x, event.y); + handleLookAt(pickRay); + } +} + +Controller.actionStartEvent.connect(actionStartEvent); +Controller.backStartEvent.connect(backStartEvent); +Script.update.connect(update); +Script.scriptEnding.connect(maybeCleanupLobby); +Controller.mouseMoveEvent.connect(mouseMoveEvent);