Merge pull request #8655 from highfidelity/RC-21

Beta Release 21 - Includes up to Developer Release 5396
This commit is contained in:
Chris Collins 2016-09-30 08:27:40 -07:00 committed by GitHub
commit 7095dee412
340 changed files with 11632 additions and 4568 deletions

View file

@ -1,7 +1,7 @@
###Dependencies
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 3.3.2
* [Qt](http://www.qt.io/download-open-source) ~> 5.5.1
* [Qt](http://www.qt.io/download-open-source) ~> 5.6.1
* [OpenSSL](https://www.openssl.org/community/binaries.html) ~> 1.0.1m
* IMPORTANT: Using the recommended version of OpenSSL is critical to avoid security vulnerabilities.
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
@ -41,14 +41,14 @@ If you would like to use a specific install of a dependency instead of the versi
Hifi uses CMake to generate build files and project files for your platform.
####Qt
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
For example, a Qt5 5.5.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/clang_64/lib/cmake/
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5.1/lib/cmake
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.1/clang_64/lib/cmake/
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.6.1-1/lib/cmake
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
####Generating build files
@ -65,7 +65,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.5.1/lib/cmake
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.1/lib/cmake
####Finding Dependencies

View file

@ -4,13 +4,11 @@ Please read the [general build guide](BUILD.md) for information on dependencies
You will need the following tools to build our Android targets.
* [cmake](http://www.cmake.org/download/) ~> 3.1.0
* Note that this is a newer version required than the minimum for hifi desktop targets.
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.4.0
* Note that this is a newer version required than the minimum for hifi desktop targets.
* [cmake](http://www.cmake.org/download/) ~> 3.5.1
* [Qt](http://www.qt.io/download-open-source/#) ~> 5.5.1
* [ant](http://ant.apache.org/bindownload.cgi) ~> 1.9.4
* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) = r10c
* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.0.2
* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) ~> r10d
* [Android SDK](http://developer.android.com/sdk/installing/index.html) ~> 24.4.1.1
* Install the latest Platform-tools
* Install the latest Build-tools
* Install the SDK Platform for API Level 19
@ -19,6 +17,12 @@ You will need the following tools to build our Android targets.
You will also need to cross-compile the dependencies required for all platforms for Android, and help CMake find these compiled libraries on your machine.
####Scribe
High Fidelity has a shader pre-processing tool called `scribe` that various libraries will call on during the build process. You must compile scribe using your native toolchain (following the build instructions for your platform) and then pass a CMake variable or set an ENV variable `SCRIBE_PATH` that is a path to the scribe executable.
CMake will fatally error if it does not find the scribe executable while using the android toolchain.
####Optional Components
* [Oculus Mobile SDK](https://developer.oculus.com/downloads/#sdk=mobile) ~> 0.4.2
@ -31,11 +35,11 @@ This is most easily accomplished by installing all Android dependencies in the s
####Qt
Install Qt 5.4 for Android for your host environment from the [Qt downloads page](http://www.qt.io/download/). Install Qt to ``$ANDROID_LIB_DIR/Qt``. This is required so that our root CMakeLists file can help CMake find your Android Qt installation.
Install Qt 5.5.1 for Android for your host environment from the [Qt downloads page](http://www.qt.io/download/). Install Qt to ``$ANDROID_LIB_DIR/Qt``. This is required so that our root CMakeLists file can help CMake find your Android Qt installation.
The component required for the Android build is the `Android armv7` component.
If you would like to install Qt to a different location, or attempt to build with a different Qt version, you can pass `ANDROID_QT_CMAKE_PREFIX_PATH` to CMake. Point to the `cmake` folder inside `$VERSION_NUMBER/android_armv7/lib`. Otherwise, our root CMakeLists will set it to `$ANDROID_LIB_DIR/Qt/5.3/android_armv7/lib/cmake`.
If you would like to install Qt to a different location, or attempt to build with a different Qt version, you can pass `ANDROID_QT_CMAKE_PREFIX_PATH` to CMake. Point to the `cmake` folder inside `$VERSION_NUMBER/android_armv7/lib`. Otherwise, our root CMakeLists will set it to `$ANDROID_LIB_DIR/Qt/5.5/android_armv7/lib/cmake`.
####OpenSSL

View file

@ -1,25 +1,31 @@
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
###Homebrew
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all High Fidelity dependencies very simple.
[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
brew tap homebrew/versions
brew install cmake openssl qt55
brew install cmake openssl
We no longer require install of qt5 via our [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas). Versions of Qt that are 5.5.x provide a mechanism to disable the wireless scanning we previously had a custom patch for.
###OpenSSL
###OpenSSL and Qt
Assuming you've installed OpenSSL or Qt 5 using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR and QT_CMAKE_PREFIX_PATH so CMake can find your installations.
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2h_1/
For Qt 5.5.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt55/5.5.1/lib/cmake
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
Note that these use the versions from homebrew formulae at the time of this writing, and the version in the path will likely change.
###Qt
You can use the online installer or the offline installer.
* [Download the online installer](http://www.qt.io/download-open-source/#section-2)
* When it asks you to select components, select the following:
* Qt > Qt 5.6
* [Download the offline installer](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-mac-x64-clang-5.6.1-1.dmg)
Once Qt is installed, you need to manually configure the following:
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.1/5.6/clang_64/lib/cmake/` directory.
###Xcode
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.

View file

@ -27,17 +27,17 @@ We expect nmake.exe to be located at the following path.
###Qt
You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version.
* [Download the online installer](http://qt-project.org/downloads)
* [Download the online installer](http://www.qt.io/download-open-source/#section-2)
* When it asks you to select components, ONLY select one of the following, 32- or 64-bit to match your build preference:
* Qt > Qt 5.5.1 > **msvc2013 32-bit**
* Qt > Qt 5.5.1 > **msvc2013 64-bit**
* Qt > Qt 5.6.1 > **msvc2013 32-bit**
* Qt > Qt 5.6.1 > **msvc2013 64-bit**
* Download the offline installer, 32- or 64-bit to match your build preference:
* [32-bit](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013-5.5.1.exe)
* [64-bit](http://download.qt.io/official_releases/qt/5.5/5.5.1/qt-opensource-windows-x86-msvc2013_64-5.5.1.exe)
* [32-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013-5.6.1-1.exe)
* [64-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe)
Once Qt is installed, you need to manually configure the following:
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.5.1\msvc2013\lib\cmake` or `Qt\5.5.1\msvc2013_64\lib\cmake` directory.
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.6.1\msvc2013\lib\cmake` or `Qt\5.6.1\msvc2013_64\lib\cmake` directory.
* You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
###External Libraries

View file

@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.2)
if (USE_ANDROID_TOOLCHAIN)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake")
set(ANDROID_NATIVE_API_LEVEL 19)
set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi-clang3.5)
set(ANDROID_STL c++_shared)
endif ()
if (WIN32)
@ -64,7 +66,7 @@ if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /OPT:REF /OPT:ICF")
else ()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-strict-aliasing -Wno-unused-parameter")
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -Woverloaded-virtual -Wdouble-promotion")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "5.1") # gcc 5.1 and on have suggest-override
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
@ -72,18 +74,30 @@ else ()
endif ()
endif(WIN32)
if ((NOT MSVC12) AND (NOT MSVC14))
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if (COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.3")
# GLM 0.9.8 on Ubuntu 14 (gcc 4.4) has issues with the simd declarations
add_definitions(-DGLM_FORCE_PURE)
endif()
endif()
if (NOT ANDROID)
if ((NOT MSVC12) AND (NOT MSVC14))
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if (COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
endif ()
else ()
# assume that the toolchain selected for android has C++11 support
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif ()
if (APPLE)
@ -98,7 +112,7 @@ endif ()
if (ANDROID)
if (NOT ANDROID_QT_CMAKE_PREFIX_PATH)
set(QT_CMAKE_PREFIX_PATH ${ANDROID_LIB_DIR}/Qt/5.4/android_armv7/lib/cmake)
set(QT_CMAKE_PREFIX_PATH ${ANDROID_LIB_DIR}/Qt/5.5/android_armv7/lib/cmake)
else ()
set(QT_CMAKE_PREFIX_PATH ${ANDROID_QT_CMAKE_PREFIX_PATH})
endif ()
@ -236,7 +250,9 @@ if (NOT ANDROID)
endif()
if (ANDROID OR DESKTOP_GVR)
add_subdirectory(interface)
add_subdirectory(gvr-interface)
add_subdirectory(plugins)
endif ()
if (DEFINED ENV{HIFI_MEMORY_DEBUGGING})

View file

@ -2,6 +2,11 @@ set(TARGET_NAME assignment-client)
setup_hifi_project(Core Gui Network Script Quick Widgets WebSockets)
# Fix up the rpath so macdeployqt works
if (APPLE)
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
endif ()
# link in the shared libraries
link_hifi_libraries(
audio avatars octree gpu model fbx entities

View file

@ -48,11 +48,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
Agent::Agent(ReceivedMessage& message) :
ThreadedAssignment(message),
_entityEditSender(),
_receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,
InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false,
DEFAULT_WINDOW_STARVE_THRESHOLD, DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES,
DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false))
{
_receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO,
RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) {
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
ResourceManager::init();

View file

@ -61,15 +61,14 @@
#include "AudioMixer.h"
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.5f; // attenuation = -6dB * log2(distance)
const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
const QString AUDIO_ENV_GROUP_KEY = "audio_env";
const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer";
InboundAudioStream::Settings AudioMixer::_streamSettings;
static const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
static const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.5f; // attenuation = -6dB * log2(distance)
static const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
static const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
static const QString AUDIO_ENV_GROUP_KEY = "audio_env";
static const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer";
int AudioMixer::_numStaticJitterFrames{ -1 };
bool AudioMixer::_enableFilter = true;
bool AudioMixer::shouldMute(float quietestFrame) {
@ -269,20 +268,18 @@ void AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData&
if (!streamToAdd.lastPopSucceeded()) {
bool forceSilentBlock = true;
if (_streamSettings._repetitionWithFade && !streamToAdd.getLastPopOutput().isNull()) {
if (!streamToAdd.getLastPopOutput().isNull()) {
bool isInjector = dynamic_cast<const InjectedAudioStream*>(&streamToAdd);
// reptition with fade is enabled, and we do have a valid previous frame to repeat
// so we mix the previously-mixed block
// this is preferable to not mixing it at all to avoid the harsh jump to silence
// in an injector, just go silent - the injector has likely ended
// in other inputs (microphone, &c.), repeat with fade to avoid the harsh jump to silence
// we'll repeat the last block until it has a block to mix
// and we'll gradually fade that repeated block into silence.
// calculate its fade factor, which depends on how many times it's already been repeated.
repeatedFrameFadeFactor = calculateRepeatedFrameFadeFactor(streamToAdd.getConsecutiveNotMixedCount() - 1);
if (repeatedFrameFadeFactor > 0.0f) {
if (!isInjector && repeatedFrameFadeFactor > 0.0f) {
// apply the repeatedFrameFadeFactor to the gain
gain *= repeatedFrameFadeFactor;
@ -641,7 +638,7 @@ QString AudioMixer::percentageForMixStats(int counter) {
void AudioMixer::sendStatsPacket() {
static QJsonObject statsObject;
statsObject["useDynamicJitterBuffers"] = _streamSettings._dynamicJitterBuffers;
statsObject["useDynamicJitterBuffers"] = _numStaticJitterFrames == -1;
statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f;
statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio;
@ -902,63 +899,62 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) {
// check the payload to see if we have asked for dynamicJitterBuffer support
const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "dynamic_jitter_buffer";
_streamSettings._dynamicJitterBuffers = audioBufferGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool();
if (_streamSettings._dynamicJitterBuffers) {
qDebug() << "Enable dynamic jitter buffers.";
bool enableDynamicJitterBuffer = audioBufferGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool();
if (enableDynamicJitterBuffer) {
qDebug() << "Enabling dynamic jitter buffers.";
bool ok;
const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "static_desired_jitter_buffer_frames";
_numStaticJitterFrames = audioBufferGroupObject[DESIRED_JITTER_BUFFER_FRAMES_KEY].toString().toInt(&ok);
if (!ok) {
_numStaticJitterFrames = InboundAudioStream::DEFAULT_STATIC_JITTER_FRAMES;
}
qDebug() << "Static desired jitter buffer frames:" << _numStaticJitterFrames;
} else {
qDebug() << "Dynamic jitter buffers disabled.";
qDebug() << "Disabling dynamic jitter buffers.";
_numStaticJitterFrames = -1;
}
// check for deprecated audio settings
auto deprecationNotice = [](const QString& setting, const QString& value) {
qInfo().nospace() << "[DEPRECATION NOTICE] " << setting << "(" << value << ") has been deprecated, and has no effect";
};
bool ok;
const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "static_desired_jitter_buffer_frames";
_streamSettings._staticDesiredJitterBufferFrames = audioBufferGroupObject[DESIRED_JITTER_BUFFER_FRAMES_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._staticDesiredJitterBufferFrames = DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES;
}
qDebug() << "Static desired jitter buffer frames:" << _streamSettings._staticDesiredJitterBufferFrames;
const QString MAX_FRAMES_OVER_DESIRED_JSON_KEY = "max_frames_over_desired";
_streamSettings._maxFramesOverDesired = audioBufferGroupObject[MAX_FRAMES_OVER_DESIRED_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._maxFramesOverDesired = DEFAULT_MAX_FRAMES_OVER_DESIRED;
}
qDebug() << "Max frames over desired:" << _streamSettings._maxFramesOverDesired;
const QString USE_STDEV_FOR_DESIRED_CALC_JSON_KEY = "use_stdev_for_desired_calc";
_streamSettings._useStDevForJitterCalc = audioBufferGroupObject[USE_STDEV_FOR_DESIRED_CALC_JSON_KEY].toBool();
if (_streamSettings._useStDevForJitterCalc) {
qDebug() << "Using stdev method for jitter calc if dynamic jitter buffers enabled";
} else {
qDebug() << "Using max-gap method for jitter calc if dynamic jitter buffers enabled";
int maxFramesOverDesired = audioBufferGroupObject[MAX_FRAMES_OVER_DESIRED_JSON_KEY].toString().toInt(&ok);
if (ok && maxFramesOverDesired != InboundAudioStream::MAX_FRAMES_OVER_DESIRED) {
deprecationNotice(MAX_FRAMES_OVER_DESIRED_JSON_KEY, QString::number(maxFramesOverDesired));
}
const QString WINDOW_STARVE_THRESHOLD_JSON_KEY = "window_starve_threshold";
_streamSettings._windowStarveThreshold = audioBufferGroupObject[WINDOW_STARVE_THRESHOLD_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowStarveThreshold = DEFAULT_WINDOW_STARVE_THRESHOLD;
int windowStarveThreshold = audioBufferGroupObject[WINDOW_STARVE_THRESHOLD_JSON_KEY].toString().toInt(&ok);
if (ok && windowStarveThreshold != InboundAudioStream::WINDOW_STARVE_THRESHOLD) {
deprecationNotice(WINDOW_STARVE_THRESHOLD_JSON_KEY, QString::number(windowStarveThreshold));
}
qDebug() << "Window A starve threshold:" << _streamSettings._windowStarveThreshold;
const QString WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY = "window_seconds_for_desired_calc_on_too_many_starves";
_streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = audioBufferGroupObject[WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES;
int windowSecondsForDesiredCalcOnTooManyStarves = audioBufferGroupObject[WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY].toString().toInt(&ok);
if (ok && windowSecondsForDesiredCalcOnTooManyStarves != InboundAudioStream::WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES) {
deprecationNotice(WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY, QString::number(windowSecondsForDesiredCalcOnTooManyStarves));
}
qDebug() << "Window A length:" << _streamSettings._windowSecondsForDesiredCalcOnTooManyStarves << "seconds";
const QString WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY = "window_seconds_for_desired_reduction";
_streamSettings._windowSecondsForDesiredReduction = audioBufferGroupObject[WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY].toString().toInt(&ok);
if (!ok) {
_streamSettings._windowSecondsForDesiredReduction = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION;
int windowSecondsForDesiredReduction = audioBufferGroupObject[WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY].toString().toInt(&ok);
if (ok && windowSecondsForDesiredReduction != InboundAudioStream::WINDOW_SECONDS_FOR_DESIRED_REDUCTION) {
deprecationNotice(WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY, QString::number(windowSecondsForDesiredReduction));
}
const QString USE_STDEV_FOR_JITTER_JSON_KEY = "use_stdev_for_desired_calc";
bool useStDevForJitterCalc = audioBufferGroupObject[USE_STDEV_FOR_JITTER_JSON_KEY].toBool();
if (useStDevForJitterCalc != InboundAudioStream::USE_STDEV_FOR_JITTER) {
deprecationNotice(USE_STDEV_FOR_JITTER_JSON_KEY, useStDevForJitterCalc ? "true" : "false");
}
qDebug() << "Window B length:" << _streamSettings._windowSecondsForDesiredReduction << "seconds";
const QString REPETITION_WITH_FADE_JSON_KEY = "repetition_with_fade";
_streamSettings._repetitionWithFade = audioBufferGroupObject[REPETITION_WITH_FADE_JSON_KEY].toBool();
if (_streamSettings._repetitionWithFade) {
qDebug() << "Repetition with fade enabled";
} else {
qDebug() << "Repetition with fade disabled";
bool repetitionWithFade = audioBufferGroupObject[REPETITION_WITH_FADE_JSON_KEY].toBool();
if (repetitionWithFade != InboundAudioStream::REPETITION_WITH_FADE) {
deprecationNotice(REPETITION_WITH_FADE_JSON_KEY, repetitionWithFade ? "true" : "false");
}
}

View file

@ -39,7 +39,7 @@ public slots:
void sendStatsPacket() override;
static const InboundAudioStream::Settings& getStreamSettings() { return _streamSettings; }
static int getStaticJitterFrames() { return _numStaticJitterFrames; }
private slots:
void broadcastMixes();
@ -112,7 +112,7 @@ private:
};
QVector<ReverbSettings> _zoneReverbSettings;
static InboundAudioStream::Settings _streamSettings;
static int _numStaticJitterFrames; // -1 denotes dynamic jitter buffering
static bool _enableFilter;
};

View file

@ -109,7 +109,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) {
bool isStereo = channelFlag == 1;
auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStreamSettings());
auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStaticJitterFrames());
avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO);
qDebug() << "creating new AvatarAudioStream... codec:" << _selectedCodecName;
@ -143,7 +143,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) {
if (streamIt == _audioStreams.end()) {
// we don't have this injected stream yet, so add it
auto injectorStream = new InjectedAudioStream(streamIdentifier, isStereo, AudioMixer::getStreamSettings());
auto injectorStream = new InjectedAudioStream(streamIdentifier, isStereo, AudioMixer::getStaticJitterFrames());
#if INJECTORS_SUPPORT_CODECS
injectorStream->setupCodec(_codec, _selectedCodecName, isStereo ? AudioConstants::STEREO : AudioConstants::MONO);
@ -270,6 +270,7 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() {
downstreamStats["desired"] = streamStats._desiredJitterBufferFrames;
downstreamStats["available_avg_10s"] = streamStats._framesAvailableAverage;
downstreamStats["available"] = (double) streamStats._framesAvailable;
downstreamStats["unplayed"] = (double) streamStats._unplayedMs;
downstreamStats["starves"] = (double) streamStats._starveCount;
downstreamStats["not_mixed"] = (double) streamStats._consecutiveNotMixedCount;
downstreamStats["overflows"] = (double) streamStats._overflowCount;
@ -294,6 +295,7 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() {
upstreamStats["desired_calc"] = avatarAudioStream->getCalculatedJitterBufferFrames();
upstreamStats["available_avg_10s"] = streamStats._framesAvailableAverage;
upstreamStats["available"] = (double) streamStats._framesAvailable;
upstreamStats["unplayed"] = (double) streamStats._unplayedMs;
upstreamStats["starves"] = (double) streamStats._starveCount;
upstreamStats["not_mixed"] = (double) streamStats._consecutiveNotMixedCount;
upstreamStats["overflows"] = (double) streamStats._overflowCount;
@ -323,6 +325,7 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() {
upstreamStats["desired_calc"] = injectorPair.second->getCalculatedJitterBufferFrames();
upstreamStats["available_avg_10s"] = streamStats._framesAvailableAverage;
upstreamStats["available"] = (double) streamStats._framesAvailable;
upstreamStats["unplayed"] = (double) streamStats._unplayedMs;
upstreamStats["starves"] = (double) streamStats._starveCount;
upstreamStats["not_mixed"] = (double) streamStats._consecutiveNotMixedCount;
upstreamStats["overflows"] = (double) streamStats._overflowCount;

View file

@ -13,10 +13,8 @@
#include "AvatarAudioStream.h"
AvatarAudioStream::AvatarAudioStream(bool isStereo, const InboundAudioStream::Settings& settings) :
PositionalAudioStream(PositionalAudioStream::Microphone, isStereo, settings)
{
}
AvatarAudioStream::AvatarAudioStream(bool isStereo, int numStaticJitterFrames) :
PositionalAudioStream(PositionalAudioStream::Microphone, isStereo, numStaticJitterFrames) {}
int AvatarAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) {
int readBytes = 0;

View file

@ -18,7 +18,7 @@
class AvatarAudioStream : public PositionalAudioStream {
public:
AvatarAudioStream(bool isStereo, const InboundAudioStream::Settings& settings);
AvatarAudioStream(bool isStereo, int numStaticJitterFrames = -1);
private:
// disallow copying of AvatarAudioStream objects

View file

@ -413,6 +413,9 @@ void AvatarMixer::handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message
}
void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
auto nodeList = DependencyManager::get<NodeList>();
nodeList->getOrCreateLinkedData(senderNode);
if (senderNode->getLinkedData()) {
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
if (nodeData != nullptr) {

View file

@ -19,6 +19,7 @@
#include <AccountManager.h>
#include <HTTPConnection.h>
#include <LogHandler.h>
#include <shared/NetworkUtils.h>
#include <NetworkingConstants.h>
#include <NumericalConstants.h>
#include <UUID.h>

View file

@ -29,8 +29,8 @@
# POSSIBILITY OF SUCH DAMAGE.
# ------------------------------------------------------------------------------
# Android CMake toolchain file, for use with the Android NDK r5-r10c
# Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended).
# Android CMake toolchain file, for use with the Android NDK r5-r10d
# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended).
# See home page: https://github.com/taka-no-me/android-cmake
#
# Usage Linux:
@ -39,12 +39,6 @@
# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
# $ make -j8
#
# Usage Linux (using standalone toolchain):
# $ export ANDROID_STANDALONE_TOOLCHAIN=/absolute/path/to/android-toolchain
# $ mkdir build && cd build
# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
# $ make -j8
#
# Usage Windows:
# You need native port of make to build your project.
# Android NDK r7 (and newer) already has make.exe on board.
@ -63,11 +57,6 @@
# ANDROID_NDK=/opt/android-ndk - path to the NDK root.
# Can be set as environment variable. Can be set only at first cmake run.
#
# ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain - path to the
# standalone toolchain. This option is not used if full NDK is found
# (ignored if ANDROID_NDK is set).
# Can be set as environment variable. Can be set only at first cmake run.
#
# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary
# Interface (ABI). This option nearly matches to the APP_ABI variable
# used by ndk-build tool from Android NDK.
@ -123,8 +112,8 @@
# * x86_64-clang3.5
#
# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions
# instead of Thumb. Is not available for "x86" (inapplicable) and
# "armeabi-v6 with VFP" (is forced to be ON) ABIs.
# instead of Thumb. Is not available for "armeabi-v6 with VFP"
# (is forced to be ON) ABI.
#
# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker
# errors even if they are not used.
@ -133,13 +122,6 @@
# libraries. Automatically turned for NDK r5x and r6x due to GLESv2
# problems.
#
# LIBRARY_OUTPUT_PATH_ROOT=${CMAKE_SOURCE_DIR} - where to output binary
# files. See additional details below.
#
# ANDROID_SET_OBSOLETE_VARIABLES=ON - if set, then toolchain defines some
# obsolete variables which were used by previous versions of this file for
# backward compatibility.
#
# ANDROID_STL=gnustl_static - specify the runtime to use.
#
# Possible values are:
@ -172,6 +154,8 @@
# Implies -frtti -fno-exceptions.
# Available for NDK r7b and newer.
# Silently degrades to gnustl_static if not available.
# c++_static -> Use the LLVM libc++ runtime as a static library.
# c++_shared -> Use the LLVM libc++ runtime as a shared library.
#
# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on
# chosen runtime. If disabled, then the user is responsible for settings
@ -200,12 +184,6 @@
# will be set true, mutually exclusive. NEON option will be set true
# if VFP is set to NEON.
#
# LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android
# libraries will be installed.
# Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be
# under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}
# (depending on the target ABI). This is convenient for Android packaging.
#
# ------------------------------------------------------------------------------
cmake_minimum_required( VERSION 2.6.3 )
@ -235,22 +213,22 @@ endif()
# this one not so much
set( CMAKE_SYSTEM_VERSION 1 )
# rpath makes low sence for Android
# rpath makes low sense for Android
set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" )
set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
# NDK search paths
set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS)
set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS )
if( CMAKE_HOST_WIN32 )
file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}/android-ndk" "$ENV{SystemDrive}/NVPACK/android-ndk" )
set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" )
else()
file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS )
set( ANDROID_NDK_SEARCH_PATHS /opt/android-ndk "${ANDROID_NDK_SEARCH_PATHS}/NVPACK/android-ndk" )
set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" )
endif()
endif()
if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH)
if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain )
endif()
@ -272,106 +250,90 @@ set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 )
macro( __LIST_FILTER listvar regex )
if( ${listvar} )
foreach( __val ${${listvar}} )
if( __val MATCHES "${regex}" )
list( REMOVE_ITEM ${listvar} "${__val}" )
endif()
endforeach()
endif()
if( ${listvar} )
foreach( __val ${${listvar}} )
if( __val MATCHES "${regex}" )
list( REMOVE_ITEM ${listvar} "${__val}" )
endif()
endforeach()
endif()
endmacro()
macro( __INIT_VARIABLE var_name )
set( __test_path 0 )
foreach( __var ${ARGN} )
if( __var STREQUAL "PATH" )
set( __test_path 1 )
break()
endif()
endforeach()
if( __test_path AND NOT EXISTS "${${var_name}}" )
unset( ${var_name} CACHE )
endif()
if( "${${var_name}}" STREQUAL "" )
set( __values 0 )
set( __test_path 0 )
foreach( __var ${ARGN} )
if( __var STREQUAL "VALUES" )
set( __values 1 )
elseif( NOT __var STREQUAL "PATH" )
set( __obsolete 0 )
if( __var MATCHES "^OBSOLETE_.*$" )
string( REPLACE "OBSOLETE_" "" __var "${__var}" )
set( __obsolete 1 )
endif()
if( __var MATCHES "^ENV_.*$" )
string( REPLACE "ENV_" "" __var "${__var}" )
set( __value "$ENV{${__var}}" )
elseif( DEFINED ${__var} )
set( __value "${${__var}}" )
else()
if( __values )
set( __value "${__var}" )
else()
set( __value "" )
endif()
endif()
if( NOT "${__value}" STREQUAL "" )
if( __test_path )
if( EXISTS "${__value}" )
file( TO_CMAKE_PATH "${__value}" ${var_name} )
if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE )
message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
endif()
break()
endif()
else()
set( ${var_name} "${__value}" )
if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE )
message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
endif()
if( __var STREQUAL "PATH" )
set( __test_path 1 )
break()
endif()
endif()
endif()
endforeach()
unset( __value )
unset( __values )
unset( __obsolete )
elseif( __test_path )
file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
endif()
unset( __test_path )
if( __test_path AND NOT EXISTS "${${var_name}}" )
unset( ${var_name} CACHE )
endif()
if( " ${${var_name}}" STREQUAL " " )
set( __values 0 )
foreach( __var ${ARGN} )
if( __var STREQUAL "VALUES" )
set( __values 1 )
elseif( NOT __var STREQUAL "PATH" )
if( __var MATCHES "^ENV_.*$" )
string( REPLACE "ENV_" "" __var "${__var}" )
set( __value "$ENV{${__var}}" )
elseif( DEFINED ${__var} )
set( __value "${${__var}}" )
elseif( __values )
set( __value "${__var}" )
else()
set( __value "" )
endif()
if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") )
set( ${var_name} "${__value}" )
break()
endif()
endif()
endforeach()
unset( __value )
unset( __values )
endif()
if( __test_path )
file( TO_CMAKE_PATH "${${var_name}}" ${var_name} )
endif()
unset( __test_path )
endmacro()
macro( __DETECT_NATIVE_API_LEVEL _var _path )
SET( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
FILE( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
if( NOT __apiFileContent )
message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
endif()
string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
unset( __apiFileContent )
unset( __ndkApiLevelRegex )
set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" )
file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
if( NOT __apiFileContent )
message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
endif()
string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
unset( __apiFileContent )
unset( __ndkApiLevelRegex )
endmacro()
macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root )
if( EXISTS "${_root}" )
file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
__LIST_FILTER( __gccExePath "^[.].*" )
list( LENGTH __gccExePath __gccExePathsCount )
if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
message( WARNING "Could not determine machine name for compiler from ${_root}" )
set( ${_var} "" )
file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
__LIST_FILTER( __gccExePath "^[.].*" )
list( LENGTH __gccExePath __gccExePathsCount )
if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE )
message( WARNING "Could not determine machine name for compiler from ${_root}" )
set( ${_var} "" )
else()
get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
endif()
unset( __gccExePath )
unset( __gccExePathsCount )
unset( __gccExeName )
else()
get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
set( ${_var} "" )
endif()
unset( __gccExePath )
unset( __gccExePathsCount )
unset( __gccExeName )
else()
set( ${_var} "" )
endif()
endmacro()
@ -419,17 +381,19 @@ if( NOT ANDROID_NDK_HOST_X64 )
endif()
# see if we have path to Android NDK
__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN )
__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
endif()
if( NOT ANDROID_NDK )
# see if we have path to Android standalone toolchain
__INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT )
__INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN )
if( NOT ANDROID_STANDALONE_TOOLCHAIN )
#try to find Android NDK in one of the the default locations
set( __ndkSearchPaths )
foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} )
foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} )
list( APPEND __ndkSearchPaths "${__ndkSearchPath}${suffix}" )
list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" )
endforeach()
endforeach()
__INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} )
@ -487,7 +451,7 @@ else()
or
export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain
or put the toolchain or NDK in the default path:
sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}
sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk
sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" )
endif()
@ -636,7 +600,7 @@ if( BUILD_WITH_ANDROID_NDK )
endif()
if( NOT __availableToolchains )
file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
if( __availableToolchains )
if( __availableToolchainsLst )
list(SORT __availableToolchainsLst) # we need clang to go after gcc
endif()
__LIST_FILTER( __availableToolchainsLst "^[.]" )
@ -669,7 +633,7 @@ if( NOT ANDROID_SUPPORTED_ABIS )
endif()
# choose target ABI
__INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} )
__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} )
# verify that target ABI is supported
list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx )
if( __androidAbiIdx EQUAL -1 )
@ -760,7 +724,7 @@ if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMa
endif()
if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 )
__INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD OBSOLETE_FORCE_ARM VALUES OFF )
__INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF )
set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE )
mark_as_advanced( ANDROID_FORCE_ARM_BUILD )
else()
@ -845,6 +809,7 @@ else()
unset( __realApiLevel )
endif()
set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE )
set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} )
if( CMAKE_VERSION VERSION_GREATER "2.8" )
list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS )
set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
@ -863,23 +828,14 @@ endif()
# runtime choice (STL, rtti, exceptions)
if( NOT ANDROID_STL )
# honor legacy ANDROID_USE_STLPORT
if( DEFINED ANDROID_USE_STLPORT )
if( ANDROID_USE_STLPORT )
set( ANDROID_STL stlport_static )
endif()
message( WARNING "You are using an obsolete variable ANDROID_USE_STLPORT to select the STL variant. Use -DANDROID_STL=stlport_static instead." )
endif()
if( NOT ANDROID_STL )
set( ANDROID_STL gnustl_static )
endif()
endif()
set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" )
set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" )
mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES )
if( BUILD_WITH_ANDROID_NDK )
if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$")
if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$")
message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
The possible values are:
none -> Do not configure the runtime.
@ -891,6 +847,8 @@ The possible values are:
stlport_shared -> Use the STLport runtime as a shared library.
gnustl_static -> (default) Use the GNU STL as a static library.
gnustl_shared -> Use the GNU STL as a shared library.
c++_static -> Use the LLVM libc++ runtime as a static library.
c++_shared -> Use the LLVM libc++ runtime as a shared library.
" )
endif()
elseif( BUILD_WITH_STANDALONE_TOOLCHAIN )
@ -1033,7 +991,7 @@ if( BUILD_WITH_ANDROID_NDK )
set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" )
elseif( ANDROID_STL MATCHES "gabi" )
if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
message( FATAL_ERROR "gabi++ is not awailable in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.")
endif()
set( ANDROID_RTTI ON )
set( ANDROID_EXCEPTIONS OFF )
@ -1066,12 +1024,40 @@ if( BUILD_WITH_ANDROID_NDK )
else()
set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" )
endif()
set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" )
set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" )
if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" )
else()
set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" )
endif()
elseif( ANDROID_STL MATCHES "c\\+\\+_shared" OR ANDROID_STL MATCHES "c\\+\\+_static" )
set( ANDROID_EXCEPTIONS ON )
set( ANDROID_RTTI ON )
set( ANDROID_CXX_ROOT "${ANDROID_NDK}/sources/cxx-stl/" )
set( ANDROID_LLVM_ROOT "${ANDROID_CXX_ROOT}/llvm-libc++" )
if( X86 )
set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/gabi++/include" )
else()
set( ANDROID_ABI_INCLUDE_DIRS "${ANDROID_CXX_ROOT}/llvm-libc++abi/include" )
endif()
set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_LLVM_ROOT}/libcxx/include" "${ANDROID_ABI_INCLUDE_DIRS}" )
# android support sfiles
include_directories ( SYSTEM ${ANDROID_NDK}/sources/android/support/include )
if(ANDROID_STL MATCHES "c\\+\\+_shared")
set ( LLVM_LIBRARY_NAME "libc++_shared.so")
else()
set ( LLVM_LIBRARY_NAME "libc++_static.a" )
endif ()
if( EXISTS "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" )
set( __libstl "${ANDROID_LLVM_ROOT}/libs/${ANDROID_NDK_ABI_NAME}/${LLVM_LIBRARY_NAME}" )
else()
message( FATAL_ERROR "Could not find libc++ library" )
endif()
else()
message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" )
endif()
@ -1144,7 +1130,12 @@ if( NOT CMAKE_C_COMPILER )
endif()
set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" )
set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" )
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" )
# Use gcc-ar if we have it for better LTO support.
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
else()
set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" )
endif()
set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" )
set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" )
set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" )
@ -1168,7 +1159,7 @@ endif()
include( CMakeForceCompiler )
CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
if( ANDROID_COMPILER_IS_CLANG )
set( CMAKE_C_COMPILER_ID Clang)
set( CMAKE_C_COMPILER_ID Clang )
endif()
set( CMAKE_C_PLATFORM_ID Linux )
if( X86_64 OR MIPS64 OR ARM64_V8A )
@ -1195,6 +1186,14 @@ set( CMAKE_ASM_COMPILER_FORCED TRUE )
set( CMAKE_COMPILER_IS_GNUASM 1)
set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm )
foreach( lang C CXX ASM )
if( ANDROID_COMPILER_IS_CLANG )
set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} )
else()
set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} )
endif()
endforeach()
# flags and definitions
remove_definitions( -DANDROID )
add_definitions( -DANDROID )
@ -1225,14 +1224,14 @@ endif()
# NDK flags
if (ARM64_V8A )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -ffunction-sections -funwind-tables" )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
if( NOT ANDROID_COMPILER_IS_CLANG )
set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" )
endif()
elseif( ARMEABI OR ARMEABI_V7A)
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 )
set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" )
set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" )
@ -1251,13 +1250,11 @@ elseif( X86 OR X86_64 )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" )
if( NOT ANDROID_COMPILER_IS_CLANG )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" )
else()
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" )
endif()
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" )
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" )
elseif( MIPS OR MIPS64 )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" )
set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" )
set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" )
set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" )
if( NOT ANDROID_COMPILER_IS_CLANG )
@ -1342,7 +1339,7 @@ if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7
else()
__INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF )
endif()
__INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON )
__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON )
__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON )
__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON )
__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON )
@ -1350,7 +1347,7 @@ __INIT_VARIABLE( ANDROID_RELRO VALUES ON )
set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" )
set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" )
set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" )
set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" )
set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" )
@ -1452,6 +1449,16 @@ if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" )
set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" )
endif()
# pie/pic
if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) )
set( CMAKE_POSITION_INDEPENDENT_CODE TRUE )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie")
else()
set( CMAKE_POSITION_INDEPENDENT_CODE FALSE )
set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" )
set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" )
endif()
# configure rtti
if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES )
if( ANDROID_RTTI )
@ -1515,27 +1522,31 @@ if( ANDROID_EXPLICIT_CRT_LINK )
endif()
# setup output directories
set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" )
set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" )
if(NOT _CMAKE_IN_TRY_COMPILE)
if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
else()
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
endif()
set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" )
if( DEFINED LIBRARY_OUTPUT_PATH_ROOT
OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml"
OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") )
set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" )
if( NOT _CMAKE_IN_TRY_COMPILE )
if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
else()
set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
endif()
set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" )
endif()
endif()
# copy shaed stl library to build directory
if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" )
get_filename_component( __libstlname "${__libstl}" NAME )
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
endif()
unset( __fileCopyProcess )
unset( __libstlname )
if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH )
get_filename_component( __libstlname "${__libstl}" NAME )
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess )
if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}")
message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" )
endif()
unset( __fileCopyProcess )
unset( __libstlname )
endif()
@ -1596,28 +1607,10 @@ macro( find_host_program )
endmacro()
macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR )
if( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI" )
set( ${VAR} "armeabi" )
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" )
set( ${VAR} "armeabi-v7a" )
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" )
set( ${VAR} "x86" )
elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS" )
set( ${VAR} "mips" )
else()
set( ${VAR} "unknown" )
endif()
endmacro()
if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif ()
# export toolchain settings for the try_compile() command
if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
if( NOT _CMAKE_IN_TRY_COMPILE )
set( __toolchain_config "")
foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES
foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN
ANDROID_NDK_HOST_X64
ANDROID_NDK
ANDROID_NDK_LAYOUT
@ -1636,9 +1629,10 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
ANDROID_RELRO
ANDROID_LIBM_PATH
ANDROID_EXPLICIT_CRT_LINK
ANDROID_APP_PIE
)
if( DEFINED ${__var} )
if( "${__var}" MATCHES " ")
if( ${__var} MATCHES " ")
set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" )
else()
set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" )
@ -1663,16 +1657,6 @@ if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 )
endif()
# set some obsolete variables for backward compatibility
set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" )
mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES )
if( ANDROID_SET_OBSOLETE_VARIABLES )
set( ANDROID_API_LEVEL ${ANDROID_NATIVE_API_LEVEL} )
set( ARM_TARGET "${ANDROID_ABI}" )
set( ARMEABI_NDK_NAME "${ANDROID_NDK_ABI_NAME}" )
endif()
# Variables controlling behavior or set by cmake toolchain:
# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64"
# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version)
@ -1686,22 +1670,15 @@ endif()
# ANDROID_RELRO : ON/OFF
# ANDROID_FORCE_ARM_BUILD : ON/OFF
# ANDROID_STL_FORCE_FEATURES : ON/OFF
# ANDROID_SET_OBSOLETE_VARIABLES : ON/OFF
# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
# Can be set only at the first run:
# ANDROID_NDK
# ANDROID_STANDALONE_TOOLCHAIN
# ANDROID_NDK : path to your NDK install
# NDK_CCACHE : path to your ccache executable
# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain
# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems)
# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID)
# LIBRARY_OUTPUT_PATH_ROOT : <any valid path>
# NDK_CCACHE : <path to your ccache executable>
# Obsolete:
# ANDROID_API_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL
# ARM_TARGET : superseded by ANDROID_ABI
# ARM_TARGETS : superseded by ANDROID_ABI (can be set only)
# ANDROID_NDK_TOOLCHAIN_ROOT : superseded by ANDROID_STANDALONE_TOOLCHAIN (can be set only)
# ANDROID_USE_STLPORT : superseded by ANDROID_STL=stlport_static
# ANDROID_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL (completely removed)
# ANDROID_STANDALONE_TOOLCHAIN
#
# Primary read-only variables:
# ANDROID : always TRUE
@ -1715,19 +1692,16 @@ endif()
# X86_64 : TRUE if configured for x86_64
# MIPS : TRUE if configured for mips
# MIPS64 : TRUE if configured for mips64
# BUILD_ANDROID : always TRUE
# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used
# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI
# ANDROID_NDK_RELEASE : from r5 to r10c; set only for NDK
# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK
# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor)
# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI
# ANDROID_SYSROOT : path to the compiler sysroot
# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform
# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used
# Obsolete:
# ARMEABI_NDK_NAME : superseded by ANDROID_NDK_ABI_NAME
#
# Secondary (less stable) read-only variables:
# ANDROID_COMPILER_VERSION : GCC version used (not Clang version)
@ -1742,12 +1716,10 @@ endif()
# ANDROID_RTTI : if rtti is enabled by the runtime
# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime
# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used
# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product/<product_name>/obj/lib/libm.so) to workaround unresolved `sincos`
#
# Defaults:
# ANDROID_DEFAULT_NDK_API_LEVEL
# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH}
# ANDROID_NDK_SEARCH_PATHS
# ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH
# ANDROID_SUPPORTED_ABIS_${ARCH}
# ANDROID_SUPPORTED_NDK_VERSIONS
# ANDROID_SUPPORTED_NDK_VERSIONS

View file

@ -20,8 +20,8 @@ if (WIN32)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip
URL_MD5 a2dcf695e0f03a70fdd1ed7480585e82
URL https://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.8.0_public.zip
URL_MD5 bea17e04acc1dd8cf7cabefa1b28cc3c
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
@ -29,8 +29,8 @@ if (WIN32)
)
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(LIBOVR_DIR ${SOURCE_DIR}/OculusSDK/LibOVR)
message("LIBOVR dir ${SOURCE_DIR}")
set(LIBOVR_DIR ${SOURCE_DIR}/LibOVR)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/x64/Release/VS2013 CACHE TYPE INTERNAL)
else()
@ -38,6 +38,7 @@ if (WIN32)
endif()
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${LIBOVR_DIR}/Include CACHE TYPE INTERNAL)
message("LIBOVR include dir ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS}")
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${LIBOVR_LIB_DIR}/LibOVR.lib CACHE TYPE INTERNAL)
elseif(APPLE)

View file

@ -15,7 +15,6 @@ ExternalProject_Add(
LOG_BUILD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
@ -32,4 +31,4 @@ elseif (WIN32)
endif ()
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/${LIB_PREFIX}glew_d.${LIB_EXT} CACHE FILEPATH "Path to glew debug library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/${LIB_PREFIX}glew.${LIB_EXT} CACHE FILEPATH "Path to glew release library")

21
cmake/externals/gli/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,21 @@
set(EXTERNAL_NAME gli)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL https://hifi-public.s3.amazonaws.com/dependencies/gli-0.8.1.0.zip
URL_MD5 00c990f59c12bbf367956ef399d6f798
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR} CACHE PATH "List of gli include directories")

View file

@ -3,8 +3,8 @@ set(EXTERNAL_NAME glm)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.5.4.zip
URL_MD5 fab76fc982b256b46208e5c750ed456a
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip
URL_MD5 579ac77a3110befa3244d68c0ceb7281
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
LOG_DOWNLOAD 1

View file

@ -5,39 +5,43 @@ set(EXTERNAL_NAME hifiAudioCodec)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
if (WIN32 OR APPLE)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
URL_MD5 23ec3fe51eaa155ea159a4971856fc13
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
elseif(NOT ANDROID)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
URL_MD5 7d37914a18aa4de971d2f45dd3043bde
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
endif()
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
if (WIN32)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
elseif(APPLE)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
elseif(NOT ANDROID)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
if (NOT ANDROID)
if (WIN32 OR APPLE)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip
URL_MD5 23ec3fe51eaa155ea159a4971856fc13
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
else ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip
URL_MD5 7d37914a18aa4de971d2f45dd3043bde
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
endif()
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL)
if (WIN32)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL)
elseif(APPLE)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
elseif(NOT ANDROID)
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL)
endif()
endif()

View file

@ -46,7 +46,7 @@ else ()
if (ANDROID)
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
endif ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://www.libsdl.org/release/SDL2-2.0.3.tar.gz
@ -61,7 +61,6 @@ endif ()
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
if (APPLE)
# NOOP
@ -78,9 +77,9 @@ elseif (WIN32)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_TEMP ${SOURCE_DIR}/lib/x86/SDL2.lib CACHE FILEPATH "Path to SDL2 library")
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR}/lib/x86 CACHE PATH "Location of SDL2 DLL")
endif()
add_paths_to_fixup_libs(${${EXTERNAL_NAME_UPPER}_DLL_PATH})
else ()
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)

View file

@ -3,9 +3,9 @@ set(EXTERNAL_NAME tbb)
include(ExternalProject)
if (ANDROID)
find_program(NDK_BUILD_COMMAND NAMES ndk-build DOC "Path to the ndk-build command")
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
@ -20,7 +20,7 @@ if (ANDROID)
)
elseif (APPLE)
find_program(MAKE_COMMAND NAMES make DOC "Path to the make command")
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz
@ -37,11 +37,11 @@ else ()
if (WIN32)
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_win.zip)
set(DOWNLOAD_MD5 d250d40bb93b255f75bcbb19e976a440)
else ()
else ()
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_lin.tgz)
set(DOWNLOAD_MD5 7830ba2bc62438325fba2ec0c95367a5)
endif ()
ExternalProject_Add(
${EXTERNAL_NAME}
URL ${DOWNLOAD_URL}
@ -60,11 +60,11 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
if (APPLE)
if (APPLE)
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib")
set(_LIB_PREFIX "lib")
set(_LIB_EXT "dylib")
ExternalProject_Add_Step(
${EXTERNAL_NAME}
change-install-name
@ -74,7 +74,7 @@ if (APPLE)
WORKING_DIRECTORY <SOURCE_DIR>
LOG 1
)
elseif (WIN32)
if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/intel64/vc12")
@ -91,18 +91,18 @@ elseif (ANDROID)
elseif (UNIX)
set(_LIB_PREFIX "lib")
set(_LIB_EXT "so")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_TBB_ARCH_DIR "intel64")
else()
set(_TBB_ARCH_DIR "ia32")
endif()
execute_process(
COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION
)
if (GCC_VERSION VERSION_GREATER 4.4 OR GCC_VERSION VERSION_EQUAL 4.4)
set(_TBB_LIB_DIR "${SOURCE_DIR}/lib/${_TBB_ARCH_DIR}/gcc4.4")
elseif (GCC_VERSION VERSION_GREATER 4.1 OR GCC_VERSION VERSION_EQUAL 4.1)
@ -110,9 +110,9 @@ elseif (UNIX)
else ()
message(STATUS "Could not find a compatible version of Threading Building Blocks library for your compiler.")
endif ()
endif ()
endif ()
if (DEFINED _TBB_LIB_DIR)
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location")

24
cmake/externals/wasapi/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,24 @@
if (WIN32)
set(EXTERNAL_NAME wasapi)
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi.zip
URL_MD5 11c8a7728d6eda7223df800e10b70723
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD 1
)
# Hide this external target (for ide users)
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${SOURCE_DIR} CACHE FILEPATH "Location of wasapi DLL")
endif()

View file

@ -1,23 +0,0 @@
#
# AutoMTC.cmake
#
# Created by Andrzej Kapolka on 12/31/13.
# Copyright 2013 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(AUTO_MTC)
set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp)
file(GLOB INCLUDE_FILES src/*.h)
if (NOT ANDROID)
set(MTC_EXECUTABLE mtc)
else ()
set(MTC_EXECUTABLE $ENV{MTC_PATH}/mtc)
endif ()
add_custom_command(OUTPUT ${AUTOMTC_SRC} COMMAND ${MTC_EXECUTABLE} -o ${AUTOMTC_SRC} ${INCLUDE_FILES} DEPENDS ${MTC_EXECUTABLE} ${INCLUDE_FILES})
endmacro()

View file

@ -1,77 +1,92 @@
#
#
# AutoScribeShader.cmake
#
#
# Created by Sam Gateau on 12/17/14.
# Copyright 2014 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
#
function(AUTOSCRIBE_SHADER SHADER_FILE)
# Grab include files
foreach(includeFile ${ARGN})
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
endforeach()
# Grab include files
foreach(includeFile ${ARGN})
list(APPEND SHADER_INCLUDE_FILES ${includeFile})
endforeach()
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
endforeach()
foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES})
get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH)
list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR})
endforeach()
#Extract the unique include shader paths
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
#message(${TARGET_NAME} Hifi for includes ${INCLUDES})
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
endforeach()
#Extract the unique include shader paths
set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
#message(${TARGET_NAME} Hifi for includes ${INCLUDES})
foreach(EXTRA_SHADER_INCLUDE ${INCLUDES})
list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE})
endforeach()
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#message(ready for includes ${SHADER_INCLUDES_PATHS})
list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS)
#message(ready for includes ${SHADER_INCLUDES_PATHS})
# make the scribe include arguments
set(SCRIBE_INCLUDES)
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
endforeach()
# make the scribe include arguments
set(SCRIBE_INCLUDES)
foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS})
set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/)
endforeach()
# Define the final name of the generated shader file
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
if(SHADER_EXT STREQUAL .slv)
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
elseif(${SHADER_EXT} STREQUAL .slf)
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
elseif(${SHADER_EXT} STREQUAL .slg)
set(SHADER_TARGET ${SHADER_TARGET}_geom.h)
endif()
# Define the final name of the generated shader file
get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE)
get_filename_component(SHADER_EXT ${SHADER_FILE} EXT)
if(SHADER_EXT STREQUAL .slv)
set(SHADER_TARGET ${SHADER_TARGET}_vert.h)
elseif(${SHADER_EXT} STREQUAL .slf)
set(SHADER_TARGET ${SHADER_TARGET}_frag.h)
elseif(${SHADER_EXT} STREQUAL .slg)
set(SHADER_TARGET ${SHADER_TARGET}_geom.h)
endif()
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
# Target dependant Custom rule on the SHADER_FILE
if (APPLE)
set(GLPROFILE MAC_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
# Target dependant Custom rule on the SHADER_FILE
if (APPLE)
set(GLPROFILE MAC_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
elseif (ANDROID)
set(GLPROFILE LINUX_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
elseif (UNIX)
set(GLPROFILE LINUX_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
# for an android build, we can't use the scribe that cmake would normally produce as a target,
# since it's unrunnable by the cross-compiling build machine
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
else ()
set(GLPROFILE PC_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
# so, we require the compiling user to point us at a compiled executable version for their native toolchain
find_program(NATIVE_SCRIBE scribe PATHS ${SCRIBE_PATH} ENV SCRIBE_PATH)
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
endif()
if (NOT NATIVE_SCRIBE)
message(FATAL_ERROR "The High Fidelity scribe tool is required for shader pre-processing. \
Please compile scribe using your native toolchain and set SCRIBE_PATH to the path containing the scribe executable in your ENV.\
")
endif ()
#output the generated file name
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
elseif (UNIX)
set(GLPROFILE LINUX_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
else ()
set(GLPROFILE PC_GL)
set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE})
endif()
#output the generated file name
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
file(GLOB INCLUDE_FILES ${SHADER_TARGET})
endfunction()
@ -79,11 +94,11 @@ endfunction()
macro(AUTOSCRIBE_SHADER_LIB)
set(HIFI_LIBRARIES_SHADER_INCLUDE_FILES "")
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
foreach(HIFI_LIBRARY ${ARGN})
foreach(HIFI_LIBRARY ${ARGN})
#if (NOT TARGET ${HIFI_LIBRARY})
# file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}/src/)
#endif ()
#file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src/*.slh)
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
endforeach()
@ -99,9 +114,9 @@ macro(AUTOSCRIBE_SHADER_LIB)
#message("${TARGET_NAME} ${SHADER_INCLUDE_FILES}")
set(AUTOSCRIBE_SHADER_SRC "")
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
endforeach()
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
@ -118,4 +133,4 @@ macro(AUTOSCRIBE_SHADER_LIB)
# Link library shaders, if they exist
include_directories("${SHADERS_DIR}")
endmacro()
endmacro()

View file

@ -16,26 +16,6 @@ macro(fixup_interface)
string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR})
set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app")
# install QtWebProcess from Qt to the application bundle
# since it is missed by macdeployqt
# https://bugreports.qt.io/browse/QTBUG-35211
set(LIBEXEC_PATH "${_INTERFACE_INSTALL_PATH}/Contents/libexec")
install(
PROGRAMS "${QT_DIR}/libexec/QtWebProcess"
DESTINATION ${LIBEXEC_PATH}
COMPONENT ${CLIENT_COMPONENT}
)
set(QTWEBPROCESS_PATH "\${CMAKE_INSTALL_PREFIX}/${LIBEXEC_PATH}")
# we also need a qt.conf in the directory of QtWebProcess
install(CODE "
file(WRITE ${QTWEBPROCESS_PATH}/qt.conf
\"[Paths]\nPlugins = ../PlugIns\nImports = ../Resources/qml\nQml2Imports = ../Resources/qml\"
)"
COMPONENT ${CLIENT_COMPONENT}
)
find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH)
if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD))
@ -49,7 +29,6 @@ macro(fixup_interface)
execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\
\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\
-verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\
-executable=\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\
)"
COMPONENT ${CLIENT_COMPONENT}
)

View file

@ -59,7 +59,12 @@ macro(install_beside_console)
set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_INSTALL_DIR}/${TARGET_NAME}")
string(REPLACE " " "\\ " ESCAPED_EXECUTABLE_NAME ${EXECUTABLE_NEEDING_FIXUP})
# configure Info.plist for COMPONENT_APP
install(CODE "
set(MACOSX_BUNDLE_EXECUTABLE_NAME domain-server)
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.server-components)
set(MACOSX_BUNDLE_BUNDLE_NAME Sandbox\\ Components)
configure_file(${HF_CMAKE_DIR}/templates/MacOSXBundleSandboxComponentsInfo.plist.in ${ESCAPED_BUNDLE_NAME}/Contents/Info.plist)
execute_process(COMMAND ${MACDEPLOYQT_COMMAND} ${ESCAPED_BUNDLE_NAME} -verbose=2 -executable=${ESCAPED_EXECUTABLE_NAME})"
COMPONENT ${SERVER_COMPONENT}
)

View file

@ -41,5 +41,15 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
POST_BUILD
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>:--release> $<TARGET_FILE:${TARGET_NAME}>"
)
set(QTAUDIO_PATH $<TARGET_FILE_DIR:${TARGET_NAME}>/audio)
# if present, replace qtaudio_windows.dll with qtaudio_wasapi.dll
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
COMMAND if exist ${QTAUDIO_PATH}/qtaudio_windows.dll ( ${CMAKE_COMMAND} -E remove ${QTAUDIO_PATH}/qtaudio_windows.dll && ${CMAKE_COMMAND} -E copy ${WASAPI_DLL_PATH}/qtaudio_wasapi.dll ${QTAUDIO_PATH} && ${CMAKE_COMMAND} -E copy ${WASAPI_DLL_PATH}/qtaudio_wasapi.pdb ${QTAUDIO_PATH} )
)
endif ()
endmacro()

View file

@ -18,6 +18,13 @@ macro(SET_PACKAGING_PARAMETERS)
set(RELEASE_TYPE $ENV{RELEASE_TYPE})
set(RELEASE_NUMBER $ENV{RELEASE_NUMBER})
string(TOLOWER "$ENV{BRANCH}" BUILD_BRANCH)
set(BUILD_GLOBAL_SERVICES "DEVELOPMENT")
set(USE_STABLE_GLOBAL_SERVICES FALSE)
message(STATUS "The BUILD_BRANCH variable is: ${BUILD_BRANCH}")
message(STATUS "The BRANCH environment variable is: $ENV{BRANCH}")
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
if (RELEASE_TYPE STREQUAL "PRODUCTION")
set(DEPLOY_PACKAGE TRUE)
@ -31,6 +38,14 @@ macro(SET_PACKAGING_PARAMETERS)
# add definition for this release type
add_definitions(-DPRODUCTION_BUILD)
# if the build is a PRODUCTION_BUILD from the "stable" branch
# then use the STABLE gobal services
if (BUILD_BRANCH STREQUAL "stable")
message(STATUS "The RELEASE_TYPE is PRODUCTION and the BUILD_BRANCH is stable...")
set(BUILD_GLOBAL_SERVICES "STABLE")
set(USE_STABLE_GLOBAL_SERVICES TRUE)
endif()
elseif (RELEASE_TYPE STREQUAL "PR")
set(DEPLOY_PACKAGE TRUE)
set(PR_BUILD 1)
@ -132,6 +147,10 @@ macro(SET_PACKAGING_PARAMETERS)
set(CLIENT_COMPONENT client)
set(SERVER_COMPONENT server)
# print out some results for testing this new build feature
message(STATUS "The BUILD_GLOBAL_SERVICES variable is: ${BUILD_GLOBAL_SERVICES}")
message(STATUS "The USE_STABLE_GLOBAL_SERVICES variable is: ${USE_STABLE_GLOBAL_SERVICES}")
# create a header file our targets can use to find out the application version
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes")
configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h")

View file

@ -1,16 +1,16 @@
#
#
# SetupHifiLibrary.cmake
#
#
# Copyright 2013 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
#
macro(SETUP_HIFI_LIBRARY)
project(${TARGET_NAME})
# grab the implementation and header files
file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c")
list(APPEND ${TARGET_NAME}_SRCS ${LIB_SRCS})
@ -34,19 +34,19 @@ macro(SETUP_HIFI_LIBRARY)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
endif()
endforeach()
setup_memory_debugger()
# create a library and set the property so it can be referenced later
if (${${TARGET_NAME}_SHARED})
add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
else ()
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE})
endif ()
set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN})
list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core)
# find these Qt modules and link them to our own target
find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED)
@ -59,7 +59,7 @@ macro(SETUP_HIFI_LIBRARY)
set(QT_RESOURCES_FILE "")
target_glm()
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Libraries")
endmacro(SETUP_HIFI_LIBRARY)
endmacro(SETUP_HIFI_LIBRARY)

View file

@ -22,7 +22,7 @@ macro(SETUP_HIFI_PROJECT)
endif ()
endforeach()
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC})
add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC})
# include the generated application version header
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")

View file

@ -0,0 +1,12 @@
#
# Copyright 2015 High Fidelity, Inc.
# Created by Bradley Austin Davis on 2015/10/10
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(TARGET_GLI)
add_dependency_external_projects(gli)
find_package(GLI REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLI_INCLUDE_DIRS})
endmacro()

View file

@ -0,0 +1,26 @@
#
# FindGLI.cmake
#
# Try to find GLI include path.
# Once done this will define
#
# GLI_INCLUDE_DIRS
#
# Created on 2016/09/03 by Bradley Austin Davis
# Copyright 2013-2016 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
# setup hints for GLI search
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("gli")
# locate header
find_path(GLI_INCLUDE_DIRS "gli/gli.hpp" HINTS ${GLI_SEARCH_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLI DEFAULT_MSG GLI_INCLUDE_DIRS)
mark_as_advanced(GLI_INCLUDE_DIRS GLI_SEARCH_DIRS)

View file

@ -9,7 +9,12 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#define USE_STABLE_GLOBAL_SERVICES @USE_STABLE_GLOBAL_SERVICES@
namespace BuildInfo {
const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@";
const QString VERSION = "@BUILD_VERSION@";
const QString BUILD_BRANCH = "@BUILD_BRANCH@";
const QString BUILD_GLOBAL_SERVICES = "@BUILD_GLOBAL_SERVICES@";
}

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
</dict>
</plist>

View file

@ -130,6 +130,11 @@ Var AR_RegFlags
SectionSetFlags ${${SecName}} $AR_SecFlags
"default_${SecName}:"
; The client is always selected by default
${If} ${SecName} == @CLIENT_COMPONENT_NAME@
SectionSetFlags ${${SecName}} 17
${EndIf}
!insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
!macroend
@ -243,6 +248,12 @@ FunctionEnd
;--------------------------------
; Installation types
Section "-Previous Install Cleanup"
; Remove the resources folder so we don't end up including removed QML files
RMDir /r "$INSTDIR\resources"
SectionEnd
@CPACK_NSIS_INSTALLATION_TYPES@
;--------------------------------
@ -589,6 +600,9 @@ Section "-Core installation"
Delete "$INSTDIR\version"
Delete "$INSTDIR\xinput1_3.dll"
;Delete old Qt files
Delete "$INSTDIR\audio\qtaudio_windows.dll"
; Delete old desktop shortcuts before they were renamed during Sandbox rename
Delete "$DESKTOP\@PRE_SANDBOX_INTERFACE_SHORTCUT_NAME@.lnk"
Delete "$DESKTOP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk"

View file

@ -9,6 +9,11 @@ endif ()
# setup the project and link required Qt modules
setup_hifi_project(Network)
# Fix up the rpath so macdeployqt works
if (APPLE)
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
endif ()
# TODO: find a solution that will handle web file changes in resources on windows without a re-build.
# Currently the resources are only copied on post-build. If one is changed but the domain-server is not, they will
# not be re-copied. This is worked-around on OS X/UNIX by using a symlink.

View file

@ -380,6 +380,14 @@
"default": "0",
"advanced": false
},
{
"name": "maximum_user_capacity_redirect_location",
"label": "Redirect to Location on Maximum Capacity",
"help": "Is there another domain, you'd like to redirect clients to when the maximum number of avatars are connected.",
"placeholder": "",
"default": "",
"advanced": false
},
{
"name": "standard_permissions",
"type": "table",
@ -1025,65 +1033,41 @@
"name": "dynamic_jitter_buffer",
"type": "checkbox",
"label": "Dynamic Jitter Buffers",
"help": "Dynamically buffer client audio based on perceived jitter in packet receipt timing",
"help": "Dynamically buffer inbound audio streams based on perceived jitter in packet receipt timing.",
"default": true,
"advanced": true
},
{
"name": "static_desired_jitter_buffer_frames",
"label": "Static Desired Jitter Buffer Frames",
"help": "If dynamic jitter buffers is disabled, this determines the target number of frames maintained by the AudioMixer's jitter buffers",
"help": "If dynamic jitter buffers is disabled, this determines the size of the jitter buffers of inbound audio streams in the mixer. Higher numbers introduce more latency.",
"placeholder": "1",
"default": "1",
"advanced": true
},
{
"name": "max_frames_over_desired",
"label": "Max Frames Over Desired",
"help": "The highest number of frames an AudioMixer's ringbuffer can exceed the desired jitter buffer frames by",
"placeholder": "10",
"default": "10",
"advanced": true
"name": "max_frames_over_desired",
"deprecated": true
},
{
"name": "use_stdev_for_desired_calc",
"type": "checkbox",
"label": "Stdev for Desired Jitter Frames Calc",
"help": "Use Philip's method (stdev of timegaps) to calculate desired jitter frames (otherwise Fred's max timegap method is used)",
"default": false,
"advanced": true
"name": "window_starve_threshold",
"deprecated": true
},
{
"name": "window_starve_threshold",
"label": "Window Starve Threshold",
"help": "If this many starves occur in an N-second window (N is the number in the next field), then the desired jitter frames will be re-evaluated using Window A.",
"placeholder": "3",
"default": "3",
"advanced": true
"name": "window_seconds_for_desired_calc_on_too_many_starves",
"deprecated": true
},
{
"name": "window_seconds_for_desired_calc_on_too_many_starves",
"label": "Timegaps Window (A) Seconds",
"help": "Window A contains a history of timegaps. Its max timegap is used to re-evaluate the desired jitter frames when too many starves occur within it.",
"placeholder": "50",
"default": "50",
"advanced": true
"name": "window_seconds_for_desired_reduction",
"deprecated": true
},
{
"name": "window_seconds_for_desired_reduction",
"label": "Timegaps Window (B) Seconds",
"help": "Window B contains a history of timegaps. Its max timegap is used as a ceiling for the desired jitter frames value.",
"placeholder": "10",
"default": "10",
"advanced": true
"name": "use_stdev_for_desired_calc",
"deprecated": true
},
{
"name": "repetition_with_fade",
"type": "checkbox",
"label": "Repetition with Fade",
"help": "Dropped frames and mixing during starves repeat the last frame, eventually fading to silence",
"default": false,
"advanced": true
"name": "repetition_with_fade",
"deprecated": true
}
]
},

View file

@ -75,7 +75,7 @@ span.port {
color: #666666;
}
.advanced-setting {
.advanced-setting, .deprecated-setting {
display: none;
}

View file

@ -40,7 +40,8 @@
<script id="panels-template" type="text/template">
<% _.each(descriptions, function(group){ %>
<% split_settings = _.partition(group.settings, function(value, index) { return !value.advanced }) %>
<% var settings = _.partition(group.settings, function(value, index) { return !value.deprecated })[0] %>
<% split_settings = _.partition(settings, function(value, index) { return !value.advanced }) %>
<% isAdvanced = _.isEmpty(split_settings[0]) %>
<% if (isAdvanced) { %>
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>

View file

@ -2,6 +2,7 @@ var Settings = {
showAdvanced: false,
METAVERSE_URL: 'https://metaverse.highfidelity.com',
ADVANCED_CLASS: 'advanced-setting',
DEPRECATED_CLASS: 'deprecated-setting',
TRIGGER_CHANGE_CLASS: 'trigger-change',
DATA_ROW_CLASS: 'value-row',
DATA_COL_CLASS: 'value-col',
@ -42,7 +43,10 @@ var Settings = {
var viewHelpers = {
getFormGroup: function(keypath, setting, values, isAdvanced) {
form_group = "<div class='form-group " + (isAdvanced ? Settings.ADVANCED_CLASS : "") + "' data-keypath='" + keypath + "'>";
form_group = "<div class='form-group " +
(isAdvanced ? Settings.ADVANCED_CLASS : "") + " " +
(setting.deprecated ? Settings.DEPRECATED_CLASS : "" ) + "' " +
"data-keypath='" + keypath + "'>";
setting_value = _(values).valueForKeyPath(keypath);
if (_.isUndefined(setting_value) || _.isNull(setting_value)) {
@ -454,7 +458,7 @@ function setupHFAccountButton() {
}
// use the existing getFormGroup helper to ask for a button
var buttonGroup = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values, false);
var buttonGroup = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values);
// add the button group to the top of the metaverse panel
$('#metaverse .panel-body').prepend(buttonGroup);
@ -665,7 +669,7 @@ function setupPlacesTable() {
}
// get a table for the places
var placesTableGroup = viewHelpers.getFormGroup('', placesTableSetting, Settings.data.values, false);
var placesTableGroup = viewHelpers.getFormGroup('', placesTableSetting, Settings.data.values);
// append the places table in the right place
$('#places_paths .panel-body').prepend(placesTableGroup);

View file

@ -317,6 +317,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
}
const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
const QString MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION = "security.maximum_user_capacity_redirect_location";
SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnectionData& nodeConnection,
const QString& username,
@ -363,7 +364,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) {
sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.",
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::TooManyUsers);
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorized);
#ifdef WANT_DEBUG
qDebug() << "stalling login due to permissions:" << username;
#endif
@ -372,8 +373,16 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
if (!userPerms.can(NodePermissions::Permission::canConnectPastMaxCapacity) && !isWithinMaxCapacity()) {
// we can't allow this user to connect because we are at max capacity
QString redirectOnMaxCapacity;
const QVariant* redirectOnMaxCapacityVariant =
valueForKeyPath(_server->_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION);
if (redirectOnMaxCapacityVariant && redirectOnMaxCapacityVariant->canConvert<QString>()) {
redirectOnMaxCapacity = redirectOnMaxCapacityVariant->toString();
qDebug() << "Redirection domain:" << redirectOnMaxCapacity;
}
sendConnectionDeniedPacket("Too many connected users.", nodeConnection.senderSockAddr,
DomainHandler::ConnectionRefusedReason::TooManyUsers);
DomainHandler::ConnectionRefusedReason::TooManyUsers, redirectOnMaxCapacity);
#ifdef WANT_DEBUG
qDebug() << "stalling login due to max capacity:" << username;
#endif
@ -623,22 +632,30 @@ void DomainGatekeeper::sendProtocolMismatchConnectionDenial(const HifiSockAddr&
}
void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr,
DomainHandler::ConnectionRefusedReason reasonCode) {
DomainHandler::ConnectionRefusedReason reasonCode,
QString extraInfo) {
// this is an agent and we've decided we won't let them connect - send them a packet to deny connection
QByteArray utfString = reason.toUtf8();
quint16 payloadSize = utfString.size();
QByteArray utfReasonString = reason.toUtf8();
quint16 reasonSize = utfReasonString.size();
QByteArray utfExtraInfo = extraInfo.toUtf8();
quint16 extraInfoSize = utfExtraInfo.size();
// setup the DomainConnectionDenied packet
auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied,
payloadSize + sizeof(payloadSize) + sizeof(uint8_t));
sizeof(uint8_t) + // reasonCode
reasonSize + sizeof(reasonSize) +
extraInfoSize + sizeof(extraInfoSize));
// pack in the reason the connection was denied (the client displays this)
if (payloadSize > 0) {
uint8_t reasonCodeWire = (uint8_t)reasonCode;
connectionDeniedPacket->writePrimitive(reasonCodeWire);
connectionDeniedPacket->writePrimitive(payloadSize);
connectionDeniedPacket->write(utfString);
}
uint8_t reasonCodeWire = (uint8_t)reasonCode;
connectionDeniedPacket->writePrimitive(reasonCodeWire);
connectionDeniedPacket->writePrimitive(reasonSize);
connectionDeniedPacket->write(utfReasonString);
// write the extra info as well
connectionDeniedPacket->writePrimitive(extraInfoSize);
connectionDeniedPacket->write(utfExtraInfo);
// send the packet off
DependencyManager::get<LimitedNodeList>()->sendPacket(std::move(connectionDeniedPacket), senderSockAddr);

View file

@ -88,7 +88,8 @@ private:
void sendConnectionTokenPacket(const QString& username, const HifiSockAddr& senderSockAddr);
static void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr,
DomainHandler::ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown);
DomainHandler::ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown,
QString extraInfo = QString());
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);

View file

@ -23,6 +23,7 @@
#include <QStandardPaths>
#include <QTimer>
#include <QUrlQuery>
#include <QCommandLineParser>
#include <AccountManager.h>
#include <BuildInfo.h>
@ -45,7 +46,11 @@
int const DomainServer::EXIT_CODE_REBOOT = 234923;
#if USE_STABLE_GLOBAL_SERVICES
const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com";
#else
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
#endif
DomainServer::DomainServer(int argc, char* argv[]) :
QCoreApplication(argc, argv),
@ -62,8 +67,11 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_webAuthenticationStateSet(),
_cookieSessionHash(),
_automaticNetworkingSetting(),
_settingsManager()
_settingsManager(),
_iceServerAddr(ICE_SERVER_DEFAULT_HOSTNAME),
_iceServerPort(ICE_SERVER_DEFAULT_PORT)
{
parseCommandLine();
qInstallMessageHandler(LogHandler::verboseMessageHandler);
LogUtils::init();
@ -79,6 +87,14 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qDebug() << "Setting up domain-server";
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
qDebug() << "[VERSION] VERSION:" << BuildInfo::VERSION;
qDebug() << "[VERSION] BUILD_BRANCH:" << BuildInfo::BUILD_BRANCH;
qDebug() << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES;
qDebug() << "[VERSION] We will be using this default ICE server:" << ICE_SERVER_DEFAULT_HOSTNAME;
// make sure we have a fresh AccountManager instance
// (need this since domain-server can restart itself and maintain static variables)
DependencyManager::set<AccountManager>();
@ -147,6 +163,53 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qDebug() << "domain-server is running";
}
void DomainServer::parseCommandLine() {
QCommandLineParser parser;
parser.setApplicationDescription("High Fidelity Domain Server");
parser.addHelpOption();
const QCommandLineOption iceServerAddressOption("i", "ice-server address", "IP:PORT or HOSTNAME:PORT");
parser.addOption(iceServerAddressOption);
const QCommandLineOption domainIDOption("d", "domain-server uuid");
parser.addOption(domainIDOption);
const QCommandLineOption getTempNameOption("get-temp-name", "Request a temporary domain-name");
parser.addOption(getTempNameOption);
const QCommandLineOption masterConfigOption("master-config", "Deprecated config-file option");
parser.addOption(masterConfigOption);
if (!parser.parse(QCoreApplication::arguments())) {
qWarning() << parser.errorText() << endl;
parser.showHelp();
Q_UNREACHABLE();
}
if (parser.isSet(iceServerAddressOption)) {
// parse the IP and port combination for this target
QString hostnamePortString = parser.value(iceServerAddressOption);
_iceServerAddr = hostnamePortString.left(hostnamePortString.indexOf(':'));
_iceServerPort = (quint16) hostnamePortString.mid(hostnamePortString.indexOf(':') + 1).toUInt();
if (_iceServerPort == 0) {
_iceServerPort = ICE_SERVER_DEFAULT_PORT;
}
if (_iceServerAddr.isEmpty()) {
qWarning() << "Could not parse an IP address and port combination from" << hostnamePortString;
QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
}
}
if (parser.isSet(domainIDOption)) {
_overridingDomainID = QUuid(parser.value(domainIDOption));
_overrideDomainID = true;
qDebug() << "domain-server ID is" << _overridingDomainID;
}
}
DomainServer::~DomainServer() {
// destroy the LimitedNodeList before the DomainServer QCoreApplication is down
DependencyManager::destroy<LimitedNodeList>();
@ -154,7 +217,7 @@ DomainServer::~DomainServer() {
void DomainServer::queuedQuit(QString quitMessage, int exitCode) {
if (!quitMessage.isEmpty()) {
qCritical() << qPrintable(quitMessage);
qWarning() << qPrintable(quitMessage);
}
QCoreApplication::exit(exitCode);
@ -295,7 +358,7 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject();
if (!domainObject.isEmpty()) {
auto id = domainObject[ID_KEY].toString();
auto id = _overrideDomainID ? _overridingDomainID.toString() : domainObject[ID_KEY].toString();
auto name = domainObject[NAME_KEY].toString();
auto key = domainObject[KEY_KEY].toString();
@ -368,11 +431,11 @@ void DomainServer::setupNodeListAndAssignments() {
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
unsigned short domainServerPort = (unsigned short) localPortValue.toUInt();
int domainServerPort = localPortValue.toInt();
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
unsigned short domainServerDTLSPort = 0;
int domainServerDTLSPort = INVALID_PORT;
if (_isUsingDTLS) {
domainServerDTLSPort = DEFAULT_DOMAIN_SERVER_DTLS_PORT;
@ -403,24 +466,30 @@ void DomainServer::setupNodeListAndAssignments() {
quint16 localHttpsPort = DOMAIN_SERVER_HTTPS_PORT;
nodeList->putLocalPortIntoSharedMemory(DOMAIN_SERVER_LOCAL_HTTPS_PORT_SMEM_KEY, this, localHttpsPort);
// set our LimitedNodeList UUID to match the UUID from our config
// nodes will currently use this to add resources to data-web that relate to our domain
const QVariant* idValueVariant = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH);
if (idValueVariant) {
nodeList->setSessionUUID(idValueVariant->toString());
bool isMetaverseDomain = false;
if (_overrideDomainID) {
nodeList->setSessionUUID(_overridingDomainID);
isMetaverseDomain = true; // assume metaverse domain
} else {
const QVariant* idValueVariant = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH);
if (idValueVariant) {
nodeList->setSessionUUID(idValueVariant->toString());
isMetaverseDomain = true; // if we have an ID, we'll assume we're a metaverse domain
} else {
nodeList->setSessionUUID(QUuid::createUuid()); // Use random UUID
}
}
// if we have an ID, we'll assume we're a metaverse domain
// now see if we think we're a temp domain (we have an API key) or a full domain
if (isMetaverseDomain) {
// see if we think we're a temp domain (we have an API key) or a full domain
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
if (temporaryDomainKey.isEmpty()) {
_type = MetaverseDomain;
} else {
_type = MetaverseTemporaryDomain;
}
} else {
nodeList->setSessionUUID(QUuid::createUuid()); // Use random UUID
}
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
@ -536,7 +605,6 @@ void DomainServer::setupAutomaticNetworking() {
} else {
qDebug() << "Cannot enable domain-server automatic networking without a domain ID."
<< "Please add an ID to your config file or via the web interface.";
return;
}
}
@ -594,12 +662,11 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
void DomainServer::updateICEServerAddresses() {
if (_iceAddressLookupID == -1) {
_iceAddressLookupID = QHostInfo::lookupHost(ICE_SERVER_DEFAULT_HOSTNAME, this, SLOT(handleICEHostInfo(QHostInfo)));
_iceAddressLookupID = QHostInfo::lookupHost(_iceServerAddr, this, SLOT(handleICEHostInfo(QHostInfo)));
}
}
void DomainServer::parseAssignmentConfigs(QSet<Assignment::Type>& excludedTypes) {
// check for configs from the command line, these take precedence
const QString ASSIGNMENT_CONFIG_REGEX_STRING = "config-([\\d]+)";
QRegExp assignmentConfigRegex(ASSIGNMENT_CONFIG_REGEX_STRING);
@ -1211,41 +1278,43 @@ void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) {
}
void DomainServer::sendICEServerAddressToMetaverseAPI() {
if (!_iceServerSocket.isNull()) {
const QString ICE_SERVER_ADDRESS = "ice_server_address";
const QString ICE_SERVER_ADDRESS = "ice_server_address";
QJsonObject domainObject;
QJsonObject domainObject;
if (!_connectedToICEServer || _iceServerSocket.isNull()) {
domainObject[ICE_SERVER_ADDRESS] = "0.0.0.0";
} else {
// we're using full automatic networking and we have a current ice-server socket, use that now
domainObject[ICE_SERVER_ADDRESS] = _iceServerSocket.getAddress().toString();
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
if (!temporaryDomainKey.isEmpty()) {
// add the temporary domain token
const QString KEY_KEY = "api_key";
domainObject[KEY_KEY] = temporaryDomainKey;
}
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
// make sure we hear about failure so we can retry
JSONCallbackParameters callbackParameters;
callbackParameters.errorCallbackReceiver = this;
callbackParameters.errorCallbackMethod = "handleFailedICEServerAddressUpdate";
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
("Updating ice-server address in High Fidelity Metaverse API to [^ \n]+");
qDebug() << "Updating ice-server address in High Fidelity Metaverse API to"
<< _iceServerSocket.getAddress().toString();
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())),
AccountManagerAuth::Optional,
QNetworkAccessManager::PutOperation,
callbackParameters,
domainUpdateJSON.toUtf8());
}
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
if (!temporaryDomainKey.isEmpty()) {
// add the temporary domain token
const QString KEY_KEY = "api_key";
domainObject[KEY_KEY] = temporaryDomainKey;
}
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
// make sure we hear about failure so we can retry
JSONCallbackParameters callbackParameters;
callbackParameters.errorCallbackReceiver = this;
callbackParameters.errorCallbackMethod = "handleFailedICEServerAddressUpdate";
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
("Updating ice-server address in High Fidelity Metaverse API to [^ \n]+");
qDebug() << "Updating ice-server address in High Fidelity Metaverse API to"
<< (_iceServerSocket.isNull() ? "" : _iceServerSocket.getAddress().toString());
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())),
AccountManagerAuth::Optional,
QNetworkAccessManager::PutOperation,
callbackParameters,
domainUpdateJSON.toUtf8());
}
void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply& requestReply) {
@ -1297,6 +1366,7 @@ void DomainServer::sendHeartbeatToIceServer() {
// reset the connection flag for ICE server
_connectedToICEServer = false;
sendICEServerAddressToMetaverseAPI();
// randomize our ice-server address (and simultaneously look up any new hostnames for available ice-servers)
randomizeICEServerAddress(true);
@ -1756,6 +1826,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
.arg(authorizationCode, oauthRedirectURL().toString(), _oauthClientID, _oauthClientSecret);
QNetworkRequest tokenRequest(tokenRequestUrl);
tokenRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
tokenRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
@ -1949,6 +2020,7 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
QNetworkRequest profileRequest(profileURL);
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
return NetworkAccessManager::getInstance().get(profileRequest);
}
@ -2267,6 +2339,7 @@ void DomainServer::processICEServerHeartbeatACK(QSharedPointer<ReceivedMessage>
if (!_connectedToICEServer) {
_connectedToICEServer = true;
sendICEServerAddressToMetaverseAPI();
qInfo() << "Connected to ice-server at" << _iceServerSocket;
}
}

View file

@ -105,6 +105,7 @@ signals:
private:
const QUuid& getID();
void parseCommandLine();
void setupNodeListAndAssignments();
bool optionallySetupOAuth();
@ -205,6 +206,11 @@ private:
friend class DomainGatekeeper;
friend class DomainMetadata;
QString _iceServerAddr;
int _iceServerPort;
bool _overrideDomainID { false }; // should we override the domain-id from settings?
QUuid _overridingDomainID { QUuid() }; // what should we override it with?
};

View file

@ -3,7 +3,7 @@ set(TARGET_NAME gvr-interface)
if (ANDROID)
set(ANDROID_APK_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk-build")
set(ANDROID_APK_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk")
set(ANDROID_SDK_ROOT $ENV{ANDROID_HOME})
set(ANDROID_APP_DISPLAY_NAME Interface)
set(ANDROID_API_LEVEL 19)
@ -13,10 +13,10 @@ if (ANDROID)
set(ANDROID_APK_VERSION_CODE 1)
set(ANDROID_APK_FULLSCREEN TRUE)
set(ANDROID_DEPLOY_QT_INSTALL "--install")
set(BUILD_SHARED_LIBS ON)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}")
setup_hifi_library(Gui Widgets AndroidExtras)
else ()
setup_hifi_project(Gui Widgets)
@ -28,12 +28,12 @@ link_hifi_libraries(shared networking audio-client avatars)
if (ANDROID)
find_package(LibOVR)
if (LIBOVR_FOUND)
add_definitions(-DHAVE_LIBOVR)
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES} ${LIBOVR_ANDROID_LIBRARIES} ${TURBOJPEG_LIBRARY})
include_directories(SYSTEM ${LIBOVR_INCLUDE_DIRS})
# we need VRLib, so add a project.properties to our apk build folder that says that
file(RELATIVE_PATH RELATIVE_VRLIB_PATH ${ANDROID_APK_OUTPUT_DIR} "${LIBOVR_VRLIB_DIR}")
file(WRITE "${ANDROID_APK_BUILD_DIR}/project.properties" "android.library.reference.1=${RELATIVE_VRLIB_PATH}")
@ -50,7 +50,7 @@ if (ANDROID AND HOCKEY_APP_ID)
set(ANDROID_ACTIVITY_NAME io.highfidelity.gvrinterface.InterfaceBetaActivity)
set(ANDROID_DEPLOY_QT_INSTALL "")
set(ANDROID_APK_CUSTOM_NAME "Interface-beta.apk")
# set the ANDROID_APK_VERSION_CODE to the number of git commits
execute_process(
COMMAND git rev-list --first-parent --count HEAD
@ -58,16 +58,16 @@ if (ANDROID AND HOCKEY_APP_ID)
OUTPUT_VARIABLE GIT_COMMIT_COUNT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(ANDROID_APK_VERSION_CODE ${GIT_COMMIT_COUNT})
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/InterfaceBetaActivity.java.in" "${ANDROID_APK_BUILD_DIR}/src/io/highfidelity/gvrinterface/InterfaceBetaActivity.java")
elseif (ANDROID)
set(HOCKEY_APP_ENABLED false)
endif ()
if (ANDROID)
set(HIFI_URL_INTENT "<intent-filter>\
\n <action android:name='android.intent.action.VIEW' />\
\n <category android:name='android.intent.category.DEFAULT' />\
@ -75,13 +75,11 @@ if (ANDROID)
\n <data android:scheme='hifi' />\
\n </intent-filter>"
)
set(ANDROID_EXTRA_APPLICATION_XML "${HOCKEY_APP_ACTIVITY}")
set(ANDROID_EXTRA_ACTIVITY_XML "${HIFI_URL_INTENT}")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/hockeyapp.xml.in" "${ANDROID_APK_BUILD_DIR}/res/values/hockeyapp.xml")
qt_create_apk()
endif (ANDROID)
copy_dlls_beside_windows_executable()
endif (ANDROID)

View file

@ -213,6 +213,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) {
publicKeyURL.setPath(publicKeyPath);
QNetworkRequest publicKeyRequest { publicKeyURL };
publicKeyRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
publicKeyRequest.setAttribute(QNetworkRequest::User, domainID);
qDebug() << "Requesting public key for domain with ID" << domainID;

View file

@ -39,9 +39,18 @@ else ()
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
endif ()
find_package(Qt5 COMPONENTS
Gui Multimedia Network OpenGL Qml Quick Script ScriptTools Svg
WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets)
if (ANDROID)
set(PLATFORM_QT_COMPONENTS AndroidExtras)
else ()
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
endif ()
find_package(
Qt5 COMPONENTS
Gui Multimedia Network OpenGL Qml Quick Script Svg
${PLATFORM_QT_COMPONENTS}
WebChannel WebSockets
)
# grab the ui files in resources/ui
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
@ -57,6 +66,26 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
# set(TS ${TARGET_NAME}_en.ts)
# qt5_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS})
# setup the android parameters that will help us produce an APK
if (ANDROID)
set(ANDROID_APK_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk-build")
set(ANDROID_APK_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}")
set(ANDROID_SDK_ROOT $ENV{ANDROID_HOME})
set(ANDROID_APP_DISPLAY_NAME Interface)
set(ANDROID_API_LEVEL 19)
set(ANDROID_APK_PACKAGE io.highfidelity.interface)
set(ANDROID_ACTIVITY_NAME io.highfidelity.interface.InterfaceActivity)
set(ANDROID_APK_VERSION_NAME "0.1")
set(ANDROID_APK_VERSION_CODE 1)
set(ANDROID_APK_FULLSCREEN TRUE)
set(ANDROID_DEPLOY_QT_INSTALL "--install")
set(BUILD_SHARED_LIBS ON)
endif ()
if (APPLE)
# configure CMake to use a custom Info.plist
@ -94,8 +123,9 @@ if (APPLE)
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
# make sure the output name for the .app bundle is correct
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME})
elseif(WIN32)
# Fix up the rpath so macdeployqt works
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
elseif (WIN32)
# configure an rc file for the chosen icon
set(CONFIGURE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}")
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
@ -104,7 +134,7 @@ elseif(WIN32)
# add an executable that also has the icon itself and the configured rc file as resources
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT})
if ( NOT DEV_BUILD )
if (NOT DEV_BUILD)
add_custom_command(
TARGET ${TARGET_NAME}
POST_BUILD
@ -113,9 +143,12 @@ elseif(WIN32)
)
endif()
else()
elseif (ANDROID)
# on android the Interface target is a library that gets linked/used by the APK shell that qtcreateapk produces
add_library(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
else ()
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM})
endif()
endif ()
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes")
@ -126,6 +159,7 @@ if (WIN32)
add_dependency_external_projects(sdl2)
add_dependency_external_projects(OpenVR)
add_dependency_external_projects(neuron)
add_dependency_external_projects(wasapi)
endif()
# disable /OPT:REF and /OPT:ICF for the Debug builds
@ -135,21 +169,32 @@ if (WIN32)
set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF")
endif()
if (NOT ANDROID)
set(NON_ANDROID_LIBRARIES steamworks-wrapper)
endif ()
# link required hifi libraries
link_hifi_libraries(shared octree gpu gl gpu-gl procedural model render
recording fbx networking model-networking entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer ui auto-updater
controllers plugins ui-plugins display-plugins input-plugins steamworks-wrapper)
link_hifi_libraries(
shared octree gpu gl gpu-gl procedural model render
recording fbx networking model-networking entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer ui auto-updater
controllers plugins
ui-plugins display-plugins input-plugins
${NON_ANDROID_LIBRARIES}
)
# include the binary directory of render-utils for shader includes
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
#fixme find a way to express faceshift as a plugin
target_bullet()
target_glew()
target_opengl()
if (NOT ANDROID)
target_glew()
endif ()
if (WIN32 OR APPLE)
target_faceshift()
endif()
@ -198,16 +243,10 @@ include_directories("${PROJECT_SOURCE_DIR}/src")
target_link_libraries(
${TARGET_NAME}
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
Qt5::Qml Qt5::Quick Qt5::Script Qt5::ScriptTools Qt5::Svg
Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
Qt5::WebChannel Qt5::WebEngine
)
# Issue causes build failure unless we add this directory.
# See https://bugreports.qt.io/browse/QTBUG-43351
if (WIN32)
add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine)
endif()
if (UNIX)
target_link_libraries(${TARGET_NAME} pthread)
endif(UNIX)
@ -291,3 +330,17 @@ if (WIN32)
package_libraries_for_deployment()
endif()
if (ANDROID)
set(HIFI_URL_INTENT "<intent-filter>\
\n <action android:name='android.intent.action.VIEW' />\
\n <category android:name='android.intent.category.DEFAULT' />\
\n <category android:name='android.intent.category.BROWSABLE' />\
\n <data android:scheme='hifi' />\
\n </intent-filter>"
)
set(ANDROID_EXTRA_ACTIVITY_XML "${HIFI_URL_INTENT}")
qt_create_apk()
endif ()

View file

@ -0,0 +1,43 @@
//
// createGlobalEventBridge.js
//
// Created by Anthony J. Thibault on 9/7/2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Stick a EventBridge object in the global namespace.
var EventBridge;
(function () {
// the TempEventBridge class queues up emitWebEvent messages and executes them when the real EventBridge is ready.
// Similarly, it holds all scriptEventReceived callbacks, and hooks them up to the real EventBridge.
function TempEventBridge() {
var self = this;
this._callbacks = [];
this._messages = [];
this.scriptEventReceived = {
connect: function (callback) {
self._callbacks.push(callback);
}
};
this.emitWebEvent = function (message) {
self._messages.push(message);
};
};
EventBridge = new TempEventBridge();
var webChannel = new QWebChannel(qt.webChannelTransport, function (channel) {
// replace the TempEventBridge with the real one.
var tempEventBridge = EventBridge;
EventBridge = channel.objects.eventBridgeWrapper.eventBridge;
tempEventBridge._callbacks.forEach(function (callback) {
EventBridge.scriptEventReceived.connect(callback);
});
tempEventBridge._messages.forEach(function (message) {
EventBridge.emitWebEvent(message);
});
});
})();

View file

@ -0,0 +1,41 @@
//
// Created by Anthony Thibault on 2016-09-02
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Sends messages over the EventBridge when text input is required.
//
(function () {
var POLL_FREQUENCY = 500; // ms
var MAX_WARNINGS = 3;
var numWarnings = 0;
function shouldRaiseKeyboard() {
if (document.activeElement.nodeName == "INPUT" || document.activeElement.nodeName == "TEXTAREA") {
return true;
} else {
// check for contenteditable attribute
for (var i = 0; i < document.activeElement.attributes.length; i++) {
if (document.activeElement.attributes[i].name === "contenteditable" &&
document.activeElement.attributes[i].value === "true") {
return true;
}
}
return false;
}
};
setInterval(function () {
var event = shouldRaiseKeyboard() ? "_RAISE_KEYBOARD" : "_LOWER_KEYBOARD";
if (typeof EventBridge != "undefined") {
EventBridge.emitWebEvent(event);
} else {
if (numWarnings < MAX_WARNINGS) {
console.log("WARNING: no global EventBridge object found");
numWarnings++;
}
}
}, POLL_FREQUENCY);
})();

View file

@ -9,10 +9,10 @@
.st1{fill:#E6E7E8;}
.st2{fill:#FFFFFF;}
</style>
<path class="st0" d="M1428.61,172H11.46c-6.27,0-11.39-5.13-11.39-11.39V49.58c0-6.27,5.13-11.39,11.39-11.39h1417.15
c6.27,0,11.39,5.13,11.39,11.39v111.03C1440,166.87,1434.87,172,1428.61,172z"/>
<path class="st1" d="M1428.61,165.81H11.46c-6.27,0-11.39-5.13-11.39-11.39V43.39c0-6.27,5.13-11.39,11.39-11.39h1417.15
c6.27,0,11.39,5.13,11.39,11.39v111.03C1440,160.68,1434.87,165.81,1428.61,165.81z"/>
<path class="st2" d="M1133.24,165.81H417.95c-4.47,0-8.12-3.65-8.12-8.12V40.11c0-4.47,3.65-8.12,8.12-8.12h715.28
c4.47,0,8.12,3.65,8.12,8.12v117.57C1141.36,162.15,1137.7,165.81,1133.24,165.81z"/>
<path class="st0" d="M1428.6,172H11.5c-6.3,0-11.4-5.1-11.4-11.4v-111c0-6.3,5.1-11.4,11.4-11.4h1417.2c6.3,0,11.4,5.1,11.4,11.4
v111C1440,166.9,1434.9,172,1428.6,172z"/>
<path class="st1" d="M1428.6,165.8H11.5c-6.3,0-11.4-5.1-11.4-11.4v-111C0.1,37.1,5.2,32,11.5,32h1417.2c6.3,0,11.4,5.1,11.4,11.4
v111C1440,160.7,1434.9,165.8,1428.6,165.8z"/>
<path class="st2" d="M1429.9,165.8H421.3c-6.3,0-11.5-3.6-11.5-8.1V40.1c0-4.5,5.1-8.1,11.5-8.1h1008.6c6.3,0,11.5,3.7,11.5,8.1
v117.6C1441.4,162.1,1436.2,165.8,1429.9,165.8z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 32 64" style="enable-background:new 0 0 32 64;" xml:space="preserve">
<style type="text/css">
.st0{fill:#168DB7;}
.st1{fill:#FFFFFF;}
.st2{opacity:0.63;fill:#58595B;enable-background:new ;}
</style>
<circle cx="15.8" cy="48.2" r="14.7"/>
<circle class="st0" cx="15.8" cy="47.6" r="14.7"/>
<circle cx="16.1" cy="44.9" r="3"/>
<path d="M18.2,50.2H14c-1.7,0-3.1,1.5-3.1,3.2V55c1.4,1.1,3.1,1.7,4.9,1.7c2.1,0,4-0.8,5.4-2.1v-1.2C21.3,51.7,19.9,50.2,18.2,50.2z
"/>
<circle cx="22.9" cy="44.9" r="1.6"/>
<path d="M24,47.9h-1.8c-0.4,0-0.8,0.2-1,0.4c0.5,0.3,1,0.7,1.4,1.1c0.5,0.5,0.7,1.2,0.7,1.9c0.1,0.4,0.1,0.8,0.1,1.2v0.3
c0.8-1,1.5-2.7,1.8-3.6v-0.1C25.2,48.8,24.6,47.9,24,47.9z"/>
<circle cx="9.1" cy="45.2" r="1.6"/>
<path d="M8.7,53.2c0-0.3,0-0.6,0-0.9v-0.1c0-0.1,0-0.2,0-0.3s0-0.1,0-0.2c0-0.1,0-0.1,0-0.2c0.1-0.9,0.7-2,1.4-2.5
c0.2-0.2,0.4-0.3,0.6-0.4c-0.2-0.2-0.6-0.3-0.9-0.3H8c-0.6,0-1.2,0.8-1.1,1.2v0.1C7.2,50.6,7.9,52.3,8.7,53.2z"/>
<circle class="st1" cx="16.1" cy="44.3" r="3"/>
<path class="st1" d="M18.2,49.6H14c-1.7,0-3.1,1.5-3.1,3.2v1.6c1.4,1.1,3.1,1.7,4.9,1.7c2.1,0,4-0.8,5.4-2.1v-1.2
C21.3,51.1,19.9,49.6,18.2,49.6z"/>
<circle class="st1" cx="22.9" cy="44.4" r="1.6"/>
<path class="st1" d="M24,47.4h-1.8c-0.4,0-0.8,0.2-1,0.4c0.5,0.3,1,0.7,1.4,1.1c0.5,0.5,0.7,1.2,0.7,1.9c0.1,0.4,0.1,0.8,0.1,1.2
v0.3c0.8-1,1.5-2.7,1.8-3.6v-0.1C25.2,48.2,24.6,47.4,24,47.4z"/>
<circle class="st1" cx="9.1" cy="44.6" r="1.6"/>
<path class="st1" d="M8.7,52.7c0-0.3,0-0.6,0-0.9v-0.1c0-0.1,0-0.2,0-0.3s0-0.1,0-0.2c0-0.1,0-0.1,0-0.2c0.1-0.9,0.7-2,1.4-2.5
c0.2-0.2,0.4-0.3,0.6-0.4c-0.2-0.2-0.6-0.3-0.9-0.3H8c-0.6,0-1.2,0.8-1.1,1.2v0.1C7.2,50,7.9,51.7,8.7,52.7z"/>
<path d="M15.9,3.4c-7,0-12.7,5.7-12.7,12.7s5.7,12.7,12.7,12.7s12.7-5.7,12.7-12.7S22.9,3.4,15.9,3.4z M15.9,27.2
c-6.1,0-11.1-5-11.1-11.1S9.8,5,15.9,5C22,4.9,27,9.9,27,16.1C27,22.2,22,27.2,15.9,27.2z"/>
<circle class="st2" cx="15.9" cy="15.5" r="12.4"/>
<path class="st1" d="M15.9,2.8c-7,0-12.7,5.7-12.7,12.7s5.7,12.7,12.7,12.7s12.7-5.7,12.7-12.7S22.9,2.8,15.9,2.8z M15.9,26.6
c-6.1,0-11.1-5-11.1-11.1s5-11.1,11.1-11.1C22,4.4,27,9.4,27,15.5S22,26.6,15.9,26.6z"/>
<circle cx="16.1" cy="12.9" r="3"/>
<path d="M18.2,18.2H14c-1.7,0-3.1,1.5-3.1,3.2V23c1.4,1.1,3.1,1.7,4.9,1.7c2.1,0,4-0.8,5.4-2.1v-1.2C21.3,19.7,19.9,18.2,18.2,18.2z
"/>
<circle cx="22.9" cy="12.9" r="1.6"/>
<path d="M24,15.9h-1.8c-0.4,0-0.8,0.2-1,0.4c0.5,0.3,1,0.7,1.4,1.1c0.5,0.5,0.7,1.2,0.7,1.9c0.1,0.4,0.1,0.8,0.1,1.2v0.3
c0.8-1,1.5-2.7,1.8-3.6v-0.1C25.2,16.8,24.6,15.9,24,15.9z"/>
<circle cx="9.1" cy="13.2" r="1.6"/>
<path d="M8.7,21.2c0-0.3,0-0.6,0-0.9v-0.1c0-0.1,0-0.2,0-0.3c0-0.1,0-0.1,0-0.2s0-0.1,0-0.2c0.1-0.9,0.7-2,1.4-2.5
c0.2-0.2,0.4-0.3,0.6-0.4c-0.2-0.2-0.6-0.3-0.9-0.3H8c-0.6,0-1.2,0.8-1.1,1.2v0.1C7.2,18.6,7.9,20.2,8.7,21.2z"/>
<circle class="st1" cx="16.1" cy="12.3" r="3"/>
<path class="st1" d="M18.2,17.6H14c-1.7,0-3.1,1.5-3.1,3.2v1.6c1.4,1.1,3.1,1.7,4.9,1.7c2.1,0,4-0.8,5.4-2.1v-1.2
C21.3,19.1,19.9,17.6,18.2,17.6z"/>
<circle class="st1" cx="22.9" cy="12.4" r="1.6"/>
<path class="st1" d="M24,15.4h-1.8c-0.4,0-0.8,0.2-1,0.4c0.5,0.3,1,0.7,1.4,1.1c0.5,0.5,0.7,1.2,0.7,1.9c0.1,0.4,0.1,0.8,0.1,1.2
v0.3c0.8-1,1.5-2.7,1.8-3.6v-0.1C25.2,16.2,24.6,15.4,24,15.4z"/>
<circle class="st1" cx="9.1" cy="12.6" r="1.6"/>
<path class="st1" d="M8.7,20.7c0-0.3,0-0.6,0-0.9v-0.1c0-0.1,0-0.2,0-0.3c0-0.1,0-0.1,0-0.2s0-0.1,0-0.2c0.1-0.9,0.7-2,1.4-2.5
c0.2-0.2,0.4-0.3,0.6-0.4c-0.2-0.2-0.6-0.3-0.9-0.3H8c-0.6,0-1.2,0.8-1.1,1.2v0.1C7.2,18,7.9,19.7,8.7,20.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 32 64" style="enable-background:new 0 0 32 64;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.64;fill:#58595B;}
.st1{fill:#FFFFFF;}
.st2{fill:#168DB7;}
</style>
<circle class="st0" cx="15.8" cy="15.5" r="12.5"/>
<path d="M15.8,3.4c-7,0-12.7,5.7-12.7,12.7s5.7,12.7,12.7,12.7c7,0,12.7-5.7,12.7-12.7S22.8,3.4,15.8,3.4z M15.8,27.3
c-6.2,0-11.2-5-11.2-11.2C4.6,10,9.7,5,15.8,5C22,5,27,10,27,16.1C27,22.3,22,27.3,15.8,27.3z"/>
<path class="st1" d="M15.8,2.8c-7,0-12.7,5.7-12.7,12.7s5.7,12.7,12.7,12.7c7,0,12.7-5.7,12.7-12.7S22.8,2.8,15.8,2.8z M15.8,26.7
c-6.2,0-11.2-5-11.2-11.2c0-6.2,5-11.2,11.2-11.2C22,4.4,27,9.4,27,15.6C27,21.7,22,26.7,15.8,26.7z"/>
<path d="M21.5,11.6H20V11c0-1-0.6-1.2-1.6-1.2h-5c-1,0-1.5,0.2-1.5,1.2v0.6h-1.5c-1,0-1.9,0.4-1.9,1.4v6.6c0,1,0.8,1.9,1.9,1.9h11
c1,0,1.7-1.1,1.7-2.1V13C23.3,12,22.5,11.6,21.5,11.6z M16.1,20.1c-2.3,0-4-1.8-4-4c0-2.3,1.8-4,4-4c2.3,0,4,1.8,4,4
S18.4,20.1,16.1,20.1z"/>
<circle cx="16.1" cy="16" r="2.4"/>
<path class="st1" d="M21.5,11H20v-0.6c0-1-0.6-1.2-1.6-1.2h-5c-1,0-1.5,0.2-1.5,1.2V11h-1.5c-1,0-1.9,0.4-1.9,1.4v6.6
c0,1,0.8,1.9,1.9,1.9h11c1,0,1.7-1.1,1.7-2.1v-6.4C23.3,11.5,22.5,11,21.5,11z M16.1,19.5c-2.3,0-4-1.8-4-4c0-2.3,1.8-4,4-4
c2.3,0,4,1.8,4,4S18.4,19.5,16.1,19.5z"/>
<circle class="st1" cx="16.1" cy="15.5" r="2.4"/>
<circle cx="15.8" cy="48.2" r="14.8"/>
<circle class="st2" cx="15.8" cy="47.6" r="14.8"/>
<path d="M21.5,43.6H20V43c0-1-0.6-1.2-1.6-1.2h-5c-1,0-1.5,0.2-1.5,1.2v0.6h-1.5c-1,0-1.9,0.4-1.9,1.4v6.6c0,1,0.8,1.9,1.9,1.9h11
c1,0,1.7-1.1,1.7-2.1V45C23.3,44.1,22.5,43.6,21.5,43.6z M16.1,52.1c-2.3,0-4-1.8-4-4c0-2.3,1.8-4,4-4c2.3,0,4,1.8,4,4
C20.1,50.2,18.4,52.1,16.1,52.1z"/>
<circle cx="16.1" cy="48" r="2.4"/>
<path class="st1" d="M21.5,43.1H20v-0.6c0-1-0.6-1.2-1.6-1.2h-5c-1,0-1.5,0.2-1.5,1.2v0.6h-1.5c-1,0-1.9,0.4-1.9,1.4v6.6
c0,1,0.8,1.9,1.9,1.9h11c1,0,1.7-1.1,1.7-2.1v-6.4C23.3,43.5,22.5,43.1,21.5,43.1z M16.1,51.5c-2.3,0-4-1.8-4-4c0-2.3,1.8-4,4-4
c2.3,0,4,1.8,4,4C20.1,49.7,18.4,51.5,16.1,51.5z"/>
<circle class="st1" cx="16.1" cy="47.5" r="2.4"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -50,16 +50,15 @@ Window {
function resetAfterTeleport() {
storyCardFrame.shown = root.shown = false;
}
function goCard(card) {
if (addressBarDialog.useFeed) {
storyCardHTML.url = addressBarDialog.metaverseServerUrl + "/user_stories/" + card.storyId;
function goCard(targetString) {
if (0 !== targetString.indexOf('hifi://')) {
storyCardHTML.url = addressBarDialog.metaverseServerUrl + targetString;
storyCardFrame.shown = true;
return;
}
addressLine.text = card.hifiUrl;
addressLine.text = targetString;
toggleOrGo(true);
}
property var allPlaces: [];
property var allStories: [];
property int cardWidth: 200;
property int cardHeight: 152;
@ -72,7 +71,6 @@ Window {
// The buttons have their button state changed on hover, so we have to manually fix them up here
onBackEnabledChanged: backArrow.buttonState = addressBarDialog.backEnabled ? 1 : 0;
onForwardEnabledChanged: forwardArrow.buttonState = addressBarDialog.forwardEnabled ? 1 : 0;
onUseFeedChanged: updateFeedState();
onReceivedHifiSchemeURL: resetAfterTeleport();
ListModel { id: suggestions }
@ -97,7 +95,6 @@ Window {
userName: model.username;
placeName: model.place_name;
hifiUrl: model.place_name + model.path;
imageUrl: model.image_url;
thumbnail: model.thumbnail_url;
action: model.action;
timestamp: model.created_at;
@ -135,7 +132,10 @@ Window {
buttonState: 1
defaultState: 1
hoverState: 2
onClicked: addressBarDialog.loadHome();
onClicked: {
addressBarDialog.loadHome();
root.shown = false;
}
anchors {
left: parent.left
leftMargin: homeButton.width / 2
@ -176,9 +176,9 @@ Window {
top: parent.top
bottom: parent.bottom
left: forwardArrow.right
right: placesButton.left
right: parent.right
leftMargin: forwardArrow.width
rightMargin: placesButton.width
rightMargin: forwardArrow.width / 2
topMargin: parent.inputAreaStep + hifi.layout.spacing
bottomMargin: parent.inputAreaStep + hifi.layout.spacing
}
@ -188,32 +188,6 @@ Window {
helperItalic: true
onTextChanged: filterChoicesByText()
}
// These two are radio buttons.
ToolbarButton {
id: placesButton
imageURL: "../images/places.svg"
buttonState: 1
defaultState: addressBarDialog.useFeed ? 0 : 1;
hoverState: addressBarDialog.useFeed ? 2 : -1;
onClicked: addressBarDialog.useFeed ? toggleFeed() : identity()
anchors {
right: feedButton.left;
bottom: addressLine.bottom;
}
}
ToolbarButton {
id: feedButton;
imageURL: "../images/snap-feed.svg";
buttonState: 0
defaultState: addressBarDialog.useFeed ? 1 : 0;
hoverState: addressBarDialog.useFeed ? -1 : 2;
onClicked: addressBarDialog.useFeed ? identity() : toggleFeed();
anchors {
right: parent.right;
bottom: addressLine.bottom;
rightMargin: feedButton.width / 2
}
}
}
Window {
@ -237,16 +211,6 @@ Window {
}
}
function toggleFeed() {
addressBarDialog.useFeed = !addressBarDialog.useFeed;
updateFeedState();
}
function updateFeedState() {
placesButton.buttonState = addressBarDialog.useFeed ? 0 : 1;
feedButton.buttonState = addressBarDialog.useFeed ? 1 : 0;
filterChoicesByText();
}
function getRequest(url, cb) { // cb(error, responseOfCorrectContentType) of url. General for 'get' text/html/json, but without redirects.
// TODO: make available to other .qml.
var request = new XMLHttpRequest();
@ -271,37 +235,6 @@ Window {
request.open("GET", url, true);
request.send();
}
function asyncMap(array, iterator, cb) {
// call iterator(element, icb) once for each element of array, and then cb(error, mappedResult)
// when icb(error, mappedElement) has been called by each iterator.
// Calls to iterator are overlapped and may call icb in any order, but the mappedResults are collected in the same
// order as the elements of the array.
// Short-circuits if error. Note that iterator MUST be an asynchronous function. (Use setTimeout if necessary.)
var count = array.length, results = [];
if (!count) {
return cb(null, results);
}
array.forEach(function (element, index) {
if (count < 0) { // don't keep iterating after we short-circuit
return;
}
iterator(element, function (error, mapped) {
results[index] = mapped;
if (error || !--count) {
count = 0; // don't cb multiple times if error
cb(error, results);
}
});
});
}
// Example:
/*asyncMap([0, 1, 2, 3, 4, 5, 6], function (elt, icb) {
console.log('called', elt);
setTimeout(function () {
console.log('answering', elt);
icb(null, elt);
}, Math.random() * 1000);
}, console.log); */
function identity(x) {
return x;
@ -321,131 +254,61 @@ Window {
cb(error);
return true;
}
function getPlace(placeData, cb) { // cb(error, side-effected-placeData), after adding path, thumbnails, and description
var url = metaverseBase + 'places/' + placeData.place_name;
getRequest(url, function (error, data) {
if (handleError(url, error, data, cb)) {
return;
}
var place = data.data.place, previews = place.previews;
placeData.path = place.path;
if (previews && previews.thumbnail) {
placeData.thumbnail_url = previews.thumbnail;
}
if (place.description) {
placeData.description = place.description;
placeData.searchText += ' ' + place.description.toUpperCase();
}
cb(error, placeData);
});
function resolveUrl(url) {
return (url.indexOf('/') === 0) ? (addressBarDialog.metaverseServerUrl + url) : url;
}
function makeModelData(data, optionalPlaceName) { // create a new obj from data
function makeModelData(data) { // create a new obj from data
// ListModel elements will only ever have those properties that are defined by the first obj that is added.
// So here we make sure that we have all the properties we need, regardless of whether it is a place data or user story.
var name = optionalPlaceName || data.place_name,
var name = data.place_name,
tags = data.tags || [data.action, data.username],
description = data.description || "",
thumbnail_url = data.thumbnail_url || "",
image_url = thumbnail_url;
if (data.details) {
try {
image_url = JSON.parse(data.details).image_url || thumbnail_url;
} catch (e) {
console.log(name, "has bad details", data.details);
}
}
thumbnail_url = data.thumbnail_url || "";
return {
place_name: name,
username: data.username || "",
path: data.path || "",
created_at: data.created_at || "",
action: data.action || "",
thumbnail_url: thumbnail_url,
image_url: image_url,
thumbnail_url: resolveUrl(thumbnail_url),
metaverseId: (data.id || "").toString(), // Some are strings from server while others are numbers. Model objects require uniformity.
tags: tags,
description: description,
online_users: data.online_users || 0,
online_users: data.details.concurrency || 0,
searchText: [name].concat(tags, description || []).join(' ').toUpperCase()
}
}
function mapDomainPlaces(domain, cb) { // cb(error, arrayOfDomainPlaceData)
function addPlace(name, icb) {
getPlace(makeModelData(domain, name), icb);
}
// IWBNI we could get these results in order with most-recent-entered first.
// In any case, we don't really need to preserve the domain.names order in the results.
asyncMap(domain.names || [], addPlace, cb);
}
function suggestable(place) {
if (addressBarDialog.useFeed) {
if (place.action === 'snapshot') {
return true;
}
return (place.place_name !== AddressManager.hostname) // Not our entry, but do show other entry points to current domain.
&& place.thumbnail_url
&& place.online_users // at least one present means it's actually online
&& place.online_users <= 20;
}
function getDomainPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model
// Each page of results is processed completely before we start on the next page.
// For each page of domains, we process each domain in parallel, and for each domain, process each place name in parallel.
// This gives us minimum latency within the page, but we do preserve the order within the page by using asyncMap and
// only appending the collected results.
var params = [
'open', // published hours handle now
// TBD: should determine if place is actually running?
'restriction=open', // Not by whitelist, etc. TBD: If logged in, add hifi to the restriction options, in order to include places that require login?
// TBD: add maturity?
'protocol=' + encodeURIComponent(AddressManager.protocolVersion()),
'sort_by=users',
'sort_order=desc',
'page=' + pageNumber
];
var url = metaverseBase + 'domains/all?' + params.join('&');
getRequest(url, function (error, data) {
if (handleError(url, error, data, cb)) {
return;
}
asyncMap(data.data.domains, mapDomainPlaces, function (error, pageResults) {
if (error) {
return cb(error);
}
// pageResults is now [ [ placeDataOneForDomainOne, placeDataTwoForDomainOne, ...], [ placeDataTwoForDomainTwo...] ]
pageResults.forEach(function (domainResults) {
allPlaces = allPlaces.concat(domainResults);
if (!addressLine.text && !addressBarDialog.useFeed) { // Don't add if the user is already filtering
domainResults.forEach(function (place) {
if (suggestable(place)) {
suggestions.append(place);
}
});
}
});
if (data.current_page < data.total_pages) {
return getDomainPage(pageNumber + 1, cb);
}
cb();
});
});
return (place.place_name !== AddressManager.hostname); // Not our entry, but do show other entry points to current domain.
// could also require right protocolVersion
}
function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model
var url = metaverseBase + 'user_stories?page=' + pageNumber;
var options = [
'include_actions=snapshot,concurrency',
'protocol=' + encodeURIComponent(AddressManager.protocolVersion()),
'page=' + pageNumber
];
var url = metaverseBase + 'user_stories?' + options.join('&');
getRequest(url, function (error, data) {
if (handleError(url, error, data, cb)) {
return;
}
var stories = data.user_stories.map(function (story) { // explicit single-argument function
return makeModelData(story);
return makeModelData(story, url);
});
allStories = allStories.concat(stories);
if (!addressLine.text && addressBarDialog.useFeed) { // Don't add if the user is already filtering
if (!addressLine.text) { // Don't add if the user is already filtering
stories.forEach(function (story) {
suggestions.append(story);
if (suggestable(story)) {
suggestions.append(story);
}
});
}
if ((data.current_page < data.total_pages) && (data.current_page <= 10)) { // just 10 pages = 100 stories for now
@ -457,7 +320,7 @@ Window {
function filterChoicesByText() {
suggestions.clear();
var words = addressLine.text.toUpperCase().split(/\s+/).filter(identity),
data = addressBarDialog.useFeed ? allStories : allPlaces;
data = allStories;
function matches(place) {
if (!words.length) {
return suggestable(place);
@ -474,12 +337,8 @@ Window {
}
function fillDestinations() {
allPlaces = [];
allStories = [];
suggestions.clear();
getDomainPage(1, function (error) {
console.log('domain query', error || 'ok', allPlaces.length);
});
getUserStoryPage(1, function (error) {
console.log('user stories query', error || 'ok', allStories.length);
});

View file

@ -1,6 +1,6 @@
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtWebEngine 1.1
import QtWebEngine 1.2
import "controls-uit"
import "styles" as HifiStyles
@ -223,12 +223,15 @@ ScrollingWindow {
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView)
}
Component.onCompleted: {
desktop.initWebviewProfileHandlers(webview.profile)
}
onWindowCloseRequested: {
root.destroy();
}
//profile: desktop.browserProfile
Component.onCompleted: {
desktop.initWebviewProfileHandlers(webview.profile)
}
profile: desktop.browserProfile
}
} // item
@ -245,4 +248,4 @@ ScrollingWindow {
break;
}
}
} // dialog
} // dialog

View file

@ -1,103 +0,0 @@
//
// MarketplaceComboBox.qml
//
// Created by Elisa Lupin-Jimenez on 3 Aug 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebChannel 1.0
import QtWebEngine 1.1
import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "controls"
import "controls-uit" as Controls
import "styles"
import "styles-uit"
Rectangle {
HifiConstants { id: hifi }
id: marketplaceComboBox
anchors.fill: parent
color: hifi.colors.baseGrayShadow
property var currentUrl: "https://metaverse.highfidelity.com/marketplace"
Controls.BaseWebView {
id: webview
url: currentUrl
anchors.top: switchMarketView.bottom
width: parent.width
height: parent.height - 40
focus: true
Timer {
id: zipTimer
running: false
repeat: false
interval: 1500
property var handler;
onTriggered: handler();
}
property var autoCancel: 'var element = $("a.btn.cancel");
element.click();'
onNewViewRequested: {
var component = Qt.createComponent("Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
if (File.isZippedFbx(desktop.currentUrl)) {
zipTimer.handler = function() {
newWindow.destroy();
runJavaScript(autoCancel);
}
zipTimer.start();
}
}
property var simpleDownload: 'var element = $("a.download-file");
element.removeClass("download-file");
element.removeAttr("download");'
onLinkHovered: {
desktop.currentUrl = hoveredUrl;
// add an error message for non-fbx files
if (File.isZippedFbx(desktop.currentUrl)) {
runJavaScript(simpleDownload, function(){console.log("ran the JS");});
}
}
}
Controls.ComboBox {
id: switchMarketView
anchors.top: parent.top
anchors.right: parent.right
colorScheme: hifi.colorSchemes.dark
width: 200
height: 40
visible: true
model: ["Marketplace", "Clara.io"]
onCurrentIndexChanged: {
if (currentIndex === 0) { webview.url = "https://metaverse.highfidelity.com/marketplace"; }
if (currentIndex === 1) { webview.url = "https://clara.io/library"; }
}
}
Controls.Label {
id: switchMarketLabel
anchors.verticalCenter: switchMarketView.verticalCenter
anchors.right: switchMarketView.left
color: hifi.colors.white
text: "Explore interesting content from: "
}
}

View file

@ -0,0 +1,167 @@
//
// Marketplaces.qml
//
// Created by Elisa Lupin-Jimenez on 3 Aug 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebChannel 1.0
import QtWebEngine 1.1
import QtWebSockets 1.0
import "qrc:///qtwebchannel/qwebchannel.js" as WebChannel
import "controls"
import "controls-uit" as Controls
import "styles"
import "styles-uit"
Rectangle {
HifiConstants { id: hifi }
id: marketplace
anchors.fill: parent
property var marketplacesUrl: "../../scripts/system/html/marketplaces.html"
property int statusBarHeight: 50
property int statusMargin: 50
property string standardMessage: "Check out other marketplaces."
property string claraMessage: "Choose a model and click Download -> Autodesk FBX."
property string claraError: "High Fidelity only supports Autodesk FBX models."
Controls.BaseWebView {
id: webview
url: marketplacesUrl
anchors.top: marketplace.top
width: parent.width
height: parent.height - statusBarHeight
focus: true
Timer {
id: zipTimer
running: false
repeat: false
interval: 1500
property var handler;
onTriggered: handler();
}
Timer {
id: alertTimer
running: false
repeat: false
interval: 9000
property var handler;
onTriggered: handler();
}
property var autoCancel: 'var element = $("a.btn.cancel");
element.click();'
property var simpleDownload: 'var element = $("a.download-file");
element.removeClass("download-file");
element.removeAttr("download");'
function displayErrorStatus() {
alertTimer.handler = function() {
statusLabel.text = claraMessage;
statusBar.color = hifi.colors.blueHighlight;
statusIcon.text = hifi.glyphs.info;
}
alertTimer.start();
}
property var notFbxHandler: 'var element = $("a.btn.btn-primary.viewer-button.download-file")
element.click();'
// this code is for removing other file types from Clara.io's download options
//property var checkFileType: "$('[data-extension]:not([data-extension=\"fbx\"])').parent().remove()"
onLinkHovered: {
desktop.currentUrl = hoveredUrl;
//runJavaScript(checkFileType, function(){console.log("Remove filetypes JS injection");});
if (File.isZippedFbx(desktop.currentUrl)) {
runJavaScript(simpleDownload, function(){console.log("Download JS injection");});
return;
}
if (File.isZipped(desktop.currentUrl)) {
statusLabel.text = claraError;
statusBar.color = hifi.colors.redHighlight;
statusIcon.text = hifi.glyphs.alert;
runJavaScript(notFbxHandler, displayErrorStatus());
}
}
onLoadingChanged: {
if (File.isClaraLink(webview.url)) {
statusLabel.text = claraMessage;
} else {
statusLabel.text = standardMessage;
}
statusBar.color = hifi.colors.blueHighlight;
statusIcon.text = hifi.glyphs.info;
}
onNewViewRequested: {
var component = Qt.createComponent("Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
if (File.isZippedFbx(desktop.currentUrl)) {
runJavaScript(autoCancel);
zipTimer.handler = function() {
newWindow.destroy();
}
zipTimer.start();
}
}
}
Rectangle {
id: statusBar
anchors.top: webview.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: hifi.colors.blueHighlight
Controls.Button {
id: switchMarketView
anchors.right: parent.right
anchors.rightMargin: statusMargin
anchors.verticalCenter: parent.verticalCenter
width: 150
text: "See all markets"
onClicked: {
webview.url = "../../scripts/system/html/marketplaces.html";
statusLabel.text = standardMessage;
}
}
Controls.Label {
id: statusLabel
anchors.verticalCenter: switchMarketView.verticalCenter
anchors.left: parent.left
anchors.leftMargin: statusMargin
color: hifi.colors.white
text: standardMessage
size: 18
}
HiFiGlyphs {
id: statusIcon
anchors.right: statusLabel.left
anchors.verticalCenter: statusLabel.verticalCenter
text: hifi.glyphs.info
color: hifi.colors.white
size: hifi.fontSizes.tableHeadingIcon
}
}
}

View file

@ -59,6 +59,11 @@ Item {
font.pixelSize: root.fontSize
text: "Avatars: " + root.avatarCount
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Frame Rate: " + root.framerate.toFixed(2);
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize

View file

@ -154,7 +154,6 @@ ScrollingWindow {
return i;
}
}
console.warn("Could not find tab for " + source);
return -1;
}
@ -189,7 +188,6 @@ ScrollingWindow {
return i;
}
}
console.warn("Could not find free tab");
return -1;
}
@ -216,7 +214,6 @@ ScrollingWindow {
var existingTabIndex = findIndexForUrl(properties.source);
if (existingTabIndex >= 0) {
console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source);
var tab = tabView.getTab(existingTabIndex);
return tab.item;
}
@ -239,16 +236,13 @@ ScrollingWindow {
var tab = tabView.getTab(freeTabIndex);
tab.title = properties.title || "Unknown";
tab.enabled = true;
console.log("New tab URL: " + properties.source)
tab.originalUrl = properties.source;
var eventBridge = properties.eventBridge;
console.log("Event bridge: " + eventBridge);
var result = tab.item;
result.enabled = true;
tabView.tabCount++;
console.log("Setting event bridge: " + eventBridge);
result.eventBridgeWrapper.eventBridge = eventBridge;
result.url = properties.source;
return result;

View file

@ -15,7 +15,7 @@ WebEngineView {
id: root
property var newUrl;
profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)"
profile: desktop.browserProfile
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")
@ -60,9 +60,4 @@ WebEngineView {
}
}
}
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
// See https://bugreports.qt.io/browse/QTBUG-49521
//profile: desktop.browserProfile
}

View file

@ -0,0 +1,164 @@
import QtQuick 2.0
Item {
id: keyItem
width: 45
height: 50
property string glyph: "a"
property bool toggle: false // does this button have the toggle behaivor?
property bool toggled: false // is this button currently toggled?
property alias mouseArea: mouseArea1
function resetToggledMode(mode) {
toggled = mode;
if (toggled) {
state = "mouseDepressed";
} else {
state = "";
}
}
MouseArea {
id: mouseArea1
width: 36
anchors.fill: parent
hoverEnabled: true
onCanceled: {
if (toggled) {
keyItem.state = "mouseDepressed";
} else {
keyItem.state = "";
}
}
onClicked: {
mouse.accepted = true;
webEntity.synthesizeKeyPress(glyph);
if (toggle) {
toggled = !toggled;
}
}
onDoubleClicked: {
mouse.accepted = true;
}
onEntered: {
keyItem.state = "mouseOver";
}
onExited: {
if (toggled) {
keyItem.state = "mouseDepressed";
} else {
keyItem.state = "";
}
}
onPressed: {
keyItem.state = "mouseClicked";
mouse.accepted = true;
}
onReleased: {
if (containsMouse) {
keyItem.state = "mouseOver";
} else {
if (toggled) {
keyItem.state = "mouseDepressed";
} else {
keyItem.state = "";
}
}
mouse.accepted = true;
}
}
Rectangle {
id: roundedRect
width: 30
color: "#121212"
radius: 2
border.color: "#00000000"
anchors.right: parent.right
anchors.rightMargin: 4
anchors.left: parent.left
anchors.leftMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
anchors.top: parent.top
anchors.topMargin: 4
}
Text {
id: letter
y: 6
width: 50
color: "#ffffff"
text: glyph
style: Text.Normal
font.family: "Tahoma"
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.top: parent.top
anchors.topMargin: 8
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 28
}
states: [
State {
name: "mouseOver"
PropertyChanges {
target: roundedRect
color: "#121212"
radius: 3
border.width: 2
border.color: "#00b4ef"
}
PropertyChanges {
target: letter
color: "#00b4ef"
style: Text.Normal
}
},
State {
name: "mouseClicked"
PropertyChanges {
target: roundedRect
color: "#1080b8"
border.width: 2
border.color: "#00b4ef"
}
PropertyChanges {
target: letter
color: "#121212"
styleColor: "#00000000"
style: Text.Normal
}
},
State {
name: "mouseDepressed"
PropertyChanges {
target: roundedRect
color: "#0578b1"
border.width: 0
}
PropertyChanges {
target: letter
color: "#121212"
styleColor: "#00000000"
style: Text.Normal
}
}
]
}

View file

@ -0,0 +1,390 @@
import QtQuick 2.0
Item {
id: keyboardBase
height: 200
property alias shiftKey: key27
property bool shiftMode: false
function resetShiftMode(mode) {
shiftMode = mode;
shiftKey.resetToggledMode(mode);
}
function toUpper(str) {
if (str === ",") {
return "<";
} else if (str === ".") {
return ">";
} else if (str === "/") {
return "?";
} else {
return str.toUpperCase(str);
}
}
function toLower(str) {
if (str === "<") {
return ",";
} else if (str === ">") {
return ".";
} else if (str === "?") {
return "/";
} else {
return str.toLowerCase(str);
}
}
function forEachKey(func) {
var i, j;
for (i = 0; i < column1.children.length; i++) {
var row = column1.children[i];
for (j = 0; j < row.children.length; j++) {
var key = row.children[j];
func(key);
}
}
}
onShiftModeChanged: {
forEachKey(function (key) {
if (shiftMode) {
key.glyph = keyboardBase.toUpper(key.glyph);
} else {
key.glyph = keyboardBase.toLower(key.glyph);
}
});
}
function alphaKeyClickedHandler(mouseArea) {
// reset shift mode to false after first keypress
if (shiftMode) {
resetShiftMode(false);
}
}
Component.onCompleted: {
// hook up callbacks to every ascii key
forEachKey(function (key) {
if (/^[a-z]+$/i.test(key.glyph)) {
key.mouseArea.onClicked.connect(alphaKeyClickedHandler);
}
});
}
Rectangle {
id: leftRect
y: 0
height: 200
color: "#252525"
anchors.right: keyboardRect.left
anchors.rightMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
}
Rectangle {
id: keyboardRect
x: 206
y: 0
width: 480
height: 200
color: "#252525"
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
Column {
id: column1
width: 480
height: 200
Row {
id: row1
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 0
Key {
id: key1
width: 44
glyph: "q"
}
Key {
id: key2
width: 44
glyph: "w"
}
Key {
id: key3
width: 44
glyph: "e"
}
Key {
id: key4
width: 43
glyph: "r"
}
Key {
id: key5
width: 43
glyph: "t"
}
Key {
id: key6
width: 44
glyph: "y"
}
Key {
id: key7
width: 44
glyph: "u"
}
Key {
id: key8
width: 43
glyph: "i"
}
Key {
id: key9
width: 42
glyph: "o"
}
Key {
id: key10
width: 44
glyph: "p"
}
Key {
id: key28
width: 45
glyph: "←"
}
}
Row {
id: row2
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 18
Key {
id: key11
width: 43
}
Key {
id: key12
width: 43
glyph: "s"
}
Key {
id: key13
width: 43
glyph: "d"
}
Key {
id: key14
width: 43
glyph: "f"
}
Key {
id: key15
width: 43
glyph: "g"
}
Key {
id: key16
width: 43
glyph: "h"
}
Key {
id: key17
width: 43
glyph: "j"
}
Key {
id: key18
width: 43
glyph: "k"
}
Key {
id: key19
width: 43
glyph: "l"
}
Key {
id: key32
width: 75
glyph: "⏎"
}
}
Row {
id: row3
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 0
Key {
id: key27
width: 46
glyph: "⇪"
toggle: true
onToggledChanged: {
shiftMode = toggled;
}
}
Key {
id: key20
width: 43
glyph: "z"
}
Key {
id: key21
width: 43
glyph: "x"
}
Key {
id: key22
width: 43
glyph: "c"
}
Key {
id: key23
width: 43
glyph: "v"
}
Key {
id: key24
width: 43
glyph: "b"
}
Key {
id: key25
width: 43
glyph: "n"
}
Key {
id: key26
width: 44
glyph: "m"
}
Key {
id: key31
width: 43
glyph: ","
}
Key {
id: key33
width: 43
glyph: "."
}
Key {
id: key36
width: 46
glyph: "/"
}
}
Row {
id: row4
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 19
Key {
id: key30
width: 89
glyph: "&123"
mouseArea.onClicked: {
keyboardBase.parent.punctuationMode = true;
}
}
Key {
id: key29
width: 285
glyph: " "
}
Key {
id: key34
width: 43
glyph: "⇦"
}
Key {
id: key35
x: 343
width: 43
glyph: "⇨"
}
}
}
}
Rectangle {
id: rightRect
y: 280
height: 200
color: "#252525"
border.width: 0
anchors.left: keyboardRect.right
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
}
Rectangle {
id: rectangle1
color: "#ffffff"
anchors.bottom: keyboardRect.top
anchors.bottomMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
}

View file

@ -0,0 +1,324 @@
import QtQuick 2.0
Item {
id: keyboardBase
height: 200
Rectangle {
id: leftRect
y: 0
height: 200
color: "#252525"
anchors.right: keyboardRect.left
anchors.rightMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
}
Rectangle {
id: keyboardRect
x: 206
y: 0
width: 480
height: 200
color: "#252525"
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
Column {
id: column1
width: 480
height: 200
Row {
id: row1
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 0
Key {
id: key1
width: 43
glyph: "1"
}
Key {
id: key2
width: 43
glyph: "2"
}
Key {
id: key3
width: 43
glyph: "3"
}
Key {
id: key4
width: 43
glyph: "4"
}
Key {
id: key5
width: 43
glyph: "5"
}
Key {
id: key6
width: 43
glyph: "6"
}
Key {
id: key7
width: 43
glyph: "7"
}
Key {
id: key8
width: 43
glyph: "8"
}
Key {
id: key9
width: 43
glyph: "9"
}
Key {
id: key10
width: 43
glyph: "0"
}
Key {
id: key28
width: 50
glyph: "←"
}
}
Row {
id: row2
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 0
Key {
id: key11
width: 43
glyph: "!"
}
Key {
id: key12
width: 43
glyph: "@"
}
Key {
id: key13
width: 43
glyph: "#"
}
Key {
id: key14
width: 43
glyph: "$"
}
Key {
id: key15
width: 43
glyph: "%"
}
Key {
id: key16
width: 43
glyph: "^"
}
Key {
id: key17
width: 43
glyph: "&"
}
Key {
id: key18
width: 43
glyph: "*"
}
Key {
id: key19
width: 43
glyph: "("
}
Key {
id: key32
width: 43
glyph: ")"
}
Key {
id: key37
width: 50
glyph: "⏎"
}
}
Row {
id: row3
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 4
Key {
id: key27
width: 43
glyph: "="
}
Key {
id: key20
width: 43
glyph: "+"
}
Key {
id: key21
width: 43
glyph: "-"
}
Key {
id: key22
width: 43
glyph: "_"
}
Key {
id: key23
width: 43
glyph: ";"
}
Key {
id: key24
width: 43
glyph: ":"
}
Key {
id: key25
width: 43
glyph: "'"
}
Key {
id: key26
width: 43
glyph: "\""
}
Key {
id: key31
width: 43
glyph: "<"
}
Key {
id: key33
width: 43
glyph: ">"
}
Key {
id: key36
width: 43
glyph: "?"
}
}
Row {
id: row4
width: 480
height: 50
anchors.left: parent.left
anchors.leftMargin: 19
Key {
id: key30
width: 65
glyph: "abc"
mouseArea.onClicked: {
keyboardBase.parent.punctuationMode = false
}
}
Key {
id: key29
width: 285
glyph: " "
}
Key {
id: key34
width: 43
glyph: "⇦"
}
Key {
id: key35
x: 343
width: 43
glyph: "⇨"
}
}
}
}
Rectangle {
id: rightRect
y: 280
height: 200
color: "#252525"
border.width: 0
anchors.left: keyboardRect.right
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
}
Rectangle {
id: rectangle1
color: "#ffffff"
anchors.bottom: keyboardRect.top
anchors.bottomMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
anchors.top: parent.top
anchors.topMargin: 0
}
}

View file

@ -1,68 +1,135 @@
import QtQuick 2.5
import QtWebEngine 1.1
import QtWebChannel 1.0
WebEngineView {
id: root
property var newUrl;
profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)"
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
});
Item {
property alias url: root.url
property alias eventBridge: eventBridgeWrapper.eventBridge
property bool keyboardRaised: false
property bool punctuationMode: false
QtObject {
id: eventBridgeWrapper
WebChannel.id: "eventBridgeWrapper"
property var eventBridge;
}
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
Timer {
id: urlReplacementTimer
running: false
repeat: false
interval: 50
onTriggered: url = newUrl;
}
WebEngineView {
id: root
x: 0
y: 0
width: parent.width
height: keyboardRaised ? parent.height - keyboard1.height : parent.height
onUrlChanged: {
var originalUrl = url.toString();
newUrl = urlHandler.fixupUrl(originalUrl).toString();
if (newUrl !== originalUrl) {
root.stop();
if (urlReplacementTimer.running) {
console.warn("Replacement timer already running");
return;
}
urlReplacementTimer.start();
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
onLoadingChanged: {
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
property string newUrl: ""
webChannel.registeredObjects: [eventBridgeWrapper]
Component.onCompleted: {
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
}
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
Timer {
id: urlReplacementTimer
running: false
repeat: false
interval: 50
onTriggered: url = root.newUrl;
}
onUrlChanged: {
var originalUrl = url.toString();
root.newUrl = urlHandler.fixupUrl(originalUrl).toString();
if (root.newUrl !== originalUrl) {
root.stop();
if (urlReplacementTimer.running) {
console.warn("Replacement timer already running");
return;
}
urlReplacementTimer.start();
}
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
keyboardRaised = false;
punctuationMode = false;
keyboard1.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
}
onNewViewRequested:{
if (desktop) {
var component = Qt.createComponent("../Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
onNewViewRequested:{
// desktop is not defined for web-entities
if (desktop) {
var component = Qt.createComponent("../Browser.qml");
var newWindow = component.createObject(desktop);
request.openIn(newWindow.webView);
}
}
}
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
// See https://bugreports.qt.io/browse/QTBUG-49521
//profile: desktop.browserProfile
// virtual keyboard, letters
Keyboard {
id: keyboard1
y: keyboardRaised ? parent.height : 0
height: keyboardRaised ? 200 : 0
visible: keyboardRaised && !punctuationMode
enabled: keyboardRaised && !punctuationMode
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
}
KeyboardPunctuation {
id: keyboard2
y: keyboardRaised ? parent.height : 0
height: keyboardRaised ? 200 : 0
visible: keyboardRaised && punctuationMode
enabled: keyboardRaised && punctuationMode
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
}
}

View file

@ -52,7 +52,7 @@ ModalWindow {
// Set from OffscreenUi::getOpenFile()
property int options; // <-- FIXME unused
property string iconText: text !== "" ? hifi.glyphs.scriptUpload : ""
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
property int iconSize: 40
property bool selectDirectory: false;

View file

@ -14,6 +14,7 @@
import Hifi 1.0
import QtQuick 2.5
import QtGraphicalEffects 1.0
import "toolbars"
import "../styles-uit"
Rectangle {
@ -23,16 +24,13 @@ Rectangle {
property string timestamp: "";
property string hifiUrl: "";
property string thumbnail: defaultThumbnail;
property string imageUrl: "";
property var goFunction: null;
property string storyId: "";
property string timePhrase: pastTime(timestamp);
property string actionPhrase: makeActionPhrase(action);
property int onlineUsers: 0;
property bool isUserStory: userName && !onlineUsers;
property int textPadding: 20;
property int textPadding: 10;
property int textSize: 24;
property int textSizeSmall: 18;
property string defaultThumbnail: Qt.resolvedUrl("../../images/default-domain.gif");
@ -58,14 +56,6 @@ Rectangle {
}
return 'about a minute ago';
}
function makeActionPhrase(actionLabel) {
switch (actionLabel) {
case "snapshot":
return "took a snapshot";
default:
return "unknown"
}
}
Image {
id: lobby;
@ -89,6 +79,7 @@ Rectangle {
property int dropSamples: 9;
property int dropSpread: 0;
DropShadow {
visible: desktop.gradientsSupported;
source: place;
anchors.fill: place;
horizontalOffset: dropHorizontalOffset;
@ -99,6 +90,7 @@ Rectangle {
spread: dropSpread;
}
DropShadow {
visible: users.visible && desktop.gradientsSupported;
source: users;
anchors.fill: users;
horizontalOffset: dropHorizontalOffset;
@ -110,7 +102,7 @@ Rectangle {
}
RalewaySemiBold {
id: place;
text: isUserStory ? "" : placeName;
text: placeName;
color: hifi.colors.white;
size: textSize;
anchors {
@ -119,14 +111,15 @@ Rectangle {
margins: textPadding;
}
}
RalewayRegular {
FiraSansRegular {
id: users;
text: isUserStory ? timePhrase : (onlineUsers + ((onlineUsers === 1) ? ' person' : ' people'));
size: textSizeSmall;
visible: action === 'concurrency';
text: onlineUsers;
size: textSize;
color: hifi.colors.white;
anchors {
bottom: parent.bottom;
right: parent.right;
verticalCenter: usersImage.verticalCenter;
right: usersImage.left;
margins: textPadding;
}
}
@ -139,9 +132,23 @@ Rectangle {
id: zmouseArea;
anchors.fill: parent;
acceptedButtons: Qt.LeftButton;
onClicked: goFunction(parent);
onClicked: goFunction("hifi://" + hifiUrl);
hoverEnabled: true;
onEntered: hoverThunk();
onExited: unhoverThunk();
}
ToolbarButton {
id: usersImage;
imageURL: "../../images/" + action + ".svg";
size: 32;
onClicked: goFunction("/user_stories/" + storyId);
buttonState: 0;
defaultState: 0;
hoverState: 1;
anchors {
bottom: parent.bottom;
right: parent.right;
margins: textPadding;
}
}
}

View file

@ -46,8 +46,20 @@ OriginalDesktop.Desktop {
}
}
property var toolbars: ({})
Component { id: toolbarBuilder; Toolbar { } }
// This used to create sysToolbar dynamically with a call to getToolbar() within onCompleted.
// Beginning with QT 5.6, this stopped working, as anything added to toolbars too early got
// wiped during startup.
Toolbar {
id: sysToolbar;
objectName: "com.highfidelity.interface.toolbar.system";
// Magic: sysToolbar.x and y come from settings, and are bound before the properties specified here are applied.
x: sysToolbar.x;
y: sysToolbar.y;
}
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
map[sysToolbar.objectName] = sysToolbar;
return map; })({});
Component.onCompleted: {
WebEngine.settings.javascriptCanOpenWindows = true;
@ -55,7 +67,6 @@ OriginalDesktop.Desktop {
WebEngine.settings.spatialNavigationEnabled = false;
WebEngine.settings.localContentCanAccessRemoteUrls = true;
var sysToolbar = desktop.getToolbar("com.highfidelity.interface.toolbar.system");
var toggleHudButton = sysToolbar.addButton({
objectName: "hudToggle",
imageURL: "../../../icons/hud.svg",

View file

@ -0,0 +1,19 @@
import QtQuick 2.5
import Qt.labs.settings 1.0
import "../../dialogs"
PreferencesDialog {
id: root
objectName: "NetworkingPreferencesDialog"
title: "Networking Settings"
showCategories: ["Networking"]
property var settings: Settings {
category: root.objectName
property alias x: root.x
property alias y: root.y
property alias width: root.width
property alias height: root.height
}
}

View file

@ -109,7 +109,7 @@ Decoration {
verticalOffset: 2
samples: 2
color: hifi.colors.baseGrayShadow60
visible: (window && window.focus)
visible: (desktop.gradientsSupported && window && window.focus)
cached: true
}
}

View file

@ -133,7 +133,6 @@
#include "scripting/LocationScriptingInterface.h"
#include "scripting/MenuScriptingInterface.h"
#include "scripting/SettingsScriptingInterface.h"
#include "scripting/WebWindowClass.h"
#include "scripting/WindowScriptingInterface.h"
#include "scripting/ControllerScriptingInterface.h"
#include "scripting/ToolbarScriptingInterface.h"
@ -176,8 +175,6 @@ static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
// For processing on QThreadPool, target 2 less than the ideal number of threads, leaving
// 2 logical cores available for time sensitive tasks.
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2;
static const int PROCESSING_THREAD_POOL_SIZE = std::max(MIN_PROCESSING_THREAD_POOL_SIZE,
QThread::idealThreadCount() - 2);
static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString SVO_EXTENSION = ".svo";
@ -217,7 +214,6 @@ Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTRE
static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
{ SNAPSHOT_EXTENSION, &Application::acceptSnapshot },
{ SVO_EXTENSION, &Application::importSVOFromURL },
{ SVO_JSON_EXTENSION, &Application::importSVOFromURL },
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
@ -268,7 +264,7 @@ public:
auto elapsedMovingAverage = _movingAverage.getAverage();
if (elapsedMovingAverage > _maxElapsedAverage) {
qDebug() << "DEADLOCK WATCHDOG WARNING:"
qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:"
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "elapsedMovingAverage:" << elapsedMovingAverage
<< "maxElapsed:" << _maxElapsed
@ -278,7 +274,7 @@ public:
_maxElapsedAverage = elapsedMovingAverage;
}
if (lastHeartbeatAge > _maxElapsed) {
qDebug() << "DEADLOCK WATCHDOG WARNING:"
qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:"
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "elapsedMovingAverage:" << elapsedMovingAverage
<< "PREVIOUS maxElapsed:" << _maxElapsed
@ -288,7 +284,7 @@ public:
_maxElapsed = lastHeartbeatAge;
}
if (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT) {
qDebug() << "DEADLOCK WATCHDOG WARNING:"
qCDebug(interfaceapp_deadlock) << "DEADLOCK WATCHDOG WARNING:"
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "elapsedMovingAverage:" << elapsedMovingAverage << "** OVER EXPECTED VALUE **"
<< "maxElapsed:" << _maxElapsed
@ -297,7 +293,7 @@ public:
}
if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) {
qDebug() << "DEADLOCK DETECTED -- "
qCDebug(interfaceapp_deadlock) << "DEADLOCK DETECTED -- "
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "[ lastHeartbeat :" << lastHeartbeat
<< "now:" << now << " ]"
@ -403,12 +399,10 @@ static const QString STATE_GROUNDED = "Grounded";
static const QString STATE_NAV_FOCUSED = "NavigationFocused";
bool setupEssentials(int& argc, char** argv) {
unsigned int listenPort = 0; // bind to an ephemeral port by default
const char** constArgv = const_cast<const char**>(argv);
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
if (portStr) {
listenPort = atoi(portStr);
}
const int listenPort = portStr ? atoi(portStr) : INVALID_PORT;
// Set build version
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
@ -537,7 +531,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
PluginContainer* pluginContainer = dynamic_cast<PluginContainer*>(this); // set the container for any plugins that care
PluginManager::getInstance()->setContainer(pluginContainer);
QThreadPool::globalInstance()->setMaxThreadCount(PROCESSING_THREAD_POOL_SIZE);
QThreadPool::globalInstance()->setMaxThreadCount(MIN_PROCESSING_THREAD_POOL_SIZE);
thread()->setPriority(QThread::HighPriority);
thread()->setObjectName("Main Thread");
@ -568,6 +562,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_deadlockWatchdogThread->start();
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
qCDebug(interfaceapp) << "[VERSION] VERSION:" << BuildInfo::VERSION;
qCDebug(interfaceapp) << "[VERSION] BUILD_BRANCH:" << BuildInfo::BUILD_BRANCH;
qCDebug(interfaceapp) << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES;
#if USE_STABLE_GLOBAL_SERVICES
qCDebug(interfaceapp) << "[VERSION] We will use STABLE global services.";
#else
qCDebug(interfaceapp) << "[VERSION] We will use DEVELOPMENT global services.";
#endif
_bookmarks = new Bookmarks(); // Before setting up the menu
@ -707,6 +711,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
// Save avatar location immediately after a teleport.
connect(getMyAvatar(), &MyAvatar::positionGoneTo,
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
@ -1033,7 +1039,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
cameraMenuChanged();
}
// set the local loopback interface for local sounds from audio scripts
// set the local loopback interface for local sounds
AudioInjector::setLocalAudioInterface(audioIO.data());
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
this->installEventFilter(this);
@ -1233,8 +1240,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
firstRun.set(false);
}
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCode) {
switch (static_cast<DomainHandler::ConnectionRefusedReason>(reasonCode)) {
void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
DomainHandler::ConnectionRefusedReason reasonCode = static_cast<DomainHandler::ConnectionRefusedReason>(reasonCodeInt);
if (reasonCode == DomainHandler::ConnectionRefusedReason::TooManyUsers && !extraInfo.isEmpty()) {
DependencyManager::get<AddressManager>()->handleLookupString(extraInfo);
return;
}
switch (reasonCode) {
case DomainHandler::ConnectionRefusedReason::ProtocolMismatch:
case DomainHandler::ConnectionRefusedReason::TooManyUsers:
case DomainHandler::ConnectionRefusedReason::Unknown: {
@ -1685,7 +1699,6 @@ void Application::paintGL() {
Finally clearFlag([this] { _inPaint = false; });
_frameCount++;
_frameCounter.increment();
auto lastPaintBegin = usecTimestampNow();
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
@ -1922,6 +1935,7 @@ void Application::paintGL() {
{
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
PerformanceTimer perfTimer("pluginOutput");
_frameCounter.increment();
displayPlugin->submitFrame(frame);
}
@ -2009,7 +2023,7 @@ void Application::resizeGL() {
static qreal lastDevicePixelRatio = 0;
qreal devicePixelRatio = _window->devicePixelRatio();
if (offscreenUi->size() != fromGlm(uiSize) || devicePixelRatio != lastDevicePixelRatio) {
qDebug() << "Device pixel ratio changed, triggering resize";
qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize;
offscreenUi->resize(fromGlm(uiSize), true);
_offscreenContext->makeCurrent();
lastDevicePixelRatio = devicePixelRatio;
@ -2860,6 +2874,8 @@ void Application::dragEnterEvent(QDragEnterEvent* event) {
event->acceptProposedAction();
}
// This is currently not used, but could be invoked if the user wants to go to the place embedded in an
// Interface-taken snapshot. (It was developed for drag and drop, before we had asset-server loading or in-world browsers.)
bool Application::acceptSnapshot(const QString& urlString) {
QUrl url(urlString);
QString snapshotPath = url.toLocalFile();
@ -3262,17 +3278,17 @@ void Application::init() {
Setting::Handle<bool> firstRun { Settings::firstRun, true };
if (addressLookupString.isEmpty() && firstRun.get()) {
qDebug() << "First run and no URL passed... attempting to go to Home or Entry...";
qCDebug(interfaceapp) << "First run and no URL passed... attempting to go to Home or Entry...";
DependencyManager::get<AddressManager>()->ifLocalSandboxRunningElse([](){
qDebug() << "Home sandbox appears to be running, going to Home.";
qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home.";
DependencyManager::get<AddressManager>()->goToLocalSandbox();
},
[](){
qDebug() << "Home sandbox does not appear to be running, going to Entry.";
qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry.";
DependencyManager::get<AddressManager>()->goToEntry();
});
} else {
qDebug() << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
}
@ -3291,7 +3307,7 @@ void Application::init() {
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
auto dims = item.getDimensions();
auto maxSize = glm::max(dims.x, dims.y, dims.z);
auto maxSize = glm::compMax(dims);
if (maxSize <= 0.0f) {
return 0.0f;
@ -4858,7 +4874,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter);
scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1);
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
@ -5034,6 +5049,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(url);
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(networkRequest);
int requestNumber = ++_avatarAttachmentRequest;
@ -5619,7 +5635,7 @@ void Application::setActiveDisplayPlugin(const QString& pluginName) {
void Application::handleLocalServerConnection() const {
auto server = qobject_cast<QLocalServer*>(sender());
qDebug() << "Got connection on local server from additional instance - waiting for parameters";
qCDebug(interfaceapp) << "Got connection on local server from additional instance - waiting for parameters";
auto socket = server->nextPendingConnection();
@ -5635,7 +5651,7 @@ void Application::readArgumentsFromLocalSocket() const {
auto message = socket->readAll();
socket->deleteLater();
qDebug() << "Read from connection: " << message;
qCDebug(interfaceapp) << "Read from connection: " << message;
// If we received a message, try to open it as a URL
if (message.length() > 0) {
@ -5727,3 +5743,18 @@ void Application::sendHoverLeaveEntity(QUuid id, PointerEvent event) {
EntityItemID entityItemID(id);
emit getEntities()->hoverLeaveEntity(entityItemID, event);
}
// FIXME? perhaps two, one for the main thread and one for the offscreen UI rendering thread?
static const int UI_RESERVED_THREADS = 1;
// Windows won't let you have all the cores
static const int OS_RESERVED_THREADS = 1;
void Application::updateThreadPoolCount() const {
auto reservedThreads = UI_RESERVED_THREADS + OS_RESERVED_THREADS + _displayPlugin->getRequiredThreadCount();
auto availableThreads = QThread::idealThreadCount() - reservedThreads;
auto threadPoolSize = std::max(MIN_PROCESSING_THREAD_POOL_SIZE, availableThreads);
qCDebug(interfaceapp) << "Ideal Thread Count " << QThread::idealThreadCount();
qCDebug(interfaceapp) << "Reserved threads " << reservedThreads;
qCDebug(interfaceapp) << "Setting thread pool size to " << threadPoolSize;
QThreadPool::globalInstance()->setMaxThreadCount(threadPoolSize);
}

View file

@ -44,12 +44,12 @@
#include <AbstractUriHandler.h>
#include <shared/RateCounter.h>
#include <ThreadSafeValueCache.h>
#include <shared/FileLogger.h>
#include "avatar/MyAvatar.h"
#include "Bookmarks.h"
#include "Camera.h"
#include "ConnectionMonitor.h"
#include "FileLogger.h"
#include "gpu/Context.h"
#include "Menu.h"
#include "octree/OctreePacketProcessor.h"
@ -223,7 +223,7 @@ public:
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
// rendering of several elements depend on that
// TODO: carry that information on the Camera as a setting
bool isHMDMode() const;
virtual bool isHMDMode() const override;
glm::mat4 getHMDSensorPose() const;
glm::mat4 getEyeOffset(int eye) const;
glm::mat4 getEyeProjection(int eye) const;
@ -286,6 +286,7 @@ public slots:
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs, const glm::vec3* givenOffset = nullptr);
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
bool importEntities(const QString& url);
void updateThreadPoolCount() const;
static void setLowVelocityFilter(bool lowVelocityFilter);
Q_INVOKABLE void loadDialog();
@ -374,7 +375,7 @@ private slots:
void nodeKilled(SharedNodePointer node);
static void packetSent(quint64 length);
void updateDisplayMode();
void domainConnectionRefused(const QString& reasonMessage, int reason);
void domainConnectionRefused(const QString& reasonMessage, int reason, const QString& extraInfo);
private:
static void initDisplay();

View file

@ -182,3 +182,16 @@ ViewFrustum Camera::toViewFrustum() const {
loadViewFrustum(result);
return result;
}
QVariantMap Camera::getViewFrustum() {
ViewFrustum frustum;
loadViewFrustum(frustum);
QVariantMap result;
result["position"].setValue(frustum.getPosition());
result["orientation"].setValue(frustum.getOrientation());
result["projection"].setValue(frustum.getProjection());
result["centerRadius"].setValue(frustum.getCenterRadius());
return result;
}

View file

@ -42,6 +42,8 @@ class Camera : public QObject {
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
Q_PROPERTY(QString mode READ getModeString WRITE setModeString)
Q_PROPERTY(QUuid cameraEntity READ getCameraEntity WRITE setCameraEntity)
Q_PROPERTY(QVariantMap frustum READ getViewFrustum CONSTANT)
public:
Camera();
@ -63,6 +65,8 @@ public:
const glm::mat4& getProjection() const { return _projection; }
void setProjection(const glm::mat4& projection);
QVariantMap getViewFrustum();
public slots:
QString getModeString() const;
void setModeString(const QString& mode);

View file

@ -14,6 +14,7 @@
#include <avatar/AvatarActionHold.h>
#include <ObjectActionOffset.h>
#include <ObjectActionSpring.h>
#include <ObjectActionTravelOriented.h>
#include <LogHandler.h>
#include "InterfaceActionFactory.h"
@ -29,6 +30,8 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i
return std::make_shared<ObjectActionSpring>(id, ownerEntity);
case ACTION_TYPE_HOLD:
return std::make_shared<AvatarActionHold>(id, ownerEntity);
case ACTION_TYPE_TRAVEL_ORIENTED:
return std::make_shared<ObjectActionTravelOriented>(id, ownerEntity);
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type");

View file

@ -13,3 +13,4 @@
Q_LOGGING_CATEGORY(interfaceapp, "hifi.interface")
Q_LOGGING_CATEGORY(interfaceapp_timing, "hifi.interface.timing")
Q_LOGGING_CATEGORY(interfaceapp_deadlock, "hifi.interface.deadlock")

View file

@ -16,5 +16,6 @@
Q_DECLARE_LOGGING_CATEGORY(interfaceapp)
Q_DECLARE_LOGGING_CATEGORY(interfaceapp_timing)
Q_DECLARE_LOGGING_CATEGORY(interfaceapp_deadlock)
#endif // hifi_InterfaceLogging_h

View file

@ -47,6 +47,8 @@
#include "Menu.h"
extern bool DEV_DECIMATE_TEXTURES;
Menu* Menu::getInstance() {
return dynamic_cast<Menu*>(qApp->getWindow()->menuBar());
}
@ -301,12 +303,6 @@ Menu::Menu() {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AvatarPreferencesDialog.qml"), "AvatarPreferencesDialog");
});
// Settings > Audio...
action = addActionToQMenuAndActionHash(settingsMenu, "Audio...");
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog");
});
// Settings > LOD...
action = addActionToQMenuAndActionHash(settingsMenu, "LOD...");
connect(action, &QAction::triggered, [] {
@ -359,7 +355,7 @@ Menu::Menu() {
//const QString = "1024 MB";
//const QString = "2048 MB";
// Developer > Render > Resolution
// Developer > Render > Maximum Texture Memory
MenuWrapper* textureMenu = renderOptionsMenu->addMenu(MenuOption::RenderMaxTextureMemory);
QActionGroup* textureGroup = new QActionGroup(textureMenu);
textureGroup->setExclusive(true);
@ -387,9 +383,54 @@ Menu::Menu() {
gpu::Texture::setAllowedGPUMemoryUsage(newMaxTextureMemory);
});
#ifdef Q_OS_WIN
#define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5
bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES);
bool recommendedSparseTextures = recommendedIncrementalTransfers;
qDebug() << "[TEXTURE TRANSFER SUPPORT]"
<< "\n\tidealThreadCount:" << QThread::idealThreadCount()
<< "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures
<< "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers;
gpu::Texture::setEnableIncrementalTextureTransfers(recommendedIncrementalTransfers);
gpu::Texture::setEnableSparseTextures(recommendedSparseTextures);
// Developer > Render > Enable Dynamic Texture Management
{
auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableDynamicTextureManagement, 0, recommendedSparseTextures);
connect(action, &QAction::triggered, [&](bool checked) {
qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Dynamic Texture Management menu option:" << checked;
gpu::Texture::setEnableSparseTextures(checked);
});
}
// Developer > Render > Enable Incremental Texture Transfer
{
auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableIncrementalTextureTransfer, 0, recommendedIncrementalTransfers);
connect(action, &QAction::triggered, [&](bool checked) {
qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Incremental Texture Transfer menu option:" << checked;
gpu::Texture::setEnableIncrementalTextureTransfers(checked);
});
}
#else
qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer and Dynamic Texture Management not supported on this platform.";
#endif
// Developer > Render > LOD Tools
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools()));
// HACK enable texture decimation
{
auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, "Decimate Textures");
connect(action, &QAction::triggered, [&](bool checked) {
DEV_DECIMATE_TEXTURES = checked;
});
}
// Developer > Assets >>>
MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets");
auto& atpMigrator = ATPAssetMigrator::getInstance();
@ -522,6 +563,11 @@ Menu::Menu() {
// Developer > Network >>>
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
action = addActionToQMenuAndActionHash(networkMenu, MenuOption::Networking);
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QUrl("hifi/dialogs/NetworkingPreferencesDialog.qml"),
"NetworkingPreferencesDialog");
});
addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
addCheckableActionToQMenuAndActionHash(networkMenu,
MenuOption::DisableActivityLogger,
@ -569,6 +615,12 @@ Menu::Menu() {
// Developer > Audio >>>
MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio");
action = addActionToQMenuAndActionHash(audioDebugMenu, "Buffers...");
connect(action, &QAction::triggered, [] {
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog");
});
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true,
audioIO.data(), SLOT(toggleAudioNoiseReduction()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio, 0, false,

View file

@ -98,6 +98,8 @@ namespace MenuOption {
const QString EchoLocalAudio = "Echo Local Audio";
const QString EchoServerAudio = "Echo Server Audio";
const QString EnableCharacterController = "Enable avatar collisions";
const QString EnableIncrementalTextureTransfer = "Enable Incremental Texture Transfer";
const QString EnableDynamicTextureManagement = "Enable Dynamic Texture Management";
const QString EnableInverseKinematics = "Enable Inverse Kinematics";
const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation";
const QString ExpandMyAvatarTiming = "Expand /myAvatar";
@ -129,6 +131,7 @@ namespace MenuOption {
const QString MuteEnvironment = "Mute Environment";
const QString MuteFaceTracking = "Mute Face Tracking";
const QString NamesAboveHeads = "Names Above Heads";
const QString Networking = "Networking...";
const QString NoFaceTracking = "None";
const QString OctreeStats = "Entity Statistics";
const QString OnePointCalibration = "1 Point Calibration";

View file

@ -59,8 +59,6 @@ const float DISPLAYNAME_ALPHA = 1.0f;
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534;
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
return ItemKey::Builder::opaqueShape();
@ -853,32 +851,54 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const {
}
glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
bool success;
Transform avatarTransform;
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
} else {
glm::quat rotation;
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
return Quaternions::Y_180 * rotation;
switch(index) {
case SENSOR_TO_WORLD_MATRIX_INDEX: {
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
bool success;
Transform avatarTransform;
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
}
case CONTROLLER_LEFTHAND_INDEX: {
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
return controllerLeftHandTransform.getRotation();
}
case CONTROLLER_RIGHTHAND_INDEX: {
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
return controllerRightHandTransform.getRotation();
}
default: {
glm::quat rotation;
_skeletonModel->getAbsoluteJointRotationInRigFrame(index, rotation);
return Quaternions::Y_180 * rotation;
}
}
}
glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
if (index == SENSOR_TO_WORLD_MATRIX_INDEX) {
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
bool success;
Transform avatarTransform;
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
} else {
glm::vec3 translation;
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
return Quaternions::Y_180 * translation;
switch(index) {
case SENSOR_TO_WORLD_MATRIX_INDEX: {
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
bool success;
Transform avatarTransform;
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
}
case CONTROLLER_LEFTHAND_INDEX: {
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
return controllerLeftHandTransform.getTranslation();
}
case CONTROLLER_RIGHTHAND_INDEX: {
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
return controllerRightHandTransform.getTranslation();
}
default: {
glm::vec3 translation;
_skeletonModel->getAbsoluteJointTranslationInRigFrame(index, translation);
return Quaternions::Y_180 * translation;
}
}
}
@ -889,6 +909,10 @@ int Avatar::getJointIndex(const QString& name) const {
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
return result;
}
int result = getFauxJointIndex(name);
if (result != -1) {
return result;
}
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointIndex(name) : -1;
}

View file

@ -56,6 +56,10 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
}
withWriteLock([&]{
glm::vec3 avatarRigidBodyPosition;
glm::quat avatarRigidBodyRotation;
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
if (_ignoreIK) {
return;
}
@ -70,9 +74,6 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
palmRotation = holdingAvatar->getUncachedLeftPalmRotation();
}
glm::vec3 avatarRigidBodyPosition;
glm::quat avatarRigidBodyRotation;
getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation);
// determine the difference in translation and rotation between the avatar's
// rigid body and the palm position. The avatar's rigid body will be moved by bullet
@ -124,13 +125,20 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
if (pose.isValid()) {
linearVelocity = pose.getVelocity();
angularVelocity = pose.getAngularVelocity();
if (isRightHand) {
pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInAvatarFrame();
} else {
pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInAvatarFrame();
}
}
if (_ignoreIK && pose.isValid()) {
// We cannot ignore other avatars IK and this is not the point of this option
// This is meant to make the grabbing behavior more reactive.
palmPosition = pose.getTranslation();
palmRotation = pose.getRotation();
Transform avatarTransform;
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
avatarTransform = myAvatar->getTransform();
palmPosition = avatarTransform.transform(pose.getTranslation() / myAvatar->getTargetScale());
palmRotation = avatarTransform.getRotation() * pose.getRotation();
} else {
glm::vec3 avatarRigidBodyPosition;
glm::quat avatarRigidBodyRotation;
@ -159,11 +167,17 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
}
} else { // regular avatar
if (isRightHand) {
palmPosition = holdingAvatar->getRightPalmPosition();
palmRotation = holdingAvatar->getRightPalmRotation();
Transform controllerRightTransform = Transform(holdingAvatar->getControllerRightHandMatrix());
Transform avatarTransform = holdingAvatar->getTransform();
palmRotation = avatarTransform.getRotation() * controllerRightTransform.getRotation();
palmPosition = avatarTransform.getTranslation() +
(avatarTransform.getRotation() * controllerRightTransform.getTranslation());
} else {
palmPosition = holdingAvatar->getLeftPalmPosition();
palmRotation = holdingAvatar->getLeftPalmRotation();
Transform controllerLeftTransform = Transform(holdingAvatar->getControllerLeftHandMatrix());
Transform avatarTransform = holdingAvatar->getTransform();
palmRotation = avatarTransform.getRotation() * controllerLeftTransform.getRotation();
palmPosition = avatarTransform.getTranslation() +
(avatarTransform.getRotation() * controllerLeftTransform.getTranslation());
}
}
@ -230,14 +244,19 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
// 3 -- ignore i of 0 1 2
// 4 -- ignore i of 1 2 3
// 5 -- ignore i of 2 3 4
if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
(i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
(i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) {
continue;
}
// This code is now disabled, but I'm leaving it commented-out because I suspect it will come back.
// if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
// (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex ||
// (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) {
// continue;
// }
measuredLinearVelocity += _measuredLinearVelocities[i];
}
measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames - 3); // 3 because of the 3 we skipped, above
measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames
// - 3 // 3 because of the 3 we skipped, above
);
if (_kinematicSetVelocity) {
rigidBody->setLinearVelocity(glmToBullet(measuredLinearVelocity));

View file

@ -532,11 +532,21 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
_hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation);
}
void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache) {
assert(QThread::currentThread() == thread());
auto userInputMapper = DependencyManager::get<UserInputMapper>();
controller::Pose controllerPose = userInputMapper->getPoseState(poseKey);
Transform transform;
transform.setTranslation(controllerPose.getTranslation());
transform.setRotation(controllerPose.getRotation());
glm::mat4 controllerMatrix = transform.getMatrix();
matrixCache.set(controllerMatrix);
}
// best called at end of main loop, after physics.
// update sensor to world matrix from current body position and hmd sensor.
// This is so the correct camera can be used for rendering.
void MyAvatar::updateSensorToWorldMatrix() {
// update the sensor mat so that the body position will end up in the desired
// position when driven from the head.
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
@ -545,10 +555,14 @@ void MyAvatar::updateSensorToWorldMatrix() {
lateUpdatePalms();
if (_enableDebugDrawSensorToWorldMatrix) {
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix), extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix),
extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
}
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
}
// Update avatar head rotation with sensor data
@ -2215,3 +2229,31 @@ bool MyAvatar::didTeleport() {
bool MyAvatar::hasDriveInput() const {
return fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Y]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
}
glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
switch(index) {
case CONTROLLER_LEFTHAND_INDEX: {
return getLeftHandControllerPoseInAvatarFrame().getRotation();
}
case CONTROLLER_RIGHTHAND_INDEX: {
return getRightHandControllerPoseInAvatarFrame().getRotation();
}
default: {
return Avatar::getAbsoluteJointRotationInObjectFrame(index);
}
}
}
glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
switch(index) {
case CONTROLLER_LEFTHAND_INDEX: {
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
}
case CONTROLLER_RIGHTHAND_INDEX: {
return getRightHandControllerPoseInAvatarFrame().getTranslation();
}
default: {
return Avatar::getAbsoluteJointTranslationInObjectFrame(index);
}
}
}

View file

@ -19,6 +19,7 @@
#include <Sound.h>
#include <controllers/Pose.h>
#include <controllers/Actions.h>
#include "Avatar.h"
#include "AtRestDetector.h"
@ -117,6 +118,9 @@ public:
// as it moves through the world.
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
// read the location of a hand controller and save the transform
void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache<glm::mat4>& matrixCache);
// best called at end of main loop, just before rendering.
// update sensor to world matrix from current body position and hmd sensor.
// This is so the correct camera can be used for rendering.
@ -270,6 +274,9 @@ public:
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled);
Q_INVOKABLE bool getCharacterControllerEnabled();
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
public slots:
void increaseSize();
void decreaseSize();
@ -410,9 +417,8 @@ private:
bool _useSnapTurn { true };
bool _clearOverlayWhenMoving { true };
// working copy of sensorToWorldMatrix.
// See AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
glm::mat4 _sensorToWorldMatrix;
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
// cache of the current HMD sensor position and orientation
// in sensor space.

View file

@ -55,7 +55,7 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu
// TODO: cache these look ups as an optimization
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
glm::mat4 jointMatrix(glm::mat4::_null);
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride->getJointStateCount()) {
jointMatrix = _rigOverride->getJointTransform(jointIndexOverride);
} else {

View file

@ -0,0 +1,41 @@
//
// InterfaceActivity.java
// gvr-interface/java
//
// Created by Stephen Birarda on 1/26/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
package io.highfidelity.gvrinterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.WindowManager;
import android.util.Log;
import org.qtproject.qt5.android.bindings.QtActivity;
public class InterfaceActivity extends QtActivity {
public static native void handleHifiURL(String hifiURLString);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Get the intent that started this activity in case we have a hifi:// URL to parse
Intent intent = getIntent();
if (intent.getAction() == Intent.ACTION_VIEW) {
Uri data = intent.getData();
if (data.getScheme().equals("hifi")) {
handleHifiURL(data.toString());
}
}
}
}

View file

@ -1,182 +0,0 @@
//
// WebWindowClass.cpp
// interface/src/scripting
//
// Created by Ryan Huffman on 11/06/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QVBoxLayout>
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QWebFrame>
#include <QWebView>
#include <QListWidget>
#include <QStyleFactory>
#include "Application.h"
#include "ui/DataWebPage.h"
#include "MainWindow.h"
#include "WebWindowClass.h"
#include "WindowScriptingInterface.h"
ScriptEventBridge::ScriptEventBridge(QObject* parent) : QObject(parent) {
}
void ScriptEventBridge::emitWebEvent(const QString& data) {
emit webEventReceived(data);
}
void ScriptEventBridge::emitScriptEvent(const QString& data) {
emit scriptEventReceived(data);
}
WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height)
: QObject(NULL), _eventBridge(new ScriptEventBridge(this)) {
auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window);
dialogWidget->setWindowTitle(title);
dialogWidget->resize(width, height);
dialogWidget->installEventFilter(this);
connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed);
auto layout = new QVBoxLayout(dialogWidget);
layout->setContentsMargins(0, 0, 0, 0);
dialogWidget->setLayout(layout);
_webView = new QWebView(dialogWidget);
layout->addWidget(_webView);
addEventBridgeToWindowObject();
_windowWidget = dialogWidget;
auto style = QStyleFactory::create("fusion");
if (style) {
_webView->setStyle(style);
}
_webView->setPage(new DataWebPage());
if (!url.startsWith("http") && !url.startsWith("file://")) {
_webView->setUrl(QUrl::fromLocalFile(url));
} else {
_webView->setUrl(url);
}
connect(this, &WebWindowClass::destroyed, _windowWidget, &QWidget::deleteLater);
connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared,
this, &WebWindowClass::addEventBridgeToWindowObject);
}
WebWindowClass::~WebWindowClass() {
}
bool WebWindowClass::eventFilter(QObject* sender, QEvent* event) {
if (sender == _windowWidget) {
if (event->type() == QEvent::Move) {
emit moved(getPosition());
}
if (event->type() == QEvent::Resize) {
emit resized(getSize());
}
}
return false;
}
void WebWindowClass::hasClosed() {
emit closed();
}
void WebWindowClass::addEventBridgeToWindowObject() {
_webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
}
void WebWindowClass::setVisible(bool visible) {
if (visible) {
QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection);
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
}
QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
}
void WebWindowClass::setURL(const QString& url) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url));
return;
}
_webView->setUrl(url);
}
QSizeF WebWindowClass::getSize() const {
QSizeF size = _windowWidget->size();
return size;
}
void WebWindowClass::setSize(QSizeF size) {
setSize(size.width(), size.height());
}
void WebWindowClass::setSize(int width, int height) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setSize", Qt::AutoConnection, Q_ARG(int, width), Q_ARG(int, height));
return;
}
_windowWidget->resize(width, height);
}
glm::vec2 WebWindowClass::getPosition() const {
QPoint position = _windowWidget->pos();
return glm::vec2(position.x(), position.y());
}
void WebWindowClass::setPosition(glm::vec2 position) {
setPosition(position.x, position.y);
}
void WebWindowClass::setPosition(int x, int y) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setPosition", Qt::AutoConnection, Q_ARG(int, x), Q_ARG(int, y));
return;
}
_windowWidget->move(x, y);
}
void WebWindowClass::raise() {
QMetaObject::invokeMethod(_windowWidget, "showNormal", Qt::AutoConnection);
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
}
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
WebWindowClass* retVal;
QString file = context->argument(0).toString();
if (context->argument(4).toBool()) {
qWarning() << "ToolWindow views with WebWindow are no longer supported. Use OverlayWebWindow instead";
return QScriptValue();
} else {
qWarning() << "WebWindow views are deprecated. Use OverlayWebWindow instead";
}
QMetaObject::invokeMethod(DependencyManager::get<WindowScriptingInterface>().data(), "doCreateWebWindow", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(WebWindowClass*, retVal),
Q_ARG(const QString&, file),
Q_ARG(QString, context->argument(1).toString()),
Q_ARG(int, context->argument(2).toInteger()),
Q_ARG(int, context->argument(3).toInteger()));
connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater);
return engine->newQObject(retVal);
}
void WebWindowClass::setTitle(const QString& title) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setTitle", Qt::AutoConnection, Q_ARG(QString, title));
return;
}
_windowWidget->setWindowTitle(title);
}

View file

@ -1,80 +0,0 @@
//
// WebWindowClass.h
// interface/src/scripting
//
// Created by Ryan Huffman on 11/06/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_WebWindowClass_h
#define hifi_WebWindowClass_h
#include <QScriptContext>
#include <QScriptEngine>
#include <QWebView>
class ScriptEventBridge : public QObject {
Q_OBJECT
public:
ScriptEventBridge(QObject* parent = NULL);
public slots:
void emitWebEvent(const QString& data);
void emitScriptEvent(const QString& data);
signals:
void webEventReceived(const QString& data);
void scriptEventReceived(const QString& data);
};
class WebWindowClass : public QObject {
Q_OBJECT
Q_PROPERTY(QObject* eventBridge READ getEventBridge)
Q_PROPERTY(QString url READ getURL)
Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition);
Q_PROPERTY(QSizeF size READ getSize WRITE setSize);
public:
WebWindowClass(const QString& title, const QString& url, int width, int height);
~WebWindowClass();
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
public slots:
void setVisible(bool visible);
glm::vec2 getPosition() const;
void setPosition(int x, int y);
void setPosition(glm::vec2 position);
QSizeF getSize() const;
void setSize(QSizeF size);
void setSize(int width, int height);
QString getURL() const { return _webView->url().url(); }
void setURL(const QString& url);
void raise();
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
void addEventBridgeToWindowObject();
void setTitle(const QString& title);
signals:
void visibilityChanged(bool visible); // Tool window
void moved(glm::vec2 position);
void resized(QSizeF size);
void closed();
protected:
virtual bool eventFilter(QObject* sender, QEvent* event) override;
private slots:
void hasClosed();
private:
QWidget* _windowWidget;
QWebView* _webView;
ScriptEventBridge* _eventBridge;
};
#endif

View file

@ -21,7 +21,6 @@
#include "MainWindow.h"
#include "Menu.h"
#include "OffscreenUi.h"
#include "WebWindowClass.h"
#include "WindowScriptingInterface.h"
@ -61,10 +60,6 @@ WindowScriptingInterface::WindowScriptingInterface() {
});
}
WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) {
return new WebWindowClass(title, url, width, height);
}
QScriptValue WindowScriptingInterface::hasFocus() {
return qApp->hasFocus();
}

View file

@ -16,9 +16,6 @@
#include <QtCore/QString>
#include <QtScript/QScriptValue>
class WebWindowClass;
class CustomPromptResult {
public:
QVariant value;
@ -61,13 +58,10 @@ public slots:
signals:
void domainChanged(const QString& domainHostname);
void svoImportRequested(const QString& url);
void domainConnectionRefused(const QString& reasonMessage, int reasonCode);
void domainConnectionRefused(const QString& reasonMessage, int reasonCode, const QString& extraInfo);
void snapshotTaken(const QString& path, bool notify);
void snapshotShared(const QString& error);
private slots:
WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
private:
QString getPreviousBrowseLocation() const;
void setPreviousBrowseLocation(const QString& location);

View file

@ -58,21 +58,19 @@ void AudioStatsDisplay::updatedDisplay(QString str) {
AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint) {
_shouldShowInjectedStreams = false;
setWindowTitle("Audio Network Statistics");
// Get statistics from the Audio Client
_stats = &DependencyManager::get<AudioClient>()->getStats();
// Create layout
_form = new QFormLayout();
_form->setSizeConstraint(QLayout::SetFixedSize);
QDialog::setLayout(_form);
// Load and initialize all channels
renderStats();
// Initialize channels' content (needed to correctly size channels)
updateStats();
// Create channels
_audioDisplayChannels = QVector<QVector<AudioStatsDisplay*>>(1);
_audioMixerID = addChannel(_form, _audioMixerStats, COLOR0);
@ -80,9 +78,16 @@ AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
_upstreamMixerID = addChannel(_form, _upstreamMixerStats, COLOR2);
_downstreamID = addChannel(_form, _downstreamStats, COLOR3);
_upstreamInjectedID = addChannel(_form, _upstreamInjectedStats, COLOR0);
connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout()));
averageUpdateTimer->start(1000);
// Initialize channels
updateChannels();
// Future renders
connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(renderStats()));
averageUpdateTimer->start(200);
// Initial render
QDialog::setLayout(_form);
}
int AudioStatsDialog::addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color) {
@ -99,148 +104,152 @@ int AudioStatsDialog::addChannel(QFormLayout* form, QVector<QString>& stats, con
return channelID;
}
void AudioStatsDialog::updateStats(QVector<QString>& stats, int channelID) {
void AudioStatsDialog::renderStats() {
updateStats();
updateChannels();
}
void AudioStatsDialog::updateChannels() {
updateChannel(_audioMixerStats, _audioMixerID);
updateChannel(_upstreamClientStats, _upstreamClientID);
updateChannel(_upstreamMixerStats, _upstreamMixerID);
updateChannel(_downstreamStats, _downstreamID);
updateChannel(_upstreamInjectedStats, _upstreamInjectedID);
}
void AudioStatsDialog::updateChannel(QVector<QString>& stats, int channelID) {
// Update all stat displays at specified channel
for (int i = 0; i < stats.size(); i++)
_audioDisplayChannels[channelID].at(i)->updatedDisplay(stats.at(i));
}
void AudioStatsDialog::renderStats() {
void AudioStatsDialog::updateStats() {
// Clear current stats from all vectors
clearAllChannels();
double audioInputBufferLatency = 0.0,
inputRingBufferLatency = 0.0,
networkRoundtripLatency = 0.0,
mixerRingBufferLatency = 0.0,
outputRingBufferLatency = 0.0,
audioOutputBufferLatency = 0.0;
double audioInputBufferLatency{ 0.0 };
double inputRingBufferLatency{ 0.0 };
double networkRoundtripLatency{ 0.0 };
double mixerRingBufferLatency{ 0.0 };
double outputRingBufferLatency{ 0.0 };
double audioOutputBufferLatency{ 0.0 };
AudioStreamStats downstreamAudioStreamStats = _stats->getMixerDownstreamStats();
SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer);
if (!audioMixerNodePointer.isNull()) {
audioInputBufferLatency = (double)_stats->getAudioInputMsecsReadStats().getWindowAverage();
inputRingBufferLatency = (double)_stats->getInputRungBufferMsecsAvailableStats().getWindowAverage();
networkRoundtripLatency = (double) audioMixerNodePointer->getPingMs();
mixerRingBufferLatency = (double)_stats->getMixerAvatarStreamStats()._framesAvailableAverage *
(double)AudioConstants::NETWORK_FRAME_MSECS;
outputRingBufferLatency = (double)downstreamAudioStreamStats._framesAvailableAverage *
(double)AudioConstants::NETWORK_FRAME_MSECS;
audioOutputBufferLatency = (double)_stats->getAudioOutputMsecsUnplayedStats().getWindowAverage();
if (SharedNodePointer audioMixerNodePointer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AudioMixer)) {
audioInputBufferLatency = (double)_stats->getInputMsRead().getWindowMax();
inputRingBufferLatency = (double)_stats->getInputMsUnplayed().getWindowMax();
networkRoundtripLatency = (double)audioMixerNodePointer->getPingMs();
mixerRingBufferLatency = (double)_stats->getMixerAvatarStreamStats()._unplayedMs;
outputRingBufferLatency = (double)_stats->getMixerDownstreamStats()._unplayedMs;
audioOutputBufferLatency = (double)_stats->getOutputMsUnplayed().getWindowMax();
}
double totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency
+ outputRingBufferLatency + audioOutputBufferLatency;
QString stats = "Audio input buffer: %1ms - avg msecs of samples read to the audio input buffer in last 10s";
_audioMixerStats.push_back(stats.arg(QString::number(audioInputBufferLatency, 'f', 2)));
double totalLatency = audioInputBufferLatency + inputRingBufferLatency + mixerRingBufferLatency
+ outputRingBufferLatency + audioOutputBufferLatency + networkRoundtripLatency;
stats = "Input ring buffer: %1ms - avg msecs of samples read to the input ring buffer in last 10s";
_audioMixerStats.push_back(stats.arg(QString::number(inputRingBufferLatency, 'f', 2)));
stats = "Network to mixer: %1ms - half of last ping value calculated by the node list";
_audioMixerStats.push_back(stats.arg(QString::number((networkRoundtripLatency / 2.0), 'f', 2)));
stats = "Network to client: %1ms - half of last ping value calculated by the node list";
_audioMixerStats.push_back(stats.arg(QString::number((mixerRingBufferLatency / 2.0),'f', 2)));
stats = "Output ring buffer: %1ms - avg msecs of samples in output ring buffer in last 10s";
_audioMixerStats.push_back(stats.arg(QString::number(outputRingBufferLatency,'f', 2)));
stats = "Audio output buffer: %1ms - avg msecs of samples in audio output buffer in last 10s";
_audioMixerStats.push_back(stats.arg(QString::number(mixerRingBufferLatency,'f', 2)));
stats = "TOTAL: %1ms - avg msecs of samples in audio output buffer in last 10s";
_audioMixerStats.push_back(stats.arg(QString::number(totalLatency, 'f', 2)));
QString stats;
_audioMixerStats.push_back("PIPELINE (averaged over the past 10s)");
stats = "Input Read:\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(audioInputBufferLatency, 'f', 0)));
stats = "Input Ring:\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(inputRingBufferLatency, 'f', 0)));
stats = "Network (client->mixer):\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(networkRoundtripLatency / 2, 'f', 0)));
stats = "Mixer Ring:\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(mixerRingBufferLatency, 'f', 0)));
stats = "Network (mixer->client):\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(networkRoundtripLatency / 2, 'f', 0)));
stats = "Output Ring:\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(outputRingBufferLatency, 'f', 0)));
stats = "Output Read:\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(audioOutputBufferLatency, 'f', 0)));
stats = "TOTAL:\t%1 ms";
_audioMixerStats.push_back(stats.arg(QString::number(totalLatency, 'f', 0)));
const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketSentTimeGaps();
const MovingMinMaxAvg<quint64>& packetSentTimeGaps = _stats->getPacketTimegaps();
_upstreamClientStats.push_back("\nUpstream Mic Audio Packets Sent Gaps (by client):");
stats = "Inter-packet timegaps (overall) | min: %1, max: %2, avg: %3";
stats = "Inter-packet timegaps";
_upstreamClientStats.push_back(stats);
stats = "overall min:\t%1, max:\t%2, avg:\t%3";
stats = stats.arg(formatUsecTime(packetSentTimeGaps.getMin()),
formatUsecTime(packetSentTimeGaps.getMax()),
formatUsecTime(packetSentTimeGaps.getAverage()));
_upstreamClientStats.push_back(stats);
stats = "Inter-packet timegaps (last 30s) | min: %1, max: %2, avg: %3";
stats = "last window min:\t%1, max:\t%2, avg:\t%3";
stats = stats.arg(formatUsecTime(packetSentTimeGaps.getWindowMin()),
formatUsecTime(packetSentTimeGaps.getWindowMax()),
formatUsecTime(packetSentTimeGaps.getWindowAverage()));
_upstreamClientStats.push_back(stats);
_upstreamMixerStats.push_back("\nUpstream mic audio stats (received and reported by audio-mixer):");
_upstreamMixerStats.push_back("\nMIXER STREAM");
_upstreamMixerStats.push_back("(this client's remote mixer stream performance)");
renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), &_upstreamMixerStats, true);
renderAudioStreamStats(&_stats->getMixerAvatarStreamStats(), &_upstreamMixerStats);
_downstreamStats.push_back("\nDownstream mixed audio stats:");
_downstreamStats.push_back("\nCLIENT STREAM");
AudioStreamStats downstreamStats = _stats->getMixerDownstreamStats();
renderAudioStreamStats(&downstreamStats, &_downstreamStats, true);
renderAudioStreamStats(&downstreamStats, &_downstreamStats);
if (_shouldShowInjectedStreams) {
foreach(const AudioStreamStats& injectedStreamAudioStats, _stats->getMixerInjectedStreamStatsMap()) {
stats = "\nUpstream injected audio stats: stream ID: %1";
stats = "\nINJECTED STREAM (ID: %1)";
stats = stats.arg(injectedStreamAudioStats._streamIdentifier.toString());
_upstreamInjectedStats.push_back(stats);
renderAudioStreamStats(&injectedStreamAudioStats, &_upstreamInjectedStats, true);
renderAudioStreamStats(&injectedStreamAudioStats, &_upstreamInjectedStats);
}
}
}
void AudioStatsDialog::renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamStats, bool isDownstreamStats) {
void AudioStatsDialog::renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamStats) {
QString stats = "Packet loss | overall: %1% (%2 lost), last_30s: %3% (%4 lost)";
QString stats = "Packet Loss";
audioStreamStats->push_back(stats);
stats = "overall:\t%1%\t(%2 lost), window:\t%3%\t(%4 lost)";
stats = stats.arg(QString::number((int)(streamStats->_packetStreamStats.getLostRate() * 100.0f)),
QString::number((int)(streamStats->_packetStreamStats._lost)),
QString::number((int)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f)),
QString::number((int)(streamStats->_packetStreamWindowStats._lost)));
QString::number((int)(streamStats->_packetStreamStats._lost)),
QString::number((int)(streamStats->_packetStreamWindowStats.getLostRate() * 100.0f)),
QString::number((int)(streamStats->_packetStreamWindowStats._lost)));
audioStreamStats->push_back(stats);
if (isDownstreamStats) {
stats = "Ringbuffer frames | desired: %1, avg_available(10s): %2 + %3, available: %4 + %5";
stats = stats.arg(QString::number(streamStats->_desiredJitterBufferFrames),
QString::number(streamStats->_framesAvailableAverage),
QString::number((int)((float)_stats->getAudioInputMsecsReadStats().getWindowAverage() /
AudioConstants::NETWORK_FRAME_MSECS)),
QString::number(streamStats->_framesAvailable),
QString::number((int)(_stats->getAudioOutputMsecsUnplayedStats().getCurrentIntervalLastSample() /
AudioConstants::NETWORK_FRAME_MSECS)));
audioStreamStats->push_back(stats);
} else {
stats = "Ringbuffer frames | desired: %1, avg_available(10s): %2, available: %3";
stats = stats.arg(QString::number(streamStats->_desiredJitterBufferFrames),
QString::number(streamStats->_framesAvailableAverage),
QString::number(streamStats->_framesAvailable));
audioStreamStats->push_back(stats);
}
stats = "Ringbuffer stats | starves: %1, prev_starve_lasted: %2, frames_dropped: %3, overflows: %4";
stats = "Ringbuffer";
audioStreamStats->push_back(stats);
stats = "available frames (avg):\t%1\t(%2), desired:\t%3";
stats = stats.arg(QString::number(streamStats->_framesAvailable),
QString::number(streamStats->_framesAvailableAverage),
QString::number(streamStats->_desiredJitterBufferFrames));
audioStreamStats->push_back(stats);
stats = "starves:\t%1, last starve duration:\t%2, drops:\t%3, overflows:\t%4";
stats = stats.arg(QString::number(streamStats->_starveCount),
QString::number(streamStats->_consecutiveNotMixedCount),
QString::number(streamStats->_framesDropped),
QString::number(streamStats->_overflowCount));
QString::number(streamStats->_consecutiveNotMixedCount),
QString::number(streamStats->_framesDropped),
QString::number(streamStats->_overflowCount));
audioStreamStats->push_back(stats);
stats = "Inter-packet timegaps";
audioStreamStats->push_back(stats);
stats = "Inter-packet timegaps (overall) | min: %1, max: %2, avg: %3";
stats = "overall min:\t%1, max:\t%2, avg:\t%3";
stats = stats.arg(formatUsecTime(streamStats->_timeGapMin),
formatUsecTime(streamStats->_timeGapMax),
formatUsecTime(streamStats->_timeGapAverage));
formatUsecTime(streamStats->_timeGapMax),
formatUsecTime(streamStats->_timeGapAverage));
audioStreamStats->push_back(stats);
stats = "Inter-packet timegaps (last 30s) | min: %1, max: %2, avg: %3";
stats = "last window min:\t%1, max:\t%2, avg:\t%3";
stats = stats.arg(formatUsecTime(streamStats->_timeGapWindowMin),
formatUsecTime(streamStats->_timeGapWindowMax),
formatUsecTime(streamStats->_timeGapWindowAverage));
formatUsecTime(streamStats->_timeGapWindowMax),
formatUsecTime(streamStats->_timeGapWindowAverage));
audioStreamStats->push_back(stats);
}
void AudioStatsDialog::clearAllChannels() {
@ -251,21 +260,6 @@ void AudioStatsDialog::clearAllChannels() {
_upstreamInjectedStats.clear();
}
void AudioStatsDialog::updateTimerTimeout() {
renderStats();
// Update all audio stats
updateStats(_audioMixerStats, _audioMixerID);
updateStats(_upstreamClientStats, _upstreamClientID);
updateStats(_upstreamMixerStats, _upstreamMixerID);
updateStats(_downstreamStats, _downstreamID);
updateStats(_upstreamInjectedStats, _upstreamInjectedID);
}
void AudioStatsDialog::paintEvent(QPaintEvent* event) {
// Repaint each stat in each channel

View file

@ -70,18 +70,18 @@ private:
QVector<QVector<AudioStatsDisplay*>> _audioDisplayChannels;
void updateStats();
int addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color);
void updateStats(QVector<QString>& stats, const int channelID);
void renderStats();
void updateChannel(QVector<QString>& stats, const int channelID);
void updateChannels();
void clearAllChannels();
void renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamstats, bool isDownstreamStats);
void renderAudioStreamStats(const AudioStreamStats* streamStats, QVector<QString>* audioStreamstats);
const AudioIOStats* _stats;
QFormLayout* _form;
bool _isEnabled;
bool _shouldShowInjectedStreams;
bool _shouldShowInjectedStreams{ false };
signals:
@ -93,7 +93,7 @@ signals:
void reject() override;
void updateTimerTimeout();
void renderStats();
protected:

View file

@ -58,7 +58,10 @@ void CachesSizeDialog::confirmClicked(bool checked) {
DependencyManager::get<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<ModelCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<SoundCache>()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES);
// Disabling the texture cache because it's a liability in cases where we're overcommiting GPU memory
#if 0
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES);
#endif
QDialog::close();
}
@ -78,4 +81,4 @@ void CachesSizeDialog::reject() {
void CachesSizeDialog::closeEvent(QCloseEvent* event) {
QDialog::closeEvent(event);
emit closed();
}
}

View file

@ -1,54 +0,0 @@
//
// DataWebPage.cpp
// interface/src/ui
//
// Created by Stephen Birarda on 2014-09-22.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <qnetworkrequest.h>
#include "Application.h"
#include <AddressManager.h>
#include <OAuthNetworkAccessManager.h>
#include "DataWebPage.h"
DataWebPage::DataWebPage(QObject* parent) :
QWebPage(parent)
{
// use an OAuthNetworkAccessManager instead of regular QNetworkAccessManager so our requests are authed
setNetworkAccessManager(OAuthNetworkAccessManager::getInstance());
// give the page an empty stylesheet
settings()->setUserStyleSheetUrl(QUrl());
}
void DataWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) {
qDebug() << "JS console message at line" << lineNumber << "from" << sourceID << "-" << message;
}
bool DataWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) {
// Handle hifi:// links and links to files with particular extensions
QString urlString = request.url().toString();
if (qApp->canAcceptURL(urlString)) {
if (qApp->acceptURL(urlString)) {
return false; // we handled it, so QWebPage doesn't need to handle it
}
}
// Make hyperlinks with target="_blank" open in user's Web browser
if (type == QWebPage::NavigationTypeLinkClicked && frame == nullptr) {
qApp->openUrl(request.url());
return false; // We handled it.
}
return true;
}
QString DataWebPage::userAgentForUrl(const QUrl& url) const {
return HIGH_FIDELITY_USER_AGENT;
}

View file

@ -1,26 +0,0 @@
//
// DataWebPage.h
// interface/src/ui
//
// Created by Stephen Birarda on 2014-09-22.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_DataWebPage_h
#define hifi_DataWebPage_h
#include <qwebpage.h>
class DataWebPage : public QWebPage {
public:
DataWebPage(QObject* parent = 0);
protected:
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID) override;
bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, QWebPage::NavigationType type) override;
virtual QString userAgentForUrl(const QUrl& url) const override;
};
#endif // hifi_DataWebPage_h

View file

@ -20,7 +20,7 @@
#include <QCheckBox>
#include <QSyntaxHighlighter>
#include "AbstractLoggerInterface.h"
#include <shared/AbstractLoggerInterface.h>
class KeywordHighlighter : public QSyntaxHighlighter {
Q_OBJECT

View file

@ -228,6 +228,7 @@ void ModelHandler::update() {
QUrl url(_model.item(i,0)->data(Qt::UserRole).toString());
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.head(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
@ -280,6 +281,7 @@ void ModelHandler::queryNewFiles(QString marker) {
url.setQuery(query);
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));

View file

@ -188,95 +188,52 @@ void setupPreferences() {
static const QString AUDIO("Audio");
{
auto getter = []()->bool { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getDynamicJitterBuffers(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setDynamicJitterBuffers(value); };
preferences->addPreference(new CheckPreference(AUDIO, "Enable dynamic jitter buffers", getter, setter));
auto getter = []()->bool { return !DependencyManager::get<AudioClient>()->getReceivedAudioStream().dynamicJitterBufferEnabled(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setDynamicJitterBufferEnabled(!value); };
auto preference = new CheckPreference(AUDIO, "Disable dynamic jitter buffer", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getDesiredJitterBufferFrames(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setStaticDesiredJitterBufferFrames(value); };
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getStaticJitterBufferFrames(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setStaticJitterBufferFrames(value); };
auto preference = new SpinnerPreference(AUDIO, "Static jitter buffer frames", getter, setter);
preference->setMin(0);
preference->setMax(10000);
preference->setMax(2000);
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getMaxFramesOverDesired(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setMaxFramesOverDesired(value); };
auto preference = new SpinnerPreference(AUDIO, "Max frames over desired", getter, setter);
preference->setMax(10000);
preference->setStep(1);
auto getter = []()->bool { return !DependencyManager::get<AudioClient>()->getOutputStarveDetectionEnabled(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionEnabled(!value); };
auto preference = new CheckPreference(AUDIO, "Disable output starve detection", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = []()->bool { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getUseStDevForJitterCalc(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setUseStDevForJitterCalc(value); };
preferences->addPreference(new CheckPreference(AUDIO, "Use standard deviation for dynamic jitter calc", getter, setter));
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowStarveThreshold(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowStarveThreshold(value); };
auto preference = new SpinnerPreference(AUDIO, "Window A starve threshold", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowSecondsForDesiredCalcOnTooManyStarves(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowSecondsForDesiredCalcOnTooManyStarves(value); };
auto preference = new SpinnerPreference(AUDIO, "Window A (raise desired on N starves) seconds", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowSecondsForDesiredReduction(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowSecondsForDesiredReduction(value); };
auto preference = new SpinnerPreference(AUDIO, "Window B (desired ceiling) seconds", getter, setter);
preference->setMax(10000);
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = []()->bool { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getRepetitionWithFade(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setRepetitionWithFade(value); };
preferences->addPreference(new CheckPreference(AUDIO, "Repetition with fade", getter, setter));
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputBufferSize(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputBufferSize(value); };
auto preference = new SpinnerPreference(AUDIO, "Output buffer initial size (frames)", getter, setter);
preference->setMin(1);
preference->setMax(20);
auto preference = new SpinnerPreference(AUDIO, "Output buffer initial frames", getter, setter);
preference->setMin(AudioClient::MIN_BUFFER_FRAMES);
preference->setMax(AudioClient::MAX_BUFFER_FRAMES);
preference->setStep(1);
preferences->addPreference(preference);
}
#if DEV_BUILD || PR_BUILD
{
auto getter = []()->bool { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionEnabled(); };
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionEnabled(value); };
auto preference = new CheckPreference(AUDIO, "Output starve detection (automatic buffer size increase)", getter, setter);
auto getter = []()->bool { return DependencyManager::get<AudioClient>()->isSimulatingJitter(); };
auto setter = [](bool value) { return DependencyManager::get<AudioClient>()->setIsSimulatingJitter(value); };
auto preference = new CheckPreference(AUDIO, "Packet jitter simulator", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionThreshold(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionThreshold(value); };
auto preference = new SpinnerPreference(AUDIO, "Output starve detection threshold", getter, setter);
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getGateThreshold(); };
auto setter = [](float value) { return DependencyManager::get<AudioClient>()->setGateThreshold(value); };
auto preference = new SpinnerPreference(AUDIO, "Packet throttle threshold", getter, setter);
preference->setMin(1);
preference->setMax(500);
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionPeriod(); };
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionPeriod(value); };
auto preference = new SpinnerPreference(AUDIO, "Output starve detection period (ms)", getter, setter);
preference->setMin(1);
preference->setMax((float)999999999);
preference->setMax(200);
preference->setStep(1);
preferences->addPreference(preference);
}
#endif
{
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
@ -332,4 +289,19 @@ void setupPreferences() {
preferences->addPreference(preference);
}
}
{
static const QString RENDER("Networking");
auto nodelist = DependencyManager::get<NodeList>();
{
static const int MIN_PORT_NUMBER { 0 };
static const int MAX_PORT_NUMBER { 65535 };
auto getter = [nodelist] { return static_cast<int>(nodelist->getSocketLocalPort()); };
auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast<quint16>(preset)); };
auto preference = new IntSpinnerPreference(RENDER, "Listening Port", getter, setter);
preference->setMin(MIN_PORT_NUMBER);
preference->setMax(MAX_PORT_NUMBER);
preferences->addPreference(preference);
}
}
}

View file

@ -161,6 +161,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
} else {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(url);
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(networkRequest);
qDebug() << "Downloading included script at" << scriptPath;

Some files were not shown because too many files have changed in this diff Show more