WIP
This commit is contained in:
parent
f4fecdc3e5
commit
efd652b77c
|
|
@ -29,6 +29,13 @@
|
||||||
<label>Display Spacing</label>
|
<label>Display Spacing</label>
|
||||||
<description>How far apart the displays are visually (not logically)</description>
|
<description>How far apart the displays are visually (not logically)</description>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="DisplaySize" type="Int">
|
||||||
|
<default>100</default>
|
||||||
|
<min>10</min>
|
||||||
|
<max>250</max>
|
||||||
|
<label>Display Size</label>
|
||||||
|
<description>Scale the displays in XR (percentage)</description>
|
||||||
|
</entry>
|
||||||
<entry name="DisplayHorizontalOffset" type="Int">
|
<entry name="DisplayHorizontalOffset" type="Int">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<min>-250</min>
|
<min>-250</min>
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
|
||||||
setFocusedDisplayDistance(BreezyDesktopConfig::focusedDisplayDistance() / 100.0f);
|
setFocusedDisplayDistance(BreezyDesktopConfig::focusedDisplayDistance() / 100.0f);
|
||||||
setAllDisplaysDistance(BreezyDesktopConfig::allDisplaysDistance() / 100.0f);
|
setAllDisplaysDistance(BreezyDesktopConfig::allDisplaysDistance() / 100.0f);
|
||||||
setDisplaySpacing(BreezyDesktopConfig::displaySpacing() / 1000.0f);
|
setDisplaySpacing(BreezyDesktopConfig::displaySpacing() / 1000.0f);
|
||||||
|
setDisplaySize(BreezyDesktopConfig::displaySize() / 100.0f);
|
||||||
setZoomOnFocusEnabled(BreezyDesktopConfig::zoomOnFocusEnabled());
|
setZoomOnFocusEnabled(BreezyDesktopConfig::zoomOnFocusEnabled());
|
||||||
setSmoothFollowThreshold(BreezyDesktopConfig::smoothFollowThreshold());
|
setSmoothFollowThreshold(BreezyDesktopConfig::smoothFollowThreshold());
|
||||||
|
|
||||||
|
|
@ -515,6 +516,18 @@ void BreezyDesktopEffect::setDisplaySpacing(qreal spacing) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal BreezyDesktopEffect::displaySize() const {
|
||||||
|
return m_displaySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreezyDesktopEffect::setDisplaySize(qreal size) {
|
||||||
|
const qreal clamped = std::clamp(size, 0.5, 2.0);
|
||||||
|
if (!qFuzzyCompare(clamped, m_displaySize)) {
|
||||||
|
m_displaySize = clamped;
|
||||||
|
Q_EMIT displaySizeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qreal BreezyDesktopEffect::displayHorizontalOffset() const {
|
qreal BreezyDesktopEffect::displayHorizontalOffset() const {
|
||||||
return m_displayHorizontalOffset;
|
return m_displayHorizontalOffset;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ namespace KWin
|
||||||
Q_PROPERTY(qreal focusedDisplayDistance READ focusedDisplayDistance NOTIFY focusedDisplayDistanceChanged)
|
Q_PROPERTY(qreal focusedDisplayDistance READ focusedDisplayDistance NOTIFY focusedDisplayDistanceChanged)
|
||||||
Q_PROPERTY(qreal allDisplaysDistance READ allDisplaysDistance NOTIFY allDisplaysDistanceChanged)
|
Q_PROPERTY(qreal allDisplaysDistance READ allDisplaysDistance NOTIFY allDisplaysDistanceChanged)
|
||||||
Q_PROPERTY(qreal displaySpacing READ displaySpacing NOTIFY displaySpacingChanged)
|
Q_PROPERTY(qreal displaySpacing READ displaySpacing NOTIFY displaySpacingChanged)
|
||||||
|
Q_PROPERTY(qreal displaySize READ displaySize NOTIFY displaySizeChanged)
|
||||||
Q_PROPERTY(qreal displayHorizontalOffset READ displayHorizontalOffset NOTIFY displayOffsetChanged)
|
Q_PROPERTY(qreal displayHorizontalOffset READ displayHorizontalOffset NOTIFY displayOffsetChanged)
|
||||||
Q_PROPERTY(qreal displayVerticalOffset READ displayVerticalOffset NOTIFY displayOffsetChanged)
|
Q_PROPERTY(qreal displayVerticalOffset READ displayVerticalOffset NOTIFY displayOffsetChanged)
|
||||||
Q_PROPERTY(int displayWrappingScheme READ displayWrappingScheme NOTIFY displayWrappingSchemeChanged)
|
Q_PROPERTY(int displayWrappingScheme READ displayWrappingScheme NOTIFY displayWrappingSchemeChanged)
|
||||||
|
|
@ -89,6 +90,8 @@ namespace KWin
|
||||||
void setAllDisplaysDistance(qreal distance);
|
void setAllDisplaysDistance(qreal distance);
|
||||||
qreal displaySpacing() const;
|
qreal displaySpacing() const;
|
||||||
void setDisplaySpacing(qreal spacing);
|
void setDisplaySpacing(qreal spacing);
|
||||||
|
qreal displaySize() const;
|
||||||
|
void setDisplaySize(qreal size);
|
||||||
qreal displayHorizontalOffset() const;
|
qreal displayHorizontalOffset() const;
|
||||||
qreal displayVerticalOffset() const;
|
qreal displayVerticalOffset() const;
|
||||||
int displayWrappingScheme() const;
|
int displayWrappingScheme() const;
|
||||||
|
|
@ -127,6 +130,7 @@ namespace KWin
|
||||||
void focusedDisplayDistanceChanged();
|
void focusedDisplayDistanceChanged();
|
||||||
void allDisplaysDistanceChanged();
|
void allDisplaysDistanceChanged();
|
||||||
void displaySpacingChanged();
|
void displaySpacingChanged();
|
||||||
|
void displaySizeChanged();
|
||||||
void displayOffsetChanged();
|
void displayOffsetChanged();
|
||||||
void displayWrappingSchemeChanged();
|
void displayWrappingSchemeChanged();
|
||||||
void enabledStateChanged();
|
void enabledStateChanged();
|
||||||
|
|
@ -191,6 +195,7 @@ namespace KWin
|
||||||
qreal m_focusedDisplayDistance = 0.85;
|
qreal m_focusedDisplayDistance = 0.85;
|
||||||
qreal m_allDisplaysDistance = 1.05;
|
qreal m_allDisplaysDistance = 1.05;
|
||||||
qreal m_displaySpacing = 0.0;
|
qreal m_displaySpacing = 0.0;
|
||||||
|
qreal m_displaySize = 1.0;
|
||||||
qreal m_displayHorizontalOffset = 0.0;
|
qreal m_displayHorizontalOffset = 0.0;
|
||||||
qreal m_displayVerticalOffset = 0.0;
|
qreal m_displayVerticalOffset = 0.0;
|
||||||
int m_displayWrappingScheme = 0; // 0=auto,1=horizontal,2=vertical,3=flat
|
int m_displayWrappingScheme = 0; // 0=auto,1=horizontal,2=vertical,3=flat
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,7 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
|
||||||
connect(ui.kcfg_ZoomOnFocusEnabled, &QCheckBox::toggled, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_ZoomOnFocusEnabled, &QCheckBox::toggled, this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_FocusedDisplayDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_FocusedDisplayDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_AllDisplaysDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_AllDisplaysDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
|
connect(ui.kcfg_DisplaySize, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_DisplaySpacing, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_DisplaySpacing, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_SmoothFollowThreshold, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_SmoothFollowThreshold, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
connect(ui.kcfg_DisplayHorizontalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
connect(ui.kcfg_DisplayHorizontalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
|
||||||
|
|
@ -456,6 +457,7 @@ void BreezyDesktopEffectConfig::updateUiFromConfig()
|
||||||
{
|
{
|
||||||
ui.kcfg_FocusedDisplayDistance->setValue(BreezyDesktopConfig::self()->focusedDisplayDistance());
|
ui.kcfg_FocusedDisplayDistance->setValue(BreezyDesktopConfig::self()->focusedDisplayDistance());
|
||||||
ui.kcfg_AllDisplaysDistance->setValue(BreezyDesktopConfig::self()->allDisplaysDistance());
|
ui.kcfg_AllDisplaysDistance->setValue(BreezyDesktopConfig::self()->allDisplaysDistance());
|
||||||
|
ui.kcfg_DisplaySize->setValue(BreezyDesktopConfig::self()->displaySize());
|
||||||
ui.kcfg_DisplaySpacing->setValue(BreezyDesktopConfig::self()->displaySpacing());
|
ui.kcfg_DisplaySpacing->setValue(BreezyDesktopConfig::self()->displaySpacing());
|
||||||
ui.kcfg_DisplayHorizontalOffset->setValue(BreezyDesktopConfig::self()->displayHorizontalOffset());
|
ui.kcfg_DisplayHorizontalOffset->setValue(BreezyDesktopConfig::self()->displayHorizontalOffset());
|
||||||
ui.kcfg_DisplayVerticalOffset->setValue(BreezyDesktopConfig::self()->displayVerticalOffset());
|
ui.kcfg_DisplayVerticalOffset->setValue(BreezyDesktopConfig::self()->displayVerticalOffset());
|
||||||
|
|
@ -492,7 +494,7 @@ void BreezyDesktopEffectConfig::checkEffectLoaded() {
|
||||||
QPalette pal = warn->palette();
|
QPalette pal = warn->palette();
|
||||||
pal.setColor(QPalette::WindowText, QColor(Qt::red));
|
pal.setColor(QPalette::WindowText, QColor(Qt::red));
|
||||||
warn->setPalette(pal);
|
warn->setPalette(pal);
|
||||||
warn->setText(tr("The Breezy Desktop KWin effect is not loaded. Please log out and back in to enable it."));
|
warn->setText(tr("The Breezy Desktop KWin effect is disabled or not loaded. Please check the Desktop Effects dialog. Otherwise, log out and back in to enable it."));
|
||||||
warn->setVisible(true);
|
warn->setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,14 +151,23 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="6" column="0">
|
||||||
<widget class="QLabel" name="labelDisplaySpacing">
|
<widget class="QLabel" name="labelDisplaySize">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Display Spacing:</string>
|
<string>Display Size:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QSlider" name="kcfg_DisplaySpacing">
|
<widget class="LabeledSlider" name="kcfg_DisplaySize">
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::NoTicks</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickStartOffset">
|
||||||
|
<double>10</double>
|
||||||
|
</property>
|
||||||
|
<property name="tickInterval">
|
||||||
|
<double>25</double>
|
||||||
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
|
|
@ -168,13 +177,30 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="labelDisplaySpacing">
|
||||||
|
<property name="text">
|
||||||
|
<string>Display Spacing:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QSlider" name="kcfg_DisplaySpacing">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tracking">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
<widget class="QLabel" name="labelFollowThreshold">
|
<widget class="QLabel" name="labelFollowThreshold">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Follow threshold:</string>
|
<string>Follow threshold:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="LabeledSlider" name="kcfg_SmoothFollowThreshold">
|
<widget class="LabeledSlider" name="kcfg_SmoothFollowThreshold">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
|
@ -196,7 +222,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="9" column="0">
|
||||||
<widget class="QLabel" name="labelVirtualDisplays">
|
<widget class="QLabel" name="labelVirtualDisplays">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add Virtual Display:</string>
|
<string>Add Virtual Display:</string>
|
||||||
|
|
@ -209,7 +235,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="9" column="1">
|
||||||
<widget class="QWidget" name="widgetVirtualDisplayButtons">
|
<widget class="QWidget" name="widgetVirtualDisplayButtons">
|
||||||
<property name="visible">
|
<property name="visible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ Item {
|
||||||
property bool customBannerEnabled: effect.customBannerEnabled
|
property bool customBannerEnabled: effect.customBannerEnabled
|
||||||
property bool smoothFollowEnabled: effect.smoothFollowEnabled
|
property bool smoothFollowEnabled: effect.smoothFollowEnabled
|
||||||
property real lookAheadScanlineMs: effect.lookAheadConfig[2]
|
property real lookAheadScanlineMs: effect.lookAheadConfig[2]
|
||||||
property var crossFovs: displays.diagonalToCrossFOVs(
|
property var fovLengths: displays.diagonalToCrossFOVs(
|
||||||
displays.degreeToRadian(effect.diagonalFOV),
|
displays.degreeToRadian(effect.diagonalFOV),
|
||||||
aspectRatio
|
aspectRatio
|
||||||
);
|
);
|
||||||
|
|
@ -84,7 +84,9 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildPerspectiveMatrix() {
|
function buildPerspectiveMatrix() {
|
||||||
const f = 1.0 / crossFovs.verticalTangent;
|
const verticalTangent = fovLengths.heightUnitDistance / 2.0;
|
||||||
|
const horizontalTangent = fovLengths.widthUnitDistance / 2.0;
|
||||||
|
const f = 1.0 / verticalTangent;
|
||||||
const nf = 1.0 / (clipNear - clipFar);
|
const nf = 1.0 / (clipNear - clipFar);
|
||||||
const m00 = f / aspectRatio;
|
const m00 = f / aspectRatio;
|
||||||
const m11 = f;
|
const m11 = f;
|
||||||
|
|
@ -102,13 +104,13 @@ Item {
|
||||||
|
|
||||||
function applyRollingShutterShear(rates) {
|
function applyRollingShutterShear(rates) {
|
||||||
// Convert to maximum shift at bottom of frame
|
// Convert to maximum shift at bottom of frame
|
||||||
const maxDxNdc = (rates.yaw * lookAheadScanlineMs) / crossFovs.horizontalTangent;
|
const maxDxNdc = (rates.yaw * lookAheadScanlineMs) / horizontalTangent;
|
||||||
const maxDyNdc = -(rates.pitch * lookAheadScanlineMs) / crossFovs.verticalTangent;
|
const maxDyNdc = -(rates.pitch * lookAheadScanlineMs) / verticalTangent;
|
||||||
|
|
||||||
let shx = maxDxNdc / 2.0;
|
let shx = maxDxNdc / 2.0;
|
||||||
let shy = maxDyNdc / 2.0;
|
let shy = maxDyNdc / 2.0;
|
||||||
|
|
||||||
const f = 1.0 / crossFovs.verticalTangent;
|
const f = 1.0 / verticalTangent;
|
||||||
const nf = 1.0 / (clipNear - clipFar);
|
const nf = 1.0 / (clipNear - clipFar);
|
||||||
const m00 = f / aspectRatio;
|
const m00 = f / aspectRatio;
|
||||||
const m11 = f;
|
const m11 = f;
|
||||||
|
|
|
||||||
|
|
@ -26,27 +26,26 @@ ProceduralMesh {
|
||||||
const fov = mesh.fovDetails;
|
const fov = mesh.fovDetails;
|
||||||
const monitor = mesh.monitorGeometry;
|
const monitor = mesh.monitorGeometry;
|
||||||
|
|
||||||
const conv = fov.curvedDisplay ? mesh.fovConversionFns.curved
|
|
||||||
: mesh.fovConversionFns.flat;
|
|
||||||
|
|
||||||
const horizontalWrap = fov.monitorWrappingScheme === 'horizontal';
|
const horizontalWrap = fov.monitorWrappingScheme === 'horizontal';
|
||||||
const verticalWrap = fov.monitorWrappingScheme === 'vertical';
|
const horizontalConversions = horizontalWrap && fov.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
|
||||||
|
|
||||||
const sideEdgeDistance = conv.centerToFovEdgeDistance(
|
const sideEdgeDistancePixels = horizontalConversions.centerToFovEdgeDistance(
|
||||||
fov.completeScreenDistancePixels, fov.widthPixels);
|
fov.completeScreenDistancePixels, fov.sizeAdjustedWidthPixels);
|
||||||
const horizontalRadians = conv.lengthToRadians(
|
const horizontalRadians = horizontalConversions.lengthToRadians(
|
||||||
fov.defaultDistanceHorizontalRadians,
|
fov.defaultDistanceHorizontalRadians,
|
||||||
fov.widthPixels,
|
fov.widthPixels,
|
||||||
sideEdgeDistance,
|
sideEdgeDistancePixels,
|
||||||
monitor.width
|
monitor.width
|
||||||
);
|
);
|
||||||
|
|
||||||
const topEdgeDistance = conv.centerToFovEdgeDistance(
|
const verticalWrap = fov.monitorWrappingScheme === 'vertical';
|
||||||
fov.completeScreenDistancePixels, fov.heightPixels);
|
const verticalConversions = verticalWrap && fov.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
|
||||||
const verticalRadians = conv.lengthToRadians(
|
const topEdgeDistancePixels = verticalConversions.centerToFovEdgeDistance(
|
||||||
|
fov.completeScreenDistancePixels, fov.sizeAdjustedHeightPixels);
|
||||||
|
const verticalRadians = verticalConversions.lengthToRadians(
|
||||||
fov.defaultDistanceVerticalRadians,
|
fov.defaultDistanceVerticalRadians,
|
||||||
fov.heightPixels,
|
fov.heightPixels,
|
||||||
topEdgeDistance,
|
topEdgeDistancePixels,
|
||||||
monitor.height
|
monitor.height
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,25 @@ QtObject {
|
||||||
return Qt.quaternion(quaternion.scalar, -quaternion.z, -quaternion.x, quaternion.y);
|
return Qt.quaternion(quaternion.scalar, -quaternion.z, -quaternion.x, quaternion.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts diagonal FOV in radians and aspect ratio to horizontal and vertical FOVs
|
// Converts diagonal FOV in radians and aspect ratio to horizontal and vertical FOV measurements
|
||||||
function diagonalToCrossFOVs(diagonalFOVRadians, aspectRatio) {
|
function diagonalToCrossFOVs(diagonalFOVRadians, aspectRatio) {
|
||||||
var diagonalTangent = Math.tan(diagonalFOVRadians / 2);
|
// first convert from a spherical FOV to a diagonal FOV on a flat plane at a unit distance of 1.0
|
||||||
var verticalTangent = diagonalTangent / Math.sqrt(1 + aspectRatio * aspectRatio);
|
const diagonalLengthUnitDistance = 2 * Math.tan(diagonalFOVRadians / 2);
|
||||||
var horizontalTangent = verticalTangent * aspectRatio;
|
|
||||||
|
// then convert to flat plane horizontal and vertical FOVs
|
||||||
|
const heightUnitDistance = diagonalLengthUnitDistance / Math.sqrt(1 + aspectRatio * aspectRatio);
|
||||||
|
const widthUnitDistance = heightUnitDistance * aspectRatio;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
diagonal: diagonalFOVRadians,
|
// then convert back to spherical FOV
|
||||||
horizontal: 2 * Math.atan(horizontalTangent),
|
diagonalRadians: diagonalFOVRadians,
|
||||||
horizontalTangent: horizontalTangent,
|
horizontalRadians: 2 * Math.atan(widthUnitDistance / 2),
|
||||||
vertical: 2 * Math.atan(verticalTangent),
|
verticalRadians: 2 * Math.atan(heightUnitDistance / 2),
|
||||||
verticalTangent: verticalTangent
|
|
||||||
|
// flat values are relative to a unit distance of 1.0
|
||||||
|
diagonalLengthUnitDistance,
|
||||||
|
widthUnitDistance,
|
||||||
|
heightUnitDistance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,33 +58,55 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildFovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice) {
|
function buildFovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice, distanceAdjustedSize) {
|
||||||
const aspect = viewportWidth / viewportHeight;
|
const aspect = viewportWidth / viewportHeight;
|
||||||
const crossFovs = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
|
const fovLengths = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
|
||||||
const defaultDistanceVerticalRadians = 2 * Math.atan(crossFovs.verticalTangent / defaultDisplayDistance);
|
|
||||||
const defaultDistanceHorizontalRadians = 2 * Math.atan(crossFovs.horizontalTangent / defaultDisplayDistance);
|
|
||||||
|
|
||||||
// distance needed for the FOV-sized monitor to fill up the screen
|
|
||||||
const fullScreenDistance = viewportHeight / (2 * crossFovs.verticalTangent);
|
|
||||||
const lensDistancePixels = fullScreenDistance / (1.0 - lensDistanceRatio) - fullScreenDistance;
|
|
||||||
|
|
||||||
// distance of a display at the default (most zoomed out) distance, plus the lens distance constant
|
|
||||||
const lensToScreenDistance = viewportHeight / (2 * Math.tan(defaultDistanceVerticalRadians / 2));
|
|
||||||
const completeScreenDistancePixels = lensToScreenDistance + lensDistancePixels;
|
|
||||||
|
|
||||||
let monitorWrappingScheme = actualWrapScheme(screens, viewportWidth, viewportHeight);
|
let monitorWrappingScheme = actualWrapScheme(screens, viewportWidth, viewportHeight);
|
||||||
if (wrappingChoice === 1) monitorWrappingScheme = 'horizontal';
|
if (wrappingChoice === 1) monitorWrappingScheme = 'horizontal';
|
||||||
else if (wrappingChoice === 2) monitorWrappingScheme = 'vertical';
|
else if (wrappingChoice === 2) monitorWrappingScheme = 'vertical';
|
||||||
else if (wrappingChoice === 3) monitorWrappingScheme = 'flat';
|
else if (wrappingChoice === 3) monitorWrappingScheme = 'flat';
|
||||||
|
|
||||||
|
const lensDistanceComplement = 1.0 - lensDistanceRatio;
|
||||||
|
const lensDistanceFactor = (1.0 / lensDistanceComplement) - 1.0;
|
||||||
|
const horizontalConversions = effect.curvedDisplay && monitorWrappingScheme === 'horizontal' ? fovConversionFns.curved : fovConversionFns.flat;
|
||||||
|
const verticalConversions = effect.curvedDisplay && monitorWrappingScheme === 'vertical' ? fovConversionFns.curved : fovConversionFns.flat;
|
||||||
|
|
||||||
|
const defaultDistanceVerticalRadians = verticalConversions.fovRadiansAtDistance(
|
||||||
|
fovLengths.verticalRadians,
|
||||||
|
fovLengths.heightUnitDistance,
|
||||||
|
defaultDisplayDistance
|
||||||
|
);
|
||||||
|
const defaultDistanceHorizontalRadians = horizontalConversions.fovRadiansAtDistance(
|
||||||
|
fovLengths.horizontalRadians,
|
||||||
|
fovLengths.widthUnitDistance,
|
||||||
|
defaultDisplayDistance
|
||||||
|
);
|
||||||
|
|
||||||
|
// distance needed for the FOV-sized monitor to fill up the screen, as measured from the lenses
|
||||||
|
const lensToUnitDistancePixels = viewportWidth / fovLengths.widthUnitDistance;
|
||||||
|
|
||||||
|
// distance from pivot point to lens
|
||||||
|
const lensDistancePixels = lensToUnitDistancePixels * lensDistanceFactor;
|
||||||
|
|
||||||
|
// distance from pivot point to full screen (monitor at unit distance from lens)
|
||||||
|
const fullScreenDistancePixels = lensToUnitDistancePixels + lensDistancePixels;
|
||||||
|
|
||||||
|
// distance of a display at the default (most zoomed out) distance from the pivot point
|
||||||
|
const completeScreenDistancePixels = fullScreenDistancePixels * defaultDisplayDistance;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
widthPixels: viewportWidth,
|
widthPixels: viewportWidth,
|
||||||
|
distanceAdjustedSize,
|
||||||
|
sizeAdjustedWidthPixels: viewportWidth * distanceAdjustedSize,
|
||||||
heightPixels: viewportHeight,
|
heightPixels: viewportHeight,
|
||||||
|
sizeAdjustedHeightPixels: viewportHeight * distanceAdjustedSize,
|
||||||
defaultDistanceVerticalRadians,
|
defaultDistanceVerticalRadians,
|
||||||
defaultDistanceHorizontalRadians,
|
defaultDistanceHorizontalRadians,
|
||||||
lensDistancePixels,
|
lensDistancePixels,
|
||||||
|
fullScreenDistancePixels,
|
||||||
completeScreenDistancePixels,
|
completeScreenDistancePixels,
|
||||||
monitorWrappingScheme: monitorWrappingScheme,
|
monitorWrappingScheme,
|
||||||
curvedDisplay: effect.curvedDisplay
|
curvedDisplay: effect.curvedDisplay
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -99,6 +129,9 @@ QtObject {
|
||||||
angleToLength: function(fovRadians, fovLength, screenDistance, toAngleOpposite, toAngleAdjacent) {
|
angleToLength: function(fovRadians, fovLength, screenDistance, toAngleOpposite, toAngleAdjacent) {
|
||||||
return toAngleOpposite / toAngleAdjacent * screenDistance;
|
return toAngleOpposite / toAngleAdjacent * screenDistance;
|
||||||
},
|
},
|
||||||
|
fovRadiansAtDistance: function(fovRadians, unitLength, newScreenDistance) {
|
||||||
|
return 2 * Math.atan(unitLength / 2 / newScreenDistance);
|
||||||
|
},
|
||||||
radiansToSegments: function(screenRadians) { return 1; }
|
radiansToSegments: function(screenRadians) { return 1; }
|
||||||
},
|
},
|
||||||
curved: {
|
curved: {
|
||||||
|
|
@ -114,6 +147,9 @@ QtObject {
|
||||||
angleToLength: function(fovRadians, fovLength, screenDistance, toAngleOpposite, toAngleAdjacent) {
|
angleToLength: function(fovRadians, fovLength, screenDistance, toAngleOpposite, toAngleAdjacent) {
|
||||||
return fovLength / fovRadians * Math.atan2(toAngleOpposite, toAngleAdjacent);
|
return fovLength / fovRadians * Math.atan2(toAngleOpposite, toAngleAdjacent);
|
||||||
},
|
},
|
||||||
|
fovRadiansAtDistance: function(fovRadians, unitLength, newScreenDistance) {
|
||||||
|
return fovRadians / newScreenDistance;
|
||||||
|
},
|
||||||
radiansToSegments: function(screenRadians) {
|
radiansToSegments: function(screenRadians) {
|
||||||
return Math.ceil(screenRadians * segmentsPerRadian);
|
return Math.ceil(screenRadians * segmentsPerRadian);
|
||||||
}
|
}
|
||||||
|
|
@ -198,8 +234,12 @@ QtObject {
|
||||||
var conversionFns = fovDetails.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
|
var conversionFns = fovDetails.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
|
||||||
|
|
||||||
if (fovDetails.monitorWrappingScheme === 'horizontal') {
|
if (fovDetails.monitorWrappingScheme === 'horizontal') {
|
||||||
var sideEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.widthPixels);
|
// monitors wrap around us horizontally
|
||||||
var monitorSpacingPixels = monitorSpacing * fovDetails.widthPixels;
|
|
||||||
|
var sideEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.sizeAdjustedWidthPixels);
|
||||||
|
var monitorSpacingPixels = monitorSpacing * fovDetails.sizeAdjustedWidthPixels;
|
||||||
|
|
||||||
|
// targetWidth is assumed to aleady be size adjusted
|
||||||
var lengthToRadianFn = function(targetWidth) {
|
var lengthToRadianFn = function(targetWidth) {
|
||||||
return conversionFns.lengthToRadians(
|
return conversionFns.lengthToRadians(
|
||||||
fovDetails.defaultDistanceHorizontalRadians,
|
fovDetails.defaultDistanceHorizontalRadians,
|
||||||
|
|
@ -209,14 +249,14 @@ QtObject {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
cachedMonitorRadians[0] = -fovDetails.defaultDistanceHorizontalRadians / 2;
|
cachedMonitorRadians[0] = -lengthToRadianFn(fovDetails.sizeAdjustedWidthPixels) / 2;
|
||||||
horizontalMonitorSort(monitorDetailsList).forEach(function(obj) {
|
horizontalMonitorSort(monitorDetailsList).forEach(function(obj) {
|
||||||
var monitorDetails = obj.monitorDetails;
|
var monitorDetails = obj.monitorDetails;
|
||||||
var originalIndex = obj.originalIndex;
|
var originalIndex = obj.originalIndex;
|
||||||
var monitorWrapDetails = monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorDetails.x, monitorDetails.width, lengthToRadianFn);
|
var monitorWrapDetails = monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorDetails.x, monitorDetails.width, lengthToRadianFn);
|
||||||
var monitorCenterRadius = conversionFns.fovEdgeToScreenCenterDistance(sideEdgeRadius, monitorDetails.width);
|
var monitorCenterRadius = conversionFns.fovEdgeToScreenCenterDistance(sideEdgeRadius, monitorDetails.width);
|
||||||
var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.heightPixels) * monitorSpacingPixels;
|
var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.sizeAdjustedHeightPixels) * monitorSpacingPixels;
|
||||||
var upCenterOffsetPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
|
var upCenterOffsetPixels = (monitorDetails.height - fovDetails.sizeAdjustedHeightPixels) / 2;
|
||||||
var upCenterPixels = upTopPixels - upCenterOffsetPixels;
|
var upCenterPixels = upTopPixels - upCenterOffsetPixels;
|
||||||
|
|
||||||
monitorPlacements.push({
|
monitorPlacements.push({
|
||||||
|
|
@ -239,8 +279,8 @@ QtObject {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (fovDetails.monitorWrappingScheme === 'vertical') {
|
} else if (fovDetails.monitorWrappingScheme === 'vertical') {
|
||||||
var topEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.heightPixels);
|
var topEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.sizeAdjustedHeightPixels);
|
||||||
var monitorSpacingPixels = monitorSpacing * fovDetails.heightPixels;
|
var monitorSpacingPixels = monitorSpacing * fovDetails.sizeAdjustedHeightPixels;
|
||||||
var lengthToRadianFn = function(targetHeight) {
|
var lengthToRadianFn = function(targetHeight) {
|
||||||
return conversionFns.lengthToRadians(
|
return conversionFns.lengthToRadians(
|
||||||
fovDetails.defaultDistanceVerticalRadians,
|
fovDetails.defaultDistanceVerticalRadians,
|
||||||
|
|
@ -250,14 +290,14 @@ QtObject {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
cachedMonitorRadians[0] = -fovDetails.defaultDistanceVerticalRadians / 2;
|
cachedMonitorRadians[0] = -lengthToRadianFn(fovDetails.sizeAdjustedHeightPixels) / 2;
|
||||||
verticalMonitorSort(monitorDetailsList).forEach(function(obj) {
|
verticalMonitorSort(monitorDetailsList).forEach(function(obj) {
|
||||||
var monitorDetails = obj.monitorDetails;
|
var monitorDetails = obj.monitorDetails;
|
||||||
var originalIndex = obj.originalIndex;
|
var originalIndex = obj.originalIndex;
|
||||||
var monitorWrapDetails = monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorDetails.y, monitorDetails.height, lengthToRadianFn);
|
var monitorWrapDetails = monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorDetails.y, monitorDetails.height, lengthToRadianFn);
|
||||||
var monitorCenterRadius = conversionFns.fovEdgeToScreenCenterDistance(topEdgeRadius, monitorDetails.height);
|
var monitorCenterRadius = conversionFns.fovEdgeToScreenCenterDistance(topEdgeRadius, monitorDetails.height);
|
||||||
var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.widthPixels) * monitorSpacingPixels;
|
var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.sizeAdjustedWidthPixels) * monitorSpacingPixels;
|
||||||
var westCenterOffsetPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
|
var westCenterOffsetPixels = (monitorDetails.width - fovDetails.sizeAdjustedWidthPixels) / 2;
|
||||||
var westCenterPixels = westLeftPixels - westCenterOffsetPixels;
|
var westCenterPixels = westLeftPixels - westCenterOffsetPixels;
|
||||||
|
|
||||||
monitorPlacements.push({
|
monitorPlacements.push({
|
||||||
|
|
@ -280,12 +320,12 @@ QtObject {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var monitorSpacingPixels = monitorSpacing * fovDetails.widthPixels;
|
var monitorSpacingPixels = monitorSpacing * fovDetails.sizeAdjustedWidthPixels;
|
||||||
monitorDetailsList.forEach(function(monitorDetails, index) {
|
monitorDetailsList.forEach(function(monitorDetails, index) {
|
||||||
var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.heightPixels) * monitorSpacingPixels;
|
var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.sizeAdjustedHeightPixels) * monitorSpacingPixels;
|
||||||
var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.widthPixels) * monitorSpacingPixels;
|
var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.sizeAdjustedWidthPixels) * monitorSpacingPixels;
|
||||||
var westCenterOffsetPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
|
var westCenterOffsetPixels = (monitorDetails.width - fovDetails.sizeAdjustedWidthPixels) / 2;
|
||||||
var upCenterOffsetPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
|
var upCenterOffsetPixels = (monitorDetails.height - fovDetails.sizeAdjustedHeightPixels) / 2;
|
||||||
var westCenterPixels = westLeftPixels - westCenterOffsetPixels;
|
var westCenterPixels = westLeftPixels - westCenterOffsetPixels;
|
||||||
var upCenterPixels = upTopPixels - upCenterOffsetPixels;
|
var upCenterPixels = upTopPixels - upCenterOffsetPixels;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,19 +33,41 @@ Item {
|
||||||
property var screens: KWinComponents.Workspace.screens.filter(function(screen) {
|
property var screens: KWinComponents.Workspace.screens.filter(function(screen) {
|
||||||
return mirrorPhysicalDisplays || screen.name.includes("BreezyDesktop") || supportedModels.some(model => screen.model.includes(model));
|
return mirrorPhysicalDisplays || screen.name.includes("BreezyDesktop") || supportedModels.some(model => screen.model.includes(model));
|
||||||
})
|
})
|
||||||
|
property var sizeAdjustedScreens: screens.map(function(screen) {
|
||||||
|
const sizeComplement = (1.0 - distanceAdjustedSize) / 2.0;
|
||||||
|
const sizeViewportOffsetX = sizeComplement * viewportResolution[0];
|
||||||
|
const sizeViewportOffsetY = sizeComplement * viewportResolution[1];
|
||||||
|
return {
|
||||||
|
geometry: {
|
||||||
|
x: screen.geometry.x * distanceAdjustedSize + sizeViewportOffsetX,
|
||||||
|
y: screen.geometry.y * distanceAdjustedSize + sizeViewportOffsetY,
|
||||||
|
width: screen.geometry.width * distanceAdjustedSize,
|
||||||
|
height: screen.geometry.height * distanceAdjustedSize
|
||||||
|
},
|
||||||
|
name: screen.name,
|
||||||
|
model: screen.model
|
||||||
|
};
|
||||||
|
})
|
||||||
|
property real distanceAdjustedSize: (effect.allDisplaysDistance - effect.lensDistanceRatio) *effect.displaySize
|
||||||
|
property var sizeAdjustedViewport: {
|
||||||
|
return {
|
||||||
|
width: viewportResolution[0] * distanceAdjustedSize,
|
||||||
|
height: viewportResolution[1] * distanceAdjustedSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// x value for placing the viewport in the middle of all screens
|
// x value for placing the viewport in the middle of all screens
|
||||||
property real screensXMid: {
|
property real screensXMid: {
|
||||||
let xMin = Number.MAX_VALUE;
|
let xMin = Number.MAX_VALUE;
|
||||||
let xMax = Number.MIN_VALUE;
|
let xMax = Number.MIN_VALUE;
|
||||||
|
|
||||||
for (let i = 0; i < screens.length; i++) {
|
for (let i = 0; i < sizeAdjustedScreens.length; i++) {
|
||||||
const geometry = screens[i].geometry;
|
const geometry = sizeAdjustedScreens[i].geometry;
|
||||||
xMin = Math.min(xMin, geometry.x);
|
xMin = Math.min(xMin, geometry.x);
|
||||||
xMax = Math.max(xMax, geometry.x + geometry.width);
|
xMax = Math.max(xMax, geometry.x + geometry.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (xMin + xMax) / 2 - (viewportResolution[0] / 2);
|
return (xMin + xMax) / 2 - (sizeAdjustedViewport.width / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// y value for placing the viewport in the middle of all screens
|
// y value for placing the viewport in the middle of all screens
|
||||||
|
|
@ -53,13 +75,13 @@ Item {
|
||||||
let yMin = Number.MAX_VALUE;
|
let yMin = Number.MAX_VALUE;
|
||||||
let yMax = Number.MIN_VALUE;
|
let yMax = Number.MIN_VALUE;
|
||||||
|
|
||||||
for (let i = 0; i < screens.length; i++) {
|
for (let i = 0; i < sizeAdjustedScreens.length; i++) {
|
||||||
const geometry = screens[i].geometry;
|
const geometry = sizeAdjustedScreens[i].geometry;
|
||||||
yMin = Math.min(yMin, geometry.y);
|
yMin = Math.min(yMin, geometry.y);
|
||||||
yMax = Math.max(yMax, geometry.y + geometry.height);
|
yMax = Math.max(yMax, geometry.y + geometry.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (yMin + yMax) / 2 - (viewportResolution[1] / 2);
|
return (yMin + yMax) / 2 - (sizeAdjustedViewport.height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Displays {
|
Displays {
|
||||||
|
|
@ -67,19 +89,20 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
property var fovDetails: displays.buildFovDetails(
|
property var fovDetails: displays.buildFovDetails(
|
||||||
screens,
|
sizeAdjustedScreens,
|
||||||
viewportResolution[0],
|
sizeAdjustedViewport.width,
|
||||||
viewportResolution[1],
|
sizeAdjustedViewport.height,
|
||||||
viewportDiagonalFOVDegrees,
|
viewportDiagonalFOVDegrees,
|
||||||
effect.lensDistanceRatio,
|
effect.lensDistanceRatio,
|
||||||
effect.allDisplaysDistance,
|
effect.allDisplaysDistance,
|
||||||
effect.displayWrappingScheme
|
effect.displayWrappingScheme,
|
||||||
|
distanceAdjustedSize
|
||||||
)
|
)
|
||||||
|
|
||||||
property var monitorPlacements: {
|
property var monitorPlacements: {
|
||||||
const dx = effect.displayHorizontalOffset * viewportResolution[0];
|
const dx = effect.displayHorizontalOffset * sizeAdjustedViewport.width;
|
||||||
const dy = effect.displayVerticalOffset * viewportResolution[1];
|
const dy = effect.displayVerticalOffset * sizeAdjustedViewport.height;
|
||||||
const adjustedGeometries = screens.map(screen => {
|
const adjustedGeometries = sizeAdjustedScreens.map(screen => {
|
||||||
const g = screen.geometry;
|
const g = screen.geometry;
|
||||||
return {
|
return {
|
||||||
x: g.x - screensXMid + dx,
|
x: g.x - screensXMid + dx,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue