resolve conflicts on merge with upstream master

This commit is contained in:
Stephen Birarda 2015-01-19 10:26:52 -08:00
commit 10be0ee984
234 changed files with 6056 additions and 5687 deletions

View file

@ -9,8 +9,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies
Currently building on Windows has been tested using the following compilers:
* Visual Studio 2013
(If anyone can test using Visual Studio 2013 Express then please update this document)
* Visual Studio 2013 Express
####Visual Studio 2013

View file

@ -38,22 +38,19 @@ elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-strict-aliasing")
endif(WIN32)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if (NOT MSVC12)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if (COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
if (COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
endif ()
if (APPLE)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")

View file

@ -51,7 +51,7 @@ Agent::Agent(const QByteArray& packet) :
void Agent::readPendingDatagrams() {
QByteArray receivedPacket;
HifiSockAddr senderSockAddr;
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
@ -103,7 +103,7 @@ void Agent::readPendingDatagrams() {
// TODO: this needs to be fixed, the goal is to test the packet version for the piggyback, but
// this is testing the version and hash of the original packet
// need to use numBytesArithmeticCodingFromBuffer()...
if (!NodeList::getInstance()->packetVersionAndHashMatch(receivedPacket)) {
if (!DependencyManager::get<NodeList>()->packetVersionAndHashMatch(receivedPacket)) {
return; // bail since piggyback data doesn't match our versioning
}
} else {
@ -127,7 +127,7 @@ void Agent::readPendingDatagrams() {
// let this continue through to the NodeList so it updates last heard timestamp
// for the sending audio mixer
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
} else if (datagramPacketType == PacketTypeBulkAvatarData
|| datagramPacketType == PacketTypeAvatarIdentity
|| datagramPacketType == PacketTypeAvatarBillboard
@ -137,9 +137,9 @@ void Agent::readPendingDatagrams() {
// let this continue through to the NodeList so it updates last heard timestamp
// for the sending avatar-mixer
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
} else {
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
}
}
}
@ -150,7 +150,7 @@ const QString AGENT_LOGGING_NAME = "agent";
void Agent::run() {
ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet()
<< NodeType::AudioMixer
<< NodeType::AvatarMixer
@ -161,7 +161,7 @@ void Agent::run() {
QUrl scriptURL;
if (_payload.isEmpty()) {
scriptURL = QUrl(QString("http://%1:%2/assignment/%3")
.arg(NodeList::getInstance()->getDomainHandler().getIP().toString())
.arg(DependencyManager::get<NodeList>()->getDomainHandler().getIP().toString())
.arg(DOMAIN_SERVER_HTTP_PORT)
.arg(uuidStringWithoutCurlyBraces(_uuid)));
} else {

View file

@ -15,6 +15,7 @@
#include <QtCore/QTimer>
#include <AccountManager.h>
#include <AddressManager.h>
#include <Assignment.h>
#include <HifiConfigVariantMap.h>
#include <LogHandler.h>
@ -48,7 +49,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
setOrganizationDomain("highfidelity.io");
setApplicationName("assignment-client");
QSettings::setDefaultFormat(QSettings::IniFormat);
// create a NodeList as an unassigned client
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
auto addressManager = DependencyManager::set<AddressManager>();
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
#ifdef _WIN32
installNativeEventFilter(&ShutdownEventListener::getInstance());
@ -91,9 +97,6 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
_requestAssignment.setWalletUUID(walletUUID);
}
// create a NodeList as an unassigned client
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
@ -136,7 +139,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
void AssignmentClient::sendAssignmentRequest() {
if (!_currentAssignment) {
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
if (_assignmentServerHostname == "localhost") {
// we want to check again for the local domain-server port in case the DS has restarted
@ -173,7 +176,7 @@ void AssignmentClient::sendAssignmentRequest() {
}
void AssignmentClient::readPendingDatagrams() {
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
QByteArray receivedPacket;
HifiSockAddr senderSockAddr;
@ -260,7 +263,7 @@ void AssignmentClient::assignmentCompleted() {
qDebug("Assignment finished or never started - waiting for new assignment.");
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
// have us handle incoming NodeList datagrams again
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0);

View file

@ -442,7 +442,7 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
// loop through all other nodes that have sufficient audio to mix
int streamsMixed = 0;
NodeList::getInstance()->eachNode([&](const SharedNodePointer& otherNode){
DependencyManager::get<NodeList>()->eachNode([&](const SharedNodePointer& otherNode){
if (otherNode->getLinkedData()) {
AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData();
@ -522,12 +522,12 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) {
memcpy(envDataAt, &wetLevel, sizeof(float));
envDataAt += sizeof(float);
}
NodeList::getInstance()->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node);
DependencyManager::get<NodeList>()->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node);
}
}
void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
// pull any new audio data from nodes off of the network stack
@ -608,7 +608,7 @@ void AudioMixer::sendStatsPacket() {
somethingToSend = true;
sizeOfStats += property.size() + value.size();
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
int clientNumber = 0;
@ -641,7 +641,7 @@ void AudioMixer::run() {
ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer);
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
@ -894,7 +894,7 @@ void AudioMixer::perSecondActions() {
_timeSpentPerHashMatchCallStats.getWindowSum() / WINDOW_LENGTH_USECS * 100.0,
_timeSpentPerHashMatchCallStats.getCurrentIntervalSum() / USECS_PER_SECOND * 100.0);
NodeList::getInstance()->eachNode([](const SharedNodePointer& node) {
DependencyManager::get<NodeList>()->eachNode([](const SharedNodePointer& node) {
if (node->getLinkedData()) {
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();

View file

@ -147,7 +147,7 @@ void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer&
removeDeadInjectedStreams();
char packet[MAX_PACKET_SIZE];
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
// The append flag is a boolean value that will be packed right after the header. The first packet sent
// inside this method will have 0 for this flag, while every subsequent packet will have 1 for this flag.

View file

@ -41,7 +41,7 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) :
_sumIdentityPackets(0)
{
// make sure we hear about node kills so we can tell the other nodes
connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
}
AvatarMixer::~AvatarMixer() {
@ -117,7 +117,7 @@ void AvatarMixer::broadcastAvatarData() {
int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData);
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
AvatarMixerClientData* nodeData = NULL;
AvatarMixerClientData* otherNodeData = NULL;
@ -222,7 +222,7 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar);
killPacket += killedNode->getUUID().toRfc4122();
NodeList::getInstance()->broadcastToNodes(killPacket,
DependencyManager::get<NodeList>()->broadcastToNodes(killPacket,
NodeSet() << NodeType::Agent);
}
}
@ -231,7 +231,7 @@ void AvatarMixer::readPendingDatagrams() {
QByteArray receivedPacket;
HifiSockAddr senderSockAddr;
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
@ -309,7 +309,7 @@ void AvatarMixer::sendStatsPacket() {
void AvatarMixer::run() {
ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer);
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;

View file

@ -76,7 +76,7 @@ void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePo
copyAt += sizeof(entityID);
packetLength += sizeof(entityID);
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
DependencyManager::get<NodeList>()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
}
@ -114,7 +114,8 @@ int EntityServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNo
hasMoreToSend = tree->encodeEntitiesDeletedSince(queryNode->getSequenceNumber(), deletedEntitiesSentAt,
outputBuffer, MAX_PACKET_SIZE, packetLength);
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node));
DependencyManager::get<NodeList>()->writeDatagram((char*) outputBuffer, packetLength,
SharedNodePointer(node));
queryNode->packetSent(outputBuffer, packetLength);
packetsSent++;
}
@ -132,7 +133,7 @@ void EntityServer::pruneDeletedEntities() {
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
NodeList::getInstance()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
DependencyManager::get<NodeList>()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
if (node->getLinkedData()) {
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
quint64 nodeLastDeletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();

View file

@ -60,11 +60,11 @@ const QString METAVOXEL_SERVER_LOGGING_NAME = "metavoxel-server";
void MetavoxelServer::run() {
commonInit(METAVOXEL_SERVER_LOGGING_NAME, NodeType::MetavoxelServer);
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
connect(nodeList, &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
connect(nodeList, &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
connect(nodeList.data(), &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
connect(nodeList.data(), &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
// initialize Bitstream before using it in multiple threads
Bitstream::preThreadingInit();
@ -101,7 +101,7 @@ void MetavoxelServer::readPendingDatagrams() {
QByteArray receivedPacket;
HifiSockAddr senderSockAddr;
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {

View file

@ -261,7 +261,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
continue;
}
const SharedNodePointer& destinationNode = NodeList::getInstance()->nodeWithUUID(nodeUUID);
const SharedNodePointer& destinationNode = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
// retrieve sequence number stats of node, prune its missing set
SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats();
@ -299,7 +299,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
numSequenceNumbersAvailable -= numSequenceNumbers;
// send it
NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode);
DependencyManager::get<NodeList>()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode);
packetsSent++;
qDebug() << "NACK Sent back to editor/client... destinationNode=" << nodeUUID;

View file

@ -179,12 +179,12 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
// actually send it
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
DependencyManager::get<NodeList>()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
packetSent = true;
} else {
// not enough room in the packet, send two packets
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
DependencyManager::get<NodeList>()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
// since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since
// there was nothing else to send.
@ -213,7 +213,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
packetsSent++;
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
DependencyManager::get<NodeList>()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
packetSent = true;
thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();
@ -242,7 +242,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes
if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) {
// just send the octree packet
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
DependencyManager::get<NodeList>()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node);
packetSent = true;
int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();
@ -575,7 +575,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
while (nodeData->hasNextNackedPacket() && packetsSentThisInterval < maxPacketsPerInterval) {
const QByteArray* packet = nodeData->getNextNackedPacket();
if (packet) {
NodeList::getInstance()->writeDatagram(*packet, _node);
DependencyManager::get<NodeList>()->writeDatagram(*packet, _node);
truePacketsSent++;
packetsSentThisInterval++;

View file

@ -9,6 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
@ -829,7 +830,7 @@ void OctreeServer::parsePayload() {
}
void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
PacketType packetType = packetTypeForPacket(receivedPacket);
@ -865,13 +866,13 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
} else {
// let processNodeData handle it.
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
}
}
}
void OctreeServer::setupDatagramProcessingThread() {
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
@ -960,7 +961,7 @@ void OctreeServer::readConfiguration() {
}
// wait until we have the domain-server settings, otherwise we bail
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
DomainHandler& domainHandler = nodeList->getDomainHandler();
qDebug() << "Waiting for domain settings from domain-server.";
@ -978,6 +979,7 @@ void OctreeServer::readConfiguration() {
const QJsonObject& settingsObject = domainHandler.getSettingsObject();
QString settingsKey = getMyDomainSettingsKey();
QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
_settings = settingsSectionObject; // keep this for later
if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
_statusHost = getLocalAddress().toString();
@ -1042,20 +1044,8 @@ void OctreeServer::readConfiguration() {
_wantBackup = !noBackup;
qDebug() << "wantBackup=" << _wantBackup;
if (_wantBackup) {
_backupExtensionFormat = OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT;
readOptionString(QString("backupExtensionFormat"), settingsSectionObject, _backupExtensionFormat);
qDebug() << "backupExtensionFormat=" << _backupExtensionFormat;
_backupInterval = OctreePersistThread::DEFAULT_BACKUP_INTERVAL;
readOptionInt(QString("backupInterval"), settingsSectionObject, _backupInterval);
qDebug() << "backupInterval=" << _backupInterval;
_maxBackupVersions = OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS;
readOptionInt(QString("maxBackupVersions"), settingsSectionObject, _maxBackupVersions);
qDebug() << "maxBackupVersions=" << _maxBackupVersions;
}
//qDebug() << "settingsSectionObject:" << settingsSectionObject;
} else {
qDebug("persistFilename= DISABLED");
}
@ -1106,7 +1096,7 @@ void OctreeServer::run() {
_tree->setIsServer(true);
// make sure our NodeList knows what type we are
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
nodeList->setOwnerType(getMyNodeType());
@ -1120,8 +1110,8 @@ void OctreeServer::run() {
beforeRun(); // after payload has been processed
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
// we need to ask the DS about agents so we can ping/reply with them
@ -1140,8 +1130,7 @@ void OctreeServer::run() {
// now set up PersistThread
_persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval,
_wantBackup, _backupInterval, _backupExtensionFormat,
_maxBackupVersions, _debugTimestampNow);
_wantBackup, _settings, _debugTimestampNow);
if (_persistThread) {
_persistThread->initialize(true);
}
@ -1223,7 +1212,7 @@ void OctreeServer::aboutToFinish() {
qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down...";
_octreeInboundPacketProcessor->shuttingDown();
NodeList::getInstance()->eachNode([this](const SharedNodePointer& node) {
DependencyManager::get<NodeList>()->eachNode([this](const SharedNodePointer& node) {
qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
forceNodeShutdown(node);
});
@ -1388,7 +1377,7 @@ void OctreeServer::sendStatsPacket() {
statsObject2[baseName + QString(".2.outbound.timing.5.avgSendTime")] = getAveragePacketSendingTime();
statsObject2[baseName + QString(".2.outbound.timing.5.nodeWaitTime")] = getAverageNodeWaitTime();
NodeList::getInstance()->sendStatsToDomainServer(statsObject2);
DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject2);
static QJsonObject statsObject3;
@ -1407,7 +1396,7 @@ void OctreeServer::sendStatsPacket() {
statsObject3[baseName + QString(".3.inbound.timing.5.avgLockWaitTimePerElement")] =
(double)_octreeInboundPacketProcessor->getAverageLockWaitTimePerElement();
NodeList::getInstance()->sendStatsToDomainServer(statsObject3);
DependencyManager::get<NodeList>()->sendStatsToDomainServer(statsObject3);
}
QMap<OctreeSendThread*, quint64> OctreeServer::_threadsDidProcess;

View file

@ -150,6 +150,7 @@ protected:
int _argc;
const char** _argv;
char** _parsedArgV;
QJsonObject _settings;
HTTPManager* _httpManager;
int _statusPort;

View file

@ -45,7 +45,7 @@ void OctreeServerDatagramProcessor::readPendingDatagrams() {
PacketType packetType = packetTypeForPacket(incomingPacket);
if (packetType == PacketTypePing) {
NodeList::getInstance()->processNodeData(senderSockAddr, incomingPacket);
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, incomingPacket);
return; // don't emit
}

View file

@ -42,6 +42,11 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
set(GLPROFILE MAC_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
elseif (UNIX)
set(GLPROFILE LINUX_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
else (APPLE)
set(GLPROFILE PC_GL)

View file

@ -0,0 +1,33 @@
# Try to find the RSSDK library
#
# You must provide a RSSDK_ROOT_DIR which contains lib and include directories
#
# Once done this will define
#
# RSSDK_FOUND - system found RSSDK
# RSSDK_INCLUDE_DIRS - the RSSDK include directory
# RSSDK_LIBRARIES - Link this to use RSSDK
#
# Created on 12/7/2014 by Thijs Wenker
# Copyright (c) 2014 High Fidelity
#
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("rssdk")
find_path(RSSDK_INCLUDE_DIRS pxcbase.h PATH_SUFFIXES include HINTS ${RSSDK_SEARCH_DIRS})
if (WIN32)
find_library(RSSDK_LIBRARY_DEBUG libpxc_d PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS})
find_library(RSSDK_LIBRARY_RELEASE libpxc PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS})
endif ()
include(SelectLibraryConfigurations)
select_library_configurations(RSSDK)
set(RSSDK_LIBRARIES "${RSSDK_LIBRARY}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RSSDK DEFAULT_MSG RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES)
mark_as_advanced(RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES RSSDK_SEARCH_DIRS)

View file

@ -305,20 +305,66 @@
"settings": [
{
"name": "persistFilename",
"label": "Persistant Filename",
"help": "the filename for your entities",
"label": "Entities Filename",
"help": "the path to the file entities are stored in. Make sure the path exists.",
"placeholder": "resources/models.svo",
"default": "resources/models.svo",
"advanced": true
},
{
"name": "persistInterval",
"label": "Persist Interval",
"help": "Interval between persist checks in msecs.",
"label": "Save Check Interval",
"help": "Milliseconds between checks for saving the current state of entities.",
"placeholder": "30000",
"default": "30000",
"advanced": true
},
{
"name": "backups",
"type": "table",
"label": "Backup Rules",
"help": "In this table you can define a set of rules for how frequently to backup copies of your entites content file.",
"numbered": false,
"default": [
{"Name":"Half Hourly Rolling","backupInterval":1800,"format":".backup.halfhourly.%N","maxBackupVersions":5},
{"Name":"Daily Rolling","backupInterval":86400,"format":".backup.daily.%N","maxBackupVersions":7},
{"Name":"Weekly Rolling","backupInterval":604800,"format":".backup.weekly.%N","maxBackupVersions":4},
{"Name":"Thirty Day Rolling","backupInterval":2592000,"format":".backup.thirtyday.%N","maxBackupVersions":12}
],
"columns": [
{
"name": "Name",
"label": "Name",
"can_set": true,
"placeholder": "Example",
"default": "Example"
},
{
"name": "format",
"label": "Rule Format",
"can_set": true,
"help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
"placeholder": ".backup.example.%N",
"default": ".backup.example.%N"
},
{
"name": "backupInterval",
"label": "Backup Interval in Seconds",
"help": "Interval between backup checks in seconds.",
"placeholder": 1800,
"default": 1800,
"can_set": true
},
{
"name": "maxBackupVersions",
"label": "Max Rolled Backup Versions",
"help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
"placeholder": 5,
"default": 5,
"can_set": true
}
]
},
{
"name": "NoPersist",
"type": "checkbox",
@ -326,30 +372,6 @@
"default": false,
"advanced": true
},
{
"name": "backupExtensionFormat",
"label": "Backup File Extension Format:",
"help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
"placeholder": ".backup.%N",
"default": ".backup.%N",
"advanced": true
},
{
"name": "backupInterval",
"label": "Backup Interval",
"help": "Interval between backup checks in msecs.",
"placeholder": "1800000",
"default": "1800000",
"advanced": true
},
{
"name": "maxBackupVersions",
"label": "Max Rolled Backup Versions",
"help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
"placeholder": "5",
"default": "5",
"advanced": true
},
{
"name": "NoBackup",
"type": "checkbox",

View file

@ -667,7 +667,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
modal_body = "<p>Choose the High Fidelity domain you want this domain-server to represent.<br/>This will set your domain ID on the settings page.</p>"
domain_select = $("<select id='domain-name-select' class='form-control'></select>")
_.each(data.data.domains, function(domain){
domain_select.append("<option value='" + domain.id + "'>" + domain.name + "</option>")
domain_select.append("<option value='" + domain.id + "'>(" + domain.id + ")" + (domain.names.length > 0 ? " [" + domain.names + "]" : "") + "</option>");
})
modal_body += "<label for='domain-name-select'>Domains</label>" + domain_select[0].outerHTML
modal_buttons["success"] = {

View file

@ -237,7 +237,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
// check for scripts the user wants to persist from their domain-server config
populateStaticScriptedAssignmentsFromSettings();
LimitedNodeList* nodeList = LimitedNodeList::createInstance(domainServerPort, domainServerDTLSPort);
auto nodeList = DependencyManager::set<LimitedNodeList>(domainServerPort, domainServerDTLSPort);
// no matter the local port, save it to shared mem so that local assignment clients can ask what it is
QSharedMemory* sharedPortMem = new QSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, this);
@ -262,11 +262,11 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
nodeList->setSessionUUID(idValueVariant->toString());
}
connect(nodeList, &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
connect(nodeList, &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
QTimer* silentNodeTimer = new QTimer(this);
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
connect(silentNodeTimer, SIGNAL(timeout()), nodeList.data(), SLOT(removeSilentNodes()));
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readAvailableDatagrams()));
@ -346,8 +346,7 @@ bool DomainServer::optionallySetupAssignmentPayment() {
}
void DomainServer::setupAutomaticNetworking() {
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
auto nodeList = DependencyManager::get<LimitedNodeList>();
const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000;
const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000;
@ -368,8 +367,10 @@ void DomainServer::setupAutomaticNetworking() {
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
// call our sendHeartbeatToIceServer immediately anytime a local or public socket changes
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer);
connect(nodeList.data(), &LimitedNodeList::localSockAddrChanged,
this, &DomainServer::sendHeartbeatToIceServer);
connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged,
this, &DomainServer::sendHeartbeatToIceServer);
// attempt to update our public socket now, this will send a heartbeat once we get public socket
requestCurrentPublicSocketViaSTUN();
@ -400,7 +401,8 @@ void DomainServer::setupAutomaticNetworking() {
dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS);
// send public socket changes to the data server so nodes can find us at our new IP
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate);
connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged,
this, &DomainServer::performIPAddressUpdate);
// attempt to update our sockets now
requestCurrentPublicSocketViaSTUN();
@ -617,7 +619,7 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
QByteArray usernameRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied);
// send this oauth request datagram back to the client
LimitedNodeList::getInstance()->writeUnverifiedDatagram(usernameRequestByteArray, senderSockAddr);
DependencyManager::get<LimitedNodeList>()->writeUnverifiedDatagram(usernameRequestByteArray, senderSockAddr);
return;
}
@ -637,7 +639,7 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
}
SharedNodePointer newNode = LimitedNodeList::getInstance()->addOrUpdateNode(nodeUUID, nodeType,
SharedNodePointer newNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode(nodeUUID, nodeType,
publicSockAddr, localSockAddr);
// when the newNode is created the linked data is also created
// if this was a static assignment set the UUID, set the sendingSockAddr
@ -670,7 +672,7 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
// we always let in a user who is sending a packet from our local socket or from the localhost address
if (senderSockAddr.getAddress() == LimitedNodeList::getInstance()->getLocalSockAddr().getAddress()
if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|| senderSockAddr.getAddress() == QHostAddress::LocalHost) {
return true;
}
@ -843,8 +845,8 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
int numBroadcastPacketLeadBytes = broadcastDataStream.device()->pos();
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
auto nodeList = DependencyManager::get<LimitedNodeList>();
// if we've established a connection via ICE with this peer, use that socket
// otherwise just try to reply back to them on their sending socket (although that may not work)
@ -910,7 +912,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
}
void DomainServer::readAvailableDatagrams() {
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
auto nodeList = DependencyManager::get<LimitedNodeList>();
HifiSockAddr senderSockAddr;
QByteArray receivedPacket;
@ -998,7 +1000,7 @@ void DomainServer::readAvailableDatagrams() {
void DomainServer::setupPendingAssignmentCredits() {
// enumerate the NodeList to find the assigned nodes
NodeList::getInstance()->eachNode([&](const SharedNodePointer& node){
DependencyManager::get<LimitedNodeList>()->eachNode([&](const SharedNodePointer& node){
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
if (!nodeData->getAssignmentUUID().isNull() && !nodeData->getWalletUUID().isNull()) {
@ -1112,7 +1114,7 @@ void DomainServer::transactionJSONCallback(const QJsonObject& data) {
}
void DomainServer::requestCurrentPublicSocketViaSTUN() {
LimitedNodeList::getInstance()->sendSTUNRequest();
DependencyManager::get<LimitedNodeList>()->sendSTUNRequest();
}
QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) {
@ -1134,7 +1136,8 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr)
void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID();
auto nodeList = DependencyManager::get<LimitedNodeList>();
const QUuid& domainID = nodeList->getSessionUUID();
// setup the domain object to send to the data server
const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address";
@ -1158,7 +1161,7 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
// add the number of currently connected agent users
int numConnectedAuthedUsers = 0;
NodeList::getInstance()->eachNode([&numConnectedAuthedUsers](const SharedNodePointer& node){
nodeList->eachNode([&numConnectedAuthedUsers](const SharedNodePointer& node){
if (node->getLinkedData() && !static_cast<DomainServerNodeData*>(node->getLinkedData())->getUsername().isEmpty()) {
++numConnectedAuthedUsers;
}
@ -1187,11 +1190,11 @@ void DomainServer::performICEUpdates() {
}
void DomainServer::sendHeartbeatToIceServer() {
LimitedNodeList::getInstance()->sendHeartbeatToIceServer(_iceServerSocket);
DependencyManager::get<LimitedNodeList>()->sendHeartbeatToIceServer(_iceServerSocket);
}
void DomainServer::sendICEPingPackets() {
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
auto nodeList = DependencyManager::get<LimitedNodeList>();
QHash<QUuid, NetworkPeer>::iterator peer = _connectingICEPeers.begin();
@ -1259,7 +1262,7 @@ void DomainServer::processICEPingReply(const QByteArray& packet, const HifiSockA
}
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
LimitedNodeList* nodeList = LimitedNodeList::getInstance();
auto nodeList = DependencyManager::get<LimitedNodeList>();
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
PacketType requestType = packetTypeForPacket(receivedPacket);
@ -1410,6 +1413,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
auto nodeList = DependencyManager::get<LimitedNodeList>();
// allow sub-handlers to handle requests that do not require authentication
if (_settingsManager.handlePublicHTTPRequest(connection, url)) {
return true;
@ -1452,7 +1457,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
const QString URI_ID = "/id";
if (connection->requestOperation() == QNetworkAccessManager::GetOperation
&& url.path() == URI_ID) {
QUuid domainID = LimitedNodeList::getInstance()->getSessionUUID();
QUuid domainID = nodeList->getSessionUUID();
connection->respond(HTTPConnection::StatusCode200, uuidStringWithoutCurlyBraces(domainID).toLocal8Bit());
return true;
@ -1474,7 +1479,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
QJsonObject assignedNodesJSON;
// enumerate the NodeList to find the assigned nodes
NodeList::getInstance()->eachNode([this, &assignedNodesJSON](const SharedNodePointer& node){
nodeList->eachNode([this, &assignedNodesJSON](const SharedNodePointer& node){
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
if (!nodeData->getAssignmentUUID().isNull()) {
@ -1536,7 +1541,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
QJsonArray nodesJSONArray;
// enumerate the NodeList to find the assigned nodes
LimitedNodeList::getInstance()->eachNode([this, &nodesJSONArray](const SharedNodePointer& node){
nodeList->eachNode([this, &nodesJSONArray](const SharedNodePointer& node){
// add the node using the UUID as the key
nodesJSONArray.append(jsonObjectForNode(node));
});
@ -1559,7 +1564,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
QUuid matchingUUID = QUuid(nodeShowRegex.cap(1));
// see if we have a node that matches this ID
SharedNodePointer matchingNode = LimitedNodeList::getInstance()->nodeWithUUID(matchingUUID);
SharedNodePointer matchingNode = nodeList->nodeWithUUID(matchingUUID);
if (matchingNode) {
// create a QJsonDocument with the stats QJsonObject
QJsonObject statsObject =
@ -1653,14 +1658,14 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
// pull the captured string, if it exists
QUuid deleteUUID = QUuid(nodeDeleteRegex.cap(1));
SharedNodePointer nodeToKill = LimitedNodeList::getInstance()->nodeWithUUID(deleteUUID);
SharedNodePointer nodeToKill = nodeList->nodeWithUUID(deleteUUID);
if (nodeToKill) {
// start with a 200 response
connection->respond(HTTPConnection::StatusCode200);
// we have a valid UUID and node - kill the node that has this assignment
QMetaObject::invokeMethod(LimitedNodeList::getInstance(), "killNodeWithUUID", Q_ARG(const QUuid&, deleteUUID));
QMetaObject::invokeMethod(nodeList.data(), "killNodeWithUUID", Q_ARG(const QUuid&, deleteUUID));
// successfully processed request
return true;
@ -1669,7 +1674,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
return true;
} else if (allNodesDeleteRegex.indexIn(url.path()) != -1) {
qDebug() << "Received request to kill all nodes.";
LimitedNodeList::getInstance()->eraseAllNodes();
nodeList->eraseAllNodes();
return true;
}
@ -1989,7 +1994,7 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
// cleanup the connection secrets that we set up for this node (on the other nodes)
foreach (const QUuid& otherNodeSessionUUID, nodeData->getSessionSecretHash().keys()) {
SharedNodePointer otherNode = LimitedNodeList::getInstance()->nodeWithUUID(otherNodeSessionUUID);
SharedNodePointer otherNode = DependencyManager::get<LimitedNodeList>()->nodeWithUUID(otherNodeSessionUUID);
if (otherNode) {
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())->getSessionSecretHash().remove(node->getUUID());
}
@ -2072,7 +2077,7 @@ void DomainServer::addStaticAssignmentsToQueue() {
// add any of the un-matched static assignments to the queue
// enumerate the nodes and check if there is one with an attached assignment with matching UUID
if (!NodeList::getInstance()->nodeWithUUID(staticAssignment->data()->getUUID())) {
if (!DependencyManager::get<LimitedNodeList>()->nodeWithUUID(staticAssignment->data()->getUUID())) {
// this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
refreshStaticAssignmentAndAddToQueue(*staticAssignment);
}

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
// Set the following variables to the right value
var NUM_AC = 3; // This is the number of AC. Their ID need to be unique and between 0 (included) and NUM_AC (excluded)

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
// Set the following variables to the values needed
var filename = HIFI_PUBLIC_BUCKET + "ozan/bartender.rec";

View file

@ -20,7 +20,7 @@
//
//For procedural walk animation
Script.include("../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include(HIFI_PUBLIC_BUCKET + "scripts/proceduralAnimationAPI.js");
var procAnimAPI = new ProcAnimAPI();

View file

@ -11,7 +11,7 @@
//
//For procedural walk animation
Script.include("../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include("proceduralAnimationAPI.js");
var procAnimAPI = new ProcAnimAPI();

View file

@ -12,7 +12,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;

View file

@ -12,7 +12,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var clapAnimation = HIFI_PUBLIC_BUCKET + "animations/ClapAnimations/ClapHands_Standing.fbx";
var ANIMATION_FRAMES_PER_CLAP = 10.0;

View file

@ -10,7 +10,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
function length(v) {
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);

View file

@ -10,7 +10,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
function length(v) {
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);

View file

@ -15,7 +15,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include("../../libraries/toolBars.js");
const LEFT_PALM = 0;

View file

@ -14,7 +14,28 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var RED = { red: 255, green: 0, blue: 0 };
var LASER_WIDTH = 2;
var pointer = [];
pointer.push(Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: RED,
alpha: 1,
visible: true,
lineWidth: LASER_WIDTH
}));
pointer.push(Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: RED,
alpha: 1,
visible: true,
lineWidth: LASER_WIDTH
}));
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;
@ -32,8 +53,13 @@ var MAX_THROWER_DELAY = 1000;
var LEFT_BUTTON_3 = 3;
var RELOAD_INTERVAL = 5;
var KICKBACK_ANGLE = 15;
var elbowKickAngle = 0.0;
var rotationBeforeKickback;
var showScore = false;
// Load some sound to use for loading and firing
var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
@ -48,10 +74,11 @@ var audioOptions = {
}
var shotsFired = 0;
var shotTime = new Date();
// initialize our triggers
var activeControllers = 0;
// initialize our controller triggers
var triggerPulled = new Array();
var numberOfTriggers = Controller.getNumberOfTriggers();
for (t = 0; t < numberOfTriggers; t++) {
@ -59,9 +86,11 @@ for (t = 0; t < numberOfTriggers; t++) {
}
var isLaunchButtonPressed = false;
var score = 0;
var bulletID = false;
var targetID = false;
// Create a reticle image in center of screen
var screenSize = Controller.getViewportDimensions();
var reticle = Overlays.addOverlay("image", {
@ -74,6 +103,16 @@ var reticle = Overlays.addOverlay("image", {
alpha: 1
});
var offButton = Overlays.addOverlay("image", {
x: screenSize.x - 48,
y: 96,
width: 32,
height: 32,
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
color: { red: 255, green: 255, blue: 255},
alpha: 1
});
if (showScore) {
var text = Overlays.addOverlay("text", {
x: screenSize.x / 2 - 100,
@ -88,25 +127,27 @@ if (showScore) {
});
}
function printVector(string, vector) {
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
}
function shootBullet(position, velocity) {
var BULLET_SIZE = 0.01;
var BULLET_LIFETIME = 20.0;
var BULLET_GRAVITY = -0.02;
Entities.addEntity(
var BULLET_SIZE = 0.07;
var BULLET_LIFETIME = 10.0;
var BULLET_GRAVITY = 0.0;
bulletID = Entities.addEntity(
{ type: "Sphere",
position: position,
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
color: { red: 10, green: 10, blue: 10 },
color: { red: 255, green: 0, blue: 0 },
velocity: velocity,
lifetime: BULLET_LIFETIME,
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
damping: 0 });
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
damping: 0.01,
density: 5000,
ignoreCollisions: false,
collisionsWillMove: true
});
// Play firing sounds
audioOptions.position = position;
@ -115,36 +156,46 @@ function shootBullet(position, velocity) {
if ((shotsFired % RELOAD_INTERVAL) == 0) {
Audio.playSound(loadSound, audioOptions);
}
// Kickback the arm
rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm");
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
MyAvatar.setJointData("LeftForeArm", armRotation);
elbowKickAngle = KICKBACK_ANGLE;
}
function shootTarget() {
var TARGET_SIZE = 0.25;
var TARGET_GRAVITY = -0.6;
var TARGET_SIZE = 0.50;
var TARGET_GRAVITY = 0.0;
var TARGET_LIFETIME = 300.0;
var TARGET_UP_VELOCITY = 3.0;
var TARGET_FWD_VELOCITY = 5.0;
var DISTANCE_TO_LAUNCH_FROM = 3.0;
var TARGET_UP_VELOCITY = 0.0;
var TARGET_FWD_VELOCITY = 0.0;
var DISTANCE_TO_LAUNCH_FROM = 5.0;
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
var camera = Camera.getPosition();
//printVector("camera", camera);
var targetDirection = Quat.angleAxis(getRandomFloat(-20.0, 20.0), { x:0, y:1, z:0 });
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
var forwardVector = Quat.getFront(targetDirection);
//printVector("forwardVector", forwardVector);
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
//printVector("newPosition", newPosition);
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
velocity.y += TARGET_UP_VELOCITY;
//printVector("velocity", velocity);
Entities.addEntity(
{ type: "Sphere",
targetID = Entities.addEntity(
{ type: "Box",
position: newPosition,
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
color: { red: 0, green: 200, blue: 200 },
dimensions: { x: TARGET_SIZE * (0.5 + Math.random()), y: TARGET_SIZE * (0.5 + Math.random()), z: TARGET_SIZE * (0.5 + Math.random()) / 4.0 },
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
velocity: velocity,
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
lifetime: TARGET_LIFETIME,
damping: 0.0001 });
rotation: Camera.getOrientation(),
damping: 0.1,
density: 100.0,
collisionsWillMove: true });
// Record start time
shotTime = new Date();
@ -154,27 +205,26 @@ function shootTarget() {
Audio.playSound(targetLaunchSound, audioOptions);
}
function entityCollisionWithEntity(entity1, entity2, collision) {
score++;
if (showScore) {
Overlays.editOverlay(text, { text: "Score: " + score } );
}
// Sort out which entity is which
// Record shot time
var endTime = new Date();
var msecs = endTime.valueOf() - shotTime.valueOf();
//print("hit, msecs = " + msecs);
//Vec3.print("penetration = ", collision.penetration);
//Vec3.print("contactPoint = ", collision.contactPoint);
Entities.deleteEntity(entity1);
Entities.deleteEntity(entity2);
// play the sound near the camera so the shooter can hear it
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(targetHitSound, audioOptions);
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
score++;
if (showScore) {
Overlays.editOverlay(text, { text: "Score: " + score } );
}
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
Script.setTimeout(deleteBulletAndTarget, 500);
// Turn the target and the bullet white
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
// play the sound near the camera so the shooter can hear it
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(targetHitSound, audioOptions);
}
}
function keyPressEvent(event) {
@ -182,55 +232,105 @@ function keyPressEvent(event) {
if (event.text == "t") {
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
Script.setTimeout(shootTarget, time);
} else if (event.text == ".") {
} else if ((event.text == ".") || (event.text == "SPACE")) {
shootFromMouse();
} else if (event.text == "r") {
playLoadSound();
} else if (event.text == "s") {
// Hit this key to dump a posture from hydra to log
Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
}
}
function playLoadSound() {
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(loadSound, audioOptions);
// Raise arm to firing posture
takeFiringPose();
}
function clearPose() {
MyAvatar.clearJointData("LeftForeArm");
MyAvatar.clearJointData("LeftArm");
MyAvatar.clearJointData("LeftHand");
}
function deleteBulletAndTarget() {
Entities.deleteEntity(bulletID);
Entities.deleteEntity(targetID);
bulletID = false;
targetID = false;
}
function takeFiringPose() {
clearPose();
if (Controller.getNumberOfSpatialControls() == 0) {
MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
}
}
MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20);
//MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
MyAvatar.attach(gunModel, "LeftHand", {x:-0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(0, 0, 79), 0.20);
// Give a bit of time to load before playing sound
Script.setTimeout(playLoadSound, 2000);
function update(deltaTime) {
if (bulletID && !bulletID.isKnownID) {
bulletID = Entities.identifyEntity(bulletID);
}
if (targetID && !targetID.isKnownID) {
targetID = Entities.identifyEntity(targetID);
}
// 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 } ));
MyAvatar.orientation = newOrientation;
//MyAvatar.orientation = newOrientation;
yawFromMouse = 0;
// apply pitch from mouse
var newPitch = MyAvatar.headPitch + pitchFromMouse;
MyAvatar.headPitch = newPitch;
//MyAvatar.headPitch = newPitch;
pitchFromMouse = 0;
// Check hydra controller for launch button press
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
isLaunchButtonPressed = true;
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
Script.setTimeout(shootTarget, time);
} else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) {
isLaunchButtonPressed = false;
if (activeControllers == 0) {
if (Controller.getNumberOfSpatialControls() > 0) {
activeControllers = Controller.getNumberOfSpatialControls();
clearPose();
}
}
// Check hydra controller for trigger press
var KICKBACK_DECAY_RATE = 0.125;
if (elbowKickAngle > 0.0) {
if (elbowKickAngle > 0.5) {
var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
elbowKickAngle -= newAngle;
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
MyAvatar.setJointData("LeftForeArm", armRotation);
} else {
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
if (Controller.getNumberOfSpatialControls() > 0) {
clearPose();
}
elbowKickAngle = 0.0;
}
}
var numberOfTriggers = Controller.getNumberOfTriggers();
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
// this is expected for hydras
// check for trigger press
var numberOfTriggers = 2;
var controllersPerTrigger = 2;
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
for (var t = 0; t < numberOfTriggers; t++) {
for (var t = 0; t < 2; t++) {
var shootABullet = false;
var triggerValue = Controller.getTriggerValue(t);
if (triggerPulled[t]) {
@ -239,21 +339,27 @@ function update(deltaTime) {
triggerPulled[t] = false; // unpulled
}
} else {
// must pull to at least 0.9
if (triggerValue > 0.9) {
// must pull to at least
if (triggerValue > 0.5) {
triggerPulled[t] = true; // pulled
shootABullet = true;
}
}
var palmController = t * controllersPerTrigger;
var palmPosition = Controller.getSpatialControlPosition(palmController);
var fingerTipController = palmController + 1;
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
var laserTip = Vec3.sum(Vec3.multiply(100.0, Vec3.subtract(fingerTipPosition, palmPosition)), palmPosition);
// Update Lasers
Overlays.editOverlay(pointer[t], {
start: palmPosition,
end: laserTip,
alpha: 1
});
if (shootABullet) {
var palmController = t * controllersPerTrigger;
var palmPosition = Controller.getSpatialControlPosition(palmController);
var fingerTipController = palmController + 1;
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
var palmToFingerTipVector =
{ x: (fingerTipPosition.x - palmPosition.x),
y: (fingerTipPosition.y - palmPosition.y),
@ -263,12 +369,8 @@ function update(deltaTime) {
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
var linearVelocity = 25;
var velocity = { x: palmToFingerTipVector.x * linearVelocity,
y: palmToFingerTipVector.y * linearVelocity,
z: palmToFingerTipVector.z * linearVelocity };
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector));
shootBullet(position, velocity);
}
@ -276,16 +378,8 @@ function update(deltaTime) {
}
}
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);
}
function shootFromMouse() {
var DISTANCE_FROM_CAMERA = 2.0;
var DISTANCE_FROM_CAMERA = 1.0;
var camera = Camera.getPosition();
var forwardVector = Quat.getFront(Camera.getOrientation());
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
@ -312,14 +406,17 @@ function mouseMoveEvent(event) {
function scriptEnding() {
Overlays.deleteOverlay(reticle);
Overlays.deleteOverlay(offButton);
Overlays.deleteOverlay(pointer[0]);
Overlays.deleteOverlay(pointer[1]);
Overlays.deleteOverlay(text);
MyAvatar.detachOne(gunModel);
clearPose();
}
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
Script.scriptEnding.connect(scriptEnding);
Script.update.connect(update);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.keyPressEvent.connect(keyPressEvent);

View file

@ -0,0 +1,742 @@
//
// hydraGrab.js
// examples
//
// Created by Clément Brisset on 4/24/14.
// Copyright 2014 High Fidelity, Inc.
//
// This script allows you to edit models either with the razor hydras or with your mouse
//
// Using the hydras :
// grab models with the triggers, you can then move the models around or scale them with both hands.
// You can switch mode using the bumpers so that you can move models around more easily.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/entityPropertyDialogBox.js");
var entityPropertyDialogBox = EntityPropertyDialogBox;
var LASER_WIDTH = 4;
var LASER_COLOR = { red: 255, green: 0, blue: 0 };
var LASER_LENGTH_FACTOR = 500;
var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = false;
var allowSmallModels = false;
var wantEntityGlow = false;
var LEFT = 0;
var RIGHT = 1;
var jointList = MyAvatar.getJointNames();
var mode = 0;
function controller(wichSide) {
this.side = wichSide;
this.palm = 2 * wichSide;
this.tip = 2 * wichSide + 1;
this.trigger = wichSide;
this.bumper = 6 * wichSide + 5;
this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm);
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
this.oldTipPosition = Controller.getSpatialControlPosition(this.tip);
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
this.oldUp = Controller.getSpatialControlNormal(this.palm);
this.up = this.oldUp;
this.oldFront = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
this.front = this.oldFront;
this.oldRight = Vec3.cross(this.front, this.up);
this.right = this.oldRight;
this.oldRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
this.rotation = this.oldRotation;
this.triggerValue = Controller.getTriggerValue(this.trigger);
this.bumperValue = Controller.isButtonPressed(this.bumper);
this.pressed = false; // is trigger pressed
this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously)
this.grabbing = false;
this.entityID = { isKnownID: false };
this.modelURL = "";
this.oldModelRotation;
this.oldModelPosition;
this.oldModelHalfDiagonal;
this.positionAtGrab;
this.rotationAtGrab;
this.modelPositionAtGrab;
this.rotationAtGrab;
this.jointsIntersectingFromStart = [];
this.laser = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: LASER_COLOR,
alpha: 1,
visible: false,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.guideScale = 0.02;
this.ball = Overlays.addOverlay("sphere", {
position: { x: 0, y: 0, z: 0 },
size: this.guideScale,
solid: true,
color: { red: 0, green: 255, blue: 0 },
alpha: 1,
visible: false,
anchor: "MyAvatar"
});
this.leftRight = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 0, green: 0, blue: 255 },
alpha: 1,
visible: false,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.topDown = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 0, green: 0, blue: 255 },
alpha: 1,
visible: false,
lineWidth: LASER_WIDTH,
anchor: "MyAvatar"
});
this.grab = function (entityID, properties) {
print("Grabbing " + entityID.id);
this.grabbing = true;
this.entityID = entityID;
this.modelURL = properties.modelURL;
this.oldModelPosition = properties.position;
this.oldModelRotation = properties.rotation;
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
this.positionAtGrab = this.palmPosition;
this.rotationAtGrab = this.rotation;
this.modelPositionAtGrab = properties.position;
this.rotationAtGrab = properties.rotation;
this.jointsIntersectingFromStart = [];
for (var i = 0; i < jointList.length; i++) {
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
if (distance < this.oldModelHalfDiagonal) {
this.jointsIntersectingFromStart.push(i);
}
}
this.showLaser(false);
}
this.release = function () {
if (this.grabbing) {
jointList = MyAvatar.getJointNames();
var closestJointIndex = -1;
var closestJointDistance = 10;
for (var i = 0; i < jointList.length; i++) {
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
if (distance < closestJointDistance) {
closestJointDistance = distance;
closestJointIndex = i;
}
}
if (closestJointIndex != -1) {
print("closestJoint: " + jointList[closestJointIndex]);
print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")");
}
if (closestJointDistance < this.oldModelHalfDiagonal) {
if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 ||
(leftController.grabbing && rightController.grabbing &&
leftController.entityID.id == rightController.entityID.id)) {
// Do nothing
} else {
print("Attaching to " + jointList[closestJointIndex]);
var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]);
var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]);
var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition);
attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset);
var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation);
MyAvatar.attach(this.modelURL, jointList[closestJointIndex],
attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal,
true, false);
Entities.deleteEntity(this.entityID);
}
}
}
this.grabbing = false;
this.entityID.isKnownID = false;
this.jointsIntersectingFromStart = [];
this.showLaser(true);
}
this.checkTrigger = function () {
if (this.triggerValue > 0.9) {
if (this.pressed) {
this.pressing = false;
} else {
this.pressing = true;
}
this.pressed = true;
} else {
this.pressing = false;
this.pressed = false;
}
}
this.checkEntity = function (properties) {
// P P - Model
// /| A - Palm
// / | d B - unit vector toward tip
// / | X - base of the perpendicular line
// A---X----->B d - distance fom axis
// x x - distance from A
//
// |X-A| = (P-A).B
// X == A + ((P-A).B)B
// d = |P-X|
var A = this.palmPosition;
var B = this.front;
var P = properties.position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var y = Vec3.dot(Vec3.subtract(P, A), this.up);
var z = Vec3.dot(Vec3.subtract(P, A), this.right);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (0 < x && sizeOK) {
return { valid: true, x: x, y: y, z: z };
}
return { valid: false };
}
this.glowedIntersectingModel = { isKnownID: false };
this.moveLaser = function () {
// the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame
var inverseRotation = Quat.inverse(MyAvatar.orientation);
var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position));
var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition));
var distance = Vec3.length(direction);
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance);
var endPosition = Vec3.sum(startPosition, direction);
Overlays.editOverlay(this.laser, {
start: startPosition,
end: endPosition
});
Overlays.editOverlay(this.ball, {
position: endPosition
});
Overlays.editOverlay(this.leftRight, {
start: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)),
end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale))
});
Overlays.editOverlay(this.topDown, {
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
});
this.showLaser(!this.grabbing || mode == 0);
if (this.glowedIntersectingModel.isKnownID) {
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
this.glowedIntersectingModel.isKnownID = false;
}
if (!this.grabbing) {
var intersection = Entities.findRayIntersection({
origin: this.palmPosition,
direction: this.front
});
var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (intersection.accurate && intersection.entityID.isKnownID && sizeOK) {
this.glowedIntersectingModel = intersection.entityID;
if (wantEntityGlow) {
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 });
}
}
}
}
this.showLaser = function (show) {
Overlays.editOverlay(this.laser, { visible: show });
Overlays.editOverlay(this.ball, { visible: show });
Overlays.editOverlay(this.leftRight, { visible: show });
Overlays.editOverlay(this.topDown, { visible: show });
}
this.moveEntity = function () {
if (this.grabbing) {
if (!this.entityID.isKnownID) {
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
this.entityID = Entities.findRayIntersection({
origin: this.palmPosition,
direction: this.front
}).entityID;
print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
}
var newPosition;
var newRotation;
switch (mode) {
case 0:
newPosition = Vec3.sum(this.palmPosition,
Vec3.multiply(this.front, this.x));
newPosition = Vec3.sum(newPosition,
Vec3.multiply(this.up, this.y));
newPosition = Vec3.sum(newPosition,
Vec3.multiply(this.right, this.z));
newRotation = Quat.multiply(this.rotation,
Quat.inverse(this.oldRotation));
newRotation = Quat.multiply(newRotation,
this.oldModelRotation);
break;
case 1:
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 });
var d = Vec3.dot(forward, MyAvatar.position);
var factor1 = Vec3.dot(forward, this.positionAtGrab) - d;
var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d;
var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab);
if (factor2 < 0) {
factor2 = 0;
}
if (factor1 <= 0) {
factor1 = 1;
factor2 = 1;
}
newPosition = Vec3.sum(this.modelPositionAtGrab,
Vec3.multiply(vector,
factor2 / factor1));
newRotation = Quat.multiply(this.rotation,
Quat.inverse(this.rotationAtGrab));
newRotation = Quat.multiply(newRotation,
this.rotationAtGrab);
break;
}
Entities.editEntity(this.entityID, {
position: newPosition,
rotation: newRotation
});
this.oldModelRotation = newRotation;
this.oldModelPosition = newPosition;
var indicesToRemove = [];
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
if (distance >= this.oldModelHalfDiagonal) {
indicesToRemove.push(this.jointsIntersectingFromStart[i]);
}
}
for (var i = 0; i < indicesToRemove.length; ++i) {
this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1));
}
}
}
this.update = function () {
this.oldPalmPosition = this.palmPosition;
this.oldTipPosition = this.tipPosition;
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
this.oldUp = this.up;
this.up = Vec3.normalize(Controller.getSpatialControlNormal(this.palm));
this.oldFront = this.front;
this.front = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
this.oldRight = this.right;
this.right = Vec3.normalize(Vec3.cross(this.front, this.up));
this.oldRotation = this.rotation;
this.rotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
this.triggerValue = Controller.getTriggerValue(this.trigger);
var bumperValue = Controller.isButtonPressed(this.bumper);
if (bumperValue && !this.bumperValue) {
if (mode == 0) {
mode = 1;
Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } });
Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } });
} else {
mode = 0;
Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } });
Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } });
}
}
this.bumperValue = bumperValue;
this.checkTrigger();
this.moveLaser();
if (!this.pressed && this.grabbing) {
// release if trigger not pressed anymore.
this.release();
}
if (this.pressing) {
// Checking for attachments intersecting
var attachments = MyAvatar.getAttachmentData();
var attachmentIndex = -1;
var attachmentX = LASER_LENGTH_FACTOR;
var newModel;
var newProperties;
for (var i = 0; i < attachments.length; ++i) {
var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName),
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation));
var scale = attachments[i].scale;
var A = this.palmPosition;
var B = this.front;
var P = position;
var x = Vec3.dot(Vec3.subtract(P, A), B);
var X = Vec3.sum(A, Vec3.multiply(B, x));
var d = Vec3.length(Vec3.subtract(P, X));
if (d < scale / 2.0 && 0 < x && x < attachmentX) {
attachmentIndex = i;
attachmentX = d;
}
}
if (attachmentIndex != -1) {
print("Detaching: " + attachments[attachmentIndex].modelURL);
MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName);
newProperties = {
type: "Model",
position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName),
Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)),
rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName),
attachments[attachmentIndex].rotation),
// TODO: how do we know the correct dimensions for detachment???
dimensions: { x: attachments[attachmentIndex].scale / 2.0,
y: attachments[attachmentIndex].scale / 2.0,
z: attachments[attachmentIndex].scale / 2.0 },
modelURL: attachments[attachmentIndex].modelURL
};
newModel = Entities.addEntity(newProperties);
} else {
// There is none so ...
// Checking model tree
Vec3.print("Looking at: ", this.palmPosition);
var pickRay = { origin: this.palmPosition,
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
var foundIntersection = Entities.findRayIntersection(pickRay);
if(!foundIntersection.accurate) {
print("No accurate intersection");
return;
}
newModel = foundIntersection.entityID;
if (!newModel.isKnownID) {
var identify = Entities.identifyEntity(newModel);
if (!identify.isKnownID) {
print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")");
return;
}
newModel = identify;
}
newProperties = Entities.getEntityProperties(newModel);
}
print("foundEntity.modelURL=" + newProperties.modelURL);
var check = this.checkEntity(newProperties);
if (!check.valid) {
return;
}
this.grab(newModel, newProperties);
this.x = check.x;
this.y = check.y;
this.z = check.z;
return;
}
}
this.cleanup = function () {
Overlays.deleteOverlay(this.laser);
Overlays.deleteOverlay(this.ball);
Overlays.deleteOverlay(this.leftRight);
Overlays.deleteOverlay(this.topDown);
}
}
var leftController = new controller(LEFT);
var rightController = new controller(RIGHT);
function moveEntities() {
if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) {
var newPosition = leftController.oldModelPosition;
var rotation = leftController.oldModelRotation;
var ratio = 1;
switch (mode) {
case 0:
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5);
var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint));
var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x));
var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x));
var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5);
var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint));
ratio = length / oldLength;
newPosition = Vec3.sum(middle,
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
break;
case 1:
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
var cos_theta = Vec3.dot(u, v);
if (cos_theta > 1) {
cos_theta = 1;
}
var angle = Math.acos(cos_theta) / Math.PI * 180;
if (angle < 0.1) {
return;
}
var w = Vec3.normalize(Vec3.cross(u, v));
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
leftController.positionAtGrab = leftController.palmPosition;
leftController.rotationAtGrab = leftController.rotation;
leftController.modelPositionAtGrab = leftController.oldModelPosition;
leftController.rotationAtGrab = rotation;
rightController.positionAtGrab = rightController.palmPosition;
rightController.rotationAtGrab = rightController.rotation;
rightController.modelPositionAtGrab = rightController.oldModelPosition;
rightController.rotationAtGrab = rotation;
break;
}
Entities.editEntity(leftController.entityID, {
position: newPosition,
rotation: rotation,
// TODO: how do we know the correct dimensions for detachment???
//radius: leftController.oldModelHalfDiagonal * ratio
dimensions: { x: leftController.oldModelHalfDiagonal * ratio,
y: leftController.oldModelHalfDiagonal * ratio,
z: leftController.oldModelHalfDiagonal * ratio }
});
leftController.oldModelPosition = newPosition;
leftController.oldModelRotation = rotation;
leftController.oldModelHalfDiagonal *= ratio;
rightController.oldModelPosition = newPosition;
rightController.oldModelRotation = rotation;
rightController.oldModelHalfDiagonal *= ratio;
return;
}
leftController.moveEntity();
rightController.moveEntity();
}
var hydraConnected = false;
function checkController(deltaTime) {
var numberOfButtons = Controller.getNumberOfButtons();
var numberOfTriggers = Controller.getNumberOfTriggers();
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
// this is expected for hydras
if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) {
if (!hydraConnected) {
hydraConnected = true;
}
leftController.update();
rightController.update();
moveEntities();
} else {
if (hydraConnected) {
hydraConnected = false;
leftController.showLaser(false);
rightController.showLaser(false);
}
}
}
var glowedEntityID = { id: -1, isKnownID: false };
// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
// added it.
var modelMenuAddedDelete = false;
var originalLightsArePickable = Entities.getLightsArePickable();
function setupModelMenus() {
print("setupModelMenus()");
// adj our menuitems
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...",
shortcutKeyEvent: { text: "`" }, afterItem: "Models" });
if (!Menu.menuItemExists("Edit", "Delete")) {
print("no delete... adding ours");
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete",
shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" });
modelMenuAddedDelete = true;
} else {
print("delete exists... don't add ours");
}
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
afterItem: "Paste Models", isCheckable: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
afterItem: "Allow Selecting of Large Models", isCheckable: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L",
afterItem: "Allow Selecting of Small Models", isCheckable: true });
Entities.setLightsArePickable(false);
}
function cleanupModelMenus() {
Menu.removeMenuItem("Edit", "Edit Properties...");
if (modelMenuAddedDelete) {
// delete our menuitems
Menu.removeMenuItem("Edit", "Delete");
}
Menu.removeMenuItem("Edit", "Allow Selecting of Large Models");
Menu.removeMenuItem("Edit", "Allow Selecting of Small Models");
Menu.removeMenuItem("Edit", "Allow Selecting of Lights");
}
function scriptEnding() {
leftController.cleanup();
rightController.cleanup();
cleanupModelMenus();
Entities.setLightsArePickable(originalLightsArePickable);
}
Script.scriptEnding.connect(scriptEnding);
// register the call back so it fires before each data send
Script.update.connect(checkController);
setupModelMenus();
var editModelID = -1;
function showPropertiesForm(editModelID) {
entityPropertyDialogBox.openDialog(editModelID);
}
Menu.menuItemEvent.connect(function (menuItem) {
print("menuItemEvent() in JS... menuItem=" + menuItem);
if (menuItem == "Allow Selecting of Small Models") {
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
} else if (menuItem == "Allow Selecting of Large Models") {
allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models");
} else if (menuItem == "Allow Selecting of Lights") {
Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights"));
} else if (menuItem == "Delete") {
if (leftController.grabbing) {
print(" Delete Entity.... leftController.entityID="+ leftController.entityID);
Entities.deleteEntity(leftController.entityID);
leftController.grabbing = false;
if (glowedEntityID.id == leftController.entityID.id) {
glowedEntityID = { id: -1, isKnownID: false };
}
} else if (rightController.grabbing) {
print(" Delete Entity.... rightController.entityID="+ rightController.entityID);
Entities.deleteEntity(rightController.entityID);
rightController.grabbing = false;
if (glowedEntityID.id == rightController.entityID.id) {
glowedEntityID = { id: -1, isKnownID: false };
}
} else {
print(" Delete Entity.... not holding...");
}
} else if (menuItem == "Edit Properties...") {
editModelID = -1;
if (leftController.grabbing) {
print(" Edit Properties.... leftController.entityID="+ leftController.entityID);
editModelID = leftController.entityID;
} else if (rightController.grabbing) {
print(" Edit Properties.... rightController.entityID="+ rightController.entityID);
editModelID = rightController.entityID;
} else {
print(" Edit Properties.... not holding...");
}
if (editModelID != -1) {
print(" Edit Properties.... about to edit properties...");
showPropertiesForm(editModelID);
}
}
});
Controller.keyReleaseEvent.connect(function (event) {
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
if (event.text == "`") {
handeMenuEvent("Edit Properties...");
}
if (event.text == "BACKSPACE") {
handeMenuEvent("Delete");
}
});

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var rightHandAnimation = HIFI_PUBLIC_BUCKET + "animations/RightHandAnimPhilip.fbx";
var leftHandAnimation = HIFI_PUBLIC_BUCKET + "animations/LeftHandAnimPhilip.fbx";

