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

This commit is contained in:
Zach Fox 2019-08-14 09:11:04 -07:00
commit 7297ac9a09
41 changed files with 1327 additions and 305 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -4418,8 +4418,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
} else if (isMeta) {
auto dialogsManager = DependencyManager::get<DialogsManager>();
dialogsManager->toggleAddressBar();
} else if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::LodTools);
}
break;
@ -6817,8 +6815,8 @@ void Application::updateRenderArgs(float deltaTime) {
_viewFrustum.setProjection(adjustedProjection);
_viewFrustum.calculate();
}
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), lodManager->getLODAngleHalfTan(), RenderArgs::DEFAULT_RENDER_MODE,
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getVisibilityDistance(),
lodManager->getBoundaryLevelAdjust(), lodManager->getLODHalfAngleTan(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE);
appRenderArgs._renderArgs._scene = getMain3DScene();

View file

@ -12,7 +12,6 @@
#include "LODManager.h"
#include <SettingHandle.h>
#include <OctreeUtils.h>
#include <Util.h>
#include <shared/GlobalAppProperties.h>
@ -93,8 +92,7 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
return;
}
// Previous values for output
float oldOctreeSizeScale = getOctreeSizeScale();
// Previous value for output
float oldLODAngle = getLODAngleDeg();
// 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
setLODAngleDeg(oldLODAngle + output);
if (oldOctreeSizeScale != _octreeSizeScale) {
if (oldLODAngle != getLODAngleDeg()) {
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
if (lodToolsDialog) {
lodToolsDialog->reloadSliders();
@ -173,21 +171,32 @@ void LODManager::autoAdjustLOD(float realTimeDelta) {
}
}
float LODManager::getLODAngleHalfTan() const {
return getPerspectiveAccuracyAngleTan(_octreeSizeScale, _boundaryLevelAdjust);
float LODManager::getLODHalfAngleTan() const {
return tan(_lodHalfAngle);
}
float LODManager::getLODAngle() const {
return 2.0f * atanf(getLODAngleHalfTan());
return 2.0f * _lodHalfAngle;
}
float LODManager::getLODAngleDeg() const {
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) {
auto newSolidAngle = std::max(0.5f, std::min(lodAngle, 90.f));
auto halTan = glm::tan(glm::radians(newSolidAngle * 0.5f));
auto octreeSizeScale = TREE_SCALE * OCTREE_TO_MESH_RATIO / halTan;
setOctreeSizeScale(octreeSizeScale);
auto newLODAngleDeg = std::max(0.001f, std::min(lodAngle, 90.f));
auto newLODHalfAngle = glm::radians(newLODAngleDeg * 0.5f);
_lodHalfAngle = newLODHalfAngle;
}
void LODManager::setSmoothScale(float t) {
@ -267,7 +276,11 @@ bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) {
};
void LODManager::setOctreeSizeScale(float sizeScale) {
_octreeSizeScale = sizeScale;
setVisibilityDistance(sizeScale / TREE_SCALE);
}
float LODManager::getOctreeSizeScale() const {
return getVisibilityDistance() * TREE_SCALE;
}
void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
@ -293,12 +306,14 @@ QString LODManager::getLODFeedbackText() {
} break;
}
// distance feedback
float octreeSizeScale = getOctreeSizeScale();
float relativeToDefault = octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE;
float visibilityDistance = getVisibilityDistance();
float relativeToDefault = visibilityDistance / DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT;
int relativeToTwentyTwenty = 20 / relativeToDefault;
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);
} else if (relativeToDefault > 0.99f) {
result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback);

View file

