From bbdf4a12055c154fd2685ff007a6a8565b1803de Mon Sep 17 00:00:00 2001 From: stojce Date: Sat, 8 Feb 2014 01:10:26 +0100 Subject: [PATCH 01/23] Allow logged-in users to name their current location & orientation --- data-server/src/DataServer.cpp | 70 ++++++++++++++++++++ interface/CMakeLists.txt | 2 +- interface/src/DatagramProcessor.cpp | 3 + interface/src/Menu.cpp | 77 +++++++++++++++++++++- interface/src/Menu.h | 4 ++ interface/src/location/LocationManager.cpp | 26 ++++++++ interface/src/location/LocationManager.h | 37 +++++++++++ interface/src/location/NamedLocation.cpp | 46 +++++++++++++ interface/src/location/NamedLocation.h | 63 ++++++++++++++++++ libraries/shared/src/DataServerClient.cpp | 73 ++++++++++++++++++++ libraries/shared/src/DataServerClient.h | 12 +++- libraries/shared/src/PacketHeaders.h | 3 + 12 files changed, 410 insertions(+), 6 deletions(-) create mode 100644 interface/src/location/LocationManager.cpp create mode 100644 interface/src/location/LocationManager.h create mode 100644 interface/src/location/NamedLocation.cpp create mode 100644 interface/src/location/NamedLocation.h diff --git a/data-server/src/DataServer.cpp b/data-server/src/DataServer.cpp index 43fc52fb06..258afb755f 100644 --- a/data-server/src/DataServer.cpp +++ b/data-server/src/DataServer.cpp @@ -20,6 +20,11 @@ const quint16 DATA_SERVER_LISTEN_PORT = 3282; const char REDIS_HOSTNAME[] = "127.0.0.1"; const unsigned short REDIS_PORT = 6379; +const int ARGV_FIXED_INDEX_START = 2; + +const char REDIS_HASH_MULTIPLE_SET[] = "HMSET"; +const char REDIS_HASH_SET[] = "HSET"; +const char REDIS_HASH_GET_ALL[] = "HGETALL"; DataServer::DataServer(int argc, char* argv[]) : QCoreApplication(argc, argv), @@ -65,6 +70,71 @@ void DataServer::readPendingDatagrams() { PacketType requestType = packetTypeForPacket(receivedPacket); + if ((requestType == PacketTypeDataServerHashPut || requestType == PacketTypeDataServerHashGet) && + packetVersionMatch(receivedPacket)) { + + QDataStream packetStream(receivedPacket); + int numReceivedHeaderBytes = numBytesForPacketHeader(receivedPacket); + packetStream.skipRawData(numReceivedHeaderBytes); + + // pull the sequence number used for this packet + quint8 sequenceNumber = 0; + + packetStream >> sequenceNumber; + + // pull the UUID that we will need as part of the key + QString userString; + packetStream >> userString; + + if (requestType == PacketTypeDataServerHashPut) { + QString dataKey, dataValue; + QStringList redisCommandKeys, redisCommandValues; + + while(true) { + packetStream >> dataKey >> dataValue; + if (dataKey.isNull() || dataKey.isEmpty()) { + break; + } + redisAppendCommand(_redis, "%s %s %s %s", + REDIS_HASH_SET, + qPrintable(userString), + qPrintable(dataKey), + qPrintable(dataValue)); + }; + + redisReply* reply = NULL; + redisGetReply(_redis, (void **) &reply); + + if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 0) { + QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerConfirm, _uuid); + replyPacket.append(sequenceNumber); + _socket.writeDatagram(replyPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); + } + + freeReplyObject(reply); + reply = NULL; + } else { + + redisReply* reply = (redisReply*) redisCommand(_redis, "%s %s", REDIS_HASH_GET_ALL, qPrintable(userString)); + + QByteArray sendPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerHashSend, _uuid); + QDataStream sendPacketStream(&sendPacket, QIODevice::Append); + + sendPacketStream << sequenceNumber; + sendPacketStream << userString; + + if (reply->type == REDIS_REPLY_ARRAY && reply->elements > 0) { + for (int i = 0; i < reply->elements; i++) { + sendPacketStream << QString(reply->element[i]->str); + } + } + // reply back with the send packet + _socket.writeDatagram(sendPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); + freeReplyObject(reply); + reply = NULL; + } + } + if ((requestType == PacketTypeDataServerPut || requestType == PacketTypeDataServerGet) && packetVersionMatch(receivedPacket)) { diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 6af6ed478d..4c300f6fda 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -57,7 +57,7 @@ configure_file(InterfaceVersion.h.in ${PROJECT_BINARY_DIR}/includes/InterfaceVer # grab the implementation and header files from src dirs file(GLOB INTERFACE_SRCS src/*.cpp src/*.h) -foreach(SUBDIR avatar devices renderer ui starfield) +foreach(SUBDIR avatar devices renderer ui starfield location) file(GLOB_RECURSE SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h) set(INTERFACE_SRCS ${INTERFACE_SRCS} ${SUBDIR_SRCS}) endforeach(SUBDIR) diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 24ec956c62..52e8b72ab2 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -116,7 +116,10 @@ void DatagramProcessor::processDatagrams() { } case PacketTypeDataServerGet: case PacketTypeDataServerPut: + case PacketTypeDataServerHashPut: + case PacketTypeDataServerHashGet: case PacketTypeDataServerSend: + case PacketTypeDataServerHashSend: case PacketTypeDataServerConfirm: DataServerClient::processMessageFromDataServer(incomingPacket); break; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 67eaa8782c..3b2b09fcd7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -114,7 +115,12 @@ Menu::Menu() : MenuOption::GoToLocation, Qt::CTRL | Qt::SHIFT | Qt::Key_L, this, - SLOT(goToLocation())); + SLOT(goToLocation())); + addActionToQMenuAndActionHash(fileMenu, + MenuOption::NameLocation, + Qt::CTRL | Qt::Key_N, + this, + SLOT(nameLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoTo, Qt::Key_At, @@ -152,8 +158,9 @@ Menu::Menu() : addActionToQMenuAndActionHash(editMenu, MenuOption::CutVoxels, Qt::CTRL | Qt::Key_X, appInstance, SLOT(cutVoxels())); addActionToQMenuAndActionHash(editMenu, MenuOption::CopyVoxels, Qt::CTRL | Qt::Key_C, appInstance, SLOT(copyVoxels())); addActionToQMenuAndActionHash(editMenu, MenuOption::PasteVoxels, Qt::CTRL | Qt::Key_V, appInstance, SLOT(pasteVoxels())); - addActionToQMenuAndActionHash(editMenu, MenuOption::NudgeVoxels, Qt::CTRL | Qt::Key_N, appInstance, SLOT(nudgeVoxels())); - + // TODO: add new shortcut + addActionToQMenuAndActionHash(editMenu, MenuOption::NudgeVoxels, 0, appInstance, SLOT(nudgeVoxels())); + #ifdef __APPLE__ addActionToQMenuAndActionHash(editMenu, MenuOption::DeleteVoxels, Qt::Key_Backspace, appInstance, SLOT(deleteVoxels())); #else @@ -964,6 +971,70 @@ void Menu::goTo() { sendFakeEnterEvent(); } +void Menu::namedLocationCreated(LocationManager::LocationCreateResponse response, NamedLocation* location) { + + if (response == LocationManager::AlreadyExists) { + QMessageBox msgBox; + msgBox.setText("That name has been claimed by " + location->getCreatedBy() + ", try something else."); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.button(QMessageBox::Ok)->setText("Go to user"); + int ret = msgBox.exec(); + + if (ret == QMessageBox::Ok) { + DataServerClient::getValuesForKeysAndUserString( + QStringList() + << DataServerKey::Domain + << DataServerKey::Position + << DataServerKey::Orientation, + location->getCreatedBy(), + Application::getInstance()->getProfile()); + } + } +} + +void Menu::nameLocation() { + // check if user is logged in or show login dialog if not + Profile* profile = Application::getInstance()->getProfile(); + if (profile->getUsername().isNull()) { + QMessageBox msgBox; + msgBox.setText("We need to tie this location to your username."); + msgBox.setInformativeText("Please login first, then try naming the location again."); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.button(QMessageBox::Ok)->setText("Login"); + if (msgBox.exec() == QMessageBox::Ok) { + login(); + } + return; + } + + QInputDialog nameDialog(Application::getInstance()->getWindow()); + nameDialog.setWindowTitle("Name this location"); + nameDialog.setLabelText("Name this location, then share that name with others.\n" + "When they come here, they'll be in the same location and orientation\n" + "(wherever you are standing and looking now) as you.\n\n" + "Location name:"); + + nameDialog.setWindowFlags(Qt::Sheet); + nameDialog.resize((int) (nameDialog.parentWidget()->size().width() * 0.30), nameDialog.size().height()); + + if (nameDialog.exec() == QDialog::Accepted) { + + QString locationName = nameDialog.textValue().trimmed(); + if (locationName.isEmpty()) { + return; + } + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + + LocationManager* manager = new LocationManager(); + connect(manager, + SIGNAL(creationCompleted(LocationManager::LocationCreateResponse, NamedLocation*)), + SLOT(namedLocationCreated(LocationManager::LocationCreateResponse, NamedLocation*))); + + manager->createNamedLocation(locationName, profile->getUsername(), myAvatar->getPosition(), myAvatar->getOrientation()); + } +} + void Menu::goToLocation() { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 5e49ca6fd1..08306f8dd0 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -15,6 +15,7 @@ #include #include +#include "location/LocationManager.h" enum FrustumDrawMode { FRUSTUM_DRAW_MODE_ALL, @@ -101,6 +102,7 @@ private slots: void editPreferences(); void goToDomain(); void goToLocation(); + void nameLocation(); void bandwidthDetailsClosed(); void voxelStatsDetailsClosed(); void lodToolsClosed(); @@ -111,6 +113,7 @@ private slots: void resetSwatchColors(); void showMetavoxelEditor(); void audioMuteToggled(); + void namedLocationCreated(LocationManager::LocationCreateResponse response, NamedLocation* location); private: static Menu* _instance; @@ -210,6 +213,7 @@ namespace MenuOption { const QString GlowMode = "Cycle Glow Mode"; const QString GoToDomain = "Go To Domain..."; const QString GoToLocation = "Go To Location..."; + const QString NameLocation = "Name this location"; const QString GoTo = "Go To..."; const QString ImportVoxels = "Import Voxels"; const QString ImportVoxelsClipboard = "Import Voxels to Clipboard"; diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp new file mode 100644 index 0000000000..11a099ae80 --- /dev/null +++ b/interface/src/location/LocationManager.cpp @@ -0,0 +1,26 @@ +// +// LocationManager.cpp +// hifi +// +// Created by Stojce Slavkovski on 2/7/14. +// +// + +#include "LocationManager.h" + +void LocationManager::createNamedLocation(QString locationName, QString creator, glm::vec3 location, glm::quat orientation) { + _namedLocation = new NamedLocation(locationName, creator, location, orientation); + connect(_namedLocation, SIGNAL(dataReceived(bool)), SLOT(locationDataReceived(bool))); + DataServerClient::getHashFieldsForKey(DataServerKey::NamedLocation, _namedLocation->locationName(), _namedLocation); +} + +void LocationManager::locationDataReceived(bool locationExists) { + disconnect(_namedLocation, SIGNAL(dataReceived(bool)), this, SLOT(locationDataReceived(bool))); + if (locationExists) { + emit creationCompleted(AlreadyExists, _namedLocation); + } else { + DataServerClient::putHashFieldsForKey(DataServerKey::NamedLocation, _namedLocation->locationName(), _namedLocation); + emit creationCompleted(Created, _namedLocation); + } +} + diff --git a/interface/src/location/LocationManager.h b/interface/src/location/LocationManager.h new file mode 100644 index 0000000000..29a29b0496 --- /dev/null +++ b/interface/src/location/LocationManager.h @@ -0,0 +1,37 @@ +// +// LocationManager.h +// hifi +// +// Created by Stojce Slavkovski on 2/7/14. +// +// + +#ifndef __hifi__LocationManager__ +#define __hifi__LocationManager__ + +#include +#include "NamedLocation.h" + +class LocationManager : public QObject { + Q_OBJECT + +public: + enum LocationCreateResponse { + Created, + AlreadyExists + }; + + LocationManager() { }; + void createNamedLocation(QString locationName, QString creator, glm::vec3 location, glm::quat orientation); + +signals: + void creationCompleted(LocationManager::LocationCreateResponse response, NamedLocation* location); + +private: + NamedLocation* _namedLocation; + +private slots: + void locationDataReceived(bool locationExists); +}; + +#endif /* defined(__hifi__LocationManager__) */ diff --git a/interface/src/location/NamedLocation.cpp b/interface/src/location/NamedLocation.cpp new file mode 100644 index 0000000000..977f368091 --- /dev/null +++ b/interface/src/location/NamedLocation.cpp @@ -0,0 +1,46 @@ +// +// LocationManager.cpp +// hifi +// +// Created by Stojce Slavkovski on 2/1/14. +// +// + +#include "NamedLocation.h" + +// deserialize data +void NamedLocation::processDataServerResponse(const QString& userString, + const QStringList& keyList, + const QStringList& valueList) { + for (int i = 0; i < keyList.count(); i++) { + if (keyList[i] == "creator") { + _createdBy = valueList[i]; + } else if (keyList[i] == "location") { + QStringList locationCoords = valueList[i].split(","); + if (locationCoords.length() == 3) { + _location = glm::vec3(locationCoords[0].toLong(), locationCoords[1].toLong(), locationCoords[2].toLong()); + } + } else if (keyList[i] == "orientation") { + + QStringList orientationCoords = valueList[i].split(","); + if (orientationCoords.length() == 4) { + _orientation = glm::quat(orientationCoords[0].toLong(), + orientationCoords[1].toLong(), + orientationCoords[2].toLong(), + orientationCoords[3].toLong()); + } + } + } + + emit dataReceived(keyList.count() > 0); +} + +// serialize data +QHash NamedLocation::getHashData() { + QHash response; + qDebug() << QString::fromStdString(glm::to_string(_location)); + response["location"] = QString::number(_location.x) + "," + QString::number(_location.y) + "," + QString::number(_location.z); + response["creator"] = _createdBy; + response["orientation"] = QString::number(_orientation.x) + "," + QString::number(_orientation.y) + "," + QString::number(_orientation.z) + "," + QString::number(_orientation.w); + return response; +} \ No newline at end of file diff --git a/interface/src/location/NamedLocation.h b/interface/src/location/NamedLocation.h new file mode 100644 index 0000000000..ea315ebf9b --- /dev/null +++ b/interface/src/location/NamedLocation.h @@ -0,0 +1,63 @@ +// +// NamedLocation.h +// hifi +// +// Created by Stojce Slavkovski on 2/1/14. +// +// + +#ifndef __hifi__NamedLocation__ +#define __hifi__NamedLocation__ + +#include +#include +#include + +#include "DataServerClient.h" + +class NamedLocation : public QObject, public DataServerCallbackObject, public DataServerCallerObject { + Q_OBJECT + +public: + + NamedLocation(QString locationName, QString createdBy, glm::vec3 location, glm::quat orientation) { + _locationName = locationName; + _createdBy = createdBy; + _location = location; + _orientation = orientation; + } + + bool isEmpty() { return _locationName.isNull() || _locationName.isEmpty(); } + + // DataServerCallbackObject implementation + void processDataServerResponse(const QString& userString, const QStringList& keyList, const QStringList& valueList); + + // DataServerCallerObject implementation + QHash getHashData(); + + // properties >> + void setLocationName(QString locationName) { _locationName = locationName; } + QString locationName() { return _locationName; } + + void createdBy(QString createdBy) { _createdBy = createdBy; } + QString getCreatedBy() { return _createdBy; } + + void setLocation(glm::vec3 location) { _location = location; } + glm::vec3 location() { return _location; } + + void setOrientation(glm::quat orentation) { _orientation = orentation; } + glm::quat orientation() { return _orientation; } + // properties << + +signals: + void dataReceived(bool locationExists); + +private: + QString _locationName; + QString _createdBy; + glm::vec3 _location; + glm::quat _orientation; + +}; + +#endif /* defined(__hifi__NamedLocation__) */ diff --git a/libraries/shared/src/DataServerClient.cpp b/libraries/shared/src/DataServerClient.cpp index fd003aa3bb..3b6fe2dbf6 100644 --- a/libraries/shared/src/DataServerClient.cpp +++ b/libraries/shared/src/DataServerClient.cpp @@ -88,6 +88,44 @@ void DataServerClient::getValueForKeyAndUserString(const QString& key, const QSt getValuesForKeysAndUserString(QStringList(key), userString, callbackObject); } +void DataServerClient::getHashFieldsForKey(const QString serverKey, QString keyValue, DataServerCallbackObject* callbackObject) { + + QByteArray getPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerHashGet); + QDataStream packetStream(&getPacket, QIODevice::Append); + packetStream << _sequenceNumber << serverKey + ":" + keyValue; + + // add the getPacket to our map of unconfirmed packets, will be deleted once we get a response from the nameserver + _unmatchedPackets.insert(_sequenceNumber, getPacket); + _callbackObjects.insert(_sequenceNumber, callbackObject); + + // send the get to the data server + NodeList::getInstance()->getNodeSocket().writeDatagram(getPacket, dataServerSockAddr().getAddress(), + dataServerSockAddr().getPort()); + _sequenceNumber++; +} + +void DataServerClient::putHashFieldsForKey(const QString serverKey, QString keyValue, DataServerCallerObject* callerObject) { + + QByteArray putPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerHashPut); + QDataStream packetStream(&putPacket, QIODevice::Append); + packetStream << _sequenceNumber << serverKey + ":" + keyValue; + + QHash hashData(callerObject->getHashData()); + QHash::const_iterator i = hashData.constBegin(); + while (i != hashData.constEnd()) { + packetStream << i.key() << i.value(); + ++i; + } + // add the getPacket to our map of unconfirmed packets, will be deleted once we get a response from the nameserver + _unmatchedPackets.insert(_sequenceNumber, putPacket); + + // send this put request to the data server + NodeList::getInstance()->getNodeSocket().writeDatagram(putPacket, dataServerSockAddr().getAddress(), + dataServerSockAddr().getPort()); + + _sequenceNumber++; +} + void DataServerClient::processConfirmFromDataServer(const QByteArray& packet) { removeMatchedPacketFromMap(packet); } @@ -113,12 +151,47 @@ void DataServerClient::processSendFromDataServer(const QByteArray& packet) { valueListString.split(MULTI_KEY_VALUE_SEPARATOR)); } } +void DataServerClient::processHashSendFromDataServer(const QByteArray& packet) { + + // pull the user string from the packet so we know who to associate this with + QDataStream packetStream(packet); + packetStream.skipRawData(numBytesForPacketHeader(packet)); + + quint8 sequenceNumber = 0; + packetStream >> sequenceNumber; + + if (_callbackObjects.find(sequenceNumber) != _callbackObjects.end()) { + // remove the packet from our two maps, it's matched + DataServerCallbackObject* callbackObject = _callbackObjects.take(sequenceNumber); + _unmatchedPackets.remove(sequenceNumber); + + QString userString, keyString, valueString; + QStringList keyList, valueList; + + packetStream >> userString; + + while(true) { + packetStream >> keyString; + packetStream >> valueString; + if (keyString.isNull() || keyString.isEmpty()) { + break; + } + + keyList << keyString; + valueList << valueString; + } + callbackObject->processDataServerResponse(userString, keyList, valueList); + } +} void DataServerClient::processMessageFromDataServer(const QByteArray& packet) { switch (packetTypeForPacket(packet)) { case PacketTypeDataServerSend: processSendFromDataServer(packet); break; + case PacketTypeDataServerHashSend: + processHashSendFromDataServer(packet); + break; case PacketTypeDataServerConfirm: processConfirmFromDataServer(packet); break; diff --git a/libraries/shared/src/DataServerClient.h b/libraries/shared/src/DataServerClient.h index 0360576645..d2f846cc6b 100644 --- a/libraries/shared/src/DataServerClient.h +++ b/libraries/shared/src/DataServerClient.h @@ -18,6 +18,11 @@ #include "HifiSockAddr.h" +class DataServerCallerObject { +public: + virtual QHash getHashData() = 0; +}; + class DataServerCallbackObject { public: virtual void processDataServerResponse(const QString& userString, const QStringList& keyList, const QStringList& valueList) = 0; @@ -35,14 +40,16 @@ public: static void getValueForKeyAndUUID(const QString& key, const QUuid& uuid, DataServerCallbackObject* callbackObject); static void getValuesForKeysAndUUID(const QStringList& keys, const QUuid& uuid, DataServerCallbackObject* callbackObject); static void getValuesForKeysAndUserString(const QStringList& keys, const QString& userString, - DataServerCallbackObject* callbackObject); - + DataServerCallbackObject* callbackObject); + static void getHashFieldsForKey(const QString serverKey, QString keyValue, DataServerCallbackObject* callbackObject); + static void putHashFieldsForKey(const QString serverKey, QString keyValue, DataServerCallerObject* callerObject); static void processMessageFromDataServer(const QByteArray& packet); static void resendUnmatchedPackets(); private: static void processConfirmFromDataServer(const QByteArray& packet); static void processSendFromDataServer(const QByteArray& packet); + static void processHashSendFromDataServer(const QByteArray& packet); static void removeMatchedPacketFromMap(const QByteArray& packet); static QMap _unmatchedPackets; @@ -57,6 +64,7 @@ namespace DataServerKey { const QString Position = "position"; const QString Orientation = "orientation"; const QString UUID = "uuid"; + const QString NamedLocation = "namedlocation"; } #endif /* defined(__hifi__DataServerClient__) */ diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 543dce0504..84f074b0a7 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -36,6 +36,9 @@ enum PacketType { PacketTypeCreateAssignment, PacketTypeDataServerPut, PacketTypeDataServerGet, + PacketTypeDataServerHashPut, + PacketTypeDataServerHashGet, + PacketTypeDataServerHashSend, PacketTypeDataServerSend, PacketTypeDataServerConfirm, PacketTypeVoxelQuery, From d1c8a693876809d3f9b305b04e52d0c883e68991 Mon Sep 17 00:00:00 2001 From: stojce Date: Sat, 8 Feb 2014 09:25:49 +0100 Subject: [PATCH 02/23] New DataServer features --- data-server/src/DataServer.cpp | 6 ++++-- interface/src/Menu.cpp | 2 +- libraries/shared/src/NodeList.cpp | 1 + libraries/shared/src/PacketHeaders.cpp | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/data-server/src/DataServer.cpp b/data-server/src/DataServer.cpp index 429a2ec331..16a274607d 100644 --- a/data-server/src/DataServer.cpp +++ b/data-server/src/DataServer.cpp @@ -69,9 +69,9 @@ void DataServer::readPendingDatagrams() { senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); PacketType requestType = packetTypeForPacket(receivedPacket); - + if ((requestType == PacketTypeDataServerHashPut || requestType == PacketTypeDataServerHashGet) && - packetVersionMatch(receivedPacket)) { + receivedPacket[numBytesArithmeticCodingFromBuffer(receivedPacket.data())] == versionForPacketType(requestType)) { QDataStream packetStream(receivedPacket); int numReceivedHeaderBytes = numBytesForPacketHeader(receivedPacket); @@ -95,6 +95,7 @@ void DataServer::readPendingDatagrams() { if (dataKey.isNull() || dataKey.isEmpty()) { break; } + redisAppendCommand(_redis, "%s %s %s %s", REDIS_HASH_SET, qPrintable(userString), @@ -127,6 +128,7 @@ void DataServer::readPendingDatagrams() { for (int i = 0; i < reply->elements; i++) { sendPacketStream << QString(reply->element[i]->str); } + qDebug() << "Found data for key" << userString; } // reply back with the send packet _socket.writeDatagram(sendPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1d3c1cf589..3f7fe8385b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -998,7 +998,7 @@ void Menu::namedLocationCreated(LocationManager::LocationCreateResponse response void Menu::nameLocation() { // check if user is logged in or show login dialog if not Profile* profile = Application::getInstance()->getProfile(); - if (profile->getUsername().isNull()) { + if (profile->getUUID().isNull()) { QMessageBox msgBox; msgBox.setText("We need to tie this location to your username."); msgBox.setInformativeText("Please login first, then try naming the location again."); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 2672f3b27b..ca378207df 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -97,6 +97,7 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeStunResponse << PacketTypeDataServerConfirm << PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend + << PacketTypeDataServerHashGet << PacketTypeDataServerHashPut << PacketTypeDataServerHashSend << PacketTypeCreateAssignment << PacketTypeRequestAssignment; if (!NON_VERIFIED_PACKETS.contains(packetTypeForPacket(packet))) { diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index b46a57d4aa..168d6700c1 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -56,6 +56,9 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeDataServerPut: case PacketTypeDataServerConfirm: case PacketTypeDataServerSend: + case PacketTypeDataServerHashPut: + case PacketTypeDataServerHashGet: + case PacketTypeDataServerHashSend: return 1; default: return 0; From 655eb2658c56a1da46323fb83e6eb9fec0415990 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 5 Mar 2014 18:18:57 -0800 Subject: [PATCH 03/23] Adding scoring, throwing targets --- examples/gun.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/examples/gun.js b/examples/gun.js index b50a8f64d8..7c6c3bbae3 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -19,11 +19,14 @@ var pitchFromMouse = 0; var isMouseDown = false; var BULLET_VELOCITY = 5.0; +var LEFT_BUTTON_3 = 3; // Load some sound to use for loading and firing var fireSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw"); var loadSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/Gun_Reload_Weapon22.raw"); var impactSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/BulletImpact2.raw"); +var targetLaunchSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw"); + var audioOptions = new AudioInjectionOptions(); audioOptions.volume = 0.9; @@ -34,6 +37,10 @@ for (t = 0; t < numberOfTriggers; t++) { triggerPulled[t] = false; } +var isLaunchButtonPressed = false; + +var score = 0; + // Create a reticle image in center of screen var screenSize = Controller.getViewportDimensions(); var reticle = Overlays.addOverlay("image", { @@ -46,14 +53,32 @@ var reticle = Overlays.addOverlay("image", { alpha: 1 }); +var text = Overlays.addOverlay("text", { + x: screenSize.x / 2 - 100, + y: screenSize.y / 2 - 50, + width: 150, + height: 50, + color: { red: 0, green: 0, blue: 0}, + textColor: { red: 255, green: 0, blue: 0}, + topMargin: 4, + leftMargin: 4, + text: "Score: " + score + }); + + +function printVector(string, vector) { + print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); +} + function shootBullet(position, velocity) { var BULLET_SIZE = 0.02; + var BULLET_GRAVITY = -0.02; Particles.addParticle( { position: position, radius: BULLET_SIZE, color: { red: 200, green: 0, blue: 0 }, velocity: velocity, - gravity: { x: 0, y: -0.1, z: 0 }, + gravity: { x: 0, y: BULLET_GRAVITY, z: 0 }, damping: 0 }); // Play firing sounds @@ -61,6 +86,37 @@ function shootBullet(position, velocity) { Audio.playSound(fireSound, audioOptions); } +function shootTarget() { + var TARGET_SIZE = 0.25; + var TARGET_GRAVITY = -0.6; + var TARGET_UP_VELOCITY = 3.0; + var TARGET_FWD_VELOCITY = 5.0; + var DISTANCE_TO_LAUNCH_FROM = 3.0; + var camera = Camera.getPosition(); + //printVector("camera", camera); + var forwardVector = Quat.getFront(Camera.getOrientation()); + //printVector("forwardVector", forwardVector); + var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM)); + //printVector("newPosition", newPosition); + var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY); + velocity.y += TARGET_UP_VELOCITY; + //printVector("velocity", velocity); + + Particles.addParticle( + { position: newPosition, + radius: TARGET_SIZE, + color: { red: 0, green: 200, blue: 200 }, + velocity: velocity, + gravity: { x: 0, y: TARGET_GRAVITY, z: 0 }, + lifetime: 1000.0, + damping: 0.99 }); + + // Play target shoot sound + audioOptions.position = newPosition; + Audio.playSound(targetLaunchSound, audioOptions); +} + + function particleCollisionWithVoxel(particle, voxel) { var HOLE_SIZE = 0.125; var particleProperties = Particles.getParticleProperties(particle); @@ -73,6 +129,21 @@ function particleCollisionWithVoxel(particle, voxel) { Audio.playSound(impactSound, audioOptions); } +function particleCollisionWithParticle(particle1, particle2) { + print("Particle/Particle!"); + score++; + Overlays.editOverlay(text, { text: "Score: " + score } ); + Particles.deleteParticle(particle1); + Particles.deleteParticle(particle2); +} + +function keyPressEvent(event) { + // if our tools are off, then don't do anything + if (event.text == "t") { + shootTarget(); + } +} + function update() { // Check for mouseLook movement, update rotation @@ -86,6 +157,15 @@ function update() { MyAvatar.headPitch = newPitch; pitchFromMouse = 0; + // Check hydra controller for launch button press + if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) { + isLaunchButtonPressed = true; + shootTarget(); + } else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) { + isLaunchButtonPressed = false; + + } + // Check hydra controller for trigger press var numberOfTriggers = Controller.getNumberOfTriggers(); @@ -174,14 +254,17 @@ function mouseMoveEvent(event) { function scriptEnding() { Overlays.deleteOverlay(reticle); + Overlays.deleteOverlay(text); } Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel); +Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle); Script.scriptEnding.connect(scriptEnding); Script.willSendVisualDataCallback.connect(update); Controller.mousePressEvent.connect(mousePressEvent); Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.keyPressEvent.connect(keyPressEvent); From 95d0128c74bf0436c9e750238b335785e32c2fd7 Mon Sep 17 00:00:00 2001 From: stojce Date: Wed, 12 Mar 2014 18:53:25 +0100 Subject: [PATCH 04/23] Using new API client --- data-server/src/DataServer.cpp | 263 --------------------- interface/src/Menu.cpp | 78 +++++- interface/src/Menu.h | 4 + interface/src/location/LocationManager.cpp | 48 +++- interface/src/location/LocationManager.h | 21 +- interface/src/location/NamedLocation.cpp | 100 +++++--- interface/src/location/NamedLocation.h | 33 ++- libraries/shared/src/AccountManager.h | 3 +- 8 files changed, 213 insertions(+), 337 deletions(-) delete mode 100644 data-server/src/DataServer.cpp diff --git a/data-server/src/DataServer.cpp b/data-server/src/DataServer.cpp deleted file mode 100644 index 16a274607d..0000000000 --- a/data-server/src/DataServer.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// -// DataServer.cpp -// hifi -// -// Created by Stephen Birarda on 1/20/2014. -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// - -#include -#include -#include - -#include -#include -#include - -#include "DataServer.h" - -const quint16 DATA_SERVER_LISTEN_PORT = 3282; - -const char REDIS_HOSTNAME[] = "127.0.0.1"; -const unsigned short REDIS_PORT = 6379; -const int ARGV_FIXED_INDEX_START = 2; - -const char REDIS_HASH_MULTIPLE_SET[] = "HMSET"; -const char REDIS_HASH_SET[] = "HSET"; -const char REDIS_HASH_GET_ALL[] = "HGETALL"; - -DataServer::DataServer(int argc, char* argv[]) : - QCoreApplication(argc, argv), - _socket(), - _redis(NULL), - _uuid(QUuid::createUuid()) -{ - _socket.bind(QHostAddress::Any, DATA_SERVER_LISTEN_PORT); - - connect(&_socket, &QUdpSocket::readyRead, this, &DataServer::readPendingDatagrams); - - _redis = redisConnect(REDIS_HOSTNAME, REDIS_PORT); - - if (_redis && _redis->err) { - if (_redis) { - qDebug() << "Redis connection error:" << _redis->errstr; - } else { - qDebug("Redis connection error - can't allocate redis context."); - } - - // couldn't connect to redis, bail out - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); - } -} - -DataServer::~DataServer() { - // disconnect from redis and free the context - if (_redis) { - redisFree(_redis); - } -} - -const int MAX_PACKET_SIZE = 1500; - -void DataServer::readPendingDatagrams() { - QByteArray receivedPacket; - HifiSockAddr senderSockAddr; - - while (_socket.hasPendingDatagrams()) { - receivedPacket.resize(_socket.pendingDatagramSize()); - _socket.readDatagram(receivedPacket.data(), _socket.pendingDatagramSize(), - senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); - - PacketType requestType = packetTypeForPacket(receivedPacket); - - if ((requestType == PacketTypeDataServerHashPut || requestType == PacketTypeDataServerHashGet) && - receivedPacket[numBytesArithmeticCodingFromBuffer(receivedPacket.data())] == versionForPacketType(requestType)) { - - QDataStream packetStream(receivedPacket); - int numReceivedHeaderBytes = numBytesForPacketHeader(receivedPacket); - packetStream.skipRawData(numReceivedHeaderBytes); - - // pull the sequence number used for this packet - quint8 sequenceNumber = 0; - - packetStream >> sequenceNumber; - - // pull the UUID that we will need as part of the key - QString userString; - packetStream >> userString; - - if (requestType == PacketTypeDataServerHashPut) { - QString dataKey, dataValue; - QStringList redisCommandKeys, redisCommandValues; - - while(true) { - packetStream >> dataKey >> dataValue; - if (dataKey.isNull() || dataKey.isEmpty()) { - break; - } - - redisAppendCommand(_redis, "%s %s %s %s", - REDIS_HASH_SET, - qPrintable(userString), - qPrintable(dataKey), - qPrintable(dataValue)); - }; - - redisReply* reply = NULL; - redisGetReply(_redis, (void **) &reply); - - if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 0) { - QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerConfirm, _uuid); - replyPacket.append(sequenceNumber); - _socket.writeDatagram(replyPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); - } - - freeReplyObject(reply); - reply = NULL; - } else { - - redisReply* reply = (redisReply*) redisCommand(_redis, "%s %s", REDIS_HASH_GET_ALL, qPrintable(userString)); - - QByteArray sendPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerHashSend, _uuid); - QDataStream sendPacketStream(&sendPacket, QIODevice::Append); - - sendPacketStream << sequenceNumber; - sendPacketStream << userString; - - if (reply->type == REDIS_REPLY_ARRAY && reply->elements > 0) { - for (int i = 0; i < reply->elements; i++) { - sendPacketStream << QString(reply->element[i]->str); - } - qDebug() << "Found data for key" << userString; - } - // reply back with the send packet - _socket.writeDatagram(sendPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); - freeReplyObject(reply); - reply = NULL; - } - } - - if ((requestType == PacketTypeDataServerPut || requestType == PacketTypeDataServerGet) && - receivedPacket[numBytesArithmeticCodingFromBuffer(receivedPacket.data())] == versionForPacketType(requestType)) { - - QDataStream packetStream(receivedPacket); - int numReceivedHeaderBytes = numBytesForPacketHeader(receivedPacket); - packetStream.skipRawData(numReceivedHeaderBytes); - - // pull the sequence number used for this packet - quint8 sequenceNumber = 0; - - packetStream >> sequenceNumber; - - // pull the UUID that we will need as part of the key - QString userString; - packetStream >> userString; - QUuid parsedUUID(userString); - - if (parsedUUID.isNull()) { - // we failed to parse a UUID, this means the user has sent us a username - - // ask redis for the UUID for this user - redisReply* reply = (redisReply*) redisCommand(_redis, "GET user:%s", qPrintable(userString)); - - if (reply->type == REDIS_REPLY_STRING) { - parsedUUID = QUuid(QString(reply->str)); - } - - if (!parsedUUID.isNull()) { - qDebug() << "Found UUID" << parsedUUID << "for username" << userString; - } else { - qDebug() << "Failed UUID lookup for username" << userString; - } - - freeReplyObject(reply); - reply = NULL; - } - - if (!parsedUUID.isNull()) { - if (requestType == PacketTypeDataServerPut) { - - // pull the key and value that specifies the data the user is putting/getting - QString dataKey, dataValue; - - packetStream >> dataKey >> dataValue; - - qDebug("Sending command to redis: SET uuid:%s:%s %s", - qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)), - qPrintable(dataKey), qPrintable(dataValue)); - - redisReply* reply = (redisReply*) redisCommand(_redis, "SET uuid:%s:%s %s", - qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)), - qPrintable(dataKey), qPrintable(dataValue)); - - if (reply->type == REDIS_REPLY_STATUS && strcmp("OK", reply->str) == 0) { - // if redis stored the value successfully reply back with a confirm - // which is a reply packet with the sequence number - QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerConfirm, _uuid); - - replyPacket.append(sequenceNumber); - - _socket.writeDatagram(replyPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); - } - - freeReplyObject(reply); - } else { - // setup a send packet with the returned data - // leverage the packetData sent by overwriting and appending - QByteArray sendPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerSend, _uuid); - QDataStream sendPacketStream(&sendPacket, QIODevice::Append); - - sendPacketStream << sequenceNumber; - - // pull the key list that specifies the data the user is putting/getting - QString keyListString; - packetStream >> keyListString; - - if (keyListString != "uuid") { - - // copy the parsed UUID - sendPacketStream << uuidStringWithoutCurlyBraces(parsedUUID); - - const char MULTI_KEY_VALUE_SEPARATOR = '|'; - - // append the keyListString back to the sendPacket - sendPacketStream << keyListString; - - QStringList keyList = keyListString.split(MULTI_KEY_VALUE_SEPARATOR); - QStringList valueList; - - foreach (const QString& dataKey, keyList) { - qDebug("Sending command to redis: GET uuid:%s:%s", - qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)), - qPrintable(dataKey)); - redisReply* reply = (redisReply*) redisCommand(_redis, "GET uuid:%s:%s", - qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)), - qPrintable(dataKey)); - - if (reply->len) { - // copy the value that redis returned - valueList << QString(reply->str); - } else { - // didn't find a value - insert a space - valueList << QChar(' '); - } - - freeReplyObject(reply); - } - - // append the value QStringList using the right separator - sendPacketStream << valueList.join(MULTI_KEY_VALUE_SEPARATOR); - } else { - // user was asking for their UUID - sendPacketStream << userString; - sendPacketStream << QString("uuid"); - sendPacketStream << uuidStringWithoutCurlyBraces(parsedUUID); - } - - // reply back with the send packet - _socket.writeDatagram(sendPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); - } - } - } - } -} diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0674826342..5224d234fb 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -115,13 +116,18 @@ Menu::Menu() : addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToDomain, Qt::CTRL | Qt::Key_D, - this, - SLOT(goToDomainDialog())); + this, + SLOT(goToDomainDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToLocation, Qt::CTRL | Qt::SHIFT | Qt::Key_L, - this, - SLOT(goToLocation())); + this, + SLOT(goToLocation())); + addActionToQMenuAndActionHash(fileMenu, + MenuOption::NameLocation, + Qt::CTRL | Qt::Key_N, + this, + SLOT(nameLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoTo, Qt::Key_At, @@ -400,6 +406,7 @@ void Menu::saveSettings(QSettings* settings) { scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); NodeList::getInstance()->saveData(settings); + } void Menu::importSettings() { @@ -959,6 +966,69 @@ void Menu::goToLocation() { sendFakeEnterEvent(); } +void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse response, NamedLocation* location) { + + if (response == LocationManager::Created) { + return; + } + + QMessageBox msgBox; + switch (response) { + case LocationManager::AlreadyExists: + msgBox.setText("That name has been already claimed, try something else."); + break; + default: + msgBox.setText("An unexpected error has occurred, please try again later."); + break; + } + + msgBox.exec(); +} + +void Menu::nameLocation() { + // check if user is logged in or show login dialog if not + + AccountManager& accountManager = AccountManager::getInstance(); + if (!accountManager.isLoggedIn() && 1 > 2) { + QMessageBox msgBox; + msgBox.setText("We need to tie this location to your username."); + msgBox.setInformativeText("Please login first, then try naming the location again."); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.button(QMessageBox::Ok)->setText("Login"); + if (msgBox.exec() == QMessageBox::Ok) { + loginForCurrentDomain(); + } + + return; + } + + QInputDialog nameDialog(Application::getInstance()->getWindow()); + nameDialog.setWindowTitle("Name this location"); + nameDialog.setLabelText("Name this location, then share that name with others.\n" + "When they come here, they'll be in the same location and orientation\n" + "(wherever you are standing and looking now) as you.\n\n" + "Location name:"); + + nameDialog.setWindowFlags(Qt::Sheet); + nameDialog.resize((int) (nameDialog.parentWidget()->size().width() * 0.30), nameDialog.size().height()); + + if (nameDialog.exec() == QDialog::Accepted) { + + QString locationName = nameDialog.textValue().trimmed(); + if (locationName.isEmpty()) { + return; + } + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + LocationManager* manager = new LocationManager(); + connect(manager, &LocationManager::creationCompleted, this, &Menu::namedLocationCreated); + NamedLocation* location = new NamedLocation(locationName, + myAvatar->getPosition(), myAvatar->getOrientation(), + NodeList::getInstance()->getDomainInfo().getHostname()); + manager->createNamedLocation(location); + } +} + void Menu::pasteToVoxel() { QInputDialog pasteToOctalCodeDialog(Application::getInstance()->getWindow()); pasteToOctalCodeDialog.setWindowTitle("Paste to Voxel"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 204b93dd4a..d701861cf1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -17,6 +17,7 @@ #include #include #include +#include "location/LocationManager.h" const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -134,6 +135,7 @@ private slots: void editPreferences(); void goToDomainDialog(); void goToLocation(); + void nameLocation(); void bandwidthDetailsClosed(); void voxelStatsDetailsClosed(); void lodToolsClosed(); @@ -141,6 +143,7 @@ private slots: void runTests(); void showMetavoxelEditor(); void audioMuteToggled(); + void namedLocationCreated(LocationManager::NamedLocationCreateResponse response, NamedLocation* location); private: static Menu* _instance; @@ -241,6 +244,7 @@ namespace MenuOption { const QString GlowMode = "Cycle Glow Mode"; const QString GoToDomain = "Go To Domain..."; const QString GoToLocation = "Go To Location..."; + const QString NameLocation = "Name this location"; const QString GoTo = "Go To..."; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseVoxelSize = "Increase Voxel Size"; diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index f57ed0f48d..0588c66818 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -8,19 +8,47 @@ #include "LocationManager.h" -void LocationManager::createNamedLocation(QString locationName, QString creator, glm::vec3 location, glm::quat orientation) { - _namedLocation = new NamedLocation(locationName, creator, location, orientation); - connect(_namedLocation, SIGNAL(dataReceived(bool)), SLOT(locationDataReceived(bool))); - // DataServerClient::getHashFieldsForKey(DataServerKey::NamedLocation, _namedLocation->locationName(), _namedLocation); +const QString GET_USER_ADDRESS = "/api/v1/users/%1/address"; +const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address"; +const QString GET_ADDRESSES = "/api/v1/addresses/%1/address"; +const QString POST_PLACE_CREATE = "/api/v1/places/"; + +LocationManager& LocationManager::getInstance() { + static LocationManager sharedInstance; + return sharedInstance; } -void LocationManager::locationDataReceived(bool locationExists) { - disconnect(_namedLocation, SIGNAL(dataReceived(bool)), this, SLOT(locationDataReceived(bool))); - if (locationExists) { - emit creationCompleted(AlreadyExists, _namedLocation); +void LocationManager::namedLocationDataReceived(const QJsonObject& data) { + if (data.isEmpty()) { + return; + } + + qDebug() << data; + if (data.contains("status") && data["status"].toString() == "success") { + NamedLocation* location = new NamedLocation(data["data"].toObject()); + emit creationCompleted(LocationManager::Created, location); } else { - // DataServerClient::putHashFieldsForKey(DataServerKey::NamedLocation, _namedLocation->locationName(), _namedLocation); - emit creationCompleted(Created, _namedLocation); + emit creationCompleted(LocationManager::AlreadyExists, NULL); } } +void LocationManager::errorDataReceived(QNetworkReply::NetworkError error, const QString& message) { + emit creationCompleted(LocationManager::SystemError, NULL); +} + +void LocationManager::createNamedLocation(NamedLocation* namedLocation) { + AccountManager& accountManager = AccountManager::getInstance(); + if (accountManager.isLoggedIn()) { + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "namedLocationDataReceived"; + callbackParams.errorCallbackReceiver = this; + callbackParams.errorCallbackMethod = "errorDataReceived"; + + qDebug() << namedLocation->toJsonString(); + accountManager.authenticatedRequest(POST_PLACE_CREATE, QNetworkAccessManager::PostOperation, + callbackParams, namedLocation->toJsonString().toUtf8()); + } +} + + diff --git a/interface/src/location/LocationManager.h b/interface/src/location/LocationManager.h index 29a29b0496..4282d0e795 100644 --- a/interface/src/location/LocationManager.h +++ b/interface/src/location/LocationManager.h @@ -11,27 +11,32 @@ #include #include "NamedLocation.h" +#include "AccountManager.h" class LocationManager : public QObject { Q_OBJECT public: - enum LocationCreateResponse { + static LocationManager& getInstance(); + + enum NamedLocationCreateResponse { Created, - AlreadyExists + AlreadyExists, + SystemError }; LocationManager() { }; - void createNamedLocation(QString locationName, QString creator, glm::vec3 location, glm::quat orientation); + void createNamedLocation(NamedLocation* namedLocation); + + void goTo(QString destination); + void goToUser(QString userName); signals: - void creationCompleted(LocationManager::LocationCreateResponse response, NamedLocation* location); - -private: - NamedLocation* _namedLocation; + void creationCompleted(LocationManager::NamedLocationCreateResponse response, NamedLocation* location); private slots: - void locationDataReceived(bool locationExists); + void namedLocationDataReceived(const QJsonObject& data); + void errorDataReceived(QNetworkReply::NetworkError error, const QString& message); }; #endif /* defined(__hifi__LocationManager__) */ diff --git a/interface/src/location/NamedLocation.cpp b/interface/src/location/NamedLocation.cpp index 977f368091..af96794fd0 100644 --- a/interface/src/location/NamedLocation.cpp +++ b/interface/src/location/NamedLocation.cpp @@ -8,39 +8,73 @@ #include "NamedLocation.h" -// deserialize data -void NamedLocation::processDataServerResponse(const QString& userString, - const QStringList& keyList, - const QStringList& valueList) { - for (int i = 0; i < keyList.count(); i++) { - if (keyList[i] == "creator") { - _createdBy = valueList[i]; - } else if (keyList[i] == "location") { - QStringList locationCoords = valueList[i].split(","); - if (locationCoords.length() == 3) { - _location = glm::vec3(locationCoords[0].toLong(), locationCoords[1].toLong(), locationCoords[2].toLong()); - } - } else if (keyList[i] == "orientation") { - - QStringList orientationCoords = valueList[i].split(","); - if (orientationCoords.length() == 4) { - _orientation = glm::quat(orientationCoords[0].toLong(), - orientationCoords[1].toLong(), - orientationCoords[2].toLong(), - orientationCoords[3].toLong()); - } - } - } - - emit dataReceived(keyList.count() > 0); +const QString JSON_FORMAT = "{\"address\":{\"position\":\"%1,%2,%3\"," + "\"orientation\":\"%4,%5,%6,%7\",\"domain\":\"%8\"},\"name\":\"%9\"}"; + +QString NamedLocation::toJsonString() { + return JSON_FORMAT.arg(QString::number(_location.x), + QString::number(_location.y), + QString::number(_location.z), + QString::number(_orientation.w), + QString::number(_orientation.x), + QString::number(_orientation.y), + QString::number(_orientation.z), + _domain, + _locationName); } -// serialize data -QHash NamedLocation::getHashData() { - QHash response; - qDebug() << QString::fromStdString(glm::to_string(_location)); - response["location"] = QString::number(_location.x) + "," + QString::number(_location.y) + "," + QString::number(_location.z); - response["creator"] = _createdBy; - response["orientation"] = QString::number(_orientation.x) + "," + QString::number(_orientation.y) + "," + QString::number(_orientation.z) + "," + QString::number(_orientation.w); - return response; +NamedLocation::NamedLocation(const QJsonObject jsonData) { + + bool hasProperties; + + if (jsonData.contains("name")) { + hasProperties = true; + _locationName = jsonData["name"].toString(); + } + + if (jsonData.contains("username")) { + hasProperties = true; + _createdBy = jsonData["username"].toString(); + } + + if (jsonData.contains("domain")) { + hasProperties = true; + _domain = jsonData["domain"].toString(); + } + + // parse position + if (jsonData.contains("position")) { + hasProperties = true; + const int NUMBER_OF_POSITION_ITEMS = 3; + const int X_ITEM = 0; + const int Y_ITEM = 1; + const int Z_ITEM = 2; + + QStringList coordinateItems = jsonData["position"].toString().split(",", QString::SkipEmptyParts); + if (coordinateItems.size() == NUMBER_OF_POSITION_ITEMS) { + double x = coordinateItems[X_ITEM].trimmed().toDouble(); + double y = coordinateItems[Y_ITEM].trimmed().toDouble(); + double z = coordinateItems[Z_ITEM].trimmed().toDouble(); + _location = glm::vec3(x, y, z); + } + } + + // parse orientation + if (jsonData.contains("orientation")) { + hasProperties = true; + QStringList orientationItems = jsonData["orientation"] .toString().split(",", QString::SkipEmptyParts); + const int NUMBER_OF_ORIENTATION_ITEMS = 4; + const int W_ITEM = 0; + const int X_ITEM = 1; + const int Y_ITEM = 2; + const int Z_ITEM = 3; + + if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) { + double w = orientationItems[W_ITEM].trimmed().toDouble(); + double x = orientationItems[X_ITEM].trimmed().toDouble(); + double y = orientationItems[Y_ITEM].trimmed().toDouble(); + double z = orientationItems[Z_ITEM].trimmed().toDouble(); + _orientation = glm::quat(w, x, y, z); + } + } } \ No newline at end of file diff --git a/interface/src/location/NamedLocation.h b/interface/src/location/NamedLocation.h index ba3c532317..4bc8c2e2ad 100644 --- a/interface/src/location/NamedLocation.h +++ b/interface/src/location/NamedLocation.h @@ -13,50 +13,47 @@ #include #include -// #include "DataServerClient.h" +#include -class NamedLocation : public QObject { //, public DataServerCallbackObject, public DataServerCallerObject { +class NamedLocation : public QObject { Q_OBJECT public: - - NamedLocation(QString locationName, QString createdBy, glm::vec3 location, glm::quat orientation) { + NamedLocation(QString locationName, glm::vec3 location, glm::quat orientation, QString domain) { _locationName = locationName; - _createdBy = createdBy; _location = location; _orientation = orientation; + _domain = domain; } + NamedLocation(const QJsonObject jsonData); + + QString toJsonString(); + bool isEmpty() { return _locationName.isNull() || _locationName.isEmpty(); } - // DataServerCallbackObject implementation - void processDataServerResponse(const QString& userString, const QStringList& keyList, const QStringList& valueList); - - // DataServerCallerObject implementation - QHash getHashData(); - - // properties >> void setLocationName(QString locationName) { _locationName = locationName; } QString locationName() { return _locationName; } - - void createdBy(QString createdBy) { _createdBy = createdBy; } - QString getCreatedBy() { return _createdBy; } - + void setLocation(glm::vec3 location) { _location = location; } glm::vec3 location() { return _location; } void setOrientation(glm::quat orentation) { _orientation = orentation; } glm::quat orientation() { return _orientation; } - // properties << - + + void setDomain(QString domain) { _domain = domain; } + QString domain() { return _domain; } + signals: void dataReceived(bool locationExists); private: + QString _locationName; QString _createdBy; glm::vec3 _location; glm::quat _orientation; + QString _domain; }; diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index 8b3c6b362c..b0797e78ca 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -50,8 +50,9 @@ public: Q_INVOKABLE bool checkAndSignalForAccessToken(); void requestAccessToken(const QString& login, const QString& password); - + QString getUsername() const { return _accountInfo.getUsername(); } + QString getAccessToken() const { return _accountInfo.getAccessToken().token; } void destroy() { delete _networkAccessManager; } From fd201c450bb48f79f79f7c0ee24a72907022ba79 Mon Sep 17 00:00:00 2001 From: stojce Date: Wed, 12 Mar 2014 23:02:21 +0100 Subject: [PATCH 05/23] Multiple destinations implementation --- interface/interface_en.ts | 8 +- interface/src/Menu.cpp | 112 ++++---------- interface/src/Menu.h | 1 + interface/src/location/LocationManager.cpp | 169 ++++++++++++++++++++- interface/src/location/LocationManager.h | 17 ++- 5 files changed, 214 insertions(+), 93 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index a8f78cd36e..20d7a74c09 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6845ab2064..a11692ad12 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -37,6 +37,7 @@ #include "InfoView.h" #include "ui/MetavoxelEditor.h" + Menu* Menu::_instance = NULL; Menu* Menu::getInstance() { @@ -79,7 +80,7 @@ Menu::Menu() : _loginAction(NULL) { Application *appInstance = Application::getInstance(); - + QMenu* fileMenu = addMenu("File"); #ifdef Q_OS_MAC @@ -860,67 +861,11 @@ void Menu::goToDomainDialog() { } void Menu::goToOrientation(QString orientation) { - - if (orientation.isEmpty()) { - return; - } - - QStringList orientationItems = orientation.split(QRegExp("_|,"), QString::SkipEmptyParts); - - const int NUMBER_OF_ORIENTATION_ITEMS = 4; - const int W_ITEM = 0; - const int X_ITEM = 1; - const int Y_ITEM = 2; - const int Z_ITEM = 3; - - if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) { - - double w = replaceLastOccurrence('-', '.', orientationItems[W_ITEM].trimmed()).toDouble(); - double x = replaceLastOccurrence('-', '.', orientationItems[X_ITEM].trimmed()).toDouble(); - double y = replaceLastOccurrence('-', '.', orientationItems[Y_ITEM].trimmed()).toDouble(); - double z = replaceLastOccurrence('-', '.', orientationItems[Z_ITEM].trimmed()).toDouble(); - - glm::quat newAvatarOrientation(w, x, y, z); - - MyAvatar* myAvatar = Application::getInstance()->getAvatar(); - glm::quat avatarOrientation = myAvatar->getOrientation(); - if (newAvatarOrientation != avatarOrientation) { - myAvatar->setOrientation(newAvatarOrientation); - } - } + LocationManager::getInstance().goToDestination(orientation); } bool Menu::goToDestination(QString destination) { - - QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); - - const int NUMBER_OF_COORDINATE_ITEMS = 3; - const int X_ITEM = 0; - const int Y_ITEM = 1; - const int Z_ITEM = 2; - if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { - - double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble(); - double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble(); - double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).toDouble(); - - glm::vec3 newAvatarPos(x, y, z); - - MyAvatar* myAvatar = Application::getInstance()->getAvatar(); - glm::vec3 avatarPos = myAvatar->getPosition(); - if (newAvatarPos != avatarPos) { - // send a node kill request, indicating to other clients that they should play the "disappeared" effect - MyAvatar::sendKillAvatar(); - - qDebug("Going To Location: %f, %f, %f...", x, y, z); - myAvatar->setPosition(newAvatarPos); - } - - return true; - } - - // no coordinates were parsed - return false; + return LocationManager::getInstance().goToDestination(destination); } void Menu::goTo() { @@ -935,25 +880,33 @@ void Menu::goTo() { int dialogReturn = gotoDialog.exec(); if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) { - - destination = gotoDialog.textValue(); - - // go to coordinate destination or to Username - if (!goToDestination(destination)) { - JSONCallbackParameters callbackParams; - callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); - callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; - - // there's a username entered by the user, make a request to the data-server for the associated location - AccountManager::getInstance().authenticatedRequest("/api/v1/users/" + gotoDialog.textValue() + "/address", - QNetworkAccessManager::GetOperation, - callbackParams); - } + LocationManager* manager = new LocationManager(); + manager->goTo(gotoDialog.textValue()); + connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); } sendFakeEnterEvent(); } +void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) { + QMessageBox msgBox; + msgBox.setText("Both user and location exists with same name"); + msgBox.setInformativeText("Where you wanna go?"); + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Open); + msgBox.button(QMessageBox::Ok)->setText("User"); + msgBox.button(QMessageBox::Open)->setText("Place"); + int userResponse = msgBox.exec(); + + if (userResponse == QMessageBox::Ok) { + Application::getInstance()->getAvatar()->goToLocationFromResponse(userData); + } else if (userResponse == QMessageBox::Open) { + Application::getInstance()->getAvatar()->goToLocationFromResponse(userData); + } + + LocationManager* manager = reinterpret_cast(sender()); + disconnect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); +} + void Menu::goToLocation() { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); glm::vec3 avatarPos = myAvatar->getPosition(); @@ -999,7 +952,7 @@ void Menu::nameLocation() { // check if user is logged in or show login dialog if not AccountManager& accountManager = AccountManager::getInstance(); - if (!accountManager.isLoggedIn() && 1 > 2) { + if (!accountManager.isLoggedIn()) { QMessageBox msgBox; msgBox.setText("We need to tie this location to your username."); msgBox.setInformativeText("Please login first, then try naming the location again."); @@ -1278,17 +1231,6 @@ void Menu::addAvatarCollisionSubMenu(QMenu* overMenu) { 0, true, avatar, SLOT(updateCollisionFlags())); } -QString Menu::replaceLastOccurrence(QChar search, QChar replace, QString string) { - int lastIndex; - lastIndex = string.lastIndexOf(search); - if (lastIndex > 0) { - lastIndex = string.lastIndexOf(search); - string.replace(lastIndex, 1, replace); - } - - return string; -} - QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) { QList menuActions; if (menu) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6ff0d79662..d47c156aa8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -149,6 +149,7 @@ private slots: void toggleChat(); void audioMuteToggled(); void namedLocationCreated(LocationManager::NamedLocationCreateResponse response, NamedLocation* location); + void multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData); private: static Menu* _instance; diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index 0588c66818..61ed401766 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -7,12 +7,17 @@ // #include "LocationManager.h" +#include "Application.h" const QString GET_USER_ADDRESS = "/api/v1/users/%1/address"; const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address"; -const QString GET_ADDRESSES = "/api/v1/addresses/%1/address"; const QString POST_PLACE_CREATE = "/api/v1/places/"; + +LocationManager::LocationManager() : _userData(), _placeData() { + +}; + LocationManager& LocationManager::getInstance() { static LocationManager sharedInstance; return sharedInstance; @@ -23,7 +28,6 @@ void LocationManager::namedLocationDataReceived(const QJsonObject& data) { return; } - qDebug() << data; if (data.contains("status") && data["status"].toString() == "success") { NamedLocation* location = new NamedLocation(data["data"].toObject()); emit creationCompleted(LocationManager::Created, location); @@ -45,10 +49,169 @@ void LocationManager::createNamedLocation(NamedLocation* namedLocation) { callbackParams.errorCallbackReceiver = this; callbackParams.errorCallbackMethod = "errorDataReceived"; - qDebug() << namedLocation->toJsonString(); accountManager.authenticatedRequest(POST_PLACE_CREATE, QNetworkAccessManager::PostOperation, callbackParams, namedLocation->toJsonString().toUtf8()); } } +void LocationManager::goTo(QString destination) { + + if (destination.startsWith("@")) { + // remove '@' and go to user + goToUser(destination.remove(0, 1)); + return; + } + + if (destination.startsWith("#")) { + // remove '#' and go to named place + goToPlace(destination.remove(0, 1)); + return; + } + + // go to coordinate destination or to Username + if (!goToDestination(destination)) { + // reset data on local variables + _userData = QJsonObject(); + _placeData = QJsonObject(); + + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "goToUserFromResponse"; + AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(destination), + QNetworkAccessManager::GetOperation, + callbackParams); + + callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; + AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(destination), + QNetworkAccessManager::GetOperation, + callbackParams); + } +} + +void LocationManager::goToUserFromResponse(const QJsonObject& jsonObject) { + _userData = jsonObject; + checkForMultipleDestinations(); +} + +void LocationManager::goToLocationFromResponse(const QJsonObject& jsonObject) { + _placeData = jsonObject; + checkForMultipleDestinations(); +} + +void LocationManager::checkForMultipleDestinations() { + if (!_userData.isEmpty() && !_placeData.isEmpty()) { + if (_userData.contains("status") && _userData["status"].toString() == "success" && + _placeData.contains("status") && _placeData["status"].toString() == "success") { + emit multipleDestinationsFound(_userData, _placeData); + return; + } + + if (_userData.contains("status") && _userData["status"].toString() == "success") { + Application::getInstance()->getAvatar()->goToLocationFromResponse(_userData); + return; + } + + if (_placeData.contains("status") && _placeData["status"].toString() == "success") { + Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData); + return; + } + + emit locationChanged(); + } +} + +void LocationManager::goToUser(QString userName) { + + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); + callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; + + AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(userName), + QNetworkAccessManager::GetOperation, + callbackParams); +} + +void LocationManager::goToPlace(QString placeName) { + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); + callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; + + AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(placeName), + QNetworkAccessManager::GetOperation, + callbackParams); +} + +void LocationManager::goToOrientation(QString orientation) { + if (orientation.isEmpty()) { + return; + } + + QStringList orientationItems = orientation.split(QRegExp("_|,"), QString::SkipEmptyParts); + + const int NUMBER_OF_ORIENTATION_ITEMS = 4; + const int W_ITEM = 0; + const int X_ITEM = 1; + const int Y_ITEM = 2; + const int Z_ITEM = 3; + + if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) { + + double w = replaceLastOccurrence('-', '.', orientationItems[W_ITEM].trimmed()).toDouble(); + double x = replaceLastOccurrence('-', '.', orientationItems[X_ITEM].trimmed()).toDouble(); + double y = replaceLastOccurrence('-', '.', orientationItems[Y_ITEM].trimmed()).toDouble(); + double z = replaceLastOccurrence('-', '.', orientationItems[Z_ITEM].trimmed()).toDouble(); + + glm::quat newAvatarOrientation(w, x, y, z); + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + glm::quat avatarOrientation = myAvatar->getOrientation(); + if (newAvatarOrientation != avatarOrientation) { + myAvatar->setOrientation(newAvatarOrientation); + } + } +} + +bool LocationManager::goToDestination(QString destination) { + + QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); + + const int NUMBER_OF_COORDINATE_ITEMS = 3; + const int X_ITEM = 0; + const int Y_ITEM = 1; + const int Z_ITEM = 2; + if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { + + double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble(); + double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble(); + double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).toDouble(); + + glm::vec3 newAvatarPos(x, y, z); + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + glm::vec3 avatarPos = myAvatar->getPosition(); + if (newAvatarPos != avatarPos) { + // send a node kill request, indicating to other clients that they should play the "disappeared" effect + MyAvatar::sendKillAvatar(); + + qDebug("Going To Location: %f, %f, %f...", x, y, z); + myAvatar->setPosition(newAvatarPos); + } + + return true; + } + + // no coordinates were parsed + return false; +} + +QString LocationManager::replaceLastOccurrence(QChar search, QChar replace, QString string) { + int lastIndex; + lastIndex = string.lastIndexOf(search); + if (lastIndex > 0) { + lastIndex = string.lastIndexOf(search); + string.replace(lastIndex, 1, replace); + } + + return string; +} diff --git a/interface/src/location/LocationManager.h b/interface/src/location/LocationManager.h index 4282d0e795..6d5beacae5 100644 --- a/interface/src/location/LocationManager.h +++ b/interface/src/location/LocationManager.h @@ -25,18 +25,33 @@ public: SystemError }; - LocationManager() { }; + LocationManager(); void createNamedLocation(NamedLocation* namedLocation); void goTo(QString destination); void goToUser(QString userName); + void goToPlace(QString placeName); + void goToOrientation(QString orientation); + bool goToDestination(QString destination); + +private: + QString replaceLastOccurrence(QChar search, QChar replace, QString string); + QJsonObject _userData; + QJsonObject _placeData; + + void checkForMultipleDestinations(); signals: void creationCompleted(LocationManager::NamedLocationCreateResponse response, NamedLocation* location); + void multipleDestinationsFound(const QJsonObject& userData, const QJsonObject& placeData); + void locationChanged(); private slots: void namedLocationDataReceived(const QJsonObject& data); void errorDataReceived(QNetworkReply::NetworkError error, const QString& message); + void goToLocationFromResponse(const QJsonObject& jsonObject); + void goToUserFromResponse(const QJsonObject& jsonObject); + }; #endif /* defined(__hifi__LocationManager__) */ From d92426c37dd6c70216598291fd280cf0e4fc0561 Mon Sep 17 00:00:00 2001 From: stojce Date: Wed, 12 Mar 2014 23:11:44 +0100 Subject: [PATCH 06/23] translation auto corrected --- interface/interface_en.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 20d7a74c09..58796e1aa4 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file From e231c8486b20da47dd4c1ea565ec7e8ea73eb36a Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 13 Mar 2014 07:47:33 +0100 Subject: [PATCH 07/23] Using singleton for location manager --- interface/interface_en.ts | 8 ++++---- interface/src/Menu.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index e658d15ba7..46d050787a 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 69cbd4a963..eb4386b84c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -884,7 +884,7 @@ void Menu::goTo() { int dialogReturn = gotoDialog.exec(); if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) { - LocationManager* manager = new LocationManager(); + LocationManager* manager = &LocationManager::getInstance(); manager->goTo(gotoDialog.textValue()); connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); } From e964b846de1e094d40310f8158a1e9c53fa8f4fd Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 13 Mar 2014 08:03:23 +0100 Subject: [PATCH 08/23] - url encoding for get requests --- interface/src/location/LocationManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index 61ed401766..f23915506d 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -74,6 +74,7 @@ void LocationManager::goTo(QString destination) { _userData = QJsonObject(); _placeData = QJsonObject(); + destination = QString::QString(QUrl::toPercentEncoding(destination)); JSONCallbackParameters callbackParams; callbackParams.jsonCallbackReceiver = this; callbackParams.jsonCallbackMethod = "goToUserFromResponse"; @@ -126,6 +127,7 @@ void LocationManager::goToUser(QString userName) { callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; + userName = QString::QString(QUrl::toPercentEncoding(userName)); AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(userName), QNetworkAccessManager::GetOperation, callbackParams); @@ -136,6 +138,7 @@ void LocationManager::goToPlace(QString placeName) { callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; + placeName = QString::QString(QUrl::toPercentEncoding(placeName)); AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(placeName), QNetworkAccessManager::GetOperation, callbackParams); From be804e0f864ff17ba7ed3c940d67206db8f9dcc8 Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 13 Mar 2014 09:30:59 +0100 Subject: [PATCH 09/23] Fixes for linux build --- interface/src/location/LocationManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index f23915506d..986371ac88 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -74,7 +74,7 @@ void LocationManager::goTo(QString destination) { _userData = QJsonObject(); _placeData = QJsonObject(); - destination = QString::QString(QUrl::toPercentEncoding(destination)); + destination = QString(QUrl::toPercentEncoding(destination)); JSONCallbackParameters callbackParams; callbackParams.jsonCallbackReceiver = this; callbackParams.jsonCallbackMethod = "goToUserFromResponse"; @@ -127,7 +127,7 @@ void LocationManager::goToUser(QString userName) { callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; - userName = QString::QString(QUrl::toPercentEncoding(userName)); + userName = QString(QUrl::toPercentEncoding(userName)); AccountManager::getInstance().authenticatedRequest(GET_USER_ADDRESS.arg(userName), QNetworkAccessManager::GetOperation, callbackParams); @@ -138,7 +138,7 @@ void LocationManager::goToPlace(QString placeName) { callbackParams.jsonCallbackReceiver = Application::getInstance()->getAvatar(); callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; - placeName = QString::QString(QUrl::toPercentEncoding(placeName)); + placeName = QString(QUrl::toPercentEncoding(placeName)); AccountManager::getInstance().authenticatedRequest(GET_PLACE_ADDRESS.arg(placeName), QNetworkAccessManager::GetOperation, callbackParams); From b3cbcc6cd6b841962cc181ffc58d2946a948eac7 Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 13 Mar 2014 10:20:16 +0100 Subject: [PATCH 10/23] minor cleanup of unused data --- libraries/shared/src/NodeList.cpp | 1 - libraries/shared/src/PacketHeaders.cpp | 3 --- libraries/shared/src/PacketHeaders.h | 3 --- 3 files changed, 7 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 523d18929c..263e29bc94 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -97,7 +97,6 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { << PacketTypeDomainServerAuthRequest << PacketTypeDomainConnectRequest << PacketTypeStunResponse << PacketTypeDataServerConfirm << PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend - << PacketTypeDataServerHashGet << PacketTypeDataServerHashPut << PacketTypeDataServerHashSend << PacketTypeCreateAssignment << PacketTypeRequestAssignment; if (!NON_VERIFIED_PACKETS.contains(checkType)) { diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 88996adceb..eccfa4fefa 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -58,9 +58,6 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeDataServerPut: case PacketTypeDataServerConfirm: case PacketTypeDataServerSend: - case PacketTypeDataServerHashPut: - case PacketTypeDataServerHashGet: - case PacketTypeDataServerHashSend: return 1; case PacketTypeVoxelSet: case PacketTypeVoxelSetDestructive: diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 47a4c65409..0122e36a61 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -39,9 +39,6 @@ enum PacketType { PacketTypeCreateAssignment, PacketTypeDataServerPut, PacketTypeDataServerGet, - PacketTypeDataServerHashPut, - PacketTypeDataServerHashGet, - PacketTypeDataServerHashSend, PacketTypeDataServerSend, PacketTypeDataServerConfirm, PacketTypeVoxelQuery, From b721533f0b934eb2ac77886a10ca3426e7da252f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:43:12 -0700 Subject: [PATCH 11/23] Make chat a dock widget, since that's the behavior it's emulating anyway (and for some reason, the current strategy causes a problem on at least Ryan's and my machine). --- interface/interface_en.ts | 16 ++++++++-------- interface/src/Application.cpp | 10 +--------- interface/src/Menu.cpp | 6 ++---- interface/src/ui/ChatWindow.cpp | 1 - interface/src/ui/ChatWindow.h | 4 ++-- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index c52ec91671..434acb80be 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fedde89a38..37b2810c68 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -292,14 +291,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : ResourceCache::setNetworkAccessManager(_networkAccessManager); ResourceCache::setRequestLimit(3); - QWidget* centralWidget = new QWidget(); - QHBoxLayout* mainLayout = new QHBoxLayout(); - mainLayout->setSpacing(0); - mainLayout->setContentsMargins(0, 0, 0, 0); - centralWidget->setLayout(mainLayout); - _glWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - centralWidget->layout()->addWidget(_glWidget); - _window->setCentralWidget(centralWidget); + _window->setCentralWidget(_glWidget); restoreSizeAndPosition(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 15cfb78cca..22b441d868 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1044,10 +1044,8 @@ void Menu::showMetavoxelEditor() { void Menu::showChat() { if (!_chatWindow) { - _chatWindow = new ChatWindow(); - QMainWindow* mainWindow = Application::getInstance()->getWindow(); - QBoxLayout* boxLayout = static_cast(mainWindow->centralWidget()->layout()); - boxLayout->addWidget(_chatWindow, 0, Qt::AlignRight); + Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); + } else { if (!_chatWindow->isVisible()) { _chatWindow->show(); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 103f045cfa..e28051f214 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -28,7 +28,6 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); ChatWindow::ChatWindow() : - QWidget(), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index fbf9fc0859..da8d423b9d 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -10,8 +10,8 @@ #define __interface__ChatWindow__ #include +#include #include -#include #include @@ -26,7 +26,7 @@ namespace Ui { class ChatWindow; } -class ChatWindow : public QWidget { +class ChatWindow : public QDockWidget { Q_OBJECT public: From a7d35944ccd22bad8cfbcf1b5c806ea284debada Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:48:57 -0700 Subject: [PATCH 12/23] Use an inner widget for the dock. --- interface/interface_en.ts | 8 ++++---- interface/src/ui/ChatWindow.cpp | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 434acb80be..9565d6e88a 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index e28051f214..b7587f9508 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -31,7 +31,10 @@ ChatWindow::ChatWindow() : ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { - ui->setupUi(this); + QWidget* widget = new QWidget(); + setWidget(widget); + + ui->setupUi(widget); FlowLayout* flowLayout = new FlowLayout(0, 4, 4); ui->usersWidget->setLayout(flowLayout); From 5f7e41b79bf59567f36d6c8ca709f1eb07ad9ee7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 10:55:27 -0700 Subject: [PATCH 13/23] More dock widget tweaks. --- interface/interface_en.ts | 8 ++++---- interface/src/Menu.cpp | 8 ++++---- interface/src/ui/ChatWindow.cpp | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 9565d6e88a..f07f50f287 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -45,7 +45,7 @@ - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 22b441d868..c4b7fdcdd6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1047,8 +1047,8 @@ void Menu::showChat() { Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); } else { - if (!_chatWindow->isVisible()) { - _chatWindow->show(); + if (!_chatWindow->toggleViewAction()->isChecked()) { + _chatWindow->toggleViewAction()->trigger(); } } } @@ -1056,8 +1056,8 @@ void Menu::showChat() { void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); - if (!_chatAction->isEnabled() && _chatWindow) { - _chatWindow->hide(); + if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) { + _chatWindow->toggleViewAction()->trigger(); } #endif } diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index b7587f9508..55f32c5c7c 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -41,6 +41,8 @@ ChatWindow::ChatWindow() : ui->messagePlainTextEdit->installEventFilter(this); + ui->closeButton->hide(); + #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { From a045a87cca07c6e36d5ddc44fd4e26bd40827a3d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Mar 2014 11:11:00 -0700 Subject: [PATCH 14/23] Remove arm stretching, add sixense calibration --- interface/src/BuckyBalls.cpp | 1 + .../src/ControllerScriptingInterface.cpp | 1 + interface/src/avatar/SkeletonModel.cpp | 42 +--- interface/src/avatar/SkeletonModel.h | 4 - interface/src/devices/SixenseManager.cpp | 222 +++++++++++++++--- interface/src/devices/SixenseManager.h | 37 ++- libraries/avatars/src/HandData.cpp | 8 +- libraries/avatars/src/HandData.h | 20 +- libraries/shared/src/SharedUtil.h | 7 +- 9 files changed, 244 insertions(+), 98 deletions(-) diff --git a/interface/src/BuckyBalls.cpp b/interface/src/BuckyBalls.cpp index 14d4d0f1a8..8e489db74b 100644 --- a/interface/src/BuckyBalls.cpp +++ b/interface/src/BuckyBalls.cpp @@ -10,6 +10,7 @@ #include "Util.h" #include "world.h" +#include "devices/SixenseManager.h" const int NUM_ELEMENTS = 3; const float RANGE_BBALLS = 0.5f; diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index b60615f124..f5ab1653f5 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -8,6 +8,7 @@ #include #include "Application.h" +#include "devices/SixenseManager.h" #include "ControllerScriptingInterface.h" ControllerScriptingInterface::ControllerScriptingInterface() : diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f405358710..7edf48602e 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -123,6 +123,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); + setJointPosition(jointIndex, palm.getPosition()); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; glm::quat palmRotation; getJointRotation(jointIndex, palmRotation, true); @@ -154,7 +155,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // no point in continuing if there are no fingers if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) { - stretchArm(jointIndex, palm.getPosition()); return; } @@ -172,8 +172,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true); } - - stretchArm(jointIndex, palm.getPosition()); } void SkeletonModel::updateJointState(int index) { @@ -200,41 +198,3 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::normalize(inverse * axes[0])) * joint.rotation; } -void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) { - // find out where the hand is pointing - glm::quat handRotation; - getJointRotation(jointIndex, handRotation, true); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::vec3 forwardVector(jointIndex == geometry.rightHandJointIndex ? -1.0f : 1.0f, 0.0f, 0.0f); - glm::vec3 handVector = handRotation * forwardVector; - - // align elbow with hand - const FBXJoint& joint = geometry.joints.at(jointIndex); - if (joint.parentIndex == -1) { - return; - } - glm::quat elbowRotation; - getJointRotation(joint.parentIndex, elbowRotation, true); - applyRotationDelta(joint.parentIndex, rotationBetween(elbowRotation * forwardVector, handVector), false); - - // set position according to normal length - float scale = extractUniformScale(_scale); - glm::vec3 handPosition = position - _translation; - glm::vec3 elbowPosition = handPosition - handVector * joint.distanceToParent * scale; - - // set shoulder orientation to point to elbow - const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex); - if (parentJoint.parentIndex == -1) { - return; - } - glm::quat shoulderRotation; - getJointRotation(parentJoint.parentIndex, shoulderRotation, true); - applyRotationDelta(parentJoint.parentIndex, rotationBetween(shoulderRotation * forwardVector, - elbowPosition - extractTranslation(_jointStates.at(parentJoint.parentIndex).transform)), false); - - // update the shoulder state - updateJointState(parentJoint.parentIndex); - - // adjust the elbow's local translation - setJointTranslation(joint.parentIndex, elbowPosition); -} diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 3d95d805ea..533f22975f 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -43,10 +43,6 @@ protected: private: - /// Using the current position and rotation of the identified (hand) joint, computes a - /// reasonable stretched configuration for the connected arm. - void stretchArm(int jointIndex, const glm::vec3& position); - Avatar* _owningAvatar; }; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 0482dbf84c..8e54e034ac 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -6,17 +6,33 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#ifdef HAVE_SIXENSE - #include "sixense.h" -#endif +#include #include "Application.h" #include "SixenseManager.h" -using namespace std; - -SixenseManager::SixenseManager() : _lastMovement(0) { #ifdef HAVE_SIXENSE +const int CALIBRATION_STATE_IDLE = 0; +const int CALIBRATION_STATE_X = 1; +const int CALIBRATION_STATE_Y = 2; +const int CALIBRATION_STATE_Z = 3; +const int CALIBRATION_STATE_COMPLETE = 4; + +// default (expected) location of neck in sixense space +const float NECK_X = 250.f; // millimeters +const float NECK_Y = 300.f; // millimeters +const float NECK_Z = 300.f; // millimeters +#endif + +SixenseManager::SixenseManager() { +#ifdef HAVE_SIXENSE + _lastMovement = 0; + + _calibrationState = CALIBRATION_STATE_IDLE; + // By default we assume the _neckBase (in orb frame) is as high above the orb + // as the "torso" is below it. + _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); + sixenseInit(); #endif } @@ -48,12 +64,18 @@ void SixenseManager::update(float deltaTime) { Hand* hand = avatar->getHand(); int maxControllers = sixenseGetMaxControllers(); - for (int i = 0; i < maxControllers; i++) { + + // we only support two controllers + sixenseControllerData controllers[2]; + + int numActiveControllers = 0; + for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { if (!sixenseIsControllerEnabled(i)) { continue; } - sixenseControllerData data; - sixenseGetNewestData(i, &data); + sixenseControllerData* data = controllers + numActiveControllers; + ++numActiveControllers; + sixenseGetNewestData(i, data); // Set palm position and normal based on Hydra position/orientation @@ -61,7 +83,7 @@ void SixenseManager::update(float deltaTime) { PalmData* palm; bool foundHand = false; for (size_t j = 0; j < hand->getNumPalms(); j++) { - if (hand->getPalms()[j].getSixenseID() == data.controller_index) { + if (hand->getPalms()[j].getSixenseID() == data->controller_index) { palm = &(hand->getPalms()[j]); foundHand = true; } @@ -70,26 +92,27 @@ void SixenseManager::update(float deltaTime) { PalmData newPalm(hand); hand->getPalms().push_back(newPalm); palm = &(hand->getPalms()[hand->getNumPalms() - 1]); - palm->setSixenseID(data.controller_index); - printf("Found new Sixense controller, ID %i\n", data.controller_index); + palm->setSixenseID(data->controller_index); + printf("Found new Sixense controller, ID %i\n", data->controller_index); } palm->setActive(true); // Read controller buttons and joystick into the hand - palm->setControllerButtons(data.buttons); - palm->setTrigger(data.trigger); - palm->setJoystick(data.joystick_x, data.joystick_y); - - glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); - // Adjust for distance between acquisition 'orb' and the user's torso - // (distance to the right of body center, distance below torso, distance behind torso) - const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f); - position = SPHERE_TO_TORSO + position; - + palm->setControllerButtons(data->buttons); + palm->setTrigger(data->trigger); + palm->setJoystick(data->joystick_x, data->joystick_y); + + glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); + // Transform the measured position into body frame. + glm::vec3 neck = _neckBase; + // Zeroing y component of the "neck" effectively raises the measured position a little bit. + neck.y = 0.f; + position = _orbRotation * (position - neck); + // Rotation of Palm - glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); - rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * rotation; + glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); + rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _orbRotation * rotation; const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); glm::vec3 newNormal = rotation * PALM_VECTOR; palm->setRawNormal(newNormal); @@ -126,14 +149,159 @@ void SixenseManager::update(float deltaTime) { palm->getFingers().push_back(finger); palm->getFingers().push_back(finger); } - + + if (numActiveControllers == 2) { + updateCalibration(controllers); + } + // if the controllers haven't been moved in a while, disable const unsigned int MOVEMENT_DISABLE_DURATION = 30 * 1000 * 1000; if (usecTimestampNow() - _lastMovement > MOVEMENT_DISABLE_DURATION) { - for (vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { + for (std::vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { it->setActive(false); } } -#endif +#endif // HAVE_SIXENSE } +#ifdef HAVE_SIXENSE + +// the calibration sequence is: +// (1) press BUTTON_FWD on both hands +// (2) reach arm straight out to the side (X) +// (3) lift arms staight up above head (Y) +// (4) move arms a bit forward (Z) +// (5) release BUTTON_FWD on both hands + +const float MINIMUM_ARM_REACH = 300.f; // millimeters +const float MAXIMUM_NOISE_LEVEL = 50.f; // millimeters +const quint64 LOCK_DURATION = USECS_PER_SECOND / 4; // time for lock to be acquired + +void SixenseManager::updateCalibration(const sixenseControllerData* controllers) { + const sixenseControllerData* dataLeft = controllers; + const sixenseControllerData* dataRight = controllers + 1; + + // calibration only happpens while both hands are holding BUTTON_FORWARD + if (dataLeft->buttons != BUTTON_FWD || dataRight->buttons != BUTTON_FWD) { + if (_calibrationState == CALIBRATION_STATE_IDLE) { + return; + } + switch (_calibrationState) { + case CALIBRATION_STATE_Y: + case CALIBRATION_STATE_Z: + case CALIBRATION_STATE_COMPLETE: + { + // compute calibration results + // ATM we only handle the case where the XAxis has been measured, and we assume the rest + // (i.e. that the orb is on a level surface) + // TODO: handle COMPLETE state where all three axes have been defined. This would allow us + // to also handle the case where left and right controllers have been reversed. + _neckBase = 0.5f * (_reachLeft + _reachRight); // neck is midway between right and left reaches + glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft); + glm::vec3 yAxis(0.f, 1.f, 0.f); + glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); + xAxis = glm::normalize(glm::cross(yAxis, zAxis)); + _orbRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); + qDebug("succeess: sixense calibration"); + } + break; + default: + qDebug("failed: sixense calibration"); + break; + } + + _calibrationState = CALIBRATION_STATE_IDLE; + return; + } + + const float* pos = dataLeft->pos; + glm::vec3 positionLeft(pos[0], pos[1], pos[2]); + pos = dataRight->pos; + glm::vec3 positionRight(pos[0], pos[1], pos[2]); + + if (_calibrationState == CALIBRATION_STATE_IDLE) { + float reach = glm::distance(positionLeft, positionRight); + if (reach > 2.f * MINIMUM_ARM_REACH) { + qDebug("started: sixense calibration"); + _averageLeft = positionLeft; + _averageRight = positionRight; + _reachLeft = _averageLeft; + _reachRight = _averageRight; + _lastDistance = reach; + _lockExpiry = usecTimestampNow() + LOCK_DURATION; + // move to next state + _calibrationState = CALIBRATION_STATE_X; + } + return; + } + + quint64 now = usecTimestampNow() + LOCK_DURATION; + // these are weighted running averages + _averageLeft = 0.9f * _averageLeft + 0.1f * positionLeft; + _averageRight = 0.9f * _averageRight + 0.1f * positionRight; + + if (_calibrationState == CALIBRATION_STATE_X) { + // compute new sliding average + float distance = glm::distance(_averageLeft, _averageRight); + if (fabs(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) { + // distance is increasing so acquire the data and push the expiry out + _reachLeft = _averageLeft; + _reachRight = _averageRight; + _lastDistance = distance; + _lockExpiry = now + LOCK_DURATION; + } else if (now > _lockExpiry) { + // lock has expired so clamp the data and move on + _lockExpiry = now + LOCK_DURATION; + _lastDistance = 0.f; + _reachUp = 0.5f * (_reachLeft + _reachRight); + _calibrationState = CALIBRATION_STATE_Y; + qDebug("success: sixense calibration: left"); + } + } + else if (_calibrationState == CALIBRATION_STATE_Y) { + glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); + glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); + float distance = (averagePosition - torso).y; + if (fabs(distance) > fabs(_lastDistance) + MAXIMUM_NOISE_LEVEL) { + // distance is increasing so acquire the data and push the expiry out + _reachUp = averagePosition; + _lastDistance = distance; + _lockExpiry = now + LOCK_DURATION; + } else if (now > _lockExpiry) { + if (_lastDistance > MINIMUM_ARM_REACH) { + // lock has expired so clamp the data and move on + _reachForward = _reachUp; + _lastDistance = 0.f; + _lockExpiry = now + LOCK_DURATION; + _calibrationState = CALIBRATION_STATE_Z; + qDebug("success: sixense calibration: up"); + } + } + } + else if (_calibrationState == CALIBRATION_STATE_Z) { + glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft); + glm::vec3 torso = 0.5f * (_reachLeft + _reachRight); + //glm::vec3 yAxis = glm::normalize(_reachUp - torso); + glm::vec3 yAxis(0.f, 1.f, 0.f); + glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); + + glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight); + float distance = glm::dot((averagePosition - torso), zAxis); + if (fabs(distance) > fabs(_lastDistance)) { + // distance is increasing so acquire the data and push the expiry out + _reachForward = averagePosition; + _lastDistance = distance; + _lockExpiry = now + LOCK_DURATION; + } else if (now > _lockExpiry) { + if (fabs(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) { + // lock has expired so clamp the data and move on + _calibrationState = CALIBRATION_STATE_COMPLETE; + qDebug("success: sixense calibration: forward"); + // TODO: it is theoretically possible to detect that the controllers have been + // accidentally switched (left hand is holding right controller) and to swap the order. + } + } + } +} +#endif // HAVE_SIXENSE + diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 1d8263ee30..de4cccb399 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -9,6 +9,21 @@ #ifndef __interface__SixenseManager__ #define __interface__SixenseManager__ +#include + +#ifdef HAVE_SIXENSE + #include + #include + #include "sixense.h" +#endif + +const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 +const unsigned int BUTTON_1 = 1U << 5; +const unsigned int BUTTON_2 = 1U << 6; +const unsigned int BUTTON_3 = 1U << 3; +const unsigned int BUTTON_4 = 1U << 4; +const unsigned int BUTTON_FWD = 1U << 7; + /// Handles interaction with the Sixense SDK (e.g., Razer Hydra). class SixenseManager : public QObject { Q_OBJECT @@ -24,7 +39,27 @@ public slots: void setFilter(bool filter); private: - +#ifdef HAVE_SIXENSE + void updateCalibration(const sixenseControllerData* controllers); + + int _calibrationState; + + // these are calibration results + glm::vec3 _neckBase; // midpoint between controllers during X-axis calibration + glm::quat _orbRotation; // rotates from orb frame into body frame + float _armLength; + + // these are measured values used to compute the calibration results + quint64 _lockExpiry; + glm::vec3 _averageLeft; + glm::vec3 _averageRight; + glm::vec3 _reachLeft; + glm::vec3 _reachRight; + glm::vec3 _reachUp; + glm::vec3 _reachForward; + float _lastDistance; + +#endif quint64 _lastMovement; }; diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 0355a4c86b..46dade6d64 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -25,10 +25,6 @@ HandData::HandData(AvatarData* owningAvatar) : addNewPalm(); } -glm::vec3 HandData::worldPositionToLeapPosition(const glm::vec3& worldPosition) const { - return glm::inverse(getBaseOrientation()) * (worldPosition - getBasePosition()) / LEAP_UNIT_SCALE; -} - glm::vec3 HandData::worldVectorToLeapVector(const glm::vec3& worldVector) const { return glm::inverse(getBaseOrientation()) * worldVector / LEAP_UNIT_SCALE; } @@ -272,9 +268,7 @@ glm::quat HandData::getBaseOrientation() const { } glm::vec3 HandData::getBasePosition() const { - const glm::vec3 LEAP_HANDS_OFFSET_FROM_TORSO(0.0, 0.3, -0.3); - return _owningAvatarData->getPosition() + getBaseOrientation() * LEAP_HANDS_OFFSET_FROM_TORSO * - _owningAvatarData->getTargetScale(); + return _owningAvatarData->getPosition(); } void FingerData::setTrailLength(unsigned int length) { diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index cdab9f71e9..f649faf080 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -28,13 +28,6 @@ const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND; const int LEAPID_INVALID = -1; const int SIXENSEID_INVALID = -1; -const int BUTTON_0 = 1; // the skinny button between 1 and 2 -const int BUTTON_1 = 32; -const int BUTTON_2 = 64; -const int BUTTON_3 = 8; -const int BUTTON_4 = 16; -const int BUTTON_FWD = 128; - const float LEAP_UNIT_SCALE = 0.001f; ///< convert mm to meters const int SIXENSE_CONTROLLER_ID_LEFT_HAND = 0; @@ -55,7 +48,6 @@ public: glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) { return getBaseOrientation() * leapDirection; } - glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const; glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const; std::vector& getPalms() { return _palms; } @@ -182,11 +174,11 @@ public: int getFramesWithoutData() const { return _numFramesWithoutData; } // Controller buttons - void setControllerButtons(int controllerButtons) { _controllerButtons = controllerButtons; } - void setLastControllerButtons(int controllerButtons) { _lastControllerButtons = controllerButtons; } + void setControllerButtons(unsigned int controllerButtons) { _controllerButtons = controllerButtons; } + void setLastControllerButtons(unsigned int controllerButtons) { _lastControllerButtons = controllerButtons; } - int getControllerButtons() const { return _controllerButtons; } - int getLastControllerButtons() const { return _lastControllerButtons; } + unsigned int getControllerButtons() const { return _controllerButtons; } + unsigned int getLastControllerButtons() const { return _lastControllerButtons; } void setTrigger(float trigger) { _trigger = trigger; } float getTrigger() const { return _trigger; } @@ -217,8 +209,8 @@ private: glm::vec3 _tipPosition; glm::vec3 _tipVelocity; - int _controllerButtons; - int _lastControllerButtons; + unsigned int _controllerButtons; + unsigned int _lastControllerButtons; float _trigger; float _joystickX, _joystickY; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 1695b3b253..439b85aa54 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -57,10 +57,9 @@ static const float DEGREES_PER_RADIAN = 180.0f / PI; static const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations static const float SQUARE_ROOT_OF_2 = (float)sqrt(2.f); static const float SQUARE_ROOT_OF_3 = (float)sqrt(3.f); -static const float METER = 1.0f; -static const float DECIMETER = 0.1f; -static const float CENTIMETER = 0.01f; -static const float MILLIIMETER = 0.001f; +static const float METERS_PER_DECIMETER = 0.1f; +static const float METERS_PER_CENTIMETER = 0.01f; +static const float METERS_PER_MILLIMETER = 0.001f; static const quint64 USECS_PER_MSEC = 1000; static const quint64 MSECS_PER_SECOND = 1000; static const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; From 4366b45445c79e1852a3772f87bacafa68780ec3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 11:13:15 -0700 Subject: [PATCH 15/23] Changed orientation tweak names, restore tweaked orientation rather than primary one. Closes #2310. --- interface/src/avatar/Head.cpp | 12 ++++++------ interface/src/avatar/Head.h | 17 +++++++++++------ interface/src/avatar/MyAvatar.cpp | 11 ++++++----- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 6c2bad865f..a9b85ffce2 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -36,9 +36,9 @@ Head::Head(Avatar* owningAvatar) : _leftEyeBlinkVelocity(0.0f), _rightEyeBlinkVelocity(0.0f), _timeWithoutTalking(0.0f), - _tweakedPitch(0.f), - _tweakedYaw(0.f), - _tweakedRoll(0.f), + _pitchTweak(0.f), + _yawTweak(0.f), + _rollTweak(0.f), _isCameraMoving(false), _faceModel(this) { @@ -202,15 +202,15 @@ glm::vec3 Head::getScalePivot() const { } float Head::getTweakedYaw() const { - return glm::clamp(_yaw + _tweakedYaw, MIN_HEAD_YAW, MAX_HEAD_YAW); + return glm::clamp(_yaw + _yawTweak, MIN_HEAD_YAW, MAX_HEAD_YAW); } float Head::getTweakedPitch() const { - return glm::clamp(_pitch + _tweakedPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); + return glm::clamp(_pitch + _pitchTweak, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } float Head::getTweakedRoll() const { - return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); + return glm::clamp(_roll + _rollTweak, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } void Head::applyCollision(CollisionInfo& collision) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 7e7a96a3a7..a9ea9b4cc6 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -70,10 +70,15 @@ public: /// Returns the point about which scaling occurs. glm::vec3 getScalePivot() const; - void tweakPitch(float pitch) { _tweakedPitch = pitch; } - void tweakYaw(float yaw) { _tweakedYaw = yaw; } - void tweakRoll(float roll) { _tweakedRoll = roll; } + void setPitchTweak(float pitch) { _pitchTweak = pitch; } + float getPitchTweak() const { return _pitchTweak; } + void setYawTweak(float yaw) { _yawTweak = yaw; } + float getYawTweak() const { return _yawTweak; } + + void setRollTweak(float roll) { _rollTweak = roll; } + float getRollTweak() const { return _rollTweak; } + virtual float getTweakedPitch() const; virtual float getTweakedYaw() const; virtual float getTweakedRoll() const; @@ -104,9 +109,9 @@ private: float _timeWithoutTalking; // tweaked angles affect the rendered head, but not the camera - float _tweakedPitch; - float _tweakedYaw; - float _tweakedRoll; + float _pitchTweak; + float _yawTweak; + float _rollTweak; bool _isCameraMoving; FaceModel _faceModel; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0a2462e656..e4aaa07a4b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -363,8 +363,9 @@ void MyAvatar::updateFromGyros(float deltaTime) { // restore rotation, lean to neutral positions const float RESTORE_PERIOD = 1.f; // seconds float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f); - head->setYaw(glm::mix(head->getYaw(), 0.0f, restorePercentage)); - head->setRoll(glm::mix(head->getRoll(), 0.0f, restorePercentage)); + head->setPitchTweak(glm::mix(head->getPitchTweak(), 0.0f, restorePercentage)); + head->setYawTweak(glm::mix(head->getYawTweak(), 0.0f, restorePercentage)); + head->setRollTweak(glm::mix(head->getRollTweak(), 0.0f, restorePercentage)); head->setLeanSideways(glm::mix(head->getLeanSideways(), 0.0f, restorePercentage)); head->setLeanForward(glm::mix(head->getLeanForward(), 0.0f, restorePercentage)); return; @@ -375,9 +376,9 @@ void MyAvatar::updateFromGyros(float deltaTime) { const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; - head->tweakPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); - head->tweakYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); - head->tweakRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); + head->setPitchTweak(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); + head->setYawTweak(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); + head->setRollTweak(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); // Update torso lean distance based on accelerometer data const float TORSO_LENGTH = 0.5f; From 576b8acef3d253f546fef78ccf5b1e9818307f39 Mon Sep 17 00:00:00 2001 From: stojce Date: Fri, 14 Mar 2014 20:09:03 +0100 Subject: [PATCH 16/23] CR fixes --- interface/interface_en.ts | 8 ++-- interface/src/Menu.cpp | 4 +- interface/src/Menu.h | 6 +-- interface/src/location/LocationManager.cpp | 43 ++++++++++------- interface/src/location/LocationManager.h | 7 +-- interface/src/location/NamedLocation.cpp | 56 ---------------------- interface/src/location/NamedLocation.h | 2 - 7 files changed, 38 insertions(+), 88 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index c52ec91671..786a76530c 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b322e6567c..98a00e05c9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -19,12 +19,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include @@ -940,7 +940,7 @@ void Menu::goToLocation() { sendFakeEnterEvent(); } -void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse response, NamedLocation* location) { +void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse response) { if (response == LocationManager::Created) { return; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b124315cbb..df622be6ac 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -17,9 +17,9 @@ #include #include #include -#include "location/LocationManager.h" -#include +#include "location/LocationManager.h" +#include "ui/ChatWindow.h" const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -149,7 +149,7 @@ private slots: void showChat(); void toggleChat(); void audioMuteToggled(); - void namedLocationCreated(LocationManager::NamedLocationCreateResponse response, NamedLocation* location); + void namedLocationCreated(LocationManager::NamedLocationCreateResponse response); void multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData); private: diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index 986371ac88..b83094ba4c 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -6,8 +6,8 @@ // // -#include "LocationManager.h" #include "Application.h" +#include "LocationManager.h" const QString GET_USER_ADDRESS = "/api/v1/users/%1/address"; const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address"; @@ -29,15 +29,14 @@ void LocationManager::namedLocationDataReceived(const QJsonObject& data) { } if (data.contains("status") && data["status"].toString() == "success") { - NamedLocation* location = new NamedLocation(data["data"].toObject()); - emit creationCompleted(LocationManager::Created, location); + emit creationCompleted(LocationManager::Created); } else { - emit creationCompleted(LocationManager::AlreadyExists, NULL); + emit creationCompleted(LocationManager::AlreadyExists); } } void LocationManager::errorDataReceived(QNetworkReply::NetworkError error, const QString& message) { - emit creationCompleted(LocationManager::SystemError, NULL); + emit creationCompleted(LocationManager::SystemError); } void LocationManager::createNamedLocation(NamedLocation* namedLocation) { @@ -149,7 +148,7 @@ void LocationManager::goToOrientation(QString orientation) { return; } - QStringList orientationItems = orientation.split(QRegExp("_|,"), QString::SkipEmptyParts); + QStringList orientationItems = orientation.remove(' ').split(QRegExp("_|,"), QString::SkipEmptyParts); const int NUMBER_OF_ORIENTATION_ITEMS = 4; const int W_ITEM = 0; @@ -159,10 +158,16 @@ void LocationManager::goToOrientation(QString orientation) { if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) { - double w = replaceLastOccurrence('-', '.', orientationItems[W_ITEM].trimmed()).toDouble(); - double x = replaceLastOccurrence('-', '.', orientationItems[X_ITEM].trimmed()).toDouble(); - double y = replaceLastOccurrence('-', '.', orientationItems[Y_ITEM].trimmed()).toDouble(); - double z = replaceLastOccurrence('-', '.', orientationItems[Z_ITEM].trimmed()).toDouble(); + // replace last occurrence of '_' with decimal point + replaceLastOccurrence('-', '.', orientationItems[W_ITEM]); + replaceLastOccurrence('-', '.', orientationItems[X_ITEM]); + replaceLastOccurrence('-', '.', orientationItems[Y_ITEM]); + replaceLastOccurrence('-', '.', orientationItems[Z_ITEM]); + + double w = orientationItems[W_ITEM].toDouble(); + double x = orientationItems[X_ITEM].toDouble(); + double y = orientationItems[Y_ITEM].toDouble(); + double z = orientationItems[Z_ITEM].toDouble(); glm::quat newAvatarOrientation(w, x, y, z); @@ -176,7 +181,7 @@ void LocationManager::goToOrientation(QString orientation) { bool LocationManager::goToDestination(QString destination) { - QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); + QStringList coordinateItems = destination.remove(' ').split(QRegExp("_|,"), QString::SkipEmptyParts); const int NUMBER_OF_COORDINATE_ITEMS = 3; const int X_ITEM = 0; @@ -184,9 +189,14 @@ bool LocationManager::goToDestination(QString destination) { const int Z_ITEM = 2; if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { - double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble(); - double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble(); - double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).toDouble(); + // replace last occurrence of '_' with decimal point + replaceLastOccurrence('-', '.', coordinateItems[X_ITEM]); + replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM]); + replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM]); + + double x = coordinateItems[X_ITEM].toDouble(); + double y = coordinateItems[Y_ITEM].toDouble(); + double z = coordinateItems[Z_ITEM].toDouble(); glm::vec3 newAvatarPos(x, y, z); @@ -207,14 +217,11 @@ bool LocationManager::goToDestination(QString destination) { return false; } -QString LocationManager::replaceLastOccurrence(QChar search, QChar replace, QString string) { +void LocationManager::replaceLastOccurrence(const QChar search, const QChar replace, QString& string) { int lastIndex; lastIndex = string.lastIndexOf(search); if (lastIndex > 0) { lastIndex = string.lastIndexOf(search); string.replace(lastIndex, 1, replace); } - - return string; } - diff --git a/interface/src/location/LocationManager.h b/interface/src/location/LocationManager.h index 6d5beacae5..a6bdaf66b4 100644 --- a/interface/src/location/LocationManager.h +++ b/interface/src/location/LocationManager.h @@ -10,8 +10,9 @@ #define __hifi__LocationManager__ #include -#include "NamedLocation.h" + #include "AccountManager.h" +#include "NamedLocation.h" class LocationManager : public QObject { Q_OBJECT @@ -35,14 +36,14 @@ public: bool goToDestination(QString destination); private: - QString replaceLastOccurrence(QChar search, QChar replace, QString string); QJsonObject _userData; QJsonObject _placeData; + void replaceLastOccurrence(const QChar search, const QChar replace, QString& string); void checkForMultipleDestinations(); signals: - void creationCompleted(LocationManager::NamedLocationCreateResponse response, NamedLocation* location); + void creationCompleted(LocationManager::NamedLocationCreateResponse response); void multipleDestinationsFound(const QJsonObject& userData, const QJsonObject& placeData); void locationChanged(); diff --git a/interface/src/location/NamedLocation.cpp b/interface/src/location/NamedLocation.cpp index af96794fd0..c6daef4961 100644 --- a/interface/src/location/NamedLocation.cpp +++ b/interface/src/location/NamedLocation.cpp @@ -22,59 +22,3 @@ QString NamedLocation::toJsonString() { _domain, _locationName); } - -NamedLocation::NamedLocation(const QJsonObject jsonData) { - - bool hasProperties; - - if (jsonData.contains("name")) { - hasProperties = true; - _locationName = jsonData["name"].toString(); - } - - if (jsonData.contains("username")) { - hasProperties = true; - _createdBy = jsonData["username"].toString(); - } - - if (jsonData.contains("domain")) { - hasProperties = true; - _domain = jsonData["domain"].toString(); - } - - // parse position - if (jsonData.contains("position")) { - hasProperties = true; - const int NUMBER_OF_POSITION_ITEMS = 3; - const int X_ITEM = 0; - const int Y_ITEM = 1; - const int Z_ITEM = 2; - - QStringList coordinateItems = jsonData["position"].toString().split(",", QString::SkipEmptyParts); - if (coordinateItems.size() == NUMBER_OF_POSITION_ITEMS) { - double x = coordinateItems[X_ITEM].trimmed().toDouble(); - double y = coordinateItems[Y_ITEM].trimmed().toDouble(); - double z = coordinateItems[Z_ITEM].trimmed().toDouble(); - _location = glm::vec3(x, y, z); - } - } - - // parse orientation - if (jsonData.contains("orientation")) { - hasProperties = true; - QStringList orientationItems = jsonData["orientation"] .toString().split(",", QString::SkipEmptyParts); - const int NUMBER_OF_ORIENTATION_ITEMS = 4; - const int W_ITEM = 0; - const int X_ITEM = 1; - const int Y_ITEM = 2; - const int Z_ITEM = 3; - - if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) { - double w = orientationItems[W_ITEM].trimmed().toDouble(); - double x = orientationItems[X_ITEM].trimmed().toDouble(); - double y = orientationItems[Y_ITEM].trimmed().toDouble(); - double z = orientationItems[Z_ITEM].trimmed().toDouble(); - _orientation = glm::quat(w, x, y, z); - } - } -} \ No newline at end of file diff --git a/interface/src/location/NamedLocation.h b/interface/src/location/NamedLocation.h index 4bc8c2e2ad..81af03b45e 100644 --- a/interface/src/location/NamedLocation.h +++ b/interface/src/location/NamedLocation.h @@ -26,8 +26,6 @@ public: _domain = domain; } - NamedLocation(const QJsonObject jsonData); - QString toJsonString(); bool isEmpty() { return _locationName.isNull() || _locationName.isEmpty(); } From 8f200e917b78790874adc4268cd22f1ee67c73c1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 14 Mar 2014 13:03:14 -0700 Subject: [PATCH 17/23] fix JS radians vs degrees issues --- examples/cameraExample.js | 2 +- examples/crazylegs.js | 8 ++++---- examples/gun.js | 2 +- examples/hydraMove.js | 2 +- examples/lookWithMouse.js | 2 +- examples/lookWithTouch.js | 2 +- examples/multitouchExample.js | 2 +- examples/seeingVoxelsExample.js | 4 ++-- libraries/script-engine/src/Quat.cpp | 12 ++++++++++-- libraries/script-engine/src/Quat.h | 6 ++++-- 10 files changed, 26 insertions(+), 16 deletions(-) diff --git a/examples/cameraExample.js b/examples/cameraExample.js index ddfff15935..6e3c51a348 100644 --- a/examples/cameraExample.js +++ b/examples/cameraExample.js @@ -74,7 +74,7 @@ function checkCamera(deltaTime) { if (yaw < -360) { yaw += 360; } - var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll); + var orientation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll); Camera.setOrientation(orientation); } } diff --git a/examples/crazylegs.js b/examples/crazylegs.js index 0f26088ae0..0daf2275f3 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -14,10 +14,10 @@ var cumulativeTime = 0.0; Script.update.connect(function(deltaTime) { cumulativeTime += deltaTime; - MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRoll(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_L_hip", Quat.fromPitchYawRoll(0.0, 0.0, -AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); - MyAvatar.setJointData("joint_R_knee", Quat.fromPitchYawRoll(0.0, 0.0, + MyAvatar.setJointData("joint_R_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); + MyAvatar.setJointData("joint_L_hip", Quat.fromPitchYawRollDegrees(0.0, 0.0, -AMPLITUDE * Math.sin(cumulativeTime * FREQUENCY))); + MyAvatar.setJointData("joint_R_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 + Math.sin(cumulativeTime * FREQUENCY)))); - MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRoll(0.0, 0.0, + MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)))); }); diff --git a/examples/gun.js b/examples/gun.js index dee01fb84d..45b7487f25 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -78,7 +78,7 @@ function update(deltaTime) { // Check for mouseLook movement, update rotation // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); MyAvatar.orientation = newOrientation; yawFromMouse = 0; diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 1f9634a8e6..92c594df9e 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -184,7 +184,7 @@ function flyWithHydra(deltaTime) { // change the body yaw based on our x controller var orientation = MyAvatar.orientation; - var deltaOrientation = Quat.fromPitchYawRoll(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); + var deltaOrientation = Quat.fromPitchYawRollDegrees(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation); // change the headPitch based on our x controller diff --git a/examples/lookWithMouse.js b/examples/lookWithMouse.js index 878813a94a..ef8f11ec16 100644 --- a/examples/lookWithMouse.js +++ b/examples/lookWithMouse.js @@ -54,7 +54,7 @@ function update(deltaTime) { print("update()..."); } // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/lookWithTouch.js b/examples/lookWithTouch.js index ddc42c04c0..852573aea6 100644 --- a/examples/lookWithTouch.js +++ b/examples/lookWithTouch.js @@ -45,7 +45,7 @@ function touchUpdateEvent(event) { function update(deltaTime) { // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMouse, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromMouse, 0)); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/multitouchExample.js b/examples/multitouchExample.js index 1041651c7b..51bbcc2c20 100644 --- a/examples/multitouchExample.js +++ b/examples/multitouchExample.js @@ -92,7 +92,7 @@ Controller.touchEndEvent.connect(touchEndEvent); function update(deltaTime) { // rotate body yaw for yaw received from multitouch rotate - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMultiTouch, z: 0 } )); + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMultiTouch, z: 0 } )); if (wantDebugging) { print("changing orientation" + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 62ebd599ee..257e869b5b 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -17,7 +17,7 @@ var yawMin = 20; var isLocal = false; // set up our VoxelViewer with a position and orientation -var orientation = Quat.fromPitchYawRoll(0, yaw, 0); +var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); function init() { if (isLocal) { @@ -40,7 +40,7 @@ function keepLooking(deltaTime) { count++; if (count % 10 == 0) { yaw += yawDirection; - orientation = Quat.fromPitchYawRoll(0, yaw, 0); + orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); if (yaw > yawMax || yaw < yawMin) { yawDirection = yawDirection * -1; } diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 14025f0c67..c939811db4 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -22,14 +22,22 @@ glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { return q1 * q2; } -glm::quat Quat::fromVec3(const glm::vec3& eulerAngles) { +glm::quat Quat::fromVec3Degrees(const glm::vec3& eulerAngles) { return glm::quat(glm::radians(eulerAngles)); } -glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) { +glm::quat Quat::fromVec3Radians(const glm::vec3& eulerAngles) { + return glm::quat(eulerAngles); +} + +glm::quat Quat::fromPitchYawRollDegrees(float pitch, float yaw, float roll) { return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll))); } +glm::quat Quat::fromPitchYawRollRadians(float pitch, float yaw, float roll) { + return glm::quat(glm::vec3(pitch, yaw, roll)); +} + glm::quat Quat::inverse(const glm::quat& q) { return glm::inverse(q); } diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 3e5f46682c..02c0a3e147 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -23,8 +23,10 @@ class Quat : public QObject { public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); - glm::quat fromVec3(const glm::vec3& vec3); - glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); // degrees + glm::quat fromVec3Degrees(const glm::vec3& vec3); // degrees + glm::quat fromVec3Radians(const glm::vec3& vec3); // radians + glm::quat fromPitchYawRollDegrees(float pitch, float yaw, float roll); // degrees + glm::quat fromPitchYawRollRadians(float pitch, float yaw, float roll); // radians glm::quat inverse(const glm::quat& q); glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation); From 608fa5869ded09188e65a6603105b7d83b739784 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 14 Mar 2014 14:51:33 -0700 Subject: [PATCH 18/23] Return the legs to the default position when we stop the script. --- examples/crazylegs.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/crazylegs.js b/examples/crazylegs.js index 0daf2275f3..c098758a38 100644 --- a/examples/crazylegs.js +++ b/examples/crazylegs.js @@ -21,3 +21,10 @@ Script.update.connect(function(deltaTime) { MyAvatar.setJointData("joint_L_knee", Quat.fromPitchYawRollDegrees(0.0, 0.0, AMPLITUDE * (1.0 - Math.sin(cumulativeTime * FREQUENCY)))); }); + +Script.scriptEnding.connect(function() { + MyAvatar.clearJointData("joint_R_hip"); + MyAvatar.clearJointData("joint_L_hip"); + MyAvatar.clearJointData("joint_R_knee"); + MyAvatar.clearJointData("joint_L_knee"); +}); From ab84526a1ba340c5b6e8a60c782b6a26fa2dad9c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Mar 2014 16:12:32 -0700 Subject: [PATCH 19/23] removing compile warnings --- interface/src/avatar/Hand.cpp | 4 ++-- interface/src/ui/BandwidthDialog.cpp | 6 +++--- interface/src/ui/LocalVoxelsOverlay.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 2 +- tests/physics/src/ShapeColliderTests.cpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 8f003d32d5..b4866c9478 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -206,8 +206,8 @@ void Hand::collideAgainstOurself() { } // ignoring everything below the parent of the parent of the last free joint int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( - skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : - (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); + skeletonModel.getLastFreeJointIndex(((int)i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : + ((int)i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); handCollisions.clear(); if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, handCollisions, skipIndex)) { diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index 15ca7c6423..8cefc9cf93 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -29,7 +29,7 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : this->QDialog::setLayout(form); // Setup labels - for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { + for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) { bool input = i % 2 == 0; BandwidthMeter::ChannelInfo& ch = _model->channelInfo(BandwidthMeter::ChannelIndex(i / 2)); QLabel* label = _labels[i] = new QLabel(); @@ -48,7 +48,7 @@ BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : } BandwidthDialog::~BandwidthDialog() { - for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { + for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) { delete _labels[i]; } } @@ -57,7 +57,7 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) { // Update labels char strBuf[64]; - for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) { + for (size_t i = 0; i < BandwidthMeter::N_STREAMS; ++i) { BandwidthMeter::ChannelIndex chIdx = BandwidthMeter::ChannelIndex(i / 2); bool input = i % 2 == 0; BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx); diff --git a/interface/src/ui/LocalVoxelsOverlay.cpp b/interface/src/ui/LocalVoxelsOverlay.cpp index 7eaf9ed5c5..9ad1428535 100644 --- a/interface/src/ui/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/LocalVoxelsOverlay.cpp @@ -41,7 +41,7 @@ void LocalVoxelsOverlay::update(float deltatime) { } _tree->lockForRead(); - if (_visible && _voxelCount != _tree->getOctreeElementsCount()) { + if (_visible && _voxelCount != (int)_tree->getOctreeElementsCount()) { _voxelCount = _tree->getOctreeElementsCount(); _voxelSystem->forceRedrawEntireTree(); } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index e42fe17df0..5cf906d82d 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -925,7 +925,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "(_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE):" << (_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE); } - if (missingItem <= std::max(0, (_incomingLastSequence - MAX_MISSING_SEQUENCE_OLD_AGE))) { + if (missingItem <= (unsigned int)std::max(0, (int)_incomingLastSequence - (int)MAX_MISSING_SEQUENCE_OLD_AGE)) { if (wantExtraDebugging) { qDebug() << "pruning really old missing sequence:" << missingItem; } diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 79de9f9175..6d7e9a6db1 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -174,7 +174,7 @@ void ShapeColliderTests::sphereMissesCapsule() { CapsuleShape capsuleB(radiusB, halfHeightB); // give the capsule some arbirary transform - float angle = 37.8; + float angle = 37.8f; glm::vec3 axis = glm::normalize( glm::vec3(-7.f, 2.8f, 9.3f) ); glm::quat rotation = glm::angleAxis(angle, axis); glm::vec3 translation(15.1f, -27.1f, -38.6f); From d02f0ba6870b7008fbd08d1648480a8afa5e59cd Mon Sep 17 00:00:00 2001 From: Geenz Date: Fri, 14 Mar 2014 19:38:17 -0400 Subject: [PATCH 20/23] =?UTF-8?q?Fix=20for=20the=20=E2=80=9Cringing?= =?UTF-8?q?=E2=80=9D=20issue.=20=20Don=E2=80=99t=20let=20Qt=20handle=20our?= =?UTF-8?q?=20buffer=20swaps.=20=20Handle=20the=20swaps=20ourselves.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interface/src/GLCanvas.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index b68c4fdacd..ea04002ddb 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,9 +13,9 @@ #include #include -GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), +GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer)), _throttleRendering(false), - _idleRenderInterval(100) + _idleRenderInterval(64) { } @@ -25,11 +25,15 @@ void GLCanvas::initializeGL() { setAcceptDrops(true); connect(Application::getInstance(), SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(activeChanged(Qt::ApplicationState))); connect(&_frameTimer, SIGNAL(timeout()), this, SLOT(throttleRender())); + + // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. + setAutoBufferSwap(false); } void GLCanvas::paintGL() { if (!_throttleRendering && !Application::getInstance()->getWindow()->isMinimized()) { Application::getInstance()->paintGL(); + swapBuffers(); } } @@ -86,6 +90,7 @@ void GLCanvas::throttleRender() { _frameTimer.start(_idleRenderInterval); if (!Application::getInstance()->getWindow()->isMinimized()) { Application::getInstance()->paintGL(); + swapBuffers(); } } From 3e1bf7fbb87868d6ec4bdd068ac439c94eac9b43 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 14 Mar 2014 17:09:09 -0700 Subject: [PATCH 21/23] Add variable name for throttled frame rate, change to multiple of 60FPS --- interface/src/GLCanvas.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index ea04002ddb..504a07d3ed 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,9 +13,11 @@ #include #include +const int MSECS_PER_FRAME_WHEN_THROTTLED = 66; + GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer)), _throttleRendering(false), - _idleRenderInterval(64) + _idleRenderInterval(MSECS_PER_FRAME_WHEN_THROTTLED) { } From 2a03cf1bab0da6a380cb1c27dd2aef8f689f9812 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 14 Mar 2014 17:17:38 -0700 Subject: [PATCH 22/23] make throttle rendering not adjust LOD --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 3 ++- interface/src/GLCanvas.h | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 37b2810c68..50dbf1b51a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1607,8 +1607,8 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) { } void Application::updateLOD() { - // adjust it unless we were asked to disable this feature - if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) { + // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) { Menu::getInstance()->autoAdjustLOD(_fps); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index a9fa04904f..cbfbf4166d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -147,6 +147,7 @@ public: glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVoxel); QGLWidget* getGLWidget() { return _glWidget; } + bool isThrottleRendering() const { return _glWidget->isThrottleRendering(); } MyAvatar* getAvatar() { return _myAvatar; } Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } @@ -339,7 +340,7 @@ private: void displayRearMirrorTools(); QMainWindow* _window; - QGLWidget* _glWidget; + GLCanvas* _glWidget; // our GLCanvas has a couple extra features bool _statsExpanded; BandwidthMeter _bandwidthMeter; diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index e6dcc38977..e6d96141b4 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -17,6 +17,7 @@ class GLCanvas : public QGLWidget { Q_OBJECT public: GLCanvas(); + bool isThrottleRendering() const { return _throttleRendering; } protected: QTimer _frameTimer; From a5eb5d6515a9fe88f0c2f02d324a2bdbb973c438 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 14 Mar 2014 17:22:35 -0700 Subject: [PATCH 23/23] handle minimize case --- interface/src/GLCanvas.cpp | 4 ++++ interface/src/GLCanvas.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index ea04002ddb..d6ef9d180c 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -19,6 +19,10 @@ GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer)), { } +bool GLCanvas::isThrottleRendering() const { + return _throttleRendering || Application::getInstance()->getWindow()->isMinimized(); +} + void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index e6d96141b4..ad396a48ce 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -17,7 +17,7 @@ class GLCanvas : public QGLWidget { Q_OBJECT public: GLCanvas(); - bool isThrottleRendering() const { return _throttleRendering; } + bool isThrottleRendering() const; protected: QTimer _frameTimer;