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

This commit is contained in:
RebeccaStankus 2019-08-14 12:04:20 -07:00
commit 9a5812d72c
52 changed files with 1483 additions and 362 deletions

View file

@ -5,7 +5,7 @@ If you are upgrading from previous versions, do a clean uninstall of those versi
Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory. Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory.
### Step 1. Visual Studio & Python ### Step 1. Visual Studio & Python 3.x
If you dont have Community or Professional edition of Visual Studio, download [Visual Studio Community 2019](https://visualstudio.microsoft.com/vs/). If you have Visual Studio 2017, you are not required to download Visual Studio 2019. If you dont have Community or Professional edition of Visual Studio, download [Visual Studio Community 2019](https://visualstudio.microsoft.com/vs/). If you have Visual Studio 2017, you are not required to download Visual Studio 2019.
@ -21,7 +21,7 @@ When selecting components, check "Desktop development with C++". On the right on
* MSVC v141 - VS 2017 C++ x64/x86 build tools * MSVC v141 - VS 2017 C++ x64/x86 build tools
* MSVC v140 - VS 2015 C++ build tools (v14.00) * MSVC v140 - VS 2015 C++ build tools (v14.00)
If you do not already have a Python development environment installed, also check "Python Development" in this screen. If you do not already have a Python 3.x development environment installed, also check "Python Development" in this screen.
If you already have Visual Studio installed and need to add Python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes. If you already have Visual Studio installed and need to add Python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes.
@ -31,9 +31,10 @@ If you do not wish to use the Python installation bundled with Visual Studio, yo
### Step 2. Installing CMake ### Step 2. Installing CMake
Download and install the latest version of CMake 3.14. Download and install the latest version of CMake 3.15.
* Note that earlier versions of CMake will work, but there is a specific bug related to the interaction of Visual Studio 2019 and CMake versions prior to 3.15 that will cause Visual Studio to rebuild far more than it needs to on every build
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.14 Version page](https://cmake.org/files/v3.14/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted. Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.15 Version page](https://cmake.org/files/v3.15/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
### Step 3. Create VCPKG environment variable ### Step 3. Create VCPKG environment variable
In the next step, you will use CMake to build High Fidelity. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them. In the next step, you will use CMake to build High Fidelity. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them.
@ -42,9 +43,18 @@ To create this variable:
* Naviagte to 'Edit the System Environment Variables' Through the start menu. * Naviagte to 'Edit the System Environment Variables' Through the start menu.
* Click on 'Environment Variables' * Click on 'Environment Variables'
* Select 'New' * Select 'New'
* Set "Variable name" to HIFI_VCPKG_BASE * Set "Variable name" to `HIFI_VCPKG_BASE`
* Set "Variable value" to any directory that you have control over. * Set "Variable value" to any directory that you have control over.
Additionally, if you have Visual Studio 2019 installed and _only_ Visual Studio 2019 (i.e. you do not have Visual Studio 2017 installed) you must add an additional environment variable `HIFI_VCPKG_BOOTSTRAP` that will fix a bug in our `vcpkg` pre-build step.
To create this variable:
* Naviagte to 'Edit the System Environment Variables' Through the start menu.
* Click on 'Environment Variables'
* Select 'New'
* Set "Variable name" to `HIFI_VCPKG_BOOTSTRAP`
* Set "Variable value" to `1`
### Step 4. Running CMake to Generate Build Files ### Step 4. Running CMake to Generate Build Files
Run Command Prompt from Start and run the following commands: Run Command Prompt from Start and run the following commands:

View file

@ -75,7 +75,7 @@ public:
void each(std::function<void(AvatarMixerSlave& slave)> functor); void each(std::function<void(AvatarMixerSlave& slave)> functor);
#ifdef DEBUG_EVENT_QUEUE #ifdef DEBUG_EVENT_QUEUE
void AvatarMixerSlavePool::queueStats(QJsonObject& stats); void queueStats(QJsonObject& stats);
#endif #endif
void setNumThreads(int numThreads); void setNumThreads(int numThreads);

View file

@ -71,16 +71,19 @@ endif()
if 'Windows' == system: if 'Windows' == system:
self.exe = os.path.join(self.path, 'vcpkg.exe') self.exe = os.path.join(self.path, 'vcpkg.exe')
self.bootstrapCmd = 'bootstrap-vcpkg.bat'
self.vcpkgUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/vcpkg-win32.tar.gz?versionId=YZYkDejDRk7L_hrK_WVFthWvisAhbDzZ' self.vcpkgUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/vcpkg-win32.tar.gz?versionId=YZYkDejDRk7L_hrK_WVFthWvisAhbDzZ'
self.vcpkgHash = '3e0ff829a74956491d57666109b3e6b5ce4ed0735c24093884317102387b2cb1b2cd1ff38af9ed9173501f6e32ffa05cc6fe6d470b77a71ca1ffc3e0aa46ab9e' self.vcpkgHash = '3e0ff829a74956491d57666109b3e6b5ce4ed0735c24093884317102387b2cb1b2cd1ff38af9ed9173501f6e32ffa05cc6fe6d470b77a71ca1ffc3e0aa46ab9e'
self.hostTriplet = 'x64-windows' self.hostTriplet = 'x64-windows'
elif 'Darwin' == system: elif 'Darwin' == system:
self.exe = os.path.join(self.path, 'vcpkg') self.exe = os.path.join(self.path, 'vcpkg')
self.bootstrapCmd = 'bootstrap-vcpkg.sh'
self.vcpkgUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/vcpkg-osx.tar.gz?versionId=_fhqSxjfrtDJBvEsQ8L_ODcdUjlpX9cc' self.vcpkgUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/vcpkg-osx.tar.gz?versionId=_fhqSxjfrtDJBvEsQ8L_ODcdUjlpX9cc'
self.vcpkgHash = '519d666d02ef22b87c793f016ca412e70f92e1d55953c8f9bd4ee40f6d9f78c1df01a6ee293907718f3bbf24075cc35492fb216326dfc50712a95858e9cbcb4d' self.vcpkgHash = '519d666d02ef22b87c793f016ca412e70f92e1d55953c8f9bd4ee40f6d9f78c1df01a6ee293907718f3bbf24075cc35492fb216326dfc50712a95858e9cbcb4d'
self.hostTriplet = 'x64-osx' self.hostTriplet = 'x64-osx'
else: else:
self.exe = os.path.join(self.path, 'vcpkg') self.exe = os.path.join(self.path, 'vcpkg')
self.bootstrapCmd = 'bootstrap-vcpkg.sh'
self.vcpkgUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/vcpkg-linux.tar.gz?versionId=97Nazh24etEVKWz33XwgLY0bvxEfZgMU' self.vcpkgUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/vcpkg-linux.tar.gz?versionId=97Nazh24etEVKWz33XwgLY0bvxEfZgMU'
self.vcpkgHash = '6a1ce47ef6621e699a4627e8821ad32528c82fce62a6939d35b205da2d299aaa405b5f392df4a9e5343dd6a296516e341105fbb2dd8b48864781d129d7fba10d' self.vcpkgHash = '6a1ce47ef6621e699a4627e8821ad32528c82fce62a6939d35b205da2d299aaa405b5f392df4a9e5343dd6a296516e341105fbb2dd8b48864781d129d7fba10d'
self.hostTriplet = 'x64-linux' self.hostTriplet = 'x64-linux'
@ -141,8 +144,14 @@ endif()
downloadVcpkg = True downloadVcpkg = True
if downloadVcpkg: if downloadVcpkg:
print("Fetching vcpkg from {} to {}".format(self.vcpkgUrl, self.path)) if "HIFI_VCPKG_BOOTSTRAP" in os.environ:
hifi_utils.downloadAndExtract(self.vcpkgUrl, self.path, self.vcpkgHash) print("Cloning vcpkg from github to {}".format(self.path))
hifi_utils.executeSubprocess(['git', 'clone', 'git@github.com:microsoft/vcpkg.git', self.path])
print("Bootstrapping vcpkg")
hifi_utils.executeSubprocess([self.bootstrapCmd], folder=self.path)
else:
print("Fetching vcpkg from {} to {}".format(self.vcpkgUrl, self.path))
hifi_utils.downloadAndExtract(self.vcpkgUrl, self.path, self.vcpkgHash)
print("Replacing port files") print("Replacing port files")
portsPath = os.path.join(self.path, 'ports') portsPath = os.path.join(self.path, 'ports')

File diff suppressed because it is too large Load diff

View file

@ -27,11 +27,15 @@ Rectangle {
HifiConstants { id: hifi } HifiConstants { id: hifi }
readonly property real treeScale: 32768; // ~20 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe // This controls the LOD. Larger number will make smaller objects visible at greater distance.
readonly property real halfTreeScale: treeScale / 2; readonly property real defaultMaxVisibilityDistance: 400.0
readonly property real unitElementMaxExtent: Math.sqrt(3.0) * 0.5
// This controls the LOD. Larger number will make smaller voxels visible at greater distance.
readonly property real defaultOctreeSizeScale: treeScale * 400.0 function visibilityDistanceToLODAngleDeg(visibilityDistance) {
var lodHalfAngle = Math.atan(unitElementMaxExtent / visibilityDistance);
var lodAngle = lodHalfAngle * 2.0;
return lodAngle * 180.0 / Math.PI;
}
Column { Column {
anchors.margins: 10 anchors.margins: 10
@ -71,7 +75,7 @@ Rectangle {
id: adjustCheckbox id: adjustCheckbox
boxSize: 20 boxSize: 20
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onCheckedChanged: LODManager.setAutomaticLODAdjust(!checked); onCheckedChanged: LODManager.setAutomaticLODAdjust(!adjustCheckbox.checked);
} }
} }
@ -89,10 +93,10 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
minimumValue: 5 minimumValue: 5
maximumValue: 2000 maximumValue: 2000
value: LODManager.getOctreeSizeScale() / treeScale value: defaultMaxVisibilityDistance
tickmarksEnabled: false tickmarksEnabled: false
onValueChanged: { onValueChanged: {
LODManager.setOctreeSizeScale(value * treeScale); LODManager.lodAngleDeg = visibilityDistanceToLODAngleDeg(slider.value);
whatYouCanSeeLabel.text = LODManager.getLODFeedbackText() whatYouCanSeeLabel.text = LODManager.getLODFeedbackText()
} }
} }
@ -106,7 +110,7 @@ Rectangle {
colorScheme: root.colorScheme colorScheme: root.colorScheme
height: 30 height: 30
onClicked: { onClicked: {
slider.value = defaultOctreeSizeScale/treeScale slider.value = defaultMaxVisibilityDistance
adjustCheckbox.checked = false adjustCheckbox.checked = false
LODManager.setAutomaticLODAdjust(adjustCheckbox.checked); LODManager.setAutomaticLODAdjust(adjustCheckbox.checked);
} }

View file

@ -292,7 +292,7 @@ static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;
// For processing on QThreadPool, we target a number of threads after reserving some // For processing on QThreadPool, we target a number of threads after reserving some
// based on how many are being consumed by the application and the display plugin. However, // based on how many are being consumed by the application and the display plugin. However,
// we will never drop below the 'min' value // we will never drop below the 'min' value
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 1; static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2;
static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString JPG_EXTENSION = ".jpg"; static const QString JPG_EXTENSION = ".jpg";
@ -4418,8 +4418,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
} else if (isMeta) { } else if (isMeta) {
auto dialogsManager = DependencyManager::get<DialogsManager>(); auto dialogsManager = DependencyManager::get<DialogsManager>();
dialogsManager->toggleAddressBar(); dialogsManager->toggleAddressBar();
} else if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::LodTools);
} }
break; break;
@ -6817,8 +6815,8 @@ void Application::updateRenderArgs(float deltaTime) {
_viewFrustum.setProjection(adjustedProjection); _viewFrustum.setProjection(adjustedProjection);
_viewFrustum.calculate(); _viewFrustum.calculate();
} }
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getOctreeSizeScale(), appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getVisibilityDistance(),
lodManager->getBoundaryLevelAdjust(), lodManager->getLODAngleHalfTan(), RenderArgs::DEFAULT_RENDER_MODE, lodManager->getBoundaryLevelAdjust(), lodManager->getLODHalfAngleTan(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE); RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE);
appRenderArgs._renderArgs._scene = getMain3DScene(); appRenderArgs._renderArgs._scene = getMain3DScene();

