Merge branch 'master' of https://github.com/highfidelity/hifi into decouple-avatar-updates

And update with current code.
This commit is contained in:
Howard Stearns 2015-08-18 15:35:37 -07:00
commit dc75b238a8
22 changed files with 803 additions and 585 deletions

View file

@ -971,12 +971,7 @@ void OctreeServer::readConfiguration() {
strcpy(_persistFilename, qPrintable(persistFilename));
qDebug("persistFilename=%s", _persistFilename);
QString persistAsFileType;
if (!readOptionString(QString("persistAsFileType"), settingsSectionObject, persistAsFileType)) {
persistAsFileType = "svo";
}
_persistAsFileType = persistAsFileType;
qDebug() << "persistAsFileType=" << _persistAsFileType;
_persistAsFileType = "json.gz";
_persistInterval = OctreePersistThread::DEFAULT_PERSIST_INTERVAL;
readOptionInt(QString("persistInterval"), settingsSectionObject, _persistInterval);

View file

@ -371,30 +371,8 @@
"name": "persistFilename",
"label": "Entities Filename",
"help": "the path to the file entities are stored in. Make sure the path exists.",
"placeholder": "resources/models.svo",
"default": "resources/models.svo",
"advanced": true
},
{
"name": "persistAsFileType",
"label": "File format for entity server's persistent data",
"help": "This defines how the entity server will save entities to disk.",
"default": "svo",
"type": "select",
"options": [
{
"value": "svo",
"label": "Entity server persists data as SVO"
},
{
"value": "json",
"label": "Entity server persists data as JSON"
},
{
"value": "json.gz",
"label": "Entity server persists data as gzipped JSON"
}
],
"placeholder": "resources/models.json.gz",
"default": "resources/models.json.gz",
"advanced": true
},
{

View file

@ -362,9 +362,12 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
this.fractionKey = optionalPersistenceKey + '.fraction';
this.save = function () {
var screenSize = Controller.getViewportDimensions();
if (screenSize.x > 0 && screenSize.y > 0) {
// Guard against invalid screen size that can occur at shut-down.
var fraction = {x: that.x / screenSize.x, y: that.y / screenSize.y};
Settings.setValue(this.fractionKey, JSON.stringify(fraction));
}
}
} else {
this.save = function () { }; // Called on move. Can be overriden or extended by clients.
}

View file