@ -17,6 +17,7 @@
#include <DependencyManager.h>
#include <NumericalConstants.h>
#include <OctreeConstants.h>
#include <OctreeUtils.h>
#include <PIDController.h>
#include <SimpleMovingAverage.h>
#include <render/Args.h>
@ -138,24 +139,28 @@ public:
/**jsdoc
* @function LODManager.setOctreeSizeScale
* @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);
/**jsdoc
* @function LODManager.getOctreeSizeScale
* @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
* @function LODManager.setBoundaryLevelAdjust
* @param {number} boundaryLevelAdjust
* @deprecated This function is deprecated and will be removed.
*/
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
/**jsdoc
* @function LODManager.getBoundaryLevelAdjust
* @returns {number}
* @deprecated This function is deprecated and will be removed.
*/
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
@ -196,8 +201,10 @@ public:
float getLODAngleDeg() const;
void setLODAngleDeg(float lodAngle);
float getLODAngleHalfTan() const;
float getLODHalfAngleTan() const;
float getLODAngle() const;
float getVisibilityDistance() const;
void setVisibilityDistance(float distance);
float getPidKp() const;
float getPidKi() const;
@ -254,7 +261,7 @@ private:
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 _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
float _lodHalfAngle = getHalfAngleFromVisibilityDistance(DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT);
int _boundaryLevelAdjust = 0;
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.enableSkybox(true);
batch.enableStereo(isStereo);
batch.clearDepthStencilFramebuffer(1.0, 0);
batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() });
_splashScreen->render(batch, viewFrustum, renderArgs._renderMethod == RenderArgs::RenderMethod::FORWARD);
});