View file

@ -12,7 +12,6 @@
#include "LODManager.h" #include "LODManager.h"
#include <SettingHandle.h> #include <SettingHandle.h>
#include <OctreeUtils.h>
#include <Util.h> #include <Util.h>
#include <shared/GlobalAppProperties.h> #include <shared/GlobalAppProperties.h>
@ -93,8 +92,7 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
return; return;
} }
// Previous values for output // Previous value for output
float oldOctreeSizeScale = getOctreeSizeScale();
float oldLODAngle = getLODAngleDeg(); float oldLODAngle = getLODAngleDeg();
// Target fps is slightly overshooted by 5hz // Target fps is slightly overshooted by 5hz
@ -165,7 +163,7 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
// And now add the output of the controller to the LODAngle where we will guarantee it is in the proper range // And now add the output of the controller to the LODAngle where we will guarantee it is in the proper range
setLODAngleDeg(oldLODAngle + output); setLODAngleDeg(oldLODAngle + output);
if (oldOctreeSizeScale != _octreeSizeScale) { if (oldLODAngle != getLODAngleDeg()) {
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
if (lodToolsDialog) { if (lodToolsDialog) {
lodToolsDialog->reloadSliders(); lodToolsDialog->reloadSliders();
@ -173,21 +171,32 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
} }
} }
float LODManager::getLODAngleHalfTan() const { float LODManager::getLODHalfAngleTan() const {
return getPerspectiveAccuracyAngleTan(_octreeSizeScale, _boundaryLevelAdjust); return tan(_lodHalfAngle);
} }
float LODManager::getLODAngle() const { float LODManager::getLODAngle() const {
return 2.0f * atanf(getLODAngleHalfTan()); return 2.0f * _lodHalfAngle;
} }
float LODManager::getLODAngleDeg() const { float LODManager::getLODAngleDeg() const {
return glm::degrees(getLODAngle()); return glm::degrees(getLODAngle());
} }
float LODManager::getVisibilityDistance() const {
float systemDistance = getVisibilityDistanceFromHalfAngle(_lodHalfAngle);
// Maintain behavior with deprecated _boundaryLevelAdjust property
return systemDistance * powf(2.0f, _boundaryLevelAdjust);
}
void LODManager::setVisibilityDistance(float distance) {
// Maintain behavior with deprecated _boundaryLevelAdjust property
float userDistance = distance / powf(2.0f, _boundaryLevelAdjust);
_lodHalfAngle = getHalfAngleFromVisibilityDistance(userDistance);
}
void LODManager::setLODAngleDeg(float lodAngle) { void LODManager::setLODAngleDeg(float lodAngle) {
auto newSolidAngle = std::max(0.5f, std::min(lodAngle, 90.f)); auto newLODAngleDeg = std::max(0.001f, std::min(lodAngle, 90.f));
auto halTan = glm::tan(glm::radians(newSolidAngle * 0.5f)); auto newLODHalfAngle = glm::radians(newLODAngleDeg * 0.5f);
auto octreeSizeScale = TREE_SCALE * OCTREE_TO_MESH_RATIO / halTan; _lodHalfAngle = newLODHalfAngle;
setOctreeSizeScale(octreeSizeScale);
} }
void LODManager::setSmoothScale(float t) { void LODManager::setSmoothScale(float t) {
@ -267,7 +276,11 @@ bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) {
}; };
void LODManager::setOctreeSizeScale(float sizeScale) { void LODManager::setOctreeSizeScale(float sizeScale) {
_octreeSizeScale = sizeScale; setVisibilityDistance(sizeScale / TREE_SCALE);
}
float LODManager::getOctreeSizeScale() const {
return getVisibilityDistance() * TREE_SCALE;
} }
void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
@ -293,12 +306,14 @@ QString LODManager::getLODFeedbackText() {
} break; } break;
} }
// distance feedback // distance feedback
float octreeSizeScale = getOctreeSizeScale(); float visibilityDistance = getVisibilityDistance();
float relativeToDefault = octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE; float relativeToDefault = visibilityDistance / DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT;
int relativeToTwentyTwenty = 20 / relativeToDefault; int relativeToTwentyTwenty = 20 / relativeToDefault;
QString result; QString result;
if (relativeToDefault > 1.01f) { if (relativeToTwentyTwenty < 1) {
result = QString("%2 times further than average vision%3").arg(relativeToDefault, 0, 'f', 3).arg(granularityFeedback);
} else if (relativeToDefault > 1.01f) {
result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault, 0, 'f', 2).arg(granularityFeedback); result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault, 0, 'f', 2).arg(granularityFeedback);
} else if (relativeToDefault > 0.99f) { } else if (relativeToDefault > 0.99f) {
result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback); result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback);

View file

