Merge branch 'master' of github.com:highfidelity/hifi into update-model-meta

This commit is contained in:
Seth Alves 2016-05-16 10:53:39 -07:00
commit 2a5efd3b82
33 changed files with 573 additions and 424 deletions

View file

@ -290,7 +290,6 @@ void Agent::executeScript() {
packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket"); packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket");
packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar"); packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar");
packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::AvatarBillboard, avatarHashMap.data(), "processAvatarBillboardPacket");
// register ourselves to the script engine // register ourselves to the script engine
_scriptEngine->registerGlobalObject("Agent", this); _scriptEngine->registerGlobalObject("Agent", this);
@ -341,15 +340,12 @@ void Agent::setIsAvatar(bool isAvatar) {
if (_isAvatar && !_avatarIdentityTimer) { if (_isAvatar && !_avatarIdentityTimer) {
// set up the avatar timers // set up the avatar timers
_avatarIdentityTimer = new QTimer(this); _avatarIdentityTimer = new QTimer(this);
_avatarBillboardTimer = new QTimer(this);
// connect our slot // connect our slot
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket); connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
connect(_avatarBillboardTimer, &QTimer::timeout, this, &Agent::sendAvatarBillboardPacket);
// start the timers // start the timers
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
_avatarBillboardTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
} }
if (!_isAvatar) { if (!_isAvatar) {
@ -359,12 +355,6 @@ void Agent::setIsAvatar(bool isAvatar) {
delete _avatarIdentityTimer; delete _avatarIdentityTimer;
_avatarIdentityTimer = nullptr; _avatarIdentityTimer = nullptr;
} }
if (_avatarBillboardTimer) {
_avatarBillboardTimer->stop();
delete _avatarBillboardTimer;
_avatarBillboardTimer = nullptr;
}
} }
} }
@ -375,14 +365,6 @@ void Agent::sendAvatarIdentityPacket() {
} }
} }
void Agent::sendAvatarBillboardPacket() {
if (_isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
scriptedAvatar->sendBillboardPacket();
}
}
void Agent::processAgentAvatarAndAudio(float deltaTime) { void Agent::processAgentAvatarAndAudio(float deltaTime) {
if (!_scriptEngine->isFinished() && _isAvatar) { if (!_scriptEngine->isFinished() && _isAvatar) {
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>(); auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
@ -491,7 +473,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) {
} }
void Agent::aboutToFinish() { void Agent::aboutToFinish() {
setIsAvatar(false);// will stop timers for sending billboards and identity packets setIsAvatar(false);// will stop timers for sending identity packets
if (_scriptEngine) { if (_scriptEngine) {
_scriptEngine->stop(); _scriptEngine->stop();

View file

@ -82,7 +82,6 @@ private:
void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; } void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; }
void sendAvatarIdentityPacket(); void sendAvatarIdentityPacket();
void sendAvatarBillboardPacket();
QString _scriptContents; QString _scriptContents;
QTimer* _scriptRequestTimeout { nullptr }; QTimer* _scriptRequestTimeout { nullptr };
@ -92,7 +91,6 @@ private:
int _numAvatarSoundSentBytes = 0; int _numAvatarSoundSentBytes = 0;
bool _isAvatar = false; bool _isAvatar = false;
QTimer* _avatarIdentityTimer = nullptr; QTimer* _avatarIdentityTimer = nullptr;
QTimer* _avatarBillboardTimer = nullptr;
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers; QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
}; };

View file

@ -864,10 +864,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
if (action == controller::toInt(controller::Action::RETICLE_CLICK)) { if (action == controller::toInt(controller::Action::RETICLE_CLICK)) {
auto reticlePos = getApplicationCompositor().getReticlePosition(); auto reticlePos = getApplicationCompositor().getReticlePosition();
QPoint globalPos(reticlePos.x, reticlePos.y); QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates.
// FIXME - it would be nice if this was self contained in the _compositor or Reticle class
auto localPos = isHMDMode() ? globalPos : _glWidget->mapFromGlobal(globalPos);
if (state) { if (state) {
QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
sendEvent(_glWidget, &mousePress); sendEvent(_glWidget, &mousePress);
@ -888,15 +885,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
} else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) { } else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) {
if (!offscreenUi->navigationFocused()) { if (!offscreenUi->navigationFocused()) {
auto reticlePosition = getApplicationCompositor().getReticlePosition(); auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
} }
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
auto reticlePosition = getApplicationCompositor().getReticlePosition(); auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
} else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) { } else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) {
if (!offscreenUi->navigationFocused()) { if (!offscreenUi->navigationFocused()) {
auto reticlePosition = getApplicationCompositor().getReticlePosition(); auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
} }
} else if (action == controller::toInt(controller::Action::RETICLE_X)) { } else if (action == controller::toInt(controller::Action::RETICLE_X)) {
auto oldPos = getApplicationCompositor().getReticlePosition(); auto oldPos = getApplicationCompositor().getReticlePosition();
@ -1071,6 +1068,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// in the queue, which can be pretty damn frequent. Hence the idle function has a bunch // in the queue, which can be pretty damn frequent. Hence the idle function has a bunch
// of logic to abort early if it's being called too often. // of logic to abort early if it's being called too often.
_idleTimer->start(0); _idleTimer->start(0);
// After all of the constructor is completed, then set firstRun to false.
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
firstRun.set(false);
} }
@ -1088,11 +1089,6 @@ void Application::checkChangeCursor() {
_cursorNeedsChanging = false; _cursorNeedsChanging = false;
} }
// After all of the constructor is completed, then set firstRun to false.
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
firstRun.set(false);
} }
void Application::showCursor(const QCursor& cursor) { void Application::showCursor(const QCursor& cursor) {
@ -1160,10 +1156,16 @@ void Application::cleanupBeforeQuit() {
getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
QThreadPool::globalInstance()->clear();
DependencyManager::get<ScriptEngines>()->saveScripts(); DependencyManager::get<ScriptEngines>()->saveScripts();
DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts
DependencyManager::destroy<ScriptEngines>(); DependencyManager::destroy<ScriptEngines>();
// Cleanup all overlays after the scripts, as scripts might add more
_overlays.cleanupAllOverlays();
// first stop all timers directly or by invokeMethod // first stop all timers directly or by invokeMethod
// depending on what thread they run in // depending on what thread they run in
locationUpdateTimer.stop(); locationUpdateTimer.stop();
@ -2269,7 +2271,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) { if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto reticlePosition = getApplicationCompositor().getReticlePosition(); auto reticlePosition = getApplicationCompositor().getReticlePosition();
offscreenUi->toggleMenu(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y))); offscreenUi->toggleMenu(QPoint(reticlePosition.x, reticlePosition.y));
} }
_keysPressed.remove(event->key()); _keysPressed.remove(event->key());
@ -2738,15 +2740,7 @@ void Application::setLowVelocityFilter(bool lowVelocityFilter) {
} }
ivec2 Application::getMouse() const { ivec2 Application::getMouse() const {
auto reticlePosition = getApplicationCompositor().getReticlePosition(); return getApplicationCompositor().getReticlePosition();
// in the HMD, the reticlePosition is the mouse position
if (isHMDMode()) {
return reticlePosition;
}
// in desktop mode, we need to map from global to widget space
return toGlm(_glWidget->mapFromGlobal(QPoint(reticlePosition.x, reticlePosition.y)));
} }
FaceTracker* Application::getActiveFaceTracker() { FaceTracker* Application::getActiveFaceTracker() {

View file

@ -73,7 +73,6 @@ AvatarManager::AvatarManager(QObject* parent) :
packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket"); packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket");
packetReceiver.registerListener(PacketType::KillAvatar, this, "processKillAvatar"); packetReceiver.registerListener(PacketType::KillAvatar, this, "processKillAvatar");
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "processAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, this, "processAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket");
} }
AvatarManager::~AvatarManager() { AvatarManager::~AvatarManager() {

View file

@ -675,7 +675,11 @@ void MyAvatar::saveData() {
settings.setValue("leanScale", _leanScale); settings.setValue("leanScale", _leanScale);
settings.setValue("scale", _targetScale); settings.setValue("scale", _targetScale);
settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences); settings.setValue("fullAvatarURL",
_fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ?
"" :
_fullAvatarURLFromPreferences.toString());
settings.setValue("fullAvatarModelName", _fullAvatarModelName); settings.setValue("fullAvatarModelName", _fullAvatarModelName);
settings.setValue("animGraphURL", _animGraphUrl); settings.setValue("animGraphURL", _animGraphUrl);

View file

@ -36,15 +36,8 @@
#include <QtQuick/QQuickWindow> #include <QtQuick/QQuickWindow>
Overlays::Overlays() : _nextOverlayID(1) { Overlays::Overlays() :
connect(qApp, &Application::beforeAboutToQuit, [=] { _nextOverlayID(1) {}
cleanupAllOverlays();
});
}
Overlays::~Overlays() {
}
void Overlays::cleanupAllOverlays() { void Overlays::cleanupAllOverlays() {
{ {

View file

@ -62,7 +62,6 @@ class Overlays : public QObject {
public: public:
Overlays(); Overlays();
~Overlays();
void init(); void init();
void update(float deltatime); void update(float deltatime);
@ -73,6 +72,8 @@ public:
Overlay::Pointer getOverlay(unsigned int id) const; Overlay::Pointer getOverlay(unsigned int id) const;
OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; } OverlayPanel::Pointer getPanel(unsigned int id) const { return _panels[id]; }
void cleanupAllOverlays();
public slots: public slots:
/// adds an overlay with the specific properties /// adds an overlay with the specific properties
unsigned int addOverlay(const QString& type, const QVariant& properties); unsigned int addOverlay(const QString& type, const QVariant& properties);
@ -145,7 +146,6 @@ signals:
private: private:
void cleanupOverlaysToDelete(); void cleanupOverlaysToDelete();
void cleanupAllOverlays();
QMap<unsigned int, Overlay::Pointer> _overlaysHUD; QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
QMap<unsigned int, Overlay::Pointer> _overlaysWorld; QMap<unsigned int, Overlay::Pointer> _overlaysWorld;

View file

@ -58,7 +58,6 @@ AvatarData::AvatarData() :
_headData(NULL), _headData(NULL),
_displayNameTargetAlpha(1.0f), _displayNameTargetAlpha(1.0f),
_displayNameAlpha(1.0f), _displayNameAlpha(1.0f),
_billboard(),
_errorLogExpiry(0), _errorLogExpiry(0),
_owningAvatarMixer(), _owningAvatarMixer(),
_targetVelocity(0.0f), _targetVelocity(0.0f),
@ -990,7 +989,7 @@ QByteArray AvatarData::identityByteArray() {
QByteArray identityData; QByteArray identityData;
QDataStream identityStream(&identityData, QIODevice::Append); QDataStream identityStream(&identityData, QIODevice::Append);
QUrl emptyURL(""); QUrl emptyURL("");
const QUrl& urlToSend = (_skeletonModelURL == AvatarData::defaultFullAvatarModelUrl()) ? emptyURL : _skeletonModelURL; const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL;
QUrl unusedModelURL; // legacy faceModel support QUrl unusedModelURL; // legacy faceModel support
@ -999,13 +998,6 @@ QByteArray AvatarData::identityByteArray() {
return identityData; return identityData;
} }
bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& data) {
if (data == _billboard) {
return false;
}
_billboard = data;
return true;
}
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL; const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL;
@ -1103,33 +1095,6 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) {
setAttachmentData(attachmentData); setAttachmentData(attachmentData);
} }
void AvatarData::setBillboard(const QByteArray& billboard) {
_billboard = billboard;
qCDebug(avatars) << "Changing billboard for avatar.";
}
void AvatarData::setBillboardFromURL(const QString &billboardURL) {
_billboardURL = billboardURL;
qCDebug(avatars) << "Changing billboard for avatar to PNG at" << qPrintable(billboardURL);
QNetworkRequest billboardRequest;
billboardRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
billboardRequest.setUrl(QUrl(billboardURL));
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* networkReply = networkAccessManager.get(billboardRequest);
connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply()));
}
void AvatarData::setBillboardFromNetworkReply() {
QNetworkReply* networkReply = static_cast<QNetworkReply*>(sender());
setBillboard(networkReply->readAll());
networkReply->deleteLater();
}
void AvatarData::setJointMappingsFromNetworkReply() { void AvatarData::setJointMappingsFromNetworkReply() {
QNetworkReply* networkReply = static_cast<QNetworkReply*>(sender()); QNetworkReply* networkReply = static_cast<QNetworkReply*>(sender());
@ -1204,21 +1169,6 @@ void AvatarData::sendIdentityPacket() {
}); });
} }
void AvatarData::sendBillboardPacket() {
if (!_billboard.isEmpty()) {
auto nodeList = DependencyManager::get<NodeList>();
// This makes sure the billboard won't be too large to send.
// Once more protocol changes are done and we can send blocks of data we can support sending > MTU sized billboards.
if (_billboard.size() <= NLPacket::maxPayloadSize(PacketType::AvatarBillboard)) {
auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard, _billboard.size());
billboardPacket->write(_billboard);
nodeList->broadcastToNodes(std::move(billboardPacket), NodeSet() << NodeType::AvatarMixer);
}
}
}
void AvatarData::updateJointMappings() { void AvatarData::updateJointMappings() {
_jointIndices.clear(); _jointIndices.clear();
_jointNames.clear(); _jointNames.clear();

View file

@ -107,7 +107,6 @@ static const float MIN_AVATAR_SCALE = .005f;
const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation
const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
// See also static AvatarData::defaultFullAvatarModelUrl(). // See also static AvatarData::defaultFullAvatarModelUrl().
const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default"); const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default");
@ -160,7 +159,6 @@ class AvatarData : public QObject, public SpatiallyNestable {
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName) Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName)
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript) Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript)
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData) Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL)
Q_PROPERTY(QStringList jointNames READ getJointNames) Q_PROPERTY(QStringList jointNames READ getJointNames)
@ -285,8 +283,6 @@ public:
bool hasIdentityChangedAfterParsing(const QByteArray& data); bool hasIdentityChangedAfterParsing(const QByteArray& data);
QByteArray identityByteArray(); QByteArray identityByteArray();
bool hasBillboardChangedAfterParsing(const QByteArray& data);
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
const QString& getDisplayName() const { return _displayName; } const QString& getDisplayName() const { return _displayName; }
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
@ -304,12 +300,6 @@ public:
Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString()); Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString());
Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString()); Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString());
virtual void setBillboard(const QByteArray& billboard);
const QByteArray& getBillboard() const { return _billboard; }
void setBillboardFromURL(const QString& billboardURL);
const QString& getBillboardURL() { return _billboardURL; }
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); } QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); } void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
@ -336,9 +326,7 @@ public:
public slots: public slots:
void sendAvatarDataPacket(); void sendAvatarDataPacket();
void sendIdentityPacket(); void sendIdentityPacket();
void sendBillboardPacket();
void setBillboardFromNetworkReply();
void setJointMappingsFromNetworkReply(); void setJointMappingsFromNetworkReply();
void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); } void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); }
@ -377,9 +365,6 @@ protected:
float _displayNameTargetAlpha; float _displayNameTargetAlpha;
float _displayNameAlpha; float _displayNameAlpha;
QByteArray _billboard;
QString _billboardURL;
QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys
QStringList _jointNames; ///< in order of depth-first traversal QStringList _jointNames; ///< in order of depth-first traversal

