mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 06:51:15 +02:00
merge upstream/master into andrew/bispinor
This commit is contained in:
commit
83d54eb46b
36 changed files with 1293 additions and 332 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -46,4 +46,6 @@ libraries/audio-client/external/*/*
|
|||
gvr-interface/assets/oculussig*
|
||||
gvr-interface/libs/*
|
||||
|
||||
TAGS
|
||||
# ignore files for various dev environments
|
||||
TAGS
|
||||
*.swp
|
||||
|
|
|
@ -549,14 +549,18 @@ void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const Hif
|
|||
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
} else if (mixerPacketType == PacketTypeMuteEnvironment) {
|
||||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
});
|
||||
SharedNodePointer sendingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (sendingNode->getCanAdjustLocks()) {
|
||||
QByteArray packet = receivedPacket;
|
||||
populatePacketHeader(packet, PacketTypeMuteEnvironment);
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() &&
|
||||
node->getLinkedData() && node != sendingNode) {
|
||||
nodeList->writeDatagram(packet, packet.size(), node);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
|
|
|
@ -508,18 +508,22 @@
|
|||
// To make this work we block the first mouseup event after the elements
|
||||
// received focus. If we block all mouseup events the user will not
|
||||
// be able to click within the selected text.
|
||||
// We also check to see if the value has changed to make sure we aren't
|
||||
// blocking a mouse-up event when clicking on an input spinner.
|
||||
var els = document.querySelectorAll("input, textarea");
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
var clicked = false;
|
||||
var originalText;
|
||||
els[i].onfocus = function() {
|
||||
originalText = this.value;
|
||||
this.select();
|
||||
clicked = false;
|
||||
};
|
||||
els[i].onmouseup = function(e) {
|
||||
if (!clicked) {
|
||||
if (!clicked && originalText == this.value) {
|
||||
e.preventDefault();
|
||||
clicked = true;
|
||||
}
|
||||
clicked = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,27 @@
|
|||
//
|
||||
|
||||
var createdRenderMenu = false;
|
||||
var createdGeneratedAudioMenu = false;
|
||||
|
||||
var ENTITIES_MENU = "Developer > Entities";
|
||||
var DEVELOPER_MENU = "Developer";
|
||||
|
||||
var ENTITIES_MENU = DEVELOPER_MENU + " > Entities";
|
||||
var COLLISION_UPDATES_TO_SERVER = "Don't send collision updates to server";
|
||||
|
||||
var RENDER_MENU = "Developer > Render";
|
||||
var RENDER_MENU = DEVELOPER_MENU + " > Render";
|
||||
var ENTITIES_ITEM = "Entities";
|
||||
var AVATARS_ITEM = "Avatars";
|
||||
|
||||
var AUDIO_MENU = DEVELOPER_MENU + " > Audio";
|
||||
var AUDIO_SOURCE_INJECT = "Generated Audio";
|
||||
var AUDIO_SOURCE_MENU = AUDIO_MENU + " > Generated Audio Source";
|
||||
var AUDIO_SOURCE_PINK_NOISE = "Pink Noise";
|
||||
var AUDIO_SOURCE_SINE_440 = "Sine 440hz";
|
||||
|
||||
|
||||
function setupMenus() {
|
||||
if (!Menu.menuExists("Developer")) {
|
||||
Menu.addMenu("Developer");
|
||||
if (!Menu.menuExists(DEVELOPER_MENU)) {
|
||||
Menu.addMenu(DEVELOPER_MENU);
|
||||
}
|
||||
if (!Menu.menuExists(ENTITIES_MENU)) {
|
||||
Menu.addMenu(ENTITIES_MENU);
|
||||
|
@ -54,6 +64,20 @@ function setupMenus() {
|
|||
if (!Menu.menuItemExists(RENDER_MENU, AVATARS_ITEM)) {
|
||||
Menu.addMenuItem({ menuName: RENDER_MENU, menuItemName: AVATARS_ITEM, isCheckable: true, isChecked: Scene.shouldRenderAvatars })
|
||||
}
|
||||
|
||||
|
||||
if (!Menu.menuExists(AUDIO_MENU)) {
|
||||
Menu.addMenu(AUDIO_MENU);
|
||||
}
|
||||
if (!Menu.menuItemExists(AUDIO_MENU, AUDIO_SOURCE_INJECT)) {
|
||||
Menu.addMenuItem({ menuName: AUDIO_MENU, menuItemName: AUDIO_SOURCE_INJECT, isCheckable: true, isChecked: false });
|
||||
Menu.addMenu(AUDIO_SOURCE_MENU);
|
||||
Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_PINK_NOISE, isCheckable: true, isChecked: false });
|
||||
Menu.addMenuItem({ menuName: AUDIO_SOURCE_MENU, menuItemName: AUDIO_SOURCE_SINE_440, isCheckable: true, isChecked: false });
|
||||
Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, true);
|
||||
Audio.selectPinkNoise();
|
||||
createdGeneratedAudioMenu = true;
|
||||
}
|
||||
}
|
||||
|
||||
Menu.menuItemEvent.connect(function (menuItem) {
|
||||
|
@ -67,7 +91,15 @@ Menu.menuItemEvent.connect(function (menuItem) {
|
|||
Scene.shouldRenderEntities = Menu.isOptionChecked(ENTITIES_ITEM);
|
||||
} else if (menuItem == AVATARS_ITEM) {
|
||||
Scene.shouldRenderAvatars = Menu.isOptionChecked(AVATARS_ITEM);
|
||||
}
|
||||
} else if (menuItem == AUDIO_SOURCE_INJECT && !createdGeneratedAudioMenu) {
|
||||
Audio.injectGeneratedNoise(Menu.isOptionChecked(AUDIO_SOURCE_INJECT));
|
||||
} else if (menuItem == AUDIO_SOURCE_PINK_NOISE && !createdGeneratedAudioMenu) {
|
||||
Audio.selectPinkNoise();
|
||||
Menu.setIsOptionChecked(AUDIO_SOURCE_SINE_440, false);
|
||||
} else if (menuItem == AUDIO_SOURCE_SINE_440 && !createdGeneratedAudioMenu) {
|
||||
Audio.selectSine440();
|
||||
Menu.setIsOptionChecked(AUDIO_SOURCE_PINK_NOISE, false);
|
||||
}
|
||||
});
|
||||
|
||||
Scene.shouldRenderAvatarsChanged.connect(function(shouldRenderAvatars) {
|
||||
|
@ -87,6 +119,12 @@ function scriptEnding() {
|
|||
Menu.removeMenuItem(RENDER_MENU, ENTITIES_ITEM);
|
||||
Menu.removeMenuItem(RENDER_MENU, AVATARS_ITEM);
|
||||
}
|
||||
|
||||
if (createdGeneratedAudioMenu) {
|
||||
Audio.injectGeneratedNoise(false);
|
||||
Menu.removeMenuItem(AUDIO_MENU, AUDIO_SOURCE_INJECT);
|
||||
Menu.removeMenu(AUDIO_SOURCE_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
setupMenus();
|
||||
|
|
|
@ -612,6 +612,10 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
// destroy the AudioClient so it and its thread have a chance to go down safely
|
||||
DependencyManager::destroy<AudioClient>();
|
||||
|
||||
#ifdef HAVE_DDE
|
||||
DependencyManager::destroy<DdeFaceTracker>();
|
||||
#endif
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
@ -1743,8 +1747,10 @@ FaceTracker* Application::getActiveFaceTracker() {
|
|||
void Application::setActiveFaceTracker() {
|
||||
#ifdef HAVE_FACESHIFT
|
||||
DependencyManager::get<Faceshift>()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_DDE
|
||||
DependencyManager::get<DdeFaceTracker>()->setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression));
|
||||
#endif
|
||||
#ifdef HAVE_VISAGE
|
||||
DependencyManager::get<Visage>()->updateEnabled();
|
||||
#endif
|
||||
|
@ -3713,17 +3719,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
}
|
||||
|
||||
// Download the FST file, to attempt to determine its model type
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qCDebug(interfaceapp) << "Downloading avatar file at " << url;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
QByteArray fstContents = reply->readAll();
|
||||
delete reply;
|
||||
QVariantHash fstMapping = FSTReader::readMapping(fstContents);
|
||||
QVariantHash fstMapping = FSTReader::downloadMapping(url);
|
||||
|
||||
FSTReader::ModelType modelType = FSTReader::predictModelType(fstMapping);
|
||||
|
||||
|
@ -3734,26 +3730,27 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
QPushButton* bodyButton = NULL;
|
||||
QPushButton* bodyAndHeadButton = NULL;
|
||||
|
||||
QString modelName = fstMapping["name"].toString();
|
||||
QString message;
|
||||
QString typeInfo;
|
||||
switch (modelType) {
|
||||
case FSTReader::HEAD_MODEL:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar head?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for your avatar head?");
|
||||
headButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
|
||||
break;
|
||||
|
||||
case FSTReader::BODY_ONLY_MODEL:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar body?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for your avatar body?");
|
||||
bodyButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
|
||||
break;
|
||||
|
||||
case FSTReader::HEAD_AND_BODY_MODEL:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for your avatar?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for your avatar?");
|
||||
bodyAndHeadButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
|
||||
break;
|
||||
|
||||
default:
|
||||
message = QString("Would you like to use '") + fstMapping["name"].toString() + QString("' for some part of your avatar head?");
|
||||
message = QString("Would you like to use '") + modelName + QString("' for some part of your avatar head?");
|
||||
headButton = msgBox.addButton(tr("Use for Head"), QMessageBox::ActionRole);
|
||||
bodyButton = msgBox.addButton(tr("Use for Body"), QMessageBox::ActionRole);
|
||||
bodyAndHeadButton = msgBox.addButton(tr("Use for Body and Head"), QMessageBox::ActionRole);
|
||||
|
@ -3766,34 +3763,18 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == headButton) {
|
||||
qCDebug(interfaceapp) << "Chose to use for head: " << url;
|
||||
_myAvatar->setFaceModelURL(url);
|
||||
UserActivityLogger::getInstance().changedModel("head", url);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
emit faceURLChanged(url);
|
||||
_myAvatar->useHeadURL(url, modelName);
|
||||
emit headURLChanged(url, modelName);
|
||||
} else if (msgBox.clickedButton() == bodyButton) {
|
||||
qCDebug(interfaceapp) << "Chose to use for body: " << url;
|
||||
_myAvatar->setSkeletonModelURL(url);
|
||||
// if the head is empty, reset it to the default head.
|
||||
if (_myAvatar->getFaceModelURLString().isEmpty()) {
|
||||
_myAvatar->setFaceModelURL(DEFAULT_HEAD_MODEL_URL);
|
||||
emit faceURLChanged(DEFAULT_HEAD_MODEL_URL.toString());
|
||||
UserActivityLogger::getInstance().changedModel("head", DEFAULT_HEAD_MODEL_URL.toString());
|
||||
}
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", url);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
emit skeletonURLChanged(url);
|
||||
_myAvatar->useBodyURL(url, modelName);
|
||||
emit bodyURLChanged(url, modelName);
|
||||
} else if (msgBox.clickedButton() == bodyAndHeadButton) {
|
||||
qCDebug(interfaceapp) << "Chose to use for body + head: " << url;
|
||||
_myAvatar->setFaceModelURL(QString());
|
||||
_myAvatar->setSkeletonModelURL(url);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", url);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
emit faceURLChanged(QString());
|
||||
emit skeletonURLChanged(url);
|
||||
_myAvatar->useFullAvatarURL(url, modelName);
|
||||
emit fullAvatarURLChanged(url, modelName);
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Declined to use the avatar: " << url;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4305,8 +4286,7 @@ void Application::checkSkeleton() {
|
|||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.exec();
|
||||
|
||||
_myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL);
|
||||
_myAvatar->sendIdentityPacket();
|
||||
_myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default");
|
||||
} else {
|
||||
_myAvatar->updateCharacterController();
|
||||
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
|
||||
|
|
|
@ -210,6 +210,8 @@ public:
|
|||
bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated; }
|
||||
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
void setActiveFaceTracker();
|
||||
|
||||
QSystemTrayIcon* getTrayIcon() { return _trayIcon; }
|
||||
ApplicationOverlay& getApplicationOverlay() { return _applicationOverlay; }
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
@ -335,8 +337,9 @@ signals:
|
|||
void checkBackgroundDownloads();
|
||||
void domainConnectionRefused(const QString& reason);
|
||||
|
||||
void faceURLChanged(const QString& newValue);
|
||||
void skeletonURLChanged(const QString& newValue);
|
||||
void headURLChanged(const QString& newValue, const QString& modelName);
|
||||
void bodyURLChanged(const QString& newValue, const QString& modelName);
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
|
||||
void beforeAboutToQuit();
|
||||
|
||||
|
@ -390,8 +393,6 @@ public slots:
|
|||
|
||||
void notifyPacketVersionMismatch();
|
||||
|
||||
void setActiveFaceTracker();
|
||||
|
||||
void domainConnectionDenied(const QString& reason);
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -55,6 +55,10 @@ void MainWindow::saveGeometry() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event) {
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
void MainWindow::moveEvent(QMoveEvent* event) {
|
||||
emit windowGeometryChanged(QRect(event->pos(), size()));
|
||||
QMainWindow::moveEvent(event);
|
||||
|
|
|
@ -30,6 +30,7 @@ signals:
|
|||
void windowShown(bool shown);
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent* event);
|
||||
virtual void moveEvent(QMoveEvent* event);
|
||||
virtual void resizeEvent(QResizeEvent* event);
|
||||
virtual void showEvent(QShowEvent* event);
|
||||
|
|
|
@ -256,7 +256,7 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
|
||||
qApp, SLOT(cameraMenuChanged()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::Key_H,
|
||||
false,
|
||||
dialogsManager.data(),
|
||||
SLOT(hmdTools(bool)));
|
||||
|
@ -362,28 +362,36 @@ Menu::Menu() {
|
|||
|
||||
QAction* noFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::NoFaceTracking,
|
||||
0, true,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(noFaceTracker);
|
||||
|
||||
#ifdef HAVE_FACESHIFT
|
||||
QAction* faceshiftFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Faceshift,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(faceshiftFaceTracker);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DDE
|
||||
QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(ddeFaceTracker);
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_VISAGE
|
||||
QAction* visageFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::Visage,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
this, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(visageFaceTracker);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_DDE
|
||||
faceTrackingMenu->addSeparator();
|
||||
QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking,
|
||||
Qt::CTRL | Qt::Key_Apostrophe,
|
||||
DependencyManager::get<DdeFaceTracker>().data(), SLOT(resetTracking()));
|
||||
ddeFaceTrackerReset->setVisible(false);
|
||||
faceTrackingMenu->addAction(ddeFaceTrackerReset);
|
||||
#endif
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes);
|
||||
|
@ -483,30 +491,6 @@ Menu::Menu() {
|
|||
0,
|
||||
audioIO.data(),
|
||||
SLOT(sendMuteEnvironmentPacket()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSourceInject,
|
||||
0,
|
||||
false,
|
||||
audioIO.data(),
|
||||
SLOT(toggleAudioSourceInject()));
|
||||
QMenu* audioSourceMenu = audioDebugMenu->addMenu("Generated Audio Source");
|
||||
{
|
||||
QAction *pinkNoise = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourcePinkNoise,
|
||||
0,
|
||||
false,
|
||||
audioIO.data(),
|
||||
SLOT(selectAudioSourcePinkNoise()));
|
||||
|
||||
QAction *sine440 = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourceSine440,
|
||||
0,
|
||||
true,
|
||||
audioIO.data(),
|
||||
SLOT(selectAudioSourceSine440()));
|
||||
|
||||
QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu);
|
||||
audioSourceGroup->addAction(pinkNoise);
|
||||
audioSourceGroup->addAction(sine440);
|
||||
}
|
||||
|
||||
auto scope = DependencyManager::get<AudioScope>();
|
||||
|
||||
|
@ -1003,3 +987,11 @@ void Menu::visibilityChanged(Discoverability::Mode discoverabilityMode) {
|
|||
qCDebug(interfaceapp) << "ERROR Menu::visibilityChanged() called with unrecognized value.";
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::setActiveFaceTracker() {
|
||||
#ifdef HAVE_DDE
|
||||
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression);
|
||||
Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE);
|
||||
#endif
|
||||
qApp->setActiveFaceTracker();
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void setVisibility();
|
||||
void setActiveFaceTracker();
|
||||
|
||||
private:
|
||||
static Menu* _instance;
|
||||
|
@ -123,9 +124,6 @@ namespace MenuOption {
|
|||
const QString AudioScopeTwentyFrames = "Twenty";
|
||||
const QString AudioStats = "Audio Stats";
|
||||
const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams";
|
||||
const QString AudioSourceInject = "Generated Audio";
|
||||
const QString AudioSourcePinkNoise = "Pink Noise";
|
||||
const QString AudioSourceSine440 = "Sine 440hz";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
|
||||
const QString BookmarkLocation = "Bookmark Location";
|
||||
|
@ -230,6 +228,7 @@ namespace MenuOption {
|
|||
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
|
||||
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetDDETracking = "Reset DDE Tracking";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts";
|
||||
const QString RunTimingTests = "Run Timing Tests";
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <ShapeCollider.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AvatarManager.h"
|
||||
|
@ -126,7 +127,7 @@ void MyAvatar::reset() {
|
|||
_skeletonModel.reset();
|
||||
getHead()->reset();
|
||||
|
||||
_velocity = glm::vec3(0.0f);
|
||||
_targetVelocity = glm::vec3(0.0f);
|
||||
setThrust(glm::vec3(0.0f));
|
||||
// Reset the pitch and roll components of the avatar's orientation, preserve yaw direction
|
||||
glm::vec3 eulers = safeEulerAngles(getOrientation());
|
||||
|
@ -605,10 +606,15 @@ void MyAvatar::saveData() {
|
|||
|
||||
settings.setValue("leanScale", _leanScale);
|
||||
settings.setValue("scale", _targetScale);
|
||||
|
||||
settings.setValue("faceModelURL", _faceModelURL);
|
||||
settings.setValue("skeletonModelURL", _skeletonModelURL);
|
||||
|
||||
|
||||
settings.setValue("useFullAvatar", _useFullAvatar);
|
||||
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences);
|
||||
settings.setValue("faceModelURL", _headURLFromPreferences);
|
||||
settings.setValue("skeletonModelURL", _skeletonURLFromPreferences);
|
||||
settings.setValue("headModelName", _headModelName);
|
||||
settings.setValue("bodyModelName", _bodyModelName);
|
||||
settings.setValue("fullAvatarModelName", _fullAvatarModelName);
|
||||
|
||||
settings.beginWriteArray("attachmentData");
|
||||
for (int i = 0; i < _attachmentData.size(); i++) {
|
||||
settings.setArrayIndex(i);
|
||||
|
@ -640,7 +646,6 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("firstFrame", pointer->getFirstFrame());
|
||||
settings.setValue("lastFrame", pointer->getLastFrame());
|
||||
settings.setValue("maskedJoints", pointer->getMaskedJoints());
|
||||
settings.setValue("running", pointer->getLoop() && pointer->isRunning());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
|
@ -669,9 +674,54 @@ void MyAvatar::loadData() {
|
|||
_targetScale = loadSetting(settings, "scale", 1.0f);
|
||||
setScale(_scale);
|
||||
Application::getInstance()->getCamera()->setScale(_scale);
|
||||
|
||||
setFaceModelURL(settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl());
|
||||
setSkeletonModelURL(settings.value("skeletonModelURL").toUrl());
|
||||
|
||||
|
||||
// The old preferences only stored the face and skeleton URLs, we didn't track if the user wanted to use 1 or 2 urls
|
||||
// for their avatar, So we need to attempt to detect this old case and set our new preferences accordingly. If
|
||||
// the head URL is empty, then we will assume they are using a full url...
|
||||
bool isOldSettings = !(settings.contains("useFullAvatar") || settings.contains("fullAvatarURL"));
|
||||
|
||||
_useFullAvatar = settings.value("useFullAvatar").toBool();
|
||||
_headURLFromPreferences = settings.value("faceModelURL", DEFAULT_HEAD_MODEL_URL).toUrl();
|
||||
_fullAvatarURLFromPreferences = settings.value("fullAvatarURL").toUrl();
|
||||
_skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl();
|
||||
_headModelName = settings.value("headModelName").toString();
|
||||
_bodyModelName = settings.value("bodyModelName").toString();
|
||||
_fullAvatarModelName = settings.value("fullAvatarModelName").toString();;
|
||||
|
||||
if (isOldSettings) {
|
||||
bool assumeFullAvatar = _headURLFromPreferences.isEmpty();
|
||||
_useFullAvatar = assumeFullAvatar;
|
||||
|
||||
if (_useFullAvatar) {
|
||||
_fullAvatarURLFromPreferences = settings.value("skeletonModelURL").toUrl();
|
||||
_headURLFromPreferences = DEFAULT_HEAD_MODEL_URL;
|
||||
_skeletonURLFromPreferences = DEFAULT_BODY_MODEL_URL;
|
||||
|
||||
QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());
|
||||
|
||||
_headModelName = "Default";
|
||||
_bodyModelName = "Default";
|
||||
_fullAvatarModelName = fullAvatarFST["name"].toString();
|
||||
|
||||
} else {
|
||||
_fullAvatarURLFromPreferences = DEFAULT_FULL_AVATAR_MODEL_URL;
|
||||
_skeletonURLFromPreferences = settings.value("skeletonModelURL").toUrl();
|
||||
|
||||
QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
|
||||
QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
|
||||
|
||||
_headModelName = headFST["name"].toString();
|
||||
_bodyModelName = bodyFST["name"].toString();
|
||||
_fullAvatarModelName = "Default";
|
||||
}
|
||||
}
|
||||
|
||||
if (_useFullAvatar) {
|
||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||
} else {
|
||||
useHeadAndBodyURLs(_headURLFromPreferences, _skeletonURLFromPreferences, _headModelName, _bodyModelName);
|
||||
}
|
||||
|
||||
QVector<AttachmentData> attachmentData;
|
||||
int attachmentCount = settings.beginReadArray("attachmentData");
|
||||
|
@ -710,13 +760,10 @@ void MyAvatar::loadData() {
|
|||
handle->setPriority(loadSetting(settings, "priority", 1.0f));
|
||||
handle->setLoop(settings.value("loop", true).toBool());
|
||||
handle->setHold(settings.value("hold", false).toBool());
|
||||
handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
|
||||
handle->setFirstFrame(settings.value("firstFrame", 0.0f).toFloat());
|
||||
handle->setLastFrame(settings.value("lastFrame", INT_MAX).toFloat());
|
||||
handle->setMaskedJoints(settings.value("maskedJoints").toStringList());
|
||||
if (settings.value("loop", true).toBool() && settings.value("running", false).toBool()) {
|
||||
handle->setRunning(true);
|
||||
}
|
||||
handle->setStartAutomatically(settings.value("startAutomatically", true).toBool());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
|
@ -897,6 +944,29 @@ void MyAvatar::clearJointAnimationPriorities() {
|
|||
}
|
||||
}
|
||||
|
||||
QString MyAvatar::getModelDescription() const {
|
||||
QString result;
|
||||
if (_useFullAvatar) {
|
||||
if (!getFullAvartarModelName().isEmpty()) {
|
||||
result = "Full Avatar \"" + getFullAvartarModelName() + "\"";
|
||||
} else {
|
||||
result = "Full Avatar \"" + _fullAvatarURLFromPreferences.fileName() + "\"";
|
||||
}
|
||||
} else {
|
||||
if (!getHeadModelName().isEmpty()) {
|
||||
result = "Head \"" + getHeadModelName() + "\"";
|
||||
} else {
|
||||
result = "Head \"" + _headURLFromPreferences.fileName() + "\"";
|
||||
}
|
||||
if (!getBodyModelName().isEmpty()) {
|
||||
result += " and Body \"" + getBodyModelName() + "\"";
|
||||
} else {
|
||||
result += " and Body \"" + _skeletonURLFromPreferences.fileName() + "\"";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
Avatar::setFaceModelURL(faceModelURL);
|
||||
_billboardValid = false;
|
||||
|
@ -907,6 +977,74 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||
_useFullAvatar = true;
|
||||
|
||||
if (_fullAvatarURLFromPreferences != fullAvatarURL) {
|
||||
_fullAvatarURLFromPreferences = fullAvatarURL;
|
||||
if (modelName.isEmpty()) {
|
||||
QVariantHash fullAvatarFST = FSTReader::downloadMapping(_fullAvatarURLFromPreferences.toString());
|
||||
_fullAvatarModelName = fullAvatarFST["name"].toString();
|
||||
} else {
|
||||
_fullAvatarModelName = modelName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!getFaceModelURLString().isEmpty()) {
|
||||
setFaceModelURL(QString());
|
||||
}
|
||||
|
||||
if (fullAvatarURL != getSkeletonModelURL()) {
|
||||
setSkeletonModelURL(fullAvatarURL);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", fullAvatarURL.toString());
|
||||
}
|
||||
sendIdentityPacket();
|
||||
}
|
||||
|
||||
void MyAvatar::useHeadURL(const QUrl& headURL, const QString& modelName) {
|
||||
useHeadAndBodyURLs(headURL, _skeletonURLFromPreferences, modelName, _bodyModelName);
|
||||
}
|
||||
|
||||
void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) {
|
||||
useHeadAndBodyURLs(_headURLFromPreferences, bodyURL, _headModelName, modelName);
|
||||
}
|
||||
|
||||
void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) {
|
||||
_useFullAvatar = false;
|
||||
|
||||
if (_headURLFromPreferences != headURL) {
|
||||
_headURLFromPreferences = headURL;
|
||||
if (headName.isEmpty()) {
|
||||
QVariantHash headFST = FSTReader::downloadMapping(_headURLFromPreferences.toString());
|
||||
_headModelName = headFST["name"].toString();
|
||||
} else {
|
||||
_headModelName = headName;
|
||||
}
|
||||
}
|
||||
|
||||
if (_skeletonURLFromPreferences != bodyURL) {
|
||||
_skeletonURLFromPreferences = bodyURL;
|
||||
if (bodyName.isEmpty()) {
|
||||
QVariantHash bodyFST = FSTReader::downloadMapping(_skeletonURLFromPreferences.toString());
|
||||
_bodyModelName = bodyFST["name"].toString();
|
||||
} else {
|
||||
_bodyModelName = bodyName;
|
||||
}
|
||||
}
|
||||
|
||||
if (headURL != getFaceModelURL()) {
|
||||
setFaceModelURL(headURL);
|
||||
UserActivityLogger::getInstance().changedModel("head", headURL.toString());
|
||||
}
|
||||
|
||||
if (bodyURL != getSkeletonModelURL()) {
|
||||
setSkeletonModelURL(bodyURL);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", bodyURL.toString());
|
||||
}
|
||||
sendIdentityPacket();
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||
Avatar::setAttachmentData(attachmentData);
|
||||
if (QThread::currentThread() != thread()) {
|
||||
|
@ -1240,28 +1378,28 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe
|
|||
void MyAvatar::updatePosition(float deltaTime) {
|
||||
// rotate velocity into camera frame
|
||||
glm::quat rotation = getHead()->getCameraOrientation();
|
||||
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
|
||||
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
|
||||
|
||||
bool isHovering = _characterController.isHovering();
|
||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering);
|
||||
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||
|
||||
// rotate back into world-frame
|
||||
_velocity = rotation * newLocalVelocity;
|
||||
_targetVelocity = rotation * newLocalVelocity;
|
||||
|
||||
_velocity += _thrust * deltaTime;
|
||||
_targetVelocity += _thrust * deltaTime;
|
||||
_thrust = glm::vec3(0.0f);
|
||||
|
||||
// cap avatar speed
|
||||
float speed = glm::length(_velocity);
|
||||
float speed = glm::length(_targetVelocity);
|
||||
if (speed > MAX_AVATAR_SPEED) {
|
||||
_velocity *= MAX_AVATAR_SPEED / speed;
|
||||
_targetVelocity *= MAX_AVATAR_SPEED / speed;
|
||||
speed = MAX_AVATAR_SPEED;
|
||||
}
|
||||
|
||||
if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
|
||||
// update position ourselves
|
||||
applyPositionDelta(deltaTime * _velocity);
|
||||
applyPositionDelta(deltaTime * _targetVelocity);
|
||||
measureMotionDerivatives(deltaTime);
|
||||
} // else physics will move avatar later
|
||||
|
||||
|
|
|
@ -116,8 +116,23 @@ public:
|
|||
virtual void setJointData(int index, const glm::quat& rotation);
|
||||
virtual void clearJointData(int index);
|
||||
virtual void clearJointsData();
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString());
|
||||
Q_INVOKABLE void useHeadURL(const QUrl& headURL, const QString& modelName = QString());
|
||||
Q_INVOKABLE void useBodyURL(const QUrl& bodyURL, const QString& modelName = QString());
|
||||
Q_INVOKABLE void useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName = QString(), const QString& bodyName = QString());
|
||||
|
||||
Q_INVOKABLE bool getUseFullAvatar() const { return _useFullAvatar; }
|
||||
Q_INVOKABLE const QUrl& getFullAvatarURLFromPreferences() const { return _fullAvatarURLFromPreferences; }
|
||||
Q_INVOKABLE const QUrl& getHeadURLFromPreferences() const { return _headURLFromPreferences; }
|
||||
Q_INVOKABLE const QUrl& getBodyURLFromPreferences() const { return _skeletonURLFromPreferences; }
|
||||
|
||||
Q_INVOKABLE const QString& getHeadModelName() const { return _headModelName; }
|
||||
Q_INVOKABLE const QString& getBodyModelName() const { return _bodyModelName; }
|
||||
Q_INVOKABLE const QString& getFullAvartarModelName() const { return _fullAvatarModelName; }
|
||||
|
||||
Q_INVOKABLE QString getModelDescription() const;
|
||||
|
||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
|
||||
|
||||
virtual glm::vec3 getSkeletonPosition() const;
|
||||
|
@ -185,6 +200,11 @@ protected:
|
|||
virtual void renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args);
|
||||
|
||||
private:
|
||||
|
||||
// These are made private for MyAvatar so that you will use the "use" methods instead
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
float _turningKeyPressTime;
|
||||
glm::vec3 _gravity;
|
||||
|
||||
|
@ -229,6 +249,16 @@ private:
|
|||
void updatePosition(float deltaTime);
|
||||
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
||||
void maybeUpdateBillboard();
|
||||
|
||||
// Avatar Preferences
|
||||
bool _useFullAvatar = false;
|
||||
QUrl _fullAvatarURLFromPreferences;
|
||||
QUrl _headURLFromPreferences;
|
||||
QUrl _skeletonURLFromPreferences;
|
||||
|
||||
QString _headModelName;
|
||||
QString _bodyModelName;
|
||||
QString _fullAvatarModelName;
|
||||
};
|
||||
|
||||
#endif // hifi_MyAvatar_h
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
@ -19,10 +20,21 @@
|
|||
#include "DdeFaceTracker.h"
|
||||
#include "FaceshiftConstants.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "Menu.h"
|
||||
|
||||
|
||||
static const QHostAddress DDE_FEATURE_POINT_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_FEATURE_POINT_SERVER_PORT = 5555;
|
||||
static const QHostAddress DDE_SERVER_ADDR("127.0.0.1");
|
||||
static const quint16 DDE_SERVER_PORT = 64204;
|
||||
static const quint16 DDE_CONTROL_PORT = 64205;
|
||||
#if defined(Q_OS_WIN)
|
||||
static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde/dde.exe";
|
||||
#elif defined(Q_OS_MAC)
|
||||
static const QString DDE_PROGRAM_PATH = QCoreApplication::applicationDirPath() + "/dde.app/Contents/MacOS/dde";
|
||||
#endif
|
||||
static const QStringList DDE_ARGUMENTS = QStringList()
|
||||
<< "--udp=" + DDE_SERVER_ADDR.toString() + ":" + QString::number(DDE_SERVER_PORT)
|
||||
<< "--receiver=" + QString::number(DDE_CONTROL_PORT)
|
||||
<< "--headless";
|
||||
|
||||
static const int NUM_EXPRESSIONS = 46;
|
||||
static const int MIN_PACKET_SIZE = (8 + NUM_EXPRESSIONS) * sizeof(float) + sizeof(int);
|
||||
|
@ -121,14 +133,16 @@ struct Packet {
|
|||
};
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker() :
|
||||
DdeFaceTracker(QHostAddress::Any, DDE_FEATURE_POINT_SERVER_PORT)
|
||||
DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
||||
DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort) :
|
||||
_ddeProcess(NULL),
|
||||
_host(host),
|
||||
_port(port),
|
||||
_serverPort(serverPort),
|
||||
_controlPort(controlPort),
|
||||
_lastReceiveTimestamp(0),
|
||||
_reset(false),
|
||||
_leftBlinkIndex(0), // see http://support.faceshift.com/support/articles/35129-export-of-blendshapes
|
||||
|
@ -157,17 +171,50 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 port) :
|
|||
}
|
||||
|
||||
DdeFaceTracker::~DdeFaceTracker() {
|
||||
if (_udpSocket.isOpen()) {
|
||||
_udpSocket.close();
|
||||
}
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void DdeFaceTracker::setEnabled(bool enabled) {
|
||||
#ifdef HAVE_DDE
|
||||
// isOpen() does not work as one might expect on QUdpSocket; don't test isOpen() before closing socket.
|
||||
_udpSocket.close();
|
||||
if (enabled) {
|
||||
_udpSocket.bind(_host, _port);
|
||||
_udpSocket.bind(_host, _serverPort);
|
||||
}
|
||||
|
||||
if (enabled && !_ddeProcess) {
|
||||
// Terminate any existing DDE process, perhaps left running after an Interface crash
|
||||
const char* DDE_EXIT_COMMAND = "exit";
|
||||
_udpSocket.writeDatagram(DDE_EXIT_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||
|
||||
qDebug() << "[Info] DDE Face Tracker Starting";
|
||||
_ddeProcess = new QProcess(qApp);
|
||||
connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
|
||||
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (!enabled && _ddeProcess) {
|
||||
_ddeProcess->kill(); // More robust than trying to send an "exit" command to DDE
|
||||
_ddeProcess = NULL;
|
||||
qDebug() << "[Info] DDE Face Tracker Stopped";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
if (_ddeProcess) {
|
||||
// DDE crashed or was manually terminated
|
||||
qDebug() << "[Info] DDE Face Tracker Stopped Unexpectedly";
|
||||
_udpSocket.close();
|
||||
_ddeProcess = NULL;
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::NoFaceTracking, true);
|
||||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::resetTracking() {
|
||||
qDebug() << "[Info] Reset DDE Tracking";
|
||||
const char* DDE_RESET_COMMAND = "reset";
|
||||
_udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||
}
|
||||
|
||||
bool DdeFaceTracker::isActive() const {
|
||||
|
@ -239,7 +286,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
|||
}
|
||||
|
||||
// Compute relative translation
|
||||
float LEAN_DAMPING_FACTOR = 200.0f;
|
||||
float LEAN_DAMPING_FACTOR = 75.0f;
|
||||
translation -= _referenceTranslation;
|
||||
translation /= LEAN_DAMPING_FACTOR;
|
||||
translation.x *= -1;
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#ifndef hifi_DdeFaceTracker_h
|
||||
#define hifi_DdeFaceTracker_h
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_OSX)
|
||||
#define HAVE_DDE
|
||||
#endif
|
||||
|
||||
#include <QProcess>
|
||||
#include <QUdpSocket>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
@ -45,9 +50,11 @@ public:
|
|||
|
||||
public slots:
|
||||
void setEnabled(bool enabled);
|
||||
void resetTracking();
|
||||
|
||||
private slots:
|
||||
|
||||
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
//sockets
|
||||
void socketErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||
void readPendingDatagrams();
|
||||
|
@ -55,11 +62,14 @@ private slots:
|
|||
|
||||
private:
|
||||
DdeFaceTracker();
|
||||
DdeFaceTracker(const QHostAddress& host, quint16 port);
|
||||
DdeFaceTracker(const QHostAddress& host, quint16 serverPort, quint16 controlPort);
|
||||
~DdeFaceTracker();
|
||||
|
||||
QProcess* _ddeProcess;
|
||||
|
||||
QHostAddress _host;
|
||||
quint16 _port;
|
||||
quint16 _serverPort;
|
||||
quint16 _controlPort;
|
||||
|
||||
float getBlendshapeCoefficient(int index) const;
|
||||
void decodePacket(const QByteArray& buffer);
|
||||
|
|
|
@ -114,8 +114,11 @@ void OculusManager::initSdk() {
|
|||
}
|
||||
|
||||
void OculusManager::shutdownSdk() {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
ovr_Shutdown();
|
||||
if (_ovrHmd) {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
_ovrHmd = nullptr;
|
||||
ovr_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void OculusManager::init() {
|
||||
|
@ -124,6 +127,12 @@ void OculusManager::init() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::deinit() {
|
||||
#ifdef OVR_DIRECT_MODE
|
||||
shutdownSdk();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::connect() {
|
||||
#ifndef OVR_DIRECT_MODE
|
||||
initSdk();
|
||||
|
|
|
@ -51,6 +51,7 @@ class Text3DOverlay;
|
|||
class OculusManager {
|
||||
public:
|
||||
static void init();
|
||||
static void deinit();
|
||||
static void connect();
|
||||
static void disconnect();
|
||||
static bool isConnected();
|
||||
|
|
|
@ -112,6 +112,7 @@ int main(int argc, const char* argv[]) {
|
|||
exitCode = app.exec();
|
||||
}
|
||||
|
||||
OculusManager::deinit();
|
||||
#ifdef Q_OS_WIN
|
||||
ReleaseMutex(mutex);
|
||||
#endif
|
||||
|
|
210
interface/src/ui/AvatarAppearanceDialog.cpp
Normal file
210
interface/src/ui/AvatarAppearanceDialog.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
// AvatarAppearanceDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFont>
|
||||
|
||||
#include <AudioClient.h>
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <devices/Faceshift.h>
|
||||
#include <devices/SixenseManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
#include "AvatarAppearanceDialog.h"
|
||||
#include "Snapshot.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "UIUtil.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
#include "ui/PreferencesDialog.h"
|
||||
|
||||
AvatarAppearanceDialog::AvatarAppearanceDialog(QWidget* parent) :
|
||||
QDialog(parent) {
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui.setupUi(this);
|
||||
|
||||
loadAvatarAppearance();
|
||||
|
||||
connect(ui.defaultButton, &QPushButton::clicked, this, &AvatarAppearanceDialog::accept);
|
||||
|
||||
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &AvatarAppearanceDialog::openHeadModelBrowser);
|
||||
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &AvatarAppearanceDialog::openBodyModelBrowser);
|
||||
connect(ui.buttonBrowseFullAvatar, &QPushButton::clicked, this, &AvatarAppearanceDialog::openFullAvatarModelBrowser);
|
||||
|
||||
connect(ui.useSeparateBodyAndHead, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useSeparateBodyAndHead);
|
||||
connect(ui.useFullAvatar, &QRadioButton::clicked, this, &AvatarAppearanceDialog::useFullAvatar);
|
||||
|
||||
connect(Application::getInstance(), &Application::headURLChanged, this, &AvatarAppearanceDialog::headURLChanged);
|
||||
connect(Application::getInstance(), &Application::bodyURLChanged, this, &AvatarAppearanceDialog::bodyURLChanged);
|
||||
connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &AvatarAppearanceDialog::fullAvatarURLChanged);
|
||||
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
ui.bodyNameLabel->setText("Body - " + myAvatar->getBodyModelName());
|
||||
ui.headNameLabel->setText("Head - " + myAvatar->getHeadModelName());
|
||||
ui.fullAvatarNameLabel->setText("Full Avatar - " + myAvatar->getFullAvartarModelName());
|
||||
|
||||
UIUtil::scaleWidgetFontSizes(this);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::useSeparateBodyAndHead(bool checked) {
|
||||
QUrl headURL(ui.faceURLEdit->text());
|
||||
QUrl bodyURL(ui.skeletonURLEdit->text());
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useHeadAndBodyURLs(headURL, bodyURL);
|
||||
setUseFullAvatar(!checked);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::useFullAvatar(bool checked) {
|
||||
QUrl fullAvatarURL(ui.fullAvatarURLEdit->text());
|
||||
DependencyManager::get<AvatarManager>()->getMyAvatar()->useFullAvatarURL(fullAvatarURL);
|
||||
setUseFullAvatar(checked);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::setUseFullAvatar(bool useFullAvatar) {
|
||||
_useFullAvatar = useFullAvatar;
|
||||
ui.faceURLEdit->setEnabled(!_useFullAvatar);
|
||||
ui.skeletonURLEdit->setEnabled(!_useFullAvatar);
|
||||
ui.fullAvatarURLEdit->setEnabled(_useFullAvatar);
|
||||
|
||||
ui.useFullAvatar->setChecked(_useFullAvatar);
|
||||
ui.useSeparateBodyAndHead->setChecked(!_useFullAvatar);
|
||||
|
||||
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::headURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.faceURLEdit->setText(newValue);
|
||||
setUseFullAvatar(false);
|
||||
ui.headNameLabel->setText("Head - " + modelName);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::bodyURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.skeletonURLEdit->setText(newValue);
|
||||
setUseFullAvatar(false);
|
||||
ui.bodyNameLabel->setText("Body - " + modelName);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.fullAvatarURLEdit->setText(newValue);
|
||||
setUseFullAvatar(true);
|
||||
ui.fullAvatarNameLabel->setText("Full Avatar - " + modelName);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::accept() {
|
||||
saveAvatarAppearance();
|
||||
|
||||
DependencyManager::get<DialogsManager>()->getPreferencesDialog()->avatarDescriptionChanged();
|
||||
|
||||
close();
|
||||
delete _marketplaceWindow;
|
||||
_marketplaceWindow = NULL;
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::setHeadUrl(QString modelUrl) {
|
||||
ui.faceURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::setSkeletonUrl(QString modelUrl) {
|
||||
ui.skeletonURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::openFullAvatarModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::openHeadModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::openBodyModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::resizeEvent(QResizeEvent *resizeEvent) {
|
||||
|
||||
// keep buttons panel at the bottom
|
||||
ui.buttonsPanel->setGeometry(0,
|
||||
size().height() - ui.buttonsPanel->height(),
|
||||
size().width(),
|
||||
ui.buttonsPanel->height());
|
||||
|
||||
// set width and height of srcollarea to match bottom panel and width
|
||||
ui.scrollArea->setGeometry(ui.scrollArea->geometry().x(), ui.scrollArea->geometry().y(),
|
||||
size().width(),
|
||||
size().height() - ui.buttonsPanel->height() - ui.scrollArea->geometry().y());
|
||||
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::loadAvatarAppearance() {
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
_useFullAvatar = myAvatar->getUseFullAvatar();
|
||||
_fullAvatarURLString = myAvatar->getFullAvatarURLFromPreferences().toString();
|
||||
_headURLString = myAvatar->getHeadURLFromPreferences().toString();
|
||||
_bodyURLString = myAvatar->getBodyURLFromPreferences().toString();
|
||||
|
||||
ui.fullAvatarURLEdit->setText(_fullAvatarURLString);
|
||||
ui.faceURLEdit->setText(_headURLString);
|
||||
ui.skeletonURLEdit->setText(_bodyURLString);
|
||||
setUseFullAvatar(_useFullAvatar);
|
||||
}
|
||||
|
||||
void AvatarAppearanceDialog::saveAvatarAppearance() {
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
QUrl headURL(ui.faceURLEdit->text());
|
||||
QString headURLString = headURL.toString();
|
||||
|
||||
QUrl bodyURL(ui.skeletonURLEdit->text());
|
||||
QString bodyURLString = bodyURL.toString();
|
||||
|
||||
QUrl fullAvatarURL(ui.fullAvatarURLEdit->text());
|
||||
QString fullAvatarURLString = fullAvatarURL.toString();
|
||||
|
||||
bool somethingChanged =
|
||||
_useFullAvatar != myAvatar->getUseFullAvatar() ||
|
||||
fullAvatarURLString != myAvatar->getFullAvatarURLFromPreferences().toString() ||
|
||||
headURLString != myAvatar->getHeadURLFromPreferences().toString() ||
|
||||
bodyURLString != myAvatar->getBodyURLFromPreferences().toString();
|
||||
|
||||
if (somethingChanged) {
|
||||
if (_useFullAvatar) {
|
||||
myAvatar->useFullAvatarURL(fullAvatarURL);
|
||||
} else {
|
||||
myAvatar->useHeadAndBodyURLs(headURL, bodyURL);
|
||||
}
|
||||
}
|
||||
}
|
64
interface/src/ui/AvatarAppearanceDialog.h
Normal file
64
interface/src/ui/AvatarAppearanceDialog.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// AvatarAppearanceDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#ifndef hifi_AvatarAppearanceDialog_h
|
||||
#define hifi_AvatarAppearanceDialog_h
|
||||
|
||||
#include "ui_avatarAppearance.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include "scripting/WebWindowClass.h"
|
||||
|
||||
class AvatarAppearanceDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AvatarAppearanceDialog(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* resizeEvent);
|
||||
|
||||
private:
|
||||
void loadAvatarAppearance();
|
||||
void saveAvatarAppearance();
|
||||
void openHeadModelBrowser();
|
||||
void openBodyModelBrowser();
|
||||
void openFullAvatarModelBrowser();
|
||||
void setUseFullAvatar(bool useFullAvatar);
|
||||
|
||||
Ui_AvatarAppearanceDialog ui;
|
||||
|
||||
bool _useFullAvatar;
|
||||
QString _headURLString;
|
||||
QString _bodyURLString;
|
||||
QString _fullAvatarURLString;
|
||||
|
||||
|
||||
QString _displayNameString;
|
||||
|
||||
WebWindowClass* _marketplaceWindow = NULL;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
void setHeadUrl(QString modelUrl);
|
||||
void setSkeletonUrl(QString modelUrl);
|
||||
void headURLChanged(const QString& newValue, const QString& modelName);
|
||||
void bodyURLChanged(const QString& newValue, const QString& modelName);
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
void useSeparateBodyAndHead(bool checked);
|
||||
void useFullAvatar(bool checked);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarAppearanceDialog_h
|
|
@ -18,6 +18,7 @@
|
|||
#include "AddressBarDialog.h"
|
||||
#include "AnimationsDialog.h"
|
||||
#include "AttachmentsDialog.h"
|
||||
#include "AvatarAppearanceDialog.h"
|
||||
#include "BandwidthDialog.h"
|
||||
#include "CachesSizeDialog.h"
|
||||
#include "DiskCacheEditor.h"
|
||||
|
@ -85,6 +86,15 @@ void DialogsManager::editPreferences() {
|
|||
}
|
||||
}
|
||||
|
||||
void DialogsManager::changeAvatarAppearance() {
|
||||
if (!_avatarAppearanceDialog) {
|
||||
maybeCreateDialog(_avatarAppearanceDialog);
|
||||
_avatarAppearanceDialog->show();
|
||||
} else {
|
||||
_avatarAppearanceDialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsManager::editAttachments() {
|
||||
if (!_attachmentsDialog) {
|
||||
maybeCreateDialog(_attachmentsDialog);
|
||||
|
|
|
@ -33,6 +33,7 @@ class OctreeStatsDialog;
|
|||
class PreferencesDialog;
|
||||
class ScriptEditorWindow;
|
||||
class QMessageBox;
|
||||
class AvatarAppearanceDialog;
|
||||
|
||||
class DialogsManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -43,6 +44,7 @@ public:
|
|||
QPointer<HMDToolsDialog> getHMDToolsDialog() const { return _hmdToolsDialog; }
|
||||
QPointer<LodToolsDialog> getLodToolsDialog() const { return _lodToolsDialog; }
|
||||
QPointer<OctreeStatsDialog> getOctreeStatsDialog() const { return _octreeStatsDialog; }
|
||||
QPointer<PreferencesDialog> getPreferencesDialog() const { return _preferencesDialog; }
|
||||
|
||||
public slots:
|
||||
void toggleAddressBar();
|
||||
|
@ -59,6 +61,7 @@ public slots:
|
|||
void hmdTools(bool showTools);
|
||||
void showScriptEditor();
|
||||
void showIRCLink();
|
||||
void changeAvatarAppearance();
|
||||
|
||||
private slots:
|
||||
void toggleToolWindow();
|
||||
|
@ -94,6 +97,7 @@ private:
|
|||
QPointer<OctreeStatsDialog> _octreeStatsDialog;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QPointer<ScriptEditorWindow> _scriptEditor;
|
||||
QPointer<AvatarAppearanceDialog> _avatarAppearanceDialog;
|
||||
};
|
||||
|
||||
#endif // hifi_DialogsManager_h
|
|
@ -19,6 +19,7 @@
|
|||
#include <NetworkingConstants.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "DialogsManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
|
@ -41,30 +42,40 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
|
|||
ui.outputBufferSizeSpinner->setMinimum(MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES);
|
||||
ui.outputBufferSizeSpinner->setMaximum(MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES);
|
||||
|
||||
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser);
|
||||
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser);
|
||||
connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser);
|
||||
connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser);
|
||||
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked,
|
||||
Application::getInstance(), &Application::loadDefaultScripts);
|
||||
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, Application::getInstance(), &Application::loadDefaultScripts);
|
||||
|
||||
DialogsManager* dialogsManager = DependencyManager::get<DialogsManager>().data();
|
||||
connect(ui.buttonChangeApperance, &QPushButton::clicked, dialogsManager, &DialogsManager::changeAvatarAppearance);
|
||||
|
||||
connect(Application::getInstance(), &Application::faceURLChanged, this, &PreferencesDialog::faceURLChanged);
|
||||
connect(Application::getInstance(), &Application::skeletonURLChanged, this, &PreferencesDialog::skeletonURLChanged);
|
||||
connect(Application::getInstance(), &Application::headURLChanged, this, &PreferencesDialog::headURLChanged);
|
||||
connect(Application::getInstance(), &Application::bodyURLChanged, this, &PreferencesDialog::bodyURLChanged);
|
||||
connect(Application::getInstance(), &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged);
|
||||
|
||||
// move dialog to left side
|
||||
move(parentWidget()->geometry().topLeft());
|
||||
setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING);
|
||||
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
|
||||
UIUtil::scaleWidgetFontSizes(this);
|
||||
}
|
||||
|
||||
void PreferencesDialog::faceURLChanged(const QString& newValue) {
|
||||
ui.faceURLEdit->setText(newValue);
|
||||
void PreferencesDialog::avatarDescriptionChanged() {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::skeletonURLChanged(const QString& newValue) {
|
||||
ui.skeletonURLEdit->setText(newValue);
|
||||
void PreferencesDialog::headURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::bodyURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) {
|
||||
ui.apperanceDescription->setText(DependencyManager::get<AvatarManager>()->getMyAvatar()->getModelDescription());
|
||||
}
|
||||
|
||||
void PreferencesDialog::accept() {
|
||||
|
@ -74,34 +85,6 @@ void PreferencesDialog::accept() {
|
|||
_marketplaceWindow = NULL;
|
||||
}
|
||||
|
||||
void PreferencesDialog::setHeadUrl(QString modelUrl) {
|
||||
ui.faceURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
|
||||
ui.skeletonURLEdit->setText(modelUrl);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openHeadModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openBodyModelBrowser() {
|
||||
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
|
||||
auto WIDTH = 900;
|
||||
auto HEIGHT = 700;
|
||||
if (!_marketplaceWindow) {
|
||||
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
|
||||
}
|
||||
_marketplaceWindow->setVisible(true);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openSnapshotLocationBrowser() {
|
||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Snapshots Location"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
|
||||
|
@ -143,12 +126,6 @@ void PreferencesDialog::loadPreferences() {
|
|||
_displayNameString = myAvatar->getDisplayName();
|
||||
ui.displayNameEdit->setText(_displayNameString);
|
||||
|
||||
_faceURLString = myAvatar->getHead()->getFaceModel().getURL().toString();
|
||||
ui.faceURLEdit->setText(_faceURLString);
|
||||
|
||||
_skeletonURLString = myAvatar->getSkeletonModel().getURL().toString();
|
||||
ui.skeletonURLEdit->setText(_skeletonURLString);
|
||||
|
||||
ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger));
|
||||
|
||||
ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get());
|
||||
|
@ -208,6 +185,7 @@ void PreferencesDialog::loadPreferences() {
|
|||
void PreferencesDialog::savePreferences() {
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
bool shouldDispatchIdentityPacket = false;
|
||||
|
||||
QString displayNameStr(ui.displayNameEdit->text());
|
||||
|
@ -217,34 +195,6 @@ void PreferencesDialog::savePreferences() {
|
|||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
auto AVATAR_FILE_EXTENSION = ".fst";
|
||||
|
||||
QUrl faceModelURL(ui.faceURLEdit->text());
|
||||
QString faceModelURLString = faceModelURL.toString();
|
||||
if (faceModelURLString != _faceURLString) {
|
||||
if (faceModelURLString.isEmpty() || faceModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
myAvatar->setFaceModelURL(faceModelURL);
|
||||
UserActivityLogger::getInstance().changedModel("head", faceModelURLString);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
} else {
|
||||
qDebug() << "ERROR: Head model not FST or blank - " << faceModelURLString;
|
||||
}
|
||||
}
|
||||
|
||||
QUrl skeletonModelURL(ui.skeletonURLEdit->text());
|
||||
QString skeletonModelURLString = skeletonModelURL.toString();
|
||||
if (skeletonModelURLString != _skeletonURLString) {
|
||||
if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
myAvatar->setSkeletonModelURL(skeletonModelURL);
|
||||
UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURLString);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
} else {
|
||||
qDebug() << "ERROR: Skeleton model not FST or blank - " << skeletonModelURLString;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldDispatchIdentityPacket) {
|
||||
myAvatar->sendIdentityPacket();
|
||||
}
|
||||
|
|
|
@ -25,31 +25,28 @@ class PreferencesDialog : public QDialog {
|
|||
public:
|
||||
PreferencesDialog(QWidget* parent = nullptr);
|
||||
|
||||
void avatarDescriptionChanged();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* resizeEvent);
|
||||
|
||||
private:
|
||||
void loadPreferences();
|
||||
void savePreferences();
|
||||
void openHeadModelBrowser();
|
||||
void openBodyModelBrowser();
|
||||
|
||||
Ui_PreferencesDialog ui;
|
||||
QString _faceURLString;
|
||||
QString _skeletonURLString;
|
||||
|
||||
QString _displayNameString;
|
||||
|
||||
WebWindowClass* _marketplaceWindow = NULL;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
void setHeadUrl(QString modelUrl);
|
||||
void setSkeletonUrl(QString modelUrl);
|
||||
void openSnapshotLocationBrowser();
|
||||
void openScriptsLocationBrowser();
|
||||
void faceURLChanged(const QString& newValue);
|
||||
void skeletonURLChanged(const QString& newValue);
|
||||
|
||||
void headURLChanged(const QString& newValue, const QString& modelName);
|
||||
void bodyURLChanged(const QString& newValue, const QString& modelName);
|
||||
void fullAvatarURLChanged(const QString& newValue, const QString& modelName);
|
||||
};
|
||||
|
||||
#endif // hifi_PreferencesDialog_h
|
||||
|
|
471
interface/ui/avatarAppearance.ui
Normal file
471
interface/ui/avatarAppearance.ui
Normal file
|
@ -0,0 +1,471 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AvatarAppearanceDialog</class>
|
||||
<widget class="QDialog" name="AvatarAppearanceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-107</y>
|
||||
<width>485</width>
|
||||
<height>1550</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<widget class="QRadioButton" name="useFullAvatar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use single avatar with Body and Head</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_fullAvatar">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="fullAvatarNameLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Full Avatar</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>fullAvatarURLEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_fullAvatar">
|
||||
|
||||
<item>
|
||||
<widget class="QLineEdit" name="fullAvatarURLEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_fullAvatar">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseFullAvatar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
|
||||
|
||||
|
||||
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QRadioButton" name="useSeparateBodyAndHead">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use separate Body and Head avatar files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_separateParts_head">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="headNameLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Head</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="faceURLEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseHead">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_separateParts_body">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
|
||||
<item>
|
||||
<widget class="QLabel" name="bodyNameLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Body</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>skeletonURLEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_skeletonURL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="skeletonURLEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseBody">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="buttonsPanel">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonsHBox_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_14">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="defaultButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
</ui>
|
|
@ -128,6 +128,8 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
|
@ -187,8 +189,9 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_appearance">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
@ -199,33 +202,47 @@
|
|||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="headLabel">
|
||||
<widget class="QLabel" name="appearanceLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Head</string>
|
||||
<string><html><head/><body><p>Appearance</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>snapshotLocationEdit</cstring>
|
||||
<cstring>apperanceDescription</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1_apperanceDescription">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="faceURLEdit"/>
|
||||
<widget class="QLineEdit" name="apperanceDescription">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<spacer name="horizontalSpacer_1_apperanceDescription">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
|
@ -241,96 +258,14 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseHead">
|
||||
<widget class="QPushButton" name="buttonChangeApperance">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="headLabel_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Body</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>skeletonURLEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="skeletonURLEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonBrowseBody">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Arial</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
<string>Change</string>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
|
@ -342,8 +277,11 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
@ -413,6 +351,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_1">
|
||||
<property name="spacing">
|
||||
|
@ -463,6 +402,10 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
||||
|
||||
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -665,6 +608,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<widget class="QCheckBox" name="sendDataCheckBox">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -493,7 +493,7 @@ void AudioClient::start() {
|
|||
_sourceGain.initialize();
|
||||
_noiseSource.initialize();
|
||||
_toneSource.initialize();
|
||||
_sourceGain.setParameters(0.25f, 0.0f);
|
||||
_sourceGain.setParameters(0.05f, 0.0f);
|
||||
_inputGain.setParameters(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
@ -726,9 +726,9 @@ void AudioClient::handleAudioInput() {
|
|||
int inputSamplesRequired = (int)((float)AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio);
|
||||
|
||||
QByteArray inputByteArray = _inputDevice->readAll();
|
||||
|
||||
|
||||
// Add audio source injection if enabled
|
||||
if (!_muted && _audioSourceInjectEnabled) {
|
||||
|
||||
int16_t* inputFrameData = (int16_t*)inputByteArray.data();
|
||||
const uint32_t inputFrameCount = inputByteArray.size() / sizeof(int16_t);
|
||||
|
||||
|
@ -737,17 +737,12 @@ void AudioClient::handleAudioInput() {
|
|||
#if ENABLE_INPUT_GAIN
|
||||
_inputGain.render(_inputFrameBuffer); // input/mic gain+mute
|
||||
#endif
|
||||
// Add audio source injection if enabled
|
||||
if (_audioSourceInjectEnabled) {
|
||||
|
||||
if (_toneSourceEnabled) { // sine generator
|
||||
_toneSource.render(_inputFrameBuffer);
|
||||
}
|
||||
else if(_noiseSourceEnabled) { // pink noise generator
|
||||
_noiseSource.render(_inputFrameBuffer);
|
||||
}
|
||||
_sourceGain.render(_inputFrameBuffer); // post gain
|
||||
if (_toneSourceEnabled) { // sine generator
|
||||
_toneSource.render(_inputFrameBuffer);
|
||||
} else if(_noiseSourceEnabled) { // pink noise generator
|
||||
_noiseSource.render(_inputFrameBuffer);
|
||||
}
|
||||
_sourceGain.render(_inputFrameBuffer); // post gain
|
||||
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/);
|
||||
}
|
||||
|
||||
|
@ -972,8 +967,8 @@ void AudioClient::setIsStereoInput(bool isStereoInput) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioClient::toggleAudioSourceInject() {
|
||||
_audioSourceInjectEnabled = !_audioSourceInjectEnabled;
|
||||
void AudioClient::enableAudioSourceInject(bool enable) {
|
||||
_audioSourceInjectEnabled = enable;
|
||||
}
|
||||
|
||||
void AudioClient::selectAudioSourcePinkNoise() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// AudioClient.h
|
||||
// interface/src
|
||||
// libraries/audio-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 1/22/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -143,9 +143,9 @@ public slots:
|
|||
void audioMixerKilled();
|
||||
void toggleMute();
|
||||
|
||||
void toggleAudioSourceInject();
|
||||
void selectAudioSourcePinkNoise();
|
||||
void selectAudioSourceSine440();
|
||||
virtual void enableAudioSourceInject(bool enable);
|
||||
virtual void selectAudioSourcePinkNoise();
|
||||
virtual void selectAudioSourceSine440();
|
||||
|
||||
void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; }
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ public:
|
|||
|
||||
public slots:
|
||||
virtual bool outputLocalInjector(bool isStereo, qreal volume, AudioInjector* injector) = 0;
|
||||
|
||||
virtual void enableAudioSourceInject(bool enable) = 0;
|
||||
virtual void selectAudioSourcePinkNoise() = 0;
|
||||
virtual void selectAudioSourceSine440() = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AbstractAudioInterface*)
|
||||
|
|
|
@ -60,6 +60,7 @@ AvatarData::AvatarData() :
|
|||
_owningAvatarMixer(),
|
||||
_lastUpdateTimer(),
|
||||
_velocity(0.0f),
|
||||
_targetVelocity(0.0f),
|
||||
_localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -103,6 +103,8 @@ const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
|
|||
|
||||
const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/models/heads/defaultAvatar_head.fst");
|
||||
const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/models/skeletons/defaultAvatar_body.fst");
|
||||
const QUrl DEFAULT_FULL_AVATAR_MODEL_URL = QUrl("http://public.highfidelity.io/marketplace/contents/029db3d4-da2c-4cb2-9c08-b9612ba576f5/02949063e7c4aed42ad9d1a58461f56d.fst");
|
||||
|
||||
|
||||
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found).
|
||||
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
||||
|
@ -294,6 +296,7 @@ public:
|
|||
|
||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||
glm::vec3 getTargetVelocity() const { return _targetVelocity; }
|
||||
|
||||
public slots:
|
||||
void sendAvatarDataPacket();
|
||||
|
@ -384,6 +387,7 @@ protected:
|
|||
void changeReferential(Referential* ref);
|
||||
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _targetVelocity;
|
||||
|
||||
AABox _localAABox;
|
||||
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
//
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "FSTReader.h"
|
||||
|
||||
|
@ -169,3 +176,17 @@ FSTReader::ModelType FSTReader::predictModelType(const QVariantHash& mapping) {
|
|||
|
||||
return ENTITY_MODEL;
|
||||
}
|
||||
|
||||
QVariantHash FSTReader::downloadMapping(const QString& url) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest = QNetworkRequest(url);
|
||||
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(networkRequest);
|
||||
qDebug() << "Downloading avatar file at " << url;
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
QByteArray fstContents = reply->readAll();
|
||||
delete reply;
|
||||
return FSTReader::readMapping(fstContents);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
|
||||
static QString getNameFromType(ModelType modelType);
|
||||
static FSTReader::ModelType getTypeFromName(const QString& name);
|
||||
static QVariantHash downloadMapping(const QString& url);
|
||||
|
||||
private:
|
||||
static void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it);
|
||||
|
|
|
@ -386,7 +386,7 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
|||
setHovering(true);
|
||||
}
|
||||
|
||||
_walkVelocity = glmToBullet(_avatarData->getVelocity());
|
||||
_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
||||
|
||||
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||
|
@ -408,6 +408,7 @@ void DynamicCharacterController::postSimulation() {
|
|||
|
||||
_avatarData->setOrientation(rotation);
|
||||
_avatarData->setPosition(position - rotation * _shapeLocalOffset);
|
||||
_avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,10 +47,11 @@ void AnimationHandle::setPriority(float priority) {
|
|||
}
|
||||
|
||||
void AnimationHandle::setStartAutomatically(bool startAutomatically) {
|
||||
_animationLoop.setStartAutomatically(startAutomatically);
|
||||
if (getStartAutomatically() && !isRunning()) {
|
||||
if (startAutomatically && !isRunning()) {
|
||||
// Start before setting _animationLoop value so that code in setRunning() is executed
|
||||
start();
|
||||
}
|
||||
_animationLoop.setStartAutomatically(startAutomatically);
|
||||
}
|
||||
|
||||
void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) {
|
||||
|
@ -59,13 +60,10 @@ void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) {
|
|||
}
|
||||
|
||||
void AnimationHandle::setRunning(bool running) {
|
||||
if (isRunning() == running) {
|
||||
if (running && isRunning()) {
|
||||
// if we're already running, this is the same as a restart
|
||||
if (running) {
|
||||
// move back to the beginning
|
||||
setFrameIndex(getFirstFrame());
|
||||
return;
|
||||
}
|
||||
setFrameIndex(getFirstFrame());
|
||||
return;
|
||||
}
|
||||
_animationLoop.setRunning(running);
|
||||
if (isRunning()) {
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioScriptingInterface.h"
|
||||
|
||||
#include "ScriptAudioInjector.h"
|
||||
#include "ScriptEngineLogging.h"
|
||||
#include "AudioScriptingInterface.h"
|
||||
|
||||
void registerAudioMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, injectorOptionsToScriptValue, injectorOptionsFromScriptValue);
|
||||
|
@ -69,3 +70,23 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioScriptingInterface::injectGeneratedNoise(bool inject) {
|
||||
if (_localAudioInterface) {
|
||||
_localAudioInterface->enableAudioSourceInject(inject);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioScriptingInterface::selectPinkNoise() {
|
||||
if (_localAudioInterface) {
|
||||
_localAudioInterface->selectAudioSourcePinkNoise();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioScriptingInterface::selectSine440() {
|
||||
if (_localAudioInterface) {
|
||||
_localAudioInterface->selectAudioSourceSine440();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ protected:
|
|||
// this method is protected to stop C++ callers from calling, but invokable from script
|
||||
Q_INVOKABLE ScriptAudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions());
|
||||
|
||||
Q_INVOKABLE void injectGeneratedNoise(bool inject);
|
||||
Q_INVOKABLE void selectPinkNoise();
|
||||
Q_INVOKABLE void selectSine440();
|
||||
|
||||
signals:
|
||||
void mutedByMixer();
|
||||
void environmentMuted();
|
||||
|
|
Loading…
Reference in a new issue