Merge branch 'master' of https://github.com/highfidelity/hifi into avatarBandwidthBudgetImprovements

Conflicts:
	libraries/avatars/src/AvatarData.cpp
This commit is contained in:
Brad Hefta-Gaub 2017-02-23 13:50:16 -08:00
commit 1b7ec7d61e
20 changed files with 281 additions and 87 deletions

View file

@ -148,13 +148,22 @@ MyAvatar::MyAvatar(RigPointer rig) :
auto player = DependencyManager::get<Deck>(); auto player = DependencyManager::get<Deck>();
auto recorder = DependencyManager::get<Recorder>(); auto recorder = DependencyManager::get<Recorder>();
connect(player.data(), &Deck::playbackStateChanged, [=] { connect(player.data(), &Deck::playbackStateChanged, [=] {
if (player->isPlaying()) { bool isPlaying = player->isPlaying();
if (isPlaying) {
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>(); auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
if (recordingInterface->getPlayFromCurrentLocation()) { if (recordingInterface->getPlayFromCurrentLocation()) {
setRecordingBasis(); setRecordingBasis();
} }
} else { } else {
clearRecordingBasis(); clearRecordingBasis();
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
}
auto audioIO = DependencyManager::get<AudioClient>();
audioIO->setIsPlayingBackRecording(isPlaying);
if (_rig) {
_rig->setEnableAnimations(!isPlaying);
} }
}); });
@ -180,8 +189,8 @@ MyAvatar::MyAvatar(RigPointer rig) :
if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() && if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&
(dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) { (dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {
// FIXME
//myAvatar->useFullAvatarURL() setSkeletonModelURL(dummyAvatar.getSkeletonModelURL());
} }
if (recordingInterface->getPlayerUseDisplayName() && dummyAvatar.getDisplayName() != getDisplayName()) { if (recordingInterface->getPlayerUseDisplayName() && dummyAvatar.getDisplayName() != getDisplayName()) {
@ -204,6 +213,11 @@ MyAvatar::MyAvatar(RigPointer rig) :
// head orientation // head orientation
_headData->setLookAtPosition(headData->getLookAtPosition()); _headData->setLookAtPosition(headData->getLookAtPosition());
} }
auto jointData = dummyAvatar.getRawJointData();
if (jointData.length() > 0 && _rig) {
_rig->copyJointsFromJointData(jointData);
}
}); });
connect(rig.get(), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete())); connect(rig.get(), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete()));
@ -471,8 +485,10 @@ void MyAvatar::simulate(float deltaTime) {
{ {
PerformanceTimer perfTimer("joints"); PerformanceTimer perfTimer("joints");
// copy out the skeleton joints from the model // copy out the skeleton joints from the model
if (_rigEnabled) {
_rig->copyJointsIntoJointData(_jointData); _rig->copyJointsIntoJointData(_jointData);
} }
}
{ {
PerformanceTimer perfTimer("head"); PerformanceTimer perfTimer("head");

View file

@ -485,6 +485,7 @@ private:
std::unordered_set<int> _headBoneSet; std::unordered_set<int> _headBoneSet;
RigPointer _rig; RigPointer _rig;
bool _prevShouldDrawHead; bool _prevShouldDrawHead;
bool _rigEnabled { true };
bool _enableDebugDrawDefaultPose { false }; bool _enableDebugDrawDefaultPose { false };
bool _enableDebugDrawAnimPose { false }; bool _enableDebugDrawAnimPose { false };

View file

@ -483,6 +483,10 @@ void Rig::setEnableInverseKinematics(bool enable) {
_enableInverseKinematics = enable; _enableInverseKinematics = enable;
} }
void Rig::setEnableAnimations(bool enable) {
_enabledAnimations = enable;
}
AnimPose Rig::getAbsoluteDefaultPose(int index) const { AnimPose Rig::getAbsoluteDefaultPose(int index) const {
if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) { if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) {
return _absoluteDefaultPoses[index]; return _absoluteDefaultPoses[index];
@ -907,7 +911,7 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
setModelOffset(rootTransform); setModelOffset(rootTransform);
if (_animNode) { if (_animNode && _enabledAnimations) {
PerformanceTimer perfTimer("handleTriggers"); PerformanceTimer perfTimer("handleTriggers");
updateAnimationStateHandlers(); updateAnimationStateHandlers();

View file

@ -210,6 +210,7 @@ public:
void computeAvatarBoundingCapsule(const FBXGeometry& geometry, float& radiusOut, float& heightOut, glm::vec3& offsetOut) const; void computeAvatarBoundingCapsule(const FBXGeometry& geometry, float& radiusOut, float& heightOut, glm::vec3& offsetOut) const;
void setEnableInverseKinematics(bool enable); void setEnableInverseKinematics(bool enable);
void setEnableAnimations(bool enable);
const glm::mat4& getGeometryToRigTransform() const { return _geometryToRigTransform; } const glm::mat4& getGeometryToRigTransform() const { return _geometryToRigTransform; }
@ -314,6 +315,7 @@ protected:
int32_t _numOverrides { 0 }; int32_t _numOverrides { 0 };
bool _lastEnableInverseKinematics { true }; bool _lastEnableInverseKinematics { true };
bool _enableInverseKinematics { true }; bool _enableInverseKinematics { true };
bool _enabledAnimations { true };
mutable uint32_t _jointNameWarningCount { 0 }; mutable uint32_t _jointNameWarningCount { 0 };

View file

@ -39,13 +39,10 @@
#include <plugins/CodecPlugin.h> #include <plugins/CodecPlugin.h>
#include <plugins/PluginManager.h> #include <plugins/PluginManager.h>
#include <udt/PacketHeaders.h> #include <udt/PacketHeaders.h>
#include <PositionalAudioStream.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <UUID.h>
#include <Transform.h> #include <Transform.h>
#include "PositionalAudioStream.h"
#include "AudioClientLogging.h" #include "AudioClientLogging.h"
#include "AudioLogging.h" #include "AudioLogging.h"
@ -294,12 +291,12 @@ QString friendlyNameForAudioDevice(IMMDevice* pEndpoint) {
IPropertyStore* pPropertyStore; IPropertyStore* pPropertyStore;
pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore);
pEndpoint->Release(); pEndpoint->Release();
pEndpoint = NULL; pEndpoint = nullptr;
PROPVARIANT pv; PROPVARIANT pv;
PropVariantInit(&pv); PropVariantInit(&pv);
HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
pPropertyStore->Release(); pPropertyStore->Release();
pPropertyStore = NULL; pPropertyStore = nullptr;
deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal);
if (!IsWindows8OrGreater()) { if (!IsWindows8OrGreater()) {
// Windows 7 provides only the 31 first characters of the device name. // Windows 7 provides only the 31 first characters of the device name.
@ -313,9 +310,9 @@ QString friendlyNameForAudioDevice(IMMDevice* pEndpoint) {
QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) { QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) {
QString deviceName; QString deviceName;
HRESULT hr = S_OK; HRESULT hr = S_OK;
CoInitialize(NULL); CoInitialize(nullptr);
IMMDeviceEnumerator* pMMDeviceEnumerator = NULL; IMMDeviceEnumerator* pMMDeviceEnumerator = nullptr;
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator);
IMMDevice* pEndpoint; IMMDevice* pEndpoint;
hr = pMMDeviceEnumerator->GetDevice(guid, &pEndpoint); hr = pMMDeviceEnumerator->GetDevice(guid, &pEndpoint);
if (hr == E_NOTFOUND) { if (hr == E_NOTFOUND) {
@ -325,7 +322,7 @@ QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) {
deviceName = ::friendlyNameForAudioDevice(pEndpoint); deviceName = ::friendlyNameForAudioDevice(pEndpoint);
} }
pMMDeviceEnumerator->Release(); pMMDeviceEnumerator->Release();
pMMDeviceEnumerator = NULL; pMMDeviceEnumerator = nullptr;
CoUninitialize(); CoUninitialize();
return deviceName; return deviceName;
} }
@ -968,8 +965,7 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
} }
void AudioClient::handleAudioInput() { void AudioClient::handleAudioInput() {
if (!_inputDevice || _isPlayingBackRecording) {
if (!_inputDevice) {
return; return;
} }

View file

@ -147,6 +147,8 @@ public:
void setPositionGetter(AudioPositionGetter positionGetter) { _positionGetter = positionGetter; } void setPositionGetter(AudioPositionGetter positionGetter) { _positionGetter = positionGetter; }
void setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; } void setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; }
void setIsPlayingBackRecording(bool isPlayingBackRecording) { _isPlayingBackRecording = isPlayingBackRecording; }
Q_INVOKABLE void setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 scale); Q_INVOKABLE void setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 scale);
void checkDevices(); void checkDevices();
@ -369,10 +371,12 @@ private:
QVector<QString> _inputDevices; QVector<QString> _inputDevices;
QVector<QString> _outputDevices; QVector<QString> _outputDevices;
bool _hasReceivedFirstPacket = false; bool _hasReceivedFirstPacket { false };
QVector<AudioInjector*> _activeLocalAudioInjectors; QVector<AudioInjector*> _activeLocalAudioInjectors;
bool _isPlayingBackRecording { false };
CodecPluginPointer _codec; CodecPluginPointer _codec;
QString _selectedCodecName; QString _selectedCodecName;
Encoder* _encoder { nullptr }; // for outbound mic stream Encoder* _encoder { nullptr }; // for outbound mic stream

View file

@ -91,4 +91,4 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt
qCWarning(audio) << "Unknown audio injector option:" << it.name(); qCWarning(audio) << "Unknown audio injector option:" << it.name();
} }
} }
} }