View file

@ -136,17 +136,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
} }
} }
void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
QByteArray billboard = message->read(message->getBytesLeftToRead());
if (avatar->getBillboard() != billboard) {
avatar->setBillboard(billboard);
}
}
void AvatarHashMap::processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) { void AvatarHashMap::processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
// read the node id // read the node id
QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));

View file

@ -53,7 +53,6 @@ private slots:
void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode); void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode); void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode); void processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
protected: protected:

View file

@ -267,7 +267,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
if (numBytes == 0) { if (numBytes == 0) {
return; return;
} }
memcpy(particleBuffer->editData(), particlePrimitives->data(), numBytes); particleBuffer->setData(numBytes, (const gpu::Byte*)particlePrimitives->data());
// Update transform and bounds // Update transform and bounds
payload.setModelTransform(transform); payload.setModelTransform(transform);

View file

@ -1332,7 +1332,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
} }
// NOTE: shapeVertices are in joint-frame // NOTE: shapeVertices are in joint-frame
QVector<ShapeVertices> shapeVertices; std::vector<ShapeVertices> shapeVertices;
shapeVertices.resize(geometry.joints.size()); shapeVertices.resize(geometry.joints.size());
// find our special joints // find our special joints
@ -1523,7 +1523,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
float clusterScale = extractUniformScale(fbxCluster.inverseBindMatrix); float clusterScale = extractUniformScale(fbxCluster.inverseBindMatrix);
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform; glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
ShapeVertices& points = shapeVertices[jointIndex]; ShapeVertices& points = shapeVertices.at(jointIndex);
float totalWeight = 0.0f; float totalWeight = 0.0f;
for (int j = 0; j < cluster.indices.size(); j++) { for (int j = 0; j < cluster.indices.size(); j++) {
@ -1585,7 +1585,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// transform cluster vertices to joint-frame and save for later // transform cluster vertices to joint-frame and save for later
float clusterScale = extractUniformScale(firstFBXCluster.inverseBindMatrix); float clusterScale = extractUniformScale(firstFBXCluster.inverseBindMatrix);
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform; glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
ShapeVertices& points = shapeVertices[jointIndex]; ShapeVertices& points = shapeVertices.at(jointIndex);
foreach (const glm::vec3& vertex, extracted.mesh.vertices) { foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertex); const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertex);
points.push_back(extractTranslation(vertexTransform) * clusterScale); points.push_back(extractTranslation(vertexTransform) * clusterScale);
@ -1626,7 +1626,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
FBXJoint& joint = geometry.joints[i]; FBXJoint& joint = geometry.joints[i];
// NOTE: points are in joint-frame // NOTE: points are in joint-frame
ShapeVertices& points = shapeVertices[i]; ShapeVertices& points = shapeVertices.at(i);
if (points.size() > 0) { if (points.size() > 0) {
// compute average point // compute average point
glm::vec3 avgPoint = glm::vec3(0.0f); glm::vec3 avgPoint = glm::vec3(0.0f);

View file

@ -624,7 +624,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
return geometryPtr; return geometryPtr;
} }
void fbxDebugDump(const FBXGeometry& fbxgeo) { void fbxDebugDump(const FBXGeometry& fbxgeo) {
qCDebug(modelformat) << "---------------- fbxGeometry ----------------"; qCDebug(modelformat) << "---------------- fbxGeometry ----------------";
qCDebug(modelformat) << " hasSkeletonJoints =" << fbxgeo.hasSkeletonJoints; qCDebug(modelformat) << " hasSkeletonJoints =" << fbxgeo.hasSkeletonJoints;

View file

@ -65,15 +65,22 @@ public:
class GLBuffer : public GPUObject { class GLBuffer : public GPUObject {
public: public:
Stamp _stamp; const GLuint _buffer;
GLuint _buffer; const GLuint _size;
GLuint _size; const Stamp _stamp;
GLBuffer(); GLBuffer(const Buffer& buffer, GLBuffer* original = nullptr);
~GLBuffer(); ~GLBuffer();
void setSize(GLuint size); void transfer();
private:
bool getNextTransferBlock(GLintptr& outOffset, GLsizeiptr& outSize, size_t& currentPage) const;
// The owning texture
const Buffer& _gpuBuffer;
}; };
static GLBuffer* syncGPUObject(const Buffer& buffer); static GLBuffer* syncGPUObject(const Buffer& buffer);
static GLuint getBufferID(const Buffer& buffer); static GLuint getBufferID(const Buffer& buffer);

View file

@ -12,12 +12,40 @@
using namespace gpu; using namespace gpu;
GLBackend::GLBuffer::GLBuffer() : GLuint allocateSingleBuffer() {
_stamp(0), GLuint result;
_buffer(0), glGenBuffers(1, &result);
_size(0) (void)CHECK_GL_ERROR();
{ return result;
}
GLBackend::GLBuffer::GLBuffer(const Buffer& buffer, GLBuffer* original) :
_buffer(allocateSingleBuffer()),
_size((GLuint)buffer._sysmem.getSize()),
_stamp(buffer._sysmem.getStamp()),
_gpuBuffer(buffer) {
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
if (GLEW_VERSION_4_4 || GLEW_ARB_buffer_storage) {
glBufferStorage(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_STORAGE_BIT);
(void)CHECK_GL_ERROR();
} else {
glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW);
(void)CHECK_GL_ERROR();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
if (original) {
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
glBindBuffer(GL_COPY_READ_BUFFER, original->_buffer);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, original->_size);
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
glBindBuffer(GL_COPY_READ_BUFFER, 0);
(void)CHECK_GL_ERROR();
}
Backend::setGPUObject(buffer, this);
Backend::incrementBufferGPUCount(); Backend::incrementBufferGPUCount();
Backend::updateBufferGPUMemoryUsage(0, _size);
} }
GLBackend::GLBuffer::~GLBuffer() { GLBackend::GLBuffer::~GLBuffer() {
@ -28,37 +56,56 @@ GLBackend::GLBuffer::~GLBuffer() {
Backend::decrementBufferGPUCount(); Backend::decrementBufferGPUCount();
} }
void GLBackend::GLBuffer::setSize(GLuint size) { void GLBackend::GLBuffer::transfer() {
Backend::updateBufferGPUMemoryUsage(_size, size); glBindBuffer(GL_ARRAY_BUFFER, _buffer);
_size = size; (void)CHECK_GL_ERROR();
GLintptr offset;
GLsizeiptr size;
size_t currentPage { 0 };
auto data = _gpuBuffer.getSysmem().readData();
while (getNextTransferBlock(offset, size, currentPage)) {
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data + offset);
(void)CHECK_GL_ERROR();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
(void)CHECK_GL_ERROR();
_gpuBuffer._flags &= ~Buffer::DIRTY;
}
bool GLBackend::GLBuffer::getNextTransferBlock(GLintptr& outOffset, GLsizeiptr& outSize, size_t& currentPage) const {
size_t pageCount = _gpuBuffer._pages.size();
// Advance to the first dirty page
while (currentPage < pageCount && (0 == (Buffer::DIRTY & _gpuBuffer._pages[currentPage]))) {
++currentPage;
}
// If we got to the end, we're done
if (currentPage >= pageCount) {
return false;
}
// Advance to the next clean page
outOffset = static_cast<GLintptr>(currentPage * _gpuBuffer._pageSize);
while (currentPage < pageCount && (0 != (Buffer::DIRTY & _gpuBuffer._pages[currentPage]))) {
_gpuBuffer._pages[currentPage] &= ~Buffer::DIRTY;
++currentPage;
}
outSize = static_cast<GLsizeiptr>((currentPage * _gpuBuffer._pageSize) - outOffset);
return true;
} }
GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) {
GLBuffer* object = Backend::getGPUObject<GLBackend::GLBuffer>(buffer); GLBuffer* object = Backend::getGPUObject<GLBackend::GLBuffer>(buffer);
if (object && (object->_stamp == buffer.getSysmem().getStamp())) { // Has the storage size changed?
return object; if (!object || object->_stamp != buffer.getSysmem().getStamp()) {
object = new GLBuffer(buffer, object);
} }
// need to have a gpu object? if (0 != (buffer._flags & Buffer::DIRTY)) {
if (!object) { object->transfer();
object = new GLBuffer();
glGenBuffers(1, &object->_buffer);
(void) CHECK_GL_ERROR();
Backend::setGPUObject(buffer, object);
} }
// Now let's update the content of the bo with the sysmem version
// TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change
//if () {
glBindBuffer(GL_ARRAY_BUFFER, object->_buffer);
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
object->_stamp = buffer.getSysmem().getStamp();
object->setSize((GLuint)buffer.getSysmem().getSize());
//}
(void) CHECK_GL_ERROR();
return object; return object;
} }

