mirror of
https://github.com/overte-org/overte.git
synced 2025-06-22 11:21:13 +02:00
code) and into shared.js (for JS code). Modify references to the metaverse server from constants to references to the new central definitions.
416 lines
14 KiB
JavaScript
416 lines
14 KiB
JavaScript
//
|
|
// 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
|
|
];
|
|
|
|
// Avatar index is 0-based
|
|
function avatarIndexToPanelIndex(avatarIndex) {
|
|
return panelPlaceOrder.indexOf(avatarIndex) + 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 avatar selector 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 avatars = {};
|
|
|
|
function changeLobbyTextures() {
|
|
var req = new XMLHttpRequest();
|
|
req.open("GET", URLs.METAVERSE_URL + "/api/v1/marketplace?category=head+%26+body&limit=21", false);
|
|
req.send(); // Data returned is randomized.
|
|
|
|
avatars = JSON.parse(req.responseText).data.items;
|
|
|
|
var NUM_PANELS = avatars.length;
|
|
|
|
var textureProp = {
|
|
textures: {}
|
|
};
|
|
|
|
for (var j = 0; j < NUM_PANELS; j++) {
|
|
var panelIndex = avatarIndexToPanelIndex(j);
|
|
textureProp["textures"]["file" + panelIndex] = avatars[j].preview_url;
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
avatars = {};
|
|
|
|
}
|
|
|
|
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.subMeshName + '';
|
|
|
|
var panelStringIndex = panelName.indexOf("Panel");
|
|
if (panelStringIndex != -1) {
|
|
var panelIndex = parseInt(panelName.slice(5));
|
|
var avatarIndex = panelIndexToPlaceIndex(panelIndex);
|
|
if (avatarIndex < avatars.length) {
|
|
var actionPlace = avatars[avatarIndex];
|
|
|
|
print("Changing avatar to " + actionPlace.name
|
|
+ " after click on panel " + panelIndex + " with avatar index " + avatarIndex);
|
|
|
|
MyAvatar.useFullAvatarURL(actionPlace.content_url);
|
|
|
|
maybeCleanupLobby();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var control = false;
|
|
|
|
function keyPressEvent(event) {
|
|
if (event.text === "CONTROL") {
|
|
control = true;
|
|
}
|
|
|
|
if (control && event.text === "a") {
|
|
if (!panelWall) {
|
|
toggleEnvironmentRendering(false);
|
|
drawLobby();
|
|
changeLobbyTextures();
|
|
} else {
|
|
cleanupLobby();
|
|
}
|
|
}
|
|
}
|
|
|
|
function keyReleaseEvent(event) {
|
|
if (event.text === "CONTROL") {
|
|
control = false;
|
|
}
|
|
}
|
|
|
|
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.subMeshName + '';
|
|
var panelStringIndex = panelName.indexOf("Panel");
|
|
if (panelStringIndex != -1) {
|
|
var panelIndex = parseInt(panelName.slice(5));
|
|
var avatarIndex = panelIndexToPlaceIndex(panelIndex);
|
|
if (avatarIndex < avatars.length) {
|
|
var actionPlace = avatars[avatarIndex];
|
|
|
|
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.playing) {
|
|
playNextMuzak();
|
|
}
|
|
}
|
|
}
|
|
|
|
function mouseMoveEvent(event) {
|
|
if (panelWall) {
|
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
|
handleLookAt(pickRay);
|
|
}
|
|
}
|
|
|
|
Controller.actionStartEvent.connect(actionStartEvent);
|
|
Controller.keyPressEvent.connect(keyPressEvent);
|
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
|
Script.update.connect(update);
|
|
Script.scriptEnding.connect(maybeCleanupLobby);
|
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|