Merge branch 'master' of https://github.com/highfidelity/hifi into domaincheckin

This commit is contained in:
Roxanne Skelly 2019-05-24 09:38:37 -07:00
commit aaee796aef
27 changed files with 451 additions and 272 deletions

View file

@ -25,7 +25,6 @@ vcpkg_from_github(
HEAD_REF master
)
vcpkg_configure_cmake(
SOURCE_PATH ${SOURCE_PATH}
OPTIONS

View file

@ -258,18 +258,13 @@ endif()
url = 'NOT DEFINED'
if platform.system() == 'Windows':
# TODO: figure out how to download with versionId
#url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows.tar.gz?versionId=Etx8novAe0.IxQ7AosLFtop7fZur.cx9'
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows.tar.gz'
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows2.tar.gz'
elif platform.system() == 'Darwin':
#url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos.tar.gz?versionId=QrGxwssB.WwU_z3QCyG7ghP1_VjTkQeK'
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos.tar.gz'
elif platform.system() == 'Linux':
if platform.linux_distribution()[1] == '16.04':
#url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-16.04.tar.gz?versionId=c9j7PW4uBDPLif7DKmgIhorh9WBMjZRB'
if platform.linux_distribution()[1][:3] == '16.':
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-16.04.tar.gz'
elif platform.linux_distribution()[1] == '18.04':
#url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-18.04.tar.gz?versionId=Z3TojPFdb5pXdahF3oi85jjKocpL0xqw'
elif platform.linux_distribution()[1][:3] == '18.':
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-18.04.tar.gz'
else:
print('UNKNOWN LINUX VERSION!!!')

View file

@ -60,7 +60,7 @@ Flickable {
HifiStylesUit.GraphikRegular {
id: volumeControlsTitle
text: "Volume Controls"
Layout.maximumWidth: parent.width
Layout.preferredWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
@ -68,8 +68,7 @@ Flickable {
SimplifiedControls.Slider {
id: peopleVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
height: 30
labelText: "People Volume"
@ -96,8 +95,7 @@ Flickable {
SimplifiedControls.Slider {
id: environmentVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: 2
height: 30
labelText: "Environment Volume"
@ -125,8 +123,7 @@ Flickable {
SimplifiedControls.Slider {
id: systemSoundVolume
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: 2
height: 30
labelText: "System Sound Volume"
@ -212,8 +209,7 @@ Flickable {
ListView {
id: inputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
@ -228,7 +224,7 @@ Flickable {
id: inputDeviceCheckbox
anchors.left: parent.left
width: parent.width - inputLevel.width
height: paintedHeight
height: 16
wrapLabel: false
checked: selectedDesktop
text: model.devicename
@ -251,6 +247,7 @@ Flickable {
}
SimplifiedControls.Button {
id: audioLoopbackButton
property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho()
function startAudioLoopback() {
@ -266,29 +263,23 @@ Flickable {
}
}
Timer {
id: loopbackTimer
interval: 8000
running: false
repeat: false
onTriggered: {
Component.onDestruction: stopAudioLoopback();
onVisibleChanged: {
if (!visible) {
stopAudioLoopback();
}
}
id: testYourMicButton
enabled: !HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: audioLoopedBack ? "STOP TESTING" : "TEST YOUR MIC"
onClicked: {
if (audioLoopedBack) {
loopbackTimer.stop();
stopAudioLoopback();
} else {
loopbackTimer.restart();
startAudioLoopback();
}
}
@ -313,8 +304,7 @@ Flickable {
ListView {
id: outputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
@ -329,7 +319,7 @@ Flickable {
id: outputDeviceCheckbox
anchors.left: parent.left
width: parent.width
height: paintedHeight
height: 16
checked: selectedDesktop
text: model.devicename
wrapLabel: false
@ -381,7 +371,6 @@ Flickable {
id: testYourSoundButton
enabled: !HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32

View file

@ -198,8 +198,7 @@ Flickable {
ListView {
id: inputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
@ -214,8 +213,10 @@ Flickable {
id: inputDeviceCheckbox
anchors.left: parent.left
width: parent.width - inputLevel.width
height: 16
checked: selectedHMD
text: model.devicename
wrapLabel: false
ButtonGroup.group: inputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo
@ -235,6 +236,7 @@ Flickable {
}
SimplifiedControls.Button {
id: audioLoopbackButton
property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho()
function startAudioLoopback() {
@ -250,29 +252,23 @@ Flickable {
}
}
Timer {
id: loopbackTimer
interval: 8000
running: false
repeat: false
onTriggered: {
Component.onDestruction: stopAudioLoopback();
onVisibleChanged: {
if (!visible) {
stopAudioLoopback();
}
}
id: testYourMicButton
enabled: HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32
text: audioLoopedBack ? "STOP TESTING" : "TEST YOUR MIC"
onClicked: {
if (audioLoopedBack) {
loopbackTimer.stop();
stopAudioLoopback();
} else {
loopbackTimer.restart();
startAudioLoopback();
}
}
@ -297,8 +293,7 @@ Flickable {
ListView {
id: outputDeviceListView
anchors.left: parent.left
anchors.right: parent.right
Layout.preferredWidth: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
interactive: false
height: contentItem.height
@ -313,11 +308,13 @@ Flickable {
id: outputDeviceCheckbox
anchors.left: parent.left
width: parent.width
checked: selectedDesktop
height: 16
checked: selectedHMD
text: model.devicename
wrapLabel: false
ButtonGroup.group: outputDeviceButtonGroup
onClicked: {
AudioScriptingInterface.setOutputDevice(model.info, true); // `false` argument for Desktop mode setting
AudioScriptingInterface.setOutputDevice(model.info, true); // `true` argument for VR mode setting
}
}
}
@ -363,7 +360,6 @@ Flickable {
id: testYourSoundButton
enabled: HMD.active
anchors.left: parent.left
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
width: 160
height: 32

View file

@ -3800,10 +3800,14 @@ void Application::handleSandboxStatus(QNetworkReply* reply) {
// If this is a first run we short-circuit the address passed in
if (_firstRun.get()) {
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
_firstRun.set(false);
if (!_overrideEntry) {
DependencyManager::get<AddressManager>()->goToEntry();
sentTo = SENT_TO_ENTRY;
} else {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
sentTo = SENT_TO_PREVIOUS_LOCATION;
}
_firstRun.set(false);
} else {
QString goingTo = "";
if (addressLookupString.isEmpty()) {
@ -9354,6 +9358,19 @@ void Application::showUrlHandler(const QUrl& url) {
}
});
}
void Application::overrideEntry(){
_overrideEntry = true;
}
void Application::forceDisplayName(const QString& displayName) {
getMyAvatar()->setDisplayName(displayName);
}
void Application::forceLoginWithTokens(const QString& tokens) {
DependencyManager::get<AccountManager>()->setAccessTokens(tokens);
Setting::Handle<bool>(KEEP_ME_LOGGED_IN_SETTING_NAME, true).set(true);
}
void Application::setConfigFileURL(const QString& fileUrl) {
DependencyManager::get<AccountManager>()->setConfigFileURL(fileUrl);
}
#if defined(Q_OS_ANDROID)
void Application::beforeEnterBackground() {

View file

@ -356,6 +356,11 @@ public:
void openDirectory(const QString& path);
void overrideEntry();
void forceDisplayName(const QString& displayName);
void forceLoginWithTokens(const QString& tokens);
void setConfigFileURL(const QString& fileUrl);
signals:
void svoImportRequested(const QString& url);
@ -828,5 +833,6 @@ private:
bool _resumeAfterLoginDialogActionTaken_WasPostponed { false };
bool _resumeAfterLoginDialogActionTaken_SafeToRun { false };
bool _startUpFinished { false };
bool _overrideEntry { false };
};
#endif // hifi_Application_h

View file

@ -521,6 +521,7 @@ void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transact
}
}
}
_otherAvatarsToChangeInPhysics.clear();
}
void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
@ -645,7 +646,7 @@ void AvatarManager::clearOtherAvatars() {
}
void AvatarManager::deleteAllAvatars() {
assert(_otherAvatarsToChangeInPhysics.empty());
_otherAvatarsToChangeInPhysics.clear();
QReadLocker locker(&_hashLock);
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {

View file

@ -83,6 +83,8 @@ int main(int argc, const char* argv[]) {
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache <dir>", "dir");
QCommandLineOption overrideScriptsPathOption(SCRIPTS_SWITCH, "set scripts <path>", "path");
QCommandLineOption responseTokensOption("tokens", "set response tokens <json>", "json");
QCommandLineOption displayNameOption("displayName", "set user display name <string>", "string");
parser.addOption(urlOption);
parser.addOption(noLauncherOption);
@ -93,6 +95,8 @@ int main(int argc, const char* argv[]) {
parser.addOption(overrideAppLocalDataPathOption);
parser.addOption(overrideScriptsPathOption);
parser.addOption(allowMultipleInstancesOption);
parser.addOption(responseTokensOption);
parser.addOption(displayNameOption);
if (!parser.parse(arguments)) {
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
@ -120,7 +124,9 @@ int main(int argc, const char* argv[]) {
static const QString APPLICATION_CONFIG_FILENAME = "config.json";
QDir applicationDir(applicationPath);
QFile configFile(applicationDir.filePath(APPLICATION_CONFIG_FILENAME));
QString configFileName = applicationDir.filePath(APPLICATION_CONFIG_FILENAME);
QFile configFile(configFileName);
QString launcherPath;
if (configFile.exists()) {
if (!configFile.open(QIODevice::ReadOnly)) {
@ -134,7 +140,7 @@ int main(int argc, const char* argv[]) {
qWarning() << "Found application config, but could not parse it: " << error.errorString();
} else {
static const QString LAUNCHER_PATH_KEY = "launcherPath";
QString launcherPath = doc.object()[LAUNCHER_PATH_KEY].toString();
launcherPath = doc.object()[LAUNCHER_PATH_KEY].toString();
if (!launcherPath.isEmpty()) {
if (!parser.isSet(noLauncherOption)) {
qDebug() << "Found a launcherPath in application config. Starting launcher.";
@ -146,6 +152,7 @@ int main(int argc, const char* argv[]) {
qDebug() << "Found a launcherPath in application config, but the launcher"
" has been suppressed. Continuing normal execution.";
}
configFile.close();
}
}
}
@ -398,6 +405,24 @@ int main(int argc, const char* argv[]) {
printSystemInformation();
auto appPointer = dynamic_cast<Application*>(&app);
if (appPointer) {
if (parser.isSet(urlOption)) {
appPointer->overrideEntry();
}
if (parser.isSet(displayNameOption)) {
QString displayName = QString(parser.value(displayNameOption));
appPointer->forceDisplayName(displayName);
}
if (!launcherPath.isEmpty()) {
appPointer->setConfigFileURL(configFileName);
}
if (parser.isSet(responseTokensOption)) {
QString tokens = QString(parser.value(responseTokensOption));
appPointer->forceLoginWithTokens(tokens);
}
}
QTranslator translator;
translator.load("i18n/interface_en");
app.installTranslator(&translator);

View file

@ -2162,6 +2162,8 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
}
bytesWritten = framesPopped * AudioConstants::SAMPLE_SIZE * deviceChannelCount;
assert(bytesWritten <= maxSize);
} else {
// nothing on network, don't grab anything from injectors, and just return 0s
memset(data, 0, maxSize);
@ -2174,7 +2176,6 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
_audio->_audioFileWav.addRawAudioChunk(reinterpret_cast<char*>(scratchBuffer), bytesWritten);
}
int bytesAudioOutputUnplayed = _audio->_audioOutput->bufferSize() - _audio->_audioOutput->bytesFree();
float msecsAudioOutputUnplayed = bytesAudioOutputUnplayed / (float)_audio->_outputFormat.bytesForDuration(USECS_PER_MSEC);
_audio->_stats.updateOutputMsUnplayed(msecsAudioOutputUnplayed);

View file

@ -364,10 +364,19 @@ int InboundAudioStream::popSamples(int maxSamples, bool allOrNothing) {
// buffer calculations.
setToStarved();
_consecutiveNotMixedCount++;
//Kick PLC to generate a filler frame, reducing 'click'
lostAudioData(allOrNothing ? (maxSamples - samplesAvailable) / _ringBuffer.getNumFrameSamples() : 1);
samplesPopped = _ringBuffer.samplesAvailable();
if (samplesPopped) {
// use PLC to generate extrapolated audio data, to reduce clicking
if (allOrNothing) {
int samplesNeeded = maxSamples - samplesAvailable;
int packetsNeeded = (samplesNeeded + _ringBuffer.getNumFrameSamples() - 1) / _ringBuffer.getNumFrameSamples();
lostAudioData(packetsNeeded);
} else {
lostAudioData(1);
}
samplesAvailable = _ringBuffer.samplesAvailable();
if (samplesAvailable > 0) {
samplesPopped = std::min(samplesAvailable, maxSamples);
popSamplesNoCheck(samplesPopped);
} else {
// No samples available means a packet is currently being

View file

@ -97,6 +97,7 @@ void AccountManager::logout() {
// remove this account from the account settings file
removeAccountFromFile();
saveLoginStatus(false);
emit logoutComplete();
// the username has changed to blank
@ -650,6 +651,39 @@ void AccountManager::refreshAccessToken() {
}
}
void AccountManager::setAccessTokens(const QString& response) {
QJsonDocument jsonResponse = QJsonDocument::fromJson(response.toUtf8());
const QJsonObject& rootObject = jsonResponse.object();
if (!rootObject.contains("error")) {
// construct an OAuthAccessToken from the json object
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|| !rootObject.contains("token_type")) {
// TODO: error handling - malformed token response
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
} else {
// clear the path from the response URL so we have the right root URL for this access token
QUrl rootURL = rootObject.contains("url") ? rootObject["url"].toString() : _authURL;
rootURL.setPath("");
qCDebug(networking) << "Storing an account with access-token for" << qPrintable(rootURL.toString());
_accountInfo = DataServerAccountInfo();
_accountInfo.setAccessTokenFromJSON(rootObject);
emit loginComplete(rootURL);
persistAccountToFile();
saveLoginStatus(true);
requestProfile();
}
} else {
// TODO: error handling
qCDebug(networking) << "Error in response for password grant -" << rootObject["error_description"].toString();
emit loginFailed();
}
}
void AccountManager::requestAccessTokenFinished() {
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
@ -895,3 +929,34 @@ void AccountManager::handleKeypairGenerationError() {
void AccountManager::setLimitedCommerce(bool isLimited) {
_limitedCommerce = isLimited;
}
void AccountManager::saveLoginStatus(bool isLoggedIn) {
if (!_configFileURL.isEmpty()) {
QFile configFile(_configFileURL);
configFile.open(QIODevice::ReadOnly | QIODevice::Text);
QJsonParseError error;
QJsonDocument jsonDocument = QJsonDocument::fromJson(configFile.readAll(), &error);
configFile.close();
QString launcherPath;
if (error.error == QJsonParseError::NoError) {
QJsonObject rootObject = jsonDocument.object();
if (rootObject.contains("launcherPath")) {
launcherPath = rootObject["launcherPath"].toString();
}
if (rootObject.contains("loggedIn")) {
rootObject["loggedIn"] = isLoggedIn;
}
jsonDocument = QJsonDocument(rootObject);
}
configFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
configFile.write(jsonDocument.toJson());
configFile.close();
if (!isLoggedIn && !launcherPath.isEmpty()) {
QProcess launcher;
launcher.setProgram(launcherPath);
launcher.startDetached();
qApp->quit();
}
}
}

View file

@ -102,6 +102,10 @@ public:
bool getLimitedCommerce() { return _limitedCommerce; }
void setLimitedCommerce(bool isLimited);
void setAccessTokens(const QString& response);
void setConfigFileURL(const QString& fileURL) { _configFileURL = fileURL; }
void saveLoginStatus(bool isLoggedIn);
public slots:
void requestAccessToken(const QString& login, const QString& password);
void requestAccessTokenWithSteam(QByteArray authSessionTicket);
@ -162,6 +166,7 @@ private:
QUuid _sessionID { QUuid::createUuid() };
bool _limitedCommerce { false };
QString _configFileURL;
};
#endif // hifi_AccountManager_h

View file

@ -0,0 +1,41 @@
"use strict";
/* jslint vars: true, plusplus: true */
//
// defaultScripts.js
//
// Authors: Zach Fox
// Created: 2019-05-23
// Copyright 2019 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
//
var DEFAULT_SCRIPTS_PATH_PREFIX = ScriptDiscoveryService.defaultScriptsPath + "/";
var DEFAULT_SCRIPTS_SEPARATE = [
DEFAULT_SCRIPTS_PATH_PREFIX + "system/controllers/controllerScripts.js",
Script.resolvePath("simplifiedUI.js")
];
function loadSeparateDefaults() {
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
}
}
var DEFAULT_SCRIPTS_COMBINED = [
DEFAULT_SCRIPTS_PATH_PREFIX + "system/request-service.js",
DEFAULT_SCRIPTS_PATH_PREFIX + "system/progress.js",
DEFAULT_SCRIPTS_PATH_PREFIX + "system/away.js"
];
function runDefaultsTogether() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.include(DEFAULT_SCRIPTS_COMBINED[i]);
}
loadSeparateDefaults();
}
runDefaultsTogether();

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -5,7 +5,7 @@
// simplifiedUI.js
//
// Authors: Wayne Chen & Zach Fox
// Created on: 5/1/2019
// Created: 2019-05-01
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
@ -103,6 +103,8 @@ var AVATAR_APP_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var AVATAR_APP_WIDTH_PX = 480;
var AVATAR_APP_HEIGHT_PX = 615;
var avatarAppWindow = false;
var POPOUT_SAFE_MARGIN_X = 30;
var POPOUT_SAFE_MARGIN_Y = 30;
function toggleAvatarApp() {
if (avatarAppWindow) {
avatarAppWindow.close();
@ -119,6 +121,10 @@ function toggleAvatarApp() {
size: {
x: AVATAR_APP_WIDTH_PX,
y: AVATAR_APP_HEIGHT_PX
},
position: {
x: Math.max(Window.x + POPOUT_SAFE_MARGIN_X, Window.x + Window.innerWidth / 2 - AVATAR_APP_WIDTH_PX / 2),
y: Math.max(Window.y + POPOUT_SAFE_MARGIN_Y, Window.y + Window.innerHeight / 2 - AVATAR_APP_HEIGHT_PX / 2)
}
});
@ -181,6 +187,10 @@ function toggleSettingsApp() {
size: {
x: SETTINGS_APP_WIDTH_PX,
y: SETTINGS_APP_HEIGHT_PX
},
position: {
x: Math.max(Window.x + POPOUT_SAFE_MARGIN_X, Window.x + Window.innerWidth / 2 - SETTINGS_APP_WIDTH_PX / 2),
y: Math.max(Window.y + POPOUT_SAFE_MARGIN_Y, Window.y + Window.innerHeight / 2 - SETTINGS_APP_HEIGHT_PX / 2)
}
});

View file

@ -0,0 +1,20 @@
# Post build script
import os
import sys
SOURCE_PATH = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..', '..'))
BUILD_PATH = os.path.join(SOURCE_PATH, 'build')
# FIXME move the helper python modules somewher other than the root of the repo
sys.path.append(SOURCE_PATH)
import hifi_utils
#for var in sys.argv:
# print("{}".format(var))
#for var in os.environ:
# print("{} = {}".format(var, os.environ[var]))
print("Create ZIP version of installer archive")
hifi_utils.executeSubprocess(['cpack', '-G', 'ZIP'], folder=BUILD_PATH)

View file

@ -1,6 +1,6 @@
@echo off
REM Set up \Microsoft Visual Studio 2015, where <arch> is \c amd64, \c x86, etc.
REM Set up \Microsoft Visual Studio 2017, where <arch> is \c amd64, \c x86, etc.
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
REM Edit this location to point to the source code of Qt