#ifndef TVISION_COLORS_H
#define TVISION_COLORS_H
#ifdef __BORLANDC__
inline
TColorDesired getFore(
const
TColorAttr &attr)
{
return
uchar(attr & 0xF);
}
inline
TColorDesired getBack(
const
TColorAttr &attr)
{
return
uchar(attr >> 4);
}
inline
void
setFore(TColorAttr &attr, TColorDesired color)
{
attr = uchar(attr & 0xF0) | uchar(color & 0xF);
}
inline
void
setBack(TColorAttr &attr, TColorDesired color)
{
attr = uchar(attr & 0xF) | uchar(color << 4);
}
inline
TColorAttr reverseAttribute(TColorAttr attr)
{
return
uchar(attr << 4) | uchar(attr >> 4);
}
#else // __BORLANDC__
#include <string.h>
struct
TColorRGB
{
uint32_t
#ifndef TV_BIG_ENDIAN
b : 8,
g : 8,
r : 8,
_unused : 8;
#else
_unused : 8,
r : 8,
g : 8,
b : 8;
#endif
TV_TRIVIALLY_CONVERTIBLE(TColorRGB, uint32_t, 0xFFFFFF)
constexpr
inline
TColorRGB(uint8_t r, uint8_t g, uint8_t b);
};
constexpr
inline
TColorRGB::TColorRGB(uint8_t r, uint8_t g, uint8_t b) :
#ifndef TV_BIG_ENDIAN
b(b),
g(g),
r(r),
_unused(0)
#else
_unused(0),
r(r),
g(g),
b(b)
#endif
{
}
struct
TColorBIOS
{
uint8_t
#ifndef TV_BIG_ENDIAN
b : 1,
g : 1,
r : 1,
bright : 1,
_unused : 4;
#else
_unused : 4,
bright : 1,
r : 1,
g : 1,
b : 1;
#endif
TV_TRIVIALLY_CONVERTIBLE(TColorBIOS, uint8_t, 0xF)
};
struct
TColorXTerm
{
uint8_t idx;
TV_TRIVIALLY_CONVERTIBLE(TColorXTerm, uint8_t, 0xFF)
};
inline
uint8_t BIOStoXTerm16(TColorBIOS);
inline
TColorBIOS RGBtoBIOS(TColorRGB);
inline
uint8_t RGBtoXTerm16(TColorRGB);
inline
uint8_t RGBtoXTerm256(TColorRGB);
inline
TColorBIOS XTerm16toBIOS(uint8_t);
inline
TColorRGB XTerm256toRGB(uint8_t);
inline
uint8_t XTerm256toXTerm16(uint8_t);
namespace
tvision
{
template
<
class
T,
size_t
N>
struct
constarray;
uint8_t RGBtoXTerm16Impl(TColorRGB)
noexcept
;
extern
const
constarray<uint8_t, 256> XTerm256toXTerm16LUT;
extern
const
constarray<uint32_t, 256> XTerm256toRGBLUT;
}
inline
uint8_t BIOStoXTerm16(TColorBIOS c)
{
uchar aux = c.b;
c.b = c.r;
c.r = aux;
return
c;
}
inline
TColorBIOS RGBtoBIOS(TColorRGB c)
{
return
XTerm16toBIOS(RGBtoXTerm16(c));
}
inline
uint8_t RGBtoXTerm16(TColorRGB c)
{
using
namespace
tvision;
return
RGBtoXTerm16Impl(c);
}
inline
uint8_t RGBtoXTerm256(TColorRGB c)
{
auto
cnvColor = [] (TColorRGB c)
{
auto
scale = [] (uchar c)
{
c += 20 & -(c < 75);
return
uchar(max<uchar>(c, 35) - 35)/40;
};
uchar r = scale(c.r),
g = scale(c.g),
b = scale(c.b);
return
16 + uchar(r*uchar(6) + g)*uchar(6) + b;
};
auto
cnvGray = [] (uchar l)
{
if
(l < 8 - 5)
return
16;
if
(l >= 238 + 5)
return
231;
return
232 + uchar(max<uchar>(l, 3) - 3)/uchar(10);
};
uchar idx = cnvColor(c);
if
(c != XTerm256toRGB(idx))
{
uchar Xmin = min(min(c.r, c.g), c.b),
Xmax = max(max(c.r, c.g), c.b);
uchar C = Xmax - Xmin;
if
(C < 12 || idx == 16)
{
uchar L = ushort(Xmax + Xmin)/2;
idx = cnvGray(L);
}
}
return
idx;
}
inline
TColorBIOS XTerm16toBIOS(uint8_t idx)
{
return
BIOStoXTerm16(idx);
}
inline
uint8_t XTerm256toXTerm16(uint8_t idx)
{
using
namespace
tvision;
return
((
const
uint8_t (&) [256]) XTerm256toXTerm16LUT)[idx];
}
inline
TColorRGB XTerm256toRGB(uint8_t idx)
{
using
namespace
tvision;
return
((
const
uint32_t (&) [256]) XTerm256toRGBLUT)[idx];
}
const
uchar
ctDefault = 0x0,
ctBIOS = 0x1,
ctRGB = 0x2,
ctXTerm = 0x3;
struct
TColorDesired
{
uint32_t _data;
TColorDesired() =
default
;
constexpr
inline
TColorDesired(
char
bios);
constexpr
inline
TColorDesired(uchar bios);
constexpr
inline
TColorDesired(
int
rgb);
inline
TColorDesired(TColorBIOS bios);
inline
TColorDesired(TColorRGB rgb);
inline
TColorDesired(TColorXTerm xterm);
TV_TRIVIALLY_ASSIGNABLE(TColorDesired)
constexpr
inline
uchar type()
const
;
constexpr
inline
bool
isDefault()
const
;
constexpr
inline
bool
isBIOS()
const
;
constexpr
inline
bool
isRGB()
const
;
constexpr
inline
bool
isXTerm()
const
;
inline
TColorBIOS asBIOS()
const
;
inline
TColorRGB asRGB()
const
;
inline
TColorXTerm asXTerm()
const
;
inline
TColorBIOS toBIOS(
bool
isForeground)
const
;
inline
bool
operator==(TColorDesired other)
const
;
inline
bool
operator!=(TColorDesired other)
const
;
constexpr
inline
uint32_t bitCast()
const
;
constexpr
inline
void
bitCast(uint32_t val);
};
constexpr
inline
TColorDesired::TColorDesired(
char
bios) :
TColorDesired(uchar(bios))
{
}
constexpr
inline
TColorDesired::TColorDesired(uchar bios) :
_data((bios & 0xF) | (ctBIOS << 24))
{
}
constexpr
inline
TColorDesired::TColorDesired(
int
rgb) :
_data((rgb & 0xFFFFFF) | (ctRGB << 24))
{
}
inline
TColorDesired::TColorDesired(TColorBIOS bios) :
TColorDesired(uchar(bios))
{
}
inline
TColorDesired::TColorDesired(TColorRGB rgb) :
TColorDesired(
int
(rgb))
{
}
inline
TColorDesired::TColorDesired(TColorXTerm xterm) :
_data(xterm | (ctXTerm << 24))
{
}
constexpr
inline
uchar TColorDesired::type()
const
{
return
_data >> 24;
}
constexpr
inline
bool
TColorDesired::isDefault()
const
{
return
type() == ctDefault;
}
constexpr
inline
bool
TColorDesired::isBIOS()
const
{
return
type() == ctBIOS;
}
constexpr
inline
bool
TColorDesired::isRGB()
const
{
return
type() == ctRGB;
}
constexpr
inline
bool
TColorDesired::isXTerm()
const
{
return
type() == ctXTerm;
}
inline
TColorBIOS TColorDesired::asBIOS()
const
{
return
_data;
}
inline
TColorRGB TColorDesired::asRGB()
const
{
return
_data;
}
inline
TColorXTerm TColorDesired::asXTerm()
const
{
return
_data;
}
inline
TColorBIOS TColorDesired::toBIOS(
bool
isForeground)
const
{
switch
(type())
{
case
ctBIOS:
return
asBIOS();
case
ctRGB:
return
RGBtoBIOS(asRGB());
case
ctXTerm:
{
uint8_t idx = asXTerm();
if
(idx >= 16)
idx = XTerm256toXTerm16(idx);
return
XTerm16toBIOS(idx);
}
default
:
return
isForeground ? 0x7 : 0x0;
}
}
inline
bool
TColorDesired::operator==(TColorDesired other)
const
{
return
memcmp
(
this
, &other,
sizeof
(*
this
)) == 0;
}
inline
bool
TColorDesired::operator!=(TColorDesired other)
const
{
return
!(*
this
== other);
}
constexpr
inline
uint32_t TColorDesired::bitCast()
const
{
return
_data;
}
constexpr
inline
void
TColorDesired::bitCast(uint32_t val)
{
_data = val;
}
const
ushort
slBold = 0x001,
slItalic = 0x002,
slUnderline = 0x004,
slBlink = 0x008,
slReverse = 0x010,
slStrike = 0x020,
slNoShadow = 0x200;
struct
TAttrPair;
struct
TColorAttr
{
using
Style = ushort;
uint64_t
_style : 10,
_fg : 27,
_bg : 27;
TColorAttr() =
default
;
constexpr
inline
TColorAttr(
int
bios);
constexpr
inline
TColorAttr(TColorDesired fg, TColorDesired bg, ushort style=0);
inline
TColorAttr(
const
TAttrPair &attrs);
TV_TRIVIALLY_ASSIGNABLE(TColorAttr)
inline
bool
isBIOS()
const
;
inline
uchar asBIOS()
const
;
inline
uchar toBIOS()
const
;
inline
operator uchar()
const
;
inline
TAttrPair operator<<(
int
shift)
const
;
inline
bool
operator==(
const
TColorAttr &other)
const
;
inline
bool
operator!=(
const
TColorAttr &other)
const
;
inline
bool
operator==(
int
bios)
const
;
inline
bool
operator!=(
int
bios)
const
;
};
constexpr
inline
TColorDesired getFore(
const
TColorAttr &attr);
constexpr
inline
TColorDesired getBack(
const
TColorAttr &attr);
constexpr
inline
ushort getStyle(
const
TColorAttr &attr);
constexpr
inline
void
setFore(TColorAttr &attr, TColorDesired fg);
constexpr
inline
void
setBack(TColorAttr &attr, TColorDesired bg);
constexpr
inline
void
setStyle(TColorAttr &attr, ushort style);
constexpr
inline
TColorAttr reverseAttribute(TColorAttr attr);
constexpr
inline
TColorAttr::TColorAttr(
int
bios) :
_style(0),
_fg(TColorDesired(uchar(bios)).bitCast()),
_bg(TColorDesired(uchar(bios >> 4)).bitCast())
{
}
constexpr
inline
TColorAttr::TColorAttr(TColorDesired fg, TColorDesired bg, ushort style) :
_style(style),
_fg(fg.bitCast()),
_bg(bg.bitCast())
{
}
inline
bool
TColorAttr::isBIOS()
const
{
return
(
int
) ::getFore(*
this
).isBIOS() & ::getBack(*
this
).isBIOS() & !::getStyle(*
this
);
}
inline
uchar TColorAttr::asBIOS()
const
{
uchar bios = uchar(_fg) | uchar(_bg << 4);
return
isBIOS() ? bios : 0x5F;
}
inline
uchar TColorAttr::toBIOS()
const
{
auto
fg = ::getFore(*
this
),
bg = ::getBack(*
this
);
return
fg.toBIOS(
true
) | (bg.toBIOS(
false
) << 4);
}
inline
TColorAttr::operator uchar()
const
{
return
asBIOS();
}
inline
bool
TColorAttr::operator==(
const
TColorAttr &other)
const
{
return
memcmp
(
this
, &other,
sizeof
(*
this
)) == 0;
}
inline
bool
TColorAttr::operator!=(
const
TColorAttr &other)
const
{
return
!(*
this
== other);
}
inline
bool
TColorAttr::operator==(
int
bios)
const
{
return
*
this
== TColorAttr {(uchar) bios};
}
inline
bool
TColorAttr::operator!=(
int
bios)
const
{
return
!(*
this
== bios);
}
constexpr
inline
TColorDesired getFore(
const
TColorAttr &attr)
{
TColorDesired color {};
color.bitCast(attr._fg);
return
color;
}
constexpr
inline
TColorDesired getBack(
const
TColorAttr &attr)
{
TColorDesired color {};
color.bitCast(attr._bg);
return
color;
}
constexpr
inline
ushort getStyle(
const
TColorAttr &attr)
{
return
attr._style;
}
constexpr
inline
void
setFore(TColorAttr &attr, TColorDesired color)
{
attr._fg = color.bitCast();
}
constexpr
inline
void
setBack(TColorAttr &attr, TColorDesired color)
{
attr._bg = color.bitCast();
}
constexpr
inline
void
setStyle(TColorAttr &attr, ushort style)
{
attr._style = style;
}
constexpr
inline
TColorAttr reverseAttribute(TColorAttr attr)
{
auto
fg = ::getFore(attr),
bg = ::getBack(attr);
if
((
int
) fg.isDefault() | bg.isDefault())
::setStyle(attr, ::getStyle(attr) ^ slReverse);
else
{
::setFore(attr, bg);
::setBack(attr, fg);
}
return
attr;
}
struct
TAttrPair
{
TColorAttr _attrs[2];
TAttrPair() =
default
;
constexpr
inline
TAttrPair(
int
bios);
constexpr
inline
TAttrPair(
const
TColorAttr &lo,
const
TColorAttr &hi=uchar(0));
TV_TRIVIALLY_ASSIGNABLE(TAttrPair)
inline
ushort asBIOS()
const
;
inline
operator ushort()
const
;
inline
TAttrPair operator>>(
int
shift)
const
;
inline
TAttrPair& operator|=(TColorAttr attr);
inline
TColorAttr& operator[](
size_t
i);
inline
const
TColorAttr& operator[](
size_t
i)
const
;
};
constexpr
inline
TAttrPair::TAttrPair(
int
bios) :
_attrs {uchar(bios & 0xFF), uchar(bios >> 8)}
{
}
constexpr
inline
TAttrPair::TAttrPair(
const
TColorAttr &lo,
const
TColorAttr &hi) :
_attrs {lo, hi}
{
}
inline
ushort TAttrPair::asBIOS()
const
{
return
_attrs[0].asBIOS() | ushort(_attrs[1].asBIOS() << 8);
}
inline
TAttrPair::operator ushort()
const
{
return
asBIOS();
}
inline
TAttrPair TAttrPair::operator>>(
int
shift)
const
{
if
(shift == 8)
return
{_attrs[1]};
return
asBIOS() >> shift;
}
inline
TAttrPair& TAttrPair::operator|=(TColorAttr attr)
{
_attrs[0] = attr;
return
*
this
;
}
inline
TColorAttr& TAttrPair::operator[](
size_t
i)
{
return
_attrs[i];
}
inline
const
TColorAttr& TAttrPair::operator[](
size_t
i)
const
{
return
_attrs[i];
}
inline
TColorAttr::TColorAttr(
const
TAttrPair &attrs)
{
*
this
= attrs[0];
}
inline
TAttrPair TColorAttr::operator<<(
int
shift)
const
{
if
(shift == 8)
return
{uchar(0), *
this
};
return
asBIOS() << shift;
}
#endif // __BORLANDC__
#endif // TVISION_COLORS_H