View file

@ -15,7 +15,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
// maybe we should make these constants...
var LEFT_PALM = 0;

View file

@ -15,7 +15,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
const KBD_UPPERCASE_DEFAULT = 0;
const KBD_LOWERCASE_DEFAULT = 1;

View file

@ -11,7 +11,7 @@
Script.load("lookWithTouch.js");
Script.load("editEntities.js");
Script.load("selectAudioDevice.js");
Script.load("hydraMove.js");
Script.load("controllers/hydra/hydraMove.js");
Script.load("headMove.js");
Script.load("inspect.js");
Script.load("lobby.js");

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include("libraries/stringHelpers.js");
Script.include("libraries/dataviewHelpers.js");
Script.include("libraries/httpMultiPart.js");
@ -527,8 +527,15 @@ function mousePressEvent(event) {
var highlightedEntityID = { isKnownID: false };
var mouseCapturedByTool = false;
var lastMousePosition = null;
var idleMouseTimerId = null;
var IDLE_MOUSE_TIMEOUT = 200;
function mouseMoveEvent(event) {
if (idleMouseTimerId) {
Script.clearTimeout(idleMouseTimerId);
}
mouseHasMovedSincePress = true;
if (isActive) {
// allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing
@ -536,36 +543,48 @@ function mouseMoveEvent(event) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y);
var entityIntersection = Entities.findRayIntersection(pickRay);
if (entityIntersection.accurate) {
if(highlightedEntityID.isKnownID && highlightedEntityID.id != entityIntersection.entityID.id) {
selectionDisplay.unhighlightSelectable(highlightedEntityID);
highlightedEntityID = { id: -1, isKnownID: false };
}
lastMousePosition = { x: event.x, y: event.y };
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
entityIntersection.properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (entityIntersection.entityID.isKnownID && sizeOK) {
if (wantEntityGlow) {
Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 });
}
highlightedEntityID = entityIntersection.entityID;
selectionDisplay.highlightSelectable(entityIntersection.entityID);
}
}
highlightEntityUnderCursor(lastMousePosition, false);
idleMouseTimerId = Script.setTimeout(handleIdleMouse, IDLE_MOUSE_TIMEOUT);
} else {
cameraManager.mouseMoveEvent(event);
}
}
function handleIdleMouse() {
idleMouseTimerId = null;
highlightEntityUnderCursor(lastMousePosition, true);
}
function highlightEntityUnderCursor(position, accurateRay) {
var pickRay = Camera.computePickRay(position.x, position.y);
var entityIntersection = Entities.findRayIntersection(pickRay, accurateRay);
if (entityIntersection.accurate) {
if(highlightedEntityID.isKnownID && highlightedEntityID.id != entityIntersection.entityID.id) {
selectionDisplay.unhighlightSelectable(highlightedEntityID);
highlightedEntityID = { id: -1, isKnownID: false };
}
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(),
entityIntersection.properties.position)) * 180 / 3.14;
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
if (entityIntersection.entityID.isKnownID && sizeOK) {
if (wantEntityGlow) {
Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 });
}
highlightedEntityID = entityIntersection.entityID;
selectionDisplay.highlightSelectable(entityIntersection.entityID);
}
}
}
function mouseReleaseEvent(event) {
if (isActive && selectionManager.hasSelection()) {
@ -662,8 +681,6 @@ function setupModelMenus() {
print("setupModelMenus()");
// adj our menuitems
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...",
shortcutKeyEvent: { text: "`" }, afterItem: "Models" });
if (!Menu.menuItemExists("Edit", "Delete")) {
print("no delete... adding ours");
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete",
@ -674,7 +691,7 @@ function setupModelMenus() {
}
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Model List..." });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
afterItem: "Paste Models", isCheckable: true, isChecked: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
@ -696,7 +713,6 @@ setupModelMenus(); // do this when first running our script.
function cleanupModelMenus() {
Menu.removeSeparator("Edit", "Models");
Menu.removeMenuItem("Edit", "Edit Properties...");
if (modelMenuAddedDelete) {
// delete our menuitems
Menu.removeMenuItem("Edit", "Delete");
@ -798,22 +814,6 @@ function handeMenuEvent(menuItem) {
MyAvatar.position = selectedModel.properties.position;
}
}
} else if (menuItem == "Edit Properties...") {
// good place to put the properties dialog
editModelID = -1;
if (selectionManager.selections.length == 1) {
print(" Edit Properties.... selectedEntityID="+ selectedEntityID);
editModelID = selectionManager.selections[0];
} else {
print(" Edit Properties.... not holding...");
}
if (editModelID != -1) {
print(" Edit Properties.... about to edit properties...");
entityPropertyDialogBox.openDialog(editModelID);
selectionManager._update();
}
} else if (menuItem == "Paste Models") {
modelImporter.paste();
} else if (menuItem == "Export Models") {
@ -841,9 +841,6 @@ Controller.keyPressEvent.connect(function(event) {
Controller.keyReleaseEvent.connect(function (event) {
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
if (event.text == "`") {
handeMenuEvent("Edit Properties...");
}
if (event.text == "BACKSPACE" || event.text == "DELETE") {
handeMenuEvent("Delete");
} else if (event.text == "TAB") {
@ -1077,6 +1074,19 @@ PropertiesTool = function(opts) {
pushCommandForSelections();
selectionManager._update();
}
} else if (data.action == "rescaleDimensions") {
var multiplier = data.percentage / 100;
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
Entities.editEntity(selectionManager.selections[i], {
dimensions: Vec3.multiply(multiplier, properties.dimensions),
});
}
pushCommandForSelections();
selectionManager._update();
}
}
}
});

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw");
var CHANCE_OF_PLAYING_SOUND = 0.01;

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var modelURL = HIFI_PUBLIC_BUCKET + "models/entities/radio/Speakers.fbx";
var soundURL = HIFI_PUBLIC_BUCKET + "sounds/family.stereo.raw";

View file

@ -0,0 +1,66 @@
//
// downloadInfoExample.js
// examples/example
//
// Created by David Rowe on 5 Jan 2015
// Copyright 2015 High Fidelity, Inc.
//
// Display downloads information the same as in the stats.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var downloadInfo,
downloadInfoOverlay;
function formatInfo(info) {
var string = "Downloads: ",
i;
for (i = 0; i < info.downloading.length; i += 1) {
string += info.downloading[i].toFixed(0) + "% ";
}
string += "(" + info.pending.toFixed(0) + " pending)";
return string;
}
// Get and log the current downloads info ...
downloadInfo = GlobalServices.getDownloadInfo();
print(formatInfo(downloadInfo));
// Display and update the downloads info in an overlay ...
function setUp() {
downloadInfoOverlay = Overlays.addOverlay("text", {
x: 300,
y: 200,
width: 300,
height: 50,
color: { red: 255, green: 255, blue: 255 },
alpha: 1.0,
backgroundColor: { red: 127, green: 127, blue: 127 },
backgroundAlpha: 0.5,
topMargin: 15,
leftMargin: 20,
text: ""
});
}
function updateInfo(info) {
Overlays.editOverlay(downloadInfoOverlay, { text: formatInfo(info) });
}
function tearDown() {
Overlays.deleteOverlay(downloadInfoOverlay);
}
setUp();
GlobalServices.downloadInfoChanged.connect(updateInfo);
GlobalServices.updateDownloadInfo();
Script.scriptEnding.connect(tearDown);

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var count = 0;
var moveUntil = 2000;

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var count = 0;
var stopAfter = 1000;

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var iteration = 0;

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
// The "Swatches" example of this script will create 9 different image overlays, that use the color feature to
// display different colors as color swatches. The overlays can be clicked on, to change the "selectedSwatch" variable

View file

@ -1,418 +0,0 @@
//
// gun.js
// examples
//
// Created by Brad Hefta-Gaub on 12/31/13.
// Modified by Philip on 3/3/14
// Copyright 2013 High Fidelity, Inc.
//
// This is an example script that turns the hydra controllers and mouse into a entity gun.
// It reads the controller, watches for trigger pulls, and launches entities.
// When entities collide with voxels they blow little holes out of the voxels.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;
}
var lastX = 0;
var lastY = 0;
var yawFromMouse = 0;
var pitchFromMouse = 0;
var isMouseDown = false;
var BULLET_VELOCITY = 20.0;
var MIN_THROWER_DELAY = 1000;
var MAX_THROWER_DELAY = 1000;
var LEFT_BUTTON_3 = 3;
var RELOAD_INTERVAL = 5;
var KICKBACK_ANGLE = 15;
var elbowKickAngle = 0.0;
var rotationBeforeKickback;
var showScore = false;
// Load some sound to use for loading and firing
var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw");
var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw");
var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw");
var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw");
var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw");
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
var audioOptions = {
volume: 0.9
}
var shotsFired = 0;
var shotTime = new Date();
var activeControllers = 0;
// initialize our controller triggers
var triggerPulled = new Array();
var numberOfTriggers = Controller.getNumberOfTriggers();
for (t = 0; t < numberOfTriggers; t++) {
triggerPulled[t] = false;
}
var isLaunchButtonPressed = false;
var score = 0;
var bulletID = false;
var targetID = false;
// Create a reticle image in center of screen
var screenSize = Controller.getViewportDimensions();
var reticle = Overlays.addOverlay("image", {
x: screenSize.x / 2 - 16,
y: screenSize.y / 2 - 16,
width: 32,
height: 32,
imageURL: HIFI_PUBLIC_BUCKET + "images/reticle.png",
color: { red: 255, green: 255, blue: 255},
alpha: 1
});
var offButton = Overlays.addOverlay("image", {
x: screenSize.x - 48,
y: 96,
width: 32,
height: 32,
imageURL: HIFI_PUBLIC_BUCKET + "images/close.png",
color: { red: 255, green: 255, blue: 255},
alpha: 1
});
if (showScore) {
var text = Overlays.addOverlay("text", {
x: screenSize.x / 2 - 100,
y: screenSize.y / 2 - 50,
width: 150,
height: 50,
color: { red: 0, green: 0, blue: 0},
textColor: { red: 255, green: 0, blue: 0},
topMargin: 4,
leftMargin: 4,
text: "Score: " + score
});
}
function printVector(string, vector) {
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
}
function shootBullet(position, velocity) {
var BULLET_SIZE = 0.07;
var BULLET_LIFETIME = 10.0;
var BULLET_GRAVITY = -0.02;
bulletID = Entities.addEntity(
{ type: "Sphere",
position: position,
dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE },
color: { red: 255, green: 0, blue: 0 },
velocity: velocity,
lifetime: BULLET_LIFETIME,
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
ignoreCollisions: false,
collisionsWillMove: true
});
// Play firing sounds
audioOptions.position = position;
Audio.playSound(fireSound, audioOptions);
shotsFired++;
if ((shotsFired % RELOAD_INTERVAL) == 0) {
Audio.playSound(loadSound, audioOptions);
}
// Kickback the arm
rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm");
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE));
MyAvatar.setJointData("LeftForeArm", armRotation);
elbowKickAngle = KICKBACK_ANGLE;
}
function shootTarget() {
var TARGET_SIZE = 0.50;
var TARGET_GRAVITY = -0.25;
var TARGET_LIFETIME = 300.0;
var TARGET_UP_VELOCITY = 0.5;
var TARGET_FWD_VELOCITY = 1.0;
var DISTANCE_TO_LAUNCH_FROM = 3.0;
var ANGLE_RANGE_FOR_LAUNCH = 20.0;
var camera = Camera.getPosition();
//printVector("camera", camera);
var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 });
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
var forwardVector = Quat.getFront(targetDirection);
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
velocity.y += TARGET_UP_VELOCITY;
targetID = Entities.addEntity(
{ type: "Box",
position: newPosition,
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
color: { red: 0, green: 200, blue: 200 },
//angularVelocity: { x: 1, y: 0, z: 0 },
velocity: velocity,
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
lifetime: TARGET_LIFETIME,
damping: 0.0001,
collisionsWillMove: true });
// Record start time
shotTime = new Date();
// Play target shoot sound
audioOptions.position = newPosition;
Audio.playSound(targetLaunchSound, audioOptions);
}
function entityCollisionWithEntity(entity1, entity2, collision) {
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
score++;
if (showScore) {
Overlays.editOverlay(text, { text: "Score: " + score } );
}
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
Script.setTimeout(deleteBulletAndTarget, 500);
// Turn the target and the bullet white
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
// play the sound near the camera so the shooter can hear it
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(targetHitSound, audioOptions);
}
}
function keyPressEvent(event) {
// if our tools are off, then don't do anything
if (event.text == "t") {
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
Script.setTimeout(shootTarget, time);
} else if (event.text == ".") {
shootFromMouse();
} else if (event.text == "r") {
playLoadSound();
} else if (event.text == "s") {
// Hit this key to dump a posture from hydra to log
Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm"));
Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm"));
Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand"));
}
}
function playLoadSound() {
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(loadSound, audioOptions);
// Raise arm to firing posture
takeFiringPose();
}
function clearPose() {
MyAvatar.clearJointData("LeftForeArm");
MyAvatar.clearJointData("LeftArm");
MyAvatar.clearJointData("LeftHand");
}
function deleteBulletAndTarget() {
Entities.deleteEntity(bulletID);
Entities.deleteEntity(targetID);
bulletID = false;
targetID = false;
}
function takeFiringPose() {
clearPose();
if (Controller.getNumberOfSpatialControls() == 0) {
MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843});
MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219});
MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333});
}
}
MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
// Give a bit of time to load before playing sound
Script.setTimeout(playLoadSound, 2000);
function update(deltaTime) {
if (bulletID && !bulletID.isKnownID) {
print("Trying to identify bullet");
bulletID = Entities.identifyEntity(bulletID);
}
if (targetID && !targetID.isKnownID) {
targetID = Entities.identifyEntity(targetID);
}
// 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 } ));
//MyAvatar.orientation = newOrientation;
yawFromMouse = 0;
// apply pitch from mouse
var newPitch = MyAvatar.headPitch + pitchFromMouse;
//MyAvatar.headPitch = newPitch;
pitchFromMouse = 0;
if (activeControllers == 0) {
if (Controller.getNumberOfSpatialControls() > 0) {
activeControllers = Controller.getNumberOfSpatialControls();
clearPose();
}
}
var KICKBACK_DECAY_RATE = 0.125;
if (elbowKickAngle > 0.0) {
if (elbowKickAngle > 0.5) {
var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE;
elbowKickAngle -= newAngle;
var armRotation = MyAvatar.getJointRotation("LeftForeArm");
armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle));
MyAvatar.setJointData("LeftForeArm", armRotation);
} else {
MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback);
if (Controller.getNumberOfSpatialControls() > 0) {
clearPose();
}
elbowKickAngle = 0.0;
}
}
// Check hydra controller for launch button press
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
isLaunchButtonPressed = true;
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
Script.setTimeout(shootTarget, time);
} else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) {
isLaunchButtonPressed = false;
}
// check for trigger press
var numberOfTriggers = 2;
var controllersPerTrigger = 2;
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
for (var t = 0; t < 2; t++) {
var shootABullet = false;
var triggerValue = Controller.getTriggerValue(t);
if (triggerPulled[t]) {
// must release to at least 0.1
if (triggerValue < 0.1) {
triggerPulled[t] = false; // unpulled
}
} else {
// must pull to at least
if (triggerValue > 0.5) {
triggerPulled[t] = true; // pulled
shootABullet = true;
}
}
if (shootABullet) {
var palmController = t * controllersPerTrigger;
var palmPosition = Controller.getSpatialControlPosition(palmController);
var fingerTipController = palmController + 1;
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
var palmToFingerTipVector =
{ x: (fingerTipPosition.x - palmPosition.x),
y: (fingerTipPosition.y - palmPosition.y),
z: (fingerTipPosition.z - palmPosition.z) };
// just off the front of the finger tip
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector));
shootBullet(position, velocity);
}
}
}
}
function mousePressEvent(event) {
isMouseDown = true;
lastX = event.x;
lastY = event.y;
if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) {
Script.stop();
} else {
shootFromMouse();
}
}
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;
}
function mouseMoveEvent(event) {
if (isMouseDown) {
var MOUSE_YAW_SCALE = -0.25;
var MOUSE_PITCH_SCALE = -12.5;
var FIXED_MOUSE_TIMESTEP = 0.016;
yawFromMouse += ((event.x - lastX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP);
pitchFromMouse += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP);
lastX = event.x;
lastY = event.y;
}
}
function scriptEnding() {
Overlays.deleteOverlay(reticle);
Overlays.deleteOverlay(offButton);
Overlays.deleteOverlay(text);
MyAvatar.detachOne(gunModel);
clearPose();
}
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
Script.scriptEnding.connect(scriptEnding);
Script.update.connect(update);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.keyPressEvent.connect(keyPressEvent);

