Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ericrius1 2016-04-26 09:28:15 -07:00
commit a492262095
181 changed files with 3019 additions and 1454 deletions

View file

@ -19,6 +19,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <thread>
#ifdef _WIN32 #ifdef _WIN32
#include <math.h> #include <math.h>
@ -577,15 +578,15 @@ void AudioMixer::domainSettingsRequestComplete() {
void AudioMixer::broadcastMixes() { void AudioMixer::broadcastMixes() {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
int64_t nextFrame = 0; auto nextFrameTimestamp = p_high_resolution_clock::now();
QElapsedTimer timer; auto timeToSleep = std::chrono::microseconds(0);
timer.start();
int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
const int TRAILING_AVERAGE_FRAMES = 100; const int TRAILING_AVERAGE_FRAMES = 100;
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
int currentFrame { 1 };
int numFramesPerSecond { (int) ceil(AudioConstants::NETWORK_FRAMES_PER_SEC) };
while (!_isFinished) { while (!_isFinished) {
const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f;
const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f;
@ -595,12 +596,12 @@ void AudioMixer::broadcastMixes() {
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
if (usecToSleep < 0) { if (timeToSleep.count() < 0) {
usecToSleep = 0; timeToSleep = std::chrono::microseconds(0);
} }
_trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio)
+ (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); + (timeToSleep.count() * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS);
float lastCutoffRatio = _performanceThrottlingRatio; float lastCutoffRatio = _performanceThrottlingRatio;
bool hasRatioChanged = false; bool hasRatioChanged = false;
@ -694,10 +695,11 @@ void AudioMixer::broadcastMixes() {
nodeList->sendPacket(std::move(mixPacket), *node); nodeList->sendPacket(std::move(mixPacket), *node);
nodeData->incrementOutgoingMixedAudioSequenceNumber(); nodeData->incrementOutgoingMixedAudioSequenceNumber();
static const int FRAMES_PER_SECOND = int(ceilf(1.0f / AudioConstants::NETWORK_FRAME_SECS));
// send an audio stream stats packet to the client approximately every second // send an audio stream stats packet to the client approximately every second
if (nextFrame % FRAMES_PER_SECOND == 0) { ++currentFrame;
currentFrame %= numFramesPerSecond;
if (nodeData->shouldSendStats(currentFrame)) {
nodeData->sendAudioStreamStatsPackets(node); nodeData->sendAudioStreamStatsPackets(node);
} }
@ -718,11 +720,14 @@ void AudioMixer::broadcastMixes() {
break; break;
} }
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - (timer.nsecsElapsed() / 1000); // push the next frame timestamp to when we should send the next
nextFrameTimestamp += std::chrono::microseconds(AudioConstants::NETWORK_FRAME_USECS);
if (usecToSleep > 0) { // sleep as long as we need until next frame, if we can
usleep(usecToSleep); auto now = p_high_resolution_clock::now();
} timeToSleep = std::chrono::duration_cast<std::chrono::microseconds>(nextFrameTimestamp - now);
std::this_thread::sleep_for(timeToSleep);
} }
} }

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <random>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QJsonArray> #include <QtCore/QJsonArray>
@ -26,7 +28,14 @@ AudioMixerClientData::AudioMixerClientData(const QUuid& nodeID) :
_outgoingMixedAudioSequenceNumber(0), _outgoingMixedAudioSequenceNumber(0),
_downstreamAudioStreamStats() _downstreamAudioStreamStats()
{ {
// of the ~94 blocks in a second of audio sent from the AudioMixer, pick a random one to send out a stats packet on
// this ensures we send out stats to this client around every second
// but do not send all of the stats packets out at the same time
std::random_device randomDevice;
std::mt19937 numberGenerator { randomDevice() };
std::uniform_int_distribution<> distribution { 1, (int) ceil(1.0f / AudioConstants::NETWORK_FRAME_SECS) };
_frameToSendStats = distribution(numberGenerator);
} }
AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() { AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() {
@ -180,6 +189,10 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() {
} }
} }
bool AudioMixerClientData::shouldSendStats(int frameNumber) {
return frameNumber == _frameToSendStats;
}
void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) { void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();

View file

@ -58,6 +58,9 @@ public:
void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; } void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; } quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }
// uses randomization to have the AudioMixer send a stats packet to this node around every second
bool shouldSendStats(int frameNumber);
signals: signals:
void injectorStreamFinished(const QUuid& streamIdentifier); void injectorStreamFinished(const QUuid& streamIdentifier);
@ -72,6 +75,8 @@ private:
quint16 _outgoingMixedAudioSequenceNumber; quint16 _outgoingMixedAudioSequenceNumber;
AudioStreamStats _downstreamAudioStreamStats; AudioStreamStats _downstreamAudioStreamStats;
int _frameToSendStats { 0 };
}; };
#endif // hifi_AudioMixerClientData_h #endif // hifi_AudioMixerClientData_h

View file

@ -36,14 +36,7 @@ const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXE
AvatarMixer::AvatarMixer(ReceivedMessage& message) : AvatarMixer::AvatarMixer(ReceivedMessage& message) :
ThreadedAssignment(message), ThreadedAssignment(message),
_broadcastThread(), _broadcastThread()
_lastFrameTimestamp(QDateTime::currentMSecsSinceEpoch()),
_trailingSleepRatio(1.0f),
_performanceThrottlingRatio(0.0f),
_sumListeners(0),
_numStatFrames(0),
_sumBillboardPackets(0),
_sumIdentityPackets(0)
{ {
// make sure we hear about node kills so we can tell the other nodes // make sure we hear about node kills so we can tell the other nodes
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled); connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
@ -51,7 +44,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver(); auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket"); packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket");
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "handleAvatarBillboardPacket");
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
} }
@ -66,13 +58,18 @@ AvatarMixer::~AvatarMixer() {
// An 80% chance of sending a identity packet within a 5 second interval. // An 80% chance of sending a identity packet within a 5 second interval.
// assuming 60 htz update rate. // assuming 60 htz update rate.
const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f; const float IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
// NOTE: some additional optimizations to consider. // NOTE: some additional optimizations to consider.
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
// if the avatar is not in view or in the keyhole. // if the avatar is not in view or in the keyhole.
void AvatarMixer::broadcastAvatarData() { void AvatarMixer::broadcastAvatarData() {
int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; int idleTime = AVATAR_DATA_SEND_INTERVAL_MSECS;
if (_lastFrameTimestamp.time_since_epoch().count() > 0) {
auto idleDuration = p_high_resolution_clock::now() - _lastFrameTimestamp;
idleTime = std::chrono::duration_cast<std::chrono::microseconds>(idleDuration).count();
}
++_numStatFrames; ++_numStatFrames;
@ -245,32 +242,13 @@ void AvatarMixer::broadcastAvatarData() {
return; return;
} }
// make sure we send out identity and billboard packets to and from new arrivals. // make sure we send out identity packets to and from new arrivals.
bool forceSend = !otherNodeData->checkAndSetHasReceivedFirstPacketsFrom(node->getUUID()); bool forceSend = !otherNodeData->checkAndSetHasReceivedFirstPacketsFrom(node->getUUID());
// we will also force a send of billboard or identity packet if (otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0
// if either has changed in the last frame
if (otherNodeData->getBillboardChangeTimestamp() > 0
&& (forceSend
|| otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
QByteArray rfcUUID = otherNode->getUUID().toRfc4122();
QByteArray billboard = otherNodeData->getAvatar().getBillboard();
auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard, rfcUUID.size() + billboard.size());
billboardPacket->write(rfcUUID);
billboardPacket->write(billboard);
nodeList->sendPacket(std::move(billboardPacket), *node);
++_sumBillboardPackets;
}
if (otherNodeData->getIdentityChangeTimestamp() > 0
&& (forceSend && (forceSend
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) { || distribution(generator) < IDENTITY_SEND_PROBABILITY)) {
QByteArray individualData = otherNodeData->getAvatar().identityByteArray(); QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
@ -385,7 +363,7 @@ void AvatarMixer::broadcastAvatarData() {
otherAvatar.doneEncoding(false); otherAvatar.doneEncoding(false);
}); });
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch(); _lastFrameTimestamp = p_high_resolution_clock::now();
} }
void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
@ -438,26 +416,12 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
// parse the identity packet and update the change timestamp if appropriate // parse the identity packet and update the change timestamp if appropriate
if (avatar.hasIdentityChangedAfterParsing(message->getMessage())) { if (avatar.hasIdentityChangedAfterParsing(message->getMessage())) {
QMutexLocker nodeDataLocker(&nodeData->getMutex()); QMutexLocker nodeDataLocker(&nodeData->getMutex());
nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch()); nodeData->flagIdentityChange();
} }
} }
} }
} }
void AvatarMixer::handleAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
if (nodeData) {
AvatarData& avatar = nodeData->getAvatar();
// parse the billboard packet and update the change timestamp if appropriate
if (avatar.hasBillboardChangedAfterParsing(message->getMessage())) {
QMutexLocker nodeDataLocker(&nodeData->getMutex());
nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
}
}
}
void AvatarMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message) { void AvatarMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message) {
DependencyManager::get<NodeList>()->processKillNode(*message); DependencyManager::get<NodeList>()->processKillNode(*message);
} }
@ -466,7 +430,6 @@ void AvatarMixer::sendStatsPacket() {
QJsonObject statsObject; QJsonObject statsObject;
statsObject["average_listeners_last_second"] = (float) _sumListeners / (float) _numStatFrames; statsObject["average_listeners_last_second"] = (float) _sumListeners / (float) _numStatFrames;
statsObject["average_billboard_packets_per_frame"] = (float) _sumBillboardPackets / (float) _numStatFrames;
statsObject["average_identity_packets_per_frame"] = (float) _sumIdentityPackets / (float) _numStatFrames; statsObject["average_identity_packets_per_frame"] = (float) _sumIdentityPackets / (float) _numStatFrames;
statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100; statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100;
@ -507,7 +470,6 @@ void AvatarMixer::sendStatsPacket() {
ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject); ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject);
_sumListeners = 0; _sumListeners = 0;
_sumBillboardPackets = 0;
_sumIdentityPackets = 0; _sumIdentityPackets = 0;
_numStatFrames = 0; _numStatFrames = 0;
} }

View file

@ -15,6 +15,8 @@
#ifndef hifi_AvatarMixer_h #ifndef hifi_AvatarMixer_h
#define hifi_AvatarMixer_h #define hifi_AvatarMixer_h
#include <PortableHighResolutionClock.h>
#include <ThreadedAssignment.h> #include <ThreadedAssignment.h>
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients /// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
@ -34,7 +36,6 @@ public slots:
private slots: private slots:
void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message); void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message);
void domainSettingsRequestComplete(); void domainSettingsRequestComplete();
@ -44,15 +45,14 @@ private:
QThread _broadcastThread; QThread _broadcastThread;
quint64 _lastFrameTimestamp; p_high_resolution_clock::time_point _lastFrameTimestamp;
float _trailingSleepRatio; float _trailingSleepRatio { 1.0f };
float _performanceThrottlingRatio; float _performanceThrottlingRatio { 0.0f };
int _sumListeners; int _sumListeners { 0 };
int _numStatFrames; int _numStatFrames { 0 };
int _sumBillboardPackets; int _sumIdentityPackets { 0 };
int _sumIdentityPackets;
float _maxKbpsPerNode = 0.0f; float _maxKbpsPerNode = 0.0f;

View file

@ -24,6 +24,7 @@
#include <NodeData.h> #include <NodeData.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <udt/PacketHeaders.h> #include <udt/PacketHeaders.h>
#include <PortableHighResolutionClock.h>
#include <SimpleMovingAverage.h> #include <SimpleMovingAverage.h>
#include <UUIDHasher.h> #include <UUIDHasher.h>
@ -33,6 +34,8 @@ const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
class AvatarMixerClientData : public NodeData { class AvatarMixerClientData : public NodeData {
Q_OBJECT Q_OBJECT
public: public:
using HRCTime = p_high_resolution_clock::time_point;
int parseData(ReceivedMessage& message) override; int parseData(ReceivedMessage& message) override;
AvatarData& getAvatar() { return *_avatar; } AvatarData& getAvatar() { return *_avatar; }
@ -45,11 +48,8 @@ public:
uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; } uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; }
quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; } HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; } void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); }
quint64 getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
void setIdentityChangeTimestamp(quint64 identityChangeTimestamp) { _identityChangeTimestamp = identityChangeTimestamp; }
void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; } void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; }
float getFullRateDistance() const { return _fullRateDistance; } float getFullRateDistance() const { return _fullRateDistance; }
@ -86,8 +86,7 @@ private:
std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers; std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers;
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom; std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
quint64 _billboardChangeTimestamp = 0; HRCTime _identityChangeTimestamp;
quint64 _identityChangeTimestamp = 0;
float _fullRateDistance = FLT_MAX; float _fullRateDistance = FLT_MAX;
float _maxAvatarDistance = FLT_MAX; float _maxAvatarDistance = FLT_MAX;

View file

@ -952,6 +952,24 @@ bool OctreeServer::readOptionInt(const QString& optionName, const QJsonObject& s
return optionAvailable; return optionAvailable;
} }
bool OctreeServer::readOptionInt64(const QString& optionName, const QJsonObject& settingsSectionObject, qint64& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
const char* argValue = getCmdOption(_argc, _argv, qPrintable(argName));
if (argValue) {
optionAvailable = true;
result = atoll(argValue);
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << result;
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toString().toLongLong(&optionAvailable);
if (optionAvailable) {
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << result;
}
}
return optionAvailable;
}
bool OctreeServer::readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result) { bool OctreeServer::readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result) {
bool optionAvailable = false; bool optionAvailable = false;
QString argName = "--" + optionName; QString argName = "--" + optionName;
@ -1055,10 +1073,10 @@ void OctreeServer::readConfiguration() {
// Debug option to demonstrate that the server's local time does not // Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock // need to be in sync with any other network node. This forces clock
// skew for the individual server node // skew for the individual server node
int clockSkew; qint64 clockSkew;
if (readOptionInt(QString("clockSkew"), settingsSectionObject, clockSkew)) { if (readOptionInt64(QString("clockSkew"), settingsSectionObject, clockSkew)) {
usecTimestampNowForceClockSkew(clockSkew); usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkew=%d", clockSkew); qDebug() << "clockSkew=" << clockSkew;
} }
// Check to see if the user passed in a command line option for setting packet send rate // Check to see if the user passed in a command line option for setting packet send rate

View file

@ -145,6 +145,7 @@ protected:
virtual OctreePointer createTree() = 0; virtual OctreePointer createTree() = 0;
bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result); bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result);
bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result); bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result);
bool readOptionInt64(const QString& optionName, const QJsonObject& settingsSectionObject, qint64& result);
bool readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result); bool readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result);
void readConfiguration(); void readConfiguration();
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { }; virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { };

View file

@ -7,9 +7,9 @@ endif ()
include(ExternalProject) include(ExternalProject)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple2.zip URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple_1.13.0.zip
URL_MD5 f05d858e8203c32b689da208ad8b39db URL_MD5 73f833649e904257b35bf4e84f8bdfb5
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
LOG_DOWNLOAD 1 LOG_DOWNLOAD 1
LOG_CONFIGURE 1 LOG_CONFIGURE 1
LOG_BUILD 1 LOG_BUILD 1

View file

@ -27,6 +27,10 @@ macro(SET_PACKAGING_PARAMETERS)
set(HIGH_FIDELITY_PROTOCOL "hifi") set(HIGH_FIDELITY_PROTOCOL "hifi")
set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_BUNDLE_NAME "Interface")
set(INTERFACE_ICON_PREFIX "interface") set(INTERFACE_ICON_PREFIX "interface")
# add definition for this release type
add_definitions(-DPRODUCTION_BUILD)
elseif (RELEASE_TYPE STREQUAL "PR") elseif (RELEASE_TYPE STREQUAL "PR")
set(DEPLOY_PACKAGE TRUE) set(DEPLOY_PACKAGE TRUE)
set(PR_BUILD 1) set(PR_BUILD 1)
@ -34,12 +38,18 @@ macro(SET_PACKAGING_PARAMETERS)
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}") set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_BUNDLE_NAME "Interface")
set(INTERFACE_ICON_PREFIX "interface-beta") set(INTERFACE_ICON_PREFIX "interface-beta")
# add definition for this release type
add_definitions(-DPR_BUILD)
else () else ()
set(DEV_BUILD 1) set(DEV_BUILD 1)
set(BUILD_VERSION "dev") set(BUILD_VERSION "dev")
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}") set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_BUNDLE_NAME "Interface")
set(INTERFACE_ICON_PREFIX "interface-beta") set(INTERFACE_ICON_PREFIX "interface-beta")
# add definition for this release type
add_definitions(-DDEV_BUILD)
endif () endif ()
if (APPLE) if (APPLE)

View file

@ -201,7 +201,7 @@ var toolBar = (function() {
}, true, false); }, true, false);
newModelButton = toolBar.addTool({ newModelButton = toolBar.addTool({
imageURL: toolIconUrl + "upload-01.svg", imageURL: toolIconUrl + "model-01.svg",
subImage: { subImage: {
x: 0, x: 0,
y: Tool.IMAGE_WIDTH, y: Tool.IMAGE_WIDTH,
@ -404,6 +404,10 @@ var toolBar = (function() {
Window.alert("Can't create " + properties.type + ": " + properties.type + " would be out of bounds."); Window.alert("Can't create " + properties.type + ": " + properties.type + " would be out of bounds.");
} }
selectionManager.clearSelections();
entityListTool.sendUpdate();
selectionManager.setSelections([entityID]);
return entityID; return entityID;
} }
@ -1194,6 +1198,30 @@ function deleteSelectedEntities() {
} }
} }
function toggleSelectedEntitiesLocked() {
if (SelectionManager.hasSelection()) {
var locked = !Entities.getEntityProperties(SelectionManager.selections[0], ["locked"]).locked;
for (var i = 0; i < selectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
Entities.editEntity(entityID, { locked: locked });
}
entityListTool.sendUpdate();
selectionManager._update();
}
}
function toggleSelectedEntitiesVisible() {
if (SelectionManager.hasSelection()) {
var visible = !Entities.getEntityProperties(SelectionManager.selections[0], ["visible"]).visible;
for (var i = 0; i < selectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
Entities.editEntity(entityID, { visible: visible });
}
entityListTool.sendUpdate();
selectionManager._update();
}
}
function handeMenuEvent(menuItem) { function handeMenuEvent(menuItem) {
if (menuItem == "Allow Selecting of Small Models") { if (menuItem == "Allow Selecting of Small Models") {
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
@ -1522,7 +1550,8 @@ PropertiesTool = function(opts) {
data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS); data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS);
} }
Entities.editEntity(selectionManager.selections[0], data.properties); Entities.editEntity(selectionManager.selections[0], data.properties);
if (data.properties.name != undefined) { if (data.properties.name !== undefined || data.properties.modelURL !== undefined
|| data.properties.visible !== undefined || data.properties.locked !== undefined) {
entityListTool.sendUpdate(); entityListTool.sendUpdate();
} }
} }

View file

