mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 17:24:24 +02:00
forgot to copy a folder in to the local repo
This commit is contained in:
parent
024dfbf8b7
commit
935d152617
8 changed files with 1505 additions and 2 deletions
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// Simplified Nametag
|
||||||
|
// defaultLocalEntityProps.js
|
||||||
|
// Created by Milad Nazeri on 2019-03-09
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// Base properties for the Local Entities
|
||||||
|
//
|
||||||
|
|
||||||
|
var localEntityProps = {
|
||||||
|
dimensions: [1, 0.1, 0],
|
||||||
|
type: "Text",
|
||||||
|
lineHeight: 0.1,
|
||||||
|
textColor: "#ffffff",
|
||||||
|
textAlpha: 1.0,
|
||||||
|
backgroundColor: "#2d2d2d",
|
||||||
|
backgroundAlpha: 0.6,
|
||||||
|
billboardMode: "full",
|
||||||
|
lifetime: 3,
|
||||||
|
canCastShadow: true
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = localEntityProps;
|
|
@ -0,0 +1,154 @@
|
||||||
|
//
|
||||||
|
// Simplified Nametag
|
||||||
|
// entityMaker.js
|
||||||
|
// Created by Milad Nazeri on 2019-02-19
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// A helper library to make entities
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
Script.require('./objectAssign.js');
|
||||||
|
|
||||||
|
function EntityMaker(type) {
|
||||||
|
this.properties = {};
|
||||||
|
this.cache = {};
|
||||||
|
this.id = null;
|
||||||
|
this.created = null;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START API
|
||||||
|
// *************************************
|
||||||
|
// #region API
|
||||||
|
|
||||||
|
|
||||||
|
// Add properties to the cache / temporary storage
|
||||||
|
function add(props){
|
||||||
|
// You can either add an object of props or 2 arguments as key and value
|
||||||
|
if (arguments.length === 2) {
|
||||||
|
var property = arguments[0];
|
||||||
|
var value = arguments[1];
|
||||||
|
props = {};
|
||||||
|
props[property] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.properties = Object.assign({}, this.properties, props);
|
||||||
|
this.cache = Object.assign({}, this.cache, this.properties);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sends the current temporary stroage to edit the entity
|
||||||
|
function sync(){
|
||||||
|
Entities.editEntity(this.id, this.properties);
|
||||||
|
this.properties = {};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Immediately edit the entity with the properties given
|
||||||
|
function edit(props){
|
||||||
|
if (arguments.length === 2) {
|
||||||
|
var property = arguments[0];
|
||||||
|
var value = arguments[1];
|
||||||
|
props = {};
|
||||||
|
props[property] = value;
|
||||||
|
}
|
||||||
|
this.properties = Object.assign({}, this.properties, props);
|
||||||
|
this.cache = Object.assign({}, this.cache, this.properties);
|
||||||
|
this.sync();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get a property either from the cache or by querying the entity directly
|
||||||
|
function get(propertyKeys, queryEntity){
|
||||||
|
if (queryEntity && typeof propertyKeys === 'string') {
|
||||||
|
var propertyValue = Entities.getEntityProperties(this.id, propertyKeys)[propertyKeys];
|
||||||
|
this.properties[propertyKeys] = propertyValue;
|
||||||
|
this.cache = Object.assign({}, this.cache, this.properties);
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryEntity && Array.isArray(propertyKeys)) {
|
||||||
|
var entityProps = Entities.getEntityProperties(this.id, propertyKeys);
|
||||||
|
for (var prop in entityProps) {
|
||||||
|
if (propertyKeys.indexOf(prop) === -1) {
|
||||||
|
delete entityProps[prop];
|
||||||
|
} else {
|
||||||
|
this.properties[prop] = entityProps[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entityProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(propertyKeys)) {
|
||||||
|
var recombinedProps = {};
|
||||||
|
propertyKeys.forEach(function (prop) {
|
||||||
|
recombinedProps[prop] = this.cache[prop];
|
||||||
|
}, this);
|
||||||
|
return recombinedProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.cache[propertyKeys];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Show the entity
|
||||||
|
function show(){
|
||||||
|
this.edit({ visible: true });
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hide the enity
|
||||||
|
function hide(){
|
||||||
|
this.edit({ visible: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add an entity if it isn't created
|
||||||
|
function create(clearPropertiesAfter){
|
||||||
|
this.id = Entities.addEntity(this.properties, this.type);
|
||||||
|
if (clearPropertiesAfter) {
|
||||||
|
this.properties = {};
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Delete the entity
|
||||||
|
function destroy(){
|
||||||
|
Entities.deleteEntity(this.id);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END API
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
EntityMaker.prototype = {
|
||||||
|
add: add,
|
||||||
|
sync: sync,
|
||||||
|
edit: edit,
|
||||||
|
get: get,
|
||||||
|
show: show,
|
||||||
|
hide: hide,
|
||||||
|
create: create,
|
||||||
|
destroy: destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = EntityMaker;
|
|
@ -0,0 +1,668 @@
|
||||||
|
//
|
||||||
|
// Simplified Nametag
|
||||||
|
// nameTagListManager.js
|
||||||
|
// Created by Milad Nazeri on 2019-03-09
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// Helps manage the list of avatars added to the nametag list
|
||||||
|
//
|
||||||
|
|
||||||
|
var ON = 'ON';
|
||||||
|
var OFF = 'OFF';
|
||||||
|
var DEBUG_ON = true;
|
||||||
|
var DEBUG_OFF = false;
|
||||||
|
var log = Script.require(
|
||||||
|
'https://hifi-content.s3.amazonaws.com/milad/ROLC/d/ROLC_High-Fidelity/02_Organize/O_Projects/Repos/hifi-content/developerTools/sharedLibraries/easyLog/easyLog.js?'
|
||||||
|
+ Date.now())(DEBUG_OFF, 'nameTagListManager.js');
|
||||||
|
|
||||||
|
|
||||||
|
var EntityMaker = Script.require('./entityMaker.js?' + Date.now());
|
||||||
|
var entityProps = Script.require('./defaultLocalEntityProps.js?' + Date.now());
|
||||||
|
var textHelper = new (Script.require('./textHelper.js?' + Date.now()));
|
||||||
|
var X = 0;
|
||||||
|
var Y = 1;
|
||||||
|
var Z = 2;
|
||||||
|
var HALF = 0.5;
|
||||||
|
var CLEAR_ENTITY_EDIT_PROPS = true;
|
||||||
|
var MILISECONDS_IN_SECOND = 1000;
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START UTILTY
|
||||||
|
// *************************************
|
||||||
|
// #region UTILTY
|
||||||
|
|
||||||
|
|
||||||
|
// Properties to give new avatars added to the list
|
||||||
|
function NewAvatarProps() {
|
||||||
|
return {
|
||||||
|
avatarInfo: null,
|
||||||
|
previousDistance: null,
|
||||||
|
currentDistance: null,
|
||||||
|
initialDistance: null,
|
||||||
|
initialDimensions: null,
|
||||||
|
previousName: null,
|
||||||
|
timeoutStarted: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Makes sure clear interval exists before changing
|
||||||
|
function maybeClearInterval() {
|
||||||
|
if (_this.redrawTimeout) {
|
||||||
|
Script.clearInterval(_this.redrawTimeout);
|
||||||
|
_this.redrawTimeout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate our initial properties for the nametag
|
||||||
|
var Z_SIZE = 0.01;
|
||||||
|
var LINE_HEIGHT_SCALER = 0.99;
|
||||||
|
var DISTANCE_SCALER_ON = 0.35;
|
||||||
|
var DISTANCE_SCALER_ALWAYS_ON = 0.50;
|
||||||
|
var distanceScaler = DISTANCE_SCALER_ON;
|
||||||
|
var userScaler = 1.0;
|
||||||
|
var DEFAULT_LINE_HEIGHT = entityProps.lineHeight;
|
||||||
|
function calculateInitialProperties(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
var avatarInfo = avatar.avatarInfo;
|
||||||
|
|
||||||
|
var adjustedScaler = null;
|
||||||
|
var distance = null;
|
||||||
|
var dimensions = null;
|
||||||
|
var lineHeight = null;
|
||||||
|
var scaledDimensions = null;
|
||||||
|
var name = null;
|
||||||
|
|
||||||
|
// Handle if we are asking for the main or sub properties
|
||||||
|
name = avatarInfo.displayName;
|
||||||
|
|
||||||
|
// Use the text helper to calculate what our dimensions for the text box should be
|
||||||
|
textHelper
|
||||||
|
.setText(name)
|
||||||
|
.setLineHeight(DEFAULT_LINE_HEIGHT);
|
||||||
|
|
||||||
|
// Calculate the distance from the camera to the target avatar
|
||||||
|
distance = getDistance(uuid);
|
||||||
|
|
||||||
|
// Adjust the distance by the distance scaler
|
||||||
|
distanceScaler = avatarNametagMode === "on" ? DISTANCE_SCALER_ON : DISTANCE_SCALER_ALWAYS_ON;
|
||||||
|
adjustedScaler = distance * distanceScaler;
|
||||||
|
// Get the new dimensions from the text helper
|
||||||
|
dimensions = [textHelper.getTotalTextLength(), DEFAULT_LINE_HEIGHT, Z_SIZE];
|
||||||
|
// Adjust the dimensions by the modified distance scaler
|
||||||
|
scaledDimensions = Vec3.multiply(dimensions, adjustedScaler);
|
||||||
|
|
||||||
|
// Adjust the lineheight to be the new scaled dimensions Y
|
||||||
|
lineHeight = scaledDimensions[Y] * LINE_HEIGHT_SCALER;
|
||||||
|
|
||||||
|
return {
|
||||||
|
distance: distance,
|
||||||
|
scaledDimensions: scaledDimensions,
|
||||||
|
lineHeight: lineHeight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Used in alwaysOn mode to show or hide if they reached the max radius
|
||||||
|
function showHide(uuid, type) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
var nametag = avatar.nametag;
|
||||||
|
|
||||||
|
if (type === "show") {
|
||||||
|
nametag.show();
|
||||||
|
} else {
|
||||||
|
nametag.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Go through the selected avatar list and see if any of the avatars need a redraw
|
||||||
|
function checkAllSelectedForRedraw() {
|
||||||
|
for (var avatar in _this.selectedAvatars) {
|
||||||
|
maybeRedraw(avatar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remake the nametags if the display name changes
|
||||||
|
function updateName(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
avatar.nametag.destroy();
|
||||||
|
|
||||||
|
avatar.nametag = new EntityMaker('local').add(entityProps);
|
||||||
|
|
||||||
|
makeNameTag(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the current data for an avatar.
|
||||||
|
function getAvatarData(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
var avatarInfo = avatar.avatarInfo;
|
||||||
|
|
||||||
|
var newAvatarInfo = AvatarManager.getAvatar(uuid);
|
||||||
|
// Save the username so it doesn't get overwritten when grabbing new avatarData
|
||||||
|
var combinedAvatarInfo = Object.assign({}, newAvatarInfo, {
|
||||||
|
username: avatarInfo === null ? null : avatarInfo.username
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now combine that avatar data with the main avatar object
|
||||||
|
_this.avatars[uuid] = Object.assign({}, avatar, { avatarInfo: combinedAvatarInfo });
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate the distance between the camera and the target avatar
|
||||||
|
function getDistance(uuid, checkAvatar, shouldSave) {
|
||||||
|
checkAvatar = checkAvatar || false;
|
||||||
|
shouldSave = shouldSave || true;
|
||||||
|
var eye = checkAvatar ? MyAvatar.position : Camera.position;
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
var avatarInfo = avatar.avatarInfo;
|
||||||
|
|
||||||
|
var target = avatarInfo.position;
|
||||||
|
|
||||||
|
var currentDistance = Vec3.distance(target, eye);
|
||||||
|
|
||||||
|
if (!checkAvatar && shouldSave) {
|
||||||
|
avatar.previousDistance = avatar.currentDistance;
|
||||||
|
avatar.currentDistance = currentDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check to see if we need to toggle our interval check because we went to 0 avatars
|
||||||
|
// or if we got our first avatar in the select list
|
||||||
|
function shouldToggleInterval() {
|
||||||
|
var currentNumberOfAvatarsSelected = Object.keys(_this.selectedAvatars).length;
|
||||||
|
|
||||||
|
if (currentNumberOfAvatarsSelected === 0 && _this.redrawTimeout) {
|
||||||
|
toggleInterval();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentNumberOfAvatarsSelected > 0 && !_this.redrawTimeout) {
|
||||||
|
toggleInterval();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Turn off and on the redraw check
|
||||||
|
var INTERVAL_CHECK_MS = 30;
|
||||||
|
function toggleInterval() {
|
||||||
|
if (_this.redrawTimeout) {
|
||||||
|
maybeClearInterval();
|
||||||
|
} else {
|
||||||
|
_this.redrawTimeout =
|
||||||
|
Script.setInterval(checkAllSelectedForRedraw, INTERVAL_CHECK_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// handle turning the peristenet mode on
|
||||||
|
function handleAlwaysOnMode(shouldTurnOnAlwaysOnMode) {
|
||||||
|
_this.reset();
|
||||||
|
if (shouldTurnOnAlwaysOnMode) {
|
||||||
|
AvatarManager
|
||||||
|
.getAvatarIdentifiers()
|
||||||
|
.forEach(function (avatar) {
|
||||||
|
if (avatar) {
|
||||||
|
add(avatar);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END UTILTY
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START Nametag
|
||||||
|
// *************************************
|
||||||
|
// #region Nametag
|
||||||
|
|
||||||
|
|
||||||
|
var _this = null;
|
||||||
|
function nameTagListManager() {
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
_this.avatars = {};
|
||||||
|
_this.selectedAvatars = {};
|
||||||
|
_this.redrawTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create or make visible either the sub or the main tag.
|
||||||
|
var REDRAW_TIMEOUT_AMOUNT_MS = 500;
|
||||||
|
var LEFT_MARGIN_SCALER = 0.15;
|
||||||
|
var RIGHT_MARGIN_SCALER = 0.10;
|
||||||
|
var TOP_MARGIN_SCALER = 0.07;
|
||||||
|
var BOTTOM_MARGIN_SCALER = 0.03;
|
||||||
|
var ABOVE_HEAD_OFFSET = 0.30;
|
||||||
|
var DISTANCE_SCALER_INTERPOLATION_OFFSET_ALWAYSON = 5;
|
||||||
|
var DISTANCE_SCALER_INTERPOLATION_OFFSET_ON = 10;
|
||||||
|
var maxDistance = MAX_RADIUS_IGNORE_METERS;
|
||||||
|
var onModeScalar = 0.55;
|
||||||
|
var alwaysOnModeScalar = -0.55;
|
||||||
|
function makeNameTag(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
var avatarInfo = avatar.avatarInfo;
|
||||||
|
var nametag = avatar.nametag;
|
||||||
|
|
||||||
|
// Make sure an anonymous name is covered before sending to calculate
|
||||||
|
|
||||||
|
avatarInfo.displayName = avatarInfo.displayName === "" ? "anonymous" : avatarInfo.displayName.trim();
|
||||||
|
avatar.previousName = avatarInfo.displayName;
|
||||||
|
|
||||||
|
// Returns back the properties we need based on what we are looking for and the distance from the avatar
|
||||||
|
var calculatedProps = calculateInitialProperties(uuid);
|
||||||
|
var distance = calculatedProps.distance;
|
||||||
|
var scaledDimensions = calculatedProps.scaledDimensions;
|
||||||
|
var lineHeight = calculatedProps.lineHeight;
|
||||||
|
|
||||||
|
// Capture the inital dimensions, distance, and displayName in case we need to redraw
|
||||||
|
avatar.previousDisplayName = avatarInfo.displayName;
|
||||||
|
avatar.initialDimensions = scaledDimensions;
|
||||||
|
avatar.initialDistance = distance;
|
||||||
|
var name = avatarInfo.displayName;
|
||||||
|
var parentID = uuid;
|
||||||
|
|
||||||
|
nametag.add("text", name);
|
||||||
|
|
||||||
|
// Multiply the new dimensions and line height with the user selected scaler
|
||||||
|
scaledDimensions = Vec3.multiply(scaledDimensions, userScaler);
|
||||||
|
|
||||||
|
maxDistance = avatarNametagMode === "on"
|
||||||
|
? MAX_ON_MODE_DISTANCE + DISTANCE_SCALER_INTERPOLATION_OFFSET_ON
|
||||||
|
: MAX_RADIUS_IGNORE_METERS + DISTANCE_SCALER_INTERPOLATION_OFFSET_ALWAYSON;
|
||||||
|
var finalScaler = (distance - maxDistance) / (MIN_DISTANCE - maxDistance);
|
||||||
|
|
||||||
|
var remainder = 1 - finalScaler;
|
||||||
|
var multipliedRemainderOn = remainder * onModeScalar;
|
||||||
|
var multipliedRemainderAlwaysOn = remainder * alwaysOnModeScalar;
|
||||||
|
finalScaler = avatarNametagMode === "on" ? finalScaler + multipliedRemainderOn : finalScaler + multipliedRemainderAlwaysOn;
|
||||||
|
|
||||||
|
scaledDimensions = Vec3.multiply(scaledDimensions, finalScaler);
|
||||||
|
|
||||||
|
lineHeight = scaledDimensions[Y] * LINE_HEIGHT_SCALER;
|
||||||
|
// Add some room for the margin by using lineHeight as a reference
|
||||||
|
scaledDimensions[X] += (lineHeight * LEFT_MARGIN_SCALER) + (lineHeight * RIGHT_MARGIN_SCALER);
|
||||||
|
scaledDimensions[Y] += (lineHeight * TOP_MARGIN_SCALER) + (lineHeight * BOTTOM_MARGIN_SCALER);
|
||||||
|
|
||||||
|
var scaledDimenionsYHalf = scaledDimensions[Y] * HALF;
|
||||||
|
var AvatarData = AvatarManager.getAvatar(uuid);
|
||||||
|
var headJointIndex = AvatarData.getJointIndex("Head");
|
||||||
|
var jointInObjectFrame = AvatarData.getAbsoluteJointTranslationInObjectFrame(headJointIndex);
|
||||||
|
var nameTagPosition = jointInObjectFrame.y + scaledDimenionsYHalf + ABOVE_HEAD_OFFSET;
|
||||||
|
var localPosition = [0, nameTagPosition, 0];
|
||||||
|
|
||||||
|
var visible = true;
|
||||||
|
if (avatarNametagMode === "alwaysOn") {
|
||||||
|
var currentDistance = getDistance(uuid, CHECK_AVATAR, false);
|
||||||
|
visible = currentDistance > MAX_RADIUS_IGNORE_METERS ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nametag
|
||||||
|
.add("leftMargin", lineHeight * LEFT_MARGIN_SCALER)
|
||||||
|
.add("rightMargin", lineHeight * RIGHT_MARGIN_SCALER)
|
||||||
|
.add("topMargin", lineHeight * TOP_MARGIN_SCALER)
|
||||||
|
.add("bottomMargin", lineHeight * BOTTOM_MARGIN_SCALER)
|
||||||
|
.add("lineHeight", lineHeight)
|
||||||
|
.add("dimensions", scaledDimensions)
|
||||||
|
.add("parentID", parentID)
|
||||||
|
.add("localPosition", localPosition)
|
||||||
|
.add("visible", visible)
|
||||||
|
.create(CLEAR_ENTITY_EDIT_PROPS);
|
||||||
|
|
||||||
|
Script.setTimeout(function () {
|
||||||
|
nametag.edit("visible", true);
|
||||||
|
}, REDRAW_TIMEOUT_AMOUNT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check to see if the display named changed or if the distance is big enough to need a redraw.
|
||||||
|
var MAX_RADIUS_IGNORE_METERS = 22;
|
||||||
|
var MAX_ON_MODE_DISTANCE = 30;
|
||||||
|
var CHECK_AVATAR = true;
|
||||||
|
var MIN_DISTANCE = 0.2;
|
||||||
|
function maybeRedraw(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
var avatarInfo = avatar.avatarInfo;
|
||||||
|
getAvatarData(uuid);
|
||||||
|
|
||||||
|
getDistance(uuid);
|
||||||
|
var avatarDistance = getDistance(uuid, CHECK_AVATAR, false);
|
||||||
|
if (avatarNametagMode === "alwaysOn" && avatarDistance > MAX_RADIUS_IGNORE_METERS) {
|
||||||
|
showHide(uuid, "hide");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avatarNametagMode === "alwaysOn" && avatarDistance < MAX_RADIUS_IGNORE_METERS) {
|
||||||
|
showHide(uuid, "show");
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarInfo.displayName = avatarInfo.displayName === "" ? "anonymous" : avatarInfo.displayName.trim();
|
||||||
|
|
||||||
|
if (avatar.previousName !== avatarInfo.displayName) {
|
||||||
|
updateName(uuid, avatarInfo.displayName);
|
||||||
|
} else {
|
||||||
|
redraw(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle redrawing if needed
|
||||||
|
function redraw(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
|
||||||
|
var nametag = avatar.nametag;
|
||||||
|
var initialDimensions = null;
|
||||||
|
var initialDistance = null;
|
||||||
|
var currentDistance = null;
|
||||||
|
var newDimensions = null;
|
||||||
|
var lineHeight = null;
|
||||||
|
|
||||||
|
initialDistance = avatar.initialDistance;
|
||||||
|
currentDistance = avatar.currentDistance;
|
||||||
|
|
||||||
|
initialDimensions = avatar.initialDimensions;
|
||||||
|
|
||||||
|
// Find our new dimensions from the new distance
|
||||||
|
newDimensions = [
|
||||||
|
(initialDimensions[X] / initialDistance) * currentDistance,
|
||||||
|
(initialDimensions[Y] / initialDistance) * currentDistance,
|
||||||
|
(initialDimensions[Z] / initialDistance) * currentDistance
|
||||||
|
];
|
||||||
|
|
||||||
|
// Multiply the new dimensions and line height with the user selected scaler
|
||||||
|
newDimensions = Vec3.multiply(newDimensions, userScaler);
|
||||||
|
|
||||||
|
var distance = getDistance(uuid, false, false);
|
||||||
|
|
||||||
|
maxDistance = avatarNametagMode === "on"
|
||||||
|
? MAX_ON_MODE_DISTANCE + DISTANCE_SCALER_INTERPOLATION_OFFSET_ON
|
||||||
|
: MAX_RADIUS_IGNORE_METERS + DISTANCE_SCALER_INTERPOLATION_OFFSET_ALWAYSON;
|
||||||
|
var finalScaler = (distance - maxDistance) / (MIN_DISTANCE - maxDistance);
|
||||||
|
var remainder = 1 - finalScaler;
|
||||||
|
var multipliedRemainderOn = remainder * onModeScalar;
|
||||||
|
var multipliedRemainderAlwaysOn = remainder * alwaysOnModeScalar;
|
||||||
|
finalScaler = avatarNametagMode === "on" ? finalScaler + multipliedRemainderOn : finalScaler + multipliedRemainderAlwaysOn;
|
||||||
|
|
||||||
|
newDimensions = Vec3.multiply(newDimensions, finalScaler);
|
||||||
|
|
||||||
|
lineHeight = newDimensions[Y] * LINE_HEIGHT_SCALER;
|
||||||
|
|
||||||
|
// Add some room for the margin by using lineHeight as a reference
|
||||||
|
newDimensions[X] += (lineHeight * LEFT_MARGIN_SCALER) + (lineHeight * RIGHT_MARGIN_SCALER);
|
||||||
|
newDimensions[Y] += (lineHeight * TOP_MARGIN_SCALER) + (lineHeight * BOTTOM_MARGIN_SCALER);
|
||||||
|
|
||||||
|
// We can generalize some of the processes that are similar in makeNameTag() and redraw() if we wanted to reduce some code
|
||||||
|
var newDimenionsYHalf = newDimensions[Y] * HALF;
|
||||||
|
var AvatarData = AvatarManager.getAvatar(uuid);
|
||||||
|
var headJointIndex = AvatarData.getJointIndex("Head");
|
||||||
|
var jointInObjectFrame = AvatarData.getAbsoluteJointTranslationInObjectFrame(headJointIndex);
|
||||||
|
var nameTagPosition = jointInObjectFrame.y + newDimenionsYHalf + ABOVE_HEAD_OFFSET;
|
||||||
|
var localPosition = [0, nameTagPosition, 0];
|
||||||
|
|
||||||
|
nametag
|
||||||
|
.add("leftMargin", lineHeight * LEFT_MARGIN_SCALER)
|
||||||
|
.add("rightMargin", lineHeight * RIGHT_MARGIN_SCALER)
|
||||||
|
.add("topMargin", lineHeight * TOP_MARGIN_SCALER)
|
||||||
|
.add("bottomMargin", lineHeight * BOTTOM_MARGIN_SCALER)
|
||||||
|
.add("lineHeight", lineHeight)
|
||||||
|
.add("dimensions", newDimensions)
|
||||||
|
.add("localPosition", localPosition)
|
||||||
|
.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a user to the list.
|
||||||
|
var DEFAULT_LIFETIME = entityProps.lifetime;
|
||||||
|
|
||||||
|
|
||||||
|
// add a user to our current selections
|
||||||
|
function add(uuid) {
|
||||||
|
// User Doesn't exist so give them new props and save in the cache, and get their current avatar info.
|
||||||
|
if (!_this.avatars[uuid]) {
|
||||||
|
_this.avatars[uuid] = new NewAvatarProps();
|
||||||
|
getAvatarData(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
|
||||||
|
_this.selectedAvatars[uuid] = true;
|
||||||
|
if (avatarNametagMode === "alwaysOn") {
|
||||||
|
entityProps.lifetime = -1;
|
||||||
|
} else {
|
||||||
|
entityProps.lifetime = DEFAULT_LIFETIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
avatar.nametag = new EntityMaker('local').add(entityProps);
|
||||||
|
|
||||||
|
// When the user clicks someone, we create their nametag
|
||||||
|
makeNameTag(uuid);
|
||||||
|
var deleteEnttyInMiliseconds = entityProps.lifetime * MILISECONDS_IN_SECOND;
|
||||||
|
|
||||||
|
// Remove from list after lifetime is over
|
||||||
|
if (avatarNametagMode === "on") {
|
||||||
|
avatar.timeoutStarted = Script.setTimeout(function () {
|
||||||
|
removeNametag(uuid);
|
||||||
|
}, deleteEnttyInMiliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if anyone is in the selected list now to see if we need to start the interval checking
|
||||||
|
shouldToggleInterval();
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the avatar from the list.
|
||||||
|
function remove(uuid) {
|
||||||
|
if (_this.selectedAvatars[uuid]) {
|
||||||
|
delete _this.selectedAvatars[uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNametag(uuid);
|
||||||
|
|
||||||
|
shouldToggleInterval();
|
||||||
|
delete _this.avatars[uuid];
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove all the current nametags.
|
||||||
|
function removeAllNametags() {
|
||||||
|
for (var uuid in _this.selectedAvatars) {
|
||||||
|
removeNametag(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove a single Nametag.
|
||||||
|
function removeNametag(uuid) {
|
||||||
|
var avatar = _this.avatars[uuid];
|
||||||
|
|
||||||
|
if (avatar) {
|
||||||
|
avatar.nametag.destroy();
|
||||||
|
delete _this.selectedAvatars[uuid];
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END Nametag
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START API
|
||||||
|
// *************************************
|
||||||
|
// #region API
|
||||||
|
|
||||||
|
|
||||||
|
// Create the manager and hook up username signal
|
||||||
|
function create() {
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destory the manager and disconnect from username signal
|
||||||
|
function destroy() {
|
||||||
|
_this.reset();
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check to see if we need to delete any close by nametags
|
||||||
|
var MAX_DELETE_RANGE = 4;
|
||||||
|
function checkIfAnyAreClose(target) {
|
||||||
|
var targetPosition = AvatarManager.getAvatar(target).position;
|
||||||
|
for (var uuid in _this.selectedAvatars) {
|
||||||
|
var position = AvatarManager.getAvatar(uuid).position;
|
||||||
|
var distance = Vec3.distance(position, targetPosition);
|
||||||
|
if (distance <= MAX_DELETE_RANGE) {
|
||||||
|
var timeoutStarted = _this.avatars[uuid].timeoutStarted;
|
||||||
|
if (timeoutStarted) {
|
||||||
|
Script.clearTimeout(timeoutStarted);
|
||||||
|
timeoutStarted = null;
|
||||||
|
}
|
||||||
|
removeNametag(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles what happens when an avatar gets triggered on
|
||||||
|
function handleSelect(uuid) {
|
||||||
|
if (avatarNametagMode === "off" || avatarNametagMode === "alwaysOn") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inSelected = uuid in _this.selectedAvatars;
|
||||||
|
|
||||||
|
if (inSelected) {
|
||||||
|
if (avatarNametagMode === "on") {
|
||||||
|
var timeoutStarted = _this.avatars[uuid].timeoutStarted;
|
||||||
|
if (timeoutStarted) {
|
||||||
|
Script.clearTimeout(timeoutStarted);
|
||||||
|
timeoutStarted = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNametag(uuid);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
checkIfAnyAreClose(uuid);
|
||||||
|
add(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check to see if we need to clear timeouts for avatars
|
||||||
|
function maybeClearAllTimeouts() {
|
||||||
|
for (var uuid in _this.selectedAvatars) {
|
||||||
|
var timeoutStarted = _this.avatars[uuid].timeoutStarted;
|
||||||
|
if (timeoutStarted) {
|
||||||
|
Script.clearTimeout(timeoutStarted);
|
||||||
|
timeoutStarted = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check to see if the uuid is in the avatars list before removing
|
||||||
|
function maybeRemove(uuid) {
|
||||||
|
if (uuid in _this.avatars) {
|
||||||
|
remove(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check to see if we need to add this user to our list
|
||||||
|
function maybeAdd(uuid) {
|
||||||
|
if (uuid && avatarNametagMode === "alwaysOn" && !(uuid in _this.avatars)) {
|
||||||
|
add(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Register the beggining scaler in case it was saved from a previous session
|
||||||
|
function registerInitialScaler(initalScaler) {
|
||||||
|
userScaler = initalScaler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle the user updating scale
|
||||||
|
function updateUserScaler(newUSerScaler) {
|
||||||
|
userScaler = newUSerScaler;
|
||||||
|
for (var avatar in _this.selectedAvatars) {
|
||||||
|
redraw(avatar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reset the avatar list
|
||||||
|
function reset() {
|
||||||
|
maybeClearAllTimeouts();
|
||||||
|
removeAllNametags();
|
||||||
|
_this.avatars = {};
|
||||||
|
shouldToggleInterval();
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Update the nametag display mode
|
||||||
|
var avatarNametagMode = "on";
|
||||||
|
function handleAvatarNametagMode(newAvatarNametagMode) {
|
||||||
|
if (avatarNametagMode === "alwaysOn") {
|
||||||
|
handleAlwaysOnMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarNametagMode = newAvatarNametagMode;
|
||||||
|
if (avatarNametagMode === "alwaysOn") {
|
||||||
|
handleAlwaysOnMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avatarNametagMode === "off" || avatarNametagMode === "on") {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END API
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
|
||||||
|
nameTagListManager.prototype = {
|
||||||
|
create: create,
|
||||||
|
destroy: destroy,
|
||||||
|
handleSelect: handleSelect,
|
||||||
|
maybeRemove: maybeRemove,
|
||||||
|
maybeAdd: maybeAdd,
|
||||||
|
registerInitialScaler: registerInitialScaler,
|
||||||
|
updateUserScaler: updateUserScaler,
|
||||||
|
handleAvatarNametagMode: handleAvatarNametagMode,
|
||||||
|
reset: reset
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = nameTagListManager;
|
|
@ -0,0 +1,32 @@
|
||||||
|
// taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
||||||
|
|
||||||
|
if (typeof Object.assign != 'function') {
|
||||||
|
// Must be writable: true, enumerable: false, configurable: true
|
||||||
|
Object.defineProperty(Object, "assign", {
|
||||||
|
value: function assign(target, varArgs) { // .length of function is 2
|
||||||
|
'use strict';
|
||||||
|
if (target == null) { // TypeError if undefined or null
|
||||||
|
throw new TypeError('Cannot convert undefined or null to object');
|
||||||
|
}
|
||||||
|
|
||||||
|
var to = Object(target);
|
||||||
|
|
||||||
|
for (var index = 1; index < arguments.length; index++) {
|
||||||
|
var nextSource = arguments[index];
|
||||||
|
|
||||||
|
if (nextSource != null) { // Skip over if undefined or null
|
||||||
|
for (var nextKey in nextSource) {
|
||||||
|
// Avoid bugs when hasOwnProperty is shadowed
|
||||||
|
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
||||||
|
to[nextKey] = nextSource[nextKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return to;
|
||||||
|
},
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,305 @@
|
||||||
|
//
|
||||||
|
// Simplified Nametag
|
||||||
|
// pickRayController.js
|
||||||
|
// Created by Milad Nazeri on 2019-03-08
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// Easy pickray controllers for Entities, Overlays, and Avatars
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
var _this;
|
||||||
|
function PickRayController(){
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
_this.rayType = null;
|
||||||
|
_this.eventHandler = null;
|
||||||
|
_this.intersection = null;
|
||||||
|
_this.lastPick = null;
|
||||||
|
_this.currentPick = null;
|
||||||
|
_this.mappingName = null;
|
||||||
|
_this.mapping = null;
|
||||||
|
_this._boundMousePressHandler = null;
|
||||||
|
_this.shouldDoublePress = null;
|
||||||
|
_this.controllEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START UTILITY
|
||||||
|
// *************************************
|
||||||
|
// #region UTILITY
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the right UUID based on hand triggered
|
||||||
|
function getUUIDFromLaser(hand) {
|
||||||
|
hand = hand === Controller.Standard.LeftHand
|
||||||
|
? Controller.Standard.LeftHand
|
||||||
|
: Controller.Standard.RightHand;
|
||||||
|
|
||||||
|
var pose = getControllerWorldLocation(hand);
|
||||||
|
var start = pose.position;
|
||||||
|
// Get the direction that the hand is facing in the world
|
||||||
|
var direction = Vec3.multiplyQbyV(pose.orientation, [0, 1, 0]);
|
||||||
|
|
||||||
|
pickRayTypeHandler(start, direction);
|
||||||
|
|
||||||
|
if (_this.currentPick) {
|
||||||
|
_this.eventHandler(_this.currentPick, _this.intersection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The following two functions are a modified version of what's found in scripts/system/libraries/controllers.js
|
||||||
|
|
||||||
|
// Utility function for the ControllerWorldLocation offset
|
||||||
|
function getGrabPointSphereOffset(handController) {
|
||||||
|
// These values must match what's in scripts/system/libraries/controllers.js
|
||||||
|
// x = upward, y = forward, z = lateral
|
||||||
|
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 };
|
||||||
|
var offset = GRAB_POINT_SPHERE_OFFSET;
|
||||||
|
if (handController === Controller.Standard.LeftHand) {
|
||||||
|
offset = {
|
||||||
|
x: -GRAB_POINT_SPHERE_OFFSET.x,
|
||||||
|
y: GRAB_POINT_SPHERE_OFFSET.y,
|
||||||
|
z: GRAB_POINT_SPHERE_OFFSET.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// controllerWorldLocation is where the controller would be, in-world, with an added offset
|
||||||
|
function getControllerWorldLocation(handController, doOffset) {
|
||||||
|
var orientation;
|
||||||
|
var position;
|
||||||
|
var valid = false;
|
||||||
|
|
||||||
|
if (handController >= 0) {
|
||||||
|
var pose = Controller.getPoseValue(handController);
|
||||||
|
valid = pose.valid;
|
||||||
|
var controllerJointIndex;
|
||||||
|
if (pose.valid) {
|
||||||
|
if (handController === Controller.Standard.RightHand) {
|
||||||
|
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND");
|
||||||
|
} else {
|
||||||
|
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
|
||||||
|
}
|
||||||
|
orientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(controllerJointIndex));
|
||||||
|
position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)));
|
||||||
|
|
||||||
|
// add to the real position so the grab-point is out in front of the hand, a bit
|
||||||
|
if (doOffset) {
|
||||||
|
var offset = getGrabPointSphereOffset(handController);
|
||||||
|
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (!HMD.isHandControllerAvailable()) {
|
||||||
|
// NOTE: keep _this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
||||||
|
var VERTICAL_HEAD_LASER_OFFSET = 0.1 * MyAvatar.sensorToWorldScale;
|
||||||
|
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, { x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0 }));
|
||||||
|
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
position: position,
|
||||||
|
translation: position,
|
||||||
|
orientation: orientation,
|
||||||
|
rotation: orientation,
|
||||||
|
valid: valid
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle if the uuid picked on is new or different
|
||||||
|
function handleUUID(uuid){
|
||||||
|
if (!_this.lastPick && !_this.currentPick) {
|
||||||
|
_this.currentPick = uuid;
|
||||||
|
_this.lastPick = uuid;
|
||||||
|
} else {
|
||||||
|
_this.lastPick = _this.currentPick;
|
||||||
|
_this.currentPick = uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function pickRayTypeHandler(pickRay){
|
||||||
|
// Handle if pickray is system generated or user generated
|
||||||
|
if (arguments.length === 2) {
|
||||||
|
pickRay = { origin: arguments[0], direction: arguments[1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each different ray pick type needs a different findRayIntersection function
|
||||||
|
switch (_this.rayType) {
|
||||||
|
case 'avatar':
|
||||||
|
var avatarIntersection = AvatarList.findRayIntersection(pickRay, [], [MyAvatar.sessionUUID], false);
|
||||||
|
_this.intersection = avatarIntersection;
|
||||||
|
handleUUID(avatarIntersection.avatarID);
|
||||||
|
break;
|
||||||
|
case 'local':
|
||||||
|
var overlayIntersection = Overlays.findRayIntersection(pickRay, [], []);
|
||||||
|
_this.intersection = overlayIntersection;
|
||||||
|
handleUUID(overlayIntersection.overlayID);
|
||||||
|
break;
|
||||||
|
case 'entity':
|
||||||
|
var entityIntersection = Entities.findRayIntersection(pickRay, [], []);
|
||||||
|
_this.intersection = entityIntersection;
|
||||||
|
handleUUID(entityIntersection.avatarID);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("ray type not handled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handle the interaction when in desktop and a mouse is pressed
|
||||||
|
function mousePressHandler(event) {
|
||||||
|
if (HMD.active || !event.isLeftButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
pickRayTypeHandler(pickRay);
|
||||||
|
if (_this.currentPick) {
|
||||||
|
_this.eventHandler(_this.currentPick, _this.intersection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Function to call when double press is singled
|
||||||
|
function doublePressHandler(event) {
|
||||||
|
mousePressHandler(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END UTILITY
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START API
|
||||||
|
// *************************************
|
||||||
|
// #region API
|
||||||
|
|
||||||
|
|
||||||
|
// After setup is given, this gets the Controller ready to be enabled
|
||||||
|
function create(){
|
||||||
|
_this.mapping = Controller.newMapping(_this.mappingName);
|
||||||
|
|
||||||
|
_this.mapping.from(Controller.Standard.LTClick).to(function (value) {
|
||||||
|
if (value === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getUUIDFromLaser(Controller.Standard.LeftHand);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
_this.mapping.from(Controller.Standard.RTClick).to(function (value) {
|
||||||
|
if (value === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getUUIDFromLaser(Controller.Standard.RightHand);
|
||||||
|
});
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set type of raypick for what kind of uuids to return
|
||||||
|
function setType(type){
|
||||||
|
_this.rayType = type;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set if double presses should register as well
|
||||||
|
function setShouldDoublePress(shouldDoublePress){
|
||||||
|
_this.shouldDoublePress = shouldDoublePress;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set the mapping name for the controller
|
||||||
|
function setMapName(name) {
|
||||||
|
_this.mappingName = name;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Enables mouse press and trigger events
|
||||||
|
function enable(){
|
||||||
|
if (!_this.controllEnabled) {
|
||||||
|
Controller.mousePressEvent.connect(mousePressHandler);
|
||||||
|
if (_this.shouldDoublePress) {
|
||||||
|
Controller.mouseDoublePressEvent.connect(doublePressHandler);
|
||||||
|
}
|
||||||
|
Controller.enableMapping(_this.mappingName);
|
||||||
|
_this.controllEnabled = true;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Disable the controller and mouse press
|
||||||
|
function disable(){
|
||||||
|
if (_this.controllEnabled) {
|
||||||
|
Controller.mousePressEvent.disconnect(mousePressHandler);
|
||||||
|
if (_this.shouldDoublePress){
|
||||||
|
Controller.mouseDoublePressEvent.disconnect(doublePressHandler);
|
||||||
|
}
|
||||||
|
Controller.disableMapping(_this.mappingName);
|
||||||
|
_this.controllEnabled = false;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Synonym for disable
|
||||||
|
function destroy(){
|
||||||
|
_this.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Register the function to be called on a click
|
||||||
|
function registerEventHandler(fn){
|
||||||
|
_this.eventHandler = fn;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END API
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
PickRayController.prototype = {
|
||||||
|
create: create,
|
||||||
|
setType: setType,
|
||||||
|
setShouldDoublePress: setShouldDoublePress,
|
||||||
|
setMapName: setMapName,
|
||||||
|
enable: enable,
|
||||||
|
disable: disable,
|
||||||
|
destroy: destroy,
|
||||||
|
registerEventHandler: registerEventHandler
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = PickRayController;
|
|
@ -0,0 +1,224 @@
|
||||||
|
//
|
||||||
|
// Simplified Nametag
|
||||||
|
// textHelper.js
|
||||||
|
// Created by Milad Nazeri on 2019-03-08
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// Module to help calculate text size
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START MAPS
|
||||||
|
// *************************************
|
||||||
|
// #region MAPS
|
||||||
|
|
||||||
|
|
||||||
|
var charMap = {
|
||||||
|
a: 0.05,
|
||||||
|
b: 0.051,
|
||||||
|
c: 0.05,
|
||||||
|
d: 0.051,
|
||||||
|
e: 0.05,
|
||||||
|
f: 0.035,
|
||||||
|
g: 0.051,
|
||||||
|
h: 0.051,
|
||||||
|
i: 0.025,
|
||||||
|
j: 0.025,
|
||||||
|
k: 0.05,
|
||||||
|
l: 0.025,
|
||||||
|
m: 0.0775,
|
||||||
|
n: 0.051,
|
||||||
|
o: 0.051,
|
||||||
|
p: 0.051,
|
||||||
|
q: 0.051,
|
||||||
|
r: 0.035,
|
||||||
|
s: 0.05,
|
||||||
|
t: 0.035,
|
||||||
|
u: 0.051,
|
||||||
|
v: 0.05,
|
||||||
|
w: 0.07,
|
||||||
|
x: 0.05,
|
||||||
|
y: 0.05,
|
||||||
|
z: 0.05,
|
||||||
|
A: 0.06,
|
||||||
|
B: 0.06,
|
||||||
|
C: 0.06,
|
||||||
|
D: 0.06,
|
||||||
|
E: 0.05,
|
||||||
|
F: 0.05,
|
||||||
|
G: 0.06,
|
||||||
|
H: 0.0625,
|
||||||
|
I: 0.0275,
|
||||||
|
J: 0.05,
|
||||||
|
K: 0.06,
|
||||||
|
L: 0.05,
|
||||||
|
M: 0.075,
|
||||||
|
N: 0.0625,
|
||||||
|
O: 0.0625,
|
||||||
|
P: 0.06,
|
||||||
|
Q: 0.0625,
|
||||||
|
R: 0.06,
|
||||||
|
S: 0.06,
|
||||||
|
T: 0.06,
|
||||||
|
U: 0.06,
|
||||||
|
V: 0.06,
|
||||||
|
W: 0.075,
|
||||||
|
X: 0.06,
|
||||||
|
Y: 0.06,
|
||||||
|
Z: 0.06
|
||||||
|
};
|
||||||
|
|
||||||
|
var symbolMap = {
|
||||||
|
"!": 0.025,
|
||||||
|
"@": 0.08,
|
||||||
|
"#": 0.07,
|
||||||
|
"$": 0.058,
|
||||||
|
"%": 0.07,
|
||||||
|
"^": 0.04,
|
||||||
|
"&": 0.06,
|
||||||
|
"*": 0.04,
|
||||||
|
"(": 0.04,
|
||||||
|
")": 0.04,
|
||||||
|
"_": 0.041,
|
||||||
|
"{": 0.034,
|
||||||
|
"}": 0.034,
|
||||||
|
"/": 0.04,
|
||||||
|
"|": 0.02,
|
||||||
|
"<": 0.049,
|
||||||
|
">": 0.049,
|
||||||
|
"[": 0.0300,
|
||||||
|
"]": 0.0300,
|
||||||
|
".": 0.0260,
|
||||||
|
",": 0.0260,
|
||||||
|
"?": 0.048,
|
||||||
|
"~": 0.0610,
|
||||||
|
"`": 0.0310,
|
||||||
|
"+": 0.0510,
|
||||||
|
"=": 0.0510
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END MAPS
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
var _this = null;
|
||||||
|
function TextHelper(){
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
this.text = "";
|
||||||
|
this.textArray = "";
|
||||||
|
this.lineHeight = 0;
|
||||||
|
this.totalTextLength = 0;
|
||||||
|
this.scaler = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START UTILITY
|
||||||
|
// *************************************
|
||||||
|
// #region UTILITY
|
||||||
|
|
||||||
|
|
||||||
|
// Split the string into a text array to be operated on
|
||||||
|
function createTextArray(){
|
||||||
|
_this.textArray = _this.text.split("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Account for the text length
|
||||||
|
function adjustForScale(defaultTextLength){
|
||||||
|
_this.totalTextLength = defaultTextLength * _this.scaler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END UTILITY
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END name
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START API
|
||||||
|
// *************************************
|
||||||
|
// #region API
|
||||||
|
|
||||||
|
|
||||||
|
// Set the text that needs to be calculated on
|
||||||
|
function setText(newText){
|
||||||
|
_this.text = newText;
|
||||||
|
createTextArray();
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set the line height which helps calculate the font size
|
||||||
|
var DEFAULT_LINE_HEIGHT = 0.1;
|
||||||
|
function setLineHeight(newLineHeight){
|
||||||
|
_this.lineHeight = newLineHeight;
|
||||||
|
_this.scaler = _this.lineHeight / DEFAULT_LINE_HEIGHT;
|
||||||
|
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate the sign dimensions
|
||||||
|
var DEFAULT_CHAR_SIZE = 0.025;
|
||||||
|
var NUMBER = 0.05;
|
||||||
|
var DIGIT_REGEX = /\d/g;
|
||||||
|
var WHITE_SPACE_REGEX = /[ ]/g;
|
||||||
|
var SPACE = 0.018;
|
||||||
|
function getTotalTextLength(){
|
||||||
|
// Map the string array to it's sizes
|
||||||
|
var lengthArray = _this.textArray.map(function(letter){
|
||||||
|
if (charMap[letter]){
|
||||||
|
return charMap[letter];
|
||||||
|
} else if (letter.match(DIGIT_REGEX)){
|
||||||
|
return NUMBER;
|
||||||
|
} else if (symbolMap[letter]) {
|
||||||
|
return symbolMap[letter];
|
||||||
|
} else if (letter.match(WHITE_SPACE_REGEX)) {
|
||||||
|
return SPACE;
|
||||||
|
} else {
|
||||||
|
return DEFAULT_CHAR_SIZE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// add up all the values in the array
|
||||||
|
var defaultTextLength = lengthArray.reduce(function(prev, curr){
|
||||||
|
return prev + curr;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
adjustForScale(defaultTextLength);
|
||||||
|
|
||||||
|
return _this.totalTextLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END API
|
||||||
|
// *************************************
|
||||||
|
|
||||||
|
TextHelper.prototype = {
|
||||||
|
setText: setText,
|
||||||
|
setLineHeight: setLineHeight,
|
||||||
|
getTotalTextLength: getTotalTextLength
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TextHelper;
|
||||||
|
|
||||||
|
// var text = new TextHelper();
|
||||||
|
// text.setText("lowbar");
|
||||||
|
// text.setLineHeight("0.1");
|
||||||
|
// text.getTotalTextLength();
|
|
@ -0,0 +1,95 @@
|
||||||
|
//
|
||||||
|
// Simplified Nametag
|
||||||
|
// Created by Milad Nazeri on 2019-02-16
|
||||||
|
// Copyright 2019 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// Click on someone to get a nametag for them
|
||||||
|
//
|
||||||
|
var PickRayController = Script.require('./resources/modules/pickRayController.js?' + Date.now());
|
||||||
|
var NameTagListManager = Script.require('./resources/modules/nameTagListManager.js?' + Date.now());
|
||||||
|
var pickRayController = new PickRayController();
|
||||||
|
var nameTagListManager = new NameTagListManager();
|
||||||
|
|
||||||
|
// Handles avatar being solo'd
|
||||||
|
pickRayController
|
||||||
|
.registerEventHandler(selectAvatar)
|
||||||
|
.setType("avatar")
|
||||||
|
.setMapName("hifi_simplifiedNametag")
|
||||||
|
.setShouldDoublePress(true)
|
||||||
|
.create()
|
||||||
|
.enable();
|
||||||
|
|
||||||
|
|
||||||
|
function selectAvatar(uuid, intersection) {
|
||||||
|
nameTagListManager.handleSelect(uuid, intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handles reset of list if you change domains
|
||||||
|
function onDomainChange() {
|
||||||
|
nameTagListManager.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Handles removing an avatar from the list if they leave the domain
|
||||||
|
function onAvatarRemoved(uuid) {
|
||||||
|
nameTagListManager.maybeRemove(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Automatically add an avatar if they come into the domain. Mainly used for alwaysOn mode.
|
||||||
|
function onAvatarAdded(uuid) {
|
||||||
|
nameTagListManager.maybeAdd(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called on init
|
||||||
|
var avatarNametagMode;
|
||||||
|
function create() {
|
||||||
|
nameTagListManager.create();
|
||||||
|
handleAvatarNametagMode(Settings.getValue("simplifiedNametag/avatarNametagMode", "on"));
|
||||||
|
|
||||||
|
Window.domainChanged.connect(onDomainChange);
|
||||||
|
AvatarManager.avatarRemovedEvent.connect(onAvatarRemoved);
|
||||||
|
AvatarManager.avatarAddedEvent.connect(onAvatarAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called when the script is closing
|
||||||
|
function destroy() {
|
||||||
|
nameTagListManager.destroy();
|
||||||
|
pickRayController.destroy();
|
||||||
|
Window.domainChanged.disconnect(onDomainChange);
|
||||||
|
AvatarManager.avatarRemovedEvent.disconnect(onAvatarRemoved);
|
||||||
|
AvatarManager.avatarAddedEvent.disconnect(onAvatarAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// chose which mode you want the nametags in. On, off, or alwaysOn.
|
||||||
|
function handleAvatarNametagMode(newAvatarNameTagMode) {
|
||||||
|
avatarNametagMode = newAvatarNameTagMode;
|
||||||
|
nameTagListManager.handleAvatarNametagMode(avatarNametagMode);
|
||||||
|
Settings.setValue("simplifiedNametag/avatarNametagMode", avatarNametagMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *************************************
|
||||||
|
// START api
|
||||||
|
// *************************************
|
||||||
|
// #region api
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
create: create,
|
||||||
|
destroy: destroy,
|
||||||
|
handleAvatarNametagMode: handleAvatarNametagMode
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// *************************************
|
||||||
|
// END api
|
||||||
|
// *************************************
|
|
@ -434,8 +434,7 @@ function ensureFirstPersonCameraInHMD(isHMDMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var simplifiedNametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
|
||||||
var simplifiedNametag = Script.require("../simplifiedNametag/simplifiedNametag.js");
|
|
||||||
var oldShowAudioTools;
|
var oldShowAudioTools;
|
||||||
var oldShowBubbleTools;
|
var oldShowBubbleTools;
|
||||||
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
|
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
|
||||||
|
|
Loading…
Reference in a new issue