View file

@ -31,8 +31,13 @@
}
function createEmitTextPropertyUpdateFunction(propertyName) {
return function() {
var properties = {};
properties[propertyName] = this.value;
EventBridge.emitWebEvent(
'{ "type":"update", "properties":{"' + propertyName + '":"' + this.value + '"}}'
JSON.stringify({
type: "update",
properties: properties,
})
);
};
}
@ -84,6 +89,8 @@
var elDimensionsY = document.getElementById("property-dim-y");
var elDimensionsZ = document.getElementById("property-dim-z");
var elResetToNaturalDimensions = document.getElementById("reset-to-natural-dimensions");
var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct");
var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button");
var elRegistrationX = document.getElementById("property-reg-x");
var elRegistrationY = document.getElementById("property-reg-y");
@ -107,7 +114,7 @@
var elGravityY = document.getElementById("property-grav-y");
var elGravityZ = document.getElementById("property-grav-z");
var elMass = document.getElementById("property-mass");
var elDensity = document.getElementById("property-density");
var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions");
var elCollisionsWillMove = document.getElementById("property-collisions-will-move");
var elLifetime = document.getElementById("property-lifetime");
@ -144,6 +151,9 @@
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
var elModelAnimationFrame = document.getElementById("property-model-animation-frame");
var elModelAnimationSettings = document.getElementById("property-model-animation-settings");
var elModelTextures = document.getElementById("property-model-textures");
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
var elTextSections = document.querySelectorAll(".text-section");
var elTextText = document.getElementById("property-text-text");
@ -171,10 +181,10 @@
elLocked.checked = properties.locked;
if (properties.locked) {
disableChildren(document.getElementById("properties-table"), 'input');
disableChildren(document.getElementById("properties-list"), 'input');
elLocked.removeAttribute('disabled');
} else {
enableChildren(document.getElementById("properties-table"), 'input');
enableChildren(document.getElementById("properties-list"), 'input');
}
elVisible.checked = properties.visible;
@ -209,7 +219,7 @@
elGravityY.value = properties.gravity.y.toFixed(2);
elGravityZ.value = properties.gravity.z.toFixed(2);
elMass.value = properties.mass.toFixed(2);
elDensity.value = properties.density.toFixed(2);
elIgnoreForCollisions.checked = properties.ignoreForCollisions;
elCollisionsWillMove.checked = properties.collisionsWillMove;
elLifetime.value = properties.lifetime;
@ -221,7 +231,7 @@
}
} else {
for (var i = 0; i < elBoxSections.length; i++) {
elBoxSections[i].style.display = 'table-row';
elBoxSections[i].style.display = 'block';
}
elBoxColorRed.value = properties.color.red;
@ -235,13 +245,17 @@
}
} else {
for (var i = 0; i < elModelSections.length; i++) {
elModelSections[i].style.display = 'table-row';
elModelSections[i].style.display = 'block';
}
elModelURL.value = properties.modelURL;
elModelAnimationURL.value = properties.animationURL;
elModelAnimationPlaying.checked = properties.animationIsPlaying;
elModelAnimationFPS.value = properties.animationFPS;
elModelAnimationFrame.value = properties.animationFrameIndex;
elModelAnimationSettings.value = properties.animationSettings;
elModelTextures.value = properties.textures;
elModelOriginalTextures.value = properties.originalTextures;
}
if (properties.type != "Text") {
@ -250,7 +264,7 @@
}
} else {
for (var i = 0; i < elTextSections.length; i++) {
elTextSections[i].style.display = 'table-row';
elTextSections[i].style.display = 'block';
}
elTextText.value = properties.text;
@ -269,7 +283,7 @@
}
} else {
for (var i = 0; i < elLightSections.length; i++) {
elLightSections[i].style.display = 'table-row';
elLightSections[i].style.display = 'block';
}
elLightDiffuseRed.value = properties.diffuseColor.red;
@ -342,7 +356,7 @@
elGravityY.addEventListener('change', gravityChangeFunction);
elGravityZ.addEventListener('change', gravityChangeFunction);
elMass.addEventListener('change', createEmitNumberPropertyUpdateFunction('mass'));
elDensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('density'));
elIgnoreForCollisions.addEventListener('change', createEmitCheckedPropertyUpdateFunction('ignoreForCollisions'));
elCollisionsWillMove.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionsWillMove'));
elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime'));
@ -385,6 +399,8 @@
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
elModelAnimationFrame.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFrameIndex'));
elModelAnimationSettings.addEventListener('change', createEmitTextPropertyUpdateFunction('animationSettings'));
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));
@ -419,343 +435,323 @@
action: "resetToNaturalDimensions",
}));
});
var resizing = false;
var startX = 0;
var originalWidth = 0;
var resizeHandleWidth = 10;
var col1 = document.querySelector("#col-label");
document.body.addEventListener('mousemove', function(event) {
if (resizing) {
var dX = event.x - startX;
col1.style.width = (originalWidth + dX) + "px";
}
elRescaleDimensionsButton.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
type: "action",
action: "rescaleDimensions",
percentage: parseInt(elRescaleDimensionsPct.value),
}));
});
document.body.addEventListener('mouseup', function(event) {
resizing = false;
});
document.body.addEventListener('mouseleave', function(event) {
resizing = false;
});
var els = document.querySelectorAll("#properties-table td");
for (var i = 0; i < els.length; i++) {
var el = els[i];
el.addEventListener('mousemove', function(event) {
if (!resizing) {
var distance = this.offsetWidth - event.offsetX;
if (distance < resizeHandleWidth) {
document.body.style.cursor = "ew-resize";
} else {
document.body.style.cursor = "initial";
}
}
});
el.addEventListener('mousedown', function(event) {
var distance = this.offsetWidth - event.offsetX;
if (distance < resizeHandleWidth) {
startX = event.x;
originalWidth = this.offsetWidth;
resizing = true;
target = this;
}
});
}
}
</script>
</head>
<body onload='loaded();'>
<div class="section-header">
<label>Entity Properties</label>
</div>
<table id="properties-table">
<colgroup>
<col id="col-label">
<col>
</colgroup>
<tr>
<td class="label">
ID
</td>
<td>
<body class="properties" onload='loaded();'>
<div id="properties-list">
<div id="type" class="property">
<div class="label">
<label>Type: </label><span id="property-type"></span>
</div>
</div>
<div class="property">
<div class="value">
<label id="property-id" class="selectable"></label>
</td>
</tr>
<tr>
<td class="label">
Type
</td>
<td>
<label id="property-type"></label>
</td>
</tr>
<tr>
<td class="label">Locked</td>
<td>
</div>
</div>
<div class="property">
<div class="label">Locked</div>
<div class="value">
<input type='checkbox' id="property-locked">
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Visible</td>
<td>
<div class="property">
<div class="label">Visible</div>
<div class="value">
<input type='checkbox' id="property-visible">
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Position</td>
<td>
<div class="input-area">X <input class="coord" type='number' id="property-pos-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-pos-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-pos-z"></input></div>
<div class="property">
<div class="label">Position</div>
<div class="value">
<div class="input-area">X <br><input class="coord" type='number' id="property-pos-x"></input></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-pos-y"></input></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-pos-z"></input></div>
<div>
<input type="button" id="move-selection-to-grid" value="Selection to Grid">
<input type="button" id="move-all-to-grid" value="All to Grid">
</div>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Registration</td>
<td>
<div class="property">
<div class="label">Registration</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-reg-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-reg-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-reg-z"></input></div>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Dimensions</td>
<td>
<div class="property">
<div class="label">Dimensions</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-dim-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-dim-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-dim-z"></input></div>
<div>
<input type="button" id="reset-to-natural-dimensions" value="Reset to Natural Dimensions">
</div>
</td>
</tr>
<div class="input-area">
<input class="" type='number' id="dimension-rescale-pct" value=100></input>%
</div>
<span>
<input type="button" id="dimension-rescale-button" value="Rescale"></input>
</span>
</div>
</div>
<tr>
<td class="label">Rotation</td>
<td>
<div class="property">
<div class="label">Rotation</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-rot-x"></input></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-rot-y"></input></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-rot-z"></input></div>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Linear Velocity</td>
<td>
<div class="property">
<div class="label">Linear Velocity</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lvel-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lvel-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lvel-z"></input></div>
</td>
</tr>
<tr>
<td class="label">Linear Damping</td>
<td>
</div>
</div>
<div class="property">
<div class="label">Linear Damping</div>
<div class="value">
<input class="coord" type='number' id="property-ldamping"></input>
</td>
</tr>
<tr>
<td class="label">Angular Velocity</td>
<td>
</div>
</div>
<div class="property">
<div class="label">Angular Velocity</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-avel-x"></input></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-avel-y"></input></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-avel-z"></input></div>
</td>
</tr>
<tr>
<td class="label">Angular Damping</td>
<td>
</div>
</div>
<div class="property">
<div class="label">Angular Damping</div>
<div class="value">
<input class="coord" type='number' id="property-adamping"></input>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Gravity</td>
<td>
<div class="property">
<div class="label">Gravity</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-grav-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-grav-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-grav-z"></input></div>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Mass</td>
<td>
<div class="property">
<div class="label">Mass</div>
<div class="value">
<input type='number' id="property-mass"></input>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Ignore For Collisions</td>
<td>
<div>
<div class="label">Density</div>
<div>
<input type='number' id="property-density"></input>
</div>
</div>
<div class="property">
<div class="label">Ignore For Collisions</div>
<div class="value">
<input type='checkbox' id="property-ignore-for-collisions"></input>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Collisions Will Move</td>
<td>
<div class="property">
<div class="label">Collisions Will Move</div>
<div class="value">
<input type='checkbox' id="property-collisions-will-move"></input>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Lifetime</td>
<td>
<div class="property">
<div class="label">Lifetime</div>
<div class="value">
<input type='number' id="property-lifetime"></input>
</td>
</tr>
</div>
</div>
<tr>
<td class="label">Script URL</td>
<td>
<div class="property">
<div class="label">Script URL</div>
<div class="value">
<input id="property-script-url" class="url"></input>
</td>
</tr>
</div>
</div>
<tr class="box-section">
<td class="label">Color</td>
<td>
<div class="box-section property">
<div class="label">Color</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-box-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-box-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-box-blue"></input></div>
</td>
</tr>
</div>
</div>
<tr class="model-section">
<td class="label">Model URL</td>
<td>
<div class="model-section property">
<div class="label">Model URL</div>
<div class="value">
<input type="text" id="property-model-url" class="url"></input>
</td>
</tr>
<tr class="model-section">
<td class="label">Animation URL</td>
<td>
</div>
</div>
<div class="model-section property">
<div class="label">Animation URL</div>
<div class="value">
<input type="text" id="property-model-animation-url" class="url"></input>
</td>
</tr>
<tr class="model-section">
<td class="label">Animation Playing</td>
<td>
</div>
</div>
<div class="model-section property">
<div class="label">Animation Playing</div>
<div class="value">
<input type='checkbox' id="property-model-animation-playing">
</td>
</tr>
<tr class="model-section">
<td class="label">Animation FPS</td>
<td>
</div>
</div>
<div class="model-section property">
<div class="label">Animation FPS</div>
<div class="value">
<input class="coord" type='number' id="property-model-animation-fps"></input>
</td>
</tr>
<tr class="model-section">
<td class="label">Animation Frame</td>
<td>
</div>
</div>
<div class="model-section property">
<div class="label">Animation Frame</div>
<div class="value">
<input class="coord" type='number' id="property-model-animation-frame"></input>
</td>
</tr>
</div>
</div>
<div class="model-section property">
<div class="label">Animation Settings</div>
<div class="value">
<textarea id="property-model-animation-settings" value='asdfasdf'></textarea>
</div>
</div>
<div class="model-section property">
<div class="label">Textures</div>
<div class="value">
<textarea id="property-model-textures" value='asdfasdf'></textarea>
</div>
</div>
<div class="model-section property">
<div class="label">Original Textures</div>
<div class="value">
<textarea id="property-model-original-textures" readonly value='asdfasdf'></textarea>
</div>
</div>
<tr class="text-section">
<td class="label">Text</td>
<td>
<div class="text-section property">
<div class="label">Text</div>
<div class="value">
<input type="text" id="property-text-text"></input>
</td>
</tr>
<tr class="text-section">
<td class="label">Line Height</td>
<td>
</div>
</div>
<div class="text-section property">
<div class="label">Line Height</div>
<div class="value">
<input class="coord" type='number' id="property-text-line-height"></input>
</td>
</tr>
<tr class="text-section">
<td class="label">Text Color</td>
<td>
</div>
</div>
<div class="text-section property">
<div class="label">Text Color</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></input></div>
</td>
</tr>
<tr class="text-section">
<td class="label">Background Color</td>
<td>
</div>
</div>
<div class="text-section property">
<div class="label">Background Color</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></input></div>
</td>
</tr>
</div>
</div>
<tr class="light-section">
<td class="label">Spot Light</td>
<td>
<div class="light-section property">
<div class="label">Spot Light</div>
<div class="value">
<input type='checkbox' id="property-light-spot-light">
</td>
</tr>
<tr class="light-section">
<td class="label">Diffuse</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Diffuse</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-light-diffuse-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-light-diffuse-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-diffuse-blue"></input></div>
</td>
</tr>
<tr class="light-section">
<td class="label">Ambient</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Ambient</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-light-ambient-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-light-ambient-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-ambient-blue"></input></div>
</td>
</tr>
<tr class="light-section">
<td class="label">Specular</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Specular</div>
<div class="value">
<div class="input-area">R <input class="coord" type='number' id="property-light-specular-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-light-specular-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-specular-blue"></input></div>
</td>
</tr>
<tr class="light-section">
<td class="label">Constant Attenuation</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Constant Attenuation</div>
<div class="value">
<input class="coord" type='number' id="property-light-constant-attenuation"></input>
</td>
</tr>
<tr class="light-section">
<td class="label">Linear Attenuation</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Linear Attenuation</div>
<div class="value">
<input class="coord" type='number' id="property-light-linear-attenuation"></input>
</td>
</tr>
<tr class="light-section">
<td class="label">Quadratic Attenuation</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Quadratic Attenuation</div>
<div class="value">
<input class="coord" type='number' id="property-light-quadratic-attenuation"></input>
</td>
</tr>
<tr class="light-section">
<td class="label">Exponent</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Exponent</div>
<div class="value">
<input class="coord" type='number' id="property-light-exponent"></input>
</td>
</tr>
<tr class="light-section">
<td class="label">Cutoff (degrees)</td>
<td>
</div>
</div>
<div class="light-section property">
<div class="label">Cutoff (degrees)</div>
<div class="value">
<input class="coord" type='number' id="property-light-cutoff"></input>
</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>