View file

@ -37,6 +37,7 @@
#include <ShapeInfo.h> #include <ShapeInfo.h>
#include <AudioHelpers.h> #include <AudioHelpers.h>
#include <Profile.h> #include <Profile.h>
#include <VariantMapToScriptValue.h>
#include "AvatarLogging.h" #include "AvatarLogging.h"
@ -2379,3 +2380,37 @@ std::priority_queue<AvatarPriority> AvatarData::sortAvatars(
} }
return sortedAvatars; return sortedAvatars;
} }
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
QScriptValue obj = engine->newObject();
for (auto entityID : value.keys()) {
QByteArray entityProperties = value.value(entityID);
QJsonDocument jsonEntityProperties = QJsonDocument::fromBinaryData(entityProperties);
if (!jsonEntityProperties.isObject()) {
qCDebug(avatars) << "bad AvatarEntityData in AvatarEntityMap" << QString(entityProperties.toHex());
}
QVariant variantEntityProperties = jsonEntityProperties.toVariant();
QVariantMap entityPropertiesMap = variantEntityProperties.toMap();
QScriptValue scriptEntityProperties = variantMapToScriptValue(entityPropertiesMap, *engine);
QString key = entityID.toString();
obj.setProperty(key, scriptEntityProperties);
}
return obj;
}
void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value) {
QScriptValueIterator itr(object);
while (itr.hasNext()) {
itr.next();
QUuid EntityID = QUuid(itr.name());
QScriptValue scriptEntityProperties = itr.value();
QVariant variantEntityProperties = scriptEntityProperties.toVariant();
QJsonDocument jsonEntityProperties = QJsonDocument::fromVariant(variantEntityProperties);
QByteArray binaryEntityProperties = jsonEntityProperties.toBinaryData();
value[EntityID] = binaryEntityProperties;
}
}

