Merge branch 'tablet-ui-tablet-is-overlay' of github.com:sethalves/hifi into tablet-ui-edit-js-tablet-as-overlay

This commit is contained in:
Seth Alves 2017-02-24 14:27:30 -08:00
commit fcd3c09404
14 changed files with 122 additions and 67 deletions

View file

@ -384,18 +384,20 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
if (includeThisAvatar) {
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
numAvatarDataBytes += avatarPacketList->write(bytes);
_stats.numOthersIncluded++;
// increment the number of avatars sent to this reciever
nodeData->incrementNumAvatarsSentLastFrame();
if (detail != AvatarData::NoData) {
_stats.numOthersIncluded++;
// set the last sent sequence number for this sender on the receiver
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
otherNodeData->getLastReceivedSequenceNumber());
// increment the number of avatars sent to this reciever
nodeData->incrementNumAvatarsSentLastFrame();
// remember the last time we sent details about this other node to the receiver
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
// set the last sent sequence number for this sender on the receiver
nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(),
otherNodeData->getLastReceivedSequenceNumber());
// remember the last time we sent details about this other node to the receiver
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
}
}
avatarPacketList->endSegment();

View file

@ -13,6 +13,7 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import Qt.labs.settings 1.0
import "../styles-uit"
import "../controls-uit" as HifiControls
@ -29,7 +30,9 @@ 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 int actionButtonAllowance: actionButtonWidth * 2
property int minNameCardWidth: palContainer.width - (actionButtonAllowance * 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth
property int nameCardWidth: minNameCardWidth + (iAmAdmin ? 0 : actionButtonAllowance)
property var myData: ({displayName: "", userName: "", audioLevel: 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.
@ -52,6 +55,16 @@ Rectangle {
letterboxMessage.visible = true
letterboxMessage.popupRadius = 0
}
Settings {
id: settings
category: "pal"
property bool filtered: false
property int nearDistance: 30
}
function refreshWithFilter() {
// We should just be able to set settings.filtered to filter.checked, but see #3249, so send to .js for saving.
pal.sendToScript({method: 'refresh', params: {filter: filter.checked && {distance: settings.nearDistance}}});
}
// This is the container for the PAL
Rectangle {
@ -88,11 +101,32 @@ Rectangle {
audioLevel: myData.audioLevel
isMyCard: true
// Size
width: nameCardWidth
width: minNameCardWidth
height: parent.height
// Anchors
anchors.left: parent.left
}
Row {
HifiControls.CheckBox {
id: filter
checked: settings.filtered
text: "in view"
boxSize: reload.height * 0.70
onCheckedChanged: refreshWithFilter()
}
HifiControls.GlyphButton {
id: reload
glyph: hifi.glyphs.reload
width: reload.height
onClicked: refreshWithFilter()
}
spacing: 50
anchors {
right: parent.right
top: parent.top
topMargin: 10
}
}
}
// Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle
Rectangle {
@ -306,45 +340,7 @@ Rectangle {
}
}
}
// Refresh button
Rectangle {
// Size
width: hifi.dimensions.tableHeaderHeight-1
height: hifi.dimensions.tableHeaderHeight-1
// Anchors
anchors.left: table.left
anchors.leftMargin: 4
anchors.top: table.top
// Style
color: hifi.colors.tableBackgroundLight
// Actual refresh icon
HiFiGlyphs {
id: reloadButton
text: hifi.glyphs.reloadSmall
// Size
size: parent.width*1.5
// Anchors
anchors.fill: parent
// Style
horizontalAlignment: Text.AlignHCenter
color: hifi.colors.darkGray
}
MouseArea {
id: reloadButtonArea
// Anchors
anchors.fill: parent
hoverEnabled: true
// Everyone likes a responsive refresh button!
// So use onPressed instead of onClicked
onPressed: {
reloadButton.color = hifi.colors.lightGrayText
pal.sendToScript({method: 'refresh'})
}
onReleased: reloadButton.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray)
onEntered: reloadButton.color = hifi.colors.baseGrayHighlight
onExited: reloadButton.color = (pressed ? hifi.colors.lightGrayText: hifi.colors.darkGray)
}
}
// Separator between user and admin functions
Rectangle {
// Size
@ -501,7 +497,7 @@ Rectangle {
if (alreadyRefreshed === true) {
letterbox('', '', 'The last editor of this object is either you or not among this list of users.');
} else {
pal.sendToScript({method: 'refresh', params: message.params});
pal.sendToScript({method: 'refresh', params: {selected: message.params}});
}
} else {
// If we've already refreshed the PAL and found the avatar in the model

View file

@ -192,6 +192,8 @@ QVariantMap Camera::getViewFrustum() {
result["orientation"].setValue(frustum.getOrientation());
result["projection"].setValue(frustum.getProjection());
result["centerRadius"].setValue(frustum.getCenterRadius());
result["fieldOfView"].setValue(frustum.getFieldOfView());
result["aspectRatio"].setValue(frustum.getAspectRatio());
return result;
}

View file

@ -85,7 +85,7 @@ AvatarManager::AvatarManager(QObject* parent) :
// immediately remove that avatar instead of waiting for the absence of packets from avatar mixer
connect(nodeList.data(), &NodeList::ignoredNode, this, [=](const QUuid& nodeID, bool enabled) {
if (enabled) {
removeAvatar(nodeID);
removeAvatar(nodeID, KillAvatarReason::AvatarIgnored);
}
});
}

View file

@ -259,6 +259,8 @@ bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3
}
void Base3DOverlay::locationChanged(bool tellPhysics) {
SpatiallyNestable::locationChanged(tellPhysics);
auto itemID = getRenderItemID();
if (render::Item::isValidID(itemID)) {
render::ScenePointer scene = qApp->getMain3DScene();
@ -266,8 +268,6 @@ void Base3DOverlay::locationChanged(bool tellPhysics) {
pendingChanges.updateItem(itemID);
scene->enqueuePendingChanges(pendingChanges);
}
// Overlays can't currently have children.
// SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also
}
void Base3DOverlay::parentDeleted() {

View file

@ -53,7 +53,7 @@ namespace render {
return overlay->getBounds();
}
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
// MAgic number while we are defining the layering mechanism:
// Magic number while we are defining the layering mechanism:
const int LAYER_NO_AA = 3;
const int LAYER_2D = 2;
const int LAYER_3D_FRONT = 1;

View file

@ -182,7 +182,7 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo
void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
qCDebug(avatars) << "Removed avatar with UUID" << uuidStringWithoutCurlyBraces(removedAvatar->getSessionUUID())
<< "from AvatarHashMap";
<< "from AvatarHashMap" << removalReason;
emit avatarRemovedEvent(removedAvatar->getSessionUUID());
}

View file

@ -1419,8 +1419,7 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& pare
return;
}
parent->forEachChild([&](SpatiallyNestablePointer child) {
if (child->getParentJointIndex() == jointIndex &&
child->getNestableType() != NestableType::Overlay) {
if (child->getParentJointIndex() == jointIndex) {
result.push_back(child->getID());
}
});

View file

@ -44,6 +44,8 @@ public:
// Mutable, but must retain structure of vector
using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
bool isGeometryLoaded() const { return (bool)_fbxGeometry; }
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
const GeometryMeshes& getMeshes() const { return *_meshes; }
const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;

View file

@ -114,7 +114,7 @@ public:
void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
bool isLoaded() const { return (bool)_renderGeometry; }
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
bool isWireframe() const { return _isWireframe; }

View file

@ -150,7 +150,6 @@ signals:
private:
bool getRequestsDomainListData();
void setRequestsDomainListData(bool requests);
bool _requestsDomainListData;
};

View file

@ -3231,9 +3231,13 @@ function MyController(hand) {
}
_this.previouslyUnhooked[childID] = now;
// we don't know if it's an entity or an overlay
Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
Overlays.editOverlay(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
} else {
Entities.editEntity(childID, { parentID: NULL_UUID });
Overlays.editOverlay(childID, { parentID: NULL_UUID });
}
}
});

