forgot to copy a folder in to the local repo

This commit is contained in:
milad 2019-05-17 12:42:10 -07:00
parent 024dfbf8b7
commit 935d152617
8 changed files with 1505 additions and 2 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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
});
}

View file

@ -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;

View file

@ -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();

View file

@ -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
// *************************************

View file

@ -434,8 +434,7 @@ function ensureFirstPersonCameraInHMD(isHMDMode) {
}
}
var simplifiedNametag = Script.require("../simplifiedNametag/simplifiedNametag.js");
var simplifiedNametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now());
var oldShowAudioTools;
var oldShowBubbleTools;
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);