@ -17,6 +17,7 @@
#include <DependencyManager.h> #include <DependencyManager.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <OctreeConstants.h> #include <OctreeConstants.h>
#include <OctreeUtils.h>
#include <PIDController.h> #include <PIDController.h>
#include <SimpleMovingAverage.h> #include <SimpleMovingAverage.h>
#include <render/Args.h> #include <render/Args.h>
@ -138,24 +139,28 @@ public:
/**jsdoc /**jsdoc
* @function LODManager.setOctreeSizeScale * @function LODManager.setOctreeSizeScale
* @param {number} sizeScale * @param {number} sizeScale
* @deprecated This function is deprecated and will be removed. Use the {@link LODManager.lodAngleDeg} property instead.
*/ */
Q_INVOKABLE void setOctreeSizeScale(float sizeScale); Q_INVOKABLE void setOctreeSizeScale(float sizeScale);
/**jsdoc /**jsdoc
* @function LODManager.getOctreeSizeScale * @function LODManager.getOctreeSizeScale
* @returns {number} * @returns {number}
* @deprecated This function is deprecated and will be removed. Use the {@link LODManager.lodAngleDeg} property instead.
*/ */
Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; } Q_INVOKABLE float getOctreeSizeScale() const;
/**jsdoc /**jsdoc
* @function LODManager.setBoundaryLevelAdjust * @function LODManager.setBoundaryLevelAdjust
* @param {number} boundaryLevelAdjust * @param {number} boundaryLevelAdjust
* @deprecated This function is deprecated and will be removed.
*/ */
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
/**jsdoc /**jsdoc
* @function LODManager.getBoundaryLevelAdjust * @function LODManager.getBoundaryLevelAdjust
* @returns {number} * @returns {number}
* @deprecated This function is deprecated and will be removed.
*/ */
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
@ -196,8 +201,10 @@ public:
float getLODAngleDeg() const; float getLODAngleDeg() const;
void setLODAngleDeg(float lodAngle); void setLODAngleDeg(float lodAngle);
float getLODAngleHalfTan() const; float getLODHalfAngleTan() const;
float getLODAngle() const; float getLODAngle() const;
float getVisibilityDistance() const;
void setVisibilityDistance(float distance);
float getPidKp() const; float getPidKp() const;
float getPidKi() const; float getPidKi() const;
@ -254,7 +261,7 @@ private:
float _desktopTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS }; float _desktopTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_DESKTOP_FPS };
float _hmdTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS }; float _hmdTargetFPS { LOD_OFFSET_FPS + LOD_DEFAULT_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS };
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; float _lodHalfAngle = getHalfAngleFromVisibilityDistance(DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT);
int _boundaryLevelAdjust = 0; int _boundaryLevelAdjust = 0;
glm::vec4 _pidCoefs{ 1.0f, 0.0f, 0.0f, 1.0f }; // Kp, Ki, Kd, Kv glm::vec4 _pidCoefs{ 1.0f, 0.0f, 0.0f, 1.0f }; // Kp, Ki, Kd, Kv

View file

@ -258,6 +258,7 @@ void GraphicsEngine::render_performFrame() {
batch.setFramebuffer(finalFramebuffer); batch.setFramebuffer(finalFramebuffer);
batch.enableSkybox(true); batch.enableSkybox(true);
batch.enableStereo(isStereo); batch.enableStereo(isStereo);
batch.clearDepthStencilFramebuffer(1.0, 0);
batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() }); batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() });
_splashScreen->render(batch, viewFrustum, renderArgs._renderMethod == RenderArgs::RenderMethod::FORWARD); _splashScreen->render(batch, viewFrustum, renderArgs._renderMethod == RenderArgs::RenderMethod::FORWARD);
}); });

View file

@ -64,7 +64,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
_lodSize->setTickPosition(QSlider::TicksBelow); _lodSize->setTickPosition(QSlider::TicksBelow);
_lodSize->setFixedWidth(SLIDER_WIDTH); _lodSize->setFixedWidth(SLIDER_WIDTH);
_lodSize->setPageStep(PAGE_STEP_LOD_SIZE); _lodSize->setPageStep(PAGE_STEP_LOD_SIZE);
int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE; int sliderValue = lodManager->getVisibilityDistance();
_lodSize->setValue(sliderValue); _lodSize->setValue(sliderValue);
form->addRow("Level of Detail:", _lodSize); form->addRow("Level of Detail:", _lodSize);
connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int))); connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int)));
@ -81,7 +81,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
void LodToolsDialog::reloadSliders() { void LodToolsDialog::reloadSliders() {
auto lodManager = DependencyManager::get<LODManager>(); auto lodManager = DependencyManager::get<LODManager>();
_lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE); _lodSize->setValue(lodManager->getVisibilityDistance());
_feedback->setText(lodManager->getLODFeedbackText()); _feedback->setText(lodManager->getLODFeedbackText());
} }
@ -93,15 +93,14 @@ void LodToolsDialog::updateAutomaticLODAdjust() {
void LodToolsDialog::sizeScaleValueChanged(int value) { void LodToolsDialog::sizeScaleValueChanged(int value) {
auto lodManager = DependencyManager::get<LODManager>(); auto lodManager = DependencyManager::get<LODManager>();
float realValue = value * TREE_SCALE; lodManager->setVisibilityDistance(value);
lodManager->setOctreeSizeScale(realValue);
_feedback->setText(lodManager->getLODFeedbackText()); _feedback->setText(lodManager->getLODFeedbackText());
} }
void LodToolsDialog::resetClicked(bool checked) { void LodToolsDialog::resetClicked(bool checked) {
int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE; int sliderValue = DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT;
_lodSize->setValue(sliderValue); _lodSize->setValue(sliderValue);
_manualLODAdjust->setChecked(false); _manualLODAdjust->setChecked(false);
@ -124,8 +123,8 @@ void LodToolsDialog::closeEvent(QCloseEvent* event) {
lodManager->setAutomaticLODAdjust(true); lodManager->setAutomaticLODAdjust(true);
// if the user adjusted the LOD above "normal" then always revert back to default // if the user adjusted the LOD above "normal" then always revert back to default
if (lodManager->getOctreeSizeScale() > DEFAULT_OCTREE_SIZE_SCALE) { if (lodManager->getVisibilityDistance() > DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) {
lodManager->setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE); lodManager->setVisibilityDistance(DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT);
} }
#endif #endif
} }

View file

@ -43,6 +43,8 @@ set(src_files
src/LaunchInterface.h src/LaunchInterface.h
src/CustomUI.h src/CustomUI.h
src/CustomUI.m src/CustomUI.m
src/NSTask+NSTaskExecveAdditions.h
src/NSTask+NSTaskExecveAdditions.m
src/main.mm src/main.mm
nib/Window.xib nib/Window.xib
nib/SplashScreen.xib nib/SplashScreen.xib

View file

@ -7,6 +7,7 @@
#import "ProcessScreen.h" #import "ProcessScreen.h"
#import "ErrorViewController.h" #import "ErrorViewController.h"
#import "Settings.h" #import "Settings.h"
#import "NSTask+NSTaskExecveAdditions.h"
@interface Launcher () @interface Launcher ()
@ -456,8 +457,6 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:[[self getAppPath] stringByAppendingString:@"interface.app/Contents/MacOS/interface"]]]; NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:[[self getAppPath] stringByAppendingString:@"interface.app/Contents/MacOS/interface"]]];
NSError *error = nil;
NSString* contentPath = [[self getDownloadPathForContentAndScripts] stringByAppendingString:@"content"]; NSString* contentPath = [[self getDownloadPathForContentAndScripts] stringByAppendingString:@"content"];
NSString* displayName = [ self displayName]; NSString* displayName = [ self displayName];
NSString* scriptsPath = [[self getAppPath] stringByAppendingString:@"interface.app/Contents/Resources/scripts/simplifiedUIBootstrapper.js"]; NSString* scriptsPath = [[self getAppPath] stringByAppendingString:@"interface.app/Contents/Resources/scripts/simplifiedUIBootstrapper.js"];
@ -484,13 +483,11 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
@"--no-updater", @"--no-updater",
@"--no-launcher", nil]; @"--no-launcher", nil];
} }
[workspace launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error];
[NSTimer scheduledTimerWithTimeInterval: 3.0 NSTask *task = [[NSTask alloc] init];
target: self task.launchPath = [url path];
selector: @selector(exitLauncher:) task.arguments = arguments;
userInfo:nil [task replaceThisProcess];
repeats: NO];
} }
- (ProcessState) currentProccessState - (ProcessState) currentProccessState
@ -500,15 +497,20 @@ static BOOL const DELETE_ZIP_FILES = TRUE;
- (void) callLaunchInterface:(NSTimer*) timer - (void) callLaunchInterface:(NSTimer*) timer
{ {
NSWindow* mainWindow = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil]; ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
[[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen]; [mainWindow setContentViewController: processScreen];
[self launchInterface]; @try
} {
[self launchInterface];
}
- (void) exitLauncher:(NSTimer*) timer @catch (NSException *exception)
{ {
[NSApp terminate:self]; NSLog(@"Caught exception: Name: %@, Reason: %@", exception.name, exception.reason);
ErrorViewController* errorViewController = [[ErrorViewController alloc] initWithNibName:@"ErrorScreen" bundle:nil];
[mainWindow setContentViewController: errorViewController];
}
} }
@end @end

