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 <stdlib.h>
#include <string.h>
#include <thread>
#ifdef _WIN32
#include <math.h>
@ -577,15 +578,15 @@ void AudioMixer::domainSettingsRequestComplete() {
void AudioMixer::broadcastMixes() {
auto nodeList = DependencyManager::get<NodeList>();
int64_t nextFrame = 0;
QElapsedTimer timer;
timer.start();
int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
auto nextFrameTimestamp = p_high_resolution_clock::now();
auto timeToSleep = std::chrono::microseconds(0);
const int TRAILING_AVERAGE_FRAMES = 100;
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
int currentFrame { 1 };
int numFramesPerSecond { (int) ceil(AudioConstants::NETWORK_FRAMES_PER_SEC) };
while (!_isFinished) {
const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f;
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 PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
if (usecToSleep < 0) {
usecToSleep = 0;
if (timeToSleep.count() < 0) {
timeToSleep = std::chrono::microseconds(0);
}
_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;
bool hasRatioChanged = false;
@ -694,10 +695,11 @@ void AudioMixer::broadcastMixes() {
nodeList->sendPacket(std::move(mixPacket), *node);
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
if (nextFrame % FRAMES_PER_SECOND == 0) {
++currentFrame;
currentFrame %= numFramesPerSecond;
if (nodeData->shouldSendStats(currentFrame)) {
nodeData->sendAudioStreamStatsPackets(node);
}
@ -718,11 +720,14 @@ void AudioMixer::broadcastMixes() {
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) {
usleep(usecToSleep);
}
// sleep as long as we need until next frame, if we can
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
//
#include <random>
#include <QtCore/QDebug>
#include <QtCore/QJsonArray>
@ -26,7 +28,14 @@ AudioMixerClientData::AudioMixerClientData(const QUuid& nodeID) :
_outgoingMixedAudioSequenceNumber(0),
_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() {
@ -180,6 +189,10 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() {
}
}
bool AudioMixerClientData::shouldSendStats(int frameNumber) {
return frameNumber == _frameToSendStats;
}
void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) {
auto nodeList = DependencyManager::get<NodeList>();

View file

@ -58,6 +58,9 @@ public:
void incrementOutgoingMixedAudioSequenceNumber() { _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:
void injectorStreamFinished(const QUuid& streamIdentifier);
@ -72,6 +75,8 @@ private:
quint16 _outgoingMixedAudioSequenceNumber;
AudioStreamStats _downstreamAudioStreamStats;
int _frameToSendStats { 0 };
};
#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) :
ThreadedAssignment(message),
_broadcastThread(),
_lastFrameTimestamp(QDateTime::currentMSecsSinceEpoch()),
_trailingSleepRatio(1.0f),
_performanceThrottlingRatio(0.0f),
_sumListeners(0),
_numStatFrames(0),
_sumBillboardPackets(0),
_sumIdentityPackets(0)
_broadcastThread()
{
// make sure we hear about node kills so we can tell the other nodes
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
@ -51,7 +44,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket");
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "handleAvatarBillboardPacket");
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.
// 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.
// 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.
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;
@ -245,32 +242,13 @@ void AvatarMixer::broadcastAvatarData() {
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());
// we will also force a send of billboard or identity packet
// 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
if (otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0
&& (forceSend
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|| distribution(generator) < IDENTITY_SEND_PROBABILITY)) {
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
@ -385,7 +363,7 @@ void AvatarMixer::broadcastAvatarData() {
otherAvatar.doneEncoding(false);
});
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch();
_lastFrameTimestamp = p_high_resolution_clock::now();
}
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
if (avatar.hasIdentityChangedAfterParsing(message->getMessage())) {
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) {
DependencyManager::get<NodeList>()->processKillNode(*message);
}
@ -466,7 +430,6 @@ void AvatarMixer::sendStatsPacket() {
QJsonObject statsObject;
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["trailing_sleep_percentage"] = _trailingSleepRatio * 100;
@ -507,7 +470,6 @@ void AvatarMixer::sendStatsPacket() {
ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject);
_sumListeners = 0;
_sumBillboardPackets = 0;
_sumIdentityPackets = 0;
_numStatFrames = 0;
}

View file

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

View file

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

View file

@ -952,6 +952,24 @@ bool OctreeServer::readOptionInt(const QString& optionName, const QJsonObject& s
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 optionAvailable = false;
QString argName = "--" + optionName;
@ -1055,10 +1073,10 @@ void OctreeServer::readConfiguration() {
// 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
// skew for the individual server node
int clockSkew;
if (readOptionInt(QString("clockSkew"), settingsSectionObject, clockSkew)) {
qint64 clockSkew;
if (readOptionInt64(QString("clockSkew"), settingsSectionObject, 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

View file

@ -145,6 +145,7 @@ protected:
virtual OctreePointer createTree() = 0;
bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& 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);
void readConfiguration();
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { };

View file

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

View file

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

View file

@ -201,7 +201,7 @@ var toolBar = (function() {
}, true, false);
newModelButton = toolBar.addTool({
imageURL: toolIconUrl + "upload-01.svg",
imageURL: toolIconUrl + "model-01.svg",
subImage: {
x: 0,
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.");
}
selectionManager.clearSelections();
entityListTool.sendUpdate();
selectionManager.setSelections([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) {
if (menuItem == "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);
}
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();
}
}

View file

@ -63,7 +63,7 @@
}
body {
padding: 24px 12px 24px 12px;
padding: 21px 21px 21px 21px;
color: #afafaf;
background-color: #404040;
@ -164,6 +164,10 @@ tr.selected {
background-color: #00b4ef;
}
tr.selected + tr.selected {
border-top: 1px solid #2e2e2e;
}
th {
text-align: center;
word-wrap: nowrap;
@ -227,6 +231,15 @@ input.search {
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 {
background-color: #383838;
color: #afafaf;
@ -275,7 +288,9 @@ input[type=number]::-webkit-inner-spin-button:after {
content: "5";
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;
}
@ -294,8 +309,8 @@ input[type=button] {
vertical-align: top;
height: 28px;
min-width: 120px;
padding: 0px 12px;
margin-right: 8px;
padding: 0px 18px;
margin-right: 6px;
border-radius: 5px;
border: none;
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=);
}
.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 {
-webkit-touch-callout: 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;
width: 100%;
margin: 22px -12px 0 -12px;
padding: 14px 12px 0 12px;
margin: 21px -21px 0 -21px;
padding: 14px 21px 0 21px;
font-family: Raleway-Regular;
font-size: 12px;
color: #afafaf;
@ -414,12 +445,12 @@ input[type=checkbox]:checked + label:hover {
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;
}
.section-header:first-child {
margin-top: 0;
margin-top: -2px;
padding-top: 0;
background: none;
height: auto;
@ -435,11 +466,16 @@ input[type=checkbox]:checked + label:hover {
float: right;
position: absolute;
top: 4px;
right: 6px;
right: 13px;
}
.section-header[collapsed="true"] {
margin-bottom: -22px;
margin-bottom: -21px;
}
hr {
border: none;
padding-top: 2px;
}
.text-group[collapsed="true"] ~ .text-group,
@ -458,20 +494,25 @@ input[type=checkbox]:checked + label:hover {
.property {
display: table;
width: 100%;
margin-top: 22px;
min-height: 29px;
margin-top: 21px;
min-height: 28px;
}
.property.checkbox {
width: auto;
}
.property label {
.property label, .number label {
display: table-cell;
vertical-align: middle;
font-family: Raleway-SemiBold;
font-size: 14px;
}
.property label .unit, .number label .unit {
margin-left: 8px;
font-family: Raleway-Light;
font-size: 13px;
}
.value {
display: block;
@ -499,12 +540,14 @@ input[type=checkbox]:checked + label:hover {
float: left;
}
.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 {
float: left;
margin-bottom: 4px;
margin-left: 1px;
margin-bottom: 3px;
margin-top: -2px;
}
.number > input {
@ -519,13 +562,6 @@ input[type=checkbox]:checked + label:hover {
clear: both;
}
.unit {
padding-left: 4px;
vertical-align: top;
position: relative;
top: 5px;
}
.dropdown {
position: relative;
margin-bottom: -17px;
@ -544,10 +580,8 @@ input[type=checkbox]:checked + label:hover {
width: 172px;
height: 28px;
padding: 0 28px 0 12px;
color: #afafaf;
background: linear-gradient(#7d7d7d 20%, #686a68 100%);
position: relative;
}
.dropdown dl[dropped="true"] {
@ -606,6 +640,17 @@ input[type=checkbox]:checked + label:hover {
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 {
box-sizing: border-box;
@ -619,7 +664,7 @@ div.refresh input[type="button"] {
.color-picker {
box-sizing: border-box;
float: left;
margin-bottom: 12px;
margin-bottom: 21px;
width: 36px;
height: 36px;
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);
}
.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 {
float: left;
margin-top: 10px;
margin-left: 12px;
margin-left: 21px;
}
.rgb label + * {
clear: both;
}
.tuple {
width: 100%;
text-align: center;
}
.tuple div {
display: inline-block;
position: relative;
min-width: 120px;
min-height: 1px;
margin-right: 6px;
}
.tuple div:nth-child(1) {
float: left;
.tuple div:last-child {
margin-right: 0;
}
.tuple div:nth-child(2) {
}
.tuple div:nth-child(3) {
float: right;
.tuple label {
margin-right: -6px;
}
.rgb .tuple input {
@ -712,31 +761,49 @@ tuple, .blue:focus, .tuple .z:focus, .tuple .roll:focus {
}
.xyz .buttons input {
margin-top: 12px;
margin-top: 14px;
}
.xyz .buttons span {
word-wrap: nowrap;
white-space: nowrap;
}
.row input {
float: left;
.row .property {
width: auto;
display: inline-block;
margin-right: 6px;
}
.row input[type=button] {
margin-left: 8px;
.row .property:last-child {
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 {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background-color: #2e2e2e;
}
::-webkit-scrollbar-thumb {
background-color: #696969;
border: 2px solid #2e2e2e;
@ -760,7 +827,28 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
#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 {
@ -773,6 +861,11 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
position: relative; /* New positioning context. */
}
#entity-list .glyph {
font-family: HiFi-Glyphs;
font-size: 14px;
}
#search-area {
padding-right: 148px;
padding-bottom: 24px;
@ -785,6 +878,8 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
#radius-and-unit {
float: right;
margin-right: -148px;
position: relative;
top: -17px;
}
@ -798,17 +893,39 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
margin-top: 28px;
border-left: 2px solid #575757;
border-right: 2px solid #575757;
}
#entity-table-scroll, #entity-table {
background-color: #1c1c1c;
}
#entity-table {
margin-top: -28px;
margin-bottom: -18px;
table-layout: fixed;
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 {
@ -817,6 +934,42 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
border-top-left-radius: 7px;
border-top-right-radius: 7px;
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 {
@ -825,39 +978,6 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
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;
bottom: -21px;
left: 0;
@ -876,25 +996,92 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
}
#properties-list .property:first-child {
margin-top: 0;
#properties-header {
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 {
color: #000000;
background-color: #00b4ef;
}
input#property-parent-id {
width: 340px;
}
input#dimension-rescale-button {
min-width: 50px;
margin-left: 6px;
}
.color-set label, .color-set span {
display: block;
input#reset-to-natural-dimensions {
margin-right: 0;
}
.color-set span {
padding-top: 2px;
input#preview-camera-button {
margin-left: 1px;
margin-right: 0;
}
#animation-fps {
margin-top: 48px;
}

View file

@ -14,25 +14,34 @@
<script src="list.min.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="spinButtons.js"></script>
<script>
var entities = {};
var selectedEntities = [];
var currentSortColumn = 'type';
var currentSortOrder = 'asc';
var currentSortOrder = 'des';
var entityList = null;
var refreshEntityListTimer = null;
const ASCENDING_STRING = '&nbsp;&#x25BE;';
const DESCENDING_STRING = '&nbsp;&#x25B4;';
const ASCENDING_STRING = '&#x25BE;';
const DESCENDING_STRING = '&#x25B4;';
const LOCKED_GLYPH = "&#xe006;";
const VISIBLE_GLYPH = "&#xe007;";
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.
debugPrint = function (message) {
console.log(message);
};
function loaded() {
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();
elEntityTable = document.getElementById("entity-table");
elEntityTableBody = document.getElementById("entity-table-body");
elRefresh = document.getElementById("refresh");
elToggleLocked = document.getElementById("locked");
elToggleVisible = document.getElementById("visible");
elDelete = document.getElementById("delete");
elTeleport = document.getElementById("teleport");
elRadius = document.getElementById("radius");
@ -50,6 +59,12 @@
document.getElementById("entity-url").onclick = function() {
setSortColumn('url');
};
document.getElementById("entity-locked").onclick = function () {
setSortColumn('locked');
};
document.getElementById("entity-visible").onclick = function () {
setSortColumn('visible');
};
function onRowClicked(clickEvent) {
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) {
var urlParts = url.split('/');
var filename = urlParts[urlParts.length - 1];
entityList.add([{ id: id, name: name, type: type, url: filename }], function(items) {
entityList.add([{ id: id, name: name, type: type, url: filename, locked: locked, visible: visible }],
function (items) {
var currentElement = items[0].elm;
var id = items[0]._values.id;
entities[id] = {
id: id,
name: name,
el: currentElement,
item: items[0],
item: items[0]
};
currentElement.setAttribute('id', 'entity_' + id);
currentElement.setAttribute('title', url);
@ -128,7 +144,7 @@
refreshEntityListTimer = setTimeout(refreshEntityListObject, 50);
} else {
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'),
type: document.querySelector('#entity-type .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) {
if (currentSortColumn == column) {
currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc";
} else {
elSortOrder[currentSortColumn].style.display = 'none';
elSortOrder[column].style.display = 'inline';
elSortOrder[currentSortColumn].innerHTML = "";
currentSortColumn = column;
currentSortOrder = "asc";
}
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING;
entityList.sort(currentSortColumn, { order: currentSortOrder });
}
setSortColumn('type');
function refreshEntities() {
clearEntities();
@ -191,13 +209,24 @@
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;
}
elRefresh.onclick = function() {
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' }));
}
elDelete.onclick = function() {
@ -238,11 +267,14 @@
var newEntities = data.entities;
if (newEntities.length == 0) {
elNoEntitiesMessage.style.display = "block";
elFooter.firstChild.nodeValue = "0 entities found";
} else {
elNoEntitiesMessage.style.display = "none";
for (var i = 0; i < newEntities.length; i++) {
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);
resize();
@ -254,15 +286,23 @@
function resize() {
// 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 ths = document.querySelectorAll("#entity-table thead th");
if (tds.length >= ths.length) {
// Update the widths of the header cells to match the body
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();
});
augmentSpinButtons();
// 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) {
event.preventDefault();
@ -280,14 +322,21 @@
<body onload='loaded();'>
<div id="entity-list-header">
<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" class="red" id="delete" value="Delete" />
</div>
<div id="entity-list">
<div id="search-area">
<input type="text" class="search" id="filter" placeholder="Filter" />
<span id="radius-and-unit"><input type="number" id="radius" value="100" /><span class="unit">m</span></span>
<span class="icon-input"><input type="text" class="search" id="filter" placeholder="Filter" /><span>Y</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 id="entity-table-scroll">
<table id="entity-table">
@ -295,12 +344,16 @@
<col span="1" id="col-type" />
<col span="1" id="col-name" />
<col span="1" id="col-url" />
<col span="1" id="col-locked" />
<col span="1" id="col-visible" />
</colgroup>
<thead>
<tr>
<th id="entity-type" data-sort="type">Type <span class="sort-order" style="display: inline">&nbsp;&#x25BE;</span></th>
<th id="entity-name" data-sort="type">Name <span class="sort-order" style="display: none">&nbsp;&#x25BE;</span></th>
<th id="entity-url" data-sort="url">File <span class="sort-order" style="display: none">&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"></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>
</thead>
<tbody class="list" id="entity-table-body">
@ -308,12 +361,14 @@
<td class="type">Type</td>
<td class="name">Name</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>
</tbody>
<tfoot>
<tr>
<td id="footer-text" colspan="3">Footer text</td>
<td id="footer-text" colspan="5"> </td>
</tr>
</tfoot>
</table>

View file

@ -17,10 +17,25 @@
<script src="colpick.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="spinButtons.js"></script>
<script>
var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0;
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) {
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) {
for (var i = 0; i < els.length; i++) {
els[i].style.display = (show) ? 'table' : 'none';
@ -297,6 +325,7 @@
var allSections = [];
var elID = document.getElementById("property-id");
var elType = document.getElementById("property-type");
var elTypeIcon = document.getElementById("type-icon");
var elName = document.getElementById("property-name");
var elLocked = document.getElementById("property-locked");
var elVisible = document.getElementById("property-visible");
@ -368,7 +397,7 @@
var elReloadScriptButton = document.getElementById("reload-script-button");
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 elColorRed = document.getElementById("property-color-red");
var elColorGreen = document.getElementById("property-color-green");
@ -474,32 +503,40 @@
data = JSON.parse(data);
if (data.type == "update") {
if (data.selections.length == 0) {
elType.innerHTML = "<i>No Selection</i>";
elTypeIcon.style.display = "none";
elType.innerHTML = "<i>No selection</i>";
elID.innerHTML = "";
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
disableProperties();
} else if (data.selections.length > 1) {
var selections = data.selections;
var ids = [];
var types = {};
var numTypes = 0;
for (var i = 0; i < selections.length; i++) {
ids.push(selections[i].id);
var type = selections[i].properties.type;
if (types[type] === undefined) {
types[type] = 0;
numTypes += 1;
}
types[type]++;
}
elID.innerHTML = ids.join("<br>");
var typeStrs = [];
for (type in types) {
typeStrs.push(type + " (" + types[type] + ")");
var type;
if (numTypes === 1) {
type = selections[0].properties.type;
} else {
type = "Multiple";
}
elType.innerHTML = typeStrs.join(", ");
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
elType.innerHTML = type + " (" + data.selections.length + ")";
elTypeIcon.innerHTML = ICON_FOR_TYPE[type];
elTypeIcon.style.display = "inline-block";
elID.innerHTML = ids.join("<br>");
disableProperties();
} else {
var activeElement = document.activeElement;
@ -516,14 +553,16 @@
elID.innerHTML = properties.id;
elType.innerHTML = properties.type;
elTypeIcon.innerHTML = ICON_FOR_TYPE[properties.type];
elTypeIcon.style.display = "inline-block";
elLocked.checked = properties.locked;
if (properties.locked) {
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
disableProperties();
elLocked.removeAttribute('disabled');
} else {
enableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
enableProperties();
}
@ -624,13 +663,17 @@
}
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;
elColorGreen.value = properties.color.green;
elColorBlue.value = properties.color.blue;
elColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
} else {
elColorSection.style.display = 'none';
for (var i = 0; i < elColorSections.length; i++) {
elColorSections[i].style.display = 'none';
}
}
if (properties.type == "Model") {
@ -862,10 +905,10 @@
elColorRed.addEventListener('change', colorChangeFunction);
elColorGreen.addEventListener('change', colorChangeFunction);
elColorBlue.addEventListener('change', colorChangeFunction);
$('#property-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
colorPickers.push($('#property-color').colpick({
colorScheme: 'dark',
layout: 'hex',
color: '000000',
onShow: function (colpick) {
$('#property-color').attr('active', 'true');
},
@ -873,12 +916,12 @@
$('#property-color').attr('active', 'false');
},
onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).css('background-color', '#' + hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
}
})
}));
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
var lightColorChangeFunction = createEmitColorPropertyUpdateFunction(
@ -886,10 +929,10 @@
elLightColorRed.addEventListener('change', lightColorChangeFunction);
elLightColorGreen.addEventListener('change', lightColorChangeFunction);
elLightColorBlue.addEventListener('change', lightColorChangeFunction);
$('#property-light-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
colorPickers.push($('#property-light-color').colpick({
colorScheme: 'dark',
layout: 'hex',
color: '000000',
onShow: function (colpick) {
$('#property-light-color').attr('active', 'true');
},
@ -897,11 +940,11 @@
$('#property-light-color').attr('active', 'false');
},
onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).css('background-color', '#' + hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
}
})
}));
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity', 1));
elLightFalloffRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('falloffRadius', 1));
@ -933,7 +976,7 @@
elTextTextColorRed.addEventListener('change', textTextColorChangeFunction);
elTextTextColorGreen.addEventListener('change', textTextColorChangeFunction);
elTextTextColorBlue.addEventListener('change', textTextColorChangeFunction);
$('#property-text-text-color').colpick({
colorPickers.push($('#property-text-text-color').colpick({
colorScheme:'dark',
layout:'hex',
color: '000000',
@ -949,14 +992,14 @@
$(el).attr('active', 'false');
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
}
});
}));
var textBackgroundColorChangeFunction = createEmitColorPropertyUpdateFunction(
'backgroundColor', elTextBackgroundColorRed, elTextBackgroundColorGreen, elTextBackgroundColorBlue);
elTextBackgroundColorRed.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction);
$('#property-text-background-color').colpick({
colorPickers.push($('#property-text-background-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
@ -971,10 +1014,10 @@
$(el).colpickHide();
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
}
});
}));
elZoneStageSunModelEnabled.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage','sunModelEnabled'));
$('#property-zone-key-light-color').colpick({
colorPickers.push($('#property-zone-key-light-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
@ -989,7 +1032,7 @@
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
}
});
}));
var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight','color', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
@ -1015,7 +1058,7 @@
elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction);
$('#property-zone-skybox-color').colpick({
colorPickers.push($('#property-zone-skybox-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
@ -1030,7 +1073,7 @@
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
}
});
}));
elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url'));
@ -1138,7 +1181,7 @@
};
// Textarea scollbars
// Textarea scrollbars
var elTextareas = document.getElementsByTagName("TEXTAREA");
var textareaOnChangeEvent = function (event) {
@ -1252,6 +1295,8 @@
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
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
@ -1262,30 +1307,32 @@
<body onload='loaded();'>
<div id="properties-list">
<div id="type" class="property value">
<label>Type:</label>
<span id="property-type"></span>
</div>
<div id="id" class="property value">
<label>ID:</label>
<span id="property-id" class="selectable"></span>
<div id="properties-header">
<div id="type" class="property value">
<span id="type-icon"></span><label id="property-type"><i>No selection</i></label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-locked">
<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>
<hr />
<div class="property text">
<label for="property-name">Name</label>
<input type="text" id="property-name">
</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">
<label for="property-user-data">User data</label>
<textarea id="property-user-data"></textarea>
</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">
@ -1305,7 +1352,35 @@
<label>Spatial</label><span>M</span>
</div>
<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><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>
@ -1317,40 +1392,28 @@
<input type="button" id="preview-camera-button" value="Preview Camera">
</div>
</div>
<div class="spatial-group property text">
<label for="property-parent-id">Parent ID</label>
<input type="text" id="property-parent-id">
</div>
<div class="spatial-group property number">
<label for="property-parent-joint-index">Parent joint index</label>
<input type="number" id="property-parent-joint-index">
<div class="spatial-group row">
<div class="property text">
<label for="property-parent-id">Parent ID</label>
<input type="text" id="property-parent-id">
</div>
<div class="property number">
<label for="property-parent-joint-index">Parent joint index</label>
<input type="number" id="property-parent-joint-index">
</div>
</div>
<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><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="z" id="property-reg-z" step="0.1"><label for="property-reg-z">Z:</label></div>
</div>
</div>
<div class="spatial-group property xyz">
<label>Dimensions</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</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>
<hr class="spatial-group poly-vox-section" />
<div class="spatial-group poly-vox-section property xyz">
<label>Voxel volume size <span class="unit">m</span></label>
<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="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>
<input type="text" id="property-z-texture-url">
</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">
<label>Physical</label><span>M</span>
</div>
<div class="physical-group property xyz">
<label>Linear velocity</label>
<label>Linear velocity <span class="unit">m/s</span></label>
<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="y" id="property-lvel-y"><label for="property-lvel-y">Y:</label></div>
@ -1403,8 +1458,9 @@
<label>Linear damping</label>
<input type="number" id="property-ldamping">
</div>
<hr class="physical-group" />
<div class="physical-group property pyr">
<label>Angular velocity</label>
<label>Angular velocity <span class="unit">deg/s</span></label>
<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="yaw" id="property-avel-y"><label for="property-avel-y">Yaw:</label></div>
@ -1415,6 +1471,7 @@
<label>Angular damping</label>
<input type="number" id="property-adamping">
</div>
<hr class="physical-group" />
<div class="physical-group property gen">
<div class="tuple">
<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>
</div>
<hr class="physical-group" />
<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><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>
@ -1431,14 +1489,15 @@
</div>
</div>
<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><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="z" id="property-lacc-z"><label for="property-lacc-z">Z:</label></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>
<label>Entity color</label>
<div class="tuple">
@ -1461,64 +1520,72 @@
<label for="property-dynamic">Dynamic</label>
</div>
<div class="behavior-group sub-section-header">
<span>Collides With</span>
</div>
<div class="behavior-group checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-collide-static">
<label for="property-collide-static">Static entities</label>
<div class="behavior-group two-column">
<div class="column">
<div class="sub-section-header">
<span>Collides With</span>
</div>
<div class="checkbox-sub-props">
<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 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>
<hr class="behavior-group" />
<div class="behavior-group property url ">
<label for="property-collision-sound-url">Collision sound URL</label>
<input type="text" id="property-collision-sound-url">
</div>
<div class="behavior-group property number">
<label>Lifetime</label>
<label>Lifetime <span class="unit">s</span></label>
<input type="number" id="property-lifetime">
</div>
<hr class="behavior-group" />
<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
@ -1551,33 +1618,47 @@
<label for="property-compound-shape-url">Compound shape URL</label>
<input type="text" id="property-compound-shape-url">
</div>
<hr class="model-group model-section" />
<div class="model-group model-section property url ">
<label for="property-model-animation-url">Animation URL</label>
<input type="text" id="property-model-animation-url">
</div>
<div class="model-group model-section property checkbox">
<input type="checkbox" id="property-model-animation-playing">
<label for="property-model-animation-playing">Animation playing</label>
</div>
<div class="model-group model-section property number">
<label>Animation FPS</label>
<input type="number" id="property-model-animation-fps">
</div>
<div class="model-group model-section property number">
<div class="tuple">
<div><label>Animation frame</label><input type="number" id="property-model-animation-frame"></div>
<div><label>First frame</label><input type="number" id="property-model-animation-first-frame"></div>
<div><label>Last frame</label><input type="number" id="property-model-animation-last-frame"></div>
<div class="model-group model-section two-column">
<div class="column">
<div class="property checkbox">
<input type="checkbox" id="property-model-animation-playing">
<label for="property-model-animation-playing">Animation playing</label>
</div>
<div class="property checkbox indent">
<input type="checkbox" id="property-model-animation-loop">
<label for="property-model-animation-loop">Animation loop</label>
</div>
<div class="property checkbox indent">
<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 class="model-group model-section property checkbox">
<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>
<hr class="model-group model-section" />
<div class="model-group model-section property textarea">
<label for="property-model-textures">Textures</label>
<textarea id="property-model-textures"></textarea>
@ -1596,7 +1677,7 @@
<input type="text" id="property-text-text">
</div>
<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">
</div>
<div class="text-group text-section property rgb">
@ -1645,8 +1726,8 @@
</div>
<div class="zone-group zone-section keylight-section property gen">
<div class="tuple">
<div><label>Light altitude</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 altitude <span class="unit">deg</span></label><input type="number" id="property-zone-key-light-direction-x"></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>
@ -1664,9 +1745,9 @@
</div>
<div class="zone-group zone-section stage-section property gen">
<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>Stage longitude</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>Latitude <span class="unit">deg</span></label><input type="number" id="property-zone-stage-latitude" min="-90" max="90" 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>Altitude <span class="unit">m</span></label><input type="number" id="property-zone-stage-altitude" step="1"></div>
</div>
</div>
<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="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>Stage hour</label><input type="number" id="property-zone-stage-hour" min="0" max="24" step="0.5"></div>
<div><label>Day of year</label><input type="number" id="property-zone-stage-day" min="0" max="365" step="1"></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>
@ -1735,7 +1816,7 @@
<div class="light-group light-section property gen">
<div class="tuple">
<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>

View file

@ -11,21 +11,15 @@
<html>
<head>
<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="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script>
function loaded() {
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");
elMinorSpacing = document.getElementById("minor-spacing");
elMajorSpacing = document.getElementById("major-spacing");
@ -37,12 +31,12 @@
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.origin) {
var origin = data.origin;
elPosY.value = origin.y.toFixed(2);
elPosY.value = origin.y;
}
if (data.minorGridEvery !== undefined) {
elMinorSpacing.value = data.minorGridEvery;
}
@ -73,7 +67,6 @@
minorGridEvery: elMinorSpacing.value,
majorGridEvery: elMajorSpacing.value,
gridColor: gridColor,
colorIndex: gridColorIndex,
snapToGrid: elSnapToGrid.checked,
visible: elHorizontalGridVisible.checked,
}));
@ -100,23 +93,52 @@
}));
});
var gridColorBox = document.getElementById('grid-color');
for (var i = 0; i < gridColors.length; i++) {
var colors = gridColors[i];
var box = document.createElement('div');
box.setAttribute('class', 'color-box');
box.style.background = 'rgb(' + colors.red + ', ' + colors.green + ', ' + colors.blue + ')';
document.getElementById("grid-colors").appendChild(box);
box.addEventListener("click", function(color, index) {
return function() {
gridColor = color;
gridColorIndex = index;
emitUpdate();
}
}({ red: colors.red, green: colors.green, blue: colors.blue }, i));
var gridColor = { red: 255, green: 255, blue: 255 };
var elColor = document.getElementById("grid-color");
var elColorRed = document.getElementById("grid-color-red");
var elColorGreen = document.getElementById("grid-color-green");
var elColorBlue = document.getElementById("grid-color-blue");
elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
elColorRed.value = gridColor.red;
elColorGreen.value = gridColor.green;
elColorBlue.value = gridColor.blue;
var colorChangeFunction = function () {
gridColor = { red: elColorRed.value, green: elColorGreen.value, blue: elColorBlue.value };
elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
emitUpdate();
};
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' }));
});
@ -146,29 +168,28 @@
<div class="property">
<div class="number">
<label>Major grid size</label>
<span>
<input type="number" id="major-spacing" min="1" step="1" /><span class="unit">m</span>
</span>
<label for="major-spacing">Major grid size <span class="unit">m</span></label>
<input type="number" id="major-spacing" min="1" step="1" />
</div>
<div class="number">
<label>Minor grid size</label>
<span>
<input type="number" id="minor-spacing" min="0.2" step="0.2" /><span class="unit">m</span>
</span>
<label for="minor-spacing">Minor grid size <span class="unit">m</span></label>
<input type="number" id="minor-spacing" min="0.2" step="0.2" />
</div>
</div>
<div class="property number">
<label>Position (Y axis)</label>
<span>
<input type="number" id="horiz-y" step="0.1" /><span class="unit">m</span>
</span>
<label for="horiz-y">Position (Y axis) <span class="unit">m</span></label>
<input type="number" id="horiz-y" step="0.1" />
</div>
<div class="property color-set">
<div class="property rgb">
<div id="grid-color" class="color-picker"></div>
<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 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,
type: properties.type,
url: properties.type == "Model" ? properties.modelURL : "",
locked: properties.locked,
visible: properties.visible
});
}
@ -99,6 +101,10 @@ EntityListTool = function(opts) {
}
} else if (data.type == "delete") {
deleteSelectedEntities();
} else if (data.type == "toggleLocked") {
toggleSelectedEntitiesLocked();
} else if (data.type == "toggleVisible") {
toggleSelectedEntitiesVisible();
} else if (data.type === "radius") {
searchRadius = data.radius;
that.sendUpdate();

View file

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

View file

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

View file

@ -3,35 +3,18 @@ float aspect(vec2 v) {
}
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.y = 1.0 - uv.y;
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));
return texture(iChannel0, uv).rgb;
}
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {

View file

@ -42,7 +42,7 @@ function createItems(count) {
name: TEST_ENTITY_NAME,
position: AUSTIN.avatarRelativePosition(AUSTIN.randomPositionXZ({ x: 0, y: 0, z: -2 }, RADIUS)),
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,
userData: JSON.stringify({
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({
title: 'Render Stats',
source: qml,
width: 300,
height: 200
width: 320,
height: 720
});
window.setPosition(500, 50);
window.closed.connect(function() { Script.stop(); });

View file

@ -241,7 +241,6 @@ Item {
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",
"type": "clip",
"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,
"endFrame": 0.0,
"timeScale": 1.0,
@ -157,7 +157,7 @@
"id": "rightHandGraspClosed",
"type": "clip",
"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,
"endFrame": 0.0,
"timeScale": 1.0,
@ -205,7 +205,7 @@
"id": "leftHandGraspOpen",
"type": "clip",
"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,
"endFrame": 0.0,
"timeScale": 1.0,
@ -217,7 +217,7 @@
"id": "leftHandGraspClosed",
"type": "clip",
"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,
"endFrame": 10.0,
"timeScale": 1.0,
@ -495,7 +495,7 @@
"id": "idleStand",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
"url": "animations/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.0,
"timeScale": 1.0,
@ -507,7 +507,7 @@
"id": "idleTalk",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/talk.fbx",
"url": "animations/talk.fbx",
"startFrame": 0.0,
"endFrame": 801.0,
"timeScale": 1.0,
@ -532,7 +532,7 @@
"id": "walkFwdShort",
"type": "clip",
"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,
"endFrame": 39.0,
"timeScale": 1.0,
@ -544,7 +544,7 @@
"id": "walkFwdNormal",
"type": "clip",
"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,
"endFrame": 35.0,
"timeScale": 1.0,
@ -556,7 +556,7 @@
"id": "walkFwdRun",
"type": "clip",
"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,
"endFrame": 21.0,
"timeScale": 1.0,
@ -570,7 +570,7 @@
"id": "idleToWalkFwd",
"type": "clip",
"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,
"endFrame": 19.0,
"timeScale": 1.0,
@ -593,7 +593,7 @@
"id": "walkBwdShort",
"type": "clip",
"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,
"endFrame": 38.0,
"timeScale": 1.0,
@ -605,7 +605,7 @@
"id": "walkBwdNormal",
"type": "clip",
"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,
"endFrame": 36.0,
"timeScale": 1.0,
@ -619,7 +619,7 @@
"id": "turnLeft",
"type": "clip",
"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,
"endFrame": 28.0,
"timeScale": 1.0,
@ -631,7 +631,7 @@
"id": "turnRight",
"type": "clip",
"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,
"endFrame": 30.0,
"timeScale": 1.0,
@ -654,7 +654,7 @@
"id": "strafeLeftShort",
"type": "clip",
"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,
"endFrame": 28.0,
"timeScale": 1.0,
@ -666,7 +666,7 @@
"id": "strafeLeftNormal",
"type": "clip",
"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,
"endFrame": 30.0,
"timeScale": 1.0,
@ -691,7 +691,7 @@
"id": "strafeRightShort",
"type": "clip",
"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,
"endFrame": 28.0,
"timeScale": 1.0,
@ -703,7 +703,7 @@
"id": "strafeRightNormal",
"type": "clip",
"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,
"endFrame": 30.0,
"timeScale": 1.0,
@ -717,7 +717,7 @@
"id": "fly",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx",
"url": "animations/fly.fbx",
"startFrame": 1.0,
"endFrame": 80.0,
"timeScale": 1.0,
@ -729,7 +729,7 @@
"id": "takeoffStand",
"type": "clip",
"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,
"endFrame": 25.0,
"timeScale": 1.0,
@ -741,7 +741,7 @@
"id": "takeoffRun",
"type": "clip",
"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,
"endFrame": 2.5,
"timeScale": 0.01,
@ -761,7 +761,7 @@
"id": "inAirStandPreApex",
"type": "clip",
"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,
"endFrame": 0.0,
"timeScale": 0.0,
@ -773,7 +773,7 @@
"id": "inAirStandApex",
"type": "clip",
"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,
"endFrame": 1.0,
"timeScale": 1.0,
@ -785,7 +785,7 @@
"id": "inAirStandPostApex",
"type": "clip",
"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,
"endFrame": 2.0,
"timeScale": 1.0,
@ -807,7 +807,7 @@
"id": "inAirRunPreApex",
"type": "clip",
"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,
"endFrame": 0.0,
"timeScale": 0.0,
@ -819,7 +819,7 @@
"id": "inAirRunApex",
"type": "clip",
"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,
"endFrame": 6.0,
"timeScale": 1.0,
@ -831,7 +831,7 @@
"id": "inAirRunPostApex",
"type": "clip",
"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,
"endFrame": 11.0,
"timeScale": 1.0,
@ -845,7 +845,7 @@
"id": "landStandImpact",
"type": "clip",
"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,
"endFrame": 6.0,
"timeScale": 1.0,
@ -857,7 +857,7 @@
"id": "landStand",
"type": "clip",
"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,
"endFrame": 28.0,
"timeScale": 1.0,
@ -869,7 +869,7 @@
"id": "landRun",
"type": "clip",
"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,
"endFrame": 6.0,
"timeScale": 0.65,
@ -891,7 +891,7 @@
"id": "userAnimA",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
"url": "animations/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.0,
"timeScale": 1.0,
@ -903,7 +903,7 @@
"id": "userAnimB",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
"url": "animations/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.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
scale = 1
filename = defaultAvatar_full/defaultAvatar_full.fbx
texdir = defaultAvatar_full/textures
joint = jointRightHand = RightHand
joint = jointNeck = Head
filename = being_of_light/being_of_light.fbx
texdir = being_of_light/textures
joint = jointRoot = Hips
joint = jointLeftHand = LeftHand
joint = jointHead = HeadTop_End
joint = jointLean = Spine
joint = jointLeftHand = LeftHand
joint = jointEyeLeft = LeftEye
joint = jointRightHand = RightHand
joint = jointNeck = Head
joint = jointEyeRight = RightEye
freeJoint = LeftArm
freeJoint = LeftForeArm
freeJoint = RightArm
freeJoint = RightForeArm
bs = MouthFrown_R = Mouth.MouthFrown_R = 1
bs = EyeOpen_L = Leye1.EyeOpen_L = 1
bs = LipsLowerDown_L = Mouth.LipsLowerDown = 0.5
bs = LipsStretch_L = Mouth.LipsStretch_L = 1
bs = MouthLeft = Mouth.MouthLeft = 1
bs = MouthSmile_L = Mouth.MouthSmile_L = 1
bs = Sneer_R = Mouth.Sneer = 0.61
bs = LipsPucker = Mouth.LipsPucker = 1
bs = EyeOpen_R = Reye1.EyeOut_R = 1
bs = LipsLowerDown_R = Mouth.LipsLowerDown = 0.43
bs = LipsStretch_R = Mouth.LipsStretch_R = 1
bs = MouthSmile_R = Mouth.MouthSmile_R = 1
bs = LipsFunnel = Mouth.LipsFunnel = 1
bs = EyeUp_L = Leye1.EyeUp_L = 1
bs = MouthDimple_L = Mouth.MouthDimple_L = 1
bs = Puff = Mouth.Puff = 1
bs = EyeIn_L = Leye1.EyeIn_L = 1
bs = EyeUp_R = Reye1.EyeUp_R = 0.99
bs = MouthDimple_R = Mouth.MouthDimple_R = 1
bs = MouthRight = Mouth.MouthRight = 1
bs = EyeOut_L = Leye1.EyeOut_L = 1
bs = JawOpen = Mouth.JawOpen = 1
bs = EyeIn_R = Reye1.EyeIn_R = 1
bs = BrowsD_L = Leye1.BrowsD_L = 1
bs = EyeDown_L = Leye1.EyeDown_L = 1
bs = EyeBlink_L = Leye1.EyeBlink_L = 1
bs = EyeOut_R = Reye1.EyeOut_R = 1
bs = LipsUpperUp_L = Mouth.LipsUpperUp = 0.49
bs = MouthFrown_L = Mouth.MouthFrown_L = 1
bs = EyeDown_R = Reye1.EyeDown_R = 1
bs = BrowsD_R = Reye1.BrowsD_R = 1
bs = EyeBlink_R = Reye1.EyeBlink_R = 1
bs = LipsUpperUp_R = Mouth.LipsUpperUp = 0.47
bs = Sneer_L = Mouth.Sneer = 0.5
jointIndex = headphone = 7
jointIndex = LeftUpLeg = 15
jointIndex = Spine = 20
jointIndex = LeftArm = 32
jointIndex = Head = 40
jointIndex = RightUpLeg = 10
jointIndex = hair = 5
jointIndex = Spine1 = 21
jointIndex = RightHandIndex1 = 27
jointIndex = Spine2 = 22
jointIndex = RightHandIndex2 = 28
jointIndex = RightHandIndex3 = 29
jointIndex = RightHandIndex4 = 30
jointIndex = RightToe_End = 14
jointIndex = shield = 4
jointIndex = LeftHandIndex1 = 35
jointIndex = LeftHandIndex2 = 36
jointIndex = RightHand = 26
jointIndex = LeftHandIndex3 = 37
jointIndex = LeftHandIndex4 = 38
jointIndex = LeftShoulder = 31
jointIndex = LeftHand = 34
jointIndex = RightForeArm = 25
jointIndex = RightLeg = 11
jointIndex = RightFoot = 12
jointIndex = mouth = 1
jointIndex = LeftToe_End = 19
jointIndex = Reye = 2
jointIndex = Hips = 9
jointIndex = RightToeBase = 13
jointIndex = HeadTop_End = 41
jointIndex = LeftFoot = 17
jointIndex = RightShoulder = 23
jointIndex = LeftLeg = 16
jointIndex = Leye = 3
jointIndex = LeftForeArm = 33
jointIndex = face = 0
jointIndex = body = 8
jointIndex = LeftToeBase = 18
jointIndex = RightArm = 24
jointIndex = top1 = 6
jointIndex = Neck = 39
rx = 0
ry = 0
rz = 0
tx = 0
ty = 0
tz = 0
bs = MouthFrown_L = Frown_Left = 1
bs = MouthLeft = Midmouth_Left = 1
bs = BrowsU_R = BrowsUp_Right = 1
bs = ChinUpperRaise = UpperLipUp_Right = 0.5
bs = ChinUpperRaise = UpperLipUp_Left = 0.5
bs = MouthSmile_R = Smile_Right = 1
bs = MouthDimple_L = Smile_Left = 0.25
bs = EyeBlink_L = Blink_Left = 1
bs = BrowsD_L = BrowsDown_Left = 1
bs = MouthFrown_R = Frown_Right = 1
bs = MouthDimple_R = Smile_Right = 0.25
bs = Sneer = Squint_Right = 0.5
bs = Sneer = Squint_Left = 0.5
bs = Sneer = NoseScrunch_Right = 0.75
bs = Sneer = NoseScrunch_Left = 0.75
bs = EyeSquint_L = Squint_Left = 1
bs = EyeBlink_R = Blink_Right = 1
bs = JawLeft = JawRotateY_Left = 0.5
bs = BrowsD_R = BrowsDown_Right = 1
bs = EyeSquint_R = Squint_Right = 1
bs = Puff = CheekPuff_Right = 1
bs = Puff = CheekPuff_Left = 1
bs = LipsUpperClose = UpperLipIn = 1
bs = JawOpen = MouthOpen = 0.69999999999999996
bs = LipsUpperUp = UpperLipUp_Right = 0.69999999999999996
bs = LipsUpperUp = UpperLipUp_Left = 0.69999999999999996
bs = LipsLowerDown = LowerLipDown_Right = 0.69999999999999996
bs = LipsLowerDown = LowerLipDown_Left = 0.69999999999999996
bs = LipsLowerOpen = LowerLipOut = 1
bs = EyeOpen_L = EyesWide_Left = 1
bs = LipsPucker = MouthNarrow_Right = 1
bs = LipsPucker = MouthNarrow_Left = 1
bs = EyeOpen_R = EyesWide_Right = 1
bs = JawRight = Jaw_Right = 1
bs = MouthRight = Midmouth_Right = 1
bs = ChinLowerRaise = Jaw_Up = 1
bs = LipsUpperOpen = UpperLipOut = 1
bs = BrowsU_C = BrowsUp_Right = 1
bs = BrowsU_C = BrowsUp_Left = 1
bs = JawFwd = JawForeward = 1
bs = BrowsU_L = BrowsUp_Left = 1
bs = MouthSmile_L = Smile_Left = 1
bs = LipsLowerClose = LowerLipIn = 1
bs = LipsFunnel = TongueUp = 1
bs = LipsFunnel = MouthWhistle_NarrowAdjust_Right = 0.5
bs = LipsFunnel = MouthWhistle_NarrowAdjust_Left = 0.5
bs = LipsFunnel = MouthNarrow_Right = 1
bs = LipsFunnel = MouthNarrow_Left = 1
bs = LipsFunnel = Jaw_Down = 0.35999999999999999
bs = LipsFunnel = JawForeward = 0.39000000000000001
jointIndex = LeftHandIndex1 = 50
jointIndex = LeftHandIndex2 = 51
jointIndex = LeftHandIndex3 = 52
jointIndex = LeftHandIndex4 = 53
jointIndex = Spine1 = 12
jointIndex = Spine2 = 13
jointIndex = RightHandThumb1 = 18
jointIndex = RightHandThumb2 = 19
jointIndex = RightHandThumb3 = 20
jointIndex = RightHandThumb4 = 21
jointIndex = LeftFoot = 8
jointIndex = LeftForeArm = 40
jointIndex = Neck = 62
jointIndex = Head = 63
jointIndex = Hips = 0
jointIndex = RightHandPinky1 = 30
jointIndex = RightHandPinky2 = 31
jointIndex = RightHandPinky3 = 32
jointIndex = RightHandPinky4 = 33
jointIndex = RightLeg = 2
jointIndex = RightForeArm = 16
jointIndex = LeftHandRing1 = 46
jointIndex = LeftHandRing2 = 47
jointIndex = LeftHandRing3 = 48
jointIndex = LeftHandRing4 = 49
jointIndex = LeftHandThumb1 = 54
jointIndex = LeftHandThumb2 = 55
jointIndex = LeftHandThumb3 = 56
jointIndex = LeftHandThumb4 = 57
jointIndex = HeadTop_End = 66
jointIndex = LeftUpLeg = 6
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 {
id: assetDirectory
name: "Asset Directory"
spacing: hifi.dimensions.contentSpacing.y
isFirst: true
HifiControls.VerticalSpacer {}
Row {
id: buttonRow
anchors.left: parent.left
@ -343,8 +344,7 @@ Window {
glyph: hifi.glyphs.reload
color: hifi.buttons.white
colorScheme: root.colorScheme
height: 26
width: 26
width: hifi.dimensions.controlLineHeight
onClicked: root.reload()
}
@ -353,7 +353,6 @@ Window {
text: "ADD TO WORLD"
color: hifi.buttons.white
colorScheme: root.colorScheme
height: 26
width: 120
enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100))
@ -365,7 +364,6 @@ Window {
text: "RENAME"
color: hifi.buttons.white
colorScheme: root.colorScheme
height: 26
width: 80
onClicked: root.renameFile()
@ -378,7 +376,6 @@ Window {
text: "DELETE"
color: hifi.buttons.red
colorScheme: root.colorScheme
height: 26
width: 80
onClicked: root.deleteFile()
@ -419,7 +416,7 @@ Window {
id: treeView
anchors.top: assetDirectory.bottom
anchors.bottom: uploadSection.top
anchors.margins: 12
anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border
anchors.left: parent.left
anchors.right: parent.right
@ -448,7 +445,7 @@ Window {
name: "Upload A File"
spacing: hifi.dimensions.contentSpacing.y
anchors.bottom: parent.bottom
height: 92
height: 95
Item {
height: parent.height

View file

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

View file

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

View file

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

View file

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

View file

@ -28,7 +28,7 @@ SpinBox {
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
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
@ -51,12 +51,13 @@ SpinBox {
horizontalAlignment: Qt.AlignLeft
padding.left: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding
padding.right: hifi.dimensions.spinnerSize
padding.top: 0
incrementControl: HiFiGlyphs {
id: incrementButton
text: hifi.glyphs.caratUp
x: 6
y: 2
y: 1
size: hifi.dimensions.spinnerSize
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
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property bool isSearchField: false
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
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
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
@ -42,11 +44,22 @@ TextField {
: (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
border.color: hifi.colors.primaryHighlight
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
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
padding.left: hifi.dimensions.textPadding
padding.left: (isSearchField ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: hifi.dimensions.textPadding
}
@ -56,7 +69,7 @@ TextField {
colorScheme: textField.colorScheme
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 4
anchors.bottomMargin: 3
visible: label != ""
}
}

View file

@ -51,7 +51,11 @@ Window {
Rectangle {
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
radius: 4
@ -129,7 +133,14 @@ Window {
HifiControls.Button {
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"
color: hifi.buttons.black
colorScheme: hifi.colorSchemes.dark
@ -151,7 +162,13 @@ Window {
Row {
id: buttonRow
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 {
action: okAction
color: hifi.buttons.black

View file

@ -24,7 +24,8 @@ Window {
resizable: true
destroyOnInvisible: true
x: 40; y: 40
implicitWidth: 400; implicitHeight: 695
implicitWidth: 400
implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300)
HifiConstants { id: hifi }
@ -32,6 +33,7 @@ Window {
property var scripts: ScriptDiscoveryService;
property var scriptsModel: scripts.scriptsModelFilter
property var runningScriptsModel: ListModel { }
property bool isHMD: false
Settings {
category: "Overlay.RunningScripts"
@ -44,7 +46,10 @@ Window {
onScriptCountChanged: updateRunningScripts();
}
Component.onCompleted: updateRunningScripts()
Component.onCompleted: {
isHMD = HMD.active;
updateRunningScripts();
}
function setDefaultFocus() {
// 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 {
tableModel: runningScriptsModel
@ -120,7 +127,7 @@ Window {
}
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 {
id: filterEdit
isSearchField: true
anchors.left: parent.left
anchors.right: parent.right
focus: true
colorScheme: hifi.colorSchemes.dark
placeholderText: "filter"
placeholderText: "Filter"
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
}
HifiControls.VerticalSpacer {}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Tree {
id: treeView
@ -195,7 +205,9 @@ Window {
anchors.right: parent.right
}
HifiControls.VerticalSpacer {}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.TextField {
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 real borderRadius: largeScreen ? 7.5 : 5.0
readonly property real borderWidth: largeScreen ? 2 : 1
readonly property vector2d contentMargin: Qt.vector2d(12, 24)
readonly property vector2d contentSpacing: Qt.vector2d(8, 12)
readonly property vector2d contentMargin: Qt.vector2d(21, 21)
readonly property vector2d contentSpacing: Qt.vector2d(11, 14)
readonly property real labelPadding: 40
readonly property real textPadding: 8
readonly property real sliderHandleSize: 18
@ -143,8 +143,8 @@ Item {
readonly property real tableHeaderHeight: 40
readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30)
readonly property real modalDialogTitleHeight: 40
readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor
readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight
readonly property real controlLineHeight: 28 // Height of spinbox control on 1920 x 1080 monitor
readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight
readonly property vector2d menuPadding: Qt.vector2d(14, 12)
}
@ -156,6 +156,7 @@ Item {
readonly property real inputLabel: dimensions.largeScreen ? 14 : 10
readonly property real textFieldInput: dimensions.largeScreen ? 15 : 12
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 buttonLabel: dimensions.largeScreen ? 13 : 9
readonly property real iconButton: dimensions.largeScreen ? 13 : 9

View file

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

View file

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

View file

@ -360,6 +360,41 @@ Menu::Menu() {
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 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
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 RenderLookAtTargets = "Show Look-at Targets";
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 RenderResolutionOne = "1";
const QString RenderResolutionTwoThird = "2/3";

View file

@ -254,10 +254,7 @@ void AvatarManager::clearAllAvatars() {
QWriteLocker locker(&_hashLock);
_myAvatar->die();
_myAvatar.reset();
_avatarHash.clear();
handleRemovedAvatar(_myAvatar);
}
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();
_eyePosition = calculateAverageEyePosition();
_eyePosition = getPosition();
if (!billboard && _owningAvatar) {
auto skeletonModel = static_cast<Avatar*>(_owningAvatar)->getSkeletonModel();
@ -238,6 +238,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition);
}
}
_eyePosition = calculateAverageEyePosition();
}
void Head::calculateMouthShapes() {

View file

@ -317,6 +317,37 @@ void MyAvatar::update(float deltaTime) {
}
currentEnergy = max(0.0f, min(currentEnergy,1.0f));
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);
@ -944,22 +975,6 @@ void MyAvatar::clearLookAtTargetAvatar() {
}
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;
}
@ -1323,23 +1338,8 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) {
}
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() ?
QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") :
QUrl::fromLocalFile(PathUtils::resourcesPath() + "avatar/avatar-animation.json") :
QUrl(_animGraphUrl);
_rig->initAnimGraph(graphUrl);

View file

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

View file

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

View file

@ -292,6 +292,8 @@ void AssetMappingModel::refresh() {
} else {
emit errorGettingMappings(request->getErrorString());
}
request->deleteLater();
});
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);
}
}
// If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one
if (!_overlayFramebuffer->getRenderBuffer(0)) {
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()));
_lodSize = new QSlider(Qt::Horizontal, this);
const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER;
const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE;
const int MAX_LOD_SIZE = 2000; // ~20:4 vision -- really good.
const int MIN_LOD_SIZE = 5; // ~20:1600 vision -- really bad!
const int STEP_LOD_SIZE = 1;
const int PAGE_STEP_LOD_SIZE = 100;
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 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 incomingPingTimeString = locale.toString(node->getPingMs());
QString incomingClockSkewString = locale.toString(clockSkewInMS);
@ -536,7 +538,9 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
" Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs";
serverDetails << "<br/>" <<
" Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs";
" Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" <<
" [" << qPrintable(formattedClockSkewString) << "]";
serverDetails << "<br/>" << "Incoming" <<
" 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(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()) {
node->setStartFrameVar(startFrameVar);

View file

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

View file

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

View file

@ -29,6 +29,7 @@ namespace AudioConstants {
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_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
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;
}
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (!entity) {
QString collisionSoundURL;
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;
}
const QString& collisionSoundURL = entity->getCollisionSoundURL();
if (collisionSoundURL.isEmpty()) {
return;
}
const float mass = entity->computeMass();
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,
// 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)
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);
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) {
EntityItem::adjustEditPacketForClockSkew(buffer, clockSkew);
}

View file

@ -32,7 +32,7 @@ public:
// My server type is the model server
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:
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);

View file

@ -370,7 +370,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
return 0;
}
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
qint64 clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
BufferParser parser(data, bytesLeftToRead);
@ -485,7 +485,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
qCDebug(entities) << " now:" << now;
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew);
qCDebug(entities) << " clockSkew:" << clockSkew;
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, 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 don't want the side effect of flag setting.
simulateKinematicMotion(skipTimeForward, false);
stepKinematicMotion(skipTimeForward);
}
if (overwriteLocalData) {
@ -760,7 +760,7 @@ void EntityItem::debugDump() const {
}
// 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());
int octets = numberOfThreeBitSectionsInCode(dataAt);
int lengthOfOctcode = (int)bytesRequiredForCodeLength(octets);
@ -872,130 +872,120 @@ void EntityItem::simulate(const quint64& now) {
qCDebug(entities) << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated;
#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;
}
void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
#ifdef WANT_DEBUG
qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed;
#endif
bool EntityItem::stepKinematicMotion(float timeElapsed) {
// get all the data
Transform transform;
glm::vec3 linearVelocity;
glm::vec3 angularVelocity;
getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity);
const float MIN_TIME_SKIP = 0.0f;
const float MAX_TIME_SKIP = 1.0f; // in seconds
timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP);
if (hasActions()) {
return;
// find out if it is moving
bool isSpinning = (glm::length2(angularVelocity) > 0.0f);
float linearSpeedSquared = glm::length2(linearVelocity);
bool isTranslating = linearSpeedSquared > 0.0f;
bool moving = isTranslating || isSpinning;
if (!moving) {
return false;
}
if (hasLocalAngularVelocity()) {
glm::vec3 localAngularVelocity = getLocalAngularVelocity();
if (timeElapsed <= 0.0f) {
// 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
if (_angularDamping > 0.0f) {
localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
#ifdef WANT_DEBUG
qCDebug(entities) << " angularDamping :" << _angularDamping;
qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity;
#endif
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
}
float angularSpeed = glm::length(localAngularVelocity);
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
if (setFlags && angularSpeed > 0.0f) {
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
}
localAngularVelocity = ENTITY_ITEM_ZERO_VEC3;
const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED =
KINEMATIC_ANGULAR_SPEED_THRESHOLD * KINEMATIC_ANGULAR_SPEED_THRESHOLD;
if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) {
angularVelocity = Vectors::ZERO;
} else {
// for improved agreement with the way Bullet integrates rotations we use an approximation
// and break the integration into bullet-sized substeps
glm::quat rotation = getRotation();
glm::quat rotation = transform.getRotation();
float dt = timeElapsed;
while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) {
glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
while (dt > 0.0f) {
glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP));
rotation = glm::normalize(dQ * rotation);
dt -= PHYSICS_ENGINE_FIXED_SUBSTEP;
}
// NOTE: this final partial substep can drift away from a real Bullet simulation however
// 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);
transform.setRotation(rotation);
}
setLocalAngularVelocity(localAngularVelocity);
}
if (hasLocalVelocity()) {
// acceleration is in the global frame, so transform it into the local frame.
// TODO: Move this into SpatiallyNestable.
bool success;
Transform transform = getParentTransform(success);
glm::vec3 localAcceleration(glm::vec3::_null);
if (success) {
localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration();
} else {
localAcceleration = getAcceleration();
}
glm::vec3 position = transform.getTranslation();
const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED =
KINEMATIC_LINEAR_SPEED_THRESHOLD * KINEMATIC_LINEAR_SPEED_THRESHOLD;
if (isTranslating) {
glm::vec3 deltaVelocity = Vectors::ZERO;
// linear damping
glm::vec3 localVelocity = getLocalVelocity();
if (_damping > 0.0f) {
localVelocity *= powf(1.0f - _damping, timeElapsed);
#ifdef WANT_DEBUG
qCDebug(entities) << " damping:" << _damping;
qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity;
qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity);
#endif
deltaVelocity = (powf(1.0f - _damping, timeElapsed) - 1.0f) * linearVelocity;
}
// integrate position forward
glm::vec3 localPosition = getLocalPosition();
glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed;
const float MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED = 1.0e-4f; // 0.01 m/sec^2
if (glm::length2(_acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) {
// 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
qCDebug(entities) << " EntityItem::simulate()....";
qCDebug(entities) << " timeElapsed:" << timeElapsed;
qCDebug(entities) << " old AACube:" << getMaximumAACube();
qCDebug(entities) << " old position:" << localPosition;
qCDebug(entities) << " old velocity:" << localVelocity;
qCDebug(entities) << " old getAABox:" << getAABox();
qCDebug(entities) << " newPosition:" << newPosition;
qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition);
#endif
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;
if (linearSpeedSquared < MIN_KINEMATIC_LINEAR_SPEED_SQUARED
&& glm::length2(deltaVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED
&& glm::length2(linearVelocity + deltaVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) {
linearVelocity = Vectors::ZERO;
} else {
// NOTE: we do NOT include the second-order acceleration term (0.5 * a * dt^2)
// when computing the displacement because Bullet also ignores that term. Yes,
// this is an approximation and it works best when dt is small.
position += timeElapsed * linearVelocity;
linearVelocity += deltaVelocity;
}
} else {
setLocalPosition(localPosition);
setLocalVelocity(localVelocity);
// no acceleration
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 {

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