View file

@ -209,6 +209,8 @@ void GLBackend::resetOutputStage() {
_output._drawFBO = 0; _output._drawFBO = 0;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
} }
glEnable(GL_FRAMEBUFFER_SRGB);
} }
void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) { void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) {

View file

@ -535,13 +535,12 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GL
GLint minFilter; GLint minFilter;
GLint magFilter; GLint magFilter;
}; };
static const GLFilterMode filterModes[] = { static const GLFilterMode filterModes[Sampler::NUM_FILTERS] = {
{ GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT, { GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT,
{ GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR, { GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR,
{ GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT, { GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT,
{ GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR, { GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR,
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT, { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
{ GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR, { GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR,
{ GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, { GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
@ -557,7 +556,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GL
glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTexParameteri(object->_target, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter); glTexParameteri(object->_target, GL_TEXTURE_MAG_FILTER, fm.magFilter);
static const GLenum comparisonFuncs[] = { static const GLenum comparisonFuncs[NUM_COMPARISON_FUNCS] = {
GL_NEVER, GL_NEVER,
GL_LESS, GL_LESS,
GL_EQUAL, GL_EQUAL,
@ -574,7 +573,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GL
glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(object->_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
} }
static const GLenum wrapModes[] = { static const GLenum wrapModes[Sampler::NUM_WRAP_MODES] = {
GL_REPEAT, // WRAP_REPEAT, GL_REPEAT, // WRAP_REPEAT,
GL_MIRRORED_REPEAT, // WRAP_MIRROR, GL_MIRRORED_REPEAT, // WRAP_MIRROR,
GL_CLAMP_TO_EDGE, // WRAP_CLAMP, GL_CLAMP_TO_EDGE, // WRAP_CLAMP,

View file

@ -109,40 +109,18 @@ void Resource::Sysmem::deallocateMemory(Byte* dataAllocated, Size size) {
} }
} }
Resource::Sysmem::Sysmem() : Resource::Sysmem::Sysmem() {}
_stamp(0),
_size(0),
_data(NULL)
{
}
Resource::Sysmem::Sysmem(Size size, const Byte* bytes) : Resource::Sysmem::Sysmem(Size size, const Byte* bytes) {
_stamp(0), if (size > 0 && bytes) {
_size(0), setData(_size, bytes);
_data(NULL)
{
if (size > 0) {
_size = allocateMemory(&_data, size);
if (_size >= size) {
if (bytes) {
memcpy(_data, bytes, size);
}
}
} }
} }
Resource::Sysmem::Sysmem(const Sysmem& sysmem) : Resource::Sysmem::Sysmem(const Sysmem& sysmem) {
_stamp(0),
_size(0),
_data(NULL)
{
if (sysmem.getSize() > 0) { if (sysmem.getSize() > 0) {
_size = allocateMemory(&_data, sysmem.getSize()); allocate(sysmem._size);
if (_size >= sysmem.getSize()) { setData(_size, sysmem._data);
if (sysmem.readData()) {
memcpy(_data, sysmem.readData(), sysmem.getSize());
}
}
} }
} }
@ -208,7 +186,6 @@ Resource::Size Resource::Sysmem::setData( Size size, const Byte* bytes ) {
if (allocate(size) == size) { if (allocate(size) == size) {
if (size && bytes) { if (size && bytes) {
memcpy( _data, bytes, _size ); memcpy( _data, bytes, _size );
_stamp++;
} }
} }
return _size; return _size;
@ -217,7 +194,6 @@ Resource::Size Resource::Sysmem::setData( Size size, const Byte* bytes ) {
Resource::Size Resource::Sysmem::setSubData( Size offset, Size size, const Byte* bytes) { Resource::Size Resource::Sysmem::setSubData( Size offset, Size size, const Byte* bytes) {
if (size && ((offset + size) <= getSize()) && bytes) { if (size && ((offset + size) <= getSize()) && bytes) {
memcpy( _data + offset, bytes, size ); memcpy( _data + offset, bytes, size );
_stamp++;
return size; return size;
} }
return 0; return 0;
@ -264,65 +240,105 @@ Buffer::Size Buffer::getBufferGPUMemoryUsage() {
return Context::getBufferGPUMemoryUsage(); return Context::getBufferGPUMemoryUsage();
} }
Buffer::Buffer() : Buffer::Buffer(Size pageSize) :
Resource(), _pageSize(pageSize) {
_sysmem(new Sysmem()) {
_bufferCPUCount++; _bufferCPUCount++;
} }
Buffer::Buffer(Size size, const Byte* bytes) : Buffer::Buffer(Size size, const Byte* bytes, Size pageSize) : Buffer(pageSize) {
Resource(), setData(size, bytes);
_sysmem(new Sysmem(size, bytes)) {
_bufferCPUCount++;
Buffer::updateBufferCPUMemoryUsage(0, _sysmem->getSize());
} }
Buffer::Buffer(const Buffer& buf) : Buffer::Buffer(const Buffer& buf) : Buffer(buf._pageSize) {
Resource(), setData(buf.getSize(), buf.getData());
_sysmem(new Sysmem(buf.getSysmem())) {
_bufferCPUCount++;
Buffer::updateBufferCPUMemoryUsage(0, _sysmem->getSize());
} }
Buffer& Buffer::operator=(const Buffer& buf) { Buffer& Buffer::operator=(const Buffer& buf) {
(*_sysmem) = buf.getSysmem(); const_cast<Size&>(_pageSize) = buf._pageSize;
setData(buf.getSize(), buf.getData());
return (*this); return (*this);
} }
Buffer::~Buffer() { Buffer::~Buffer() {
_bufferCPUCount--; _bufferCPUCount--;
Buffer::updateBufferCPUMemoryUsage(_sysmem.getSize(), 0);
if (_sysmem) {
Buffer::updateBufferCPUMemoryUsage(_sysmem->getSize(), 0);
delete _sysmem;
_sysmem = NULL;
}
} }
Buffer::Size Buffer::resize(Size size) { Buffer::Size Buffer::resize(Size size) {
_end = size;
auto prevSize = editSysmem().getSize(); auto prevSize = editSysmem().getSize();
auto newSize = editSysmem().resize(size); if (prevSize < size) {
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize); auto newPages = getRequiredPageCount();
return newSize; auto newSize = newPages * _pageSize;
editSysmem().resize(newSize);
// All new pages start off as clean, because they haven't been populated by data
_pages.resize(newPages, 0);
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize);
}
return _end;
} }
void Buffer::markDirty(Size offset, Size bytes) {
if (!bytes) {
return;
}
_flags |= DIRTY;
// Find the starting page
Size startPage = (offset / _pageSize);
// Non-zero byte count, so at least one page is dirty
Size pageCount = 1;
// How much of the page is after the offset?
Size remainder = _pageSize - (offset % _pageSize);
// If there are more bytes than page space remaining, we need to increase the page count
if (bytes > remainder) {
// Get rid of the amount that will fit in the current page
bytes -= remainder;
pageCount += (bytes / _pageSize);
if (bytes % _pageSize) {
++pageCount;
}
}
// Mark the pages dirty
for (Size i = 0; i < pageCount; ++i) {
_pages[i + startPage] |= DIRTY;
}
}
Buffer::Size Buffer::setData(Size size, const Byte* data) { Buffer::Size Buffer::setData(Size size, const Byte* data) {
auto prevSize = editSysmem().getSize(); resize(size);
auto newSize = editSysmem().setData(size, data); setSubData(0, size, data);
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize); return _end;
return newSize;
} }
Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) { Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) {
return editSysmem().setSubData( offset, size, data); auto changedBytes = editSysmem().setSubData(offset, size, data);
if (changedBytes) {
markDirty(offset, changedBytes);
}
return changedBytes;
} }
Buffer::Size Buffer::append(Size size, const Byte* data) { Buffer::Size Buffer::append(Size size, const Byte* data) {
auto prevSize = editSysmem().getSize(); auto offset = _end;
auto newSize = editSysmem().append( size, data); resize(_end + size);
Buffer::updateBufferCPUMemoryUsage(prevSize, newSize); setSubData(offset, size, data);
return newSize; return _end;
}
Buffer::Size Buffer::getSize() const {
Q_ASSERT(getSysmem().getSize() >= _end);
return _end;
}
Buffer::Size Buffer::getRequiredPageCount() const {
Size result = _end / _pageSize;
if (_end % _pageSize) {
++result;
}
return result;
} }
const Element BufferView::DEFAULT_ELEMENT = Element( gpu::SCALAR, gpu::UINT8, gpu::RAW ); const Element BufferView::DEFAULT_ELEMENT = Element( gpu::SCALAR, gpu::UINT8, gpu::RAW );

View file

@ -88,10 +88,10 @@ protected:
// Access the byte array. // Access the byte array.
// The edit version allow to map data. // The edit version allow to map data.
const Byte* readData() const { return _data; } const Byte* readData() const { return _data; }
Byte* editData() { _stamp++; return _data; } Byte* editData() { return _data; }
template< typename T > const T* read() const { return reinterpret_cast< T* > ( _data ); } template< typename T > const T* read() const { return reinterpret_cast< T* > ( _data ); }
template< typename T > T* edit() { _stamp++; return reinterpret_cast< T* > ( _data ); } template< typename T > T* edit() { return reinterpret_cast< T* > ( _data ); }
// Access the current version of the sysmem, used to compare if copies are in sync // Access the current version of the sysmem, used to compare if copies are in sync
Stamp getStamp() const { return _stamp; } Stamp getStamp() const { return _stamp; }
@ -102,9 +102,9 @@ protected:
bool isAvailable() const { return (_data != 0); } bool isAvailable() const { return (_data != 0); }
private: private:
Stamp _stamp; Stamp _stamp { 0 };
Size _size; Size _size { 0 };
Byte* _data; Byte* _data { nullptr };
}; };
}; };
@ -115,22 +115,28 @@ class Buffer : public Resource {
static void updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); static void updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
public: public:
enum Flag {
DIRTY = 0x01,
};
// Currently only one flag... 'dirty'
using PageFlags = std::vector<uint8_t>;
static const Size DEFAULT_PAGE_SIZE = 4096;
static uint32_t getBufferCPUCount(); static uint32_t getBufferCPUCount();
static Size getBufferCPUMemoryUsage(); static Size getBufferCPUMemoryUsage();
static uint32_t getBufferGPUCount(); static uint32_t getBufferGPUCount();
static Size getBufferGPUMemoryUsage(); static Size getBufferGPUMemoryUsage();
Buffer(); Buffer(Size pageSize = DEFAULT_PAGE_SIZE);
Buffer(Size size, const Byte* bytes); Buffer(Size size, const Byte* bytes, Size pageSize = DEFAULT_PAGE_SIZE);
Buffer(const Buffer& buf); // deep copy of the sysmem buffer Buffer(const Buffer& buf); // deep copy of the sysmem buffer
Buffer& operator=(const Buffer& buf); // deep copy of the sysmem buffer Buffer& operator=(const Buffer& buf); // deep copy of the sysmem buffer
~Buffer(); ~Buffer();
// The size in bytes of data stored in the buffer // The size in bytes of data stored in the buffer
Size getSize() const { return getSysmem().getSize(); } Size getSize() const;
const Byte* getData() const { return getSysmem().readData(); } const Byte* getData() const { return getSysmem().readData(); }
Byte* editData() { return editSysmem().editData(); }
// Resize the buffer // Resize the buffer
// Keep previous data [0 to min(pSize, mSize)] // Keep previous data [0 to min(pSize, mSize)]
Size resize(Size pSize); Size resize(Size pSize);
@ -143,6 +149,23 @@ public:
// \return the number of bytes copied // \return the number of bytes copied
Size setSubData(Size offset, Size size, const Byte* data); Size setSubData(Size offset, Size size, const Byte* data);
template <typename T>
Size setSubData(Size index, const T& t) {
Size offset = index * sizeof(T);
Size size = sizeof(T);
return setSubData(offset, size, reinterpret_cast<const Byte*>(&t));
}
template <typename T>
Size setSubData(Size index, const std::vector<T>& t) {
if (t.empty()) {
return 0;
}
Size offset = index * sizeof(T);
Size size = t.size() * sizeof(T);
return setSubData(offset, size, reinterpret_cast<const Byte*>(&t[0]));
}
// Append new data at the end of the current buffer // Append new data at the end of the current buffer
// do a resize( size + getSize) and copy the new data // do a resize( size + getSize) and copy the new data
// \return the number of bytes copied // \return the number of bytes copied
@ -155,18 +178,38 @@ public:
template <typename T> template <typename T>
Size append(const std::vector<T>& t) { Size append(const std::vector<T>& t) {
if (t.empty()) {
return _end;
}
return append(sizeof(T) * t.size(), reinterpret_cast<const Byte*>(&t[0])); return append(sizeof(T) * t.size(), reinterpret_cast<const Byte*>(&t[0]));
} }
// Access the sysmem object.
const Sysmem& getSysmem() const { assert(_sysmem); return (*_sysmem); }
Sysmem& editSysmem() { assert(_sysmem); return (*_sysmem); }
const GPUObjectPointer gpuObject {}; const GPUObjectPointer gpuObject {};
protected: protected:
void markDirty(Size offset, Size bytes);
Sysmem* _sysmem = NULL; template <typename T>
void markDirty(Size index, Size count = 1) {
markDirty(sizeof(T) * index, sizeof(T) * count);
}
// Access the sysmem object, limited to ourselves and GPUObject derived classes
const Sysmem& getSysmem() const { return _sysmem; }
Sysmem& editSysmem() { return _sysmem; }
Byte* editData() { return editSysmem().editData(); }
Size getRequiredPageCount() const;
Size _end { 0 };
mutable uint8_t _flags;
mutable PageFlags _pages;
const Size _pageSize;
Sysmem _sysmem;
// FIXME find a more generic way to do this.
friend class GLBackend;
friend class BufferView;
}; };
typedef std::shared_ptr<Buffer> BufferPointer; typedef std::shared_ptr<Buffer> BufferPointer;
@ -290,8 +333,14 @@ public:
int _stride; int _stride;
}; };
#if 0
// Direct memory access to the buffer contents is incompatible with the paging memory scheme
template <typename T> Iterator<T> begin() { return Iterator<T>(&edit<T>(0), _stride); } template <typename T> Iterator<T> begin() { return Iterator<T>(&edit<T>(0), _stride); }
template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>()), _stride); } template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>()), _stride); }
#else
template <typename T> Iterator<const T> begin() const { return Iterator<const T>(&get<T>(), _stride); }
template <typename T> Iterator<const T> end() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
#endif
template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(), _stride); } template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(), _stride); }
template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); } template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
@ -328,6 +377,7 @@ public:
qDebug() << "Accessing buffer outside the BufferView range, element size = " << sizeof(T) << " when bufferView size = " << _size; qDebug() << "Accessing buffer outside the BufferView range, element size = " << sizeof(T) << " when bufferView size = " << _size;
} }
#endif #endif
_buffer->markDirty(_offset, sizeof(T));
T* t = (reinterpret_cast<T*> (_buffer->editData() + _offset)); T* t = (reinterpret_cast<T*> (_buffer->editData() + _offset));
return *(t); return *(t);
} }
@ -361,6 +411,7 @@ public:
qDebug() << "Accessing buffer outside the BufferView range, index = " << index << " number elements = " << getNum<T>(); qDebug() << "Accessing buffer outside the BufferView range, index = " << index << " number elements = " << getNum<T>();
} }
#endif #endif
_buffer->markDirty(elementOffset, sizeof(T));
return *(reinterpret_cast<T*> (_buffer->editData() + elementOffset)); return *(reinterpret_cast<T*> (_buffer->editData() + elementOffset));
} }
}; };

