From 80c91ebe7ce5382b5c09f1c32717425aeaeabcd3 Mon Sep 17 00:00:00 2001 From: Awawa <69086569+awawa-dev@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:31:23 +0100 Subject: [PATCH] Feature to re-order displays in multi-display mode (DirectX) --- include/base/Grabber.h | 3 ++ include/led-strip/ChannelCalibration.h | 2 +- sources/base/Grabber.cpp | 23 +++++++++++++ sources/base/SystemWrapper.cpp | 2 ++ sources/base/schema/schema-systemGrabber.json | 16 ++++++++++ sources/grabber/windows/DX/DxGrabber.cpp | 30 +++++++++++++++-- sources/led-strip/ChannelCalibration.cpp | 10 +++--- sources/led-strip/ColorCalibration.cpp | 32 +++++++++---------- www/i18n/en.json | 4 ++- 9 files changed, 97 insertions(+), 25 deletions(-) diff --git a/include/base/Grabber.h b/include/base/Grabber.h index 0a69e8eca..0472ac43c 100644 --- a/include/base/Grabber.h +++ b/include/base/Grabber.h @@ -86,6 +86,8 @@ class Grabber : public DetectionAutomatic, public DetectionManual, protected Lut void setMonitorNits(int nits); + void setReorderDisplays(int order); + void setFpsSoftwareDecimation(int decimation) override; int getFpsSoftwareDecimation() override; @@ -269,6 +271,7 @@ public slots: int _actualWidth, _actualHeight, _actualFPS; QString _actualDeviceName; uint _targetMonitorNits; + int _reorderDisplays; int _lineLength; int _frameByteSize; diff --git a/include/led-strip/ChannelCalibration.h b/include/led-strip/ChannelCalibration.h index df08513b0..614f34303 100644 --- a/include/led-strip/ChannelCalibration.h +++ b/include/led-strip/ChannelCalibration.h @@ -44,7 +44,7 @@ class ChannelCalibration public: ChannelCalibration(quint8 instance, QString channelName, const QJsonObject& colorConfig, int defaultR, int defaultG, int defaultB); - void apply(uint8_t input, uint8_t brightness, uint8_t& red, uint8_t& green, uint8_t& blue); + void apply(uint64_t input, uint8_t brightness, uint64_t& red, uint64_t& green, uint64_t& blue) const; ColorRgb getAdjustment() const; void setAdjustment(const QJsonArray& value); diff --git a/sources/base/Grabber.cpp b/sources/base/Grabber.cpp index d25dfa0b8..0fdf7b828 100644 --- a/sources/base/Grabber.cpp +++ b/sources/base/Grabber.cpp @@ -74,6 +74,7 @@ Grabber::Grabber(const QString& configurationPath, const QString& grabberName) , _actualFPS(0) , _actualDeviceName("") , _targetMonitorNits(200) + , _reorderDisplays(0) , _lineLength(-1) , _frameByteSize(-1) , _signalDetectionEnabled(false) @@ -184,6 +185,28 @@ void Grabber::setMonitorNits(int nits) } } +void Grabber::setReorderDisplays(int order) +{ + if (_reorderDisplays != order) + { + _reorderDisplays = order; + + Debug(_log, "Set re-order display permutation to %i", _reorderDisplays); + + if (_initialized && !_blocked) + { + Debug(_log, "Restarting video grabber"); + uninit(); + start(); + } + else + { + Info(_log, "Delayed restart of the grabber due to change of monitor display-order value"); + _restartNeeded = true; + } + } +} + void Grabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom) { if (_width > 0 && _height > 0) diff --git a/sources/base/SystemWrapper.cpp b/sources/base/SystemWrapper.cpp index 00c60626f..a899e0486 100644 --- a/sources/base/SystemWrapper.cpp +++ b/sources/base/SystemWrapper.cpp @@ -169,6 +169,8 @@ void SystemWrapper::handleSettingsUpdate(settings::type type, const QJsonDocumen _grabber->setMonitorNits(obj["monitor_nits"].toInt(200)); + _grabber->setReorderDisplays(obj["reorder_displays"].toInt(0)); + _grabber->setSignalDetectionOffset( obj["sDHOffsetMin"].toDouble(0.25), obj["sDVOffsetMin"].toDouble(0.25), diff --git a/sources/base/schema/schema-systemGrabber.json b/sources/base/schema/schema-systemGrabber.json index 8fcbe7ed6..d0191415e 100644 --- a/sources/base/schema/schema-systemGrabber.json +++ b/sources/base/schema/schema-systemGrabber.json @@ -71,6 +71,22 @@ }, "propertyOrder" : 25 }, + "reorder_displays" : + { + "type" : "integer", + "format": "stepper", + "title" : "edt_conf_reorder_displays_title", + "default" : 0, + "minimum" : 0, + "maximum" : 255, + "required" : true, + "options": { + "dependencies": { + "hardware": true + } + }, + "propertyOrder" : 26 + }, "cropLeft" : { "type" : "integer", diff --git a/sources/grabber/windows/DX/DxGrabber.cpp b/sources/grabber/windows/DX/DxGrabber.cpp index 66d42faee..f08f55417 100644 --- a/sources/grabber/windows/DX/DxGrabber.cpp +++ b/sources/grabber/windows/DX/DxGrabber.cpp @@ -26,6 +26,7 @@ */ #define NOMINMAX +#include #include #include #include @@ -779,6 +780,11 @@ void DxGrabber::grabFrame() int targetSizeX = 0, targetSizeY = 0; int divide = getTargetSystemFrameDimension(display->actualWidth, display->actualHeight, targetSizeX, targetSizeY); + if (_reorderDisplays > 0 && result == 0) + { + images.push_back(std::pair>(width, Image(targetSizeX, 1))); + } + width += targetSizeX; height = std::max(targetSizeY, height); } @@ -800,11 +806,31 @@ void DxGrabber::grabFrame() memset(image.rawMem(), 0, image.size()); } - for (auto&& source : images) + if (_reorderDisplays > 0) { - image.insertHorizontal(source.first, source.second); + for (int permutation = 0; + permutation < _reorderDisplays && + std::next_permutation(images.begin(), images.end(), + [=](const std::pair>& a, const std::pair>& b) + { + return a.first < b.first; + }); + permutation++); + + int targetX = 0; + for (auto it = images.begin(); it != images.end(); ++it) + { + it->first = targetX; + targetX += it->second.width(); + } } + for (auto&& source : images) + if (_reorderDisplays == 0 || source.second.height() > 1) + { + image.insertHorizontal(source.first, source.second); + } + if (_signalDetectionEnabled) { if (checkSignalDetectionManual(image)) diff --git a/sources/led-strip/ChannelCalibration.cpp b/sources/led-strip/ChannelCalibration.cpp index f26136f53..c8bd9f8fe 100644 --- a/sources/led-strip/ChannelCalibration.cpp +++ b/sources/led-strip/ChannelCalibration.cpp @@ -118,9 +118,9 @@ bool ChannelCalibration::isEnabled() const return _enabled; } -void ChannelCalibration::apply(uint8_t input, uint8_t brightness, uint8_t& red, uint8_t& green, uint8_t& blue) -{ - red = std::min(((brightness * input * _targetCalibration.red) / 65025), (int)UINT8_MAX); - green = std::min(((brightness * input * _targetCalibration.green) / 65025), (int)UINT8_MAX); - blue = std::min(((brightness * input * _targetCalibration.blue) / 65025), (int)UINT8_MAX); +void ChannelCalibration::apply(uint64_t input, uint8_t brightness, uint64_t& red, uint64_t& green, uint64_t& blue) const +{ + red = (brightness * input * _targetCalibration.red + (65025 / 2)) / 65025; + green = (brightness * input * _targetCalibration.green + (65025 / 2)) / 65025; + blue = (brightness * input * _targetCalibration.blue + (65025 / 2)) / 65025; } diff --git a/sources/led-strip/ColorCalibration.cpp b/sources/led-strip/ColorCalibration.cpp index 700b69a6a..c9732bbec 100644 --- a/sources/led-strip/ColorCalibration.cpp +++ b/sources/led-strip/ColorCalibration.cpp @@ -109,9 +109,9 @@ void ColorCalibration::calibrate(ColorRgb& color) { if (B_RGB != 255) { - color.red = ((uint32_t)color.red * B_RGB) / 255; - color.green = ((uint32_t)color.green * B_RGB) / 255; - color.blue = ((uint32_t)color.blue * B_RGB) / 255; + color.red = ((uint32_t)color.red * B_RGB + (255 / 2)) / 255; + color.green = ((uint32_t)color.green * B_RGB + (255 / 2)) / 255; + color.blue = ((uint32_t)color.blue * B_RGB + (255 / 2)) / 255; } } else @@ -121,17 +121,17 @@ void ColorCalibration::calibrate(ColorRgb& color) uint32_t nrg = (uint32_t)(255 - ored) * (ogreen); uint32_t rg = (uint32_t)(ored) * (ogreen); - uint8_t black = nrng * (255 - oblue) / 65025; - uint8_t red = rng * (255 - oblue) / 65025; - uint8_t green = nrg * (255 - oblue) / 65025; - uint8_t blue = nrng * (oblue) / 65025; - uint8_t cyan = nrg * (oblue) / 65025; - uint8_t magenta = rng * (oblue) / 65025; - uint8_t yellow = rg * (255 - oblue) / 65025; - uint8_t white = rg * (oblue) / 65025; + uint32_t black = nrng * (255 - oblue); + uint32_t red = rng * (255 - oblue); + uint32_t green = nrg * (255 - oblue); + uint32_t blue = nrng * (oblue); + uint32_t cyan = nrg * (oblue); + uint32_t magenta = rng * (oblue); + uint32_t yellow = rg * (255 - oblue); + uint32_t white = rg * (oblue); - uint8_t OR, OG, OB, RR, RG, RB, GR, GG, GB, BR, BG, BB; - uint8_t CR, CG, CB, MR, MG, MB, YR, YG, YB, WR, WG, WB; + uint64_t OR, OG, OB, RR, RG, RB, GR, GG, GB, BR, BG, BB; + uint64_t CR, CG, CB, MR, MG, MB, YR, YG, YB, WR, WG, WB; _blackCalibration->apply(black, 255, OR, OG, OB); _redCalibration->apply(red, B_RGB, RR, RG, RB); @@ -142,9 +142,9 @@ void ColorCalibration::calibrate(ColorRgb& color) _yellowCalibration->apply(yellow, B_CMY, YR, YG, YB); _whiteCalibration->apply(white, B_W, WR, WG, WB); - color.red = OR + RR + GR + BR + CR + MR + YR + WR; - color.green = OG + RG + GG + BG + CG + MG + YG + WG; - color.blue = OB + RB + GB + BB + CB + MB + YB + WB; + color.red = std::min((OR + RR + GR + BR + CR + MR + YR + WR + (65025 / 2)) / 65025, (uint64_t) 255); + color.green = std::min((OG + RG + GG + BG + CG + MG + YG + WG + (65025 / 2)) / 65025, (uint64_t) 255); + color.blue = std::min((OB + RB + GB + BB + CB + MB + YB + WB + (65025 / 2)) / 65025, (uint64_t) 255); } } _colorspaceCalibration->applyBacklight(ored, ogreen, oblue); diff --git a/www/i18n/en.json b/www/i18n/en.json index 89e2d18d6..c64b203b8 100644 --- a/www/i18n/en.json +++ b/www/i18n/en.json @@ -1267,5 +1267,7 @@ "wiz_home_assistant_title": "Home Assistant lights wizard", "wiz_ha_intro": "Please select the address of the Home Assistant instance and enter the 'Long Lived Access Tokens' created there.", "select_ha_intro": "Select Home Assistant", - "edt_dev_spec_constantBrightness_title": "Constant brightness" + "edt_dev_spec_constantBrightness_title": "Constant brightness", + "edt_conf_reorder_displays_title": "Reorder displays", + "edt_conf_reorder_displays_expl": "Manipulate the order (permutations) of the displays until you get the correct one in multi-display mode" }