@ -63,7 +63,7 @@
} }
body { body {
padding: 24px 12px 24px 12px; padding: 21px 21px 21px 21px;
color: #afafaf; color: #afafaf;
background-color: #404040; background-color: #404040;
@ -164,6 +164,10 @@ tr.selected {
background-color: #00b4ef; background-color: #00b4ef;
} }
tr.selected + tr.selected {
border-top: 1px solid #2e2e2e;
}
th { th {
text-align: center; text-align: center;
word-wrap: nowrap; word-wrap: nowrap;
@ -227,6 +231,15 @@ input.search {
border-radius: 14px; border-radius: 14px;
} }
input.search:focus {
outline: none;
box-sizing: border-box;
height: 26px;
margin-top: 1px;
margin-bottom: 1px;
box-shadow: 0 0 0px 1px #00b4ef;
}
input:disabled, textarea:disabled { input:disabled, textarea:disabled {
background-color: #383838; background-color: #383838;
color: #afafaf; color: #afafaf;
@ -275,7 +288,9 @@ input[type=number]::-webkit-inner-spin-button:after {
content: "5"; content: "5";
bottom: 6px; bottom: 6px;
} }
input[type="number"]::-webkit-inner-spin-button:hover {
input[type=number].hover-up::-webkit-inner-spin-button:before,
input[type=number].hover-down::-webkit-inner-spin-button:after {
color: #ffffff; color: #ffffff;
} }
@ -294,8 +309,8 @@ input[type=button] {
vertical-align: top; vertical-align: top;
height: 28px; height: 28px;
min-width: 120px; min-width: 120px;
padding: 0px 12px; padding: 0px 18px;
margin-right: 8px; margin-right: 6px;
border-radius: 5px; border-radius: 5px;
border: none; border: none;
color: #fff; color: #fff;
@ -370,6 +385,22 @@ input[type=checkbox]:checked + label:hover {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVDhPnZLPSsNAEMa/XVPBCE0RhNy0OarP4Av4AD6JB0GwVBA8efBBxHsgh4CQswcRoUIpiIpVAm3zZ5M4szFSbQPBH3xkJvNNZskOer2eLIriKM/ze1JOcS1UHmdZduF5ngEKjr/fN4Z6+oKerwA2gxC4HAFPEWVLsAzgZAvYt3Q6Enw6jg7uBAaTFMNwhpnKdbXCkAJdy8ROu4XrXW2HTJIErHcFDD6nC02Mom8PwymeE2gvS0ZRBBaTlsOXEmdlrfLLOI7Bakrl/zWxCT8T/904f9QW/b06qtrCUdtFCqdjYs2Q2jAPX8c2XQd7Kr/wfV8vwIPs4Ga1ixe5Xrr/YFLTYfKIvWzM6ZtwXZdX7lxXG0L+sxXHcW5t254opRzawQ0S72+dPmjTroIgOP0CQSMt5LDn1T8AAAAASUVORK5CYII=); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVDhPnZLPSsNAEMa/XVPBCE0RhNy0OarP4Av4AD6JB0GwVBA8efBBxHsgh4CQswcRoUIpiIpVAm3zZ5M4szFSbQPBH3xkJvNNZskOer2eLIriKM/ze1JOcS1UHmdZduF5ngEKjr/fN4Z6+oKerwA2gxC4HAFPEWVLsAzgZAvYt3Q6Enw6jg7uBAaTFMNwhpnKdbXCkAJdy8ROu4XrXW2HTJIErHcFDD6nC02Mom8PwymeE2gvS0ZRBBaTlsOXEmdlrfLLOI7Bakrl/zWxCT8T/904f9QW/b06qtrCUdtFCqdjYs2Q2jAPX8c2XQd7Kr/wfV8vwIPs4Ga1ixe5Xrr/YFLTYfKIvWzM6ZtwXZdX7lxXG0L+sxXHcW5t254opRzawQ0S72+dPmjTroIgOP0CQSMt5LDn1T8AAAAASUVORK5CYII=);
} }
.icon-input input {
position: relative;
padding-left: 36px;
}
.icon-input span {
position: absolute;
left: 6px;
top: -2px;
font-family: hifi-glyphs;
font-size: 30px;
color: #afafaf;
}
.icon-input input:focus + span {
color: #ffffff;
}
.selectable { .selectable {
-webkit-touch-callout: text; -webkit-touch-callout: text;
-webkit-user-select: text; -webkit-user-select: text;
@ -396,11 +427,11 @@ input[type=checkbox]:checked + label:hover {
} }
.section-header, .sub-section-header { .section-header, .sub-section-header, hr {
display: table; display: table;
width: 100%; width: 100%;
margin: 22px -12px 0 -12px; margin: 21px -21px 0 -21px;
padding: 14px 12px 0 12px; padding: 14px 21px 0 21px;
font-family: Raleway-Regular; font-family: Raleway-Regular;
font-size: 12px; font-size: 12px;
color: #afafaf; color: #afafaf;
@ -414,12 +445,12 @@ input[type=checkbox]:checked + label:hover {
background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAqCAIAAAAbNW1vAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAmSURBVChTY1BFAgzhSIDBAQmMcoYHRwIJMCgjAQZ9JMBgBQdWVgBh5XmBV5A2FQAAAABJRU5ErkJggg==) repeat-x top left; background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAqCAIAAAAbNW1vAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAmSURBVChTY1BFAgzhSIDBAQmMcoYHRwIJMCgjAQZ9JMBgBQdWVgBh5XmBV5A2FQAAAABJRU5ErkJggg==) repeat-x top left;
} }
.sub-section-header, .no-collapse { .sub-section-header, .no-collapse, hr {
background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAjSURBVBhXY1RVVf3PgARYjIyMoEwIYHRwcEBRwQSloYCBAQCwjgPMiI7W2QAAAABJRU5ErkJggg==) repeat-x top left; background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAjSURBVBhXY1RVVf3PgARYjIyMoEwIYHRwcEBRwQSloYCBAQCwjgPMiI7W2QAAAABJRU5ErkJggg==) repeat-x top left;
} }
.section-header:first-child { .section-header:first-child {
margin-top: 0; margin-top: -2px;
padding-top: 0; padding-top: 0;
background: none; background: none;
height: auto; height: auto;
@ -435,11 +466,16 @@ input[type=checkbox]:checked + label:hover {
float: right; float: right;
position: absolute; position: absolute;
top: 4px; top: 4px;
right: 6px; right: 13px;
} }
.section-header[collapsed="true"] { .section-header[collapsed="true"] {
margin-bottom: -22px; margin-bottom: -21px;
}
hr {
border: none;
padding-top: 2px;
} }
.text-group[collapsed="true"] ~ .text-group, .text-group[collapsed="true"] ~ .text-group,
@ -458,20 +494,25 @@ input[type=checkbox]:checked + label:hover {
.property { .property {
display: table; display: table;
width: 100%; width: 100%;
margin-top: 22px; margin-top: 21px;
min-height: 29px; min-height: 28px;
} }
.property.checkbox { .property.checkbox {
width: auto; width: auto;
} }
.property label { .property label, .number label {
display: table-cell; display: table-cell;
vertical-align: middle; vertical-align: middle;
font-family: Raleway-SemiBold; font-family: Raleway-SemiBold;
font-size: 14px; font-size: 14px;
} }
.property label .unit, .number label .unit {
margin-left: 8px;
font-family: Raleway-Light;
font-size: 13px;
}
.value { .value {
display: block; display: block;
@ -499,12 +540,14 @@ input[type=checkbox]:checked + label:hover {
float: left; float: left;
} }
.property .number + .number { .property .number + .number {
margin-left: 12px; margin-left: 10px;
} }
.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label { .text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label {
float: left; float: left;
margin-bottom: 4px; margin-left: 1px;
margin-bottom: 3px;
margin-top: -2px;
} }
.number > input { .number > input {
@ -519,13 +562,6 @@ input[type=checkbox]:checked + label:hover {
clear: both; clear: both;
} }
.unit {
padding-left: 4px;
vertical-align: top;
position: relative;
top: 5px;
}
.dropdown { .dropdown {
position: relative; position: relative;
margin-bottom: -17px; margin-bottom: -17px;
@ -544,10 +580,8 @@ input[type=checkbox]:checked + label:hover {
width: 172px; width: 172px;
height: 28px; height: 28px;
padding: 0 28px 0 12px; padding: 0 28px 0 12px;
color: #afafaf; color: #afafaf;
background: linear-gradient(#7d7d7d 20%, #686a68 100%); background: linear-gradient(#7d7d7d 20%, #686a68 100%);
position: relative; position: relative;
} }
.dropdown dl[dropped="true"] { .dropdown dl[dropped="true"] {
@ -606,6 +640,17 @@ input[type=checkbox]:checked + label:hover {
background-color: #00b4ef; background-color: #00b4ef;
} }
.dropdown dl[disabled="disabled"], .dropdown dl[disabled="disabled"][dropped="true"] {
color: #252525;
background: linear-gradient(#575757 20%, #252525 100%);
}
.dropdown dl[disabled="disabled"] dd {
display: none;
}
.dropdown dl[disabled="disabled"] dt:hover {
color: #252525;
}
div.refresh { div.refresh {
box-sizing: border-box; box-sizing: border-box;
@ -619,7 +664,7 @@ div.refresh input[type="button"] {
.color-picker { .color-picker {
box-sizing: border-box; box-sizing: border-box;
float: left; float: left;
margin-bottom: 12px; margin-bottom: 21px;
width: 36px; width: 36px;
height: 36px; height: 36px;
border: 4px solid #afafaf; border: 4px solid #afafaf;
@ -636,32 +681,36 @@ div.refresh input[type="button"] {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABDSURBVChTjcoLCkAhCETRNq0tf97Y5xGZ1gVJ45TH6njThIO+xk2UwhWFcEdH6JCqOuiQiMDi/hcii3crRRb/7ggAPvIMVihQwvSXAAAAAElFTkSuQmCC); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABDSURBVChTjcoLCkAhCETRNq0tf97Y5xGZ1gVJ45TH6njThIO+xk2UwhWFcEdH6JCqOuiQiMDi/hcii3crRRb/7ggAPvIMVihQwvSXAAAAAElFTkSuQmCC);
} }
.color-picker[disabled="disabled"] {
border-color: #afafaf;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABTSURBVChTjcxBDoAwCETRwTs33sFjwB6uaCE1Ggvav5qQF7CSqu40dllHjYiOT3gh3yV8Ii+Fb+RNMEP9hm3sKENmBhG5P1aImWMH/EMerSAAOAFgTC/R8ZXSXAAAAABJRU5ErkJggg==);
}
.colpick[disabled="disabled"] {
display: none !important;
}
.rgb label { .rgb label {
float: left; float: left;
margin-top: 10px; margin-top: 10px;
margin-left: 12px; margin-left: 21px;
} }
.rgb label + * { .rgb label + * {
clear: both; clear: both;
} }
.tuple {
width: 100%;
text-align: center;
}
.tuple div { .tuple div {
display: inline-block; display: inline-block;
position: relative; position: relative;
min-width: 120px; margin-right: 6px;
min-height: 1px;
} }
.tuple div:nth-child(1) { .tuple div:last-child {
float: left; margin-right: 0;
} }
.tuple div:nth-child(2) {
} .tuple label {
.tuple div:nth-child(3) { margin-right: -6px;
float: right;
} }
.rgb .tuple input { .rgb .tuple input {
@ -712,31 +761,49 @@ tuple, .blue:focus, .tuple .z:focus, .tuple .roll:focus {
} }
.xyz .buttons input { .xyz .buttons input {
margin-top: 12px; margin-top: 14px;
} }
.xyz .buttons span { .xyz .buttons span {
word-wrap: nowrap; word-wrap: nowrap;
white-space: nowrap; white-space: nowrap;
} }
.row input { .row .property {
float: left; width: auto;
display: inline-block;
margin-right: 6px;
} }
.row input[type=button] { .row .property:last-child {
margin-left: 8px;
margin-right: 0; margin-right: 0;
} }
.row .property input {
clear: both;
float: left;
}
.two-column {
display: table;
width: 100%;
}
.two-column > div {
display: table-cell;
width: 50%;
}
.column {
vertical-align: top;
}
.indent {
margin-left: 24px;
}
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 10px; width: 10px;
height: 10px; height: 10px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background-color: #2e2e2e; background-color: #2e2e2e;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: #696969; background-color: #696969;
border: 2px solid #2e2e2e; border: 2px solid #2e2e2e;
@ -760,7 +827,28 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
#entity-list-header { #entity-list-header {
margin-bottom: 24px; margin-bottom: 36px;
}
#entity-list-header div {
display: inline-block;
width: 65px;
margin-right: 6px;
}
#entity-list-header div input:first-child {
margin-right: 0;
float: left;
width: 33px;
border-right: 1px solid #808080;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
#entity-list-header div input:last-child {
margin-right: 0;
float: right;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
} }
#delete { #delete {
@ -773,6 +861,11 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
position: relative; /* New positioning context. */ position: relative; /* New positioning context. */
} }
#entity-list .glyph {
font-family: HiFi-Glyphs;
font-size: 14px;
}
#search-area { #search-area {
padding-right: 148px; padding-right: 148px;
padding-bottom: 24px; padding-bottom: 24px;
@ -785,6 +878,8 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
#radius-and-unit { #radius-and-unit {
float: right; float: right;
margin-right: -148px; margin-right: -148px;
position: relative;
top: -17px;
} }
@ -798,17 +893,39 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
margin-top: 28px; margin-top: 28px;
border-left: 2px solid #575757; border-left: 2px solid #575757;
border-right: 2px solid #575757; border-right: 2px solid #575757;
}
#entity-table-scroll, #entity-table {
background-color: #1c1c1c; background-color: #1c1c1c;
} }
#entity-table { #entity-table {
margin-top: -28px; margin-top: -28px;
margin-bottom: -18px; margin-bottom: -18px;
table-layout: fixed; table-layout: fixed;
border: none; border: none;
background-color: #1c1c1c;
}
#col-type {
width: 16%;
}
#col-name {
width: 34%;
}
#col-url {
width: 34%;
}
#col-locked, #col-visible {
width: 8%;
}
#entity-table thead tr, #entity-table thead tr th,
#entity-table tfoot tr, #entity-table tfoot tr td {
background: none;
}
#entity-table .glyph {
margin: 0 -2px 0 -2px;
vertical-align: middle;
} }
#entity-table thead { #entity-table thead {
@ -817,6 +934,42 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
border-top-left-radius: 7px; border-top-left-radius: 7px;
border-top-right-radius: 7px; border-top-right-radius: 7px;
border-bottom: 1px solid #575757; border-bottom: 1px solid #575757;
position: absolute;
top: 49px;
left: 0;
width: 100%;
}
#entity-table thead th {
box-sizing: border-box;
padding: 0 0 0 8px;
vertical-align: middle;
}
#entity-table th:focus {
outline: none;
}
#entity-table th .glyph {
position: relative;
left: 0;
}
#entity-table thead .sort-order {
display: inline-block;
width: 8px;
margin: -5px 0 -3px 0;
text-align: right;
vertical-align: middle;
}
#entity-table td {
box-sizing: border-box;
}
#entity-table td.glyph {
text-align: center;
padding: 0;
} }
#entity-table tfoot { #entity-table tfoot {
@ -825,39 +978,6 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
border-bottom-left-radius: 7px; border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px; border-bottom-right-radius: 7px;
border-top: 1px solid #575757; border-top: 1px solid #575757;
}
#entity-table thead tr, #entity-table thead tr th,
#entity-table tfoot tr, #entity-table tfoot tr td {
background: none;
}
#entity-table th:focus {
outline: none;
}
#col-type {
width: 16%;
}
#col-name {
width: 42%;
}
#col-url {
width: 42%;
}
#entity-table thead {
position: absolute;
top: 49px;
left: 0;
width: 100%;
}
#entity-table thead th {
padding: 0;
}
#entity-table tfoot {
position: absolute; position: absolute;
bottom: -21px; bottom: -21px;
left: 0; left: 0;
@ -876,25 +996,92 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
} }
#properties-list .property:first-child { #properties-header {
margin-top: 0; display: table-row;
height: 28px;
} }
#properties-header .property {
display: table-cell;
vertical-align: middle;
}
#properties-header .checkbox {
position: relative;
top: -1px;
}
#properties-header #type-icon {
font-family: hifi-glyphs;
font-size: 31px;
color: #00b4ef;
margin: -4px 12px -4px -2px;
width: auto;
display: none;
vertical-align: middle;
}
#properties-header #property-type {
padding: 5px 24px 5px 0;
border-right: 1px solid #808080;
height: 100%;
width: auto;
display: inline-block;
vertical-align: middle;
}
#properties-header .checkbox:last-child {
padding-left: 24px;
}
#properties-header .checkbox label {
background-position-y: 1px;
}
#properties-header .checkbox label span {
font-family: HiFi-Glyphs;
font-size: 20px;
padding-right: 6px;
vertical-align: top;
position: relative;
top: -4px;
}
#properties-header input[type=checkbox]:checked + label span {
color: #ffffff;
}
#properties-header + hr {
margin-top: 12px;
}
#id label {
width: 24px;
}
#property-id {
display: inline-block;
}
#property-id::selection { #property-id::selection {
color: #000000; color: #000000;
background-color: #00b4ef; background-color: #00b4ef;
} }
input#property-parent-id {
width: 340px;
}
input#dimension-rescale-button { input#dimension-rescale-button {
min-width: 50px; min-width: 50px;
margin-left: 6px; margin-left: 6px;
} }
input#reset-to-natural-dimensions {
margin-right: 0;
.color-set label, .color-set span {
display: block;
} }
.color-set span { input#preview-camera-button {
padding-top: 2px; margin-left: 1px;
margin-right: 0;
}
#animation-fps {
margin-top: 48px;
} }

View file

