mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
9 Commits
62319ad136
...
1825d9bd8c
Author | SHA1 | Date |
---|---|---|
|
1825d9bd8c | |
|
f8531bc64b | |
|
1a967aad95 | |
|
fb7c5e04cf | |
|
504a26a60a | |
|
6b330da74e | |
|
bec34c38f7 | |
|
79a2af5d44 | |
|
36d14669c5 |
|
@ -36,7 +36,8 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left;
|
||||
uint16_t *anim = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
|
||||
|
||||
const uint8_t *remap = bp->remap; // store so we don't have to access it via bp every time
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap(); // store so we don't have to access it via bp every time
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
Colour *dst_ln = dst + bp->pitch;
|
||||
|
@ -135,6 +136,43 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (m == 0) {
|
||||
*dst = src_px->data;
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[GB(m, 0, 8)];
|
||||
*anim = 0;
|
||||
*dst = AdjustBrightness(c, GB(m, 8, 8));
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
if (m == 0) {
|
||||
*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[GB(m, 0, 8)];
|
||||
*anim = 0;
|
||||
*dst = ComposeColourPANoCheck(AdjustBrightness(c, GB(m, 8, 8)), c.a * src_px->a / 255, *dst);
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::CrashRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
|
@ -273,6 +311,7 @@ void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
|
|||
default: NOT_REACHED();
|
||||
case BlitterMode::Normal: Draw<BlitterMode::Normal>(bp, zoom); return;
|
||||
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap>(bp, zoom); return;
|
||||
|
@ -323,7 +362,7 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
|||
|
||||
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||
{
|
||||
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
|
||||
*((Colour *)video + x + y * _screen.pitch) = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
|
||||
|
||||
/* Set the colour in the anim-buffer too, if we are rendering to the screen */
|
||||
if (_screen_disable_anim) return;
|
||||
|
@ -333,7 +372,7 @@ void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
|
|||
|
||||
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
|
||||
{
|
||||
const Colour c = LookupColourInPalette(colour.p);
|
||||
const Colour c = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
|
||||
|
||||
if (_screen_disable_anim) {
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
||||
|
@ -357,7 +396,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, PixelColour
|
|||
return;
|
||||
}
|
||||
|
||||
Colour colour32 = LookupColourInPalette(colour.p);
|
||||
Colour colour32 = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
|
||||
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
|
||||
|
||||
do {
|
||||
|
|
|
@ -33,7 +33,7 @@ template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bpp
|
|||
GNU_TARGET("sse4.1")
|
||||
inline void Blitter_32bppSSE4_Anim::Draw(const BlitterParams *bp, ZoomLevel zoom)
|
||||
{
|
||||
const uint8_t * const remap = bp->remap;
|
||||
const uint8_t * const remap = bp->remap->GetPaletteRemap();
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
uint16_t *anim_line = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
|
|
@ -20,12 +20,13 @@ void *Blitter_32bppBase::MoveTo(void *video, int x, int y)
|
|||
|
||||
void Blitter_32bppBase::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||
{
|
||||
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
|
||||
const Colour c = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
}
|
||||
|
||||
void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
|
||||
{
|
||||
const Colour c = LookupColourInPalette(colour.p);
|
||||
const Colour c = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
});
|
||||
|
@ -33,7 +34,7 @@ void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int
|
|||
|
||||
void Blitter_32bppBase::DrawRect(void *video, int width, int height, PixelColour colour)
|
||||
{
|
||||
Colour colour32 = LookupColourInPalette(colour.p);
|
||||
Colour colour32 = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
|
||||
|
||||
do {
|
||||
Colour *dst = (Colour *)video;
|
||||
|
|
|
@ -48,7 +48,8 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
|
|||
Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left;
|
||||
|
||||
/* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */
|
||||
const uint8_t *remap = bp->remap;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
/* next dst line begins here */
|
||||
|
@ -142,6 +143,37 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (m == 0) {
|
||||
*dst = src_px->data;
|
||||
} else {
|
||||
const Colour c = remap_rgba[GB(m, 0, 8)];
|
||||
*dst = AdjustBrightness(c, GB(m, 8, 8));
|
||||
}
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
do {
|
||||
uint m = *src_n;
|
||||
if (m == 0) {
|
||||
*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
|
||||
} else {
|
||||
const Colour c = remap_rgba[GB(m, 0, 8)];
|
||||
*dst = ComposeColourPANoCheck(AdjustBrightness(c, GB(m, 8, 8)), src_px->a, *dst);
|
||||
}
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::CrashRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
|
@ -263,6 +295,7 @@ void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode,
|
|||
default: NOT_REACHED();
|
||||
case BlitterMode::Normal: Draw<BlitterMode::Normal, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, Tpal_to_rgb>(bp, zoom); return;
|
||||
|
|
|
@ -23,6 +23,8 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
|
|||
{
|
||||
const Blitter_32bppSimple::Pixel *src, *src_line;
|
||||
Colour *dst, *dst_line;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
/* Find where to start reading in the source sprite */
|
||||
src_line = (const Blitter_32bppSimple::Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom);
|
||||
|
@ -42,7 +44,19 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
|
|||
if (src->m == 0) {
|
||||
if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
|
||||
} else {
|
||||
if (bp->remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst);
|
||||
if (remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(remap[src->m]), src->v), src->a, *dst);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way */
|
||||
if (src->m == 0) {
|
||||
if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
|
||||
} else {
|
||||
const Colour &c = remap_rgba[src->m];
|
||||
if (c.a != 0) {
|
||||
*dst = ComposeColourPA(AdjustBrightness(c, src->v), src->a, *dst);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -53,7 +67,7 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
|
|||
*dst = ComposeColourRGBA(g, g, g, src->a, *dst);
|
||||
}
|
||||
} else {
|
||||
if (bp->remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst);
|
||||
if (remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(remap[src->m]), src->v), src->a, *dst);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -73,7 +87,7 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
|
|||
case BlitterMode::TransparentRemap:
|
||||
/* Apply custom transparency remap. */
|
||||
if (src->a != 0) {
|
||||
*dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]);
|
||||
*dst = this->LookupColourInPalette(remap[GetNearestColourIndex(*dst)]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ inline void Blitter_32bppSSSE3::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
|
||||
#endif
|
||||
{
|
||||
const uint8_t * const remap = bp->remap;
|
||||
const uint8_t * const remap = bp->remap->GetPaletteRemap();
|
||||
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
|
||||
int effective_width = bp->width;
|
||||
|
||||
|
|
|
@ -32,10 +32,14 @@ void Blitter_40bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
|
|||
if (_screen_disable_anim) {
|
||||
Blitter_32bppOptimized::SetPixel(video, x, y, colour);
|
||||
} else {
|
||||
size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
|
||||
*((Colour *)video + x + y_offset) = _black_colour;
|
||||
bool has_rgb = colour.HasRGB();
|
||||
const Colour colour32 = has_rgb ? colour.ToColour() : _black_colour;
|
||||
const uint8_t colour8 = has_rgb ? 0 : colour.p;
|
||||
|
||||
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour.p;
|
||||
size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
|
||||
*((Colour *)video + x + y_offset) = colour32;
|
||||
|
||||
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour8;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +51,10 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, PixelColour
|
|||
return;
|
||||
}
|
||||
|
||||
bool has_rgb = colour.HasRGB();
|
||||
const Colour colour32 = has_rgb ? colour.ToColour() : _black_colour;
|
||||
const uint8_t colour8 = has_rgb ? 0 : colour.p;
|
||||
|
||||
assert(VideoDriver::GetInstance()->GetAnimBuffer() != nullptr);
|
||||
uint8_t *anim_line = ((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + VideoDriver::GetInstance()->GetAnimBuffer();
|
||||
|
||||
|
@ -55,8 +63,8 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, PixelColour
|
|||
uint8_t *anim = anim_line;
|
||||
|
||||
for (int i = width; i > 0; i--) {
|
||||
*dst = _black_colour;
|
||||
*anim = colour.p;
|
||||
*dst = colour32;
|
||||
*anim = colour8;
|
||||
dst++;
|
||||
anim++;
|
||||
}
|
||||
|
@ -73,12 +81,16 @@ void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
|
|||
return;
|
||||
}
|
||||
|
||||
bool has_rgb = colour.HasRGB();
|
||||
const Colour colour32 = has_rgb ? colour.ToColour() : _black_colour;
|
||||
const uint8_t colour8 = has_rgb ? 0 : colour.p;
|
||||
|
||||
assert(VideoDriver::GetInstance()->GetAnimBuffer() != nullptr);
|
||||
uint8_t *anim = ((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + VideoDriver::GetInstance()->GetAnimBuffer();
|
||||
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||
*((Colour *)video + x + y * _screen.pitch) = _black_colour;
|
||||
*(anim + x + y * _screen.pitch) = colour.p;
|
||||
*((Colour *)video + x + y * _screen.pitch) = colour32;
|
||||
*(anim + x + y * _screen.pitch) = colour8;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -114,7 +126,8 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
uint8_t *anim = VideoDriver::GetInstance()->GetAnimBuffer() + ((uint32_t *)bp->dst - (uint32_t *)_screen.dst_ptr) + bp->top * bp->pitch + bp->left;
|
||||
|
||||
/* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */
|
||||
const uint8_t *remap = bp->remap;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
|
||||
|
||||
for (int y = 0; y < bp->height; y++) {
|
||||
/* next dst line begins here */
|
||||
|
@ -225,6 +238,49 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
|||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::RGBAColourRemap:
|
||||
if (src_px->a == 255) {
|
||||
do {
|
||||
uint8_t m = GB(*src_n, 0, 8);
|
||||
/* In case the m-channel is zero, only apply the crash remap by darkening the RGB colour. */
|
||||
if (m == 0) {
|
||||
*dst = *src_px;
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[GB(m, 0, 8)];
|
||||
if (c.a != 0) {
|
||||
*dst = ComposeColourRGBANoCheck(c.r, c.g, c.b, c.a, *dst);
|
||||
*anim = 0;
|
||||
}
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
} else {
|
||||
do {
|
||||
uint8_t m = GB(*src_n, 0, 8);
|
||||
Colour b = this->RealizeBlendedColour(*anim, *dst);
|
||||
if (m == 0) {
|
||||
Colour c = *src_px;
|
||||
*dst = this->ComposeColourRGBANoCheck(c.r, c.g, c.b, src_px->a / 255, b);
|
||||
*anim = 0;
|
||||
} else {
|
||||
const Colour &c = remap_rgba[m];
|
||||
if (c.a != 0) {
|
||||
*dst = this->ComposeColourPANoCheck(c, c.a * src_px->a / 255, b);
|
||||
*anim = 0; // Animation colours don't work with alpha-blending.
|
||||
}
|
||||
}
|
||||
anim++;
|
||||
dst++;
|
||||
src_px++;
|
||||
src_n++;
|
||||
} while (--n != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BlitterMode::BlackRemap:
|
||||
do {
|
||||
*anim++ = 0;
|
||||
|
@ -341,6 +397,7 @@ void Blitter_40bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
|
|||
default: NOT_REACHED();
|
||||
case BlitterMode::Normal: Draw<BlitterMode::Normal>(bp, zoom); return;
|
||||
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap>(bp, zoom); return;
|
||||
|
@ -374,7 +431,8 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
|||
anim = anim - width + _screen.pitch;
|
||||
} while (--height);
|
||||
} else if (pal == PALETTE_NEWSPAPER) {
|
||||
const uint8_t *remap = GetNonSprite(pal, SpriteType::Recolour) + 1;
|
||||
const RecolourSprite *rs = GetRecolourSprite(pal);
|
||||
const uint8_t *remap = rs->GetPaletteRemap();
|
||||
do {
|
||||
for (int i = 0; i != width; i++) {
|
||||
if (*anim == 0) {
|
||||
|
@ -389,7 +447,8 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
|||
anim = anim - width + _screen.pitch;
|
||||
} while (--height);
|
||||
} else {
|
||||
const uint8_t *remap = GetNonSprite(pal, SpriteType::Recolour) + 1;
|
||||
const RecolourSprite *rs = GetRecolourSprite(pal);
|
||||
const uint8_t *remap = rs->GetPaletteRemap();
|
||||
do {
|
||||
for (int i = 0; i != width; i++) {
|
||||
if (*anim != 0) *anim = remap[*anim];
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
void Blitter_8bppBase::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal)
|
||||
{
|
||||
const uint8_t *ctab = GetNonSprite(pal, SpriteType::Recolour) + 1;
|
||||
const uint8_t *ctab = GetRecolourSprite(pal)->GetPaletteRemap();
|
||||
|
||||
do {
|
||||
for (int i = 0; i != width; i++) *((uint8_t *)dst + i) = ctab[((uint8_t *)dst)[i]];
|
||||
|
|
|
@ -85,7 +85,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
|
|||
switch (mode) {
|
||||
case BlitterMode::ColourRemap:
|
||||
case BlitterMode::CrashRemap: {
|
||||
const uint8_t *remap = bp->remap;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
do {
|
||||
uint m = remap[*src];
|
||||
if (m != 0) *dst = m;
|
||||
|
@ -101,7 +101,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
|
|||
|
||||
case BlitterMode::Transparent:
|
||||
case BlitterMode::TransparentRemap: {
|
||||
const uint8_t *remap = bp->remap;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
src += pixels;
|
||||
do {
|
||||
*dst = remap[*dst];
|
||||
|
|
|
@ -20,6 +20,7 @@ void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoom
|
|||
{
|
||||
const uint8_t *src, *src_line;
|
||||
uint8_t *dst, *dst_line;
|
||||
const uint8_t *remap = bp->remap->GetPaletteRemap();
|
||||
|
||||
/* Find where to start reading in the source sprite */
|
||||
src_line = (const uint8_t *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom);
|
||||
|
@ -38,12 +39,12 @@ void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoom
|
|||
switch (mode) {
|
||||
case BlitterMode::ColourRemap:
|
||||
case BlitterMode::CrashRemap:
|
||||
colour = bp->remap[*src];
|
||||
colour = remap[*src];
|
||||
break;
|
||||
|
||||
case BlitterMode::Transparent:
|
||||
case BlitterMode::TransparentRemap:
|
||||
if (*src != 0) colour = bp->remap[*dst];
|
||||
if (*src != 0) colour = remap[*dst];
|
||||
break;
|
||||
|
||||
case BlitterMode::BlackRemap:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
enum class BlitterMode : uint8_t {
|
||||
Normal, ///< Perform the simple blitting.
|
||||
ColourRemap, ///< Perform a colour remapping.
|
||||
RGBAColourRemap, ///< Perform a colour remapping.
|
||||
Transparent, ///< Perform transparency darkening remapping.
|
||||
TransparentRemap, ///< Perform transparency colour remapping.
|
||||
CrashRemap, ///< Perform a crash remapping.
|
||||
|
@ -31,7 +32,7 @@ public:
|
|||
/** Parameters related to blitting. */
|
||||
struct BlitterParams {
|
||||
const void *sprite; ///< Pointer to the sprite how ever the encoder stored it
|
||||
const uint8_t *remap; ///< XXX -- Temporary storage for remap array
|
||||
const RecolourSprite *remap; ///< Pointer to the RecolourSprite to use with remapping.
|
||||
|
||||
int skip_left; ///< How much pixels of the source to skip on the left (based on zoom of dst)
|
||||
int skip_top; ///< How much pixels of the source to skip on the top (based on zoom of dst)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "smallmap_gui.h"
|
||||
#include "game/game.hpp"
|
||||
#include "goal_base.h"
|
||||
#include "spritecache.h"
|
||||
#include "story_base.h"
|
||||
#include "company_cmd.h"
|
||||
#include "timer/timer.h"
|
||||
|
@ -55,6 +56,7 @@ void UpdateObjectColours(const Company *c);
|
|||
CompanyID _local_company; ///< Company controlled by the human player at this client. Can also be #COMPANY_SPECTATOR.
|
||||
CompanyID _current_company; ///< Company currently doing an action.
|
||||
TypedIndexContainer<std::array<Colours, MAX_COMPANIES>, CompanyID> _company_colours; ///< NOSAVE: can be determined from company structs.
|
||||
TypedIndexContainer<std::array<PaletteID, MAX_COMPANIES>, CompanyID> _company_palettes; ///< NOSAVE: can be determined from company structs.
|
||||
std::string _company_manager_face; ///< for company manager face storage in openttd.cfg
|
||||
uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick
|
||||
|
||||
|
@ -163,7 +165,7 @@ TextColour GetDrawStringCompanyColour(CompanyID company)
|
|||
*/
|
||||
PaletteID GetCompanyPalette(CompanyID company)
|
||||
{
|
||||
return GetColourPalette(_company_colours[company]);
|
||||
return _company_palettes[company];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -513,7 +515,7 @@ static Colours GenerateCompanyColour()
|
|||
|
||||
/* Move the colours that look similar to each company's colour to the side */
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
Colours pcolour = c->colour;
|
||||
Colours pcolour = Colours(c->colour & 0xF);
|
||||
|
||||
for (uint i = 0; i < COLOUR_END; i++) {
|
||||
if (colours[i] == pcolour) {
|
||||
|
@ -566,6 +568,40 @@ restart:;
|
|||
}
|
||||
}
|
||||
|
||||
void ClearLivery(Livery &livery)
|
||||
{
|
||||
DeallocateDynamicSprite(livery.cached_pal_1cc);
|
||||
DeallocateDynamicSprite(livery.cached_pal_2cc);
|
||||
DeallocateDynamicSprite(livery.cached_pal_2cr);
|
||||
|
||||
livery.cached_pal_1cc = PALETTE_RECOLOUR_START + GB(livery.colour1, 0, 4);
|
||||
livery.cached_pal_2cc = SPR_2CCMAP_BASE + GB(livery.colour1, 0, 4) + GB(livery.colour2, 0, 4) * 16;
|
||||
livery.cached_pal_2cr = SPR_2CCMAP_BASE + GB(livery.colour2, 0, 4) + GB(livery.colour1, 0, 4) * 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cached palettes for a livery.
|
||||
* @param livery Livery to update.
|
||||
* @param always_update Always update instead of clearing livery (for LS_DEFAULT which is always needed).
|
||||
*/
|
||||
void UpdateLivery(Livery &livery, bool always_update)
|
||||
{
|
||||
if ((always_update || livery.in_use != 0) && (ColoursPacker(livery.colour1).IsCustom() || ColoursPacker(livery.colour2).IsCustom())) {
|
||||
PaletteID pal_1cc = PALETTE_RECOLOUR_START + GB(livery.colour1, 0, 4);
|
||||
livery.cached_pal_1cc = CreateCompanyColourRemap(livery.colour1, livery.colour1, false, pal_1cc, livery.cached_pal_1cc);
|
||||
|
||||
if (_loaded_newgrf_features.has_2CC) {
|
||||
PaletteID pal_2cc = SPR_2CCMAP_BASE + GB(livery.colour1, 0, 4) + GB(livery.colour2, 0, 4) * 16;
|
||||
livery.cached_pal_2cc = CreateCompanyColourRemap(livery.colour1, livery.colour2, true, pal_2cc, livery.cached_pal_2cc);
|
||||
|
||||
PaletteID pal_2cr = SPR_2CCMAP_BASE + GB(livery.colour2, 0, 4) + GB(livery.colour1, 0, 4) * 16;
|
||||
livery.cached_pal_2cr = CreateCompanyColourRemap(livery.colour2, livery.colour1, true, pal_2cr, livery.cached_pal_2cr);
|
||||
}
|
||||
} else {
|
||||
ClearLivery(livery);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the livery schemes to the company's primary colour.
|
||||
* This is used on loading games without livery information and on new company start up.
|
||||
|
@ -577,6 +613,7 @@ void ResetCompanyLivery(Company *c)
|
|||
c->livery[scheme].in_use = 0;
|
||||
c->livery[scheme].colour1 = c->colour;
|
||||
c->livery[scheme].colour2 = c->colour;
|
||||
UpdateLivery(c->livery[scheme], scheme == LS_DEFAULT);
|
||||
}
|
||||
|
||||
for (Group *g : Group::Iterate()) {
|
||||
|
@ -584,8 +621,12 @@ void ResetCompanyLivery(Company *c)
|
|||
g->livery.in_use = 0;
|
||||
g->livery.colour1 = c->colour;
|
||||
g->livery.colour2 = c->colour;
|
||||
UpdateLivery(g->livery, false);
|
||||
}
|
||||
}
|
||||
|
||||
_company_colours[c->index] = c->livery[LS_DEFAULT].colour1;
|
||||
_company_palettes[c->index] = c->livery[LS_DEFAULT].cached_pal_1cc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -613,7 +654,6 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = CompanyID::Invalid(
|
|||
c->colour = colour;
|
||||
|
||||
ResetCompanyLivery(c);
|
||||
_company_colours[c->index] = c->colour;
|
||||
|
||||
/* Scale the initial loan based on the inflation rounded down to the loan interval. The maximum loan has already been inflation adjusted. */
|
||||
c->money = c->current_loan = std::min<int64_t>((INITIAL_LOAN * _economy.inflation_prices >> 16) / LOAN_INTERVAL * LOAN_INTERVAL, _economy.max_loan);
|
||||
|
@ -1076,11 +1116,16 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint32_t bits, uint s
|
|||
*/
|
||||
void UpdateCompanyLiveries(Company *c)
|
||||
{
|
||||
UpdateLivery(c->livery[LS_DEFAULT], true);
|
||||
for (int i = 1; i < LS_END; i++) {
|
||||
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
|
||||
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
|
||||
UpdateLivery(c->livery[i], false);
|
||||
}
|
||||
UpdateCompanyGroupLiveries(c);
|
||||
|
||||
_company_colours[c->index] = c->livery[LS_DEFAULT].colour1;
|
||||
_company_palettes[c->index] = c->livery[LS_DEFAULT].cached_pal_1cc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1093,7 +1138,7 @@ void UpdateCompanyLiveries(Company *c)
|
|||
*/
|
||||
CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool primary, Colours colour)
|
||||
{
|
||||
if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
|
||||
if (scheme >= LS_END) return CMD_ERROR;
|
||||
|
||||
/* Default scheme can't be reset to invalid. */
|
||||
if (scheme == LS_DEFAULT && colour == INVALID_COLOUR) return CMD_ERROR;
|
||||
|
@ -1117,9 +1162,11 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
|
|||
* original and cached company colours too. */
|
||||
if (scheme == LS_DEFAULT) {
|
||||
UpdateCompanyLiveries(c);
|
||||
_company_colours[_current_company] = colour;
|
||||
/* Update cached colour/palette for company */
|
||||
c->colour = colour;
|
||||
CompanyAdminUpdate(c);
|
||||
} else {
|
||||
UpdateLivery(c->livery[scheme], false);
|
||||
}
|
||||
} else {
|
||||
if (scheme != LS_DEFAULT) AssignBit(c->livery[scheme].in_use, 1, colour != INVALID_COLOUR);
|
||||
|
@ -1128,6 +1175,8 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
|
|||
|
||||
if (scheme == LS_DEFAULT) {
|
||||
UpdateCompanyLiveries(c);
|
||||
} else {
|
||||
UpdateLivery(c->livery[scheme], false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "livery.h"
|
||||
|
||||
enum ClientID : uint32_t;
|
||||
enum Colours : uint8_t;
|
||||
enum Colours : uint32_t;
|
||||
|
||||
CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
|
||||
CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAction action, const std::string &public_key);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "company_type.h"
|
||||
#include "gfx_type.h"
|
||||
#include "vehicle_type.h"
|
||||
#include "livery.h"
|
||||
|
||||
bool CheckTakeoverVehicleLimit(CompanyID cbig, CompanyID small);
|
||||
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner);
|
||||
|
@ -24,6 +25,8 @@ void CompanyAdminUpdate(const Company *company);
|
|||
void CompanyAdminBankrupt(CompanyID company_id);
|
||||
void UpdateLandscapingLimits();
|
||||
void UpdateCompanyLiveries(Company *c);
|
||||
void ClearLivery(Livery &livery);
|
||||
void UpdateLivery(Livery &livery, bool always_update);
|
||||
|
||||
Money GetAvailableMoney(CompanyID company);
|
||||
Money GetAvailableMoneyForCommand();
|
||||
|
@ -37,7 +40,9 @@ extern CompanyID _local_company;
|
|||
extern CompanyID _current_company;
|
||||
|
||||
extern TypedIndexContainer<std::array<Colours, MAX_COMPANIES>, CompanyID> _company_colours;
|
||||
extern TypedIndexContainer<std::array<PaletteID, MAX_COMPANIES>, CompanyID> _company_palettes;
|
||||
extern std::string _company_manager_face;
|
||||
|
||||
PaletteID GetCompanyPalette(CompanyID company);
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
/** @file company_gui.cpp %Company related GUIs. */
|
||||
|
||||
#include "palette_func.h"
|
||||
#include "stdafx.h"
|
||||
#include "currency.h"
|
||||
#include "error.h"
|
||||
|
@ -47,6 +48,7 @@
|
|||
#include "timer/timer.h"
|
||||
#include "timer/timer_window.h"
|
||||
#include "core/string_consumer.hpp"
|
||||
#include "blitter/factory.hpp"
|
||||
|
||||
#include "widgets/company_widget.h"
|
||||
|
||||
|
@ -584,6 +586,13 @@ static const LiveryClass _livery_class[LS_END] = {
|
|||
LC_ROAD, LC_ROAD,
|
||||
};
|
||||
|
||||
StringID GetColourString(Colours colour)
|
||||
{
|
||||
if (ColoursPacker(colour).IsCustom()) return STR_COLOUR_CUSTOM;
|
||||
if (colour == INVALID_COLOUR) return STR_COLOUR_DEFAULT;
|
||||
return STR_COLOUR_DARK_BLUE + colour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Colour selection list item, with icon and string components.
|
||||
* @tparam TSprite Recolourable sprite to draw as icon.
|
||||
|
@ -591,12 +600,372 @@ static const LiveryClass _livery_class[LS_END] = {
|
|||
template <SpriteID TSprite = SPR_SQUARE>
|
||||
class DropDownListColourItem : public DropDownIcon<DropDownString<DropDownListItem>> {
|
||||
public:
|
||||
DropDownListColourItem(int colour, bool masked) :
|
||||
DropDownIcon<DropDownString<DropDownListItem>>(TSprite, GetColourPalette(static_cast<Colours>(colour % COLOUR_END)), GetString(colour < COLOUR_END ? (STR_COLOUR_DARK_BLUE + colour) : STR_COLOUR_DEFAULT), colour, masked)
|
||||
DropDownListColourItem(PaletteID pal, StringID str, int value, bool masked) :
|
||||
DropDownIcon<DropDownString<DropDownListItem>>(TSprite, pal, GetString(str), value, masked)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SelectCustomColourWindow : public Window {
|
||||
/* Preserved values from parent window when this window was opened. */
|
||||
uint32_t sel;
|
||||
LiveryClass lc;
|
||||
bool ctrl_pressed;
|
||||
bool primary;
|
||||
bool group;
|
||||
|
||||
Scrollbar *hue, *sat, *val, *con;
|
||||
Colours current;
|
||||
|
||||
HsvColour current_hsv;
|
||||
uint8_t contrast;
|
||||
|
||||
static inline const int BUTTON_SIZE = 10;
|
||||
static inline const int CON_MAX = UINT8_MAX;
|
||||
|
||||
void SetPresetColours()
|
||||
{
|
||||
for (uint i = 0; i < std::size(_settings_client.gui.preset_colours); ++i) {
|
||||
this->GetWidget<NWidgetCore>(WID_SCC_PRESETS + i)->colour = _settings_client.gui.preset_colours[i];
|
||||
}
|
||||
}
|
||||
|
||||
Colour AdjustBrightness(const Colour &rgb, ColourShade shade, int contrast) const
|
||||
{
|
||||
int level = (shade - SHADE_NORMAL) * contrast / (SHADE_END / 2);
|
||||
return {
|
||||
ClampTo<uint8_t>(std::max(1, rgb.r + level)),
|
||||
ClampTo<uint8_t>(std::max(1, rgb.g + level)),
|
||||
ClampTo<uint8_t>(std::max(1, rgb.b + level))
|
||||
};
|
||||
}
|
||||
|
||||
bool SetScrollbarPositions()
|
||||
{
|
||||
bool changed = false;
|
||||
changed |= this->hue->SetPosition(HsvColour::HUE_MAX - this->current_hsv.h);
|
||||
changed |= this->sat->SetPosition(this->current_hsv.s);
|
||||
changed |= this->val->SetPosition(HsvColour::VAL_MAX - this->current_hsv.v);
|
||||
changed |= this->con->SetPosition(CON_MAX - this->contrast);
|
||||
return changed;
|
||||
}
|
||||
|
||||
public:
|
||||
SelectCustomColourWindow(WindowDesc &desc, int window_number, CompanyID company, Colours colour, uint32_t sel, LiveryClass lc, bool ctrl, bool primary, bool group) :
|
||||
Window(desc), sel(sel), lc(lc), ctrl_pressed(ctrl), primary(primary), group(group)
|
||||
{
|
||||
this->InitNested(window_number);
|
||||
this->owner = (Owner)company;
|
||||
|
||||
this->current = colour;
|
||||
|
||||
ColoursPacker colourp(colour);
|
||||
if ((colourp.GetHue() | colourp.GetSaturation() | colourp.GetValue()) == 0) {
|
||||
auto [rgba, contrast] = GetCompanyColourRGB(colour);
|
||||
this->current_hsv = ConvertRgbToHsv(rgba);
|
||||
this->contrast = contrast;
|
||||
} else {
|
||||
this->current_hsv = colourp.Hsv();
|
||||
this->contrast = colourp.GetContrast();
|
||||
}
|
||||
|
||||
this->hue = this->GetScrollbar(WID_SCC_SCROLLBAR_HUE);
|
||||
this->hue->SetCapacity(HsvColour::HUE_MAX / BUTTON_SIZE);
|
||||
this->hue->SetCount(HsvColour::HUE_MAX + HsvColour::HUE_MAX / BUTTON_SIZE);
|
||||
this->sat = this->GetScrollbar(WID_SCC_SCROLLBAR_SAT);
|
||||
this->sat->SetCapacity(HsvColour::SAT_MAX / BUTTON_SIZE);
|
||||
this->sat->SetCount(HsvColour::SAT_MAX + HsvColour::SAT_MAX / BUTTON_SIZE);
|
||||
this->val = this->GetScrollbar(WID_SCC_SCROLLBAR_VAL);
|
||||
this->val->SetCapacity(HsvColour::VAL_MAX / BUTTON_SIZE);
|
||||
this->val->SetCount(HsvColour::VAL_MAX + HsvColour::VAL_MAX / BUTTON_SIZE);
|
||||
this->con = this->GetScrollbar(WID_SCC_SCROLLBAR_CON);
|
||||
this->con->SetCapacity(CON_MAX / BUTTON_SIZE);
|
||||
this->con->SetCount(CON_MAX + CON_MAX / BUTTON_SIZE);
|
||||
|
||||
this->SetScrollbarPositions();
|
||||
this->SetPresetColours();
|
||||
}
|
||||
|
||||
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SCC_CAPTION:
|
||||
return GetString(stringid, this->owner);
|
||||
|
||||
default:
|
||||
return this->Window::GetWidgetString(widget, stringid);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
{
|
||||
HsvColour hsv = this->current_hsv;
|
||||
switch (widget) {
|
||||
case WID_SCC_HUE: {
|
||||
int range = r.Height() - 1;
|
||||
int mid = CentreBounds(r.left, r.right, 0);
|
||||
hsv.s = HsvColour::SAT_MAX;
|
||||
for (int i = 0; i <= range; i++) {
|
||||
hsv.h = HsvColour::HUE_MAX * i / range;
|
||||
hsv.v = HsvColour::VAL_MAX;
|
||||
GfxFillRect(r.left, r.bottom - i, mid - 1, r.bottom - i, ConvertHsvToRgb(hsv), FILLRECT_OPAQUE);
|
||||
hsv.v = HsvColour::VAL_MAX * 3 / 4;
|
||||
GfxFillRect(mid, r.bottom - i, r.right, r.bottom - i, ConvertHsvToRgb(hsv), FILLRECT_OPAQUE);
|
||||
}
|
||||
|
||||
/* Mark current value. */
|
||||
GfxDrawLine(r.left, r.bottom - this->current_hsv.h * range / HsvColour::HUE_MAX, r.right, r.bottom - this->current_hsv.h * range / HsvColour::HUE_MAX, PC_WHITE, 1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_SCC_SAT: {
|
||||
int width = r.Width() - 1;
|
||||
int height = r.Height() - 1;
|
||||
|
||||
for (int x = 0; x <= width; x++) {
|
||||
hsv.s = HsvColour::SAT_MAX * x / width;
|
||||
for (int y = 0; y <= height; y++) {
|
||||
hsv.v = HsvColour::VAL_MAX * y / height;
|
||||
GfxFillRect(r.left + x, r.bottom - y, r.left + x, r.bottom - y, ConvertHsvToRgb(hsv), FILLRECT_OPAQUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark current value. */
|
||||
GfxDrawLine(r.left + this->current_hsv.s * width / HsvColour::SAT_MAX, r.top, r.left + this->current_hsv.s * width / HsvColour::SAT_MAX, r.bottom, PC_WHITE, 1, 1);
|
||||
GfxDrawLine(r.left, r.bottom - this->current_hsv.v * height / HsvColour::VAL_MAX, r.right, r.bottom - this->current_hsv.v * height / HsvColour::VAL_MAX, PC_WHITE, 1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_SCC_CON: {
|
||||
int range = r.Height() - 1;
|
||||
int mid = CentreBounds(r.left, r.right, 0);
|
||||
Colour rgb = ConvertHsvToRgb(HsvColour{0, 0, HsvColour::VAL_MAX / 2});
|
||||
for (int i = 0; i <= range; i++) {
|
||||
int contrast = i * CON_MAX / width;
|
||||
GfxFillRect(r.left, r.bottom - i, mid - 1, r.bottom - i, AdjustBrightness(rgb, SHADE_LIGHTEST, contrast), FILLRECT_OPAQUE);
|
||||
GfxFillRect(mid, r.bottom - i, r.right, r.bottom - i, AdjustBrightness(rgb, SHADE_DARKEST, contrast), FILLRECT_OPAQUE);
|
||||
}
|
||||
|
||||
/* Mark current value. */
|
||||
GfxDrawLine(r.left, r.bottom - this->contrast * range / CON_MAX, r.right, r.bottom - this->contrast * range / CON_MAX, PC_WHITE, 1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_SCC_OUTPUT: {
|
||||
int range = r.Height();
|
||||
/* Pack and unpack to colours, to produce the result. */
|
||||
Colours colour = this->PackColour();
|
||||
ColoursPacker colourp(colour);
|
||||
HsvColour hsv = colourp.Hsv();
|
||||
uint8_t con = colourp.GetContrast();
|
||||
for (ColourShade shade = SHADE_BEGIN; shade != SHADE_END; ++shade) {
|
||||
Colour c = ConvertHsvToRgb(AdjustHsvColourBrightness(hsv, shade, con));
|
||||
GfxFillRect(r.left, r.bottom - (shade + 1) * range / SHADE_END + 1, r.right, r.bottom - shade * range / SHADE_END, c, FILLRECT_OPAQUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (widget >= WID_SCC_DEFAULT && widget <= WID_SCC_DEFAULT_LAST && !_ctrl_pressed) {
|
||||
/* Select colour from default preset. */
|
||||
this->current = this->GetWidget<NWidgetCore>(widget)->colour;
|
||||
|
||||
auto [rgba, contrast] = GetCompanyColourRGB(this->current);
|
||||
this->current_hsv = ConvertRgbToHsv(rgba);
|
||||
this->contrast = contrast;
|
||||
|
||||
changed = this->SetScrollbarPositions();
|
||||
}
|
||||
|
||||
if (widget >= WID_SCC_PRESETS && widget <= WID_SCC_PRESETS_LAST) {
|
||||
if (_ctrl_pressed) {
|
||||
/* Save colour to preset. */
|
||||
_settings_client.gui.preset_colours[widget - WID_SCC_PRESETS] = this->PackColour();
|
||||
this->SetPresetColours();
|
||||
} else {
|
||||
/* Select colour from preset. */
|
||||
ColoursPacker cp(_settings_client.gui.preset_colours[widget - WID_SCC_PRESETS]);
|
||||
this->current_hsv = cp.Hsv();
|
||||
this->contrast = cp.GetContrast();
|
||||
|
||||
changed = this->SetScrollbarPositions();
|
||||
}
|
||||
}
|
||||
|
||||
if (widget == WID_SCC_HUE) {
|
||||
/* Click and drag on hue widget */
|
||||
const NWidgetCore *wi = this->GetWidget<NWidgetCore>(widget);
|
||||
this->current_hsv.h = std::clamp<int>(HsvColour::HUE_MAX - (pt.y - wi->pos_y) * HsvColour::HUE_MAX / (int)wi->current_y, 0, HsvColour::HUE_MAX);
|
||||
this->contrast = CON_MAX - this->con->GetPosition();
|
||||
|
||||
changed = this->SetScrollbarPositions();
|
||||
if (click_count > 0) this->mouse_capture_widget = widget;
|
||||
}
|
||||
|
||||
if (widget == WID_SCC_SAT) {
|
||||
/* Click and drag on saturation/value widget */
|
||||
const NWidgetCore *wi = this->GetWidget<NWidgetCore>(widget);
|
||||
this->current_hsv.s = std::clamp<int>((pt.x - wi->pos_x) * HsvColour::SAT_MAX / (int)wi->current_x, 0, HsvColour::SAT_MAX);
|
||||
this->current_hsv.v = std::clamp<int>(HsvColour::VAL_MAX - (pt.y - wi->pos_y) * HsvColour::VAL_MAX / (int)wi->current_y, 0, HsvColour::VAL_MAX);
|
||||
this->contrast = CON_MAX - this->con->GetPosition();
|
||||
|
||||
changed = this->SetScrollbarPositions();
|
||||
if (click_count > 0) this->mouse_capture_widget = widget;
|
||||
}
|
||||
|
||||
if (widget == WID_SCC_CON) {
|
||||
/* Click and drag on contrast widget */
|
||||
const NWidgetCore *wi = this->GetWidget<NWidgetCore>(widget);
|
||||
this->contrast = std::clamp<int>(CON_MAX - (pt.y - wi->pos_y) * CON_MAX / (int)wi->current_y, 0, CON_MAX);
|
||||
|
||||
changed = this->SetScrollbarPositions();
|
||||
if (click_count > 0) this->mouse_capture_widget = widget;
|
||||
}
|
||||
|
||||
if (!changed) return;
|
||||
|
||||
this->SetDirty();
|
||||
this->SetTimeout();
|
||||
}
|
||||
|
||||
void OnScrollbarScroll(WidgetID) override
|
||||
{
|
||||
/* Update colour from new scrollbar positions. */
|
||||
this->current_hsv.h = HsvColour::HUE_MAX - this->hue->GetPosition();
|
||||
this->current_hsv.s = this->sat->GetPosition();
|
||||
this->current_hsv.v = HsvColour::VAL_MAX - this->val->GetPosition();
|
||||
this->contrast = CON_MAX - this->con->GetPosition();
|
||||
|
||||
this->SetTimeout();
|
||||
}
|
||||
|
||||
Colours PackColour() const
|
||||
{
|
||||
Colours colour;
|
||||
ColoursPacker cp(colour);
|
||||
cp.SetIndex(this->current);
|
||||
cp.SetCustom(true);
|
||||
cp.SetHue(this->current_hsv.h);
|
||||
cp.SetSaturation(this->current_hsv.s);
|
||||
cp.SetValue(this->current_hsv.v);
|
||||
cp.SetContrast(this->contrast);
|
||||
return colour;
|
||||
}
|
||||
|
||||
void OnTimeout() override
|
||||
{
|
||||
Colours colour = this->PackColour();
|
||||
if (colour != this->current) {
|
||||
this->current = colour;
|
||||
|
||||
if (this->group) {
|
||||
Command<CMD_SET_GROUP_LIVERY>::Post((GroupID)this->sel, primary, this->current);
|
||||
} else {
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
/* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
|
||||
if (HasBit(this->sel, scheme) || (this->ctrl_pressed && _livery_class[scheme] == this->lc && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
|
||||
Command<CMD_SET_COMPANY_COLOUR>::Post(scheme, primary, this->current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr NWidgetPart _nested_select_custom_colour_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCC_CAPTION), SetStringTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), SetPadding(WidgetDimensions::unscaled.frametext),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_BLUE, WID_SCC_DEFAULT + 0), SetFill(1, 1), SetMinimalSize(16, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_PALE_GREEN, WID_SCC_DEFAULT + 1), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_PINK, WID_SCC_DEFAULT + 2), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_SCC_DEFAULT + 3), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_RED, WID_SCC_DEFAULT + 4), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_SCC_DEFAULT + 5), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_SCC_DEFAULT + 6), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_SCC_DEFAULT + 7), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BLUE, WID_SCC_DEFAULT + 8), SetFill(1, 1), SetMinimalSize(16, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_SCC_DEFAULT + 9), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCC_DEFAULT + 10), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_PURPLE, WID_SCC_DEFAULT + 11), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SCC_DEFAULT + 12), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SCC_DEFAULT + 13), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCC_DEFAULT + 14), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_SCC_DEFAULT + 15), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_BLUE, WID_SCC_PRESETS + 0), SetFill(1, 1), SetMinimalSize(16, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_PALE_GREEN, WID_SCC_PRESETS + 1), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_PINK, WID_SCC_PRESETS + 2), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_SCC_PRESETS + 3), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_RED, WID_SCC_PRESETS + 4), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_SCC_PRESETS + 5), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_SCC_PRESETS + 6), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_SCC_PRESETS + 7), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BLUE, WID_SCC_PRESETS + 8), SetFill(1, 1), SetMinimalSize(16, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_SCC_PRESETS + 9), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCC_PRESETS + 10), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_PURPLE, WID_SCC_PRESETS + 11), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SCC_PRESETS + 12), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SCC_PRESETS + 13), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCC_PRESETS + 14), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_SCC_PRESETS + 15), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_INSET, COLOUR_GREY),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_HUE), SetMinimalSize(16, 0),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_HUE),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_INSET, COLOUR_GREY),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_SAT), SetMinimalSize(160, 160),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_VAL),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_SAT),
|
||||
NWidget(NWID_SPACER), SetMinimalSize(11, 11),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_INSET, COLOUR_GREY),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_CON), SetMinimalSize(16, 0),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_CON),
|
||||
EndContainer(),
|
||||
NWidget(WWT_INSET, COLOUR_GREY),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_OUTPUT), SetFill(1, 1), SetMinimalSize(16, 0),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _select_custom_colour_desc(
|
||||
WDP_AUTO, {}, 0, 0,
|
||||
WC_CUSTOM_COLOUR, WC_NONE,
|
||||
{},
|
||||
_nested_select_custom_colour_widgets
|
||||
);
|
||||
|
||||
/** Company livery colour scheme window. */
|
||||
struct SelectCompanyLiveryWindow : public Window {
|
||||
private:
|
||||
|
@ -608,57 +977,86 @@ private:
|
|||
GUIGroupList groups{};
|
||||
Scrollbar *vscroll = nullptr;
|
||||
|
||||
void ShowColourDropDownMenu(uint32_t widget)
|
||||
/**
|
||||
* Get the first selected livery.
|
||||
*/
|
||||
const Livery *GetSelectedLivery() const
|
||||
{
|
||||
uint32_t used_colours = 0;
|
||||
const Livery *livery, *default_livery = nullptr;
|
||||
bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
|
||||
uint8_t default_col = 0;
|
||||
|
||||
/* Disallow other company colours for the primary colour */
|
||||
if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->index != _local_company) SetBit(used_colours, c->colour);
|
||||
}
|
||||
}
|
||||
|
||||
const Company *c = Company::Get(this->window_number);
|
||||
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
/* Get the first selected livery to use as the default dropdown item */
|
||||
LiveryScheme scheme;
|
||||
for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
||||
if (HasBit(this->sel, scheme)) break;
|
||||
}
|
||||
|
||||
if (scheme == LS_END) scheme = LS_DEFAULT;
|
||||
livery = &c->livery[scheme];
|
||||
if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
|
||||
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
return &c->livery[scheme];
|
||||
} else {
|
||||
const Group *g = Group::Get(this->sel);
|
||||
return &g->livery;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default selected livery.
|
||||
*/
|
||||
const Livery *GetDefaultLivery() const
|
||||
{
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
if (!HasBit(this->sel, LS_DEFAULT)) return &c->livery[LS_DEFAULT];
|
||||
} else {
|
||||
const Group *g = Group::Get(this->sel);
|
||||
livery = &g->livery;
|
||||
if (g->parent == GroupID::Invalid()) {
|
||||
default_livery = &c->livery[LS_DEFAULT];
|
||||
return &c->livery[LS_DEFAULT];
|
||||
} else {
|
||||
const Group *pg = Group::Get(g->parent);
|
||||
default_livery = &pg->livery;
|
||||
return &pg->livery;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void ShowColourDropDownMenu(uint32_t widget)
|
||||
{
|
||||
uint32_t used_colours = 0;
|
||||
bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
|
||||
|
||||
/* Disallow other company colours for the primary colour */
|
||||
if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->index != _local_company) SetBit(used_colours, c->colour & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first selected livery to use as the default dropdown item */
|
||||
const Livery *livery = GetSelectedLivery();
|
||||
const Livery *default_livery = GetDefaultLivery();
|
||||
|
||||
DropDownList list;
|
||||
if (default_livery != nullptr) {
|
||||
/* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */
|
||||
default_col = (primary ? default_livery->colour1 : default_livery->colour2) + COLOUR_END;
|
||||
list.push_back(std::make_unique<DropDownListColourItem<>>(default_col, false));
|
||||
list.push_back(std::make_unique<DropDownListColourItem<>>(primary ? default_livery->cached_pal_1cc : default_livery->cached_pal_2cr, STR_COLOUR_DEFAULT, INVALID_COLOUR, false));
|
||||
}
|
||||
for (Colours colour = COLOUR_BEGIN; colour != COLOUR_END; colour++) {
|
||||
list.push_back(std::make_unique<DropDownListColourItem<>>(colour, HasBit(used_colours, colour)));
|
||||
list.push_back(std::make_unique<DropDownListColourItem<>>(GetColourPalette(colour), GetColourString(colour), colour, HasBit(used_colours, colour)));
|
||||
}
|
||||
list.push_back(std::make_unique<DropDownListColourItem<>>(primary ? livery->cached_pal_1cc : livery->cached_pal_2cr, STR_COLOUR_CUSTOM, 0xFF, BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32));
|
||||
|
||||
uint8_t sel;
|
||||
int sel;
|
||||
if (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) {
|
||||
sel = primary ? livery->colour1 : livery->colour2;
|
||||
Colours col = primary ? livery->colour1 : livery->colour2;
|
||||
if (ColoursPacker(col).IsCustom()) {
|
||||
sel = 0xFF;
|
||||
} else {
|
||||
sel = ColoursPacker(col).GetIndex();
|
||||
}
|
||||
} else {
|
||||
sel = default_col;
|
||||
sel = INVALID_COLOUR;
|
||||
}
|
||||
ShowDropDownList(this, std::move(list), sel, widget);
|
||||
}
|
||||
|
@ -820,7 +1218,7 @@ public:
|
|||
if (scheme == LS_END) scheme = LS_DEFAULT;
|
||||
const Livery *livery = &c->livery[scheme];
|
||||
if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
|
||||
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
|
||||
colour = GetColourString(primary ? livery->colour1 : livery->colour2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -828,7 +1226,7 @@ public:
|
|||
const Group *g = Group::Get(this->sel);
|
||||
const Livery *livery = &g->livery;
|
||||
if (HasBit(livery->in_use, primary ? 0 : 1)) {
|
||||
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
|
||||
colour = GetColourString(primary ? livery->colour1 : livery->colour2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -868,26 +1266,26 @@ public:
|
|||
|
||||
int y = ir.top;
|
||||
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
|
||||
/* Helper function to draw livery info. */
|
||||
auto draw_livery = [&](std::string_view str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
|
||||
/* Livery Label. */
|
||||
DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
|
||||
|
||||
/* Text below the first dropdown. */
|
||||
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
|
||||
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
|
||||
DrawSprite(SPR_SQUARE, HasBit(livery.in_use, 0) ? livery.cached_pal_1cc : c->livery[LS_DEFAULT].cached_pal_1cc, pri_squ.left, y + square_offs);
|
||||
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? GetColourString(livery.colour1) : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
|
||||
|
||||
/* Text below the second dropdown. */
|
||||
if (sec.right > sec.left) { // Second dropdown has non-zero size.
|
||||
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
|
||||
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
|
||||
DrawSprite(SPR_SQUARE, HasBit(livery.in_use, 1) ? livery.cached_pal_2cr : c->livery[LS_DEFAULT].cached_pal_2cr, sec_squ.left, y + square_offs);
|
||||
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? GetColourString(livery.colour2) : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
|
||||
}
|
||||
|
||||
y += this->line_height;
|
||||
};
|
||||
|
||||
const Company *c = Company::Get(this->window_number);
|
||||
|
||||
if (livery_class < LC_GROUP_RAIL) {
|
||||
int pos = this->vscroll->GetPosition();
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
|
@ -998,6 +1396,16 @@ public:
|
|||
bool local = this->window_number == _local_company;
|
||||
if (!local) return;
|
||||
|
||||
if (index == 0xFF) {
|
||||
/* Special case for 'Custom...' option */
|
||||
int number = ((widget == WID_SCL_PRI_COL_DROPDOWN) ? 1 : 0) | (this->window_number << 1);
|
||||
if (BringWindowToFrontById(WC_CUSTOM_COLOUR, number)) return;
|
||||
|
||||
const Livery *livery = GetSelectedLivery();
|
||||
new SelectCustomColourWindow(_select_custom_colour_desc, number, (CompanyID)this->window_number, (widget == WID_SCL_PRI_COL_DROPDOWN) ? livery->colour1 : livery->colour2, this->sel, this->livery_class, _ctrl_pressed, widget == WID_SCL_PRI_COL_DROPDOWN, this->livery_class >= LC_GROUP_RAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
Colours colour = static_cast<Colours>(index);
|
||||
if (colour >= COLOUR_END) colour = INVALID_COLOUR;
|
||||
|
||||
|
@ -1114,10 +1522,10 @@ void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
|
|||
/**
|
||||
* Draws the face of a company manager's face.
|
||||
* @param cmf the company manager's face
|
||||
* @param colour the (background) colour of the gradient
|
||||
* @param palette the (background) colour of the gradient
|
||||
* @param r position to draw the face
|
||||
*/
|
||||
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
|
||||
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, PaletteID palette, const Rect &r)
|
||||
{
|
||||
/* Determine offset from centre of drawing rect. */
|
||||
Dimension d = GetSpriteSize(SPR_GRADIENT);
|
||||
|
@ -1148,7 +1556,7 @@ void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const
|
|||
}
|
||||
|
||||
/* Draw the gradient (background) */
|
||||
DrawSprite(SPR_GRADIENT, GetColourPalette(colour), x, y);
|
||||
DrawSprite(SPR_GRADIENT, palette, x, y);
|
||||
|
||||
/* Thirdly, draw sprites. */
|
||||
for (auto var : SetBitIterator(active_vars)) {
|
||||
|
@ -2105,7 +2513,7 @@ struct CompanyWindow : Window
|
|||
const Company *c = Company::Get(this->window_number);
|
||||
switch (widget) {
|
||||
case WID_C_FACE:
|
||||
DrawCompanyManagerFace(c->face, c->colour, r);
|
||||
DrawCompanyManagerFace(c->face, GetCompanyPalette(c->index), r);
|
||||
break;
|
||||
|
||||
case WID_C_FACE_TITLE:
|
||||
|
@ -2359,8 +2767,8 @@ struct BuyCompanyWindow : Window {
|
|||
{
|
||||
switch (widget) {
|
||||
case WID_BC_FACE: {
|
||||
const Company *c = Company::Get(this->window_number);
|
||||
DrawCompanyManagerFace(c->face, c->colour, r);
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
DrawCompanyManagerFace(c->face, GetCompanyPalette(c->index), r);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,6 @@ uint32_t MaskCompanyManagerFaceBits(const CompanyManagerFace &cmf, FaceVars vars
|
|||
std::string FormatCompanyManagerFaceCode(const CompanyManagerFace &cmf);
|
||||
std::optional<CompanyManagerFace> ParseCompanyManagerFaceCode(std::string_view str);
|
||||
|
||||
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r);
|
||||
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, PaletteID palette, const Rect &r);
|
||||
|
||||
#endif /* COMPANY_MANAGER_FACE_H */
|
||||
|
|
|
@ -1949,7 +1949,7 @@ static bool ConCompanies(std::span<std::string_view> argv)
|
|||
/* Grab the company name */
|
||||
std::string company_name = GetString(STR_COMPANY_NAME, c->index);
|
||||
|
||||
std::string colour = GetString(STR_COLOUR_DARK_BLUE + _company_colours[c->index]);
|
||||
std::string colour = GetString(STR_COLOUR_DARK_BLUE + _company_colours[c->index] & 0xF);
|
||||
IConsolePrint(CC_INFO, "#:{}({}) Company Name: '{}' Year Founded: {} Money: {} Loan: {} Value: {} (T:{}, R:{}, P:{}, S:{}) {}",
|
||||
c->index + 1, colour, company_name,
|
||||
c->inaugurated_year, (int64_t)c->money, (int64_t)c->current_loan, (int64_t)CalculateCompanyValue(c),
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "company_base.h"
|
||||
#include "company_func.h"
|
||||
#include "company_manager_face.h"
|
||||
#include "sprite.h"
|
||||
#include "strings_func.h"
|
||||
#include "zoom_func.h"
|
||||
#include "window_func.h"
|
||||
|
@ -188,7 +189,7 @@ public:
|
|||
switch (widget) {
|
||||
case WID_EM_FACE: {
|
||||
const Company *c = Company::Get(this->company);
|
||||
DrawCompanyManagerFace(c->face, c->colour, r);
|
||||
DrawCompanyManagerFace(c->face, GetCompanyPalette(c->index), r);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
61
src/gfx.cpp
61
src/gfx.cpp
|
@ -72,8 +72,8 @@ int _gui_scale_cfg; ///< GUI scale in config.
|
|||
* @ingroup dirty
|
||||
*/
|
||||
static Rect _invalid_rect;
|
||||
static const uint8_t *_colour_remap_ptr;
|
||||
static uint8_t _string_colourremap[3]; ///< Recoloursprite for stringdrawing. The grf loader ensures that #SpriteType::Font sprites only use colours 0 to 2.
|
||||
static const RecolourSprite *_colour_remap_ptr;
|
||||
static RecolourSpriteRGBA _string_colourremap; ///< RecolourSprite for string drawing.
|
||||
|
||||
static const uint DIRTY_BLOCK_HEIGHT = 8;
|
||||
static const uint DIRTY_BLOCK_WIDTH = 64;
|
||||
|
@ -470,19 +470,32 @@ void DrawRectOutline(const Rect &r, PixelColour colour, int width, int dash)
|
|||
* Set the colour remap to be for the given colour.
|
||||
* @param colour the new colour of the remap.
|
||||
*/
|
||||
static void SetColourRemap(TextColour colour)
|
||||
static BlitterMode SetColourRemap(TextColour colour)
|
||||
{
|
||||
if (colour == TC_INVALID) return;
|
||||
if (colour == TC_INVALID) return BlitterMode::ColourRemap;
|
||||
|
||||
/* Black strings have no shading ever; the shading is black, so it
|
||||
* would be invisible at best, but it actually makes it illegible. */
|
||||
bool no_shade = (colour & TC_NO_SHADE) != 0 || colour == TC_BLACK;
|
||||
|
||||
if ((colour & TC_IS_RGB_COLOUR) && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32) {
|
||||
/* Unpack RGB TextColour */
|
||||
TextColourPacker tcp(colour);
|
||||
_string_colourremap.rgba[1] = tcp.ToColour();
|
||||
_string_colourremap.rgba[2] = _cur_palette.palette[no_shade ? 0 : PC_BLACK.p];
|
||||
_colour_remap_ptr = &_string_colourremap;
|
||||
|
||||
return BlitterMode::RGBAColourRemap;
|
||||
}
|
||||
|
||||
bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0;
|
||||
colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR | TC_FORCED);
|
||||
|
||||
_string_colourremap[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour].p;
|
||||
_string_colourremap[2] = no_shade ? 0 : 1;
|
||||
_colour_remap_ptr = _string_colourremap;
|
||||
_string_colourremap.palette[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour].p;
|
||||
_string_colourremap.palette[2] = no_shade ? 0 : PC_BLACK.p;
|
||||
_colour_remap_ptr = &_string_colourremap;
|
||||
|
||||
return BlitterMode::ColourRemap;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -602,7 +615,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
|||
/* Update the last colour for the truncation ellipsis. */
|
||||
last_colour = colour;
|
||||
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
|
||||
SetColourRemap(do_shadow ? TC_BLACK : colour);
|
||||
BlitterMode bm = SetColourRemap(do_shadow ? TC_BLACK : colour); // the last run also sets the colour for the truncation dots
|
||||
|
||||
for (int i = 0; i < run.GetGlyphCount(); i++) {
|
||||
GlyphID glyph = glyphs[i];
|
||||
|
@ -623,7 +636,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
|||
|
||||
if (do_shadow && (glyph & SPRITE_GLYPH) != 0) continue;
|
||||
|
||||
GfxMainBlitter(sprite, begin_x + (do_shadow ? shadow_offset : 0), top + (do_shadow ? shadow_offset : 0), BlitterMode::ColourRemap);
|
||||
GfxMainBlitter(sprite, begin_x + (do_shadow ? shadow_offset : 0), top + (do_shadow ? shadow_offset : 0), bm);
|
||||
}
|
||||
}
|
||||
return last_colour;
|
||||
|
@ -640,7 +653,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
|||
}
|
||||
|
||||
if (underline) {
|
||||
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, PixelColour{_string_colourremap[1]});
|
||||
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, PixelColour{_string_colourremap.GetPaletteRemap()[1]});
|
||||
}
|
||||
|
||||
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
|
||||
|
@ -948,11 +961,11 @@ Dimension GetStringListBoundingBox(std::span<const StringID> list, FontSize font
|
|||
*/
|
||||
void DrawCharCentered(char32_t c, const Rect &r, TextColour colour)
|
||||
{
|
||||
SetColourRemap(colour);
|
||||
BlitterMode bm = SetColourRemap(colour);
|
||||
GfxMainBlitter(GetGlyph(FS_NORMAL, c),
|
||||
CentreBounds(r.left, r.right, GetCharacterWidth(FS_NORMAL, c)),
|
||||
CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)),
|
||||
BlitterMode::ColourRemap);
|
||||
bm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -983,13 +996,13 @@ Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
|
|||
* @param pal The palette to get the blitter mode for.
|
||||
* @return The blitter mode associated with the palette.
|
||||
*/
|
||||
static BlitterMode GetBlitterMode(PaletteID pal)
|
||||
static BlitterMode GetBlitterMode(PaletteID pal, const RecolourSprite &recolour)
|
||||
{
|
||||
switch (pal) {
|
||||
case PAL_NONE: return BlitterMode::Normal;
|
||||
case PALETTE_CRASH: return BlitterMode::CrashRemap;
|
||||
case PALETTE_ALL_BLACK: return BlitterMode::BlackRemap;
|
||||
default: return BlitterMode::ColourRemap;
|
||||
default: return recolour.IsRGB() && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32 ? BlitterMode::RGBAColourRemap : BlitterMode::ColourRemap;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1006,15 +1019,17 @@ void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSpri
|
|||
SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
|
||||
if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
|
||||
pal = GB(pal, 0, PALETTE_WIDTH);
|
||||
_colour_remap_ptr = GetNonSprite(pal, SpriteType::Recolour) + 1;
|
||||
_colour_remap_ptr = GetRecolourSprite(pal);
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, pal == PALETTE_TO_TRANSPARENT ? BlitterMode::Transparent : BlitterMode::TransparentRemap, sub, real_sprite);
|
||||
} else if (pal != PAL_NONE) {
|
||||
BlitterMode bm;
|
||||
if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) {
|
||||
SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
|
||||
bm = SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
|
||||
} else {
|
||||
_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1;
|
||||
_colour_remap_ptr = GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH));
|
||||
bm = GetBlitterMode(pal, *_colour_remap_ptr);
|
||||
}
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal), sub, real_sprite);
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, bm, sub, real_sprite);
|
||||
} else {
|
||||
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, BlitterMode::Normal, sub, real_sprite);
|
||||
}
|
||||
|
@ -1034,15 +1049,17 @@ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub,
|
|||
SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
|
||||
if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
|
||||
pal = GB(pal, 0, PALETTE_WIDTH);
|
||||
_colour_remap_ptr = GetNonSprite(pal, SpriteType::Recolour) + 1;
|
||||
_colour_remap_ptr = GetRecolourSprite(pal);
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, pal == PALETTE_TO_TRANSPARENT ? BlitterMode::Transparent : BlitterMode::TransparentRemap, sub, real_sprite, zoom);
|
||||
} else if (pal != PAL_NONE) {
|
||||
BlitterMode bm;
|
||||
if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) {
|
||||
SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
|
||||
bm = SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
|
||||
} else {
|
||||
_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1;
|
||||
_colour_remap_ptr = GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH));
|
||||
bm = GetBlitterMode(pal, *_colour_remap_ptr);
|
||||
}
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal), sub, real_sprite, zoom);
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, bm, sub, real_sprite, zoom);
|
||||
} else {
|
||||
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, BlitterMode::Normal, sub, real_sprite, zoom);
|
||||
}
|
||||
|
|
|
@ -280,7 +280,7 @@ struct SubSprite {
|
|||
int left, top, right, bottom;
|
||||
};
|
||||
|
||||
enum Colours : uint8_t {
|
||||
enum Colours : uint32_t {
|
||||
COLOUR_BEGIN,
|
||||
COLOUR_DARK_BLUE = COLOUR_BEGIN,
|
||||
COLOUR_PALE_GREEN,
|
||||
|
@ -299,13 +299,14 @@ enum Colours : uint8_t {
|
|||
COLOUR_GREY,
|
||||
COLOUR_WHITE,
|
||||
COLOUR_END,
|
||||
INVALID_COLOUR = 0xFF,
|
||||
INVALID_COLOUR = UINT32_MAX,
|
||||
};
|
||||
DECLARE_INCREMENT_DECREMENT_OPERATORS(Colours)
|
||||
DECLARE_ENUM_AS_ADDABLE(Colours)
|
||||
DECLARE_ENUM_AS_BIT_SET(Colours)
|
||||
|
||||
/** Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palette.png */
|
||||
enum TextColour : uint16_t {
|
||||
enum TextColour : uint32_t {
|
||||
TC_BEGIN = 0x00,
|
||||
TC_FROMSTRING = 0x00,
|
||||
TC_BLUE = 0x00,
|
||||
|
@ -331,9 +332,10 @@ enum TextColour : uint16_t {
|
|||
TC_IS_PALETTE_COLOUR = 0x100, ///< Colour value is already a real palette colour index, not an index of a StringColour.
|
||||
TC_NO_SHADE = 0x200, ///< Do not add shading to this text colour.
|
||||
TC_FORCED = 0x400, ///< Ignore colour changes from strings.
|
||||
TC_IS_RGB_COLOUR = 0x800, ///< Colour includes RGB component.
|
||||
|
||||
TC_COLOUR_MASK = 0xFF, ///< Mask to test if TextColour (without flags) is within limits.
|
||||
TC_FLAGS_MASK = 0x700, ///< Mask to test if TextColour (with flags) is within limits.
|
||||
TC_FLAGS_MASK = 0xF00, ///< Mask to test if TextColour (with flags) is within limits.
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(TextColour)
|
||||
|
||||
|
@ -404,12 +406,30 @@ DECLARE_ENUM_AS_BIT_SET(StringAlignment)
|
|||
|
||||
/** Colour for pixel/line drawing. */
|
||||
struct PixelColour {
|
||||
uint8_t p; ///< Palette index.
|
||||
uint8_t p = 0; ///< Palette index.
|
||||
uint8_t r = 0; ///< Red component.
|
||||
uint8_t g = 0; ///< Green component.
|
||||
uint8_t b = 0; ///< Blue component.
|
||||
|
||||
constexpr PixelColour() : p(0) {}
|
||||
constexpr PixelColour() {}
|
||||
explicit constexpr PixelColour(uint8_t p) : p(p) {}
|
||||
constexpr PixelColour(uint8_t p, Colour colour) : p(p), r(colour.r), g(colour.g), b(colour.b) {}
|
||||
PixelColour(Colour colour);
|
||||
|
||||
constexpr inline TextColour ToTextColour() const { return static_cast<TextColour>(this->p) | TC_IS_PALETTE_COLOUR; }
|
||||
constexpr inline bool HasRGB() const { return (this->r | this->g | this->b) != 0; }
|
||||
constexpr inline Colour ToColour() const { return {this->r, this->g, this->b}; }
|
||||
TextColour ToTextColour() const;
|
||||
};
|
||||
|
||||
struct HsvColour {
|
||||
static constexpr int HUE_MAX = 360 * 128; ///< Maximum value for hue.
|
||||
static constexpr int SAT_MAX = UINT8_MAX; ///< Maximum value for saturation.
|
||||
static constexpr int VAL_MAX = UINT8_MAX; ///< Maximum value for value.
|
||||
static constexpr int HUE_RGN = HUE_MAX / 6;
|
||||
|
||||
uint16_t h; ///< Hue ranging from 0 to HUE_MAX.
|
||||
uint8_t s; ///< Saturation ranging from 0 to SAT_MAX.
|
||||
uint8_t v; ///< Value (brightness) ranging from 0 to VAL_MAX.
|
||||
};
|
||||
|
||||
#endif /* GFX_TYPE_H */
|
||||
|
|
|
@ -87,6 +87,7 @@ struct Group : GroupPool::PoolItem<&_group_pool> {
|
|||
|
||||
Group() {}
|
||||
Group(CompanyID owner, VehicleType vehicle_type) : owner(owner), vehicle_type(vehicle_type) {}
|
||||
~Group();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "core/pool_func.hpp"
|
||||
#include "order_backup.h"
|
||||
#include "group_cmd.h"
|
||||
#include "spritecache.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
|
@ -308,6 +309,7 @@ static void PropagateChildLivery(const Group *g, bool reset_cache)
|
|||
Group *cg = Group::Get(childgroup);
|
||||
if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1;
|
||||
if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2;
|
||||
UpdateLivery(cg->livery, false);
|
||||
PropagateChildLivery(cg, reset_cache);
|
||||
}
|
||||
}
|
||||
|
@ -323,11 +325,20 @@ void UpdateCompanyGroupLiveries(const Company *c)
|
|||
if (g->owner == c->index && g->parent == GroupID::Invalid()) {
|
||||
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
|
||||
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
|
||||
UpdateLivery(g->livery, false);
|
||||
PropagateChildLivery(g, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Group::~Group()
|
||||
{
|
||||
if (CleaningPool()) return;
|
||||
|
||||
DeallocateDynamicSprite(this->livery.cached_pal_1cc);
|
||||
DeallocateDynamicSprite(this->livery.cached_pal_2cc);
|
||||
DeallocateDynamicSprite(this->livery.cached_pal_2cr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new vehicle group.
|
||||
|
@ -483,8 +494,9 @@ CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID gro
|
|||
if (!HasBit(g->livery.in_use, 0) || !HasBit(g->livery.in_use, 1)) {
|
||||
/* Update livery with new parent's colours if either colour is default. */
|
||||
const Livery *livery = GetParentLivery(g);
|
||||
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = livery->colour1;
|
||||
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = livery->colour2;
|
||||
if (!HasBit(g->livery.in_use, 0)) if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = livery->colour1;
|
||||
if (!HasBit(g->livery.in_use, 1)) if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = livery->colour2;
|
||||
UpdateLivery(g->livery, false);
|
||||
|
||||
PropagateChildLivery(g, true);
|
||||
MarkWholeScreenDirty();
|
||||
|
@ -680,8 +692,6 @@ CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool prima
|
|||
|
||||
if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
|
||||
|
||||
if (colour >= COLOUR_END && colour != INVALID_COLOUR) return CMD_ERROR;
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
if (primary) {
|
||||
AssignBit(g->livery.in_use, 0, colour != INVALID_COLOUR);
|
||||
|
@ -692,6 +702,7 @@ CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool prima
|
|||
if (colour == INVALID_COLOUR) colour = GetParentLivery(g)->colour2;
|
||||
g->livery.colour2 = colour;
|
||||
}
|
||||
UpdateLivery(g->livery, false);
|
||||
|
||||
PropagateChildLivery(g, true);
|
||||
MarkWholeScreenDirty();
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "vehiclelist.h"
|
||||
#include "vehiclelist_cmd.h"
|
||||
|
||||
enum Colours : uint8_t;
|
||||
enum Colours : uint32_t;
|
||||
enum class GroupFlag : uint8_t;
|
||||
|
||||
/** Action for \c CmdAlterGroup. */
|
||||
|
|
|
@ -170,6 +170,7 @@ STR_ITEMS :{COMMA}{NBSP}it
|
|||
STR_CRATES :{COMMA}{NBSP}crate{P "" s}
|
||||
|
||||
STR_COLOUR_DEFAULT :Default
|
||||
STR_COLOUR_CUSTOM :Custom...
|
||||
###length 17
|
||||
STR_COLOUR_DARK_BLUE :Dark Blue
|
||||
STR_COLOUR_PALE_GREEN :Pale Green
|
||||
|
@ -2325,6 +2326,11 @@ STR_LIVERY_LARGE_PLANE :Large Aeroplane
|
|||
STR_LIVERY_PASSENGER_TRAM :Passenger Tram
|
||||
STR_LIVERY_FREIGHT_TRAM :Freight Tram
|
||||
|
||||
STR_LIVERY_HUE :{BLACK}Hue
|
||||
STR_LIVERY_SATURATION :{BLACK}Saturation
|
||||
STR_LIVERY_LIGHTNESS :{BLACK}Lightness
|
||||
STR_LIVERY_CONTRAST :{BLACK}Contrast
|
||||
|
||||
# Face selection window
|
||||
STR_FACE_CAPTION :{WHITE}Face Selection
|
||||
STR_FACE_CANCEL_TOOLTIP :{BLACK}Cancel new face selection
|
||||
|
|
|
@ -79,6 +79,10 @@ struct Livery {
|
|||
uint8_t in_use = 0; ///< Bit 0 set if this livery should override the default livery first colour, Bit 1 for the second colour.
|
||||
Colours colour1 = COLOUR_BEGIN; ///< First colour, for all vehicles.
|
||||
Colours colour2 = COLOUR_BEGIN; ///< Second colour, for vehicles with 2CC support.
|
||||
|
||||
PaletteID cached_pal_1cc = 0; ///< NOSAVE: cached 1CC palette.
|
||||
PaletteID cached_pal_2cc = 0; ///< NOSAVE: cached 2CC palette.
|
||||
PaletteID cached_pal_2cr = 0; ///< NOSAVE: cached reversed 2CC palette.
|
||||
};
|
||||
|
||||
void ResetCompanyLivery(Company *c);
|
||||
|
|
|
@ -553,10 +553,19 @@ void ShowSelectGameWindow();
|
|||
void SetupColoursAndInitialWindow()
|
||||
{
|
||||
for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
|
||||
const uint8_t *b = GetNonSprite(GetColourPalette(i), SpriteType::Recolour) + 1;
|
||||
assert(b != nullptr);
|
||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||
SetColourGradient(i, j, PixelColour{b[0xC6 + j]});
|
||||
const RecolourSprite *rs = GetRecolourSprite(GetColourPalette(i));
|
||||
assert(rs != nullptr);
|
||||
const uint8_t *remap = rs->GetPaletteRemap();
|
||||
if (rs->IsRGB()) {
|
||||
const Colour *rgba_remap = rs->GetRGBARemap();
|
||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||
const Colour &c = rgba_remap[j];
|
||||
SetColourGradient(i, j, PixelColour{remap[0xC6 + j], c});
|
||||
}
|
||||
} else {
|
||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||
SetColourGradient(i, j, PixelColour{remap[0xC6 + j]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -325,7 +325,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
|
|||
p->Send_uint8 (c->index);
|
||||
p->Send_string(GetString(STR_COMPANY_NAME, c->index));
|
||||
p->Send_string(GetString(STR_PRESIDENT_NAME, c->index));
|
||||
p->Send_uint8 (c->colour);
|
||||
p->Send_uint8 (c->colour & 0xF);
|
||||
p->Send_bool (true);
|
||||
p->Send_uint32(c->inaugurated_year.base());
|
||||
p->Send_bool (c->is_ai);
|
||||
|
@ -348,7 +348,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Compa
|
|||
p->Send_uint8 (c->index);
|
||||
p->Send_string(GetString(STR_COMPANY_NAME, c->index));
|
||||
p->Send_string(GetString(STR_PRESIDENT_NAME, c->index));
|
||||
p->Send_uint8 (c->colour);
|
||||
p->Send_uint8 (c->colour & 0xF);
|
||||
p->Send_bool (true);
|
||||
p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy
|
||||
|
||||
|
|
|
@ -1678,6 +1678,9 @@ static void AfterLoadGRFs()
|
|||
InitRailTypes();
|
||||
InitRoadTypes();
|
||||
|
||||
/* Force cached palettes to be refreshed */
|
||||
ResetVehicleColourMap();
|
||||
|
||||
for (Engine *e : Engine::IterateType(VEH_ROAD)) {
|
||||
if (_gted[e->index].rv_max_speed != 0) {
|
||||
/* Set RV maximum speed from the mph/0.8 unit value */
|
||||
|
@ -1855,6 +1858,9 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
|
|||
/* Pseudo sprite processing is finished; free temporary stuff */
|
||||
_cur_gps.ClearDataForNextFile();
|
||||
|
||||
/* Make note of last sprite ID loaded for dynamic sprite management */
|
||||
ClearDynamicSprites();
|
||||
|
||||
/* Call any functions that should be run after GRFs have been loaded. */
|
||||
AfterLoadGRFs();
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "water.h"
|
||||
#include "landscape.h"
|
||||
#include "company_base.h"
|
||||
#include "company_func.h"
|
||||
#include "town.h"
|
||||
#include "newgrf_animation_base.h"
|
||||
|
||||
|
@ -241,7 +242,7 @@ static uint16_t GetAirportTileCallback(CallbackID callback, uint32_t param1, uin
|
|||
return object.ResolveCallback(regs100);
|
||||
}
|
||||
|
||||
static void AirportDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &dts, Colours colour)
|
||||
static void AirportDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &dts, PaletteID cc_pal)
|
||||
{
|
||||
SpriteID image = dts.ground.sprite;
|
||||
SpriteID pal = dts.ground.pal;
|
||||
|
@ -250,11 +251,11 @@ static void AirportDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &
|
|||
if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
|
||||
DrawWaterClassGround(ti);
|
||||
} else {
|
||||
DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, GetColourPalette(colour)));
|
||||
DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, cc_pal));
|
||||
}
|
||||
}
|
||||
|
||||
DrawNewGRFTileSeq(ti, &dts, TO_BUILDINGS, 0, GetColourPalette(colour));
|
||||
DrawNewGRFTileSeq(ti, &dts, TO_BUILDINGS, 0, cc_pal);
|
||||
}
|
||||
|
||||
bool DrawNewAirportTile(TileInfo *ti, Station *st, const AirportTileSpec *airts)
|
||||
|
@ -278,7 +279,7 @@ bool DrawNewAirportTile(TileInfo *ti, Station *st, const AirportTileSpec *airts)
|
|||
|
||||
auto processor = group->ProcessRegisters(object, nullptr);
|
||||
auto dts = processor.GetLayout();
|
||||
AirportDrawTileLayout(ti, dts, Company::Get(st->owner)->colour);
|
||||
AirportDrawTileLayout(ti, dts, GetCompanyPalette(st->owner));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -528,7 +528,7 @@ struct NewsWindow : Window {
|
|||
|
||||
case WID_N_MGR_FACE: {
|
||||
const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
|
||||
DrawCompanyManagerFace(cni->face, cni->colour, r);
|
||||
DrawCompanyManagerFace(cni->face, cni->colour, r); // XXX TODO this should be a palette
|
||||
GfxFillRect(r, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
|
||||
break;
|
||||
}
|
||||
|
|
139
src/palette.cpp
139
src/palette.cpp
|
@ -15,6 +15,7 @@
|
|||
#include "landscape_type.h"
|
||||
#include "palette_func.h"
|
||||
#include "settings_type.h"
|
||||
#include "sprite.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "table/palettes.h"
|
||||
|
@ -84,6 +85,7 @@ static uint CalculateColourDistance(const Colour &col1, int r2, int g2, int b2)
|
|||
/* Palette indexes for conversion. See docs/palettes/palette_key.png */
|
||||
const uint8_t PALETTE_INDEX_CC_START = 198; ///< Palette index of start of company colour remap area.
|
||||
const uint8_t PALETTE_INDEX_CC_END = PALETTE_INDEX_CC_START + 8; ///< Palette index of end of company colour remap area.
|
||||
const uint8_t PALETTE_INDEX_CC2_START = 80; ///< Palette index of start of second company colour remap area.
|
||||
const uint8_t PALETTE_INDEX_START = 1; ///< Palette index of start of defined palette.
|
||||
const uint8_t PALETTE_INDEX_END = 215; ///< Palette index of end of defined palette.
|
||||
|
||||
|
@ -368,6 +370,81 @@ TextColour GetContrastColour(PixelColour background, uint8_t threshold)
|
|||
return sq1000_brightness < ((uint) threshold) * ((uint) threshold) * 1000 ? TC_WHITE : TC_BLACK;
|
||||
}
|
||||
|
||||
HsvColour ConvertRgbToHsv(Colour rgb)
|
||||
{
|
||||
HsvColour hsv;
|
||||
|
||||
uint8_t rgbmin = std::min({rgb.r, rgb.g, rgb.b});
|
||||
uint8_t rgbmax = std::max({rgb.r, rgb.g, rgb.b});
|
||||
|
||||
hsv.v = rgbmax;
|
||||
if (hsv.v == 0) {
|
||||
hsv.h = 0;
|
||||
hsv.s = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
int d = rgbmax - rgbmin;
|
||||
hsv.s = HsvColour::SAT_MAX * d / rgbmax;
|
||||
if (hsv.s == 0) {
|
||||
hsv.h = 0;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
int hue;
|
||||
if (rgbmax == rgb.r) {
|
||||
hue = HsvColour::HUE_RGN * 0 + HsvColour::HUE_RGN * ((int)rgb.g - (int)rgb.b) / d;
|
||||
} else if (rgbmax == rgb.g) {
|
||||
hue = HsvColour::HUE_RGN * 2 + HsvColour::HUE_RGN * ((int)rgb.b - (int)rgb.r) / d;
|
||||
} else {
|
||||
hue = HsvColour::HUE_RGN * 4 + HsvColour::HUE_RGN * ((int)rgb.r - (int)rgb.g) / d;
|
||||
}
|
||||
if (hue > HsvColour::HUE_MAX) hue -= HsvColour::HUE_MAX;
|
||||
if (hue < 0) hue += HsvColour::HUE_MAX;
|
||||
hsv.h = hue;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
Colour ConvertHsvToRgb(HsvColour hsv)
|
||||
{
|
||||
if (hsv.s == 0) return Colour(hsv.v, hsv.v, hsv.v);
|
||||
if (hsv.h >= HsvColour::HUE_MAX) hsv.h = 0;
|
||||
|
||||
int region = hsv.h / HsvColour::HUE_RGN;
|
||||
int remainder = (hsv.h - (region * HsvColour::HUE_RGN)) * 6;
|
||||
int p = (hsv.v * (HsvColour::SAT_MAX - hsv.s)) / HsvColour::SAT_MAX;
|
||||
int q = (hsv.v * (HsvColour::SAT_MAX - ((hsv.s * remainder) / HsvColour::HUE_MAX))) / HsvColour::SAT_MAX;
|
||||
int t = (hsv.v * (HsvColour::SAT_MAX - ((hsv.s * (HsvColour::HUE_MAX - remainder)) / HsvColour::HUE_MAX))) / HsvColour::SAT_MAX;
|
||||
|
||||
switch (region) {
|
||||
case 0: return Colour(hsv.v, t, p);
|
||||
case 1: return Colour(q, hsv.v, p);
|
||||
case 2: return Colour(p, hsv.v, t);
|
||||
case 3: return Colour(p, q, hsv.v);
|
||||
case 4: return Colour(t, p, hsv.v);
|
||||
default: return Colour(hsv.v, p, q);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust brightness of an HSV colour.
|
||||
* @param hsv colour to adjust.
|
||||
* @param shade shade to apply.
|
||||
* @param contrast contrast of shade.
|
||||
* @returns Adjusted HSV colour.
|
||||
**/
|
||||
HsvColour AdjustHsvColourBrightness(HsvColour hsv, ColourShade shade, int contrast)
|
||||
{
|
||||
HsvColour r = hsv;
|
||||
int amt = (shade - SHADE_NORMAL) * (16 + contrast) / 8;
|
||||
int overflow = (hsv.v + amt) - HsvColour::VAL_MAX;
|
||||
r.v = ClampTo<uint8_t>(hsv.v + amt);
|
||||
r.s = ClampTo<uint8_t>(hsv.s - std::max(0, overflow));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lookup table of colour shades for all 16 colour gradients.
|
||||
* 8 colours per gradient from darkest (0) to lightest (7)
|
||||
|
@ -387,6 +464,10 @@ struct ColourGradients
|
|||
*/
|
||||
PixelColour GetColourGradient(Colours colour, ColourShade shade)
|
||||
{
|
||||
ColoursPacker cp(colour);
|
||||
if (cp.IsCustom()) {
|
||||
return ConvertHsvToRgb(AdjustHsvColourBrightness(cp.Hsv(), shade, cp.GetContrast()));
|
||||
}
|
||||
return ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END];
|
||||
}
|
||||
|
||||
|
@ -402,3 +483,61 @@ void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_in
|
|||
assert(shade < SHADE_END);
|
||||
ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END] = palette_index;
|
||||
}
|
||||
|
||||
PixelColour::PixelColour(Colour colour) : r(colour.r), g(colour.g), b(colour.b)
|
||||
{
|
||||
this->p = GetNearestColourIndex(colour);
|
||||
}
|
||||
|
||||
TextColour PixelColour::ToTextColour() const
|
||||
{
|
||||
TextColour tc = static_cast<TextColour>(this->p) | TC_IS_PALETTE_COLOUR;
|
||||
if (this->HasRGB()) {
|
||||
tc |= TC_IS_RGB_COLOUR;
|
||||
TextColourPacker tcp(tc);
|
||||
tcp.SetR(this->r);
|
||||
tcp.SetG(this->g);
|
||||
tcp.SetB(this->b);
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
|
||||
std::pair<Colour, uint8_t> GetCompanyColourRGB(Colours colour)
|
||||
{
|
||||
static constexpr uint8_t CC_PALETTE_CONTRAST = 90;
|
||||
|
||||
PaletteID pal = GetColourPalette(colour);
|
||||
const RecolourSprite *map = GetRecolourSprite(pal);
|
||||
|
||||
Colour rgb = _palette.palette[map->palette[PALETTE_INDEX_CC_START + SHADE_NORMAL]];
|
||||
return {rgb, CC_PALETTE_CONTRAST};
|
||||
}
|
||||
|
||||
PaletteID CreateCompanyColourRemap(Colours colour1, Colours colour2, bool twocc, PaletteID basemap, PaletteID hint)
|
||||
{
|
||||
DeallocateDynamicSprite(hint);
|
||||
|
||||
PaletteID pal = AllocateDynamicSprite();
|
||||
const RecolourSprite *base = GetRecolourSprite(basemap);
|
||||
RecolourSpriteRGBA *p = new (InjectSprite(SpriteType::Recolour, pal, sizeof(RecolourSpriteRGBA)).data()) RecolourSpriteRGBA();
|
||||
|
||||
/* Copy base remap */
|
||||
p->palette = base->palette;
|
||||
std::ranges::transform(p->palette, p->rgba.begin(), [](const uint8_t &col) { return _palette.palette[col]; });
|
||||
|
||||
auto apply_colour = [](RecolourSpriteRGBA &remap, uint8_t index, Colours colour) {
|
||||
ColoursPacker cp{colour};
|
||||
if (!cp.IsCustom()) return;
|
||||
|
||||
HsvColour hsv = cp.Hsv();
|
||||
uint8_t con = cp.GetContrast();
|
||||
for (ColourShade shade = SHADE_BEGIN; shade != SHADE_END; ++shade) {
|
||||
remap.rgba[index + shade] = ConvertHsvToRgb(AdjustHsvColourBrightness(hsv, shade, con));
|
||||
}
|
||||
};
|
||||
|
||||
apply_colour(*p, PALETTE_INDEX_CC_START, colour1);
|
||||
if (twocc) apply_colour(*p, PALETTE_INDEX_CC2_START, colour2);
|
||||
|
||||
return pal;
|
||||
}
|
||||
|
|
|
@ -83,9 +83,16 @@ enum ColourShade : uint8_t {
|
|||
};
|
||||
DECLARE_INCREMENT_DECREMENT_OPERATORS(ColourShade)
|
||||
|
||||
HsvColour ConvertRgbToHsv(Colour rgb);
|
||||
Colour ConvertHsvToRgb(HsvColour hsv);
|
||||
HsvColour AdjustHsvColourBrightness(HsvColour hsv, ColourShade shade, int contrast);
|
||||
|
||||
PixelColour GetColourGradient(Colours colour, ColourShade shade);
|
||||
void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_colour);
|
||||
|
||||
std::pair<Colour, uint8_t> GetCompanyColourRGB(Colours colour);
|
||||
PaletteID CreateCompanyColourRemap(Colours rgb1, Colours rgb2, bool twocc, PaletteID basemap, PaletteID hint);
|
||||
|
||||
/**
|
||||
* Return the colour for a particular greyscale level.
|
||||
* @param level Intensity, 0 = black, 15 = white
|
||||
|
@ -124,4 +131,84 @@ static constexpr PixelColour PC_FIELDS {0x25}; ///< Light
|
|||
static constexpr PixelColour PC_TREES {0x57}; ///< Green palette colour for trees.
|
||||
static constexpr PixelColour PC_WATER {0xC9}; ///< Dark blue palette colour for water.
|
||||
|
||||
/**
|
||||
* Stretch TNumBits to fill 8 bits.
|
||||
* The most-significant digits are repeated as least-significant digits so that the full 8 bit range is used, e.g.:
|
||||
* 000000 -> 00000000, 111100 -> 11110011, 111111 -> 11111111
|
||||
* @param v Value of TNumBits to stretch.
|
||||
* @returns 8 bit stretched value.
|
||||
*/
|
||||
template <uint TNumBits>
|
||||
inline constexpr uint8_t StretchBits(uint8_t v)
|
||||
{
|
||||
return (v << (8 - TNumBits)) | (v >> (8 - (8 - TNumBits) * 2));
|
||||
}
|
||||
|
||||
struct ColoursPacker
|
||||
{
|
||||
Colours &c;
|
||||
|
||||
explicit constexpr ColoursPacker(Colours &c) : c(c) { }
|
||||
|
||||
/*
|
||||
* Constants for the bit packing used by Colours.
|
||||
*/
|
||||
static constexpr const uint IS_CUSTOM_BIT = 4;
|
||||
static constexpr const uint INDEX_START = 0; ///< Packed start of index component
|
||||
static constexpr const uint INDEX_SIZE = 4; ///< Packed size of index component
|
||||
static constexpr const uint HUE_START = 7; ///< Packed start of hue component
|
||||
static constexpr const uint HUE_SIZE = 9; ///< Packed size of hue component
|
||||
static constexpr const uint SAT_START = 16; ///< Packed start of saturation component
|
||||
static constexpr const uint SAT_SIZE = 6; ///< Packed size of saturation component
|
||||
static constexpr const uint VAL_START = 22; ///< Packed start of value component
|
||||
static constexpr const uint VAL_SIZE = 6; ///< Packed size of value component
|
||||
static constexpr const uint CON_START = 28; ///< Packed start of contrast component
|
||||
static constexpr const uint CON_SIZE = 4; ///< Packed size of contrast component
|
||||
|
||||
/* Colours is considered unused and blank if only the I component is set. */
|
||||
inline constexpr bool IsCustom() const { return HasBit(this->c, IS_CUSTOM_BIT); }
|
||||
|
||||
inline constexpr uint8_t GetIndex() const { return GB(this->c, INDEX_START, INDEX_SIZE); }
|
||||
inline constexpr uint16_t GetHue() const { return GB(this->c, HUE_START, HUE_SIZE) * HsvColour::HUE_MAX / (1U << 9); }
|
||||
inline constexpr uint8_t GetSaturation() const { return StretchBits<SAT_SIZE>(GB(this->c, SAT_START, SAT_SIZE)); }
|
||||
inline constexpr uint8_t GetValue() const { return StretchBits<VAL_SIZE>(GB(this->c, VAL_START, VAL_SIZE)); }
|
||||
inline constexpr uint8_t GetContrast() const { return StretchBits<CON_SIZE>(GB(this->c, CON_START, CON_SIZE)); }
|
||||
|
||||
inline void SetCustom(bool v) { SB(this->c, IS_CUSTOM_BIT, 1, v); }
|
||||
|
||||
inline void SetIndex(uint8_t v) { SB(this->c, INDEX_START, INDEX_SIZE, v); }
|
||||
inline void SetHue(uint16_t v) { SB(this->c, HUE_START, HUE_SIZE, v * (1U << HUE_SIZE) / HsvColour::HUE_MAX); }
|
||||
inline void SetSaturation(uint8_t v) { SB(this->c, SAT_START, SAT_SIZE, v >> (8 - SAT_SIZE)); }
|
||||
inline void SetValue(uint8_t v) { SB(this->c, VAL_START, VAL_SIZE, v >> (8 - VAL_SIZE)); }
|
||||
inline void SetContrast(uint8_t v) { SB(this->c, CON_START, CON_SIZE, v >> (8 - CON_SIZE)); }
|
||||
|
||||
inline constexpr HsvColour Hsv() const { return {this->GetHue(), this->GetSaturation(), this->GetValue()}; }
|
||||
};
|
||||
|
||||
struct TextColourPacker
|
||||
{
|
||||
TextColour &tc;
|
||||
|
||||
constexpr TextColourPacker(TextColour &tc) : tc(tc) { }
|
||||
|
||||
static constexpr uint8_t R_START = 12; ///< Packed start of red component
|
||||
static constexpr uint8_t R_SIZE = 6; ///< Packed size of red component
|
||||
|
||||
static constexpr uint8_t G_START = 18; ///< Packed start of green component
|
||||
static constexpr uint8_t G_SIZE = 6; ///< Packed size of green component
|
||||
|
||||
static constexpr uint8_t B_START = 24; ///< Packed start of blue component
|
||||
static constexpr uint8_t B_SIZE = 6; ///< Packed size of blue component
|
||||
|
||||
inline constexpr uint8_t GetR() const { return StretchBits<R_SIZE>(GB(this->tc, R_START, R_SIZE)); }
|
||||
inline constexpr uint8_t GetG() const { return StretchBits<G_SIZE>(GB(this->tc, G_START, G_SIZE)); }
|
||||
inline constexpr uint8_t GetB() const { return StretchBits<B_SIZE>(GB(this->tc, B_START, B_SIZE)); }
|
||||
|
||||
inline constexpr void SetR(uint8_t v) { SB(this->tc, R_START, R_SIZE, v >> (8 - R_SIZE)); }
|
||||
inline constexpr void SetG(uint8_t v) { SB(this->tc, G_START, G_SIZE, v >> (8 - G_SIZE)); }
|
||||
inline constexpr void SetB(uint8_t v) { SB(this->tc, B_START, B_SIZE, v >> (8 - B_SIZE)); }
|
||||
|
||||
inline constexpr Colour ToColour() const { return Colour(this->GetR(), this->GetG(), this->GetB()); }
|
||||
};
|
||||
|
||||
#endif /* PALETTE_FUNC_H */
|
||||
|
|
|
@ -3383,6 +3383,8 @@ bool AfterLoadGame()
|
|||
}
|
||||
|
||||
for (Company *c : Company::Iterate()) {
|
||||
UpdateLivery(c->livery[LS_DEFAULT], true);
|
||||
_company_palettes[c->index] = c->livery[LS_DEFAULT].cached_pal_1cc;
|
||||
UpdateCompanyLiveries(c);
|
||||
}
|
||||
|
||||
|
|
|
@ -410,9 +410,11 @@ public:
|
|||
class SlCompanyLiveries : public DefaultSaveLoadHandler<SlCompanyLiveries, CompanyProperties> {
|
||||
public:
|
||||
static inline const SaveLoad description[] = {
|
||||
SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Livery, colour1, SLE_FILE_U8 | SLE_VAR_U32, SLV_34, SLV_CUSTOM_COMPANY_COLOURS),
|
||||
SLE_CONDVAR(Livery, colour2, SLE_FILE_U8 | SLE_VAR_U32, SLV_34, SLV_CUSTOM_COMPANY_COLOURS),
|
||||
SLE_CONDVAR(Livery, colour1, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Livery, colour2, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
|
||||
};
|
||||
static inline const SaveLoadCompatTable compat_description = _company_liveries_compat;
|
||||
|
||||
|
@ -511,7 +513,8 @@ static const SaveLoad _company_desc[] = {
|
|||
SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(CompanyProperties, max_loan, SLE_INT64, SLV_MAX_LOAN_FOR_COMPANY, SL_MAX_VERSION),
|
||||
|
||||
SLE_VAR(CompanyProperties, colour, SLE_UINT8),
|
||||
SLE_CONDVAR(CompanyProperties, colour, SLE_FILE_U8 | SLE_VAR_U32, SL_MIN_VERSION, SLV_CUSTOM_COMPANY_COLOURS),
|
||||
SLE_CONDVAR(CompanyProperties, colour, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
|
||||
SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8),
|
||||
SLE_VAR(CompanyProperties, block_preview, SLE_UINT8),
|
||||
|
||||
|
|
|
@ -23,8 +23,10 @@ static const SaveLoad _group_desc[] = {
|
|||
SLE_VAR(Group, vehicle_type, SLE_UINT8),
|
||||
SLE_VAR(Group, flags, SLE_UINT8),
|
||||
SLE_CONDVAR(Group, livery.in_use, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Group, livery.colour1, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Group, livery.colour2, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Group, livery.colour1, SLE_FILE_U8 | SLE_VAR_U32, SLV_GROUP_LIVERIES, SLV_CUSTOM_COMPANY_COLOURS),
|
||||
SLE_CONDVAR(Group, livery.colour2, SLE_FILE_U8 | SLE_VAR_U32, SLV_GROUP_LIVERIES, SLV_CUSTOM_COMPANY_COLOURS),
|
||||
SLE_CONDVAR(Group, livery.colour1, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Group, livery.colour2, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Group, parent, SLE_UINT16, SLV_189, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Group, number, SLE_UINT16, SLV_GROUP_NUMBERS, SL_MAX_VERSION),
|
||||
};
|
||||
|
|
|
@ -179,7 +179,8 @@ static const SaveLoad _industry_desc[] = {
|
|||
|
||||
SLE_VAR(Industry, type, SLE_UINT8),
|
||||
SLE_VAR(Industry, owner, SLE_UINT8),
|
||||
SLE_VAR(Industry, random_colour, SLE_UINT8),
|
||||
SLE_CONDVAR(Industry, random_colour, SLE_FILE_U8 | SLE_VAR_U32, SL_MIN_VERSION, SLV_CUSTOM_COMPANY_COLOURS),
|
||||
SLE_CONDVAR(Industry, random_colour, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
|
||||
SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, SLV_31, SL_MAX_VERSION),
|
||||
SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8),
|
||||
|
|
|
@ -406,6 +406,7 @@ enum SaveLoadVersion : uint16_t {
|
|||
SLV_FACE_STYLES, ///< 355 PR#14319 Addition of face styles, replacing gender and ethnicity.
|
||||
SLV_INDUSTRY_NUM_VALID_HISTORY, ///< 356 PR#14416 Store number of valid history records for industries.
|
||||
SLV_INDUSTRY_ACCEPTED_HISTORY, ///< 357 PR#14321 Add per-industry history of cargo delivered and waiting.
|
||||
SLV_CUSTOM_COMPANY_COLOURS, ///< 358 PR#11634 Custom company colours.
|
||||
|
||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||
};
|
||||
|
|
|
@ -210,6 +210,7 @@ struct GUISettings {
|
|||
uint8_t osk_activation; ///< Mouse gesture to trigger the OSK.
|
||||
Colours starting_colour; ///< default color scheme for the company to start a new game with
|
||||
Colours starting_colour_secondary; ///< default secondary color scheme for the company to start a new game with
|
||||
Colours preset_colours[16]; ///< custom colour presets.
|
||||
bool show_newgrf_name; ///< Show the name of the NewGRF in the build vehicle window
|
||||
bool show_cargo_in_vehicle_lists; ///< Show the cargoes the vehicles can carry in the list windows
|
||||
bool auto_remove_signals; ///< automatically remove signals when in the way during rail construction
|
||||
|
|
|
@ -185,6 +185,6 @@ inline PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, Pal
|
|||
* @param colour Colour.
|
||||
* @return Recolour palette.
|
||||
*/
|
||||
static inline PaletteID GetColourPalette(Colours colour) { return PALETTE_RECOLOUR_START + colour; }
|
||||
static inline PaletteID GetColourPalette(Colours colour) { return PALETTE_RECOLOUR_START + (colour % COLOUR_END); }
|
||||
|
||||
#endif /* SPRITE_H */
|
||||
|
|
|
@ -406,6 +406,40 @@ static bool ResizeSprites(SpriteLoader::SpriteCollection &sprite, ZoomLevels spr
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read recolour sprite data.
|
||||
* @param file SpriteFile to read from.
|
||||
* @param entries Number of entries to read.
|
||||
*/
|
||||
void RecolourSprite::Read(SpriteFile &file, size_t entries)
|
||||
{
|
||||
assert(entries <= RecolourSprite::PALETTE_SIZE);
|
||||
if (file.NeedsPaletteRemap()) {
|
||||
/* Remapping from "Windows" to "DOS" requires a temporary buffer as entries are overwritten. */
|
||||
std::array<uint8_t, RecolourSprite::PALETTE_SIZE> tmp{};
|
||||
file.ReadBlock(tmp.data(), entries);
|
||||
|
||||
for (uint i = 0; i < entries; ++i) {
|
||||
this->palette[i] = _palmap_w2d[tmp[_palmap_d2w[i]]];
|
||||
}
|
||||
} else {
|
||||
file.ReadBlock(this->palette.data(), entries);
|
||||
}
|
||||
}
|
||||
|
||||
void RecolourSpriteRGBA::Read(SpriteFile &file, size_t entries)
|
||||
{
|
||||
this->RecolourSprite::Read(file, entries);
|
||||
|
||||
/* Colour is byte-arranged differently by platform, so read components individually. */
|
||||
for (uint i = 0; i < entries; ++i) {
|
||||
this->rgba[i].r = file.ReadByte();
|
||||
this->rgba[i].g = file.ReadByte();
|
||||
this->rgba[i].b = file.ReadByte();
|
||||
this->rgba[i].a = file.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a recolour sprite into memory.
|
||||
* @param file GRF we're reading from.
|
||||
|
@ -416,31 +450,23 @@ static bool ResizeSprites(SpriteLoader::SpriteCollection &sprite, ZoomLevels spr
|
|||
*/
|
||||
static void *ReadRecolourSprite(SpriteFile &file, size_t file_pos, uint num, SpriteAllocator &allocator)
|
||||
{
|
||||
/* "Normal" recolour sprites are ALWAYS 257 bytes. Then there is a small
|
||||
* number of recolour sprites that are 17 bytes that only exist in DOS
|
||||
* GRFs which are the same as 257 byte recolour sprites, but with the last
|
||||
* 240 bytes zeroed. */
|
||||
static const uint RECOLOUR_SPRITE_SIZE = 257;
|
||||
uint8_t *dest = allocator.Allocate<uint8_t>(std::max(RECOLOUR_SPRITE_SIZE, num));
|
||||
|
||||
file.SeekTo(file_pos, SEEK_SET);
|
||||
if (file.NeedsPaletteRemap()) {
|
||||
uint8_t *dest_tmp = new uint8_t[std::max(RECOLOUR_SPRITE_SIZE, num)];
|
||||
|
||||
/* Only a few recolour sprites are less than 257 bytes */
|
||||
if (num < RECOLOUR_SPRITE_SIZE) std::fill_n(dest_tmp, RECOLOUR_SPRITE_SIZE, 0);
|
||||
file.ReadBlock(dest_tmp, num);
|
||||
/* The first byte of the recolour sprite records the number of entries, with
|
||||
* the caveat that as this is a single byte 256 is recorded as 0. */
|
||||
uint entries = file.ReadByte();
|
||||
if (entries == 0) entries = 256;
|
||||
--num;
|
||||
|
||||
/* The data of index 0 is never used; "literal 00" according to the (New)GRF specs. */
|
||||
for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
|
||||
dest[i] = _palmap_w2d[dest_tmp[_palmap_d2w[i - 1] + 1]];
|
||||
}
|
||||
delete[] dest_tmp;
|
||||
} else {
|
||||
file.ReadBlock(dest, num);
|
||||
if (entries > num) {
|
||||
Debug(grf, 1, "ReadRecolourSprite: Expected recolour sprite with {} entries but only {} present", entries, num);
|
||||
entries = num;
|
||||
}
|
||||
|
||||
return dest;
|
||||
num -= entries;
|
||||
RecolourSprite *rs = (num == entries * 4) ? allocator.New<RecolourSpriteRGBA>() : allocator.New<RecolourSprite>();
|
||||
rs->Read(file, entries);
|
||||
return rs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -733,7 +759,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
|
|||
SpriteID i = 0;
|
||||
for (; i != static_cast<SpriteID>(_spritecache.size()) && candidate_bytes < to_remove; i++) {
|
||||
const SpriteCache *sc = GetSpriteCache(i);
|
||||
if (sc->ptr != nullptr) {
|
||||
if (sc->ptr != nullptr && sc->file != nullptr) {
|
||||
push({ sc->lru, i, sc->length });
|
||||
if (candidate_bytes >= to_remove) break;
|
||||
}
|
||||
|
@ -742,7 +768,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
|
|||
* only sprites with LRU values <= the maximum (i.e. the top of the heap) need to be considered */
|
||||
for (; i != static_cast<SpriteID>(_spritecache.size()); i++) {
|
||||
const SpriteCache *sc = GetSpriteCache(i);
|
||||
if (sc->ptr != nullptr && sc->lru <= candidates.front().lru) {
|
||||
if (sc->ptr != nullptr && sc->file != nullptr && sc->lru <= candidates.front().lru) {
|
||||
push({ sc->lru, i, sc->length });
|
||||
while (!candidates.empty() && candidate_bytes - candidates.front().size >= to_remove) {
|
||||
pop();
|
||||
|
@ -784,6 +810,10 @@ void IncreaseSpriteLRU()
|
|||
|
||||
void SpriteCache::ClearSpriteData()
|
||||
{
|
||||
if (this->ptr == nullptr) return;
|
||||
|
||||
if (this->type == SpriteType::Recolour) reinterpret_cast<RecolourSprite *>(this->ptr.get())->~RecolourSprite();
|
||||
|
||||
_spritecache_bytes_used -= this->length;
|
||||
this->ptr.reset();
|
||||
}
|
||||
|
@ -795,6 +825,32 @@ void *UniquePtrSpriteAllocator::AllocatePtr(size_t size)
|
|||
return this->data.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and inject memory for a memory-based sprite.
|
||||
*/
|
||||
std::span<std::byte> InjectSprite(SpriteType type, SpriteID load_index, size_t len)
|
||||
{
|
||||
if (SpriteExists(load_index)) GetSpriteCache(load_index)->ClearSpriteData();
|
||||
|
||||
SpriteCache *sc = AllocateSpriteCache(load_index);
|
||||
sc->file_pos = SIZE_MAX;
|
||||
sc->file = nullptr;
|
||||
sc->id = 0;
|
||||
sc->lru = 0;
|
||||
sc->type = type;
|
||||
sc->warned = false;
|
||||
sc->control_flags = {};
|
||||
|
||||
UniquePtrSpriteAllocator cache_allocator;
|
||||
cache_allocator.Allocate<std::byte>(len);
|
||||
|
||||
sc->ptr = std::move(cache_allocator.data);
|
||||
sc->length = static_cast<uint32_t>(cache_allocator.size);
|
||||
_spritecache_bytes_used += sc->length;
|
||||
|
||||
return {sc->ptr.get(), sc->length};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the case when a sprite of different type is requested than is present in the SpriteCache.
|
||||
* For SpriteType::Font sprites, it is normal. In other cases, default sprite is loaded instead.
|
||||
|
@ -928,3 +984,44 @@ void GfxClearFontSpriteCache()
|
|||
}
|
||||
|
||||
/* static */ SpriteCollMap<ReusableBuffer<SpriteLoader::CommonPixel>> SpriteLoader::Sprite::buffer;
|
||||
|
||||
static SpriteID _sprites_end; ///< First usable free sprite ID.
|
||||
static std::vector<uint32_t> _dynamic_sprites; ///< List of used/free custom sprite slots.
|
||||
|
||||
/**
|
||||
* Clear custom sprites mapping and set first usable free sprite ID.
|
||||
*/
|
||||
void ClearDynamicSprites()
|
||||
{
|
||||
_dynamic_sprites.clear();
|
||||
_sprites_end = _spritecache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a custom sprite ID.
|
||||
*/
|
||||
SpriteID AllocateDynamicSprite()
|
||||
{
|
||||
/* Find first unused slot, or make one. */
|
||||
auto it = std::ranges::find(_dynamic_sprites, 0);
|
||||
if (it == std::end(_dynamic_sprites)) it = _dynamic_sprites.emplace(it, 0);
|
||||
|
||||
(*it)++;
|
||||
return _sprites_end + std::distance(std::begin(_dynamic_sprites), it);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a custom sprite ID as deallocated.
|
||||
* The sprite slot is merely marked as reusable.
|
||||
*/
|
||||
void DeallocateDynamicSprite(SpriteID sprite)
|
||||
{
|
||||
if (sprite >= _sprites_end && sprite < _sprites_end + _dynamic_sprites.size()) {
|
||||
assert(_dynamic_sprites[sprite - _sprites_end] > 0);
|
||||
--_dynamic_sprites[sprite - _sprites_end];
|
||||
|
||||
if (_dynamic_sprites[sprite - _sprites_end] == 0) {
|
||||
GetSpriteCache(sprite)->ClearSpriteData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,10 +41,9 @@ inline const Sprite *GetSprite(SpriteID sprite, SpriteType type)
|
|||
return (Sprite*)GetRawSprite(sprite, type);
|
||||
}
|
||||
|
||||
inline const uint8_t *GetNonSprite(SpriteID sprite, SpriteType type)
|
||||
inline const RecolourSprite *GetRecolourSprite(SpriteID sprite)
|
||||
{
|
||||
assert(type == SpriteType::Recolour);
|
||||
return (uint8_t*)GetRawSprite(sprite, type);
|
||||
return static_cast<RecolourSprite *>(GetRawSprite(sprite, SpriteType::Recolour));
|
||||
}
|
||||
|
||||
void GfxInitSpriteMem();
|
||||
|
@ -60,5 +59,10 @@ size_t GetGRFSpriteOffset(uint32_t id);
|
|||
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id);
|
||||
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num);
|
||||
void DupSprite(SpriteID old_spr, SpriteID new_spr);
|
||||
std::span<std::byte> InjectSprite(SpriteType type, SpriteID load_index, size_t len);
|
||||
|
||||
void ClearDynamicSprites();
|
||||
SpriteID AllocateDynamicSprite();
|
||||
void DeallocateDynamicSprite(SpriteID spite);
|
||||
|
||||
#endif /* SPRITECACHE_H */
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#define SPRITECACHE_TYPE_H
|
||||
|
||||
#include "core/enum_type.hpp"
|
||||
#include "gfx_type.h"
|
||||
#include "spriteloader/sprite_file_type.hpp"
|
||||
|
||||
/** Data structure describing a sprite. */
|
||||
struct Sprite {
|
||||
|
@ -21,6 +23,29 @@ struct Sprite {
|
|||
std::byte data[]; ///< Sprite data.
|
||||
};
|
||||
|
||||
/** Data structure describing a palette remap. */
|
||||
class RecolourSprite {
|
||||
public:
|
||||
static constexpr size_t PALETTE_SIZE = 256; ///< Number of entries in a recolour sprite.
|
||||
|
||||
virtual ~RecolourSprite() {}
|
||||
virtual void Read(SpriteFile &file, size_t entries);
|
||||
inline const uint8_t *GetPaletteRemap() const { return this->palette.data(); }
|
||||
virtual bool IsRGB() const { return false; }
|
||||
virtual const Colour *GetRGBARemap() const { return nullptr; }
|
||||
|
||||
std::array<uint8_t, PALETTE_SIZE> palette{}; ///< Palette index remap, mapping from one palette index to another.
|
||||
};
|
||||
|
||||
class RecolourSpriteRGBA : public RecolourSprite {
|
||||
public:
|
||||
void Read(SpriteFile &file, size_t entries) override;
|
||||
bool IsRGB() const override { return true; }
|
||||
const Colour *GetRGBARemap() const override { return this->rgba.data(); }
|
||||
|
||||
std::array<Colour, PALETTE_SIZE> rgba{}; ///< RGBA remap, mapping from palette index to colour.
|
||||
};
|
||||
|
||||
enum class SpriteCacheCtrlFlag : uint8_t {
|
||||
AllowZoomMin1xPal, ///< Allow use of sprite min zoom setting at 1x in palette mode.
|
||||
AllowZoomMin1x32bpp, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.
|
||||
|
|
|
@ -117,6 +117,18 @@ public:
|
|||
return static_cast<T *>(this->AllocatePtr(size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate memory and construct an object in the sprite cache.
|
||||
* @tparam T Type to construct.
|
||||
* @tparam Targs The constructor parameter types.
|
||||
* @param args Parameters for the constructor.
|
||||
*/
|
||||
template <typename T, typename... Targs>
|
||||
T *New(Targs &&... args)
|
||||
{
|
||||
return new (this->Allocate<T>(sizeof(T))) T(std::forward<Targs &&>(args)...);
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Allocate memory for a sprite.
|
||||
|
|
|
@ -26,6 +26,7 @@ static const SettingVariant _gui_settings_table[] = {
|
|||
};
|
||||
[templates]
|
||||
SDTC_BOOL = SDTC_BOOL( $var, SettingFlags({$flags}), $def, $str, $strhelp, $strval, $pre_cb, $post_cb, $str_cb, $help_cb, $val_cb, $def_cb, $from, $to, $cat, $extra, $startup),
|
||||
SDTC_LIST = SDTC_LIST( $var, $type, SettingFlags({$flags}), $def, $from, $to, $cat, $extra, $startup),
|
||||
SDTC_OMANY = SDTC_OMANY( $var, $type, SettingFlags({$flags}), $def, $max, $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $str_cb, $help_cb, $val_cb, $def_cb, $from, $to, $cat, $extra, $startup),
|
||||
SDTC_VAR = SDTC_VAR( $var, $type, SettingFlags({$flags}), $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $str_cb, $help_cb, $val_cb, $def_cb, $range_cb, $from, $to, $cat, $extra, $startup),
|
||||
|
||||
|
@ -348,7 +349,7 @@ post_cb = InvalidateCompanyLiveryWindow
|
|||
|
||||
[SDTC_VAR]
|
||||
var = gui.starting_colour
|
||||
type = SLE_UINT8
|
||||
type = SLE_UINT32
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown
|
||||
def = COLOUR_END
|
||||
min = 0
|
||||
|
@ -359,7 +360,7 @@ strval = STR_COLOUR_DARK_BLUE
|
|||
|
||||
[SDTC_VAR]
|
||||
var = gui.starting_colour_secondary
|
||||
type = SLE_UINT8
|
||||
type = SLE_UINT32
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown
|
||||
def = COLOUR_END
|
||||
min = 0
|
||||
|
@ -368,6 +369,13 @@ str = STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_SECONDARY
|
|||
strhelp = STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_SECONDARY_HELPTEXT
|
||||
strval = STR_COLOUR_SECONDARY_DARK_BLUE
|
||||
|
||||
[SDTC_LIST]
|
||||
var = gui.preset_colours
|
||||
type = SLE_UINT32
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
|
||||
def = """"
|
||||
cat = SC_BASIC
|
||||
|
||||
[SDTC_BOOL]
|
||||
var = gui.auto_remove_signals
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
|
||||
|
|
|
@ -2045,7 +2045,6 @@ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_
|
|||
const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
|
||||
{
|
||||
const Company *c = Company::Get(company);
|
||||
LiveryScheme scheme = LS_DEFAULT;
|
||||
|
||||
if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
|
||||
if (v != nullptr) {
|
||||
|
@ -2063,11 +2062,12 @@ const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID
|
|||
* whether any _other_ liveries are in use. */
|
||||
if (c->livery[LS_DEFAULT].in_use != 0) {
|
||||
/* Determine the livery scheme to use */
|
||||
scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
|
||||
LiveryScheme scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
|
||||
if (c->livery[scheme].in_use != 0) return &c->livery[scheme];
|
||||
}
|
||||
}
|
||||
|
||||
return &c->livery[scheme];
|
||||
return &c->livery[LS_DEFAULT];
|
||||
}
|
||||
|
||||
|
||||
|
@ -2080,6 +2080,15 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng
|
|||
|
||||
const Engine *e = Engine::Get(engine_type);
|
||||
|
||||
/* Default livery for spectators */
|
||||
static const Livery default_livery = {
|
||||
0, COLOUR_GREY, COLOUR_GREY,
|
||||
PALETTE_RECOLOUR_START, SPR_2CCMAP_BASE, SPR_2CCMAP_BASE,
|
||||
};
|
||||
|
||||
bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
|
||||
const Livery *livery = Company::IsValidID(company) ? GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries) : &default_livery;
|
||||
|
||||
/* Check if we should use the colour map callback */
|
||||
if (e->info.callback_mask.Test(VehicleCallbackMask::ColourRemap)) {
|
||||
uint16_t callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
|
||||
|
@ -2090,6 +2099,15 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng
|
|||
/* If bit 14 is set, then the company colours are applied to the
|
||||
* map else it's returned as-is. */
|
||||
if (!HasBit(callback, 14)) {
|
||||
/* Test if this is the standard remap/reversed remap */
|
||||
if (map == PALETTE_RECOLOUR_START + (livery->colour1 & 0xF)) {
|
||||
map = livery->cached_pal_1cc;
|
||||
} else if (map == SPR_2CCMAP_BASE + (livery->colour1 & 0xF) + (livery->colour2 & 0xF) * 16) {
|
||||
map = livery->cached_pal_2cc;
|
||||
} else if (map == SPR_2CCMAP_BASE + (livery->colour2 & 0xF) + (livery->colour1 & 0xF) * 16) {
|
||||
map = livery->cached_pal_2cr;
|
||||
}
|
||||
|
||||
/* Update cache */
|
||||
if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
|
||||
return map;
|
||||
|
@ -2097,17 +2115,19 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng
|
|||
}
|
||||
}
|
||||
|
||||
bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
|
||||
|
||||
if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
|
||||
|
||||
/* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
|
||||
if (!Company::IsValidID(company)) return map;
|
||||
|
||||
const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
|
||||
|
||||
map += livery->colour1;
|
||||
if (twocc) map += livery->colour2 * 16;
|
||||
if (map == PALETTE_RECOLOUR_START || map == SPR_2CCMAP_BASE) {
|
||||
/* Use cached palette when using default remaps */
|
||||
map = twocc ? livery->cached_pal_2cc : livery->cached_pal_1cc;
|
||||
} else {
|
||||
/* Add offsets for custom NewGRF remaps */
|
||||
map += livery->colour1;
|
||||
if (twocc) map += livery->colour2 * 16;
|
||||
}
|
||||
|
||||
/* Update cache */
|
||||
if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
|
||||
|
|
|
@ -1290,7 +1290,7 @@ void OpenGLBackend::RenderOglSprite(const OpenGLSprite *gl_sprite, PaletteID pal
|
|||
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, OpenGLSprite::pal_pbo);
|
||||
_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
_glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, 256, GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1);
|
||||
_glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, 256, GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH))->GetPaletteRemap());
|
||||
_glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RED, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
|
|
@ -300,8 +300,6 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra
|
|||
if (flags.Test(FrameFlag::Transparent)) {
|
||||
GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR);
|
||||
} else {
|
||||
assert(colour < COLOUR_END);
|
||||
|
||||
const PixelColour dark = GetColourGradient(colour, SHADE_DARK);
|
||||
const PixelColour medium_dark = GetColourGradient(colour, SHADE_LIGHT);
|
||||
const PixelColour medium_light = GetColourGradient(colour, SHADE_LIGHTER);
|
||||
|
|
|
@ -75,6 +75,25 @@ enum CompanyFinancesWidgets : WidgetID {
|
|||
};
|
||||
|
||||
|
||||
/** Widgets of the #SelectCustomColourWindow class. */
|
||||
enum SelectCustomColourWidgets {
|
||||
WID_SCC_CAPTION, ///< Caption of window.
|
||||
WID_SCC_HUE,
|
||||
WID_SCC_SCROLLBAR_HUE, ///< Hue scrollbar.
|
||||
WID_SCC_SAT,
|
||||
WID_SCC_SCROLLBAR_SAT, ///< Saturation scrollbar.
|
||||
WID_SCC_VAL,
|
||||
WID_SCC_SCROLLBAR_VAL, ///< Value scrollbar.
|
||||
WID_SCC_CON,
|
||||
WID_SCC_SCROLLBAR_CON, ///< Contrast scrollbar.
|
||||
WID_SCC_OUTPUT,
|
||||
WID_SCC_DEFAULT, ///< First default colour.
|
||||
WID_SCC_DEFAULT_LAST = WID_SCC_DEFAULT + COLOUR_END - 1,
|
||||
WID_SCC_PRESETS, ///< First preset colour.
|
||||
WID_SCC_PRESETS_LAST = WID_SCC_PRESETS + COLOUR_END - 1,
|
||||
};
|
||||
|
||||
|
||||
/** Widgets of the #SelectCompanyLiveryWindow class. */
|
||||
enum SelectCompanyLiveryWidgets : WidgetID {
|
||||
WID_SCL_CAPTION, ///< Caption of window.
|
||||
|
|
|
@ -231,6 +231,12 @@ enum WindowClass : uint16_t {
|
|||
*/
|
||||
WC_COMPANY_COLOUR,
|
||||
|
||||
/**
|
||||
* Custom colour selection; %Window numbers:
|
||||
* - #CompanyID = #SelectCustomColourWidgets
|
||||
*/
|
||||
WC_CUSTOM_COLOUR,
|
||||
|
||||
/**
|
||||
* Alter company face window; %Window numbers:
|
||||
* - #CompanyID = #SelectCompanyManagerFaceWidgets
|
||||
|
|
Loading…
Reference in New Issue