View file

@ -46,6 +46,7 @@ typedef unsigned long long quint64;
#include <QVariantMap> #include <QVariantMap>
#include <QVector> #include <QVector>
#include <QtScript/QScriptable> #include <QtScript/QScriptable>
#include <QtScript/QScriptValueIterator>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <JointData.h> #include <JointData.h>
@ -847,6 +848,11 @@ Q_DECLARE_METATYPE(RayToAvatarIntersectionResult)
QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& results); QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& results);
void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, RayToAvatarIntersectionResult& results); void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, RayToAvatarIntersectionResult& results);
Q_DECLARE_METATYPE(AvatarEntityMap)
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value);
void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value);
// faux joint indexes (-1 means invalid) // faux joint indexes (-1 means invalid)
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534; // -2 const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534; // -2
const int CONTROLLER_RIGHTHAND_INDEX = 65533; // -3 const int CONTROLLER_RIGHTHAND_INDEX = 65533; // -3

View file

@ -576,6 +576,7 @@ void ScriptEngine::init() {
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
qScriptRegisterMetaType(this, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue); qScriptRegisterMetaType(this, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue);
qScriptRegisterMetaType(this, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this); qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this); qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this);

View file

@ -366,6 +366,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS
} }
if (root) { if (root) {
removeButtonsFromHomeScreen();
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL))); QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL)));
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl))); QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl)));

View file

@ -12,14 +12,14 @@
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include("/~/system/libraries/toolBars.js"); Script.include("/~/system/libraries/toolBars.js");
var recordingFile = "recording.rec"; var recordingFile = "recording.hfr";
function setPlayerOptions() { function setPlayerOptions() {
Recording.setPlayFromCurrentLocation(true); Recording.setPlayFromCurrentLocation(true);
Recording.setPlayerUseDisplayName(false); Recording.setPlayerUseDisplayName(false);
Recording.setPlayerUseAttachments(false); Recording.setPlayerUseAttachments(false);
Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseHeadModel(false);
Recording.setPlayerUseSkeletonModel(false); Recording.setPlayerUseSkeletonModel(true);
} }
var windowDimensions = Controller.getViewportDimensions(); var windowDimensions = Controller.getViewportDimensions();
@ -142,7 +142,6 @@ function setupTimer() {
backgroundAlpha: 1.0, backgroundAlpha: 1.0,
visible: true visible: true
}); });
} }
function updateTimer() { function updateTimer() {
@ -272,7 +271,7 @@ function mousePressEvent(event) {
} }
} else if (loadIcon === toolBar.clicked(clickedOverlay)) { } else if (loadIcon === toolBar.clicked(clickedOverlay)) {
if (!Recording.isRecording() && !Recording.isPlaying()) { if (!Recording.isRecording() && !Recording.isPlaying()) {
recordingFile = Window.browse("Load recorcding from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)"); recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
Recording.loadRecording(recordingFile); Recording.loadRecording(recordingFile);
} }
@ -345,5 +344,3 @@ Script.scriptEnding.connect(scriptEnding);
// Should be called last to put everything into position // Should be called last to put everything into position
moveUI(); moveUI();

View file

@ -16,19 +16,51 @@
var TABLET_BUTTON_NAME = "AUDIO"; var TABLET_BUTTON_NAME = "AUDIO";
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
var MUTE_ICONS = {
icon: "icons/tablet-icons/mic-mute-i.svg",
activeIcon: "icons/tablet-icons/mic-mute-a.svg"
};
var UNMUTE_ICONS = {
icon: "icons/tablet-icons/mic-unmute-i.svg",
activeIcon: "icons/tablet-icons/mic-unmute-a.svg"
};
function onMuteToggled() { function onMuteToggled() {
button.editProperties({ isActive: AudioDevice.getMuted() }); if (AudioDevice.getMuted()) {
button.editProperties(MUTE_ICONS);
} else {
button.editProperties(UNMUTE_ICONS);
}
} }
function onClicked(){
var shouldActivateButton = false;
var onAudioScreen = false;
function onClicked() {
if (onAudioScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
var entity = HMD.tabletID; var entity = HMD.tabletID;
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
shouldActivateButton = true;
tablet.gotoMenuScreen("Audio"); tablet.gotoMenuScreen("Audio");
onAudioScreen = true;
}
}
function onScreenChanged(type, url) {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onAudioScreen = false;
} }
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({ var button = tablet.addButton({
icon: "icons/tablet-icons/mic-unmute-i.svg", icon: AudioDevice.getMuted() ? MUTE_ICONS.icon : UNMUTE_ICONS.icon,
activeIcon: "icons/tablet-icons/mic-mute-a.svg", activeIcon: AudioDevice.getMuted() ? MUTE_ICONS.activeIcon : UNMUTE_ICONS.activeIcon,
text: TABLET_BUTTON_NAME, text: TABLET_BUTTON_NAME,
sortOrder: 1 sortOrder: 1
}); });
@ -36,10 +68,12 @@ var button = tablet.addButton({
onMuteToggled(); onMuteToggled();
button.clicked.connect(onClicked); button.clicked.connect(onClicked);
tablet.screenChanged.connect(onScreenChanged);
AudioDevice.muteToggled.connect(onMuteToggled); AudioDevice.muteToggled.connect(onMuteToggled);
Script.scriptEnding.connect(function () { Script.scriptEnding.connect(function () {
button.clicked.disconnect(onClicked); button.clicked.disconnect(onClicked);
tablet.screenChanged.disconnect(onScreenChanged);
AudioDevice.muteToggled.disconnect(onMuteToggled); AudioDevice.muteToggled.disconnect(onMuteToggled);
tablet.removeButton(button); tablet.removeButton(button);
}); });

View file

@ -1233,7 +1233,13 @@ function MyController(hand) {
}); });
if (grabbableEntities.length > 0) { if (grabbableEntities.length > 0) {
if (!this.grabPointIntersectsEntity) { if (!this.grabPointIntersectsEntity) {
// don't do haptic pulse for tablet
var nonTabletEntities = grabbableEntities.filter(function(entityID) {
return entityID != HMD.tabletID && entityID != HMD.homeButtonID;
});
if (nonTabletEntities.length > 0) {
Controller.triggerHapticPulse(1, 20, this.hand); Controller.triggerHapticPulse(1, 20, this.hand);
}
this.grabPointIntersectsEntity = true; this.grabPointIntersectsEntity = true;
this.grabPointSphereOn(); this.grabPointSphereOn();
} }

View file

@ -49,24 +49,30 @@ function calcSpawnInfo(hand, height) {
var handController = getControllerWorldLocation(hand, true); var handController = getControllerWorldLocation(hand, true);
var controllerPosition = handController.position; var controllerPosition = handController.position;
// compute the angle of the chord with length (height / 2) // base of the tablet is slightly above controller position
var theta = Math.asin(height / (2 * Vec3.distance(headPos, controllerPosition))); var TABLET_BASE_DISPLACEMENT = {x: 0, y: 0.1, z: 0};
var tabletBase = Vec3.sum(controllerPosition, TABLET_BASE_DISPLACEMENT);
// then we can use this angle to rotate the vector between the HMD position and the center of the tablet. var d = Vec3.subtract(headPos, tabletBase);
// this vector, u, will become our new look at direction. var theta = Math.acos(d.y / Vec3.length(d));
var d = Vec3.normalize(Vec3.subtract(headPos, controllerPosition)); d.y = 0;
if (Vec3.length(d) < 0.0001) {
d = {x: 1, y: 0, z: 0};
} else {
d = Vec3.normalize(d);
}
var w = Vec3.normalize(Vec3.cross(Y_AXIS, d)); var w = Vec3.normalize(Vec3.cross(Y_AXIS, d));
var q = Quat.angleAxis(theta * (180 / Math.PI), w); var ANGLE_OFFSET = 25;
var q = Quat.angleAxis(theta * (180 / Math.PI) - (90 - ANGLE_OFFSET), w);
var u = Vec3.multiplyQbyV(q, d); var u = Vec3.multiplyQbyV(q, d);
// use u to compute a full lookAt quaternion. // use u to compute a full lookAt quaternion.
var lookAtRot = Quat.lookAt(controllerPosition, Vec3.sum(controllerPosition, u), Y_AXIS); var lookAtRot = Quat.lookAt(tabletBase, Vec3.sum(tabletBase, u), Y_AXIS);
var yDisplacement = (height / 2);
// adjust the tablet position by a small amount.
var yDisplacement = (height / 2) + 0.1;
var zDisplacement = 0.05; var zDisplacement = 0.05;
var tabletOffset = Vec3.multiplyQbyV(lookAtRot, {x: 0, y: yDisplacement, z: zDisplacement}); var tabletOffset = Vec3.multiplyQbyV(lookAtRot, {x: 0, y: yDisplacement, z: zDisplacement});
finalPosition = Vec3.sum(controllerPosition, tabletOffset); finalPosition = Vec3.sum(tabletBase, tabletOffset);
return { return {
position: finalPosition, position: finalPosition,
rotation: lookAtRot rotation: lookAtRot

View file

@ -52,10 +52,16 @@ function onMessageBoxClosed(id, button) {
Window.messageBoxClosed.connect(onMessageBoxClosed); Window.messageBoxClosed.connect(onMessageBoxClosed);
var shouldActivateButton = false;
var onMarketplaceScreen = false;
function showMarketplace() { function showMarketplace() {
UserActivityLogger.openedMarketplace(); UserActivityLogger.openedMarketplace();
shouldActivateButton = true;
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
onMarketplaceScreen = true;
tablet.webEventReceived.connect(function (message) { tablet.webEventReceived.connect(function (message) {
if (message === GOTO_DIRECTORY) { if (message === GOTO_DIRECTORY) {
@ -98,15 +104,10 @@ function showMarketplace() {
}); });
} }
function toggleMarketplace() {
var entity = HMD.tabletID;
Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})});
showMarketplace();
}
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var marketplaceButton = tablet.addButton({ var marketplaceButton = tablet.addButton({
icon: "icons/tablet-icons/market-i.svg", icon: "icons/tablet-icons/market-i.svg",
activeIcon: "icons/tablet-icons/market-a.svg",
text: "MARKET", text: "MARKET",
sortOrder: 9 sortOrder: 9
}); });
@ -117,16 +118,30 @@ function onCanWriteAssetsChanged() {
} }
function onClick() { function onClick() {
toggleMarketplace(); if (onMarketplaceScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
var entity = HMD.tabletID;
Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})});
showMarketplace();
}
}
function onScreenChanged(type, url) {
// for toolbar mode: change button to active when window is first openend, false otherwise.
marketplaceButton.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onMarketplaceScreen = false;
} }
marketplaceButton.clicked.connect(onClick); marketplaceButton.clicked.connect(onClick);
tablet.screenChanged.connect(onScreenChanged);
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
Script.scriptEnding.connect(function () { Script.scriptEnding.connect(function () {
if (tablet) {
tablet.removeButton(marketplaceButton); tablet.removeButton(marketplaceButton);
} tablet.screenChanged.disconnect(onScreenChanged);
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);
}); });