@ -14,25 +14,34 @@
<script src="list.min.js"></script> <script src="list.min.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="eventBridgeLoader.js"></script> <script type="text/javascript" src="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script> <script>
var entities = {}; var entities = {};
var selectedEntities = []; var selectedEntities = [];
var currentSortColumn = 'type'; var currentSortColumn = 'type';
var currentSortOrder = 'asc'; var currentSortOrder = 'des';
var entityList = null; var entityList = null;
var refreshEntityListTimer = null; var refreshEntityListTimer = null;
const ASCENDING_STRING = '&nbsp;&#x25BE;'; const ASCENDING_STRING = '&#x25BE;';
const DESCENDING_STRING = '&nbsp;&#x25B4;'; const DESCENDING_STRING = '&#x25B4;';
const LOCKED_GLYPH = "&#xe006;";
const VISIBLE_GLYPH = "&#xe007;";
const DELETE = 46; // Key code for the delete key. const DELETE = 46; // Key code for the delete key.
const MAX_ITEMS = Number.MAX_VALUE; // Used to set the max length of the list of discovered entities. const MAX_ITEMS = Number.MAX_VALUE; // Used to set the max length of the list of discovered entities.
debugPrint = function (message) {
console.log(message);
};
function loaded() { function loaded() {
openEventBridge(function() { openEventBridge(function() {
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url'], page: MAX_ITEMS}); entityList = new List('entity-list', { valueNames: ['name', 'type', 'url', 'locked', 'visible'], page: MAX_ITEMS});
entityList.clear(); entityList.clear();
elEntityTable = document.getElementById("entity-table"); elEntityTable = document.getElementById("entity-table");
elEntityTableBody = document.getElementById("entity-table-body"); elEntityTableBody = document.getElementById("entity-table-body");
elRefresh = document.getElementById("refresh"); elRefresh = document.getElementById("refresh");
elToggleLocked = document.getElementById("locked");
elToggleVisible = document.getElementById("visible");
elDelete = document.getElementById("delete"); elDelete = document.getElementById("delete");
elTeleport = document.getElementById("teleport"); elTeleport = document.getElementById("teleport");
elRadius = document.getElementById("radius"); elRadius = document.getElementById("radius");
@ -50,6 +59,12 @@
document.getElementById("entity-url").onclick = function() { document.getElementById("entity-url").onclick = function() {
setSortColumn('url'); setSortColumn('url');
}; };
document.getElementById("entity-locked").onclick = function () {
setSortColumn('locked');
};
document.getElementById("entity-visible").onclick = function () {
setSortColumn('visible');
};
function onRowClicked(clickEvent) { function onRowClicked(clickEvent) {
var id = this.dataset.entityId; var id = this.dataset.entityId;
@ -101,19 +116,20 @@
})); }));
} }
function addEntity(id, name, type, url) { function addEntity(id, name, type, url, locked, visible) {
var urlParts = url.split('/');
var filename = urlParts[urlParts.length - 1];
if (entities[id] === undefined) { if (entities[id] === undefined) {
var urlParts = url.split('/'); entityList.add([{ id: id, name: name, type: type, url: filename, locked: locked, visible: visible }],
var filename = urlParts[urlParts.length - 1]; function (items) {
entityList.add([{ id: id, name: name, type: type, url: filename }], function(items) {
var currentElement = items[0].elm; var currentElement = items[0].elm;
var id = items[0]._values.id; var id = items[0]._values.id;
entities[id] = { entities[id] = {
id: id, id: id,
name: name, name: name,
el: currentElement, el: currentElement,
item: items[0], item: items[0]
}; };
currentElement.setAttribute('id', 'entity_' + id); currentElement.setAttribute('id', 'entity_' + id);
currentElement.setAttribute('title', url); currentElement.setAttribute('title', url);
@ -128,7 +144,7 @@
refreshEntityListTimer = setTimeout(refreshEntityListObject, 50); refreshEntityListTimer = setTimeout(refreshEntityListObject, 50);
} else { } else {
var item = entities[id].item; var item = entities[id].item;
item.values({ name: name, url: url }); item.values({ name: name, url: filename, locked: locked, visible: visible });
} }
} }
@ -141,19 +157,21 @@
name: document.querySelector('#entity-name .sort-order'), name: document.querySelector('#entity-name .sort-order'),
type: document.querySelector('#entity-type .sort-order'), type: document.querySelector('#entity-type .sort-order'),
url: document.querySelector('#entity-url .sort-order'), url: document.querySelector('#entity-url .sort-order'),
locked: document.querySelector('#entity-locked .sort-order'),
visible: document.querySelector('#entity-visible .sort-order')
} }
function setSortColumn(column) { function setSortColumn(column) {
if (currentSortColumn == column) { if (currentSortColumn == column) {
currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc"; currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc";
} else { } else {
elSortOrder[currentSortColumn].style.display = 'none'; elSortOrder[currentSortColumn].innerHTML = "";
elSortOrder[column].style.display = 'inline';
currentSortColumn = column; currentSortColumn = column;
currentSortOrder = "asc"; currentSortOrder = "asc";
} }
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING; elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING;
entityList.sort(currentSortColumn, { order: currentSortOrder }); entityList.sort(currentSortColumn, { order: currentSortOrder });
} }
setSortColumn('type');
function refreshEntities() { function refreshEntities() {
clearEntities(); clearEntities();
@ -191,13 +209,24 @@
elFooter.firstChild.nodeValue = entityList.visibleItems.length + " entities found"; elFooter.firstChild.nodeValue = entityList.visibleItems.length + " entities found";
} }
// HACK: Fixes the footer and header text sometimes not displaying after adding or deleting entities.
// The problem appears to be a bug in the Qt HTML/CSS rendering (Qt 5.5).
document.getElementById("radius").focus();
document.getElementById("radius").blur();
return notFound; return notFound;
} }
elRefresh.onclick = function() { elRefresh.onclick = function() {
refreshEntities(); refreshEntities();
} }
elTeleport.onclick = function() { elToggleLocked.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' }));
}
elToggleVisible.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' }));
}
elTeleport.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' })); EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' }));
} }
elDelete.onclick = function() { elDelete.onclick = function() {
@ -238,11 +267,14 @@
var newEntities = data.entities; var newEntities = data.entities;
if (newEntities.length == 0) { if (newEntities.length == 0) {
elNoEntitiesMessage.style.display = "block"; elNoEntitiesMessage.style.display = "block";
elFooter.firstChild.nodeValue = "0 entities found";
} else { } else {
elNoEntitiesMessage.style.display = "none"; elNoEntitiesMessage.style.display = "none";
for (var i = 0; i < newEntities.length; i++) { for (var i = 0; i < newEntities.length; i++) {
var id = newEntities[i].id; var id = newEntities[i].id;
addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url); addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url,
newEntities[i].locked ? LOCKED_GLYPH : null,
newEntities[i].visible ? VISIBLE_GLYPH : null);
} }
updateSelectedEntities(data.selectedIDs); updateSelectedEntities(data.selectedIDs);
resize(); resize();
@ -254,15 +286,23 @@
function resize() { function resize() {
// Take up available window space // Take up available window space
elEntityTableScroll.style.height = window.innerHeight - 200; elEntityTableScroll.style.height = window.innerHeight - 207;
// Update the widths of the header cells to match the body
var tds = document.querySelectorAll("#entity-table-body tr:first-child td"); var tds = document.querySelectorAll("#entity-table-body tr:first-child td");
var ths = document.querySelectorAll("#entity-table thead th"); var ths = document.querySelectorAll("#entity-table thead th");
if (tds.length >= ths.length) { if (tds.length >= ths.length) {
// Update the widths of the header cells to match the body
for (var i = 0; i < ths.length; i++) { for (var i = 0; i < ths.length; i++) {
ths[i].style.width = tds[i].offsetWidth; ths[i].width = tds[i].offsetWidth;
} }
} else {
// Reasonable widths if nothing is displayed
var tableWidth = document.getElementById("entity-table").offsetWidth;
ths[0].width = 0.16 * tableWidth;
ths[1].width = 0.34 * tableWidth;
ths[2].width = 0.34 * tableWidth;
ths[3].width = 0.08 * tableWidth;
ths[4].width = 0.08 * tableWidth;
} }
}; };
@ -270,6 +310,8 @@
resize(); resize();
}); });
augmentSpinButtons();
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked // Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) { document.addEventListener("contextmenu", function (event) {
event.preventDefault(); event.preventDefault();
@ -280,14 +322,21 @@
<body onload='loaded();'> <body onload='loaded();'>
<div id="entity-list-header"> <div id="entity-list-header">
<input type="button" class="glyph" id="refresh" value="F" /> <input type="button" class="glyph" id="refresh" value="F" />
<div>
<input type="button" id="locked" class="glyph" value="&#xe006;" />
<input type="button" id="visible" class="glyph" value="&#xe007;" />
</div>
<input type="button" id="teleport" value="Jump To Selection" /> <input type="button" id="teleport" value="Jump To Selection" />
<input type="button" class="red" id="delete" value="Delete" /> <input type="button" class="red" id="delete" value="Delete" />
</div> </div>
<div id="entity-list"> <div id="entity-list">
<div id="search-area"> <div id="search-area">
<input type="text" class="search" id="filter" placeholder="Filter" /> <span class="icon-input"><input type="text" class="search" id="filter" placeholder="Filter" /><span>Y</span></span>
<span id="radius-and-unit"><input type="number" id="radius" value="100" /><span class="unit">m</span></span> <div id="radius-and-unit" class="number">
<label for="radius">Search radius <span class="unit">m</span></label>
<input type="number" id="radius" value="100" />
</div>
</div> </div>
<div id="entity-table-scroll"> <div id="entity-table-scroll">
<table id="entity-table"> <table id="entity-table">
@ -295,12 +344,16 @@
<col span="1" id="col-type" /> <col span="1" id="col-type" />
<col span="1" id="col-name" /> <col span="1" id="col-name" />
<col span="1" id="col-url" /> <col span="1" id="col-url" />
<col span="1" id="col-locked" />
<col span="1" id="col-visible" />
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th id="entity-type" data-sort="type">Type <span class="sort-order" style="display: inline">&nbsp;&#x25BE;</span></th> <th id="entity-type" data-sort="type">Type<span class="sort-order"></span></th>
<th id="entity-name" data-sort="type">Name <span class="sort-order" style="display: none">&nbsp;&#x25BE;</span></th> <th id="entity-name" data-sort="type">Name<span class="sort-order"></span></th>
<th id="entity-url" data-sort="url">File <span class="sort-order" style="display: none">&nbsp;&#x25BE;</span></th> <th id="entity-url" data-sort="url">File<span class="sort-order"></span></th>
<th id="entity-locked" data-sort="locked"><span class="glyph">&#xe006;</span><span class="sort-order"></span></th>
<th colspan="2" id="entity-visible" data-sort="visible"><span class="glyph">&#xe007;</span><span class="sort-order"></span></th>
</tr> </tr>
</thead> </thead>
<tbody class="list" id="entity-table-body"> <tbody class="list" id="entity-table-body">
@ -308,12 +361,14 @@
<td class="type">Type</td> <td class="type">Type</td>
<td class="name">Name</td> <td class="name">Name</td>
<td class="url"><div class='outer'><div class='inner'>URL</div></div></td> <td class="url"><div class='outer'><div class='inner'>URL</div></div></td>
<td class="id" style="display: none">Type</td> <td class="locked glyph">?</td>
<td class="visible glyph">?</td>
<td class="id" style="display: none">ID</td>
</tr> </tr>
</tbody> </tbody>
<tfoot> <tfoot>
<tr> <tr>
<td id="footer-text" colspan="3">Footer text</td> <td id="footer-text" colspan="5"> </td>
</tr> </tr>
</tfoot> </tfoot>
</table> </table>

View file