View file

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSTask (NSTaskExecveAdditions)
- (void) replaceThisProcess;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,73 @@
#import "NSTask+NSTaskExecveAdditions.h"
#import <libgen.h>
char **
toCArray(NSArray<NSString *> *array)
{
// Add one to count to accommodate the NULL that terminates the array.
char **cArray = (char **) calloc([array count] + 1, sizeof(char *));
if (cArray == NULL) {
NSException *exception = [NSException
exceptionWithName:@"MemoryException"
reason:@"malloc failed"
userInfo:nil];
@throw exception;
}
char *str;
for (int i = 0; i < [array count]; i++) {
str = (char *) [array[i] UTF8String];
if (str == NULL) {
NSException *exception = [NSException
exceptionWithName:@"NULLStringException"
reason:@"UTF8String was NULL"
userInfo:nil];
@throw exception;
}
if (asprintf(&cArray[i], "%s", str) == -1) {
for (int j = 0; j < i; j++) {
free(cArray[j]);
}
free(cArray);
NSException *exception = [NSException
exceptionWithName:@"MemoryException"
reason:@"malloc failed"
userInfo:nil];
@throw exception;
}
}
return cArray;
}
@implementation NSTask (NSTaskExecveAdditions)
- (void) replaceThisProcess {
char **args = toCArray([@[[self launchPath]] arrayByAddingObjectsFromArray:[self arguments]]);
NSMutableArray *env = [[NSMutableArray alloc] init];
NSDictionary* environvment = [[NSProcessInfo processInfo] environment];
for (NSString* key in environvment) {
NSString* environmentVariable = [[key stringByAppendingString:@"="] stringByAppendingString:environvment[key]];
[env addObject:environmentVariable];
}
char** envp = toCArray(env);
// `execve` replaces the current process with `path`.
// It will only return if it fails to replace the current process.
chdir(dirname(args[0]));
execve(args[0], (char * const *)args, envp);
// If we're here `execve` failed. :(
for (int i = 0; i < [[self arguments] count]; i++) {
free((void *) args[i]);
}
free((void *) args);
NSException *exception = [NSException
exceptionWithName:@"ExecveException"
reason:[NSString stringWithFormat:@"couldn't execve: %s", strerror(errno)]
userInfo:nil];
@throw exception;
}
@end

View file

@ -213,6 +213,12 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
} }
} }
float AnimInverseKinematics::getInterpolationAlpha(float timer) {
float alpha = (JOINT_CHAIN_INTERP_TIME - timer) / JOINT_CHAIN_INTERP_TIME;
alpha = 1.0f - powf(2.0f, -10.0f * alpha);
return alpha;
}
void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec) { void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec) {
// compute absolute poses that correspond to relative target poses // compute absolute poses that correspond to relative target poses
AnimPoseVec absolutePoses; AnimPoseVec absolutePoses;
@ -227,6 +233,8 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
accumulator.clearAndClean(); accumulator.clearAndClean();
} }
std::map<int, int> targetToChainMap;
float maxError = 0.0f; float maxError = 0.0f;
int numLoops = 0; int numLoops = 0;
const int MAX_IK_LOOPS = 16; const int MAX_IK_LOOPS = 16;
@ -248,17 +256,13 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
break; break;
} }
} }
// on last iteration, interpolate jointChains, if necessary // on last iteration, interpolate jointChains, if necessary
if (numLoops == MAX_IK_LOOPS) { if (numLoops == MAX_IK_LOOPS) {
for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) { for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
targetToChainMap.insert(std::pair<int, int>(_prevJointChainInfoVec[i].target.getIndex(), (int)i));
if (_prevJointChainInfoVec[i].timer > 0.0f) { if (_prevJointChainInfoVec[i].timer > 0.0f) {
float alpha = getInterpolationAlpha(_prevJointChainInfoVec[i].timer);
float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
// ease in expo
alpha = 1.0f - powf(2.0f, -10.0f * alpha);
size_t chainSize = std::min(_prevJointChainInfoVec[i].jointInfoVec.size(), jointChainInfoVec[i].jointInfoVec.size()); size_t chainSize = std::min(_prevJointChainInfoVec[i].jointInfoVec.size(), jointChainInfoVec[i].jointInfoVec.size());
if (jointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown) { if (jointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown) {
@ -336,22 +340,47 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
for (auto& target: targets) { for (auto& target: targets) {
int tipIndex = target.getIndex(); int tipIndex = target.getIndex();
int parentIndex = (tipIndex >= 0) ? _skeleton->getParentIndex(tipIndex) : -1; int parentIndex = (tipIndex >= 0) ? _skeleton->getParentIndex(tipIndex) : -1;
int chainIndex = targetToChainMap[tipIndex];
bool needsInterpolation = _prevJointChainInfoVec[chainIndex].timer > 0.0f;
float alpha = needsInterpolation ? getInterpolationAlpha(_prevJointChainInfoVec[chainIndex].timer) : 0.0f;
// update rotationOnly targets that don't lie on the ik chain of other ik targets. // update rotationOnly targets that don't lie on the ik chain of other ik targets.
if (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() && target.getType() == IKTarget::Type::RotationOnly) { if (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() &&
const glm::quat& targetRotation = target.getRotation(); (target.getType() == IKTarget::Type::RotationOnly || target.getType() == IKTarget::Type::Unknown)) {
// compute tip's new parent-relative rotation if (target.getType() == IKTarget::Type::RotationOnly) {
// Q = Qp * q --> q' = Qp^ * Q const glm::quat& targetRotation = target.getRotation();
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot()) * targetRotation; // compute tip's new parent-relative rotation
RotationConstraint* constraint = getConstraint(tipIndex); // Q = Qp * q --> q' = Qp^ * Q
if (constraint) { glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot()) * targetRotation;
constraint->apply(newRelativeRotation); RotationConstraint* constraint = getConstraint(tipIndex);
// TODO: ATM the final rotation target just fails but we need to provide if (constraint) {
// feedback to the IK system so that it can adjust the bones up the skeleton constraint->apply(newRelativeRotation);
// to help this rotation target get met. // TODO: ATM the final rotation target just fails but we need to provide
// feedback to the IK system so that it can adjust the bones up the skeleton
// to help this rotation target get met.
}
if (needsInterpolation) {
_relativePoses[tipIndex].rot() = safeMix(_relativePoses[tipIndex].rot(), newRelativeRotation, alpha);
} else {
_relativePoses[tipIndex].rot() = newRelativeRotation;
}
// Add last known rotations to interpolate from
if (_rotationOnlyIKRotations.find(tipIndex) == _rotationOnlyIKRotations.end()) {
_rotationOnlyIKRotations.insert(std::pair<int, glm::quat>(tipIndex, _relativePoses[tipIndex].rot()));
} else {
_rotationOnlyIKRotations[tipIndex] = _relativePoses[tipIndex].rot();
}
absolutePoses[tipIndex].rot() = targetRotation;
} else {
bool rotationSnapshotExist = _rotationOnlyIKRotations.find(tipIndex) != _rotationOnlyIKRotations.end();
if (needsInterpolation) {
if (rotationSnapshotExist) {
glm::quat lastKnownRotation = _rotationOnlyIKRotations[tipIndex];
_relativePoses[tipIndex].rot() = safeMix(_relativePoses[tipIndex].rot(), lastKnownRotation, (1 - alpha));
}
} else if (rotationSnapshotExist) {
_rotationOnlyIKRotations.erase(tipIndex);
}
} }
_relativePoses[tipIndex].rot() = newRelativeRotation;
absolutePoses[tipIndex].rot() = targetRotation;
} }
} }
@ -928,6 +957,10 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
(jointChainInfoVec[i].target.getType() != _prevJointChainInfoVec[i].target.getType() || (jointChainInfoVec[i].target.getType() != _prevJointChainInfoVec[i].target.getType() ||
jointChainInfoVec[i].target.getPoleVectorEnabled() != _prevJointChainInfoVec[i].target.getPoleVectorEnabled())) { jointChainInfoVec[i].target.getPoleVectorEnabled() != _prevJointChainInfoVec[i].target.getPoleVectorEnabled())) {
_prevJointChainInfoVec[i].timer = JOINT_CHAIN_INTERP_TIME; _prevJointChainInfoVec[i].timer = JOINT_CHAIN_INTERP_TIME;
// Clear the rotations when the target is known
if (jointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown) {
_rotationOnlyIKRotations.erase(jointChainInfoVec[i].target.getIndex());
}
} }
} }
} }

View file

@ -148,6 +148,7 @@ protected:
void clearConstraints(); void clearConstraints();
void initConstraints(); void initConstraints();
void initLimitCenterPoses(); void initLimitCenterPoses();
float getInterpolationAlpha(float timer);
// no copies // no copies
AnimInverseKinematics(const AnimInverseKinematics&) = delete; AnimInverseKinematics(const AnimInverseKinematics&) = delete;
@ -181,6 +182,7 @@ protected:
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
AnimPoseVec _relativePoses; // current relative poses AnimPoseVec _relativePoses; // current relative poses
AnimPoseVec _limitCenterPoses; // relative AnimPoseVec _limitCenterPoses; // relative
std::map<int, glm::quat> _rotationOnlyIKRotations;
std::map<int, AnimPose> _secondaryTargetsInRigFrame; std::map<int, AnimPose> _secondaryTargetsInRigFrame;