View file

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

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) {
// compute absolute poses that correspond to relative target poses
AnimPoseVec absolutePoses;
@ -227,6 +233,8 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
accumulator.clearAndClean();
}
std::map<int, int> targetToChainMap;
float maxError = 0.0f;
int numLoops = 0;
const int MAX_IK_LOOPS = 16;
@ -248,17 +256,13 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
break;
}
}
// on last iteration, interpolate jointChains, if necessary
if (numLoops == MAX_IK_LOOPS) {
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) {
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);
float alpha = getInterpolationAlpha(_prevJointChainInfoVec[i].timer);
size_t chainSize = std::min(_prevJointChainInfoVec[i].jointInfoVec.size(), jointChainInfoVec[i].jointInfoVec.size());
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) {
int tipIndex = target.getIndex();
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.
if (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() && target.getType() == IKTarget::Type::RotationOnly) {
const glm::quat& targetRotation = target.getRotation();
// compute tip's new parent-relative rotation
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot()) * targetRotation;
RotationConstraint* constraint = getConstraint(tipIndex);
if (constraint) {
constraint->apply(newRelativeRotation);
// 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 (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() &&
(target.getType() == IKTarget::Type::RotationOnly || target.getType() == IKTarget::Type::Unknown)) {
if (target.getType() == IKTarget::Type::RotationOnly) {
const glm::quat& targetRotation = target.getRotation();
// compute tip's new parent-relative rotation
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot()) * targetRotation;
RotationConstraint* constraint = getConstraint(tipIndex);
if (constraint) {
constraint->apply(newRelativeRotation);
// 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.getPoleVectorEnabled() != _prevJointChainInfoVec[i].target.getPoleVectorEnabled())) {
_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 initConstraints();
void initLimitCenterPoses();
float getInterpolationAlpha(float timer);
// no copies
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
@ -181,6 +182,7 @@ protected:
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
AnimPoseVec _relativePoses; // current relative poses
AnimPoseVec _limitCenterPoses; // relative
std::map<int, glm::quat> _rotationOnlyIKRotations;
std::map<int, AnimPose> _secondaryTargetsInRigFrame;

View file

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

View file

@ -128,6 +128,7 @@ void AnimStateMachine::switchState(const AnimVariantMap& animVars, const AnimCon
auto prevStateNode = _children[_currentState->getChildIndex()];
auto nextStateNode = _children[desiredState->getChildIndex()];
bool interpActive = _duringInterp;
_duringInterp = true;
_alpha = 0.0f;
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);
_nextPoses = nextStateNode->evaluate(animVars, context, dt, triggers);
} else if (_interpType == InterpType::SnapshotPrev) {
// snapshot previoius pose
// snapshot previous pose
_prevPoses = _poses;
// no need to evaluate _nextPoses we will do it dynamically during the interp,
// however we need to set the current frame.
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 {
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;
_animVars.set("talkOverlayAlpha", easeOutInValue);
_animVars.set("idleOverlayAlpha", easeOutInValue); // backward compatibility for older anim graphs.
} else {
_animVars.set("talkOverlayAlpha", 1.0f);
_animVars.set("idleOverlayAlpha", 1.0f); // backward compatibility for older anim graphs.
}
} else {
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 talkAlpha = 1.0f - easeOutInValue;
_animVars.set("talkOverlayAlpha", talkAlpha);
_animVars.set("idleOverlayAlpha", talkAlpha); // backward compatibility for older anim graphs.
} else {
_animVars.set("talkOverlayAlpha", 0.0f);
_animVars.set("idleOverlayAlpha", 0.0f); // backward compatibility for older anim graphs.
}
}

View file

@ -33,8 +33,8 @@ using namespace gpu::gl;
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
#endif
bool GLTexelFormat::isCompressed() const {
switch (internalFormat) {
bool GLTexelFormat::isCompressed(GLenum format) {
switch (format) {
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_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 result = GL_RGBA8;
switch (dstFormat.getDimension()) {

View file

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

View file

@ -33,6 +33,7 @@ class GL45Backend : public GLBackend {
friend class Context;
public:
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
static GLint MAX_COMBINED_SHADER_STORAGE_BLOCKS;
static GLint MAX_UNIFORM_LOCATIONS;
#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 amountCopied = sourceSize;
bool compressed = GLTexelFormat::isCompressed(internalFormat);
if (GL_TEXTURE_2D == _target) {
switch (internalFormat) {
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
case GL_COMPRESSED_RED_RGTC1:
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;
if (compressed) {
glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
} else {
glTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
}
} else if (GL_TEXTURE_CUBE_MAP == _target) {
switch (internalFormat) {
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
case GL_COMPRESSED_RED_RGTC1:
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:
#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;
// DSA and cubemap functions are notoriously buggy. use the 4.1 compatible pathway
glActiveTexture(GL_TEXTURE0 + GL45Backend::RESOURCE_TRANSFER_TEX_UNIT);
glBindTexture(_target, _texture);
auto target = GLTexture::CUBE_FACE_LAYOUT[face];
if (compressed) {
glCompressedTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, internalFormat,
static_cast<GLsizei>(sourceSize), sourcePointer);
} else {
glTexSubImage2D(target, mip, 0, yOffset, size.x, size.y, format, type, sourcePointer);
}
glBindTexture(_target, 0);
} else {
assert(false);
amountCopied = 0;
}
(void)CHECK_GL_ERROR();
return amountCopied;
}

View file

@ -334,12 +334,17 @@ void Socket::checkForReadyReadBackup() {
qCDebug(networking) << "Socket::checkForReadyReadyBackup() last sequence number"
<< (uint32_t) _lastReceivedSequenceNumber << "from" << _lastPacketSockAddr << "-"
<< _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
int droppedCount = 0;
while (_udpSocket.hasPendingDatagrams()) {
_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;
// 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_OCTREE_SIZE_SCALE = TREE_SCALE * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT;
const float DEFAULT_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT = 400.0f; // max distance where a 1x1x1 cube is visible for 20:20 vision
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,
// 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 <AACube.h>
float calculateRenderAccuracy(const glm::vec3& position,
const AABox& bounds,
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 visibilityDistance) {
return visibilityDistance / powf(2.0f, renderLevel);
}
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) {
return voxelSizeScale / powf(2.0f, renderLevel);
float getPerspectiveAccuracyHalfAngleTan(float visibilityDistance, int boundaryLevelAdjust) {
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, visibilityDistance);
return UNIT_ELEMENT_MAX_EXTENT / visibleDistanceAtMaxScale;
}
float getPerspectiveAccuracyAngleTan(float octreeSizeScale, int boundaryLevelAdjust) {
const float maxScale = (float)TREE_SCALE;
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
return (maxScale / visibleDistanceAtMaxScale);
float getPerspectiveAccuracyHalfAngle(float visibilityDistance, int boundaryLevelAdjust) {
return atan(getPerspectiveAccuracyHalfAngleTan(visibilityDistance, boundaryLevelAdjust));
}
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) {
return atan(getPerspectiveAccuracyAngleTan(octreeSizeScale, boundaryLevelAdjust));
float getVisibilityDistanceFromHalfAngle(float halfAngle) {
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
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 QJsonDocument;
/// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple
/// 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 visibilityDistance);
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
float getPerspectiveAccuracyAngleTan(float octreeSizeScale, int boundaryLevelAdjust);
float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust);
float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust);
float getPerspectiveAccuracyHalfAngleTan(float visibilityDistance, int boundaryLevelAdjust);
float getPerspectiveAccuracyHalfAngle(float visibilityDistance, int boundaryLevelAdjust);
float getVisibilityDistanceFromHalfAngle(float halfAngle);
float getHalfAngleFromVisibilityDistance(float visibilityDistance);
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
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
{
float angle = glm::degrees(getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust));
float angle = glm::degrees(getPerspectiveAccuracyHalfAngle(args->_sizeScale, args->_boundaryLevelAdjust));
Transform crosshairModel;
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

View file

@ -218,12 +218,12 @@ void XMLHttpRequestClass::requestFinished() {
}
}
setReadyState(DONE);
emit requestComplete();
disconnectFromReply(_reply);
_reply->deleteLater();
_reply = nullptr;
setReadyState(DONE);
emit requestComplete();
}
void XMLHttpRequestClass::abortRequest() {

View file

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

View file

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

View file

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

View file

@ -602,7 +602,7 @@ function maybeUpdateOutputDeviceMutedOverlay() {
var oldAutomaticLODAdjust;
var oldLODAngleDeg;
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() {
oldAutomaticLODAdjust = LODManager.automaticLODAdjust;
oldLODAngleDeg = LODManager.lodAngleDeg;

View file

@ -30,6 +30,8 @@ source_group("UI Files" FILES ${QT_UI_FILES})
# have qt5 wrap them and generate the appropriate header files
qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
setup_memory_debugger()
# add them to the nitpick source files
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_DISABLE_TEXTURE_COMPRESSION_PARAMETER = "disable-texture-compression";
QUrl OvenCLIApplication::_inputUrlParameter;
QUrl OvenCLIApplication::_outputUrlParameter;
QString OvenCLIApplication::_typeParameter;
OvenCLIApplication::OvenCLIApplication(int argc, char* 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
QCommandLineParser parser;
parser.setApplicationDescription("High Fidelity Oven");
parser.addOptions({
{ 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" },
@ -37,25 +48,45 @@ OvenCLIApplication::OvenCLIApplication(int argc, char* argv[]) :
{ CLI_DISABLE_TEXTURE_COMPRESSION_PARAMETER, "Disable texture compression." }
});
parser.addHelpOption();
parser.process(*this);
auto versionOption = parser.addVersionOption();
auto helpOption = parser.addHelpOption();
if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) {
BakerCLI* cli = new BakerCLI(this);
QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER)));
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();
QStringList arguments;
for (int i = 0; i < argc; ++i) {
arguments << argv[i];
}
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:
OvenCLIApplication(int argc, char* argv[]);
static void parseCommandLine(int argc, char* argv[]);
static OvenCLIApplication* instance() { return dynamic_cast<OvenCLIApplication*>(QCoreApplication::instance()); }
private:
static QUrl _inputUrlParameter;
static QUrl _outputUrlParameter;
static QString _typeParameter;
};
#endif // hifi_OvenCLIApplication_h

View file

@ -18,14 +18,19 @@
int main (int argc, char** argv) {
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
if (argc > 1) {
OvenCLIApplication::parseCommandLine(argc, argv);
// init the settings interface so we can save and load settings
Setting::init();
OvenCLIApplication app { argc, argv };
return app.exec();
} else {
// init the settings interface so we can save and load settings
Setting::init();
OvenGUIApplication app { argc, argv };
return app.exec();
}