diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Wasabi/bfc/draw/gradient.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Wasabi/bfc/draw/gradient.cpp')
-rw-r--r-- | Src/Wasabi/bfc/draw/gradient.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/Src/Wasabi/bfc/draw/gradient.cpp b/Src/Wasabi/bfc/draw/gradient.cpp new file mode 100644 index 00000000..b8468ee0 --- /dev/null +++ b/Src/Wasabi/bfc/draw/gradient.cpp @@ -0,0 +1,309 @@ +#include <precomp.h> + +#include "gradient.h" + +#include <math.h>//floor +#include <bfc/ptrlist.h> +#include <bfc/parse/pathparse.h> + + +#define DEFAULT_GRAD_MODE L"linear" + +template<class T> inline void SWAP(T &a, T &b) { + T c = a; + a = b; + b = c; +} + + + + +inline unsigned int LERPu(unsigned int a, unsigned int b, double p) { +// ASSERT(p >= 0); +// ASSERT(p <= 1.f); + unsigned int ret = (unsigned int)((double)b * p + (double)a * (1. - p)); + return ret; +} + +inline float LERPf(double a, double b, float p) { +// ASSERT(p >= 0); +// ASSERT(p <= 1.f); + return (float)(b * p + a * (1. - p)); +} + +Gradient::Gradient() : + gammagroup(L"") +{ + gradient_x1 = 0.0f; + gradient_y1 = 0.0f; + gradient_x2 = 1.0f; + gradient_y2 = 1.0f; + reverse_colors = 0; + antialias = 0; + mode = DEFAULT_GRAD_MODE; + list.addItem(new GradientPoint(0.0f, 0xff00ff00)); + list.addItem(new GradientPoint(.5, 0x000000ff)); + list.addItem(new GradientPoint(1.0f, 0xffff0000)); +} + +Gradient::~Gradient() { + list.deleteAll(); +} + +void Gradient::setX1(float x1) { + gradient_x1 = x1; + onParamChange(); +} + +void Gradient::setY1(float y1) { + gradient_y1 = y1; + onParamChange(); +} + +void Gradient::setX2(float x2) { + gradient_x2 = x2; + onParamChange(); +} + +void Gradient::setY2(float y2) { + gradient_y2 = y2; + onParamChange(); +} + +void Gradient::clearPoints() { + list.deleteAll(); + onParamChange(); +} + +void Gradient::addPoint(float pos, ARGB32 color) +{ + list.addItem(new GradientPoint(pos, color, gammagroup)); + onParamChange(); +} + +void Gradient::setPoints(const wchar_t *pointlist) +{ + clearPoints(); + if (pointlist == NULL || *pointlist == '\0') return; +// 0.5=233,445,245,123; + PathParserW pp(pointlist, L";"); + if (pp.getNumStrings() <= 0) return; + for (int i = 0; i < pp.getNumStrings(); i++) + { + PathParserW rp(pp.enumString(i), L"="); + if (rp.getNumStrings() != 2) + continue; + float pos = (float)WTOF(rp.enumString(0)); + ARGB32 color = (ARGB32)WASABI_API_SKIN->parse(rp.enumString(1), L"coloralpha"); + addPoint(pos, color); + } +} + +void Gradient::setReverseColors(int c) { + reverse_colors = c; +} + +void Gradient::setAntialias(int c) { + antialias = c; +} + +void Gradient::setMode(const wchar_t *_mode) { + mode = _mode; + if (mode.isempty()) + mode = DEFAULT_GRAD_MODE; +} + +void Gradient::setGammaGroup(const wchar_t *group) { + gammagroup = group; + // reset our points + foreach(list) + list.getfor()->color.setColorGroup(group); + endfor +} + +static inline ARGB32 colorLerp(ARGB32 color1, ARGB32 color2, double pos) { + unsigned int a1 = (color1>>24) & 0xff; + unsigned int a2 = (color2>>24) & 0xff; + unsigned int r1 = (color1>>16) & 0xff; + unsigned int r2 = (color2>>16) & 0xff; + unsigned int g1 = (color1>>8) & 0xff; + unsigned int g2 = (color2>>8) & 0xff; + unsigned int b1 = (color1) & 0xff; + unsigned int b2 = (color2) & 0xff; + return (LERPu(a1, a2, pos)<<24) | (LERPu(r1, r2, pos) << 16) | (LERPu(g1,g2,pos)<<8) | LERPu(b1, b2, pos); +} + +void Gradient::renderGrad(ARGB32 *ptr, int len, int *positions) { + + int npos = list.getNumItems(); + ASSERT(npos >= 2); + + ARGB32 color1, color2; + for (int i = 0; i < npos-1; i++) { + color1 = list.q(i)->color.getColor(); + color2 = list.q(i+1)->color.getColor(); + + if (reverse_colors) { + color1 = BGRATOARGB(color1); + color2 = BGRATOARGB(color2); + } + + int x1 = positions[i]; + int x2 = positions[i+1]; + if (x1 == x2) continue; + // hflip if need be + if (x1 > x2) { + SWAP(x1, x2); + SWAP(color1, color2); + } + float c = 0; + float segment_len = (float)((x2 - x1)+1); + + if (x1 < 0) { // clip left + c += -x1; + x1 = 0; + } + for (int x = x1; x < x2; x++, c += 1.0f) { + if (x >= len) break; // clip right + ptr[x] = colorLerp(color1, color2, c / segment_len); + } + } +#if 0//later + // fill in left if needed + if (positions[0] > 0) MEMFILL<ARGB32>(ptr, list.q(0)->color, positions[0]); + + // and right if needed + int rpos = positions[npos-1]; + if (rpos < len) MEMFILL<ARGB32>(ptr+rpos, list.getLast()->color, len-rpos); +#endif +} + +void Gradient::renderGradient(ARGB32 *bits, int w, int h, int pitch) +{ + if (pitch == 0) + pitch = w; + + list.sort(); + + ARGB32 default_color = 0xffff00ff; + if (list.getNumItems() == 1) default_color = list.q(0)->color.getColor(); + // blank it out to start + if (pitch == w) + MEMFILL<ARGB32>(bits, default_color, w * h); + else + { + for (int i=0;i<h;i++) + MEMFILL<ARGB32>(bits+i*pitch, default_color, w); + } + + if (list.getNumItems() > 1) { + if (mode.iscaseequal(L"linear")) { +//FUCKO: not if endcaps are filled + + // force non-vertical lines + if (ABS(gradient_x1 - gradient_x2) < 0.0005f) gradient_x2 = gradient_x1+0.0005f; + + double px1 = gradient_x1 * w, py1 = gradient_y1 * h; + double px2 = gradient_x2 * w, py2 = gradient_y2 * h; + + // convert to y = mx + b + double m = (py2 - py1)/(px2 - px1); + m = -1.f/m; // invert the slope + + int nitems = list.getNumItems(); + + // get the in-pixels x and y for points on the gradient + for (int i = 0; i < nitems; i++) { + GradientPoint *gp = list.q(i); + // need x and y given pos + gp->x = LERPf(px1, px2, gp->pos); + gp->y = LERPf(py1, py2, gp->pos); + } + + MemBlock<int> positions(nitems); + for (int _y = 0; _y < h; _y++) { + // project all the color points onto this scanline + for (int i = 0; i < nitems; i++) { + GradientPoint *gp = list.q(i); +// y = mx + b +// b = y - mx; + double newb = gp->y - m * gp->x; +// y = mx + newb +// y - newb = mx +// (y - newb)/m = x + double xxx = (_y - newb)/m; + positions[i] = (int)floor(xxx+0.5f); + } + renderGrad(bits+_y*pitch, w, positions); + } + } else if (mode.iscaseequal(L"circular")) { + double tot = SQRT(SQR(gradient_x1 - gradient_x2) + SQR(gradient_y1 - gradient_y2)); + foreach(list) + GradientPoint *gp = list.getfor(); + gp->dist = gp->pos * tot; + endfor + + ARGB32 *dst = bits; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + ARGB32 c; + if (antialias) { + double fx = (((double)x)-0.5f) / (double)w; + double fy = (((double)y)-0.5f) / (double)h; + ARGB32 ul = getPixelCirc(fx, fy); + fx = (((double)x)+0.5f) / (double)w; + fy = (((double)y)-0.5f) / (double)h; + ARGB32 ur = getPixelCirc(fx, fy); + fx = (((double)x)+0.5f) / (double)w; + fy = (((double)y)+0.5f) / (double)h; + ARGB32 lr = getPixelCirc(fx, fy); + fx = (((double)x)-0.5f) / (double)w; + fy = (((double)y)+0.5f) / (double)h; + ARGB32 ll = getPixelCirc(fx, fy); + c = colorLerp(colorLerp(ll, lr, 0.5f), colorLerp(ul, ur, 0.5f), 0.5); + } else { + double fy = (double)y / (double)h; + double fx = (double)x / (double)w; + c = getPixelCirc(fx, fy); + } + *dst++ = c; + } + dst += (pitch-w); + } + } + }//list.getNumItems()>1 + + if (pitch == w) + premultiplyARGB32(bits, w * h); + else + { + for (int i=0;i<h;i++) + premultiplyARGB32(bits+i*pitch, w); + } + +} + +ARGB32 Gradient::getPixelCirc(double fx, double fy) { + int nitems = list.getNumItems(); + //double dist = SQR(fx - gradient_x1) + SQR(fy - gradient_y1); + double dist = SQRT(SQR(fx - gradient_x1) + SQR(fy - gradient_y1)); + ARGB32 c = 0xff00ff00; + if (dist <= list.q(0)->dist) + c = list.q(0)->color.getColor(); + else if (dist >= list.getLast()->dist) + c = list.getLast()->color.getColor(); + else for (int i = 0; i < nitems-1; i++) { + if (list.q(i)->dist <= dist && list.q(i+1)->dist >= dist) { + double pdist = list.q(i+1)->dist - list.q(i)->dist; + double pp = dist - list.q(i)->dist; + pp /= pdist; + if (list.q(i)->color.getColor() == list.q(i+1)->color.getColor()) + c = list.q(i)->color.getColor(); + else + c = colorLerp(list.q(i)->color.getColor(), list.q(i+1)->color.getColor(), pp); + break; + } + } + if (reverse_colors) c = BGRATOARGB(c); + return c; +} |