diff --git a/engine/src/efxfixture.cpp b/engine/src/efxfixture.cpp index 4568c2f600..53107ca1ea 100644 --- a/engine/src/efxfixture.cpp +++ b/engine/src/efxfixture.cpp @@ -99,7 +99,8 @@ void EFXFixture::setHead(GroupHead const & head) (fxi->tiltMsbChannel(head.head) != QLCChannel::invalid())) modes << PanTilt; - if((fxi->masterIntensityChannel(head.head) != QLCChannel::invalid())) + if((fxi->masterIntensityChannel() != QLCChannel::invalid()) || + (fxi->intensityChannel(head.head) != QLCChannel::invalid())) modes << Dimmer; if((fxi->rgbChannels (head.head).size () >= 3)) @@ -159,7 +160,7 @@ bool EFXFixture::isValid() const else if (m_mode == PanTilt && fxi->panMsbChannel(head().head) == QLCChannel::invalid() && // Maybe a device can pan OR tilt fxi->tiltMsbChannel(head().head) == QLCChannel::invalid()) // but not both. Teh sux0r. return false; - else if (m_mode == Dimmer && fxi->masterIntensityChannel(head().head) == QLCChannel::invalid() ) + else if (m_mode == Dimmer && fxi->masterIntensityChannel() == QLCChannel::invalid() && fxi->intensityChannel(head().head) == QLCChannel::invalid() ) return false; else if (m_mode == RGB && fxi->rgbChannels(head().head).size () == 0) return false; @@ -197,7 +198,7 @@ QStringList EFXFixture::modeList() (fxi->tiltMsbChannel(head().head) != QLCChannel::invalid()) ) modes << KXMLQLCEFXFixtureModePanTilt; - if((fxi->masterIntensityChannel(head().head) != QLCChannel::invalid())) + if(fxi->masterIntensityChannel() != QLCChannel::invalid() || fxi->intensityChannel(head().head) != QLCChannel::invalid()) modes << KXMLQLCEFXFixtureModeDimmer; if((fxi->rgbChannels (head().head).size () >= 3)) @@ -493,9 +494,13 @@ void EFXFixture::setPointDimmer(QList universes, float dimmer) Q_ASSERT(fxi != NULL); /* Don't write dimmer data directly to universes but use FadeChannel to avoid steps at EFX loop restart */ - if (fxi->masterIntensityChannel(head().head) != QLCChannel::invalid()) + if (fxi->intensityChannel(head().head) != QLCChannel::invalid()) { - setFadeChannel(fxi->masterIntensityChannel(head().head), dimmer); + setFadeChannel(fxi->intensityChannel(head().head), dimmer); + } + else if (fxi->masterIntensityChannel() != QLCChannel::invalid()) + { + setFadeChannel(fxi->masterIntensityChannel(), dimmer); } } diff --git a/engine/src/fixture.cpp b/engine/src/fixture.cpp index b00c912be5..0bfe9b4b4c 100644 --- a/engine/src/fixture.cpp +++ b/engine/src/fixture.cpp @@ -340,27 +340,32 @@ quint32 Fixture::tiltLsbChannel(int head) const } } -quint32 Fixture::masterIntensityChannel(int head) const +quint32 Fixture::masterIntensityChannel() const +{ + if (m_fixtureMode == NULL) + { + return QLCChannel::invalid(); + } + + return m_fixtureMode->masterIntensityChannel(); +} + +quint32 Fixture::intensityChannel(int head) const { if (head == -1) return QLCChannel::invalid(); - if (m_fixtureMode != NULL) + if (m_fixtureMode == NULL) { - quint32 dimmerCh = QLCChannel::invalid(); - if (head < m_fixtureMode->heads().size()) - dimmerCh = m_fixtureMode->heads().at(head).masterIntensityChannel(); - - if (dimmerCh == QLCChannel::invalid()) - { - dimmerCh = channel(QLCChannel::Intensity, QLCChannel::NoColour); - } - return dimmerCh; + return QLCChannel::invalid(); } - else + + if (head >= m_fixtureMode->heads().size()) { return QLCChannel::invalid(); } + + return m_fixtureMode->heads().at(head).intensityChannel(); } QVector Fixture::rgbChannels(int head) const diff --git a/engine/src/fixture.h b/engine/src/fixture.h index 1de8432d02..148b3d91c5 100644 --- a/engine/src/fixture.h +++ b/engine/src/fixture.h @@ -266,8 +266,11 @@ class Fixture : public QObject /** @see QLCFixtureHead */ quint32 tiltLsbChannel(int head = 0) const; + /** @see QLCFixtureMode */ + quint32 masterIntensityChannel() const; + /** @see QLCFixtureHead */ - quint32 masterIntensityChannel(int head = 0) const; + quint32 intensityChannel(int head = 0) const; /** @see QLCFixtureHead */ QVector rgbChannels(int head = 0) const; diff --git a/engine/src/qlcfixturehead.cpp b/engine/src/qlcfixturehead.cpp index 64f7c8f987..5cce4b8a3b 100644 --- a/engine/src/qlcfixturehead.cpp +++ b/engine/src/qlcfixturehead.cpp @@ -31,7 +31,7 @@ QLCFixtureHead::QLCFixtureHead() , m_tiltMsbChannel(QLCChannel::invalid()) , m_panLsbChannel(QLCChannel::invalid()) , m_tiltLsbChannel(QLCChannel::invalid()) - , m_masterIntensityChannel(QLCChannel::invalid()) + , m_intensityChannel(QLCChannel::invalid()) { } @@ -42,7 +42,7 @@ QLCFixtureHead::QLCFixtureHead(const QLCFixtureHead& head) , m_tiltMsbChannel(head.m_tiltMsbChannel) , m_panLsbChannel(head.m_panLsbChannel) , m_tiltLsbChannel(head.m_tiltLsbChannel) - , m_masterIntensityChannel(head.m_masterIntensityChannel) + , m_intensityChannel(head.m_intensityChannel) , m_rgbChannels(head.m_rgbChannels) , m_cmyChannels(head.m_cmyChannels) , m_colorWheels(head.m_colorWheels) @@ -98,9 +98,9 @@ quint32 QLCFixtureHead::tiltLsbChannel() const return m_tiltLsbChannel; } -quint32 QLCFixtureHead::masterIntensityChannel() const +quint32 QLCFixtureHead::intensityChannel() const { - return m_masterIntensityChannel; + return m_intensityChannel; } QVector QLCFixtureHead::rgbChannels() const @@ -137,8 +137,9 @@ void QLCFixtureHead::cacheChannels(const QLCFixtureMode* mode) m_tiltMsbChannel = QLCChannel::invalid(); m_panLsbChannel = QLCChannel::invalid(); m_tiltLsbChannel = QLCChannel::invalid(); - m_masterIntensityChannel = QLCChannel::invalid(); + m_intensityChannel = QLCChannel::invalid(); m_colorWheels.clear(); + m_shutterChannels.clear(); QSetIterator it(m_channels); while (it.hasNext() == true) @@ -157,7 +158,7 @@ void QLCFixtureHead::cacheChannels(const QLCFixtureMode* mode) if (ch->group() == QLCChannel::Pan) { if (ch->controlByte() == QLCChannel::MSB && - m_panMsbChannel > i) + m_panMsbChannel > i) // m_channels is QSet, it's not iterated in numeric order; prefer lower numbers { m_panMsbChannel = i; } @@ -180,12 +181,12 @@ void QLCFixtureHead::cacheChannels(const QLCFixtureMode* mode) m_tiltLsbChannel = i; } } - else if (ch->group() == QLCChannel::Intensity) + else if (ch->group() == QLCChannel::Intensity && ch->controlByte() == QLCChannel::MSB) { if (ch->colour() == QLCChannel::NoColour && - m_masterIntensityChannel > i) + m_intensityChannel > i) { - m_masterIntensityChannel = i; + m_intensityChannel = i; } else if (ch->colour() == QLCChannel::Red && r > i) { @@ -212,15 +213,13 @@ void QLCFixtureHead::cacheChannels(const QLCFixtureMode* mode) y = i; } } - else if (ch->group() == QLCChannel::Colour) + else if (ch->group() == QLCChannel::Colour && ch->controlByte() == QLCChannel::MSB) { - if (ch->controlByte() == QLCChannel::MSB) - m_colorWheels << i; + m_colorWheels << i; } - else if (ch->group() == QLCChannel::Shutter) + else if (ch->group() == QLCChannel::Shutter && ch->controlByte() == QLCChannel::MSB) { - if (ch->controlByte() == QLCChannel::MSB) - m_shutterChannels << i; + m_shutterChannels << i; } } @@ -297,7 +296,7 @@ bool QLCFixtureHead::saveXML(QXmlStreamWriter *doc) const QLCDimmerHead::QLCDimmerHead(int head) : QLCFixtureHead() { - m_masterIntensityChannel = head; + m_intensityChannel = head; m_channelsCached = true; } diff --git a/engine/src/qlcfixturehead.h b/engine/src/qlcfixturehead.h index 084d3553c4..92c11f34b0 100644 --- a/engine/src/qlcfixturehead.h +++ b/engine/src/qlcfixturehead.h @@ -97,10 +97,10 @@ class QLCFixtureHead quint32 tiltLsbChannel() const; /** - * Get the master intensity channel. For dimmers this is invalid. - * @return The master intensity channel or QLCChannel::invalid() if not applicable. + * Get the intensity (dimmer) channel. For dimmers this return the sole channel of the head. + * @return The intensity channel or QLCChannel::invalid() if not applicable. */ - quint32 masterIntensityChannel() const; + quint32 intensityChannel() const; /** * Get a list of RGB channels. If the fixture doesn't support RGB mixing, @@ -147,8 +147,8 @@ class QLCFixtureHead /** The fine tilt channel */ quint32 m_tiltLsbChannel; - /** The master intensity channel */ - quint32 m_masterIntensityChannel; + /** The intensity (dimmer) channel */ + quint32 m_intensityChannel; /** The RGB mix intensity channels */ QVector m_rgbChannels; diff --git a/engine/src/qlcfixturemode.cpp b/engine/src/qlcfixturemode.cpp index ac7e0e6499..d460a469e8 100644 --- a/engine/src/qlcfixturemode.cpp +++ b/engine/src/qlcfixturemode.cpp @@ -32,12 +32,14 @@ QLCFixtureMode::QLCFixtureMode(QLCFixtureDef* fixtureDef) : m_fixtureDef(fixtureDef) + , m_masterIntensityChannel(QLCChannel::invalid()) { Q_ASSERT(fixtureDef != NULL); } QLCFixtureMode::QLCFixtureMode(QLCFixtureDef* fixtureDef, const QLCFixtureMode* mode) : m_fixtureDef(fixtureDef) + , m_masterIntensityChannel(QLCChannel::invalid()) { Q_ASSERT(fixtureDef != NULL); Q_ASSERT(mode != NULL); @@ -57,6 +59,7 @@ QLCFixtureMode& QLCFixtureMode::operator=(const QLCFixtureMode& mode) m_name = mode.m_name; m_physical = mode.m_physical; m_heads = mode.m_heads; + m_masterIntensityChannel = QLCChannel::invalid(); /* Clear the existing list of channels */ m_channels.clear(); @@ -224,6 +227,11 @@ quint32 QLCFixtureMode::channelNumber(QLCChannel::Group group, QLCChannel::Contr return QLCChannel::invalid(); } +quint32 QLCFixtureMode::masterIntensityChannel() const +{ + return m_masterIntensityChannel; +} + /***************************************************************************** * Heads *****************************************************************************/ @@ -271,6 +279,18 @@ void QLCFixtureMode::cacheHeads() QLCFixtureHead& head(m_heads[i]); head.cacheChannels(this); } + + for (int i = 0; i < m_channels.size(); i++) + { + if (m_channels.at(i)->group() == QLCChannel::Intensity && + m_channels.at(i)->controlByte() == QLCChannel::MSB && + m_channels.at(i)->colour() == QLCChannel::NoColour && + headForChannel(i) == -1) + { + m_masterIntensityChannel = i; + break; + } + } } /**************************************************************************** diff --git a/engine/src/qlcfixturemode.h b/engine/src/qlcfixturemode.h index d5eee8bd25..9e283c5d3e 100644 --- a/engine/src/qlcfixturemode.h +++ b/engine/src/qlcfixturemode.h @@ -196,10 +196,14 @@ class QLCFixtureMode */ quint32 channelNumber(QLCChannel::Group group, QLCChannel::ControlByte cByte = QLCChannel::MSB) const; + quint32 masterIntensityChannel() const; + protected: /** List of channels (pointers are not owned) */ QVector m_channels; + quint32 m_masterIntensityChannel; + /********************************************************************* * Heads *********************************************************************/ diff --git a/engine/src/rgbmatrix.cpp b/engine/src/rgbmatrix.cpp index 6a1ba84d10..623b28a5fa 100644 --- a/engine/src/rgbmatrix.cpp +++ b/engine/src/rgbmatrix.cpp @@ -631,9 +631,6 @@ void RGBMatrix::roundCheck() void RGBMatrix::updateMapChannels(const RGBMap& map, const FixtureGroup* grp) { - quint32 mdAssigned = QLCChannel::invalid(); - quint32 mdFxi = Fixture::invalidId(); - uint fadeTime = (overrideFadeInSpeed() == defaultSpeed()) ? fadeInSpeed() : overrideFadeInSpeed(); // Create/modify fade channels for ALL pixels in the color map. @@ -647,16 +644,36 @@ void RGBMatrix::updateMapChannels(const RGBMap& map, const FixtureGroup* grp) if (fxi == NULL) continue; - if (grpHead.fxi != mdFxi) - { - mdAssigned = QLCChannel::invalid(); - mdFxi = grpHead.fxi; - } - QLCFixtureHead head = fxi->head(grpHead.head); QVector rgb = head.rgbChannels(); QVector cmy = head.cmyChannels(); + + quint32 masterDim = fxi->masterIntensityChannel(); + quint32 headDim = head.intensityChannel(); + + // Collect all dimmers that affect current head: + // They are the master dimmer (affects whole fixture) + // and per-head dimmer. + // + // If there are no RGB or CMY channels, the least important* dimmer channel + // is used to create grayscale image. + // + // The rest of the dimmer channels are set to full if dimmer control is + // enabled. + // + // Note: If there is only one head, and only one dimmer channel, + // make it a master dimmer in fixture definition. + // + // *least important - per head dimmer if present, + // otherwise per fixture dimmer if present + QVector dim; + if (masterDim != QLCChannel::invalid()) + dim << masterDim; + + if (headDim != QLCChannel::invalid()) + dim << headDim; + if (rgb.size() == 3) { // RGB color mixing @@ -707,24 +724,30 @@ void RGBMatrix::updateMapChannels(const RGBMap& map, const FixtureGroup* grp) m_fader->add(fc); } } - - if (m_dimmerControl && - head.masterIntensityChannel() != QLCChannel::invalid()) + else if (!dim.empty()) { - //qDebug() << "RGBMatrix: found dimmer at" << head.masterIntensityChannel(); - // Simple intensity (dimmer) channel + // Set dimmer to value of the color (e.g. for PARs) QColor col(map[y][x]); - FadeChannel fc(doc(), grpHead.fxi, head.masterIntensityChannel()); - if (col.value() == 0 && mdAssigned != head.masterIntensityChannel()) - fc.setTarget(0); - else + + FadeChannel fc(doc(), grpHead.fxi, dim.last()); + // the weights are taken from + // https://en.wikipedia.org/wiki/YUV#SDTV_with_BT.601 + fc.setTarget((0.299 * col.redF() + 0.587 * col.greenF() + 0.114 * col.blueF()) * 255); + insertStartValues(fc, fadeTime); + m_fader->add(fc); + dim.pop_back(); + } + + if (m_dimmerControl) + { + // Set the rest of the dimmer channels to full on + foreach(quint32 ch, dim) { + FadeChannel fc(doc(), grpHead.fxi, ch); fc.setTarget(255); - if (mdAssigned == QLCChannel::invalid()) - mdAssigned = head.masterIntensityChannel(); + insertStartValues(fc, fadeTime); + m_fader->add(fc); } - insertStartValues(fc, fadeTime); - m_fader->add(fc); } } } diff --git a/engine/test/qlcfixturehead/qlcfixturehead_test.cpp b/engine/test/qlcfixturehead/qlcfixturehead_test.cpp index 468460a0a9..1886b36262 100644 --- a/engine/test/qlcfixturehead/qlcfixturehead_test.cpp +++ b/engine/test/qlcfixturehead/qlcfixturehead_test.cpp @@ -189,7 +189,7 @@ void QLCFixtureHead_Test::cacheChannelsRgbMaster() QCOMPARE(head.tiltLsbChannel(), QLCChannel::invalid()); QCOMPARE(head.rgbChannels(), QVector () << 0 << 1 << 2); QCOMPARE(head.cmyChannels(), QVector ()); - QCOMPARE(head.masterIntensityChannel(), quint32(3)); + QCOMPARE(head.intensityChannel(), quint32(3)); } void QLCFixtureHead_Test::cacheChannelsCmyMaster() @@ -226,7 +226,7 @@ void QLCFixtureHead_Test::cacheChannelsCmyMaster() QCOMPARE(head.tiltLsbChannel(), QLCChannel::invalid()); QCOMPARE(head.rgbChannels(), QVector ()); QCOMPARE(head.cmyChannels(), QVector () << 0 << 1 << 3); - QCOMPARE(head.masterIntensityChannel(), quint32(2)); + QCOMPARE(head.intensityChannel(), quint32(2)); } void QLCFixtureHead_Test::cacheChannelsPanTilt() @@ -263,7 +263,7 @@ void QLCFixtureHead_Test::cacheChannelsPanTilt() QCOMPARE(head.tiltLsbChannel(), quint32(3)); QCOMPARE(head.rgbChannels(), QVector ()); QCOMPARE(head.cmyChannels(), QVector ()); - QCOMPARE(head.masterIntensityChannel(), QLCChannel::invalid()); + QCOMPARE(head.intensityChannel(), QLCChannel::invalid()); head.cacheChannels((QLCFixtureMode*) 0xDEADBEEF); QCOMPARE(head.panMsbChannel(), quint32(0)); @@ -272,7 +272,7 @@ void QLCFixtureHead_Test::cacheChannelsPanTilt() QCOMPARE(head.tiltLsbChannel(), quint32(3)); QCOMPARE(head.rgbChannels(), QVector ()); QCOMPARE(head.cmyChannels(), QVector ()); - QCOMPARE(head.masterIntensityChannel(), QLCChannel::invalid()); + QCOMPARE(head.intensityChannel(), QLCChannel::invalid()); } void QLCFixtureHead_Test::doublePanTilt() @@ -348,7 +348,7 @@ void QLCFixtureHead_Test::cacheChannelsColor() void QLCFixtureHead_Test::dimmerHead() { QLCDimmerHead dh(5); - QCOMPARE(dh.masterIntensityChannel(), quint32(5)); + QCOMPARE(dh.intensityChannel(), quint32(5)); QCOMPARE(dh.m_channelsCached, true); } diff --git a/engine/test/qlcfixturemode/qlcfixturemode_test.cpp b/engine/test/qlcfixturemode/qlcfixturemode_test.cpp index 0fa2fe80a7..0aa86238b2 100644 --- a/engine/test/qlcfixturemode/qlcfixturemode_test.cpp +++ b/engine/test/qlcfixturemode/qlcfixturemode_test.cpp @@ -409,6 +409,48 @@ void QLCFixtureMode_Test::copy() delete anotherDef; } +void QLCFixtureMode_Test::intensityChannels() +{ + QLCFixtureDef def; + + QLCChannel * masterCh = new QLCChannel(); + masterCh->setGroup(QLCChannel::Intensity); + masterCh->setControlByte(QLCChannel::MSB); + masterCh->setColour(QLCChannel::NoColour); + def.addChannel(masterCh); + + QLCChannel * h1Ch = new QLCChannel(); + h1Ch->setGroup(QLCChannel::Intensity); + h1Ch->setControlByte(QLCChannel::MSB); + h1Ch->setColour(QLCChannel::NoColour); + def.addChannel(h1Ch); + + QLCChannel * h2Ch = new QLCChannel(); + h2Ch->setGroup(QLCChannel::Intensity); + h2Ch->setControlByte(QLCChannel::MSB); + h2Ch->setColour(QLCChannel::NoColour); + def.addChannel(h2Ch); + + QLCFixtureMode mode(&def); + mode.insertChannel(masterCh, 0); + mode.insertChannel(h1Ch, 1); + mode.insertChannel(h2Ch, 2); + + QLCFixtureHead h1; + h1.addChannel(1); + mode.insertHead(0, h1); + + QLCFixtureHead h2; + h2.addChannel(2); + mode.insertHead(1, h2); + + mode.cacheHeads(); + + QCOMPARE(mode.masterIntensityChannel(), 0U); + QCOMPARE(mode.heads()[0].intensityChannel(), 1U); + QCOMPARE(mode.heads()[1].intensityChannel(), 2U); +} + void QLCFixtureMode_Test::load() { QBuffer buffer; diff --git a/engine/test/qlcfixturemode/qlcfixturemode_test.h b/engine/test/qlcfixturemode/qlcfixturemode_test.h index f25c1ef0e1..7e24dde5cb 100644 --- a/engine/test/qlcfixturemode/qlcfixturemode_test.h +++ b/engine/test/qlcfixturemode/qlcfixturemode_test.h @@ -43,6 +43,7 @@ private slots: void channelNumber(); void heads(); void copy(); + void intensityChannels(); void load(); void loadWrongRoot(); diff --git a/qmlui/mainview2d.cpp b/qmlui/mainview2d.cpp index 7f16f0d884..a7d0dcf014 100644 --- a/qmlui/mainview2d.cpp +++ b/qmlui/mainview2d.cpp @@ -289,7 +289,7 @@ void MainView2D::updateFixture(Fixture *fixture) for (int headIdx = 0; headIdx < fixture->heads(); headIdx++) { - quint32 mdIndex = fixture->masterIntensityChannel(headIdx); + quint32 mdIndex = fixture->intensityChannel(headIdx); //qDebug() << "Head" << headIdx << "dimmer channel:" << mdIndex; qreal intValue = 1.0; if (mdIndex != QLCChannel::invalid()) diff --git a/ui/src/monitor/monitorfixtureitem.cpp b/ui/src/monitor/monitorfixtureitem.cpp index 68fd02e423..e6b0ad1dcf 100644 --- a/ui/src/monitor/monitorfixtureitem.cpp +++ b/ui/src/monitor/monitorfixtureitem.cpp @@ -77,17 +77,26 @@ MonitorFixtureItem::MonitorFixtureItem(Doc *doc, quint32 fid) //qDebug() << "Add CMY comp at address:" << cmyComp; } - if (head.masterIntensityChannel() != QLCChannel::invalid()) + fxiItem->m_dimmer = head.intensityChannel(); + if (fxiItem->m_dimmer != QLCChannel::invalid()) + { + qDebug() << "Set dimmer to:" << fxiItem->m_dimmer; + } + + fxiItem->m_masterDimmer = fxi->masterIntensityChannel(); + if (fxiItem->m_masterDimmer != QLCChannel::invalid()) { - fxiItem->m_masterDimmer = head.masterIntensityChannel(); qDebug() << "Set master dimmer to:" << fxiItem->m_masterDimmer; + } + + if ((fxiItem->m_dimmer != QLCChannel::invalid()) || (fxiItem->m_masterDimmer != QLCChannel::invalid())) + { fxiItem->m_back = new QGraphicsEllipseItem(this); fxiItem->m_back->setPen(QPen(Qt::white, 1)); fxiItem->m_back->setBrush(QBrush(Qt::black)); } else { - fxiItem->m_masterDimmer = QLCChannel::invalid(); fxiItem->m_back = NULL; } @@ -324,7 +333,7 @@ void MonitorFixtureItem::setSize(QSize size) update(); } -QColor MonitorFixtureItem::computeColor(FixtureHead *head, const QByteArray & values) +QColor MonitorFixtureItem::computeColor(const FixtureHead *head, const QByteArray & values) { foreach (quint32 c, head->m_colorWheels) { @@ -359,16 +368,29 @@ QColor MonitorFixtureItem::computeColor(FixtureHead *head, const QByteArray & va return QColor(255,255,255); } -uchar MonitorFixtureItem::computeAlpha(FixtureHead *head, const QByteArray & values) +uchar MonitorFixtureItem::computeAlpha(const FixtureHead *head, const QByteArray & values) { - uchar alpha = 255; + // postpone division as late as possible to improve accuracy + unsigned mul = 255U; + unsigned div = 1U; + if (head->m_masterDimmer != UINT_MAX /*QLCChannel::invalid()*/) - alpha = values.at(head->m_masterDimmer); + { + mul *= static_cast(values.at(head->m_masterDimmer)); + div *= 255U; + } + + if (head->m_dimmer != UINT_MAX /*QLCChannel::invalid()*/) + { + mul *= static_cast(values.at(head->m_dimmer)); + div *= 255U; + } - return alpha; + qDebug() << mul << "/" << div << "=" << (mul /div); + return mul / div; } -FixtureHead::ShutterState MonitorFixtureItem::computeShutter(FixtureHead *head, const QByteArray & values) +FixtureHead::ShutterState MonitorFixtureItem::computeShutter(const FixtureHead *head, const QByteArray & values) { FixtureHead::ShutterState result = FixtureHead::Open; diff --git a/ui/src/monitor/monitorfixtureitem.h b/ui/src/monitor/monitorfixtureitem.h index 632781cdf7..6641104afd 100644 --- a/ui/src/monitor/monitorfixtureitem.h +++ b/ui/src/monitor/monitorfixtureitem.h @@ -69,6 +69,7 @@ struct FixtureHead int m_strobePhase; QTimer* m_strobeTimer; + quint32 m_dimmer; quint32 m_masterDimmer; quint32 m_panChannel; int m_panMaxDegrees; @@ -131,9 +132,10 @@ protected slots: private: void computeTiltPosition(FixtureHead *h, uchar value); void computePanPosition(FixtureHead *h, uchar value); - QColor computeColor(FixtureHead *head, const QByteArray & values); - uchar computeAlpha(FixtureHead *head, const QByteArray & values); - FixtureHead::ShutterState computeShutter(FixtureHead *head, const QByteArray & values); + + QColor computeColor(const FixtureHead *head, const QByteArray & values); + uchar computeAlpha(const FixtureHead *head, const QByteArray & values); + FixtureHead::ShutterState computeShutter(const FixtureHead *head, const QByteArray & values); signals: void itemDropped(MonitorFixtureItem *); diff --git a/ui/src/rgbmatrixeditor.cpp b/ui/src/rgbmatrixeditor.cpp index 0daac50f96..bc41a29652 100644 --- a/ui/src/rgbmatrixeditor.cpp +++ b/ui/src/rgbmatrixeditor.cpp @@ -995,7 +995,7 @@ void RGBMatrixEditor::slotSaveToSequenceClicked() grpScene->setValue(head.fxi, rgbCh.at(2), 0); } - quint32 master = fxi->masterIntensityChannel(head.head); + quint32 master = fxi->intensityChannel(head.head); if (master != QLCChannel::invalid()) grpScene->setValue(head.fxi, master, 0); } @@ -1063,7 +1063,7 @@ void RGBMatrixEditor::slotSaveToSequenceClicked() step.values.append(SceneValue(head.fxi, rgbCh.at(2), rgb.blue())); } - quint32 master = fxi->masterIntensityChannel(head.head); + quint32 master = fxi->intensityChannel(head.head); if (master != QLCChannel::invalid()) step.values.append(SceneValue(head.fxi, master, 255)); } diff --git a/ui/test/monitorfixtureitem/monitorfixtureitem.pro b/ui/test/monitorfixtureitem/monitorfixtureitem.pro new file mode 100644 index 0000000000..695aa24ac0 --- /dev/null +++ b/ui/test/monitorfixtureitem/monitorfixtureitem.pro @@ -0,0 +1,21 @@ +include(../../../variables.pri) + +TEMPLATE = app +LANGUAGE = C++ +TARGET = monitorfixtureitem_test + +QT += testlib gui script +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +INCLUDEPATH += ../../../plugins/interfaces +INCLUDEPATH += ../../../engine/src +INCLUDEPATH += ../../src ../../src/monitor +DEPENDPATH += ../../src + +QMAKE_LIBDIR += ../../../engine/src +QMAKE_LIBDIR += ../../src +LIBS += -lqlcplusengine -lqlcplusui + +# Test sources +SOURCES += monitorfixtureitem_test.cpp +HEADERS += monitorfixtureitem_test.h diff --git a/ui/test/monitorfixtureitem/monitorfixtureitem_test.cpp b/ui/test/monitorfixtureitem/monitorfixtureitem_test.cpp new file mode 100644 index 0000000000..5b131f2fc2 --- /dev/null +++ b/ui/test/monitorfixtureitem/monitorfixtureitem_test.cpp @@ -0,0 +1,295 @@ +/* + Q Light Controller Plus + monitorfixtureitem_test.cpp + + Copyright (C) Heikki Junnila + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include + +#define protected public +#define private public +#include "monitorfixtureitem.h" +#undef protected +#undef private + +#include "monitorfixtureitem_test.h" +#include "qlcfixturedefcache.h" +#include "qlcfixturedef.h" +#include "qlcfile.h" +#include "qlcmacros.h" +#include "doc.h" + +#include "../../../engine/test/common/resource_paths.h" + +void MonitorFixtureItem_Test::initTestCase() +{ + m_doc = new Doc(this); + + QDir dir(INTERNAL_FIXTUREDIR); + dir.setFilter(QDir::Files); + dir.setNameFilters(QStringList() << QString("*%1").arg(KExtFixture)); + QVERIFY(m_doc->fixtureDefCache()->loadMap(dir) == true); +} + +void MonitorFixtureItem_Test::cleanupTestCase() +{ + delete m_doc; + m_doc = NULL; +} + +void MonitorFixtureItem_Test::cleanup() +{ + m_doc->clearContents(); +} + +void MonitorFixtureItem_Test::computeAlpha() +{ + QFETCH(QString, manufacturer); + QFETCH(QString, model); + QFETCH(QString, mode); + QFETCH(quint32, masterDimmer); + QFETCH(quint32, head1Dimmer); + QFETCH(quint32, head2Dimmer); + + Fixture* fxi = new Fixture(m_doc); + fxi->setName("Test Fixture"); + + QLCFixtureDef* def = m_doc->fixtureDefCache()->fixtureDef(manufacturer, model); + QVERIFY(def != NULL); + QVERIFY(def != NULL); + QVERIFY(def->channels().size() > 0); + QLCFixtureMode* m = def->mode(mode); + QVERIFY(m != NULL); + + fxi->setFixtureDefinition(def, m); + fxi->setUniverse(0); + fxi->setAddress(0); + m_doc->addFixture(fxi); + + MonitorFixtureItem* mfi = new MonitorFixtureItem(m_doc, fxi->id()); + const FixtureHead* h1 = mfi->m_heads.at(0); + const FixtureHead* h2 = mfi->m_heads.at(1); + + QVERIFY(h1 != NULL); + QVERIFY(h2 != NULL); + + if (masterDimmer != QLCChannel::invalid()) + { + QCOMPARE(h1->m_masterDimmer, masterDimmer); + QCOMPARE(h2->m_masterDimmer, masterDimmer); + } + else + { + QCOMPARE(h1->m_masterDimmer, QLCChannel::invalid()); + QCOMPARE(h2->m_masterDimmer, QLCChannel::invalid()); + } + + if (head1Dimmer != QLCChannel::invalid()) + { + QCOMPARE(h1->m_dimmer, head1Dimmer); + } + else + { + QCOMPARE(h1->m_dimmer, QLCChannel::invalid()); + } + + if (head2Dimmer != QLCChannel::invalid()) + { + QCOMPARE(h2->m_dimmer, head2Dimmer); + } + else + { + QCOMPARE(h2->m_dimmer, QLCChannel::invalid()); + } + + if (masterDimmer == QLCChannel::invalid() && head1Dimmer == QLCChannel::invalid()) + { + { + QByteArray values(fxi->channels(), 255); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)255u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)255u); + } + + { + QByteArray values(fxi->channels(), 127); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)255u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)255u); + } + + { + QByteArray values(fxi->channels(), 0); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)255u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)255u); + } + } + else if (masterDimmer != QLCChannel::invalid() && head1Dimmer == QLCChannel::invalid()) + { + { + QByteArray values(fxi->channels(), 255); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)255u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)255u); + } + + { + QByteArray values(fxi->channels(), 127); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)127u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)127u); + } + + { + QByteArray values(fxi->channels(), 0); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)0u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)0u); + } + } + else if (masterDimmer == QLCChannel::invalid() && head1Dimmer != QLCChannel::invalid()) + { + { + QByteArray values(fxi->channels(), 255); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)255u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)255u); + } + + { + QByteArray values(fxi->channels(), 127); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)127u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)127u); + } + + { + QByteArray values(fxi->channels(), 0); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)0u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)0u); + } + } + else // masterDimmer != QLCChannel::invalid() && head1Dimmer != QLCChannel::invalid() + { + // change both master & head dimmer + + { + QByteArray values(fxi->channels(), 255); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)255u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)255u); + } + + { + QByteArray values(fxi->channels(), 127); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)63u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)63u); + } + + { + QByteArray values(fxi->channels(), 0); + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)0u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)0u); + } + + // change only master dimmer + + { + QByteArray values(fxi->channels(), 255); + values[masterDimmer] = 127; + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)127u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)127u); + } + + { + QByteArray values(fxi->channels(), 255); + values[masterDimmer] = 0; + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)0u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)0u); + } + + // change only head dimmer + + { + QByteArray values(fxi->channels(), 255); + values[head1Dimmer] = 100; + values[head2Dimmer] = 200; + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)100u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)200u); + } + + { + QByteArray values(fxi->channels(), 255); + values[head1Dimmer] = 0; + values[head2Dimmer] = 0; + QCOMPARE(mfi->computeAlpha(h1, values), (uchar)0u); + QCOMPARE(mfi->computeAlpha(h2, values), (uchar)0u); + } + } +} + +void MonitorFixtureItem_Test::computeAlpha_data() +{ + QTest::addColumn("manufacturer"); + QTest::addColumn("model"); + QTest::addColumn("mode"); + QTest::addColumn("masterDimmer"); + QTest::addColumn("head1Dimmer"); + QTest::addColumn("head2Dimmer"); + + QTest::newRow("5 heads with dimmer") + << "Showtec" + << "Sunstrip Active" + << "5 Channels Mode" + << QLCChannel::invalid() + << 0u + << 1u; + + QTest::newRow("4 heads with dimmer and RGB") + << "American DJ" + << "Quad Scan LED" + << "28 Channels mode" + << QLCChannel::invalid() + << 5u + << 12u; + + QTest::newRow("Master dimmer and 4 heads with dimmer") + << "American DJ" + << "Event Bar LED" + << "25 Channel Mode" + << 24u + << 4u + << 9u; + + QTest::newRow("Master dimmer and 3 heads with RGB") + << "American DJ" + << "Mega Bar LED" + << "11 Channels" + << 10u + << QLCChannel::invalid() + << QLCChannel::invalid(); + + QTest::newRow("Master dimmer and 4 heads with dimmer and RGB") + << "ADB" + << "ALC4" + << "Extended 21 Channels (CT Linear)" + << 0u + << 1u + << 6u; + + QTest::newRow("4 RGB heads") + << "American DJ" + << "Dotz Bar 1.4" + << "12 Channel" + << QLCChannel::invalid() + << QLCChannel::invalid() + << QLCChannel::invalid(); +} + +QTEST_MAIN(MonitorFixtureItem_Test) diff --git a/ui/test/monitorfixtureitem/monitorfixtureitem_test.h b/ui/test/monitorfixtureitem/monitorfixtureitem_test.h new file mode 100644 index 0000000000..9cd78ccd3d --- /dev/null +++ b/ui/test/monitorfixtureitem/monitorfixtureitem_test.h @@ -0,0 +1,42 @@ +/* + Q Light Controller Plus + monitorfixtureitem_test.h + + Copyright (C) Heikki Junnila + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MONITORFIXTUREITEM_TEST_H +#define MONITORFIXTUREITEM_TEST_H + +#include + +class Doc; +class MonitorFixtureItem_Test : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + void cleanup(); + + void computeAlpha(); + void computeAlpha_data(); + +private: + Doc* m_doc; +}; + +#endif diff --git a/ui/test/monitorfixtureitem/test.sh b/ui/test/monitorfixtureitem/test.sh new file mode 100755 index 0000000000..fca595a26b --- /dev/null +++ b/ui/test/monitorfixtureitem/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +LD_LIBRARY_PATH=../../src:../../../engine/src \ + DYLD_FALLBACK_LIBRARY_PATH=../../src:../../../engine/src \ + ./monitorfixtureitem_test diff --git a/ui/test/test.pro b/ui/test/test.pro index 8422f5c15d..c86a51d0ad 100644 --- a/ui/test/test.pro +++ b/ui/test/test.pro @@ -5,6 +5,7 @@ SUBDIRS += addfixture SUBDIRS += efxpreviewarea SUBDIRS += functionselection SUBDIRS += monitorfixture +SUBDIRS += monitorfixtureitem SUBDIRS += palettegenerator SUBDIRS += vcbutton SUBDIRS += vccuelist