|
@@ -1,7 +1,10 @@
|
|
|
#include "Gradient.h"
|
|
|
|
|
|
+#include "CubicSpline.h"
|
|
|
+
|
|
|
#include <cmath>
|
|
|
#include <algorithm>
|
|
|
+#include <functional>
|
|
|
#include <QtXml/QDomDocument>
|
|
|
#include <QFile>
|
|
|
|
|
@@ -12,38 +15,49 @@ Gradient::Gradient(void) :
|
|
|
}
|
|
|
|
|
|
|
|
|
-Gradient::Gradient(const std::vector<std::pair<RGBColor, float>>& colors, bool repeat, int precalcSteps) :
|
|
|
+Gradient::Gradient(std::vector<std::pair<RGBColor, float>> colors, bool repeat, int precalcSteps) :
|
|
|
repeat{ repeat }
|
|
|
{
|
|
|
- if(colors.empty())
|
|
|
+ if(colors.empty() || colors.size() < 2)
|
|
|
return;
|
|
|
- /*std::sort(colors.begin(), colors.end(),
|
|
|
- [] (const std::pair<RGBColor, float>& a, const std::pair<RGBColor, float>& b) {
|
|
|
- return a.second < b.second;
|
|
|
- });*/
|
|
|
+ std::sort(colors.begin(), colors.end(),
|
|
|
+ [] (const auto& a, const auto& b) {
|
|
|
+ return a.second < b.second;
|
|
|
+ });
|
|
|
|
|
|
max = colors.at(colors.size() - 1).second;
|
|
|
+
|
|
|
+ std::vector<std::pair<RGBColorf, float>> linearColors;
|
|
|
+ std::transform(colors.begin(), colors.end(), std::back_inserter(linearColors),
|
|
|
+ [] (auto c) { return c; });
|
|
|
+
|
|
|
+ std::vector<std::pair<float, float>> rs;
|
|
|
+ std::vector<std::pair<float, float>> gs;
|
|
|
+ std::vector<std::pair<float, float>> bs;
|
|
|
+
|
|
|
+ std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(rs),
|
|
|
+ [] (auto p) { return std::pair{ p.second, p.first.r }; });
|
|
|
+ std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(gs),
|
|
|
+ [] (auto p) { return std::pair{ p.second, p.first.g }; });
|
|
|
+ std::transform(linearColors.begin(), linearColors.end(), std::back_inserter(bs),
|
|
|
+ [] (auto p) { return std::pair{ p.second, p.first.b }; });
|
|
|
+
|
|
|
+ CubicSpline rsp(rs, false);
|
|
|
+ CubicSpline gsp(gs, false);
|
|
|
+ CubicSpline bsp(bs, false);
|
|
|
+
|
|
|
+ if(precalcSteps <= 0) {
|
|
|
+ precalcSteps = int(max * 15) + 10;
|
|
|
+ }
|
|
|
+
|
|
|
for (int i = 0; i < precalcSteps; i++) {
|
|
|
float position = i * max / precalcSteps;
|
|
|
- RGBColor left = RGBColor{ 0, 0, 0 };
|
|
|
- RGBColor right = RGBColor{ 0, 0, 0 };
|
|
|
- float lerp = 0.0f;
|
|
|
- RGBColor atPosition = RGBColor{ 0, 0, 0 };
|
|
|
- // slow, but not in any critical path
|
|
|
- for (auto it = colors.begin(); it != colors.end(); ++it) {
|
|
|
- if (it->second > position) {
|
|
|
- if (it == colors.begin()) {
|
|
|
- atPosition = it->first;
|
|
|
- break;
|
|
|
- }
|
|
|
- else {
|
|
|
- float lerp = (position - (it - 1)->second) / (it->second - (it - 1)->second);
|
|
|
- atPosition = lerpColors((it - 1)->first, it->first, lerp);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- this->colors.push_back(atPosition);
|
|
|
+ RGBColorf at = {
|
|
|
+ rsp.interpolateAt(position),
|
|
|
+ gsp.interpolateAt(position),
|
|
|
+ bsp.interpolateAt(position)
|
|
|
+ };
|
|
|
+ this->colors.push_back(at);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -67,16 +81,16 @@ Gradient Gradient::readXml(const QString& xml)
|
|
|
std::vector<std::pair<RGBColor, float>> colorArr;
|
|
|
for (int i = 0; i < colors.length(); ++i) {
|
|
|
auto child = colors.item(i).toElement();
|
|
|
- uint8_t r = child.attributeNode("r").value().toInt();
|
|
|
- uint8_t g = child.attributeNode("g").value().toInt();
|
|
|
- uint8_t b = child.attributeNode("b").value().toInt();
|
|
|
+ uint8_t r = uint8_t(child.attributeNode("r").value().toInt());
|
|
|
+ uint8_t g = uint8_t(child.attributeNode("g").value().toInt());
|
|
|
+ uint8_t b = uint8_t(child.attributeNode("b").value().toInt());
|
|
|
float p = child.attributeNode("p").value().toInt();
|
|
|
|
|
|
printf("rgb (%s): %d, %d, %d\n", child.text().toUtf8().data(), r, g, b);
|
|
|
colorArr.push_back({ { r, g, b }, p });
|
|
|
}
|
|
|
|
|
|
- return Gradient(colorArr, repeat);
|
|
|
+ return Gradient(std::move(colorArr), repeat);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -88,6 +102,8 @@ RGBColor Gradient::get(float x) const
|
|
|
RGBColor lerped = lerpColors(left, right, lerp);
|
|
|
return lerped;*/
|
|
|
|
|
|
+ if (x < 0)
|
|
|
+ return colors[0];
|
|
|
if (x > this->max) {
|
|
|
if (repeat)
|
|
|
x = ::fmodf(x, this->max);
|
|
@@ -104,7 +120,7 @@ RGBColor Gradient::get(float x) const
|
|
|
int right = int(pos + 1);
|
|
|
float lerp = pos - left;
|
|
|
|
|
|
- if (lerp < 1e-5) {
|
|
|
+ if (lerp < 1e-5f) {
|
|
|
return colors.at(left);
|
|
|
}
|
|
|
else {
|
|
@@ -113,20 +129,19 @@ RGBColor Gradient::get(float x) const
|
|
|
}
|
|
|
|
|
|
|
|
|
-RGBColor Gradient::lerpColors(RGBColor a, RGBColor b, float val)
|
|
|
+RGBColorf Gradient::lerpColors(RGBColorf a, RGBColorf b, float val)
|
|
|
{
|
|
|
- auto mklin = [] (double x) {
|
|
|
- return x * x;//::pow(x, 2.4);
|
|
|
- };
|
|
|
- auto unlin = [] (double x) {
|
|
|
- return ::sqrt(x);// ::pow(x, 1.0 / 2.4);
|
|
|
+ return RGBColorf {
|
|
|
+ b.r * val + a.r * (1 - val),
|
|
|
+ b.g * val + a.g * (1 - val),
|
|
|
+ b.b * val + a.b * (1 - val)
|
|
|
};
|
|
|
+}
|
|
|
|
|
|
- return RGBColor{
|
|
|
- uint8_t(unlin(mklin(b.r) * val + mklin(a.r) * (1 - val))),
|
|
|
- uint8_t(unlin(mklin(b.g) * val + mklin(a.g) * (1 - val))),
|
|
|
- uint8_t(unlin(mklin(b.b) * val + mklin(a.b) * (1 - val)))
|
|
|
- };
|
|
|
+
|
|
|
+RGBColor Gradient::lerpColors(RGBColor a, RGBColor b, float val)
|
|
|
+{
|
|
|
+ return RGBColor{ lerpColors(RGBColorf{ a }, RGBColorf{ b }, val) };
|
|
|
}
|
|
|
|
|
|
|