diff --git a/examples/utilities/tools/render/debug.js b/examples/utilities/tools/render/debug.js
index f195c607a4..eba967491b 100644
--- a/examples/utilities/tools/render/debug.js
+++ b/examples/utilities/tools/render/debug.js
@@ -14,9 +14,6 @@ Render.RenderShadowTask.enabled = true;
var RDT = Render.RenderDeferredTask;
RDT.AmbientOcclusion.enabled = true;
RDT.DebugDeferredBuffer.enabled = false;
-["DrawOpaqueDeferred", "DrawTransparentDeferred", "DrawOverlay3DOpaque", "DrawOverlay3DTransparent"]
- .map(function(name) { return RDT[name]; })
- .forEach(function(job) { job.maxDrawn = job.numDrawn; });
// Set up the qml ui
var qml = Script.resolvePath('main.qml');
@@ -39,4 +36,4 @@ function setDebugBufferSize(x) {
Render.RenderDeferredTask.DebugDeferredBuffer.size = {x: x, y: -1, z: 1, w: 1};
}
-Script.scriptEnding.connect(function() { Render.fromJSON(oldConfig); } );
+Script.scriptEnding.connect(function() { Render.load(oldConfig); } );
diff --git a/examples/utilities/tools/render/main.qml b/examples/utilities/tools/render/main.qml
index 9e825ad4df..22f263b2d0 100644
--- a/examples/utilities/tools/render/main.qml
+++ b/examples/utilities/tools/render/main.qml
@@ -12,98 +12,109 @@ import QtQuick 2.5
import QtQuick.Controls 1.4
Column {
- spacing: 8
-
- Repeater {
- model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred",
- "Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ]
- ConfigSlider {
- label: qsTr(modelData.split(":")[0])
- integral: true
- config: Render.getConfig(modelData.split(":")[1])
- property: "maxDrawn"
- max: config.numDrawn
- }
- }
-
- Row {
- CheckBox {
- text: qsTr("Display Status")
- onCheckedChanged: { Render.getConfig("DrawStatus").showDisplay = checked }
- }
- CheckBox {
- text: qsTr("Network/Physics Status")
- onCheckedChanged: { Render.getConfig("DrawStatus").showNetwork = checked }
- }
- }
-
- ConfigSlider {
- label: qsTr("Tone Mapping Exposure")
- config: Render.getConfig("ToneMapping")
- property: "exposure"
- min: -10; max: 10
+ id: root
+ spacing: 16
+ Switch {
+ checked: true
+ onClicked: ui.visible = checked
}
Column {
- id: ambientOcclusion
- property var config: Render.getConfig("AmbientOcclusion")
+ id: ui
+ spacing: 8
- Label { text: qsTr("Ambient Occlusion") }
- // TODO: Add gpuTimer
- CheckBox { text: qsTr("Dithering"); checked: ambientOcclusion.config.ditheringEnabled }
Repeater {
- model: [
- "Resolution Level:resolutionLevel:4",
- "Obscurance Level:obscuranceLevel:1",
- "Radius:radius:2",
- "Falloff Bias:falloffBias:0.2",
- "Edge Sharpness:edgeSharpness:1",
- "Blur Radius:blurRadius:6",
- "Blur Deviation:blurDeviation:3"
- ]
- ConfigSlider {
- label: qsTr(modelData.split(":")[0])
- config: ambientOcclusion.config
- property: modelData.split(":")[1]
- max: modelData.split(":")[2]
- }
- }
- Repeater {
- model: [
- "Samples:numSamples:32",
- "Spiral Turns:numSpiralTurns:30:"
- ]
+ model: [ "Opaque:DrawOpaqueDeferred", "Transparent:DrawTransparentDeferred",
+ "Opaque Overlays:DrawOverlay3DOpaque", "Transparent Overlays:DrawOverlay3DTransparent" ]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: true
- config: ambientOcclusion.config
- property: modelData.split(":")[1]
- max: modelData.split(":")[2]
+ config: Render.getConfig(modelData.split(":")[1])
+ property: "maxDrawn"
+ max: config.numDrawn
+ min: -1
}
}
- }
- Column {
- id: debug
- property var config: Render.getConfig("DebugDeferredBuffer")
-
- function setDebugMode(mode) {
- debug.config.enabled = (mode != 0);
- debug.config.mode = mode;
+ Row {
+ CheckBox {
+ text: qsTr("Display Status")
+ onCheckedChanged: { Render.getConfig("DrawStatus").showDisplay = checked }
+ }
+ CheckBox {
+ text: qsTr("Network/Physics Status")
+ onCheckedChanged: { Render.getConfig("DrawStatus").showNetwork = checked }
+ }
}
- Label { text: qsTr("Debug Buffer") }
- ExclusiveGroup { id: bufferGroup }
- Repeater {
- model: [
- "Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth",
- "Lighting", "Shadow", "Pyramid Depth", "Ambient Occlusion", "Custom Shader"
- ]
- RadioButton {
- text: qsTr(modelData)
- exclusiveGroup: bufferGroup
- checked: index == 0
- onCheckedChanged: if (checked) debug.setDebugMode(index);
+ ConfigSlider {
+ label: qsTr("Tone Mapping Exposure")
+ config: Render.getConfig("ToneMapping")
+ property: "exposure"
+ min: -10; max: 10
+ }
+
+ Column {
+ id: ambientOcclusion
+ property var config: Render.getConfig("AmbientOcclusion")
+
+ Label { text: qsTr("Ambient Occlusion") }
+ // TODO: Add gpuTimer
+ CheckBox { text: qsTr("Dithering"); checked: ambientOcclusion.config.ditheringEnabled }
+ Repeater {
+ model: [
+ "Resolution Level:resolutionLevel:4",
+ "Obscurance Level:obscuranceLevel:1",
+ "Radius:radius:2",
+ "Falloff Bias:falloffBias:0.2",
+ "Edge Sharpness:edgeSharpness:1",
+ "Blur Radius:blurRadius:6",
+ "Blur Deviation:blurDeviation:3"
+ ]
+ ConfigSlider {
+ label: qsTr(modelData.split(":")[0])
+ config: ambientOcclusion.config
+ property: modelData.split(":")[1]
+ max: modelData.split(":")[2]
+ }
+ }
+ Repeater {
+ model: [
+ "Samples:numSamples:32",
+ "Spiral Turns:numSpiralTurns:30:"
+ ]
+ ConfigSlider {
+ label: qsTr(modelData.split(":")[0])
+ integral: true
+ config: ambientOcclusion.config
+ property: modelData.split(":")[1]
+ max: modelData.split(":")[2]
+ }
+ }
+ }
+
+ Column {
+ id: debug
+ property var config: Render.getConfig("DebugDeferredBuffer")
+
+ function setDebugMode(mode) {
+ debug.config.enabled = (mode != 0);
+ debug.config.mode = mode;
+ }
+
+ Label { text: qsTr("Debug Buffer") }
+ ExclusiveGroup { id: bufferGroup }
+ Repeater {
+ model: [
+ "Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth",
+ "Lighting", "Shadow", "Pyramid Depth", "Ambient Occlusion", "Custom Shader"
+ ]
+ RadioButton {
+ text: qsTr(modelData)
+ exclusiveGroup: bufferGroup
+ checked: index == 0
+ onCheckedChanged: if (checked && index > 0) debug.setDebugMode(index - 1);
+ }
}
}
}
diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml
index 382acc237c..89ab333a0d 100644
--- a/interface/resources/qml/Browser.qml
+++ b/interface/resources/qml/Browser.qml
@@ -14,7 +14,8 @@ Window {
destroyOnInvisible: true
width: 800
height: 600
-
+ property alias webView: webview
+
Component.onCompleted: {
visible = true
addressBar.text = webview.url
@@ -28,6 +29,7 @@ Window {
}
Item {
+ id:item
anchors.fill: parent
Rectangle {
anchors.left: parent.left
@@ -125,12 +127,10 @@ Window {
console.log("New icon: " + icon)
}
- profile: WebEngineProfile {
- id: webviewProfile
- storageName: "qmlUserBrowser"
- }
-
+ profile: desktop.browserProfile
+
}
+
} // item
Keys.onPressed: {
diff --git a/interface/resources/qml/ForceLoad.qml b/interface/resources/qml/ForceLoad.qml
new file mode 100644
index 0000000000..55d8b98b1b
--- /dev/null
+++ b/interface/resources/qml/ForceLoad.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import QtMultimedia 5.5
+
+Item {
+ Audio {
+ id: audio
+ autoLoad: true
+ autoPlay: true
+ loops: Audio.Infinite
+ }
+}
+
diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml
index 35738c56b1..d2f78191ea 100644
--- a/interface/resources/qml/Stats.qml
+++ b/interface/resources/qml/Stats.qml
@@ -267,15 +267,9 @@ Item {
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
- visible: root.showAcuity
+ visible: root.expanded
text: "LOD: " + root.lodStatus;
}
- Text {
- color: root.fontColor;
- font.pixelSize: root.fontSize
- visible: root.expanded && !root.showAcuity
- text: root.lodStatsRenderText;
- }
}
}
}
diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml
index c7ae322cba..18080cd448 100644
--- a/interface/resources/qml/controls/WebView.qml
+++ b/interface/resources/qml/controls/WebView.qml
@@ -11,6 +11,7 @@ WebEngineView {
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
});
+
}
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
@@ -36,6 +37,10 @@ WebEngineView {
}
}
+ onFeaturePermissionRequested: {
+ grantFeaturePermission(securityOrigin, feature, true);
+ }
+
onLoadingChanged: {
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
@@ -48,9 +53,12 @@ WebEngineView {
}
}
- profile: WebEngineProfile {
- id: webviewProfile
- httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)"
- storageName: "qmlWebEngine"
+ onNewViewRequested:{
+ var component = Qt.createComponent("../Browser.qml");
+ var newWindow = component.createObject(desktop);
+ request.openIn(newWindow.webView)
}
+
+
+ profile: desktop.browserProfile
}
diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml
index 5951101194..5227d3cb2e 100644
--- a/interface/resources/qml/hifi/Desktop.qml
+++ b/interface/resources/qml/hifi/Desktop.qml
@@ -9,7 +9,7 @@ Desktop {
id: desktop
Component.onCompleted: {
- WebEngine.settings.javascriptCanOpenWindows = false;
+ WebEngine.settings.javascriptCanOpenWindows = true;
WebEngine.settings.javascriptCanAccessClipboard = false;
WebEngine.settings.spatialNavigationEnabled = true;
WebEngine.settings.localContentCanAccessRemoteUrls = true;
@@ -19,6 +19,12 @@ Desktop {
property alias toolWindow: toolWindow
ToolWindow { id: toolWindow }
+ property var browserProfile: WebEngineProfile {
+ id: webviewProfile
+ httpUserAgent: "Chrome/48.0 (HighFidelityInterface)"
+ storageName: "qmlWebEngine"
+ }
+
Action {
text: "Open Browser"
shortcut: "Ctrl+B"
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 792a06e136..7c1fd9279b 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -210,7 +210,7 @@ static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
-static const unsigned int CAPPED_SIM_FRAMERATE = 60;
+static const unsigned int CAPPED_SIM_FRAMERATE = 120;
static const int CAPPED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / CAPPED_SIM_FRAMERATE;
static const uint32_t INVALID_FRAME = UINT32_MAX;
@@ -1615,13 +1615,7 @@ void Application::paintGL() {
});
}
- // Some LOD-like controls need to know a smoothly varying "potential" frame rate that doesn't
- // include time waiting for sync, and which can report a number above target if we've got the headroom.
- // In my tests, the following is mostly less than 0.5ms, and never more than 3ms. I don't think its worth measuring during runtime.
- const float paintWaitAndQTTimerAllowance = 0.001f; // seconds
- // Store both values now for use by next cycle.
_lastInstantaneousFps = instantaneousFps;
- _lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance);
_pendingPaint = false;
}
@@ -1713,6 +1707,7 @@ bool Application::event(QEvent* event) {
if ((int)event->type() == (int)Paint) {
paintGL();
+ return true;
}
if (!_keyboardFocusedItem.isInvalidID()) {
@@ -3099,11 +3094,7 @@ void Application::update(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()");
- if (DependencyManager::get
()->getUseAcuity()) {
- updateLOD();
- } else {
- DependencyManager::get()->updatePIDRenderDistance(getTargetFrameRate(), getLastInstanteousFps(), deltaTime, isThrottleRendering());
- }
+ updateLOD();
{
PerformanceTimer perfTimer("devices");
@@ -3607,7 +3598,7 @@ glm::vec3 Application::getSunDirection() {
// FIXME, preprocessor guard this check to occur only in DEBUG builds
static QThread * activeRenderingThread = nullptr;
-PickRay Application::computePickRay(float x, float y) {
+PickRay Application::computePickRay(float x, float y) const {
vec2 pickPoint { x, y };
PickRay result;
if (isHMDMode()) {
@@ -4729,7 +4720,7 @@ glm::uvec2 Application::getCanvasSize() const {
return glm::uvec2(_glWidget->width(), _glWidget->height());
}
-QRect Application::getApplicationGeometry() const {
+QRect Application::getRenderingGeometry() const {
auto geometry = _glWidget->geometry();
auto topLeft = geometry.topLeft();
auto topLeftScreen = _glWidget->mapToGlobal(topLeft);
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 482f0afef6..96bafce23f 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -114,7 +114,7 @@ public:
bool eventFilter(QObject* object, QEvent* event) override;
glm::uvec2 getCanvasSize() const;
- QRect getApplicationGeometry() const;
+ QRect getRenderingGeometry() const;
glm::uvec2 getUiSize() const;
QSize getDeviceSize() const;
@@ -157,7 +157,6 @@ public:
float getFps() const { return _fps; }
float getTargetFrameRate(); // frames/second
float getLastInstanteousFps() const { return _lastInstantaneousFps; }
- float getLastUnsynchronizedFps() const { return _lastUnsynchronizedFps; }
float getFieldOfView() { return _fieldOfView.get(); }
void setFieldOfView(float fov);
@@ -169,7 +168,7 @@ public:
virtual ViewFrustum* getCurrentViewFrustum() override { return getDisplayViewFrustum(); }
virtual QThread* getMainThread() override { return thread(); }
- virtual PickRay computePickRay(float x, float y) override;
+ virtual PickRay computePickRay(float x, float y) const override;
virtual glm::vec3 getAvatarPosition() const override;
virtual qreal getDevicePixelRatio() override;
@@ -405,7 +404,6 @@ private:
QElapsedTimer _timerStart;
QElapsedTimer _lastTimeUpdated;
float _lastInstantaneousFps { 0.0f };
- float _lastUnsynchronizedFps { 0.0f };
ShapeManager _shapeManager;
PhysicalEntitySimulation _entitySimulation;
diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp
index 389e43a5ff..64b506059c 100644
--- a/interface/src/LODManager.cpp
+++ b/interface/src/LODManager.cpp
@@ -20,29 +20,8 @@
Setting::Handle desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS);
Setting::Handle hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS);
-// There are two different systems in use, based on lodPreference:
-// pid: renderDistance is adjusted by a PID such that frame rate targets are met.
-// acuity: a pseudo-acuity target is held, or adjusted to match minimum frame rates (and a PID controlls avatar rendering distance)
-// If unspecified, acuity is used only if user has specified non-default minumum frame rates.
-Setting::Handle lodPreference("lodPreference", (int)LODManager::LODPreference::acuity);
-const float SMALLEST_REASONABLE_HORIZON = 50.0f; // meters
-Setting::Handle renderDistanceInverseHighLimit("renderDistanceInverseHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON);
-void LODManager::setRenderDistanceInverseHighLimit(float newValue) {
- renderDistanceInverseHighLimit.set(newValue); // persist it, and tell all the controllers that use it
- _renderDistanceController.setControlledValueHighLimit(newValue);
-}
LODManager::LODManager() {
-
- setRenderDistanceInverseHighLimit(renderDistanceInverseHighLimit.get());
- setRenderDistanceInverseLowLimit(1.0f / (float)TREE_SCALE);
- // Advice for tuning parameters:
- // See PIDController.h. There's a section on tuning in the reference.
- // Turn on logging with the following (or from js with LODManager.setRenderDistanceControllerHistory("render pid", 240))
- //setRenderDistanceControllerHistory("render pid", 60 * 4);
- // Note that extra logging/hysteresis is turned off in Avatar.cpp when the above logging is on.
- setRenderDistanceKP(0.000012f); // Usually about 0.6 of largest that doesn't oscillate when other parameters 0.
- setRenderDistanceKI(0.00002f); // Big enough to bring us to target with the above KP.
}
float LODManager::getLODDecreaseFPS() {
@@ -234,53 +213,7 @@ QString LODManager::getLODFeedbackText() {
return result;
}
-static float renderDistance = (float)TREE_SCALE;
-static int renderedCount = 0;
-static int lastRenderedCount = 0;
-bool LODManager::getUseAcuity() { return lodPreference.get() == (int)LODManager::LODPreference::acuity; }
-void LODManager::setUseAcuity(bool newValue) { lodPreference.set(newValue ? (int)LODManager::LODPreference::acuity : (int)LODManager::LODPreference::pid); }
-float LODManager::getRenderDistance() {
- return renderDistance;
-}
-int LODManager::getRenderedCount() {
- return lastRenderedCount;
-}
-QString LODManager::getLODStatsRenderText() {
- const QString label = "Rendered objects: ";
- return label + QString::number(getRenderedCount()) + " w/in " + QString::number((int)getRenderDistance()) + "m";
-}
-// compare autoAdjustLOD()
-void LODManager::updatePIDRenderDistance(float targetFps, float measuredFps, float deltaTime, bool isThrottled) {
- float distance;
- if (!isThrottled) {
- _renderDistanceController.setMeasuredValueSetpoint(targetFps); // No problem updating in flight.
- // The PID controller raises the controlled value when the measured value goes up.
- // The measured value is frame rate. When the controlled value (1 / render cutoff distance)
- // goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate
- // goes up.
- distance = 1.0f / _renderDistanceController.update(measuredFps, deltaTime);
- } else {
- // Here we choose to just use the maximum render cutoff distance if throttled.
- distance = 1.0f / _renderDistanceController.getControlledValueLowLimit();
- }
- _renderDistanceAverage.updateAverage(distance);
- renderDistance = _renderDistanceAverage.getAverage(); // average only once per cycle
- lastRenderedCount = renderedCount;
- renderedCount = 0;
-}
-
bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) {
- // NOTE: this branch of code is the alternate form of LOD that uses PID controllers.
- if (!getUseAcuity()) {
- float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition());
- float largestDimension = bounds.getLargestDimension();
- const float scenerySize = 300; // meters
- bool isRendered = (largestDimension > scenerySize) || // render scenery regardless of distance
- (distanceToCamera < renderDistance + largestDimension);
- renderedCount += isRendered ? 1 : 0;
- return isRendered;
- }
-
// FIXME - eventually we want to use the render accuracy as an indicator for the level of detail
// to use in rendering.
float renderAccuracy = args->_viewFrustum->calculateRenderAccuracy(bounds, args->_sizeScale, args->_boundaryLevelAdjust);
@@ -299,12 +232,6 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
void LODManager::loadSettings() {
setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get());
setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get());
-
- if (lodPreference.get() == (int)LODManager::LODPreference::unspecified) {
- setUseAcuity((getDesktopLODDecreaseFPS() != DEFAULT_DESKTOP_LOD_DOWN_FPS) || (getHMDLODDecreaseFPS() != DEFAULT_HMD_LOD_DOWN_FPS));
- }
- Menu::getInstance()->getActionForOption(MenuOption::LodTools)->setEnabled(getUseAcuity());
- Menu::getInstance()->getSubMenuFromName(MenuOption::RenderResolution, Menu::getInstance()->getSubMenuFromName("Render", Menu::getInstance()->getMenu("Developer")))->setEnabled(getUseAcuity());
}
void LODManager::saveSettings() {
diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h
index 4863324161..ef4d9c8e62 100644
--- a/interface/src/LODManager.h
+++ b/interface/src/LODManager.h
@@ -18,8 +18,8 @@
#include
#include
-const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 15.0;
-const float DEFAULT_HMD_LOD_DOWN_FPS = 30.0;
+const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0;
+const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0;
const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps
const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps
const float INCREASE_LOD_GAP = 15.0f;
@@ -76,27 +76,6 @@ public:
Q_INVOKABLE float getLODDecreaseFPS();
Q_INVOKABLE float getLODIncreaseFPS();
- enum class LODPreference {
- pid = 0,
- acuity,
- unspecified
- };
- static bool getUseAcuity();
- static void setUseAcuity(bool newValue);
- Q_INVOKABLE void setRenderDistanceKP(float newValue) { _renderDistanceController.setKP(newValue); }
- Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); }
- Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); }
- Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); }
- Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); }
- Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); }
- Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); }
- Q_INVOKABLE float getRenderDistanceInverseHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); }
- Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue);
- void updatePIDRenderDistance(float targetFps, float measuredFps, float deltaTime, bool isThrottled);
- float getRenderDistance();
- int getRenderedCount();
- QString getLODStatsRenderText();
-
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
void autoAdjustLOD(float currentFPS);
@@ -126,9 +105,6 @@ private:
SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES;
SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES;
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
-
- PIDController _renderDistanceController{};
- SimpleMovingAverage _renderDistanceAverage{ 10 };
};
#endif // hifi_LODManager_h
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 6da4481840..8e48237b8e 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -162,7 +162,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
void AvatarManager::simulateAvatarFades(float deltaTime) {
QVector::iterator fadingIterator = _avatarFades.begin();
- const float SHRINK_RATE = 0.9f;
+ const float SHRINK_RATE = 0.15f;
const float MIN_FADE_SCALE = MIN_AVATAR_SCALE;
render::ScenePointer scene = qApp->getMain3DScene();
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 98d25a64c8..8c84299e08 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -421,8 +421,8 @@ private:
AtRestDetector _hmdAtRestDetector;
bool _lastIsMoving { false };
bool _hoverReferenceCameraFacingIsCaptured { false };
- glm::vec3 _hoverReferenceCameraFacing; // hmd sensor space
-
+ glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space
+
float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f };
float AUDIO_ENERGY_CONSTANT { 0.000001f };
float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f };
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index c77c4fdd78..e4c98215c2 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -144,6 +144,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
} else {
handParams.isRightEnabled = false;
}
+ handParams.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
_rig->updateFromHandParameters(handParams, deltaTime);
diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp
index 76bf48b45e..37eff80df9 100644
--- a/interface/src/ui/ApplicationCompositor.cpp
+++ b/interface/src/ui/ApplicationCompositor.cpp
@@ -335,6 +335,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) {
if (qApp->isHMDMode()) {
+ QMutexLocker locker(&_reticlePositionInHMDLock);
return QPointF(_reticlePositionInHMD.x, _reticlePositionInHMD.y);
}
return event->localPos();
@@ -349,7 +350,7 @@ void ApplicationCompositor::handleLeaveEvent() {
if (shouldCaptureMouse()) {
QWidget* mainWidget = (QWidget*)qApp->getWindow();
- QRect mainWidgetFrame = qApp->getApplicationGeometry();
+ QRect mainWidgetFrame = qApp->getRenderingGeometry();
QRect uncoveredRect = mainWidgetFrame;
foreach(QWidget* widget, QApplication::topLevelWidgets()) {
if (widget->isWindow() && widget->isVisible() && widget != mainWidget) {
@@ -388,6 +389,7 @@ bool ApplicationCompositor::handleRealMouseMoveEvent(bool sendFakeEvent) {
// If we're in HMD mode
if (shouldCaptureMouse()) {
+ QMutexLocker locker(&_reticlePositionInHMDLock);
auto newPosition = QCursor::pos();
auto changeInRealMouse = newPosition - _lastKnownRealMouse;
auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse);
@@ -403,6 +405,7 @@ bool ApplicationCompositor::handleRealMouseMoveEvent(bool sendFakeEvent) {
glm::vec2 ApplicationCompositor::getReticlePosition() {
if (qApp->isHMDMode()) {
+ QMutexLocker locker(&_reticlePositionInHMDLock);
return _reticlePositionInHMD;
}
return toGlm(QCursor::pos());
@@ -410,6 +413,7 @@ glm::vec2 ApplicationCompositor::getReticlePosition() {
void ApplicationCompositor::setReticlePosition(glm::vec2 position, bool sendFakeEvent) {
if (qApp->isHMDMode()) {
+ QMutexLocker locker(&_reticlePositionInHMDLock);
const float MOUSE_EXTENTS_VERT_ANGULAR_SIZE = 170.0f; // 5deg from poles
const float MOUSE_EXTENTS_VERT_PIXELS = VIRTUAL_SCREEN_SIZE_Y * (MOUSE_EXTENTS_VERT_ANGULAR_SIZE / DEFAULT_HMD_UI_VERT_ANGULAR_SIZE);
const float MOUSE_EXTENTS_HORZ_ANGULAR_SIZE = 360.0f; // full sphere
diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h
index 1fb37c3085..5489bffa02 100644
--- a/interface/src/ui/ApplicationCompositor.h
+++ b/interface/src/ui/ApplicationCompositor.h
@@ -9,11 +9,13 @@
#ifndef hifi_ApplicationCompositor_h
#define hifi_ApplicationCompositor_h
+#include
+#include
+
#include
#include
#include
#include
-#include
#include
#include
@@ -81,19 +83,19 @@ public:
float getAlpha() const { return _alpha; }
void setAlpha(float alpha) { _alpha = alpha; }
- Q_INVOKABLE bool getReticleVisible() { return _reticleVisible; }
- Q_INVOKABLE void setReticleVisible(bool visible) { _reticleVisible = visible; }
+ bool getReticleVisible() { return _reticleVisible; }
+ void setReticleVisible(bool visible) { _reticleVisible = visible; }
- Q_INVOKABLE float getReticleDepth() { return _reticleDepth; }
- Q_INVOKABLE void setReticleDepth(float depth) { _reticleDepth = depth; }
+ float getReticleDepth() { return _reticleDepth; }
+ void setReticleDepth(float depth) { _reticleDepth = depth; }
- Q_INVOKABLE glm::vec2 getReticlePosition();
- Q_INVOKABLE void setReticlePosition(glm::vec2 position, bool sendFakeEvent = true);
+ glm::vec2 getReticlePosition();
+ void setReticlePosition(glm::vec2 position, bool sendFakeEvent = true);
- Q_INVOKABLE void setReticleApparentPosition(glm::vec3 position) { _drawAt3D = true; _drawAt3DPosition = position; }
- Q_INVOKABLE void restoreReticleApparentPosition() { _drawAt3D = false; }
+ void setReticleApparentPosition(glm::vec3 position) { _drawAt3D = true; _drawAt3DPosition = position; }
+ void restoreReticleApparentPosition() { _drawAt3D = false; }
- Q_INVOKABLE glm::vec2 getReticleMaximumPosition() const;
+ glm::vec2 getReticleMaximumPosition() const;
ReticleInterface* getReticleInterface() { return _reticleInterface; }
@@ -141,21 +143,22 @@ private:
std::unique_ptr _alphaPropertyAnimation;
- bool _reticleVisible { true };
- float _reticleDepth { 1.0f };
- bool _drawAt3D { false };
- glm::vec3 _drawAt3DPosition;
+ std::atomic _reticleVisible { true };
+ std::atomic _reticleDepth { 1.0f };
// NOTE: when the compositor is running in HMD mode, it will control the reticle position as a custom
// application specific position, when it's in desktop mode, the reticle position will simply move
// the system mouse.
- glm::vec2 _reticlePositionInHMD{ 0.0f, 0.0f };
+ glm::vec2 _reticlePositionInHMD { 0.0f, 0.0f };
+ mutable QMutex _reticlePositionInHMDLock { QMutex::Recursive };
+
+ bool _drawAt3D { false };
+ glm::vec3 _drawAt3DPosition;
+
QPointF _lastKnownRealMouse;
- QPoint _lastKnownCursorPos;
bool _ignoreMouseMove { false };
ReticleInterface* _reticleInterface;
-
};
// Scripting interface available to control the Reticle
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index b654f797ec..67b5135e0c 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -252,12 +252,8 @@ void ApplicationOverlay::buildFramebufferObject() {
PROFILE_RANGE(__FUNCTION__);
auto uiSize = qApp->getUiSize();
- QSize desiredSize (uiSize.x, uiSize.y);
- int currentWidth = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0;
- int currentHeight = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0;
- QSize frameBufferCurrentSize(currentWidth, currentHeight);
- if (_overlayFramebuffer && desiredSize == frameBufferCurrentSize) {
+ if (_overlayFramebuffer && uiSize == _overlayFramebuffer->getSize()) {
// Already built
return;
}
@@ -271,8 +267,8 @@ void ApplicationOverlay::buildFramebufferObject() {
_overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
- auto width = desiredSize.width();
- auto height = desiredSize.height();
+ auto width = uiSize.x;
+ auto height = uiSize.y;
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR);
_overlayColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 80f2989127..93bacdd402 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -87,13 +87,6 @@ void setupPreferences() {
}
static const QString LOD_TUNING("Level of Detail Tuning");
- CheckPreference* acuityToggle;
- {
- auto getter = []()->bool { return DependencyManager::get()->getUseAcuity(); };
- auto setter = [](bool value) { DependencyManager::get()->setUseAcuity(value); };
- preferences->addPreference(acuityToggle = new CheckPreference(LOD_TUNING, "Render based on visual acuity", getter, setter));
- }
-
{
auto getter = []()->float { return DependencyManager::get()->getDesktopLODDecreaseFPS(); };
auto setter = [](float value) { DependencyManager::get()->setDesktopLODDecreaseFPS(value); };
@@ -101,7 +94,6 @@ void setupPreferences() {
preference->setMin(0);
preference->setMax(120);
preference->setStep(1);
- preference->setEnabler(acuityToggle);
preferences->addPreference(preference);
}
@@ -112,18 +104,6 @@ void setupPreferences() {
preference->setMin(0);
preference->setMax(120);
preference->setStep(1);
- preference->setEnabler(acuityToggle);
- preferences->addPreference(preference);
- }
-
- {
- auto getter = []()->float { return 1.0f / DependencyManager::get()->getRenderDistanceInverseHighLimit(); };
- auto setter = [](float value) { DependencyManager::get()->setRenderDistanceInverseHighLimit(1.0f / value); };
- auto preference = new SpinnerPreference(LOD_TUNING, "Minimum Display Distance", getter, setter);
- preference->setMin(5);
- preference->setMax(32768);
- preference->setStep(1);
- preference->setEnabler(acuityToggle, true);
preferences->addPreference(preference);
}
@@ -274,7 +254,7 @@ void setupPreferences() {
{
auto getter = []()->float { return DependencyManager::get()->getOutputBufferSize(); };
auto setter = [](float value) { DependencyManager::get()->setOutputBufferSize(value); };
- auto preference = new SpinnerPreference(AUDIO, "Output Buffer Size (frames)", getter, setter);
+ auto preference = new SpinnerPreference(AUDIO, "Output Buffer Initial Size (frames)", getter, setter);
preference->setMin(1);
preference->setMax(20);
preference->setStep(1);
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index 1ee26a865d..c9c4c68dc9 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -283,9 +283,7 @@ void Stats::updateStats(bool force) {
STAT_UPDATE(localLeaves, (int)OctreeElement::getLeafNodeCount());
// LOD Details
STAT_UPDATE(lodStatus, "You can see " + DependencyManager::get()->getLODFeedbackText());
- STAT_UPDATE(lodStatsRenderText, DependencyManager::get()->getLODStatsRenderText());
}
- STAT_UPDATE(showAcuity, (_expanded || force) && DependencyManager::get()->getUseAcuity());
bool performanceTimerIsActive = PerformanceTimer::isActive();
bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index bebfbf6f70..ba3c8f2391 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -30,7 +30,6 @@ class Stats : public QQuickItem {
Q_PROPERTY(QString monospaceFont READ monospaceFont CONSTANT)
Q_PROPERTY(float audioPacketlossUpstream READ getAudioPacketLossUpstream)
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
- Q_PROPERTY(bool showAcuity READ getShowAcuity WRITE setShowAcuity NOTIFY showAcuityChanged)
STATS_PROPERTY(int, serverCount, 0)
STATS_PROPERTY(int, renderrate, 0)
@@ -80,7 +79,6 @@ class Stats : public QQuickItem {
STATS_PROPERTY(QString, packetStats, QString())
STATS_PROPERTY(QString, lodStatus, QString())
STATS_PROPERTY(QString, timingStats, QString())
- STATS_PROPERTY(QString, lodStatsRenderText, QString())
STATS_PROPERTY(int, serverElements, 0)
STATS_PROPERTY(int, serverInternal, 0)
STATS_PROPERTY(int, serverLeaves, 0)
@@ -112,15 +110,12 @@ public:
emit expandedChanged();
}
}
- bool getShowAcuity() { return _showAcuity; }
- void setShowAcuity(bool newValue) { _showAcuity = newValue; }
public slots:
void forceUpdateStats() { updateStats(true); }
signals:
void expandedChanged();
- void showAcuityChanged();
void timingExpandedChanged();
void serverCountChanged();
void renderrateChanged();
@@ -128,7 +123,6 @@ signals:
void simrateChanged();
void avatarSimrateChanged();
void avatarCountChanged();
- void lodStatsRenderTextChanged();
void packetInCountChanged();
void packetOutCountChanged();
void mbpsInChanged();
@@ -182,7 +176,6 @@ private:
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
bool _resetRecentMaxPacketsSoon{ true };
bool _expanded{ false };
- bool _showAcuity{ false };
bool _timingExpanded{ false };
QString _monospaceFont;
const AudioIOStats* _audioStats;
diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index ff1dea3d48..48ad9b852d 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -670,7 +670,7 @@ void AnimInverseKinematics::initConstraints() {
stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST);
std::vector minDots;
- const float MAX_SHOULDER_SWING = PI / 20.0f;
+ const float MAX_SHOULDER_SWING = PI / 6.0f;
minDots.push_back(cosf(MAX_SHOULDER_SWING));
stConstraint->setSwingLimits(minDots);
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 817054a9f5..3952dc5b40 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1080,8 +1080,31 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
if (_animSkeleton && _animNode) {
+
+ const float HAND_RADIUS = 0.05f;
+ const float BODY_RADIUS = params.bodyCapsuleRadius;
+ const float MIN_LENGTH = 1.0e-4f;
+
+ // project the hips onto the xz plane.
+ auto hipsTrans = _internalPoseSet._absolutePoses[_animSkeleton->nameToJointIndex("Hips")].trans;
+ const glm::vec2 bodyCircleCenter(hipsTrans.x, hipsTrans.z);
+
if (params.isLeftEnabled) {
- _animVars.set("leftHandPosition", params.leftPosition);
+
+ // project the hand position onto the xz plane.
+ glm::vec2 handCircleCenter(params.leftPosition.x, params.leftPosition.z);
+
+ // check for 2d overlap of the hand and body circles.
+ auto circleToCircle = handCircleCenter - bodyCircleCenter;
+ const float circleToCircleLength = glm::length(circleToCircle);
+ const float penetrationDistance = HAND_RADIUS + BODY_RADIUS - circleToCircleLength;
+ if (penetrationDistance > 0.0f && circleToCircleLength > MIN_LENGTH) {
+ // push the hands out of the body
+ handCircleCenter += penetrationDistance * glm::normalize(circleToCircle);
+ }
+
+ glm::vec3 handPosition(handCircleCenter.x, params.leftPosition.y, handCircleCenter.y);
+ _animVars.set("leftHandPosition", handPosition);
_animVars.set("leftHandRotation", params.leftOrientation);
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
} else {
@@ -1089,8 +1112,23 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
_animVars.unset("leftHandRotation");
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
+
if (params.isRightEnabled) {
- _animVars.set("rightHandPosition", params.rightPosition);
+
+ // project the hand position onto the xz plane.
+ glm::vec2 handCircleCenter(params.rightPosition.x, params.rightPosition.z);
+
+ // check for 2d overlap of the hand and body circles.
+ auto circleToCircle = handCircleCenter - bodyCircleCenter;
+ const float circleToCircleLength = glm::length(circleToCircle);
+ const float penetrationDistance = HAND_RADIUS + BODY_RADIUS - circleToCircleLength;
+ if (penetrationDistance > 0.0f && circleToCircleLength > MIN_LENGTH) {
+ // push the hands out of the body
+ handCircleCenter += penetrationDistance * glm::normalize(circleToCircle);
+ }
+
+ glm::vec3 handPosition(handCircleCenter.x, params.rightPosition.y, handCircleCenter.y);
+ _animVars.set("rightHandPosition", handPosition);
_animVars.set("rightHandRotation", params.rightOrientation);
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
} else {
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index e4668d6c2a..9c5b014d55 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -67,6 +67,7 @@ public:
struct HandParameters {
bool isLeftEnabled;
bool isRightEnabled;
+ float bodyCapsuleRadius;
glm::vec3 leftPosition = glm::vec3(); // rig space
glm::quat leftOrientation = glm::quat(); // rig space (z forward)
glm::vec3 rightPosition = glm::vec3(); // rig space
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 60c9287912..01ceb73941 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -80,8 +80,9 @@ AudioClient::AudioClient() :
_isStereoInput(false),
_outputStarveDetectionStartTimeMsec(0),
_outputStarveDetectionCount(0),
- _outputBufferSizeFrames("audioOutputBufferSize", DEFAULT_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES),
- _outputStarveDetectionEnabled("audioOutputStarveDetectionEnabled",
+ _outputBufferSizeFrames("audioOutputBufferSizeFrames", DEFAULT_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES),
+ _sessionOutputBufferSizeFrames(_outputBufferSizeFrames.get()),
+ _outputStarveDetectionEnabled("audioOutputBufferStarveDetectionEnabled",
DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED),
_outputStarveDetectionPeriodMsec("audioOutputStarveDetectionPeriod",
DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_PERIOD),
@@ -109,6 +110,7 @@ AudioClient::AudioClient() :
connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples,
this, &AudioClient::processReceivedSamples, Qt::DirectConnection);
+ connect(this, &AudioClient::changeDevice, this, [=](const QAudioDeviceInfo& outputDeviceInfo) { switchOutputToAudioDevice(outputDeviceInfo); });
_inputDevices = getDeviceNames(QAudio::AudioInput);
_outputDevices = getDeviceNames(QAudio::AudioOutput);
@@ -277,9 +279,9 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
const QAudioFormat& desiredAudioFormat,
QAudioFormat& adjustedAudioFormat) {
- // FIXME: directly using 24khz has a bug somewhere that causes channels to be swapped.
- // Continue using our internal resampler, for now.
- if (true || !audioDevice.isFormatSupported(desiredAudioFormat)) {
+ // There had been a note here that 2khz was swapping channels. That doesn't seem to be happening
+ // any more for me. If it does, then we'll want to always resample.
+ if (!audioDevice.isFormatSupported(desiredAudioFormat)) {
qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;
qCDebug(audioclient, "The desired audio format is not supported by this device");
@@ -287,7 +289,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
adjustedAudioFormat = desiredAudioFormat;
adjustedAudioFormat.setChannelCount(2);
- if (false && audioDevice.isFormatSupported(adjustedAudioFormat)) {
+ if (audioDevice.isFormatSupported(adjustedAudioFormat)) {
return true;
} else {
adjustedAudioFormat.setChannelCount(1);
@@ -971,10 +973,8 @@ void AudioClient::outputNotify() {
_outputStarveDetectionStartTimeMsec = now;
_outputStarveDetectionCount = 0;
- int oldOutputBufferSizeFrames = _outputBufferSizeFrames.get();
- int newOutputBufferSizeFrames = oldOutputBufferSizeFrames + 1;
- setOutputBufferSize(newOutputBufferSizeFrames);
- newOutputBufferSizeFrames = _outputBufferSizeFrames.get();
+ int oldOutputBufferSizeFrames = _sessionOutputBufferSizeFrames;
+ int newOutputBufferSizeFrames = setOutputBufferSize(oldOutputBufferSizeFrames + 1, false);
if (newOutputBufferSizeFrames > oldOutputBufferSizeFrames) {
qCDebug(audioclient) << "Starve detection threshold met, increasing buffer size to " << newOutputBufferSizeFrames;
}
@@ -1038,15 +1038,19 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
// setup our general output device for audio-mixer audio
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
- _audioOutput->setBufferSize(_outputBufferSizeFrames.get() * _outputFrameSize * sizeof(int16_t));
+ int osDefaultBufferSize = _audioOutput->bufferSize();
+ int requestedSize = _sessionOutputBufferSizeFrames *_outputFrameSize * sizeof(int16_t);
+ _audioOutput->setBufferSize(requestedSize);
connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify);
- qCDebug(audioclient) << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / sizeof(int16_t) / (float)_outputFrameSize;
-
_audioOutputIODevice.start();
_audioOutput->start(&_audioOutputIODevice);
+ qCDebug(audioclient) << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / sizeof(int16_t) / (float)_outputFrameSize <<
+ "requested bytes:" << requestedSize << "actual bytes:" << _audioOutput->bufferSize() <<
+ "os default:" << osDefaultBufferSize << "period size:" << _audioOutput->periodSize();
+
// setup a loopback audio output device
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
@@ -1060,19 +1064,23 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
return supportedFormat;
}
-void AudioClient::setOutputBufferSize(int numFrames) {
+int AudioClient::setOutputBufferSize(int numFrames, bool persist) {
numFrames = std::min(std::max(numFrames, MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES), MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES);
- if (numFrames != _outputBufferSizeFrames.get()) {
+ if (numFrames != _sessionOutputBufferSizeFrames) {
qCDebug(audioclient) << "Audio output buffer size (frames): " << numFrames;
- _outputBufferSizeFrames.set(numFrames);
+ _sessionOutputBufferSizeFrames = numFrames;
+ if (persist) {
+ _outputBufferSizeFrames.set(numFrames);
+ }
if (_audioOutput) {
// The buffer size can't be adjusted after QAudioOutput::start() has been called, so
// recreate the device by switching to the default.
QAudioDeviceInfo outputDeviceInfo = defaultAudioDeviceForMode(QAudio::AudioOutput);
- switchOutputToAudioDevice(outputDeviceInfo);
+ emit changeDevice(outputDeviceInfo); // On correct thread, please, as setOutputBufferSize can be called from main thread.
}
}
+ return numFrames;
}
// The following constant is operating system dependent due to differences in
@@ -1143,6 +1151,9 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
}
int bytesAudioOutputUnplayed = _audio->_audioOutput->bufferSize() - _audio->_audioOutput->bytesFree();
+ if (!bytesAudioOutputUnplayed) {
+ qCDebug(audioclient) << "empty audio buffer";
+ }
if (bytesAudioOutputUnplayed == 0 && bytesWritten == 0) {
_unfulfilledReads++;
}
diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h
index 6b2f39c47c..d3145629ee 100644
--- a/libraries/audio-client/src/AudioClient.h
+++ b/libraries/audio-client/src/AudioClient.h
@@ -57,11 +57,7 @@ static const int NUM_AUDIO_CHANNELS = 2;
static const int DEFAULT_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 3;
static const int MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 1;
static const int MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 20;
-#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN)
- static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED = false;
-#else
- static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED = true;
-#endif
+static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED = true;
static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_THRESHOLD = 3;
static const quint64 DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_PERIOD = 10 * 1000; // 10 Seconds
@@ -156,7 +152,7 @@ public slots:
void processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer);
void sendMuteEnvironmentPacket();
- void setOutputBufferSize(int numFrames);
+ int setOutputBufferSize(int numFrames, bool persist = true);
virtual bool outputLocalInjector(bool isStereo, AudioInjector* injector);
@@ -184,6 +180,7 @@ signals:
void outputBytesToNetwork(int numBytes);
void inputBytesFromNetwork(int numBytes);
+ void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
void deviceChanged();
void receivedFirstPacket();
@@ -230,6 +227,7 @@ private:
int _outputStarveDetectionCount;
Setting::Handle _outputBufferSizeFrames;
+ int _sessionOutputBufferSizeFrames;
Setting::Handle _outputStarveDetectionEnabled;
Setting::Handle _outputStarveDetectionPeriodMsec;
// Maximum number of starves per _outputStarveDetectionPeriod before increasing buffer size
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
index 8140dd3312..ce3faeb196 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
@@ -28,6 +28,11 @@
const float DPI = 30.47f;
const float METERS_TO_INCHES = 39.3701f;
+static uint32_t _currentWebCount { 0 };
+// Don't allow more than 100 concurrent web views
+static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 100;
+// If a web-view hasn't been rendered for 30 seconds, de-allocate the framebuffer
+static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND;
EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity{ new RenderableWebEntityItem(entityID) };
@@ -41,28 +46,123 @@ RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemI
}
RenderableWebEntityItem::~RenderableWebEntityItem() {
- if (_webSurface) {
- _webSurface->pause();
- _webSurface->disconnect(_connection);
- // The lifetime of the QML surface MUST be managed by the main thread
- // Additionally, we MUST use local variables copied by value, rather than
- // member variables, since they would implicitly refer to a this that
- // is no longer valid
- auto webSurface = _webSurface;
- AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
- webSurface->deleteLater();
- });
- }
-
- QObject::disconnect(_mousePressConnection);
- QObject::disconnect(_mouseReleaseConnection);
- QObject::disconnect(_mouseMoveConnection);
- QObject::disconnect(_hoverLeaveConnection);
+ destroyWebSurface();
qDebug() << "Destroyed web entity " << getID();
}
+bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
+ if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) {
+ qWarning() << "Too many concurrent web views to create new view";
+ return false;
+ }
+
+ qDebug() << "Building web surface";
+ ++_currentWebCount;
+ // Save the original GL context, because creating a QML surface will create a new context
+ QOpenGLContext * currentContext = QOpenGLContext::currentContext();
+ QSurface * currentSurface = currentContext->surface();
+ _webSurface = new OffscreenQmlSurface();
+ _webSurface->create(currentContext);
+ _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
+ _webSurface->load("WebEntity.qml");
+ _webSurface->resume();
+ _webSurface->getRootItem()->setProperty("url", _sourceUrl);
+ _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) {
+ _texture = textureId;
+ });
+ // Restore the original GL context
+ currentContext->makeCurrent(currentSurface);
+
+ auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) {
+ // Ignore mouse interaction if we're locked
+ if (this->getLocked()) {
+ return;
+ }
+
+ if (event->button() == Qt::MouseButton::RightButton) {
+ if (event->type() == QEvent::MouseButtonPress) {
+ const QMouseEvent* mouseEvent = static_cast(event);
+ _lastPress = toGlm(mouseEvent->pos());
+ }
+ }
+
+ if (intersection.entityID == getID()) {
+ if (event->button() == Qt::MouseButton::RightButton) {
+ if (event->type() == QEvent::MouseButtonRelease) {
+ const QMouseEvent* mouseEvent = static_cast(event);
+ ivec2 dist = glm::abs(toGlm(mouseEvent->pos()) - _lastPress);
+ if (!glm::any(glm::greaterThan(dist, ivec2(1)))) {
+ AbstractViewStateInterface::instance()->postLambdaEvent([this] {
+ QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack");
+ });
+ }
+ _lastPress = ivec2(INT_MIN);
+ }
+ return;
+ }
+
+ // FIXME doesn't work... double click events not received
+ if (event->type() == QEvent::MouseButtonDblClick) {
+ AbstractViewStateInterface::instance()->postLambdaEvent([this] {
+ _webSurface->getRootItem()->setProperty("url", _sourceUrl);
+ });
+ }
+
+ if (event->button() == Qt::MouseButton::MiddleButton) {
+ if (event->type() == QEvent::MouseButtonRelease) {
+ AbstractViewStateInterface::instance()->postLambdaEvent([this] {
+ _webSurface->getRootItem()->setProperty("url", _sourceUrl);
+ });
+ }
+ return;
+ }
+
+ // Map the intersection point to an actual offscreen pixel
+ glm::vec3 point = intersection.intersection;
+ point -= getPosition();
+ point = glm::inverse(getRotation()) * point;
+ point /= getDimensions();
+ point += 0.5f;
+ point.y = 1.0f - point.y;
+ point *= getDimensions() * METERS_TO_INCHES * DPI;
+
+ if (event->button() == Qt::MouseButton::LeftButton) {
+ if (event->type() == QEvent::MouseButtonPress) {
+ this->_pressed = true;
+ this->_lastMove = ivec2((int)point.x, (int)point.y);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ this->_pressed = false;
+ }
+ }
+ if (event->type() == QEvent::MouseMove) {
+ this->_lastMove = ivec2((int)point.x, (int)point.y);
+ }
+
+ // Forward the mouse event.
+ QMouseEvent mappedEvent(event->type(),
+ QPoint((int)point.x, (int)point.y),
+ event->screenPos(), event->button(),
+ event->buttons(), event->modifiers());
+ QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
+ }
+ };
+ _mousePressConnection = QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent);
+ _mouseReleaseConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent);
+ _mouseMoveConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent);
+ _hoverLeaveConnection = QObject::connect(renderer, &EntityTreeRenderer::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) {
+ if (this->_pressed && this->getID() == entityItemID) {
+ // If the user mouses off the entity while the button is down, simulate a mouse release
+ QMouseEvent mappedEvent(QEvent::MouseButtonRelease,
+ QPoint(_lastMove.x, _lastMove.y),
+ Qt::MouseButton::LeftButton,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+ QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
+ }
+ });
+ return true;
+}
+
void RenderableWebEntityItem::render(RenderArgs* args) {
-
#ifdef WANT_EXTRA_DEBUGGING
{
gpu::Batch& batch = *args->_batch;
@@ -72,116 +172,19 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
}
#endif
- QOpenGLContext * currentContext = QOpenGLContext::currentContext();
- QSurface * currentSurface = currentContext->surface();
if (!_webSurface) {
- _webSurface = new OffscreenQmlSurface();
- _webSurface->create(currentContext);
- _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
- _webSurface->load("WebEntity.qml");
- _webSurface->resume();
- _webSurface->getRootItem()->setProperty("url", _sourceUrl);
- _connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) {
- _texture = textureId;
- });
-
- auto forwardMouseEvent = [=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event) {
- // Ignore mouse interaction if we're locked
- if (this->getLocked()) {
- return;
- }
-
- if (event->button() == Qt::MouseButton::RightButton) {
- if (event->type() == QEvent::MouseButtonPress) {
- const QMouseEvent* mouseEvent = static_cast(event);
- _lastPress = toGlm(mouseEvent->pos());
- }
- }
-
- if (intersection.entityID == getID()) {
- if (event->button() == Qt::MouseButton::RightButton) {
- if (event->type() == QEvent::MouseButtonRelease) {
- const QMouseEvent* mouseEvent = static_cast(event);
- ivec2 dist = glm::abs(toGlm(mouseEvent->pos()) - _lastPress);
- if (!glm::any(glm::greaterThan(dist, ivec2(1)))) {
- AbstractViewStateInterface::instance()->postLambdaEvent([this] {
- QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack");
- });
- }
- _lastPress = ivec2(INT_MIN);
- }
- return;
- }
-
- // FIXME doesn't work... double click events not received
- if (event->type() == QEvent::MouseButtonDblClick) {
- AbstractViewStateInterface::instance()->postLambdaEvent([this] {
- _webSurface->getRootItem()->setProperty("url", _sourceUrl);
- });
- }
-
- if (event->button() == Qt::MouseButton::MiddleButton) {
- if (event->type() == QEvent::MouseButtonRelease) {
- AbstractViewStateInterface::instance()->postLambdaEvent([this] {
- _webSurface->getRootItem()->setProperty("url", _sourceUrl);
- });
- }
- return;
- }
-
- // Map the intersection point to an actual offscreen pixel
- glm::vec3 point = intersection.intersection;
- point -= getPosition();
- point = glm::inverse(getRotation()) * point;
- point /= getDimensions();
- point += 0.5f;
- point.y = 1.0f - point.y;
- point *= getDimensions() * METERS_TO_INCHES * DPI;
-
- if (event->button() == Qt::MouseButton::LeftButton) {
- if (event->type() == QEvent::MouseButtonPress) {
- this->_pressed = true;
- this->_lastMove = ivec2((int)point.x, (int)point.y);
- } else if (event->type() == QEvent::MouseButtonRelease) {
- this->_pressed = false;
- }
- }
- if (event->type() == QEvent::MouseMove) {
- this->_lastMove = ivec2((int)point.x, (int)point.y);
- }
-
- // Forward the mouse event.
- QMouseEvent mappedEvent(event->type(),
- QPoint((int)point.x, (int)point.y),
- event->screenPos(), event->button(),
- event->buttons(), event->modifiers());
- QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
- }
- };
-
- EntityTreeRenderer* renderer = static_cast(args->_renderer);
- _mousePressConnection = QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent);
- _mouseReleaseConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent);
- _mouseMoveConnection = QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent);
- _hoverLeaveConnection = QObject::connect(renderer, &EntityTreeRenderer::hoverLeaveEntity, [=](const EntityItemID& entityItemID, const MouseEvent& event) {
- if (this->_pressed && this->getID() == entityItemID) {
- // If the user mouses off the entity while the button is down, simulate a mouse release
- QMouseEvent mappedEvent(QEvent::MouseButtonRelease,
- QPoint(_lastMove.x, _lastMove.y),
- Qt::MouseButton::LeftButton,
- Qt::MouseButtons(), Qt::KeyboardModifiers());
- QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
- }
- });
+ if (!buildWebSurface(static_cast(args->_renderer))) {
+ return;
+ }
}
+ _lastRenderTime = usecTimestampNow();
glm::vec2 dims = glm::vec2(getDimensions());
dims *= METERS_TO_INCHES * DPI;
// The offscreen surface is idempotent for resizes (bails early
// if it's a no-op), so it's safe to just call resize every frame
// without worrying about excessive overhead.
_webSurface->resize(QSize(dims.x, dims.y));
- currentContext->makeCurrent(currentSurface);
PerformanceTimer perfTimer("RenderableWebEntityItem::render");
Q_ASSERT(getType() == EntityTypes::Web);
@@ -223,3 +226,37 @@ void RenderableWebEntityItem::setProxyWindow(QWindow* proxyWindow) {
QObject* RenderableWebEntityItem::getEventHandler() {
return _webSurface->getEventHandler();
}
+
+void RenderableWebEntityItem::destroyWebSurface() {
+ if (_webSurface) {
+ --_currentWebCount;
+ _webSurface->pause();
+ _webSurface->disconnect(_connection);
+ QObject::disconnect(_mousePressConnection);
+ _mousePressConnection = QMetaObject::Connection();
+ QObject::disconnect(_mouseReleaseConnection);
+ _mouseReleaseConnection = QMetaObject::Connection();
+ QObject::disconnect(_mouseMoveConnection);
+ _mouseMoveConnection = QMetaObject::Connection();
+ QObject::disconnect(_hoverLeaveConnection);
+ _hoverLeaveConnection = QMetaObject::Connection();
+
+ // The lifetime of the QML surface MUST be managed by the main thread
+ // Additionally, we MUST use local variables copied by value, rather than
+ // member variables, since they would implicitly refer to a this that
+ // is no longer valid
+ auto webSurface = _webSurface;
+ AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
+ webSurface->deleteLater();
+ });
+ _webSurface = nullptr;
+ }
+}
+
+
+void RenderableWebEntityItem::update(const quint64& now) {
+ auto interval = now - _lastRenderTime;
+ if (interval > MAX_NO_RENDER_INTERVAL) {
+ destroyWebSurface();
+ }
+}
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h
index da1ddbf1a1..49a55b6b27 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h
@@ -18,6 +18,7 @@
class OffscreenQmlSurface;
class QWindow;
class QObject;
+class EntityTreeRenderer;
class RenderableWebEntityItem : public WebEntityItem {
public:
@@ -31,15 +32,22 @@ public:
void setProxyWindow(QWindow* proxyWindow);
QObject* getEventHandler();
+ void update(const quint64& now) override;
+ bool needsToCallUpdate() const { return _webSurface != nullptr; }
+
SIMPLE_RENDERABLE();
private:
+ bool buildWebSurface(EntityTreeRenderer* renderer);
+ void destroyWebSurface();
+
OffscreenQmlSurface* _webSurface{ nullptr };
QMetaObject::Connection _connection;
uint32_t _texture{ 0 };
ivec2 _lastPress{ INT_MIN };
bool _pressed{ false };
ivec2 _lastMove{ INT_MIN };
+ uint64_t _lastRenderTime{ 0 };
QMetaObject::Connection _mousePressConnection;
QMetaObject::Connection _mouseReleaseConnection;
diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp
index 16196aa129..4b798cbcd9 100644
--- a/libraries/entities/src/ParticleEffectEntityItem.cpp
+++ b/libraries/entities/src/ParticleEffectEntityItem.cpp
@@ -103,6 +103,7 @@ EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID
// our non-pure virtual subclass for now...
ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID) :
EntityItem(entityItemID),
+ _previousPosition(getPosition()),
_lastSimulated(usecTimestampNow())
{
_type = EntityTypes::ParticleEffect;
@@ -623,7 +624,8 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
}
// emit a new particle at tail index.
- _particles.push_back(createParticle());
+ _particles.push_back(createParticle(glm::mix(_previousPosition, getPosition(),
+ (deltaTime - timeLeftInFrame) / deltaTime)));
auto particle = _particles.back();
particle.lifetime += timeLeftInFrame;
@@ -637,15 +639,16 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_timeUntilNextEmit -= timeLeftInFrame;
}
+ _previousPosition = getPosition();
}
-ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
+ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle(const glm::vec3& position) {
Particle particle;
particle.seed = randFloatInRange(-1.0f, 1.0f);
if (getEmitterShouldTrail()) {
- particle.position = getPosition();
+ particle.position = position;
}
// Position, velocity, and acceleration
if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) {
diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h
index 5afcbe2ae1..ba6f32b51f 100644
--- a/libraries/entities/src/ParticleEffectEntityItem.h
+++ b/libraries/entities/src/ParticleEffectEntityItem.h
@@ -227,7 +227,7 @@ protected:
bool isAnimatingSomething() const;
- Particle createParticle();
+ Particle createParticle(const glm::vec3& position);
void stepSimulation(float deltaTime);
void integrateParticle(Particle& particle, float deltaTime);
@@ -275,7 +275,7 @@ protected:
float _azimuthStart = DEFAULT_AZIMUTH_START;
float _azimuthFinish = DEFAULT_AZIMUTH_FINISH;
-
+ glm::vec3 _previousPosition;
quint64 _lastSimulated { 0 };
bool _isEmitting { true };
diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp
index 42eea08057..e22feb694d 100644
--- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp
+++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp
@@ -175,6 +175,7 @@ private:
doneCurrent();
getContextObject()->moveToThread(QCoreApplication::instance()->thread());
+ _thread.quit();
_cond.wakeOne();
}
@@ -228,7 +229,7 @@ private:
_quickWindow->setRenderTarget(GetName(*_fbo), QSize(_size.x, _size.y));
- {
+ try {
PROFILE_RANGE("qml_render")
TexturePtr texture = _textures.getNextTexture();
_fbo->Bind(Framebuffer::Target::Draw);
@@ -245,8 +246,10 @@ private:
DefaultFramebuffer().Bind(Framebuffer::Target::Draw);
_quickWindow->resetOpenGLState();
_escrow.submit(GetName(*texture));
+ _lastRenderTime = usecTimestampNow();
+ } catch (std::runtime_error& error) {
+ qWarning() << "Failed to render QML " << error.what();
}
- _lastRenderTime = usecTimestampNow();
}
void aboutToQuit() {
@@ -321,7 +324,7 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
_renderer = new OffscreenQmlRenderer(this, shareContext);
-
+ _renderer->_renderControl->_renderWindow = _proxyWindow;
// Create a QML engine.
_qmlEngine = new QQmlEngine;
if (!_qmlEngine->incubationController()) {
@@ -610,7 +613,10 @@ bool OffscreenQmlSurface::isPaused() const {
}
void OffscreenQmlSurface::setProxyWindow(QWindow* window) {
- _renderer->_renderControl->_renderWindow = window;
+ _proxyWindow = window;
+ if (_renderer && _renderer->_renderControl) {
+ _renderer->_renderControl->_renderWindow = window;
+ }
}
QObject* OffscreenQmlSurface::getEventHandler() {
diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h
index 9e3ee06f92..5641d16a30 100644
--- a/libraries/gl/src/gl/OffscreenQmlSurface.h
+++ b/libraries/gl/src/gl/OffscreenQmlSurface.h
@@ -95,7 +95,7 @@ private:
bool _paused{ true };
uint8_t _maxFps{ 60 };
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p.toPoint(); } };
-
+ QWindow* _proxyWindow { nullptr };
};
#endif
diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h
index 5362ca52e4..a8543d6070 100644
--- a/libraries/physics/src/CharacterController.h
+++ b/libraries/physics/src/CharacterController.h
@@ -78,6 +78,8 @@ public:
glm::vec3 getLinearVelocity() const;
+ float getCapsuleRadius() const { return _radius; }
+
enum class State {
Ground = 0,
Takeoff,
diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h
index 1165816dd2..815cb45423 100644
--- a/libraries/render-utils/src/AbstractViewStateInterface.h
+++ b/libraries/render-utils/src/AbstractViewStateInterface.h
@@ -36,7 +36,7 @@ public:
virtual QThread* getMainThread() = 0;
- virtual PickRay computePickRay(float x, float y) = 0;
+ virtual PickRay computePickRay(float x, float y) const = 0;
virtual glm::vec3 getAvatarPosition() const = 0;
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 91c9ec623d..3b741ac734 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -92,15 +92,15 @@ void Model::setScale(const glm::vec3& scale) {
_scaledToFit = false;
}
-const float METERS_PER_MILLIMETER = 0.01f;
+const float SCALE_CHANGE_EPSILON = 0.01f;
void Model::setScaleInternal(const glm::vec3& scale) {
- if (glm::distance(_scale, scale) > METERS_PER_MILLIMETER) {
+ if (glm::distance(_scale, scale) > SCALE_CHANGE_EPSILON) {
_scale = scale;
if (_scale.x == 0.0f || _scale.y == 0.0f || _scale.z == 0.0f) {
assert(false);
}
- initJointTransforms();
+ simulate(0.0f, true);
}
}
diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp
index a660e918a9..7e7ca77b88 100644
--- a/libraries/script-engine/src/AudioScriptingInterface.cpp
+++ b/libraries/script-engine/src/AudioScriptingInterface.cpp
@@ -45,8 +45,11 @@ ScriptAudioInjector* AudioScriptingInterface::playSound(Sound* sound, const Audi
// stereo option isn't set from script, this comes from sound metadata or filename
AudioInjectorOptions optionsCopy = injectorOptions;
optionsCopy.stereo = sound->isStereo();
-
- return new ScriptAudioInjector(AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface));
+ auto injector = AudioInjector::playSound(sound->getByteArray(), optionsCopy, _localAudioInterface);
+ if (!injector) {
+ return NULL;
+ }
+ return new ScriptAudioInjector(injector);
} else {
qCDebug(scriptengine) << "AudioScriptingInterface::playSound called with null Sound object.";
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index 7575cc83e7..efd230bc28 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -30,7 +30,6 @@ const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)");
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here
static vr::IVRCompositor* _compositor{ nullptr };
-static vr::TrackedDevicePose_t _presentThreadTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
static mat4 _sensorResetMat;
@@ -43,12 +42,12 @@ bool OpenVrDisplayPlugin::isSupported() const {
void OpenVrDisplayPlugin::activate() {
_container->setIsOptionChecked(StandingHMDSensorMode, true);
- if (!_hmd) {
- _hmd = acquireOpenVrSystem();
+ if (!_system) {
+ _system = acquireOpenVrSystem();
}
- Q_ASSERT(_hmd);
+ Q_ASSERT(_system);
- _hmd->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
+ _system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
// Recommended render target size is per-eye, so double the X size for
// left + right eyes
_renderTargetSize.x *= 2;
@@ -56,8 +55,8 @@ void OpenVrDisplayPlugin::activate() {
{
Lock lock(_poseMutex);
openvr_for_each_eye([&](vr::Hmd_Eye eye) {
- _eyeOffsets[eye] = toGlm(_hmd->GetEyeToHeadTransform(eye));
- _eyeProjections[eye] = toGlm(_hmd->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL));
+ _eyeOffsets[eye] = toGlm(_system->GetEyeToHeadTransform(eye));
+ _eyeProjections[eye] = toGlm(_system->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL));
});
// FIXME Calculate the proper combined projection by using GetProjectionRaw values from both eyes
_cullingProjection = _eyeProjections[0];
@@ -71,9 +70,9 @@ void OpenVrDisplayPlugin::activate() {
void OpenVrDisplayPlugin::deactivate() {
_container->setIsOptionChecked(StandingHMDSensorMode, false);
- if (_hmd) {
+ if (_system) {
releaseOpenVrSystem();
- _hmd = nullptr;
+ _system = nullptr;
}
_compositor = nullptr;
HmdDisplayPlugin::deactivate();
@@ -96,9 +95,31 @@ void OpenVrDisplayPlugin::resetSensors() {
_sensorResetMat = glm::inverse(cancelOutRollAndPitch(m));
}
-
glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
- Lock lock(_poseMutex);
+
+ float displayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
+ float frameDuration = 1.f / displayFrequency;
+ float vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
+
+#if THREADED_PRESENT
+ // TODO: this seems awfuly long, 44ms total, but it produced the best results.
+ const float NUM_PREDICTION_FRAMES = 3.0f;
+ float predictedSecondsFromNow = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons;
+#else
+ uint64_t frameCounter;
+ float timeSinceLastVsync;
+ _system->GetTimeSinceLastVsync(&timeSinceLastVsync, &frameCounter);
+ float predictedSecondsFromNow = 3.0f * frameDuration - timeSinceLastVsync + vsyncToPhotons;
+#endif
+
+ vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
+ _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
+
+ // copy and process predictedTrackedDevicePoses
+ for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
+ _trackedDevicePose[i] = predictedTrackedDevicePose[i];
+ _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
+ }
return _trackedDevicePoseMat4[0];
}
@@ -112,18 +133,8 @@ void OpenVrDisplayPlugin::internalPresent() {
_compositor->Submit(vr::Eye_Left, &texture, &leftBounds);
_compositor->Submit(vr::Eye_Right, &texture, &rightBounds);
- glFinish();
-
- _compositor->WaitGetPoses(_presentThreadTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
-
- {
- // copy and process _presentThreadTrackedDevicePoses
- Lock lock(_poseMutex);
- for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
- _trackedDevicePose[i] = _presentThreadTrackedDevicePose[i];
- _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking);
- }
- }
+ vr::TrackedDevicePose_t currentTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
+ _compositor->WaitGetPoses(currentTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
// Handle the mirroring in the base class
HmdDisplayPlugin::internalPresent();
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h
index 9c480e48f7..4344c3c48f 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.h
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.h
@@ -35,7 +35,7 @@ protected:
virtual void internalPresent() override;
private:
- vr::IVRSystem* _hmd { nullptr };
+ vr::IVRSystem* _system { nullptr };
static const QString NAME;
mutable Mutex _poseMutex;
};