View file

@ -10,26 +10,46 @@
// //
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
//var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; // var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
(function() { (function() {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({ var button = tablet.addButton({
icon: "icons/tablet-icons/menu-i.svg", icon: "icons/tablet-icons/menu-i.svg",
activeIcon: "icons/tablet-icons/menu-a.svg",
text: "MENU", text: "MENU",
sortOrder: 3 sortOrder: 3
}); });
var shouldActivateButton = false;
var onMenuScreen = false;
function onClicked() { function onClicked() {
if (onMenuScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
var entity = HMD.tabletID; var entity = HMD.tabletID;
Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})}); Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})});
shouldActivateButton = true;
tablet.gotoMenuScreen(); tablet.gotoMenuScreen();
onMenuScreen = true;
}
}
function onScreenChanged(type, url) {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onMenuScreen = false;
} }
button.clicked.connect(onClicked); button.clicked.connect(onClicked);
tablet.screenChanged.connect(onScreenChanged);
Script.scriptEnding.connect(function () { Script.scriptEnding.connect(function () {
button.clicked.disconnect(onClicked); button.clicked.disconnect(onClicked);
tablet.removeButton(button); tablet.removeButton(button);
tablet.screenChanged.disconnect(onScreenChanged);
}); });
}()); }());

View file

@ -477,23 +477,17 @@ var button;
var buttonName = "PEOPLE"; var buttonName = "PEOPLE";
var tablet = null; var tablet = null;
function onTabletScreenChanged(type, url) {
if (type !== "QML" || url !== "../Pal.qml") {
off();
}
}
function startup() { function startup() {
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
button = tablet.addButton({ button = tablet.addButton({
text: buttonName, text: buttonName,
icon: "icons/tablet-icons/people-i.svg", icon: "icons/tablet-icons/people-i.svg",
activeIcon: "icons/tablet-icons/people-a.svg",
sortOrder: 7 sortOrder: 7
}); });
tablet.fromQml.connect(fromQml); tablet.fromQml.connect(fromQml);
button.clicked.connect(onTabletButtonClicked); button.clicked.connect(onTabletButtonClicked);
tablet.screenChanged.connect(onTabletScreenChanged); tablet.screenChanged.connect(onTabletScreenChanged);
Users.usernameFromIDReply.connect(usernameFromIDReply); Users.usernameFromIDReply.connect(usernameFromIDReply);
Window.domainChanged.connect(clearLocalQMLDataAndClosePAL); Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);
@ -524,8 +518,17 @@ function off() {
Users.requestsDomainListData = false; Users.requestsDomainListData = false;
} }
var onPalScreen = false;
var shouldActivateButton = false;
function onTabletButtonClicked() { function onTabletButtonClicked() {
if (onPalScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
shouldActivateButton = true;
tablet.loadQMLSource("../Pal.qml"); tablet.loadQMLSource("../Pal.qml");
onPalScreen = true;
Users.requestsDomainListData = true; Users.requestsDomainListData = true;
populateUserList(); populateUserList();
isWired = true; isWired = true;
@ -535,6 +538,19 @@ function onTabletButtonClicked() {
triggerMapping.enable(); triggerMapping.enable();
triggerPressMapping.enable(); triggerPressMapping.enable();
audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS); audioTimer = createAudioInterval(conserveResources ? AUDIO_LEVEL_CONSERVED_UPDATE_INTERVAL_MS : AUDIO_LEVEL_UPDATE_INTERVAL_MS);
}
}
function onTabletScreenChanged(type, url) {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onPalScreen = false;
// disable sphere overlays when not on pal screen.
if (type !== "QML" || url !== "../Pal.qml") {
off();
}
} }
// //
@ -621,14 +637,12 @@ function shutdown() {
button.clicked.disconnect(onTabletButtonClicked); button.clicked.disconnect(onTabletButtonClicked);
tablet.removeButton(button); tablet.removeButton(button);
tablet.screenChanged.disconnect(onTabletScreenChanged); tablet.screenChanged.disconnect(onTabletScreenChanged);
Users.usernameFromIDReply.disconnect(usernameFromIDReply); Users.usernameFromIDReply.disconnect(usernameFromIDReply);
Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL); Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL);
Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL);
Messages.subscribe(CHANNEL); Messages.subscribe(CHANNEL);
Messages.messageReceived.disconnect(receiveMessage); Messages.messageReceived.disconnect(receiveMessage);
Users.avatarDisconnected.disconnect(avatarDisconnected); Users.avatarDisconnected.disconnect(avatarDisconnected);
off(); off();
} }

