diff -r 52e10e8d88cc -r 1a4342d80de7 src/colors.cpp
--- a/src/colors.cpp Wed Jun 08 19:33:00 2022 +0300
+++ b/src/colors.cpp Wed Jun 08 20:41:21 2022 +0300
@@ -1,115 +1,72 @@
-/*
- * LDForge: LDraw parts authoring CAD
- * Copyright (C) 2013 - 2020 Teemu Piippo
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include "colors.h"
-const ldraw::ColorDefinition ldraw::ColorTable::unknownColor{{}, {}, "Unknown", "???"};
+const ColorDefinition unknownColor{{}, {}, "Unknown", "???"};
-/**
- * @brief Clears the color table
- */
-void ldraw::ColorTable::clear()
-{
- this->definitions = {};
-}
-
-/**
- * @brief Loads colors from LDConfig.ldr
- * @param device Opened LDConfig.ldr I/O device
- * @param errors Where to write any errors into
- * @returns whether or not it succeeded.
- */
-Result ldraw::ColorTable::load(QIODevice& device, QTextStream& errors)
+template
+static QString replaced(QString text, Args&&... args)
{
- this->clear();
- if (device.isReadable())
- {
- QTextStream stream{&device};
- QString line;
- while (stream.readLineInto(&line))
- {
- this->loadColorFromString(line);
- }
- return Success;
- }
- else
- {
- errors << "could not read colors";
- return Failure;
- }
-}
-
-/**
- * @brief Gets color information by color index.
- * @param color
- * @returns color table information
- */
-const ldraw::ColorDefinition& ldraw::ColorTable::operator[](Color color) const
-{
- auto it = this->definitions.find(color.index);
- if (it != this->definitions.end())
- {
- return it->second;
- }
- else
- {
- return unknownColor;
- }
-}
-
-/**
- * @brief Gets the amount of elements in the color table
- * @returns int
- */
-int ldraw::ColorTable::size() const
-{
- return this->definitions.size();
+ text.replace(args...);
+ return text;
}
/**
* @brief Parses an LDConfig.ldr line from a string
* @param string LDConfig.ldr line to parse
*/
-void ldraw::ColorTable::loadColorFromString(const QString& string)
+static auto loadColorFromString(const QString& string)
{
- const QRegExp pattern{
- R"(^\s*0 \!COLOUR\s+([^\s]+)\s+)"_q +
- R"(CODE\s+(\d+)\s+)"_q +
- R"(VALUE\s+(\#[0-9a-fA-F]{3,6})\s+)"_q +
- R"(EDGE\s+(\#[0-9a-fA-F]{3,6}))"_q +
- R"((?:\s+ALPHA\s+(\d+))?)"_q
- };
+ std::optional> result;
+ static const QRegExp pattern{QStringLiteral(
+ R"(^\s*0 \!COLOUR\s+([^\s]+)\s+)"
+ R"(CODE\s+(\d+)\s+)"
+ R"(VALUE\s+(\#[0-9a-fA-F]{3,6})\s+)"
+ R"(EDGE\s+(\#[0-9a-fA-F]{3,6}))"
+ R"((?:\s+ALPHA\s+(\d+))?)"
+ )};
if (pattern.indexIn(string) != -1)
{
const int code = pattern.cap(2).toInt();
- ColorDefinition& definition = this->definitions[code];
- definition = {}; // in case there's an existing definition
- definition.name = pattern.cap(1);
- definition.displayName = definition.name;
- definition.displayName.replace("_", " ");
- definition.faceColor = pattern.cap(3);
- definition.edgeColor = pattern.cap(4);
+ const QString name = pattern.cap(1);
+ ColorDefinition definition = {
+ .faceColor = pattern.cap(3),
+ .edgeColor = pattern.cap(4),
+ .name = name,
+ .displayName = replaced(name, "_", " "),
+ };
if (not pattern.cap(5).isEmpty())
{
const int alpha = pattern.cap(5).toInt();
definition.faceColor.setAlpha(alpha);
}
+ result = std::make_pair(ColorIndex{code}, definition);
}
+ return result;
+}
+
+/**
+ * @brief Loads colors from LDConfig.ldr
+ */
+std::optional loadColorTable(QIODevice &device, QTextStream &errors)
+{
+ std::optional result;
+ if (device.isReadable())
+ {
+ result.emplace();
+ QTextStream stream{&device};
+ QString line;
+ while (stream.readLineInto(&line))
+ {
+ const auto pair = loadColorFromString(line);
+ if (pair.has_value()) {
+ (*result)[pair->first] = pair->second;
+ }
+ }
+ }
+ else
+ {
+ errors << "could not read colors";
+ }
+ return result;
}
/**
@@ -118,109 +75,67 @@
* @param color
* @returns luma value [0, 1]
*/
-double luma(const QColor& color)
+qreal luma(const QColor& color)
{
- return 0.2126 * color.redF() + 0.7152 * color.greenF() + 0.0722 * color.blueF();
+ return luma(color.redF(), color.greenF(), color.blueF());
}
-/**
- * @brief Returns a direct color index that codes the specified color value
- * @param color
- * @returns direct color index
- */
-ldraw::Color ldraw::directColor(const QColor& color)
+//! @brief Returns a direct color index that codes the specified color value
+ColorIndex directColor(const QColor& color)
{
- return ldraw::Color{0x2000000 | (color.red() << 16) | (color.green() << 8) | color.blue()};
+ return directColor(color.red(), color.green(), color.blue());
}
-/**
- * @brief Checks whether or not the specified color index is a direct color
- * @param color Color to check
- * @returns bool
- */
-bool ldraw::isDirectColor(ldraw::Color color)
+//! @brief Returns a face color for @param color, taking direct colors into account
+std::optional colorFace(ColorIndex color, const ColorTable& colorTable)
{
- return color.index >= 0x2000000;
+ std::optional result;
+ if (isDirectColor(color)) {
+ const std::array rgb = directColorRgb(color);
+ result = QColor{rgb[0], rgb[1], rgb[2]};
+ }
+ else {
+ const ColorDefinition* def = findInMap(colorTable, color);
+ if (def != nullptr) {
+ result = def->faceColor;
+ }
+ }
+ return result;
}
-/**
- * @brief Extracts the color value from a direct color index
- * @param color Direct color index
- * @returns color value. Returns a default-constructed QColor in case a non-direct color is given.
- */
-QColor ldraw::directColorFace(ldraw::Color color)
+//! @brief Returns an edge color for @param color, taking direct colors into account
+std::optional colorEdge(ColorIndex color, const ColorTable& colorTable)
{
- if (isDirectColor(color))
- {
- return {(color.index >> 16) & 0xff, (color.index >> 8) & 0xff, color.index & 0xff};
+ if (isDirectColor(color)) {
+ const std::array rgb = directColorRgb(color);
+ return (luma(rgb[0], rgb[1], rgb[2]) < 0.4) ? Qt::white : Qt::black;
}
- else
- {
- return {};
+ else {
+ return colorFace(color, colorTable);
}
}
-/**
- * @brief Gets the face color for the specified color index
- * @param color Color index to get face color for
- * @param colorTable Color table to use for lookup
- * @returns QColor
- */
-QColor ldraw::colorFace(ldraw::Color color, const ldraw::ColorTable& colorTable)
-{
- if (isDirectColor(color))
- {
- return directColorFace(color);
- }
- else
- {
- return colorTable[color].faceColor;
- }
-}
-
-QColor ldraw::colorEdge(ldraw::Color color, const ldraw::ColorTable& colorTable)
-{
- if (isDirectColor(color))
- {
- QColor const faceColor = directColorFace(color);
- return (luma(faceColor) < 0.4) ? Qt::white : Qt::black;
- }
- else
- {
- return colorTable[color].faceColor;
- }
-}
-
-/**
- * @brief Writes a color index into a @c QDataStream
- * @param stream
- * @param color
- * @returns stream
- */
-QDataStream& operator<<(QDataStream& stream, ldraw::Color color)
+QDataStream& operator<<(QDataStream& stream, ColorIndex color)
{
return stream << color.index;
}
-/**
- * @brief Reads a color index from a @c QDataStream
- * @param stream
- * @param color
- * @returns stream
- */
-QDataStream& operator>>(QDataStream& stream, ldraw::Color& color)
+QDataStream& operator>>(QDataStream& stream, ColorIndex& color)
{
return stream >> color.index;
}
-QString ldraw::colorDisplayName(ldraw::Color color, const ldraw::ColorTable &colorTable)
+std::optional colorDisplayName(ColorIndex color, const ColorTable &colorTable)
{
- if (isDirectColor(color))
- {
- return directColorFace(color).name();
+ std::optional result;
+ if (isDirectColor(color)) {
+ result = colorFace(color, colorTable).value_or(QColor{}).name();
}
- else
- {
- return colorTable[color].displayName;
+ else {
+ const ColorDefinition* def = findInMap(colorTable, color);
+ if (def != nullptr) {
+ result = def->displayName;
+ }
}
+ return result;
}