void RGBMatrix_Test::previewMaps() { RGBMatrix mtx(m_doc); QVERIFY(mtx.algorithm() != NULL); QCOMPARE(mtx.algorithm()->name(), QString("Stripes")); int steps = mtx.stepsCount(); QCOMPARE(steps, 0); RGBMap map = mtx.previewMap(0); QCOMPARE(map.size(), 0); // No fixture group mtx.setFixtureGroup(0); steps = mtx.stepsCount(); QCOMPARE(steps, 5); map = mtx.previewMap(0); QCOMPARE(map.size(), 5); for (int z = 0; z < steps; z++) { map = mtx.previewMap(z); for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { if (x == z) QCOMPARE(map[y][x], QColor(Qt::black).rgb()); else QCOMPARE(map[y][x], uint(0)); } } } }
void RGBText_Test::verticalScroll() { RGBText text(m_doc); text.setText("QLC"); text.setAnimationStyle(RGBText::Vertical); QFontMetrics fm(text.font()); QCOMPARE(text.rgbMapStepCount(QSize()), fm.ascent() * 3); // Q, L, C // Since fonts and their rendering differs from installation to installation, // these tests are here only to check that nothing crashes. The end result is // more or less OS, platform, HW and SW dependent and testing individual pixels // would thus be rather pointless. for (int i = 0; i < fm.ascent() * 3; i++) { RGBMap map = text.rgbMap(QSize(10, 10), QRgb(0xFFFFFFFF), i); QCOMPARE(map.size(), 10); for (int y = 0; y < 10; y++) QCOMPARE(map[y].size(), 10); } // Invalid step RGBMap map = text.rgbMap(QSize(10, 10), QRgb(0xFFFFFFFF), fm.ascent() * 4); QCOMPARE(map.size(), 10); for (int i = 0; i < 10; i++) { QCOMPARE(map[i].size(), 10); for (int j = 0; j < 10; j++) { QCOMPARE(map[i][j], QRgb(0)); } } }
void RGBText_Test::horizontalScroll() { RGBText text(m_doc); text.setText("QLC"); text.setAnimationStyle(RGBText::Horizontal); QFontMetrics fm(text.font()); #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) QCOMPARE(text.rgbMapStepCount(QSize()), fm.width("QLC")); #else QCOMPARE(text.rgbMapStepCount(QSize()), fm.horizontalAdvance("QLC")); #endif // Since fonts and their rendering differs from installation to installation, // these tests are here only to check that nothing crashes. The end result is // more or less OS, platform, HW and SW dependent and testing individual pixels // would thus be rather pointless. #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) for (int i = 0; i < fm.width("QLC"); i++) #else for (int i = 0; i < fm.horizontalAdvance("QLC"); i++) #endif { RGBMap map = text.rgbMap(QSize(10, 10), QRgb(0xFFFFFFFF), i); QCOMPARE(map.size(), 10); for (int y = 0; y < 10; y++) QCOMPARE(map[y].size(), 10); } // Invalid step #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) RGBMap map = text.rgbMap(QSize(10, 10), QRgb(0xFFFFFFFF), fm.width("QLC")); #else RGBMap map = text.rgbMap(QSize(10, 10), QRgb(0xFFFFFFFF), fm.horizontalAdvance("QLC")); #endif QCOMPARE(map.size(), 10); for (int i = 0; i < 10; i++) { QCOMPARE(map[i].size(), 10); for (int j = 0; j < 10; j++) { QCOMPARE(map[i][j], QRgb(0)); } } }
void RGBText_Test::staticLetters() { RGBText text(m_doc); text.setText("QLC"); text.setAnimationStyle(RGBText::StaticLetters); QCOMPARE(text.rgbMapStepCount(QSize()), 3); // Q, L, C QRgb color(0xFFFFFFFF); // Since fonts and their rendering differs from installation to installation, // these tests are here only to check that nothing crashes. The end result is // more or less OS, platform, HW and SW dependent and testing individual pixels // would thus be rather pointless. RGBMap map = text.rgbMap(QSize(10, 10), color, 0); QCOMPARE(map.size(), 10); for (int i = 0; i < 10; i++) QCOMPARE(map[i].size(), 10); map = text.rgbMap(QSize(10, 10), color, 1); QCOMPARE(map.size(), 10); for (int i = 0; i < 10; i++) QCOMPARE(map[i].size(), 10); map = text.rgbMap(QSize(10, 10), color, 2); QCOMPARE(map.size(), 10); for (int i = 0; i < 10; i++) QCOMPARE(map[i].size(), 10); // Invalid step map = text.rgbMap(QSize(10, 10), color, 3); QCOMPARE(map.size(), 10); for (int i = 0; i < 10; i++) { QCOMPARE(map[i].size(), 10); for (int j = 0; j < 10; j++) { QCOMPARE(map[i][j], QColor(Qt::black).rgb()); } } }
void RGBMatrixEditor::slotPreviewTimeout() { RGBItem* shape = NULL; if (m_matrix->duration() <= 0) return; m_previewIterator += MasterTimer::tick(); if (m_previewIterator >= m_matrix->duration()) { //qDebug() << "previewTimeout. Step:" << m_previewStep; if (m_matrix->runOrder() == RGBMatrix::PingPong) { if (m_previewDirection == Function::Forward && (m_previewStep + 1) == m_previewMaps.size()) m_previewDirection = Function::Backward; else if (m_previewDirection == Function::Backward && (m_previewStep - 1) < 0) m_previewDirection = Function::Forward; } if (m_previewDirection == Function::Forward) { m_previewStep++; if (m_previewStep >= m_previewMaps.size()) { m_previewStep = 0; m_matrix->setStepColor(m_matrix->startColor()); } else m_matrix->updateStepColor(m_previewDirection); } else { m_previewStep--; if (m_previewStep < 0) { m_previewStep = m_previewMaps.size() - 1; if (m_matrix->endColor().isValid()) m_matrix->setStepColor(m_matrix->endColor()); else m_matrix->setStepColor(m_matrix->startColor()); } else m_matrix->updateStepColor(m_previewDirection); } m_previewMaps = m_matrix->previewMaps(); m_previewIterator = 0; } RGBMap map; if (m_previewStep >= 0 && m_previewStep < m_previewMaps.size()) map = m_previewMaps[m_previewStep]; for (int y = 0; y < map.size(); y++) { for (int x = 0; x < map[y].size(); x++) { QLCPoint pt(x, y); if (m_previewHash.contains(pt) == true) { shape = static_cast<RGBItem*>(m_previewHash[pt]); if (shape->color() != QColor(map[y][x]).rgb()) shape->setColor(map[y][x]); if (shape->color() == QColor(Qt::black).rgb()) shape->draw(m_matrix->fadeOutSpeed()); else shape->draw(m_matrix->fadeInSpeed()); } } } }
bool RGBMatrixEditor::createPreviewItems() { m_previewHash.clear(); m_scene->clear(); FixtureGroup* grp = m_doc->fixtureGroup(m_matrix->fixtureGroup()); if (grp == NULL) { QGraphicsTextItem* text = new QGraphicsTextItem(tr("No fixture group to control")); text->setDefaultTextColor(Qt::white); m_scene->addItem(text); return false; } m_previewDirection = m_matrix->direction(); if (m_previewDirection == Function::Forward) { m_matrix->setStepColor(m_matrix->startColor()); } else { if (m_matrix->endColor().isValid()) m_matrix->setStepColor(m_matrix->endColor()); else m_matrix->setStepColor(m_matrix->startColor()); } m_matrix->calculateColorDelta(); m_previewMaps = m_matrix->previewMaps(); if ((m_previewDirection == Function::Forward) || m_previewMaps.isEmpty()) { m_previewStep = 0; } else { m_previewStep = m_previewMaps.size() - 1; } RGBMap map; if (m_previewStep < m_previewMaps.size()) map = m_previewMaps[m_previewStep]; if (map.isEmpty()) return false; for (int x = 0; x < grp->size().width(); x++) { for (int y = 0; y < grp->size().height(); y++) { QLCPoint pt(x, y); if (grp->headHash().contains(pt) == true) { RGBItem* item = new RGBItem; item->setRect(x * RECT_SIZE + RECT_PADDING + ITEM_PADDING, y * RECT_SIZE + RECT_PADDING + ITEM_PADDING, ITEM_SIZE - (2 * ITEM_PADDING), ITEM_SIZE - (2 * ITEM_PADDING)); item->setColor(map[y][x]); item->draw(0); m_scene->addItem(item); m_previewHash[pt] = item; } } } return true; }
void RGBMatrix::updateMapChannels(const RGBMap& map, const FixtureGroup* grp) { quint32 mdAssigned = QLCChannel::invalid(); quint32 mdFxi = Fixture::invalidId(); uint fadeTime = 0; if (overrideFadeInSpeed() == defaultSpeed()) fadeTime = fadeInSpeed(); else fadeTime = overrideFadeInSpeed(); // Create/modify fade channels for ALL pixels in the color map. for (int y = 0; y < map.size(); y++) { for (int x = 0; x < map[y].size(); x++) { QLCPoint pt(x, y); GroupHead grpHead(grp->head(pt)); Fixture* fxi = doc()->fixture(grpHead.fxi); 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(); if (rgb.size() == 3) { // RGB color mixing FadeChannel fc; fc.setFixture(doc(), grpHead.fxi); fc.setChannel(rgb.at(0)); fc.setTarget(qRed(map[y][x])); insertStartValues(fc, fadeTime); m_fader->add(fc); fc.setChannel(rgb.at(1)); fc.setTarget(qGreen(map[y][x])); insertStartValues(fc, fadeTime); m_fader->add(fc); fc.setChannel(rgb.at(2)); fc.setTarget(qBlue(map[y][x])); insertStartValues(fc, fadeTime); m_fader->add(fc); } else if (cmy.size() == 3) { // CMY color mixing QColor col(map[y][x]); FadeChannel fc; fc.setFixture(doc(), grpHead.fxi); fc.setChannel(cmy.at(0)); fc.setTarget(col.cyan()); insertStartValues(fc, fadeTime); m_fader->add(fc); fc.setChannel(cmy.at(1)); fc.setTarget(col.magenta()); insertStartValues(fc, fadeTime); m_fader->add(fc); fc.setChannel(cmy.at(2)); fc.setTarget(col.yellow()); insertStartValues(fc, fadeTime); m_fader->add(fc); } if (m_dimmerControl && head.masterIntensityChannel() != QLCChannel::invalid()) { //qDebug() << "RGBMatrix: found dimmer at" << head.masterIntensityChannel(); // Simple intensity (dimmer) channel QColor col(map[y][x]); FadeChannel fc; fc.setFixture(doc(), grpHead.fxi); fc.setChannel(head.masterIntensityChannel()); if (col.value() == 0 && mdAssigned != head.masterIntensityChannel()) fc.setTarget(0); else { fc.setTarget(255); if (mdAssigned == QLCChannel::invalid()) mdAssigned = head.masterIntensityChannel(); } insertStartValues(fc, fadeTime); m_fader->add(fc); } } } }
void RGBMatrixEditor::slotPreviewTimeout() { if (m_matrix == NULL || m_group == NULL || m_matrix->duration() <= 0) return; RGBMap map; m_previewIterator += MasterTimer::tick(); if (m_previewIterator >= m_matrix->duration()) { int stepsCount = m_matrix->stepsCount(); //qDebug() << "previewTimeout. Step:" << m_previewStep; if (m_matrix->runOrder() == RGBMatrix::PingPong) { if (m_previewDirection == Function::Forward && (m_previewStep + 1) == stepsCount) m_previewDirection = Function::Backward; else if (m_previewDirection == Function::Backward && (m_previewStep - 1) < 0) m_previewDirection = Function::Forward; } if (m_previewDirection == Function::Forward) { m_previewStep++; if (m_previewStep >= stepsCount) { m_previewStep = 0; m_matrix->setStepColor(m_matrix->startColor()); } else m_matrix->updateStepColor(m_previewStep); } else { m_previewStep--; if (m_previewStep < 0) { m_previewStep = stepsCount - 1; if (m_matrix->endColor().isValid()) m_matrix->setStepColor(m_matrix->endColor()); else m_matrix->setStepColor(m_matrix->startColor()); } else m_matrix->updateStepColor(m_previewStep); } map = m_matrix->previewMap(m_previewStep); m_previewIterator = 0; /* for (int y = 0; y < map.size(); y++) { for (int x = 0; x < map[y].size(); x++) { QLCPoint pt(x, y); if (m_group->head(pt).isValid()) { if (shape->color() != QColor(map[y][x]).rgb()) shape->setColor(map[y][x]); if (shape->color() == QColor(Qt::black).rgb()) shape->draw(m_matrix->fadeOutSpeed()); else shape->draw(m_matrix->fadeInSpeed()); } } } */ if (m_previewData.isEmpty() || map.isEmpty()) return; QHashIterator<QLCPoint, GroupHead> it(m_group->headHash()); while(it.hasNext()) { it.next(); QLCPoint pt(it.key()); //GroupHead head(it.value()); int ptIdx = pt.x() + (pt.y() * m_group->size().width()); if (ptIdx < m_previewData.size()) m_previewData[ptIdx] = QVariant(QColor(map[pt.y()][pt.x()])); } //qDebug() << "Preview data changed !"; emit previewDataChanged(m_previewData); } }
void RGBMatrix::updateMapChannels(const RGBMap& map, const FixtureGroup* grp) { uint fadeTime = (overrideFadeInSpeed() == defaultSpeed()) ? fadeInSpeed() : overrideFadeInSpeed(); // Create/modify fade channels for ALL pixels in the color map. for (int y = 0; y < map.size(); y++) { for (int x = 0; x < map[y].size(); x++) { QLCPoint pt(x, y); GroupHead grpHead(grp->head(pt)); Fixture* fxi = doc()->fixture(grpHead.fxi); if (fxi == NULL) continue; QLCFixtureHead head = fxi->head(grpHead.head); QVector <quint32> rgb = head.rgbChannels(); QVector <quint32> cmy = head.cmyChannels(); quint32 masterDim = fxi->masterIntensityChannel(); quint32 headDim = head.channelNumber(QLCChannel::Intensity, QLCChannel::MSB); // 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 and target color is > 0 (see // http://www.qlcplus.org/forum/viewtopic.php?f=29&t=11090) // // 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; uint col = map[y][x]; if (rgb.size() == 3) { // RGB color mixing { FadeChannel fc(doc(), grpHead.fxi, rgb.at(0)); fc.setTarget(qRed(col)); insertStartValues(fc, fadeTime); m_fader->add(fc); } { FadeChannel fc(doc(), grpHead.fxi, rgb.at(1)); fc.setTarget(qGreen(col)); insertStartValues(fc, fadeTime); m_fader->add(fc); } { FadeChannel fc(doc(), grpHead.fxi, rgb.at(2)); fc.setTarget(qBlue(col)); insertStartValues(fc, fadeTime); m_fader->add(fc); } } else if (cmy.size() == 3) { // CMY color mixing QColor cmyCol(col); { FadeChannel fc(doc(), grpHead.fxi, cmy.at(0)); fc.setTarget(cmyCol.cyan()); insertStartValues(fc, fadeTime); m_fader->add(fc); } { FadeChannel fc(doc(), grpHead.fxi, cmy.at(1)); fc.setTarget(cmyCol.magenta()); insertStartValues(fc, fadeTime); m_fader->add(fc); } { FadeChannel fc(doc(), grpHead.fxi, cmy.at(2)); fc.setTarget(cmyCol.yellow()); insertStartValues(fc, fadeTime); m_fader->add(fc); } } else if (!dim.empty()) { // Set dimmer to value of the color (e.g. for PARs) 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 * qRed(col) + 0.587 * qGreen(col) + 0.114 * qBlue(col)); 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(col == 0 ? 0 : 255); insertStartValues(fc, fadeTime); m_fader->add(fc); } } } }