I'm currently attempting to create a color gradient class for my Mandelbrot Set explorer.
It reads the color constraints (RGBA8888
color and position between 0 and 1) from a text file and adds them to a vector, which is lateron used to determine colors at a certain position.
To compute a color, the algorithm searches the next constraint to either side from the given position, splits the color into the four single channels, and then, for each one, searches the lower of both and adds a portion of the difference equal to the ratio (x-lpos)/(upos-lpos)
to the lower color. Afterwards, the channels are shifted and ORed together, and then returned as RGBA8888
unsigned integer. (See the code below.)
EDIT: I completely rewrote the gradient class, fixing some issues and making it more readable for the sake of debugging (It gets slow as hell, though, but -Os
more or less takes care of that). However, It's still not as it's supposed to be.
class Gradient { //remade, Some irrelevant methods and de-/constructors removed
private:
map<double, unsigned int> constraints;
public:
unsigned int operator[](double value) {
//Forbid out-of-range values, return black
if (value < 0 || value > 1+1E-10) return 0xff;
//Find upper and lower constraint
auto upperC = constraints.lower_bound(value);
if (upperC == constraints.end()) upperC = constraints.begin();
auto lowerC = upperC == constraints.begin() ? prev(constraints.end(), 1) : prev(upperC, 1);
if (value == lowerC->first) return lowerC->second;
double lpos = lowerC->first;
double upos = upperC->first;
if (upos < lpos) upos += 1;
//lower color channels
unsigned char lred = (lowerC->second >> 24) & 0xff;
unsigned char lgreen = (lowerC->second >> 16) & 0xff;
unsigned char lblue = (lowerC->second >> 8) & 0xff;
unsigned char lalpha = lowerC->second & 0xff;
//upper color channels
unsigned char ured = (upperC->second >> 24) & 0xff;
unsigned char ugreen = (upperC->second >> 16) & 0xff;
unsigned char ublue = (upperC->second >> 8) & 0xff;
unsigned char ualpha = upperC->second & 0xff;
unsigned char red = 0, green = 0, blue = 0, alpha = 0xff;
//Compute each channel using
// lower color + dist(lower, x)/dist(lower, upper) * diff(lower color, upper color)
if (lred < ured)
red = lred + (value - lpos)/(upos - lpos) * (ured - lred);
else red = ured + (upos - value)/(upos - lpos) * (ured - lred);
if (lgreen < ugreen)
green = lgreen + (value - lpos)/(upos - lpos) * (ugreen - green);
else green = ugreen + (upos - value)/(upos - lpos) * (ugreen - lgreen);
if (lblue < ublue)
blue = lblue + (value - lpos)/(upos - lpos) * (ublue - lblue);
else blue = ublue + (upos - value)/(upos - lpos) * (ublue - lblue);
if (lalpha < ualpha)
alpha = lalpha + (value - lpos)/(upos - lpos) * (ualpha - lalpha);
else alpha = ualpha + (upos - value)/(upos - lpos) * (ualpha - lalpha);
//Merge channels together and return
return (red << 24) | (green << 16) | (blue << 8 ) | alpha;
}
void addConstraint(unsigned int color, double position) {
constraints[position] = color;
}
};
Usage in the update method:
image[r + rres*i] = grd[ratio];
//With image being a vector<unsigned int>, which is then used as data source for a `SDL_Texture` using `SDL_UpdateTexture`
It only works partially, though. When I only use a black/white gradient, the resulting image is as intended:
Gradient file:
2
0 000000ff
1 ffffffff
However, when I use a more colorful gradient (a linear version of the Ultra Fractal gradient, input file below), the image is far from the intended result the image still doesn't show the desired coloring:
Gradient file:
5
0 000764ff
.16 206bcbff
.42 edffffff
.6425 ffaa00ff
0.8575 000200ff
What am I doing wrong? I've rewritten the operator[]
method multiple times, without anything changing.
Questions for clarification or general remarks on my code are welcome.