@ -17,10 +17,25 @@
<script src="colpick.js"></script> <script src="colpick.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="eventBridgeLoader.js"></script> <script type="text/javascript" src="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script> <script>
var PI = 3.14159265358979; var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0; var DEGREES_TO_RADIANS = PI / 180.0;
var RADIANS_TO_DEGREES = 180.0 / PI; var RADIANS_TO_DEGREES = 180.0 / PI;
var ICON_FOR_TYPE = {
Box: "V",
Sphere: "n",
ParticleEffect: "&#xe004;",
Model: "&#xe008;",
Web: "q",
Text: "l",
Light: "p",
Zone: "o",
PolyVox: "&#xe005;",
Multiple: "&#xe000;"
}
var colorPickers = [];
debugPrint = function(message) { debugPrint = function(message) {
EventBridge.emitWebEvent( EventBridge.emitWebEvent(
@ -44,6 +59,19 @@
} }
} }
function enableProperties() {
enableChildren(document.getElementById("properties-list"), "input, textarea, checkbox, .dropdown dl, .color-picker");
enableChildren(document, ".colpick");
}
function disableProperties() {
disableChildren(document.getElementById("properties-list"), "input, textarea, checkbox, .dropdown dl, .color-picker");
disableChildren(document, ".colpick");
for (var i = 0; i < colorPickers.length; i++) {
colorPickers[i].colpickHide();
}
}
function showElements(els, show) { function showElements(els, show) {
for (var i = 0; i < els.length; i++) { for (var i = 0; i < els.length; i++) {
els[i].style.display = (show) ? 'table' : 'none'; els[i].style.display = (show) ? 'table' : 'none';
@ -297,6 +325,7 @@
var allSections = []; var allSections = [];
var elID = document.getElementById("property-id"); var elID = document.getElementById("property-id");
var elType = document.getElementById("property-type"); var elType = document.getElementById("property-type");
var elTypeIcon = document.getElementById("type-icon");
var elName = document.getElementById("property-name"); var elName = document.getElementById("property-name");
var elLocked = document.getElementById("property-locked"); var elLocked = document.getElementById("property-locked");
var elVisible = document.getElementById("property-visible"); var elVisible = document.getElementById("property-visible");
@ -368,7 +397,7 @@
var elReloadScriptButton = document.getElementById("reload-script-button"); var elReloadScriptButton = document.getElementById("reload-script-button");
var elUserData = document.getElementById("property-user-data"); var elUserData = document.getElementById("property-user-data");
var elColorSection = document.getElementById("color-section"); var elColorSections = document.querySelectorAll(".color-section");
var elColor = document.getElementById("property-color"); var elColor = document.getElementById("property-color");
var elColorRed = document.getElementById("property-color-red"); var elColorRed = document.getElementById("property-color-red");
var elColorGreen = document.getElementById("property-color-green"); var elColorGreen = document.getElementById("property-color-green");
@ -474,32 +503,40 @@
data = JSON.parse(data); data = JSON.parse(data);
if (data.type == "update") { if (data.type == "update") {
if (data.selections.length == 0) { if (data.selections.length == 0) {
elType.innerHTML = "<i>No Selection</i>"; elTypeIcon.style.display = "none";
elType.innerHTML = "<i>No selection</i>";
elID.innerHTML = ""; elID.innerHTML = "";
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox'); disableProperties();
} else if (data.selections.length > 1) { } else if (data.selections.length > 1) {
var selections = data.selections; var selections = data.selections;
var ids = []; var ids = [];
var types = {}; var types = {};
var numTypes = 0;
for (var i = 0; i < selections.length; i++) { for (var i = 0; i < selections.length; i++) {
ids.push(selections[i].id); ids.push(selections[i].id);
var type = selections[i].properties.type; var type = selections[i].properties.type;
if (types[type] === undefined) { if (types[type] === undefined) {
types[type] = 0; types[type] = 0;
numTypes += 1;
} }
types[type]++; types[type]++;
} }
elID.innerHTML = ids.join("<br>");
var type;
var typeStrs = []; if (numTypes === 1) {
for (type in types) { type = selections[0].properties.type;
typeStrs.push(type + " (" + types[type] + ")"); } else {
type = "Multiple";
} }
elType.innerHTML = typeStrs.join(", "); elType.innerHTML = type + " (" + data.selections.length + ")";
elTypeIcon.innerHTML = ICON_FOR_TYPE[type];
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox'); elTypeIcon.style.display = "inline-block";
elID.innerHTML = ids.join("<br>");
disableProperties();
} else { } else {
var activeElement = document.activeElement; var activeElement = document.activeElement;
@ -516,14 +553,16 @@
elID.innerHTML = properties.id; elID.innerHTML = properties.id;
elType.innerHTML = properties.type; elType.innerHTML = properties.type;
elTypeIcon.innerHTML = ICON_FOR_TYPE[properties.type];
elTypeIcon.style.display = "inline-block";
elLocked.checked = properties.locked; elLocked.checked = properties.locked;
if (properties.locked) { if (properties.locked) {
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox'); disableProperties();
elLocked.removeAttribute('disabled'); elLocked.removeAttribute('disabled');
} else { } else {
enableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox'); enableProperties();
} }
@ -624,13 +663,17 @@
} }
if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "ParticleEffect") { if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "ParticleEffect") {
elColorSection.style.display = 'table'; for (var i = 0; i < elColorSections.length; i++) {
elColorSections[i].style.display = 'table';
}
elColorRed.value = properties.color.red; elColorRed.value = properties.color.red;
elColorGreen.value = properties.color.green; elColorGreen.value = properties.color.green;
elColorBlue.value = properties.color.blue; elColorBlue.value = properties.color.blue;
elColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")"; elColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
} else { } else {
elColorSection.style.display = 'none'; for (var i = 0; i < elColorSections.length; i++) {
elColorSections[i].style.display = 'none';
}
} }
if (properties.type == "Model") { if (properties.type == "Model") {
@ -862,10 +905,10 @@
elColorRed.addEventListener('change', colorChangeFunction); elColorRed.addEventListener('change', colorChangeFunction);
elColorGreen.addEventListener('change', colorChangeFunction); elColorGreen.addEventListener('change', colorChangeFunction);
elColorBlue.addEventListener('change', colorChangeFunction); elColorBlue.addEventListener('change', colorChangeFunction);
$('#property-color').colpick({ colorPickers.push($('#property-color').colpick({
colorScheme:'dark', colorScheme: 'dark',
layout:'hex', layout: 'hex',
color:'000000', color: '000000',
onShow: function (colpick) { onShow: function (colpick) {
$('#property-color').attr('active', 'true'); $('#property-color').attr('active', 'true');
}, },
@ -873,12 +916,12 @@
$('#property-color').attr('active', 'false'); $('#property-color').attr('active', 'false');
}, },
onSubmit: function (hsb, hex, rgb, el) { onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex); $(el).css('background-color', '#' + hex);
$(el).colpickHide(); $(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
} }
}) }));
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight')); elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
var lightColorChangeFunction = createEmitColorPropertyUpdateFunction( var lightColorChangeFunction = createEmitColorPropertyUpdateFunction(
@ -886,10 +929,10 @@
elLightColorRed.addEventListener('change', lightColorChangeFunction); elLightColorRed.addEventListener('change', lightColorChangeFunction);
elLightColorGreen.addEventListener('change', lightColorChangeFunction); elLightColorGreen.addEventListener('change', lightColorChangeFunction);
elLightColorBlue.addEventListener('change', lightColorChangeFunction); elLightColorBlue.addEventListener('change', lightColorChangeFunction);
$('#property-light-color').colpick({ colorPickers.push($('#property-light-color').colpick({
colorScheme:'dark', colorScheme: 'dark',
layout:'hex', layout: 'hex',
color:'000000', color: '000000',
onShow: function (colpick) { onShow: function (colpick) {
$('#property-light-color').attr('active', 'true'); $('#property-light-color').attr('active', 'true');
}, },
@ -897,11 +940,11 @@
$('#property-light-color').attr('active', 'false'); $('#property-light-color').attr('active', 'false');
}, },
onSubmit: function (hsb, hex, rgb, el) { onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex); $(el).css('background-color', '#' + hex);
$(el).colpickHide(); $(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
} }
}) }));
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity', 1)); elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity', 1));
elLightFalloffRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('falloffRadius', 1)); elLightFalloffRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('falloffRadius', 1));
@ -933,7 +976,7 @@
elTextTextColorRed.addEventListener('change', textTextColorChangeFunction); elTextTextColorRed.addEventListener('change', textTextColorChangeFunction);
elTextTextColorGreen.addEventListener('change', textTextColorChangeFunction); elTextTextColorGreen.addEventListener('change', textTextColorChangeFunction);
elTextTextColorBlue.addEventListener('change', textTextColorChangeFunction); elTextTextColorBlue.addEventListener('change', textTextColorChangeFunction);
$('#property-text-text-color').colpick({ colorPickers.push($('#property-text-text-color').colpick({
colorScheme:'dark', colorScheme:'dark',
layout:'hex', layout:'hex',
color: '000000', color: '000000',
@ -949,14 +992,14 @@
$(el).attr('active', 'false'); $(el).attr('active', 'false');
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b); emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
} }
}); }));
var textBackgroundColorChangeFunction = createEmitColorPropertyUpdateFunction( var textBackgroundColorChangeFunction = createEmitColorPropertyUpdateFunction(
'backgroundColor', elTextBackgroundColorRed, elTextBackgroundColorGreen, elTextBackgroundColorBlue); 'backgroundColor', elTextBackgroundColorRed, elTextBackgroundColorGreen, elTextBackgroundColorBlue);
elTextBackgroundColorRed.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorRed.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction);
$('#property-text-background-color').colpick({ colorPickers.push($('#property-text-background-color').colpick({
colorScheme:'dark', colorScheme:'dark',
layout:'hex', layout:'hex',
color:'000000', color:'000000',
@ -971,10 +1014,10 @@
$(el).colpickHide(); $(el).colpickHide();
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b); emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
} }
}); }));
elZoneStageSunModelEnabled.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage','sunModelEnabled')); elZoneStageSunModelEnabled.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage','sunModelEnabled'));
$('#property-zone-key-light-color').colpick({ colorPickers.push($('#property-zone-key-light-color').colpick({
colorScheme:'dark', colorScheme:'dark',
layout:'hex', layout:'hex',
color:'000000', color:'000000',
@ -989,7 +1032,7 @@
$(el).colpickHide(); $(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight'); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
} }
}); }));
var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight','color', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue); var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight','color', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction); elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction); elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
@ -1015,7 +1058,7 @@
elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction); elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction); elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction); elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction);
$('#property-zone-skybox-color').colpick({ colorPickers.push($('#property-zone-skybox-color').colpick({
colorScheme:'dark', colorScheme:'dark',
layout:'hex', layout:'hex',
color:'000000', color:'000000',
@ -1030,7 +1073,7 @@
$(el).colpickHide(); $(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox'); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
} }
}); }));
elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url')); elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url'));
@ -1138,7 +1181,7 @@
}; };
// Textarea scollbars // Textarea scrollbars
var elTextareas = document.getElementsByTagName("TEXTAREA"); var elTextareas = document.getElementsByTagName("TEXTAREA");
var textareaOnChangeEvent = function (event) { var textareaOnChangeEvent = function (event) {
@ -1252,6 +1295,8 @@
elDropdowns = document.getElementsByTagName("select"); elDropdowns = document.getElementsByTagName("select");
} }
augmentSpinButtons();
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked // Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) { document.addEventListener("contextmenu", function (event) {
event.preventDefault(); event.preventDefault();
@ -1262,30 +1307,32 @@
<body onload='loaded();'> <body onload='loaded();'>
<div id="properties-list"> <div id="properties-list">
<div id="type" class="property value"> <div id="properties-header">
<label>Type:</label> <div id="type" class="property value">
<span id="property-type"></span> <span id="type-icon"></span><label id="property-type"><i>No selection</i></label>
</div> </div>
<div id="id" class="property value"> <div class="property checkbox">
<label>ID:</label> <input type="checkbox" id="property-locked">
<span id="property-id" class="selectable"></span> <label for="property-locked"><span>&#xe006;</span>&nbsp;Locked</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-visible">
<label for="property-visible"><span>&#xe007;</span>&nbsp;Visible</label>
</div>
</div> </div>
<hr />
<div class="property text"> <div class="property text">
<label for="property-name">Name</label> <label for="property-name">Name</label>
<input type="text" id="property-name"> <input type="text" id="property-name">
</div> </div>
<div class="property checkbox">
<input type="checkbox" id="property-locked">
<label for="property-locked">Locked</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-visible">
<label for="property-visible">Visible</label>
</div>
<div class="property textarea"> <div class="property textarea">
<label for="property-user-data">User data</label> <label for="property-user-data">User data</label>
<textarea id="property-user-data"></textarea> <textarea id="property-user-data"></textarea>
</div> </div>
<div id="id" class="property value">
<label>ID:</label>
<span id="property-id" class="selectable"></span>
</div>
<div class="section-header hyperlink-group hyperlink-section"> <div class="section-header hyperlink-group hyperlink-section">
@ -1305,7 +1352,35 @@
<label>Spatial</label><span>M</span> <label>Spatial</label><span>M</span>
</div> </div>
<div class="spatial-group property xyz"> <div class="spatial-group property xyz">
<label>Position</label> <label>Dimensions <span class="unit">m</span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-dim-x" step="0.1"><label for="property-dim-x">X:</label></div>
<div><input type="number" class="y" id="property-dim-y" step="0.1"><label for="property-dim-y">Y:</label></div>
<div><input type="number" class="z" id="property-dim-z" step="0.1"><label for="property-dim-z">Z:</label></div>
</div>
</div>
<div class="spatial-group property gen">
<label>Scale <span class="unit">%</span></label>
<div class="row">
<input type="number" id="dimension-rescale-pct" value=100>
<input type="button" class="blue" id="dimension-rescale-button" value="Rescale">
<input type="button" class="red" id="reset-to-natural-dimensions" value="Reset Dimensions">
</div>
</div>
<hr class="spatial-group" />
<div class="spatial-group property pyr">
<label>Rotation <span class="unit">deg</span></label>
<div class="tuple">
<div><input type="number" class="pitch" id="property-rot-x" step="0.1"><label for="property-rot-x">Pitch:</label></div>
<div><input type="number" class="yaw" id="property-rot-y" step="0.1"><label for="property-rot-y">Yaw:</label></div>
<div><input type="number" class="roll" id="property-rot-z" step="0.1"><label for="property-rot-z">Roll:</label></div>
</div>
</div>
<hr class="spatial-group" />
<div class="spatial-group property xyz">
<label>Position <span class="unit">m</span></label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="x" id="property-pos-x"><label for="property-pos-x">X:</label></div> <div><input type="number" class="x" id="property-pos-x"><label for="property-pos-x">X:</label></div>
<div><input type="number" class="y" id="property-pos-y"><label for="property-pos-y">Y:</label></div> <div><input type="number" class="y" id="property-pos-y"><label for="property-pos-y">Y:</label></div>
@ -1317,40 +1392,28 @@
<input type="button" id="preview-camera-button" value="Preview Camera"> <input type="button" id="preview-camera-button" value="Preview Camera">
</div> </div>
</div> </div>
<div class="spatial-group property text"> <div class="spatial-group row">
<label for="property-parent-id">Parent ID</label> <div class="property text">
<input type="text" id="property-parent-id"> <label for="property-parent-id">Parent ID</label>
</div> <input type="text" id="property-parent-id">
<div class="spatial-group property number"> </div>
<label for="property-parent-joint-index">Parent joint index</label> <div class="property number">
<input type="number" id="property-parent-joint-index"> <label for="property-parent-joint-index">Parent joint index</label>
<input type="number" id="property-parent-joint-index">
</div>
</div> </div>
<div class="spatial-group property xyz"> <div class="spatial-group property xyz">
<label>Registration</label> <label>Registration <span class="unit">(pivot offset as ratio of dimension)</span></label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="x" id="property-reg-x" step="0.1"><label for="property-reg-x">X:</label></div> <div><input type="number" class="x" id="property-reg-x" step="0.1"><label for="property-reg-x">X:</label></div>
<div><input type="number" class="y" id="property-reg-y" step="0.1"><label for="property-reg-y">Y:</label></div> <div><input type="number" class="y" id="property-reg-y" step="0.1"><label for="property-reg-y">Y:</label></div>
<div><input type="number" class="z" id="property-reg-z" step="0.1"><label for="property-reg-z">Z:</label></div> <div><input type="number" class="z" id="property-reg-z" step="0.1"><label for="property-reg-z">Z:</label></div>
</div> </div>
</div> </div>
<div class="spatial-group property xyz">
<label>Dimensions</label> <hr class="spatial-group poly-vox-section" />
<div class="tuple"> <div class="spatial-group poly-vox-section property xyz">
<div><input type="number" class="x" id="property-dim-x" step="0.1"><label for="property-dim-x">X:</label></div> <label>Voxel volume size <span class="unit">m</span></label>
<div><input type="number" class="y" id="property-dim-y" step="0.1"><label for="property-dim-y">Y:</label></div>
<div><input type="number" class="z" id="property-dim-z" step="0.1"><label for="property-dim-z">Z:</label></div>
</div>
</div>
<div class="spatial-group property gen">
<label>Scale</label>
<div class="row">
<input type="number" id="dimension-rescale-pct" value=100>
<input type="button" class="blue" id="dimension-rescale-button" value="Rescale">
<input type="button" class="red" id="reset-to-natural-dimensions" value="Reset Dimensions">
</div>
</div>
<div class="spatial-group poly-vox-section property XYZ">
<label>Voxel volume size</label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="x" id="property-voxel-volume-size-x"><label for="property-voxel-volume-size-x">X:</label></div> <div><input type="number" class="x" id="property-voxel-volume-size-x"><label for="property-voxel-volume-size-x">X:</label></div>
<div><input type="number" class="y" id="property-voxel-volume-size-y"><label for="property-voxel-volume-size-y">Y:</label></div> <div><input type="number" class="y" id="property-voxel-volume-size-y"><label for="property-voxel-volume-size-y">Y:</label></div>
@ -1378,21 +1441,13 @@
<label for="property-z-texture-url">Z-axis texture URL</label> <label for="property-z-texture-url">Z-axis texture URL</label>
<input type="text" id="property-z-texture-url"> <input type="text" id="property-z-texture-url">
</div> </div>
<div class="spatial-group property pyr">
<label>Rotation</label>
<div class="tuple">
<div><input type="number" class="pitch" id="property-rot-x" step="0.1"><label for="property-rot-x">Pitch:</label></div>
<div><input type="number" class="yaw" id="property-rot-y" step="0.1"><label for="property-rot-y">Yaw:</label></div>
<div><input type="number" class="roll" id="property-rot-z" step="0.1"><label for="property-rot-z">Roll:</label></div>
</div>
</div>
<div class="section-header physical-group"> <div class="section-header physical-group">
<label>Physical</label><span>M</span> <label>Physical</label><span>M</span>
</div> </div>
<div class="physical-group property xyz"> <div class="physical-group property xyz">
<label>Linear velocity</label> <label>Linear velocity <span class="unit">m/s</span></label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="x" id="property-lvel-x"><label for="property-lvel-x">X:</label></div> <div><input type="number" class="x" id="property-lvel-x"><label for="property-lvel-x">X:</label></div>
<div><input type="number" class="y" id="property-lvel-y"><label for="property-lvel-y">Y:</label></div> <div><input type="number" class="y" id="property-lvel-y"><label for="property-lvel-y">Y:</label></div>
@ -1403,8 +1458,9 @@
<label>Linear damping</label> <label>Linear damping</label>
<input type="number" id="property-ldamping"> <input type="number" id="property-ldamping">
</div> </div>
<hr class="physical-group" />
<div class="physical-group property pyr"> <div class="physical-group property pyr">
<label>Angular velocity</label> <label>Angular velocity <span class="unit">deg/s</span></label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="pitch" id="property-avel-x"><label for="property-avel-x">Pitch:</label></div> <div><input type="number" class="pitch" id="property-avel-x"><label for="property-avel-x">Pitch:</label></div>
<div><input type="number" class="yaw" id="property-avel-y"><label for="property-avel-y">Yaw:</label></div> <div><input type="number" class="yaw" id="property-avel-y"><label for="property-avel-y">Yaw:</label></div>
@ -1415,6 +1471,7 @@
<label>Angular damping</label> <label>Angular damping</label>
<input type="number" id="property-adamping"> <input type="number" id="property-adamping">
</div> </div>
<hr class="physical-group" />
<div class="physical-group property gen"> <div class="physical-group property gen">
<div class="tuple"> <div class="tuple">
<div><label>Restitution</label><input type="number" id="property-restitution"></div> <div><label>Restitution</label><input type="number" id="property-restitution"></div>
@ -1422,8 +1479,9 @@
<div><label>Density</label><input type="number" id="property-density"></div> <div><label>Density</label><input type="number" id="property-density"></div>
</div> </div>
</div> </div>
<hr class="physical-group" />
<div class="physical-group property xyz"> <div class="physical-group property xyz">
<label>Gravity</label> <label>Gravity <span class="unit">m/s<sup>2</sup></span></label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="x" id="property-grav-x"><label for="property-grav-x">X:</label></div> <div><input type="number" class="x" id="property-grav-x"><label for="property-grav-x">X:</label></div>
<div><input type="number" class="y" id="property-grav-y"><label for="property-grav-y">Y:</label></div> <div><input type="number" class="y" id="property-grav-y"><label for="property-grav-y">Y:</label></div>
@ -1431,14 +1489,15 @@
</div> </div>
</div> </div>
<div class="physical-group property xyz"> <div class="physical-group property xyz">
<label>Acceleration</label> <label>Acceleration <span class="unit">m/s<sup>2</sup></span></label>
<div class="tuple"> <div class="tuple">
<div><input type="number" class="x" id="property-lacc-x"><label for="property-lacc-x">X:</label></div> <div><input type="number" class="x" id="property-lacc-x"><label for="property-lacc-x">X:</label></div>
<div><input type="number" class="y" id="property-lacc-y"><label for="property-lacc-y">Y:</label></div> <div><input type="number" class="y" id="property-lacc-y"><label for="property-lacc-y">Y:</label></div>
<div><input type="number" class="z" id="property-lacc-z"><label for="property-lacc-z">Z:</label></div> <div><input type="number" class="z" id="property-lacc-z"><label for="property-lacc-z">Z:</label></div>
</div> </div>
</div> </div>
<div id="color-section" class="physical-group property rgb"> <hr class="physical-group color-section" />
<div class="physical-group color-section property rgb">
<div id="property-color" class="color-picker"></div> <div id="property-color" class="color-picker"></div>
<label>Entity color</label> <label>Entity color</label>
<div class="tuple"> <div class="tuple">
@ -1461,64 +1520,72 @@
<label for="property-dynamic">Dynamic</label> <label for="property-dynamic">Dynamic</label>
</div> </div>
<div class="behavior-group sub-section-header"> <div class="behavior-group two-column">
<span>Collides With</span> <div class="column">
</div> <div class="sub-section-header">
<div class="behavior-group checkbox-sub-props"> <span>Collides With</span>
<div class="property checkbox"> </div>
<input type="checkbox" id="property-collide-static"> <div class="checkbox-sub-props">
<label for="property-collide-static">Static entities</label> <div class="property checkbox">
<input type="checkbox" id="property-collide-static">
<label for="property-collide-static">Static entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-dynamic">
<label for="property-collide-dynamic">Dynamic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-kinematic">
<label for="property-collide-kinematic">Kinematic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-myAvatar">
<label for="property-collide-myAvatar">My avatar</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-otherAvatar">
<label for="property-collide-otherAvatar">Other avatars</label>
</div>
</div>
</div>
<div class="column">
<div class="sub-section-header">
<span>Grabbing</span>
</div>
<div class="checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-grabbable">
<label for="property-grabbable">Grabbable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-wants-trigger">
<label for="property-wants-trigger">Triggerable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-ignore-ik">
<label for="property-ignore-ik">Ignore inverse kinematics</label>
</div>
</div>
</div> </div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-dynamic">
<label for="property-collide-dynamic">Dynamic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-kinematic">
<label for="property-collide-kinematic">Kinematic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-myAvatar">
<label for="property-collide-myAvatar">My avatar</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-otherAvatar">
<label for="property-collide-otherAvatar">Other avatars</label>
</div>
</div>
<div class="behavior-group sub-section-header">
<span>Grabbing</span>
</div>
<div class="behavior-group checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-grabbable">
<label for="property-grabbable">Grabbable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-wants-trigger">
<label for="property-wants-trigger">Triggerable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-ignore-ik">
<label for="property-ignore-ik">Ignore inverse kinematics</label>
</div>
</div> </div>
<hr class="behavior-group" />
<div class="behavior-group property url "> <div class="behavior-group property url ">
<label for="property-collision-sound-url">Collision sound URL</label> <label for="property-collision-sound-url">Collision sound URL</label>
<input type="text" id="property-collision-sound-url"> <input type="text" id="property-collision-sound-url">
</div> </div>
<div class="behavior-group property number"> <div class="behavior-group property number">
<label>Lifetime</label> <label>Lifetime <span class="unit">s</span></label>
<input type="number" id="property-lifetime"> <input type="number" id="property-lifetime">
</div> </div>
<hr class="behavior-group" />
<div class="behavior-group property url "> <div class="behavior-group property url ">
<!-- <!--
FIXME: If reload buttons at the end of each URL continue to work OK during beta, this reload button and associated FIXME: If reload buttons at the end of each URL continue to work OK during beta, this reload button and associated
@ -1551,33 +1618,47 @@
<label for="property-compound-shape-url">Compound shape URL</label> <label for="property-compound-shape-url">Compound shape URL</label>
<input type="text" id="property-compound-shape-url"> <input type="text" id="property-compound-shape-url">
</div> </div>
<hr class="model-group model-section" />
<div class="model-group model-section property url "> <div class="model-group model-section property url ">
<label for="property-model-animation-url">Animation URL</label> <label for="property-model-animation-url">Animation URL</label>
<input type="text" id="property-model-animation-url"> <input type="text" id="property-model-animation-url">
</div> </div>
<div class="model-group model-section property checkbox">
<input type="checkbox" id="property-model-animation-playing"> <div class="model-group model-section two-column">
<label for="property-model-animation-playing">Animation playing</label> <div class="column">
</div> <div class="property checkbox">
<div class="model-group model-section property number"> <input type="checkbox" id="property-model-animation-playing">
<label>Animation FPS</label> <label for="property-model-animation-playing">Animation playing</label>
<input type="number" id="property-model-animation-fps"> </div>
</div> <div class="property checkbox indent">
<div class="model-group model-section property number"> <input type="checkbox" id="property-model-animation-loop">
<div class="tuple"> <label for="property-model-animation-loop">Animation loop</label>
<div><label>Animation frame</label><input type="number" id="property-model-animation-frame"></div> </div>
<div><label>First frame</label><input type="number" id="property-model-animation-first-frame"></div> <div class="property checkbox indent">
<div><label>Last frame</label><input type="number" id="property-model-animation-last-frame"></div> <input type="checkbox" id="property-model-animation-hold">
<label for="property-model-animation-hold">Animation hold</label>
</div>
<div id="animation-fps" class="property number">
<label>Animation FPS</label>
<input type="number" id="property-model-animation-fps">
</div>
</div>
<div class="column">
<div class="property number">
<label>Animation frame</label>
<input type="number" id="property-model-animation-frame">
</div>
<div class="property number">
<label>First frame</label>
<input type="number" id="property-model-animation-first-frame">
</div>
<div class="property number">
<label>Last frame</label>
<input type="number" id="property-model-animation-last-frame">
</div>
</div> </div>
</div> </div>
<div class="model-group model-section property checkbox"> <hr class="model-group model-section" />
<input type="checkbox" id="property-model-animation-loop">
<label for="property-model-animation-loop">Animation loop</label>
</div>
<div class="model-group model-section property checkbox">
<input type="checkbox" id="property-model-animation-hold">
<label for="property-model-animation-hold">Animation hold</label>
</div>
<div class="model-group model-section property textarea"> <div class="model-group model-section property textarea">
<label for="property-model-textures">Textures</label> <label for="property-model-textures">Textures</label>
<textarea id="property-model-textures"></textarea> <textarea id="property-model-textures"></textarea>
@ -1596,7 +1677,7 @@
<input type="text" id="property-text-text"> <input type="text" id="property-text-text">
</div> </div>
<div class="text-group text-section property number"> <div class="text-group text-section property number">
<label>Line height</label> <label>Line height <span class="unit">m</span></label>
<input type="number" id="property-text-line-height" min="0" step="0.005"> <input type="number" id="property-text-line-height" min="0" step="0.005">
</div> </div>
<div class="text-group text-section property rgb"> <div class="text-group text-section property rgb">
@ -1645,8 +1726,8 @@
</div> </div>
<div class="zone-group zone-section keylight-section property gen"> <div class="zone-group zone-section keylight-section property gen">
<div class="tuple"> <div class="tuple">
<div><label>Light altitude</label><input type="number" id="property-zone-key-light-direction-x"></div> <div><label>Light altitude <span class="unit">deg</span></label><input type="number" id="property-zone-key-light-direction-x"></div>
<div><label>Light azimuth</label><input type="number" id="property-zone-key-light-direction-y"></div> <div><label>Light azimuth <span class="unit">deg</span></label><input type="number" id="property-zone-key-light-direction-y"></div>
<div></div> <div></div>
</div> </div>
</div> </div>
@ -1664,9 +1745,9 @@
</div> </div>
<div class="zone-group zone-section stage-section property gen"> <div class="zone-group zone-section stage-section property gen">
<div class="tuple"> <div class="tuple">
<div><label>Stage latitude</label><input type="number" id="property-zone-stage-latitude" min="-90" max="90" step="1"></div> <div><label>Latitude <span class="unit">deg</span></label><input type="number" id="property-zone-stage-latitude" min="-90" max="90" step="1"></div>
<div><label>Stage longitude</label><input type="number" id="property-zone-stage-longitude" min="-180" max="180" step="1"></div> <div><label>Longitude <span class="unit">deg</span></label><input type="number" id="property-zone-stage-longitude" min="-180" max="180" step="1"></div>
<div><label>Stage altitude</label><input type="number" id="property-zone-stage-altitude" step="1"></div> <div><label>Altitude <span class="unit">m</span></label><input type="number" id="property-zone-stage-altitude" step="1"></div>
</div> </div>
</div> </div>
<div class="zone-group zone-section stage-section property checkbox"> <div class="zone-group zone-section stage-section property checkbox">
@ -1676,8 +1757,8 @@
<div class="zone-group zone-section stage-section property gen"> <div class="zone-group zone-section stage-section property gen">
<div class="tuple"> <div class="tuple">
<div><label>Stage day of year</label><input type="number" id="property-zone-stage-day" min="0" max="365" step="1"></div> <div><label>Day of year</label><input type="number" id="property-zone-stage-day" min="0" max="365" step="1"></div>
<div><label>Stage hour</label><input type="number" id="property-zone-stage-hour" min="0" max="24" step="0.5"></div> <div><label>Hour</label><input type="number" id="property-zone-stage-hour" min="0" max="24" step="0.5"></div>
<div></div> <div></div>
</div> </div>
</div> </div>
@ -1735,7 +1816,7 @@
<div class="light-group light-section property gen"> <div class="light-group light-section property gen">
<div class="tuple"> <div class="tuple">
<div><label>Intensity</label><input type="number" id="property-light-intensity" min="0" step="0.1"></div> <div><label>Intensity</label><input type="number" id="property-light-intensity" min="0" step="0.1"></div>
<div><label>Fall-off radius</label><input type="number" id="property-light-falloff-radius" min="0" step="0.1"></div> <div><label>Fall-off radius <span class="unit">m</span></label><input type="number" id="property-light-falloff-radius" min="0" step="0.1"></div>
<div></div> <div></div>
</div> </div>
</div> </div>

View file

@ -11,21 +11,15 @@
<html> <html>
<head> <head>
<link rel="stylesheet" type="text/css" href="edit-style.css"> <link rel="stylesheet" type="text/css" href="edit-style.css">
<link rel="stylesheet" type="text/css" href="css/colpick.css">
<script src="jquery-2.1.4.min.js"></script>
<script src="colpick.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="eventBridgeLoader.js"></script> <script type="text/javascript" src="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script> <script>
function loaded() { function loaded() {
openEventBridge(function() { openEventBridge(function() {
var gridColor = { red: 0, green: 0, blue: 0 };
var gridColors = [
{ red: 0, green: 0, blue: 0 },
{ red: 255, green: 255, blue: 255 },
{ red: 255, green: 0, blue: 0 },
{ red: 0, green: 255, blue: 0},
{ red: 0, green: 0, blue: 255 },
];
var gridColorIndex = 0;
elPosY = document.getElementById("horiz-y"); elPosY = document.getElementById("horiz-y");
elMinorSpacing = document.getElementById("minor-spacing"); elMinorSpacing = document.getElementById("minor-spacing");
elMajorSpacing = document.getElementById("major-spacing"); elMajorSpacing = document.getElementById("major-spacing");
@ -37,12 +31,12 @@
if (window.EventBridge !== undefined) { if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) { EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data); data = JSON.parse(data);
if (data.origin) { if (data.origin) {
var origin = data.origin; var origin = data.origin;
elPosY.value = origin.y.toFixed(2); elPosY.value = origin.y;
} }
if (data.minorGridEvery !== undefined) { if (data.minorGridEvery !== undefined) {
elMinorSpacing.value = data.minorGridEvery; elMinorSpacing.value = data.minorGridEvery;
} }
@ -73,7 +67,6 @@
minorGridEvery: elMinorSpacing.value, minorGridEvery: elMinorSpacing.value,
majorGridEvery: elMajorSpacing.value, majorGridEvery: elMajorSpacing.value,
gridColor: gridColor, gridColor: gridColor,
colorIndex: gridColorIndex,
snapToGrid: elSnapToGrid.checked, snapToGrid: elSnapToGrid.checked,
visible: elHorizontalGridVisible.checked, visible: elHorizontalGridVisible.checked,
})); }));
@ -100,23 +93,52 @@
})); }));
}); });
var gridColorBox = document.getElementById('grid-color'); var gridColor = { red: 255, green: 255, blue: 255 };
var elColor = document.getElementById("grid-color");
for (var i = 0; i < gridColors.length; i++) { var elColorRed = document.getElementById("grid-color-red");
var colors = gridColors[i]; var elColorGreen = document.getElementById("grid-color-green");
var box = document.createElement('div'); var elColorBlue = document.getElementById("grid-color-blue");
box.setAttribute('class', 'color-box'); elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
box.style.background = 'rgb(' + colors.red + ', ' + colors.green + ', ' + colors.blue + ')'; elColorRed.value = gridColor.red;
document.getElementById("grid-colors").appendChild(box); elColorGreen.value = gridColor.green;
box.addEventListener("click", function(color, index) { elColorBlue.value = gridColor.blue;
return function() {
gridColor = color; var colorChangeFunction = function () {
gridColorIndex = index; gridColor = { red: elColorRed.value, green: elColorGreen.value, blue: elColorBlue.value };
emitUpdate(); elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
} emitUpdate();
}({ red: colors.red, green: colors.green, blue: colors.blue }, i)); };
var colorPickFunction = function (red, green, blue) {
elColorRed.value = red;
elColorGreen.value = green;
elColorBlue.value = blue;
gridColor = { red: red, green: green, blue: blue };
emitUpdate();
} }
elColorRed.addEventListener('change', colorChangeFunction);
elColorGreen.addEventListener('change', colorChangeFunction);
elColorBlue.addEventListener('change', colorChangeFunction);
$('#grid-color').colpick({
colorScheme: 'dark',
layout: 'hex',
color: { r: gridColor.red, g: gridColor.green, b: gridColor.blue },
onShow: function (colpick) {
$('#grid-color').attr('active', 'true');
},
onHide: function (colpick) {
$('#grid-color').attr('active', 'false');
},
onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#' + hex);
$(el).colpickHide();
colorPickFunction(rgb.r, rgb.g, rgb.b);
}
});
augmentSpinButtons();
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' })); EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
}); });
@ -146,29 +168,28 @@
<div class="property"> <div class="property">
<div class="number"> <div class="number">
<label>Major grid size</label> <label for="major-spacing">Major grid size <span class="unit">m</span></label>
<span> <input type="number" id="major-spacing" min="1" step="1" />
<input type="number" id="major-spacing" min="1" step="1" /><span class="unit">m</span>
</span>
</div> </div>
<div class="number"> <div class="number">
<label>Minor grid size</label> <label for="minor-spacing">Minor grid size <span class="unit">m</span></label>
<span> <input type="number" id="minor-spacing" min="0.2" step="0.2" />
<input type="number" id="minor-spacing" min="0.2" step="0.2" /><span class="unit">m</span>
</span>
</div> </div>
</div> </div>
<div class="property number"> <div class="property number">
<label>Position (Y axis)</label> <label for="horiz-y">Position (Y axis) <span class="unit">m</span></label>
<span> <input type="number" id="horiz-y" step="0.1" />
<input type="number" id="horiz-y" step="0.1" /><span class="unit">m</span>
</span>
</div> </div>
<div class="property color-set"> <div class="property rgb">
<div id="grid-color" class="color-picker"></div>
<label>Grid line color</label> <label>Grid line color</label>
<span id="grid-colors"></span> <div class="tuple">
<div><input type="number" class="red" id="grid-color-red"><label for="grid-color-red">Red:</label></div>
<div><input type="number" class="green" id="grid-color-green"><label for="grid-color-green">Green:</label></div>
<div><input type="number" class="blue" id="grid-color-blue"><label for="grid-color-blue">Blue:</label></div>
</div>
</div> </div>
<div class="property"> <div class="property">