View file

@ -98,6 +98,7 @@ void Material::setFresnel(const Color& fresnel, bool isSRGB) {
} }
void Material::setMetallic(float metallic) { void Material::setMetallic(float metallic) {
metallic = glm::clamp(metallic, 0.0f, 1.0f);
_key.setMetallic(metallic > 0.0f); _key.setMetallic(metallic > 0.0f);
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
_schemaBuffer.edit<Schema>()._metallic = metallic; _schemaBuffer.edit<Schema>()._metallic = metallic;

View file

@ -118,29 +118,18 @@ AnimDebugDraw::AnimDebugDraw() :
// HACK: add red, green and blue axis at (1,1,1) // HACK: add red, green and blue axis at (1,1,1)
_animDebugDrawData->_vertexBuffer->resize(sizeof(Vertex) * 6); _animDebugDrawData->_vertexBuffer->resize(sizeof(Vertex) * 6);
Vertex* data = (Vertex*)_animDebugDrawData->_vertexBuffer->editData();
static std::vector<Vertex> vertices({
data[0].pos = glm::vec3(1.0, 1.0f, 1.0f); Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(255, 0, 0, 255) },
data[0].rgba = toRGBA(255, 0, 0, 255); Vertex { glm::vec3(2.0, 1.0f, 1.0f), toRGBA(255, 0, 0, 255) },
data[1].pos = glm::vec3(2.0, 1.0f, 1.0f); Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(0, 255, 0, 255) },
data[1].rgba = toRGBA(255, 0, 0, 255); Vertex { glm::vec3(1.0, 2.0f, 1.0f), toRGBA(0, 255, 0, 255) },
Vertex { glm::vec3(1.0, 1.0f, 1.0f), toRGBA(0, 0, 255, 255) },
data[2].pos = glm::vec3(1.0, 1.0f, 1.0f); Vertex { glm::vec3(1.0, 1.0f, 2.0f), toRGBA(0, 0, 255, 255) },
data[2].rgba = toRGBA(0, 255, 0, 255); });
data[3].pos = glm::vec3(1.0, 2.0f, 1.0f); static std::vector<uint16_t> indices({ 0, 1, 2, 3, 4, 5 });
data[3].rgba = toRGBA(0, 255, 0, 255); _animDebugDrawData->_vertexBuffer->setSubData<Vertex>(0, vertices);
_animDebugDrawData->_indexBuffer->setSubData<uint16_t>(0, indices);
data[4].pos = glm::vec3(1.0, 1.0f, 1.0f);
data[4].rgba = toRGBA(0, 0, 255, 255);
data[5].pos = glm::vec3(1.0, 1.0f, 2.0f);
data[5].rgba = toRGBA(0, 0, 255, 255);
_animDebugDrawData->_indexBuffer->resize(sizeof(uint16_t) * 6);
uint16_t* indices = (uint16_t*)_animDebugDrawData->_indexBuffer->editData();
for (int i = 0; i < 6; i++) {
indices[i] = i;
}
} }
AnimDebugDraw::~AnimDebugDraw() { AnimDebugDraw::~AnimDebugDraw() {
@ -356,9 +345,13 @@ void AnimDebugDraw::update() {
numVerts += (int)DebugDraw::getInstance().getRays().size() * VERTICES_PER_RAY; numVerts += (int)DebugDraw::getInstance().getRays().size() * VERTICES_PER_RAY;
// allocate verts! // allocate verts!
data._vertexBuffer->resize(sizeof(Vertex) * numVerts); std::vector<Vertex> vertices;
Vertex* verts = (Vertex*)data._vertexBuffer->editData(); vertices.resize(numVerts);
Vertex* v = verts; //Vertex* verts = (Vertex*)data._vertexBuffer->editData();
Vertex* v = nullptr;
if (numVerts) {
v = &vertices[0];
}
// draw absolute poses // draw absolute poses
for (auto& iter : _absolutePoses) { for (auto& iter : _absolutePoses) {
@ -381,6 +374,8 @@ void AnimDebugDraw::update() {
} }
} }
} }
data._vertexBuffer->resize(sizeof(Vertex) * numVerts);
data._vertexBuffer->setSubData<Vertex>(0, vertices);
// draw markers from shared DebugDraw singleton // draw markers from shared DebugDraw singleton
for (auto& iter : markerMap) { for (auto& iter : markerMap) {
@ -408,20 +403,19 @@ void AnimDebugDraw::update() {
} }
DebugDraw::getInstance().clearRays(); DebugDraw::getInstance().clearRays();
assert(numVerts == (v - verts)); assert((!numVerts && !v) || (numVerts == (v - &vertices[0])));
render::Item::Bound theBound; render::Item::Bound theBound;
for (int i = 0; i < numVerts; i++) { for (int i = 0; i < numVerts; i++) {
theBound += verts[i].pos; theBound += vertices[i].pos;
} }
data._bound = theBound; data._bound = theBound;
data._isVisible = (numVerts > 0); data._isVisible = (numVerts > 0);
data._indexBuffer->resize(sizeof(uint16_t) * numVerts); data._indexBuffer->resize(sizeof(uint16_t) * numVerts);
uint16_t* indices = (uint16_t*)data._indexBuffer->editData();
for (int i = 0; i < numVerts; i++) { for (int i = 0; i < numVerts; i++) {
indices[i] = i; data._indexBuffer->setSubData<uint16_t>(i, (uint16_t)i);;
} }
}); });
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);

View file