View file

@ -6,8 +6,8 @@ body {
padding: 0;
background-color: #efefef;
font-family: Sans-Serif;
font-size: 12px;
font-family: Arial;
font-size: 11.5px;
-webkit-touch-callout: none;
-webkit-user-select: none;
@ -17,6 +17,12 @@ body {
user-select: none;
}
body.properties {
background-color: rgb(76, 76, 76);
color: rgb(204, 204, 204);
font-size: 11px;
}
.selectable {
-webkit-touch-callout: text;
-webkit-user-select: text;
@ -85,25 +91,33 @@ input[type=button] {
border: 0;
color: #fff;
font-weight: bold;
margin: 0 2px;
margin-top: 5px;
font-size: .9em;
}
input {
textarea, input {
margin: 0;
padding: 2px;
border: 1px solid #999;
background-color: #eee;
}
textarea {
width: 100%;
resize: vertical;
}
input.url {
width: 100%;
}
input.coord {
width: 7em;
display: block;
}
table#entity-table {
border-collapse: collapse;
font-family: Sans-Serif;
font-size: 12px;
/* font-size: 12px; */
width: 100%;
}
@ -140,31 +154,62 @@ th#entity-url {
div.input-area {
display: inline-block;
font-size: 10px;
}
input {
}
#type {
font-size: 14px;
}
#type label {
color: rgb(150, 150, 150);
}
#properties-list input, #properties-list textarea {
background-color: rgb(102, 102, 102);
color: rgb(204, 204, 204);
border: none;
font-size: 10px;
}
#properties-list input[type=button] {
cursor: pointer;
background-color: rgb(51, 102, 102);
border-color: #608e96;
border-radius: 5px;
padding: 5px 10px;
border: 0;
color: rgb(204, 204, 204);
}
#properties-list .property {
padding: 8px 8px;
border-top: 1px solid rgb(63, 63, 63);
min-height: 1em;
}
table#properties-table {
table#properties-list {
border: none;
border-collapse: collapse;
width: 100%;
background-color: #efefef;
font-family: Arial;
font-size: 12px;
table-layout: fixed;
}
#properties-table tr {
#properties-list > div {
margin: 4px 0;
}
#properties-list {
border-bottom: 1px solid #e5e5e5;
}
#properties-table td.label {
padding-right: 10px;
border-right: 1px solid #999;
text-align: right;
#properties-list .label {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
@ -174,8 +219,8 @@ table#properties-table {
height: 1.2em;
}
#properties-table td {
padding: 5px;
#properties-list .value > div{
padding: 4px 0;
}
col#col-label {

View file

@ -68,7 +68,7 @@ function Tooltip() {
text += "Lifetime: " + properties.lifetime + "\n"
}
text += "Age: " + properties.ageAsText + "\n"
text += "Mass: " + properties.mass + "\n"
text += "Density: " + properties.density + "\n"
text += "Script: " + properties.script + "\n"

View file

@ -105,6 +105,8 @@ CameraManager = function() {
Camera.mode = "independent";
that.updateCamera();
cameraTool.setVisible(true);
}
that.disable = function(ignoreCamera) {
@ -115,6 +117,7 @@ CameraManager = function() {
if (!ignoreCamera) {
Camera.mode = that.previousCameraMode;
}
cameraTool.setVisible(false);
}
that.focus = function(position, dimensions, easeOrientation) {
@ -243,9 +246,9 @@ CameraManager = function() {
}
that.mousePressEvent = function(event) {
// if (cameraTool.mousePressEvent(event)) {
// return true;
// }
if (cameraTool.mousePressEvent(event)) {
return true;
}
if (!that.enabled) return;
@ -291,7 +294,7 @@ CameraManager = function() {
that.updateCamera = function() {
if (!that.enabled || Camera.mode != "independent") {
// cameraTool.update();
cameraTool.update();
return;
}
@ -313,7 +316,7 @@ CameraManager = function() {
Camera.setOrientation(q);
// cameraTool.update();
cameraTool.update();
}
function normalizeDegrees(degrees) {
@ -383,7 +386,7 @@ CameraManager = function() {
Controller.wheelEvent.connect(that.wheelEvent);
// var cameraTool = new CameraTool(that);
var cameraTool = new CameraTool(that);
return that;
}
@ -395,43 +398,21 @@ CameraTool = function(cameraManager) {
var GREEN = { red: 26, green: 193, blue: 105 };
var BLUE = { red: 0, green: 131, blue: 204 };
var ORIENTATION_OVERLAY_SIZE = 20;
var BORDER_WIDTH = 1;
var ORIENTATION_OVERLAY_SIZE = 26;
var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2;
var ORIENTATION_OVERLAY_CUBE_SIZE = 8,
var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5,
var ORIENTATION_OVERLAY_OFFSET = {
x: 96,
x: 30,
y: 30,
}
var UI_URL = HIFI_PUBLIC_BUCKET + "images/tools/camera-controls.svg";
var UI_WIDTH = 128;
var UI_HEIGHT = 61;
var UI_WIDTH = 70;
var UI_HEIGHT = 70;
var UI_PADDING = 10;
var UI_BUTTON_WIDTH = 64;
var UI_BUTTON_HEIGHT = 30;
var UI_SUBIMAGE_FIRST_PERSON = {
x: 0,
y: 0,
width: UI_WIDTH,
height: UI_HEIGHT
},
var UI_SUBIMAGE_THIRD_PERSON = {
x: 0,
y: UI_HEIGHT,
width: UI_WIDTH,
height: UI_HEIGHT
},
var UI_SUBIMAGE_OTHER = {
x: 0,
y: UI_HEIGHT * 2,
width: UI_WIDTH,
height: UI_HEIGHT
},
var lastKnownWidth = Window.innerWidth;
var uiPosition = {
@ -439,20 +420,28 @@ CameraTool = function(cameraManager) {
y: UI_PADDING,
};
var ui = Overlays.addOverlay("image", {
imageURL: UI_URL,
var backgroundBorder = Overlays.addOverlay("text", {
x: uiPosition.x - BORDER_WIDTH,
y: uiPosition.y - BORDER_WIDTH,
width: UI_WIDTH + BORDER_WIDTH * 2,
height: UI_HEIGHT + BORDER_WIDTH * 2,
alpha: 0,
text: "",
backgroundColor: { red: 101, green: 101, blue: 101 },
backgroundAlpha: 1.0,
visible: false,
});
var background = Overlays.addOverlay("text", {
x: uiPosition.x,
y: uiPosition.y,
subImage: {
x: 0,
y: 0,
width: UI_WIDTH,
height: UI_HEIGHT
},
width: UI_WIDTH,
height: UI_HEIGHT,
alpha: 1.0,
visible: true
alpha: 0,
text: "",
backgroundColor: { red: 51, green: 51, blue: 51 },
backgroundAlpha: 1.0,
visible: false,
});
var defaultCubeProps = {
@ -470,15 +459,16 @@ CameraTool = function(cameraManager) {
start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 },
color: { red: 255, green: 0, blue: 0 },
visible: true,
visible: false,
drawOnHUD: true,
};
var orientationOverlay = OverlayGroup({
position: {
x: uiPosition.x + ORIENTATION_OVERLAY_OFFSET.x,
y: uiPosition.y + ORIENTATION_OVERLAY_OFFSET.y,
}
x: uiPosition.x + UI_WIDTH / 2,
y: uiPosition.y + UI_HEIGHT / 2,
},
visible: false,
});
var OOHS = ORIENTATION_OVERLAY_HALF_SIZE;
@ -512,7 +502,8 @@ CameraTool = function(cameraManager) {
Script.scriptEnding.connect(function() {
orientationOverlay.destroy();
Overlays.deleteOverlay(ui);
Overlays.deleteOverlay(background);
Overlays.deleteOverlay(backgroundBorder);
});
var flip = Quat.fromPitchYawRollDegrees(0, 180, 0);
@ -527,16 +518,20 @@ CameraTool = function(cameraManager) {
x: lastKnownWidth - UI_WIDTH - UI_PADDING,
y: UI_PADDING,
};
Overlays.editOverlay(ui, {
x: uiPosition.x,
y: uiPosition.y
});
orientationOverlay.setProperties({
position: {
x: uiPosition.x + ORIENTATION_OVERLAY_OFFSET.x,
y: uiPosition.y + ORIENTATION_OVERLAY_OFFSET.y,
}
});
Overlays.editOverlay(backgroundBorder, {
x: uiPosition.x - BORDER_WIDTH,
y: uiPosition.y - BORDER_WIDTH,
});
Overlays.editOverlay(background, {
x: uiPosition.x,
y: uiPosition.y,
});
}
}
@ -558,40 +553,16 @@ CameraTool = function(cameraManager) {
targetYaw = event.isLeftButton ? 0 : 180;
cameraManager.setTargetPitchYaw(targetPitch, targetYaw);
return true;
} else if (clickedOverlay == ui) {
var x = event.x - uiPosition.x;
var y = event.y - uiPosition.y;
// Did we hit a button?
if (x < UI_BUTTON_WIDTH) {
if (y < UI_BUTTON_HEIGHT) {
Camera.mode = "first person";
} else {
Camera.mode = "third person";
}
}
return true;
}
};
function updateMode() {
var mode = Camera.mode;
var subImage = UI_SUBIMAGE_OTHER;
if (mode == "first person") {
subImage = UI_SUBIMAGE_FIRST_PERSON;
} else if (mode == "third person") {
subImage = UI_SUBIMAGE_THIRD_PERSON;
}
Overlays.editOverlay(ui, { subImage: subImage });
}
Camera.modeUpdated.connect(updateMode);
updateMode();
that.setVisible = function(visible) {
orientationOverlay.setProperties({ visible: visible });
Overlays.editOverlay(background, { visible: visible });
Overlays.editOverlay(backgroundBorder, { visible: visible });
};
that.setVisible(false);
return that;
};

View file

@ -164,7 +164,7 @@ EntityPropertyDialogBox = (function () {
array.push({ label: "Collisions:", type: "header" });
index++;
array.push({ label: "Mass:", value: properties.mass.toFixed(decimals) });
array.push({ label: "Density:", value: properties.density.toFixed(decimals) });
index++;
array.push({ label: "Ignore for Collisions:", type: "checkbox", value: properties.ignoreForCollisions });
index++;
@ -353,7 +353,7 @@ EntityPropertyDialogBox = (function () {
properties.gravity.z = array[index++].value;
index++; // skip header
properties.mass = array[index++].value;
properties.density = array[index++].value;
properties.ignoreForCollisions = array[index++].value;
properties.collisionsWillMove = array[index++].value;

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
SPACE_LOCAL = "local";
SPACE_WORLD = "world";
@ -242,6 +242,9 @@ SelectionDisplay = (function () {
var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18;
var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17;
var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.png";
var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.png";
var showExtendedStretchHandles = false;
var spaceMode = SPACE_LOCAL;
@ -590,7 +593,7 @@ SelectionDisplay = (function () {
});
var yawHandle = Overlays.addOverlay("billboard", {
url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png",
url: ROTATE_ARROW_WEST_NORTH_URL,
position: { x:0, y: 0, z: 0},
color: rotateHandleColor,
alpha: rotateHandleAlpha,
@ -603,7 +606,7 @@ SelectionDisplay = (function () {
var pitchHandle = Overlays.addOverlay("billboard", {
url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png",
url: ROTATE_ARROW_WEST_NORTH_URL,
position: { x:0, y: 0, z: 0},
color: rotateHandleColor,
alpha: rotateHandleAlpha,
@ -616,7 +619,7 @@ SelectionDisplay = (function () {
var rollHandle = Overlays.addOverlay("billboard", {
url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png",
url: ROTATE_ARROW_WEST_NORTH_URL,
position: { x:0, y: 0, z: 0},
color: rotateHandleColor,
alpha: rotateHandleAlpha,
@ -835,8 +838,8 @@ SelectionDisplay = (function () {
rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far };
Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-south.png" });
Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-south.png" });
Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL });
Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL });
} else {
@ -867,8 +870,8 @@ SelectionDisplay = (function () {
pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z };
rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near};
Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" });
Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" });
Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL });
Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL });
}
} else {
@ -899,8 +902,8 @@ SelectionDisplay = (function () {
pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z };
rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far};
Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" });
Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" });
Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL });
Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL });
} else {
@ -928,8 +931,8 @@ SelectionDisplay = (function () {
rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near };
pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z};
Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" });
Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" });
Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL });
Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL });
}
}

View file

@ -9,7 +9,7 @@ OverlayGroup = function(opts) {
var rootPosition = opts.position || { x: 0, y: 0, z: 0 };
var rootRotation = opts.rotation || Quat.fromPitchYawRollRadians(0, 0, 0);
var visible = true;
var visible = opts.visible == true;
function updateOverlays() {
for (overlayID in overlays) {

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var panelWall = false;
var orbShell = false;
@ -66,20 +66,20 @@ function textOverlayPosition() {
Vec3.multiply(Quat.getUp(Camera.orientation), TEXT_DISTANCE_DOWN));
}
var panelLocationOrder = [
var panelPlaceOrder = [
7, 8, 9, 10, 11, 12, 13,
0, 1, 2, 3, 4, 5, 6,
14, 15, 16, 17, 18, 19, 20
];
// Location index is 0-based
function locationIndexToPanelIndex(locationIndex) {
return panelLocationOrder.indexOf(locationIndex) + 1;
// place index is 0-based
function placeIndexToPanelIndex(placeIndex) {
return panelPlaceOrder.indexOf(placeIndex) + 1;
}
// Panel index is 1-based
function panelIndexToLocationIndex(panelIndex) {
return panelLocationOrder[panelIndex - 1];
function panelIndexToPlaceIndex(panelIndex) {
return panelPlaceOrder[panelIndex - 1];
}
var MAX_NUM_PANELS = 21;
@ -138,33 +138,34 @@ function drawLobby() {
// add an attachment on this avatar so other people see them in the lobby
MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15);
// start the drone sound
currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME });
if (droneSound.downloaded) {
// start the drone sound
currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME });
}
// start one of our muzak sounds
playRandomMuzak();
}
}
var locations = {};
var places = {};
function changeLobbyTextures() {
var req = new XMLHttpRequest();
req.open("GET", "https://data.highfidelity.io/api/v1/locations?limit=21", false);
req.open("GET", "https://data.highfidelity.io/api/v1/places?limit=21", false);
req.send();
locations = JSON.parse(req.responseText).data.locations;
places = JSON.parse(req.responseText).data.places;
var NUM_PANELS = locations.length;
var NUM_PANELS = places.length;
var textureProp = {
textures: {}
};
for (var j = 0; j < NUM_PANELS; j++) {
var panelIndex = locationIndexToPanelIndex(j);
textureProp["textures"]["file" + panelIndex] = HIFI_PUBLIC_BUCKET + "images/locations/"
+ locations[j].id + "/hifi-location-" + locations[j].id + "_640x360.jpg";
var panelIndex = placeIndexToPanelIndex(j);
textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby;
};
Overlays.editOverlay(panelWall, textureProp);
@ -232,7 +233,7 @@ function cleanupLobby() {
Audio.stopInjector(currentMuzakInjector);
currentMuzakInjector = null;
locations = {};
places = {};
toggleEnvironmentRendering(true);
MyAvatar.detachOne(HELMET_ATTACHMENT_URL);
@ -250,14 +251,14 @@ function actionStartEvent(event) {
var panelStringIndex = panelName.indexOf("Panel");
if (panelStringIndex != -1) {
var panelIndex = parseInt(panelName.slice(5));
var locationIndex = panelIndexToLocationIndex(panelIndex);
if (locationIndex < locations.length) {
var actionLocation = locations[locationIndex];
var placeIndex = panelIndexToPlaceIndex(panelIndex);
if (placeIndex < places.length) {
var actionPlace = places[placeIndex];
print("Jumping to " + actionLocation.name + " at " + actionLocation.path
+ " in " + actionLocation.domain.name + " after click on panel " + panelIndex + " with location index " + locationIndex);
print("Jumping to " + actionPlace.name + " at " + actionPlace.address
+ " after click on panel " + panelIndex + " with place index " + placeIndex);
Window.location = actionLocation;
Window.location = actionPlace.address;
maybeCleanupLobby();
}
}
@ -300,15 +301,15 @@ function handleLookAt(pickRay) {
var panelStringIndex = panelName.indexOf("Panel");
if (panelStringIndex != -1) {
var panelIndex = parseInt(panelName.slice(5));
var locationIndex = panelIndexToLocationIndex(panelIndex);
if (locationIndex < locations.length) {
var actionLocation = locations[locationIndex];
var placeIndex = panelIndexToPlaceIndex(panelIndex);
if (placeIndex < places.length) {
var actionPlace = places[placeIndex];
if (actionLocation.description == "") {
Overlays.editOverlay(descriptionText, { text: actionLocation.name, visible: showText });
if (actionPlace.description == "") {
Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText });
} else {
// handle line wrapping
var allWords = actionLocation.description.split(" ");
var allWords = actionPlace.description.split(" ");
var currentGoodLine = "";
var currentTestLine = "";
var formatedDescription = "";
@ -353,7 +354,7 @@ function update(deltaTime) {
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
// if the reticle is up then we may need to play the next muzak
if (!Audio.isInjectorPlaying(currentMuzakInjector)) {
if (currentMuzakInjector && !Audio.isInjectorPlaying(currentMuzakInjector)) {
playNextMuzak();
}
}

View file

@ -259,14 +259,16 @@ function checkSize(){
// Triggers notification if a user logs on or off
function onOnlineUsersChanged(users) {
for (user in users) {
if (last_users.indexOf(users[user]) == -1.0) {
createNotification(users[user] + " has joined");
if (!isStartingUp()) { // Skip user notifications at startup.
for (user in users) {
if (last_users.indexOf(users[user]) == -1.0) {
createNotification(users[user] + " has joined");
}
}
}
for (user in last_users) {
if (users.indexOf(last_users[user]) == -1.0) {
createNotification(last_users[user] + " has left");
for (user in last_users) {
if (users.indexOf(last_users[user]) == -1.0) {
createNotification(last_users[user] + " has left");
}
}
}
last_users = users;
@ -348,17 +350,38 @@ function dismiss(firstNoteOut, firstButOut, firstOut) {
myAlpha.splice(firstOut,1);
}
// This is meant to show users online at startup but currently shows 0 users.
function onConnected() {
// This reports the number of users online at startup
function reportUsers() {
var numUsers = GlobalServices.onlineUsers.length;
var welcome = "Welcome! There are " + numUsers + " users online now.";
createNotification(welcome);
}
var STARTUP_TIMEOUT = 500, // ms
startingUp = true,
startupTimer = null;
function finishStartup() {
startingUp = false;
Script.clearTimeout(startupTimer);
reportUsers();
}
function isStartingUp() {
// Is starting up until get no checks that it is starting up for STARTUP_TIMEOUT
if (startingUp) {
if (startupTimer) {
Script.clearTimeout(startupTimer);
}
startupTimer = Script.setTimeout(finishStartup, STARTUP_TIMEOUT);
}
return startingUp;
}
AudioDevice.muteToggled.connect(onMuteStateChanged);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.mousePressEvent.connect(mousePressEvent);
GlobalServices.connected.connect(onConnected);
GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
GlobalServices.incomingMessage.connect(onIncomingMessage);
Controller.keyReleaseEvent.connect(keyReleaseEvent);

525
examples/realsenseHands.js Normal file
View file

@ -0,0 +1,525 @@
//
// realsenseHands.js
// examples
//
// Created by Thijs Wenker on 18 Dec 2014.
// Copyright 2014 High Fidelity, Inc.
//
// This is an example script that uses the Intel RealSense to make the avatar's hands replicate the user's hand actions.
// Most of this script is copied from leapHands.js
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var leapHands = (function () {
var isOnHMD,
MotionTracker = "RealSense",
LEAP_ON_HMD_MENU_ITEM = "Leap Motion on HMD",
LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip
HMD_OFFSET = 0.070, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief
hasHandAndWristJoints,
handToWristOffset = [], // For avatars without a wrist joint we control an estimate of a proper hand joint position
HAND_OFFSET = 0.4, // Relative distance of wrist to hand versus wrist to index finger knuckle
hands,
wrists,
NUM_HANDS = 2, // 0 = left; 1 = right
fingers,
NUM_FINGERS = 5, // 0 = thumb; ...; 4 = pinky
THUMB = 0,
MIDDLE_FINGER = 2,
NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal joint
MAX_HAND_INACTIVE_COUNT = 20,
calibrationStatus,
UNCALIBRATED = 0,
CALIBRATING = 1,
CALIBRATED = 2,
CALIBRATION_TIME = 1000, // milliseconds
avatarScale,
avatarFaceModelURL,
avatarSkeletonModelURL,
settingsTimer;
function printSkeletonJointNames() {
var jointNames,
i;
print(MyAvatar.skeletonModelURL);
print("Skeleton joint names ...");
jointNames = MyAvatar.getJointNames();
for (i = 0; i < jointNames.length; i += 1) {
print(i + ": " + jointNames[i]);
}
print("... skeleton joint names");
/*
http://public.highfidelity.io/models/skeletons/ron_standing.fst
Skeleton joint names ...
0: Hips
1: RightUpLeg
2: RightLeg
3: RightFoot
4: RightToeBase
5: RightToe_End
6: LeftUpLeg
7: LeftLeg
8: LeftFoot
9: LeftToeBase
10: LeftToe_End
11: Spine
12: Spine1
13: Spine2
14: RightShoulder
15: RightArm
16: RightForeArm
17: RightHand
18: RightHandPinky1
19: RightHandPinky2
20: RightHandPinky3
21: RightHandPinky4
22: RightHandRing1
23: RightHandRing2
24: RightHandRing3
25: RightHandRing4
26: RightHandMiddle1
27: RightHandMiddle2
28: RightHandMiddle3
29: RightHandMiddle4
30: RightHandIndex1
31: RightHandIndex2
32: RightHandIndex3
33: RightHandIndex4
34: RightHandThumb1
35: RightHandThumb2
36: RightHandThumb3
37: RightHandThumb4
38: LeftShoulder
39: LeftArm
40: LeftForeArm
41: LeftHand
42: LeftHandPinky1
43: LeftHandPinky2
44: LeftHandPinky3
45: LeftHandPinky4
46: LeftHandRing1
47: LeftHandRing2
48: LeftHandRing3
49: LeftHandRing4
50: LeftHandMiddle1
51: LeftHandMiddle2
52: LeftHandMiddle3
53: LeftHandMiddle4
54: LeftHandIndex1
55: LeftHandIndex2
56: LeftHandIndex3
57: LeftHandIndex4
58: LeftHandThumb1
59: LeftHandThumb2
60: LeftHandThumb3
61: LeftHandThumb4
62: Neck
63: Head
64: HeadTop_End
65: body
... skeleton joint names
*/
}
function finishCalibration() {
var avatarPosition,
handPosition,
middleFingerPosition,
leapHandHeight,
h;
if (!isOnHMD) {
if (hands[0].controller.isActive() && hands[1].controller.isActive()) {
leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0;
} else {
calibrationStatus = UNCALIBRATED;
return;
}
}
avatarPosition = MyAvatar.position;
for (h = 0; h < NUM_HANDS; h += 1) {
handPosition = MyAvatar.getJointPosition(hands[h].jointName);
if (!hasHandAndWristJoints) {
middleFingerPosition = MyAvatar.getJointPosition(fingers[h][MIDDLE_FINGER][0].jointName);
handToWristOffset[h] = Vec3.multiply(Vec3.subtract(handPosition, middleFingerPosition), 1.0 - HAND_OFFSET);
}
if (isOnHMD) {
// Offset of Leap Motion origin from physical eye position
hands[h].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET };
} else {
hands[h].zeroPosition = {
x: handPosition.x - avatarPosition.x,
y: handPosition.y - avatarPosition.y,
z: avatarPosition.z - handPosition.z
};
hands[h].zeroPosition = Vec3.multiplyQbyV(MyAvatar.orientation, hands[h].zeroPosition);
hands[h].zeroPosition.y = hands[h].zeroPosition.y - leapHandHeight;
}
}
MyAvatar.clearJointData("LeftHand");
MyAvatar.clearJointData("LeftForeArm");
MyAvatar.clearJointData("LeftArm");
MyAvatar.clearJointData("RightHand");
MyAvatar.clearJointData("RightForeArm");
MyAvatar.clearJointData("RightArm");
calibrationStatus = CALIBRATED;
print("Leap Motion: Calibrated");
}
function calibrate() {
var jointNames,
i;
calibrationStatus = CALIBRATING;
avatarScale = MyAvatar.scale;
avatarFaceModelURL = MyAvatar.faceModelURL;
avatarSkeletonModelURL = MyAvatar.skeletonModelURL;
// Does this skeleton have both wrist and hand joints?
hasHandAndWristJoints = false;
jointNames = MyAvatar.getJointNames();
for (i = 0; i < jointNames.length; i += 1) {
hasHandAndWristJoints = hasHandAndWristJoints || jointNames[i].toLowerCase() === "leftwrist";
}
// Set avatar arms vertical, forearms horizontal, as "zero" position for calibration
MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, -90.0));
MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0));
MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 90.0));
MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0));
MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
// Wait for arms to assume their positions before calculating
Script.setTimeout(finishCalibration, CALIBRATION_TIME);
}
function checkCalibration() {
if (calibrationStatus === CALIBRATED) {
return true;
}
if (calibrationStatus !== CALIBRATING) {
calibrate();
}
return false;
}
function setIsOnHMD() {
isOnHMD = Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM);
print("Leap Motion: " + (isOnHMD ? "Is on HMD" : "Is on desk"));
}
function checkSettings() {
if (calibrationStatus > UNCALIBRATED && (MyAvatar.scale !== avatarScale
|| MyAvatar.faceModelURL !== avatarFaceModelURL
|| MyAvatar.skeletonModelURL !== avatarSkeletonModelURL
|| Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM) !== isOnHMD)) {
print("Leap Motion: Recalibrate...");
calibrationStatus = UNCALIBRATED;
setIsOnHMD();
}
}
function setUp() {
wrists = [
{
jointName: "LeftWrist",
controller: Controller.createInputController(MotionTracker, "joint_L_wrist")
},
{
jointName: "RightWrist",
controller: Controller.createInputController(MotionTracker, "joint_R_wrist")
}
];
hands = [
{
jointName: "LeftHand",
controller: Controller.createInputController(MotionTracker, "joint_L_hand"),
inactiveCount: 0
},
{
jointName: "RightHand",
controller: Controller.createInputController(MotionTracker, "joint_R_hand"),
inactiveCount: 0
}
];
// The Leap controller's first joint is the hand-metacarpal joint but this joint's data is not used because it's too
// dependent on the model skeleton exactly matching the Leap skeleton; using just the second and subsequent joints
// seems to work better over all.
fingers = [{}, {}];
fingers[0] = [
[
{ jointName: "LeftHandThumb1", controller: Controller.createInputController(MotionTracker, "joint_L_thumb2") },
{ jointName: "LeftHandThumb2", controller: Controller.createInputController(MotionTracker, "joint_L_thumb3") },
{ jointName: "LeftHandThumb3", controller: Controller.createInputController(MotionTracker, "joint_L_thumb4") }
],
[
{ jointName: "LeftHandIndex1", controller: Controller.createInputController(MotionTracker, "joint_L_index2") },
{ jointName: "LeftHandIndex2", controller: Controller.createInputController(MotionTracker, "joint_L_index3") },
{ jointName: "LeftHandIndex3", controller: Controller.createInputController(MotionTracker, "joint_L_index4") }
],
[
{ jointName: "LeftHandMiddle1", controller: Controller.createInputController(MotionTracker, "joint_L_middle2") },
{ jointName: "LeftHandMiddle2", controller: Controller.createInputController(MotionTracker, "joint_L_middle3") },
{ jointName: "LeftHandMiddle3", controller: Controller.createInputController(MotionTracker, "joint_L_middle4") }
],
[
{ jointName: "LeftHandRing1", controller: Controller.createInputController(MotionTracker, "joint_L_ring2") },
{ jointName: "LeftHandRing2", controller: Controller.createInputController(MotionTracker, "joint_L_ring3") },
{ jointName: "LeftHandRing3", controller: Controller.createInputController(MotionTracker, "joint_L_ring4") }
],
[
{ jointName: "LeftHandPinky1", controller: Controller.createInputController(MotionTracker, "joint_L_pinky2") },
{ jointName: "LeftHandPinky2", controller: Controller.createInputController(MotionTracker, "joint_L_pinky3") },
{ jointName: "LeftHandPinky3", controller: Controller.createInputController(MotionTracker, "joint_L_pinky4") }
]
];
fingers[1] = [
[
{ jointName: "RightHandThumb1", controller: Controller.createInputController(MotionTracker, "joint_R_thumb2") },
{ jointName: "RightHandThumb2", controller: Controller.createInputController(MotionTracker, "joint_R_thumb3") },
{ jointName: "RightHandThumb3", controller: Controller.createInputController(MotionTracker, "joint_R_thumb4") }
],
[
{ jointName: "RightHandIndex1", controller: Controller.createInputController(MotionTracker, "joint_R_index2") },
{ jointName: "RightHandIndex2", controller: Controller.createInputController(MotionTracker, "joint_R_index3") },
{ jointName: "RightHandIndex3", controller: Controller.createInputController(MotionTracker, "joint_R_index4") }
],
[
{ jointName: "RightHandMiddle1", controller: Controller.createInputController(MotionTracker, "joint_R_middle2") },
{ jointName: "RightHandMiddle2", controller: Controller.createInputController(MotionTracker, "joint_R_middle3") },
{ jointName: "RightHandMiddle3", controller: Controller.createInputController(MotionTracker, "joint_R_middle4") }
],
[
{ jointName: "RightHandRing1", controller: Controller.createInputController(MotionTracker, "joint_R_ring2") },
{ jointName: "RightHandRing2", controller: Controller.createInputController(MotionTracker, "joint_R_ring3") },
{ jointName: "RightHandRing3", controller: Controller.createInputController(MotionTracker, "joint_R_ring4") }
],
[
{ jointName: "RightHandPinky1", controller: Controller.createInputController(MotionTracker, "joint_R_pinky2") },
{ jointName: "RightHandPinky2", controller: Controller.createInputController(MotionTracker, "joint_R_pinky3") },
{ jointName: "RightHandPinky3", controller: Controller.createInputController(MotionTracker, "joint_R_pinky4") }
]
];
setIsOnHMD();
settingsTimer = Script.setInterval(checkSettings, 2000);
calibrationStatus = UNCALIBRATED;
}
function moveHands() {
var h,
i,
j,
side,
handOffset,
wristOffset,
handRotation,
locRotation,
cameraOrientation,
inverseAvatarOrientation;
for (h = 0; h < NUM_HANDS; h += 1) {
side = h === 0 ? -1.0 : 1.0;
if (hands[h].controller.isActive()) {
// Calibrate if necessary.
if (!checkCalibration()) {
return;
}
// Hand position ...
handOffset = hands[h].controller.getAbsTranslation();
handRotation = hands[h].controller.getAbsRotation();
if (isOnHMD) {
// Adjust to control wrist position if "hand" joint is at wrist ...
if (!hasHandAndWristJoints) {
wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]);
handOffset = Vec3.sum(handOffset, wristOffset);
}
// Hand offset in camera coordinates ...
handOffset = {
x: hands[h].zeroPosition.x - handOffset.x,
y: hands[h].zeroPosition.y - handOffset.z,
z: hands[h].zeroPosition.z + handOffset.y
};
handOffset.z = -handOffset.z;
// Hand offset in world coordinates ...
cameraOrientation = Camera.getOrientation();
handOffset = Vec3.sum(Camera.getPosition(), Vec3.multiplyQbyV(cameraOrientation, handOffset));
// Hand offset in avatar coordinates ...
inverseAvatarOrientation = Quat.inverse(MyAvatar.orientation);
handOffset = Vec3.subtract(handOffset, MyAvatar.position);
handOffset = Vec3.multiplyQbyV(inverseAvatarOrientation, handOffset);
handOffset.z = -handOffset.z;
handOffset.x = -handOffset.x;
// Hand rotation in camera coordinates ...
handRotation = {
x: handRotation.z,
y: handRotation.y,
z: handRotation.x,
w: handRotation.w
};
// Hand rotation in avatar coordinates ...
if (h === 0) {
handRotation.x = -handRotation.x;
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 }), handRotation);
} else {
handRotation.z = -handRotation.z;
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation);
}
cameraOrientation.x = -cameraOrientation.x;
cameraOrientation.z = -cameraOrientation.z;
handRotation = Quat.multiply(cameraOrientation, handRotation);
handRotation = Quat.multiply(inverseAvatarOrientation, handRotation);
} else {
// Hand offset in camera coordinates ...
handOffset = {
x: -handOffset.x,
y: hands[h].zeroPosition.y + handOffset.y,
z: hands[h].zeroPosition.z - handOffset.z
};
// Hand rotation in camera coordinates ...
handRotation = {
x: handRotation.y,
y: handRotation.z,
z: -handRotation.x,
w: handRotation.w
};
// Hand rotation in avatar coordinates ...
if (h === 0) {
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }),
handRotation);
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 1, y: 0, z: 0 }),
handRotation);
} else {
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }),
handRotation);
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 1, y: 0, z: 0 }),
handRotation);
}
}
// Set hand position and orientation ...
MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true);
// Set finger joints ...
for (i = 0; i < NUM_FINGERS; i += 1) {
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
if (fingers[h][i][j].controller !== null) {
locRotation = fingers[h][i][j].controller.getLocRotation();
if (i === THUMB) {
locRotation = {
x: side * locRotation.y,
y: side * -locRotation.z,
z: side * -locRotation.x,
w: locRotation.w
};
} else {
locRotation = {
x: -locRotation.x,
y: -locRotation.z,
z: -locRotation.y,
w: locRotation.w
};
}
MyAvatar.setJointData(fingers[h][i][j].jointName, locRotation);
}
}
}
hands[h].inactiveCount = 0;
} else {
if (hands[h].inactiveCount < MAX_HAND_INACTIVE_COUNT) {
hands[h].inactiveCount += 1;
if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) {
if (h === 0) {
MyAvatar.clearJointData("LeftHand");
MyAvatar.clearJointData("LeftForeArm");
MyAvatar.clearJointData("LeftArm");
} else {
MyAvatar.clearJointData("RightHand");
MyAvatar.clearJointData("RightForeArm");
MyAvatar.clearJointData("RightArm");
}
}
}
}
}
}
function tearDown() {
var h,
i,
j;
Script.clearInterval(settingsTimer);
for (h = 0; h < NUM_HANDS; h += 1) {
Controller.releaseInputController(hands[h].controller);
Controller.releaseInputController(wrists[h].controller);
for (i = 0; i < NUM_FINGERS; i += 1) {
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
if (fingers[h][i][j].controller !== null) {
Controller.releaseInputController(fingers[h][i][j].controller);
}
}
}
}
}
return {
printSkeletonJointNames: printSkeletonJointNames,
setUp : setUp,
moveHands : moveHands,
tearDown : tearDown
};
}());
//leapHands.printSkeletonJointNames();
leapHands.setUp();
Script.update.connect(leapHands.moveHands);
Script.scriptEnding.connect(leapHands.tearDown);