View file

@ -57,14 +57,12 @@ const AnimPoseVec& AnimRandomSwitch::evaluate(const AnimVariantMap& animVars, co
lowerBound = upperBound; lowerBound = upperBound;
} }
if (abs(_randomSwitchEvaluationCount - context.getEvaluationCount()) > 1) { if (abs(_randomSwitchEvaluationCount - context.getEvaluationCount()) > 1) {
_duringInterp = false; switchRandomState(animVars, context, desiredState, false);
switchRandomState(animVars, context, desiredState, _duringInterp);
} else { } else {
// firing a random switch, be sure that we aren't completing a previously triggered transition // firing a random switch, be sure that we aren't completing a previously triggered transition
if (currentStateHasPriority) { if (currentStateHasPriority) {
if (desiredState->getID() != _currentState->getID()) { if (desiredState->getID() != _currentState->getID()) {
_duringInterp = true; switchRandomState(animVars, context, desiredState, true);
switchRandomState(animVars, context, desiredState, _duringInterp);
} else { } else {
_duringInterp = false; _duringInterp = false;
} }
@ -79,8 +77,7 @@ const AnimPoseVec& AnimRandomSwitch::evaluate(const AnimVariantMap& animVars, co
// evaluate currentState transitions // evaluate currentState transitions
auto transitionState = evaluateTransitions(animVars); auto transitionState = evaluateTransitions(animVars);
if (transitionState != _currentState) { if (transitionState != _currentState) {
_duringInterp = true; switchRandomState(animVars, context, transitionState, true);
switchRandomState(animVars, context, transitionState, _duringInterp);
_triggerTime = randFloatInRange(_triggerTimeMin, _triggerTimeMax); _triggerTime = randFloatInRange(_triggerTimeMin, _triggerTimeMax);
_randomSwitchTime = randFloatInRange(_randomSwitchTimeMin, _randomSwitchTimeMax); _randomSwitchTime = randFloatInRange(_randomSwitchTimeMin, _randomSwitchTimeMax);
} }
@ -172,6 +169,9 @@ void AnimRandomSwitch::switchRandomState(const AnimVariantMap& animVars, const A
_lastPlayedState = nextStateNode->getID(); _lastPlayedState = nextStateNode->getID();
if (shouldInterp) { if (shouldInterp) {
bool interpActive = _duringInterp;
_duringInterp = true;
const float FRAMES_PER_SECOND = 30.0f; const float FRAMES_PER_SECOND = 30.0f;
auto prevStateNode = _children[_currentState->getChildIndex()]; auto prevStateNode = _children[_currentState->getChildIndex()];
@ -195,13 +195,21 @@ void AnimRandomSwitch::switchRandomState(const AnimVariantMap& animVars, const A
} }
_nextPoses = nextStateNode->evaluate(animVars, context, dt, triggers); _nextPoses = nextStateNode->evaluate(animVars, context, dt, triggers);
} else if (_interpType == InterpType::SnapshotPrev) { } else if (_interpType == InterpType::SnapshotPrev) {
// snapshot previoius pose // snapshot previous pose
_prevPoses = _poses; _prevPoses = _poses;
// no need to evaluate _nextPoses we will do it dynamically during the interp, // no need to evaluate _nextPoses we will do it dynamically during the interp,
// however we need to set the current frame. // however we need to set the current frame.
if (!desiredState->getResume()) { if (!desiredState->getResume()) {
nextStateNode->setCurrentFrame(desiredState->_interpTarget - duration); nextStateNode->setCurrentFrame(desiredState->_interpTarget - duration);
} }
} else if (_interpType == InterpType::EvaluateBoth) {
// need to set current frame in destination branch.
nextStateNode->setCurrentFrame(desiredState->_interpTarget - duration);
if (interpActive) {
// snapshot previous pose
_prevPoses = _poses;
_interpType = InterpType::SnapshotPrev;
}
} else { } else {
assert(false); assert(false);
} }

View file

@ -128,6 +128,7 @@ void AnimStateMachine::switchState(const AnimVariantMap& animVars, const AnimCon
auto prevStateNode = _children[_currentState->getChildIndex()]; auto prevStateNode = _children[_currentState->getChildIndex()];
auto nextStateNode = _children[desiredState->getChildIndex()]; auto nextStateNode = _children[desiredState->getChildIndex()];
bool interpActive = _duringInterp;
_duringInterp = true; _duringInterp = true;
_alpha = 0.0f; _alpha = 0.0f;
float duration = std::max(0.001f, animVars.lookup(desiredState->_interpDurationVar, desiredState->_interpDuration)); float duration = std::max(0.001f, animVars.lookup(desiredState->_interpDurationVar, desiredState->_interpDuration));
@ -146,11 +147,19 @@ void AnimStateMachine::switchState(const AnimVariantMap& animVars, const AnimCon
nextStateNode->setCurrentFrame(desiredState->_interpTarget); nextStateNode->setCurrentFrame(desiredState->_interpTarget);
_nextPoses = nextStateNode->evaluate(animVars, context, dt, triggers); _nextPoses = nextStateNode->evaluate(animVars, context, dt, triggers);
} else if (_interpType == InterpType::SnapshotPrev) { } else if (_interpType == InterpType::SnapshotPrev) {
// snapshot previoius pose // snapshot previous pose
_prevPoses = _poses; _prevPoses = _poses;
// no need to evaluate _nextPoses we will do it dynamically during the interp, // no need to evaluate _nextPoses we will do it dynamically during the interp,
// however we need to set the current frame. // however we need to set the current frame.
nextStateNode->setCurrentFrame(desiredState->_interpTarget - duration); nextStateNode->setCurrentFrame(desiredState->_interpTarget - duration);
} else if (_interpType == InterpType::EvaluateBoth) {
// need to set current frame in destination branch.
nextStateNode->setCurrentFrame(desiredState->_interpTarget - duration);
if (interpActive) {
// snapshot previous pose
_prevPoses = _poses;
_interpType = InterpType::SnapshotPrev;
}
} else { } else {
assert(false); assert(false);
} }

View file

@ -2112,8 +2112,10 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
} }
float easeOutInValue = _talkIdleInterpTime < 0.5f ? 4.0f * powf(_talkIdleInterpTime, 3.0f) : 4.0f * powf((_talkIdleInterpTime - 1.0f), 3.0f) + 1.0f; float easeOutInValue = _talkIdleInterpTime < 0.5f ? 4.0f * powf(_talkIdleInterpTime, 3.0f) : 4.0f * powf((_talkIdleInterpTime - 1.0f), 3.0f) + 1.0f;
_animVars.set("talkOverlayAlpha", easeOutInValue); _animVars.set("talkOverlayAlpha", easeOutInValue);
_animVars.set("idleOverlayAlpha", easeOutInValue); // backward compatibility for older anim graphs.
} else { } else {
_animVars.set("talkOverlayAlpha", 1.0f); _animVars.set("talkOverlayAlpha", 1.0f);
_animVars.set("idleOverlayAlpha", 1.0f); // backward compatibility for older anim graphs.
} }
} else { } else {
if (_talkIdleInterpTime < 1.0f) { if (_talkIdleInterpTime < 1.0f) {
@ -2124,8 +2126,10 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
float easeOutInValue = _talkIdleInterpTime < 0.5f ? 4.0f * powf(_talkIdleInterpTime, 3.0f) : 4.0f * powf((_talkIdleInterpTime - 1.0f), 3.0f) + 1.0f; float easeOutInValue = _talkIdleInterpTime < 0.5f ? 4.0f * powf(_talkIdleInterpTime, 3.0f) : 4.0f * powf((_talkIdleInterpTime - 1.0f), 3.0f) + 1.0f;
float talkAlpha = 1.0f - easeOutInValue; float talkAlpha = 1.0f - easeOutInValue;
_animVars.set("talkOverlayAlpha", talkAlpha); _animVars.set("talkOverlayAlpha", talkAlpha);
_animVars.set("idleOverlayAlpha", talkAlpha); // backward compatibility for older anim graphs.
} else { } else {
_animVars.set("talkOverlayAlpha", 0.0f); _animVars.set("talkOverlayAlpha", 0.0f);
_animVars.set("idleOverlayAlpha", 0.0f); // backward compatibility for older anim graphs.
} }
} }

View file