View file

@ -0,0 +1,51 @@
//
// spinButtons.js
//
// Created by David Rowe on 20 Apr 2016
// Copyright 2016 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
//
function hoverSpinButtons(event) {
var input = event.target,
x = event.offsetX,
y = event.offsetY,
width = input.offsetWidth,
height = input.offsetHeight,
SPIN_WIDTH = 11,
SPIN_MARGIN = 2,
maxX = width - SPIN_MARGIN,
minX = maxX - SPIN_WIDTH;
if (minX <= x && x <= maxX) {
if (y < height / 2) {
input.classList.remove("hover-down");
input.classList.add("hover-up");
} else {
input.classList.remove("hover-up");
input.classList.add("hover-down");
}
} else {
input.classList.remove("hover-up");
input.classList.remove("hover-down");
}
}
function unhoverSpinButtons(event) {
event.target.classList.remove("hover-up");
event.target.classList.remove("hover-down");
}
function augmentSpinButtons() {
var inputs, i, length;
inputs = document.getElementsByTagName("INPUT");
for (i = 0, length = inputs.length; i < length; i += 1) {
if (inputs[i].type === "number") {
inputs[i].addEventListener("mousemove", hoverSpinButtons);
inputs[i].addEventListener("mouseout", unhoverSpinButtons);
}
}
}

View file

@ -59,6 +59,8 @@ EntityListTool = function(opts) {
name: properties.name, name: properties.name,
type: properties.type, type: properties.type,
url: properties.type == "Model" ? properties.modelURL : "", url: properties.type == "Model" ? properties.modelURL : "",
locked: properties.locked,
visible: properties.visible
}); });
} }
@ -99,6 +101,10 @@ EntityListTool = function(opts) {
} }
} else if (data.type == "delete") { } else if (data.type == "delete") {
deleteSelectedEntities(); deleteSelectedEntities();
} else if (data.type == "toggleLocked") {
toggleSelectedEntitiesLocked();
} else if (data.type == "toggleVisible") {
toggleSelectedEntitiesVisible();
} else if (data.type === "radius") { } else if (data.type === "radius") {
searchRadius = data.radius; searchRadius = data.radius;
that.sendUpdate(); that.sendUpdate();

View file

@ -3,14 +3,7 @@ var GRID_CONTROLS_HTML_URL = Script.resolvePath('../html/gridControls.html');
Grid = function(opts) { Grid = function(opts) {
var that = {}; var that = {};
var colors = [ var gridColor = { red: 255, green: 255, blue: 255 };
{ red: 0, green: 0, blue: 0 },
{ red: 255, green: 255, blue: 255 },
{ red: 255, green: 0, blue: 0 },
{ red: 0, green: 255, blue: 0 },
{ red: 0, green: 0, blue: 255 },
];
var colorIndex = 0;
var gridAlpha = 0.6; var gridAlpha = 0.6;
var origin = { x: 0, y: +MyAvatar.getJointPosition('LeftToeBase').y.toFixed(1) + 0.1, z: 0 }; var origin = { x: 0, y: +MyAvatar.getJointPosition('LeftToeBase').y.toFixed(1) + 0.1, z: 0 };
var scale = 500; var scale = 500;
@ -28,7 +21,7 @@ Grid = function(opts) {
position: origin, position: origin,
visible: false, visible: false,
drawInFront: false, drawInFront: false,
color: colors[0], color: gridColor,
alpha: gridAlpha, alpha: gridAlpha,
minorGridEvery: minorGridEvery, minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery, majorGridEvery: majorGridEvery,
@ -52,12 +45,6 @@ Grid = function(opts) {
updateGrid(); updateGrid();
}; };
that.getColorIndex = function() { return colorIndex; };
that.setColorIndex = function(value) {
colorIndex = value;
updateGrid();
};
that.getSnapToGrid = function() { return snapToGrid; }; that.getSnapToGrid = function() { return snapToGrid; };
that.setSnapToGrid = function(value) { that.setSnapToGrid = function(value) {
snapToGrid = value; snapToGrid = value;
@ -175,8 +162,8 @@ Grid = function(opts) {
majorGridEvery = data.majorGridEvery; majorGridEvery = data.majorGridEvery;
} }
if (data.colorIndex !== undefined) { if (data.gridColor !== undefined) {
colorIndex = data.colorIndex; gridColor = data.gridColor;
} }
if (data.gridSize) { if (data.gridSize) {
@ -196,7 +183,7 @@ Grid = function(opts) {
visible: that.visible && that.enabled, visible: that.visible && that.enabled,
minorGridEvery: minorGridEvery, minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery, majorGridEvery: majorGridEvery,
color: colors[colorIndex], color: gridColor,
alpha: gridAlpha, alpha: gridAlpha,
}); });

View file

@ -1,5 +1,6 @@
import QtQuick 2.5 import QtQuick 2.5
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import Qt.labs.settings 1.0
Rectangle { Rectangle {
id: root id: root
@ -8,67 +9,68 @@ Rectangle {
signal sendToScript(var message); signal sendToScript(var message);
property var values: []; property var values: [];
property var host: AddressManager.hostname property alias destination: addressLine.text
readonly property string nullDestination: "169.254.0.1"
property bool running: false
function statusReport() {
Component.onCompleted: { console.log("PERF status connected: " + AddressManager.isConnected);
Window.domainChanged.connect(function(newDomain){
if (newDomain !== root.host) {
root.host = AddressManager.hostname;
}
});
} }
onHostChanged: { Timer {
if (root.running) { id: readyStateTimer
if (host !== "Dreaming" && host !== "Playa") { interval: 500
repeat: true
running: false
onTriggered: {
if (!root.running) {
stop();
return; return;
} }
console.log("PERF new domain " + host) if (AddressManager.isConnected) {
if (host === "Dreaming") { console.log("PERF already connected, disconnecting");
AddressManager.handleLookupString("Playa"); AddressManager.handleLookupString(root.nullDestination);
return; return;
} }
stop();
console.log("PERF disconnected, moving to target " + root.destination);
AddressManager.handleLookupString(root.destination);
if (host === "Playa") { // If we've arrived, start running the test
console.log("PERF starting timers and frame timing"); console.log("PERF starting timers and frame timing");
// If we've arrived, start running the test FrameTimings.start();
FrameTimings.start(); rotationTimer.start();
rotationTimer.start(); stopTimer.start();
stopTimer.start();
}
} }
} }
function startTest() { function startTest() {
console.log("PERF startTest()"); console.log("PERF startTest()");
root.running = true if (!root.running) {
console.log("PERF current host: " + AddressManager.hostname) root.running = true
// If we're already in playa, we need to go somewhere else... readyStateTimer.start();
if ("Playa" === AddressManager.hostname) {
console.log("PERF Navigating to dreaming")
AddressManager.handleLookupString("Dreaming/0,0,0");
} else {
console.log("PERF Navigating to playa")
AddressManager.handleLookupString("Playa");
} }
} }
function stopTest() { function stopTest() {
console.log("PERF stopTest()"); console.log("PERF stopTest()");
root.running = false; if (root.running) {
stopTimer.stop(); root.running = false;
rotationTimer.stop(); stopTimer.stop();
FrameTimings.finish(); rotationTimer.stop();
root.values = FrameTimings.getValues(); FrameTimings.finish();
AddressManager.handleLookupString("Dreaming/0,0,0"); root.values = FrameTimings.getValues();
resultGraph.requestPaint(); AddressManager.handleLookupString(root.nullDestination);
console.log("PERF Value Count: " + root.values.length); resultGraph.requestPaint();
console.log("PERF Max: " + FrameTimings.max); console.log("PERF Value Count: " + root.values.length);
console.log("PERF Min: " + FrameTimings.min); console.log("PERF Max: " + FrameTimings.max);
console.log("PERF Avg: " + FrameTimings.mean); console.log("PERF Min: " + FrameTimings.min);
console.log("PERF StdDev: " + FrameTimings.standardDeviation); console.log("PERF Avg: " + FrameTimings.mean);
console.log("PERF StdDev: " + FrameTimings.standardDeviation);
}
} }
function yaw(a) { function yaw(a) {
@ -82,7 +84,6 @@ Rectangle {
MyAvatar.setOrientationVar(yaw(Date.now() / 1000)); MyAvatar.setOrientationVar(yaw(Date.now() / 1000));
} }
property bool running: false
Timer { Timer {
id: stopTimer id: stopTimer
@ -102,14 +103,43 @@ Rectangle {
Row { Row {
id: row id: row
anchors { left: parent.left; right: parent.right; } anchors { left: parent.left; right: parent.right; top: parent.top; margins: 16 }
spacing: 8 spacing: 8
Button { Button {
text: root.running ? "Stop" : "Run" text: root.running ? "Stop" : "Run"
onClicked: root.running ? stopTest() : startTest(); onClicked: root.running ? stopTest() : startTest();
} }
Button {
text: "Disconnect"
onClicked: AddressManager.handleLookupString(root.nullDestination);
}
Button {
text: "Connect"
onClicked: AddressManager.handleLookupString(root.destination);
}
Button {
text: "Status"
onClicked: statusReport();
}
} }
TextField {
id: addressLine
focus: true
anchors {
left: parent.left; right: parent.right;
top: row.bottom; margins: 16;
}
text: "Playa"
onTextChanged: console.log("PERF new target " + text);
}
Settings {
category: "Qml.Performance.RenderTest"
property alias destination: addressLine.text
}
// Rectangle { // Rectangle {
// anchors { left: parent.left; right: parent.right; top: row.bottom; topMargin: 8; bottom: parent.bottom; } // anchors { left: parent.left; right: parent.right; top: row.bottom; topMargin: 8; bottom: parent.bottom; }
// //anchors.fill: parent // //anchors.fill: parent
@ -130,7 +160,7 @@ Rectangle {
Canvas { Canvas {
id: resultGraph id: resultGraph
anchors { left: parent.left; right: parent.right; top: row.bottom; margins: 16; bottom: parent.bottom; } anchors { left: parent.left; right: parent.right; top: addressLine.bottom; margins: 16; bottom: parent.bottom; }
property real maxValue: 200; property real maxValue: 200;
property real perFrame: 10000; property real perFrame: 10000;
property real k1: (5 / maxValue) * height; property real k1: (5 / maxValue) * height;

View file

@ -3,35 +3,18 @@ float aspect(vec2 v) {
} }
vec3 aspectCorrectedTexture() { vec3 aspectCorrectedTexture() {
vec2 uv = _position.xy; vec2 uv;
if (abs(_position.y) > 0.4999) {
uv = _position.xz;
} else if (abs(_position.z) > 0.4999) {
uv = _position.xy;
} else {
uv = _position.yz;
}
uv += 0.5; uv += 0.5;
uv.y = 1.0 - uv.y; uv.y = 1.0 - uv.y;
return texture(iChannel0, uv).rgb;
float targetAspect = iWorldScale.x / iWorldScale.y;
float sourceAspect = aspect(iChannelResolution[0].xy);
float aspectCorrection = sourceAspect / targetAspect;
if (aspectCorrection > 1.0) {
float offset = aspectCorrection - 1.0;
float halfOffset = offset / 2.0;
uv.y -= halfOffset;
uv.y *= aspectCorrection;
} else {
float offset = 1.0 - aspectCorrection;
float halfOffset = offset / 2.0;
uv.x -= halfOffset;
uv.x /= aspectCorrection;
}
if (any(lessThan(uv, vec2(0.0)))) {
return vec3(0.0);
}
if (any(greaterThan(uv, vec2(1.0)))) {
return vec3(0.0);
}
vec4 color = texture(iChannel0, uv);
return color.rgb * max(0.5, sourceAspect) * max(0.9, fract(iWorldPosition.x));
} }
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {

View file

@ -42,7 +42,7 @@ function createItems(count) {
name: TEST_ENTITY_NAME, name: TEST_ENTITY_NAME,
position: AUSTIN.avatarRelativePosition(AUSTIN.randomPositionXZ({ x: 0, y: 0, z: -2 }, RADIUS)), position: AUSTIN.avatarRelativePosition(AUSTIN.randomPositionXZ({ x: 0, y: 0, z: -2 }, RADIUS)),
color: { r: 255, g: 255, b: 255 }, color: { r: 255, g: 255, b: 255 },
dimensions: AUSTIN.randomDimensions(), dimensions: { x: 0.5, y: 0.5, z: 0.5 }, //AUSTIN.randomDimensions(),
lifetime: ENTITY_LIFETIME, lifetime: ENTITY_LIFETIME,
userData: JSON.stringify({ userData: JSON.stringify({
ProceduralEntity: { ProceduralEntity: {

View file

@ -0,0 +1,49 @@
//
// stats.qml
// examples/utilities/cache
//
// Created by Zach Pomerantz on 4/1/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../lib/plotperf"
Item {
id: root
anchors.fill: parent
property var caches: [ ["Present", "present"], ["Present", "present"], ["New", "newFrame"], ["Dropped", "dropped"], ["Simulation", "simulation"], ["Avatar", "avatar"] ]
property var colors: [ "#1AC567", "#00B4EF" ]
Grid {
id: grid
rows: (root.caches.length / 2); columns: 2; spacing: 8
anchors.fill: parent
Repeater {
id: repeater
model: root.caches
Row {
PlotPerf {
title: modelData[0] + " Rate"
height: (grid.height - (grid.spacing * ((root.caches.length / 2) + 1))) / (root.caches.length / 2)
width: grid.width / 2 - grid.spacing * 1.5
object: Rates
valueScale: 1
valueUnit: "fps"
valueNumDigits: "2"
plots: [{
prop: modelData[1],
color: root.colors[index % 2]
}]
}
}
}
}
}

View file

@ -0,0 +1,21 @@
//
// cacheStats.js
// examples/utilities/cache
//
// Zach Pomerantz, created on 4/1/2016.
// Copyright 2016 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
//
// Set up the qml ui
var qml = Script.resolvePath('rates.qml');
var window = new OverlayWindow({
title: 'Render Rates',
source: qml,
width: 300,
height: 200
});
window.setPosition(500, 50);
window.closed.connect(function() { Script.stop(); });

View file

@ -14,8 +14,8 @@ var qml = Script.resolvePath('stats.qml');
var window = new OverlayWindow({ var window = new OverlayWindow({
title: 'Render Stats', title: 'Render Stats',
source: qml, source: qml,
width: 300, width: 320,
height: 200 height: 720
}); });
window.setPosition(500, 50); window.setPosition(500, 50);
window.closed.connect(function() { Script.stop(); }); window.closed.connect(function() { Script.stop(); });

View file

@ -241,7 +241,6 @@ Item {
color: "#E2334D" color: "#E2334D"
} }
] ]
} }
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -145,7 +145,7 @@
"id": "rightHandGraspOpen", "id": "rightHandGraspOpen",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_right.fbx", "url": "animations/hydra_pose_open_right.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 0.0, "endFrame": 0.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -157,7 +157,7 @@
"id": "rightHandGraspClosed", "id": "rightHandGraspClosed",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_right.fbx", "url": "animations/hydra_pose_closed_right.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 0.0, "endFrame": 0.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -205,7 +205,7 @@
"id": "leftHandGraspOpen", "id": "leftHandGraspOpen",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_left.fbx", "url": "animations/hydra_pose_open_left.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 0.0, "endFrame": 0.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -217,7 +217,7 @@
"id": "leftHandGraspClosed", "id": "leftHandGraspClosed",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_left.fbx", "url": "animations/hydra_pose_closed_left.fbx",
"startFrame": 10.0, "startFrame": 10.0,
"endFrame": 10.0, "endFrame": 10.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -495,7 +495,7 @@
"id": "idleStand", "id": "idleStand",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx", "url": "animations/idle.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 90.0, "endFrame": 90.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -507,7 +507,7 @@
"id": "idleTalk", "id": "idleTalk",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/talk.fbx", "url": "animations/talk.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 801.0, "endFrame": 801.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -532,7 +532,7 @@
"id": "walkFwdShort", "id": "walkFwdShort",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_fwd.fbx", "url": "animations/walk_short_fwd.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 39.0, "endFrame": 39.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -544,7 +544,7 @@
"id": "walkFwdNormal", "id": "walkFwdNormal",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_fwd.fbx", "url": "animations/walk_fwd.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 35.0, "endFrame": 35.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -556,7 +556,7 @@
"id": "walkFwdRun", "id": "walkFwdRun",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/run_fwd.fbx", "url": "animations/run_fwd.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 21.0, "endFrame": 21.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -570,7 +570,7 @@
"id": "idleToWalkFwd", "id": "idleToWalkFwd",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle_to_walk.fbx", "url": "animations/idle_to_walk.fbx",
"startFrame": 1.0, "startFrame": 1.0,
"endFrame": 19.0, "endFrame": 19.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -593,7 +593,7 @@
"id": "walkBwdShort", "id": "walkBwdShort",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_bwd.fbx", "url": "animations/walk_short_bwd.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 38.0, "endFrame": 38.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -605,7 +605,7 @@
"id": "walkBwdNormal", "id": "walkBwdNormal",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_bwd.fbx", "url": "animations/walk_bwd.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 36.0, "endFrame": 36.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -619,7 +619,7 @@
"id": "turnLeft", "id": "turnLeft",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_left.fbx", "url": "animations/turn_left.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 28.0, "endFrame": 28.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -631,7 +631,7 @@
"id": "turnRight", "id": "turnRight",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_right.fbx", "url": "animations/turn_right.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 30.0, "endFrame": 30.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -654,7 +654,7 @@
"id": "strafeLeftShort", "id": "strafeLeftShort",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_left.fbx", "url": "animations/side_step_short_left.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 28.0, "endFrame": 28.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -666,7 +666,7 @@
"id": "strafeLeftNormal", "id": "strafeLeftNormal",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_left.fbx", "url": "animations/side_step_left.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 30.0, "endFrame": 30.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -691,7 +691,7 @@
"id": "strafeRightShort", "id": "strafeRightShort",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_right.fbx", "url": "animations/side_step_short_right.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 28.0, "endFrame": 28.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -703,7 +703,7 @@
"id": "strafeRightNormal", "id": "strafeRightNormal",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_right.fbx", "url": "animations/side_step_right.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 30.0, "endFrame": 30.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -717,7 +717,7 @@
"id": "fly", "id": "fly",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx", "url": "animations/fly.fbx",
"startFrame": 1.0, "startFrame": 1.0,
"endFrame": 80.0, "endFrame": 80.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -729,7 +729,7 @@
"id": "takeoffStand", "id": "takeoffStand",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_takeoff.fbx", "url": "animations/jump_standing_takeoff.fbx",
"startFrame": 17.0, "startFrame": 17.0,
"endFrame": 25.0, "endFrame": 25.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -741,7 +741,7 @@
"id": "takeoffRun", "id": "takeoffRun",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_takeoff.fbx", "url": "animations/jump_takeoff.fbx",
"startFrame": 1.0, "startFrame": 1.0,
"endFrame": 2.5, "endFrame": 2.5,
"timeScale": 0.01, "timeScale": 0.01,
@ -761,7 +761,7 @@
"id": "inAirStandPreApex", "id": "inAirStandPreApex",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_apex.fbx", "url": "animations/jump_standing_apex.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 0.0, "endFrame": 0.0,
"timeScale": 0.0, "timeScale": 0.0,
@ -773,7 +773,7 @@
"id": "inAirStandApex", "id": "inAirStandApex",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_apex.fbx", "url": "animations/jump_standing_apex.fbx",
"startFrame": 1.0, "startFrame": 1.0,
"endFrame": 1.0, "endFrame": 1.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -785,7 +785,7 @@
"id": "inAirStandPostApex", "id": "inAirStandPostApex",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_apex.fbx", "url": "animations/jump_standing_apex.fbx",
"startFrame": 2.0, "startFrame": 2.0,
"endFrame": 2.0, "endFrame": 2.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -807,7 +807,7 @@
"id": "inAirRunPreApex", "id": "inAirRunPreApex",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", "url": "animations/jump_in_air.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 0.0, "endFrame": 0.0,
"timeScale": 0.0, "timeScale": 0.0,
@ -819,7 +819,7 @@
"id": "inAirRunApex", "id": "inAirRunApex",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", "url": "animations/jump_in_air.fbx",
"startFrame": 6.0, "startFrame": 6.0,
"endFrame": 6.0, "endFrame": 6.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -831,7 +831,7 @@
"id": "inAirRunPostApex", "id": "inAirRunPostApex",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", "url": "animations/jump_in_air.fbx",
"startFrame": 11.0, "startFrame": 11.0,
"endFrame": 11.0, "endFrame": 11.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -845,7 +845,7 @@
"id": "landStandImpact", "id": "landStandImpact",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_land.fbx", "url": "animations/jump_standing_land.fbx",
"startFrame": 1.0, "startFrame": 1.0,
"endFrame": 6.0, "endFrame": 6.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -857,7 +857,7 @@
"id": "landStand", "id": "landStand",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_land.fbx", "url": "animations/jump_standing_land.fbx",
"startFrame": 6.0, "startFrame": 6.0,
"endFrame": 28.0, "endFrame": 28.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -869,7 +869,7 @@
"id": "landRun", "id": "landRun",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_land.fbx", "url": "animations/jump_land.fbx",
"startFrame": 1.0, "startFrame": 1.0,
"endFrame": 6.0, "endFrame": 6.0,
"timeScale": 0.65, "timeScale": 0.65,
@ -891,7 +891,7 @@
"id": "userAnimA", "id": "userAnimA",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx", "url": "animations/idle.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 90.0, "endFrame": 90.0,
"timeScale": 1.0, "timeScale": 1.0,
@ -903,7 +903,7 @@
"id": "userAnimB", "id": "userAnimB",
"type": "clip", "type": "clip",
"data": { "data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx", "url": "animations/idle.fbx",
"startFrame": 0.0, "startFrame": 0.0,
"endFrame": 90.0, "endFrame": 90.0,
"timeScale": 1.0, "timeScale": 1.0,

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,20 +0,0 @@
filename=defaultAvatar/body.fbx
texdir=defaultAvatar
scale=8.666
joint = jointRoot = jointRoot
joint = jointLean = jointSpine
joint = jointNeck = jointNeck
joint = jointHead = jointHeadtop
joint = joint_L_shoulder = joint_L_shoulder
freeJoint = joint_L_arm
freeJoint = joint_L_elbow
joint = jointLeftHand = joint_L_hand
joint = joint_R_shoulder = joint_R_shoulder
freeJoint = joint_R_arm
freeJoint = joint_R_elbow
joint = jointRightHand = joint_R_hand

View file

@ -1,97 +1,135 @@
name = defaultAvatar_full name = being_of_light
type = body+head type = body+head
scale = 1 scale = 1
filename = defaultAvatar_full/defaultAvatar_full.fbx filename = being_of_light/being_of_light.fbx
texdir = defaultAvatar_full/textures texdir = being_of_light/textures
joint = jointRightHand = RightHand
joint = jointNeck = Head
joint = jointRoot = Hips joint = jointRoot = Hips
joint = jointLeftHand = LeftHand
joint = jointHead = HeadTop_End joint = jointHead = HeadTop_End
joint = jointLean = Spine joint = jointLean = Spine
joint = jointLeftHand = LeftHand joint = jointEyeLeft = LeftEye
joint = jointRightHand = RightHand
joint = jointNeck = Head
joint = jointEyeRight = RightEye
freeJoint = LeftArm freeJoint = LeftArm
freeJoint = LeftForeArm freeJoint = LeftForeArm
freeJoint = RightArm freeJoint = RightArm
freeJoint = RightForeArm freeJoint = RightForeArm
bs = MouthFrown_R = Mouth.MouthFrown_R = 1 bs = MouthFrown_L = Frown_Left = 1
bs = EyeOpen_L = Leye1.EyeOpen_L = 1 bs = MouthLeft = Midmouth_Left = 1
bs = LipsLowerDown_L = Mouth.LipsLowerDown = 0.5 bs = BrowsU_R = BrowsUp_Right = 1
bs = LipsStretch_L = Mouth.LipsStretch_L = 1 bs = ChinUpperRaise = UpperLipUp_Right = 0.5
bs = MouthLeft = Mouth.MouthLeft = 1 bs = ChinUpperRaise = UpperLipUp_Left = 0.5
bs = MouthSmile_L = Mouth.MouthSmile_L = 1 bs = MouthSmile_R = Smile_Right = 1
bs = Sneer_R = Mouth.Sneer = 0.61 bs = MouthDimple_L = Smile_Left = 0.25
bs = LipsPucker = Mouth.LipsPucker = 1 bs = EyeBlink_L = Blink_Left = 1
bs = EyeOpen_R = Reye1.EyeOut_R = 1 bs = BrowsD_L = BrowsDown_Left = 1
bs = LipsLowerDown_R = Mouth.LipsLowerDown = 0.43 bs = MouthFrown_R = Frown_Right = 1
bs = LipsStretch_R = Mouth.LipsStretch_R = 1 bs = MouthDimple_R = Smile_Right = 0.25
bs = MouthSmile_R = Mouth.MouthSmile_R = 1 bs = Sneer = Squint_Right = 0.5
bs = LipsFunnel = Mouth.LipsFunnel = 1 bs = Sneer = Squint_Left = 0.5
bs = EyeUp_L = Leye1.EyeUp_L = 1 bs = Sneer = NoseScrunch_Right = 0.75
bs = MouthDimple_L = Mouth.MouthDimple_L = 1 bs = Sneer = NoseScrunch_Left = 0.75
bs = Puff = Mouth.Puff = 1 bs = EyeSquint_L = Squint_Left = 1
bs = EyeIn_L = Leye1.EyeIn_L = 1 bs = EyeBlink_R = Blink_Right = 1
bs = EyeUp_R = Reye1.EyeUp_R = 0.99 bs = JawLeft = JawRotateY_Left = 0.5
bs = MouthDimple_R = Mouth.MouthDimple_R = 1 bs = BrowsD_R = BrowsDown_Right = 1
bs = MouthRight = Mouth.MouthRight = 1 bs = EyeSquint_R = Squint_Right = 1
bs = EyeOut_L = Leye1.EyeOut_L = 1 bs = Puff = CheekPuff_Right = 1
bs = JawOpen = Mouth.JawOpen = 1 bs = Puff = CheekPuff_Left = 1
bs = EyeIn_R = Reye1.EyeIn_R = 1 bs = LipsUpperClose = UpperLipIn = 1
bs = BrowsD_L = Leye1.BrowsD_L = 1 bs = JawOpen = MouthOpen = 0.69999999999999996
bs = EyeDown_L = Leye1.EyeDown_L = 1 bs = LipsUpperUp = UpperLipUp_Right = 0.69999999999999996
bs = EyeBlink_L = Leye1.EyeBlink_L = 1 bs = LipsUpperUp = UpperLipUp_Left = 0.69999999999999996
bs = EyeOut_R = Reye1.EyeOut_R = 1 bs = LipsLowerDown = LowerLipDown_Right = 0.69999999999999996
bs = LipsUpperUp_L = Mouth.LipsUpperUp = 0.49 bs = LipsLowerDown = LowerLipDown_Left = 0.69999999999999996
bs = MouthFrown_L = Mouth.MouthFrown_L = 1 bs = LipsLowerOpen = LowerLipOut = 1
bs = EyeDown_R = Reye1.EyeDown_R = 1 bs = EyeOpen_L = EyesWide_Left = 1
bs = BrowsD_R = Reye1.BrowsD_R = 1 bs = LipsPucker = MouthNarrow_Right = 1
bs = EyeBlink_R = Reye1.EyeBlink_R = 1 bs = LipsPucker = MouthNarrow_Left = 1
bs = LipsUpperUp_R = Mouth.LipsUpperUp = 0.47 bs = EyeOpen_R = EyesWide_Right = 1
bs = Sneer_L = Mouth.Sneer = 0.5 bs = JawRight = Jaw_Right = 1
jointIndex = headphone = 7 bs = MouthRight = Midmouth_Right = 1
jointIndex = LeftUpLeg = 15 bs = ChinLowerRaise = Jaw_Up = 1
jointIndex = Spine = 20 bs = LipsUpperOpen = UpperLipOut = 1
jointIndex = LeftArm = 32 bs = BrowsU_C = BrowsUp_Right = 1
jointIndex = Head = 40 bs = BrowsU_C = BrowsUp_Left = 1
jointIndex = RightUpLeg = 10 bs = JawFwd = JawForeward = 1
jointIndex = hair = 5 bs = BrowsU_L = BrowsUp_Left = 1
jointIndex = Spine1 = 21 bs = MouthSmile_L = Smile_Left = 1
jointIndex = RightHandIndex1 = 27 bs = LipsLowerClose = LowerLipIn = 1
jointIndex = Spine2 = 22 bs = LipsFunnel = TongueUp = 1
jointIndex = RightHandIndex2 = 28 bs = LipsFunnel = MouthWhistle_NarrowAdjust_Right = 0.5
jointIndex = RightHandIndex3 = 29 bs = LipsFunnel = MouthWhistle_NarrowAdjust_Left = 0.5
jointIndex = RightHandIndex4 = 30 bs = LipsFunnel = MouthNarrow_Right = 1
jointIndex = RightToe_End = 14 bs = LipsFunnel = MouthNarrow_Left = 1
jointIndex = shield = 4 bs = LipsFunnel = Jaw_Down = 0.35999999999999999
jointIndex = LeftHandIndex1 = 35 bs = LipsFunnel = JawForeward = 0.39000000000000001
jointIndex = LeftHandIndex2 = 36 jointIndex = LeftHandIndex1 = 50
jointIndex = RightHand = 26 jointIndex = LeftHandIndex2 = 51
jointIndex = LeftHandIndex3 = 37 jointIndex = LeftHandIndex3 = 52
jointIndex = LeftHandIndex4 = 38 jointIndex = LeftHandIndex4 = 53
jointIndex = LeftShoulder = 31 jointIndex = Spine1 = 12
jointIndex = LeftHand = 34 jointIndex = Spine2 = 13
jointIndex = RightForeArm = 25 jointIndex = RightHandThumb1 = 18
jointIndex = RightLeg = 11 jointIndex = RightHandThumb2 = 19
jointIndex = RightFoot = 12 jointIndex = RightHandThumb3 = 20
jointIndex = mouth = 1 jointIndex = RightHandThumb4 = 21
jointIndex = LeftToe_End = 19 jointIndex = LeftFoot = 8
jointIndex = Reye = 2 jointIndex = LeftForeArm = 40
jointIndex = Hips = 9 jointIndex = Neck = 62
jointIndex = RightToeBase = 13 jointIndex = Head = 63
jointIndex = HeadTop_End = 41 jointIndex = Hips = 0
jointIndex = LeftFoot = 17 jointIndex = RightHandPinky1 = 30
jointIndex = RightShoulder = 23 jointIndex = RightHandPinky2 = 31
jointIndex = LeftLeg = 16 jointIndex = RightHandPinky3 = 32
jointIndex = Leye = 3 jointIndex = RightHandPinky4 = 33
jointIndex = LeftForeArm = 33 jointIndex = RightLeg = 2
jointIndex = face = 0 jointIndex = RightForeArm = 16
jointIndex = body = 8 jointIndex = LeftHandRing1 = 46
jointIndex = LeftToeBase = 18 jointIndex = LeftHandRing2 = 47
jointIndex = RightArm = 24 jointIndex = LeftHandRing3 = 48
jointIndex = top1 = 6 jointIndex = LeftHandRing4 = 49
jointIndex = Neck = 39 jointIndex = LeftHandThumb1 = 54
rx = 0 jointIndex = LeftHandThumb2 = 55
ry = 0 jointIndex = LeftHandThumb3 = 56
rz = 0 jointIndex = LeftHandThumb4 = 57
tx = 0 jointIndex = HeadTop_End = 66
ty = 0 jointIndex = LeftUpLeg = 6
tz = 0 jointIndex = LeftToeBase = 9
jointIndex = LeftHandPinky1 = 42
jointIndex = LeftHandPinky2 = 43
jointIndex = LeftHandPinky3 = 44
jointIndex = LeftHandPinky4 = 45
jointIndex = LeftLeg = 7
jointIndex = RightEye = 65
jointIndex = RightHand = 17
jointIndex = RightToeBase = 4
jointIndex = RightUpLeg = 1
jointIndex = RightArm = 15
jointIndex = RightHandRing1 = 26
jointIndex = RightHandRing2 = 27
jointIndex = RightHandRing3 = 28
jointIndex = RightHandRing4 = 29
jointIndex = RightHandIndex1 = 22
jointIndex = RightHandIndex2 = 23
jointIndex = RightHandIndex3 = 24
jointIndex = RightHandIndex4 = 25
jointIndex = LeftToe_End = 10
jointIndex = LeftHandMiddle1 = 58
jointIndex = LeftHandMiddle2 = 59
jointIndex = LeftHandMiddle3 = 60
jointIndex = LeftShoulder = 38
jointIndex = LeftHandMiddle4 = 61
jointIndex = RightFoot = 3
jointIndex = LeftHand = 41
jointIndex = RightHandMiddle1 = 34
jointIndex = RightHandMiddle2 = 35
jointIndex = RightHandMiddle3 = 36
jointIndex = RightShoulder = 14
jointIndex = LeftEye = 64
jointIndex = RightHandMiddle4 = 37
jointIndex = Body = 67
jointIndex = LeftArm = 39
jointIndex = RightToe_End = 5
jointIndex = Spine = 11

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,45 +0,0 @@
# faceshift target mapping file
name= defaultAvatar_head
filename=defaultAvatar/head.fbx
texdir=defaultAvatar
scale=5.333
rx=0
ry=0
rz=0
tx=0
ty=0
tz=0
joint = jointNeck = jointNeck
bs = BrowsD_L = Leye1.BrowsD_L = 0.97
bs = BrowsD_R = Reye1.BrowsD_R = 1
bs = CheekSquint_L = Leye1.CheekSquint_L = 1
bs = CheekSquint_R = Reye1.CheekSquint_R = 1
bs = EyeBlink_L = Leye1.EyeBlink_L = 1
bs = EyeBlink_R = Reye1.EyeBlink_R = 1
bs = EyeDown_L = Leye1.EyeDown_L = 1
bs = EyeDown_R = Reye1.EyeDown_R = 0.99
bs = EyeIn_L = Leye1.EyeIn_L = 0.92
bs = EyeIn_R = Reye1.EyeIn_R = 1
bs = EyeOpen_L = Leye1.EyeOpen_L = 1
bs = EyeOpen_R = Reye1.EyeOpen_R = 1
bs = EyeOut_L = Leye1.EyeOut_L = 0.99
bs = EyeOut_R = Reye1.EyeOut_R = 1
bs = EyeUp_L = Leye1.EyeUp_L = 0.93
bs = EyeUp_R = Reye1.EyeUp_R = 1
bs = JawOpen = Mouth.JawOpen = 1
bs = LipsFunnel = Mouth.LipsFunnel = 1
bs = LipsLowerDown = Mouth.LipsLowerDown = 1
bs = LipsPucker = Mouth.LipsPucker = 1
bs = LipsStretch_L = Mouth.LipsStretch_L = 0.96
bs = LipsStretch_R = Mouth.LipsStretch_R = 1
bs = LipsUpperUp = Mouth.LipsUpperUp = 1
bs = MouthDimple_L = Mouth.MouthDimple_L = 1
bs = MouthDimple_R = Mouth.MouthDimple_R = 1
bs = MouthFrown_L = Mouth.MouthFrown_L = 1
bs = MouthFrown_R = Mouth.MouthFrown_R = 1
bs = MouthLeft = Mouth.MouthLeft = 1
bs = MouthRight = Mouth.MouthRight = 1
bs = MouthSmile_L = Mouth.MouthSmile_L = 1
bs = MouthSmile_R = Mouth.MouthSmile_R = 1
bs = Puff = Mouth.Puff = 1
bs = Sneer = Mouth.Sneer = 1

View file

@ -330,9 +330,10 @@ Window {
HifiControls.ContentSection { HifiControls.ContentSection {
id: assetDirectory id: assetDirectory
name: "Asset Directory" name: "Asset Directory"
spacing: hifi.dimensions.contentSpacing.y
isFirst: true isFirst: true
HifiControls.VerticalSpacer {}
Row { Row {
id: buttonRow id: buttonRow
anchors.left: parent.left anchors.left: parent.left
@ -343,8 +344,7 @@ Window {
glyph: hifi.glyphs.reload glyph: hifi.glyphs.reload
color: hifi.buttons.white color: hifi.buttons.white
colorScheme: root.colorScheme colorScheme: root.colorScheme
height: 26 width: hifi.dimensions.controlLineHeight
width: 26
onClicked: root.reload() onClicked: root.reload()
} }
@ -353,7 +353,6 @@ Window {
text: "ADD TO WORLD" text: "ADD TO WORLD"
color: hifi.buttons.white color: hifi.buttons.white
colorScheme: root.colorScheme colorScheme: root.colorScheme
height: 26
width: 120 width: 120
enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100)) enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100))
@ -365,7 +364,6 @@ Window {
text: "RENAME" text: "RENAME"
color: hifi.buttons.white color: hifi.buttons.white
colorScheme: root.colorScheme colorScheme: root.colorScheme
height: 26
width: 80 width: 80
onClicked: root.renameFile() onClicked: root.renameFile()
@ -378,7 +376,6 @@ Window {
text: "DELETE" text: "DELETE"
color: hifi.buttons.red color: hifi.buttons.red
colorScheme: root.colorScheme colorScheme: root.colorScheme
height: 26
width: 80 width: 80
onClicked: root.deleteFile() onClicked: root.deleteFile()
@ -419,7 +416,7 @@ Window {
id: treeView id: treeView
anchors.top: assetDirectory.bottom anchors.top: assetDirectory.bottom
anchors.bottom: uploadSection.top anchors.bottom: uploadSection.top
anchors.margins: 12 anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@ -448,7 +445,7 @@ Window {
name: "Upload A File" name: "Upload A File"
spacing: hifi.dimensions.contentSpacing.y spacing: hifi.dimensions.contentSpacing.y
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
height: 92 height: 95
Item { Item {
height: parent.height height: parent.height

View file

@ -30,7 +30,7 @@ Window {
title: "Edit" title: "Edit"
property alias tabView: tabView property alias tabView: tabView
implicitWidth: 520; implicitHeight: 695 implicitWidth: 520; implicitHeight: 695
minSize: Qt.vector2d(412, 500) minSize: Qt.vector2d(456, 500)
HifiConstants { id: hifi } HifiConstants { id: hifi }

View file

@ -19,7 +19,7 @@ Original.Button {
property int colorScheme: hifi.colorSchemes.light property int colorScheme: hifi.colorSchemes.light
width: 120 width: 120
height: 28 height: hifi.dimensions.controlLineHeight
style: ButtonStyle { style: ButtonStyle {

View file

@ -59,7 +59,7 @@ FocusScope {
id: comboBox id: comboBox
anchors.fill: parent anchors.fill: parent
visible: false visible: false
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control.
} }
FiraSansSemiBold { FiraSansSemiBold {

View file

@ -46,7 +46,7 @@ Column {
Item { Item {
id: leadingSpace id: leadingSpace
width: 1 width: 1
height: isFirst ? hifi.dimensions.contentSpacing.y : 0 height: isFirst ? 7 : 0
anchors.top: parent.top anchors.top: parent.top
} }
@ -80,14 +80,14 @@ Column {
right: parent.right right: parent.right
top: topBar.bottom top: topBar.bottom
} }
height: (isCollapsible ? 3 : 2) * hifi.dimensions.contentSpacing.y height: isCollapsible ? 36 : 28
RalewayRegular { RalewayRegular {
id: title id: title
anchors { anchors {
left: parent.left left: parent.left
top: parent.top top: parent.top
topMargin: hifi.dimensions.contentSpacing.y topMargin: 12
} }
size: hifi.fontSizes.sectionName size: hifi.fontSizes.sectionName
font.capitalization: Font.AllUppercase font.capitalization: Font.AllUppercase

View file

@ -28,7 +28,7 @@ SpinBox {
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput font.pixelSize: hifi.fontSizes.textFieldInput
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control.
y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0 y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0
@ -51,12 +51,13 @@ SpinBox {
horizontalAlignment: Qt.AlignLeft horizontalAlignment: Qt.AlignLeft
padding.left: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding padding.left: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding
padding.right: hifi.dimensions.spinnerSize padding.right: hifi.dimensions.spinnerSize
padding.top: 0
incrementControl: HiFiGlyphs { incrementControl: HiFiGlyphs {
id: incrementButton id: incrementButton
text: hifi.glyphs.caratUp text: hifi.glyphs.caratUp
x: 6 x: 6
y: 2 y: 1
size: hifi.dimensions.spinnerSize size: hifi.dimensions.spinnerSize
color: styleData.upPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray color: styleData.upPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray
} }

View file

@ -0,0 +1,67 @@
//
// TextField.qml
//
// Created by David Rowe on 21 Apr 2016
// Copyright 2016 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
Item {
property string icon: ""
property int iconSize: 30
property string text: ""
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
signal clicked()
height: Math.max(glyph.visible ? glyph.height - 4 : 0, string.visible ? string.height : 0)
width: glyph.width + string.anchors.leftMargin + string.width
HiFiGlyphs {
id: glyph
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: -2
text: parent.icon
size: parent.iconSize
color: isLightColorScheme
? (mouseArea.containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.lightGray)
: (mouseArea.containsMouse ? hifi.colors.faintGray : hifi.colors.lightGrayText)
visible: text !== ""
width: visible ? implicitWidth : 0
}
RalewaySemiBold {
id: string
anchors {
left: glyph.visible ? glyph.right : parent.left
leftMargin: visible && glyph.visible ? hifi.dimensions.contentSpacing.x : 0
verticalCenter: glyph.visible ? glyph.verticalCenter : undefined
}
text: parent.text
size: hifi.fontSizes.inputLabel
color: isLightColorScheme
? (mouseArea.containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.lightGray)
: (mouseArea.containsMouse ? hifi.colors.faintGray : hifi.colors.lightGrayText)
font.underline: true;
visible: text !== ""
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: parent.clicked()
}
}

View file

@ -20,15 +20,17 @@ TextField {
property int colorScheme: hifi.colorSchemes.light property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property bool isSearchField: false
property string label: "" property string label: ""
property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0) property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + 1 : 0)
placeholderText: textField.placeholderText placeholderText: textField.placeholderText
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput font.pixelSize: hifi.fontSizes.textFieldInput
height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered. font.italic: textField.text == ""
height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered.
y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0 y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0
@ -42,11 +44,22 @@ TextField {
: (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow) : (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
border.color: hifi.colors.primaryHighlight border.color: hifi.colors.primaryHighlight
border.width: textField.focus ? 1 : 0 border.width: textField.focus ? 1 : 0
radius: isSearchField ? textField.height / 2 : 0
HiFiGlyphs {
text: hifi.glyphs.search
color: textColor
size: hifi.fontSizes.textFieldSearchIcon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: hifi.dimensions.textPadding - 2
visible: isSearchField
}
} }
placeholderTextColor: hifi.colors.lightGray placeholderTextColor: hifi.colors.lightGray
selectedTextColor: hifi.colors.black selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight selectionColor: hifi.colors.primaryHighlight
padding.left: hifi.dimensions.textPadding padding.left: (isSearchField ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: hifi.dimensions.textPadding padding.right: hifi.dimensions.textPadding
} }
@ -56,7 +69,7 @@ TextField {
colorScheme: textField.colorScheme colorScheme: textField.colorScheme
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.top anchors.bottom: parent.top
anchors.bottomMargin: 4 anchors.bottomMargin: 3
visible: label != "" visible: label != ""
} }
} }

View file

@ -51,7 +51,11 @@ Window {
Rectangle { Rectangle {
id: attachmentsBackground id: attachmentsBackground
anchors { left: parent.left; right: parent.right; top: parent.top; bottom: newAttachmentButton.top; margins: 8 } anchors {
left: parent.left; right: parent.right; top: parent.top; bottom: newAttachmentButton.top;
margins: hifi.dimensions.contentMargin.x
bottomMargin: hifi.dimensions.contentSpacing.y
}
color: hifi.colors.baseGrayShadow color: hifi.colors.baseGrayShadow
radius: 4 radius: 4
@ -129,7 +133,14 @@ Window {
HifiControls.Button { HifiControls.Button {
id: newAttachmentButton id: newAttachmentButton
anchors { left: parent.left; right: parent.right; bottom: buttonRow.top; margins: 8 } anchors {
left: parent.left
right: parent.right
bottom: buttonRow.top
margins: hifi.dimensions.contentMargin.x;
topMargin: hifi.dimensions.contentSpacing.y
bottomMargin: hifi.dimensions.contentSpacing.y
}
text: "New Attachment" text: "New Attachment"
color: hifi.buttons.black color: hifi.buttons.black
colorScheme: hifi.colorSchemes.dark colorScheme: hifi.colorSchemes.dark
@ -151,7 +162,13 @@ Window {
Row { Row {
id: buttonRow id: buttonRow
spacing: 8 spacing: 8
anchors { right: parent.right; bottom: parent.bottom; margins: 8 } anchors {
right: parent.right
bottom: parent.bottom
margins: hifi.dimensions.contentMargin.x
topMargin: hifi.dimensions.contentSpacing.y
bottomMargin: hifi.dimensions.contentSpacing.y
}
HifiControls.Button { HifiControls.Button {
action: okAction action: okAction
color: hifi.buttons.black color: hifi.buttons.black

View file

@ -24,7 +24,8 @@ Window {
resizable: true resizable: true
destroyOnInvisible: true destroyOnInvisible: true
x: 40; y: 40 x: 40; y: 40
implicitWidth: 400; implicitHeight: 695 implicitWidth: 400
implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300) minSize: Qt.vector2d(200, 300)
HifiConstants { id: hifi } HifiConstants { id: hifi }
@ -32,6 +33,7 @@ Window {
property var scripts: ScriptDiscoveryService; property var scripts: ScriptDiscoveryService;
property var scriptsModel: scripts.scriptsModelFilter property var scriptsModel: scripts.scriptsModelFilter
property var runningScriptsModel: ListModel { } property var runningScriptsModel: ListModel { }
property bool isHMD: false
Settings { Settings {
category: "Overlay.RunningScripts" category: "Overlay.RunningScripts"
@ -44,7 +46,10 @@ Window {
onScriptCountChanged: updateRunningScripts(); onScriptCountChanged: updateRunningScripts();
} }
Component.onCompleted: updateRunningScripts() Component.onCompleted: {
isHMD = HMD.active;
updateRunningScripts();
}
function setDefaultFocus() { function setDefaultFocus() {
// Work around FocusScope of scrollable window. // Work around FocusScope of scrollable window.
@ -109,7 +114,9 @@ Window {
} }
} }
HifiControls.VerticalSpacer {} HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Table { HifiControls.Table {
tableModel: runningScriptsModel tableModel: runningScriptsModel
@ -120,7 +127,7 @@ Window {
} }
HifiControls.VerticalSpacer { HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Table view draws a little taller than it's height. height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
} }
} }
@ -175,16 +182,19 @@ Window {
HifiControls.TextField { HifiControls.TextField {
id: filterEdit id: filterEdit
isSearchField: true
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
focus: true focus: true
colorScheme: hifi.colorSchemes.dark colorScheme: hifi.colorSchemes.dark
placeholderText: "filter" placeholderText: "Filter"
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i") onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i") Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
} }
HifiControls.VerticalSpacer {} HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Tree { HifiControls.Tree {
id: treeView id: treeView
@ -195,7 +205,9 @@ Window {
anchors.right: parent.right anchors.right: parent.right
} }
HifiControls.VerticalSpacer {} HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.TextField { HifiControls.TextField {
id: selectedScript id: selectedScript
@ -236,7 +248,25 @@ Window {
} }
} }
HifiControls.VerticalSpacer { } HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight - (!isHMD ? 3 : 0)
}
HifiControls.TextAction {
id: directoryButton
icon: hifi.glyphs.script
iconSize: 24
text: "Reveal Scripts Folder"
onClicked: fileDialogHelper.openDirectory(scripts.defaultScriptsPath)
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
visible: !isHMD
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight - 3
visible: !isHMD
}
} }
} }
} }

View file

@ -131,8 +131,8 @@ Item {
readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080 readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080
readonly property real borderRadius: largeScreen ? 7.5 : 5.0 readonly property real borderRadius: largeScreen ? 7.5 : 5.0
readonly property real borderWidth: largeScreen ? 2 : 1 readonly property real borderWidth: largeScreen ? 2 : 1
readonly property vector2d contentMargin: Qt.vector2d(12, 24) readonly property vector2d contentMargin: Qt.vector2d(21, 21)
readonly property vector2d contentSpacing: Qt.vector2d(8, 12) readonly property vector2d contentSpacing: Qt.vector2d(11, 14)
readonly property real labelPadding: 40 readonly property real labelPadding: 40
readonly property real textPadding: 8 readonly property real textPadding: 8
readonly property real sliderHandleSize: 18 readonly property real sliderHandleSize: 18
@ -143,8 +143,8 @@ Item {
readonly property real tableHeaderHeight: 40 readonly property real tableHeaderHeight: 40
readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30) readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30)
readonly property real modalDialogTitleHeight: 40 readonly property real modalDialogTitleHeight: 40
readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor readonly property real controlLineHeight: 28 // Height of spinbox control on 1920 x 1080 monitor
readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight
readonly property vector2d menuPadding: Qt.vector2d(14, 12) readonly property vector2d menuPadding: Qt.vector2d(14, 12)
} }
@ -156,6 +156,7 @@ Item {
readonly property real inputLabel: dimensions.largeScreen ? 14 : 10 readonly property real inputLabel: dimensions.largeScreen ? 14 : 10
readonly property real textFieldInput: dimensions.largeScreen ? 15 : 12 readonly property real textFieldInput: dimensions.largeScreen ? 15 : 12
readonly property real textFieldInputLabel: dimensions.largeScreen ? 13 : 9 readonly property real textFieldInputLabel: dimensions.largeScreen ? 13 : 9
readonly property real textFieldSearchIcon: dimensions.largeScreen ? 30 : 24
readonly property real tableText: dimensions.largeScreen ? 15 : 12 readonly property real tableText: dimensions.largeScreen ? 15 : 12
readonly property real buttonLabel: dimensions.largeScreen ? 13 : 9 readonly property real buttonLabel: dimensions.largeScreen ? 13 : 9
readonly property real iconButton: dimensions.largeScreen ? 13 : 9 readonly property real iconButton: dimensions.largeScreen ? 13 : 9

View file

@ -215,7 +215,7 @@ Fadable {
bottom: parent.bottom bottom: parent.bottom
} }
width: parent.contentWidth width: parent.contentWidth
height: footer.height + 2 * hifi.dimensions.contentSpacing.y height: footer.height + 2 * hifi.dimensions.contentSpacing.y + 3
color: hifi.colors.baseGray color: hifi.colors.baseGray
visible: footer.height > 0 visible: footer.height > 0

View file

@ -131,6 +131,7 @@
#include "scripting/WebWindowClass.h" #include "scripting/WebWindowClass.h"
#include "scripting/WindowScriptingInterface.h" #include "scripting/WindowScriptingInterface.h"
#include "scripting/ControllerScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h"
#include "scripting/RatesScriptingInterface.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#include "SpeechRecognizer.h" #include "SpeechRecognizer.h"
#endif #endif
@ -1384,6 +1385,7 @@ void Application::initializeUi() {
rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data()); rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
rootContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data()); rootContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface); rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
rootContext->setContextProperty("Rates", new RatesScriptingInterface(this));
rootContext->setContextProperty("TREE_SCALE", TREE_SCALE); rootContext->setContextProperty("TREE_SCALE", TREE_SCALE);
rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Quat", new Quat());
@ -3102,10 +3104,8 @@ void Application::updateMyAvatarLookAtPosition() {
} else { } else {
// I am not looking at anyone else, so just look forward // I am not looking at anyone else, so just look forward
if (isHMD) { if (isHMD) {
glm::mat4 headPose = myAvatar->getHMDSensorMatrix(); glm::mat4 worldHMDMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
glm::quat headRotation = glm::quat_cast(headPose); lookAtSpot = transformPoint(worldHMDMat, glm::vec3(0.0f, 0.0f, -TREE_SCALE));
lookAtSpot = myAvatar->getPosition() +
myAvatar->getOrientation() * (headRotation * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
} else { } else {
lookAtSpot = myAvatar->getHead()->getEyePosition() + lookAtSpot = myAvatar->getHead()->getEyePosition() +
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); (myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
@ -4439,6 +4439,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
// AvatarManager has some custom types // AvatarManager has some custom types
AvatarManager::registerMetaTypes(scriptEngine); AvatarManager::registerMetaTypes(scriptEngine);
scriptEngine->registerGlobalObject("Rates", new RatesScriptingInterface(this));
// hook our avatar and avatar hash map object into this script engine // hook our avatar and avatar hash map object into this script engine
scriptEngine->registerGlobalObject("MyAvatar", getMyAvatar()); scriptEngine->registerGlobalObject("MyAvatar", getMyAvatar());
qScriptRegisterMetaType(scriptEngine, audioListenModeToScriptValue, audioListenModeFromScriptValue); qScriptRegisterMetaType(scriptEngine, audioListenModeToScriptValue, audioListenModeFromScriptValue);

View file

@ -40,11 +40,10 @@ const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
const float ADJUST_LOD_DOWN_BY = 0.9f; const float ADJUST_LOD_DOWN_BY = 0.9f;
const float ADJUST_LOD_UP_BY = 1.1f; const float ADJUST_LOD_UP_BY = 1.1f;
// This controls how low the auto-adjust LOD will go a value of 1 means it will adjust to a point where you must be 0.25 // The default value DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
// meters away from an object of TREE_SCALE before you can see it (which is effectively completely blind). The default value
// DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
const float ADJUST_LOD_MIN_SIZE_SCALE = 1.0f;
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
// This controls how low the auto-adjust LOD will go. We want a minimum vision of ~20:500 or 0.04 of default
const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.04f;
class RenderArgs; class RenderArgs;
class AABox; class AABox;

View file

@ -360,6 +360,41 @@ Menu::Menu() {
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false)); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false));
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false)); resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false));
//const QString = "Automatic Texture Memory";
//const QString = "64 MB";
//const QString = "256 MB";
//const QString = "512 MB";
//const QString = "1024 MB";
//const QString = "2048 MB";
// Developer > Render > Resolution
MenuWrapper* textureMenu = renderOptionsMenu->addMenu(MenuOption::RenderMaxTextureMemory);
QActionGroup* textureGroup = new QActionGroup(textureMenu);
textureGroup->setExclusive(true);
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTextureAutomatic, 0, true));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture64MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture256MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture512MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture1024MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture2048MB, 0, false));
connect(textureGroup, &QActionGroup::triggered, [textureGroup] {
auto checked = textureGroup->checkedAction();
auto text = checked->text();
gpu::Context::Size newMaxTextureMemory { 0 };
if (MenuOption::RenderMaxTexture64MB == text) {
newMaxTextureMemory = MB_TO_BYTES(64);
} else if (MenuOption::RenderMaxTexture256MB == text) {
newMaxTextureMemory = MB_TO_BYTES(256);
} else if (MenuOption::RenderMaxTexture512MB == text) {
newMaxTextureMemory = MB_TO_BYTES(512);
} else if (MenuOption::RenderMaxTexture1024MB == text) {
newMaxTextureMemory = MB_TO_BYTES(1024);
} else if (MenuOption::RenderMaxTexture2048MB == text) {
newMaxTextureMemory = MB_TO_BYTES(2048);
}
gpu::Texture::setAllowedGPUMemoryUsage(newMaxTextureMemory);
});
// Developer > Render > LOD Tools // Developer > Render > LOD Tools
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools())); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools()));

View file

@ -150,6 +150,13 @@ namespace MenuOption {
const QString RenderFocusIndicator = "Show Eye Focus"; const QString RenderFocusIndicator = "Show Eye Focus";
const QString RenderLookAtTargets = "Show Look-at Targets"; const QString RenderLookAtTargets = "Show Look-at Targets";
const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderLookAtVectors = "Show Look-at Vectors";
const QString RenderMaxTextureMemory = "Maximum Texture Memory";
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
const QString RenderMaxTexture64MB = "64 MB";
const QString RenderMaxTexture256MB = "256 MB";
const QString RenderMaxTexture512MB = "512 MB";
const QString RenderMaxTexture1024MB = "1024 MB";
const QString RenderMaxTexture2048MB = "2048 MB";
const QString RenderResolution = "Scale Resolution"; const QString RenderResolution = "Scale Resolution";
const QString RenderResolutionOne = "1"; const QString RenderResolutionOne = "1";
const QString RenderResolutionTwoThird = "2/3"; const QString RenderResolutionTwoThird = "2/3";

View file

@ -254,10 +254,7 @@ void AvatarManager::clearAllAvatars() {
QWriteLocker locker(&_hashLock); QWriteLocker locker(&_hashLock);
_myAvatar->die(); handleRemovedAvatar(_myAvatar);
_myAvatar.reset();
_avatarHash.clear();
} }
void AvatarManager::setLocalLights(const QVector<AvatarManager::LocalLight>& localLights) { void AvatarManager::setLocalLights(const QVector<AvatarManager::LocalLight>& localLights) {

View file

@ -230,7 +230,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
} }
_leftEyePosition = _rightEyePosition = getPosition(); _leftEyePosition = _rightEyePosition = getPosition();
_eyePosition = calculateAverageEyePosition(); _eyePosition = getPosition();
if (!billboard && _owningAvatar) { if (!billboard && _owningAvatar) {
auto skeletonModel = static_cast<Avatar*>(_owningAvatar)->getSkeletonModel(); auto skeletonModel = static_cast<Avatar*>(_owningAvatar)->getSkeletonModel();
@ -238,6 +238,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition); skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition);
} }
} }
_eyePosition = calculateAverageEyePosition();
} }
void Head::calculateMouthShapes() { void Head::calculateMouthShapes() {

View file

@ -317,6 +317,37 @@ void MyAvatar::update(float deltaTime) {
} }
currentEnergy = max(0.0f, min(currentEnergy,1.0f)); currentEnergy = max(0.0f, min(currentEnergy,1.0f));
emit energyChanged(currentEnergy); emit energyChanged(currentEnergy);
updateEyeContactTarget(deltaTime);
}
void MyAvatar::updateEyeContactTarget(float deltaTime) {
_eyeContactTargetTimer -= deltaTime;
if (_eyeContactTargetTimer < 0.0f) {
const float CHANCE_OF_CHANGING_TARGET = 0.01f;
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
float const FIFTY_FIFTY_CHANCE = 0.5f;
float const EYE_TO_MOUTH_CHANCE = 0.25f;
switch (_eyeContactTarget) {
case LEFT_EYE:
_eyeContactTarget = (randFloat() < EYE_TO_MOUTH_CHANCE) ? MOUTH : RIGHT_EYE;
break;
case RIGHT_EYE:
_eyeContactTarget = (randFloat() < EYE_TO_MOUTH_CHANCE) ? MOUTH : LEFT_EYE;
break;
case MOUTH:
default:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? RIGHT_EYE : LEFT_EYE;
break;
}
const float EYE_TARGET_DELAY_TIME = 0.33f;
_eyeContactTargetTimer = EYE_TARGET_DELAY_TIME;
}
}
} }
extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
@ -944,22 +975,6 @@ void MyAvatar::clearLookAtTargetAvatar() {
} }
eyeContactTarget MyAvatar::getEyeContactTarget() { eyeContactTarget MyAvatar::getEyeContactTarget() {
float const CHANCE_OF_CHANGING_TARGET = 0.01f;
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
float const FIFTY_FIFTY_CHANCE = 0.5f;
switch (_eyeContactTarget) {
case LEFT_EYE:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? MOUTH : RIGHT_EYE;
break;
case RIGHT_EYE:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? LEFT_EYE : MOUTH;
break;
case MOUTH:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? RIGHT_EYE : LEFT_EYE;
break;
}
}
return _eyeContactTarget; return _eyeContactTarget;
} }
@ -1323,23 +1338,8 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) {
} }
void MyAvatar::initAnimGraph() { void MyAvatar::initAnimGraph() {
// avatar.json
// https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9
//
// ik-avatar.json
// https://gist.github.com/hyperlogic/e58e0a24cc341ad5d060
//
// ik-avatar-hands.json
// https://gist.githubusercontent.com/hyperlogic/04a02c47eb56d8bfaebb
//
// ik-avatar-hands-idle.json
// https://gist.githubusercontent.com/hyperlogic/d951c78532e7a20557ad
//
// or run a local web-server
// python -m SimpleHTTPServer&
//auto graphUrl = QUrl("http://localhost:8000/avatar.json");
auto graphUrl =_animGraphUrl.isEmpty() ? auto graphUrl =_animGraphUrl.isEmpty() ?
QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : QUrl::fromLocalFile(PathUtils::resourcesPath() + "avatar/avatar-animation.json") :
QUrl(_animGraphUrl); QUrl(_animGraphUrl);
_rig->initAnimGraph(graphUrl); _rig->initAnimGraph(graphUrl);

View file

@ -331,6 +331,8 @@ private:
bool cameraInsideHead() const; bool cameraInsideHead() const;
void updateEyeContactTarget(float deltaTime);
// These are made private for MyAvatar so that you will use the "use" methods instead // These are made private for MyAvatar so that you will use the "use" methods instead
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
@ -371,6 +373,7 @@ private:
float _oculusYawOffset; float _oculusYawOffset;
eyeContactTarget _eyeContactTarget; eyeContactTarget _eyeContactTarget;
float _eyeContactTargetTimer { 0.0f };
glm::vec3 _trackedHeadPosition; glm::vec3 _trackedHeadPosition;

View file

@ -127,9 +127,9 @@ int main(int argc, const char* argv[]) {
const char* CLOCK_SKEW = "--clockSkew"; const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW); const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
if (clockSkewOption) { if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption); qint64 clockSkew = atoll(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew); usecTimestampNowForceClockSkew(clockSkew);
qCDebug(interfaceapp, "clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew); qCDebug(interfaceapp) << "clockSkewOption=" << clockSkewOption << "clockSkew=" << clockSkew;
} }
// Oculus initialization MUST PRECEDE OpenGL context creation. // Oculus initialization MUST PRECEDE OpenGL context creation.

View file

@ -292,6 +292,8 @@ void AssetMappingModel::refresh() {
} else { } else {
emit errorGettingMappings(request->getErrorString()); emit errorGettingMappings(request->getErrorString());
} }
request->deleteLater();
}); });
request->start(); request->start();

View file

@ -0,0 +1,37 @@
//
// RatesScriptingInterface.h
// interface/src/scripting
//
// Created by Zach Pomerantz on 4/20/16.
// Copyright 2016 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_RATES_SCRIPTING_INTERFACE_H
#define HIFI_RATES_SCRIPTING_INTERFACE_H
#include <display-plugins/DisplayPlugin.h>
class RatesScriptingInterface : public QObject {
Q_OBJECT
Q_PROPERTY(float render READ getRenderRate)
Q_PROPERTY(float present READ getPresentRate)
Q_PROPERTY(float newFrame READ getNewFrameRate)
Q_PROPERTY(float dropped READ getDropRate)
Q_PROPERTY(float simulation READ getSimulationRate)
Q_PROPERTY(float avatar READ getAvatarRate)
public:
RatesScriptingInterface(QObject* parent) : QObject(parent) {}
float getRenderRate() { return qApp->getFps(); }
float getPresentRate() { return qApp->getActiveDisplayPlugin()->presentRate(); }
float getNewFrameRate() { return qApp->getActiveDisplayPlugin()->newFramePresentRate(); }
float getDropRate() { return qApp->getActiveDisplayPlugin()->droppedFrameRate(); }
float getSimulationRate() { return qApp->getAverageSimsPerSecond(); }
float getAvatarRate() { return qApp->getAvatarSimrate(); }
};
#endif // HIFI_INTERFACE_RATES_SCRIPTING_INTERFACE_H

