📄 gradient.cpp
字号:
#include "stdafx.h"
#include "Gradient.h"
#include <math.h>
IMPLEMENT_SERIAL(CGradient, CObject, 0)
IMPLEMENT_SERIAL(CPeg, CObject, 0)
UINT CPeg::uniqueID = 0;
//------------------------------------------------------------
CPeg::CPeg()
{
id = uniqueID;
uniqueID++;
colour = 0x00000000;
position = 0.0f;
}
CPeg::CPeg(const CPeg &src)
{
colour = src.colour;
position = src.position;
id = src.id;
}
CPeg & CPeg::operator = (const CPeg &src)
{
colour = src.colour;
position = src.position;
id = src.id;
return *this;
}
void CPeg::Serialize(CArchive &ar)
{
if(ar.IsLoading())
{
ar >> colour;
ar >> position;
id = uniqueID;
uniqueID++;
}
else
{
ar << colour;
ar << position;
}
}
//-------------------------------------------------------------
CGradient::CGradient()
{
m_StartPeg.colour = 0x00000000;
m_StartPeg.position = 0.0f;
m_EndPeg.colour = 0x00FFFFFF;
m_EndPeg.position = 1.0f;
m_Background.colour = 0x00000000; //A default pal
m_Background.position = 0.0f;
m_InterpolationMethod = Cosine;
m_UseBackground = false;
m_Quantization = -1;
}
CGradient::CGradient(CGradient &src)
{
m_StartPeg.colour = m_StartPeg.colour;
m_EndPeg.colour = m_EndPeg.colour;
m_Background.colour = m_Background.colour;
m_InterpolationMethod = src.m_InterpolationMethod;
m_UseBackground = src.m_UseBackground;
m_Quantization = src.m_Quantization;
pegs.RemoveAll();
for(int i = 0; i < src.pegs.GetSize(); i++)
{
pegs.Add(src.pegs[i]);
}
}
CGradient::~CGradient()
{
pegs.RemoveAll();
}
CGradient& CGradient::operator =(CGradient &src)
{
pegs.RemoveAll();
for(int i = 0; i < src.pegs.GetSize(); i++)
{
pegs.Add(src.pegs[i]);
}
m_StartPeg.colour = m_StartPeg.colour;
m_EndPeg.colour = m_EndPeg.colour;
m_Background.colour = m_Background.colour;
m_InterpolationMethod = src.m_InterpolationMethod;
m_UseBackground = src.m_UseBackground;
m_Quantization = src.m_Quantization;
return *this;
}
int CGradient::AddPeg(COLORREF crColour, float fPosition)
{
CPeg peg;
if(fPosition < 0)
fPosition = 0;
else if(fPosition > 1)
fPosition = 1;
peg.colour = crColour;
peg.position = fPosition;
pegs.Add(peg);
SortPegs();
return IndexFromId(peg.GetID());
}
int CGradient::AddPeg(CPeg peg)
{
return AddPeg(peg.colour, peg.position);
}
//----- Assorted short functions -----//
void CGradient::RemovePeg(int iIndex) {pegs.RemoveAt(iIndex);}
void CGradient::SortPegs() {QuickSort(0, pegs.GetUpperBound());}
int CGradient::GetPegCount() const {return pegs.GetSize();}
const CPeg CGradient::GetPeg(int iIndex) const
{
ASSERT(iIndex > -4 && iIndex != -1 && iIndex < GetPegCount());
//You must pass a valid peg index or STARTPEG, ENDPEG, or BACKGROUND!
if(iIndex >= 0)
{
const CPeg peg(pegs[iIndex]);
return peg;
}
else if(iIndex == STARTPEG)
return m_StartPeg;
else if(iIndex == ENDPEG)
return m_EndPeg;
else return m_Background;
}
int CGradient::SetPeg(int iIndex, COLORREF crColour, float fPosition)
{
UINT tempid;
ASSERT(iIndex > -4 && iIndex != -1 && iIndex < GetPegCount());
//You must pass a valid peg index or STARTPEG, ENDPEG, or BACKGROUND!
if(fPosition < 0) fPosition = 0;
else if(fPosition > 1) fPosition = 1;
if(iIndex == STARTPEG)
m_StartPeg.colour = crColour;
else if(iIndex == ENDPEG)
m_EndPeg.colour = crColour;
else if(iIndex == BACKGROUND)
m_Background.colour = crColour;
else
{
pegs[iIndex].colour = crColour;
pegs[iIndex].position = fPosition;
tempid = pegs[iIndex].GetID();
SortPegs();
return IndexFromId(tempid);
}
return -1;
}
int CGradient::SetPeg(int iIndex, CPeg peg)
{
UINT tempid;
ASSERT(iIndex > -4 && iIndex != -1 && iIndex < GetPegCount());
//You must pass a valid peg index or STARTPEG, ENDPEG, or BACKGROUND!
if(peg.position < 0.0f) peg.position = 0.0f;
else if(peg.position > 1.0f) peg.position = 1.0f;
if(iIndex == STARTPEG)
m_StartPeg.colour = peg.colour;
else if(iIndex == ENDPEG)
m_EndPeg.colour = peg.colour;
else if(iIndex == BACKGROUND)
m_Background.colour = peg.colour;
else
{
pegs[iIndex].colour = peg.colour;
pegs[iIndex].position = peg.position;
tempid = pegs[iIndex].GetID();
SortPegs();
return IndexFromId(tempid);
}
return -1;
}
void CGradient::Make8BitPalette(RGBTRIPLE *lpPal)
{
MakeEntries(lpPal, 256);
}
void CGradient::MakePalette(CPalette *lpPal)
{
RGBTRIPLE *entries = new RGBTRIPLE[256];
LOGPALETTE *logpal;
logpal = (LOGPALETTE*)malloc(2*sizeof(WORD) + 256*sizeof(PALETTEENTRY));
lpPal->DeleteObject();
Make8BitPalette(entries);
logpal->palVersion = 0x300;
logpal->palNumEntries = 256;
for(int i = 0; i < 256; i++)
{
logpal->palPalEntry[i].peRed = entries[i].rgbtRed;
logpal->palPalEntry[i].peGreen = entries[i].rgbtGreen;
logpal->palPalEntry[i].peBlue = entries[i].rgbtBlue;
logpal->palPalEntry[i].peFlags = PC_RESERVED;
}
delete[] entries;
lpPal->CreatePalette(logpal);
free(logpal);
}
void CGradient::MakeEntries(RGBTRIPLE *lpPal, int iEntryCount)
{
float pos;
COLORREF colour;
ASSERT(iEntryCount > 1);
ASSERT(iEntryCount < 65535);
InterpolateFn Interpolate = GetInterpolationProc();
ASSERT(Interpolate != NULL);
if(pegs.GetSize() > 0)
{
//Some things are already constant and so can be found early
float firstpegpos = pegs[0].position;
float lastpegpos = pegs[pegs.GetUpperBound()].position;
COLORREF lastpegcolour = pegs[pegs.GetUpperBound()].colour;
int curpeg;
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);
}
}
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 second;
if(position == end) return first;
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)));
}
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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -