Merge remote-tracking branch 'upstream/master'
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) { };
|
||||
|
|
6
cmake/externals/glew/CMakeLists.txt
vendored
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = ' ▾';
|
||||
const DESCENDING_STRING = ' ▴';
|
||||
const ASCENDING_STRING = '▾';
|
||||
const DESCENDING_STRING = '▴';
|
||||
const LOCKED_GLYPH = "";
|
||||
const VISIBLE_GLYPH = "";
|
||||
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="" />
|
||||
<input type="button" id="visible" class="glyph" value="" />
|
||||
</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"> ▾</span></th>
|
||||
<th id="entity-name" data-sort="type">Name <span class="sort-order" style="display: none"> ▾</span></th>
|
||||
<th id="entity-url" data-sort="url">File <span class="sort-order" style="display: none"> ▾</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"></span><span class="sort-order"></span></th>
|
||||
<th colspan="2" id="entity-visible" data-sort="visible"><span class="glyph"></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>
|
||||
|
|
|
@ -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: "",
|
||||
Model: "",
|
||||
Web: "q",
|
||||
Text: "l",
|
||||
Light: "p",
|
||||
Zone: "o",
|
||||
PolyVox: "",
|
||||
Multiple: ""
|
||||
}
|
||||
|
||||
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></span> Locked</label>
|
||||
</div>
|
||||
<div class="property checkbox">
|
||||
<input type="checkbox" id="property-visible">
|
||||
<label for="property-visible"><span></span> 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>
|
||||
|
|
|
@ -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">
|
||||
|
|
51
examples/html/spinButtons.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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: {
|
||||
|
|
49
examples/utilities/render/rates.qml
Normal 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]
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
examples/utilities/render/renderRates.js
Normal 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(); });
|
|
@ -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(); });
|
|
@ -241,7 +241,6 @@ Item {
|
|||
color: "#E2334D"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
BIN
interface/resources/avatar/animations/fly.fbx
Normal file
BIN
interface/resources/avatar/animations/hydra_pose_closed_left.fbx
Normal file
BIN
interface/resources/avatar/animations/hydra_pose_open_left.fbx
Normal file
BIN
interface/resources/avatar/animations/hydra_pose_open_right.fbx
Normal file
BIN
interface/resources/avatar/animations/idle.fbx
Normal file
BIN
interface/resources/avatar/animations/idle_to_walk.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_in_air.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_land.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_standing_apex.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_standing_land.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_standing_takeoff.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_takeoff.fbx
Normal file
BIN
interface/resources/avatar/animations/run_fwd.fbx
Normal file
BIN
interface/resources/avatar/animations/side_step_left.fbx
Normal file
BIN
interface/resources/avatar/animations/side_step_right.fbx
Normal file
BIN
interface/resources/avatar/animations/side_step_short_left.fbx
Normal file
BIN
interface/resources/avatar/animations/side_step_short_right.fbx
Normal file
BIN
interface/resources/avatar/animations/talk.fbx
Normal file
BIN
interface/resources/avatar/animations/turn_left.fbx
Normal file
BIN
interface/resources/avatar/animations/turn_right.fbx
Normal file
BIN
interface/resources/avatar/animations/walk_bwd.fbx
Normal file
BIN
interface/resources/avatar/animations/walk_fwd.fbx
Normal file
BIN
interface/resources/avatar/animations/walk_short_bwd.fbx
Normal file
BIN
interface/resources/avatar/animations/walk_short_fwd.fbx
Normal 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,
|
BIN
interface/resources/meshes/being_of_light/being_of_light.fbx
Normal file
After Width: | Height: | Size: 2.6 MiB |
After Width: | Height: | Size: 2.9 MiB |
After Width: | Height: | Size: 645 KiB |
Before Width: | Height: | Size: 330 KiB |
Before Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 4.6 KiB |
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
Before Width: | Height: | Size: 4.6 KiB |
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Original.Button {
|
|||
property int colorScheme: hifi.colorSchemes.light
|
||||
|
||||
width: 120
|
||||
height: 28
|
||||
height: hifi.dimensions.controlLineHeight
|
||||
|
||||
style: ButtonStyle {
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
67
interface/resources/qml/controls-uit/TextAction.qml
Normal 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()
|
||||
}
|
||||
}
|
|
@ -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 != ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -292,6 +292,8 @@ void AssetMappingModel::refresh() {
|
|||
} else {
|
||||
emit errorGettingMappings(request->getErrorString());
|
||||
}
|
||||
|
||||
request->deleteLater();
|
||||
});
|
||||
|
||||
request->start();
|
||||
|
|
37
interface/src/scripting/RatesScriptingInterface.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) <<
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|