mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 01:10:12 +02:00
merge upstream/master into avatar-interaction
This commit is contained in:
commit
b65855a384
48 changed files with 898 additions and 458 deletions
4
BUILD.md
4
BUILD.md
|
@ -3,7 +3,7 @@ Dependencies
|
||||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.11
|
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.11
|
||||||
* [Qt](http://qt-project.org/downloads) ~> 5.2.0
|
* [Qt](http://qt-project.org/downloads) ~> 5.2.0
|
||||||
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
* [zLib](http://www.zlib.net/) ~> 1.2.8
|
||||||
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.0
|
* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.2
|
||||||
* [qxmpp](https://code.google.com/p/qxmpp/) ~> 0.7.6
|
* [qxmpp](https://code.google.com/p/qxmpp/) ~> 0.7.6
|
||||||
|
|
||||||
#####Linux only
|
#####Linux only
|
||||||
|
@ -142,4 +142,4 @@ If you need to debug Interface, you can run interface from within Visual Studio
|
||||||
####Debugging Interface
|
####Debugging Interface
|
||||||
* In the Solution Explorer, right click interface and click Set as StartUp Project
|
* In the Solution Explorer, right click interface and click Set as StartUp Project
|
||||||
* Set the "Working Directory" for the Interface debugging sessions to the Debug output directory so that your application can load resources. Do this: right click interface and click Properties, choose Debugging from Configuration Properties, set Working Directory to .\Debug
|
* Set the "Working Directory" for the Interface debugging sessions to the Debug output directory so that your application can load resources. Do this: right click interface and click Properties, choose Debugging from Configuration Properties, set Working Directory to .\Debug
|
||||||
* Now you can run and debug interface through Visual Studio
|
* Now you can run and debug interface through Visual Studio
|
||||||
|
|
|
@ -23,7 +23,7 @@ Running Interface
|
||||||
When you launch interface, you will automatically connect to our default domain: "root.highfidelity.io".
|
When you launch interface, you will automatically connect to our default domain: "root.highfidelity.io".
|
||||||
|
|
||||||
If you don't see anything, make sure your preferences are pointing to
|
If you don't see anything, make sure your preferences are pointing to
|
||||||
root.highfidelity.io, if you still have no luck it's possible our servers are
|
root.highfidelity.io (set your domain via Cmnd+D/Cntrl+D), if you still have no luck it's possible our servers are
|
||||||
simply down; if you're experiencing a major bug, let us know by adding an issue to this repository.
|
simply down; if you're experiencing a major bug, let us know by adding an issue to this repository.
|
||||||
Make sure to include details about your computer and how to reproduce the bug.
|
Make sure to include details about your computer and how to reproduce the bug.
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,11 @@ void Agent::run() {
|
||||||
ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);
|
ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer);
|
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet()
|
||||||
|
<< NodeType::AudioMixer
|
||||||
|
<< NodeType::AvatarMixer
|
||||||
|
<< NodeType::VoxelServer
|
||||||
|
<< NodeType::ParticleServer);
|
||||||
|
|
||||||
// figure out the URL for the script for this agent assignment
|
// figure out the URL for the script for this agent assignment
|
||||||
QString scriptURLString("http://%1:8080/assignment/%2");
|
QString scriptURLString("http://%1:8080/assignment/%2");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "AssignmentFactory.h"
|
#include "AssignmentFactory.h"
|
||||||
|
#include "AssignmentThread.h"
|
||||||
|
|
||||||
#include "AssignmentClient.h"
|
#include "AssignmentClient.h"
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||||
|
|
||||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||||
QCoreApplication(argc, argv),
|
QCoreApplication(argc, argv),
|
||||||
_currentAssignment(NULL)
|
_currentAssignment()
|
||||||
{
|
{
|
||||||
setOrganizationName("High Fidelity");
|
setOrganizationName("High Fidelity");
|
||||||
setOrganizationDomain("highfidelity.io");
|
setOrganizationDomain("highfidelity.io");
|
||||||
|
@ -124,7 +125,7 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||||
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
||||||
// construct the deployed assignment from the packet data
|
// construct the deployed assignment from the packet data
|
||||||
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
|
_currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket));
|
||||||
|
|
||||||
if (_currentAssignment) {
|
if (_currentAssignment) {
|
||||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||||
|
@ -137,14 +138,13 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
|
qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
|
||||||
|
|
||||||
// start the deployed assignment
|
// start the deployed assignment
|
||||||
QThread* workerThread = new QThread(this);
|
AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this);
|
||||||
|
|
||||||
connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run()));
|
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
||||||
|
connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit);
|
||||||
connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted()));
|
connect(_currentAssignment.data(), &ThreadedAssignment::finished,
|
||||||
connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit()));
|
this, &AssignmentClient::assignmentCompleted);
|
||||||
connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater()));
|
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||||
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
|
||||||
|
|
||||||
_currentAssignment->moveToThread(workerThread);
|
_currentAssignment->moveToThread(workerThread);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
|
|
||||||
// let the assignment handle the incoming datagrams for its duration
|
// let the assignment handle the incoming datagrams for its duration
|
||||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment,
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(),
|
||||||
&ThreadedAssignment::readPendingDatagrams);
|
&ThreadedAssignment::readPendingDatagrams);
|
||||||
|
|
||||||
// Starts an event loop, and emits workerThread->started()
|
// Starts an event loop, and emits workerThread->started()
|
||||||
|
@ -202,10 +202,12 @@ void AssignmentClient::assignmentCompleted() {
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
// have us handle incoming NodeList datagrams again
|
// have us handle incoming NodeList datagrams again
|
||||||
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0);
|
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0);
|
||||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||||
|
|
||||||
_currentAssignment = NULL;
|
// clear our current assignment shared pointer now that we're done with it
|
||||||
|
// if the assignment thread is still around it has its own shared pointer to the assignment
|
||||||
|
_currentAssignment.clear();
|
||||||
|
|
||||||
// reset our NodeList by switching back to unassigned and clearing the list
|
// reset our NodeList by switching back to unassigned and clearing the list
|
||||||
nodeList->setOwnerType(NodeType::Unassigned);
|
nodeList->setOwnerType(NodeType::Unassigned);
|
||||||
|
|
|
@ -24,7 +24,7 @@ private slots:
|
||||||
void handleAuthenticationRequest();
|
void handleAuthenticationRequest();
|
||||||
private:
|
private:
|
||||||
Assignment _requestAssignment;
|
Assignment _requestAssignment;
|
||||||
ThreadedAssignment* _currentAssignment;
|
SharedAssignmentPointer _currentAssignment;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__AssignmentClient__) */
|
#endif /* defined(__hifi__AssignmentClient__) */
|
||||||
|
|
16
assignment-client/src/AssignmentThread.cpp
Normal file
16
assignment-client/src/AssignmentThread.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
//
|
||||||
|
// AssignmentThread.cpp
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2014-03-28.
|
||||||
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssignmentThread.h"
|
||||||
|
|
||||||
|
AssignmentThread::AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent) :
|
||||||
|
QThread(parent),
|
||||||
|
_assignment(assignment)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
23
assignment-client/src/AssignmentThread.h
Normal file
23
assignment-client/src/AssignmentThread.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// AssignmentThread.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2014-03-28.
|
||||||
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__AssignmentThread__
|
||||||
|
#define __hifi__AssignmentThread__
|
||||||
|
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <ThreadedAssignment.h>
|
||||||
|
|
||||||
|
class AssignmentThread : public QThread {
|
||||||
|
public:
|
||||||
|
AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent);
|
||||||
|
private:
|
||||||
|
SharedAssignmentPointer _assignment;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__AssignmentThread__) */
|
|
@ -21,8 +21,9 @@ quint64 endSceneSleepTime = 0;
|
||||||
|
|
||||||
OctreeSendThread::OctreeSendThread(OctreeServer* myServer, SharedNodePointer node) :
|
OctreeSendThread::OctreeSendThread(OctreeServer* myServer, SharedNodePointer node) :
|
||||||
_myServer(myServer),
|
_myServer(myServer),
|
||||||
_node(node),
|
_nodeUUID(node->getUUID()),
|
||||||
_packetData(),
|
_packetData(),
|
||||||
|
_nodeMissingCount(0),
|
||||||
_processLock(),
|
_processLock(),
|
||||||
_isShuttingDown(false)
|
_isShuttingDown(false)
|
||||||
{
|
{
|
||||||
|
@ -43,46 +44,68 @@ OctreeSendThread::~OctreeSendThread() {
|
||||||
}
|
}
|
||||||
qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client disconnected "
|
qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client disconnected "
|
||||||
"- ending sending thread [" << this << "]";
|
"- ending sending thread [" << this << "]";
|
||||||
_node.clear();
|
|
||||||
OctreeServer::clientDisconnected();
|
OctreeServer::clientDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeSendThread::setIsShuttingDown() {
|
void OctreeSendThread::setIsShuttingDown() {
|
||||||
QMutexLocker locker(&_processLock); // this will cause us to wait till the process loop is complete
|
|
||||||
_isShuttingDown = true;
|
_isShuttingDown = true;
|
||||||
OctreeServer::stopTrackingThread(this);
|
OctreeServer::stopTrackingThread(this);
|
||||||
|
|
||||||
|
// this will cause us to wait till the process loop is complete, we do this after we change _isShuttingDown
|
||||||
|
QMutexLocker locker(&_processLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OctreeSendThread::process() {
|
bool OctreeSendThread::process() {
|
||||||
|
if (_isShuttingDown) {
|
||||||
|
return false; // exit early if we're shutting down
|
||||||
|
}
|
||||||
|
|
||||||
OctreeServer::didProcess(this);
|
OctreeServer::didProcess(this);
|
||||||
|
|
||||||
float lockWaitElapsedUsec = OctreeServer::SKIP_TIME;
|
float lockWaitElapsedUsec = OctreeServer::SKIP_TIME;
|
||||||
quint64 lockWaitStart = usecTimestampNow();
|
quint64 lockWaitStart = usecTimestampNow();
|
||||||
QMutexLocker locker(&_processLock);
|
_processLock.lock();
|
||||||
quint64 lockWaitEnd = usecTimestampNow();
|
quint64 lockWaitEnd = usecTimestampNow();
|
||||||
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
|
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
|
||||||
OctreeServer::trackProcessWaitTime(lockWaitElapsedUsec);
|
OctreeServer::trackProcessWaitTime(lockWaitElapsedUsec);
|
||||||
|
|
||||||
if (_isShuttingDown) {
|
|
||||||
return false; // exit early if we're shutting down
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 start = usecTimestampNow();
|
quint64 start = usecTimestampNow();
|
||||||
|
|
||||||
// don't do any send processing until the initial load of the octree is complete...
|
// don't do any send processing until the initial load of the octree is complete...
|
||||||
if (_myServer->isInitialLoadComplete()) {
|
if (_myServer->isInitialLoadComplete()) {
|
||||||
if (!_node.isNull()) {
|
SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID, false);
|
||||||
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(_node->getLinkedData());
|
if (node) {
|
||||||
|
_nodeMissingCount = 0;
|
||||||
|
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
|
||||||
|
|
||||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||||
if (nodeData && !nodeData->isShuttingDown()) {
|
if (nodeData && !nodeData->isShuttingDown()) {
|
||||||
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
||||||
packetDistributor(_node, nodeData, viewFrustumChanged);
|
packetDistributor(node, nodeData, viewFrustumChanged);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_nodeMissingCount++;
|
||||||
|
const int MANY_FAILED_LOCKS = 1;
|
||||||
|
if (_nodeMissingCount >= MANY_FAILED_LOCKS) {
|
||||||
|
|
||||||
|
QString safeServerName("Octree");
|
||||||
|
if (_myServer) {
|
||||||
|
safeServerName = _myServer->getMyServerName();
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << qPrintable(safeServerName) << "server: sending thread [" << this << "]"
|
||||||
|
<< "failed to get nodeWithUUID() " << _nodeUUID <<". Failed:" << _nodeMissingCount << "times";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_processLock.unlock();
|
||||||
|
|
||||||
|
if (_isShuttingDown) {
|
||||||
|
return false; // exit early if we're shutting down
|
||||||
|
}
|
||||||
|
|
||||||
// Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap
|
// Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap
|
||||||
if (isStillRunning()) {
|
if (isStillRunning()) {
|
||||||
// dynamically sleep until we need to fire off the next set of octree elements
|
// dynamically sleep until we need to fire off the next set of octree elements
|
||||||
|
|
|
@ -38,14 +38,15 @@ protected:
|
||||||
virtual bool process();
|
virtual bool process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedNodePointer _node;
|
|
||||||
OctreeServer* _myServer;
|
OctreeServer* _myServer;
|
||||||
|
QUuid _nodeUUID;
|
||||||
|
|
||||||
int handlePacketSend(const SharedNodePointer& node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
|
int handlePacketSend(const SharedNodePointer& node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
|
||||||
int packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged);
|
int packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged);
|
||||||
|
|
||||||
OctreePacketData _packetData;
|
OctreePacketData _packetData;
|
||||||
|
|
||||||
|
int _nodeMissingCount;
|
||||||
QMutex _processLock; // don't allow us to have our nodeData, or our thread to be deleted while we're processing
|
QMutex _processLock; // don't allow us to have our nodeData, or our thread to be deleted while we're processing
|
||||||
bool _isShuttingDown;
|
bool _isShuttingDown;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1160,7 +1160,6 @@ QString OctreeServer::getStatusLink() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeServer::sendStatsPacket() {
|
void OctreeServer::sendStatsPacket() {
|
||||||
|
|
||||||
// TODO: we have too many stats to fit in a single MTU... so for now, we break it into multiple JSON objects and
|
// TODO: we have too many stats to fit in a single MTU... so for now, we break it into multiple JSON objects and
|
||||||
// send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the
|
// send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the
|
||||||
// the following features:
|
// the following features:
|
||||||
|
@ -1241,59 +1240,78 @@ QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidPacketDistributor;
|
||||||
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidHandlePacketSend;
|
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidHandlePacketSend;
|
||||||
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidCallWriteDatagram;
|
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidCallWriteDatagram;
|
||||||
|
|
||||||
|
QMutex OctreeServer::_threadsDidProcessMutex;
|
||||||
|
QMutex OctreeServer::_threadsDidPacketDistributorMutex;
|
||||||
|
QMutex OctreeServer::_threadsDidHandlePacketSendMutex;
|
||||||
|
QMutex OctreeServer::_threadsDidCallWriteDatagramMutex;
|
||||||
|
|
||||||
|
|
||||||
void OctreeServer::didProcess(OctreeSendThread* thread) {
|
void OctreeServer::didProcess(OctreeSendThread* thread) {
|
||||||
|
QMutexLocker locker(&_threadsDidProcessMutex);
|
||||||
_threadsDidProcess[thread] = usecTimestampNow();
|
_threadsDidProcess[thread] = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeServer::didPacketDistributor(OctreeSendThread* thread) {
|
void OctreeServer::didPacketDistributor(OctreeSendThread* thread) {
|
||||||
|
QMutexLocker locker(&_threadsDidPacketDistributorMutex);
|
||||||
_threadsDidPacketDistributor[thread] = usecTimestampNow();
|
_threadsDidPacketDistributor[thread] = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeServer::didHandlePacketSend(OctreeSendThread* thread) {
|
void OctreeServer::didHandlePacketSend(OctreeSendThread* thread) {
|
||||||
|
QMutexLocker locker(&_threadsDidHandlePacketSendMutex);
|
||||||
_threadsDidHandlePacketSend[thread] = usecTimestampNow();
|
_threadsDidHandlePacketSend[thread] = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeServer::didCallWriteDatagram(OctreeSendThread* thread) {
|
void OctreeServer::didCallWriteDatagram(OctreeSendThread* thread) {
|
||||||
|
QMutexLocker locker(&_threadsDidCallWriteDatagramMutex);
|
||||||
_threadsDidCallWriteDatagram[thread] = usecTimestampNow();
|
_threadsDidCallWriteDatagram[thread] = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OctreeServer::stopTrackingThread(OctreeSendThread* thread) {
|
void OctreeServer::stopTrackingThread(OctreeSendThread* thread) {
|
||||||
|
QMutexLocker lockerA(&_threadsDidProcessMutex);
|
||||||
|
QMutexLocker lockerB(&_threadsDidPacketDistributorMutex);
|
||||||
|
QMutexLocker lockerC(&_threadsDidHandlePacketSendMutex);
|
||||||
|
QMutexLocker lockerD(&_threadsDidCallWriteDatagramMutex);
|
||||||
|
|
||||||
_threadsDidProcess.remove(thread);
|
_threadsDidProcess.remove(thread);
|
||||||
_threadsDidPacketDistributor.remove(thread);
|
_threadsDidPacketDistributor.remove(thread);
|
||||||
_threadsDidHandlePacketSend.remove(thread);
|
_threadsDidHandlePacketSend.remove(thread);
|
||||||
|
_threadsDidCallWriteDatagram.remove(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
int howManyThreadsDidSomething(QMap<OctreeSendThread*, quint64>& something, quint64 since) {
|
int howManyThreadsDidSomething(QMutex& mutex, QMap<OctreeSendThread*, quint64>& something, quint64 since) {
|
||||||
if (since == 0) {
|
|
||||||
return something.size();
|
|
||||||
}
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
QMap<OctreeSendThread*, quint64>::const_iterator i = something.constBegin();
|
if (mutex.tryLock()) {
|
||||||
while (i != something.constEnd()) {
|
if (since == 0) {
|
||||||
if (i.value() > since) {
|
count = something.size();
|
||||||
count++;
|
} else {
|
||||||
|
QMap<OctreeSendThread*, quint64>::const_iterator i = something.constBegin();
|
||||||
|
while (i != something.constEnd()) {
|
||||||
|
if (i.value() > since) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++i;
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int OctreeServer::howManyThreadsDidProcess(quint64 since) {
|
int OctreeServer::howManyThreadsDidProcess(quint64 since) {
|
||||||
return howManyThreadsDidSomething(_threadsDidProcess, since);
|
return howManyThreadsDidSomething(_threadsDidProcessMutex, _threadsDidProcess, since);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OctreeServer::howManyThreadsDidPacketDistributor(quint64 since) {
|
int OctreeServer::howManyThreadsDidPacketDistributor(quint64 since) {
|
||||||
return howManyThreadsDidSomething(_threadsDidPacketDistributor, since);
|
return howManyThreadsDidSomething(_threadsDidPacketDistributorMutex, _threadsDidPacketDistributor, since);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OctreeServer::howManyThreadsDidHandlePacketSend(quint64 since) {
|
int OctreeServer::howManyThreadsDidHandlePacketSend(quint64 since) {
|
||||||
return howManyThreadsDidSomething(_threadsDidHandlePacketSend, since);
|
return howManyThreadsDidSomething(_threadsDidHandlePacketSendMutex, _threadsDidHandlePacketSend, since);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OctreeServer::howManyThreadsDidCallWriteDatagram(quint64 since) {
|
int OctreeServer::howManyThreadsDidCallWriteDatagram(quint64 since) {
|
||||||
return howManyThreadsDidSomething(_threadsDidCallWriteDatagram, since);
|
return howManyThreadsDidSomething(_threadsDidCallWriteDatagramMutex, _threadsDidCallWriteDatagram, since);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,10 @@ protected:
|
||||||
static QMap<OctreeSendThread*, quint64> _threadsDidHandlePacketSend;
|
static QMap<OctreeSendThread*, quint64> _threadsDidHandlePacketSend;
|
||||||
static QMap<OctreeSendThread*, quint64> _threadsDidCallWriteDatagram;
|
static QMap<OctreeSendThread*, quint64> _threadsDidCallWriteDatagram;
|
||||||
|
|
||||||
|
static QMutex _threadsDidProcessMutex;
|
||||||
|
static QMutex _threadsDidPacketDistributorMutex;
|
||||||
|
static QMutex _threadsDidHandlePacketSendMutex;
|
||||||
|
static QMutex _threadsDidCallWriteDatagramMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __octree_server__OctreeServer__
|
#endif // __octree_server__OctreeServer__
|
||||||
|
|
|
@ -23,10 +23,10 @@ function printVector(string, vector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var CHANCE_OF_MOVING = 0.005;
|
var CHANCE_OF_MOVING = 0.005;
|
||||||
var CHANCE_OF_SOUND = 0.005;
|
var CHANCE_OF_SOUND = 0.000;
|
||||||
var CHANCE_OF_HEAD_TURNING = 0.05;
|
var CHANCE_OF_HEAD_TURNING = 0.05;
|
||||||
var CHANCE_OF_BIG_MOVE = 0.1;
|
var CHANCE_OF_BIG_MOVE = 0.1;
|
||||||
var CHANCE_OF_WAVING = 0.005; // Currently this isn't working
|
var CHANCE_OF_WAVING = 0.009;
|
||||||
|
|
||||||
var shouldReceiveVoxels = true;
|
var shouldReceiveVoxels = true;
|
||||||
var VOXEL_FPS = 60.0;
|
var VOXEL_FPS = 60.0;
|
||||||
|
@ -39,12 +39,16 @@ var isWaving = false;
|
||||||
var waveFrequency = 0.0;
|
var waveFrequency = 0.0;
|
||||||
var waveAmplitude = 0.0;
|
var waveAmplitude = 0.0;
|
||||||
|
|
||||||
var X_MIN = 0.0;
|
var X_MIN = 20.0;
|
||||||
var X_MAX = 5.0;
|
var X_MAX = 25.0;
|
||||||
var Z_MIN = 0.0;
|
var Z_MIN = 20.0;
|
||||||
var Z_MAX = 5.0;
|
var Z_MAX = 25.0;
|
||||||
var Y_PELVIS = 2.5;
|
var Y_PELVIS = 2.5;
|
||||||
var SHOULDER_JOINT_NUMBER = 15;
|
var SPINE_JOINT_NUMBER = 13;
|
||||||
|
var SHOULDER_JOINT_NUMBER = 17;
|
||||||
|
var ELBOW_JOINT_NUMBER = 18;
|
||||||
|
var JOINT_R_HIP = 1;
|
||||||
|
var JOINT_R_KNEE = 2;
|
||||||
|
|
||||||
var MOVE_RANGE_SMALL = 0.5;
|
var MOVE_RANGE_SMALL = 0.5;
|
||||||
var MOVE_RANGE_BIG = Math.max(X_MAX - X_MIN, Z_MAX - Z_MIN) / 2.0;
|
var MOVE_RANGE_BIG = Math.max(X_MAX - X_MIN, Z_MAX - Z_MIN) / 2.0;
|
||||||
|
@ -61,6 +65,9 @@ var targetDirection = { x: 0, y: 0, z: 0, w: 0 };
|
||||||
var currentDirection = { x: 0, y: 0, z: 0, w: 0 };
|
var currentDirection = { x: 0, y: 0, z: 0, w: 0 };
|
||||||
var targetHeadPitch = 0.0;
|
var targetHeadPitch = 0.0;
|
||||||
|
|
||||||
|
var walkFrequency = 5.0;
|
||||||
|
var walkAmplitude = 45.0;
|
||||||
|
|
||||||
var cumulativeTime = 0.0;
|
var cumulativeTime = 0.0;
|
||||||
|
|
||||||
var sounds = [];
|
var sounds = [];
|
||||||
|
@ -115,12 +122,30 @@ printVector("New bot, position = ", Avatar.position);
|
||||||
function stopWaving() {
|
function stopWaving() {
|
||||||
isWaving = false;
|
isWaving = false;
|
||||||
Avatar.clearJointData(SHOULDER_JOINT_NUMBER);
|
Avatar.clearJointData(SHOULDER_JOINT_NUMBER);
|
||||||
|
Avatar.clearJointData(ELBOW_JOINT_NUMBER);
|
||||||
|
Avatar.clearJointData(SPINE_JOINT_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function keepWalking() {
|
||||||
|
Avatar.setJointData(JOINT_R_HIP, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0));
|
||||||
|
Avatar.setJointData(JOINT_R_KNEE, Quat.fromPitchYawRollDegrees(walkAmplitude * Math.sin(cumulativeTime * walkFrequency), 0.0, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopWalking() {
|
||||||
|
Avatar.clearJointData(JOINT_R_HIP);
|
||||||
|
Avatar.clearJointData(JOINT_R_KNEE);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBehavior(deltaTime) {
|
function updateBehavior(deltaTime) {
|
||||||
|
|
||||||
cumulativeTime += deltaTime;
|
cumulativeTime += deltaTime;
|
||||||
|
|
||||||
|
// Hack - right now you need to set the avatar position a bit after the avatar is made to make sure it's there.
|
||||||
|
|
||||||
|
if (CHANCE_OF_MOVING == 0.000) {
|
||||||
|
Avatar.position = firstPosition;
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldReceiveVoxels && ((cumulativeTime - lastVoxelQueryTime) > (1.0 / VOXEL_FPS))) {
|
if (shouldReceiveVoxels && ((cumulativeTime - lastVoxelQueryTime) > (1.0 / VOXEL_FPS))) {
|
||||||
VoxelViewer.setPosition(Avatar.position);
|
VoxelViewer.setPosition(Avatar.position);
|
||||||
VoxelViewer.setOrientation(Avatar.orientation);
|
VoxelViewer.setOrientation(Avatar.orientation);
|
||||||
|
@ -134,13 +159,18 @@ function updateBehavior(deltaTime) {
|
||||||
|
|
||||||
if (!isWaving && (Math.random() < CHANCE_OF_WAVING)) {
|
if (!isWaving && (Math.random() < CHANCE_OF_WAVING)) {
|
||||||
isWaving = true;
|
isWaving = true;
|
||||||
waveFrequency = 1.0 + Math.random() * 5.0;
|
waveFrequency = 3.0 + Math.random() * 5.0;
|
||||||
waveAmplitude = 5.0 + Math.random() * 60.0;
|
waveAmplitude = 5.0 + Math.random() * 60.0;
|
||||||
Script.setTimeout(stopWaving, 1000 + Math.random() * 2000);
|
Script.setTimeout(stopWaving, 1000 + Math.random() * 2000);
|
||||||
|
Avatar.setJointData(ELBOW_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 45, 0.0)); // Initially turn the palm outward
|
||||||
} else if (isWaving) {
|
} else if (isWaving) {
|
||||||
Avatar.setJointData(SHOULDER_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, waveAmplitude * Math.sin(cumulativeTime * waveFrequency)));
|
Avatar.setJointData(SHOULDER_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 60 + waveAmplitude * Math.sin((cumulativeTime - 0.25) * waveFrequency)));
|
||||||
|
Avatar.setJointData(ELBOW_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 25 + waveAmplitude/2.0 * Math.sin(cumulativeTime * 1.2 * waveFrequency)));
|
||||||
|
Avatar.setJointData(SPINE_JOINT_NUMBER, Quat.fromPitchYawRollDegrees(0.0, 0.0, 60 + waveAmplitude/4.0 * Math.sin(cumulativeTime * waveFrequency)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Math.random() < CHANCE_OF_SOUND) {
|
if (Math.random() < CHANCE_OF_SOUND) {
|
||||||
playRandomSound();
|
playRandomSound();
|
||||||
}
|
}
|
||||||
|
@ -168,11 +198,13 @@ function updateBehavior(deltaTime) {
|
||||||
targetPosition.y = Y_PELVIS;
|
targetPosition.y = Y_PELVIS;
|
||||||
|
|
||||||
isMoving = true;
|
isMoving = true;
|
||||||
} else {
|
} else if (isMoving) {
|
||||||
|
keepWalking();
|
||||||
Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE));
|
Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE));
|
||||||
Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE);
|
Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE);
|
||||||
if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) {
|
if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) {
|
||||||
isMoving = false;
|
isMoving = false;
|
||||||
|
stopWalking();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1326,7 +1326,7 @@ function wheelEvent(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.wheelEvent.connect(wheelEvent);
|
// Controller.wheelEvent.connect(wheelEvent);
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
|
|
@ -27,6 +27,9 @@ var BULLET_VELOCITY = 5.0;
|
||||||
var MIN_THROWER_DELAY = 1000;
|
var MIN_THROWER_DELAY = 1000;
|
||||||
var MAX_THROWER_DELAY = 1000;
|
var MAX_THROWER_DELAY = 1000;
|
||||||
var LEFT_BUTTON_3 = 3;
|
var LEFT_BUTTON_3 = 3;
|
||||||
|
var RELOAD_INTERVAL = 9;
|
||||||
|
|
||||||
|
var showScore = false;
|
||||||
|
|
||||||
// Load some sound to use for loading and firing
|
// 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 fireSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw");
|
||||||
|
@ -38,6 +41,8 @@ var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazo
|
||||||
var audioOptions = new AudioInjectionOptions();
|
var audioOptions = new AudioInjectionOptions();
|
||||||
audioOptions.volume = 0.9;
|
audioOptions.volume = 0.9;
|
||||||
|
|
||||||
|
var shotsFired = 0;
|
||||||
|
|
||||||
var shotTime = new Date();
|
var shotTime = new Date();
|
||||||
|
|
||||||
// initialize our triggers
|
// initialize our triggers
|
||||||
|
@ -63,7 +68,8 @@ var reticle = Overlays.addOverlay("image", {
|
||||||
alpha: 1
|
alpha: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
var text = Overlays.addOverlay("text", {
|
if (showScore) {
|
||||||
|
var text = Overlays.addOverlay("text", {
|
||||||
x: screenSize.x / 2 - 100,
|
x: screenSize.x / 2 - 100,
|
||||||
y: screenSize.y / 2 - 50,
|
y: screenSize.y / 2 - 50,
|
||||||
width: 150,
|
width: 150,
|
||||||
|
@ -74,6 +80,8 @@ var text = Overlays.addOverlay("text", {
|
||||||
leftMargin: 4,
|
leftMargin: 4,
|
||||||
text: "Score: " + score
|
text: "Score: " + score
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function printVector(string, vector) {
|
function printVector(string, vector) {
|
||||||
|
@ -94,6 +102,10 @@ function shootBullet(position, velocity) {
|
||||||
// Play firing sounds
|
// Play firing sounds
|
||||||
audioOptions.position = position;
|
audioOptions.position = position;
|
||||||
Audio.playSound(fireSound, audioOptions);
|
Audio.playSound(fireSound, audioOptions);
|
||||||
|
shotsFired++;
|
||||||
|
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||||
|
Audio.playSound(loadSound, audioOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shootTarget() {
|
function shootTarget() {
|
||||||
|
@ -147,12 +159,15 @@ function particleCollisionWithVoxel(particle, voxel, penetration) {
|
||||||
Voxels.eraseVoxel(position.x, position.y, position.z, HOLE_SIZE);
|
Voxels.eraseVoxel(position.x, position.y, position.z, HOLE_SIZE);
|
||||||
//audioOptions.position = position;
|
//audioOptions.position = position;
|
||||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
Audio.playSound(targetHitSound, audioOptions);
|
Audio.playSound(impactSound, audioOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function particleCollisionWithParticle(particle1, particle2) {
|
function particleCollisionWithParticle(particle1, particle2) {
|
||||||
score++;
|
score++;
|
||||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
if (showScore) {
|
||||||
|
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||||
|
}
|
||||||
|
|
||||||
// Sort out which particle is which
|
// Sort out which particle is which
|
||||||
|
|
||||||
// Record shot time
|
// Record shot time
|
||||||
|
@ -171,12 +186,12 @@ function keyPressEvent(event) {
|
||||||
if (event.text == "t") {
|
if (event.text == "t") {
|
||||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||||
Script.setTimeout(shootTarget, time);
|
Script.setTimeout(shootTarget, time);
|
||||||
|
} if (event.text == ".") {
|
||||||
|
shootFromMouse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
|
|
||||||
|
|
||||||
// Check for mouseLook movement, update rotation
|
// Check for mouseLook movement, update rotation
|
||||||
// rotate body yaw for yaw received from mouse
|
// rotate body yaw for yaw received from mouse
|
||||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
||||||
|
@ -257,18 +272,21 @@ function mousePressEvent(event) {
|
||||||
isMouseDown = true;
|
isMouseDown = true;
|
||||||
lastX = event.x;
|
lastX = event.x;
|
||||||
lastY = event.y;
|
lastY = event.y;
|
||||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
Audio.playSound(loadSound, audioOptions);
|
//Audio.playSound(loadSound, audioOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mouseReleaseEvent(event) {
|
function shootFromMouse() {
|
||||||
// position
|
|
||||||
var DISTANCE_FROM_CAMERA = 2.0;
|
var DISTANCE_FROM_CAMERA = 2.0;
|
||||||
var camera = Camera.getPosition();
|
var camera = Camera.getPosition();
|
||||||
var forwardVector = Quat.getFront(Camera.getOrientation());
|
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||||
var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
|
var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
|
||||||
shootBullet(newPosition, velocity);
|
shootBullet(newPosition, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseReleaseEvent(event) {
|
||||||
|
// position
|
||||||
isMouseDown = false;
|
isMouseDown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,11 +162,11 @@ function flyWithHydra(deltaTime) {
|
||||||
if (thrustMultiplier < MAX_THRUST_MULTIPLIER) {
|
if (thrustMultiplier < MAX_THRUST_MULTIPLIER) {
|
||||||
thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE);
|
thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE);
|
||||||
}
|
}
|
||||||
var currentOrientation = MyAvatar.orientation;
|
var headOrientation = MyAvatar.headOrientation;
|
||||||
|
|
||||||
var front = Quat.getFront(currentOrientation);
|
var front = Quat.getFront(headOrientation);
|
||||||
var right = Quat.getRight(currentOrientation);
|
var right = Quat.getRight(headOrientation);
|
||||||
var up = Quat.getUp(currentOrientation);
|
var up = Quat.getUp(headOrientation);
|
||||||
|
|
||||||
var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS *
|
var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS *
|
||||||
thrustJoystickPosition.y * thrustMultiplier * deltaTime);
|
thrustJoystickPosition.y * thrustMultiplier * deltaTime);
|
||||||
|
|
|
@ -4,22 +4,22 @@
|
||||||
<context>
|
<context>
|
||||||
<name>Application</name>
|
<name>Application</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Application.cpp" line="1380"/>
|
<location filename="src/Application.cpp" line="1382"/>
|
||||||
<source>Export Voxels</source>
|
<source>Export Voxels</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Application.cpp" line="1381"/>
|
<location filename="src/Application.cpp" line="1383"/>
|
||||||
<source>Sparse Voxel Octree Files (*.svo)</source>
|
<source>Sparse Voxel Octree Files (*.svo)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Application.cpp" line="3608"/>
|
<location filename="src/Application.cpp" line="3711"/>
|
||||||
<source>Open Script</source>
|
<source>Open Script</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Application.cpp" line="3609"/>
|
<location filename="src/Application.cpp" line="3712"/>
|
||||||
<source>JavaScript Files (*.js)</source>
|
<source>JavaScript Files (*.js)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -27,56 +27,49 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ChatWindow</name>
|
<name>ChatWindow</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="ui/chatWindow.ui" line="20"/>
|
<location filename="ui/chatWindow.ui" line="29"/>
|
||||||
<location filename="../build/interface/ui_chatWindow.h" line="143"/>
|
<location filename="../build/interface/ui_chatWindow.h" line="153"/>
|
||||||
<source>Chat</source>
|
<source>Chat</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="ui/chatWindow.ui" line="50"/>
|
<location filename="ui/chatWindow.ui" line="57"/>
|
||||||
<location filename="../build/interface/ui_chatWindow.h" line="144"/>
|
<location filename="../build/interface/ui_chatWindow.h" line="154"/>
|
||||||
<source>Connecting to XMPP...</source>
|
<source>Connecting to XMPP...</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="ui/chatWindow.ui" line="71"/>
|
<location filename="ui/chatWindow.ui" line="78"/>
|
||||||
<location filename="../build/interface/ui_chatWindow.h" line="145"/>
|
<location filename="../build/interface/ui_chatWindow.h" line="155"/>
|
||||||
<source> online now:</source>
|
<source> online now:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
<location filename="src/ui/ChatWindow.cpp" line="135"/>
|
||||||
<source>day</source>
|
<source>day</source>
|
||||||
<translation>
|
<translation type="unfinished">
|
||||||
<numerusform>%n day</numerusform>
|
<numerusform></numerusform>
|
||||||
<numerusform>%n days</numerusform>
|
<numerusform></numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
<location filename="src/ui/ChatWindow.cpp" line="135"/>
|
||||||
<source>hour</source>
|
<source>hour</source>
|
||||||
<translation>
|
<translation type="unfinished">
|
||||||
<numerusform>%n hour</numerusform>
|
<numerusform></numerusform>
|
||||||
<numerusform>%n hours</numerusform>
|
<numerusform></numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
<location filename="src/ui/ChatWindow.cpp" line="135"/>
|
||||||
<source>minute</source>
|
<source>minute</source>
|
||||||
<translation>
|
<translation type="unfinished">
|
||||||
<numerusform>%n minute</numerusform>
|
<numerusform></numerusform>
|
||||||
<numerusform>%n minutes</numerusform>
|
<numerusform></numerusform>
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message numerus="yes">
|
|
||||||
<source>second</source>
|
|
||||||
<translation type="vanished">
|
|
||||||
<numerusform>%n second</numerusform>
|
|
||||||
<numerusform>%n seconds</numerusform>
|
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/ui/ChatWindow.cpp" line="183"/>
|
<location filename="src/ui/ChatWindow.cpp" line="191"/>
|
||||||
<source>%1 online now:</source>
|
<source>%1 online now:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -113,18 +106,18 @@
|
||||||
<context>
|
<context>
|
||||||
<name>Menu</name>
|
<name>Menu</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Menu.cpp" line="460"/>
|
<location filename="src/Menu.cpp" line="464"/>
|
||||||
<source>Open .ini config file</source>
|
<source>Open .ini config file</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Menu.cpp" line="462"/>
|
<location filename="src/Menu.cpp" line="466"/>
|
||||||
<location filename="src/Menu.cpp" line="474"/>
|
<location filename="src/Menu.cpp" line="478"/>
|
||||||
<source>Text files (*.ini)</source>
|
<source>Text files (*.ini)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="src/Menu.cpp" line="472"/>
|
<location filename="src/Menu.cpp" line="476"/>
|
||||||
<source>Save .ini config file</source>
|
<source>Save .ini config file</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
uniform sampler2DShadow shadowMap;
|
uniform sampler2DShadow shadowMap;
|
||||||
|
|
||||||
|
varying vec4 shadowColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
gl_FragColor = gl_Color * mix(vec4(0.8, 0.8, 0.8, 1.0), vec4(1.0, 1.0, 1.0, 1.0),
|
gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, gl_TexCoord[0].stp));
|
||||||
shadow2D(shadowMap, gl_TexCoord[0].stp));
|
|
||||||
}
|
}
|
||||||
|
|
28
interface/resources/shaders/shadow_map.vert
Normal file
28
interface/resources/shaders/shadow_map.vert
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// shadow_map.vert
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 3/27/14.
|
||||||
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
varying vec4 shadowColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
// the shadow color includes only the ambient terms
|
||||||
|
shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient);
|
||||||
|
|
||||||
|
// the normal color includes diffuse
|
||||||
|
vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
|
||||||
|
gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position)));
|
||||||
|
|
||||||
|
// generate the shadow texture coordinate using the eye position
|
||||||
|
vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex;
|
||||||
|
gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition),
|
||||||
|
dot(gl_EyePlaneR[0], eyePosition), 1.0);
|
||||||
|
|
||||||
|
// use the fixed function transform
|
||||||
|
gl_Position = ftransform();
|
||||||
|
}
|
|
@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_lastQueriedViewFrustum(),
|
_lastQueriedViewFrustum(),
|
||||||
_lastQueriedTime(usecTimestampNow()),
|
_lastQueriedTime(usecTimestampNow()),
|
||||||
_audioScope(256, 200, true),
|
_audioScope(256, 200, true),
|
||||||
|
_trailingAudioLoudness(0.f),
|
||||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||||
_mouseX(0),
|
_mouseX(0),
|
||||||
_mouseY(0),
|
_mouseY(0),
|
||||||
|
@ -169,6 +170,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_bytesPerSecond(0),
|
_bytesPerSecond(0),
|
||||||
_recentMaxPackets(0),
|
_recentMaxPackets(0),
|
||||||
_resetRecentMaxPacketsSoon(true),
|
_resetRecentMaxPacketsSoon(true),
|
||||||
|
_previousScriptLocation(),
|
||||||
_logger(new FileLogger(this))
|
_logger(new FileLogger(this))
|
||||||
{
|
{
|
||||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||||
|
@ -1636,6 +1638,8 @@ void Application::updateLOD() {
|
||||||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
// 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()) {
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) {
|
||||||
Menu::getInstance()->autoAdjustLOD(_fps);
|
Menu::getInstance()->autoAdjustLOD(_fps);
|
||||||
|
} else {
|
||||||
|
Menu::getInstance()->resetLODAdjust();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1842,15 +1846,6 @@ void Application::updateDialogs(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::updateAudio(float deltaTime) {
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateAudio()");
|
|
||||||
|
|
||||||
// Update audio stats for procedural sounds
|
|
||||||
_audio.setLastAcceleration(_myAvatar->getThrust());
|
|
||||||
_audio.setLastVelocity(_myAvatar->getVelocity());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::updateCursor(float deltaTime) {
|
void Application::updateCursor(float deltaTime) {
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
|
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
|
||||||
|
@ -1899,7 +1894,6 @@ void Application::update(float deltaTime) {
|
||||||
updateMetavoxels(deltaTime); // update metavoxels
|
updateMetavoxels(deltaTime); // update metavoxels
|
||||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||||
updateAudio(deltaTime); // Update audio stats for procedural sounds
|
|
||||||
updateCursor(deltaTime); // Handle cursor updates
|
updateCursor(deltaTime); // Handle cursor updates
|
||||||
|
|
||||||
_particles.update(); // update the particles...
|
_particles.update(); // update the particles...
|
||||||
|
@ -2187,19 +2181,26 @@ void Application::updateShadowMap() {
|
||||||
(_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
|
(_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
|
||||||
loadViewFrustum(_myCamera, _viewFrustum);
|
loadViewFrustum(_myCamera, _viewFrustum);
|
||||||
glm::vec3 points[] = {
|
glm::vec3 points[] = {
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale)),
|
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale)),
|
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale)),
|
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale)),
|
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale)),
|
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale)),
|
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale)),
|
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale),
|
||||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale)) };
|
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) };
|
||||||
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
glm::vec3 center;
|
||||||
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
|
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
|
||||||
minima = glm::min(minima, points[i]);
|
center += points[i];
|
||||||
maxima = glm::max(maxima, points[i]);
|
|
||||||
}
|
}
|
||||||
|
center /= (float)(sizeof(points) / sizeof(points[0]));
|
||||||
|
float radius = 0.0f;
|
||||||
|
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
|
||||||
|
radius = qMax(radius, glm::distance(points[i], center));
|
||||||
|
}
|
||||||
|
center = inverseRotation * center;
|
||||||
|
glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius);
|
||||||
|
glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
|
||||||
|
|
||||||
// stretch out our extents in z so that we get all of the avatars
|
// stretch out our extents in z so that we get all of the avatars
|
||||||
minima.z -= _viewFrustum.getFarClip() * 0.5f;
|
minima.z -= _viewFrustum.getFarClip() * 0.5f;
|
||||||
|
@ -2494,14 +2495,103 @@ void Application::displayOverlay() {
|
||||||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude());
|
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audio Scope
|
||||||
|
const int AUDIO_SCOPE_Y_OFFSET = 135;
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||||
_audio.renderMuteIcon(1, _glWidget->height() - 50);
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
|
||||||
int oscilloscopeTop = _glWidget->height() - 135;
|
int oscilloscopeTop = _glWidget->height() - AUDIO_SCOPE_Y_OFFSET;
|
||||||
_audioScope.render(25, oscilloscopeTop);
|
_audioScope.render(MIRROR_VIEW_LEFT_PADDING, oscilloscopeTop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audio VU Meter and Mute Icon
|
||||||
|
const int MUTE_ICON_SIZE = 24;
|
||||||
|
const int AUDIO_METER_INSET = 2;
|
||||||
|
const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET;
|
||||||
|
const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
|
||||||
|
const int AUDIO_METER_HEIGHT = 8;
|
||||||
|
const int AUDIO_METER_Y_GAP = 8;
|
||||||
|
const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET;
|
||||||
|
|
||||||
|
int audioMeterY;
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||||
|
audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_Y_GAP;
|
||||||
|
} else {
|
||||||
|
audioMeterY = AUDIO_METER_Y_GAP;
|
||||||
|
}
|
||||||
|
_audio.renderMuteIcon(MIRROR_VIEW_LEFT_PADDING, audioMeterY);
|
||||||
|
|
||||||
|
|
||||||
|
const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};
|
||||||
|
const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};
|
||||||
|
const float AUDIO_METER_RED[] = {1.0, 0.0, 0.0};
|
||||||
|
const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
const float CLIPPING_INDICATOR_TIME = 1.0f;
|
||||||
|
const float AUDIO_METER_AVERAGING = 0.5;
|
||||||
|
const float LOG2 = log(2.f);
|
||||||
|
const float MAX_LOG2_SAMPLE = 15.f;
|
||||||
|
float audioLevel = 0.f;
|
||||||
|
float loudness = _audio.getLastInputLoudness() + 1.f;
|
||||||
|
_trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
|
||||||
|
|
||||||
|
float log2loudness = log(_trailingAudioLoudness) / LOG2;
|
||||||
|
|
||||||
|
audioLevel = log2loudness / MAX_LOG2_SAMPLE * AUDIO_METER_SCALE_WIDTH;
|
||||||
|
|
||||||
|
bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
if (isClipping) {
|
||||||
|
glColor3f(1, 0, 0);
|
||||||
|
} else {
|
||||||
|
glColor3f(0, 0, 0);
|
||||||
|
}
|
||||||
|
// Draw audio meter background Quad
|
||||||
|
glVertex2i(AUDIO_METER_X, audioMeterY);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
|
||||||
|
glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
|
||||||
|
|
||||||
|
if (audioLevel > AUDIO_RED_START) {
|
||||||
|
if (!isClipping) {
|
||||||
|
glColor3fv(AUDIO_METER_RED);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Red Quad
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
audioLevel = AUDIO_RED_START;
|
||||||
|
}
|
||||||
|
if (audioLevel > AUDIO_GREEN_START) {
|
||||||
|
if (!isClipping) {
|
||||||
|
glColor3fv(AUDIO_METER_GREEN);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Green Quad
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
audioLevel = AUDIO_GREEN_START;
|
||||||
|
}
|
||||||
|
// Draw Blue Quad
|
||||||
|
if (!isClipping) {
|
||||||
|
glColor3fv(AUDIO_METER_BLUE);
|
||||||
|
} else {
|
||||||
|
glColor3f(1, 1, 1);
|
||||||
|
}
|
||||||
|
// Draw Blue (low level) quad
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
|
||||||
_myAvatar->renderHeadMouse();
|
_myAvatar->renderHeadMouse();
|
||||||
|
@ -3523,13 +3613,21 @@ void Application::reloadAllScripts() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::uploadFST() {
|
void Application::uploadFST(bool isHead) {
|
||||||
FstReader reader;
|
FstReader reader(isHead);
|
||||||
if (reader.zip()) {
|
if (reader.zip()) {
|
||||||
reader.send();
|
reader.send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::uploadHead() {
|
||||||
|
uploadFST(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::uploadSkeleton() {
|
||||||
|
uploadFST(false);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::removeScriptName(const QString& fileNameString) {
|
void Application::removeScriptName(const QString& fileNameString) {
|
||||||
_activeScripts.removeOne(fileNameString);
|
_activeScripts.removeOne(fileNameString);
|
||||||
}
|
}
|
||||||
|
@ -3601,12 +3699,20 @@ void Application::loadScript(const QString& scriptName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadDialog() {
|
void Application::loadDialog() {
|
||||||
// shut down and stop any existing script
|
QString suggestedName;
|
||||||
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
|
||||||
QString suggestedName = desktopLocation.append("/script.js");
|
if (_previousScriptLocation.isEmpty()) {
|
||||||
|
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
|
suggestedName = desktopLocation.append("/script.js");
|
||||||
|
} else {
|
||||||
|
suggestedName = _previousScriptLocation;
|
||||||
|
}
|
||||||
|
|
||||||
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
|
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
|
||||||
tr("JavaScript Files (*.js)"));
|
tr("JavaScript Files (*.js)"));
|
||||||
|
if (!fileNameString.isEmpty()) {
|
||||||
|
_previousScriptLocation = fileNameString;
|
||||||
|
}
|
||||||
|
|
||||||
loadScript(fileNameString);
|
loadScript(fileNameString);
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,7 +261,9 @@ public slots:
|
||||||
void stopAllScripts();
|
void stopAllScripts();
|
||||||
void reloadAllScripts();
|
void reloadAllScripts();
|
||||||
|
|
||||||
void uploadFST();
|
void uploadFST(bool isHead);
|
||||||
|
void uploadHead();
|
||||||
|
void uploadSkeleton();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void timer();
|
void timer();
|
||||||
|
@ -312,7 +314,6 @@ private:
|
||||||
void updateMetavoxels(float deltaTime);
|
void updateMetavoxels(float deltaTime);
|
||||||
void updateCamera(float deltaTime);
|
void updateCamera(float deltaTime);
|
||||||
void updateDialogs(float deltaTime);
|
void updateDialogs(float deltaTime);
|
||||||
void updateAudio(float deltaTime);
|
|
||||||
void updateCursor(float deltaTime);
|
void updateCursor(float deltaTime);
|
||||||
|
|
||||||
Avatar* findLookatTargetAvatar(glm::vec3& eyePosition, QUuid &nodeUUID);
|
Avatar* findLookatTargetAvatar(glm::vec3& eyePosition, QUuid &nodeUUID);
|
||||||
|
@ -397,6 +398,7 @@ private:
|
||||||
quint64 _lastQueriedTime;
|
quint64 _lastQueriedTime;
|
||||||
|
|
||||||
Oscilloscope _audioScope;
|
Oscilloscope _audioScope;
|
||||||
|
float _trailingAudioLoudness;
|
||||||
|
|
||||||
OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server
|
OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server
|
||||||
|
|
||||||
|
@ -483,6 +485,8 @@ private:
|
||||||
ControllerScriptingInterface _controllerScriptingInterface;
|
ControllerScriptingInterface _controllerScriptingInterface;
|
||||||
QPointer<LogDialog> _logDialog;
|
QPointer<LogDialog> _logDialog;
|
||||||
|
|
||||||
|
QString _previousScriptLocation;
|
||||||
|
|
||||||
FileLogger* _logger;
|
FileLogger* _logger;
|
||||||
|
|
||||||
void checkVersion();
|
void checkVersion();
|
||||||
|
|
|
@ -60,15 +60,16 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
|
||||||
_measuredJitter(0),
|
_measuredJitter(0),
|
||||||
_jitterBufferSamples(initialJitterBufferSamples),
|
_jitterBufferSamples(initialJitterBufferSamples),
|
||||||
_lastInputLoudness(0),
|
_lastInputLoudness(0),
|
||||||
|
_timeSinceLastClip(-1.0),
|
||||||
_dcOffset(0),
|
_dcOffset(0),
|
||||||
_noiseGateMeasuredFloor(0),
|
_noiseGateMeasuredFloor(0),
|
||||||
_noiseGateSampleCounter(0),
|
_noiseGateSampleCounter(0),
|
||||||
_noiseGateOpen(false),
|
_noiseGateOpen(false),
|
||||||
_noiseGateEnabled(true),
|
_noiseGateEnabled(true),
|
||||||
|
_toneInjectionEnabled(false),
|
||||||
_noiseGateFramesToClose(0),
|
_noiseGateFramesToClose(0),
|
||||||
_lastVelocity(0),
|
|
||||||
_lastAcceleration(0),
|
|
||||||
_totalPacketsReceived(0),
|
_totalPacketsReceived(0),
|
||||||
|
_totalInputAudioSamples(0),
|
||||||
_collisionSoundMagnitude(0.0f),
|
_collisionSoundMagnitude(0.0f),
|
||||||
_collisionSoundFrequency(0.0f),
|
_collisionSoundFrequency(0.0f),
|
||||||
_collisionSoundNoise(0.0f),
|
_collisionSoundNoise(0.0f),
|
||||||
|
@ -391,7 +392,7 @@ void Audio::handleAudioInput() {
|
||||||
inputSamplesRequired,
|
inputSamplesRequired,
|
||||||
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
|
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
|
||||||
_inputFormat, _desiredInputFormat);
|
_inputFormat, _desiredInputFormat);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Impose Noise Gate
|
// Impose Noise Gate
|
||||||
//
|
//
|
||||||
|
@ -420,13 +421,24 @@ void Audio::handleAudioInput() {
|
||||||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
||||||
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
||||||
const float DC_OFFSET_AVERAGING = 0.99f;
|
const float DC_OFFSET_AVERAGING = 0.99f;
|
||||||
|
const float CLIPPING_THRESHOLD = 0.90f;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check clipping, adjust DC offset, and check if should open noise gate
|
||||||
|
//
|
||||||
float measuredDcOffset = 0.f;
|
float measuredDcOffset = 0.f;
|
||||||
|
// Increment the time since the last clip
|
||||||
|
if (_timeSinceLastClip >= 0.0f) {
|
||||||
|
_timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||||
measuredDcOffset += monoAudioSamples[i];
|
measuredDcOffset += monoAudioSamples[i];
|
||||||
monoAudioSamples[i] -= (int16_t) _dcOffset;
|
monoAudioSamples[i] -= (int16_t) _dcOffset;
|
||||||
thisSample = fabsf(monoAudioSamples[i]);
|
thisSample = fabsf(monoAudioSamples[i]);
|
||||||
|
if (thisSample > (32767.f * CLIPPING_THRESHOLD)) {
|
||||||
|
_timeSinceLastClip = 0.0f;
|
||||||
|
}
|
||||||
loudness += thisSample;
|
loudness += thisSample;
|
||||||
// Noise Reduction: Count peaks above the average loudness
|
// Noise Reduction: Count peaks above the average loudness
|
||||||
if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) {
|
if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) {
|
||||||
|
@ -481,6 +493,16 @@ void Audio::handleAudioInput() {
|
||||||
_lastInputLoudness = 0;
|
_lastInputLoudness = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Add tone injection if enabled
|
||||||
|
//
|
||||||
|
const float TONE_FREQ = 220.f / SAMPLE_RATE * TWO_PI;
|
||||||
|
const float QUARTER_VOLUME = 8192.f;
|
||||||
|
if (_toneInjectionEnabled) {
|
||||||
|
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||||
|
monoAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add input data just written to the scope
|
// add input data just written to the scope
|
||||||
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
|
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
|
||||||
|
@ -675,7 +697,9 @@ void Audio::toggleAudioNoiseReduction() {
|
||||||
_noiseGateEnabled = !_noiseGateEnabled;
|
_noiseGateEnabled = !_noiseGateEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::toggleToneInjection() {
|
||||||
|
_toneInjectionEnabled = !_toneInjectionEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
// Take a pointer to the acquired microphone input samples and add procedural sounds
|
// Take a pointer to the acquired microphone input samples and add procedural sounds
|
||||||
void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
||||||
|
|
|
@ -47,13 +47,11 @@ public:
|
||||||
Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent = 0);
|
Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent = 0);
|
||||||
|
|
||||||
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); }
|
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); }
|
||||||
|
float getTimeSinceLastClip() const { return _timeSinceLastClip; }
|
||||||
float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
|
float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
|
||||||
|
|
||||||
void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; }
|
void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; }
|
||||||
|
|
||||||
void setLastAcceleration(const glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; }
|
|
||||||
void setLastVelocity(const glm::vec3 lastVelocity) { _lastVelocity = lastVelocity; }
|
|
||||||
|
|
||||||
void setJitterBufferSamples(int samples) { _jitterBufferSamples = samples; }
|
void setJitterBufferSamples(int samples) { _jitterBufferSamples = samples; }
|
||||||
int getJitterBufferSamples() { return _jitterBufferSamples; }
|
int getJitterBufferSamples() { return _jitterBufferSamples; }
|
||||||
|
|
||||||
|
@ -83,6 +81,7 @@ public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void toggleMute();
|
void toggleMute();
|
||||||
void toggleAudioNoiseReduction();
|
void toggleAudioNoiseReduction();
|
||||||
|
void toggleToneInjection();
|
||||||
|
|
||||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
||||||
|
|
||||||
|
@ -130,16 +129,17 @@ private:
|
||||||
float _measuredJitter;
|
float _measuredJitter;
|
||||||
int16_t _jitterBufferSamples;
|
int16_t _jitterBufferSamples;
|
||||||
float _lastInputLoudness;
|
float _lastInputLoudness;
|
||||||
|
float _timeSinceLastClip;
|
||||||
float _dcOffset;
|
float _dcOffset;
|
||||||
float _noiseGateMeasuredFloor;
|
float _noiseGateMeasuredFloor;
|
||||||
float* _noiseSampleFrames;
|
float* _noiseSampleFrames;
|
||||||
int _noiseGateSampleCounter;
|
int _noiseGateSampleCounter;
|
||||||
bool _noiseGateOpen;
|
bool _noiseGateOpen;
|
||||||
bool _noiseGateEnabled;
|
bool _noiseGateEnabled;
|
||||||
|
bool _toneInjectionEnabled;
|
||||||
int _noiseGateFramesToClose;
|
int _noiseGateFramesToClose;
|
||||||
glm::vec3 _lastVelocity;
|
|
||||||
glm::vec3 _lastAcceleration;
|
|
||||||
int _totalPacketsReceived;
|
int _totalPacketsReceived;
|
||||||
|
int _totalInputAudioSamples;
|
||||||
|
|
||||||
float _collisionSoundMagnitude;
|
float _collisionSoundMagnitude;
|
||||||
float _collisionSoundFrequency;
|
float _collisionSoundFrequency;
|
||||||
|
|
|
@ -146,7 +146,8 @@ Menu::Menu() :
|
||||||
SLOT(goTo()));
|
SLOT(goTo()));
|
||||||
|
|
||||||
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
|
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
|
||||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadFST, 0, Application::getInstance(), SLOT(uploadFST()));
|
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead()));
|
||||||
|
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadSkeleton, 0, Application::getInstance(), SLOT(uploadSkeleton()));
|
||||||
|
|
||||||
addDisabledActionAndSeparator(fileMenu, "Settings");
|
addDisabledActionAndSeparator(fileMenu, "Settings");
|
||||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings()));
|
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings()));
|
||||||
|
@ -241,7 +242,7 @@ Menu::Menu() :
|
||||||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog()));
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog()));
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, true);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
||||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails()));
|
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails()));
|
||||||
|
@ -361,6 +362,12 @@ Menu::Menu() :
|
||||||
false,
|
false,
|
||||||
appInstance->getAudio(),
|
appInstance->getAudio(),
|
||||||
SLOT(toggleMute()));
|
SLOT(toggleMute()));
|
||||||
|
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
appInstance->getAudio(),
|
||||||
|
SLOT(toggleToneInjection()));
|
||||||
|
|
||||||
|
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
|
||||||
Qt::CTRL | Qt::SHIFT | Qt::Key_V,
|
Qt::CTRL | Qt::SHIFT | Qt::Key_V,
|
||||||
|
@ -394,8 +401,6 @@ void Menu::loadSettings(QSettings* settings) {
|
||||||
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||||
_maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS);
|
_maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS);
|
||||||
_voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
|
_voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
|
||||||
_avatarLODDistanceMultiplier = loadSetting(settings, "avatarLODDistanceMultiplier",
|
|
||||||
DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
|
|
||||||
_boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0);
|
_boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0);
|
||||||
|
|
||||||
settings->beginGroup("View Frustum Offset Camera");
|
settings->beginGroup("View Frustum Offset Camera");
|
||||||
|
@ -435,7 +440,6 @@ void Menu::saveSettings(QSettings* settings) {
|
||||||
settings->setValue("maxVoxels", _maxVoxels);
|
settings->setValue("maxVoxels", _maxVoxels);
|
||||||
settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond);
|
settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond);
|
||||||
settings->setValue("voxelSizeScale", _voxelSizeScale);
|
settings->setValue("voxelSizeScale", _voxelSizeScale);
|
||||||
settings->setValue("avatarLODDistanceMultiplier", _avatarLODDistanceMultiplier);
|
|
||||||
settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust);
|
settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust);
|
||||||
settings->beginGroup("View Frustum Offset Camera");
|
settings->beginGroup("View Frustum Offset Camera");
|
||||||
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
||||||
|
@ -928,14 +932,17 @@ void Menu::goTo() {
|
||||||
|
|
||||||
int dialogReturn = gotoDialog.exec();
|
int dialogReturn = gotoDialog.exec();
|
||||||
if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) {
|
if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) {
|
||||||
LocationManager* manager = &LocationManager::getInstance();
|
goToUser(gotoDialog.textValue());
|
||||||
manager->goTo(gotoDialog.textValue());
|
|
||||||
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendFakeEnterEvent();
|
sendFakeEnterEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::goToUser(const QString& user) {
|
||||||
|
LocationManager* manager = &LocationManager::getInstance();
|
||||||
|
manager->goTo(user);
|
||||||
|
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
|
void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setText("Both user and location exists with same name");
|
msgBox.setText("Both user and location exists with same name");
|
||||||
|
@ -1103,13 +1110,28 @@ void Menu::showMetavoxelEditor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::showChat() {
|
void Menu::showChat() {
|
||||||
|
if (!_chatAction->isEnabled()) {
|
||||||
|
// Don't do anything if chat is disabled (No
|
||||||
|
// QXMPP library or xmpp is disconnected).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||||
if (!_chatWindow) {
|
if (!_chatWindow) {
|
||||||
Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow());
|
mainWindow->addDockWidget(Qt::NoDockWidgetArea, _chatWindow = new ChatWindow());
|
||||||
|
}
|
||||||
} else {
|
if (!_chatWindow->toggleViewAction()->isChecked()) {
|
||||||
if (!_chatWindow->toggleViewAction()->isChecked()) {
|
int width = _chatWindow->width();
|
||||||
_chatWindow->toggleViewAction()->trigger();
|
int y = qMax((mainWindow->height() - _chatWindow->height()) / 2, 0);
|
||||||
}
|
_chatWindow->move(mainWindow->width(), y);
|
||||||
|
_chatWindow->resize(0, _chatWindow->height());
|
||||||
|
_chatWindow->toggleViewAction()->trigger();
|
||||||
|
|
||||||
|
QPropertyAnimation* slideAnimation = new QPropertyAnimation(_chatWindow, "geometry", _chatWindow);
|
||||||
|
slideAnimation->setStartValue(_chatWindow->geometry());
|
||||||
|
slideAnimation->setEndValue(QRect(mainWindow->width() - width, _chatWindow->y(),
|
||||||
|
width, _chatWindow->height()));
|
||||||
|
slideAnimation->setDuration(250);
|
||||||
|
slideAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1204,7 +1226,10 @@ void Menu::autoAdjustLOD(float currentFPS) {
|
||||||
if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) {
|
if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) {
|
||||||
// attempt to lower the detail in proportion to the fps difference
|
// attempt to lower the detail in proportion to the fps difference
|
||||||
float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f;
|
float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f;
|
||||||
_avatarLODDistanceMultiplier *= (targetFps / _fastFPSAverage.getAverage());
|
float averageFps = _fastFPSAverage.getAverage();
|
||||||
|
const float MAXIMUM_MULTIPLIER_SCALE = 2.0f;
|
||||||
|
_avatarLODDistanceMultiplier *= (averageFps < EPSILON) ? MAXIMUM_MULTIPLIER_SCALE :
|
||||||
|
qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps);
|
||||||
_lastAvatarDetailDrop = now;
|
_lastAvatarDetailDrop = now;
|
||||||
}
|
}
|
||||||
} else if (_fastFPSAverage.getAverage() > ADJUST_LOD_UP_FPS) {
|
} else if (_fastFPSAverage.getAverage() > ADJUST_LOD_UP_FPS) {
|
||||||
|
@ -1250,6 +1275,12 @@ void Menu::autoAdjustLOD(float currentFPS) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::resetLODAdjust() {
|
||||||
|
_fpsAverage.reset();
|
||||||
|
_fastFPSAverage.reset();
|
||||||
|
_lastAvatarDetailDrop = _lastAdjust = usecTimestampNow();
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::setVoxelSizeScale(float sizeScale) {
|
void Menu::setVoxelSizeScale(float sizeScale) {
|
||||||
_voxelSizeScale = sizeScale;
|
_voxelSizeScale = sizeScale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
// User Tweakable LOD Items
|
// User Tweakable LOD Items
|
||||||
QString getLODFeedbackText();
|
QString getLODFeedbackText();
|
||||||
void autoAdjustLOD(float currentFPS);
|
void autoAdjustLOD(float currentFPS);
|
||||||
|
void resetLODAdjust();
|
||||||
void setVoxelSizeScale(float sizeScale);
|
void setVoxelSizeScale(float sizeScale);
|
||||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||||
float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||||
|
@ -121,6 +122,7 @@ public slots:
|
||||||
void importSettings();
|
void importSettings();
|
||||||
void exportSettings();
|
void exportSettings();
|
||||||
void goTo();
|
void goTo();
|
||||||
|
void goToUser(const QString& user);
|
||||||
void pasteToVoxel();
|
void pasteToVoxel();
|
||||||
|
|
||||||
void toggleLoginMenuItem();
|
void toggleLoginMenuItem();
|
||||||
|
@ -240,6 +242,7 @@ namespace MenuOption {
|
||||||
const QString FilterSixense = "Smooth Sixense Movement";
|
const QString FilterSixense = "Smooth Sixense Movement";
|
||||||
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
||||||
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
||||||
|
const QString AudioToneInjection = "Inject Test Tone";
|
||||||
const QString EchoServerAudio = "Echo Server Audio";
|
const QString EchoServerAudio = "Echo Server Audio";
|
||||||
const QString EchoLocalAudio = "Echo Local Audio";
|
const QString EchoLocalAudio = "Echo Local Audio";
|
||||||
const QString MuteAudio = "Mute Microphone";
|
const QString MuteAudio = "Mute Microphone";
|
||||||
|
@ -300,7 +303,8 @@ namespace MenuOption {
|
||||||
const QString StopAllScripts = "Stop All Scripts";
|
const QString StopAllScripts = "Stop All Scripts";
|
||||||
const QString TestPing = "Test Ping";
|
const QString TestPing = "Test Ping";
|
||||||
const QString TransmitterDrive = "Transmitter Drive";
|
const QString TransmitterDrive = "Transmitter Drive";
|
||||||
const QString UploadFST = "Upload FST file";
|
const QString UploadHead = "Upload Head Model";
|
||||||
|
const QString UploadSkeleton = "Upload Skeleton Model";
|
||||||
const QString Visage = "Visage";
|
const QString Visage = "Visage";
|
||||||
const QString Quit = "Quit";
|
const QString Quit = "Quit";
|
||||||
const QString Voxels = "Voxels";
|
const QString Voxels = "Voxels";
|
||||||
|
|
|
@ -252,7 +252,8 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
||||||
|
|
||||||
const float DISPLAYNAME_DISTANCE = 10.0f;
|
const float DISPLAYNAME_DISTANCE = 10.0f;
|
||||||
setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
|
setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
|
||||||
if (renderMode != NORMAL_RENDER_MODE) {
|
if (renderMode != NORMAL_RENDER_MODE || (isMyAvatar() &&
|
||||||
|
Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderDisplayName();
|
renderDisplayName();
|
||||||
|
@ -318,9 +319,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
void Avatar::renderBody(RenderMode renderMode) {
|
void Avatar::renderBody(RenderMode renderMode) {
|
||||||
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||||
// render the billboard until both models are loaded
|
// render the billboard until both models are loaded
|
||||||
if (renderMode != SHADOW_RENDER_MODE) {
|
renderBillboard();
|
||||||
renderBillboard();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE);
|
_skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE);
|
||||||
|
@ -403,9 +402,13 @@ void Avatar::renderDisplayName() {
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glm::vec3 textPosition;
|
glm::vec3 textPosition;
|
||||||
getSkeletonModel().getNeckPosition(textPosition);
|
if (getSkeletonModel().getNeckPosition(textPosition)) {
|
||||||
textPosition += getBodyUpDirection() * getHeadHeight() * 1.1f;
|
textPosition += getBodyUpDirection() * getHeadHeight() * 1.1f;
|
||||||
|
} else {
|
||||||
|
const float HEAD_PROPORTION = 0.75f;
|
||||||
|
textPosition = _position + getBodyUpDirection() * (getBillboardSize() * HEAD_PROPORTION);
|
||||||
|
}
|
||||||
|
|
||||||
glTranslatef(textPosition.x, textPosition.y, textPosition.z);
|
glTranslatef(textPosition.x, textPosition.y, textPosition.z);
|
||||||
|
|
||||||
// we need "always facing camera": we must remove the camera rotation from the stack
|
// we need "always facing camera": we must remove the camera rotation from the stack
|
||||||
|
|
|
@ -156,7 +156,8 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
|
||||||
//palm.addToPenetration(averagePenetration);
|
//palm.addToPenetration(averagePenetration);
|
||||||
} else {
|
} else {
|
||||||
// someone else's hand against MyAvatar
|
// someone else's hand against MyAvatar
|
||||||
averageContactPoint /= float(handCollisions.size());
|
// TODO: submit collision info to MyAvatar which should lean accordingly
|
||||||
|
averageContactPoint /= (float)handCollisions.size();
|
||||||
avatar->applyCollision(averageContactPoint, totalPenetration);
|
avatar->applyCollision(averageContactPoint, totalPenetration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ void MyAvatar::reset() {
|
||||||
// TODO? resurrect headMouse stuff?
|
// TODO? resurrect headMouse stuff?
|
||||||
//_headMouseX = _glWidget->width() / 2;
|
//_headMouseX = _glWidget->width() / 2;
|
||||||
//_headMouseY = _glWidget->height() / 2;
|
//_headMouseY = _glWidget->height() / 2;
|
||||||
|
_skeletonModel.reset();
|
||||||
getHead()->reset();
|
getHead()->reset();
|
||||||
getHand()->reset();
|
getHand()->reset();
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
||||||
direction += fingerVector / length;
|
direction += fingerVector / length;
|
||||||
}
|
}
|
||||||
fingerVector = glm::inverse(palmRotation) * fingerVector * -sign;
|
fingerVector = glm::inverse(palmRotation) * fingerVector * -sign;
|
||||||
IndexValue indexValue = { int(i), atan2f(fingerVector.z, fingerVector.x) };
|
IndexValue indexValue = { (int)i, atan2f(fingerVector.z, fingerVector.x) };
|
||||||
fingerIndices.append(indexValue);
|
fingerIndices.append(indexValue);
|
||||||
}
|
}
|
||||||
qSort(fingerIndices.begin(), fingerIndices.end());
|
qSort(fingerIndices.begin(), fingerIndices.end());
|
||||||
|
|
|
@ -1264,7 +1264,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
remainingModels.insert(model.key());
|
remainingModels.insert(model.key());
|
||||||
}
|
}
|
||||||
while (!remainingModels.isEmpty()) {
|
while (!remainingModels.isEmpty()) {
|
||||||
QString topID = getTopModelID(parentMap, models, *remainingModels.constBegin());
|
QString first = *remainingModels.constBegin();
|
||||||
|
foreach (const QString& id, remainingModels) {
|
||||||
|
if (id < first) {
|
||||||
|
first = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString topID = getTopModelID(parentMap, models, first);
|
||||||
appendModelIDs(parentMap.value(topID), childMap, models, remainingModels, modelIDs);
|
appendModelIDs(parentMap.value(topID), childMap, models, remainingModels, modelIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1586,7 +1592,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
int numVertices = extracted.mesh.vertices.size();
|
int numVertices = extracted.mesh.vertices.size();
|
||||||
jointShapeInfo.numVertices = numVertices;
|
jointShapeInfo.numVertices = numVertices;
|
||||||
if (numVertices > 0) {
|
if (numVertices > 0) {
|
||||||
averageVertex /= float(jointShapeInfo.numVertices);
|
averageVertex /= (float)jointShapeInfo.numVertices;
|
||||||
float averageRadius = 0.f;
|
float averageRadius = 0.f;
|
||||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||||
averageRadius += glm::distance(vertex, averageVertex);
|
averageRadius += glm::distance(vertex, averageVertex);
|
||||||
|
@ -1617,7 +1623,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
} else {
|
} else {
|
||||||
// collide the joint like a sphere
|
// collide the joint like a sphere
|
||||||
if (jointShapeInfo.numVertices > 0) {
|
if (jointShapeInfo.numVertices > 0) {
|
||||||
jointShapeInfo.averageVertex /= float(jointShapeInfo.numVertices);
|
jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
|
||||||
joint.shapePosition = jointShapeInfo.averageVertex;
|
joint.shapePosition = jointShapeInfo.averageVertex;
|
||||||
} else {
|
} else {
|
||||||
joint.shapePosition = glm::vec3(0.f);
|
joint.shapePosition = glm::vec3(0.f);
|
||||||
|
@ -1627,7 +1633,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
&& jointShapeInfo.numVertices > 0) {
|
&& jointShapeInfo.numVertices > 0) {
|
||||||
// the bone projection algorithm was not able to compute the joint radius
|
// the bone projection algorithm was not able to compute the joint radius
|
||||||
// so we use an alternative measure
|
// so we use an alternative measure
|
||||||
jointShapeInfo.averageRadius /= float(jointShapeInfo.numVertices);
|
jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices;
|
||||||
joint.boneRadius = jointShapeInfo.averageRadius;
|
joint.boneRadius = jointShapeInfo.averageRadius;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,11 @@ void GeometryCache::renderHemisphere(int slices, int stacks) {
|
||||||
GLfloat* vertexData = new GLfloat[vertices * 3];
|
GLfloat* vertexData = new GLfloat[vertices * 3];
|
||||||
GLfloat* vertex = vertexData;
|
GLfloat* vertex = vertexData;
|
||||||
for (int i = 0; i < stacks - 1; i++) {
|
for (int i = 0; i < stacks - 1; i++) {
|
||||||
float phi = PI_OVER_TWO * float(i) / float(stacks - 1);
|
float phi = PI_OVER_TWO * (float)i / (float)(stacks - 1);
|
||||||
float z = sinf(phi), radius = cosf(phi);
|
float z = sinf(phi), radius = cosf(phi);
|
||||||
|
|
||||||
for (int j = 0; j < slices; j++) {
|
for (int j = 0; j < slices; j++) {
|
||||||
float theta = TWO_PI * float(j) / float(slices);
|
float theta = TWO_PI * (float)j / (float)slices;
|
||||||
|
|
||||||
*(vertex++) = sinf(theta) * radius;
|
*(vertex++) = sinf(theta) * radius;
|
||||||
*(vertex++) = cosf(theta) * radius;
|
*(vertex++) = cosf(theta) * radius;
|
||||||
|
@ -181,7 +181,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) {
|
||||||
float y = (float)i / (stacks - 1);
|
float y = (float)i / (stacks - 1);
|
||||||
|
|
||||||
for (int j = 0; j <= slices; j++) {
|
for (int j = 0; j <= slices; j++) {
|
||||||
float theta = 3.f * PI_OVER_TWO + PI * float(j) / float(slices);
|
float theta = 3.f * PI_OVER_TWO + PI * (float)j / (float)slices;
|
||||||
|
|
||||||
//normals
|
//normals
|
||||||
*(vertex++) = sinf(theta);
|
*(vertex++) = sinf(theta);
|
||||||
|
|
|
@ -170,9 +170,16 @@ void Model::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::reset() {
|
void Model::reset() {
|
||||||
|
if (_jointStates.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
foreach (Model* attachment, _attachments) {
|
foreach (Model* attachment, _attachments) {
|
||||||
attachment->reset();
|
attachment->reset();
|
||||||
}
|
}
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
|
_jointStates[i].rotation = geometry.joints.at(i).rotation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return 'true' if geometry is up to date
|
// return 'true' if geometry is up to date
|
||||||
|
|
|
@ -160,7 +160,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
||||||
|
|
||||||
// Center of coordinate system -> upper left of bar
|
// Center of coordinate system -> upper left of bar
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(float(barX), float(y), 0.0f);
|
glTranslatef((float)barX, (float)y, 0.0f);
|
||||||
|
|
||||||
// Render captions
|
// Render captions
|
||||||
setColorRGBA(COLOR_TEXT);
|
setColorRGBA(COLOR_TEXT);
|
||||||
|
@ -202,7 +202,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
||||||
// Render scale indicators
|
// Render scale indicators
|
||||||
setColorRGBA(COLOR_INDICATOR);
|
setColorRGBA(COLOR_INDICATOR);
|
||||||
for (int j = NUMBER_OF_MARKERS; --j > 0;) {
|
for (int j = NUMBER_OF_MARKERS; --j > 0;) {
|
||||||
renderVerticalLine(int(barWidth * j / NUMBER_OF_MARKERS), 0, h);
|
renderVerticalLine((barWidth * j) / NUMBER_OF_MARKERS, 0, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render bars
|
// Render bars
|
||||||
|
@ -210,8 +210,8 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
||||||
for (size_t i = 0; i < N_CHANNELS; ++i) {
|
for (size_t i = 0; i < N_CHANNELS; ++i) {
|
||||||
|
|
||||||
ChannelIndex chIdx = ChannelIndex(i);
|
ChannelIndex chIdx = ChannelIndex(i);
|
||||||
int wIn = int(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
int wIn = (int)(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||||
int wOut = int(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
int wOut = (int)(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||||
|
|
||||||
setColorRGBA(channelInfo(chIdx).colorRGBA);
|
setColorRGBA(channelInfo(chIdx).colorRGBA);
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <QFormLayout>
|
#include <QGridLayout>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QLayoutItem>
|
#include <QLayoutItem>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QSizePolicy>
|
#include <QSizePolicy>
|
||||||
#include <QTextDocument>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -31,17 +30,18 @@ ChatWindow::ChatWindow() :
|
||||||
ui(new Ui::ChatWindow),
|
ui(new Ui::ChatWindow),
|
||||||
numMessagesAfterLastTimeStamp(0)
|
numMessagesAfterLastTimeStamp(0)
|
||||||
{
|
{
|
||||||
QWidget* widget = new QWidget();
|
ui->setupUi(this);
|
||||||
setWidget(widget);
|
|
||||||
|
// remove the title bar (see the Qt docs on setTitleBarWidget)
|
||||||
ui->setupUi(widget);
|
setTitleBarWidget(new QWidget());
|
||||||
|
|
||||||
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
||||||
ui->usersWidget->setLayout(flowLayout);
|
ui->usersWidget->setLayout(flowLayout);
|
||||||
|
|
||||||
ui->messagePlainTextEdit->installEventFilter(this);
|
ui->messagesGridLayout->setColumnStretch(0, 1);
|
||||||
|
ui->messagesGridLayout->setColumnStretch(1, 3);
|
||||||
|
|
||||||
ui->closeButton->hide();
|
ui->messagePlainTextEdit->installEventFilter(this);
|
||||||
|
|
||||||
#ifdef HAVE_QXMPP
|
#ifdef HAVE_QXMPP
|
||||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||||
|
@ -76,41 +76,48 @@ ChatWindow::~ChatWindow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
||||||
QWidget::keyPressEvent(event);
|
QDockWidget::keyPressEvent(event);
|
||||||
if (event->key() == Qt::Key_Escape) {
|
if (event->key() == Qt::Key_Escape) {
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatWindow::showEvent(QShowEvent* event) {
|
void ChatWindow::showEvent(QShowEvent* event) {
|
||||||
QWidget::showEvent(event);
|
QDockWidget::showEvent(event);
|
||||||
if (!event->spontaneous()) {
|
if (!event->spontaneous()) {
|
||||||
|
activateWindow();
|
||||||
ui->messagePlainTextEdit->setFocus();
|
ui->messagePlainTextEdit->setFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
||||||
Q_UNUSED(sender);
|
if (sender == ui->messagePlainTextEdit) {
|
||||||
|
if (event->type() != QEvent::KeyPress) {
|
||||||
if (event->type() != QEvent::KeyPress) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
|
||||||
if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) &&
|
|
||||||
(keyEvent->modifiers() & Qt::ShiftModifier) == 0) {
|
|
||||||
QString messageText = ui->messagePlainTextEdit->document()->toPlainText().trimmed();
|
|
||||||
if (!messageText.isEmpty()) {
|
|
||||||
#ifdef HAVE_QXMPP
|
|
||||||
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
|
||||||
QXmppMessage message;
|
|
||||||
message.setTo(publicChatRoom->jid());
|
|
||||||
message.setType(QXmppMessage::GroupChat);
|
|
||||||
message.setBody(messageText);
|
|
||||||
XmppClient::getInstance().getXMPPClient().sendPacket(message);
|
|
||||||
#endif
|
|
||||||
ui->messagePlainTextEdit->document()->clear();
|
|
||||||
}
|
}
|
||||||
return true;
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
|
if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) &&
|
||||||
|
(keyEvent->modifiers() & Qt::ShiftModifier) == 0) {
|
||||||
|
QString messageText = ui->messagePlainTextEdit->document()->toPlainText().trimmed();
|
||||||
|
if (!messageText.isEmpty()) {
|
||||||
|
#ifdef HAVE_QXMPP
|
||||||
|
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
|
||||||
|
QXmppMessage message;
|
||||||
|
message.setTo(publicChatRoom->jid());
|
||||||
|
message.setType(QXmppMessage::GroupChat);
|
||||||
|
message.setBody(messageText);
|
||||||
|
XmppClient::getInstance().getXMPPClient().sendPacket(message);
|
||||||
|
#endif
|
||||||
|
ui->messagePlainTextEdit->document()->clear();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event->type() != QEvent::MouseButtonRelease) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QString user = sender->property("user").toString();
|
||||||
|
Menu::getInstance()->goToUser(user);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -138,8 +145,9 @@ void ChatWindow::addTimeStamp() {
|
||||||
timeLabel->setStyleSheet("color: palette(shadow);"
|
timeLabel->setStyleSheet("color: palette(shadow);"
|
||||||
"background-color: palette(highlight);"
|
"background-color: palette(highlight);"
|
||||||
"padding: 4px;");
|
"padding: 4px;");
|
||||||
|
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
timeLabel->setAlignment(Qt::AlignHCenter);
|
timeLabel->setAlignment(Qt::AlignHCenter);
|
||||||
ui->messagesFormLayout->addRow(timeLabel);
|
ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2);
|
||||||
numMessagesAfterLastTimeStamp = 0;
|
numMessagesAfterLastTimeStamp = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,13 +195,21 @@ void ChatWindow::participantsChanged() {
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
foreach (const QString& participant, participants) {
|
foreach (const QString& participant, participants) {
|
||||||
QLabel* userLabel = new QLabel(getParticipantName(participant));
|
QString participantName = getParticipantName(participant);
|
||||||
|
QLabel* userLabel = new QLabel();
|
||||||
|
userLabel->setText(participantName);
|
||||||
userLabel->setStyleSheet("background-color: palette(light);"
|
userLabel->setStyleSheet("background-color: palette(light);"
|
||||||
"border-radius: 5px;"
|
"border-radius: 5px;"
|
||||||
"color: #267077;"
|
"color: #267077;"
|
||||||
"padding: 2px;"
|
"padding-top: 3px;"
|
||||||
|
"padding-right: 2px;"
|
||||||
|
"padding-bottom: 2px;"
|
||||||
|
"padding-left: 2px;"
|
||||||
"border: 1px solid palette(shadow);"
|
"border: 1px solid palette(shadow);"
|
||||||
"font-weight: bold");
|
"font-weight: bold");
|
||||||
|
userLabel->setProperty("user", participantName);
|
||||||
|
userLabel->setCursor(Qt::PointingHandCursor);
|
||||||
|
userLabel->installEventFilter(this);
|
||||||
ui->usersWidget->layout()->addWidget(userLabel);
|
ui->usersWidget->layout()->addWidget(userLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,19 +220,25 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QLabel* userLabel = new QLabel(getParticipantName(message.from()));
|
QLabel* userLabel = new QLabel(getParticipantName(message.from()));
|
||||||
userLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
userLabel->setStyleSheet("padding: 2px; font-weight: bold");
|
userLabel->setStyleSheet("padding: 2px; font-weight: bold");
|
||||||
userLabel->setAlignment(Qt::AlignTop);
|
userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight);
|
||||||
|
|
||||||
QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>"));
|
QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>"));
|
||||||
messageLabel->setWordWrap(true);
|
messageLabel->setWordWrap(true);
|
||||||
messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
messageLabel->setOpenExternalLinks(true);
|
messageLabel->setOpenExternalLinks(true);
|
||||||
messageLabel->setStyleSheet("padding: 2px; margin-right: 20px");
|
messageLabel->setStyleSheet("padding-bottom: 2px; padding-left: 2px; padding-top: 2px; padding-right: 20px");
|
||||||
messageLabel->setAlignment(Qt::AlignTop);
|
messageLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
|
||||||
ui->messagesFormLayout->addRow(userLabel, messageLabel);
|
if (getParticipantName(message.from()) == AccountManager::getInstance().getUsername()) {
|
||||||
ui->messagesFormLayout->parentWidget()->updateGeometry();
|
userLabel->setStyleSheet(userLabel->styleSheet() + "; background-color: #e1e8ea");
|
||||||
|
messageLabel->setStyleSheet(messageLabel->styleSheet() + "; background-color: #e1e8ea");
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0);
|
||||||
|
ui->messagesGridLayout->addWidget(messageLabel, ui->messagesGridLayout->rowCount() - 1, 1);
|
||||||
|
ui->messagesGridLayout->parentWidget()->updateGeometry();
|
||||||
Application::processEvents();
|
Application::processEvents();
|
||||||
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
||||||
verticalScrollBar->setSliderPosition(verticalScrollBar->maximum());
|
verticalScrollBar->setSliderPosition(verticalScrollBar->maximum());
|
||||||
|
|
|
@ -127,7 +127,7 @@ void Oscilloscope::render(int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch low pass factor (and convert to fix point) / downsample factor
|
// fetch low pass factor (and convert to fix point) / downsample factor
|
||||||
int lowPassFixPt = -int(std::numeric_limits<short>::min()) * _lowPassCoeff;
|
int lowPassFixPt = -(int)(std::numeric_limits<short>::min()) * _lowPassCoeff;
|
||||||
unsigned downsample = _downsampleRatio;
|
unsigned downsample = _downsampleRatio;
|
||||||
// keep half of the buffer for writing and ensure an even vertex count
|
// keep half of the buffer for writing and ensure an even vertex count
|
||||||
unsigned usedWidth = min(_width, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u;
|
unsigned usedWidth = min(_width, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u;
|
||||||
|
@ -141,7 +141,7 @@ void Oscilloscope::render(int x, int y) {
|
||||||
short const* inPtr = _samples + _writePos[ch];
|
short const* inPtr = _samples + _writePos[ch];
|
||||||
short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch;
|
short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch;
|
||||||
int sample = 0, x = usedWidth;
|
int sample = 0, x = usedWidth;
|
||||||
for (int i = int(usedSamples); --i >= 0 ;) {
|
for (int i = (int)usedSamples; --i >= 0 ;) {
|
||||||
if (inPtr == basePtr) {
|
if (inPtr == basePtr) {
|
||||||
// handle boundary, reading the circular sample buffer
|
// handle boundary, reading the circular sample buffer
|
||||||
inPtr = endPtr;
|
inPtr = endPtr;
|
||||||
|
|
|
@ -506,8 +506,10 @@ void VoxelSystem::initVoxelMemory() {
|
||||||
_perlinModulateProgram.setUniformValue("permutationNormalTexture", 0);
|
_perlinModulateProgram.setUniformValue("permutationNormalTexture", 0);
|
||||||
_perlinModulateProgram.release();
|
_perlinModulateProgram.release();
|
||||||
|
|
||||||
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath()
|
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||||
+ "shaders/shadow_map.frag");
|
Application::resourcesPath() + "shaders/shadow_map.vert");
|
||||||
|
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||||
|
Application::resourcesPath() + "shaders/shadow_map.frag");
|
||||||
_shadowMapProgram.link();
|
_shadowMapProgram.link();
|
||||||
|
|
||||||
_shadowMapProgram.bind();
|
_shadowMapProgram.bind();
|
||||||
|
@ -1471,10 +1473,6 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||||
_shadowMapProgram.bind();
|
_shadowMapProgram.bind();
|
||||||
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
|
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
|
||||||
glEnable(GL_TEXTURE_GEN_S);
|
|
||||||
glEnable(GL_TEXTURE_GEN_T);
|
|
||||||
glEnable(GL_TEXTURE_GEN_R);
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
|
|
||||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]);
|
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]);
|
||||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]);
|
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]);
|
||||||
|
@ -1496,10 +1494,7 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||||
_shadowMapProgram.release();
|
_shadowMapProgram.release();
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
glDisable(GL_TEXTURE_GEN_S);
|
|
||||||
glDisable(GL_TEXTURE_GEN_T);
|
|
||||||
glDisable(GL_TEXTURE_GEN_R);
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
|
|
||||||
} else if (texture) {
|
} else if (texture) {
|
||||||
_perlinModulateProgram.release();
|
_perlinModulateProgram.release();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ChatWindow</class>
|
<class>ChatWindow</class>
|
||||||
<widget class="QWidget" name="ChatWindow">
|
<widget class="QDockWidget" name="ChatWindow">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
|
@ -13,180 +13,188 @@
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>0</height>
|
<height>238</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Chat</string>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
|
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<property name="features">
|
||||||
<property name="spacing">
|
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
<property name="allowedAreas">
|
||||||
<property name="leftMargin">
|
<set>Qt::NoDockWidgetArea</set>
|
||||||
<number>8</number>
|
</property>
|
||||||
</property>
|
<property name="windowTitle">
|
||||||
<property name="topMargin">
|
<string>Chat</string>
|
||||||
<number>8</number>
|
</property>
|
||||||
</property>
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
<property name="rightMargin">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<number>8</number>
|
<property name="spacing">
|
||||||
</property>
|
<number>0</number>
|
||||||
<property name="bottomMargin">
|
</property>
|
||||||
<number>8</number>
|
<property name="leftMargin">
|
||||||
</property>
|
<number>8</number>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QLabel" name="connectingToXMPPLabel">
|
<property name="topMargin">
|
||||||
<property name="sizePolicy">
|
<number>8</number>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
</property>
|
||||||
<horstretch>0</horstretch>
|
<property name="rightMargin">
|
||||||
<verstretch>0</verstretch>
|
<number>8</number>
|
||||||
</sizepolicy>
|
</property>
|
||||||
</property>
|
<property name="bottomMargin">
|
||||||
<property name="text">
|
<number>8</number>
|
||||||
<string>Connecting to XMPP...</string>
|
</property>
|
||||||
</property>
|
<item>
|
||||||
<property name="alignment">
|
<widget class="QLabel" name="connectingToXMPPLabel">
|
||||||
<set>Qt::AlignCenter</set>
|
<property name="sizePolicy">
|
||||||
</property>
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
</widget>
|
<horstretch>0</horstretch>
|
||||||
</item>
|
<verstretch>0</verstretch>
|
||||||
<item>
|
</sizepolicy>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
</property>
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLabel" name="numOnlineLabel">
|
<string>Connecting to XMPP...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="numOnlineLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string> online now:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="closeButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../resources/resources.qrc">
|
||||||
|
<normaloff>:/images/close.svg</normaloff>:/images/close.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="usersWidget" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="messagesScrollArea">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">margin-top: 12px;</string>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>382</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
|
<string notr="true">margin-top: 0px;</string>
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string> online now:</string>
|
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QGridLayout" name="messagesGridLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</widget>
|
||||||
<item>
|
</item>
|
||||||
<widget class="QPushButton" name="closeButton">
|
<item>
|
||||||
<property name="sizePolicy">
|
<widget class="QPlainTextEdit" name="messagePlainTextEdit">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<property name="sizePolicy">
|
||||||
<horstretch>0</horstretch>
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
<verstretch>0</verstretch>
|
<horstretch>0</horstretch>
|
||||||
</sizepolicy>
|
<verstretch>0</verstretch>
|
||||||
</property>
|
</sizepolicy>
|
||||||
<property name="maximumSize">
|
</property>
|
||||||
<size>
|
<property name="minimumSize">
|
||||||
<width>16</width>
|
<size>
|
||||||
<height>16</height>
|
<width>0</width>
|
||||||
</size>
|
<height>60</height>
|
||||||
</property>
|
</size>
|
||||||
<property name="focusPolicy">
|
|
||||||
<enum>Qt::NoFocus</enum>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../resources/resources.qrc">
|
|
||||||
<normaloff>:/images/close.svg</normaloff>:/images/close.svg</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QWidget" name="usersWidget" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QScrollArea" name="messagesScrollArea">
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">margin-top: 12px;</string>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="widgetResizable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>358</width>
|
|
||||||
<height>464</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">margin-top: 0px;</string>
|
<string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tabChangesFocus">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="messagesFormLayout">
|
|
||||||
<property name="fieldGrowthPolicy">
|
|
||||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalSpacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="verticalSpacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
</layout>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QPlainTextEdit" name="messagePlainTextEdit">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>60</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
|
|
||||||
</property>
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::NoFrame</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeAdjustPolicy">
|
|
||||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
|
||||||
</property>
|
|
||||||
<property name="tabChangesFocus">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>messagePlainTextEdit</tabstop>
|
<tabstop>messagePlainTextEdit</tabstop>
|
||||||
|
|
|
@ -1096,7 +1096,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
|
||||||
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
|
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
|
||||||
MetavoxelInfo info = {
|
MetavoxelInfo info = {
|
||||||
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
|
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()),
|
||||||
float(infoValue.property(guide->_sizeHandle).toNumber()), guide->_visitation->info.inputValues,
|
(float)infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues,
|
||||||
guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() };
|
guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() };
|
||||||
|
|
||||||
// extract and convert the values provided by the script
|
// extract and convert the values provided by the script
|
||||||
|
|
|
@ -144,14 +144,15 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
||||||
break;
|
break;
|
||||||
case QNetworkAccessManager::PostOperation:
|
case QNetworkAccessManager::PostOperation:
|
||||||
case QNetworkAccessManager::PutOperation:
|
case QNetworkAccessManager::PutOperation:
|
||||||
authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
|
||||||
if (dataMultiPart) {
|
if (dataMultiPart) {
|
||||||
if (operation == QNetworkAccessManager::PostOperation) {
|
if (operation == QNetworkAccessManager::PostOperation) {
|
||||||
networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart);
|
networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart);
|
||||||
} else {
|
} else {
|
||||||
networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart);
|
networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart);
|
||||||
}
|
}
|
||||||
|
dataMultiPart->setParent(networkReply);
|
||||||
} else {
|
} else {
|
||||||
|
authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
if (operation == QNetworkAccessManager::PostOperation) {
|
if (operation == QNetworkAccessManager::PostOperation) {
|
||||||
networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray);
|
networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray);
|
||||||
} else {
|
} else {
|
||||||
|
@ -199,6 +200,7 @@ void AccountManager::passSuccessToCallback() {
|
||||||
qDebug() << jsonResponse;
|
qDebug() << jsonResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete requestReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) {
|
void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) {
|
||||||
|
@ -219,6 +221,7 @@ void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode)
|
||||||
qDebug() << "Error" << errorCode << "-" << requestReply->errorString();
|
qDebug() << "Error" << errorCode << "-" << requestReply->errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete requestReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AccountManager::hasValidAccessToken() {
|
bool AccountManager::hasValidAccessToken() {
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QHttpMultiPart>
|
#include <QHttpMultiPart>
|
||||||
|
#include <QTemporaryDir>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "AccountManager.h"
|
#include "AccountManager.h"
|
||||||
|
|
||||||
#include "FstReader.h"
|
#include "FstReader.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,20 +25,30 @@ static const QString NAME_FIELD = "name";
|
||||||
static const QString FILENAME_FIELD = "filename";
|
static const QString FILENAME_FIELD = "filename";
|
||||||
static const QString TEXDIR_FIELD = "texdir";
|
static const QString TEXDIR_FIELD = "texdir";
|
||||||
static const QString LOD_FIELD = "lod";
|
static const QString LOD_FIELD = "lod";
|
||||||
static const QString HEAD_SPECIFIC_FIELD = "bs";
|
|
||||||
|
|
||||||
static const QString MODEL_URL = "/api/v1/models";
|
static const QString MODEL_URL = "/api/v1/models";
|
||||||
|
|
||||||
static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB
|
static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB
|
||||||
|
|
||||||
FstReader::FstReader() :
|
// Class providing the QObject parent system to QTemporaryDir
|
||||||
|
class TemporaryDir : public QTemporaryDir, public QObject {
|
||||||
|
public:
|
||||||
|
virtual ~TemporaryDir() {
|
||||||
|
// ensuring the entire object gets deleted by the QObject parent.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FstReader::FstReader(bool isHead) :
|
||||||
|
_zipDir(new TemporaryDir()),
|
||||||
_lodCount(-1),
|
_lodCount(-1),
|
||||||
_texturesCount(-1),
|
_texturesCount(-1),
|
||||||
_totalSize(0),
|
_totalSize(0),
|
||||||
_isHead(false),
|
_isHead(isHead),
|
||||||
_readyToSend(false),
|
_readyToSend(false),
|
||||||
_dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType))
|
_dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType))
|
||||||
{
|
{
|
||||||
|
_zipDir->setParent(_dataMultiPart);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FstReader::~FstReader() {
|
FstReader::~FstReader() {
|
||||||
|
@ -63,20 +73,20 @@ bool FstReader::zip() {
|
||||||
QString("ModelUploader::zip()"),
|
QString("ModelUploader::zip()"),
|
||||||
QString("Could not open FST file."),
|
QString("Could not open FST file."),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
return false;
|
qDebug() << "[Warning] " << QString("Could not open FST file.");
|
||||||
}
|
|
||||||
|
|
||||||
// Compress and copy the fst
|
|
||||||
if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_totalSize += QFileInfo(fst).size();
|
|
||||||
if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(),
|
|
||||||
QString("fst"))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "Reading FST file : " << QFileInfo(fst).filePath();
|
qDebug() << "Reading FST file : " << QFileInfo(fst).filePath();
|
||||||
|
|
||||||
|
// Compress and copy the fst
|
||||||
|
if (!compressFile(QFileInfo(fst).filePath(), _zipDir->path() + "/" + QFileInfo(fst).fileName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!addPart(_zipDir->path() + "/" + QFileInfo(fst).fileName(),
|
||||||
|
QString("fst"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Let's read through the FST file
|
// Let's read through the FST file
|
||||||
QTextStream stream(&fst);
|
QTextStream stream(&fst);
|
||||||
QList<QString> line;
|
QList<QString> line;
|
||||||
|
@ -86,73 +96,63 @@ bool FstReader::zip() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_totalSize > MAX_SIZE) {
|
|
||||||
QMessageBox::warning(NULL,
|
|
||||||
QString("ModelUploader::zip()"),
|
|
||||||
QString("Model too big, over %1 Bytes.").arg(MAX_SIZE),
|
|
||||||
QMessageBox::Ok);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// according to what is read, we modify the command
|
// according to what is read, we modify the command
|
||||||
if (line[1] == HEAD_SPECIFIC_FIELD) {
|
if (line[0] == NAME_FIELD) {
|
||||||
_isHead = true;
|
|
||||||
} else if (line[1] == NAME_FIELD) {
|
|
||||||
QHttpPart textPart;
|
QHttpPart textPart;
|
||||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
||||||
" name=\"model_name\"");
|
" name=\"model_name\"");
|
||||||
textPart.setBody(line[1].toUtf8());
|
textPart.setBody(line[1].toUtf8());
|
||||||
_dataMultiPart->append(textPart);
|
_dataMultiPart->append(textPart);
|
||||||
} else if (line[1] == FILENAME_FIELD) {
|
} else if (line[0] == FILENAME_FIELD) {
|
||||||
QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]);
|
QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]);
|
||||||
if (!fbx.exists() || !fbx.isFile()) { // Check existence
|
if (!fbx.exists() || !fbx.isFile()) { // Check existence
|
||||||
QMessageBox::warning(NULL,
|
QMessageBox::warning(NULL,
|
||||||
QString("ModelUploader::zip()"),
|
QString("ModelUploader::zip()"),
|
||||||
QString("FBX file %1 could not be found.").arg(fbx.fileName()),
|
QString("FBX file %1 could not be found.").arg(fbx.fileName()),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(fbx.fileName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Compress and copy
|
// Compress and copy
|
||||||
if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) {
|
if (!compressFile(fbx.filePath(), _zipDir->path() + "/" + line[1])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_totalSize += fbx.size();
|
if (!addPart(_zipDir->path() + "/" + line[1], "fbx")) {
|
||||||
if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (line[1] == TEXDIR_FIELD) { // Check existence
|
} else if (line[0] == TEXDIR_FIELD) { // Check existence
|
||||||
QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]);
|
QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]);
|
||||||
if (!texdir.exists() || !texdir.isDir()) {
|
if (!texdir.exists() || !texdir.isDir()) {
|
||||||
QMessageBox::warning(NULL,
|
QMessageBox::warning(NULL,
|
||||||
QString("ModelUploader::zip()"),
|
QString("ModelUploader::zip()"),
|
||||||
QString("Texture directory could not be found."),
|
QString("Texture directory could not be found."),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
qDebug() << "[Warning] " << QString("Texture directory could not be found.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!addTextures(texdir)) { // Recursive compress and copy
|
if (!addTextures(texdir)) { // Recursive compress and copy
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (line[1] == LOD_FIELD) {
|
} else if (line[0] == LOD_FIELD) {
|
||||||
QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]);
|
QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]);
|
||||||
if (!lod.exists() || !lod.isFile()) { // Check existence
|
if (!lod.exists() || !lod.isFile()) { // Check existence
|
||||||
QMessageBox::warning(NULL,
|
QMessageBox::warning(NULL,
|
||||||
QString("ModelUploader::zip()"),
|
QString("ModelUploader::zip()"),
|
||||||
QString("FBX file %1 could not be found.").arg(lod.fileName()),
|
QString("FBX file %1 could not be found.").arg(lod.fileName()),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(lod.fileName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Compress and copy
|
// Compress and copy
|
||||||
if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) {
|
if (!compressFile(lod.filePath(), _zipDir->path() + "/" + line[1])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_totalSize += lod.size();
|
if (!addPart(_zipDir->path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) {
|
||||||
if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QHttpPart textPart;
|
QHttpPart textPart;
|
||||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
||||||
" name=\"model_category\"");
|
" name=\"model_category\"");
|
||||||
|
@ -173,6 +173,9 @@ bool FstReader::send() {
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart);
|
AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart);
|
||||||
|
_zipDir = NULL;
|
||||||
|
_dataMultiPart = NULL;
|
||||||
|
qDebug() << "Model sent.";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -189,11 +192,10 @@ bool FstReader::addTextures(const QFileInfo& texdir) {
|
||||||
foreach (QFileInfo info, list) {
|
foreach (QFileInfo info, list) {
|
||||||
if (info.isFile()) {
|
if (info.isFile()) {
|
||||||
// Compress and copy
|
// Compress and copy
|
||||||
if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) {
|
if (!compressFile(info.filePath(), _zipDir->path() + "/" + info.fileName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_totalSize += info.size();
|
if (!addPart(_zipDir->path() + "/" + info.fileName(),
|
||||||
if (!addPart(_zipDir.path() + "/" + info.fileName(),
|
|
||||||
QString("texture%1").arg(++_texturesCount))) {
|
QString("texture%1").arg(++_texturesCount))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -214,12 +216,13 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa
|
||||||
|
|
||||||
QFile outFile(outFileName);
|
QFile outFile(outFileName);
|
||||||
if (!outFile.open(QIODevice::WriteOnly)) {
|
if (!outFile.open(QIODevice::WriteOnly)) {
|
||||||
QDir(_zipDir.path()).mkpath(QFileInfo(outFileName).path());
|
QDir(_zipDir->path()).mkpath(QFileInfo(outFileName).path());
|
||||||
if (!outFile.open(QIODevice::WriteOnly)) {
|
if (!outFile.open(QIODevice::WriteOnly)) {
|
||||||
QMessageBox::warning(NULL,
|
QMessageBox::warning(NULL,
|
||||||
QString("ModelUploader::compressFile()"),
|
QString("ModelUploader::compressFile()"),
|
||||||
QString("Could not compress %1").arg(inFileName),
|
QString("Could not compress %1").arg(inFileName),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
qDebug() << "[Warning] " << QString("Could not compress %1").arg(inFileName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +240,8 @@ bool FstReader::addPart(const QString &path, const QString& name) {
|
||||||
QString("ModelUploader::addPart()"),
|
QString("ModelUploader::addPart()"),
|
||||||
QString("Could not open %1").arg(path),
|
QString("Could not open %1").arg(path),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
|
qDebug() << "[Warning] " << QString("Could not open %1").arg(path);
|
||||||
|
delete file;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +254,19 @@ bool FstReader::addPart(const QString &path, const QString& name) {
|
||||||
_dataMultiPart->append(part);
|
_dataMultiPart->append(part);
|
||||||
file->setParent(_dataMultiPart);
|
file->setParent(_dataMultiPart);
|
||||||
|
|
||||||
|
|
||||||
|
qDebug() << "File " << QFileInfo(*file).fileName() << " added to model.";
|
||||||
|
_totalSize += file->size();
|
||||||
|
if (_totalSize > MAX_SIZE) {
|
||||||
|
QMessageBox::warning(NULL,
|
||||||
|
QString("ModelUploader::zip()"),
|
||||||
|
QString("Model too big, over %1 Bytes.").arg(MAX_SIZE),
|
||||||
|
QMessageBox::Ok);
|
||||||
|
qDebug() << "[Warning] " << QString("Model too big, over %1 Bytes.").arg(MAX_SIZE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qDebug() << "Current model size: " << _totalSize;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,19 @@
|
||||||
#ifndef __hifi__FstReader__
|
#ifndef __hifi__FstReader__
|
||||||
#define __hifi__FstReader__
|
#define __hifi__FstReader__
|
||||||
|
|
||||||
#include <QTemporaryDir>
|
class TemporaryDir;
|
||||||
|
|
||||||
class QHttpMultiPart;
|
class QHttpMultiPart;
|
||||||
|
|
||||||
class FstReader {
|
class FstReader : public QObject {
|
||||||
public:
|
public:
|
||||||
FstReader();
|
FstReader(bool isHead);
|
||||||
~FstReader();
|
~FstReader();
|
||||||
|
|
||||||
bool zip();
|
bool zip();
|
||||||
bool send();
|
bool send();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTemporaryDir _zipDir;
|
TemporaryDir* _zipDir;
|
||||||
int _lodCount;
|
int _lodCount;
|
||||||
int _texturesCount;
|
int _texturesCount;
|
||||||
int _totalSize;
|
int _totalSize;
|
||||||
|
|
|
@ -51,6 +51,7 @@ Node::Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const
|
||||||
_lastHeardMicrostamp(usecTimestampNow()),
|
_lastHeardMicrostamp(usecTimestampNow()),
|
||||||
_publicSocket(publicSocket),
|
_publicSocket(publicSocket),
|
||||||
_localSocket(localSocket),
|
_localSocket(localSocket),
|
||||||
|
_symmetricSocket(),
|
||||||
_activeSocket(NULL),
|
_activeSocket(NULL),
|
||||||
_connectionSecret(),
|
_connectionSecret(),
|
||||||
_bytesReceivedMovingAverage(NULL),
|
_bytesReceivedMovingAverage(NULL),
|
||||||
|
@ -84,6 +85,15 @@ void Node::setLocalSocket(const HifiSockAddr& localSocket) {
|
||||||
_localSocket = localSocket;
|
_localSocket = localSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::setSymmetricSocket(const HifiSockAddr& symmetricSocket) {
|
||||||
|
if (_activeSocket == &_symmetricSocket) {
|
||||||
|
// if the active socket was the symmetric socket then reset it to NULL
|
||||||
|
_activeSocket = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_symmetricSocket = symmetricSocket;
|
||||||
|
}
|
||||||
|
|
||||||
void Node::activateLocalSocket() {
|
void Node::activateLocalSocket() {
|
||||||
qDebug() << "Activating local socket for node" << *this;
|
qDebug() << "Activating local socket for node" << *this;
|
||||||
_activeSocket = &_localSocket;
|
_activeSocket = &_localSocket;
|
||||||
|
@ -94,6 +104,11 @@ void Node::activatePublicSocket() {
|
||||||
_activeSocket = &_publicSocket;
|
_activeSocket = &_publicSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::activateSymmetricSocket() {
|
||||||
|
qDebug() << "Activating symmetric socket for node" << *this;
|
||||||
|
_activeSocket = &_symmetricSocket;
|
||||||
|
}
|
||||||
|
|
||||||
void Node::recordBytesReceived(int bytesReceived) {
|
void Node::recordBytesReceived(int bytesReceived) {
|
||||||
if (!_bytesReceivedMovingAverage) {
|
if (!_bytesReceivedMovingAverage) {
|
||||||
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
|
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
|
||||||
|
|
|
@ -70,11 +70,14 @@ public:
|
||||||
void setPublicSocket(const HifiSockAddr& publicSocket);
|
void setPublicSocket(const HifiSockAddr& publicSocket);
|
||||||
const HifiSockAddr& getLocalSocket() const { return _localSocket; }
|
const HifiSockAddr& getLocalSocket() const { return _localSocket; }
|
||||||
void setLocalSocket(const HifiSockAddr& localSocket);
|
void setLocalSocket(const HifiSockAddr& localSocket);
|
||||||
|
const HifiSockAddr& getSymmetricSocket() const { return _symmetricSocket; }
|
||||||
|
void setSymmetricSocket(const HifiSockAddr& symmetricSocket);
|
||||||
|
|
||||||
const HifiSockAddr* getActiveSocket() const { return _activeSocket; }
|
const HifiSockAddr* getActiveSocket() const { return _activeSocket; }
|
||||||
|
|
||||||
void activatePublicSocket();
|
void activatePublicSocket();
|
||||||
void activateLocalSocket();
|
void activateLocalSocket();
|
||||||
|
void activateSymmetricSocket();
|
||||||
|
|
||||||
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
||||||
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
||||||
|
@ -110,6 +113,7 @@ private:
|
||||||
quint64 _lastHeardMicrostamp;
|
quint64 _lastHeardMicrostamp;
|
||||||
HifiSockAddr _publicSocket;
|
HifiSockAddr _publicSocket;
|
||||||
HifiSockAddr _localSocket;
|
HifiSockAddr _localSocket;
|
||||||
|
HifiSockAddr _symmetricSocket;
|
||||||
HifiSockAddr* _activeSocket;
|
HifiSockAddr* _activeSocket;
|
||||||
QUuid _connectionSecret;
|
QUuid _connectionSecret;
|
||||||
SimpleMovingAverage* _bytesReceivedMovingAverage;
|
SimpleMovingAverage* _bytesReceivedMovingAverage;
|
||||||
|
|
|
@ -294,6 +294,15 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
|
||||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
QByteArray replyPacket = constructPingReplyPacket(packet);
|
QByteArray replyPacket = constructPingReplyPacket(packet);
|
||||||
writeDatagram(replyPacket, matchingNode, senderSockAddr);
|
writeDatagram(replyPacket, matchingNode, senderSockAddr);
|
||||||
|
|
||||||
|
// If we don't have a symmetric socket for this node and this socket doesn't match
|
||||||
|
// what we have for public and local then set it as the symmetric.
|
||||||
|
// This allows a server on a reachable port to communicate with nodes on symmetric NATs
|
||||||
|
if (matchingNode->getSymmetricSocket().isNull()) {
|
||||||
|
if (senderSockAddr != matchingNode->getLocalSocket() && senderSockAddr != matchingNode->getPublicSocket()) {
|
||||||
|
matchingNode->setSymmetricSocket(senderSockAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -357,10 +366,20 @@ int NodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID, bool blockingLock) {
|
||||||
QMutexLocker locker(&_nodeHashMutex);
|
const int WAIT_TIME = 10; // wait up to 10ms in the try lock case
|
||||||
return _nodeHash.value(nodeUUID);
|
SharedNodePointer node;
|
||||||
}
|
// if caller wants us to block and guarantee the correct answer, then honor that request
|
||||||
|
if (blockingLock) {
|
||||||
|
// this will block till we can get access
|
||||||
|
QMutexLocker locker(&_nodeHashMutex);
|
||||||
|
node = _nodeHash.value(nodeUUID);
|
||||||
|
} else if (_nodeHashMutex.tryLock(WAIT_TIME)) { // some callers are willing to get wrong answers but not block
|
||||||
|
node = _nodeHash.value(nodeUUID);
|
||||||
|
_nodeHashMutex.unlock();
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
SharedNodePointer NodeList::sendingNodeForPacket(const QByteArray& packet) {
|
SharedNodePointer NodeList::sendingNodeForPacket(const QByteArray& packet) {
|
||||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||||
|
@ -772,7 +791,7 @@ QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) {
|
||||||
return replyPacket;
|
return replyPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer& node) {
|
void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) {
|
||||||
|
|
||||||
// send the ping packet to the local and public sockets for this node
|
// send the ping packet to the local and public sockets for this node
|
||||||
QByteArray localPingPacket = constructPingPacket(PingType::Local);
|
QByteArray localPingPacket = constructPingPacket(PingType::Local);
|
||||||
|
@ -780,6 +799,11 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer&
|
||||||
|
|
||||||
QByteArray publicPingPacket = constructPingPacket(PingType::Public);
|
QByteArray publicPingPacket = constructPingPacket(PingType::Public);
|
||||||
writeDatagram(publicPingPacket, node, node->getPublicSocket());
|
writeDatagram(publicPingPacket, node, node->getPublicSocket());
|
||||||
|
|
||||||
|
if (!node->getSymmetricSocket().isNull()) {
|
||||||
|
QByteArray symmetricPingPacket = constructPingPacket(PingType::Symmetric);
|
||||||
|
writeDatagram(symmetricPingPacket, node, node->getSymmetricSocket());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||||
|
@ -850,7 +874,7 @@ void NodeList::pingInactiveNodes() {
|
||||||
foreach (const SharedNodePointer& node, getNodeHash()) {
|
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||||
if (!node->getActiveSocket()) {
|
if (!node->getActiveSocket()) {
|
||||||
// we don't have an active link to this node, ping it to set that up
|
// we don't have an active link to this node, ping it to set that up
|
||||||
pingPublicAndLocalSocketsForInactiveNode(node);
|
pingPunchForInactiveNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -869,6 +893,8 @@ void NodeList::activateSocketFromNodeCommunication(const QByteArray& packet, con
|
||||||
sendingNode->activateLocalSocket();
|
sendingNode->activateLocalSocket();
|
||||||
} else if (pingType == PingType::Public && !sendingNode->getActiveSocket()) {
|
} else if (pingType == PingType::Public && !sendingNode->getActiveSocket()) {
|
||||||
sendingNode->activatePublicSocket();
|
sendingNode->activatePublicSocket();
|
||||||
|
} else if (pingType == PingType::Symmetric && !sendingNode->getActiveSocket()) {
|
||||||
|
sendingNode->activateSymmetricSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace PingType {
|
||||||
const PingType_t Agnostic = 0;
|
const PingType_t Agnostic = 0;
|
||||||
const PingType_t Local = 1;
|
const PingType_t Local = 1;
|
||||||
const PingType_t Public = 2;
|
const PingType_t Public = 2;
|
||||||
|
const PingType_t Symmetric = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NodeList : public QObject {
|
class NodeList : public QObject {
|
||||||
|
@ -101,9 +102,9 @@ public:
|
||||||
|
|
||||||
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic);
|
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic);
|
||||||
QByteArray constructPingReplyPacket(const QByteArray& pingPacket);
|
QByteArray constructPingReplyPacket(const QByteArray& pingPacket);
|
||||||
void pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer& node);
|
void pingPunchForInactiveNode(const SharedNodePointer& node);
|
||||||
|
|
||||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID, bool blockingLock = true);
|
||||||
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
||||||
|
|
||||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType,
|
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||||
|
|
|
@ -20,18 +20,15 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedAssignment::deleteLater() {
|
|
||||||
// move the NodeList back to the QCoreApplication instance's thread
|
|
||||||
NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread());
|
|
||||||
QObject::deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThreadedAssignment::setFinished(bool isFinished) {
|
void ThreadedAssignment::setFinished(bool isFinished) {
|
||||||
_isFinished = isFinished;
|
_isFinished = isFinished;
|
||||||
|
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
aboutToFinish();
|
aboutToFinish();
|
||||||
emit finished();
|
emit finished();
|
||||||
|
|
||||||
|
// move the NodeList back to the QCoreApplication instance's thread
|
||||||
|
NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef __hifi__ThreadedAssignment__
|
#ifndef __hifi__ThreadedAssignment__
|
||||||
#define __hifi__ThreadedAssignment__
|
#define __hifi__ThreadedAssignment__
|
||||||
|
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
|
|
||||||
class ThreadedAssignment : public Assignment {
|
class ThreadedAssignment : public Assignment {
|
||||||
|
@ -22,7 +24,6 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
/// threaded run of assignment
|
/// threaded run of assignment
|
||||||
virtual void run() = 0;
|
virtual void run() = 0;
|
||||||
virtual void deleteLater();
|
|
||||||
virtual void readPendingDatagrams() = 0;
|
virtual void readPendingDatagrams() = 0;
|
||||||
virtual void sendStatsPacket();
|
virtual void sendStatsPacket();
|
||||||
|
|
||||||
|
@ -36,5 +37,6 @@ signals:
|
||||||
void finished();
|
void finished();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer;
|
||||||
|
|
||||||
#endif /* defined(__hifi__ThreadedAssignment__) */
|
#endif /* defined(__hifi__ThreadedAssignment__) */
|
||||||
|
|
|
@ -1594,7 +1594,7 @@ void QTimeSpan::setFromMonths(qreal months)
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(hasValidReference(), "setFromMonths", "Can not set interval from time unit month if there is no reference date.");
|
Q_ASSERT_X(hasValidReference(), "setFromMonths", "Can not set interval from time unit month if there is no reference date.");
|
||||||
|
|
||||||
int fullMonths = int(months);
|
int fullMonths = (int)months;
|
||||||
qreal fractionalMonth = months - fullMonths;
|
qreal fractionalMonth = months - fullMonths;
|
||||||
|
|
||||||
QDateTime endDate = d->reference;
|
QDateTime endDate = d->reference;
|
||||||
|
@ -1631,7 +1631,7 @@ void QTimeSpan::setFromYears(qreal years)
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(hasValidReference(), "setFromYears", "Can not set interval from time unit year if there is no reference date.");
|
Q_ASSERT_X(hasValidReference(), "setFromYears", "Can not set interval from time unit year if there is no reference date.");
|
||||||
|
|
||||||
int fullYears = int(years);
|
int fullYears = (int)years;
|
||||||
qreal fractionalYear = years - fullYears;
|
qreal fractionalYear = years - fullYears;
|
||||||
|
|
||||||
QDateTime endDate = d->reference;
|
QDateTime endDate = d->reference;
|
||||||
|
|
|
@ -192,7 +192,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
||||||
float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1);
|
float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1);
|
||||||
for (int i = 0; i < numberOfSteps; ++i) {
|
for (int i = 0; i < numberOfSteps; ++i) {
|
||||||
// translate sphereA into world-frame
|
// translate sphereA into world-frame
|
||||||
glm::vec3 localPosition = localStartPosition + (float(i) * delta) * yAxis;
|
glm::vec3 localPosition = localStartPosition + ((float)i * delta) * yAxis;
|
||||||
sphereA.setPosition(rotation * localPosition + translation);
|
sphereA.setPosition(rotation * localPosition + translation);
|
||||||
|
|
||||||
// sphereA agains capsuleB
|
// sphereA agains capsuleB
|
||||||
|
|
Loading…
Reference in a new issue