View file

@ -281,7 +281,7 @@ void ApplicationOverlay::buildFramebufferObject() {
_overlayFramebuffer->setRenderBuffer(0, newColorAttachment); _overlayFramebuffer->setRenderBuffer(0, newColorAttachment);
} }
} }
// If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one // If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one
if (!_overlayFramebuffer->getRenderBuffer(0)) { if (!_overlayFramebuffer->getRenderBuffer(0)) {
const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP); const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP);

View file

@ -51,8 +51,8 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
connect(_manualLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); connect(_manualLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust()));
_lodSize = new QSlider(Qt::Horizontal, this); _lodSize = new QSlider(Qt::Horizontal, this);
const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; const int MAX_LOD_SIZE = 2000; // ~20:4 vision -- really good.
const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE; const int MIN_LOD_SIZE = 5; // ~20:1600 vision -- really bad!
const int STEP_LOD_SIZE = 1; const int STEP_LOD_SIZE = 1;
const int PAGE_STEP_LOD_SIZE = 100; const int PAGE_STEP_LOD_SIZE = 100;
const int SLIDER_WIDTH = 300; const int SLIDER_WIDTH = 300;

View file

@ -515,7 +515,9 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost()); QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost());
QString incomingRecovered = locale.toString((uint)seqStats.getRecovered()); QString incomingRecovered = locale.toString((uint)seqStats.getRecovered());
int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC; qint64 clockSkewInUsecs = node->getClockSkewUsec();
QString formattedClockSkewString = formatUsecTime(clockSkewInUsecs);
qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC;
QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage());
QString incomingPingTimeString = locale.toString(node->getPingMs()); QString incomingPingTimeString = locale.toString(node->getPingMs());
QString incomingClockSkewString = locale.toString(clockSkewInMS); QString incomingClockSkewString = locale.toString(clockSkewInMS);
@ -536,7 +538,9 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
" Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs";
serverDetails << "<br/>" << serverDetails << "<br/>" <<
" Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs"; " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" <<
" [" << qPrintable(formattedClockSkewString) << "]";
serverDetails << "<br/>" << "Incoming" << serverDetails << "<br/>" << "Incoming" <<
" Bytes: " << qPrintable(incomingBytesString) << " Bytes: " << qPrintable(incomingBytesString) <<

View file

@ -248,7 +248,11 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString&
READ_OPTIONAL_STRING(loopFlagVar, jsonObj); READ_OPTIONAL_STRING(loopFlagVar, jsonObj);
READ_OPTIONAL_STRING(mirrorFlagVar, jsonObj); READ_OPTIONAL_STRING(mirrorFlagVar, jsonObj);
auto node = std::make_shared<AnimClip>(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); // animation urls can be relative to the containing url document.
auto tempUrl = QUrl(url);
tempUrl = jsonUrl.resolved(tempUrl);
auto node = std::make_shared<AnimClip>(id, tempUrl.toString(), startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
if (!startFrameVar.isEmpty()) { if (!startFrameVar.isEmpty()) {
node->setStartFrameVar(startFrameVar); node->setStartFrameVar(startFrameVar);

View file

@ -64,9 +64,9 @@ void AnimationReader::run() {
if (urlValid) { if (urlValid) {
// Parse the FBX directly from the QNetworkReply // Parse the FBX directly from the QNetworkReply
FBXGeometry* fbxgeo = nullptr; FBXGeometry::Pointer fbxgeo;
if (_url.path().toLower().endsWith(".fbx")) { if (_url.path().toLower().endsWith(".fbx")) {
fbxgeo = readFBX(_data, QVariantHash(), _url.path()); fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path()));
} else { } else {
QString errorStr("usupported format"); QString errorStr("usupported format");
emit onError(299, errorStr); emit onError(299, errorStr);
@ -117,16 +117,16 @@ const QVector<FBXAnimationFrame>& Animation::getFramesReference() const {
void Animation::downloadFinished(const QByteArray& data) { void Animation::downloadFinished(const QByteArray& data) {
// parse the animation/fbx file on a background thread. // parse the animation/fbx file on a background thread.
AnimationReader* animationReader = new AnimationReader(_url, data); AnimationReader* animationReader = new AnimationReader(_url, data);
connect(animationReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(animationParseSuccess(FBXGeometry*))); connect(animationReader, SIGNAL(onSuccess(FBXGeometry::Pointer)), SLOT(animationParseSuccess(FBXGeometry::Pointer)));
connect(animationReader, SIGNAL(onError(int, QString)), SLOT(animationParseError(int, QString))); connect(animationReader, SIGNAL(onError(int, QString)), SLOT(animationParseError(int, QString)));
QThreadPool::globalInstance()->start(animationReader); QThreadPool::globalInstance()->start(animationReader);
} }
void Animation::animationParseSuccess(FBXGeometry* geometry) { void Animation::animationParseSuccess(FBXGeometry::Pointer geometry) {
qCDebug(animation) << "Animation parse success" << _url.toDisplayString(); qCDebug(animation) << "Animation parse success" << _url.toDisplayString();
_geometry.reset(geometry); _geometry = geometry;
finishedLoading(true); finishedLoading(true);
} }

View file

@ -68,12 +68,12 @@ protected:
virtual void downloadFinished(const QByteArray& data) override; virtual void downloadFinished(const QByteArray& data) override;
protected slots: protected slots:
void animationParseSuccess(FBXGeometry* geometry); void animationParseSuccess(FBXGeometry::Pointer geometry);
void animationParseError(int error, QString str); void animationParseError(int error, QString str);
private: private:
std::unique_ptr<FBXGeometry> _geometry; FBXGeometry::Pointer _geometry;
}; };
/// Reads geometry in a worker thread. /// Reads geometry in a worker thread.
@ -85,7 +85,7 @@ public:
virtual void run(); virtual void run();
signals: signals:
void onSuccess(FBXGeometry* geometry); void onSuccess(FBXGeometry::Pointer geometry);
void onError(int error, QString str); void onError(int error, QString str);
private: private:

View file

@ -29,6 +29,7 @@ namespace AudioConstants {
const int NETWORK_FRAME_SAMPLES_PER_CHANNEL = NETWORK_FRAME_BYTES_PER_CHANNEL / sizeof(AudioSample); const int NETWORK_FRAME_SAMPLES_PER_CHANNEL = NETWORK_FRAME_BYTES_PER_CHANNEL / sizeof(AudioSample);
const float NETWORK_FRAME_SECS = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL / float(AudioConstants::SAMPLE_RATE)); const float NETWORK_FRAME_SECS = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL / float(AudioConstants::SAMPLE_RATE));
const float NETWORK_FRAME_MSECS = NETWORK_FRAME_SECS * 1000.0f; const float NETWORK_FRAME_MSECS = NETWORK_FRAME_SECS * 1000.0f;
const float NETWORK_FRAMES_PER_SEC = 1.0f / NETWORK_FRAME_SECS;
// be careful with overflows when using this constant // be careful with overflows when using this constant
const int NETWORK_FRAME_USECS = static_cast<int>(NETWORK_FRAME_MSECS * 1000.0f); const int NETWORK_FRAME_USECS = static_cast<int>(NETWORK_FRAME_MSECS * 1000.0f);

View file

@ -820,16 +820,24 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
return; return;
} }
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); QString collisionSoundURL;
if (!entity) { float mass = 1.0; // value doesn't get used, but set it so compiler is quiet
AACube minAACube;
bool success = false;
_tree->withReadLock([&] {
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (entity) {
collisionSoundURL = entity->getCollisionSoundURL();
mass = entity->computeMass();
minAACube = entity->getMinimumAACube(success);
}
});
if (!success) {
return; return;
} }
const QString& collisionSoundURL = entity->getCollisionSoundURL();
if (collisionSoundURL.isEmpty()) { if (collisionSoundURL.isEmpty()) {
return; return;
} }
const float mass = entity->computeMass();
const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity() const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
// The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact, // The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact,
// but that first contact depends on exactly where we hit in the physics step. // but that first contact depends on exactly where we hit in the physics step.
@ -854,11 +862,6 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
bool success;
auto minAACube = entity->getMinimumAACube(success);
if (!success) {
return;
}
const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position); AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
} }

View file

@ -29,7 +29,7 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer<Received
} }
} }
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew) { void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew) {
if (type == PacketType::EntityAdd || type == PacketType::EntityEdit) { if (type == PacketType::EntityAdd || type == PacketType::EntityEdit) {
EntityItem::adjustEditPacketForClockSkew(buffer, clockSkew); EntityItem::adjustEditPacketForClockSkew(buffer, clockSkew);
} }

View file

@ -32,7 +32,7 @@ public:
// My server type is the model server // My server type is the model server
virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual char getMyNodeType() const { return NodeType::EntityServer; }
virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew); virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew);
public slots: public slots:
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode); void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);

View file

@ -370,7 +370,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
return 0; return 0;
} }
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0; qint64 clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
BufferParser parser(data, bytesLeftToRead); BufferParser parser(data, bytesLeftToRead);
@ -485,7 +485,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
qCDebug(entities) << " now:" << now; qCDebug(entities) << " now:" << now;
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now); qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew); qCDebug(entities) << " clockSkew:" << clockSkew;
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now); qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now);
qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now); qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now);
@ -731,7 +731,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// we want to extrapolate the motion forward to compensate for packet travel time, but // we want to extrapolate the motion forward to compensate for packet travel time, but
// we don't want the side effect of flag setting. // we don't want the side effect of flag setting.
simulateKinematicMotion(skipTimeForward, false); stepKinematicMotion(skipTimeForward);
} }
if (overwriteLocalData) { if (overwriteLocalData) {
@ -760,7 +760,7 @@ void EntityItem::debugDump() const {
} }
// adjust any internal timestamps to fix clock skew for this server // adjust any internal timestamps to fix clock skew for this server
void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, int clockSkew) { void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSkew) {
unsigned char* dataAt = reinterpret_cast<unsigned char*>(buffer.data()); unsigned char* dataAt = reinterpret_cast<unsigned char*>(buffer.data());
int octets = numberOfThreeBitSectionsInCode(dataAt); int octets = numberOfThreeBitSectionsInCode(dataAt);
int lengthOfOctcode = (int)bytesRequiredForCodeLength(octets); int lengthOfOctcode = (int)bytesRequiredForCodeLength(octets);
@ -872,130 +872,120 @@ void EntityItem::simulate(const quint64& now) {
qCDebug(entities) << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated; qCDebug(entities) << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated;
#endif #endif
simulateKinematicMotion(timeElapsed); if (!hasActions()) {
if (!stepKinematicMotion(timeElapsed)) {
// this entity is no longer moving
// flag it to transition from KINEMATIC to STATIC
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
setAcceleration(Vectors::ZERO);
}
}
_lastSimulated = now; _lastSimulated = now;
} }
void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) { bool EntityItem::stepKinematicMotion(float timeElapsed) {
#ifdef WANT_DEBUG // get all the data
qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; Transform transform;
#endif glm::vec3 linearVelocity;
glm::vec3 angularVelocity;
getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity);
const float MIN_TIME_SKIP = 0.0f; // find out if it is moving
const float MAX_TIME_SKIP = 1.0f; // in seconds bool isSpinning = (glm::length2(angularVelocity) > 0.0f);
float linearSpeedSquared = glm::length2(linearVelocity);
timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); bool isTranslating = linearSpeedSquared > 0.0f;
bool moving = isTranslating || isSpinning;
if (hasActions()) { if (!moving) {
return; return false;
} }
if (hasLocalAngularVelocity()) { if (timeElapsed <= 0.0f) {
glm::vec3 localAngularVelocity = getLocalAngularVelocity(); // someone gave us a useless time value so bail early
// but return 'true' because it is moving
return true;
}
const float MAX_TIME_ELAPSED = 1.0f; // seconds
if (timeElapsed > MAX_TIME_ELAPSED) {
qCWarning(entities) << "kinematic timestep = " << timeElapsed << " truncated to " << MAX_TIME_ELAPSED;
}
timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED);
if (isSpinning) {
// angular damping // angular damping
if (_angularDamping > 0.0f) { if (_angularDamping > 0.0f) {
localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed); angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
#ifdef WANT_DEBUG
qCDebug(entities) << " angularDamping :" << _angularDamping;
qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity;
#endif
} }
float angularSpeed = glm::length(localAngularVelocity); const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED =
KINEMATIC_ANGULAR_SPEED_THRESHOLD * KINEMATIC_ANGULAR_SPEED_THRESHOLD;
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) {
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { angularVelocity = Vectors::ZERO;
if (setFlags && angularSpeed > 0.0f) {
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
}
localAngularVelocity = ENTITY_ITEM_ZERO_VEC3;
} else { } else {
// for improved agreement with the way Bullet integrates rotations we use an approximation // for improved agreement with the way Bullet integrates rotations we use an approximation
// and break the integration into bullet-sized substeps // and break the integration into bullet-sized substeps
glm::quat rotation = getRotation(); glm::quat rotation = transform.getRotation();
float dt = timeElapsed; float dt = timeElapsed;
while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) { while (dt > 0.0f) {
glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP); glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP));
rotation = glm::normalize(dQ * rotation); rotation = glm::normalize(dQ * rotation);
dt -= PHYSICS_ENGINE_FIXED_SUBSTEP; dt -= PHYSICS_ENGINE_FIXED_SUBSTEP;
} }
// NOTE: this final partial substep can drift away from a real Bullet simulation however transform.setRotation(rotation);
// it only becomes significant for rapidly rotating objects
// (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec).
glm::quat dQ = computeBulletRotationStep(localAngularVelocity, dt);
rotation = glm::normalize(dQ * rotation);
bool success;
setOrientation(rotation, success, false);
} }
setLocalAngularVelocity(localAngularVelocity);
} }
if (hasLocalVelocity()) { glm::vec3 position = transform.getTranslation();
const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED =
// acceleration is in the global frame, so transform it into the local frame. KINEMATIC_LINEAR_SPEED_THRESHOLD * KINEMATIC_LINEAR_SPEED_THRESHOLD;
// TODO: Move this into SpatiallyNestable. if (isTranslating) {
bool success; glm::vec3 deltaVelocity = Vectors::ZERO;
Transform transform = getParentTransform(success);
glm::vec3 localAcceleration(glm::vec3::_null);
if (success) {
localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration();
} else {
localAcceleration = getAcceleration();
}
// linear damping // linear damping
glm::vec3 localVelocity = getLocalVelocity();
if (_damping > 0.0f) { if (_damping > 0.0f) {
localVelocity *= powf(1.0f - _damping, timeElapsed); deltaVelocity = (powf(1.0f - _damping, timeElapsed) - 1.0f) * linearVelocity;
#ifdef WANT_DEBUG
qCDebug(entities) << " damping:" << _damping;
qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity;
qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity);
#endif
} }
// integrate position forward const float MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED = 1.0e-4f; // 0.01 m/sec^2
glm::vec3 localPosition = getLocalPosition(); if (glm::length2(_acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) {
glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed; // yes acceleration
// acceleration is in world-frame but we need it in local-frame
glm::vec3 linearAcceleration = _acceleration;
bool success;
Transform parentTransform = getParentTransform(success);
if (success) {
linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration;
}
deltaVelocity += linearAcceleration * timeElapsed;
#ifdef WANT_DEBUG if (linearSpeedSquared < MIN_KINEMATIC_LINEAR_SPEED_SQUARED
qCDebug(entities) << " EntityItem::simulate()...."; && glm::length2(deltaVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED
qCDebug(entities) << " timeElapsed:" << timeElapsed; && glm::length2(linearVelocity + deltaVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) {
qCDebug(entities) << " old AACube:" << getMaximumAACube(); linearVelocity = Vectors::ZERO;
qCDebug(entities) << " old position:" << localPosition; } else {
qCDebug(entities) << " old velocity:" << localVelocity; // NOTE: we do NOT include the second-order acceleration term (0.5 * a * dt^2)
qCDebug(entities) << " old getAABox:" << getAABox(); // when computing the displacement because Bullet also ignores that term. Yes,
qCDebug(entities) << " newPosition:" << newPosition; // this is an approximation and it works best when dt is small.
qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition); position += timeElapsed * linearVelocity;
#endif linearVelocity += deltaVelocity;
localPosition = newLocalPosition;
// apply effective acceleration, which will be the same as gravity if the Entity isn't at rest.
localVelocity += localAcceleration * timeElapsed;
float speed = glm::length(localVelocity);
const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec
if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) {
setVelocity(ENTITY_ITEM_ZERO_VEC3);
if (setFlags && speed > 0.0f) {
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
} }
} else { } else {
setLocalPosition(localPosition); // no acceleration
setLocalVelocity(localVelocity); if (linearSpeedSquared < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) {
linearVelocity = Vectors::ZERO;
} else {
// NOTE: we don't use second-order acceleration term for linear displacement
// because Bullet doesn't use it.
position += timeElapsed * linearVelocity;
linearVelocity += deltaVelocity;
}
} }
#ifdef WANT_DEBUG
qCDebug(entities) << " new position:" << position;
qCDebug(entities) << " new velocity:" << velocity;
qCDebug(entities) << " new AACube:" << getMaximumAACube();
qCDebug(entities) << " old getAABox:" << getAABox();
#endif
} }
transform.setTranslation(position);
setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity);
return true;
} }
bool EntityItem::isMoving() const { bool EntityItem::isMoving() const {

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