533 lines
17 KiB
C++
533 lines
17 KiB
C++
#include "Gradient.h"
|
|
#include <QCoreApplication>
|
|
|
|
//extern char *GetBinDir(char *str);
|
|
|
|
BYTE GetRValue(COLORREF colour)
|
|
{
|
|
QColor color(colour);
|
|
return color.red();
|
|
}
|
|
|
|
BYTE GetGValue(COLORREF colour)
|
|
{
|
|
QColor color(colour);
|
|
return color.green();
|
|
}
|
|
|
|
BYTE GetBValue(COLORREF colour)
|
|
{
|
|
QColor color(colour);
|
|
return color.blue();
|
|
}
|
|
|
|
|
|
CGradient::CGradient()
|
|
{
|
|
m_StartPeg.colour = 0x00FFFFFF;//
|
|
m_StartPeg.position = 0.0f;
|
|
m_EndPeg.colour = 0x00000000;//
|
|
m_EndPeg.position = 1.0f;
|
|
m_Background.colour = 0x00FFFFFF; //A default pal
|
|
m_Background.position = 0.0f;
|
|
m_InterpolationMethod = Linear;
|
|
m_UseBackground = false;
|
|
m_Quantization = -1;
|
|
|
|
m_FileFlag = "LogPlus";
|
|
pegs.clear();
|
|
}
|
|
CGradient::~CGradient()
|
|
{
|
|
pegs.clear();
|
|
}
|
|
|
|
//void CGradient::MakeEntries(RGBTRIPLE *lpPal, int iEntryCount)
|
|
//{
|
|
// float pos;
|
|
// COLORREF colour;
|
|
// int curpeg;
|
|
// if ( iEntryCount < 1 || iEntryCount >= 65535)
|
|
// return ;
|
|
|
|
// InterpolateFn Interpolate = GetInterpolationProc();
|
|
|
|
// if(pegs.count() > 0)
|
|
// {
|
|
// //Some things are already constant and so can be found early
|
|
// float firstpegpos = pegs[0].position;
|
|
// float lastpegpos = pegs[pegs.count()-1].position;
|
|
// COLORREF lastpegcolour = pegs[pegs.count()-1].colour;
|
|
|
|
|
|
// for(int i = 0; i < iEntryCount; i++)
|
|
// {
|
|
// if(m_Quantization == -1)
|
|
// pos = (float)i/iEntryCount;
|
|
// else
|
|
// pos = ((float)(int)(((float)i/iEntryCount)*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
|
|
|
|
// if(pos <= firstpegpos)
|
|
// {
|
|
// colour = Interpolate(m_StartPeg.colour, pegs[0].colour, pos, 0, firstpegpos);
|
|
// lpPal[i].rgbtRed = GetRValue(colour);
|
|
// lpPal[i].rgbtGreen = GetGValue(colour);
|
|
// lpPal[i].rgbtBlue = GetBValue(colour);
|
|
// }
|
|
// else if(pos > lastpegpos)
|
|
// {
|
|
// colour = Interpolate(lastpegcolour, m_EndPeg.colour, pos, lastpegpos, 1);
|
|
// lpPal[i].rgbtRed = GetRValue(colour);
|
|
// lpPal[i].rgbtGreen = GetGValue(colour);
|
|
// lpPal[i].rgbtBlue = GetBValue(colour);
|
|
// }
|
|
// else
|
|
// {
|
|
// curpeg = IndexFromPos(pos);
|
|
// colour = Interpolate(pegs[curpeg].colour, pegs[curpeg+1].colour, pos, pegs[curpeg].position, pegs[curpeg+1].position);
|
|
// lpPal[i].rgbtRed = GetRValue(colour);
|
|
// lpPal[i].rgbtGreen = GetGValue(colour);
|
|
// lpPal[i].rgbtBlue = GetBValue(colour);
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// //When there are no extra peg we can just interpolate the start and end
|
|
// for(int i = 0; i < iEntryCount; i++)
|
|
// {
|
|
// if(m_Quantization == -1)
|
|
// pos = (float)i/iEntryCount;
|
|
// else
|
|
// pos = ((float)(int)(((float)i/iEntryCount)*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
|
|
|
|
// colour = Interpolate(m_StartPeg.colour, m_EndPeg.colour, pos, 0, 1);
|
|
// lpPal[i].rgbtRed = GetRValue(colour);
|
|
// lpPal[i].rgbtGreen = GetGValue(colour);
|
|
// lpPal[i].rgbtBlue = GetBValue(colour);
|
|
// }
|
|
// }
|
|
|
|
// if(m_UseBackground)
|
|
// {
|
|
// lpPal[0].rgbtRed = GetRValue(m_Background.colour);
|
|
// lpPal[0].rgbtGreen = GetGValue(m_Background.colour);
|
|
// lpPal[0].rgbtBlue = GetBValue(m_Background.colour);
|
|
// }
|
|
//}
|
|
|
|
InterpolateFn CGradient::GetInterpolationProc()
|
|
{
|
|
switch(m_InterpolationMethod)
|
|
{
|
|
case Linear: return InterpolateLinear;
|
|
case FlatStart: return InterpolateFlatStart;
|
|
case FlatMid: return InterpolateFlatMid;
|
|
case FlatEnd: return InterpolateFlatEnd;
|
|
case Cosine: return InterpolateCosine;
|
|
case HSLRedBlue: return InterpolateHSLClockwise;
|
|
case HSLBlueRed: return InterpolateHSLAntiClockwise;
|
|
case HSLShortest: return InterpolateHSLShortest;
|
|
case HSLLongest: return InterpolateHSLLongest;
|
|
case Reverse:
|
|
{
|
|
QVector <CPeg> pegsTemp;
|
|
//CArray <CPeg, CPeg&> pegsTemp;
|
|
int n = pegs.count();
|
|
pegsTemp.clear();
|
|
pegsTemp.resize(n);
|
|
|
|
for (int i=0; i<n; i++)
|
|
{
|
|
pegsTemp[i].colour = pegs[n-i-1].colour;
|
|
}
|
|
|
|
for (int i=0; i<n; i++)
|
|
{
|
|
pegs[i].colour = pegsTemp[i].colour;
|
|
}
|
|
|
|
CPeg temp;
|
|
temp.colour = m_StartPeg.colour;
|
|
m_StartPeg.colour = m_EndPeg.colour;
|
|
m_EndPeg.colour = temp.colour;
|
|
|
|
return InterpolateReverse;
|
|
}
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int CGradient::IndexFromPos(float pos)
|
|
{
|
|
//ASSERT(pos >= 0.0f && pos <= 1.0f);
|
|
if ( pos<0 || pos>1 )
|
|
return NONE;
|
|
// positions betwen 0 and 1!
|
|
|
|
if(pos < pegs[0].position)
|
|
return STARTPEG;
|
|
|
|
for(int i = 0; i < pegs.count()-1; i++)
|
|
if(pos >= pegs[i].position && pos <= pegs[i+1].position)
|
|
return i;
|
|
|
|
return -1; // Eh? somethings wrong here
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateLinear(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
if(start == end) return first;
|
|
if(end - start == 0) return second;
|
|
if(position == start) return first;
|
|
if(position == end) return second;
|
|
return RGB((BYTE)((GetRValue(second)*(position - start) + GetRValue(first)*(end-position))/(end-start)),
|
|
(BYTE)((GetGValue(second)*(position - start) + GetGValue(first)*(end-position))/(end-start)),
|
|
(BYTE)((GetBValue(second)*(position - start) + GetBValue(first)*(end-position))/(end-start)));
|
|
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateReverse(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
if(start == end) return first;
|
|
if(end - start == 0) return second;
|
|
if(position == start) return first;
|
|
if(position == end) return second;
|
|
// return RGB((BYTE)((GetRValue(first)*(position - start) + GetRValue(second)*(end-position))/(end-start)),
|
|
// (BYTE)((GetGValue(first)*(position - start) + GetGValue(second)*(end-position))/(end-start)),
|
|
// (BYTE)((GetBValue(first)*(position - start) + GetBValue(second)*(end-position))/(end-start)));
|
|
|
|
return RGB((BYTE)((GetRValue(second)*(position - start) + GetRValue(first)*(end-position))/(end-start)),
|
|
(BYTE)((GetGValue(second)*(position - start) + GetGValue(first)*(end-position))/(end-start)),
|
|
(BYTE)((GetBValue(second)*(position - start) + GetBValue(first)*(end-position))/(end-start)));
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateFlatStart(COLORREF first, COLORREF, float, float, float)
|
|
{return first;}
|
|
|
|
COLORREF CGradient::InterpolateFlatMid(COLORREF first, COLORREF second, float, float, float)
|
|
{
|
|
unsigned short sr, sg, sb, er, eg, eb;
|
|
sr = GetRValue(first);
|
|
sg = GetGValue(first);
|
|
sb = GetBValue(first);
|
|
er = GetRValue(second);
|
|
eg = GetGValue(second);
|
|
eb = GetBValue(second);
|
|
|
|
return RGB((sr+er)/2, (sg+eg)/2, (sb+eb)/2);
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateFlatEnd(COLORREF, COLORREF second, float, float, float)
|
|
{return second;}
|
|
|
|
COLORREF CGradient::InterpolateCosine(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
float theta = (position-start)/(end-start) * 3.1415927f;
|
|
float f = (1 - cosf(theta)) * .5f;
|
|
|
|
return RGB((BYTE)(((float)GetRValue(first))*(1-f) + ((float)GetRValue(second))*f),
|
|
(BYTE)(((float)GetGValue(first))*(1-f) + ((float)GetGValue(second))*f),
|
|
(BYTE)(((float)GetBValue(first))*(1-f) + ((float)GetBValue(second))*f));
|
|
}
|
|
void RGB_to_HSL (float r, float g, float b, float *h, float *s, float *l)
|
|
{
|
|
float v;
|
|
float m;
|
|
float vm;
|
|
float r2, g2, b2;
|
|
|
|
v = max(r,g);
|
|
v = max(v,b);
|
|
m = min(r,g);
|
|
m = min(m,b);
|
|
|
|
if ((*l = (m + v) / 2.0f) <= 0.0f) return;
|
|
if ((*s = vm = v - m) > 0.0f) {
|
|
*s /= (*l <= 0.5f) ? (v + m ) :
|
|
(2.0f - v - m) ;
|
|
} else
|
|
return;
|
|
|
|
|
|
r2 = (v - r) / vm;
|
|
g2 = (v - g) / vm;
|
|
b2 = (v - b) / vm;
|
|
|
|
if (r == v)
|
|
*h = (g == m ? 5.0f + b2 : 1.0f - g2);
|
|
else if (g == v)
|
|
*h = (b == m ? 1.0f + r2 : 3.0f - b2);
|
|
else
|
|
*h = (r == m ? 3.0f + g2 : 5.0f - r2);
|
|
|
|
*h /= 6.0f;
|
|
}
|
|
|
|
void HSL_to_RGB(float h, float sl, float l, float *r, float *g, float *b)
|
|
{
|
|
float v;
|
|
|
|
v = (l <= 0.5f) ? (l * (1.0f + sl)) : (l + sl - l * sl);
|
|
if (v <= 0) {
|
|
*r = *g = *b = 0.0f;
|
|
} else {
|
|
float m;
|
|
float sv;
|
|
int sextant;
|
|
float fract, vsf, mid1, mid2;
|
|
|
|
m = l + l - v;
|
|
sv = (v - m ) / v;
|
|
h *= 6.0f;
|
|
sextant = (int)h;
|
|
fract = h - sextant;
|
|
vsf = v * sv * fract;
|
|
mid1 = m + vsf;
|
|
mid2 = v - vsf;
|
|
switch (sextant) {
|
|
case 0: *r = v; *g = mid1; *b = m; break;
|
|
case 1: *r = mid2; *g = v; *b = m; break;
|
|
case 2: *r = m; *g = v; *b = mid1; break;
|
|
case 3: *r = m; *g = mid2; *b = v; break;
|
|
case 4: *r = mid1; *g = m; *b = v; break;
|
|
case 5: *r = v; *g = m; *b = mid2; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateHSLClockwise(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
|
|
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
|
|
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
|
|
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
|
|
(float)GetBValue(second)/255.0f, &eh, &es, &el);
|
|
|
|
sh = sh - floorf(sh);
|
|
eh = eh - floorf(eh);
|
|
|
|
//Interpolate H clockwise
|
|
if(eh >= sh) h = (eh*(position - start) + sh*(end-position))/(end-start);
|
|
else h = ((eh + 1.0f)*(position - start) + sh*(end-position))/(end-start);
|
|
h = (h>=1.0f)?h-1.0f:h;
|
|
|
|
s = ((es*(position - start) + ss*(end-position))/(end-start));
|
|
l = ((el*(position - start) + sl*(end-position))/(end-start));
|
|
|
|
HSL_to_RGB(h, s, l, &r, &g, &b);
|
|
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateHSLAntiClockwise(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
|
|
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
|
|
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
|
|
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
|
|
(float)GetBValue(second)/255.0f, &eh, &es, &el);
|
|
|
|
sh = sh - floorf(sh);
|
|
eh = eh - floorf(eh);
|
|
|
|
//Interpolate H anticlockwise
|
|
if(eh <= sh) h = (eh*(position - start) + sh*(end-position))/(end-start);
|
|
else h = ((eh + 1.0f)*(position - start) + sh*(end-position))/(end-start);
|
|
h = (h>=1.0f)?h-1.0f:h;
|
|
|
|
s = ((es*(position - start) + ss*(end-position))/(end-start));
|
|
l = ((el*(position - start) + sl*(end-position))/(end-start));
|
|
|
|
HSL_to_RGB(h, s, l, &r, &g, &b);
|
|
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateHSLLongest(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
|
|
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
|
|
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
|
|
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
|
|
(float)GetBValue(second)/255.0f, &eh, &es, &el);
|
|
|
|
sh = sh - (float)floor(sh);
|
|
eh = eh - (float)floor(eh);
|
|
|
|
//Interpolate H short route
|
|
if(((eh-sh)-floor(eh-sh) < 0.5f)?(eh < sh):(eh >= sh)) h = (eh*(position - start) + sh*(end-position))/(end-start);
|
|
else h = ((eh+(sh>eh?1.0f:-1.0f))*(position - start) + sh*(end-position))/(end-start);
|
|
//TRACE3("sh: %f eh: %f h: %f\n", sh, eh, h);
|
|
|
|
h = h - floorf(h);
|
|
|
|
s = ((es*(position - start) + ss*(end-position))/(end-start));
|
|
l = ((el*(position - start) + sl*(end-position))/(end-start));
|
|
|
|
HSL_to_RGB(h, s, l, &r, &g, &b);
|
|
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
|
|
}
|
|
|
|
COLORREF CGradient::InterpolateHSLShortest(COLORREF first, COLORREF second, float position, float start, float end)
|
|
{
|
|
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
|
|
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
|
|
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
|
|
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
|
|
(float)GetBValue(second)/255.0f, &eh, &es, &el);
|
|
|
|
sh = sh - (float)floor(sh);
|
|
eh = eh - (float)floor(eh);
|
|
|
|
//Interpolate H short route
|
|
if(((eh-sh)-floor(eh-sh) > 0.5f)?(eh < sh):(eh >= sh)) h = (eh*(position - start) + sh*(end-position))/(end-start);
|
|
else h = ((eh+(sh>eh?1.0f:-1.0f))*(position - start) + sh*(end-position))/(end-start);
|
|
//TRACE3("sh: %f eh: %f h: %f\n", sh, eh, h);
|
|
|
|
h = h - floorf(h);
|
|
|
|
s = ((es*(position - start) + ss*(end-position))/(end-start));
|
|
l = ((el*(position - start) + sl*(end-position))/(end-start));
|
|
|
|
HSL_to_RGB(h, s, l, &r, &g, &b);
|
|
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
|
|
}
|
|
|
|
void CGradient::GetColorArray(COLORREF colorArr[])
|
|
{
|
|
float pos;
|
|
|
|
InterpolateFn Interpolate = GetInterpolationProc();
|
|
|
|
//if (pegs.GetSize() > 0)
|
|
if (pegs.count() > 0)
|
|
{
|
|
float firstpegpos = pegs[0].position;
|
|
COLORREF fistpegcolour = pegs[0].colour;
|
|
float lastpegpos = pegs[pegs.count()-1].position;
|
|
COLORREF lastpegcolour = pegs[pegs.count()-1].colour;
|
|
//float lastpegpos = pegs[pegs.GetUpperBound()].position;
|
|
//COLORREF lastpegcolour = pegs[pegs.GetUpperBound()].colour;
|
|
int curpeg;
|
|
|
|
int index; float pos2; COLORREF colour;
|
|
for (index=0,pos=0.0; index<256; index++,pos+=0.003906)
|
|
{
|
|
if(m_Quantization != -1)
|
|
pos2 = ((float)(int)(pos*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
|
|
else pos2 = pos;
|
|
|
|
if (pos2 <= firstpegpos)
|
|
{
|
|
colour = Interpolate(m_StartPeg.colour, pegs[0].colour, pos2, 0, firstpegpos);
|
|
colorArr[index] = colour;
|
|
}
|
|
else if (pos2 > lastpegpos)
|
|
{
|
|
colour = Interpolate(lastpegcolour, m_EndPeg.colour, pos2, lastpegpos, 1);
|
|
colorArr[index] = colour;
|
|
}
|
|
else
|
|
{
|
|
curpeg = IndexFromPos2(pos2);
|
|
colour = Interpolate(pegs[curpeg].colour, pegs[curpeg+1].colour, pos2, pegs[curpeg].position, pegs[curpeg+1].position);
|
|
colorArr[index] = colour;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
else //pegs.size == 0
|
|
{
|
|
int index; float pos2; COLORREF colour;
|
|
for (index=0,pos=0.0; index<256; index++,pos+=0.003906)
|
|
{
|
|
if (m_Quantization != -1)
|
|
pos2 = ((float)(int)(pos*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
|
|
else pos2 = pos;
|
|
|
|
colour = Interpolate(m_StartPeg.colour, m_EndPeg.colour, pos2, 0, 1);
|
|
colorArr[index] = colour;
|
|
}
|
|
|
|
}
|
|
}
|
|
int CGradient::IndexFromPos2(float pos)
|
|
{
|
|
int begin = 0;
|
|
//int end = pegs.GetSize()-1;
|
|
int end = pegs.count()-1;
|
|
int mid;
|
|
|
|
while(begin <= end)
|
|
{
|
|
mid = (begin + end) / 2;
|
|
if (pos > pegs[mid].position)
|
|
{
|
|
begin = mid+1;
|
|
}
|
|
else
|
|
{
|
|
end = mid-1;
|
|
}
|
|
}
|
|
|
|
// if (mid==0)
|
|
// mid =1;
|
|
return end;
|
|
}
|
|
//读取配色方案
|
|
void CGradient::Serialize(QString strCfg)//CArchive &ar)
|
|
{
|
|
//lhj 2019-8-14 配色文件转换成TXT格式
|
|
// 保存为TXT格式
|
|
// strCfg.TrimLeft();
|
|
// strCfg.TrimRight();
|
|
strCfg.trimmed();
|
|
|
|
int i,n;
|
|
char str[256],strName[256];
|
|
//CString strCipPath;
|
|
CPeg peg;
|
|
|
|
//GetBinDir(str);
|
|
memset(str, '\0', sizeof (str));
|
|
strcat(str, QCoreApplication::applicationDirPath().toStdString().c_str());
|
|
strcat(str,"\\color\\");
|
|
strcat(str,strCfg.toStdString().c_str());
|
|
//strcat(str,"_clr.cfg");
|
|
|
|
FILE *fp;
|
|
fp=fopen(str,"r");
|
|
if ( fp!=NULL)
|
|
{
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%s",str);
|
|
//m_FileFlag.Format("%s",str);
|
|
m_FileFlag = str;
|
|
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%ld",&m_Background.colour);
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%ld %ld",&m_StartPeg.colour,&m_EndPeg.colour);
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%d",&i);
|
|
m_UseBackground=i;
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%d",&m_Quantization);
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%d",&m_InterpolationMethod);
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%d",&n);
|
|
pegs.clear();
|
|
for( i = 0; i < n; i++)
|
|
{
|
|
fgets(strName,256,fp);
|
|
sscanf(strName,"%ld %g",&peg.colour,&peg.position);
|
|
pegs.append(peg);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|