Skip to content

Commit

Permalink
RGB Matrix with generic dimmers
Browse files Browse the repository at this point in the history
- for each head, compute separately master dimmer channel and per-head dimmer
- adjust all related code (especially 2D monitor)
- RGB Matrix: if there are no RGB/CMY channels for a head:
  - if there is a per-head dimmer channel, it is faded to color value
    of the RGB matrix cell and all other dimmers are set to full
    (if dimmer control is enabled)
  - if there is no per-head dimmer, master dimmer is faded
  - if there is only master dimmer, and you don't want to have it faded,
    don't add it to RGB matrix :)

Fixes #827
  • Loading branch information
janosvitok committed Nov 16, 2016
1 parent 63f5998 commit fadf10b
Show file tree
Hide file tree
Showing 20 changed files with 570 additions and 81 deletions.
15 changes: 10 additions & 5 deletions engine/src/efxfixture.cpp
Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -493,9 +494,13 @@ void EFXFixture::setPointDimmer(QList<Universe *> 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);
}
}

Expand Down
29 changes: 17 additions & 12 deletions engine/src/fixture.cpp
Expand Up @@ -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 <quint32> Fixture::rgbChannels(int head) const
Expand Down
5 changes: 4 additions & 1 deletion engine/src/fixture.h
Expand Up @@ -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 <quint32> rgbChannels(int head = 0) const;
Expand Down
31 changes: 15 additions & 16 deletions engine/src/qlcfixturehead.cpp
Expand Up @@ -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())
{
}

Expand All @@ -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)
Expand Down Expand Up @@ -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 <quint32> QLCFixtureHead::rgbChannels() const
Expand Down Expand Up @@ -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 <quint32> it(m_channels);
while (it.hasNext() == true)
Expand All @@ -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;
}
Expand All @@ -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)
{
Expand All @@ -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;
}
}

Expand Down Expand Up @@ -297,7 +296,7 @@ bool QLCFixtureHead::saveXML(QXmlStreamWriter *doc) const
QLCDimmerHead::QLCDimmerHead(int head)
: QLCFixtureHead()
{
m_masterIntensityChannel = head;
m_intensityChannel = head;
m_channelsCached = true;
}

10 changes: 5 additions & 5 deletions engine/src/qlcfixturehead.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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 <quint32> m_rgbChannels;
Expand Down
20 changes: 20 additions & 0 deletions engine/src/qlcfixturemode.cpp
Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -224,6 +227,11 @@ quint32 QLCFixtureMode::channelNumber(QLCChannel::Group group, QLCChannel::Contr
return QLCChannel::invalid();
}

quint32 QLCFixtureMode::masterIntensityChannel() const
{
return m_masterIntensityChannel;
}

/*****************************************************************************
* Heads
*****************************************************************************/
Expand Down Expand Up @@ -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;
}
}
}

/****************************************************************************
Expand Down
4 changes: 4 additions & 0 deletions engine/src/qlcfixturemode.h
Expand Up @@ -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 <QLCChannel*> m_channels;

quint32 m_masterIntensityChannel;

/*********************************************************************
* Heads
*********************************************************************/
Expand Down
67 changes: 45 additions & 22 deletions engine/src/rgbmatrix.cpp
Expand Up @@ -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.
Expand All @@ -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 <quint32> rgb = head.rgbChannels();
QVector <quint32> 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 <quint32> dim;
if (masterDim != QLCChannel::invalid())
dim << masterDim;

if (headDim != QLCChannel::invalid())
dim << headDim;

if (rgb.size() == 3)
{
// RGB color mixing
Expand Down Expand Up @@ -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);
}
}
}
Expand Down

0 comments on commit fadf10b

Please sign in to comment.