@ -78,7 +78,8 @@ public:
void setVsyncEnabled(bool vsyncEnabled) { _vsyncEnabled = vsyncEnabled; } void setVsyncEnabled(bool vsyncEnabled) { _vsyncEnabled = vsyncEnabled; }
bool isVsyncEnabled() const { return _vsyncEnabled; } bool isVsyncEnabled() const { return _vsyncEnabled; }
// Three threads, one for rendering, one for texture transfers, one reserved for the GL driver // Three threads, one for rendering, one for texture transfers, one reserved for the GL driver
int getRequiredThreadCount() const override { return 3; } // Drop to one reserved for better other-task performance in desktop
int getRequiredThreadCount() const override { return 1; }
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override; virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override;
void copyTextureToQuickFramebuffer(NetworkTexturePointer source, void copyTextureToQuickFramebuffer(NetworkTexturePointer source,

View file

@ -53,6 +53,8 @@ public:
void updateVisionSqueezeParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition, void updateVisionSqueezeParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition,
int visionSqueezePerEye, float visionSqueezeGroundPlaneY, int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
float visionSqueezeSpotlightSize); float visionSqueezeSpotlightSize);
// Attempt to reserve two threads.
int getRequiredThreadCount() const override { return 2; }
signals: signals:
void hmdMountedChanged(); void hmdMountedChanged();

View file

@ -33,8 +33,8 @@ using namespace gpu::gl;
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
#endif #endif
bool GLTexelFormat::isCompressed() const { bool GLTexelFormat::isCompressed(GLenum format) {
switch (internalFormat) { switch (format) {
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
@ -92,6 +92,11 @@ bool GLTexelFormat::isCompressed() const {
} }
} }
bool GLTexelFormat::isCompressed() const {
return isCompressed(internalFormat);
}
GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
GLenum result = GL_RGBA8; GLenum result = GL_RGBA8;
switch (dstFormat.getDimension()) { switch (dstFormat.getDimension()) {

View file

@ -14,13 +14,15 @@ namespace gpu { namespace gl {
class GLTexelFormat { class GLTexelFormat {
public: public:
GLenum internalFormat; GLenum internalFormat{ GL_RGBA8 };
GLenum format; GLenum format{ GL_RGBA };
GLenum type; GLenum type{ GL_UNSIGNED_BYTE };
GLTexelFormat(GLenum glinternalFormat, GLenum glformat, GLenum gltype) : internalFormat(glinternalFormat), format(glformat), type(gltype) {} GLTexelFormat(GLenum glinternalFormat, GLenum glformat, GLenum gltype) : internalFormat(glinternalFormat), format(glformat), type(gltype) {}
GLTexelFormat(GLenum glinternalFormat) : internalFormat(glinternalFormat) {} GLTexelFormat(GLenum glinternalFormat) : internalFormat(glinternalFormat) {}
static bool isCompressed(GLenum glinternalFormat);
bool isCompressed() const; bool isCompressed() const;
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) { static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) {

View file

@ -33,6 +33,7 @@ class GL45Backend : public GLBackend {
friend class Context; friend class Context;
public: public:
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
static GLint MAX_COMBINED_SHADER_STORAGE_BLOCKS; static GLint MAX_COMBINED_SHADER_STORAGE_BLOCKS;
static GLint MAX_UNIFORM_LOCATIONS; static GLint MAX_UNIFORM_LOCATIONS;
#if GPU_BINDLESS_TEXTURES #if GPU_BINDLESS_TEXTURES

View file

@ -226,81 +226,31 @@ void GL45Texture::generateMips() const {
Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const { Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const {
Size amountCopied = sourceSize; Size amountCopied = sourceSize;
bool compressed = GLTexelFormat::isCompressed(internalFormat);
if (GL_TEXTURE_2D == _target) { if (GL_TEXTURE_2D == _target) {
switch (internalFormat) { if (compressed) {
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat,
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: static_cast<GLsizei>(sourceSize), sourcePointer);
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: } else {
case GL_COMPRESSED_RED_RGTC1: glTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
case GL_COMPRESSED_RG_RGTC2:
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
break;
default:
glTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
break;
} }
} else if (GL_TEXTURE_CUBE_MAP == _target) { } else if (GL_TEXTURE_CUBE_MAP == _target) {
switch (internalFormat) { // DSA and cubemap functions are notoriously buggy. use the 4.1 compatible pathway
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: glActiveTexture(GL_TEXTURE0 + GL45Backend::RESOURCE_TRANSFER_TEX_UNIT);
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: glBindTexture(_target, _texture);
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: auto target = GLTexture::CUBE_FACE_LAYOUT[face];
case GL_COMPRESSED_RED_RGTC1: if (compressed) {
case GL_COMPRESSED_RG_RGTC2: glCompressedTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, internalFormat,
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: static_cast<GLsizei>(sourceSize), sourcePointer);
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: } else {
case GL_COMPRESSED_RGB8_ETC2: glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
#if AMD_CUBE_MAP_EXT_WORKAROUND
if (glCompressedTextureSubImage2DEXT) {
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
} else
#endif
{
glCompressedTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
}
break;
default:
#if AMD_CUBE_MAP_EXT_WORKAROUND
if (glTextureSubImage2DEXT) {
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
glTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
} else
#endif
{
glTextureSubImage3D(_id, mip, 0, yOffset, face, size.x, size.y, 1, format, type, sourcePointer);
}
break;
} }
glBindTexture(_target, 0);
} else { } else {
assert(false); assert(false);
amountCopied = 0; amountCopied = 0;
} }
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
return amountCopied; return amountCopied;
} }

View file

@ -334,12 +334,17 @@ void Socket::checkForReadyReadBackup() {
qCDebug(networking) << "Socket::checkForReadyReadyBackup() last sequence number" qCDebug(networking) << "Socket::checkForReadyReadyBackup() last sequence number"
<< (uint32_t) _lastReceivedSequenceNumber << "from" << _lastPacketSockAddr << "-" << (uint32_t) _lastReceivedSequenceNumber << "from" << _lastPacketSockAddr << "-"
<< _lastPacketSizeRead << "bytes"; << _lastPacketSizeRead << "bytes";
#ifdef DEBUG_EVENT_QUEUE
qCDebug(networking) << "NodeList event queue size:" << ::hifi::qt::getEventQueueSize(thread());
#endif
// drop all of the pending datagrams on the floor // drop all of the pending datagrams on the floor
int droppedCount = 0;
while (_udpSocket.hasPendingDatagrams()) { while (_udpSocket.hasPendingDatagrams()) {
_udpSocket.readDatagram(nullptr, 0); _udpSocket.readDatagram(nullptr, 0);
++droppedCount;
} }
qCDebug(networking) << "Flushed" << droppedCount << "Packets";
} }
} }

View file

@ -21,8 +21,9 @@ const int TREE_SCALE = 32768; // ~20 miles.. This is the number of meters of the
const int HALF_TREE_SCALE = TREE_SCALE / 2; const int HALF_TREE_SCALE = TREE_SCALE / 2;
// This controls the LOD. Larger number will make smaller voxels visible at greater distance. // This controls the LOD. Larger number will make smaller voxels visible at greater distance.
const float MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT = 400.0f; // max distance where a 1x1x1 cube is visible for 20:20 vision const float DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT = 400.0f; // max distance where a 1x1x1 cube is visible for 20:20 vision
const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT; const float UNIT_ELEMENT_MAX_EXTENT = sqrtf(3.0f) / 2.0f; // A unit cube tilted on its edge will have its edge jutting out sqrt(3)/2 units from the center
const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT;
// Since entities like models live inside of octree cells, and they themselves can have very small mesh parts, // Since entities like models live inside of octree cells, and they themselves can have very small mesh parts,
// we want to have some constant that controls have big a mesh part must be to render even if the octree cell itself // we want to have some constant that controls have big a mesh part must be to render even if the octree cell itself

View file

@ -18,64 +18,31 @@
#include <AABox.h> #include <AABox.h>
#include <AACube.h> #include <AACube.h>
float calculateRenderAccuracy(const glm::vec3& position, float boundaryDistanceForRenderLevel(unsigned int renderLevel, float visibilityDistance) {
const AABox& bounds, return visibilityDistance / powf(2.0f, renderLevel);
float octreeSizeScale,
int boundaryLevelAdjust) {
float largestDimension = bounds.getLargestDimension();
const float maxScale = (float)TREE_SCALE;
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
static std::once_flag once;
static QMap<float, float> shouldRenderTable;
std::call_once(once, [&] {
float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small
float scale = maxScale;
float factor = 1.0f;
while (scale > SMALLEST_SCALE_IN_TABLE) {
scale /= 2.0f;
factor /= 2.0f;
shouldRenderTable[scale] = factor;
}
});
float closestScale = maxScale;
float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale;
QMap<float, float>::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension);
if (lowerBound != shouldRenderTable.constEnd()) {
closestScale = lowerBound.key();
visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value();
}
if (closestScale < largestDimension) {
visibleDistanceAtClosestScale *= 2.0f;
}
// FIXME - for now, it's either visible or not visible. We want to adjust this to eventually return
// a floating point for objects that have small angular size to indicate that they may be rendered
// with lower preciscion
float distanceToCamera = glm::length(bounds.calcCenter() - position);
return (distanceToCamera <= visibleDistanceAtClosestScale) ? 1.0f : 0.0f;
} }
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) { float getPerspectiveAccuracyHalfAngleTan(float visibilityDistance, int boundaryLevelAdjust) {
return voxelSizeScale / powf(2.0f, renderLevel); float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, visibilityDistance);
return UNIT_ELEMENT_MAX_EXTENT / visibleDistanceAtMaxScale;
} }
float getPerspectiveAccuracyAngleTan(float octreeSizeScale, int boundaryLevelAdjust) { float getPerspectiveAccuracyHalfAngle(float visibilityDistance, int boundaryLevelAdjust) {
const float maxScale = (float)TREE_SCALE; return atan(getPerspectiveAccuracyHalfAngleTan(visibilityDistance, boundaryLevelAdjust));
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
return (maxScale / visibleDistanceAtMaxScale);
} }
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) { float getVisibilityDistanceFromHalfAngle(float halfAngle) {
return atan(getPerspectiveAccuracyAngleTan(octreeSizeScale, boundaryLevelAdjust)); float halfAngleTan = tan(halfAngle);
return UNIT_ELEMENT_MAX_EXTENT / halfAngleTan;
} }
float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust) { float getHalfAngleFromVisibilityDistance(float visibilityDistance) {
float halfAngleTan = UNIT_ELEMENT_MAX_EXTENT / visibilityDistance;
return atan(halfAngleTan);
}
float getOrthographicAccuracySize(float visibilityDistance, int boundaryLevelAdjust) {
// Smallest visible element is 1cm // Smallest visible element is 1cm
const float smallestSize = 0.01f; const float smallestSize = 0.01f;
return (smallestSize * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) / boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale); return (smallestSize * DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) / boundaryDistanceForRenderLevel(boundaryLevelAdjust, visibilityDistance);
} }

