mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 16:55:07 +02:00
first cut, pretty ugly
This commit is contained in:
parent
5bef6ea029
commit
51246a2e45
3 changed files with 73 additions and 40 deletions
|
@ -31,6 +31,7 @@ Item {
|
|||
property real displayNameTextPixelSize: 18
|
||||
property int usernameTextHeight: 12
|
||||
property real audioLevel: 0.0
|
||||
property real avgAudioLevel: 0.0
|
||||
property bool isMyCard: false
|
||||
property bool selected: false
|
||||
property bool isAdmin: false
|
||||
|
@ -335,7 +336,7 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Per-Avatar Gain Slider
|
||||
// Per-Avatar Gain Slider
|
||||
Slider {
|
||||
id: gainSlider
|
||||
// Size
|
||||
|
@ -369,7 +370,7 @@ Item {
|
|||
mouse.accepted = false
|
||||
}
|
||||
onReleased: {
|
||||
// the above mouse.accepted seems to make this
|
||||
// the above mouse.accepted seems to make this
|
||||
// never get called, nonetheless...
|
||||
mouse.accepted = false
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Pal.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// People Action List
|
||||
// People Action List
|
||||
//
|
||||
// Created by Howard Stearns on 12/12/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
|
@ -29,8 +29,8 @@ Rectangle {
|
|||
property int myCardHeight: 90
|
||||
property int rowHeight: 70
|
||||
property int actionButtonWidth: 55
|
||||
property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth
|
||||
property var myData: ({displayName: "", userName: "", audioLevel: 0.0, admin: true}) // valid dummy until set
|
||||
property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 5 : 3) - 4 - hifi.dimensions.scrollbarBackgroundWidth
|
||||
property var myData: ({displayName: "", userName: "", audioLevel: 0.0, avgAudioLevel: 0.0, admin: true}) // valid dummy until set
|
||||
property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring.
|
||||
property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities.
|
||||
property bool iAmAdmin: false
|
||||
|
@ -86,6 +86,7 @@ Rectangle {
|
|||
displayName: myData.displayName
|
||||
userName: myData.userName
|
||||
audioLevel: myData.audioLevel
|
||||
avgAudioLevel: myData.avgAudioLevel
|
||||
isMyCard: true
|
||||
// Size
|
||||
width: nameCardWidth
|
||||
|
@ -184,6 +185,13 @@ Rectangle {
|
|||
movable: false
|
||||
resizable: false
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "avgAudioLevel"
|
||||
title: "VOL"
|
||||
width: actionButtonWidth
|
||||
movable: false
|
||||
resizable: false
|
||||
}
|
||||
TableViewColumn {
|
||||
visible: iAmAdmin
|
||||
role: "mute"
|
||||
|
@ -218,6 +226,7 @@ Rectangle {
|
|||
id: itemCell
|
||||
property bool isCheckBox: styleData.role === "personalMute" || styleData.role === "ignore"
|
||||
property bool isButton: styleData.role === "mute" || styleData.role === "kick"
|
||||
property bool isText: styleData.role == "avgAudioLevel"
|
||||
// This NameCard refers to the cell that contains an avatar's
|
||||
// DisplayName and UserName
|
||||
NameCard {
|
||||
|
@ -226,7 +235,8 @@ Rectangle {
|
|||
displayName: styleData.value
|
||||
userName: model ? model.userName : ""
|
||||
audioLevel: model ? model.audioLevel : 0.0
|
||||
visible: !isCheckBox && !isButton
|
||||
avgAudioLevel: model ? model.avgAudioLevel : 0.0
|
||||
visible: !isCheckBox && !isButton && !isText
|
||||
uuid: model ? model.sessionId : ""
|
||||
selected: styleData.selected
|
||||
isAdmin: model && model.admin
|
||||
|
@ -236,7 +246,16 @@ Rectangle {
|
|||
// Anchors
|
||||
anchors.left: parent.left
|
||||
}
|
||||
|
||||
Text {
|
||||
id: avgAudioVolume
|
||||
text: model ? model.avgAudioLevel : 0.0
|
||||
visible: isText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
}
|
||||
|
||||
// This CheckBox belongs in the columns that contain the stateful action buttons ("Mute" & "Ignore" for now)
|
||||
// KNOWN BUG with the Checkboxes: When clicking in the center of the sorting header, the checkbox
|
||||
// will appear in the "hovered" state. Hovering over the checkbox will fix it.
|
||||
|
@ -272,7 +291,7 @@ Rectangle {
|
|||
checked = Qt.binding(function() { return (model[styleData.role])})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This Button belongs in the columns that contain the stateless action buttons ("Silence" & "Ban" for now)
|
||||
HifiControls.Button {
|
||||
id: actionButton
|
||||
|
@ -542,23 +561,28 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'updateAudioLevel':
|
||||
case 'updateAudioLevel':
|
||||
for (var userId in message.params) {
|
||||
var audioLevel = message.params[userId];
|
||||
var audioLevel = message.params[userId][0];
|
||||
var avgAudioLevel = message.params[userId][1];
|
||||
// If the userId is 0, we're updating "myData".
|
||||
if (userId == 0) {
|
||||
myData.audioLevel = audioLevel;
|
||||
myCard.audioLevel = audioLevel; // Defensive programming
|
||||
myData.avgAudioLevel = avgAudioLevel;
|
||||
myCard.avgAudioLevel = avgAudioLevel;
|
||||
} else {
|
||||
var userIndex = findSessionIndex(userId);
|
||||
if (userIndex != -1) {
|
||||
userModel.setProperty(userIndex, "audioLevel", audioLevel);
|
||||
userModelData[userIndex].audioLevel = audioLevel; // Defensive programming
|
||||
userModel.setProperty(userIndex, "avgAudioLevel", avgAudioLevel);
|
||||
userModelData[userIndex].avgAudioLevel = avgAudioLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'clearLocalQMLData':
|
||||
case 'clearLocalQMLData':
|
||||
ignored = {};
|
||||
gainSliderValueDB = {};
|
||||
break;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
||||
// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed
|
||||
// something, will revisit as this is sorta horrible.
|
||||
const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"),
|
||||
"idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png")
|
||||
|
@ -87,7 +87,7 @@ ExtendedOverlay.prototype.hover = function (hovering) {
|
|||
} else {
|
||||
lastHoveringId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.editOverlay({color: color(this.selected, hovering, this.audioLevel)});
|
||||
if (this.model) {
|
||||
this.model.editOverlay({textures: textures(this.selected, hovering)});
|
||||
|
@ -104,7 +104,7 @@ ExtendedOverlay.prototype.select = function (selected) {
|
|||
if (this.selected === selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
UserActivityLogger.palAction(selected ? "avatar_selected" : "avatar_deselected", this.key);
|
||||
|
||||
this.editOverlay({color: color(selected, this.hovering, this.audioLevel)});
|
||||
|
@ -273,7 +273,7 @@ function sendToQml(message) {
|
|||
//
|
||||
function addAvatarNode(id) {
|
||||
var selected = ExtendedOverlay.isSelected(id);
|
||||
return new ExtendedOverlay(id, "sphere", {
|
||||
return new ExtendedOverlay(id, "sphere", {
|
||||
drawInFront: true,
|
||||
solid: true,
|
||||
alpha: 0.8,
|
||||
|
@ -290,6 +290,7 @@ function populateUserList(selectData) {
|
|||
userName: '',
|
||||
sessionId: id || '',
|
||||
audioLevel: 0.0,
|
||||
avgAudioLevel: 0.0,
|
||||
admin: false,
|
||||
personalMute: !!id && Users.getPersonalMuteStatus(id), // expects proper boolean, not null
|
||||
ignore: !!id && Users.getIgnoreStatus(id) // ditto
|
||||
|
@ -341,7 +342,7 @@ function updateOverlays() {
|
|||
var target = avatar.position;
|
||||
var distance = Vec3.distance(target, eye);
|
||||
var offset = 0.2;
|
||||
|
||||
|
||||
// base offset on 1/2 distance from hips to head if we can
|
||||
var headIndex = avatar.getJointIndex("Head");
|
||||
if (headIndex > 0) {
|
||||
|
@ -350,7 +351,7 @@ function updateOverlays() {
|
|||
|
||||
// get diff between target and eye (a vector pointing to the eye from avatar position)
|
||||
var diff = Vec3.subtract(target, eye);
|
||||
|
||||
|
||||
// move a bit in front, towards the camera
|
||||
target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset));
|
||||
|
||||
|
@ -361,12 +362,12 @@ function updateOverlays() {
|
|||
overlay.editOverlay({
|
||||
color: color(ExtendedOverlay.isSelected(id), overlay.hovering, overlay.audioLevel),
|
||||
position: target,
|
||||
dimensions: 0.032 * distance
|
||||
dimensions: 0.032 * distance
|
||||
});
|
||||
if (overlay.model) {
|
||||
overlay.model.ping = pingPong;
|
||||
overlay.model.editOverlay({
|
||||
position: target,
|
||||
position: target,
|
||||
scale: 0.2 * distance, // constant apparent size
|
||||
rotation: Camera.orientation
|
||||
});
|
||||
|
@ -433,7 +434,7 @@ function handleMouseMoveEvent(event) { // find out which overlay (if any) is ove
|
|||
handleMouseMove(pickRay);
|
||||
}
|
||||
function handleTriggerPressed(hand, value) {
|
||||
// The idea is if you press one trigger, it is the one
|
||||
// The idea is if you press one trigger, it is the one
|
||||
// we will consider the mouse. Even if the other is pressed,
|
||||
// we ignore it until this one is no longer pressed.
|
||||
isPressed = value > TRIGGER_PRESS_THRESHOLD;
|
||||
|
@ -441,10 +442,10 @@ function handleTriggerPressed(hand, value) {
|
|||
currentHandPressed = isPressed ? hand : 0;
|
||||
return;
|
||||
}
|
||||
if (currentHandPressed == hand) {
|
||||
if (currentHandPressed == hand) {
|
||||
currentHandPressed = isPressed ? hand : 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// otherwise, the other hand is still triggered
|
||||
// so do nothing.
|
||||
}
|
||||
|
@ -574,41 +575,48 @@ function receiveMessage(channel, messageString, senderID) {
|
|||
Messages.subscribe(CHANNEL);
|
||||
Messages.messageReceived.connect(receiveMessage);
|
||||
|
||||
|
||||
var AVERAGING_RATIO = 0.05;
|
||||
var LONG_AVERAGING_RATIO = 0.75;
|
||||
var LOUDNESS_FLOOR = 11.0;
|
||||
var LOUDNESS_SCALE = 2.8 / 5.0;
|
||||
var LOG2 = Math.log(2.0);
|
||||
var myData = {}; // we're not includied in ExtendedOverlay.get.
|
||||
|
||||
function scaleAudio(val) {
|
||||
var audioLevel = 0.0;
|
||||
if (val <= LOUDNESS_FLOOR) {
|
||||
audioLevel = val / LOUDNESS_FLOOR * LOUDNESS_SCALE;
|
||||
} else {
|
||||
audioLevel = (val -(LOUDNESS_FLOOR -1 )) * LOUDNESS_SCALE;
|
||||
}
|
||||
if (audioLevel > 1.0) {
|
||||
audioLevel = 1;
|
||||
}
|
||||
return audioLevel;
|
||||
}
|
||||
function getAudioLevel(id) {
|
||||
// the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged
|
||||
// But of course it gets the data at a different rate, so we tweak the averaging ratio and frequency
|
||||
// of updating (the latter for efficiency too).
|
||||
var avatar = AvatarList.getAvatar(id);
|
||||
var audioLevel = 0.0;
|
||||
var avgAudioLevel = 0.0;
|
||||
var data = id ? ExtendedOverlay.get(id) : myData;
|
||||
if (!data) {
|
||||
return audioLevel;
|
||||
}
|
||||
if (data) {
|
||||
|
||||
// we will do exponential moving average by taking some the last loudness and averaging
|
||||
data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness);
|
||||
// we will do exponential moving average by taking some the last loudness and averaging
|
||||
data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness);
|
||||
data.longAccumulatedLevel = LONG_AVERAGING_RATIO * (data.longAccumulatedLevel || 0) + (1 - LONG_AVERAGING_RATIO) * (avatar.audioLoudness);
|
||||
|
||||
// add 1 to insure we don't go log() and hit -infinity. Math.log is
|
||||
// natural log, so to get log base 2, just divide by ln(2).
|
||||
var logLevel = Math.log(data.accumulatedLevel + 1) / LOG2;
|
||||
// add 1 to insure we don't go log() and hit -infinity. Math.log is
|
||||
// natural log, so to get log base 2, just divide by ln(2).
|
||||
audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2);
|
||||
avgAudioLevel = scaleAudio(Math.log(data.longAccumulatedLevel + 1) / LOG2);
|
||||
|
||||
if (logLevel <= LOUDNESS_FLOOR) {
|
||||
audioLevel = logLevel / LOUDNESS_FLOOR * LOUDNESS_SCALE;
|
||||
} else {
|
||||
audioLevel = (logLevel - (LOUDNESS_FLOOR - 1.0)) * LOUDNESS_SCALE;
|
||||
data.audioLevel = audioLevel;
|
||||
data.averageAudioLevel = avgAudioLevel;
|
||||
}
|
||||
if (audioLevel > 1.0) {
|
||||
audioLevel = 1;
|
||||
}
|
||||
data.audioLevel = audioLevel;
|
||||
return audioLevel;
|
||||
return [audioLevel, avgAudioLevel];
|
||||
}
|
||||
|
||||
function createAudioInterval(interval) {
|
||||
|
|
Loading…
Reference in a new issue