View file

@ -14,10 +14,27 @@
(function() { // BEGIN LOCAL_SCOPE (function() { // BEGIN LOCAL_SCOPE
var gotoQmlSource = "TabletAddressDialog.qml"; var gotoQmlSource = "TabletAddressDialog.qml";
var buttonName = "GOTO"; var buttonName = "GOTO";
var onGotoScreen = false;
var shouldActivateButton = false;
function onClicked(){ function onClicked() {
if (onGotoScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
shouldActivateButton = true;
tablet.loadQMLSource(gotoQmlSource); tablet.loadQMLSource(gotoQmlSource);
onGotoScreen = true;
} }
}
function onScreenChanged(type, url) {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onGotoScreen = false;
}
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({ var button = tablet.addButton({
icon: "icons/tablet-icons/goto-i.svg", icon: "icons/tablet-icons/goto-i.svg",
@ -27,12 +44,12 @@
}); });
button.clicked.connect(onClicked); button.clicked.connect(onClicked);
tablet.screenChanged.connect(onScreenChanged);
Script.scriptEnding.connect(function () { Script.scriptEnding.connect(function () {
button.clicked.disconnect(onClicked); button.clicked.disconnect(onClicked);
if (tablet) {
tablet.removeButton(button); tablet.removeButton(button);
} tablet.screenChanged.disconnect(onScreenChanged);
}); });
}()); // END LOCAL_SCOPE }()); // END LOCAL_SCOPE

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
// //
// users.js // tablet-users.js
// //
// Created by Faye Li on 18 Jan 2017. // Created by Faye Li on 18 Jan 2017.
// Copyright 2017 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
@ -36,16 +36,34 @@
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({ var button = tablet.addButton({
icon: "icons/tablet-icons/users-i.svg", icon: "icons/tablet-icons/users-i.svg",
activeIcon: "icons/tablet-icons/users-a.svg",
text: "USERS", text: "USERS",
sortOrder: 11 sortOrder: 11
}); });
var onUsersScreen = false;
var shouldActivateButton = false;
function onClicked() { function onClicked() {
if (onUsersScreen) {
// for toolbar-mode: go back to home screen, this will close the window.
tablet.gotoHomeScreen();
} else {
var tabletEntity = HMD.tabletID; var tabletEntity = HMD.tabletID;
if (tabletEntity) { if (tabletEntity) {
Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})});
} }
shouldActivateButton = true;
tablet.gotoWebScreen(USERS_URL); tablet.gotoWebScreen(USERS_URL);
onUsersScreen = true;
}
}
function onScreenChanged() {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onUsersScreen = false;
} }
function onWebEventReceived(event) { function onWebEventReceived(event) {
@ -94,6 +112,7 @@
button.clicked.connect(onClicked); button.clicked.connect(onClicked);
tablet.webEventReceived.connect(onWebEventReceived); tablet.webEventReceived.connect(onWebEventReceived);
tablet.screenChanged.connect(onScreenChanged);
function cleanup() { function cleanup() {
button.clicked.disconnect(onClicked); button.clicked.disconnect(onClicked);