View file

@ -20,18 +20,13 @@ class AABox;
class AACube; class AACube;
class QJsonDocument; class QJsonDocument;
/// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple float boundaryDistanceForRenderLevel(unsigned int renderLevel, float visibilityDistance);
/// level it returns 0.0f for things that are so small for the current settings that they could not be visible.
float calculateRenderAccuracy(const glm::vec3& position,
const AABox& bounds,
float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE,
int boundaryLevelAdjust = 0);
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale); float getPerspectiveAccuracyHalfAngleTan(float visibilityDistance, int boundaryLevelAdjust);
float getPerspectiveAccuracyHalfAngle(float visibilityDistance, int boundaryLevelAdjust);
float getPerspectiveAccuracyAngleTan(float octreeSizeScale, int boundaryLevelAdjust); float getVisibilityDistanceFromHalfAngle(float halfAngle);
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust); float getHalfAngleFromVisibilityDistance(float visibilityDistance);
float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust); float getOrthographicAccuracySize(float visibilityDistance, int boundaryLevelAdjust);
// MIN_ELEMENT_ANGULAR_DIAMETER = angular diameter of 1x1x1m cube at 400m = sqrt(3) / 400 = 0.0043301 radians ~= 0.25 degrees // MIN_ELEMENT_ANGULAR_DIAMETER = angular diameter of 1x1x1m cube at 400m = sqrt(3) / 400 = 0.0043301 radians ~= 0.25 degrees
const float MIN_ELEMENT_ANGULAR_DIAMETER = 0.0043301f; // radians const float MIN_ELEMENT_ANGULAR_DIAMETER = 0.0043301f; // radians

View file

@ -120,7 +120,7 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS
// Draw the LOD Reticle // Draw the LOD Reticle
{ {
float angle = glm::degrees(getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); float angle = glm::degrees(getPerspectiveAccuracyHalfAngle(args->_sizeScale, args->_boundaryLevelAdjust));
Transform crosshairModel; Transform crosshairModel;
crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1000.0)); crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1000.0));
crosshairModel.setScale(1000.0f * tanf(glm::radians(angle))); // Scaling at the actual tan of the lod angle => Multiplied by TWO crosshairModel.setScale(1000.0f * tanf(glm::radians(angle))); // Scaling at the actual tan of the lod angle => Multiplied by TWO

View file