@ -59,7 +59,8 @@ void FramebufferCache::createPrimaryFramebuffer() {
_deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create());
auto colorFormat = gpu::Element::COLOR_RGBA_32; // auto colorFormat = gpu::Element::COLOR_RGBA_32;
auto colorFormat = gpu::Element::COLOR_SRGBA_32;
auto width = _frameBufferSize.width(); auto width = _frameBufferSize.width();
auto height = _frameBufferSize.height(); auto height = _frameBufferSize.height();
@ -95,10 +96,7 @@ void FramebufferCache::createPrimaryFramebuffer() {
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
// FIXME: Decide on the proper one, let s stick to R11G11B10 for now
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler));
_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler)); _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler));
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler));
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
@ -212,7 +210,7 @@ gpu::TexturePointer FramebufferCache::getLightingTexture() {
gpu::FramebufferPointer FramebufferCache::getFramebuffer() { gpu::FramebufferPointer FramebufferCache::getFramebuffer() {
if (_cachedFramebuffers.isEmpty()) { if (_cachedFramebuffers.isEmpty()) {
_cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height()))); _cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_SRGBA_32, _frameBufferSize.width(), _frameBufferSize.height())));
} }
gpu::FramebufferPointer result = _cachedFramebuffers.front(); gpu::FramebufferPointer result = _cachedFramebuffers.front();
_cachedFramebuffers.pop_front(); _cachedFramebuffers.pop_front();

View file

@ -18,7 +18,7 @@
// the interpolated normal // the interpolated normal
in vec3 _normal; in vec3 _normal;
in vec3 _modelNormal; in vec3 _modelNormal;
in vec3 _color; in vec4 _color;
in vec2 _texCoord0; in vec2 _texCoord0;
in vec4 _position; in vec4 _position;

View file

@ -116,35 +116,25 @@ void DrawStatus::run(const SceneContextPointer& sceneContext,
// FIrst thing, we collect the bound and the status for all the items we want to render // FIrst thing, we collect the bound and the status for all the items we want to render
int nbItems = 0; int nbItems = 0;
{ {
if (!_itemBounds) { _itemBounds.resize(inItems.size());
_itemBounds = std::make_shared<gpu::Buffer>(); _itemStatus.resize(inItems.size());
} _itemCells.resize(inItems.size());
if (!_itemStatus) {
_itemStatus = std::make_shared<gpu::Buffer>();;
}
if (!_itemCells) {
_itemCells = std::make_shared<gpu::Buffer>();;
}
_itemBounds->resize((inItems.size() * sizeof(AABox))); // AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
_itemStatus->resize((inItems.size() * NUM_STATUS_VEC4_PER_ITEM * sizeof(glm::vec4))); // glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
_itemCells->resize((inItems.size() * sizeof(Octree::Location))); // Octree::Location* itemCell = reinterpret_cast<Octree::Location*> (_itemCells->editData());
for (size_t i = 0; i < inItems.size(); ++i) {
AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData()); const auto& item = inItems[i];
glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
Octree::Location* itemCell = reinterpret_cast<Octree::Location*> (_itemCells->editData());
for (auto& item : inItems) {
if (!item.bound.isInvalid()) { if (!item.bound.isInvalid()) {
if (!item.bound.isNull()) { if (!item.bound.isNull()) {
(*itemAABox) = item.bound; _itemBounds[i] = item.bound;
} else { } else {
(*itemAABox).setBox(item.bound.getCorner(), 0.1f); _itemBounds[i].setBox(item.bound.getCorner(), 0.1f);
} }
auto& itemScene = scene->getItem(item.id); auto& itemScene = scene->getItem(item.id);
_itemCells[i] = scene->getSpatialTree().getCellLocation(itemScene.getCell());
(*itemCell) = scene->getSpatialTree().getCellLocation(itemScene.getCell());
auto itemStatusPointer = itemScene.getStatus(); auto itemStatusPointer = itemScene.getStatus();
if (itemStatusPointer) { if (itemStatusPointer) {
@ -152,25 +142,19 @@ void DrawStatus::run(const SceneContextPointer& sceneContext,
auto&& currentStatusValues = itemStatusPointer->getCurrentValues(); auto&& currentStatusValues = itemStatusPointer->getCurrentValues();
int valueNum = 0; int valueNum = 0;
for (int vec4Num = 0; vec4Num < NUM_STATUS_VEC4_PER_ITEM; vec4Num++) { for (int vec4Num = 0; vec4Num < NUM_STATUS_VEC4_PER_ITEM; vec4Num++) {
(*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData()); auto& value = (vec4Num ? _itemStatus[i].first : _itemStatus[i].second);
value = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
for (int component = 0; component < VEC4_LENGTH; component++) { for (int component = 0; component < VEC4_LENGTH; component++) {
valueNum = vec4Num * VEC4_LENGTH + component; valueNum = vec4Num * VEC4_LENGTH + component;
if (valueNum < (int)currentStatusValues.size()) { if (valueNum < (int)currentStatusValues.size()) {
(*itemStatus)[component] = currentStatusValues[valueNum].getPackedData(); value[component] = currentStatusValues[valueNum].getPackedData();
} }
} }
itemStatus++;
} }
} else { } else {
(*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData()); _itemStatus[i].first = _itemStatus[i].second = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
itemStatus++;
(*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
itemStatus++;
} }
nbItems++; nbItems++;
itemAABox++;
itemCell++;
} }
} }
} }
@ -194,25 +178,20 @@ void DrawStatus::run(const SceneContextPointer& sceneContext,
// bind the one gpu::Pipeline we need // bind the one gpu::Pipeline we need
batch.setPipeline(getDrawItemBoundsPipeline()); batch.setPipeline(getDrawItemBoundsPipeline());
AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData()); //AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData()); //glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
Octree::Location* itemCell = reinterpret_cast<Octree::Location*> (_itemCells->editData()); //Octree::Location* itemCell = reinterpret_cast<Octree::Location*> (_itemCells->editData());
const unsigned int VEC3_ADRESS_OFFSET = 3; const unsigned int VEC3_ADRESS_OFFSET = 3;
if (_showDisplay) { if (_showDisplay) {
for (int i = 0; i < nbItems; i++) { for (int i = 0; i < nbItems; i++) {
batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)&(_itemBounds[i]));
batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*)&(_itemBounds[i])) + VEC3_ADRESS_OFFSET);
glm::ivec4 cellLocation(itemCell->pos.x, itemCell->pos.y, itemCell->pos.z, itemCell->depth);
glm::ivec4 cellLocation(_itemCells[i].pos, _itemCells[i].depth);
batch._glUniform4iv(_drawItemCellLocLoc, 1, ((const int*)(&cellLocation))); batch._glUniform4iv(_drawItemCellLocLoc, 1, ((const int*)(&cellLocation)));
batch.draw(gpu::LINES, 24, 0); batch.draw(gpu::LINES, 24, 0);
itemCell++;
} }
} }
@ -222,10 +201,10 @@ void DrawStatus::run(const SceneContextPointer& sceneContext,
if (_showNetwork) { if (_showNetwork) {
for (int i = 0; i < nbItems; i++) { for (int i = 0; i < nbItems; i++) {
batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*)&(_itemBounds[i]));
batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*)&(_itemBounds[i])) + VEC3_ADRESS_OFFSET);
batch._glUniform4iv(_drawItemStatusValue0Loc, 1, (const int*)(itemStatus + NUM_STATUS_VEC4_PER_ITEM * i)); batch._glUniform4iv(_drawItemStatusValue0Loc, 1, (const int*)&(_itemStatus[i].first));
batch._glUniform4iv(_drawItemStatusValue1Loc, 1, (const int*)(itemStatus + NUM_STATUS_VEC4_PER_ITEM * i + 1)); batch._glUniform4iv(_drawItemStatusValue1Loc, 1, (const int*)&(_itemStatus[i].second));
batch.draw(gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM, 0); batch.draw(gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM, 0);
} }
} }

View file

@ -68,9 +68,13 @@ namespace render {
gpu::Stream::FormatPointer _drawItemFormat; gpu::Stream::FormatPointer _drawItemFormat;
gpu::PipelinePointer _drawItemBoundsPipeline; gpu::PipelinePointer _drawItemBoundsPipeline;
gpu::PipelinePointer _drawItemStatusPipeline; gpu::PipelinePointer _drawItemStatusPipeline;
gpu::BufferPointer _itemBounds;
gpu::BufferPointer _itemCells; std::vector<AABox> _itemBounds;
gpu::BufferPointer _itemStatus; std::vector<std::pair<glm::ivec4, glm::ivec4>> _itemStatus;
std::vector<Octree::Location> _itemCells;
//gpu::BufferPointer _itemBounds;
//gpu::BufferPointer _itemCells;
//gpu::BufferPointer _itemStatus;
gpu::TexturePointer _statusIconMap; gpu::TexturePointer _statusIconMap;
}; };
} }

View file

@ -62,8 +62,6 @@
#include "MIDIEvent.h" #include "MIDIEvent.h"
std::atomic<bool> ScriptEngine::_stoppingAllScripts { false };
static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3"; static const QString SCRIPT_EXCEPTION_FORMAT = "[UncaughtException] %1 in %2:%3";
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature) Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
@ -756,7 +754,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString&
QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
return QScriptValue(); // bail early return QScriptValue(); // bail early
} }
@ -792,7 +790,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
} }
void ScriptEngine::run() { void ScriptEngine::run() {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
return; // bail early - avoid setting state in init(), as evaluate() will bail too return; // bail early - avoid setting state in init(), as evaluate() will bail too
} }
@ -1025,7 +1023,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int
} }
QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename(); qCDebug(scriptengine) << "Script.setInterval() while shutting down is ignored... parent script:" << getFilename();
return NULL; // bail early return NULL; // bail early
} }
@ -1034,7 +1032,7 @@ QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS)
} }
QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename(); qCDebug(scriptengine) << "Script.setTimeout() while shutting down is ignored... parent script:" << getFilename();
return NULL; // bail early return NULL; // bail early
} }
@ -1086,7 +1084,7 @@ void ScriptEngine::print(const QString& message) {
// If no callback is specified, the included files will be loaded synchronously and will block execution until // If no callback is specified, the included files will be loaded synchronously and will block execution until
// all of the files have finished loading. // all of the files have finished loading.
void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) { void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
qCDebug(scriptengine) << "Script.include() while shutting down is ignored..." qCDebug(scriptengine) << "Script.include() while shutting down is ignored..."
<< "includeFiles:" << includeFiles << "parent script:" << getFilename(); << "includeFiles:" << includeFiles << "parent script:" << getFilename();
return; // bail early return; // bail early
@ -1184,7 +1182,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
} }
void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
qCDebug(scriptengine) << "Script.include() while shutting down is ignored... " qCDebug(scriptengine) << "Script.include() while shutting down is ignored... "
<< "includeFile:" << includeFile << "parent script:" << getFilename(); << "includeFile:" << includeFile << "parent script:" << getFilename();
return; // bail early return; // bail early
@ -1199,7 +1197,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
// as a stand-alone script. To accomplish this, the ScriptEngine class just emits a signal which // as a stand-alone script. To accomplish this, the ScriptEngine class just emits a signal which
// the Application or other context will connect to in order to know to actually load the script // the Application or other context will connect to in order to know to actually load the script
void ScriptEngine::load(const QString& loadFile) { void ScriptEngine::load(const QString& loadFile) {
if (_stoppingAllScripts) { if (DependencyManager::get<ScriptEngines>()->isStopped()) {
qCDebug(scriptengine) << "Script.load() while shutting down is ignored... " qCDebug(scriptengine) << "Script.load() while shutting down is ignored... "
<< "loadFile:" << loadFile << "parent script:" << getFilename(); << "loadFile:" << loadFile << "parent script:" << getFilename();
return; // bail early return; // bail early

View file

@ -83,6 +83,10 @@ public:
/// run the script in the callers thread, exit when stop() is called. /// run the script in the callers thread, exit when stop() is called.
void run(); void run();
void waitTillDoneRunning();
QString getFilename() const;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can // NOTE - these are NOT intended to be public interfaces available to scripts, the are only Q_INVOKABLE so we can
// properly ensure they are only called on the correct thread // properly ensure they are only called on the correct thread
@ -199,8 +203,6 @@ protected:
qint64 _lastUpdate; qint64 _lastUpdate;
void init(); void init();
QString getFilename() const;
void waitTillDoneRunning();
bool evaluatePending() const { return _evaluatesPending > 0; } bool evaluatePending() const { return _evaluatesPending > 0; }
void timerFired(); void timerFired();
void stopAllTimers(); void stopAllTimers();
@ -232,9 +234,6 @@ protected:
QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty. QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty.
void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation); void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function<void()> operation);
void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args);
friend class ScriptEngines;
static std::atomic<bool> _stoppingAllScripts;
}; };
#endif // hifi_ScriptEngine_h #endif // hifi_ScriptEngine_h