View file

@ -34,7 +34,7 @@ var TABLET_NATURAL_DIMENSIONS = {x: 33.797, y: 50.129, z: 2.269};
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png";
var TABLET_MODEL_PATH = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx";
// var TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx";
var LOCAL_TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx";
// returns object with two fields:
// * position - position in front of the user
@ -112,11 +112,18 @@ WebTablet = function (url, width, dpi, hand, clientOnly) {
this.dpi = DEFAULT_DPI * (DEFAULT_WIDTH / this.width);
}
var modelURL;
if (Settings.getValue("tabletVisibleToOthers")) {
modelURL = TABLET_MODEL_PATH;
} else {
modelURL = LOCAL_TABLET_MODEL_PATH;
}
var tabletProperties = {
name: "WebTablet Tablet",
type: "Model",
modelURL: TABLET_MODEL_PATH,
url: TABLET_MODEL_PATH, // for overlay
modelURL: modelURL,
url: modelURL, // for overlay
grabbable: true, // for overlay
userData: JSON.stringify({
"grabbableKey": {"grabbable": true}

View file

@ -37,6 +37,15 @@ var conserveResources = true;
Script.include("/~/system/libraries/controllers.js");
function projectVectorOntoPlane(normalizedVector, planeNormal) {
return Vec3.cross(planeNormal, Vec3.cross(normalizedVector, planeNormal));
}
function angleBetweenVectorsInPlane(from, to, normal) {
var projectedFrom = projectVectorOntoPlane(from, normal);
var projectedTo = projectVectorOntoPlane(to, normal);
return Vec3.orientedAngle(projectedFrom, projectedTo, normal);
}
//
// Overlays.
//
@ -229,7 +238,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
break;
case 'refresh':
removeOverlays();
populateUserList(message.params);
// If filter is specified from .qml instead of through settings, update the settings.
if (message.params.filter !== undefined) {
Settings.setValue('pal/filtered', !!message.params.filter);
}
populateUserList(message.params.selected);
UserActivityLogger.palAction("refresh", "");
break;
case 'updateGain':
@ -271,13 +284,42 @@ function addAvatarNode(id) {
color: color(selected, false, 0.0),
ignoreRayIntersection: false}, selected, !conserveResources);
}
// Each open/refresh will capture a stable set of avatarsOfInterest, within the specified filter.
var avatarsOfInterest = {};
function populateUserList(selectData) {
var filter = Settings.getValue('pal/filtered') && {distance: Settings.getValue('pal/nearDistance')};
var data = [], avatars = AvatarList.getAvatarIdentifiers();
conserveResources = avatars.length > 20;
avatarsOfInterest = {};
var myPosition = filter && Camera.position,
frustum = filter && Camera.frustum,
verticalHalfAngle = filter && (frustum.fieldOfView / 2),
horizontalHalfAngle = filter && (verticalHalfAngle * frustum.aspectRatio),
orientation = filter && Camera.orientation,
front = filter && Quat.getFront(orientation),
verticalAngleNormal = filter && Quat.getRight(orientation),
horizontalAngleNormal = filter && Quat.getUp(orientation);
avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging
var avatar = AvatarList.getAvatar(id);
var name = avatar.sessionDisplayName;
if (!name) {
// Either we got a data packet but no identity yet, or something is really messed up. In any case,
// we won't be able to do anything with this user, so don't include them.
// In normal circumstances, a refresh will bring in the new user, but if we're very heavily loaded,
// we could be losing and gaining people randomly.
print('No avatar identity data for', id);
return;
}
if (id && myPosition && (Vec3.distance(avatar.position, myPosition) > filter.distance)) {
return;
}
var normal = id && filter && Vec3.normalize(Vec3.subtract(avatar.position, myPosition));
var horizontal = normal && angleBetweenVectorsInPlane(normal, front, horizontalAngleNormal);
var vertical = normal && angleBetweenVectorsInPlane(normal, front, verticalAngleNormal);
if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) {
return;
}
var avatarPalDatum = {
displayName: avatar.sessionDisplayName,
displayName: name,
userName: '',
sessionId: id || '',
audioLevel: 0.0,
@ -289,10 +331,12 @@ function populateUserList(selectData) {
addAvatarNode(id); // No overlay for ourselves
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
Users.requestUsernameFromID(id);
avatarsOfInterest[id] = true;
}
data.push(avatarPalDatum);
print('PAL data:', JSON.stringify(avatarPalDatum));
});
conserveResources = Object.keys(avatarsOfInterest).length > 20;
sendToQml({ method: 'users', params: data });
if (selectData) {
selectData[2] = true;
@ -317,8 +361,8 @@ var pingPong = true;
function updateOverlays() {
var eye = Camera.position;
AvatarList.getAvatarIdentifiers().forEach(function (id) {
if (!id) {
return; // don't update ourself
if (!id || !avatarsOfInterest[id]) {
return; // don't update ourself, or avatars we're not interested in
}
var avatar = AvatarList.getAvatar(id);
if (!avatar) {