@ -30,34 +30,18 @@ Q_DECLARE_METATYPE(QByteArray*)
XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
_engine(engine), _engine(engine),
_async(true), _timer(this) {
_url(),
_method(""),
_responseType(""),
_request(),
_reply(NULL),
_sendData(NULL),
_rawResponseData(),
_responseData(""),
_onTimeout(QScriptValue::NullValue),
_onReadyStateChange(QScriptValue::NullValue),
_readyState(XMLHttpRequestClass::UNSENT),
_errorCode(QNetworkReply::NoError),
_timeout(0),
_timer(this),
_numRedirects(0) {
_request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); _request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
_timer.setSingleShot(true); _timer.setSingleShot(true);
} }
XMLHttpRequestClass::~XMLHttpRequestClass() { XMLHttpRequestClass::~XMLHttpRequestClass() {
if (_reply) { delete _reply; } if (_reply) { _reply->deleteLater(); }
if (_sendData) { delete _sendData; }
} }
QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEngine* engine) { QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEngine* engine) {
return engine->newQObject(new XMLHttpRequestClass(engine)); return engine->newQObject(new XMLHttpRequestClass(engine), QScriptEngine::ScriptOwnership);
} }
QScriptValue XMLHttpRequestClass::getStatus() const { QScriptValue XMLHttpRequestClass::getStatus() const {
@ -169,13 +153,12 @@ void XMLHttpRequestClass::send() {
void XMLHttpRequestClass::send(const QScriptValue& data) { void XMLHttpRequestClass::send(const QScriptValue& data) {
if (_readyState == OPENED && !_reply) { if (_readyState == OPENED && !_reply) {
if (!data.isNull()) { if (!data.isNull()) {
_sendData = new QBuffer(this);
if (data.isObject()) { if (data.isObject()) {
QByteArray ba = qscriptvalue_cast<QByteArray>(data); _sendData = qscriptvalue_cast<QByteArray>(data);
_sendData->setData(ba);
} else { } else {
_sendData->setData(data.toString().toUtf8()); _sendData = data.toString().toUtf8();
} }
} }
@ -237,6 +220,10 @@ void XMLHttpRequestClass::requestFinished() {
setReadyState(DONE); setReadyState(DONE);
emit requestComplete(); emit requestComplete();
disconnectFromReply(_reply);
_reply->deleteLater();
_reply = nullptr;
} }
void XMLHttpRequestClass::abortRequest() { void XMLHttpRequestClass::abortRequest() {
@ -246,7 +233,7 @@ void XMLHttpRequestClass::abortRequest() {
disconnectFromReply(_reply); disconnectFromReply(_reply);
_reply->abort(); _reply->abort();
_reply->deleteLater(); _reply->deleteLater();
_reply = NULL; _reply = nullptr;
} }
} }

View file

@ -98,23 +98,23 @@ private:
void disconnectFromReply(QNetworkReply* reply); void disconnectFromReply(QNetworkReply* reply);
void abortRequest(); void abortRequest();
QScriptEngine* _engine; QScriptEngine* _engine { nullptr };
bool _async; bool _async { true };
QUrl _url; QUrl _url;
QString _method; QString _method;
QString _responseType; QString _responseType;
QNetworkRequest _request; QNetworkRequest _request;
QNetworkReply* _reply; QNetworkReply* _reply { nullptr };
QBuffer* _sendData; QByteArray _sendData;
QByteArray _rawResponseData; QByteArray _rawResponseData;
QScriptValue _responseData; QScriptValue _responseData;
QScriptValue _onTimeout; QScriptValue _onTimeout { QScriptValue::NullValue };
QScriptValue _onReadyStateChange; QScriptValue _onReadyStateChange { QScriptValue::NullValue };
ReadyState _readyState; ReadyState _readyState { XMLHttpRequestClass::UNSENT };
QNetworkReply::NetworkError _errorCode; QNetworkReply::NetworkError _errorCode { QNetworkReply::NoError };
int _timeout; int _timeout { 0 };
QTimer _timer; QTimer _timer;
int _numRedirects; int _numRedirects { 0 };
private slots: private slots:
void requestFinished(); void requestFinished();

View file

@ -39,6 +39,10 @@ Q_LOGGING_CATEGORY(trace_baker, "trace.baker")
#endif #endif
static bool tracingEnabled() { static bool tracingEnabled() {
if (!DependencyManager::isSet<tracing::Tracer>()) {
return false;
}
// Cheers, love! The cavalry's here! // Cheers, love! The cavalry's here!
auto tracer = DependencyManager::get<tracing::Tracer>(); auto tracer = DependencyManager::get<tracing::Tracer>();
return (tracer && tracer->isEnabled()); return (tracer && tracer->isEnabled());

View file

@ -12,10 +12,10 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#ifdef WIN32 #if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
// Enable event queue debugging // Enable event queue debugging
#define DEBUG_EVENT_QUEUE #define DEBUG_EVENT_QUEUE
#endif // WIN32 #endif
namespace hifi { namespace qt { namespace hifi { namespace qt {
void addBlockingForbiddenThread(const QString& name, QThread* thread = nullptr); void addBlockingForbiddenThread(const QString& name, QThread* thread = nullptr);

View file

@ -80,7 +80,7 @@ Item {
valueVar: LODManager["lodAngleDeg"] valueVar: LODManager["lodAngleDeg"]
valueVarSetter: (function (v) { LODManager["lodAngleDeg"] = v }) valueVarSetter: (function (v) { LODManager["lodAngleDeg"] = v })
max: 90.0 max: 90.0
min: 0.5 min: 0.01
integral: false integral: false
anchors.left: parent.left anchors.left: parent.left
@ -239,6 +239,7 @@ Item {
object: LODManager object: LODManager
valueScale: 1.0 valueScale: 1.0
valueUnit: "deg" valueUnit: "deg"
valueNumDigits: 2
plots: [ plots: [
{ {
prop: "lodAngleDeg", prop: "lodAngleDeg",

View file

@ -39,6 +39,10 @@ module.exports = {
if (error) { if (error) {
response = { statusCode: httpRequest.status }; response = { statusCode: httpRequest.status };
} }
// Break circular reference to httpRequest so the engine can garbage collect it.
httpRequest.onreadystatechange = null;
callback(error, response, optionalCallbackParameter); callback(error, response, optionalCallbackParameter);
} }
}; };

View file

@ -476,7 +476,7 @@ function maybeUpdateOutputDeviceMutedOverlay() {
var oldAutomaticLODAdjust; var oldAutomaticLODAdjust;
var oldLODAngleDeg; var oldLODAngleDeg;
var SIMPLIFIED_UI_AUTO_LOD_ADJUST = false; var SIMPLIFIED_UI_AUTO_LOD_ADJUST = false;
var SIMPLIFIED_UI_LOD_ANGLE_DEG = 0.5; var SIMPLIFIED_UI_LOD_ANGLE_DEG = 0.248;
function modifyLODSettings() { function modifyLODSettings() {
oldAutomaticLODAdjust = LODManager.automaticLODAdjust; oldAutomaticLODAdjust = LODManager.automaticLODAdjust;
oldLODAngleDeg = LODManager.lodAngleDeg; oldLODAngleDeg = LODManager.lodAngleDeg;

View file

@ -355,7 +355,7 @@ CameraManager = function() {
return; return;
} }
if (event.isRightButton || (event.isLeftButton && event.isControl && !event.isShifted)) { if (event.isRightButton || (event.isLeftButton && event.isAlt && !event.isShifted)) {
that.mode = MODE_ORBIT; that.mode = MODE_ORBIT;
} else if (event.isMiddleButton || (event.isLeftButton && event.isControl && event.isShifted)) { } else if (event.isMiddleButton || (event.isLeftButton && event.isControl && event.isShifted)) {
that.mode = MODE_PAN; that.mode = MODE_PAN;

View file

@ -30,6 +30,8 @@ source_group("UI Files" FILES ${QT_UI_FILES})
# have qt5 wrap them and generate the appropriate header files # have qt5 wrap them and generate the appropriate header files
qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
setup_memory_debugger()
# add them to the nitpick source files # add them to the nitpick source files
set(NITPICK_SRCS ${NITPICK_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") set(NITPICK_SRCS ${NITPICK_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")

View file

@ -24,12 +24,23 @@ static const QString CLI_OUTPUT_PARAMETER = "o";
static const QString CLI_TYPE_PARAMETER = "t"; static const QString CLI_TYPE_PARAMETER = "t";
static const QString CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER = "disable-texture-compression"; static const QString CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER = "disable-texture-compression";
QUrl OvenCLIApplication::_inputUrlParameter;
QUrl OvenCLIApplication::_outputUrlParameter;
QString OvenCLIApplication::_typeParameter;
OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) : OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) :
QCoreApplication(argc, argv) QCoreApplication(argc, argv)
{ {
BakerCLI* cli = new BakerCLI(this);
QMetaObject::invokeMethod(cli, "bakeFile", Qt::QueuedConnection, Q_ARG(QUrl, _inputUrlParameter),
Q_ARG(QString, _outputUrlParameter.toString()), Q_ARG(QString, _typeParameter));
}
void OvenCLIApplication::parseCommandLine(int argc, char* argv[]) {
// parse the command line parameters // parse the command line parameters
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription("High Fidelity Oven");
parser.addOptions({ parser.addOptions({
{ CLI_INPUT_PARAMETER, "Path to file that you would like to bake.", "input" }, { CLI_INPUT_PARAMETER, "Path to file that you would like to bake.", "input" },
{ CLI_OUTPUT_PARAMETER, "Path to folder that will be used as output.", "output" }, { CLI_OUTPUT_PARAMETER, "Path to folder that will be used as output.", "output" },
@ -37,25 +48,45 @@ OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) :
{ CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER, "Disable texture compression." } { CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER, "Disable texture compression." }
}); });
parser.addHelpOption(); auto versionOption = parser.addVersionOption();
parser.process(*this); auto helpOption = parser.addHelpOption();
if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { QStringList arguments;
BakerCLI* cli = new BakerCLI(this); for (int i = 0; i < argc; ++i) {
QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER))); arguments << argv[i];
QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER)));
QString type = parser.isSet(CLI_TYPE_PARAMETER) ? parser.value(CLI_TYPE_PARAMETER) : QString::null;
if (parser.isSet(CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER)) {
qDebug() << "Disabling texture compression";
TextureBaker::setCompressionEnabled(false);
}
QMetaObject::invokeMethod(cli, "bakeFile", Qt::QueuedConnection, Q_ARG(QUrl, inputUrl),
Q_ARG(QString, outputUrl.toString()), Q_ARG(QString, type));
} else {
parser.showHelp();
QCoreApplication::quit();
} }
if (!parser.parse(arguments)) {
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
QCoreApplication mockApp(argc, argv); // required for call to showHelp()
parser.showHelp();
Q_UNREACHABLE();
}
if (parser.isSet(versionOption)) {
parser.showVersion();
Q_UNREACHABLE();
}
if (parser.isSet(helpOption)) {
QCoreApplication mockApp(argc, argv); // required for call to showHelp()
parser.showHelp();
Q_UNREACHABLE();
}
if (!parser.isSet(CLI_INPUT_PARAMETER) || !parser.isSet(CLI_OUTPUT_PARAMETER)) {
std::cout << "Error: Input and Output not set" << std::endl; // Avoid Qt log spam
QCoreApplication mockApp(argc, argv); // required for call to showHelp()
parser.showHelp();
Q_UNREACHABLE();
}
_inputUrlParameter = QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER));
_outputUrlParameter = QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER));
_typeParameter = parser.isSet(CLI_TYPE_PARAMETER) ? parser.value(CLI_TYPE_PARAMETER) : QString::null;
if (parser.isSet(CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER)) {
qDebug() << "Disabling texture compression";
TextureBaker::setCompressionEnabled(false);
}
} }

View file

@ -21,7 +21,14 @@ class OvenCLIApplication : public QCoreApplication, public Oven {
public: public:
OvenCLIApplication(int argc, char* argv[]); OvenCLIApplication(int argc, char* argv[]);
static void parseCommandLine(int argc, char* argv[]);
static OvenCLIApplication* instance() { return dynamic_cast<OvenCLIApplication*>(QCoreApplication::instance()); } static OvenCLIApplication* instance() { return dynamic_cast<OvenCLIApplication*>(QCoreApplication::instance()); }
private:
static QUrl _inputUrlParameter;
static QUrl _outputUrlParameter;
static QString _typeParameter;
}; };
#endif // hifi_OvenCLIApplication_h #endif // hifi_OvenCLIApplication_h

View file

@ -18,14 +18,19 @@
int main (int argc, char** argv) { int main (int argc, char** argv) {
setupHifiApplication("Oven"); setupHifiApplication("Oven");
// init the settings interface so we can save and load settings
Setting::init();
// figure out if we're launching our GUI application or just the simple command line interface // figure out if we're launching our GUI application or just the simple command line interface
if (argc > 1) { if (argc > 1) {
OvenCLIApplication::parseCommandLine(argc, argv);
// init the settings interface so we can save and load settings
Setting::init();
OvenCLIApplication app { argc, argv }; OvenCLIApplication app { argc, argv };
return app.exec(); return app.exec();
} else { } else {
// init the settings interface so we can save and load settings
Setting::init();
OvenGUIApplication app { argc, argv }; OvenGUIApplication app { argc, argv };
return app.exec(); return app.exec();
} }