View file

@ -119,26 +119,27 @@ void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
} }
void ScriptEngines::addScriptEngine(ScriptEngine* engine) { void ScriptEngines::addScriptEngine(ScriptEngine* engine) {
_allScriptsMutex.lock(); if (_isStopped) {
_allKnownScriptEngines.insert(engine); engine->deleteLater();
_allScriptsMutex.unlock(); } else {
QMutexLocker locker(&_allScriptsMutex);
_allKnownScriptEngines.insert(engine);
}
} }
void ScriptEngines::removeScriptEngine(ScriptEngine* engine) { void ScriptEngines::removeScriptEngine(ScriptEngine* engine) {
// If we're not already in the middle of stopping all scripts, then we should remove ourselves // If we're not already in the middle of stopping all scripts, then we should remove ourselves
// from the list of running scripts. We don't do this if we're in the process of stopping all scripts // from the list of running scripts. We don't do this if we're in the process of stopping all scripts
// because that method removes scripts from its list as it iterates them // because that method removes scripts from its list as it iterates them
if (!_stoppingAllScripts) { if (!_isStopped) {
_allScriptsMutex.lock(); QMutexLocker locker(&_allScriptsMutex);
_allKnownScriptEngines.remove(engine); _allKnownScriptEngines.remove(engine);
_allScriptsMutex.unlock();
} }
} }
void ScriptEngines::shutdownScripting() { void ScriptEngines::shutdownScripting() {
_allScriptsMutex.lock(); _isStopped = true;
_stoppingAllScripts = true; QMutexLocker locker(&_allScriptsMutex);
ScriptEngine::_stoppingAllScripts = true;
qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size(); qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines); QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
@ -174,8 +175,6 @@ void ScriptEngines::shutdownScripting() {
i.remove(); i.remove();
} }
} }
_stoppingAllScripts = false;
_allScriptsMutex.unlock();
qCDebug(scriptengine) << "DONE Stopping all scripts...."; qCDebug(scriptengine) << "DONE Stopping all scripts....";
} }
@ -499,7 +498,6 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
} }
} }
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) { void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) {
bool removed = false; bool removed = false;
{ {

View file

@ -86,16 +86,17 @@ protected:
void onScriptEngineLoaded(const QString& scriptFilename); void onScriptEngineLoaded(const QString& scriptFilename);
void onScriptEngineError(const QString& scriptFilename); void onScriptEngineError(const QString& scriptFilename);
void launchScriptEngine(ScriptEngine* engine); void launchScriptEngine(ScriptEngine* engine);
bool isStopped() const { return _isStopped; }
QReadWriteLock _scriptEnginesHashLock; QReadWriteLock _scriptEnginesHashLock;
QHash<QUrl, ScriptEngine*> _scriptEnginesHash; QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
QSet<ScriptEngine*> _allKnownScriptEngines; QSet<ScriptEngine*> _allKnownScriptEngines;
QMutex _allScriptsMutex; QMutex _allScriptsMutex;
std::atomic<bool> _stoppingAllScripts { false };
std::list<ScriptInitializer> _scriptInitializers; std::list<ScriptInitializer> _scriptInitializers;
mutable Setting::Handle<QString> _scriptsLocationHandle; mutable Setting::Handle<QString> _scriptsLocationHandle;
ScriptsModel _scriptsModel; ScriptsModel _scriptsModel;
ScriptsModelFilter _scriptsModelFilter; ScriptsModelFilter _scriptsModelFilter;
std::atomic<bool> _isStopped { false };
}; };
QUrl normalizeScriptURL(const QUrl& rawScriptURL); QUrl normalizeScriptURL(const QUrl& rawScriptURL);

View file

@ -262,6 +262,14 @@ eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(goActive);
eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(goActive); eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(goActive);
eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(goActive); eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(goActive);
eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(goActive); eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(goActive);
eventMapping.from(Controller.Standard.LT).peek().to(goActive);
eventMapping.from(Controller.Standard.LB).peek().to(goActive);
eventMapping.from(Controller.Standard.LS).peek().to(goActive);
eventMapping.from(Controller.Standard.RT).peek().to(goActive);
eventMapping.from(Controller.Standard.RB).peek().to(goActive);
eventMapping.from(Controller.Standard.RS).peek().to(goActive);
eventMapping.from(Controller.Standard.Back).peek().to(goActive);
eventMapping.from(Controller.Standard.Start).peek().to(goActive);
Controller.enableMapping(eventMappingName); Controller.enableMapping(eventMappingName);
Script.scriptEnding.connect(function () { Script.scriptEnding.connect(function () {
@ -270,4 +278,4 @@ Script.scriptEnding.connect(function () {
Controller.disableMapping(eventMappingName); Controller.disableMapping(eventMappingName);
Controller.mousePressEvent.disconnect(goActive); Controller.mousePressEvent.disconnect(goActive);
Controller.keyPressEvent.disconnect(maybeGoActive); Controller.keyPressEvent.disconnect(maybeGoActive);
}); });

View file

@ -739,6 +739,9 @@ function MyController(hand) {
}; };
this.propsArePhysical = function(props) { this.propsArePhysical = function(props) {
if (!props.dynamic) {
return false;
}
var isPhysical = (props.shapeType && props.shapeType != 'none'); var isPhysical = (props.shapeType && props.shapeType != 'none');
return isPhysical; return isPhysical;
} }

View file

@ -9,7 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
var PopUpMenu = function(properties) { var PopUpMenu = function (properties) {
var value = properties.value, var value = properties.value,
promptOverlay, promptOverlay,
valueOverlay, valueOverlay,
@ -21,9 +21,8 @@ var PopUpMenu = function(properties) {
MIN_MAX_BUTTON_SVG_WIDTH = 17.1, MIN_MAX_BUTTON_SVG_WIDTH = 17.1,
MIN_MAX_BUTTON_SVG_HEIGHT = 32.5, MIN_MAX_BUTTON_SVG_HEIGHT = 32.5,
MIN_MAX_BUTTON_WIDTH = 14, MIN_MAX_BUTTON_WIDTH = 14,
MIN_MAX_BUTTON_HEIGHT = MIN_MAX_BUTTON_WIDTH; MIN_MAX_BUTTON_HEIGHT = MIN_MAX_BUTTON_WIDTH,
MIN_MAX_BUTTON_SVG = Script.resolvePath("assets/images/tools/min-max-toggle.svg");
MIN_MAX_BUTTON_SVG = Script.resolvePath("assets/images/tools/min-max-toggle.svg");
function positionDisplayOptions() { function positionDisplayOptions() {
var y, var y,
@ -203,7 +202,7 @@ var PopUpMenu = function(properties) {
width: MIN_MAX_BUTTON_SVG_WIDTH, width: MIN_MAX_BUTTON_SVG_WIDTH,
height: MIN_MAX_BUTTON_SVG_HEIGHT / 2 height: MIN_MAX_BUTTON_SVG_HEIGHT / 2
}, },
color: properties.buttonColor, //color: properties.buttonColor,
alpha: properties.buttonAlpha, alpha: properties.buttonAlpha,
visible: properties.visible visible: properties.visible
}); });
@ -218,11 +217,10 @@ var PopUpMenu = function(properties) {
}; };
}; };
var usersWindow = (function() { var usersWindow = (function () {
var baseURL = Script.resolvePath("assets/images/tools/"); var baseURL = Script.resolvePath("assets/images/tools/"),
WINDOW_WIDTH = 260,
var WINDOW_WIDTH = 260,
WINDOW_MARGIN = 12, WINDOW_MARGIN = 12,
WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct
WINDOW_FONT = { WINDOW_FONT = {
@ -248,6 +246,17 @@ var usersWindow = (function() {
WINDOW_BACKGROUND_ALPHA = 0.8, WINDOW_BACKGROUND_ALPHA = 0.8,
windowPane, windowPane,
windowHeading, windowHeading,
// Window border is similar to that of edit.js.
WINDOW_BORDER_WIDTH = WINDOW_WIDTH + 2 * WINDOW_BASE_MARGIN,
WINDOW_BORDER_TOP_MARGIN = 2 * WINDOW_BASE_MARGIN,
WINDOW_BORDER_BOTTOM_MARGIN = WINDOW_BASE_MARGIN,
WINDOW_BORDER_LEFT_MARGIN = WINDOW_BASE_MARGIN,
WINDOW_BORDER_RADIUS = 4,
WINDOW_BORDER_COLOR = { red: 255, green: 255, blue: 255 },
WINDOW_BORDER_ALPHA = 0.5,
windowBorder,
MIN_MAX_BUTTON_SVG = baseURL + "min-max-toggle.svg", MIN_MAX_BUTTON_SVG = baseURL + "min-max-toggle.svg",
MIN_MAX_BUTTON_SVG_WIDTH = 17.1, MIN_MAX_BUTTON_SVG_WIDTH = 17.1,
MIN_MAX_BUTTON_SVG_HEIGHT = 32.5, MIN_MAX_BUTTON_SVG_HEIGHT = 32.5,
@ -331,6 +340,7 @@ var usersWindow = (function() {
visibilityControl, visibilityControl,
windowHeight, windowHeight,
windowBorderHeight,
windowTextHeight, windowTextHeight,
windowLineSpacing, windowLineSpacing,
windowLineHeight, // = windowTextHeight + windowLineSpacing windowLineHeight, // = windowTextHeight + windowLineSpacing
@ -356,14 +366,21 @@ var usersWindow = (function() {
MENU_ITEM_AFTER = "Chat...", MENU_ITEM_AFTER = "Chat...",
SETTING_USERS_WINDOW_MINIMIZED = "UsersWindow.Minimized", SETTING_USERS_WINDOW_MINIMIZED = "UsersWindow.Minimized",
SETINGS_USERS_WINDOW_OFFSET = "UsersWindow.Offset",
// +ve x, y values are offset from left, top of screen; -ve from right, bottom.
isVisible = true, isVisible = true,
isMinimized = false, isMinimized = false,
isBorderVisible = false,
viewportHeight, viewport,
isMirrorDisplay = false, isMirrorDisplay = false,
isFullscreenMirror = false, isFullscreenMirror = false,
windowPosition = { }, // Bottom left corner of window pane.
isMovingWindow = false,
movingClickOffset = { x: 0, y: 0 },
isUsingScrollbars = false, isUsingScrollbars = false,
isMovingScrollbar = false, isMovingScrollbar = false,
scrollbarBackgroundPosition = {}, scrollbarBackgroundPosition = {},
@ -379,19 +396,23 @@ var usersWindow = (function() {
if (isMinimized) { if (isMinimized) {
windowHeight = windowTextHeight + WINDOW_MARGIN + WINDOW_BASE_MARGIN; windowHeight = windowTextHeight + WINDOW_MARGIN + WINDOW_BASE_MARGIN;
windowBorderHeight = windowHeight + WINDOW_BORDER_TOP_MARGIN + WINDOW_BORDER_BOTTOM_MARGIN;
return; return;
} }
// Reserve space for title, friends button, and option controls // Reserve space for title, friends button, and option controls
nonUsersHeight = WINDOW_MARGIN + windowLineHeight + FRIENDS_BUTTON_SPACER + FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER + windowLineHeight + VISIBILITY_SPACER + windowLineHeight + WINDOW_BASE_MARGIN; nonUsersHeight = WINDOW_MARGIN + windowLineHeight + FRIENDS_BUTTON_SPACER + FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER
+ windowLineHeight + VISIBILITY_SPACER
+ windowLineHeight + WINDOW_BASE_MARGIN;
// Limit window to height of viewport minus VU meter and mirror if displayed // Limit window to height of viewport above window position minus VU meter and mirror if displayed
windowHeight = linesOfUsers.length * windowLineHeight - windowLineSpacing + nonUsersHeight; windowHeight = linesOfUsers.length * windowLineHeight - windowLineSpacing + nonUsersHeight;
maxWindowHeight = viewportHeight - AUDIO_METER_HEIGHT; maxWindowHeight = windowPosition.y - AUDIO_METER_HEIGHT;
if (isMirrorDisplay && !isFullscreenMirror) { if (isMirrorDisplay && !isFullscreenMirror) {
maxWindowHeight -= MIRROR_HEIGHT; maxWindowHeight -= MIRROR_HEIGHT;
} }
windowHeight = Math.max(Math.min(windowHeight, maxWindowHeight), nonUsersHeight); windowHeight = Math.max(Math.min(windowHeight, maxWindowHeight), nonUsersHeight);
windowBorderHeight = windowHeight + WINDOW_BORDER_TOP_MARGIN + WINDOW_BORDER_BOTTOM_MARGIN;
// Corresponding number of users to actually display // Corresponding number of users to actually display
numUsersToDisplay = Math.max(Math.round((windowHeight - nonUsersHeight) / windowLineHeight), 0); numUsersToDisplay = Math.max(Math.round((windowHeight - nonUsersHeight) / windowLineHeight), 0);
@ -405,38 +426,57 @@ var usersWindow = (function() {
} }
function updateOverlayPositions() { function updateOverlayPositions() {
var y; // Overlay positions are all relative to windowPosition; windowPosition is the position of the windowPane overlay.
var windowLeft = windowPosition.x,
windowTop = windowPosition.y - windowHeight,
x,
y;
Overlays.editOverlay(windowBorder, {
x: windowPosition.x - WINDOW_BORDER_LEFT_MARGIN,
y: windowTop - WINDOW_BORDER_TOP_MARGIN
});
Overlays.editOverlay(windowPane, { Overlays.editOverlay(windowPane, {
y: viewportHeight - windowHeight x: windowLeft,
y: windowTop
}); });
Overlays.editOverlay(windowHeading, { Overlays.editOverlay(windowHeading, {
y: viewportHeight - windowHeight + WINDOW_MARGIN x: windowLeft + WINDOW_MARGIN,
y: windowTop + WINDOW_MARGIN
}); });
Overlays.editOverlay(minimizeButton, { Overlays.editOverlay(minimizeButton, {
y: viewportHeight - windowHeight + WINDOW_MARGIN / 2 x: windowLeft + WINDOW_WIDTH - WINDOW_MARGIN / 2 - MIN_MAX_BUTTON_WIDTH,
y: windowTop + WINDOW_MARGIN / 2
}); });
scrollbarBackgroundPosition.y = viewportHeight - windowHeight + WINDOW_MARGIN + windowTextHeight; scrollbarBackgroundPosition.x = windowLeft + WINDOW_WIDTH - 0.5 * WINDOW_MARGIN - SCROLLBAR_BACKGROUND_WIDTH;
scrollbarBackgroundPosition.y = windowTop + WINDOW_MARGIN + windowTextHeight;
Overlays.editOverlay(scrollbarBackground, { Overlays.editOverlay(scrollbarBackground, {
x: scrollbarBackgroundPosition.x,
y: scrollbarBackgroundPosition.y y: scrollbarBackgroundPosition.y
}); });
scrollbarBarPosition.y = scrollbarBackgroundPosition.y + 1 + scrollbarValue * (scrollbarBackgroundHeight - scrollbarBarHeight - 2); scrollbarBarPosition.y = scrollbarBackgroundPosition.y + 1
+ scrollbarValue * (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
Overlays.editOverlay(scrollbarBar, { Overlays.editOverlay(scrollbarBar, {
x: scrollbarBackgroundPosition.x + 1,
y: scrollbarBarPosition.y y: scrollbarBarPosition.y
}); });
y = viewportHeight - FRIENDS_BUTTON_HEIGHT - DISPLAY_SPACER - windowLineHeight - VISIBILITY_SPACER - windowLineHeight - WINDOW_BASE_MARGIN; x = windowLeft + WINDOW_MARGIN;
y = windowPosition.y - FRIENDS_BUTTON_HEIGHT - DISPLAY_SPACER
- windowLineHeight - VISIBILITY_SPACER
- windowLineHeight - WINDOW_BASE_MARGIN;
Overlays.editOverlay(friendsButton, { Overlays.editOverlay(friendsButton, {
x: x,
y: y y: y
}); });
y += FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER; y += FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER;
displayControl.updatePosition(WINDOW_MARGIN, y); displayControl.updatePosition(x, y);
y += windowLineHeight + VISIBILITY_SPACER; y += windowLineHeight + VISIBILITY_SPACER;
visibilityControl.updatePosition(WINDOW_MARGIN, y); visibilityControl.updatePosition(x, y);
} }
function updateUsersDisplay() { function updateUsersDisplay() {
@ -487,6 +527,10 @@ var usersWindow = (function() {
}); });
} }
Overlays.editOverlay(windowBorder, {
height: windowBorderHeight
});
Overlays.editOverlay(windowPane, { Overlays.editOverlay(windowPane, {
height: windowHeight, height: windowHeight,
text: displayText text: displayText
@ -512,7 +556,7 @@ var usersWindow = (function() {
usersRequest.send(); usersRequest.send();
} }
processUsers = function() { processUsers = function () {
var response, var response,
myUsername, myUsername,
user, user,
@ -565,12 +609,15 @@ var usersWindow = (function() {
} }
}; };
pollUsersTimedOut = function() { pollUsersTimedOut = function () {
print("Error: Request for users status timed out"); print("Error: Request for users status timed out");
usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
}; };
function updateOverlayVisibility() { function updateOverlayVisibility() {
Overlays.editOverlay(windowBorder, {
visible: isVisible && isBorderVisible
});
Overlays.editOverlay(windowPane, { Overlays.editOverlay(windowPane, {
visible: isVisible visible: isVisible
}); });
@ -670,7 +717,7 @@ var usersWindow = (function() {
if (clickedOverlay === windowPane) { if (clickedOverlay === windowPane) {
overlayX = event.x - WINDOW_MARGIN; overlayX = event.x - WINDOW_MARGIN;
overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN - windowLineHeight; overlayY = event.y - windowPosition.y + windowHeight - WINDOW_MARGIN - windowLineHeight;
numLinesBefore = Math.round(overlayY / windowLineHeight); numLinesBefore = Math.round(overlayY / windowLineHeight);
minY = numLinesBefore * windowLineHeight; minY = numLinesBefore * windowLineHeight;
@ -683,7 +730,8 @@ var usersWindow = (function() {
userClicked = firstUserToDisplay + lineClicked; userClicked = firstUserToDisplay + lineClicked;
if (0 <= userClicked && userClicked < linesOfUsers.length && 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[userClicked]].textWidth) { if (0 <= userClicked && userClicked < linesOfUsers.length && 0 <= overlayX
&& overlayX <= usersOnline[linesOfUsers[userClicked]].textWidth) {
//print("Go to " + usersOnline[linesOfUsers[userClicked]].username); //print("Go to " + usersOnline[linesOfUsers[userClicked]].username);
location.goToUser(usersOnline[linesOfUsers[userClicked]].username); location.goToUser(usersOnline[linesOfUsers[userClicked]].username);
} }
@ -735,13 +783,29 @@ var usersWindow = (function() {
friendsWindow.setURL(FRIENDS_WINDOW_URL); friendsWindow.setURL(FRIENDS_WINDOW_URL);
friendsWindow.setVisible(true); friendsWindow.setVisible(true);
friendsWindow.raise(); friendsWindow.raise();
return;
}
if (clickedOverlay === windowBorder) {
movingClickOffset = {
x: event.x - windowPosition.x,
y: event.y - windowPosition.y
};
isMovingWindow = true;
} }
} }
function onMouseMoveEvent(event) { function onMouseMoveEvent(event) {
var isVisible;
if (isMovingScrollbar) { if (isMovingScrollbar) {
if (scrollbarBackgroundPosition.x - WINDOW_MARGIN <= event.x && event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH + WINDOW_MARGIN && scrollbarBackgroundPosition.y - WINDOW_MARGIN <= event.y && event.y <= scrollbarBackgroundPosition.y + scrollbarBackgroundHeight + WINDOW_MARGIN) { if (scrollbarBackgroundPosition.x - WINDOW_MARGIN <= event.x
scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y) / (scrollbarBackgroundHeight - scrollbarBarHeight - 2); && event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH + WINDOW_MARGIN
&& scrollbarBackgroundPosition.y - WINDOW_MARGIN <= event.y
&& event.y <= scrollbarBackgroundPosition.y + scrollbarBackgroundHeight + WINDOW_MARGIN) {
scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y)
/ (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
scrollbarValue = Math.min(Math.max(scrollbarValue, 0.0), 1.0); scrollbarValue = Math.min(Math.max(scrollbarValue, 0.0), 1.0);
firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay)); firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay));
updateOverlayPositions(); updateOverlayPositions();
@ -753,35 +817,95 @@ var usersWindow = (function() {
isMovingScrollbar = false; isMovingScrollbar = false;
} }
} }
if (isMovingWindow) {
windowPosition = {
x: event.x - movingClickOffset.x,
y: event.y - movingClickOffset.y
};
calculateWindowHeight();
updateOverlayPositions();
updateUsersDisplay();
} else {
isVisible = isBorderVisible;
if (isVisible) {
isVisible = windowPosition.x - WINDOW_BORDER_LEFT_MARGIN <= event.x
&& event.x <= windowPosition.x - WINDOW_BORDER_LEFT_MARGIN + WINDOW_BORDER_WIDTH
&& windowPosition.y - windowHeight - WINDOW_BORDER_TOP_MARGIN <= event.y
&& event.y <= windowPosition.y + WINDOW_BORDER_BOTTOM_MARGIN;
} else {
isVisible = windowPosition.x <= event.x && event.x <= windowPosition.x + WINDOW_WIDTH
&& windowPosition.y - windowHeight <= event.y && event.y <= windowPosition.y;
}
if (isVisible !== isBorderVisible) {
isBorderVisible = isVisible;
Overlays.editOverlay(windowBorder, {
visible: isBorderVisible
});
}
}
} }
function onMouseReleaseEvent() { function onMouseReleaseEvent() {
Overlays.editOverlay(scrollbarBar, { var offset = {};
backgroundAlpha: SCROLLBAR_BAR_ALPHA
}); if (isMovingScrollbar) {
isMovingScrollbar = false; Overlays.editOverlay(scrollbarBar, {
backgroundAlpha: SCROLLBAR_BAR_ALPHA
});
isMovingScrollbar = false;
}
if (isMovingWindow) {
// Save offset of bottom of window to nearest edge of the window.
offset.x = (windowPosition.x + WINDOW_WIDTH / 2 < viewport.x / 2) ? windowPosition.x : windowPosition.x - viewport.x;
offset.y = (windowPosition.y < viewport.y / 2) ? windowPosition.y : windowPosition.y - viewport.y;
Settings.setValue(SETINGS_USERS_WINDOW_OFFSET, JSON.stringify(offset));
isMovingWindow = false;
}
} }
function onScriptUpdate() { function onScriptUpdate() {
var oldViewportHeight = viewportHeight, var oldViewport = viewport,
oldIsMirrorDisplay = isMirrorDisplay, oldIsMirrorDisplay = isMirrorDisplay,
oldIsFullscreenMirror = isFullscreenMirror, oldIsFullscreenMirror = isFullscreenMirror,
MIRROR_MENU_ITEM = "Mirror", MIRROR_MENU_ITEM = "Mirror",
FULLSCREEN_MIRROR_MENU_ITEM = "Fullscreen Mirror"; FULLSCREEN_MIRROR_MENU_ITEM = "Fullscreen Mirror";
viewportHeight = Controller.getViewportDimensions().y; viewport = Controller.getViewportDimensions();
isMirrorDisplay = Menu.isOptionChecked(MIRROR_MENU_ITEM); isMirrorDisplay = Menu.isOptionChecked(MIRROR_MENU_ITEM);
isFullscreenMirror = Menu.isOptionChecked(FULLSCREEN_MIRROR_MENU_ITEM); isFullscreenMirror = Menu.isOptionChecked(FULLSCREEN_MIRROR_MENU_ITEM);
if (viewportHeight !== oldViewportHeight || isMirrorDisplay !== oldIsMirrorDisplay || isFullscreenMirror !== oldIsFullscreenMirror) { if (viewport.y !== oldViewport.y || isMirrorDisplay !== oldIsMirrorDisplay
|| isFullscreenMirror !== oldIsFullscreenMirror) {
calculateWindowHeight(); calculateWindowHeight();
updateUsersDisplay(); updateUsersDisplay();
updateOverlayPositions();
} }
if (viewport.y !== oldViewport.y) {
if (windowPosition.y > oldViewport.y / 2) {
// Maintain position w.r.t. bottom of window.
windowPosition.y = viewport.y - (oldViewport.y - windowPosition.y);
}
}
if (viewport.x !== oldViewport.x) {
if (windowPosition.x + (WINDOW_WIDTH / 2) > oldViewport.x / 2) {
// Maintain position w.r.t. right of window.
windowPosition.x = viewport.x - (oldViewport.x - windowPosition.x);
}
}
updateOverlayPositions();
} }
function setUp() { function setUp() {
var textSizeOverlay; var textSizeOverlay,
offsetSetting,
offset = {},
hmdViewport;
textSizeOverlay = Overlays.addOverlay("text", { textSizeOverlay = Overlays.addOverlay("text", {
font: WINDOW_FONT, font: WINDOW_FONT,
@ -792,13 +916,40 @@ var usersWindow = (function() {
windowLineHeight = windowTextHeight + windowLineSpacing; windowLineHeight = windowTextHeight + windowLineSpacing;
Overlays.deleteOverlay(textSizeOverlay); Overlays.deleteOverlay(textSizeOverlay);
viewportHeight = Controller.getViewportDimensions().y; viewport = Controller.getViewportDimensions();
offsetSetting = Settings.getValue(SETINGS_USERS_WINDOW_OFFSET);
if (offsetSetting !== "") {
offset = JSON.parse(Settings.getValue(SETINGS_USERS_WINDOW_OFFSET));
}
if (offset.hasOwnProperty("x") && offset.hasOwnProperty("y")) {
windowPosition.x = offset.x < 0 ? viewport.x + offset.x : offset.x;
windowPosition.y = offset.y <= 0 ? viewport.y + offset.y : offset.y;
} else {
hmdViewport = Controller.getRecommendedOverlayRect();
windowPosition = {
x: (viewport.x - hmdViewport.width) / 2, // HMD viewport is narrower than screen.
y: hmdViewport.height // HMD viewport starts at top of screen but only extends down so far.
};
}
calculateWindowHeight(); calculateWindowHeight();
windowBorder = Overlays.addOverlay("rectangle", {
x: 0,
y: viewport.y, // Start up off-screen
width: WINDOW_BORDER_WIDTH,
height: windowBorderHeight,
radius: WINDOW_BORDER_RADIUS,
color: WINDOW_BORDER_COLOR,
alpha: WINDOW_BORDER_ALPHA,
visible: isVisible && isBorderVisible
});
windowPane = Overlays.addOverlay("text", { windowPane = Overlays.addOverlay("text", {
x: 0, x: 0,
y: viewportHeight, // Start up off-screen y: viewport.y,
width: WINDOW_WIDTH, width: WINDOW_WIDTH,
height: windowHeight, height: windowHeight,
topMargin: WINDOW_MARGIN + windowLineHeight, topMargin: WINDOW_MARGIN + windowLineHeight,
@ -813,8 +964,8 @@ var usersWindow = (function() {
}); });
windowHeading = Overlays.addOverlay("text", { windowHeading = Overlays.addOverlay("text", {
x: WINDOW_MARGIN, x: 0,
y: viewportHeight, y: viewport.y,
width: WINDOW_WIDTH - 2 * WINDOW_MARGIN, width: WINDOW_WIDTH - 2 * WINDOW_MARGIN,
height: windowTextHeight, height: windowTextHeight,
topMargin: 0, topMargin: 0,
@ -828,8 +979,8 @@ var usersWindow = (function() {
}); });
minimizeButton = Overlays.addOverlay("image", { minimizeButton = Overlays.addOverlay("image", {
x: WINDOW_WIDTH - WINDOW_MARGIN / 2 - MIN_MAX_BUTTON_WIDTH, x: 0,
y: viewportHeight, y: viewport.y,
width: MIN_MAX_BUTTON_WIDTH, width: MIN_MAX_BUTTON_WIDTH,
height: MIN_MAX_BUTTON_HEIGHT, height: MIN_MAX_BUTTON_HEIGHT,
imageURL: MIN_MAX_BUTTON_SVG, imageURL: MIN_MAX_BUTTON_SVG,
@ -845,11 +996,11 @@ var usersWindow = (function() {
}); });
scrollbarBackgroundPosition = { scrollbarBackgroundPosition = {
x: WINDOW_WIDTH - 0.5 * WINDOW_MARGIN - SCROLLBAR_BACKGROUND_WIDTH, x: 0,
y: viewportHeight y: viewport.y
}; };
scrollbarBackground = Overlays.addOverlay("text", { scrollbarBackground = Overlays.addOverlay("text", {
x: scrollbarBackgroundPosition.x, x: 0,
y: scrollbarBackgroundPosition.y, y: scrollbarBackgroundPosition.y,
width: SCROLLBAR_BACKGROUND_WIDTH, width: SCROLLBAR_BACKGROUND_WIDTH,
height: windowTextHeight, height: windowTextHeight,
@ -860,11 +1011,11 @@ var usersWindow = (function() {
}); });
scrollbarBarPosition = { scrollbarBarPosition = {
x: WINDOW_WIDTH - 0.5 * WINDOW_MARGIN - SCROLLBAR_BACKGROUND_WIDTH + 1, x: 0,
y: viewportHeight y: viewport.y
}; };
scrollbarBar = Overlays.addOverlay("text", { scrollbarBar = Overlays.addOverlay("text", {
x: scrollbarBarPosition.x, x: 0,
y: scrollbarBarPosition.y, y: scrollbarBarPosition.y,
width: SCROLLBAR_BACKGROUND_WIDTH - 2, width: SCROLLBAR_BACKGROUND_WIDTH - 2,
height: windowTextHeight, height: windowTextHeight,
@ -875,8 +1026,8 @@ var usersWindow = (function() {
}); });
friendsButton = Overlays.addOverlay("image", { friendsButton = Overlays.addOverlay("image", {
x: WINDOW_MARGIN, x: 0,
y: viewportHeight, y: viewport.y,
width: FRIENDS_BUTTON_WIDTH, width: FRIENDS_BUTTON_WIDTH,
height: FRIENDS_BUTTON_HEIGHT, height: FRIENDS_BUTTON_HEIGHT,
imageURL: FRIENDS_BUTTON_SVG, imageURL: FRIENDS_BUTTON_SVG,
@ -895,8 +1046,8 @@ var usersWindow = (function() {
value: DISPLAY_VALUES[0], value: DISPLAY_VALUES[0],
values: DISPLAY_VALUES, values: DISPLAY_VALUES,
displayValues: DISPLAY_DISPLAY_VALUES, displayValues: DISPLAY_DISPLAY_VALUES,
x: WINDOW_MARGIN, x: 0,
y: viewportHeight, y: viewport.y,
width: WINDOW_WIDTH - 1.5 * WINDOW_MARGIN, width: WINDOW_WIDTH - 1.5 * WINDOW_MARGIN,
promptWidth: DISPLAY_PROMPT_WIDTH, promptWidth: DISPLAY_PROMPT_WIDTH,
lineHeight: windowLineHeight, lineHeight: windowLineHeight,
@ -928,8 +1079,8 @@ var usersWindow = (function() {
value: myVisibility, value: myVisibility,
values: VISIBILITY_VALUES, values: VISIBILITY_VALUES,
displayValues: VISIBILITY_DISPLAY_VALUES, displayValues: VISIBILITY_DISPLAY_VALUES,
x: WINDOW_MARGIN, x: 0,
y: viewportHeight, y: viewport.y,
width: WINDOW_WIDTH - 1.5 * WINDOW_MARGIN, width: WINDOW_WIDTH - 1.5 * WINDOW_MARGIN,
promptWidth: VISIBILITY_PROMPT_WIDTH, promptWidth: VISIBILITY_PROMPT_WIDTH,
lineHeight: windowLineHeight, lineHeight: windowLineHeight,
@ -979,6 +1130,7 @@ var usersWindow = (function() {
Menu.removeMenuItem(MENU_NAME, MENU_ITEM); Menu.removeMenuItem(MENU_NAME, MENU_ITEM);
Script.clearTimeout(usersTimer); Script.clearTimeout(usersTimer);
Overlays.deleteOverlay(windowBorder);
Overlays.deleteOverlay(windowPane); Overlays.deleteOverlay(windowPane);
Overlays.deleteOverlay(windowHeading); Overlays.deleteOverlay(windowHeading);
Overlays.deleteOverlay(minimizeButton); Overlays.deleteOverlay(minimizeButton);
@ -991,4 +1143,4 @@ var usersWindow = (function() {
setUp(); setUp();
Script.scriptEnding.connect(tearDown); Script.scriptEnding.connect(tearDown);
}()); }());