mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 02:03:57 +02:00
Merge upstream master into audio fixes.
This commit is contained in:
commit
f305b81655
56 changed files with 1029 additions and 568 deletions
4
BUILD.md
4
BUILD.md
|
@ -3,7 +3,7 @@ Dependencies
|
|||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.11
|
||||
* [Qt](http://qt-project.org/downloads) ~> 5.2.0
|
||||
* [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
|
||||
|
||||
#####Linux only
|
||||
|
@ -142,4 +142,4 @@ If you need to debug Interface, you can run interface from within Visual Studio
|
|||
####Debugging Interface
|
||||
* 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
|
||||
* 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".
|
||||
|
||||
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.
|
||||
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);
|
||||
|
||||
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
|
||||
QString scriptURLString("http://%1:8080/assignment/%2");
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <SharedUtil.h>
|
||||
|
||||
#include "AssignmentFactory.h"
|
||||
#include "AssignmentThread.h"
|
||||
|
||||
#include "AssignmentClient.h"
|
||||
|
||||
|
@ -28,7 +29,7 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
|||
|
||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv),
|
||||
_currentAssignment(NULL)
|
||||
_currentAssignment()
|
||||
{
|
||||
setOrganizationName("High Fidelity");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
|
@ -124,7 +125,7 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
||||
// construct the deployed assignment from the packet data
|
||||
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
|
||||
_currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket));
|
||||
|
||||
if (_currentAssignment) {
|
||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||
|
@ -137,14 +138,13 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
|
||||
|
||||
// start the deployed assignment
|
||||
QThread* workerThread = new QThread(this);
|
||||
AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this);
|
||||
|
||||
connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run()));
|
||||
|
||||
connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted()));
|
||||
connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit()));
|
||||
connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater()));
|
||||
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
||||
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
||||
connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit);
|
||||
connect(_currentAssignment.data(), &ThreadedAssignment::finished,
|
||||
this, &AssignmentClient::assignmentCompleted);
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
|
||||
_currentAssignment->moveToThread(workerThread);
|
||||
|
||||
|
@ -153,7 +153,7 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
|
||||
// let the assignment handle the incoming datagrams for its duration
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment,
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(),
|
||||
&ThreadedAssignment::readPendingDatagrams);
|
||||
|
||||
// Starts an event loop, and emits workerThread->started()
|
||||
|
@ -202,10 +202,12 @@ void AssignmentClient::assignmentCompleted() {
|
|||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
// 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);
|
||||
|
||||
_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
|
||||
nodeList->setOwnerType(NodeType::Unassigned);
|
||||
|
|
|
@ -24,7 +24,7 @@ private slots:
|
|||
void handleAuthenticationRequest();
|
||||
private:
|
||||
Assignment _requestAssignment;
|
||||
ThreadedAssignment* _currentAssignment;
|
||||
SharedAssignmentPointer _currentAssignment;
|
||||
};
|
||||
|
||||
#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) :
|
||||
_myServer(myServer),
|
||||
_node(node),
|
||||
_nodeUUID(node->getUUID()),
|
||||
_packetData(),
|
||||
_nodeMissingCount(0),
|
||||
_processLock(),
|
||||
_isShuttingDown(false)
|
||||
{
|
||||
|
@ -43,46 +44,68 @@ OctreeSendThread::~OctreeSendThread() {
|
|||
}
|
||||
qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client disconnected "
|
||||
"- ending sending thread [" << this << "]";
|
||||
_node.clear();
|
||||
OctreeServer::clientDisconnected();
|
||||
}
|
||||
|
||||
void OctreeSendThread::setIsShuttingDown() {
|
||||
QMutexLocker locker(&_processLock); // this will cause us to wait till the process loop is complete
|
||||
_isShuttingDown = true;
|
||||
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() {
|
||||
if (_isShuttingDown) {
|
||||
return false; // exit early if we're shutting down
|
||||
}
|
||||
|
||||
OctreeServer::didProcess(this);
|
||||
|
||||
float lockWaitElapsedUsec = OctreeServer::SKIP_TIME;
|
||||
quint64 lockWaitStart = usecTimestampNow();
|
||||
QMutexLocker locker(&_processLock);
|
||||
_processLock.lock();
|
||||
quint64 lockWaitEnd = usecTimestampNow();
|
||||
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
|
||||
OctreeServer::trackProcessWaitTime(lockWaitElapsedUsec);
|
||||
|
||||
if (_isShuttingDown) {
|
||||
return false; // exit early if we're shutting down
|
||||
}
|
||||
|
||||
quint64 start = usecTimestampNow();
|
||||
|
||||
// don't do any send processing until the initial load of the octree is complete...
|
||||
if (_myServer->isInitialLoadComplete()) {
|
||||
if (!_node.isNull()) {
|
||||
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(_node->getLinkedData());
|
||||
SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID, false);
|
||||
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
|
||||
if (nodeData && !nodeData->isShuttingDown()) {
|
||||
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
|
||||
if (isStillRunning()) {
|
||||
// dynamically sleep until we need to fire off the next set of octree elements
|
||||
|
|
|
@ -38,14 +38,15 @@ protected:
|
|||
virtual bool process();
|
||||
|
||||
private:
|
||||
SharedNodePointer _node;
|
||||
OctreeServer* _myServer;
|
||||
QUuid _nodeUUID;
|
||||
|
||||
int handlePacketSend(const SharedNodePointer& node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
|
||||
int packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged);
|
||||
|
||||
OctreePacketData _packetData;
|
||||
|
||||
int _nodeMissingCount;
|
||||
QMutex _processLock; // don't allow us to have our nodeData, or our thread to be deleted while we're processing
|
||||
bool _isShuttingDown;
|
||||
};
|
||||
|
|
|
@ -1160,7 +1160,6 @@ QString OctreeServer::getStatusLink() {
|
|||
}
|
||||
|
||||
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
|
||||
// send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the
|
||||
// the following features:
|
||||
|
@ -1241,59 +1240,78 @@ QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidPacketDistributor;
|
|||
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidHandlePacketSend;
|
||||
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidCallWriteDatagram;
|
||||
|
||||
QMutex OctreeServer::_threadsDidProcessMutex;
|
||||
QMutex OctreeServer::_threadsDidPacketDistributorMutex;
|
||||
QMutex OctreeServer::_threadsDidHandlePacketSendMutex;
|
||||
QMutex OctreeServer::_threadsDidCallWriteDatagramMutex;
|
||||
|
||||
|
||||
void OctreeServer::didProcess(OctreeSendThread* thread) {
|
||||
QMutexLocker locker(&_threadsDidProcessMutex);
|
||||
_threadsDidProcess[thread] = usecTimestampNow();
|
||||
}
|
||||
|
||||
void OctreeServer::didPacketDistributor(OctreeSendThread* thread) {
|
||||
QMutexLocker locker(&_threadsDidPacketDistributorMutex);
|
||||
_threadsDidPacketDistributor[thread] = usecTimestampNow();
|
||||
}
|
||||
|
||||
void OctreeServer::didHandlePacketSend(OctreeSendThread* thread) {
|
||||
QMutexLocker locker(&_threadsDidHandlePacketSendMutex);
|
||||
_threadsDidHandlePacketSend[thread] = usecTimestampNow();
|
||||
}
|
||||
|
||||
void OctreeServer::didCallWriteDatagram(OctreeSendThread* thread) {
|
||||
QMutexLocker locker(&_threadsDidCallWriteDatagramMutex);
|
||||
_threadsDidCallWriteDatagram[thread] = usecTimestampNow();
|
||||
}
|
||||
|
||||
|
||||
void OctreeServer::stopTrackingThread(OctreeSendThread* thread) {
|
||||
QMutexLocker lockerA(&_threadsDidProcessMutex);
|
||||
QMutexLocker lockerB(&_threadsDidPacketDistributorMutex);
|
||||
QMutexLocker lockerC(&_threadsDidHandlePacketSendMutex);
|
||||
QMutexLocker lockerD(&_threadsDidCallWriteDatagramMutex);
|
||||
|
||||
_threadsDidProcess.remove(thread);
|
||||
_threadsDidPacketDistributor.remove(thread);
|
||||
_threadsDidHandlePacketSend.remove(thread);
|
||||
_threadsDidCallWriteDatagram.remove(thread);
|
||||
}
|
||||
|
||||
int howManyThreadsDidSomething(QMap<OctreeSendThread*, quint64>& something, quint64 since) {
|
||||
if (since == 0) {
|
||||
return something.size();
|
||||
}
|
||||
int howManyThreadsDidSomething(QMutex& mutex, QMap<OctreeSendThread*, quint64>& something, quint64 since) {
|
||||
int count = 0;
|
||||
QMap<OctreeSendThread*, quint64>::const_iterator i = something.constBegin();
|
||||
while (i != something.constEnd()) {
|
||||
if (i.value() > since) {
|
||||
count++;
|
||||
if (mutex.tryLock()) {
|
||||
if (since == 0) {
|
||||
count = something.size();
|
||||
} else {
|
||||
QMap<OctreeSendThread*, quint64>::const_iterator i = something.constBegin();
|
||||
while (i != something.constEnd()) {
|
||||
if (i.value() > since) {
|
||||
count++;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
mutex.unlock();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int OctreeServer::howManyThreadsDidProcess(quint64 since) {
|
||||
return howManyThreadsDidSomething(_threadsDidProcess, since);
|
||||
return howManyThreadsDidSomething(_threadsDidProcessMutex, _threadsDidProcess, since);
|
||||
}
|
||||
|
||||
int OctreeServer::howManyThreadsDidPacketDistributor(quint64 since) {
|
||||
return howManyThreadsDidSomething(_threadsDidPacketDistributor, since);
|
||||
return howManyThreadsDidSomething(_threadsDidPacketDistributorMutex, _threadsDidPacketDistributor, since);
|
||||
}
|
||||
|
||||
int OctreeServer::howManyThreadsDidHandlePacketSend(quint64 since) {
|
||||
return howManyThreadsDidSomething(_threadsDidHandlePacketSend, since);
|
||||
return howManyThreadsDidSomething(_threadsDidHandlePacketSendMutex, _threadsDidHandlePacketSend, 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> _threadsDidCallWriteDatagram;
|
||||
|
||||
static QMutex _threadsDidProcessMutex;
|
||||
static QMutex _threadsDidPacketDistributorMutex;
|
||||
static QMutex _threadsDidHandlePacketSendMutex;
|
||||
static QMutex _threadsDidCallWriteDatagramMutex;
|
||||
};
|
||||
|
||||
#endif // __octree_server__OctreeServer__
|
||||
|
|
|
@ -23,10 +23,10 @@ function printVector(string, vector) {
|
|||
}
|
||||
|
||||
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_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 VOXEL_FPS = 60.0;
|
||||
|
@ -39,12 +39,16 @@ var isWaving = false;
|
|||
var waveFrequency = 0.0;
|
||||
var waveAmplitude = 0.0;
|
||||
|
||||
var X_MIN = 0.0;
|
||||
var X_MAX = 5.0;
|
||||
var Z_MIN = 0.0;
|
||||
var Z_MAX = 5.0;
|
||||
var X_MIN = 20.0;
|
||||
var X_MAX = 25.0;
|
||||
var Z_MIN = 20.0;
|
||||
var Z_MAX = 25.0;
|
||||
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_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 targetHeadPitch = 0.0;
|
||||
|
||||
var walkFrequency = 5.0;
|
||||
var walkAmplitude = 45.0;
|
||||
|
||||
var cumulativeTime = 0.0;
|
||||
|
||||
var sounds = [];
|
||||
|
@ -115,12 +122,30 @@ printVector("New bot, position = ", Avatar.position);
|
|||
function stopWaving() {
|
||||
isWaving = false;
|
||||
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) {
|
||||
|
||||
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))) {
|
||||
VoxelViewer.setPosition(Avatar.position);
|
||||
VoxelViewer.setOrientation(Avatar.orientation);
|
||||
|
@ -134,13 +159,18 @@ function updateBehavior(deltaTime) {
|
|||
|
||||
if (!isWaving && (Math.random() < CHANCE_OF_WAVING)) {
|
||||
isWaving = true;
|
||||
waveFrequency = 1.0 + Math.random() * 5.0;
|
||||
waveFrequency = 3.0 + Math.random() * 5.0;
|
||||
waveAmplitude = 5.0 + Math.random() * 60.0;
|
||||
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) {
|
||||
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) {
|
||||
playRandomSound();
|
||||
}
|
||||
|
@ -168,11 +198,13 @@ function updateBehavior(deltaTime) {
|
|||
targetPosition.y = Y_PELVIS;
|
||||
|
||||
isMoving = true;
|
||||
} else {
|
||||
} else if (isMoving) {
|
||||
keepWalking();
|
||||
Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE));
|
||||
Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE);
|
||||
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.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
|
|
|
@ -27,6 +27,9 @@ var BULLET_VELOCITY = 5.0;
|
|||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var LEFT_BUTTON_3 = 3;
|
||||
var RELOAD_INTERVAL = 9;
|
||||
|
||||
var showScore = false;
|
||||
|
||||
// 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");
|
||||
|
@ -38,6 +41,8 @@ var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazo
|
|||
var audioOptions = new AudioInjectionOptions();
|
||||
audioOptions.volume = 0.9;
|
||||
|
||||
var shotsFired = 0;
|
||||
|
||||
var shotTime = new Date();
|
||||
|
||||
// initialize our triggers
|
||||
|
@ -63,7 +68,8 @@ var reticle = Overlays.addOverlay("image", {
|
|||
alpha: 1
|
||||
});
|
||||
|
||||
var text = Overlays.addOverlay("text", {
|
||||
if (showScore) {
|
||||
var text = Overlays.addOverlay("text", {
|
||||
x: screenSize.x / 2 - 100,
|
||||
y: screenSize.y / 2 - 50,
|
||||
width: 150,
|
||||
|
@ -74,6 +80,8 @@ var text = Overlays.addOverlay("text", {
|
|||
leftMargin: 4,
|
||||
text: "Score: " + score
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function printVector(string, vector) {
|
||||
|
@ -94,6 +102,10 @@ function shootBullet(position, velocity) {
|
|||
// Play firing sounds
|
||||
audioOptions.position = position;
|
||||
Audio.playSound(fireSound, audioOptions);
|
||||
shotsFired++;
|
||||
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
}
|
||||
}
|
||||
|
||||
function shootTarget() {
|
||||
|
@ -147,12 +159,15 @@ function particleCollisionWithVoxel(particle, voxel, penetration) {
|
|||
Voxels.eraseVoxel(position.x, position.y, position.z, HOLE_SIZE);
|
||||
//audioOptions.position = position;
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(targetHitSound, audioOptions);
|
||||
Audio.playSound(impactSound, audioOptions);
|
||||
}
|
||||
|
||||
function particleCollisionWithParticle(particle1, particle2) {
|
||||
score++;
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
if (showScore) {
|
||||
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||
}
|
||||
|
||||
// Sort out which particle is which
|
||||
|
||||
// Record shot time
|
||||
|
@ -171,12 +186,12 @@ function keyPressEvent(event) {
|
|||
if (event.text == "t") {
|
||||
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||
Script.setTimeout(shootTarget, time);
|
||||
} if (event.text == ".") {
|
||||
shootFromMouse();
|
||||
}
|
||||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
|
||||
|
||||
// Check for mouseLook movement, update rotation
|
||||
// rotate body yaw for yaw received from mouse
|
||||
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
||||
|
@ -257,18 +272,21 @@ function mousePressEvent(event) {
|
|||
isMouseDown = true;
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
Audio.playSound(loadSound, audioOptions);
|
||||
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||
//Audio.playSound(loadSound, audioOptions);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
// position
|
||||
function shootFromMouse() {
|
||||
var DISTANCE_FROM_CAMERA = 2.0;
|
||||
var camera = Camera.getPosition();
|
||||
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||
var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
|
||||
shootBullet(newPosition, velocity);
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
// position
|
||||
isMouseDown = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -162,11 +162,11 @@ function flyWithHydra(deltaTime) {
|
|||
if (thrustMultiplier < MAX_THRUST_MULTIPLIER) {
|
||||
thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE);
|
||||
}
|
||||
var currentOrientation = MyAvatar.orientation;
|
||||
var headOrientation = MyAvatar.headOrientation;
|
||||
|
||||
var front = Quat.getFront(currentOrientation);
|
||||
var right = Quat.getRight(currentOrientation);
|
||||
var up = Quat.getUp(currentOrientation);
|
||||
var front = Quat.getFront(headOrientation);
|
||||
var right = Quat.getRight(headOrientation);
|
||||
var up = Quat.getUp(headOrientation);
|
||||
|
||||
var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS *
|
||||
thrustJoystickPosition.y * thrustMultiplier * deltaTime);
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
<context>
|
||||
<name>Application</name>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="1380"/>
|
||||
<location filename="src/Application.cpp" line="1382"/>
|
||||
<source>Export Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="1381"/>
|
||||
<location filename="src/Application.cpp" line="1383"/>
|
||||
<source>Sparse Voxel Octree Files (*.svo)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="3608"/>
|
||||
<location filename="src/Application.cpp" line="3703"/>
|
||||
<source>Open Script</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="3609"/>
|
||||
<location filename="src/Application.cpp" line="3704"/>
|
||||
<source>JavaScript Files (*.js)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -27,25 +27,25 @@
|
|||
<context>
|
||||
<name>ChatWindow</name>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="20"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="143"/>
|
||||
<location filename="ui/chatWindow.ui" line="29"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="153"/>
|
||||
<source>Chat</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="50"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="144"/>
|
||||
<location filename="ui/chatWindow.ui" line="57"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="154"/>
|
||||
<source>Connecting to XMPP...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="71"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="145"/>
|
||||
<location filename="ui/chatWindow.ui" line="78"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="155"/>
|
||||
<source> online now:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="135"/>
|
||||
<source>day</source>
|
||||
<translation>
|
||||
<numerusform>%n day</numerusform>
|
||||
|
@ -53,7 +53,7 @@
|
|||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="135"/>
|
||||
<source>hour</source>
|
||||
<translation>
|
||||
<numerusform>%n hour</numerusform>
|
||||
|
@ -61,7 +61,7 @@
|
|||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="135"/>
|
||||
<source>minute</source>
|
||||
<translation>
|
||||
<numerusform>%n minute</numerusform>
|
||||
|
@ -76,7 +76,7 @@
|
|||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="183"/>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="191"/>
|
||||
<source>%1 online now:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -113,18 +113,18 @@
|
|||
<context>
|
||||
<name>Menu</name>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="459"/>
|
||||
<location filename="src/Menu.cpp" line="462"/>
|
||||
<source>Open .ini config file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="461"/>
|
||||
<location filename="src/Menu.cpp" line="473"/>
|
||||
<location filename="src/Menu.cpp" line="464"/>
|
||||
<location filename="src/Menu.cpp" line="476"/>
|
||||
<source>Text files (*.ini)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="471"/>
|
||||
<location filename="src/Menu.cpp" line="474"/>
|
||||
<source>Save .ini config file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
varying vec4 shadowColor;
|
||||
|
||||
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),
|
||||
shadow2D(shadowMap, gl_TexCoord[0].stp));
|
||||
gl_FragColor = mix(shadowColor, gl_Color, 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(),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_audioScope(256, 200, true),
|
||||
_trailingAudioLoudness(0.f),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_mouseX(0),
|
||||
_mouseY(0),
|
||||
|
@ -169,6 +170,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_bytesPerSecond(0),
|
||||
_recentMaxPackets(0),
|
||||
_resetRecentMaxPacketsSoon(true),
|
||||
_previousScriptLocation(),
|
||||
_logger(new FileLogger(this))
|
||||
{
|
||||
// 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
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) {
|
||||
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) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
|
||||
|
@ -1899,7 +1894,6 @@ void Application::update(float deltaTime) {
|
|||
updateMetavoxels(deltaTime); // update metavoxels
|
||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
updateAudio(deltaTime); // Update audio stats for procedural sounds
|
||||
updateCursor(deltaTime); // Handle cursor updates
|
||||
|
||||
_particles.update(); // update the particles...
|
||||
|
@ -2187,19 +2181,26 @@ void Application::updateShadowMap() {
|
|||
(_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
glm::vec3 points[] = {
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale)),
|
||||
inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale)) };
|
||||
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale),
|
||||
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale),
|
||||
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale),
|
||||
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) };
|
||||
glm::vec3 center;
|
||||
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
|
||||
minima = glm::min(minima, points[i]);
|
||||
maxima = glm::max(maxima, points[i]);
|
||||
center += 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
|
||||
minima.z -= _viewFrustum.getFarClip() * 0.5f;
|
||||
|
@ -2494,14 +2495,103 @@ void Application::displayOverlay() {
|
|||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Audio Scope
|
||||
const int AUDIO_SCOPE_Y_OFFSET = 135;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
_audio.renderMuteIcon(1, _glWidget->height() - 50);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
|
||||
int oscilloscopeTop = _glWidget->height() - 135;
|
||||
_audioScope.render(25, oscilloscopeTop);
|
||||
int oscilloscopeTop = _glWidget->height() - AUDIO_SCOPE_Y_OFFSET;
|
||||
_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)) {
|
||||
_myAvatar->renderHeadMouse();
|
||||
|
@ -3523,13 +3613,21 @@ void Application::reloadAllScripts() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::uploadFST() {
|
||||
FstReader reader;
|
||||
void Application::uploadFST(bool isHead) {
|
||||
FstReader reader(isHead);
|
||||
if (reader.zip()) {
|
||||
reader.send();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::uploadHead() {
|
||||
uploadFST(true);
|
||||
}
|
||||
|
||||
void Application::uploadSkeleton() {
|
||||
uploadFST(false);
|
||||
}
|
||||
|
||||
void Application::removeScriptName(const QString& fileNameString) {
|
||||
_activeScripts.removeOne(fileNameString);
|
||||
}
|
||||
|
@ -3601,12 +3699,20 @@ void Application::loadScript(const QString& scriptName) {
|
|||
}
|
||||
|
||||
void Application::loadDialog() {
|
||||
// shut down and stop any existing script
|
||||
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
QString suggestedName = desktopLocation.append("/script.js");
|
||||
QString suggestedName;
|
||||
|
||||
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,
|
||||
tr("JavaScript Files (*.js)"));
|
||||
if (!fileNameString.isEmpty()) {
|
||||
_previousScriptLocation = fileNameString;
|
||||
}
|
||||
|
||||
loadScript(fileNameString);
|
||||
}
|
||||
|
|
|
@ -261,7 +261,9 @@ public slots:
|
|||
void stopAllScripts();
|
||||
void reloadAllScripts();
|
||||
|
||||
void uploadFST();
|
||||
void uploadFST(bool isHead);
|
||||
void uploadHead();
|
||||
void uploadSkeleton();
|
||||
|
||||
private slots:
|
||||
void timer();
|
||||
|
@ -312,7 +314,6 @@ private:
|
|||
void updateMetavoxels(float deltaTime);
|
||||
void updateCamera(float deltaTime);
|
||||
void updateDialogs(float deltaTime);
|
||||
void updateAudio(float deltaTime);
|
||||
void updateCursor(float deltaTime);
|
||||
|
||||
Avatar* findLookatTargetAvatar(glm::vec3& eyePosition, QUuid &nodeUUID);
|
||||
|
@ -397,6 +398,7 @@ private:
|
|||
quint64 _lastQueriedTime;
|
||||
|
||||
Oscilloscope _audioScope;
|
||||
float _trailingAudioLoudness;
|
||||
|
||||
OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server
|
||||
|
||||
|
@ -483,6 +485,8 @@ private:
|
|||
ControllerScriptingInterface _controllerScriptingInterface;
|
||||
QPointer<LogDialog> _logDialog;
|
||||
|
||||
QString _previousScriptLocation;
|
||||
|
||||
FileLogger* _logger;
|
||||
|
||||
void checkVersion();
|
||||
|
|
|
@ -60,15 +60,16 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
|
|||
_measuredJitter(0),
|
||||
_jitterBufferSamples(initialJitterBufferSamples),
|
||||
_lastInputLoudness(0),
|
||||
_timeSinceLastClip(-1.0),
|
||||
_dcOffset(0),
|
||||
_noiseGateMeasuredFloor(0),
|
||||
_noiseGateSampleCounter(0),
|
||||
_noiseGateOpen(false),
|
||||
_noiseGateEnabled(true),
|
||||
_toneInjectionEnabled(false),
|
||||
_noiseGateFramesToClose(0),
|
||||
_lastVelocity(0),
|
||||
_lastAcceleration(0),
|
||||
_totalPacketsReceived(0),
|
||||
_totalInputAudioSamples(0),
|
||||
_collisionSoundMagnitude(0.0f),
|
||||
_collisionSoundFrequency(0.0f),
|
||||
_collisionSoundNoise(0.0f),
|
||||
|
@ -393,7 +394,7 @@ void Audio::handleAudioInput() {
|
|||
inputSamplesRequired,
|
||||
NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL,
|
||||
_inputFormat, _desiredInputFormat);
|
||||
|
||||
|
||||
//
|
||||
// Impose Noise Gate
|
||||
//
|
||||
|
@ -422,13 +423,24 @@ void Audio::handleAudioInput() {
|
|||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
||||
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
||||
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;
|
||||
|
||||
// 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++) {
|
||||
measuredDcOffset += monoAudioSamples[i];
|
||||
monoAudioSamples[i] -= (int16_t) _dcOffset;
|
||||
thisSample = fabsf(monoAudioSamples[i]);
|
||||
if (thisSample > (32767.f * CLIPPING_THRESHOLD)) {
|
||||
_timeSinceLastClip = 0.0f;
|
||||
}
|
||||
loudness += thisSample;
|
||||
// Noise Reduction: Count peaks above the average loudness
|
||||
if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) {
|
||||
|
@ -483,6 +495,16 @@ void Audio::handleAudioInput() {
|
|||
_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
|
||||
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
|
||||
|
@ -504,7 +526,7 @@ void Audio::handleAudioInput() {
|
|||
if (audioMixer && audioMixer->getActiveSocket()) {
|
||||
MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar();
|
||||
glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition();
|
||||
glm::quat headOrientation = interfaceAvatar->getHead()->getTweakedOrientation();
|
||||
glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientation();
|
||||
|
||||
// we need the amount of bytes in the buffer + 1 for type
|
||||
// + 12 for 3 floats for position + float for bearing + 1 attenuation byte
|
||||
|
@ -692,6 +714,10 @@ void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) {
|
|||
}
|
||||
}
|
||||
|
||||
void Audio::toggleToneInjection() {
|
||||
_toneInjectionEnabled = !_toneInjectionEnabled;
|
||||
}
|
||||
|
||||
// Take a pointer to the acquired microphone input samples and add procedural sounds
|
||||
void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
||||
float sample;
|
||||
|
|
|
@ -47,13 +47,11 @@ public:
|
|||
Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent = 0);
|
||||
|
||||
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); }
|
||||
float getTimeSinceLastClip() const { return _timeSinceLastClip; }
|
||||
float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
|
||||
|
||||
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; }
|
||||
int getJitterBufferSamples() { return _jitterBufferSamples; }
|
||||
|
||||
|
@ -83,6 +81,7 @@ public slots:
|
|||
void reset();
|
||||
void toggleMute();
|
||||
void toggleAudioNoiseReduction();
|
||||
void toggleToneInjection();
|
||||
|
||||
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
|
||||
|
||||
|
@ -130,16 +129,17 @@ private:
|
|||
float _measuredJitter;
|
||||
int16_t _jitterBufferSamples;
|
||||
float _lastInputLoudness;
|
||||
float _timeSinceLastClip;
|
||||
float _dcOffset;
|
||||
float _noiseGateMeasuredFloor;
|
||||
float* _noiseSampleFrames;
|
||||
int _noiseGateSampleCounter;
|
||||
bool _noiseGateOpen;
|
||||
bool _noiseGateEnabled;
|
||||
bool _toneInjectionEnabled;
|
||||
int _noiseGateFramesToClose;
|
||||
glm::vec3 _lastVelocity;
|
||||
glm::vec3 _lastAcceleration;
|
||||
int _totalPacketsReceived;
|
||||
int _totalInputAudioSamples;
|
||||
|
||||
float _collisionSoundMagnitude;
|
||||
float _collisionSoundFrequency;
|
||||
|
|
|
@ -146,7 +146,8 @@ Menu::Menu() :
|
|||
SLOT(goTo()));
|
||||
|
||||
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");
|
||||
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings()));
|
||||
|
@ -241,7 +242,7 @@ Menu::Menu() :
|
|||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||
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);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails()));
|
||||
|
@ -360,6 +361,12 @@ Menu::Menu() :
|
|||
false,
|
||||
appInstance->getAudio(),
|
||||
SLOT(toggleMute()));
|
||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection,
|
||||
0,
|
||||
false,
|
||||
appInstance->getAudio(),
|
||||
SLOT(toggleToneInjection()));
|
||||
|
||||
|
||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_V,
|
||||
|
@ -393,8 +400,6 @@ void Menu::loadSettings(QSettings* settings) {
|
|||
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||
_maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS);
|
||||
_voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
|
||||
_avatarLODDistanceMultiplier = loadSetting(settings, "avatarLODDistanceMultiplier",
|
||||
DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
|
||||
_boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0);
|
||||
|
||||
settings->beginGroup("View Frustum Offset Camera");
|
||||
|
@ -434,7 +439,6 @@ void Menu::saveSettings(QSettings* settings) {
|
|||
settings->setValue("maxVoxels", _maxVoxels);
|
||||
settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond);
|
||||
settings->setValue("voxelSizeScale", _voxelSizeScale);
|
||||
settings->setValue("avatarLODDistanceMultiplier", _avatarLODDistanceMultiplier);
|
||||
settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust);
|
||||
settings->beginGroup("View Frustum Offset Camera");
|
||||
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
|
||||
|
@ -927,14 +931,17 @@ void Menu::goTo() {
|
|||
|
||||
int dialogReturn = gotoDialog.exec();
|
||||
if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) {
|
||||
LocationManager* manager = &LocationManager::getInstance();
|
||||
manager->goTo(gotoDialog.textValue());
|
||||
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
|
||||
goToUser(gotoDialog.textValue());
|
||||
}
|
||||
|
||||
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) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Both user and location exists with same name");
|
||||
|
@ -1102,13 +1109,28 @@ void Menu::showMetavoxelEditor() {
|
|||
}
|
||||
|
||||
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) {
|
||||
Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow());
|
||||
|
||||
} else {
|
||||
if (!_chatWindow->toggleViewAction()->isChecked()) {
|
||||
_chatWindow->toggleViewAction()->trigger();
|
||||
}
|
||||
mainWindow->addDockWidget(Qt::NoDockWidgetArea, _chatWindow = new ChatWindow());
|
||||
}
|
||||
if (!_chatWindow->toggleViewAction()->isChecked()) {
|
||||
int width = _chatWindow->width();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1203,7 +1225,10 @@ void Menu::autoAdjustLOD(float currentFPS) {
|
|||
if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) {
|
||||
// attempt to lower the detail in proportion to the fps difference
|
||||
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;
|
||||
}
|
||||
} else if (_fastFPSAverage.getAverage() > ADJUST_LOD_UP_FPS) {
|
||||
|
@ -1249,6 +1274,12 @@ void Menu::autoAdjustLOD(float currentFPS) {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::resetLODAdjust() {
|
||||
_fpsAverage.reset();
|
||||
_fastFPSAverage.reset();
|
||||
_lastAvatarDetailDrop = _lastAdjust = usecTimestampNow();
|
||||
}
|
||||
|
||||
void Menu::setVoxelSizeScale(float sizeScale) {
|
||||
_voxelSizeScale = sizeScale;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
// User Tweakable LOD Items
|
||||
QString getLODFeedbackText();
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
void resetLODAdjust();
|
||||
void setVoxelSizeScale(float sizeScale);
|
||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||
float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
|
||||
|
@ -121,6 +122,7 @@ public slots:
|
|||
void importSettings();
|
||||
void exportSettings();
|
||||
void goTo();
|
||||
void goToUser(const QString& user);
|
||||
void pasteToVoxel();
|
||||
|
||||
void toggleLoginMenuItem();
|
||||
|
@ -240,6 +242,7 @@ namespace MenuOption {
|
|||
const QString FilterSixense = "Smooth Sixense Movement";
|
||||
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
||||
const QString AudioNoiseReduction = "Audio Noise Reduction";
|
||||
const QString AudioToneInjection = "Inject Test Tone";
|
||||
const QString EchoServerAudio = "Echo Server Audio";
|
||||
const QString EchoLocalAudio = "Echo Local Audio";
|
||||
const QString MuteAudio = "Mute Microphone";
|
||||
|
@ -299,7 +302,8 @@ namespace MenuOption {
|
|||
const QString StopAllScripts = "Stop All Scripts";
|
||||
const QString TestPing = "Test Ping";
|
||||
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 Quit = "Quit";
|
||||
const QString Voxels = "Voxels";
|
||||
|
|
|
@ -246,7 +246,8 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
|
||||
const float DISPLAYNAME_DISTANCE = 10.0f;
|
||||
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;
|
||||
}
|
||||
renderDisplayName();
|
||||
|
@ -312,9 +313,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
|||
void Avatar::renderBody(RenderMode renderMode) {
|
||||
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
|
||||
// render the billboard until both models are loaded
|
||||
if (renderMode != SHADOW_RENDER_MODE) {
|
||||
renderBillboard();
|
||||
}
|
||||
renderBillboard();
|
||||
return;
|
||||
}
|
||||
_skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE);
|
||||
|
@ -762,25 +761,6 @@ bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Avatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) {
|
||||
// compute lean angles
|
||||
glm::vec3 leverAxis = contactPoint - getPosition();
|
||||
float leverLength = glm::length(leverAxis);
|
||||
if (leverLength > EPSILON) {
|
||||
glm::quat bodyRotation = getOrientation();
|
||||
glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f);
|
||||
glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f);
|
||||
|
||||
leverAxis = leverAxis / leverLength;
|
||||
glm::vec3 effectivePenetration = penetration - glm::dot(penetration, leverAxis) * leverAxis;
|
||||
// we use the small-angle approximation for sine below to compute the length of
|
||||
// the opposite side of a narrow right triangle
|
||||
float sideways = - glm::dot(effectivePenetration, xAxis) / leverLength;
|
||||
float forward = glm::dot(effectivePenetration, zAxis) / leverLength;
|
||||
getHead()->addLean(sideways, forward);
|
||||
}
|
||||
}
|
||||
|
||||
float Avatar::getBoundingRadius() const {
|
||||
// TODO: also use head model when computing the avatar's bounding radius
|
||||
return _skeletonModel.getBoundingRadius();
|
||||
|
|
|
@ -145,7 +145,7 @@ public:
|
|||
/// \return true if we expect the avatar would move as a result of the collision
|
||||
bool collisionWouldMoveAvatar(CollisionInfo& collision) const;
|
||||
|
||||
void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration);
|
||||
virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { }
|
||||
|
||||
/// \return bounding radius of avatar
|
||||
virtual float getBoundingRadius() const;
|
||||
|
|
|
@ -50,9 +50,9 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
|||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2]))
|
||||
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1]))
|
||||
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0]))
|
||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2]))
|
||||
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1]))
|
||||
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0]))
|
||||
* joint.rotation;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ
|
|||
// likewise with the eye joints
|
||||
glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getTweakedOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||
_owningHead->getSaccade() - _translation, 1.0f));
|
||||
glm::quat between = rotationBetween(front, lookAt);
|
||||
|
|
|
@ -156,7 +156,8 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
|
|||
//palm.addToPenetration(averagePenetration);
|
||||
} else {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,9 +36,11 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_leftEyeBlinkVelocity(0.0f),
|
||||
_rightEyeBlinkVelocity(0.0f),
|
||||
_timeWithoutTalking(0.0f),
|
||||
_pitchTweak(0.f),
|
||||
_yawTweak(0.f),
|
||||
_rollTweak(0.f),
|
||||
_deltaPitch(0.f),
|
||||
_deltaYaw(0.f),
|
||||
_deltaRoll(0.f),
|
||||
_deltaLeanSideways(0.f),
|
||||
_deltaLeanForward(0.f),
|
||||
_isCameraMoving(false),
|
||||
_faceModel(this)
|
||||
{
|
||||
|
@ -50,13 +52,12 @@ void Head::init() {
|
|||
}
|
||||
|
||||
void Head::reset() {
|
||||
_yaw = _pitch = _roll = 0.0f;
|
||||
_baseYaw = _basePitch = _baseRoll = 0.0f;
|
||||
_leanForward = _leanSideways = 0.0f;
|
||||
_faceModel.reset();
|
||||
}
|
||||
|
||||
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||
|
||||
// Update audio trailing average for rendering facial animations
|
||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||
Visage* visage = Application::getInstance()->getVisage();
|
||||
|
@ -165,6 +166,19 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
|||
_eyePosition = calculateAverageEyePosition();
|
||||
}
|
||||
|
||||
void Head::relaxLean(float deltaTime) {
|
||||
// restore rotation, lean to neutral positions
|
||||
const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds
|
||||
float relaxationFactor = 1.f - glm::min(deltaTime / LEAN_RELAXATION_PERIOD, 1.f);
|
||||
_deltaYaw *= relaxationFactor;
|
||||
_deltaPitch *= relaxationFactor;
|
||||
_deltaRoll *= relaxationFactor;
|
||||
_leanSideways *= relaxationFactor;
|
||||
_leanForward *= relaxationFactor;
|
||||
_deltaLeanSideways *= relaxationFactor;
|
||||
_deltaLeanForward *= relaxationFactor;
|
||||
}
|
||||
|
||||
void Head::render(float alpha, bool forShadowMap) {
|
||||
if (_faceModel.render(alpha, forShadowMap) && _renderLookatVectors) {
|
||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
||||
|
@ -178,14 +192,14 @@ void Head::setScale (float scale) {
|
|||
_scale = scale;
|
||||
}
|
||||
|
||||
glm::quat Head::getTweakedOrientation() const {
|
||||
glm::quat Head::getFinalOrientation() const {
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(
|
||||
glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() )));
|
||||
}
|
||||
|
||||
glm::quat Head::getCameraOrientation () const {
|
||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
|
||||
return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f)));
|
||||
return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.f, 0.0f)));
|
||||
}
|
||||
|
||||
glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
|
||||
|
@ -197,16 +211,21 @@ glm::vec3 Head::getScalePivot() const {
|
|||
return _faceModel.isActive() ? _faceModel.getTranslation() : _position;
|
||||
}
|
||||
|
||||
float Head::getTweakedYaw() const {
|
||||
return glm::clamp(_yaw + _yawTweak, MIN_HEAD_YAW, MAX_HEAD_YAW);
|
||||
float Head::getFinalYaw() const {
|
||||
return glm::clamp(_baseYaw + _deltaYaw, MIN_HEAD_YAW, MAX_HEAD_YAW);
|
||||
}
|
||||
|
||||
float Head::getTweakedPitch() const {
|
||||
return glm::clamp(_pitch + _pitchTweak, MIN_HEAD_PITCH, MAX_HEAD_PITCH);
|
||||
float Head::getFinalPitch() const {
|
||||
return glm::clamp(_basePitch + _deltaPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH);
|
||||
}
|
||||
|
||||
float Head::getTweakedRoll() const {
|
||||
return glm::clamp(_roll + _rollTweak, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
|
||||
float Head::getFinalRoll() const {
|
||||
return glm::clamp(_baseRoll + _deltaRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
|
||||
}
|
||||
|
||||
void Head::addLeanDeltas(float sideways, float forward) {
|
||||
_deltaLeanSideways += sideways;
|
||||
_deltaLeanForward += forward;
|
||||
}
|
||||
|
||||
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
|
||||
|
|
|
@ -44,9 +44,15 @@ public:
|
|||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; }
|
||||
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; }
|
||||
void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; }
|
||||
void setLeanForward(float leanForward) { _leanForward = leanForward; }
|
||||
|
||||
glm::quat getTweakedOrientation() const;
|
||||
/// \return orientationBody * orientationBase+Delta
|
||||
glm::quat getFinalOrientation() const;
|
||||
|
||||
/// \return orientationBody * orientationBasePitch
|
||||
glm::quat getCameraOrientation () const;
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||
|
||||
|
@ -57,6 +63,10 @@ public:
|
|||
glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
|
||||
glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; }
|
||||
glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
||||
float getLeanSideways() const { return _leanSideways; }
|
||||
float getLeanForward() const { return _leanForward; }
|
||||
float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; }
|
||||
float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; }
|
||||
|
||||
glm::quat getEyeRotation(const glm::vec3& eyePosition) const;
|
||||
|
||||
|
@ -67,21 +77,24 @@ public:
|
|||
float getAverageLoudness() const { return _averageLoudness; }
|
||||
glm::vec3 calculateAverageEyePosition() { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; }
|
||||
|
||||
/// Returns the point about which scaling occurs.
|
||||
/// \return the point about which scaling occurs.
|
||||
glm::vec3 getScalePivot() const;
|
||||
|
||||
void setPitchTweak(float pitch) { _pitchTweak = pitch; }
|
||||
float getPitchTweak() const { return _pitchTweak; }
|
||||
void setDeltaPitch(float pitch) { _deltaPitch = pitch; }
|
||||
float getDeltaPitch() const { return _deltaPitch; }
|
||||
|
||||
void setYawTweak(float yaw) { _yawTweak = yaw; }
|
||||
float getYawTweak() const { return _yawTweak; }
|
||||
void setDeltaYaw(float yaw) { _deltaYaw = yaw; }
|
||||
float getDeltaYaw() const { return _deltaYaw; }
|
||||
|
||||
void setRollTweak(float roll) { _rollTweak = roll; }
|
||||
float getRollTweak() const { return _rollTweak; }
|
||||
void setDeltaRoll(float roll) { _deltaRoll = roll; }
|
||||
float getDeltaRoll() const { return _deltaRoll; }
|
||||
|
||||
virtual float getTweakedPitch() const;
|
||||
virtual float getTweakedYaw() const;
|
||||
virtual float getTweakedRoll() const;
|
||||
virtual float getFinalPitch() const;
|
||||
virtual float getFinalYaw() const;
|
||||
virtual float getFinalRoll() const;
|
||||
|
||||
void relaxLean(float deltaTime);
|
||||
void addLeanDeltas(float sideways, float forward);
|
||||
|
||||
private:
|
||||
// disallow copies of the Head, copy of owning Avatar is disallowed too
|
||||
|
@ -106,10 +119,14 @@ private:
|
|||
float _rightEyeBlinkVelocity;
|
||||
float _timeWithoutTalking;
|
||||
|
||||
// tweaked angles affect the rendered head, but not the camera
|
||||
float _pitchTweak;
|
||||
float _yawTweak;
|
||||
float _rollTweak;
|
||||
// delta angles for local head rotation (driven by hardware input)
|
||||
float _deltaPitch;
|
||||
float _deltaYaw;
|
||||
float _deltaRoll;
|
||||
|
||||
// delta lean angles for lean perturbations (driven by collisions)
|
||||
float _deltaLeanSideways;
|
||||
float _deltaLeanForward;
|
||||
|
||||
bool _isCameraMoving;
|
||||
FaceModel _faceModel;
|
||||
|
|
|
@ -94,7 +94,13 @@ void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) {
|
|||
}
|
||||
|
||||
void MyAvatar::update(float deltaTime) {
|
||||
Head* head = getHead();
|
||||
head->relaxLean(deltaTime);
|
||||
updateFromGyros(deltaTime);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) {
|
||||
// Faceshift drive is enabled, set the avatar drive based on the head position
|
||||
moveWithLean();
|
||||
}
|
||||
|
||||
// Update head mouse from faceshift if active
|
||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||
|
@ -112,15 +118,14 @@ void MyAvatar::update(float deltaTime) {
|
|||
//_headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height());
|
||||
}
|
||||
|
||||
Head* head = getHead();
|
||||
if (OculusManager::isConnected()) {
|
||||
float yaw, pitch, roll; // these angles will be in radians
|
||||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
|
||||
// but these euler angles are stored in degrees
|
||||
head->setYaw(yaw * DEGREES_PER_RADIAN);
|
||||
head->setPitch(pitch * DEGREES_PER_RADIAN);
|
||||
head->setRoll(roll * DEGREES_PER_RADIAN);
|
||||
head->setBaseYaw(yaw * DEGREES_PER_RADIAN);
|
||||
head->setBasePitch(pitch * DEGREES_PER_RADIAN);
|
||||
head->setBaseRoll(roll * DEGREES_PER_RADIAN);
|
||||
}
|
||||
|
||||
// Get audio loudness data from audio input device
|
||||
|
@ -230,7 +235,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
if (!Application::getInstance()->getFaceshift()->isActive() && OculusManager::isConnected() &&
|
||||
fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD &&
|
||||
fabs(getHead()->getYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) {
|
||||
fabs(getHead()->getBaseYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) {
|
||||
|
||||
// if we're wearing the oculus
|
||||
// and this acceleration is above the pull threshold
|
||||
|
@ -240,7 +245,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
_bodyYaw = getAbsoluteHeadYaw();
|
||||
|
||||
// set the head yaw to zero for this draw
|
||||
getHead()->setYaw(0);
|
||||
getHead()->setBaseYaw(0);
|
||||
|
||||
// correct the oculus yaw offset
|
||||
OculusManager::updateYawOffset();
|
||||
|
@ -361,26 +366,16 @@ void MyAvatar::updateFromGyros(float deltaTime) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// restore rotation, lean to neutral positions
|
||||
const float RESTORE_PERIOD = 0.25f; // seconds
|
||||
float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f);
|
||||
head->setPitchTweak(glm::mix(head->getPitchTweak(), 0.0f, restorePercentage));
|
||||
head->setYawTweak(glm::mix(head->getYawTweak(), 0.0f, restorePercentage));
|
||||
head->setRollTweak(glm::mix(head->getRollTweak(), 0.0f, restorePercentage));
|
||||
head->setLeanSideways(glm::mix(head->getLeanSideways(), 0.0f, restorePercentage));
|
||||
head->setLeanForward(glm::mix(head->getLeanForward(), 0.0f, restorePercentage));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the rotation of the avatar's head (as seen by others, not affecting view frustum)
|
||||
// to be scaled. Pitch is greater to emphasize nodding behavior / synchrony.
|
||||
const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f;
|
||||
head->setPitchTweak(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
head->setYawTweak(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
head->setRollTweak(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
head->setDeltaPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
head->setDeltaYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
head->setDeltaRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = 0.5f;
|
||||
|
@ -390,13 +385,11 @@ void MyAvatar::updateFromGyros(float deltaTime) {
|
|||
-MAX_LEAN, MAX_LEAN));
|
||||
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),
|
||||
-MAX_LEAN, MAX_LEAN));
|
||||
}
|
||||
|
||||
// if Faceshift drive is enabled, set the avatar drive based on the head position
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) {
|
||||
return;
|
||||
}
|
||||
|
||||
void MyAvatar::moveWithLean() {
|
||||
// Move with Lean by applying thrust proportional to leaning
|
||||
Head* head = getHead();
|
||||
glm::quat orientation = head->getCameraOrientation();
|
||||
glm::vec3 front = orientation * IDENTITY_FRONT;
|
||||
glm::vec3 right = orientation * IDENTITY_RIGHT;
|
||||
|
@ -506,7 +499,7 @@ void MyAvatar::saveData(QSettings* settings) {
|
|||
settings->setValue("bodyPitch", _bodyPitch);
|
||||
settings->setValue("bodyRoll", _bodyRoll);
|
||||
|
||||
settings->setValue("headPitch", getHead()->getPitch());
|
||||
settings->setValue("headPitch", getHead()->getBasePitch());
|
||||
|
||||
settings->setValue("position_x", _position.x);
|
||||
settings->setValue("position_y", _position.y);
|
||||
|
@ -532,7 +525,7 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
_bodyPitch = loadSetting(settings, "bodyPitch", 0.0f);
|
||||
_bodyRoll = loadSetting(settings, "bodyRoll", 0.0f);
|
||||
|
||||
getHead()->setPitch(loadSetting(settings, "headPitch", 0.0f));
|
||||
getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f));
|
||||
|
||||
_position.x = loadSetting(settings, "position_x", 0.0f);
|
||||
_position.y = loadSetting(settings, "position_y", 0.0f);
|
||||
|
@ -575,9 +568,9 @@ void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) {
|
|||
setOrientation(orientation);
|
||||
|
||||
// then vertically
|
||||
float oldPitch = getHead()->getPitch();
|
||||
getHead()->setPitch(oldPitch - deltaY * ANGULAR_SCALE);
|
||||
rotation = glm::angleAxis(glm::radians((getHead()->getPitch() - oldPitch)), orientation * IDENTITY_RIGHT);
|
||||
float oldPitch = getHead()->getBasePitch();
|
||||
getHead()->setBasePitch(oldPitch - deltaY * ANGULAR_SCALE);
|
||||
rotation = glm::angleAxis(glm::radians((getHead()->getBasePitch() - oldPitch)), orientation * IDENTITY_RIGHT);
|
||||
|
||||
setPosition(position + rotation * (getPosition() - position));
|
||||
}
|
||||
|
@ -683,7 +676,7 @@ void MyAvatar::updateThrust(float deltaTime) {
|
|||
_thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up;
|
||||
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
|
||||
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime;
|
||||
getHead()->setPitch(getHead()->getPitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
|
||||
getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime);
|
||||
|
||||
// If thrust keys are being held down, slowly increase thrust to allow reaching great speeds
|
||||
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
||||
|
@ -1153,3 +1146,21 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
void MyAvatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) {
|
||||
glm::vec3 leverAxis = contactPoint - getPosition();
|
||||
float leverLength = glm::length(leverAxis);
|
||||
if (leverLength > EPSILON) {
|
||||
// compute lean perturbation angles
|
||||
glm::quat bodyRotation = getOrientation();
|
||||
glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f);
|
||||
glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f);
|
||||
|
||||
leverAxis = leverAxis / leverLength;
|
||||
glm::vec3 effectivePenetration = penetration - glm::dot(penetration, leverAxis) * leverAxis;
|
||||
// use the small-angle approximation for sine
|
||||
float sideways = - glm::dot(effectivePenetration, xAxis) / leverLength;
|
||||
float forward = glm::dot(effectivePenetration, zAxis) / leverLength;
|
||||
getHead()->addLeanDeltas(sideways, forward);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
void update(float deltaTime);
|
||||
void simulate(float deltaTime);
|
||||
void updateFromGyros(float deltaTime);
|
||||
void moveWithLean();
|
||||
|
||||
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE);
|
||||
void renderBody(RenderMode renderMode);
|
||||
|
@ -87,6 +88,9 @@ public:
|
|||
virtual void clearJointData(int index);
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration);
|
||||
|
||||
public slots:
|
||||
void goHome();
|
||||
void increaseSize();
|
||||
|
|
|
@ -72,11 +72,15 @@ void SkeletonModel::getHandShapes(int jointIndex, QVector<const Shape*>& shapes)
|
|||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
for (int i = 0; i < _jointStates.size(); i++) {
|
||||
const FBXJoint& joint = geometry.joints[i];
|
||||
int parentIndex = joint.parentIndex;
|
||||
if (i == jointIndex) {
|
||||
// this shape is the hand
|
||||
shapes.push_back(_shapes[i]);
|
||||
if (parentIndex != -1) {
|
||||
// also add the forearm
|
||||
shapes.push_back(_shapes[parentIndex]);
|
||||
}
|
||||
} else {
|
||||
int parentIndex = joint.parentIndex;
|
||||
while (parentIndex != -1) {
|
||||
if (parentIndex == jointIndex) {
|
||||
// this shape is a child of the hand
|
||||
|
@ -146,7 +150,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
|
|||
direction += fingerVector / length;
|
||||
}
|
||||
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);
|
||||
}
|
||||
qSort(fingerIndices.begin(), fingerIndices.end());
|
||||
|
@ -199,8 +203,8 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const
|
|||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
|
||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanSideways(),
|
||||
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanForward(),
|
||||
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(),
|
||||
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(),
|
||||
glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
}
|
||||
|
||||
|
|
|
@ -1259,7 +1259,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
remainingModels.insert(model.key());
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1588,7 +1594,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
int numVertices = extracted.mesh.vertices.size();
|
||||
jointShapeInfo.numVertices = numVertices;
|
||||
if (numVertices > 0) {
|
||||
averageVertex /= float(jointShapeInfo.numVertices);
|
||||
averageVertex /= (float)jointShapeInfo.numVertices;
|
||||
float averageRadius = 0.f;
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
averageRadius += glm::distance(vertex, averageVertex);
|
||||
|
@ -1619,7 +1625,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
} else {
|
||||
// collide the joint like a sphere
|
||||
if (jointShapeInfo.numVertices > 0) {
|
||||
jointShapeInfo.averageVertex /= float(jointShapeInfo.numVertices);
|
||||
jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
|
||||
joint.shapePosition = jointShapeInfo.averageVertex;
|
||||
} else {
|
||||
joint.shapePosition = glm::vec3(0.f);
|
||||
|
@ -1629,7 +1635,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
&& jointShapeInfo.numVertices > 0) {
|
||||
// the bone projection algorithm was not able to compute the joint radius
|
||||
// so we use an alternative measure
|
||||
jointShapeInfo.averageRadius /= float(jointShapeInfo.numVertices);
|
||||
jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices;
|
||||
joint.boneRadius = jointShapeInfo.averageRadius;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,11 @@ void GeometryCache::renderHemisphere(int slices, int stacks) {
|
|||
GLfloat* vertexData = new GLfloat[vertices * 3];
|
||||
GLfloat* vertex = vertexData;
|
||||
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);
|
||||
|
||||
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++) = cosf(theta) * radius;
|
||||
|
@ -181,7 +181,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) {
|
|||
float y = (float)i / (stacks - 1);
|
||||
|
||||
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
|
||||
*(vertex++) = sinf(theta);
|
||||
|
|
|
@ -160,7 +160,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
|||
|
||||
// Center of coordinate system -> upper left of bar
|
||||
glPushMatrix();
|
||||
glTranslatef(float(barX), float(y), 0.0f);
|
||||
glTranslatef((float)barX, (float)y, 0.0f);
|
||||
|
||||
// Render captions
|
||||
setColorRGBA(COLOR_TEXT);
|
||||
|
@ -202,7 +202,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
|||
// Render scale indicators
|
||||
setColorRGBA(COLOR_INDICATOR);
|
||||
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
|
||||
|
@ -210,8 +210,8 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
|||
for (size_t i = 0; i < N_CHANNELS; ++i) {
|
||||
|
||||
ChannelIndex chIdx = ChannelIndex(i);
|
||||
int wIn = int(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||
int wOut = int(barWidth * outputStream(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);
|
||||
|
||||
setColorRGBA(channelInfo(chIdx).colorRGBA);
|
||||
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QFrame>
|
||||
#include <QLayoutItem>
|
||||
#include <QPalette>
|
||||
#include <QScrollBar>
|
||||
#include <QSizePolicy>
|
||||
#include <QTextDocument>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -31,17 +30,18 @@ ChatWindow::ChatWindow() :
|
|||
ui(new Ui::ChatWindow),
|
||||
numMessagesAfterLastTimeStamp(0)
|
||||
{
|
||||
QWidget* widget = new QWidget();
|
||||
setWidget(widget);
|
||||
|
||||
ui->setupUi(widget);
|
||||
ui->setupUi(this);
|
||||
|
||||
// remove the title bar (see the Qt docs on setTitleBarWidget)
|
||||
setTitleBarWidget(new QWidget());
|
||||
|
||||
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
||||
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
|
||||
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
|
||||
|
@ -76,41 +76,48 @@ ChatWindow::~ChatWindow() {
|
|||
}
|
||||
|
||||
void ChatWindow::keyPressEvent(QKeyEvent* event) {
|
||||
QWidget::keyPressEvent(event);
|
||||
QDockWidget::keyPressEvent(event);
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWindow::showEvent(QShowEvent* event) {
|
||||
QWidget::showEvent(event);
|
||||
QDockWidget::showEvent(event);
|
||||
if (!event->spontaneous()) {
|
||||
activateWindow();
|
||||
ui->messagePlainTextEdit->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
|
||||
Q_UNUSED(sender);
|
||||
|
||||
if (event->type() != QEvent::KeyPress) {
|
||||
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();
|
||||
if (sender == ui->messagePlainTextEdit) {
|
||||
if (event->type() != QEvent::KeyPress) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -138,8 +145,9 @@ void ChatWindow::addTimeStamp() {
|
|||
timeLabel->setStyleSheet("color: palette(shadow);"
|
||||
"background-color: palette(highlight);"
|
||||
"padding: 4px;");
|
||||
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
timeLabel->setAlignment(Qt::AlignHCenter);
|
||||
ui->messagesFormLayout->addRow(timeLabel);
|
||||
ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2);
|
||||
numMessagesAfterLastTimeStamp = 0;
|
||||
}
|
||||
}
|
||||
|
@ -187,13 +195,21 @@ void ChatWindow::participantsChanged() {
|
|||
delete item;
|
||||
}
|
||||
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);"
|
||||
"border-radius: 5px;"
|
||||
"color: #267077;"
|
||||
"padding: 2px;"
|
||||
"padding-top: 3px;"
|
||||
"padding-right: 2px;"
|
||||
"padding-bottom: 2px;"
|
||||
"padding-left: 2px;"
|
||||
"border: 1px solid palette(shadow);"
|
||||
"font-weight: bold");
|
||||
userLabel->setProperty("user", participantName);
|
||||
userLabel->setCursor(Qt::PointingHandCursor);
|
||||
userLabel->installEventFilter(this);
|
||||
ui->usersWidget->layout()->addWidget(userLabel);
|
||||
}
|
||||
}
|
||||
|
@ -204,19 +220,25 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
|||
}
|
||||
|
||||
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->setAlignment(Qt::AlignTop);
|
||||
userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight);
|
||||
|
||||
QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>"));
|
||||
messageLabel->setWordWrap(true);
|
||||
messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
messageLabel->setOpenExternalLinks(true);
|
||||
messageLabel->setStyleSheet("padding: 2px; margin-right: 20px");
|
||||
messageLabel->setAlignment(Qt::AlignTop);
|
||||
messageLabel->setStyleSheet("padding-bottom: 2px; padding-left: 2px; padding-top: 2px; padding-right: 20px");
|
||||
messageLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
|
||||
ui->messagesFormLayout->addRow(userLabel, messageLabel);
|
||||
ui->messagesFormLayout->parentWidget()->updateGeometry();
|
||||
if (getParticipantName(message.from()) == AccountManager::getInstance().getUsername()) {
|
||||
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();
|
||||
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
|
||||
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
|
||||
int lowPassFixPt = -int(std::numeric_limits<short>::min()) * _lowPassCoeff;
|
||||
int lowPassFixPt = -(int)(std::numeric_limits<short>::min()) * _lowPassCoeff;
|
||||
unsigned downsample = _downsampleRatio;
|
||||
// keep half of the buffer for writing and ensure an even vertex count
|
||||
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* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch;
|
||||
int sample = 0, x = usedWidth;
|
||||
for (int i = int(usedSamples); --i >= 0 ;) {
|
||||
for (int i = (int)usedSamples; --i >= 0 ;) {
|
||||
if (inPtr == basePtr) {
|
||||
// handle boundary, reading the circular sample buffer
|
||||
inPtr = endPtr;
|
||||
|
|
|
@ -506,8 +506,10 @@ void VoxelSystem::initVoxelMemory() {
|
|||
_perlinModulateProgram.setUniformValue("permutationNormalTexture", 0);
|
||||
_perlinModulateProgram.release();
|
||||
|
||||
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath()
|
||||
+ "shaders/shadow_map.frag");
|
||||
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/shadow_map.vert");
|
||||
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/shadow_map.frag");
|
||||
_shadowMapProgram.link();
|
||||
|
||||
_shadowMapProgram.bind();
|
||||
|
@ -1471,10 +1473,6 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) {
|
|||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
_shadowMapProgram.bind();
|
||||
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_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)) {
|
||||
_shadowMapProgram.release();
|
||||
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) {
|
||||
_perlinModulateProgram.release();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ChatWindow</class>
|
||||
<widget class="QWidget" name="ChatWindow">
|
||||
<widget class="QDockWidget" name="ChatWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
|
@ -13,180 +13,188 @@
|
|||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>0</height>
|
||||
<height>238</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Chat</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="connectingToXMPPLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<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="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="allowedAreas">
|
||||
<set>Qt::NoDockWidgetArea</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Chat</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="connectingToXMPPLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<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">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Preferred" 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>
|
||||
<string notr="true">margin-top: 0px;</string>
|
||||
</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>
|
||||
</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>358</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<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">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>
|
||||
<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>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>messagePlainTextEdit</tabstop>
|
||||
|
|
|
@ -93,9 +93,9 @@ QByteArray AvatarData::toByteArray() {
|
|||
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale);
|
||||
|
||||
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedYaw());
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedPitch());
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedRoll());
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalYaw());
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalPitch());
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalRoll());
|
||||
|
||||
// Head lean X,Z (head lateral and fwd/back motion relative to torso)
|
||||
memcpy(destinationBuffer, &_headData->_leanSideways, sizeof(_headData->_leanSideways));
|
||||
|
@ -288,9 +288,9 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
|||
}
|
||||
return maxAvailableSize;
|
||||
}
|
||||
_headData->setYaw(headYaw);
|
||||
_headData->setPitch(headPitch);
|
||||
_headData->setRoll(headRoll);
|
||||
_headData->setBaseYaw(headYaw);
|
||||
_headData->setBasePitch(headPitch);
|
||||
_headData->setBaseRoll(headRoll);
|
||||
} // 6 bytes
|
||||
|
||||
// Head lean (relative to pelvis)
|
||||
|
|
|
@ -128,8 +128,8 @@ public:
|
|||
void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); }
|
||||
|
||||
// access to Head().set/getMousePitch (degrees)
|
||||
float getHeadPitch() const { return _headData->getPitch(); }
|
||||
void setHeadPitch(float value) { _headData->setPitch(value); };
|
||||
float getHeadPitch() const { return _headData->getBasePitch(); }
|
||||
void setHeadPitch(float value) { _headData->setBasePitch(value); };
|
||||
|
||||
// access to Head().set/getAverageLoudness
|
||||
float getAudioLoudness() const { return _headData->getAudioLoudness(); }
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#include "HeadData.h"
|
||||
|
||||
HeadData::HeadData(AvatarData* owningAvatar) :
|
||||
_yaw(0.0f),
|
||||
_pitch(0.0f),
|
||||
_roll(0.0f),
|
||||
_baseYaw(0.0f),
|
||||
_basePitch(0.0f),
|
||||
_baseRoll(0.0f),
|
||||
_leanSideways(0.0f),
|
||||
_leanForward(0.0f),
|
||||
_lookAtPosition(0.0f, 0.0f, 0.0f),
|
||||
|
@ -32,7 +32,7 @@ HeadData::HeadData(AvatarData* owningAvatar) :
|
|||
}
|
||||
|
||||
glm::quat HeadData::getOrientation() const {
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll)));
|
||||
return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, _baseYaw, _baseRoll)));
|
||||
}
|
||||
|
||||
void HeadData::setOrientation(const glm::quat& orientation) {
|
||||
|
@ -44,27 +44,20 @@ void HeadData::setOrientation(const glm::quat& orientation) {
|
|||
|
||||
// the rest goes to the head
|
||||
glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation));
|
||||
_pitch = eulers.x;
|
||||
_yaw = eulers.y;
|
||||
_roll = eulers.z;
|
||||
_basePitch = eulers.x;
|
||||
_baseYaw = eulers.y;
|
||||
_baseRoll = eulers.z;
|
||||
}
|
||||
|
||||
void HeadData::addYaw(float yaw) {
|
||||
setYaw(_yaw + yaw);
|
||||
setBaseYaw(_baseYaw + yaw);
|
||||
}
|
||||
|
||||
void HeadData::addPitch(float pitch) {
|
||||
setPitch(_pitch + pitch);
|
||||
setBasePitch(_basePitch + pitch);
|
||||
}
|
||||
|
||||
void HeadData::addRoll(float roll) {
|
||||
setRoll(_roll + roll);
|
||||
}
|
||||
|
||||
|
||||
void HeadData::addLean(float sideways, float forwards) {
|
||||
// Add lean as impulse
|
||||
_leanSideways += sideways;
|
||||
_leanForward += forwards;
|
||||
setBaseRoll(_baseRoll + roll);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,19 +32,15 @@ public:
|
|||
virtual ~HeadData() { };
|
||||
|
||||
// degrees
|
||||
float getLeanSideways() const { return _leanSideways; }
|
||||
void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; }
|
||||
float getLeanForward() const { return _leanForward; }
|
||||
void setLeanForward(float leanForward) { _leanForward = leanForward; }
|
||||
float getYaw() const { return _yaw; }
|
||||
void setYaw(float yaw) { _yaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); }
|
||||
float getPitch() const { return _pitch; }
|
||||
void setPitch(float pitch) { _pitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); }
|
||||
float getRoll() const { return _roll; }
|
||||
void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
|
||||
virtual float getTweakedYaw() const { return _yaw; }
|
||||
virtual float getTweakedPitch() const { return _pitch; }
|
||||
virtual float getTweakedRoll() const { return _roll; }
|
||||
float getBaseYaw() const { return _baseYaw; }
|
||||
void setBaseYaw(float yaw) { _baseYaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); }
|
||||
float getBasePitch() const { return _basePitch; }
|
||||
void setBasePitch(float pitch) { _basePitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); }
|
||||
float getBaseRoll() const { return _baseRoll; }
|
||||
void setBaseRoll(float roll) { _baseRoll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
|
||||
virtual float getFinalYaw() const { return _baseYaw; }
|
||||
virtual float getFinalPitch() const { return _basePitch; }
|
||||
virtual float getFinalRoll() const { return _baseRoll; }
|
||||
|
||||
glm::quat getOrientation() const;
|
||||
void setOrientation(const glm::quat& orientation);
|
||||
|
@ -64,7 +60,6 @@ public:
|
|||
void addYaw(float yaw);
|
||||
void addPitch(float pitch);
|
||||
void addRoll(float roll);
|
||||
void addLean(float sideways, float forwards);
|
||||
|
||||
const glm::vec3& getLookAtPosition() const { return _lookAtPosition; }
|
||||
void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; }
|
||||
|
@ -73,9 +68,9 @@ public:
|
|||
|
||||
protected:
|
||||
// degrees
|
||||
float _yaw;
|
||||
float _pitch;
|
||||
float _roll;
|
||||
float _baseYaw;
|
||||
float _basePitch;
|
||||
float _baseRoll;
|
||||
float _leanSideways;
|
||||
float _leanForward;
|
||||
|
||||
|
|
|
@ -1096,7 +1096,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
|
|||
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
|
||||
MetavoxelInfo info = {
|
||||
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() };
|
||||
|
||||
// extract and convert the values provided by the script
|
||||
|
|
|
@ -144,14 +144,15 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
|
|||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
case QNetworkAccessManager::PutOperation:
|
||||
authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
if (dataMultiPart) {
|
||||
if (operation == QNetworkAccessManager::PostOperation) {
|
||||
networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart);
|
||||
} else {
|
||||
networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart);
|
||||
}
|
||||
dataMultiPart->setParent(networkReply);
|
||||
} else {
|
||||
authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
if (operation == QNetworkAccessManager::PostOperation) {
|
||||
networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray);
|
||||
} else {
|
||||
|
@ -199,6 +200,7 @@ void AccountManager::passSuccessToCallback() {
|
|||
qDebug() << jsonResponse;
|
||||
}
|
||||
}
|
||||
delete requestReply;
|
||||
}
|
||||
|
||||
void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode) {
|
||||
|
@ -219,6 +221,7 @@ void AccountManager::passErrorToCallback(QNetworkReply::NetworkError errorCode)
|
|||
qDebug() << "Error" << errorCode << "-" << requestReply->errorString();
|
||||
}
|
||||
}
|
||||
delete requestReply;
|
||||
}
|
||||
|
||||
bool AccountManager::hasValidAccessToken() {
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
#include <QFileDialog>
|
||||
#include <QStandardPaths>
|
||||
#include <QHttpMultiPart>
|
||||
#include <QTemporaryDir>
|
||||
#include <QVariant>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "AccountManager.h"
|
||||
|
||||
#include "FstReader.h"
|
||||
|
||||
|
||||
|
@ -25,20 +25,30 @@ static const QString NAME_FIELD = "name";
|
|||
static const QString FILENAME_FIELD = "filename";
|
||||
static const QString TEXDIR_FIELD = "texdir";
|
||||
static const QString LOD_FIELD = "lod";
|
||||
static const QString HEAD_SPECIFIC_FIELD = "bs";
|
||||
|
||||
static const QString MODEL_URL = "/api/v1/models";
|
||||
|
||||
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),
|
||||
_texturesCount(-1),
|
||||
_totalSize(0),
|
||||
_isHead(false),
|
||||
_isHead(isHead),
|
||||
_readyToSend(false),
|
||||
_dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType))
|
||||
{
|
||||
_zipDir->setParent(_dataMultiPart);
|
||||
|
||||
}
|
||||
|
||||
FstReader::~FstReader() {
|
||||
|
@ -63,20 +73,20 @@ bool FstReader::zip() {
|
|||
QString("ModelUploader::zip()"),
|
||||
QString("Could not open FST file."),
|
||||
QMessageBox::Ok);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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"))) {
|
||||
qDebug() << "[Warning] " << QString("Could not open FST file.");
|
||||
return false;
|
||||
}
|
||||
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
|
||||
QTextStream stream(&fst);
|
||||
QList<QString> line;
|
||||
|
@ -86,73 +96,63 @@ bool FstReader::zip() {
|
|||
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
|
||||
if (line[1] == HEAD_SPECIFIC_FIELD) {
|
||||
_isHead = true;
|
||||
} else if (line[1] == NAME_FIELD) {
|
||||
if (line[0] == NAME_FIELD) {
|
||||
QHttpPart textPart;
|
||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
||||
" name=\"model_name\"");
|
||||
textPart.setBody(line[1].toUtf8());
|
||||
_dataMultiPart->append(textPart);
|
||||
} else if (line[1] == FILENAME_FIELD) {
|
||||
} else if (line[0] == FILENAME_FIELD) {
|
||||
QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]);
|
||||
if (!fbx.exists() || !fbx.isFile()) { // Check existence
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("FBX file %1 could not be found.").arg(fbx.fileName()),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(fbx.fileName());
|
||||
return false;
|
||||
}
|
||||
// Compress and copy
|
||||
if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) {
|
||||
if (!compressFile(fbx.filePath(), _zipDir->path() + "/" + line[1])) {
|
||||
return false;
|
||||
}
|
||||
_totalSize += fbx.size();
|
||||
if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) {
|
||||
if (!addPart(_zipDir->path() + "/" + line[1], "fbx")) {
|
||||
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]);
|
||||
if (!texdir.exists() || !texdir.isDir()) {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("Texture directory could not be found."),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Texture directory could not be found.");
|
||||
return false;
|
||||
}
|
||||
if (!addTextures(texdir)) { // Recursive compress and copy
|
||||
return false;
|
||||
}
|
||||
} else if (line[1] == LOD_FIELD) {
|
||||
} else if (line[0] == LOD_FIELD) {
|
||||
QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]);
|
||||
if (!lod.exists() || !lod.isFile()) { // Check existence
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::zip()"),
|
||||
QString("FBX file %1 could not be found.").arg(lod.fileName()),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("FBX file %1 could not be found.").arg(lod.fileName());
|
||||
return false;
|
||||
}
|
||||
// Compress and copy
|
||||
if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) {
|
||||
if (!compressFile(lod.filePath(), _zipDir->path() + "/" + line[1])) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QHttpPart textPart;
|
||||
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;"
|
||||
" name=\"model_category\"");
|
||||
|
@ -173,6 +173,9 @@ bool FstReader::send() {
|
|||
}
|
||||
|
||||
AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart);
|
||||
_zipDir = NULL;
|
||||
_dataMultiPart = NULL;
|
||||
qDebug() << "Model sent.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -189,11 +192,10 @@ bool FstReader::addTextures(const QFileInfo& texdir) {
|
|||
foreach (QFileInfo info, list) {
|
||||
if (info.isFile()) {
|
||||
// Compress and copy
|
||||
if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) {
|
||||
if (!compressFile(info.filePath(), _zipDir->path() + "/" + info.fileName())) {
|
||||
return false;
|
||||
}
|
||||
_totalSize += info.size();
|
||||
if (!addPart(_zipDir.path() + "/" + info.fileName(),
|
||||
if (!addPart(_zipDir->path() + "/" + info.fileName(),
|
||||
QString("texture%1").arg(++_texturesCount))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -214,12 +216,13 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa
|
|||
|
||||
QFile outFile(outFileName);
|
||||
if (!outFile.open(QIODevice::WriteOnly)) {
|
||||
QDir(_zipDir.path()).mkpath(QFileInfo(outFileName).path());
|
||||
QDir(_zipDir->path()).mkpath(QFileInfo(outFileName).path());
|
||||
if (!outFile.open(QIODevice::WriteOnly)) {
|
||||
QMessageBox::warning(NULL,
|
||||
QString("ModelUploader::compressFile()"),
|
||||
QString("Could not compress %1").arg(inFileName),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Could not compress %1").arg(inFileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -237,6 +240,8 @@ bool FstReader::addPart(const QString &path, const QString& name) {
|
|||
QString("ModelUploader::addPart()"),
|
||||
QString("Could not open %1").arg(path),
|
||||
QMessageBox::Ok);
|
||||
qDebug() << "[Warning] " << QString("Could not open %1").arg(path);
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -249,6 +254,19 @@ bool FstReader::addPart(const QString &path, const QString& name) {
|
|||
_dataMultiPart->append(part);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,20 +10,19 @@
|
|||
#ifndef __hifi__FstReader__
|
||||
#define __hifi__FstReader__
|
||||
|
||||
#include <QTemporaryDir>
|
||||
|
||||
class TemporaryDir;
|
||||
class QHttpMultiPart;
|
||||
|
||||
class FstReader {
|
||||
class FstReader : public QObject {
|
||||
public:
|
||||
FstReader();
|
||||
FstReader(bool isHead);
|
||||
~FstReader();
|
||||
|
||||
bool zip();
|
||||
bool send();
|
||||
|
||||
private:
|
||||
QTemporaryDir _zipDir;
|
||||
TemporaryDir* _zipDir;
|
||||
int _lodCount;
|
||||
int _texturesCount;
|
||||
int _totalSize;
|
||||
|
|
|
@ -51,6 +51,7 @@ Node::Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const
|
|||
_lastHeardMicrostamp(usecTimestampNow()),
|
||||
_publicSocket(publicSocket),
|
||||
_localSocket(localSocket),
|
||||
_symmetricSocket(),
|
||||
_activeSocket(NULL),
|
||||
_connectionSecret(),
|
||||
_bytesReceivedMovingAverage(NULL),
|
||||
|
@ -84,6 +85,15 @@ void Node::setLocalSocket(const HifiSockAddr& 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() {
|
||||
qDebug() << "Activating local socket for node" << *this;
|
||||
_activeSocket = &_localSocket;
|
||||
|
@ -94,6 +104,11 @@ void Node::activatePublicSocket() {
|
|||
_activeSocket = &_publicSocket;
|
||||
}
|
||||
|
||||
void Node::activateSymmetricSocket() {
|
||||
qDebug() << "Activating symmetric socket for node" << *this;
|
||||
_activeSocket = &_symmetricSocket;
|
||||
}
|
||||
|
||||
void Node::recordBytesReceived(int bytesReceived) {
|
||||
if (!_bytesReceivedMovingAverage) {
|
||||
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
|
||||
|
|
|
@ -70,11 +70,14 @@ public:
|
|||
void setPublicSocket(const HifiSockAddr& publicSocket);
|
||||
const HifiSockAddr& getLocalSocket() const { return _localSocket; }
|
||||
void setLocalSocket(const HifiSockAddr& localSocket);
|
||||
|
||||
const HifiSockAddr& getSymmetricSocket() const { return _symmetricSocket; }
|
||||
void setSymmetricSocket(const HifiSockAddr& symmetricSocket);
|
||||
|
||||
const HifiSockAddr* getActiveSocket() const { return _activeSocket; }
|
||||
|
||||
void activatePublicSocket();
|
||||
void activateLocalSocket();
|
||||
void activateSymmetricSocket();
|
||||
|
||||
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
||||
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
||||
|
@ -110,6 +113,7 @@ private:
|
|||
quint64 _lastHeardMicrostamp;
|
||||
HifiSockAddr _publicSocket;
|
||||
HifiSockAddr _localSocket;
|
||||
HifiSockAddr _symmetricSocket;
|
||||
HifiSockAddr* _activeSocket;
|
||||
QUuid _connectionSecret;
|
||||
SimpleMovingAverage* _bytesReceivedMovingAverage;
|
||||
|
|
|
@ -294,6 +294,15 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
|
|||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
QByteArray replyPacket = constructPingReplyPacket(packet);
|
||||
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;
|
||||
|
@ -357,10 +366,20 @@ int NodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||
QMutexLocker locker(&_nodeHashMutex);
|
||||
return _nodeHash.value(nodeUUID);
|
||||
}
|
||||
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID, bool blockingLock) {
|
||||
const int WAIT_TIME = 10; // wait up to 10ms in the try lock case
|
||||
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) {
|
||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||
|
@ -772,7 +791,7 @@ QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) {
|
|||
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
|
||||
QByteArray localPingPacket = constructPingPacket(PingType::Local);
|
||||
|
@ -780,6 +799,11 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer&
|
|||
|
||||
QByteArray publicPingPacket = constructPingPacket(PingType::Public);
|
||||
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,
|
||||
|
@ -850,7 +874,7 @@ void NodeList::pingInactiveNodes() {
|
|||
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||
if (!node->getActiveSocket()) {
|
||||
// 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();
|
||||
} else if (pingType == PingType::Public && !sendingNode->getActiveSocket()) {
|
||||
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 Local = 1;
|
||||
const PingType_t Public = 2;
|
||||
const PingType_t Symmetric = 3;
|
||||
}
|
||||
|
||||
class NodeList : public QObject {
|
||||
|
@ -101,9 +102,9 @@ public:
|
|||
|
||||
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic);
|
||||
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 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) {
|
||||
_isFinished = isFinished;
|
||||
|
||||
if (_isFinished) {
|
||||
aboutToFinish();
|
||||
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__
|
||||
#define __hifi__ThreadedAssignment__
|
||||
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include "Assignment.h"
|
||||
|
||||
class ThreadedAssignment : public Assignment {
|
||||
|
@ -22,7 +24,6 @@ public:
|
|||
public slots:
|
||||
/// threaded run of assignment
|
||||
virtual void run() = 0;
|
||||
virtual void deleteLater();
|
||||
virtual void readPendingDatagrams() = 0;
|
||||
virtual void sendStatsPacket();
|
||||
|
||||
|
@ -36,5 +37,6 @@ signals:
|
|||
void finished();
|
||||
};
|
||||
|
||||
typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer;
|
||||
|
||||
#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.");
|
||||
|
||||
int fullMonths = int(months);
|
||||
int fullMonths = (int)months;
|
||||
qreal fractionalMonth = months - fullMonths;
|
||||
|
||||
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.");
|
||||
|
||||
int fullYears = int(years);
|
||||
int fullYears = (int)years;
|
||||
qreal fractionalYear = years - fullYears;
|
||||
|
||||
QDateTime endDate = d->reference;
|
||||
|
|
|
@ -192,7 +192,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
|||
float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1);
|
||||
for (int i = 0; i < numberOfSteps; ++i) {
|
||||
// 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 agains capsuleB
|
||||
|
|
Loading…
Reference in a new issue