mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge branch 'master' of github.com:highfidelity/hifi into qt-launcher
This commit is contained in:
commit
bc207638a5
42 changed files with 748 additions and 219 deletions
4
cmake/externals/wasapi/CMakeLists.txt
vendored
4
cmake/externals/wasapi/CMakeLists.txt
vendored
|
@ -6,8 +6,8 @@ if (WIN32)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://public.highfidelity.com/dependencies/qtaudio_wasapi12.zip
|
||||
URL_MD5 9e2eef41165f85344808f754b48bf08d
|
||||
URL https://public.highfidelity.com/dependencies/qtaudio_wasapi13.zip
|
||||
URL_MD5 aa56a45f19c18caee13d29a40d1d7d28
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Source: hifi-deps
|
||||
Version: 0.1
|
||||
Version: 0.3
|
||||
Description: Collected dependencies for High Fidelity applications
|
||||
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
|
||||
|
|
|
@ -265,7 +265,7 @@ endif()
|
|||
if platform.system() == 'Windows':
|
||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows3.tar.gz'
|
||||
elif platform.system() == 'Darwin':
|
||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos3.tar.gz'
|
||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos.tar.gz?versionId=bLAgnoJ8IMKpqv8NFDcAu8hsyQy3Rwwz'
|
||||
elif platform.system() == 'Linux':
|
||||
if platform.linux_distribution()[1][:3] == '16.':
|
||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-16.04-with-symbols.tar.gz'
|
||||
|
|
|
@ -133,15 +133,12 @@ Item {
|
|||
|
||||
ListElement {
|
||||
text: "Low World Detail"
|
||||
worldDetailQualityValue: 0.25
|
||||
}
|
||||
ListElement {
|
||||
text: "Medium World Detail"
|
||||
worldDetailQualityValue: 0.5
|
||||
}
|
||||
ListElement {
|
||||
text: "Full World Detail"
|
||||
worldDetailQualityValue: 0.75
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,14 +155,7 @@ Item {
|
|||
currentIndex: -1
|
||||
|
||||
function refreshWorldDetailDropdown() {
|
||||
var currentWorldDetailQuality = LODManager.worldDetailQuality;
|
||||
if (currentWorldDetailQuality <= 0.25) {
|
||||
worldDetailDropdown.currentIndex = 0;
|
||||
} else if (currentWorldDetailQuality <= 0.5) {
|
||||
worldDetailDropdown.currentIndex = 1;
|
||||
} else {
|
||||
worldDetailDropdown.currentIndex = 2;
|
||||
}
|
||||
worldDetailDropdown.currentIndex = LODManager.worldDetailQuality;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
@ -173,7 +163,7 @@ Item {
|
|||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
LODManager.worldDetailQuality = model.get(currentIndex).worldDetailQualityValue;
|
||||
LODManager.worldDetailQuality = currentIndex;
|
||||
worldDetailDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,13 +258,12 @@ Flickable {
|
|||
Layout.preferredHeight: contentItem.height
|
||||
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
|
||||
interactive: false
|
||||
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
|
||||
clip: true
|
||||
model: AudioScriptingInterface.devices.input
|
||||
delegate: Item {
|
||||
width: parent.width
|
||||
height: inputDeviceCheckbox.height
|
||||
|
||||
width: parent.width
|
||||
height: model.type != "hmd" ? inputDeviceCheckbox.height + simplifiedUI.margins.settings.spacingBetweenRadiobuttons : 0
|
||||
visible: model.type != "hmd"
|
||||
SimplifiedControls.RadioButton {
|
||||
id: inputDeviceCheckbox
|
||||
anchors.left: parent.left
|
||||
|
@ -354,13 +353,12 @@ Flickable {
|
|||
Layout.preferredHeight: contentItem.height
|
||||
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
|
||||
interactive: false
|
||||
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
|
||||
clip: true
|
||||
model: AudioScriptingInterface.devices.output
|
||||
delegate: Item {
|
||||
width: parent.width
|
||||
height: outputDeviceCheckbox.height
|
||||
|
||||
height: model.type != "hmd" ? outputDeviceCheckbox.height +simplifiedUI.margins.settings.spacingBetweenRadiobuttons : 0
|
||||
visible: model.type != "hmd"
|
||||
SimplifiedControls.RadioButton {
|
||||
id: outputDeviceCheckbox
|
||||
anchors.left: parent.left
|
||||
|
|
|
@ -259,13 +259,13 @@ Flickable {
|
|||
Layout.preferredHeight: contentItem.height
|
||||
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
|
||||
interactive: false
|
||||
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
|
||||
clip: true
|
||||
model: AudioScriptingInterface.devices.input
|
||||
delegate: Item {
|
||||
width: parent.width
|
||||
height: inputDeviceCheckbox.height
|
||||
|
||||
width: parent.width
|
||||
height: model.type != "desktop" ? inputDeviceCheckbox.height + simplifiedUI.margins.settings.spacingBetweenRadiobuttons : 0
|
||||
visible: model.type != "desktop"
|
||||
|
||||
SimplifiedControls.RadioButton {
|
||||
id: inputDeviceCheckbox
|
||||
anchors.left: parent.left
|
||||
|
@ -355,13 +355,12 @@ Flickable {
|
|||
Layout.preferredHeight: contentItem.height
|
||||
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
|
||||
interactive: false
|
||||
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
|
||||
clip: true
|
||||
model: AudioScriptingInterface.devices.output
|
||||
delegate: Item {
|
||||
width: parent.width
|
||||
height: outputDeviceCheckbox.height
|
||||
|
||||
height: model.type != "desktop" ? outputDeviceCheckbox.height + simplifiedUI.margins.settings.spacingBetweenRadiobuttons : 0
|
||||
visible: model.type != "desktop"
|
||||
SimplifiedControls.RadioButton {
|
||||
id: outputDeviceCheckbox
|
||||
anchors.left: parent.left
|
||||
|
|
|
@ -429,7 +429,7 @@ Rectangle {
|
|||
SimplifiedControls.TextField {
|
||||
id: goToTextField
|
||||
readonly property string shortPlaceholderText: "Jump to..."
|
||||
readonly property string longPlaceholderText: "Type the name of a location to quickly jump there..."
|
||||
readonly property string longPlaceholderText: "Quickly jump to a location by typing '/LocationName'"
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(parent.width, 445)
|
||||
height: 35
|
||||
|
|
10
interface/resources/serverless/empty.json
Normal file
10
interface/resources/serverless/empty.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"DataVersion": 3,
|
||||
"Paths": {
|
||||
"/": "/0, 0, 0/0,0,0,0"
|
||||
},
|
||||
"Entities": [
|
||||
],
|
||||
"Id": "{5807d519-eb7d-496d-b22a-0820811291c9}",
|
||||
"Version": 120
|
||||
}
|
|
@ -5845,14 +5845,14 @@ void Application::pushPostUpdateLambda(void* key, const std::function<void()>& f
|
|||
// to everyone.
|
||||
// The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition().
|
||||
// Note that it is called BEFORE we update position or joints based on sensors, etc.
|
||||
void Application::updateMyAvatarLookAtPosition() {
|
||||
void Application::updateMyAvatarLookAtPosition(float deltaTime) {
|
||||
PerformanceTimer perfTimer("lookAt");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");
|
||||
|
||||
auto myAvatar = getMyAvatar();
|
||||
FaceTracker* faceTracker = getActiveFaceTracker();
|
||||
myAvatar->updateLookAtPosition(faceTracker, _myCamera);
|
||||
myAvatar->updateEyesLookAtPosition(faceTracker, _myCamera, deltaTime);
|
||||
}
|
||||
|
||||
void Application::updateThreads(float deltaTime) {
|
||||
|
@ -6636,7 +6636,7 @@ void Application::update(float deltaTime) {
|
|||
{
|
||||
PROFILE_RANGE(simulation, "MyAvatar");
|
||||
PerformanceTimer perfTimer("MyAvatar");
|
||||
qApp->updateMyAvatarLookAtPosition();
|
||||
qApp->updateMyAvatarLookAtPosition(deltaTime);
|
||||
avatarManager->updateMyAvatar(deltaTime);
|
||||
}
|
||||
}
|
||||
|
@ -7516,6 +7516,7 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine
|
|||
scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get<AvatarManager>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get<LODManager>().data());
|
||||
qScriptRegisterMetaType(scriptEngine.data(), worldDetailQualityToScriptValue, worldDetailQualityFromScriptValue);
|
||||
|
||||
scriptEngine->registerGlobalObject("Keyboard", DependencyManager::get<KeyboardScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Performance", new PerformanceScriptingInterface());
|
||||
|
|
|
@ -292,7 +292,7 @@ public:
|
|||
|
||||
virtual void pushPostUpdateLambda(void* key, const std::function<void()>& func) override;
|
||||
|
||||
void updateMyAvatarLookAtPosition();
|
||||
void updateMyAvatarLookAtPosition(float deltaTime);
|
||||
|
||||
float getGameLoopRate() const { return _gameLoopCounter.rate(); }
|
||||
|
||||
|
|
|
@ -19,11 +19,8 @@
|
|||
#include "ui/DialogsManager.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
const float LODManager::DEFAULT_DESKTOP_LOD_DOWN_FPS = LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS;
|
||||
const float LODManager::DEFAULT_HMD_LOD_DOWN_FPS = LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS;
|
||||
|
||||
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", LODManager::DEFAULT_DESKTOP_LOD_DOWN_FPS);
|
||||
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", LODManager::DEFAULT_HMD_LOD_DOWN_FPS);
|
||||
Setting::Handle<int> desktopWorldDetailQuality("desktopWorldDetailQuality", (int)DEFAULT_WORLD_DETAIL_QUALITY);
|
||||
Setting::Handle<int> hmdWorldDetailQuality("hmdWorldDetailQuality", (int)DEFAULT_WORLD_DETAIL_QUALITY);
|
||||
|
||||
LODManager::LODManager() {
|
||||
}
|
||||
|
@ -326,19 +323,21 @@ QString LODManager::getLODFeedbackText() {
|
|||
}
|
||||
|
||||
void LODManager::loadSettings() {
|
||||
setDesktopLODTargetFPS(desktopLODDecreaseFPS.get());
|
||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||
auto desktopQuality = static_cast<WorldDetailQuality>(desktopWorldDetailQuality.get());
|
||||
auto hmdQuality = static_cast<WorldDetailQuality>(hmdWorldDetailQuality.get());
|
||||
|
||||
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
|
||||
if (qApp->property(hifi::properties::OCULUS_STORE).toBool() && firstRun.get()) {
|
||||
const float LOD_HIGH_QUALITY_LEVEL = 0.75f;
|
||||
setHMDLODTargetFPS(LOD_HIGH_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS);
|
||||
} else {
|
||||
setHMDLODTargetFPS(hmdLODDecreaseFPS.get());
|
||||
hmdQuality = WORLD_DETAIL_HIGH;
|
||||
}
|
||||
|
||||
setWorldDetailQuality(desktopQuality, false);
|
||||
setWorldDetailQuality(hmdQuality, true);
|
||||
}
|
||||
|
||||
void LODManager::saveSettings() {
|
||||
desktopLODDecreaseFPS.set(getDesktopLODTargetFPS());
|
||||
hmdLODDecreaseFPS.set(getHMDLODTargetFPS());
|
||||
desktopWorldDetailQuality.set((int)_desktopWorldDetailQuality);
|
||||
hmdWorldDetailQuality.set((int)_hmdWorldDetailQuality);
|
||||
}
|
||||
|
||||
const float MIN_DECREASE_FPS = 0.5f;
|
||||
|
@ -393,54 +392,33 @@ float LODManager::getLODTargetFPS() const {
|
|||
}
|
||||
}
|
||||
|
||||
void LODManager::setWorldDetailQuality(float quality) {
|
||||
static const float MIN_FPS = 10;
|
||||
static const float LOW = 0.25f;
|
||||
|
||||
bool isLowestValue = quality == LOW;
|
||||
bool isHMDMode = qApp->isHMDMode();
|
||||
|
||||
float maxFPS = isHMDMode ? LOD_MAX_LIKELY_HMD_FPS : LOD_MAX_LIKELY_DESKTOP_FPS;
|
||||
float desiredFPS = maxFPS;
|
||||
|
||||
if (!isLowestValue) {
|
||||
float calculatedFPS = (maxFPS - (maxFPS * quality));
|
||||
desiredFPS = calculatedFPS < MIN_FPS ? MIN_FPS : calculatedFPS;
|
||||
}
|
||||
|
||||
void LODManager::setWorldDetailQuality(WorldDetailQuality quality, bool isHMDMode) {
|
||||
float desiredFPS = isHMDMode ? QUALITY_TO_FPS_HMD[quality] : QUALITY_TO_FPS_DESKTOP[quality];
|
||||
if (isHMDMode) {
|
||||
_hmdWorldDetailQuality = quality;
|
||||
setHMDLODTargetFPS(desiredFPS);
|
||||
} else {
|
||||
_desktopWorldDetailQuality = quality;
|
||||
setDesktopLODTargetFPS(desiredFPS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LODManager::setWorldDetailQuality(WorldDetailQuality quality) {
|
||||
setWorldDetailQuality(quality, qApp->isHMDMode());
|
||||
emit worldDetailQualityChanged();
|
||||
}
|
||||
|
||||
float LODManager::getWorldDetailQuality() const {
|
||||
WorldDetailQuality LODManager::getWorldDetailQuality() const {
|
||||
return qApp->isHMDMode() ? _hmdWorldDetailQuality : _desktopWorldDetailQuality;
|
||||
}
|
||||
|
||||
static const float LOW = 0.25f;
|
||||
static const float MEDIUM = 0.5f;
|
||||
static const float HIGH = 0.75f;
|
||||
QScriptValue worldDetailQualityToScriptValue(QScriptEngine* engine, const WorldDetailQuality& worldDetailQuality) {
|
||||
return worldDetailQuality;
|
||||
}
|
||||
|
||||
bool inHMD = qApp->isHMDMode();
|
||||
|
||||
float targetFPS = 0.0f;
|
||||
if (inHMD) {
|
||||
targetFPS = getHMDLODTargetFPS();
|
||||
} else {
|
||||
targetFPS = getDesktopLODTargetFPS();
|
||||
}
|
||||
float maxFPS = inHMD ? LOD_MAX_LIKELY_HMD_FPS : LOD_MAX_LIKELY_DESKTOP_FPS;
|
||||
float percentage = 1.0f - targetFPS / maxFPS;
|
||||
|
||||
if (percentage <= LOW) {
|
||||
return LOW;
|
||||
} else if (percentage <= MEDIUM) {
|
||||
return MEDIUM;
|
||||
}
|
||||
|
||||
return HIGH;
|
||||
void worldDetailQualityFromScriptValue(const QScriptValue& object, WorldDetailQuality& worldDetailQuality) {
|
||||
worldDetailQuality =
|
||||
static_cast<WorldDetailQuality>(std::min(std::max(object.toInt32(), (int)WORLD_DETAIL_LOW), (int)WORLD_DETAIL_HIGH));
|
||||
}
|
||||
|
||||
void LODManager::setLODQualityLevel(float quality) {
|
||||
|
|
|
@ -23,26 +23,52 @@
|
|||
#include <render/Args.h>
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* <p>The world detail quality rendered.</p>
|
||||
* <table>
|
||||
* <thead>
|
||||
* <tr><th>Value</th><th>Description</th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td><code>0</code></td><td>Low world detail quality.</td></tr>
|
||||
* <tr><td><code>1</code></td><td>Medium world detail quality.</td></tr>
|
||||
* <tr><td><code>2</code></td><td>High world detail quality.</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {number} LODManager.WorldDetailQuality
|
||||
*/
|
||||
enum WorldDetailQuality {
|
||||
WORLD_DETAIL_LOW = 0,
|
||||
WORLD_DETAIL_MEDIUM,
|
||||
WORLD_DETAIL_HIGH
|
||||
};
|
||||
Q_DECLARE_METATYPE(WorldDetailQuality);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
const float LOD_DEFAULT_QUALITY_LEVEL = 0.2f; // default quality level setting is High (lower framerate)
|
||||
#else
|
||||
const float LOD_DEFAULT_QUALITY_LEVEL = 0.5f; // default quality level setting is Mid
|
||||
#endif
|
||||
const float LOD_MAX_LIKELY_DESKTOP_FPS = 60.0f; // this is essentially, V-synch fps
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
const float LOD_MAX_LIKELY_HMD_FPS = 36.0f; // this is essentially, V-synch fps
|
||||
const WorldDetailQuality DEFAULT_WORLD_DETAIL_QUALITY = WORLD_DETAIL_LOW;
|
||||
const std::vector<float> QUALITY_TO_FPS_DESKTOP = { 60.0f, 30.0f, 15.0f };
|
||||
const std::vector<float> QUALITY_TO_FPS_HMD = { 25.0f, 16.0f, 10.0f };
|
||||
#else
|
||||
const float LOD_MAX_LIKELY_HMD_FPS = 90.0f; // this is essentially, V-synch fps
|
||||
const WorldDetailQuality DEFAULT_WORLD_DETAIL_QUALITY = WORLD_DETAIL_MEDIUM;
|
||||
const std::vector<float> QUALITY_TO_FPS_DESKTOP = { 60.0f, 30.0f, 15.0f };
|
||||
const std::vector<float> QUALITY_TO_FPS_HMD = { 90.0f, 45.0f, 22.5f };
|
||||
#endif
|
||||
|
||||
const float LOD_OFFSET_FPS = 5.0f; // offset of FPS to add for computing the target framerate
|
||||
|
||||
class AABox;
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* The LOD class manages your Level of Detail functions within Interface.
|
||||
* @namespace LODManager
|
||||
*
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
* @hifi-avatar
|
||||
|
@ -51,12 +77,12 @@ class AABox;
|
|||
* @property {number} engineRunTime <em>Read-only.</em>
|
||||
* @property {number} gpuTime <em>Read-only.</em>
|
||||
*/
|
||||
|
||||
class LODManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
Q_PROPERTY(float worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality NOTIFY worldDetailQualityChanged)
|
||||
Q_PROPERTY(WorldDetailQuality worldDetailQuality READ getWorldDetailQuality WRITE setWorldDetailQuality
|
||||
NOTIFY worldDetailQualityChanged)
|
||||
|
||||
Q_PROPERTY(float lodQualityLevel READ getLODQualityLevel WRITE setLODQualityLevel NOTIFY lodQualityLevelChanged)
|
||||
|
||||
|
@ -193,8 +219,8 @@ public:
|
|||
float getSmoothRenderTime() const { return _smoothRenderTime; };
|
||||
float getSmoothRenderFPS() const { return (_smoothRenderTime > 0.0f ? (float)MSECS_PER_SECOND / _smoothRenderTime : 0.0f); };
|
||||
|
||||
void setWorldDetailQuality(float quality);
|
||||
float getWorldDetailQuality() const;
|
||||
void setWorldDetailQuality(WorldDetailQuality quality);
|
||||
WorldDetailQuality getWorldDetailQuality() const;
|
||||
|
||||
void setLODQualityLevel(float quality);
|
||||
float getLODQualityLevel() const;
|
||||
|
@ -220,9 +246,6 @@ public:
|
|||
float getPidOd() const;
|
||||
float getPidO() const;
|
||||
|
||||
static const float DEFAULT_DESKTOP_LOD_DOWN_FPS;
|
||||
static const float DEFAULT_HMD_LOD_DOWN_FPS;
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -244,6 +267,8 @@ signals:
|
|||
private:
|
||||
LODManager();
|
||||
|
||||
void setWorldDetailQuality(WorldDetailQuality quality, bool isHMDMode);
|
||||
|
||||
std::mutex _automaticLODLock;
|
||||
bool _automaticLODAdjust = true;
|
||||
|
||||
|
@ -258,8 +283,11 @@ private:
|
|||
|
||||
float _lodQualityLevel{ LOD_DEFAULT_QUALITY_LEVEL };
|
||||
|
||||
float _desktopTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS };
|
||||
float _hmdTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS };
|
||||
WorldDetailQuality _desktopWorldDetailQuality { DEFAULT_WORLD_DETAIL_QUALITY };
|
||||
WorldDetailQuality _hmdWorldDetailQuality { DEFAULT_WORLD_DETAIL_QUALITY };
|
||||
|
||||
float _desktopTargetFPS { QUALITY_TO_FPS_DESKTOP[_desktopWorldDetailQuality] };
|
||||
float _hmdTargetFPS { QUALITY_TO_FPS_HMD[_hmdWorldDetailQuality] };
|
||||
|
||||
float _lodHalfAngle = getHalfAngleFromVisibilityDistance(DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT);
|
||||
int _boundaryLevelAdjust = 0;
|
||||
|
@ -269,4 +297,7 @@ private:
|
|||
glm::vec4 _pidOutputs{ 0.0f };
|
||||
};
|
||||
|
||||
QScriptValue worldDetailQualityToScriptValue(QScriptEngine* engine, const WorldDetailQuality& worldDetailQuality);
|
||||
void worldDetailQualityFromScriptValue(const QScriptValue& object, WorldDetailQuality& worldDetailQuality);
|
||||
|
||||
#endif // hifi_LODManager_h
|
||||
|
|
|
@ -92,7 +92,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
|
|||
RenderScriptingInterface::getInstance()->setShadowsEnabled(true);
|
||||
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME);
|
||||
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.75f);
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_HIGH);
|
||||
|
||||
break;
|
||||
case PerformancePreset::MID:
|
||||
|
@ -104,7 +104,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
|
|||
|
||||
RenderScriptingInterface::getInstance()->setShadowsEnabled(false);
|
||||
qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::INTERACTIVE);
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.5f);
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_MEDIUM);
|
||||
|
||||
break;
|
||||
case PerformancePreset::LOW:
|
||||
|
@ -114,7 +114,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP
|
|||
|
||||
RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommandedPpiScale);
|
||||
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(0.25f);
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_LOW);
|
||||
|
||||
break;
|
||||
case PerformancePreset::UNKNOWN:
|
||||
|
|
|
@ -906,6 +906,25 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
|
|||
updateViewBoom();
|
||||
}
|
||||
|
||||
// Head's look at blending needs updating
|
||||
// before we perform rig animations and IK.
|
||||
{
|
||||
PerformanceTimer perfTimer("lookat");
|
||||
|
||||
CameraMode mode = qApp->getCamera().getMode();
|
||||
if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_FIRST_PERSON_LOOK_AT || mode == CAMERA_MODE_FIRST_PERSON ||
|
||||
mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
|
||||
if (!_pointAtActive || !_isPointTargetValid) {
|
||||
updateHeadLookAt(deltaTime);
|
||||
} else {
|
||||
resetHeadLookAt();
|
||||
}
|
||||
} else if (_headLookAtActive) {
|
||||
resetHeadLookAt();
|
||||
_headLookAtActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// update sensorToWorldMatrix for camera and hand controllers
|
||||
// before we perform rig animations and IK.
|
||||
updateSensorToWorldMatrix();
|
||||
|
@ -957,18 +976,6 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
|
|||
head->setPosition(headPosition);
|
||||
head->setScale(getModelScale());
|
||||
head->simulate(deltaTime);
|
||||
CameraMode mode = qApp->getCamera().getMode();
|
||||
if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_FIRST_PERSON_LOOK_AT || mode == CAMERA_MODE_FIRST_PERSON ||
|
||||
mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
|
||||
if (!_pointAtActive || !_isPointTargetValid) {
|
||||
updateHeadLookAt(deltaTime);
|
||||
} else {
|
||||
resetHeadLookAt();
|
||||
}
|
||||
} else if (_headLookAtActive){
|
||||
resetHeadLookAt();
|
||||
_headLookAtActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Record avatars movements.
|
||||
|
@ -2151,7 +2158,7 @@ static float lookAtCostFunction(const glm::vec3& myForward, const glm::vec3& myP
|
|||
const float DISTANCE_FACTOR = 3.14f;
|
||||
const float MY_ANGLE_FACTOR = 1.0f;
|
||||
const float OTHER_ANGLE_FACTOR = 1.0f;
|
||||
const float OTHER_IS_TALKING_TERM = otherIsTalking ? 1.0f : 0.0f;
|
||||
const float OTHER_IS_TALKING_TERM = otherIsTalking ? -1.0f : 0.0f;
|
||||
const float LOOKING_AT_OTHER_ALREADY_TERM = lookingAtOtherAlready ? -0.2f : 0.0f;
|
||||
|
||||
const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; // meters
|
||||
|
@ -2177,6 +2184,9 @@ static float lookAtCostFunction(const glm::vec3& myForward, const glm::vec3& myP
|
|||
|
||||
void MyAvatar::computeMyLookAtTarget(const AvatarHash& hash) {
|
||||
glm::vec3 myForward = _lookAtYaw * IDENTITY_FORWARD;
|
||||
if (_skeletonModel->isLoaded()) {
|
||||
myForward = getHeadJointFrontVector();
|
||||
}
|
||||
glm::vec3 myPosition = getHead()->getEyePosition();
|
||||
CameraMode mode = qApp->getCamera().getMode();
|
||||
if (mode == CAMERA_MODE_FIRST_PERSON_LOOK_AT || mode == CAMERA_MODE_FIRST_PERSON) {
|
||||
|
@ -2189,7 +2199,7 @@ void MyAvatar::computeMyLookAtTarget(const AvatarHash& hash) {
|
|||
foreach (const AvatarSharedPointer& avatarData, hash) {
|
||||
std::shared_ptr<Avatar> avatar = std::static_pointer_cast<Avatar>(avatarData);
|
||||
if (!avatar->isMyAvatar() && avatar->isInitialized()) {
|
||||
glm::vec3 otherForward = avatar->getHead()->getForwardDirection();
|
||||
glm::vec3 otherForward = avatar->getHeadJointFrontVector();
|
||||
glm::vec3 otherPosition = avatar->getHead()->getEyePosition();
|
||||
const float TIME_WITHOUT_TALKING_THRESHOLD = 1.0f;
|
||||
bool otherIsTalking = avatar->getHead()->getTimeWithoutTalking() <= TIME_WITHOUT_TALKING_THRESHOLD;
|
||||
|
@ -2277,7 +2287,9 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
AvatarHash hash = DependencyManager::get<AvatarManager>()->getHashCopy();
|
||||
|
||||
// determine what the best look at target for my avatar should be.
|
||||
computeMyLookAtTarget(hash);
|
||||
if (!_scriptControlsEyesLookAt) {
|
||||
computeMyLookAtTarget(hash);
|
||||
}
|
||||
|
||||
// snap look at position for avatars that are looking at me.
|
||||
snapOtherAvatarLookAtTargetsToMe(hash);
|
||||
|
@ -6612,7 +6624,7 @@ bool MyAvatar::getIsJointOverridden(int jointIndex) const {
|
|||
return _skeletonModel->getIsJointOverridden(jointIndex);
|
||||
}
|
||||
|
||||
void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera) {
|
||||
void MyAvatar::updateEyesLookAtPosition(FaceTracker* faceTracker, Camera& myCamera, float deltaTime) {
|
||||
|
||||
updateLookAtTargetAvatar();
|
||||
|
||||
|
@ -6642,6 +6654,13 @@ void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera)
|
|||
} else {
|
||||
lookAtSpot = myHead->getEyePosition() + glm::normalize(leftVec) * 1000.0f;
|
||||
}
|
||||
} else if (_scriptControlsEyesLookAt) {
|
||||
if (_scriptEyesControlTimer < MAX_LOOK_AT_TIME_SCRIPT_CONTROL) {
|
||||
_scriptEyesControlTimer += deltaTime;
|
||||
lookAtSpot = _eyesLookAtTarget.get();
|
||||
} else {
|
||||
_scriptControlsEyesLookAt = false;
|
||||
}
|
||||
} else {
|
||||
controller::Pose leftEyePose = getControllerPoseInAvatarFrame(controller::Action::LEFT_EYE);
|
||||
controller::Pose rightEyePose = getControllerPoseInAvatarFrame(controller::Action::RIGHT_EYE);
|
||||
|
@ -6704,8 +6723,9 @@ void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera)
|
|||
if (headPose.isValid()) {
|
||||
lookAtSpot = transformPoint(headPose.getMatrix(), glm::vec3(0.0f, 0.0f, TREE_SCALE));
|
||||
} else {
|
||||
lookAtSpot = myHead->getEyePosition() +
|
||||
(getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
|
||||
lookAtSpot = _shouldTurnToFaceCamera ?
|
||||
myHead->getLookAtPosition() :
|
||||
myHead->getEyePosition() + getHeadJointFrontVector() * (float)TREE_SCALE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6725,7 +6745,7 @@ void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
_eyesLookAtTarget.set(lookAtSpot);
|
||||
getHead()->setLookAtPosition(lookAtSpot);
|
||||
}
|
||||
|
||||
|
@ -6808,6 +6828,17 @@ void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) {
|
|||
_lookAtScriptTarget = lookAtTarget;
|
||||
}
|
||||
|
||||
void MyAvatar::setEyesLookAt(const glm::vec3& lookAtTarget) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
BLOCKING_INVOKE_METHOD(this, "setEyesLookAt",
|
||||
Q_ARG(const glm::vec3&, lookAtTarget));
|
||||
return;
|
||||
}
|
||||
_eyesLookAtTarget.set(lookAtTarget);
|
||||
_scriptEyesControlTimer = 0.0f;
|
||||
_scriptControlsEyesLookAt = true;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getLookAtPivotPoint() {
|
||||
glm::vec3 avatarUp = getWorldOrientation() * Vectors::UP;
|
||||
glm::vec3 yAxisEyePosition = getWorldPosition() + avatarUp * glm::dot(avatarUp, _skeletonModel->getDefaultEyeModelPosition());
|
||||
|
@ -6900,4 +6931,3 @@ void MyAvatar::resetPointAt() {
|
|||
POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1765,10 +1765,26 @@ public:
|
|||
/**jsdoc
|
||||
* Returns the current head look at target point in world coordinates.
|
||||
* @function MyAvatar.getHeadLookAt
|
||||
* @returns {Vec3} Default position between your avatar's eyes in world coordinates.
|
||||
* @returns {Vec3} The head's look at target in world coordinates.
|
||||
*/
|
||||
Q_INVOKABLE glm::vec3 getHeadLookAt() { return _lookAtCameraTarget; }
|
||||
|
||||
/**jsdoc
|
||||
* Force the avatar's eyes to look to the specified location.
|
||||
* Once this method is called, API calls will have full control of the eyes for a limited time.
|
||||
* If this method is not called for two seconds, the engine will regain control of the eyes.
|
||||
* @function MyAvatar.setEyesLookAt
|
||||
* @param {Vec3} lookAtTarget - The target point in world coordinates.
|
||||
*/
|
||||
Q_INVOKABLE void setEyesLookAt(const glm::vec3& lookAtTarget);
|
||||
|
||||
/**jsdoc
|
||||
* Returns the current eyes look at target point in world coordinates.
|
||||
* @function MyAvatar.getEyesLookAt
|
||||
* @returns {Vec3} The eyes's look at target in world coordinates.
|
||||
*/
|
||||
Q_INVOKABLE glm::vec3 getEyesLookAt() { return _eyesLookAtTarget.get(); }
|
||||
|
||||
/**jsdoc
|
||||
* Aims the pointing directional blending towards the provided target point.
|
||||
* The "point" reaction should be triggered before using this method.
|
||||
|
@ -1906,7 +1922,7 @@ public:
|
|||
bool getFlowActive() const;
|
||||
bool getNetworkGraphActive() const;
|
||||
|
||||
void updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera);
|
||||
void updateEyesLookAtPosition(FaceTracker* faceTracker, Camera& myCamera, float deltaTime);
|
||||
|
||||
// sets the reaction enabled and triggered parameters of the passed in params
|
||||
// also clears internal reaction triggers
|
||||
|
@ -2666,6 +2682,9 @@ private:
|
|||
|
||||
eyeContactTarget _eyeContactTarget;
|
||||
float _eyeContactTargetTimer { 0.0f };
|
||||
ThreadSafeValueCache<glm::vec3> _eyesLookAtTarget { glm::vec3() };
|
||||
bool _scriptControlsEyesLookAt{ false };
|
||||
float _scriptEyesControlTimer{ 0.0f };
|
||||
|
||||
glm::vec3 _trackedHeadPosition;
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ enum AudioDeviceRole {
|
|||
SelectedDesktopRole,
|
||||
SelectedHMDRole,
|
||||
PeakRole,
|
||||
InfoRole
|
||||
InfoRole,
|
||||
TypeRole
|
||||
};
|
||||
|
||||
QHash<int, QByteArray> AudioDeviceList::_roles {
|
||||
|
@ -52,7 +53,8 @@ QHash<int, QByteArray> AudioDeviceList::_roles {
|
|||
{ SelectedDesktopRole, "selectedDesktop" },
|
||||
{ SelectedHMDRole, "selectedHMD" },
|
||||
{ PeakRole, "peak" },
|
||||
{ InfoRole, "info" }
|
||||
{ InfoRole, "info" },
|
||||
{ TypeRole, "type"}
|
||||
};
|
||||
|
||||
static QString getTargetDevice(bool hmd, QAudio::Mode mode) {
|
||||
|
@ -60,12 +62,6 @@ static QString getTargetDevice(bool hmd, QAudio::Mode mode) {
|
|||
auto& setting = getSetting(hmd, mode);
|
||||
if (setting.isSet()) {
|
||||
deviceName = setting.get();
|
||||
} else if (hmd) {
|
||||
if (mode == QAudio::AudioInput) {
|
||||
deviceName = qApp->getActiveDisplayPlugin()->getPreferredAudioInDevice();
|
||||
} else { // if (_mode == QAudio::AudioOutput)
|
||||
deviceName = qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice();
|
||||
}
|
||||
} else {
|
||||
deviceName = HifiAudioDeviceInfo::DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
@ -144,6 +140,8 @@ QVariant AudioDeviceList::data(const QModelIndex& index, int role) const {
|
|||
return _devices.at(index.row())->selectedHMD;
|
||||
} else if (role == InfoRole) {
|
||||
return QVariant::fromValue<HifiAudioDeviceInfo>(_devices.at(index.row())->info);
|
||||
} else if (role == TypeRole) {
|
||||
return _devices.at(index.row())->type;
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -166,8 +164,8 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) {
|
|||
QString deviceName = getTargetDevice(contextIsHMD, _mode);
|
||||
// FIXME can't use blocking connections here, so we can't determine whether the switch succeeded or not
|
||||
// We need to have the AudioClient emit signals on switch success / failure
|
||||
QMetaObject::invokeMethod(client, "switchAudioDevice",
|
||||
Q_ARG(QAudio::Mode, _mode), Q_ARG(QString, deviceName));
|
||||
QMetaObject::invokeMethod(client, "switchAudioDevice",
|
||||
Q_ARG(QAudio::Mode, _mode), Q_ARG(QString, deviceName), Q_ARG(bool, contextIsHMD));
|
||||
|
||||
#if 0
|
||||
bool switchResult = false;
|
||||
|
@ -265,13 +263,20 @@ void AudioDeviceList::onDevicesChanged(const QList<HifiAudioDeviceInfo>& devices
|
|||
bool hmdIsSelected = false;
|
||||
bool desktopIsSelected = false;
|
||||
|
||||
foreach(const HifiAudioDeviceInfo& deviceInfo, devices) {
|
||||
for (bool isHMD : {false, true}) {
|
||||
auto& backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName;
|
||||
if (deviceInfo.deviceName() == backupSelectedDeviceName) {
|
||||
HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||
selectedDevice = deviceInfo;
|
||||
backupSelectedDeviceName.clear();
|
||||
if (!_backupSelectedDesktopDeviceName.isEmpty() && !_backupSelectedHMDDeviceName.isEmpty()) {
|
||||
foreach(const HifiAudioDeviceInfo& deviceInfo, devices) {
|
||||
for (bool isHMD : {false, true}) {
|
||||
auto& backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName;
|
||||
if (deviceInfo.deviceName() == backupSelectedDeviceName) {
|
||||
if (isHMD && deviceInfo.getDeviceType() != HifiAudioDeviceInfo::desktop) {
|
||||
_selectedHMDDevice= deviceInfo;
|
||||
backupSelectedDeviceName.clear();
|
||||
} else if (!isHMD && deviceInfo.getDeviceType() != HifiAudioDeviceInfo::hmd) {
|
||||
_selectedDesktopDevice = deviceInfo;
|
||||
backupSelectedDeviceName.clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,10 +286,18 @@ void AudioDeviceList::onDevicesChanged(const QList<HifiAudioDeviceInfo>& devices
|
|||
device.info = deviceInfo;
|
||||
|
||||
if (deviceInfo.isDefault()) {
|
||||
if (deviceInfo.getMode() == QAudio::AudioInput) {
|
||||
device.display = "Computer's default microphone (recommended)";
|
||||
} else {
|
||||
device.display = "Computer's default audio (recommended)";
|
||||
if (deviceInfo.getDeviceType() == HifiAudioDeviceInfo::desktop) {
|
||||
if (deviceInfo.getMode() == QAudio::AudioInput) {
|
||||
device.display = "Computer's default microphone (recommended)";
|
||||
} else {
|
||||
device.display = "Computer's default audio (recommended)";
|
||||
}
|
||||
} else if (deviceInfo.getDeviceType() == HifiAudioDeviceInfo::hmd) {
|
||||
if (deviceInfo.getMode() == QAudio::AudioInput) {
|
||||
device.display = "Headset's default mic (recommended)";
|
||||
} else {
|
||||
device.display = "Headset's default audio (recommended)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
device.display = device.info.deviceName()
|
||||
|
@ -292,6 +305,19 @@ void AudioDeviceList::onDevicesChanged(const QList<HifiAudioDeviceInfo>& devices
|
|||
.remove("Device")
|
||||
.replace(" )", ")");
|
||||
}
|
||||
|
||||
switch (deviceInfo.getDeviceType()) {
|
||||
case HifiAudioDeviceInfo::hmd:
|
||||
device.type = "hmd";
|
||||
break;
|
||||
case HifiAudioDeviceInfo::desktop:
|
||||
device.type = "desktop";
|
||||
break;
|
||||
case HifiAudioDeviceInfo::both:
|
||||
device.type = "both";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (bool isHMD : {false, true}) {
|
||||
HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||
|
@ -302,8 +328,14 @@ void AudioDeviceList::onDevicesChanged(const QList<HifiAudioDeviceInfo>& devices
|
|||
}
|
||||
else {
|
||||
//no selected device for context. fallback to saved
|
||||
const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName;
|
||||
isSelected = (device.info.deviceName() == savedDeviceName);
|
||||
QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName;
|
||||
|
||||
if (device.info.deviceName() == savedDeviceName) {
|
||||
if ((isHMD && device.info.getDeviceType() != HifiAudioDeviceInfo::desktop) ||
|
||||
(!isHMD && device.info.getDeviceType() != HifiAudioDeviceInfo::hmd)) {
|
||||
isSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
QString display;
|
||||
bool selectedDesktop { false };
|
||||
bool selectedHMD { false };
|
||||
QString type;
|
||||
};
|
||||
|
||||
class AudioDeviceList : public QAbstractListModel {
|
||||
|
|
|
@ -18,15 +18,23 @@
|
|||
#include "DependencyManager.h"
|
||||
|
||||
/**jsdoc
|
||||
* The Keyboard API provides facilities to use 3D Physical keyboard.
|
||||
* The <code>Keyboard</code> API provides facilities to use an in-world, virtual keyboard. When enabled, this keyboard is
|
||||
* displayed instead of the 2D keyboard that raises at the bottom of the tablet or Web entities when a text input field has
|
||||
* focus and you're in HMD mode.
|
||||
*
|
||||
* @namespace Keyboard
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
* @hifi-avatar
|
||||
*
|
||||
* @property {bool} raised - <code>true</code> If the keyboard is visible <code>false</code> otherwise
|
||||
* @property {bool} password - <code>true</code> Will show * instead of characters in the text display <code>false</code> otherwise
|
||||
* @property {boolean} raised - <code>true</code> if the virtual keyboard is visible, <code>false</code> if it isn't.
|
||||
* @property {boolean} password - <code>true</code> if <code>"*"</code>s are displayed on the virtual keyboard's display
|
||||
* instead of the characters typed, <code>false</code> if the actual characters are displayed.
|
||||
* @property {boolean} use3DKeyboard - <code>true</code> if user settings have "Use Virtual Keyboard" enabled,
|
||||
* <code>false</code> if it's disabled. <em>Read-only.</em>
|
||||
* @property {boolean} preferMalletsOverLasers - <code>true</code> if user settings for the virtual keyboard have "Mallets"
|
||||
* selected, <code>false</code> if "Lasers" is selected. <em>Read-only.</em>
|
||||
*/
|
||||
|
||||
class KeyboardScriptingInterface : public QObject, public Dependency {
|
||||
|
@ -39,14 +47,61 @@ class KeyboardScriptingInterface : public QObject, public Dependency {
|
|||
public:
|
||||
KeyboardScriptingInterface() = default;
|
||||
~KeyboardScriptingInterface() = default;
|
||||
|
||||
/**jsdoc
|
||||
* Loads a JSON file that defines the virtual keyboard's layout. The default JSON file used is
|
||||
* {@link https://github.com/highfidelity/hifi/blob/master/interface/resources/config/keyboard.json|https://github.com/highfidelity/hifi/.../keyboard.json}.
|
||||
* @function Keyboard.loadKeyboardFile
|
||||
* @param {string} path - The keyboard JSON file.
|
||||
*/
|
||||
Q_INVOKABLE void loadKeyboardFile(const QString& string);
|
||||
|
||||
/**jsdoc
|
||||
* Enables the left mallet so that it is displayed when in HMD mode.
|
||||
* @function Keyboard.enableLeftMallet
|
||||
*/
|
||||
Q_INVOKABLE void enableLeftMallet();
|
||||
|
||||
/**jsdoc
|
||||
* Enables the right mallet so that it is displayed when in HMD mode.
|
||||
* @function Keyboard.enableRightMallet
|
||||
*/
|
||||
Q_INVOKABLE void enableRightMallet();
|
||||
|
||||
/**jsdoc
|
||||
* Disables the left mallet so that it is not displayed when in HMD mode.
|
||||
* @function Keyboard.disableLeftMallet
|
||||
*/
|
||||
Q_INVOKABLE void disableLeftMallet();
|
||||
|
||||
/**jsdoc
|
||||
* Disables the right mallet so that it is not displayed when in HMD mode.
|
||||
* @function Keyboard.disableRightMallet
|
||||
*/
|
||||
Q_INVOKABLE void disableRightMallet();
|
||||
|
||||
/**jsdoc
|
||||
* Configures the virtual keyboard to recognize a ray pointer as the left hand's laser.
|
||||
* @function Keyboard.setLeftHandLaser
|
||||
* @param {number} leftHandLaser - The ID of a ray pointer created by {@link Pointers.createPointer}.
|
||||
*/
|
||||
Q_INVOKABLE void setLeftHandLaser(unsigned int leftHandLaser);
|
||||
|
||||
/**jsdoc
|
||||
* Configures the virtual keyboard to recognize a ray pointer as the right hand's laser.
|
||||
* @function Keyboard.setRightHandLaser
|
||||
* @param {number} rightHandLaser - The ID of a ray pointer created by {@link Pointers.createPointer}.
|
||||
*/
|
||||
Q_INVOKABLE void setRightHandLaser(unsigned int rightHandLaser);
|
||||
|
||||
/**jsdoc
|
||||
* Checks whether an entity is part of the virtual keyboard.
|
||||
* @function Keyboard.containsID
|
||||
* @param {Uuid} entityID - The entity ID.
|
||||
* @returns {boolean} <code>true</code> if the entity is part of the virtual keyboard, <code>false</code> if it isn't.
|
||||
*/
|
||||
Q_INVOKABLE bool containsID(const QUuid& overlayID) const;
|
||||
|
||||
private:
|
||||
bool getPreferMalletsOverLasers() const;
|
||||
bool isRaised() const;
|
||||
|
|
|
@ -41,7 +41,8 @@ void MenuScriptingInterface::removeMenu(const QString& menu) {
|
|||
|
||||
bool MenuScriptingInterface::menuExists(const QString& menu) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->menuExists(menu);
|
||||
Menu* menuInstance = Menu::getInstance();
|
||||
return menuInstance && menuInstance->menuExists(menu);
|
||||
}
|
||||
bool result { false };
|
||||
BLOCKING_INVOKE_METHOD(Menu::getInstance(), "menuExists",
|
||||
|
@ -84,7 +85,8 @@ void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString&
|
|||
|
||||
bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& menuitem) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->menuItemExists(menu, menuitem);
|
||||
Menu* menuInstance = Menu::getInstance();
|
||||
return menuInstance && menuInstance->menuItemExists(menu, menuitem);
|
||||
}
|
||||
bool result { false };
|
||||
BLOCKING_INVOKE_METHOD(Menu::getInstance(), "menuItemExists",
|
||||
|
@ -96,7 +98,8 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString&
|
|||
|
||||
bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->isOptionChecked(menuOption);
|
||||
Menu* menuInstance = Menu::getInstance();
|
||||
return menuInstance && menuInstance->isOptionChecked(menuOption);
|
||||
}
|
||||
bool result { false };
|
||||
BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isOptionChecked",
|
||||
|
@ -113,7 +116,8 @@ void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool
|
|||
|
||||
bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->isOptionChecked(menuOption);
|
||||
Menu* menuInstance = Menu::getInstance();
|
||||
return menuInstance && menuInstance->isMenuEnabled(menuOption);
|
||||
}
|
||||
bool result { false };
|
||||
BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isMenuEnabled",
|
||||
|
|
|
@ -58,18 +58,19 @@ void setupPreferences() {
|
|||
static const QString GRAPHICS_QUALITY { "Graphics Quality" };
|
||||
{
|
||||
auto getter = []()->float {
|
||||
return DependencyManager::get<LODManager>()->getWorldDetailQuality();
|
||||
return (int)DependencyManager::get<LODManager>()->getWorldDetailQuality();
|
||||
};
|
||||
|
||||
auto setter = [](float value) {
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(value);
|
||||
auto setter = [](int value) {
|
||||
DependencyManager::get<LODManager>()->setWorldDetailQuality(static_cast<WorldDetailQuality>(value));
|
||||
};
|
||||
|
||||
auto wodSlider = new SliderPreference(GRAPHICS_QUALITY, "World Detail", getter, setter);
|
||||
wodSlider->setMin(0.25f);
|
||||
wodSlider->setMax(0.75f);
|
||||
wodSlider->setStep(0.25f);
|
||||
preferences->addPreference(wodSlider);
|
||||
auto wodButtons = new RadioButtonsPreference(GRAPHICS_QUALITY, "World Detail", getter, setter);
|
||||
QStringList items;
|
||||
items << "Low World Detail" << "Medium World Detail" << "High World Detail";
|
||||
wodButtons->setHeading("World Detail");
|
||||
wodButtons->setItems(items);
|
||||
preferences->addPreference(wodButtons);
|
||||
|
||||
auto getterShadow = []()->bool {
|
||||
auto menu = Menu::getInstance();
|
||||
|
|
|
@ -6,6 +6,7 @@ setup_hifi_library(Network Multimedia ${PLATFORM_QT_COMPONENTS})
|
|||
link_hifi_libraries(audio plugins)
|
||||
include_hifi_library_headers(shared)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
||||
if (ANDROID)
|
||||
else ()
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <QtMultimedia/QAudioInput>
|
||||
#include <QtMultimedia/QAudioOutput>
|
||||
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <ThreadHelpers.h>
|
||||
#include <NodeList.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include <SettingHandle.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Transform.h>
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
|
||||
#include "AudioClientLogging.h"
|
||||
#include "AudioLogging.h"
|
||||
|
@ -81,20 +83,50 @@ Mutex _recordMutex;
|
|||
|
||||
HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode);
|
||||
|
||||
static QString getHmdAudioDeviceName(QAudio::Mode mode) {
|
||||
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getAllDisplayPlugins()) {
|
||||
if (displayPlugin && displayPlugin->isHmd()) {
|
||||
if (mode == QAudio::AudioInput) {
|
||||
return displayPlugin->getPreferredAudioInDevice();
|
||||
} else {
|
||||
return displayPlugin->getPreferredAudioOutDevice();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
QList<HifiAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) {
|
||||
//get hmd device name prior to locking device mutex. in case of shutdown, this thread will be locked and audio client
|
||||
//cannot properly shut down.
|
||||
QString hmdDeviceName = getHmdAudioDeviceName(mode);
|
||||
|
||||
// NOTE: availableDevices() clobbers the Qt internal device list
|
||||
Lock lock(_deviceMutex);
|
||||
auto devices = QAudioDeviceInfo::availableDevices(mode);
|
||||
|
||||
QList<HifiAudioDeviceInfo> newDevices;
|
||||
|
||||
for (auto& device : devices) {
|
||||
newDevices.push_back(HifiAudioDeviceInfo(device, false, mode));
|
||||
}
|
||||
|
||||
newDevices.push_front(defaultAudioDeviceForMode(mode));
|
||||
|
||||
|
||||
if (!hmdDeviceName.isNull() && !hmdDeviceName.isEmpty()) {
|
||||
HifiAudioDeviceInfo hmdDevice;
|
||||
foreach(auto device, newDevices) {
|
||||
if (device.getDevice().deviceName() == hmdDeviceName) {
|
||||
hmdDevice = HifiAudioDeviceInfo(device.getDevice(), true, mode, HifiAudioDeviceInfo::hmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hmdDevice.getDevice().isNull()) {
|
||||
newDevices.push_front(hmdDevice);
|
||||
}
|
||||
}
|
||||
return newDevices;
|
||||
}
|
||||
|
||||
|
@ -110,8 +142,8 @@ void AudioClient::checkDevices() {
|
|||
auto inputDevices = getAvailableDevices(QAudio::AudioInput);
|
||||
auto outputDevices = getAvailableDevices(QAudio::AudioOutput);
|
||||
|
||||
QMetaObject::invokeMethod(this, "changeDefault", Q_ARG(HifiAudioDeviceInfo, inputDevices.first()), Q_ARG(QAudio::Mode, QAudio::AudioInput));
|
||||
QMetaObject::invokeMethod(this, "changeDefault", Q_ARG(HifiAudioDeviceInfo, outputDevices.first()), Q_ARG(QAudio::Mode, QAudio::AudioOutput));
|
||||
checkDefaultChanges(inputDevices);
|
||||
checkDefaultChanges(outputDevices);
|
||||
|
||||
Lock lock(_deviceMutex);
|
||||
if (inputDevices != _inputDevices) {
|
||||
|
@ -125,6 +157,14 @@ void AudioClient::checkDevices() {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioClient::checkDefaultChanges(QList<HifiAudioDeviceInfo>& devices) {
|
||||
foreach(auto device, devices) {
|
||||
if (device.isDefault()) {
|
||||
QMetaObject::invokeMethod(this, "changeDefault", Q_ARG(HifiAudioDeviceInfo, device), Q_ARG(QAudio::Mode, device.getMode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudio::Mode mode) const {
|
||||
Lock lock(_deviceMutex);
|
||||
|
||||
|
@ -386,12 +426,14 @@ void AudioClient::setAudioPaused(bool pause) {
|
|||
}
|
||||
}
|
||||
|
||||
HifiAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||
HifiAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName, bool isHmd=false) {
|
||||
HifiAudioDeviceInfo result;
|
||||
foreach (HifiAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
||||
if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) {
|
||||
result = audioDevice;
|
||||
break;
|
||||
if ((!isHmd && audioDevice.getDeviceType() != HifiAudioDeviceInfo::hmd) || (isHmd && audioDevice.getDeviceType() != HifiAudioDeviceInfo::desktop)) {
|
||||
result = audioDevice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -477,7 +519,7 @@ HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
// find a device in the list that matches the name we have and return it
|
||||
foreach(QAudioDeviceInfo audioDevice, devices){
|
||||
if (audioDevice.deviceName() == CFStringGetCStringPtr(deviceName, kCFStringEncodingMacRoman)) {
|
||||
return HifiAudioDeviceInfo(audioDevice, true, mode);
|
||||
return HifiAudioDeviceInfo(audioDevice, true, mode, HifiAudioDeviceInfo::desktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +574,7 @@ HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
HifiAudioDeviceInfo foundDevice;
|
||||
foreach(QAudioDeviceInfo audioDevice, devices) {
|
||||
if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) {
|
||||
foundDevice=HifiAudioDeviceInfo(audioDevice,true,mode);
|
||||
foundDevice = HifiAudioDeviceInfo(audioDevice, true, mode, HifiAudioDeviceInfo::desktop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -558,8 +600,8 @@ HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
}
|
||||
#endif
|
||||
// fallback for failed lookup is the default device
|
||||
return (mode == QAudio::AudioInput) ? HifiAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice(), true,mode) :
|
||||
HifiAudioDeviceInfo(QAudioDeviceInfo::defaultOutputDevice(), true, mode);
|
||||
return (mode == QAudio::AudioInput) ? HifiAudioDeviceInfo(QAudioDeviceInfo::defaultInputDevice(), true, mode, HifiAudioDeviceInfo::desktop) :
|
||||
HifiAudioDeviceInfo(QAudioDeviceInfo::defaultOutputDevice(), true, mode, HifiAudioDeviceInfo::desktop);
|
||||
}
|
||||
|
||||
bool AudioClient::getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName) {
|
||||
|
@ -763,6 +805,7 @@ void AudioClient::stop() {
|
|||
// Destruction of the pointers will occur when the parent object (this) is destroyed)
|
||||
{
|
||||
Lock lock(_checkDevicesMutex);
|
||||
_checkDevicesTimer->stop();
|
||||
_checkDevicesTimer = nullptr;
|
||||
}
|
||||
{
|
||||
|
@ -948,13 +991,18 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) {
|
|||
|
||||
void AudioClient::changeDefault(HifiAudioDeviceInfo newDefault, QAudio::Mode mode) {
|
||||
HifiAudioDeviceInfo currentDevice = mode == QAudio::AudioInput ? _inputDeviceInfo : _outputDeviceInfo;
|
||||
if (currentDevice.isDefault() && currentDevice.getDevice() != newDefault.getDevice()) {
|
||||
if (currentDevice.isDefault() && currentDevice.getDeviceType() == newDefault.getDeviceType() && currentDevice.getDevice() != newDefault.getDevice()) {
|
||||
switchAudioDevice(mode, newDefault);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioClient::switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo& deviceInfo) {
|
||||
auto device = deviceInfo;
|
||||
if (deviceInfo.getDevice().isNull()) {
|
||||
qCDebug(audioclient) << __FUNCTION__ << " switching to null device :"
|
||||
<< deviceInfo.deviceName() << " : " << deviceInfo.getDevice().deviceName();
|
||||
}
|
||||
|
||||
if (mode == QAudio::AudioInput) {
|
||||
return switchInputToAudioDevice(device);
|
||||
} else {
|
||||
|
@ -962,8 +1010,8 @@ bool AudioClient::switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo
|
|||
}
|
||||
}
|
||||
|
||||
bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QString& deviceName) {
|
||||
return switchAudioDevice(mode, getNamedAudioDeviceForMode(mode, deviceName));
|
||||
bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QString& deviceName, bool isHmd) {
|
||||
return switchAudioDevice(mode, getNamedAudioDeviceForMode(mode, deviceName, isHmd));
|
||||
}
|
||||
|
||||
void AudioClient::configureReverb() {
|
||||
|
@ -1771,7 +1819,8 @@ void AudioClient::outputFormatChanged() {
|
|||
bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) {
|
||||
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
|
||||
|
||||
qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << _inputDeviceInfo.deviceName() <<"----"<<inputDeviceInfo.getDevice().deviceName() << "]";
|
||||
qCDebug(audioclient) << __FUNCTION__ << "_inputDeviceInfo: [" << _inputDeviceInfo.deviceName() << ":" << _inputDeviceInfo.getDevice().deviceName()
|
||||
<< "-- inputDeviceInfo:" << inputDeviceInfo.deviceName() << ":" << inputDeviceInfo.getDevice().deviceName() << "]";
|
||||
bool supportedFormat = false;
|
||||
|
||||
// NOTE: device start() uses the Qt internal device list
|
||||
|
@ -1823,8 +1872,9 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice
|
|||
}
|
||||
|
||||
if (!inputDeviceInfo.getDevice().isNull()) {
|
||||
qCDebug(audioclient) << "The audio input device " << inputDeviceInfo.deviceName() << "is available.";
|
||||
qCDebug(audioclient) << "The audio input device" << inputDeviceInfo.deviceName() << ":" << inputDeviceInfo.getDevice().deviceName() << "is available.";
|
||||
|
||||
//do not update UI that we're changing devices if default or same device
|
||||
bool doEmit = _inputDeviceInfo.deviceName() != inputDeviceInfo.deviceName();
|
||||
_inputDeviceInfo = inputDeviceInfo;
|
||||
if (doEmit) {
|
||||
|
@ -1959,9 +2009,9 @@ void AudioClient::setHeadsetPluggedIn(bool pluggedIn) {
|
|||
bool aecEnabled = enableAEC.get();
|
||||
|
||||
if ((pluggedIn || !aecEnabled) && _inputDeviceInfo.deviceName() != VOICE_RECOGNITION) {
|
||||
switchAudioDevice(QAudio::AudioInput, VOICE_RECOGNITION);
|
||||
switchAudioDevice(QAudio::AudioInput, VOICE_RECOGNITION, false);
|
||||
} else if (!pluggedIn && aecEnabled && _inputDeviceInfo.deviceName() != VOICE_COMMUNICATION) {
|
||||
switchAudioDevice(QAudio::AudioInput, VOICE_COMMUNICATION);
|
||||
switchAudioDevice(QAudio::AudioInput, VOICE_COMMUNICATION, false);
|
||||
}
|
||||
}
|
||||
_isHeadsetPluggedIn = pluggedIn;
|
||||
|
@ -2006,8 +2056,9 @@ void AudioClient::noteAwakening() {
|
|||
|
||||
bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) {
|
||||
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
|
||||
|
||||
qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]";
|
||||
|
||||
qCDebug(audioclient) << __FUNCTION__ << "_outputdeviceInfo: [" << _outputDeviceInfo.deviceName() << ":" << _outputDeviceInfo.getDevice().deviceName()
|
||||
<< "-- outputDeviceInfo:" << outputDeviceInfo.deviceName() << ":" << outputDeviceInfo.getDevice().deviceName() << "]";
|
||||
bool supportedFormat = false;
|
||||
|
||||
// NOTE: device start() uses the Qt internal device list
|
||||
|
@ -2063,7 +2114,9 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi
|
|||
}
|
||||
|
||||
if (!outputDeviceInfo.getDevice().isNull()) {
|
||||
qCDebug(audioclient) << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
||||
qCDebug(audioclient) << "The audio output device" << outputDeviceInfo.deviceName() << ":" << outputDeviceInfo.getDevice().deviceName() << "is available.";
|
||||
|
||||
//do not update UI that we're changing devices if default or same device
|
||||
bool doEmit = _outputDeviceInfo.deviceName() != outputDeviceInfo.deviceName();
|
||||
_outputDeviceInfo = outputDeviceInfo;
|
||||
if (doEmit) {
|
||||
|
|
|
@ -238,10 +238,11 @@ public slots:
|
|||
|
||||
bool shouldLoopbackInjectors() override { return _shouldEchoToServer; }
|
||||
Q_INVOKABLE void changeDefault(HifiAudioDeviceInfo newDefault, QAudio::Mode mode);
|
||||
void checkDefaultChanges(QList<HifiAudioDeviceInfo>& devices);
|
||||
|
||||
// calling with a null QAudioDevice will use the system default
|
||||
bool switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo& deviceInfo = HifiAudioDeviceInfo());
|
||||
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
|
||||
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName, bool isHmd);
|
||||
// Qt opensles plugin is not able to detect when the headset is plugged in
|
||||
void setHeadsetPluggedIn(bool pluggedIn);
|
||||
|
||||
|
|
|
@ -22,15 +22,14 @@ HifiAudioDeviceInfo& HifiAudioDeviceInfo::operator=(const HifiAudioDeviceInfo& o
|
|||
_audioDeviceInfo = other.getDevice();
|
||||
_mode = other.getMode();
|
||||
_isDefault = other.isDefault();
|
||||
_deviceType = other.getDeviceType();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool HifiAudioDeviceInfo::operator==(const HifiAudioDeviceInfo& rhs) const {
|
||||
//Does the QAudioDeviceinfo match as well as is this the default device or
|
||||
return getDevice() == rhs.getDevice() && isDefault() == rhs.isDefault();
|
||||
}
|
||||
bool HifiAudioDeviceInfo::operator!=(const HifiAudioDeviceInfo& rhs) const {
|
||||
return getDevice() != rhs.getDevice() || isDefault() != rhs.isDefault();
|
||||
}
|
||||
|
||||
}
|
|
@ -23,19 +23,27 @@ class HifiAudioDeviceInfo : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DeviceType {
|
||||
desktop,
|
||||
hmd,
|
||||
both
|
||||
};
|
||||
|
||||
HifiAudioDeviceInfo() : QObject() {}
|
||||
HifiAudioDeviceInfo(const HifiAudioDeviceInfo &deviceInfo) : QObject(){
|
||||
_audioDeviceInfo = deviceInfo.getDevice();
|
||||
_mode = deviceInfo.getMode();
|
||||
_isDefault = deviceInfo.isDefault();
|
||||
_deviceType = deviceInfo.getDeviceType();
|
||||
}
|
||||
|
||||
HifiAudioDeviceInfo(QAudioDeviceInfo deviceInfo, bool isDefault, QAudio::Mode mode) :
|
||||
HifiAudioDeviceInfo(QAudioDeviceInfo deviceInfo, bool isDefault, QAudio::Mode mode, DeviceType devType=both) :
|
||||
_audioDeviceInfo(deviceInfo),
|
||||
_isDefault(isDefault),
|
||||
_mode(mode){
|
||||
_mode(mode),
|
||||
_deviceType(devType){
|
||||
}
|
||||
|
||||
|
||||
void setMode(QAudio::Mode mode) { _mode = mode; }
|
||||
void setIsDefault() { _isDefault = true; }
|
||||
void setDevice(QAudioDeviceInfo devInfo);
|
||||
|
@ -52,7 +60,7 @@ public:
|
|||
QAudioDeviceInfo getDevice() const { return _audioDeviceInfo; }
|
||||
bool isDefault() const { return _isDefault; }
|
||||
QAudio::Mode getMode() const { return _mode; }
|
||||
|
||||
DeviceType getDeviceType() const { return _deviceType; }
|
||||
HifiAudioDeviceInfo& operator=(const HifiAudioDeviceInfo& other);
|
||||
bool operator==(const HifiAudioDeviceInfo& rhs) const;
|
||||
bool operator!=(const HifiAudioDeviceInfo& rhs) const;
|
||||
|
@ -61,6 +69,7 @@ private:
|
|||
QAudioDeviceInfo _audioDeviceInfo;
|
||||
bool _isDefault { false };
|
||||
QAudio::Mode _mode { QAudio::AudioInput };
|
||||
DeviceType _deviceType{ both };
|
||||
|
||||
public:
|
||||
static const QString DEFAULT_DEVICE_NAME;
|
||||
|
|
|
@ -165,9 +165,6 @@ AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& av
|
|||
_status = Status::ENDED;
|
||||
}
|
||||
|
||||
if (previousStatus != _status) {
|
||||
qDebug(avatars_renderer) << "AvatarTransit " << avatarTransitStatusToStringMap[(int)previousStatus] << "->" << avatarTransitStatusToStringMap[_status];
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,10 +96,16 @@ void Head::simulate(float deltaTime) {
|
|||
// no blinking when brows are raised; blink less with increasing loudness
|
||||
const float BASE_BLINK_RATE = 15.0f / 60.0f;
|
||||
const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f;
|
||||
if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(fabs(_averageLoudness - _longTermAverageLoudness)) *
|
||||
if (_forceBlinkToRetarget || forceBlink ||
|
||||
(_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(fabs(_averageLoudness - _longTermAverageLoudness)) *
|
||||
ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) {
|
||||
float randSpeedVariability = randFloat();
|
||||
float eyeBlinkVelocity = BLINK_SPEED + randSpeedVariability * BLINK_SPEED_VARIABILITY;
|
||||
if (_forceBlinkToRetarget) {
|
||||
// Slow down by half the blink if reseting eye target
|
||||
eyeBlinkVelocity = 0.5f * eyeBlinkVelocity;
|
||||
_forceBlinkToRetarget = false;
|
||||
}
|
||||
_leftEyeBlinkVelocity = eyeBlinkVelocity;
|
||||
_rightEyeBlinkVelocity = eyeBlinkVelocity;
|
||||
if (randFloat() < 0.5f) {
|
||||
|
@ -114,13 +120,12 @@ void Head::simulate(float deltaTime) {
|
|||
|
||||
if (_leftEyeBlink == FULLY_CLOSED) {
|
||||
_leftEyeBlinkVelocity = -BLINK_SPEED;
|
||||
|
||||
updateEyeLookAt();
|
||||
} else if (_leftEyeBlink == FULLY_OPEN) {
|
||||
_leftEyeBlinkVelocity = 0.0f;
|
||||
}
|
||||
if (_rightEyeBlink == FULLY_CLOSED) {
|
||||
_rightEyeBlinkVelocity = -BLINK_SPEED;
|
||||
|
||||
} else if (_rightEyeBlink == FULLY_OPEN) {
|
||||
_rightEyeBlinkVelocity = 0.0f;
|
||||
}
|
||||
|
@ -350,3 +355,24 @@ float Head::getFinalPitch() const {
|
|||
float Head::getFinalRoll() const {
|
||||
return glm::clamp(_baseRoll + _deltaRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
|
||||
}
|
||||
|
||||
void Head::setLookAtPosition(const glm::vec3& lookAtPosition) {
|
||||
if (_isEyeLookAtUpdated && _requestLookAtPosition != lookAtPosition) {
|
||||
_lookAtPositionChanged = usecTimestampNow();
|
||||
glm::vec3 oldAvatarLookAtVector = _requestLookAtPosition - _owningAvatar->getWorldPosition();
|
||||
glm::vec3 newAvatarLookAtVector = lookAtPosition - _owningAvatar->getWorldPosition();
|
||||
const float MIN_BLINK_ANGLE = 0.35f; // 20 degrees
|
||||
_forceBlinkToRetarget = angleBetween(oldAvatarLookAtVector, newAvatarLookAtVector) > MIN_BLINK_ANGLE;
|
||||
if (_forceBlinkToRetarget) {
|
||||
_isEyeLookAtUpdated = false;
|
||||
} else {
|
||||
_lookAtPosition = lookAtPosition;
|
||||
}
|
||||
}
|
||||
_requestLookAtPosition = lookAtPosition;
|
||||
}
|
||||
|
||||
void Head::updateEyeLookAt() {
|
||||
_lookAtPosition = _requestLookAtPosition;
|
||||
_isEyeLookAtUpdated = true;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,9 @@ public:
|
|||
|
||||
float getTimeWithoutTalking() const { return _timeWithoutTalking; }
|
||||
|
||||
virtual void setLookAtPosition(const glm::vec3& lookAtPosition) override;
|
||||
void updateEyeLookAt();
|
||||
|
||||
protected:
|
||||
// disallow copies of the Head, copy of owning Avatar is disallowed too
|
||||
Head(const Head&);
|
||||
|
@ -123,6 +126,10 @@ protected:
|
|||
int _leftEyeLookAtID;
|
||||
int _rightEyeLookAtID;
|
||||
|
||||
glm::vec3 _requestLookAtPosition;
|
||||
bool _forceBlinkToRetarget { false };
|
||||
bool _isEyeLookAtUpdated { false };
|
||||
|
||||
// private methods
|
||||
void calculateMouthShapes(float timeRatio);
|
||||
void applyEyelidOffset(glm::quat headOrientation);
|
||||
|
|
|
@ -3214,3 +3214,12 @@ void AvatarData::clearAvatarGrabData(const QUuid& grabID) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 AvatarData::getHeadJointFrontVector() const {
|
||||
int headJointIndex = getJointIndex("Head");
|
||||
glm::quat headJointRotation = Quaternions::Y_180 * getAbsoluteJointRotationInObjectFrame(headJointIndex);// getAbsoluteJointRotationInRigFrame(headJointIndex, headJointRotation);
|
||||
headJointRotation = getWorldOrientation() * headJointRotation;
|
||||
float headYaw = safeEulerAngles(headJointRotation).y;
|
||||
glm::quat headYawRotation = glm::angleAxis(headYaw, Vectors::UP);
|
||||
return headYawRotation * IDENTITY_FORWARD;
|
||||
}
|
||||
|
|
|
@ -1484,6 +1484,7 @@ public:
|
|||
std::vector<AvatarSkeletonTrait::UnpackedJointData> getSkeletonData() const;
|
||||
void sendSkeletonData() const;
|
||||
QVector<JointData> getJointData() const;
|
||||
glm::vec3 getHeadJointFrontVector() const;
|
||||
|
||||
signals:
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
void setBlendshapeCoefficients(const QVector<float>& blendshapeCoefficients) { _blendshapeCoefficients = blendshapeCoefficients; }
|
||||
|
||||
const glm::vec3& getLookAtPosition() const { return _lookAtPosition; }
|
||||
void setLookAtPosition(const glm::vec3& lookAtPosition) {
|
||||
virtual void setLookAtPosition(const glm::vec3& lookAtPosition) {
|
||||
if (_lookAtPosition != lookAtPosition) {
|
||||
_lookAtPositionChanged = usecTimestampNow();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QPluginLoader>
|
||||
#include <shared/QtHelpers.h>
|
||||
|
||||
//#define HIFI_PLUGINMANAGER_DEBUG
|
||||
#if defined(HIFI_PLUGINMANAGER_DEBUG)
|
||||
|
@ -21,6 +22,7 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include "RuntimePlugin.h"
|
||||
#include "CodecPlugin.h"
|
||||
|
@ -221,7 +223,17 @@ const OculusPlatformPluginPointer PluginManager::getOculusPlatformPlugin() {
|
|||
return oculusPlatformPlugin;
|
||||
}
|
||||
|
||||
const DisplayPluginList& PluginManager::getDisplayPlugins() {
|
||||
DisplayPluginList PluginManager::getAllDisplayPlugins() {
|
||||
if (thread() != QThread::currentThread()) {
|
||||
DisplayPluginList list;
|
||||
QMetaObject::invokeMethod(this, "getAllDisplayPlugins", Qt::BlockingQueuedConnection, Q_RETURN_ARG(DisplayPluginList, list));
|
||||
return list;
|
||||
} else {
|
||||
return _displayPlugins;
|
||||
}
|
||||
}
|
||||
|
||||
const DisplayPluginList& PluginManager::getDisplayPlugins() {
|
||||
static std::once_flag once;
|
||||
static auto deviceAddedCallback = [](QString deviceName) {
|
||||
qCDebug(plugins) << "Added device: " << deviceName;
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
|
||||
using PluginFilter = std::function<bool(const QJsonObject&)>;
|
||||
void setPluginFilter(PluginFilter pluginFilter) { _pluginFilter = pluginFilter; }
|
||||
Q_INVOKABLE DisplayPluginList getAllDisplayPlugins();
|
||||
|
||||
signals:
|
||||
void inputDeviceRunningChanged(const QString& pluginName, bool isRunning, const QStringList& runningDevices);
|
||||
|
|
|
@ -377,7 +377,7 @@ function displayInitialLaunchWindow() {
|
|||
|
||||
initialLaunchWindow.fromQml.connect(onMessageFromInitialLaunchWindow);
|
||||
|
||||
Window.location = "file:///~/serverless/tutorial.json";
|
||||
Window.location = "file:///~/serverless/empty.json";
|
||||
}
|
||||
|
||||
var SECOND_LAUNCH_QML_PATH = Script.resolvePath("simplifiedFTUE/SecondLaunchWindow.qml");
|
||||
|
@ -405,7 +405,7 @@ function displaySecondLaunchWindow() {
|
|||
|
||||
secondLaunchWindow.fromQml.connect(onMessageFromSecondLaunchWindow);
|
||||
|
||||
Window.location = "file:///~/serverless/tutorial.json";
|
||||
Window.location = "file:///~/serverless/empty.json";
|
||||
}
|
||||
|
||||
function closeInitialLaunchWindow() {
|
||||
|
|
|
@ -61,17 +61,21 @@ Item {
|
|||
Rectangle {
|
||||
width: 5
|
||||
height: 5
|
||||
color: "red"
|
||||
ColorAnimation on color { loops: Animation.Infinite; from: "red"; to: "yellow"; duration: 1000 }
|
||||
color: "blue"
|
||||
ColorAnimation on color { loops: Animation.Infinite; from: "blue"; to: "yellow"; duration: 1000 }
|
||||
}
|
||||
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
url: "https://google.com/"
|
||||
x: 6; y: 6;
|
||||
width: parent.width * 0.8
|
||||
height: parent.height * 0.8
|
||||
url: "https://www.webrtc-experiment.com/Pluginfree-Screen-Sharing/#19583796789766627"
|
||||
// url: "https://vimeo.com/108650530"
|
||||
// url: "https://www.youtube.com/watch?v=7EWQOeQf32U&autoplay=1&loop=1"
|
||||
// x: 6; y: 6;
|
||||
anchors.fill: parent
|
||||
// width: parent.width * 0.8
|
||||
// height: parent.height * 0.8
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ void MacQml::init() {
|
|||
_surface->load(url, callback);
|
||||
_surface->resize(_window->size());
|
||||
_surface->resume();
|
||||
|
||||
_window->installEventFilter(_surface.get());
|
||||
}
|
||||
|
||||
void MacQml::draw() {
|
||||
|
|
|
@ -9,7 +9,7 @@ public:
|
|||
QmlPtr _surface;
|
||||
GLuint _fbo{ 0 };
|
||||
|
||||
MacQml(const QWindow* window) : Parent(window) {}
|
||||
MacQml(QWindow* window) : Parent(window) {}
|
||||
void update() override;
|
||||
void init() override;
|
||||
void draw() override;
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
std::array<std::array<QmlInfo, DIVISIONS_Y>, DIVISIONS_X> _surfaces;
|
||||
GLuint _fbo{ 0 };
|
||||
|
||||
StressWeb(const QWindow* window) : Parent(window) {}
|
||||
StressWeb(QWindow* window) : Parent(window) {}
|
||||
static QString getSourceUrl(bool video);
|
||||
void buildSurface(QmlInfo& qmlInfo, bool video);
|
||||
void destroySurface(QmlInfo& qmlInfo);
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
class TestCase {
|
||||
public:
|
||||
using QmlPtr = QSharedPointer<hifi::qml::OffscreenSurface>;
|
||||
using Builder = std::function<TestCase*(const QWindow*)>;
|
||||
TestCase(const QWindow* window) : _window(window) {}
|
||||
using Builder = std::function<TestCase*(QWindow*)>;
|
||||
TestCase(QWindow* window) : _window(window) {}
|
||||
virtual void init();
|
||||
virtual void destroy();
|
||||
virtual void update();
|
||||
|
@ -18,6 +18,6 @@ public:
|
|||
|
||||
protected:
|
||||
QOpenGLFunctions_4_1_Core _glf;
|
||||
const QWindow* _window;
|
||||
QWindow* _window;
|
||||
std::function<void(uint32_t, void*)> _discardLamdba;
|
||||
};
|
||||
|
|
|
@ -205,12 +205,22 @@ void TestWindow::resizeEvent(QResizeEvent* ev) {
|
|||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#ifdef Q_OS_MAC
|
||||
auto format = getDefaultOpenGLSurfaceFormat();
|
||||
format.setVersion(4, 1);
|
||||
// Deal with some weirdness in the chromium context sharing on Mac.
|
||||
// The primary share context needs to be 3.2, so that the Chromium will
|
||||
// succeed in it's creation of it's command stub contexts.
|
||||
format.setVersion(3, 2);
|
||||
// This appears to resolve the issues with corrupted fonts on OSX. No
|
||||
// idea why.
|
||||
qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "true");
|
||||
// https://i.kym-cdn.com/entries/icons/original/000/008/342/ihave.jpg
|
||||
QSurfaceFormat::setDefaultFormat(format);
|
||||
#endif
|
||||
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
TestCase::Builder builder = [](const QWindow* window)->TestCase*{ return new MacQml(window); };
|
||||
TestCase::Builder builder = [](QWindow* window)->TestCase*{ return new MacQml(window); };
|
||||
TestWindow window(builder);
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# General
|
||||
This document describes the process to build Qt 5.12.3.
|
||||
Note that there are three patches. The first (to qfloat16.h) is needed to compile QT 5.12.3 on Visual Studio 2017 due to a bug in Visual Studio (*bitset* will not compile. Note that there is a change in CMakeLists.txt to support this.
|
||||
The second patch is to OpenSL ES audio.
|
||||
The third is a patch to QScriptEngine to prevent crashes in QScriptEnginePrivate::reportAdditionalMemoryCost, during garbage collection. See https://bugreports.qt.io/browse/QTBUG-76176
|
||||
Note that there are several patches.
|
||||
* The first (to qfloat16.h) is needed to compile QT 5.12.3 on Visual Studio 2017 due to a bug in Visual Studio (*bitset* will not compile. Note that there is a change in CMakeLists.txt to support this.
|
||||
* The second patch is to OpenSL ES audio and allow audio echo cancelllation on Android.
|
||||
* The third is a patch to QScriptEngine to prevent crashes in QScriptEnginePrivate::reportAdditionalMemoryCost, during garbage collection. See https://bugreports.qt.io/browse/QTBUG-76176
|
||||
* The fourth is a patch which fixes video playback on WebEngineViews on mac. See https://bugreports.qt.io/browse/QTBUG-70967
|
||||
## Requirements
|
||||
### Windows
|
||||
1. Visual Studio 2017
|
||||
|
@ -222,6 +224,7 @@ git clone --recursive git://code.qt.io/qt/qt5.git -b 5.12.3 --single-branch
|
|||
`cd qt5`
|
||||
`git apply --ignore-space-change --ignore-whitespace patches/aec.patch`
|
||||
`git apply --ignore-space-change --ignore-whitespace patches/qtscript-crash-fix.patch`
|
||||
`git apply --ignore-space-change --ignore-whitespace patches/mac-web-video.patch`
|
||||
`cd ..`
|
||||
#### Configuring
|
||||
`mkdir qt5-install`
|
||||
|
|
247
tools/qt-builder/patches/mac-web-video.patch
Normal file
247
tools/qt-builder/patches/mac-web-video.patch
Normal file
|
@ -0,0 +1,247 @@
|
|||
Submodule qtwebengine contains modified content
|
||||
diff --git a/qtwebengine/src/core/stream_video_node.cpp b/qtwebengine/src/core/stream_video_node.cpp
|
||||
index 29922f86..baa39d3b 100644
|
||||
--- a/qtwebengine/src/core/stream_video_node.cpp
|
||||
+++ b/qtwebengine/src/core/stream_video_node.cpp
|
||||
@@ -62,38 +62,45 @@ protected:
|
||||
const char *vertexShader() const override {
|
||||
// Keep in sync with cc::VertexShaderVideoTransform
|
||||
static const char *shader =
|
||||
- "attribute highp vec4 a_position;\n"
|
||||
- "attribute mediump vec2 a_texCoord;\n"
|
||||
- "uniform highp mat4 matrix;\n"
|
||||
- "uniform highp mat4 texMatrix;\n"
|
||||
- "varying mediump vec2 v_texCoord;\n"
|
||||
- "void main() {\n"
|
||||
- " gl_Position = matrix * a_position;\n"
|
||||
- " v_texCoord = vec4(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0)).xy;\n"
|
||||
- "}";
|
||||
+ R"SHADER(#version 150 core
|
||||
+in vec4 a_position;
|
||||
+in vec2 a_texCoord;
|
||||
+uniform mat4 matrix;
|
||||
+uniform mat4 texMatrix;
|
||||
+out vec2 v_texCoord;
|
||||
+void main() {
|
||||
+ gl_Position = matrix * a_position;
|
||||
+ v_texCoord = vec4(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0)).xy;
|
||||
+}
|
||||
+ )SHADER";
|
||||
return shader;
|
||||
}
|
||||
|
||||
const char *fragmentShader() const override {
|
||||
// Keep in sync with cc::FragmentShaderRGBATexAlpha
|
||||
static const char *shaderExternal =
|
||||
- "#extension GL_OES_EGL_image_external : require\n"
|
||||
- "varying mediump vec2 v_texCoord;\n"
|
||||
- "uniform samplerExternalOES s_texture;\n"
|
||||
- "uniform lowp float alpha;\n"
|
||||
- "void main() {\n"
|
||||
- " lowp vec4 texColor = texture2D(s_texture, v_texCoord);\n"
|
||||
- " gl_FragColor = texColor * alpha;\n"
|
||||
- "}";
|
||||
+ R"SHADER(#version 150 core
|
||||
+#extension GL_OES_EGL_image_external : require
|
||||
+in vec2 v_texCoord;
|
||||
+uniform samplerExternalOES s_texture;
|
||||
+uniform float alpha;
|
||||
+out vec4 fragColor;
|
||||
+void main() {
|
||||
+ vec4 texColor = texture(s_texture, v_texCoord);
|
||||
+ fragColor = texColor * alpha;
|
||||
+}
|
||||
+ )SHADER";
|
||||
static const char *shader2DRect =
|
||||
- "#extension GL_ARB_texture_rectangle : require\n"
|
||||
- "varying mediump vec2 v_texCoord;\n"
|
||||
- "uniform sampler2DRect s_texture;\n"
|
||||
- "uniform lowp float alpha;\n"
|
||||
- "void main() {\n"
|
||||
- " lowp vec4 texColor = texture2DRect(s_texture, v_texCoord);\n"
|
||||
- " gl_FragColor = texColor * alpha;\n"
|
||||
- "}";
|
||||
+ R"SHADER(#version 150 core
|
||||
+in vec2 v_texCoord;
|
||||
+uniform sampler2D s_texture;
|
||||
+uniform float alpha;
|
||||
+out vec4 fragColor;
|
||||
+void main() {
|
||||
+ vec4 texColor = texture(s_texture, v_texCoord);
|
||||
+ fragColor = texColor * alpha;
|
||||
+}
|
||||
+ )SHADER";
|
||||
if (m_target == ExternalTarget)
|
||||
return shaderExternal;
|
||||
else
|
||||
diff --git a/qtwebengine/src/core/yuv_video_node.cpp b/qtwebengine/src/core/yuv_video_node.cpp
|
||||
index 4a436d95..dc4b6ff9 100644
|
||||
--- a/qtwebengine/src/core/yuv_video_node.cpp
|
||||
+++ b/qtwebengine/src/core/yuv_video_node.cpp
|
||||
@@ -59,39 +59,41 @@ public:
|
||||
YUVVideoMaterialShader(const gfx::ColorSpace &colorSpace)
|
||||
{
|
||||
static const char *shaderHead =
|
||||
- "varying mediump vec2 v_yaTexCoord;\n"
|
||||
- "varying mediump vec2 v_uvTexCoord;\n"
|
||||
- "uniform sampler2D y_texture;\n"
|
||||
- "uniform sampler2D u_texture;\n"
|
||||
- "uniform sampler2D v_texture;\n"
|
||||
- "uniform mediump float alpha;\n"
|
||||
- "uniform mediump vec4 ya_clamp_rect;\n"
|
||||
- "uniform mediump vec4 uv_clamp_rect;\n";
|
||||
- static const char *shader =
|
||||
- "void main() {\n"
|
||||
- " mediump vec2 ya_clamped =\n"
|
||||
- " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n"
|
||||
- " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n"
|
||||
- " mediump vec2 uv_clamped =\n"
|
||||
- " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n"
|
||||
- " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n"
|
||||
- " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n"
|
||||
- " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned);\n"
|
||||
- " mediump vec3 rgb = DoColorConversion(yuv);\n"
|
||||
- " gl_FragColor = vec4(rgb, 1.0) * alpha;\n"
|
||||
- "}";
|
||||
+ R"SHADER(#version 150 core
|
||||
+in vec2 v_yaTexCoord;
|
||||
+in vec2 v_uvTexCoord;
|
||||
+uniform sampler2D y_texture;
|
||||
+uniform sampler2D u_texture;
|
||||
+uniform sampler2D v_texture;
|
||||
+uniform float alpha;
|
||||
+uniform vec4 ya_clamp_rect;
|
||||
+uniform vec4 uv_clamp_rect;
|
||||
+out vec4 fragColor;
|
||||
+ )SHADER";
|
||||
+
|
||||
+ static const char *shader = R"SHADER(
|
||||
+void main() {
|
||||
+ vec2 ya_clamped =
|
||||
+ max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));
|
||||
+ float y_raw = texture(y_texture, ya_clamped).x;
|
||||
+ vec2 uv_clamped =
|
||||
+ max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));
|
||||
+ float u_unsigned = texture(u_texture, uv_clamped).x;
|
||||
+ float v_unsigned = texture(v_texture, uv_clamped).x;
|
||||
+ vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned);
|
||||
+ vec3 rgb = DoColorConversion(yuv);
|
||||
+ fragColor = vec4(rgb, 1.0) * alpha;
|
||||
+}
|
||||
+ )SHADER";
|
||||
+
|
||||
// Invalid or unspecified color spaces should be treated as REC709.
|
||||
gfx::ColorSpace src = colorSpace.IsValid() ? colorSpace : gfx::ColorSpace::CreateREC709();
|
||||
gfx::ColorSpace dst = gfx::ColorSpace::CreateSRGB();
|
||||
std::unique_ptr<gfx::ColorTransform> transform =
|
||||
gfx::ColorTransform::NewColorTransform(src, dst, gfx::ColorTransform::Intent::INTENT_PERCEPTUAL);
|
||||
|
||||
- QByteArray header(shaderHead);
|
||||
- if (QOpenGLContext::currentContext()->isOpenGLES())
|
||||
- header = QByteArray("precision mediump float;\n") + header;
|
||||
-
|
||||
m_csShader = QByteArray::fromStdString(transform->GetShaderSource());
|
||||
- m_fragmentShader = header + m_csShader + QByteArray(shader);
|
||||
+ m_fragmentShader = QByteArray(shaderHead) + m_csShader + QByteArray(shader);
|
||||
}
|
||||
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
|
||||
|
||||
@@ -108,20 +110,22 @@ protected:
|
||||
const char *vertexShader() const override {
|
||||
// Keep in sync with logic in VertexShader in components/viz/service/display/shader.cc
|
||||
const char *shader =
|
||||
- "attribute highp vec4 a_position;\n"
|
||||
- "attribute mediump vec2 a_texCoord;\n"
|
||||
- "uniform highp mat4 matrix;\n"
|
||||
- "varying mediump vec2 v_yaTexCoord;\n"
|
||||
- "varying mediump vec2 v_uvTexCoord;\n"
|
||||
- "uniform mediump vec2 yaTexScale;\n"
|
||||
- "uniform mediump vec2 yaTexOffset;\n"
|
||||
- "uniform mediump vec2 uvTexScale;\n"
|
||||
- "uniform mediump vec2 uvTexOffset;\n"
|
||||
- "void main() {\n"
|
||||
- " gl_Position = matrix * a_position;\n"
|
||||
- " v_yaTexCoord = a_texCoord * yaTexScale + yaTexOffset;\n"
|
||||
- " v_uvTexCoord = a_texCoord * uvTexScale + uvTexOffset;\n"
|
||||
- "}";
|
||||
+ R"SHADER(#version 150 core
|
||||
+in vec4 a_position;
|
||||
+in vec2 a_texCoord;
|
||||
+uniform mat4 matrix;
|
||||
+out vec2 v_yaTexCoord;
|
||||
+out vec2 v_uvTexCoord;
|
||||
+uniform vec2 yaTexScale;
|
||||
+uniform vec2 yaTexOffset;
|
||||
+uniform vec2 uvTexScale;
|
||||
+uniform vec2 uvTexOffset;
|
||||
+void main() {
|
||||
+ gl_Position = matrix * a_position;
|
||||
+ v_yaTexCoord = a_texCoord * yaTexScale + yaTexOffset;
|
||||
+ v_uvTexCoord = a_texCoord * uvTexScale + uvTexOffset;
|
||||
+}
|
||||
+ )SHADER";
|
||||
return shader;
|
||||
}
|
||||
|
||||
@@ -168,33 +172,35 @@ public:
|
||||
YUVAVideoMaterialShader(const gfx::ColorSpace &colorSpace) : YUVVideoMaterialShader(colorSpace)
|
||||
{
|
||||
static const char *shaderHead =
|
||||
- "varying mediump vec2 v_yaTexCoord;\n"
|
||||
- "varying mediump vec2 v_uvTexCoord;\n"
|
||||
- "uniform sampler2D y_texture;\n"
|
||||
- "uniform sampler2D u_texture;\n"
|
||||
- "uniform sampler2D v_texture;\n"
|
||||
- "uniform sampler2D a_texture;\n"
|
||||
- "uniform mediump float alpha;\n"
|
||||
- "uniform mediump vec4 ya_clamp_rect;\n"
|
||||
- "uniform mediump vec4 uv_clamp_rect;\n";
|
||||
+ R"SHADER(#version 150 core
|
||||
+in vec2 v_yaTexCoord;
|
||||
+in vec2 v_uvTexCoord;
|
||||
+uniform sampler2D y_texture;
|
||||
+uniform sampler2D u_texture;
|
||||
+uniform sampler2D v_texture;
|
||||
+uniform sampler2D a_texture;
|
||||
+uniform float alpha;
|
||||
+uniform vec4 ya_clamp_rect;
|
||||
+uniform vec4 uv_clamp_rect;
|
||||
+out vec4 fragColor;
|
||||
+ )SHADER";
|
||||
static const char *shader =
|
||||
- "void main() {\n"
|
||||
- " mediump vec2 ya_clamped =\n"
|
||||
- " max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));\n"
|
||||
- " mediump float y_raw = texture2D(y_texture, ya_clamped).x;\n"
|
||||
- " mediump vec2 uv_clamped =\n"
|
||||
- " max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));\n"
|
||||
- " mediump float u_unsigned = texture2D(u_texture, uv_clamped).x;\n"
|
||||
- " mediump float v_unsigned = texture2D(v_texture, uv_clamped).x;\n"
|
||||
- " mediump float a_raw = texture2D(a_texture, ya_clamped).x;\n"
|
||||
- " mediump vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned);\n"
|
||||
- " mediump vec3 rgb = DoColorConversion(yuv);\n"
|
||||
- " gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);\n"
|
||||
- "}";
|
||||
- QByteArray header(shaderHead);
|
||||
- if (QOpenGLContext::currentContext()->isOpenGLES())
|
||||
- header = QByteArray("precision mediump float;\n") + header;
|
||||
- m_fragmentShader = header + m_csShader + QByteArray(shader);
|
||||
+ R"SHADER(
|
||||
+void main() {
|
||||
+ vec2 ya_clamped =
|
||||
+ max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));
|
||||
+ float y_raw = texture(y_texture, ya_clamped).x;
|
||||
+ vec2 uv_clamped =
|
||||
+ max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));
|
||||
+ float u_unsigned = texture(u_texture, uv_clamped).x;
|
||||
+ float v_unsigned = texture(v_texture, uv_clamped).x;
|
||||
+ float a_raw = texture(a_texture, ya_clamped).x;
|
||||
+ vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned);
|
||||
+ vec3 rgb = DoColorConversion(yuv);
|
||||
+ fragColor = vec4(rgb, 1.0) * (alpha * a_raw);
|
||||
+}
|
||||
+ )SHADER";
|
||||
+ m_fragmentShader = QByteArray(shaderHead) + m_csShader + QByteArray(shader);
|
||||
}
|
||||
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
|
||||
|
Loading…
Reference in a new issue