View file

@ -10,7 +10,7 @@
//
var buttonImageUrl = "https://public.highfidelity.io/images/tools/sit.svg";
var buttonImageUrl = "https://s3.amazonaws.com/hifi-public/images/tools/sit.svg";
var windowDimensions = Controller.getViewportDimensions();

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/220Sine.wav");

View file

@ -11,7 +11,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
// A few sample files you may want to try:

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var soundClip = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav");

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("libraries/globals.js");
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
Script.include("libraries/toolBars.js");
var recordingFile = "recording.rec";

View file

@ -2,7 +2,7 @@ set(TARGET_NAME interface)
project(${TARGET_NAME})
# set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb")
set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb" "RSSDK")
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)

9
interface/external/rssdk/readme.txt vendored Normal file
View file

@ -0,0 +1,9 @@
Instructions for adding the Intel Realsense (RSSDK) to Interface
Thijs Wenker, December 19, 2014
This is Windows only for now.
1. Download the SDK at https://software.intel.com/en-us/intel-realsense-sdk/download
2. Copy the `lib` and `include` folder inside this directory

13
interface/external/sdl2/readme.txt vendored Normal file
View file

@ -0,0 +1,13 @@
Instructions for adding the SDL library (SDL2) to Interface
David Rowe, 11 Jan 2015
You can download the SDL development library from https://www.libsdl.org/. Interface has been tested with version 2.0.3.
1. Copy the include and lib folders into the interface/externals/sdl2 folder.
This readme.txt should be there as well.
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects).
If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sdl2' that contains the two folders mentioned above.
2. Clear your build directory, run cmake and build, and you should be all set.

View file