@ -47,6 +47,16 @@ Item {
font.pixelSize: root.fontSize
text: "Framerate: " + root.framerate
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Simrate: " + root.simrate
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Avatar Simrate: " + root.avatarSimrate
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize

View file

@ -112,9 +112,7 @@
#include "InterfaceActionFactory.h"
#include "avatar/AvatarManager.h"
#include "audio/AudioScope.h"
#include "devices/DdeFaceTracker.h"
#include "devices/EyeTracker.h"
#include "devices/Faceshift.h"
@ -148,6 +146,8 @@
#include "ui/AddressBarDialog.h"
#include "ui/UpdateDialog.h"
#include "ui/overlays/Cube3DOverlay.h"
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
// FIXME seems to be broken.
#if defined(Q_OS_WIN)
@ -172,7 +172,6 @@ public:
void call() { _fun(); }
};
using namespace std;
// Starfield information
@ -299,6 +298,13 @@ bool setupEssentials(int& argc, char** argv) {
return true;
}
// FIXME move to header, or better yet, design some kind of UI manager
// to take care of highlighting keyboard focused items, rather than
// continuing to overburden Application.cpp
Cube3DOverlay* _keyboardFocusHighlight{ nullptr };
int _keyboardFocusHighlightID{ -1 };
Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
QApplication(argc, argv),
_dependencyManagerIsSetup(setupEssentials(argc, argv)),
@ -687,8 +693,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
webEntity->setProxyWindow(_window->windowHandle());
_keyboardFocusedItem = entityItemID;
_lastAcceptedKeyPress = usecTimestampNow();
if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
_keyboardFocusHighlight = new Cube3DOverlay();
_keyboardFocusHighlight->setAlpha(1.0f);
_keyboardFocusHighlight->setBorderSize(1.0f);
_keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });
_keyboardFocusHighlight->setIsSolid(false);
_keyboardFocusHighlight->setPulseMin(0.5);
_keyboardFocusHighlight->setPulseMax(1.0);
_keyboardFocusHighlight->setColorPulse(1.0);
_keyboardFocusHighlight->setIgnoreRayIntersection(true);
_keyboardFocusHighlight->setDrawInFront(true);
}
_keyboardFocusHighlight->setRotation(webEntity->getRotation());
_keyboardFocusHighlight->setPosition(webEntity->getPosition());
_keyboardFocusHighlight->setDimensions(webEntity->getDimensions() * 1.05f);
_keyboardFocusHighlight->setVisible(true);
_keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);
}
}
if (_keyboardFocusedItem == UNKNOWN_ENTITY_ID && _keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
}
});
@ -696,6 +723,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity,
[=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID;
if (_keyboardFocusHighlight) {
_keyboardFocusHighlight->setVisible(false);
}
});
}
@ -707,6 +737,11 @@ void Application::aboutToQuit() {
}
void Application::cleanupBeforeQuit() {
if (_keyboardFocusHighlightID > 0) {
getOverlays().deleteOverlay(_keyboardFocusHighlightID);
_keyboardFocusHighlightID = -1;
}
_keyboardFocusHighlight = nullptr;
_entities.clear(); // this will allow entity scripts to properly shutdown
@ -718,6 +753,7 @@ void Application::cleanupBeforeQuit() {
// first stop all timers directly or by invokeMethod
// depending on what thread they run in
_avatarUpdate->stop();
locationUpdateTimer->stop();
balanceUpdateTimer->stop();
identityPacketTimer->stop();
@ -1969,10 +2005,19 @@ void Application::checkFPS() {
void Application::idle() {
PROFILE_RANGE(__FUNCTION__);
static SimpleAverage<float> interIdleDurations;
static uint64_t lastIdleStart{ 0 };
static uint64_t lastIdleEnd{ 0 };
uint64_t now = usecTimestampNow();
uint64_t idleStartToStartDuration = now - lastIdleStart;
if (lastIdleStart > 0 && idleStartToStartDuration > 0) {
_simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration);
}
lastIdleStart = now;
if (lastIdleEnd != 0) {
uint64_t now = usecTimestampNow();
interIdleDurations.update(now - lastIdleEnd);
static uint64_t lastReportTime = now;
if ((now - lastReportTime) >= (USECS_PER_SECOND)) {
@ -2067,6 +2112,28 @@ void Application::idle() {
lastIdleEnd = usecTimestampNow();
}
float Application::getAverageSimsPerSecond() {
uint64_t now = usecTimestampNow();
if (now - _lastSimsPerSecondUpdate > USECS_PER_SECOND) {
_simsPerSecondReport = _simsPerSecond.getAverage();
_lastSimsPerSecondUpdate = now;
}
return _simsPerSecondReport;
}
void Application::setAvatarSimrateSample(float sample) {
_avatarSimsPerSecond.updateAverage(sample);
}
float Application::getAvatarSimrate() {
uint64_t now = usecTimestampNow();
if (now - _lastAvatarSimsPerSecondUpdate > USECS_PER_SECOND) {
_avatarSimsPerSecondReport = _avatarSimsPerSecond.getAverage();
_lastAvatarSimsPerSecondUpdate = now;
}
return _avatarSimsPerSecondReport;
}
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
InputDevice::setLowVelocityFilter(lowVelocityFilter);
}
@ -2289,7 +2356,6 @@ QVector<EntityItemID> Application::pasteEntities(float x, float y, float z) {
void Application::initDisplay() {
}
static QTimer* avatarTimer = NULL;
void Application::init() {
// Make sure Login state is up to date
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
@ -2353,10 +2419,7 @@ void Application::init() {
connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
connect(_myAvatar, &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
const qint64 AVATAR_UPDATE_INTERVAL_MSECS = 1000 / 55;
avatarTimer = new QTimer(this);
connect(avatarTimer, &QTimer::timeout, this, &Application::avatarUpdate);
avatarTimer->start(AVATAR_UPDATE_INTERVAL_MSECS);
_avatarUpdate = new AvatarUpdate();
}
void Application::closeMirrorView() {
@ -2421,16 +2484,6 @@ void Application::updateMouseRay() {
}
}
void Application::avatarUpdate() {
PerformanceTimer perfTimer("myAvatar");
qint64 now = usecTimestampNow();
float deltaTime = (now - _lastAvatarUpdate) / (1000.0f * 1000.0f);
_lastAvatarUpdate = now;
updateMyAvatarLookAtPosition();
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
DependencyManager::get<AvatarManager>()->updateMyAvatar(deltaTime);
}
// Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone.
// (Maybe this code should be moved there?)
// The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition().
@ -2445,18 +2498,19 @@ void Application::updateMyAvatarLookAtPosition() {
auto eyeTracker = DependencyManager::get<EyeTracker>();
bool isLookingAtSomeone = false;
bool isHMD = _avatarUpdate->isHMDMode();
glm::vec3 lookAtSpot;
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
// When I am in mirror mode, just look right at the camera (myself); don't switch gaze points because when physically
// looking in a mirror one's eyes appear steady.
if (!isHMDMode()) {
if (!isHMD) {
lookAtSpot = _myCamera.getPosition();
} else {
lookAtSpot = _myCamera.getPosition() + transformPoint(_myAvatar->getSensorToWorldMatrix(), extractTranslation(getHMDSensorPose()));
}
} else if (eyeTracker->isTracking() && (isHMDMode() || eyeTracker->isSimulating())) {
} else if (eyeTracker->isTracking() && (isHMD || eyeTracker->isSimulating())) {
// Look at the point that the user is looking at.
if (isHMDMode()) {
if (isHMD) {
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();
glm::quat hmdRotation = glm::quat_cast(headPose);
lookAtSpot = _myCamera.getPosition() +
@ -2499,7 +2553,7 @@ void Application::updateMyAvatarLookAtPosition() {
}
} else {
// I am not looking at anyone else, so just look forward
if (isHMDMode()) {
if (isHMD) {
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();
glm::quat headRotation = glm::quat_cast(headPose);
lookAtSpot = _myCamera.getPosition() +
@ -2730,9 +2784,6 @@ void Application::update(float deltaTime) {
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
//loop through all the other avatars and simulate them...
DependencyManager::get<AvatarManager>()->updateOtherAvatars(deltaTime);
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
updateDialogs(deltaTime); // update various stats dialogs if present
updateCursor(deltaTime); // Handle cursor updates
@ -2803,7 +2854,7 @@ void Application::update(float deltaTime) {
_overlays.update(deltaTime);
}
avatarUpdate();
_avatarUpdate->avatarUpdateIfSynchronous();
{
PerformanceTimer perfTimer("emitSimulating");

View file

@ -38,6 +38,7 @@
#include <ViewFrustum.h>
#include <plugins/PluginContainer.h>
#include <plugins/PluginManager.h>
#include <SimpleMovingAverage.h>
#include "AudioClient.h"
#include "Bookmarks.h"
@ -47,6 +48,7 @@
#include "Menu.h"
#include "Physics.h"
#include "Stars.h"
#include "avatar/AvatarUpdate.h"
#include "avatar/Avatar.h"
#include "avatar/MyAvatar.h"
#include <input-plugins/KeyboardMouseDevice.h>
@ -350,6 +352,14 @@ public:
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
void updateMyAvatarLookAtPosition();
AvatarUpdate* getAvatarUpdater() { return _avatarUpdate; }
MyAvatar* getMyAvatar() { return _myAvatar; }
float getAvatarSimrate();
void setAvatarSimrateSample(float sample);
float getAverageSimsPerSecond();
signals:
/// Fired when we're simulating; allows external parties to hook in.
@ -494,7 +504,6 @@ private:
// Various helper functions called during update()
void updateLOD();
void updateMouseRay();
void updateMyAvatarLookAtPosition();
void updateThreads(float deltaTime);
void updateCamera(float deltaTime);
void updateDialogs(float deltaTime);
@ -563,6 +572,10 @@ private:
KeyboardMouseDevice* _keyboardMouseDevice{ nullptr }; // Default input device, the good old keyboard mouse and maybe touchpad
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
AvatarUpdate* _avatarUpdate;
SimpleMovingAverage _avatarSimsPerSecond{10};
int _avatarSimsPerSecondReport = 0;
quint64 _lastAvatarSimsPerSecondUpdate = 0;
Camera _myCamera; // My view onto the world
Camera _mirrorCamera; // Cammera for mirror view
QRect _mirrorViewRect;
@ -682,8 +695,9 @@ private:
EntityItemID _keyboardFocusedItem;
quint64 _lastAcceptedKeyPress = 0;
void avatarUpdate();
quint64 _lastAvatarUpdate = 0;
SimpleMovingAverage _simsPerSecond{10};
int _simsPerSecondReport = 0;
quint64 _lastSimsPerSecondUpdate = 0;
};
#endif // hifi_Application_h

View file

@ -688,6 +688,23 @@ glm::vec3 Avatar::getDisplayNamePosition() const {
const float HEAD_PROPORTION = 0.75f;
namePosition = _position + getBodyUpDirection() * (getBillboardSize() * HEAD_PROPORTION);
}
#ifdef DEBUG
// TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed.
// See other TODO below.
if (glm::isnan(namePosition.x) || glm::isnan(namePosition.y) || glm::isnan(namePosition.z)
|| glm::isinf(namePosition.x) || glm::isinf(namePosition.y) || glm::isinf(namePosition.z)) {
qDebug() << "namePosition =" << namePosition;
glm::vec3 tempPosition(0.0f);
if (getSkeletonModel().getNeckPosition(tempPosition)) {
qDebug() << "getBodyUpDirection() =" << getBodyUpDirection();
qDebug() << "getHeadHeight() =" << getHeadHeight();
} else {
qDebug() << "_position =" << _position;
qDebug() << "getBodyUpDirection() =" << getBodyUpDirection();
qDebug() << "getBillboardSize() =" << getBillboardSize();
}
}
#endif
return namePosition;
}
@ -722,7 +739,8 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, floa
// Compute correct scale to apply
float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio;
#ifdef DEBUG
// TODO: Temporary logging to track cause of invalid scale vale; remove once cause has been fixed.
// TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed.
// Problem is probably due to an invalid getDisplayNamePosition(). See extra logging above.
if (scale == 0.0f || glm::isnan(scale) || glm::isinf(scale)) {
if (scale == 0.0f) {
qDebug() << "ASSERT because scale == 0.0f";
@ -733,6 +751,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, floa
if (glm::isinf(scale)) {
qDebug() << "ASSERT because isinf(scale)";
}
qDebug() << "textPosition =" << textPosition;
qDebug() << "windowSizeY =" << windowSizeY;
qDebug() << "p1.y =" << p1.y;
qDebug() << "p1.w =" << p1.w;

View file

@ -0,0 +1,98 @@
//
// AvatarUpdate.cpp
// interface/src/avatar
//
// Created by Howard Stearns on 8/18/15.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
//
#include <DependencyManager.h>
#include "Application.h"
#include "AvatarManager.h"
#include "AvatarUpdate.h"
#include "InterfaceLogging.h"
enum UpdateType {
Synchronous = 1,
Timer,
Thread
};
AvatarUpdate::AvatarUpdate() : _lastAvatarUpdate(0) {
Settings settings;
int type = settings.value("AvatarUpdateType", UpdateType::Synchronous).toInt();
_targetSimrate = settings.value("AvatarUpdateTargetSimrate", 60).toInt();
qCDebug(interfaceapp) << "AvatarUpdate using" << type << "at" << _targetSimrate << "sims/second";
switch (type) {
case UpdateType::Synchronous:
_timer = nullptr;
break;
case UpdateType::Timer:
initTimer();
break;
default:
initThread();
break;
}
}
void AvatarUpdate::stop() {
if (!_timer) {
return;
}
_timer->stop();
if (_avatarThread) {
return;
}
_avatarThread->quit();
}
void AvatarUpdate::initTimer() {
const qint64 AVATAR_UPDATE_INTERVAL_MSECS = 1000 / _targetSimrate;
_timer = new QTimer(this);
connect(_timer, &QTimer::timeout, this, &AvatarUpdate::avatarUpdate);
_timer->start(AVATAR_UPDATE_INTERVAL_MSECS);
}
void AvatarUpdate::initThread() {
_avatarThread = new QThread();
_avatarThread->setObjectName("Avatar Update Thread");
this->moveToThread(_avatarThread);
connect(_avatarThread, &QThread::started, this, &AvatarUpdate::initTimer);
_avatarThread->start();
}
// There are a couple of ways we could do this.
// Right now, the goals are:
// 1. allow development to switch between UpdateType
// 2. minimize changes everwhere, particularly outside of Avatars.
// As an example of the latter, we could make Application::isHMDMode() thread safe, but in this case
// we just made AvatarUpdate::isHMDMode() thread safe.
void AvatarUpdate::avatarUpdateIfSynchronous() {
// Keep our own updated value, so that our asynchronous code can consult it.
_isHMDMode = Application::getInstance()->isHMDMode();
if (_updateBillboard) {
Application::getInstance()->getMyAvatar()->doUpdateBillboard();
}
if (_timer) {
return;
}
avatarUpdate();
}
void AvatarUpdate::avatarUpdate() {
PerformanceTimer perfTimer("AvatarUpdate");
quint64 now = usecTimestampNow();
float deltaTime = (now - _lastAvatarUpdate) / (1000.0f * 1000.0f);
Application::getInstance()->setAvatarSimrateSample(1.0f / deltaTime);
_lastAvatarUpdate = now;
//loop through all the other avatars and simulate them...
//gets current lookat data, removes missing avatars, etc.
DependencyManager::get<AvatarManager>()->updateOtherAvatars(deltaTime);
Application::getInstance()->updateMyAvatarLookAtPosition();
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
DependencyManager::get<AvatarManager>()->updateMyAvatar(deltaTime);
}

View file

@ -0,0 +1,42 @@
//
// AvatarUpdate.h
// interface/src/avatar
//
// Created by Howard Stearns on 8/18/15.
///
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
//
#ifndef __hifi__AvatarUpdate__
#define __hifi__AvatarUpdate__
#include <QtCore/QObject>
#include <QTimer>
// Home for the avatarUpdate operations (e.g., whether on a separate thread, pipelined in various ways, etc.)
// TODO: become GenericThread
// This might get folded into AvatarManager.
class AvatarUpdate : public QObject {
Q_OBJECT
public:
AvatarUpdate();
void avatarUpdateIfSynchronous();
bool isHMDMode() { return _isHMDMode; }
void setRequestBillboardUpdate(bool needsUpdate) { _updateBillboard = needsUpdate; }
void stop();
private:
void initTimer();
void initThread();
void avatarUpdate();
int _targetSimrate;
bool _isHMDMode;
bool _updateBillboard;
QTimer* _timer;
QThread* _avatarThread;
quint64 _lastAvatarUpdate;
};
#endif /* defined(__hifi__AvatarUpdate__) */

View file

@ -388,7 +388,7 @@ glm::quat Head::getCameraOrientation() const {
// to change the driving direction while in Oculus mode. It is used to support driving toward where you're
// head is looking. Note that in oculus mode, your actual camera view and where your head is looking is not
// always the same.
if (qApp->isHMDMode()) {
if (qApp->getAvatarUpdater()->isHMDMode()) {
MyAvatar* myAvatar = dynamic_cast<MyAvatar*>(_owningAvatar);
if (myAvatar && myAvatar->getStandingHMDSensorMode()) {
return glm::quat_cast(myAvatar->getSensorToWorldMatrix()) * myAvatar->getHMDSensorOrientation();

View file

@ -284,7 +284,7 @@ void MyAvatar::updateSensorToWorldMatrix() {
void MyAvatar::updateFromTrackers(float deltaTime) {
glm::vec3 estimatedPosition, estimatedRotation;
bool inHmd = qApp->isHMDMode();
bool inHmd = qApp->getAvatarUpdater()->isHMDMode();
if (isPlaying() && inHmd) {
return;
@ -1363,7 +1363,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
setOrientation(getOrientation() *
glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f))));
if (qApp->isHMDMode()) {
if (qApp->getAvatarUpdater()->isHMDMode()) {
glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation();
glm::quat bodyOrientation = getWorldBodyOrientation();
glm::quat localOrientation = glm::inverse(bodyOrientation) * orientation;
@ -1584,6 +1584,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
}
void MyAvatar::maybeUpdateBillboard() {
qApp->getAvatarUpdater()->setRequestBillboardUpdate(false);
if (_billboardValid || !(_skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures())) {
return;
}
@ -1592,7 +1593,9 @@ void MyAvatar::maybeUpdateBillboard() {
return;
}
}
qApp->getAvatarUpdater()->setRequestBillboardUpdate(true);
}
void MyAvatar::doUpdateBillboard() {
RenderArgs renderArgs(qApp->getGPUContext());
QImage image = qApp->renderAvatarBillboard(&renderArgs);
_billboard.clear();

View file

@ -164,6 +164,7 @@ public:
static const float ZOOM_DEFAULT;
bool getStandingHMDSensorMode() const { return _standingHMDSensorMode; }
void doUpdateBillboard();
public slots:
void increaseSize();

View file

@ -114,6 +114,8 @@ void Stats::updateStats() {
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
STAT_UPDATE(serverCount, nodeList->size());
STAT_UPDATE(framerate, (int)qApp->getFps());
STAT_UPDATE(simrate, (int)Application::getInstance()->getAverageSimsPerSecond());
STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate());
auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond());

View file

@ -30,6 +30,8 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, serverCount, 0)
STATS_PROPERTY(int, framerate, 0)
STATS_PROPERTY(int, simrate, 0)
STATS_PROPERTY(int, avatarSimrate, 0)
STATS_PROPERTY(int, avatarCount, 0)
STATS_PROPERTY(int, packetInCount, 0)
STATS_PROPERTY(int, packetOutCount, 0)
@ -95,6 +97,8 @@ signals:
void timingExpandedChanged();
void serverCountChanged();
void framerateChanged();
void simrateChanged();
void avatarSimrateChanged();
void avatarCountChanged();
void packetInCountChanged();
void packetOutCountChanged();

View file

@ -154,9 +154,9 @@ public:
DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString);
DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString);
DEFINE_PROPERTY(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool);
DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray);
DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector<glm::vec3>);
DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector<float>);
DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray);
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString);
DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString);

View file

@ -170,9 +170,10 @@ bool PolyLineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
glm::vec3 pos = getPosition();
glm::vec3 halfBox = getDimensions() * 0.5f;
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
if ((point.x < - halfBox.x || point.x > halfBox.x) ||
(point.y < -halfBox.y || point.y > halfBox.y) ||
(point.z < - halfBox.z || point.z > halfBox.z)) {
qDebug() << "Point is outside entity's bounding box";
return false;
}

View file

@ -1108,13 +1108,12 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
if (subdata.name == "Materials") {
materials = getIntVector(subdata);
} else if (subdata.name == "MappingInformationType") {
if (subdata.properties.at(0) == "ByPolygon") {
if (subdata.properties.at(0) == "ByPolygon")
isMaterialPerPolygon = true;
} else {
isMaterialPerPolygon = false;
}
}
}
} else if (child.name == "LayerElementTexture") {
@ -1126,7 +1125,6 @@ ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex) {
}
}
bool isMultiMaterial = false;
if (isMaterialPerPolygon) {
isMultiMaterial = true;

View file

@ -123,9 +123,9 @@ public:
DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) :
_function(func), _writeMask(writeMask), _enabled(enabled) {}
bool isEnabled() const { return _enabled; }
bool isEnabled() const { return _enabled != 0; }
ComparisonFunction getFunction() const { return ComparisonFunction(_function); }
bool getWriteMask() const { return _writeMask; }
uint8 getWriteMask() const { return _writeMask; }
int32 getRaw() const { return *(reinterpret_cast<const int32*>(this)); }
DepthTest(int32 raw) { *(reinterpret_cast<int32*>(this)) = raw; }
@ -301,7 +301,7 @@ public:
DepthTest getDepthTest() const { return _values.depthTest; }
bool isDepthTestEnabled() const { return getDepthTest().isEnabled(); }
bool getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); }
uint8 getDepthTestWriteMask() const { return getDepthTest().getWriteMask(); }
ComparisonFunction getDepthTestFunc() const { return getDepthTest().getFunction(); }
// Stencil test

View file

@ -92,7 +92,7 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
// dQ = Q1 * Q0^
btQuaternion deltaQ = target * bodyRotation.inverse();
float angle = deltaQ.getAngle();
const float MIN_ANGLE = 1.0e-4;
const float MIN_ANGLE = 1.0e-4f;
if (angle > MIN_ANGLE) {
targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis();
}

View file

@ -1808,7 +1808,6 @@ void Model::segregateMeshGroups() {
const FBXMesh& mesh = geometry.meshes.at(i);
const MeshState& state = _meshStates.at(i);
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
bool hasTangents = !mesh.tangents.isEmpty();
bool hasSpecular = mesh.hasSpecularTexture();

View file

@ -239,7 +239,7 @@ private:
return;
}
Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _size);
//Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _size);
//Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _textures._size);
_renderControl->sync();

View file

@ -44,7 +44,7 @@ const int16_t COLLISION_GROUP_OTHER_AVATAR = 1 << 6;
const int16_t COLLISION_GROUP_MY_ATTACHMENT = 1 << 7;
const int16_t COLLISION_GROUP_OTHER_ATTACHMENT = 1 << 8;
// ...
const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15;
const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 14;
/* Note: In order for objectA to collide with objectB at the filter stage