@ -85,10 +85,13 @@
#include "Util.h"
#include "audio/AudioToolBox.h"
#include "audio/AudioIOStatsRenderer.h"
#include "audio/AudioScope.h"
#include "devices/DdeFaceTracker.h"
#include "devices/Faceshift.h"
#include "devices/Leapmotion.h"
#include "devices/RealSense.h"
#include "devices/MIDIManager.h"
#include "devices/OculusManager.h"
#include "devices/TV3DManager.h"
@ -142,8 +145,42 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
}
}
bool setupEssentials(int& argc, char** argv) {
unsigned int listenPort = 0; // bind to an ephemeral port by default
const char** constArgv = const_cast<const char**>(argv);
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
if (portStr) {
listenPort = atoi(portStr);
}
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
// Set dependencies
auto glCanvas = DependencyManager::set<GLCanvas>();
auto addressManager = DependencyManager::set<AddressManager>();
auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
auto geometryCache = DependencyManager::set<GeometryCache>();
auto glowEffect = DependencyManager::set<GlowEffect>();
auto faceshift = DependencyManager::set<Faceshift>();
auto audio = DependencyManager::set<Audio>();
auto audioScope = DependencyManager::set<AudioScope>();
auto audioIOStatsRenderer = DependencyManager::set<AudioIOStatsRenderer>();
auto deferredLightingEffect = DependencyManager::set<DeferredLightingEffect>();
auto ambientOcclusionEffect = DependencyManager::set<AmbientOcclusionEffect>();
auto textureCache = DependencyManager::set<TextureCache>();
auto animationCache = DependencyManager::set<AnimationCache>();
auto visage = DependencyManager::set<Visage>();
auto ddeFaceTracker = DependencyManager::set<DdeFaceTracker>();
auto modelBlender = DependencyManager::set<ModelBlender>();
auto audioToolBox = DependencyManager::set<AudioToolBox>();
return true;
}
Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
QApplication(argc, argv),
_dependencyManagerIsSetup(setupEssentials(argc, argv)),
_window(new MainWindow(desktop())),
_toolWindow(NULL),
_nodeThread(new QThread(this)),
@ -189,9 +226,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_isVSyncOn(true),
_aboutToQuit(false)
{
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
auto nodeList = DependencyManager::get<NodeList>();
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
// read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
@ -218,27 +257,20 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
_bookmarks = new Bookmarks(); // Before setting up the menu
// call Menu getInstance static method to set up the menu
_window->setMenuBar(Menu::getInstance());
_runningScriptsWidget = new RunningScriptsWidget(_window);
unsigned int listenPort = 0; // bind to an ephemeral port by default
const char** constArgv = const_cast<const char**>(argv);
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
if (portStr) {
listenPort = atoi(portStr);
}
// start the nodeThread so its event loop is running
_nodeThread->start();
// make sure the node thread is given highest priority
_nodeThread->setPriority(QThread::TimeCriticalPriority);
// put the NodeList and datagram processing on the node thread
NodeList* nodeList = NodeList::createInstance(NodeType::Agent, listenPort);
nodeList->moveToThread(_nodeThread);
_datagramProcessor.moveToThread(_nodeThread);
@ -248,7 +280,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// put the audio processing on a separate thread
QThread* audioThread = new QThread(this);
Audio::SharedPointer audioIO = DependencyManager::get<Audio>();
auto audioIO = DependencyManager::get<Audio>();
audioIO->moveToThread(audioThread);
connect(audioThread, &QThread::started, audioIO.data(), &Audio::start);
@ -271,11 +303,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer);
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
connect(nodeList, &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID);
connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);
connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded);
connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled);
connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID);
connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset);
// connect to appropriate slots on AccountManager
AccountManager& accountManager = AccountManager::getInstance();
@ -301,11 +333,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// once the event loop has started, check and signal for an access token
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
AddressManager::SharedPointer addressManager = DependencyManager::get<AddressManager>();
auto addressManager = DependencyManager::get<AddressManager>();
// use our MyAvatar position and quat for address manager path
addressManager->setPositionGetter(getPositionForPath);
addressManager->setOrientationGetter(getOrientationForPath);
connect(addressManager.data(), &AddressManager::rootPlaceNameChanged, this, &Application::updateWindowTitle);
_settings = new QSettings(this);
_numChangedSettings = 0;
@ -325,7 +359,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// move the silentNodeTimer to the _nodeThread
QTimer* silentNodeTimer = new QTimer();
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
connect(silentNodeTimer, SIGNAL(timeout()), nodeList.data(), SLOT(removeSilentNodes()));
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
silentNodeTimer->moveToThread(_nodeThread);
@ -444,7 +478,7 @@ Application::~Application() {
// kill any audio injectors that are still around
AudioScriptingInterface::getInstance().stopAllInjectors();
Audio::SharedPointer audioIO = DependencyManager::get<Audio>();
auto audioIO = DependencyManager::get<Audio>();
// stop the audio process
QMetaObject::invokeMethod(audioIO.data(), "stop", Qt::BlockingQueuedConnection);
@ -459,6 +493,8 @@ Application::~Application() {
Menu::getInstance()->deleteLater();
_myAvatar = NULL;
DependencyManager::destroy<GLCanvas>();
}
void Application::saveSettings() {
@ -734,7 +770,7 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod
foreach(NodeType_t type, destinationNodeTypes) {
// Perform the broadcast for one type
int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(packet, NodeSet() << type);
int nReceivingNodes = DependencyManager::get<NodeList>()->broadcastToNodes(packet, NodeSet() << type);
// Feed number of bytes to corresponding channel of the bandwidth meter, if any (done otherwise)
BandwidthMeter::ChannelIndex channel;
@ -882,13 +918,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
Menu::getInstance()->triggerOption(MenuOption::Chat);
break;
case Qt::Key_N:
if (isMeta) {
Menu::getInstance()->triggerOption(MenuOption::NameLocation);
}
break;
case Qt::Key_Up:
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
if (!isShifted) {
@ -953,7 +982,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
if (isShifted) {
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f);
if (TV3DManager::isConnected()) {
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
TV3DManager::configureCamera(_myCamera, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
}
} else {
@ -966,7 +995,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
if (isShifted) {
_viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f);
if (TV3DManager::isConnected()) {
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
TV3DManager::configureCamera(_myCamera, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
}
@ -1328,7 +1357,7 @@ void Application::dropEvent(QDropEvent *event) {
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
if (snapshotData) {
if (!snapshotData->getDomain().isEmpty()) {
NodeList::getInstance()->getDomainHandler().setHostnameAndPort(snapshotData->getDomain());
DependencyManager::get<NodeList>()->getDomainHandler().setHostnameAndPort(snapshotData->getDomain());
}
_myAvatar->setPosition(snapshotData->getLocation());
@ -1342,7 +1371,7 @@ void Application::dropEvent(QDropEvent *event) {
}
void Application::sendPingPackets() {
QByteArray pingPacket = NodeList::getInstance()->constructPingPacket();
QByteArray pingPacket = DependencyManager::get<NodeList>()->constructPingPacket();
controlledBroadcastToNodes(pingPacket, NodeSet()
<< NodeType::EntityServer
<< NodeType::AudioMixer << NodeType::AvatarMixer
@ -1368,7 +1397,7 @@ void Application::timer() {
_timerStart.start();
// ask the node list to check in with the domain server
NodeList::getInstance()->sendDomainServerCheckIn();
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
}
void Application::idle() {
@ -1424,7 +1453,7 @@ void Application::idle() {
void Application::checkBandwidthMeterClick() {
// ... to be called upon button release
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth) &&
Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
Menu::getInstance()->isOptionChecked(MenuOption::UserInterface) &&
@ -1460,7 +1489,7 @@ void Application::setFullscreen(bool fullscreen) {
}
void Application::setEnable3DTVMode(bool enable3DTVMode) {
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
resizeGL(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
}
@ -1486,7 +1515,7 @@ void Application::setEnableVRMode(bool enableVRMode) {
_myCamera.setHmdRotation(glm::quat());
}
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
resizeGL(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
}
@ -1496,7 +1525,7 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) {
bool Application::mouseOnScreen() const {
if (OculusManager::isConnected()) {
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
return getMouseX() >= 0 && getMouseX() <= glCanvas->getDeviceWidth() &&
getMouseY() >= 0 && getMouseY() <= glCanvas->getDeviceHeight();
}
@ -1538,9 +1567,9 @@ int Application::getMouseDragStartedY() const {
}
FaceTracker* Application::getActiveFaceTracker() {
Faceshift::SharedPointer faceshift = DependencyManager::get<Faceshift>();
Visage::SharedPointer visage = DependencyManager::get<Visage>();
DdeFaceTracker::SharedPointer dde = DependencyManager::get<DdeFaceTracker>();
auto faceshift = DependencyManager::get<Faceshift>();
auto visage = DependencyManager::get<Visage>();
auto dde = DependencyManager::get<DdeFaceTracker>();
return (dde->isActive() ? static_cast<FaceTracker*>(dde.data()) :
(faceshift->isActive() ? static_cast<FaceTracker*>(faceshift.data()) :
@ -1654,9 +1683,10 @@ void Application::init() {
DependencyManager::get<Visage>()->init();
Leapmotion::init();
RealSense::init();
// fire off an immediate domain-server check in now that settings are loaded
NodeList::getInstance()->sendDomainServerCheckIn();
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
_entities.init();
_entities.setViewFrustum(getViewFrustum());
@ -1684,7 +1714,7 @@ void Application::init() {
_metavoxels.init();
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
_rearMirrorTools = new RearMirrorTools(glCanvas.data(), _mirrorViewRect, _settings);
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
@ -1774,7 +1804,7 @@ void Application::updateMouseRay() {
void Application::updateFaceshift() {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateFaceshift()");
Faceshift::SharedPointer faceshift = DependencyManager::get<Faceshift>();
auto faceshift = DependencyManager::get<Faceshift>();
// Update faceshift
faceshift->update();
@ -2104,12 +2134,17 @@ void Application::updateMyAvatar(float deltaTime) {
_myAvatar->update(deltaTime);
{
quint64 now = usecTimestampNow();
quint64 dt = now - _lastSendAvatarDataTime;
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS) {
// send head/hand data to the avatar mixer and voxel server
PerformanceTimer perfTimer("send");
QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData);
packet.append(_myAvatar->toByteArray());
controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer);
_lastSendAvatarDataTime = now;
}
}
@ -2123,7 +2158,7 @@ int Application::sendNackPackets() {
char packet[MAX_PACKET_SIZE];
// iterates thru all nodes in NodeList
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
nodeList->eachNode([&](const SharedNodePointer& node){
@ -2221,7 +2256,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
int inViewServers = 0;
int unknownJurisdictionServers = 0;
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
nodeList->eachNode([&](const SharedNodePointer& node) {
// only send to the NodeTypes that are serverType
@ -2585,7 +2620,7 @@ void Application::updateShadowMap() {
fbo->release();
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
}
@ -2762,7 +2797,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
}
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
DependencyManager::get<DeferredLightingEffect>()->prepare();
if (!selfAvatarOnly) {
@ -2813,6 +2848,8 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
{
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
PROFILE_RANGE("DeferredLighting");
PerformanceTimer perfTimer("lighting");
DependencyManager::get<DeferredLightingEffect>()->render();
@ -2921,7 +2958,7 @@ bool Application::getCascadeShadowsEnabled() {
}
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
float horizontalScale = glCanvas->getDeviceWidth() / 2.0f;
float verticalScale = glCanvas->getDeviceHeight() / 2.0f;
@ -3107,12 +3144,18 @@ void Application::setMenuShortcutsEnabled(bool enabled) {
void Application::updateWindowTitle(){
QString buildVersion = " (build " + applicationVersion() + ")";
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
QString currentPlaceName = DependencyManager::get<AddressManager>()->getRootPlaceName();
if (currentPlaceName.isEmpty()) {
currentPlaceName = nodeList->getDomainHandler().getHostname();
}
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
+ DependencyManager::get<AddressManager>()->getCurrentDomain() + connectionStatus + buildVersion;
+ currentPlaceName + connectionStatus + buildVersion;
#ifndef WIN32
// crashes with vs2013/win32
@ -3124,23 +3167,34 @@ void Application::updateWindowTitle(){
void Application::updateLocationInServer() {
AccountManager& accountManager = AccountManager::getInstance();
DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler();
auto addressManager = DependencyManager::get<AddressManager>();
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
if (accountManager.isLoggedIn() && domainHandler.isConnected() && !domainHandler.getUUID().isNull()) {
if (accountManager.isLoggedIn() && domainHandler.isConnected()
&& (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) {
// construct a QJsonObject given the user's current address information
QJsonObject rootObject;
QJsonObject locationObject;
QString pathString = DependencyManager::get<AddressManager>()->currentPath();
QString pathString = addressManager->currentPath();
const QString LOCATION_KEY_IN_ROOT = "location";
const QString PATH_KEY_IN_LOCATION = "path";
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
const QString PATH_KEY_IN_LOCATION = "path";
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION, domainHandler.getUUID().toString());
if (!addressManager->getRootPlaceID().isNull()) {
const QString PLACE_ID_KEY_IN_LOCATION = "place_id";
locationObject.insert(PLACE_ID_KEY_IN_LOCATION,
uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID()));
} else {
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION,
uuidStringWithoutCurlyBraces(domainHandler.getUUID()));
}
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
@ -3175,7 +3229,7 @@ void Application::domainChanged(const QString& domainHostname) {
void Application::connectedToDomain(const QString& hostname) {
AccountManager& accountManager = AccountManager::getInstance();
const QUuid& domainID = NodeList::getInstance()->getDomainHandler().getUUID();
const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID();
if (accountManager.isLoggedIn() && !domainID.isNull()) {
// update our data-server with the domain-server we're logged in with
@ -3437,6 +3491,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels);
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
scriptEngine->registerGlobalObject("AvatarManager", &_avatarManager);
@ -3461,8 +3516,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
// when the application is about to quit, stop our script engine so it unwinds properly
connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
NodeList* nodeList = NodeList::getInstance();
connect(nodeList, &NodeList::nodeKilled, scriptEngine, &ScriptEngine::nodeKilled);
auto nodeList = DependencyManager::get<NodeList>();
connect(nodeList.data(), &NodeList::nodeKilled, scriptEngine, &ScriptEngine::nodeKilled);
scriptEngine->moveToThread(workerThread);
@ -3922,3 +3977,31 @@ float Application::getRenderResolutionScale() const {
return 1.0f;
}
}
int Application::getRenderAmbientLight() const {
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLightGlobal)) {
return -1;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight0)) {
return 0;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight1)) {
return 1;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight2)) {
return 2;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight3)) {
return 3;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight4)) {
return 4;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight5)) {
return 5;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight6)) {
return 6;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight7)) {
return 7;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight8)) {
return 8;
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderAmbientLight9)) {
return 9;
} else {
return -1;
}
}

View file

@ -33,11 +33,13 @@
#include <NodeList.h>
#include <OctreeQuery.h>
#include <PacketHeaders.h>
#include <PhysicsEngine.h>
#include <ScriptEngine.h>
#include <TextureCache.h>
#include <ViewFrustum.h>
#include "Audio.h"
#include "Bookmarks.h"
#include "Camera.h"
#include "DatagramProcessor.h"
#include "Environment.h"
@ -111,6 +113,10 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.722f;
static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.56f;
static const float MIRROR_FIELD_OF_VIEW = 30.0f;
// 70 times per second - target is 60hz, but this helps account for any small deviations
// in the update loop
static const quint64 MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS = (1000 * 1000) / 70;
static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND;
static const QString INFO_HELP_PATH = "html/interface-welcome-allsvg.html";
@ -282,6 +288,7 @@ public:
bool isLookingAtMyAvatar(Avatar* avatar);
float getRenderResolutionScale() const;
int getRenderAmbientLight() const;
unsigned int getRenderTargetFramerate() const;
bool isVSyncOn() const;
@ -296,6 +303,8 @@ public:
QRect getDesirableApplicationGeometry();
RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; }
Bookmarks* getBookmarks() const { return _bookmarks; }
signals:
/// Fired when we're simulating; allows external parties to hook in.
@ -425,6 +434,7 @@ private:
int sendNackPackets();
bool _dependencyManagerIsSetup;
MainWindow* _window;
ToolWindow* _toolWindow;
@ -566,9 +576,13 @@ private:
quint64 _lastNackTime;
quint64 _lastSendDownstreamAudioStats;
quint64 _lastSendAvatarDataTime;
bool _isVSyncOn;
bool _aboutToQuit;
Bookmarks* _bookmarks;
};
#endif // hifi_Application_h

View file

@ -25,6 +25,7 @@
#include <mmdeviceapi.h>
#include <devicetopology.h>
#include <Functiondiscoverykeys_devpkey.h>
#include <VersionHelpers.h>
#endif
#include <AudioConstants.h>
@ -179,12 +180,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
#ifdef WIN32
QString deviceName;
//Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that.
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
const DWORD VISTA_MAJOR_VERSION = 6;
if (osvi.dwMajorVersion < VISTA_MAJOR_VERSION) {// lower then vista
if (!IsWindowsVistaOrGreater()) { // lower then vista
if (mode == QAudio::AudioInput) {
WAVEINCAPS wic;
// first use WAVE_MAPPER to get the default devices manufacturer ID
@ -223,9 +219,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
pPropertyStore->Release();
pPropertyStore = NULL;
deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal);
const DWORD WINDOWS7_MAJOR_VERSION = 6;
const DWORD WINDOWS7_MINOR_VERSION = 1;
if (osvi.dwMajorVersion <= WINDOWS7_MAJOR_VERSION && osvi.dwMinorVersion <= WINDOWS7_MINOR_VERSION) {
if (!IsWindows8OrGreater()) {
// Windows 7 provides only the 31 first characters of the device name.
const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31;
deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN);
@ -691,7 +685,7 @@ void Audio::handleAudioInput() {
emit inputReceived(QByteArray(reinterpret_cast<const char*>(networkAudioSamples),
AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL));
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
if (_recorder && _recorder.data()->isRecording()) {
@ -802,11 +796,12 @@ void Audio::sendMuteEnvironmentPacket() {
mutePacketStream.writeBytes(reinterpret_cast<const char *>(&MUTE_RADIUS), sizeof(float));
// grab our audio mixer from the NodeList, if it exists
SharedNodePointer audioMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer);
auto nodelist = DependencyManager::get<NodeList>();
SharedNodePointer audioMixer = nodelist->soloNodeOfType(NodeType::AudioMixer);
if (audioMixer) {
// send off this mute packet
NodeList::getInstance()->writeDatagram(mutePacket, audioMixer);
nodelist->writeDatagram(mutePacket, audioMixer);
}
}
@ -880,7 +875,7 @@ bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* inje
localFormat.setChannelCount(isStereo ? 2 : 1);
QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName),
localFormat, this);
localFormat);
localOutput->setVolume(volume);
// move the localOutput to the same thread as the local injector buffer
@ -899,6 +894,7 @@ bool Audio::outputLocalInjector(bool isStereo, qreal volume, AudioInjector* inje
return false;
}
void Audio::outputFormatChanged() {
int outputFormatChannelCountTimesSampleRate = _outputFormat.channelCount() * _outputFormat.sampleRate();
_outputFrameSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * outputFormatChannelCountTimesSampleRate / _desiredOutputFormat.sampleRate();

View file

@ -73,9 +73,9 @@ class QAudioInput;
class QAudioOutput;
class QIODevice;
class Audio : public AbstractAudioInterface {
class Audio : public AbstractAudioInterface, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY(Audio)
SINGLETON_DEPENDENCY
public:
class AudioOutputIODevice : public QIODevice {

View file

@ -0,0 +1,73 @@
//
// Bookmarks.cpp
// interface/src
//
// Created by David Rowe on 13 Jan 2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QFile>
#include <QJsonDocument>
#include <QStandardPaths>
#include "Bookmarks.h"
Bookmarks::Bookmarks() {
_bookmarksFilename = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + BOOKMARKS_FILENAME;
readFromFile();
}
void Bookmarks::insert(const QString& name, const QString& address) {
_bookmarks.insert(name, address);
if (contains(name)) {
qDebug() << "Added bookmark:" << name << "," << address;
persistToFile();
} else {
qWarning() << "Couldn't add bookmark: " << name << "," << address;
}
}
void Bookmarks::remove(const QString& name) {
_bookmarks.remove(name);
if (!contains(name)) {
qDebug() << "Deleted bookmark:" << name;
persistToFile();
} else {
qWarning() << "Couldn't delete bookmark:" << name;
}
}
bool Bookmarks::contains(const QString& name) const {
return _bookmarks.contains(name);
}
void Bookmarks::readFromFile() {
QFile loadFile(_bookmarksFilename);
if (!loadFile.open(QIODevice::ReadOnly)) {
qWarning("Couldn't open bookmarks file for reading");
return;
}
QByteArray data = loadFile.readAll();
QJsonDocument json(QJsonDocument::fromJson(data));
_bookmarks = json.object().toVariantMap();
}
void Bookmarks::persistToFile() {
QFile saveFile(_bookmarksFilename);
if (!saveFile.open(QIODevice::WriteOnly)) {
qWarning("Couldn't open bookmarks file for writing");
return;
}
QJsonDocument json(QJsonObject::fromVariantMap(_bookmarks));
QByteArray data = json.toJson();
saveFile.write(data);
}

41
interface/src/Bookmarks.h Normal file
View file

@ -0,0 +1,41 @@
//
// Bookmarks.h
// interface/src
//
// Created by David Rowe on 13 Jan 2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_Bookmarks_h
#define hifi_Bookmarks_h
#include <QJsonObject>
#include <QDebug>
#include <QMap>
#include <QObject>
class Bookmarks: public QObject {
Q_OBJECT
public:
Bookmarks();
void insert(const QString& name, const QString& address); // Overwrites any existing entry with same name.
void remove(const QString& name);
bool contains(const QString& name) const;
QVariantMap* getBookmarks() { return &_bookmarks; };
private:
QVariantMap _bookmarks; // { name: address, ... }
const QString BOOKMARKS_FILENAME = "bookmarks.json";
QString _bookmarksFilename;
void readFromFile();
void persistToFile();
};
#endif // hifi_Bookmarks_h

View file

@ -122,7 +122,7 @@ void Camera::setFarClip(float f) {
}
PickRay Camera::computePickRay(float x, float y) {
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
return computeViewPickRay(x / glCanvas->width(), y / glCanvas->height());
}

View file

@ -34,9 +34,9 @@ void DatagramProcessor::processDatagrams() {
static QByteArray incomingPacket;
Application* application = Application::getInstance();
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) {
while (DependencyManager::get<NodeList>()->getNodeSocket().hasPendingDatagrams()) {
incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(),
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
@ -88,8 +88,7 @@ void DatagramProcessor::processDatagrams() {
case PacketTypeEnvironmentData: {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::networkReceive()... _octreeProcessor.queueReceivedPacket()");
SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(incomingPacket);
SharedNodePointer matchedNode = DependencyManager::get<NodeList>()->sendingNodeForPacket(incomingPacket);
if (matchedNode) {
// add this packet to our list of octree packets and process them on the octree data processing

View file

@ -19,9 +19,9 @@
#include <DependencyManager.h>
/// customized canvas that simply forwards requests/events to the singleton application
class GLCanvas : public QGLWidget {
class GLCanvas : public QGLWidget, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY(GLCanvas)
SINGLETON_DEPENDENCY
public:
bool isThrottleRendering() const;

View file

@ -11,9 +11,9 @@
#include <cstdlib>
#include <QBoxLayout>
#include <QColorDialog>
#include <QClipboard>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFileDialog>
@ -44,20 +44,27 @@
#include "Audio.h"
#include "audio/AudioIOStatsRenderer.h"
#include "audio/AudioScope.h"
#include "devices/Faceshift.h"
#include "devices/OculusManager.h"
#include "devices/RealSense.h"
#include "devices/Visage.h"
#include "Menu.h"
#include "scripting/LocationScriptingInterface.h"
#include "scripting/MenuScriptingInterface.h"
#include "Util.h"
#include "ui/AddressBarDialog.h"
#include "ui/AnimationsDialog.h"
#include "ui/AttachmentsDialog.h"
#include "ui/BandwidthDialog.h"
#include "ui/CachesSizeDialog.h"
#include "ui/DataWebDialog.h"
#include "ui/HMDToolsDialog.h"
#include "ui/LodToolsDialog.h"
#include "ui/LoginDialog.h"
#include "ui/OctreeStatsDialog.h"
#include "ui/PreferencesDialog.h"
#include "ui/InfoView.h"
#include "ui/MetavoxelEditor.h"
#include "ui/MetavoxelNetworkSimulator.h"
#include "ui/ModelsBrowser.h"
#include "ui/LoginDialog.h"
#include "ui/NodeBounds.h"
Menu* Menu::_instance = NULL;
@ -79,56 +86,9 @@ Menu* Menu::getInstance() {
return _instance;
}
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;
const int ONE_SECOND_OF_FRAMES = 60;
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
const QString CONSOLE_TITLE = "Scripting Console";
const float CONSOLE_WINDOW_OPACITY = 0.95f;
const int CONSOLE_WIDTH = 800;
const int CONSOLE_HEIGHT = 200;
Menu::Menu() :
_actionHash(),
_receivedAudioStreamSettings(),
_bandwidthDialog(NULL),
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
_realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
_faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION),
_faceshiftHostname(DEFAULT_FACESHIFT_HOSTNAME),
_jsConsole(NULL),
_octreeStatsDialog(NULL),
_lodToolsDialog(NULL),
_hmdToolsDialog(NULL),
_newLocationDialog(NULL),
_userLocationsDialog(NULL),
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
_speechRecognizer(),
#endif
_octreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
_oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE),
_sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED),
_invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS),
_automaticAvatarLOD(true),
_avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS),
_avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS),
_avatarLODDistanceMultiplier(DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER),
_boundaryLevelAdjust(0),
_maxOctreePacketsPerSecond(DEFAULT_MAX_OCTREE_PPS),
_lastAdjust(usecTimestampNow()),
_lastAvatarDetailDrop(usecTimestampNow()),
_fpsAverage(FIVE_SECONDS_OF_FRAMES),
_fastFPSAverage(ONE_SECOND_OF_FRAMES),
_loginAction(NULL),
_preferencesDialog(NULL),
_loginDialog(NULL),
_hasLoginDialogDisplayed(false),
_snapshotsLocation(),
_scriptsLocation(),
_walletPrivateKey(),
_shouldRenderTableNeedsRebuilding(true)
_lastAvatarDetailDrop(usecTimestampNow())
{
Application *appInstance = Application::getInstance();
@ -164,22 +124,25 @@ Menu::Menu() :
addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
appInstance, SLOT(toggleRunningScriptsWidget()));
addDisabledActionAndSeparator(fileMenu, "Go");
addActionToQMenuAndActionHash(fileMenu,
MenuOption::NameLocation,
Qt::CTRL | Qt::Key_N,
this,
SLOT(nameLocation()));
addActionToQMenuAndActionHash(fileMenu,
MenuOption::MyLocations,
Qt::CTRL | Qt::Key_K,
this,
SLOT(toggleLocationList()));
addDisabledActionAndSeparator(fileMenu, "Location");
addActionToQMenuAndActionHash(fileMenu, MenuOption::BookmarkLocation, 0,
this, SLOT(bookmarkLocation()));
_bookmarksMenu = fileMenu->addMenu(MenuOption::Bookmarks);
_bookmarksMenu->setEnabled(false);
_deleteBookmarksMenu = addActionToQMenuAndActionHash(fileMenu,
MenuOption::DeleteBookmark, 0,
this, SLOT(deleteBookmark()));
_deleteBookmarksMenu->setEnabled(false);
loadBookmarks();
addActionToQMenuAndActionHash(fileMenu,
MenuOption::AddressBar,
Qt::Key_Enter,
this,
SLOT(toggleAddressBar()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0,
this, SLOT(copyAddress()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0,
this, SLOT(copyPath()));
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0,
@ -303,7 +266,7 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
avatar, SLOT(updateMotionBehavior()));
QMenu* collisionsMenu = avatarMenu->addMenu("Collide With...");
QMenu* collisionsMenu = avatarMenu->addMenu("Collide With");
addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideAsRagdoll, 0, false,
avatar, SLOT(onToggleRagdoll()));
addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideWithAvatars,
@ -354,11 +317,8 @@ Menu::Menu() :
QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders");
NodeBounds& nodeBounds = appInstance->getNodeBoundsDisplay();
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersVoxelNodes,
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
&nodeBounds, SLOT(setShowVoxelNodes(bool)));
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
Qt::CTRL | Qt::SHIFT | Qt::Key_2, false,
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
&nodeBounds, SLOT(setShowEntityNodes(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false);
@ -383,6 +343,21 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DisableAutoAdjustLOD);
QMenu* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
ambientLightGroup->setExclusive(true);
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
@ -484,6 +459,11 @@ Menu::Menu() :
QMenu* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion");
addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false);
#ifdef HAVE_RSSDK
QMenu* realSenseOptionsMenu = handOptionsMenu->addMenu("RealSense");
addActionToQMenuAndActionHash(realSenseOptionsMenu, MenuOption::LoadRSSDKFile, 0, this, SLOT(loadRSSDKFile()));
#endif
QMenu* networkMenu = developerMenu->addMenu("Network");
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false);
addCheckableActionToQMenuAndActionHash(networkMenu,
@ -492,6 +472,7 @@ Menu::Menu() :
false,
&UserActivityLogger::getInstance(),
SLOT(disable(bool)));
addActionToQMenuAndActionHash(networkMenu, MenuOption::CachesSize, 0, this, SLOT(cachesSizeDialog()));
addActionToQMenuAndActionHash(developerMenu, MenuOption::WalletPrivateKey, 0, this, SLOT(changePrivateKey()));
@ -510,7 +491,7 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings);
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings);
Audio::SharedPointer audioIO = DependencyManager::get<Audio>();
auto audioIO = DependencyManager::get<Audio>();
QMenu* audioDebugMenu = developerMenu->addMenu("Audio");
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction,
0,
@ -559,7 +540,7 @@ Menu::Menu() :
audioSourceGroup->addAction(sine440);
}
AudioScope::SharedPointer scope = DependencyManager::get<AudioScope>();
auto scope = DependencyManager::get<AudioScope>();
QMenu* audioScopeMenu = audioDebugMenu->addMenu("Audio Scope");
addCheckableActionToQMenuAndActionHash(audioScopeMenu, MenuOption::AudioScope,
@ -597,7 +578,7 @@ Menu::Menu() :
audioScopeFramesGroup->addAction(fiftyFrames);
}
AudioIOStatsRenderer::SharedPointer statsRenderer = DependencyManager::get<AudioIOStatsRenderer>();
auto statsRenderer = DependencyManager::get<AudioIOStatsRenderer>();
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStats,
Qt::CTRL | Qt::SHIFT | Qt::Key_A,
false,
@ -619,15 +600,6 @@ Menu::Menu() :
#endif
}
Menu::~Menu() {
bandwidthDetailsClosed();
octreeStatsDetailsClosed();
if (_hmdToolsDialog) {
delete _hmdToolsDialog;
_hmdToolsDialog = NULL;
}
}
void Menu::loadSettings(QSettings* settings) {
bool lockedSettings = false;
if (!settings) {
@ -644,7 +616,7 @@ void Menu::loadSettings(QSettings* settings) {
_receivedAudioStreamSettings._windowSecondsForDesiredReduction = settings->value("windowSecondsForDesiredReduction", DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION).toInt();
_receivedAudioStreamSettings._repetitionWithFade = settings->value("repetitionWithFade", DEFAULT_REPETITION_WITH_FADE).toBool();
QSharedPointer<Audio> audio = DependencyManager::get<Audio>();
auto audio = DependencyManager::get<Audio>();
audio->setOutputStarveDetectionEnabled(settings->value("audioOutputStarveDetectionEnabled", DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED).toBool());
audio->setOutputStarveDetectionThreshold(settings->value("audioOutputStarveDetectionThreshold", DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_THRESHOLD).toInt());
audio->setOutputStarveDetectionPeriod(settings->value("audioOutputStarveDetectionPeriod", DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_PERIOD).toInt());
@ -678,7 +650,7 @@ void Menu::loadSettings(QSettings* settings) {
Application::getInstance()->updateWindowTitle();
// notify that a settings has changed
connect(&NodeList::getInstance()->getDomainHandler(), &DomainHandler::hostnameChanged, this, &Menu::bumpSettings);
connect(&DependencyManager::get<NodeList>()->getDomainHandler(), &DomainHandler::hostnameChanged, this, &Menu::bumpSettings);
// MyAvatar caches some menu options, so we have to update them whenever we load settings.
// TODO: cache more settings in MyAvatar that are checked with very high frequency.
@ -709,7 +681,7 @@ void Menu::saveSettings(QSettings* settings) {
settings->setValue("windowSecondsForDesiredReduction", _receivedAudioStreamSettings._windowSecondsForDesiredReduction);
settings->setValue("repetitionWithFade", _receivedAudioStreamSettings._repetitionWithFade);
QSharedPointer<Audio> audio = DependencyManager::get<Audio>();
auto audio = DependencyManager::get<Audio>();
settings->setValue("audioOutputStarveDetectionEnabled", audio->getOutputStarveDetectionEnabled());
settings->setValue("audioOutputStarveDetectionThreshold", audio->getOutputStarveDetectionThreshold());
settings->setValue("audioOutputStarveDetectionPeriod", audio->getOutputStarveDetectionPeriod());
@ -960,7 +932,7 @@ void Menu::bumpSettings() {
void sendFakeEnterEvent() {
QPoint lastCursorPosition = QCursor::pos();
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
QPoint windowPosition = glCanvas->mapFromGlobal(lastCursorPosition);
QEnterEvent enterEvent = QEnterEvent(windowPosition, windowPosition, lastCursorPosition);
@ -1059,10 +1031,143 @@ void Menu::toggleAddressBar() {
}
}
void Menu::copyAddress() {
auto addressManager = DependencyManager::get<AddressManager>();
QString address = addressManager->currentAddress().toString();
QClipboard* clipboard = QApplication::clipboard();
clipboard->setText(address);
}
void Menu::copyPath() {
auto addressManager = DependencyManager::get<AddressManager>();
QString path = addressManager->currentPath();
QClipboard* clipboard = QApplication::clipboard();
clipboard->setText(path);
}
void Menu::changeVSync() {
Application::getInstance()->setVSyncEnabled(isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn));
}
void Menu::loadBookmarks() {
QVariantMap* bookmarks = Application::getInstance()->getBookmarks()->getBookmarks();
if (bookmarks->count() > 0) {
QMapIterator<QString, QVariant> i(*bookmarks);
while (i.hasNext()) {
i.next();
QString bookmarkName = i.key();
QString bookmarkAddress = i.value().toString();
QAction* teleportAction = new QAction(getMenu(MenuOption::Bookmarks));
teleportAction->setData(bookmarkAddress);
connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark()));
addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, bookmarkName, 0, QAction::NoRole);
}
_bookmarksMenu->setEnabled(true);
_deleteBookmarksMenu->setEnabled(true);
}
}
void Menu::bookmarkLocation() {
QInputDialog bookmarkLocationDialog(Application::getInstance()->getWindow());
bookmarkLocationDialog.setWindowTitle("Bookmark Location");
bookmarkLocationDialog.setLabelText("Name:");
bookmarkLocationDialog.setInputMode(QInputDialog::TextInput);
bookmarkLocationDialog.resize(400, 200);
if (bookmarkLocationDialog.exec() == QDialog::Rejected) {
return;
}
QString bookmarkName = bookmarkLocationDialog.textValue().trimmed();
bookmarkName = bookmarkName.replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
if (bookmarkName.length() == 0) {
return;
}
auto addressManager = DependencyManager::get<AddressManager>();
QString bookmarkAddress = addressManager->currentAddress().toString();
Bookmarks* bookmarks = Application::getInstance()->getBookmarks();
if (bookmarks->contains(bookmarkName)) {
QMessageBox duplicateBookmarkMessage;
duplicateBookmarkMessage.setIcon(QMessageBox::Warning);
duplicateBookmarkMessage.setText("The bookmark name you entered already exists in your list.");
duplicateBookmarkMessage.setInformativeText("Would you like to overwrite it?");
duplicateBookmarkMessage.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
duplicateBookmarkMessage.setDefaultButton(QMessageBox::Yes);
if (duplicateBookmarkMessage.exec() == QMessageBox::No) {
return;
}
removeAction(_bookmarksMenu, bookmarkName);
}
QAction* teleportAction = new QAction(getMenu(MenuOption::Bookmarks));
teleportAction->setData(bookmarkAddress);
connect(teleportAction, SIGNAL(triggered()), this, SLOT(teleportToBookmark()));
QList<QAction*> menuItems = _bookmarksMenu->actions();
int position = 0;
while (position < menuItems.count() && bookmarkName > menuItems[position]->text()) {
position += 1;
}
addActionToQMenuAndActionHash(_bookmarksMenu, teleportAction, bookmarkName, 0,
QAction::NoRole, position);
bookmarks->insert(bookmarkName, bookmarkAddress); // Overwrites any item with the same bookmarkName.
_bookmarksMenu->setEnabled(true);
_deleteBookmarksMenu->setEnabled(true);
}
void Menu::teleportToBookmark() {
QAction *action = qobject_cast<QAction *>(sender());
QString address = action->data().toString();
DependencyManager::get<AddressManager>()->handleLookupString(address);
}
void Menu::deleteBookmark() {
QStringList bookmarkList;
QList<QAction*> menuItems = _bookmarksMenu->actions();
for (int i = 0; i < menuItems.count(); i += 1) {
bookmarkList.append(menuItems[i]->text());
}
QInputDialog deleteBookmarkDialog(Application::getInstance()->getWindow());
deleteBookmarkDialog.setWindowTitle("Delete Bookmark");
deleteBookmarkDialog.setLabelText("Select the bookmark to delete");
deleteBookmarkDialog.resize(400, 400);
deleteBookmarkDialog.setOption(QInputDialog::UseListViewForComboBoxItems);
deleteBookmarkDialog.setComboBoxItems(bookmarkList);
deleteBookmarkDialog.setOkButtonText("Delete");
if (deleteBookmarkDialog.exec() == QDialog::Rejected) {
return;
}
QString bookmarkName = deleteBookmarkDialog.textValue().trimmed();
if (bookmarkName.length() == 0) {
return;
}
removeAction(_bookmarksMenu, bookmarkName);
Bookmarks* bookmarks = Application::getInstance()->getBookmarks();
bookmarks->remove(bookmarkName);
if (_bookmarksMenu->actions().count() == 0) {
_bookmarksMenu->setEnabled(false);
_deleteBookmarksMenu->setEnabled(false);
}
}
void Menu::displayNameLocationResponse(const QString& errorString) {
if (!errorString.isEmpty()) {
@ -1072,66 +1177,6 @@ void Menu::displayNameLocationResponse(const QString& errorString) {
}
}
void Menu::toggleLocationList() {
if (!_userLocationsDialog) {
JavascriptObjectMap locationObjectMap;
locationObjectMap.insert("InterfaceLocation", DependencyManager::get<AddressManager>().data());
_userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap);
}
if (!_userLocationsDialog->isVisible()) {
_userLocationsDialog->show();
}
_userLocationsDialog->raise();
_userLocationsDialog->activateWindow();
_userLocationsDialog->showNormal();
}
void Menu::nameLocation() {
// check if user is logged in or show login dialog if not
AccountManager& accountManager = AccountManager::getInstance();
if (!accountManager.isLoggedIn()) {
QMessageBox msgBox;
msgBox.setText("We need to tie this location to your username.");
msgBox.setInformativeText("Please login first, then try naming the location again.");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.button(QMessageBox::Ok)->setText("Login");
if (msgBox.exec() == QMessageBox::Ok) {
loginForCurrentDomain();
}
return;
}
DomainHandler& domainHandler = NodeList::getInstance()->getDomainHandler();
if (domainHandler.getUUID().isNull()) {
const QString UNREGISTERED_DOMAIN_MESSAGE = "This domain is not registered with High Fidelity."
"\n\nYou cannot create a global location in an unregistered domain.";
QMessageBox::critical(this, "Unregistered Domain", UNREGISTERED_DOMAIN_MESSAGE);
return;
}
if (!_newLocationDialog) {
JavascriptObjectMap locationObjectMap;
locationObjectMap.insert("InterfaceLocation", DependencyManager::get<AddressManager>().data());
_newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap);
}
if (!_newLocationDialog->isVisible()) {
_newLocationDialog->show();
}
_newLocationDialog->raise();
_newLocationDialog->activateWindow();
_newLocationDialog->showNormal();
}
void Menu::toggleLoginMenuItem() {
AccountManager& accountManager = AccountManager::getInstance();
@ -1153,7 +1198,7 @@ void Menu::bandwidthDetails() {
if (! _bandwidthDialog) {
_bandwidthDialog = new BandwidthDialog(DependencyManager::get<GLCanvas>().data(),
Application::getInstance()->getBandwidthMeter());
connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed()));
connect(_bandwidthDialog, SIGNAL(closed()), _bandwidthDialog, SLOT(deleteLater()));
_bandwidthDialog->show();
@ -1203,6 +1248,10 @@ void Menu::showChat() {
}
}
void Menu::loadRSSDKFile() {
RealSense::getInstance()->loadRSSDKFile();
}
void Menu::toggleChat() {
#ifdef HAVE_QXMPP
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
@ -1253,18 +1302,11 @@ void Menu::audioMuteToggled() {
}
}
void Menu::bandwidthDetailsClosed() {
if (_bandwidthDialog) {
delete _bandwidthDialog;
_bandwidthDialog = NULL;
}
}
void Menu::octreeStatsDetails() {
if (!_octreeStatsDialog) {
_octreeStatsDialog = new OctreeStatsDialog(DependencyManager::get<GLCanvas>().data(),
Application::getInstance()->getOcteeSceneStats());
connect(_octreeStatsDialog, SIGNAL(closed()), SLOT(octreeStatsDetailsClosed()));
connect(_octreeStatsDialog, SIGNAL(closed()), _octreeStatsDialog, SLOT(deleteLater()));
_octreeStatsDialog->show();
if (_hmdToolsDialog) {
_hmdToolsDialog->watchWindow(_octreeStatsDialog->windowHandle());
@ -1273,13 +1315,6 @@ void Menu::octreeStatsDetails() {
_octreeStatsDialog->raise();
}
void Menu::octreeStatsDetailsClosed() {
if (_octreeStatsDialog) {
delete _octreeStatsDialog;
_octreeStatsDialog = NULL;
}
}
QString Menu::getLODFeedbackText() {
// determine granularity feedback
int boundaryLevelAdjust = getBoundaryLevelAdjust();
@ -1443,11 +1478,23 @@ bool Menu::shouldRenderMesh(float largestDimension, float distanceToCamera) {
return (distanceToCamera <= visibleDistanceAtClosestScale);
}
void Menu::cachesSizeDialog() {
qDebug() << "Caches size:" << _cachesSizeDialog.isNull();
if (!_cachesSizeDialog) {
_cachesSizeDialog = new CachesSizeDialog(DependencyManager::get<GLCanvas>().data());
connect(_cachesSizeDialog, SIGNAL(closed()), _cachesSizeDialog, SLOT(deleteLater()));
_cachesSizeDialog->show();
if (_hmdToolsDialog) {
_hmdToolsDialog->watchWindow(_cachesSizeDialog->windowHandle());
}
}
_cachesSizeDialog->raise();
}
void Menu::lodTools() {
if (!_lodToolsDialog) {
_lodToolsDialog = new LodToolsDialog(DependencyManager::get<GLCanvas>().data());
connect(_lodToolsDialog, SIGNAL(closed()), SLOT(lodToolsClosed()));
connect(_lodToolsDialog, SIGNAL(closed()), _lodToolsDialog, SLOT(deleteLater()));
_lodToolsDialog->show();
if (_hmdToolsDialog) {
_hmdToolsDialog->watchWindow(_lodToolsDialog->windowHandle());
@ -1456,13 +1503,6 @@ void Menu::lodTools() {
_lodToolsDialog->raise();
}
void Menu::lodToolsClosed() {
if (_lodToolsDialog) {
delete _lodToolsDialog;
_lodToolsDialog = NULL;
}
}
void Menu::hmdTools(bool showTools) {
if (showTools) {
if (!_hmdToolsDialog) {

View file

@ -27,14 +27,13 @@
#include "SpeechRecognizer.h"
#endif
#include "ui/AddressBarDialog.h"
#include "devices/Faceshift.h"
#include "devices/SixenseManager.h"
#include "ui/ChatWindow.h"
#include "ui/DataWebDialog.h"
#include "ui/JSConsole.h"
#include "ui/LoginDialog.h"
#include "ui/PreferencesDialog.h"
#include "ui/ScriptEditorWindow.h"
// Make an LOD handler class and move everything overthere
const float ADJUST_LOD_DOWN_FPS = 40.0;
const float ADJUST_LOD_UP_FPS = 55.0;
const float DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f;
@ -50,26 +49,37 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f;
const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f;
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;
const int ONE_SECOND_OF_FRAMES = 60;
const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;
//////////////////////////////////////////////////////////
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
const QString SETTINGS_ADDRESS_KEY = "address";
class QSettings;
class AddressBarDialog;
class AnimationsDialog;
class AttachmentsDialog;
class CachesSizeDialog;
class BandwidthDialog;
class DataWebDialog;
class HMDToolsDialog;
class LodToolsDialog;
class LoginDialog;
class OctreeStatsDialog;
class PreferencesDialog;
class MetavoxelEditor;
class MetavoxelNetworkSimulator;
class ChatWindow;
class OctreeStatsDialog;
class MenuItemProperties;
class Menu : public QMenuBar {
Q_OBJECT
public:
static Menu* getInstance();
~Menu();
void triggerOption(const QString& menuOption);
QAction* getActionForOption(const QString& menuOption);
@ -159,6 +169,7 @@ public slots:
void showLoginForCurrentDomain();
void bandwidthDetails();
void octreeStatsDetails();
void cachesSizeDialog();
void lodTools();
void hmdTools(bool showTools);
void loadSettings(QSettings* settings = NULL);
@ -166,6 +177,8 @@ public slots:
void importSettings();
void exportSettings();
void toggleAddressBar();
void copyAddress();
void copyPath();
void toggleLoginMenuItem();
void toggleSixense(bool shouldEnable);
@ -189,11 +202,9 @@ private slots:
void editAttachments();
void editAnimations();
void changePrivateKey();
void nameLocation();
void toggleLocationList();
void bandwidthDetailsClosed();
void octreeStatsDetailsClosed();
void lodToolsClosed();
void bookmarkLocation();
void teleportToBookmark();
void deleteBookmark();
void hmdToolsClosed();
void runTests();
void showMetavoxelEditor();
@ -206,6 +217,7 @@ private slots:
void audioMuteToggled();
void displayNameLocationResponse(const QString& errorString);
void changeVSync();
void loadRSSDKFile();
private:
static Menu* _instance;
@ -242,54 +254,65 @@ private:
QHash<QString, QAction*> _actionHash;
InboundAudioStream::Settings _receivedAudioStreamSettings;
BandwidthDialog* _bandwidthDialog;
float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus
float _realWorldFieldOfView; // The actual FOV set by the user's monitor size and view distance
float _faceshiftEyeDeflection;
QString _faceshiftHostname;
// in Degrees, doesn't apply to HMD like Oculus
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
// The actual FOV set by the user's monitor size and view distance
float _realWorldFieldOfView = DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES;
float _faceshiftEyeDeflection = DEFAULT_FACESHIFT_EYE_DEFLECTION;
QString _faceshiftHostname = DEFAULT_FACESHIFT_HOSTNAME;
QDialog* _jsConsole = nullptr;
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
SpeechRecognizer _speechRecognizer;
#endif
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
float _oculusUIAngularSize = DEFAULT_OCULUS_UI_ANGULAR_SIZE;
float _sixenseReticleMoveSpeed = DEFAULT_SIXENSE_RETICLE_MOVE_SPEED;
bool _invertSixenseButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
bool _hasLoginDialogDisplayed = false;
bool _automaticAvatarLOD = true;
float _avatarLODDecreaseFPS = DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS;
float _avatarLODIncreaseFPS = ADJUST_LOD_UP_FPS;
float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER;
int _boundaryLevelAdjust = 0;
int _maxOctreePacketsPerSecond = DEFAULT_MAX_OCTREE_PPS;
quint64 _lastAdjust;
quint64 _lastAvatarDetailDrop;
SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES;
SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES;
QPointer<AddressBarDialog> _addressBarDialog;
QPointer<AnimationsDialog> _animationsDialog;
QPointer<AttachmentsDialog> _attachmentsDialog;
QPointer<BandwidthDialog> _bandwidthDialog;
QPointer<CachesSizeDialog> _cachesSizeDialog;
QPointer<HMDToolsDialog> _hmdToolsDialog;
QPointer<LodToolsDialog> _lodToolsDialog;
QPointer<LoginDialog> _loginDialog;
QPointer<OctreeStatsDialog> _octreeStatsDialog;
QPointer<PreferencesDialog> _preferencesDialog;
QPointer<MetavoxelEditor> _MetavoxelEditor;
QPointer<MetavoxelNetworkSimulator> _metavoxelNetworkSimulator;
QPointer<ScriptEditorWindow> _ScriptEditor;
QPointer<ChatWindow> _chatWindow;
QDialog* _jsConsole;
OctreeStatsDialog* _octreeStatsDialog;
LodToolsDialog* _lodToolsDialog;
HMDToolsDialog* _hmdToolsDialog;
QPointer<DataWebDialog> _newLocationDialog;
QPointer<DataWebDialog> _userLocationsDialog;
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
SpeechRecognizer _speechRecognizer;
#endif
float _octreeSizeScale;
float _oculusUIAngularSize;
float _sixenseReticleMoveSpeed;
bool _invertSixenseButtons;
bool _automaticAvatarLOD;
float _avatarLODDecreaseFPS;
float _avatarLODIncreaseFPS;
float _avatarLODDistanceMultiplier;
int _boundaryLevelAdjust;
int _maxOctreePacketsPerSecond;
QString replaceLastOccurrence(QChar search, QChar replace, QString string);
quint64 _lastAdjust;
quint64 _lastAvatarDetailDrop;
SimpleMovingAverage _fpsAverage;
SimpleMovingAverage _fastFPSAverage;
QAction* _loginAction;
QPointer<PreferencesDialog> _preferencesDialog;
QPointer<AttachmentsDialog> _attachmentsDialog;
QPointer<AnimationsDialog> _animationsDialog;
QPointer<AddressBarDialog> _addressBarDialog;
QPointer<LoginDialog> _loginDialog;
bool _hasLoginDialogDisplayed;
QAction* _chatAction;
QAction* _loginAction = nullptr;
QAction* _chatAction = nullptr;
QString _snapshotsLocation;
QString _scriptsLocation;
QByteArray _walletPrivateKey;
bool _shouldRenderTableNeedsRebuilding;
bool _shouldRenderTableNeedsRebuilding = true;
QMap<float, float> _shouldRenderTable;
void loadBookmarks();
QMenu* _bookmarksMenu;
QAction* _deleteBookmarksMenu;
};
namespace MenuOption {
@ -317,7 +340,10 @@ namespace MenuOption {
const QString Bandwidth = "Bandwidth Display";
const QString BandwidthDetails = "Bandwidth Details";
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
const QString BookmarkLocation = "Bookmark Location";
const QString Bookmarks = "Bookmarks";
const QString CascadedShadows = "Cascaded";
const QString CachesSize = "Caches Size";
const QString Chat = "Chat...";
const QString ChatCircling = "Chat Circling";
const QString CollideAsRagdoll = "Collide With Self (Ragdoll)";
@ -325,7 +351,10 @@ namespace MenuOption {
const QString CollideWithEnvironment = "Collide With World Boundaries";
const QString Collisions = "Collisions";
const QString Console = "Console...";
const QString CopyAddress = "Copy Address to Clipboard";
const QString CopyPath = "Copy Path to Clipboard";
const QString ControlWithSpeech = "Control With Speech";
const QString DeleteBookmark = "Delete Bookmark...";
const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene";
const QString DontDoPrecisionPicking = "Don't Do Precision Picking";
const QString DecreaseAvatarSize = "Decrease Avatar Size";
@ -369,6 +398,7 @@ namespace MenuOption {
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";
const QString LoadScriptURL = "Open and Run Script from URL...";
const QString LoadRSSDKFile = "Load .rssdk file";
const QString LodTools = "LOD Tools";
const QString Login = "Login";
const QString Log = "Log";
@ -379,8 +409,6 @@ namespace MenuOption {
const QString Mirror = "Mirror";
const QString MuteAudio = "Mute Microphone";
const QString MuteEnvironment = "Mute Environment";
const QString MyLocations = "My Locations...";
const QString NameLocation = "Name this location";
const QString NetworkSimulator = "Network Simulator...";
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
@ -406,13 +434,24 @@ namespace MenuOption {
const QString RenderTargetFramerate40 = "40";
const QString RenderTargetFramerate30 = "30";
const QString RenderTargetFramerateVSyncOn = "V-Sync On";
const QString RenderResolution = "Scale Resolution";
const QString RenderResolutionOne = "1";
const QString RenderResolutionTwoThird = "2/3";
const QString RenderResolutionHalf = "1/2";
const QString RenderResolutionThird = "1/3";
const QString RenderResolutionQuarter = "1/4";
const QString RenderAmbientLight = "Ambient Light";
const QString RenderAmbientLightGlobal = "Global";
const QString RenderAmbientLight0 = "OLD_TOWN_SQUARE";
const QString RenderAmbientLight1 = "GRACE_CATHEDRAL";
const QString RenderAmbientLight2 = "EUCALYPTUS_GROVE";
const QString RenderAmbientLight3 = "ST_PETERS_BASILICA";
const QString RenderAmbientLight4 = "UFFIZI_GALLERY";
const QString RenderAmbientLight5 = "GALILEOS_TOMB";
const QString RenderAmbientLight6 = "VINE_STREET_KITCHEN";
const QString RenderAmbientLight7 = "BREEZEWAY";
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
const QString ResetAvatarSize = "Reset Avatar Size";
const QString ResetSensors = "Reset Sensors";
const QString RunningScripts = "Running Scripts";

View file

@ -496,7 +496,7 @@ void MetavoxelSystem::render() {
}
void MetavoxelSystem::refreshVoxelData() {
NodeList::getInstance()->eachNode([](const SharedNodePointer& node){
DependencyManager::get<NodeList>()->eachNode([](const SharedNodePointer& node){
if (node->getType() == NodeType::MetavoxelServer) {
QMutexLocker locker(&node->getMutex());
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
@ -798,7 +798,7 @@ void MetavoxelSystem::applyMaterialEdit(const MetavoxelEditMessage& message, boo
Q_ARG(bool, reliable));
return;
}
QSharedPointer<NetworkTexture> texture = DependencyManager::get<TextureCache>()->getTexture(
auto texture = DependencyManager::get<TextureCache>()->getTexture(
material->getDiffuse(), SPLAT_TEXTURE);
if (texture->isLoaded()) {
MetavoxelEditMessage newMessage = message;
@ -819,7 +819,7 @@ MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
}
void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) {
NodeList::getInstance()->eachNode([&visitor, &render](const SharedNodePointer& node){
DependencyManager::get<NodeList>()->eachNode([&visitor, &render](const SharedNodePointer& node){
if (node->getType() == NodeType::MetavoxelServer) {
QMutexLocker locker(&node->getMutex());
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
@ -1045,7 +1045,7 @@ SendDelayer::SendDelayer(const SharedNodePointer& node, const QByteArray& data)
}
void SendDelayer::timerEvent(QTimerEvent* event) {
NodeList::getInstance()->writeDatagram(_data, _node);
DependencyManager::get<NodeList>()->writeDatagram(_data, _node);
deleteLater();
}
@ -1068,7 +1068,7 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
delayer->startTimer(delay);
} else {
NodeList::getInstance()->writeDatagram(data, _node);
DependencyManager::get<NodeList>()->writeDatagram(data, _node);
}
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
}
@ -1178,7 +1178,7 @@ void VoxelBuffer::render(bool cursor) {
if (!_materials.isEmpty()) {
_networkTextures.resize(_materials.size());
TextureCache::SharedPointer textureCache = DependencyManager::get<TextureCache>();
auto textureCache = DependencyManager::get<TextureCache>();
for (int i = 0; i < _materials.size(); i++) {
const SharedObjectPointer material = _materials.at(i);
if (material) {
@ -2233,7 +2233,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g
const QVector<SharedObjectPointer>& materials = node->getMaterial()->getMaterials();
_networkTextures.resize(materials.size());
TextureCache::SharedPointer textureCache = DependencyManager::get<TextureCache>();
auto textureCache = DependencyManager::get<TextureCache>();
for (int i = 0; i < materials.size(); i++) {
const SharedObjectPointer& material = materials.at(i);
if (material) {

View file

@ -55,7 +55,6 @@ static const QString MODEL_URL = "/api/v1/models";
static const QString SETTING_NAME = "LastModelUploadLocation";
static const long long BYTES_PER_MEGABYTES = 1024 * 1024;
static const unsigned long long MAX_SIZE = 50 * 1024 * BYTES_PER_MEGABYTES; // 50 GB (Virtually remove limit)
static const int MAX_TEXTURE_SIZE = 1024;
static const int TIMEOUT = 1000;
@ -503,7 +502,7 @@ void ModelUploader::processCheck() {
QString("Your model is now available in the browser."),
QMessageBox::Ok);
DependencyManager::get<GeometryCache>()->refresh(_url);
TextureCache::SharedPointer textureCache = DependencyManager::get<TextureCache>();
auto textureCache = DependencyManager::get<TextureCache>();
foreach (const QByteArray& filename, _textureFilenames) {
textureCache->refresh(_textureBase + filename);
}

View file

@ -31,20 +31,30 @@ static const QString IS_TRUNCATED_NAME = "IsTruncated";
static const QString CONTAINER_NAME = "Contents";
static const QString KEY_NAME = "Key";
ScriptItem::ScriptItem(const QString& filename, const QString& fullPath) :
_filename(filename),
_fullPath(fullPath) {
TreeNodeBase::TreeNodeBase(TreeNodeFolder* parent, const QString& name, TreeNodeType type) :
_parent(parent),
_name(name),
_type(type) {
};
TreeNodeScript::TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin) :
TreeNodeBase(NULL, localPath.split("/").last(), TREE_NODE_TYPE_SCRIPT),
_localPath(localPath),
_fullPath(fullPath),
_origin(origin) {
};
TreeNodeFolder::TreeNodeFolder(const QString& foldername, TreeNodeFolder* parent) :
TreeNodeBase(parent, foldername, TREE_NODE_TYPE_FOLDER) {
};
ScriptsModel::ScriptsModel(QObject* parent) :
QAbstractListModel(parent),
QAbstractItemModel(parent),
_loadingScripts(false),
_localDirectory(),
_fsWatcher(),
_localFiles(),
_remoteFiles()
_treeNodes()
{
_localDirectory.setFilter(QDir::Files | QDir::Readable);
_localDirectory.setNameFilters(QStringList("*.js"));
@ -57,31 +67,61 @@ ScriptsModel::ScriptsModel(QObject* parent) :
reloadRemoteFiles();
}
QVariant ScriptsModel::data(const QModelIndex& index, int role) const {
const QList<ScriptItem*>* files = NULL;
int row = 0;
bool isLocal = index.row() < _localFiles.size();
if (isLocal) {
files = &_localFiles;
row = index.row();
} else {
files = &_remoteFiles;
row = index.row() - _localFiles.size();
}
ScriptsModel::~ScriptsModel() {
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
delete _treeNodes.at(i);
}
_treeNodes.clear();
}
if (role == Qt::DisplayRole) {
return QVariant((*files)[row]->getFilename() + (isLocal ? " (local)" : ""));
} else if (role == ScriptPath) {
return QVariant((*files)[row]->getFullPath());
TreeNodeBase* ScriptsModel::getTreeNodeFromIndex(const QModelIndex& index) const {
if (index.isValid()) {
return static_cast<TreeNodeBase*>(index.internalPointer());
}
return NULL;
}
QModelIndex ScriptsModel::index(int row, int column, const QModelIndex& parent) const {
if (row < 0 || column < 0) {
return QModelIndex();
}
return createIndex(row, column, getFolderNodes(static_cast<TreeNodeFolder*>(getTreeNodeFromIndex(parent))).at(row));
}
QModelIndex ScriptsModel::parent(const QModelIndex& child) const {
TreeNodeFolder* parent = (static_cast<TreeNodeBase*>(child.internalPointer()))->getParent();
if (!parent) {
return QModelIndex();
}
TreeNodeFolder* grandParent = parent->getParent();
int row = getFolderNodes(grandParent).indexOf(parent);
return createIndex(row, 0, parent);
}
QVariant ScriptsModel::data(const QModelIndex& index, int role) const {
TreeNodeBase* node = getTreeNodeFromIndex(index);
if (node->getType() == TREE_NODE_TYPE_SCRIPT) {
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
if (role == Qt::DisplayRole) {
return QVariant(script->getName() + (script->getOrigin() == SCRIPT_ORIGIN_LOCAL ? " (local)" : ""));
} else if (role == ScriptPath) {
return QVariant(script->getFullPath());
}
} else if (node->getType() == TREE_NODE_TYPE_FOLDER) {
TreeNodeFolder* folder = static_cast<TreeNodeFolder*>(node);
if (role == Qt::DisplayRole) {
return QVariant(folder->getName());
}
}
return QVariant();
}
int ScriptsModel::rowCount(const QModelIndex& parent) const {
if (parent.isValid()) {
return 0;
}
return _localFiles.length() + _remoteFiles.length();
return getFolderNodes(static_cast<TreeNodeFolder*>(getTreeNodeFromIndex(parent))).count();
}
int ScriptsModel::columnCount(const QModelIndex& parent) const {
return 1;
}
void ScriptsModel::updateScriptsLocation(const QString& newPath) {
@ -93,7 +133,7 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) {
if (!_localDirectory.absolutePath().isEmpty()) {
_fsWatcher.addPath(_localDirectory.absolutePath());
}
}
}
reloadLocalFiles();
}
@ -101,8 +141,14 @@ void ScriptsModel::updateScriptsLocation(const QString& newPath) {
void ScriptsModel::reloadRemoteFiles() {
if (!_loadingScripts) {
_loadingScripts = true;
while (!_remoteFiles.isEmpty()) {
delete _remoteFiles.takeFirst();
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
TreeNodeBase* node = _treeNodes.at(i);
if (node->getType() == TREE_NODE_TYPE_SCRIPT &&
static_cast<TreeNodeScript*>(node)->getOrigin() == SCRIPT_ORIGIN_REMOTE)
{
delete node;
_treeNodes.removeAt(i);
}
}
requestRemoteFiles();
}
@ -121,7 +167,6 @@ void ScriptsModel::requestRemoteFiles(QString marker) {
QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
}
void ScriptsModel::downloadFinished() {
@ -170,7 +215,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
xml.readNext();
lastKey = xml.text().toString();
if (jsRegex.exactMatch(xml.text().toString())) {
_remoteFiles.append(new ScriptItem(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey));
_treeNodes.append(new TreeNodeScript(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey, SCRIPT_ORIGIN_REMOTE));
}
}
xml.readNext();
@ -178,7 +223,7 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
}
xml.readNext();
}
rebuildTree();
endResetModel();
// Error handling
@ -198,8 +243,14 @@ bool ScriptsModel::parseXML(QByteArray xmlFile) {
void ScriptsModel::reloadLocalFiles() {
beginResetModel();
while (!_localFiles.isEmpty()) {
delete _localFiles.takeFirst();
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
TreeNodeBase* node = _treeNodes.at(i);
if (node->getType() == TREE_NODE_TYPE_SCRIPT &&
static_cast<TreeNodeScript*>(node)->getOrigin() == SCRIPT_ORIGIN_LOCAL)
{
delete node;
_treeNodes.removeAt(i);
}
}
_localDirectory.refresh();
@ -207,8 +258,53 @@ void ScriptsModel::reloadLocalFiles() {
const QFileInfoList localFiles = _localDirectory.entryInfoList();
for (int i = 0; i < localFiles.size(); i++) {
QFileInfo file = localFiles[i];
_localFiles.append(new ScriptItem(file.fileName(), file.absoluteFilePath()));
_treeNodes.append(new TreeNodeScript(file.fileName(), file.absoluteFilePath(), SCRIPT_ORIGIN_LOCAL));
}
rebuildTree();
endResetModel();
}
void ScriptsModel::rebuildTree() {
for (int i = _treeNodes.size() - 1; i >= 0; i--) {
if (_treeNodes.at(i)->getType() == TREE_NODE_TYPE_FOLDER) {
delete _treeNodes.at(i);
_treeNodes.removeAt(i);
}
}
QHash<QString, TreeNodeFolder*> folders;
for (int i = 0; i < _treeNodes.size(); i++) {
TreeNodeBase* node = _treeNodes.at(i);
if (node->getType() == TREE_NODE_TYPE_SCRIPT) {
TreeNodeScript* script = static_cast<TreeNodeScript*>(node);
TreeNodeFolder* parent = NULL;
QString hash;
QStringList pathList = script->getLocalPath().split(tr("/"));
pathList.removeLast();
QStringList::const_iterator pathIterator;
for (pathIterator = pathList.constBegin(); pathIterator != pathList.constEnd(); ++pathIterator) {
hash.append(*pathIterator + "/");
if (!folders.contains(hash)) {
folders[hash] = new TreeNodeFolder(*pathIterator, parent);
}
parent = folders[hash];
}
script->setParent(parent);
}
}
QHash<QString, TreeNodeFolder*>::const_iterator folderIterator;
for (folderIterator = folders.constBegin(); folderIterator != folders.constEnd(); ++folderIterator) {
_treeNodes.append(*folderIterator);
}
folders.clear();
}
QList<TreeNodeBase*> ScriptsModel::getFolderNodes(TreeNodeFolder* parent) const {
QList<TreeNodeBase*> result;
for (int i = 0; i < _treeNodes.size(); i++) {
TreeNodeBase* node = _treeNodes.at(i);
if (node->getParent() == parent) {
result.append(node);
}
}
return result;
}

View file

@ -12,30 +12,69 @@
#ifndef hifi_ScriptsModel_h
#define hifi_ScriptsModel_h
#include <QAbstractListModel>
#include <QAbstractItemModel>
#include <QDir>
#include <QNetworkReply>
#include <QFileSystemWatcher>
class ScriptItem {
public:
ScriptItem(const QString& filename, const QString& fullPath);
class TreeNodeFolder;
const QString& getFilename() { return _filename; };
const QString& getFullPath() { return _fullPath; };
private:
QString _filename;
QString _fullPath;
enum ScriptOrigin {
SCRIPT_ORIGIN_LOCAL,
SCRIPT_ORIGIN_REMOTE
};
class ScriptsModel : public QAbstractListModel {
enum TreeNodeType {
TREE_NODE_TYPE_SCRIPT,
TREE_NODE_TYPE_FOLDER
};
class TreeNodeBase {
public:
TreeNodeFolder* getParent() const { return _parent; }
void setParent(TreeNodeFolder* parent) { _parent = parent; }
TreeNodeType getType() { return _type; }
const QString& getName() { return _name; };
private:
TreeNodeFolder* _parent;
TreeNodeType _type;
protected:
QString _name;
TreeNodeBase(TreeNodeFolder* parent, const QString& name, TreeNodeType type);
};
class TreeNodeScript : public TreeNodeBase {
public:
TreeNodeScript(const QString& localPath, const QString& fullPath, ScriptOrigin origin);
const QString& getLocalPath() { return _localPath; }
const QString& getFullPath() { return _fullPath; };
const ScriptOrigin getOrigin() { return _origin; };
private:
QString _localPath;
QString _fullPath;
ScriptOrigin _origin;
};
class TreeNodeFolder : public TreeNodeBase {
public:
TreeNodeFolder(const QString& foldername, TreeNodeFolder* parent);
};
class ScriptsModel : public QAbstractItemModel {
Q_OBJECT
public:
ScriptsModel(QObject* parent = NULL);
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
~ScriptsModel();
QModelIndex index(int row, int column, const QModelIndex& parent) const;
QModelIndex parent(const QModelIndex& child) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
TreeNodeBase* getTreeNodeFromIndex(const QModelIndex& index) const;
QList<TreeNodeBase*> getFolderNodes(TreeNodeFolder* parent) const;
enum Role {
ScriptPath = Qt::UserRole,
@ -50,13 +89,13 @@ protected slots:
protected:
void requestRemoteFiles(QString marker = QString());
bool parseXML(QByteArray xmlFile);
void rebuildTree();
private:
bool _loadingScripts;
QDir _localDirectory;
QFileSystemWatcher _fsWatcher;
QList<ScriptItem*> _localFiles;
QList<ScriptItem*> _remoteFiles;
QList<TreeNodeBase*> _treeNodes;
};
#endif // hifi_ScriptsModel_h

View file

@ -0,0 +1,44 @@
//
// ScriptsModelFilter.cpp
// interface/src
//
// Created by Thijs Wenker on 01/11/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptsModelFilter.h"
ScriptsModelFilter::ScriptsModelFilter(QObject *parent) :
QSortFilterProxyModel(parent) {
}
bool ScriptsModelFilter::lessThan(const QModelIndex& left, const QModelIndex& right) const {
ScriptsModel* scriptsModel = static_cast<ScriptsModel*>(sourceModel());
TreeNodeBase* leftNode = scriptsModel->getTreeNodeFromIndex(left);
TreeNodeBase* rightNode = scriptsModel->getTreeNodeFromIndex(right);
if (leftNode->getType() != rightNode->getType()) {
return leftNode->getType() == TREE_NODE_TYPE_FOLDER;
}
return leftNode->getName() < rightNode->getName();
}
bool ScriptsModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const {
if (!filterRegExp().isEmpty()) {
ScriptsModel* scriptsModel = static_cast<ScriptsModel*>(sourceModel());
TreeNodeBase* node = scriptsModel->getFolderNodes(
static_cast<TreeNodeFolder*>(scriptsModel->getTreeNodeFromIndex(sourceParent))).at(sourceRow);
QModelIndex sourceIndex = sourceModel()->index(sourceRow, this->filterKeyColumn(), sourceParent);
if (node->getType() == TREE_NODE_TYPE_FOLDER) {
int rows = scriptsModel->rowCount(sourceIndex);
for (int i = 0; i < rows; i++) {
if (filterAcceptsRow(i, sourceIndex)) {
return true;
}
}
}
}
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
}

View file

@ -0,0 +1,27 @@
//
// ScriptsModelFilter.h
// interface/src
//
// Created by Thijs Wenker on 01/11/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ScriptsModelFilter_h
#define hifi_ScriptsModelFilter_h
#include "ScriptsModel.h"
#include <QSortFilterProxyModel>
class ScriptsModelFilter : public QSortFilterProxyModel {
Q_OBJECT
public:
ScriptsModelFilter(QObject *parent = NULL);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const;
bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
};
#endif // hifi_ScriptsModelFilter_h

View file

@ -33,7 +33,7 @@
using namespace std;
void renderWorldBox() {
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
// Show edge of world
float red[] = {1, 0, 0};

View file

@ -97,7 +97,7 @@ void AudioIOStats::parseAudioStreamStatsPacket(const QByteArray& packet) {
void AudioIOStats::sendDownstreamAudioStatsPacket() {
Audio::SharedPointer audioIO = DependencyManager::get<Audio>();
auto audioIO = DependencyManager::get<Audio>();
// since this function is called every second, we'll sample for some of our stats here
_inputRingBufferMsecsAvailableStats.update(audioIO->getInputRingBufferMsecsAvailable());
@ -128,7 +128,7 @@ void AudioIOStats::sendDownstreamAudioStatsPacket() {
dataAt += sizeof(AudioStreamStats);
// send packet
NodeList* nodeList = NodeList::getInstance();
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
nodeList->writeDatagram(packet, dataAt - packet, audioMixer);
}

View file

@ -71,7 +71,7 @@ void AudioIOStatsRenderer::render(const float* color, int width, int height) {
float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f;
AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats();
SharedNodePointer audioMixerNodePointer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer);
SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer);
if (!audioMixerNodePointer.isNull()) {
audioInputBufferLatency = _stats->getAudioInputMsecsReadStats().getWindowAverage();
inputRingBufferLatency = (float) _stats->getInputRungBufferMsecsAvailableStats().getWindowAverage();

View file

@ -19,9 +19,9 @@
class AudioIOStats;
class AudioStreamStats;
class AudioIOStatsRenderer : public QObject {
class AudioIOStatsRenderer : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY(AudioIOStatsRenderer)
SINGLETON_DEPENDENCY
public:
void render(const float* color, int width, int height);

View file

@ -41,7 +41,7 @@ AudioScope::AudioScope() :
_outputLeftID(DependencyManager::get<GeometryCache>()->allocateID()),
_outputRightD(DependencyManager::get<GeometryCache>()->allocateID())
{
Audio::SharedPointer audioIO = DependencyManager::get<Audio>();
auto audioIO = DependencyManager::get<Audio>();
connect(&audioIO->getReceivedAudioStream(), &MixedProcessedAudioStream::addedSilence,
this, &AudioScope::addStereoSilenceToScope);
connect(&audioIO->getReceivedAudioStream(), &MixedProcessedAudioStream::addedLastFrameRepeatedWithFade,
@ -155,7 +155,7 @@ void AudioScope::renderLineStrip(int id, const float* color, int x, int y, int n
int remainder = (n - offset) % numSamplesToAverage;
y += SCOPE_HEIGHT / 2;
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
QVector<glm::vec2> points;

View file

@ -17,9 +17,9 @@
#include <QByteArray>
#include <QObject>
class AudioScope : public QObject {
class AudioScope : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY(AudioScope)
SINGLETON_DEPENDENCY
public:
// Audio scope methods for allocation/deallocation
void allocateScope();

View file

@ -25,10 +25,6 @@ const int MUTE_ICON_SIZE = 24;
AudioToolBox::AudioToolBox() :
_iconPulseTimeReference(usecTimestampNow())
{
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
_micTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic.svg"));
_muteTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic-mute.svg"));
_boxTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/audio-box.svg"));
}
bool AudioToolBox::mousePressEvent(int x, int y) {
@ -40,10 +36,20 @@ bool AudioToolBox::mousePressEvent(int x, int y) {
}
void AudioToolBox::render(int x, int y, bool boxed) {
glEnable(GL_TEXTURE_2D);
Audio::SharedPointer audioIO = DependencyManager::get<Audio>();
auto glCanvas = DependencyManager::get<GLCanvas>();
if (_micTextureId == 0) {
_micTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic.svg"));
}
if (_muteTextureId == 0) {
_muteTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/mic-mute.svg"));
}
if (_boxTextureId == 0) {
_boxTextureId = glCanvas->bindTexture(QImage(PathUtils::resourcesPath() + "images/audio-box.svg"));
}
auto audioIO = DependencyManager::get<Audio>();
if (boxed) {
bool isClipping = ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f));

View file

@ -14,8 +14,8 @@
#include <DependencyManager.h>
class AudioToolBox : public QObject {
SINGLETON_DEPENDENCY(AudioToolBox)
class AudioToolBox : public Dependency {
SINGLETON_DEPENDENCY
public:
void render(int x, int y, bool boxed);
@ -23,11 +23,11 @@ public:
protected:
AudioToolBox();
private:
GLuint _micTextureId;
GLuint _muteTextureId;
GLuint _boxTextureId;
GLuint _micTextureId = 0;
GLuint _muteTextureId = 0;
GLuint _boxTextureId = 0;
QRect _iconBounds;
qint64 _iconPulseTimeReference;
qint64 _iconPulseTimeReference = 0;
};
#endif // hifi_AudioToolBox_h

View file

@ -272,7 +272,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool
}
if (postLighting && glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) {
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
// render pointing lasers
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
@ -950,7 +950,7 @@ int Avatar::_jointConesID = GeometryCache::UNKNOWN_ID;
// render a makeshift cone section that serves as a body part connecting joint spheres
void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2) {
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
if (_jointConesID == GeometryCache::UNKNOWN_ID) {
_jointConesID = geometryCache->allocateID();

View file

@ -80,8 +80,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
// Only use face trackers when not playing back a recording.
if (!myAvatar->isPlaying()) {
FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker();
DdeFaceTracker::SharedPointer dde = DependencyManager::get<DdeFaceTracker>();
Faceshift::SharedPointer faceshift = DependencyManager::get<Faceshift>();
auto dde = DependencyManager::get<DdeFaceTracker>();
auto faceshift = DependencyManager::get<Faceshift>();
if ((_isFaceshiftConnected = (faceshift == faceTracker))) {
_blendshapeCoefficients = faceTracker->getBlendshapeCoefficients();
@ -339,7 +339,7 @@ void Head::addLeanDeltas(float sideways, float forward) {
}
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
DependencyManager::get<GlowEffect>()->begin();
glLineWidth(2.0);

View file

@ -146,7 +146,7 @@ void MyAvatar::update(float deltaTime) {
head->relaxLean(deltaTime);
updateFromTrackers(deltaTime);
// Get audio loudness data from audio input device
Audio::SharedPointer audio = DependencyManager::get<Audio>();
auto audio = DependencyManager::get<Audio>();
head->setAudioLoudness(audio->getLastInputLoudness());
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
@ -864,7 +864,7 @@ int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
void MyAvatar::sendKillAvatar() {
QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar);
NodeList::getInstance()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer);
DependencyManager::get<NodeList>()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer);
}
void MyAvatar::updateLookAtTargetAvatar() {

View file

@ -339,7 +339,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
glScalef(fanScale, fanScale, fanScale);
const int AXIS_COUNT = 3;
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
for (int i = 0; i < AXIS_COUNT; i++) {
if (joint.rotationMin[i] <= -PI + EPSILON && joint.rotationMax[i] >= PI - EPSILON) {
@ -381,7 +381,7 @@ void SkeletonModel::renderJointConstraints(int jointIndex) {
}
void SkeletonModel::renderOrientationDirections(int jointIndex, glm::vec3 position, const glm::quat& orientation, float size) {
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
if (!_jointOrientationLines.contains(jointIndex)) {
OrientationLineIDs jointLineIDs;
@ -594,7 +594,7 @@ void SkeletonModel::renderRagdoll() {
float radius1 = 0.008f;
float radius2 = 0.01f;
glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame();
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
for (int i = 0; i < numPoints; ++i) {
glPushMatrix();
// NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative
@ -954,7 +954,7 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
endPoint = endPoint - _translation;
glTranslatef(endPoint.x, endPoint.y, endPoint.z);
glColor4f(0.6f, 0.6f, 0.8f, alpha);
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
// draw a yellow sphere at the capsule startpoint
@ -990,7 +990,7 @@ void SkeletonModel::renderJointCollisionShapes(float alpha) {
continue;
}
GeometryCache::SharedPointer geometryCache = DependencyManager::get<GeometryCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
glPushMatrix();
// shapes are stored in simulation-frame but we want position to be model-relative

View file

@ -18,9 +18,9 @@
#include "FaceTracker.h"
class DdeFaceTracker : public FaceTracker {
class DdeFaceTracker : public FaceTracker, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY(DdeFaceTracker)
SINGLETON_DEPENDENCY
public:
//initialization

View file

@ -23,10 +23,13 @@
#include "FaceTracker.h"
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
const QString DEFAULT_FACESHIFT_HOSTNAME = "localhost";
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
class Faceshift : public FaceTracker {
class Faceshift : public FaceTracker, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY(Faceshift)
SINGLETON_DEPENDENCY
public:
void init();

View file

@ -13,6 +13,7 @@
#include "InterfaceConfig.h"
#include "OculusManager.h"
#include "ui/overlays/Text3DOverlay.h"
#include <QDesktopWidget>
#include <QGuiApplication>
@ -562,7 +563,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
}
// restore our normal viewport
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
glMatrixMode(GL_PROJECTION);
@ -581,7 +582,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) {
glLoadIdentity();
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -1.0, 1.0);
glDisable(GL_DEPTH_TEST);

View file

@ -19,12 +19,9 @@
#include <ProgramObject.h>
#include "ui/overlays/Text3DOverlay.h"
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
class Camera;
class PalmData;
class Text3DOverlay;
/// Handles interaction with the Oculus Rift.
class OculusManager {

View file

@ -215,7 +215,7 @@ void PrioVR::renderCalibrationCountdown() {
static TextRenderer* textRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY, 18, QFont::Bold,
false, TextRenderer::OUTLINE_EFFECT, 2);
QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "...";
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
textRenderer->draw((glCanvas->width() - textRenderer->computeWidth(text.constData())) / 2,
glCanvas->height() / 2,
text);

View file

@ -0,0 +1,250 @@
//
// RealSense.cpp
// interface/src/devices
//
// Created by Thijs Wenker on 12/10/14
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RealSense.h"
#include "MainWindow.h"
#include "Menu.h"
#include "SharedUtil.h"
const int PALMROOT_NUM_JOINTS = 2;
const int FINGER_NUM_JOINTS = 4;
const DeviceTracker::Name RealSense::NAME = "RealSense";
// find the index of a joint from
// the side: true = right
// the finger & the bone:
// finger in [0..4] : bone in [0..3] a finger phalange
// [-1] up the hand branch : bone in [0..1] <=> [ hand, forearm]
MotionTracker::Index evalRealSenseJointIndex(bool isRightSide, int finger, int bone) {
#ifdef HAVE_RSSDK
MotionTracker::Index offset = 1 // start after root
+ (int(isRightSide) * PXCHandData::NUMBER_OF_JOINTS) // then offset for side
+ PALMROOT_NUM_JOINTS; // then add the arm/forearm/hand chain
if (finger >= 0) {
// from there go down in the correct finger and bone
return offset + (finger * FINGER_NUM_JOINTS) + bone;
} else {
// or go back up for the correct root bone
return offset - 1 - bone;
}
#else
return -1;
#endif // HAVE_RSSDK
}
// static
void RealSense::init() {
DeviceTracker* device = DeviceTracker::getDevice(NAME);
if (!device) {
// create a new RealSense and register it
RealSense* realSense = new RealSense();
DeviceTracker::registerDevice(NAME, realSense);
}
}
// static
RealSense* RealSense::getInstance() {
DeviceTracker* device = DeviceTracker::getDevice(NAME);
if (!device) {
// create a new RealSense and register it
RealSense* realSense = new RealSense();
DeviceTracker::registerDevice(NAME, realSense);
}
return dynamic_cast< RealSense* > (device);
}
RealSense::RealSense() :
MotionTracker(),
_active(false)
{
#ifdef HAVE_RSSDK
_handData = NULL;
_session = PXCSession_Create();
initSession(false, NULL);
// Create the RealSense joint hierarchy
std::vector< Semantic > sides;
sides.push_back("joint_L_");
sides.push_back("joint_R_");
std::vector< Semantic > rootBones;
rootBones.push_back("wrist");
rootBones.push_back("hand");
std::vector< Semantic > fingers;
fingers.push_back("thumb");
fingers.push_back("index");
fingers.push_back("middle");
fingers.push_back("ring");
fingers.push_back("pinky");
std::vector< Semantic > fingerBones;
fingerBones.push_back("1");
fingerBones.push_back("2");
fingerBones.push_back("3");
fingerBones.push_back("4");
std::vector< Index > palms;
for (unsigned int s = 0; s < sides.size(); s++) {
Index rootJoint = 0;
for (unsigned int rb = 0; rb < rootBones.size(); rb++) {
rootJoint = addJoint(sides[s] + rootBones[rb], rootJoint);
}
// capture the hand index for debug
palms.push_back(rootJoint);
for (unsigned int f = 0; f < fingers.size(); f++) {
for (unsigned int b = 0; b < fingerBones.size(); b++) {
rootJoint = addJoint(sides[s] + fingers[f] + fingerBones[b], rootJoint);
}
}
}
#endif // HAVE_RSSDK
}
RealSense::~RealSense() {
#ifdef HAVE_RSSDK
_manager->Release();
#endif // HAVE_RSSDK
}
void RealSense::initSession(bool playback, QString filename) {
#ifdef HAVE_RSSDK
_active = false;
_properlyInitialized = false;
if (_handData != NULL) {
_handData->Release();
_handController->Release();
_session->Release();
_config->Release();
}
_manager = _session->CreateSenseManager();
if (playback) {
_manager->QueryCaptureManager()->SetFileName(filename.toStdWString().c_str(), false);
}
_manager->QueryCaptureManager()->SetRealtime(!playback);
_manager->EnableHand(0);
_handController = _manager->QueryHand();
if (_manager->Init() == PXC_STATUS_NO_ERROR) {
_handData = _handController->CreateOutput();
PXCCapture::Device *device = _manager->QueryCaptureManager()->QueryDevice();
PXCCapture::DeviceInfo dinfo;
_manager->QueryCaptureManager()->QueryDevice()->QueryDeviceInfo(&dinfo);
if (dinfo.model == PXCCapture::DEVICE_MODEL_IVCAM)
{
device->SetDepthConfidenceThreshold(1);
device->SetMirrorMode(PXCCapture::Device::MIRROR_MODE_DISABLED);
device->SetIVCAMFilterOption(6);
}
_properlyInitialized = true;
}
_config = _handController->CreateActiveConfiguration();
_config->EnableStabilizer(true);
_config->SetTrackingMode(PXCHandData::TRACKING_MODE_FULL_HAND);
_config->ApplyChanges();
#endif // HAVE_RSSDK
}
#ifdef HAVE_RSSDK
glm::quat quatFromPXCPoint4DF32(const PXCPoint4DF32& basis) {
return glm::normalize(glm::quat(basis.w, basis.x, basis.y, basis.z) * glm::quat(glm::vec3(0, M_PI, 0)));
}
glm::vec3 vec3FromPXCPoint3DF32(const PXCPoint3DF32& vec) {
return glm::vec3(-vec.x, vec.y, -vec.z);
}
#endif // HAVE_RSSDK
void RealSense::update() {
#ifdef HAVE_RSSDK
bool wasActive = _active;
_active = _manager->IsConnected() && _properlyInitialized;
if (_active || wasActive) {
// Go through all the joints and increment their counter since last update.
// Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive.
// TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) {
(*jointIt).tickNewFrame();
}
}
if (!_active) {
return;
}
pxcStatus sts = _manager->AcquireFrame(true);
_handData->Update();
PXCHandData::JointData nodes[2][PXCHandData::NUMBER_OF_JOINTS] = {};
PXCHandData::ExtremityData extremitiesPointsNodes[2][PXCHandData::NUMBER_OF_EXTREMITIES] = {};
for (pxcI32 i = 0; i < _handData->QueryNumberOfHands(); i++) {
PXCHandData::IHand* handData;
if (_handData->QueryHandData(PXCHandData::ACCESS_ORDER_BY_TIME, i, handData) == PXC_STATUS_NO_ERROR) {
int rightSide = handData->QueryBodySide() == PXCHandData::BODY_SIDE_RIGHT;
PXCHandData::JointData jointData;
JointTracker* parentJointTracker = _jointsArray.data();
//Iterate Joints
int rootBranchIndex = -1;
JointTracker* palmJoint = NULL;
for (int j = 0; j < PXCHandData::NUMBER_OF_JOINTS; j++) {
handData->QueryTrackedJoint((PXCHandData::JointType)j, jointData);
nodes[i][j] = jointData;
if (j == PXCHandData::JOINT_WRIST) {
JointTracker* wrist = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 1)); // 1 is the index of the wrist joint
wrist->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld));
wrist->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation));
wrist->updateLocFromAbsTransform(parentJointTracker);
wrist->activeFrame();
parentJointTracker = wrist;
continue;
} else if (j == PXCHandData::JOINT_CENTER) {
palmJoint = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 0)); // 0 is the index of the palm joint
palmJoint->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld));
palmJoint->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation));
palmJoint->updateLocFromAbsTransform(parentJointTracker);
palmJoint->activeFrame();
parentJointTracker = palmJoint;
continue;
}
int finger_index = j - PALMROOT_NUM_JOINTS;
int finger = finger_index / FINGER_NUM_JOINTS;
int finger_bone = finger_index % FINGER_NUM_JOINTS;
JointTracker* ljointTracker = editJointTracker(evalRealSenseJointIndex(rightSide, finger, finger_bone));
if (jointData.confidence > 0) {
ljointTracker->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld));
ljointTracker->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation));
ljointTracker->updateLocFromAbsTransform(parentJointTracker);
ljointTracker->activeFrame();
}
if (finger_bone == (FINGER_NUM_JOINTS - 1)) {
parentJointTracker = palmJoint;
continue;
}
parentJointTracker = ljointTracker;
}
}
}
_manager->ReleaseFrame();
#endif // HAVE_RSSDK
}
void RealSense::loadRSSDKFile() {
QString locationDir(QStandardPaths::displayName(QStandardPaths::DesktopLocation));
QString fileNameString = QFileDialog::getOpenFileName(Application::getInstance()->getWindow(), tr("Open RSSDK clip"),
locationDir,
tr("RSSDK Recordings (*.rssdk)"));
if (!fileNameString.isEmpty()) {
initSession(true, fileNameString);
}
}

View file

@ -0,0 +1,63 @@
//
// RealSense.h
// interface/src/devices
//
// Created by Thijs Wenker on 12/10/14
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RealSense_h
#define hifi_RealSense_h
#include <QFileDialog>
#include "MotionTracker.h"
#ifdef HAVE_RSSDK
#include <pxcsession.h>
#include <pxchandmodule.h>
#include <pxchandconfiguration.h>
#include <pxcsensemanager.h>
#include <pxchanddata.h>
#endif
/// Handles interaction with the RealSense skeleton tracking suit.
class RealSense : public QObject, public MotionTracker {
Q_OBJECT
public:
static const Name NAME;
static void init();
/// RealSense MotionTracker factory
static RealSense* getInstance();
bool isActive() const { return _active; }
virtual void update();
void loadRSSDKFile();
protected:
RealSense();
virtual ~RealSense();
void initSession(bool playback, QString filename);
private:
#ifdef HAVE_RSSDK
PXCSession* _session;
PXCSenseManager* _manager;
PXCHandModule* _handController;
PXCHandData* _handData;
PXCHandConfiguration* _config;
#endif
bool _properlyInitialized;
bool _active;
};
#endif // hifi_RealSense_h

View file

@ -451,7 +451,7 @@ void SixenseManager::updateCalibration(const sixenseControllerData* controllers)
void SixenseManager::emulateMouse(PalmData* palm, int index) {
Application* application = Application::getInstance();
MyAvatar* avatar = application->getAvatar();
GLCanvas::SharedPointer glCanvas = DependencyManager::get<GLCanvas>();
auto glCanvas = DependencyManager::get<GLCanvas>();
QPoint pos;
Qt::MouseButton bumperButton;

Some files were not shown because too many files have changed in this diff Show more