mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
11 Commits
9429a1d7e8
...
d5e0fa7a73
Author | SHA1 | Date |
---|---|---|
|
d5e0fa7a73 | |
|
b32f46f36e | |
|
b82ffa3542 | |
|
8e2df7809b | |
|
821784004d | |
|
f0447d59d4 | |
|
cbdd358ae8 | |
|
2cdd50f40e | |
|
56942a15c7 | |
|
5eeda026a4 | |
|
edc5b8ea1f |
|
@ -187,7 +187,6 @@ add_files(
|
||||||
fios_gui.cpp
|
fios_gui.cpp
|
||||||
fontcache.cpp
|
fontcache.cpp
|
||||||
fontcache.h
|
fontcache.h
|
||||||
fontdetection.h
|
|
||||||
framerate_gui.cpp
|
framerate_gui.cpp
|
||||||
framerate_type.h
|
framerate_type.h
|
||||||
gamelog.cpp
|
gamelog.cpp
|
||||||
|
|
|
@ -321,19 +321,19 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
||||||
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8_t colour)
|
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||||
{
|
{
|
||||||
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
|
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
|
||||||
|
|
||||||
/* Set the colour in the anim-buffer too, if we are rendering to the screen */
|
/* Set the colour in the anim-buffer too, if we are rendering to the screen */
|
||||||
if (_screen_disable_anim) return;
|
if (_screen_disable_anim) return;
|
||||||
|
|
||||||
this->anim_buf[this->ScreenToAnimOffset((uint32_t *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8);
|
this->anim_buf[this->ScreenToAnimOffset((uint32_t *)video) + x + y * this->anim_buf_pitch] = colour.p | (DEFAULT_BRIGHTNESS << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash)
|
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);
|
const Colour c = LookupColourInPalette(colour.p);
|
||||||
|
|
||||||
if (_screen_disable_anim) {
|
if (_screen_disable_anim) {
|
||||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
||||||
|
@ -341,7 +341,7 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
uint16_t * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)video);
|
uint16_t * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)video);
|
||||||
const uint16_t anim_colour = colour | (DEFAULT_BRIGHTNESS << 8);
|
const uint16_t anim_colour = colour.p | (DEFAULT_BRIGHTNESS << 8);
|
||||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
||||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||||
offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour;
|
offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour;
|
||||||
|
@ -349,7 +349,7 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t colour)
|
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, PixelColour colour)
|
||||||
{
|
{
|
||||||
if (_screen_disable_anim) {
|
if (_screen_disable_anim) {
|
||||||
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
||||||
|
@ -357,7 +357,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t col
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Colour colour32 = LookupColourInPalette(colour);
|
Colour colour32 = LookupColourInPalette(colour.p);
|
||||||
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
|
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -367,7 +367,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8_t col
|
||||||
for (int i = width; i > 0; i--) {
|
for (int i = width; i > 0; i--) {
|
||||||
*dst = colour32;
|
*dst = colour32;
|
||||||
/* Set the colour in the anim-buffer too */
|
/* Set the colour in the anim-buffer too */
|
||||||
*anim = colour | (DEFAULT_BRIGHTNESS << 8);
|
*anim = colour.p | (DEFAULT_BRIGHTNESS << 8);
|
||||||
dst++;
|
dst++;
|
||||||
anim++;
|
anim++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ public:
|
||||||
|
|
||||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||||
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
||||||
void SetPixel(void *video, int x, int y, uint8_t colour) override;
|
void SetPixel(void *video, int x, int y, PixelColour colour) override;
|
||||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override;
|
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
|
||||||
void DrawRect(void *video, int width, int height, uint8_t colour) override;
|
void DrawRect(void *video, int width, int height, PixelColour colour) override;
|
||||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||||
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;
|
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;
|
||||||
|
|
|
@ -18,22 +18,22 @@ void *Blitter_32bppBase::MoveTo(void *video, int x, int y)
|
||||||
return (uint32_t *)video + x + y * _screen.pitch;
|
return (uint32_t *)video + x + y * _screen.pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8_t colour)
|
void Blitter_32bppBase::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||||
{
|
{
|
||||||
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
|
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash)
|
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);
|
const Colour c = LookupColourInPalette(colour.p);
|
||||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8_t colour)
|
void Blitter_32bppBase::DrawRect(void *video, int width, int height, PixelColour colour)
|
||||||
{
|
{
|
||||||
Colour colour32 = LookupColourInPalette(colour);
|
Colour colour32 = LookupColourInPalette(colour.p);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Colour *dst = (Colour *)video;
|
Colour *dst = (Colour *)video;
|
||||||
|
|
|
@ -19,9 +19,9 @@ class Blitter_32bppBase : public Blitter {
|
||||||
public:
|
public:
|
||||||
uint8_t GetScreenDepth() override { return 32; }
|
uint8_t GetScreenDepth() override { return 32; }
|
||||||
void *MoveTo(void *video, int x, int y) override;
|
void *MoveTo(void *video, int x, int y) override;
|
||||||
void SetPixel(void *video, int x, int y, uint8_t colour) override;
|
void SetPixel(void *video, int x, int y, PixelColour colour) override;
|
||||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override;
|
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
|
||||||
void DrawRect(void *video, int width, int height, uint8_t colour) override;
|
void DrawRect(void *video, int width, int height, PixelColour colour) override;
|
||||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||||
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
||||||
|
|
|
@ -27,7 +27,7 @@ static FBlitter_40bppAnim iFBlitter_40bppAnim;
|
||||||
static const Colour _black_colour(0, 0, 0);
|
static const Colour _black_colour(0, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
void Blitter_40bppAnim::SetPixel(void *video, int x, int y, uint8_t colour)
|
void Blitter_40bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||||
{
|
{
|
||||||
if (_screen_disable_anim) {
|
if (_screen_disable_anim) {
|
||||||
Blitter_32bppOptimized::SetPixel(video, x, y, colour);
|
Blitter_32bppOptimized::SetPixel(video, x, y, colour);
|
||||||
|
@ -35,11 +35,11 @@ void Blitter_40bppAnim::SetPixel(void *video, int x, int y, uint8_t colour)
|
||||||
size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
|
size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
|
||||||
*((Colour *)video + x + y_offset) = _black_colour;
|
*((Colour *)video + x + y_offset) = _black_colour;
|
||||||
|
|
||||||
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour;
|
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour.p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8_t colour)
|
void Blitter_40bppAnim::DrawRect(void *video, int width, int height, PixelColour colour)
|
||||||
{
|
{
|
||||||
if (_screen_disable_anim) {
|
if (_screen_disable_anim) {
|
||||||
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
||||||
|
@ -56,7 +56,7 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8_t col
|
||||||
|
|
||||||
for (int i = width; i > 0; i--) {
|
for (int i = width; i > 0; i--) {
|
||||||
*dst = _black_colour;
|
*dst = _black_colour;
|
||||||
*anim = colour;
|
*anim = colour.p;
|
||||||
dst++;
|
dst++;
|
||||||
anim++;
|
anim++;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, uint8_t col
|
||||||
} while (--height);
|
} while (--height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash)
|
void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
|
||||||
{
|
{
|
||||||
if (_screen_disable_anim) {
|
if (_screen_disable_anim) {
|
||||||
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
/* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */
|
||||||
|
@ -78,7 +78,7 @@ void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
|
||||||
|
|
||||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||||
*((Colour *)video + x + y * _screen.pitch) = _black_colour;
|
*((Colour *)video + x + y * _screen.pitch) = _black_colour;
|
||||||
*(anim + x + y * _screen.pitch) = colour;
|
*(anim + x + y * _screen.pitch) = colour.p;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
class Blitter_40bppAnim : public Blitter_32bppOptimized {
|
class Blitter_40bppAnim : public Blitter_32bppOptimized {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void SetPixel(void *video, int x, int y, uint8_t colour) override;
|
void SetPixel(void *video, int x, int y, PixelColour colour) override;
|
||||||
void DrawRect(void *video, int width, int height, uint8_t colour) override;
|
void DrawRect(void *video, int width, int height, PixelColour colour) override;
|
||||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override;
|
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
|
||||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||||
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
||||||
|
|
|
@ -29,23 +29,23 @@ void *Blitter_8bppBase::MoveTo(void *video, int x, int y)
|
||||||
return (uint8_t *)video + x + y * _screen.pitch;
|
return (uint8_t *)video + x + y * _screen.pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8_t colour)
|
void Blitter_8bppBase::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||||
{
|
{
|
||||||
*((uint8_t *)video + x + y * _screen.pitch) = colour;
|
*((uint8_t *)video + x + y * _screen.pitch) = colour.p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash)
|
void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
|
||||||
{
|
{
|
||||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||||
*((uint8_t *)video + x + y * _screen.pitch) = colour;
|
*((uint8_t *)video + x + y * _screen.pitch) = colour.p;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8_t colour)
|
void Blitter_8bppBase::DrawRect(void *video, int width, int height, PixelColour colour)
|
||||||
{
|
{
|
||||||
std::byte *p = static_cast<std::byte *>(video);
|
std::byte *p = static_cast<std::byte *>(video);
|
||||||
do {
|
do {
|
||||||
std::fill_n(p, width, static_cast<std::byte>(colour));
|
std::fill_n(p, width, static_cast<std::byte>(colour.p));
|
||||||
p += _screen.pitch;
|
p += _screen.pitch;
|
||||||
} while (--height);
|
} while (--height);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@ public:
|
||||||
uint8_t GetScreenDepth() override { return 8; }
|
uint8_t GetScreenDepth() override { return 8; }
|
||||||
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
||||||
void *MoveTo(void *video, int x, int y) override;
|
void *MoveTo(void *video, int x, int y) override;
|
||||||
void SetPixel(void *video, int x, int y, uint8_t colour) override;
|
void SetPixel(void *video, int x, int y, PixelColour colour) override;
|
||||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash) override;
|
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash) override;
|
||||||
void DrawRect(void *video, int width, int height, uint8_t colour) override;
|
void DrawRect(void *video, int width, int height, PixelColour colour) override;
|
||||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||||
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
||||||
|
|
|
@ -95,18 +95,18 @@ public:
|
||||||
* @param video The destination pointer (video-buffer).
|
* @param video The destination pointer (video-buffer).
|
||||||
* @param x The x position within video-buffer.
|
* @param x The x position within video-buffer.
|
||||||
* @param y The y position within video-buffer.
|
* @param y The y position within video-buffer.
|
||||||
* @param colour A 8bpp mapping colour.
|
* @param colour A pixel colour.
|
||||||
*/
|
*/
|
||||||
virtual void SetPixel(void *video, int x, int y, uint8_t colour) = 0;
|
virtual void SetPixel(void *video, int x, int y, PixelColour colour) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a single horizontal line in a single colour on the video-buffer.
|
* Make a single horizontal line in a single colour on the video-buffer.
|
||||||
* @param video The destination pointer (video-buffer).
|
* @param video The destination pointer (video-buffer).
|
||||||
* @param width The length of the line.
|
* @param width The length of the line.
|
||||||
* @param height The height of the line.
|
* @param height The height of the line.
|
||||||
* @param colour A 8bpp mapping colour.
|
* @param colour A pixel colour.
|
||||||
*/
|
*/
|
||||||
virtual void DrawRect(void *video, int width, int height, uint8_t colour) = 0;
|
virtual void DrawRect(void *video, int width, int height, PixelColour colour) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a line with a given colour.
|
* Draw a line with a given colour.
|
||||||
|
@ -117,11 +117,11 @@ public:
|
||||||
* @param y2 The y coordinate to where the lines goes.
|
* @param y2 The y coordinate to where the lines goes.
|
||||||
* @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows).
|
* @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows).
|
||||||
* @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows).
|
* @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows).
|
||||||
* @param colour A 8bpp mapping colour.
|
* @param colour A pixel colour.
|
||||||
* @param width Line width.
|
* @param width Line width.
|
||||||
* @param dash Length of dashes for dashed lines. 0 means solid line.
|
* @param dash Length of dashes for dashed lines. 0 means solid line.
|
||||||
*/
|
*/
|
||||||
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash = 0) = 0;
|
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash = 0) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy from a buffer to the screen.
|
* Copy from a buffer to the screen.
|
||||||
|
|
|
@ -20,9 +20,9 @@ public:
|
||||||
void DrawColourMappingRect(void *, int, int, PaletteID) override {};
|
void DrawColourMappingRect(void *, int, int, PaletteID) override {};
|
||||||
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
|
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
|
||||||
void *MoveTo(void *, int, int) override { return nullptr; };
|
void *MoveTo(void *, int, int) override { return nullptr; };
|
||||||
void SetPixel(void *, int, int, uint8_t) override {};
|
void SetPixel(void *, int, int, PixelColour) override {};
|
||||||
void DrawRect(void *, int, int, uint8_t) override {};
|
void DrawRect(void *, int, int, PixelColour) override {};
|
||||||
void DrawLine(void *, int, int, int, int, int, int, uint8_t, int, int) override {};
|
void DrawLine(void *, int, int, int, int, int, int, PixelColour, int, int) override {};
|
||||||
void CopyFromBuffer(void *, const void *, int, int) override {};
|
void CopyFromBuffer(void *, const void *, int, int) override {};
|
||||||
void CopyToBuffer(const void *, void *, int, int) override {};
|
void CopyToBuffer(const void *, void *, int, int) override {};
|
||||||
void CopyImageToBuffer(const void *, void *, int, int, int) override {};
|
void CopyImageToBuffer(const void *, void *, int, int, int) override {};
|
||||||
|
|
|
@ -60,8 +60,8 @@ public:
|
||||||
|
|
||||||
void DrawWidget(const Rect &r, WidgetID) const override
|
void DrawWidget(const Rect &r, WidgetID) const override
|
||||||
{
|
{
|
||||||
GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE);
|
GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{4}, FILLRECT_OPAQUE);
|
||||||
GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER);
|
GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{0}, FILLRECT_CHECKER);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -385,10 +385,10 @@ bool HandleBootstrap()
|
||||||
/* Initialise the palette. The biggest step is 'faking' some recolour sprites.
|
/* Initialise the palette. The biggest step is 'faking' some recolour sprites.
|
||||||
* This way the mauve and gray colours work and we can show the user interface. */
|
* This way the mauve and gray colours work and we can show the user interface. */
|
||||||
GfxInitPalettes();
|
GfxInitPalettes();
|
||||||
static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
|
static const uint8_t offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
|
||||||
for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
|
for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
|
||||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||||
SetColourGradient(i, j, offsets[i] + j);
|
SetColourGradient(i, j, PixelColour(offsets[i] + j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -956,7 +956,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||||
int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
|
int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
|
||||||
int sprite_width = sprite_left + sprite_right;
|
int sprite_width = sprite_left + sprite_right;
|
||||||
int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
|
int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
|
||||||
int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
||||||
|
|
||||||
auto badge_column_widths = badge_classes.GetColumnWidths();
|
auto badge_column_widths = badge_classes.GetColumnWidths();
|
||||||
|
|
||||||
|
|
|
@ -410,7 +410,7 @@ void VehicleCargoList::AgeCargo()
|
||||||
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
|
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
|
||||||
} else if (cargo_next == current_station) {
|
} else if (cargo_next == current_station) {
|
||||||
return MTA_DELIVER;
|
return MTA_DELIVER;
|
||||||
} else if (next_station.Contains(cargo_next.base())) {
|
} else if (next_station.Contains(cargo_next)) {
|
||||||
return MTA_KEEP;
|
return MTA_KEEP;
|
||||||
} else {
|
} else {
|
||||||
return MTA_TRANSFER;
|
return MTA_TRANSFER;
|
||||||
|
@ -470,7 +470,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
|
||||||
new_shares.ChangeShare(current_station, INT_MIN);
|
new_shares.ChangeShare(current_station, INT_MIN);
|
||||||
StationIDStack excluded = next_station;
|
StationIDStack excluded = next_station;
|
||||||
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
|
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
|
||||||
new_shares.ChangeShare(StationID{excluded.Pop()}, INT_MIN);
|
new_shares.ChangeShare(excluded.Pop(), INT_MIN);
|
||||||
}
|
}
|
||||||
if (new_shares.GetShares()->empty()) {
|
if (new_shares.GetShares()->empty()) {
|
||||||
cargo_next = StationID::Invalid();
|
cargo_next = StationID::Invalid();
|
||||||
|
@ -743,7 +743,7 @@ uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool incl
|
||||||
{
|
{
|
||||||
uint max_move = action.MaxMove();
|
uint max_move = action.MaxMove();
|
||||||
while (!next.IsEmpty()) {
|
while (!next.IsEmpty()) {
|
||||||
this->ShiftCargo(action, StationID{next.Pop()});
|
this->ShiftCargo(action, next.Pop());
|
||||||
if (action.MaxMove() == 0) break;
|
if (action.MaxMove() == 0) break;
|
||||||
}
|
}
|
||||||
if (include_invalid && action.MaxMove() > 0) {
|
if (include_invalid && action.MaxMove() > 0) {
|
||||||
|
@ -853,7 +853,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
|
||||||
*/
|
*/
|
||||||
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
|
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
|
||||||
{
|
{
|
||||||
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid.base(), false);
|
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -555,7 +555,7 @@ public:
|
||||||
inline bool HasCargoFor(StationIDStack next) const
|
inline bool HasCargoFor(StationIDStack next) const
|
||||||
{
|
{
|
||||||
while (!next.IsEmpty()) {
|
while (!next.IsEmpty()) {
|
||||||
if (this->packets.find(StationID{next.Pop()}) != this->packets.end()) return true;
|
if (this->packets.find(next.Pop()) != this->packets.end()) return true;
|
||||||
}
|
}
|
||||||
/* Packets for StationID::Invalid() can go anywhere. */
|
/* Packets for StationID::Invalid() can go anywhere. */
|
||||||
return this->packets.find(StationID::Invalid()) != this->packets.end();
|
return this->packets.find(StationID::Invalid()) != this->packets.end();
|
||||||
|
|
|
@ -74,8 +74,8 @@ static const uint TOWN_PRODUCTION_DIVISOR = 256;
|
||||||
struct CargoSpec {
|
struct CargoSpec {
|
||||||
CargoLabel label; ///< Unique label of the cargo type.
|
CargoLabel label; ///< Unique label of the cargo type.
|
||||||
uint8_t bitnum = INVALID_CARGO_BITNUM; ///< Cargo bit number, is #INVALID_CARGO_BITNUM for a non-used spec.
|
uint8_t bitnum = INVALID_CARGO_BITNUM; ///< Cargo bit number, is #INVALID_CARGO_BITNUM for a non-used spec.
|
||||||
uint8_t legend_colour;
|
PixelColour legend_colour;
|
||||||
uint8_t rating_colour;
|
PixelColour rating_colour;
|
||||||
uint8_t weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
|
uint8_t weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
|
||||||
uint16_t multiplier = 0x100; ///< Capacity multiplier for vehicles. (8 fractional bits)
|
uint16_t multiplier = 0x100; ///< Capacity multiplier for vehicles. (8 fractional bits)
|
||||||
CargoClasses classes; ///< Classes of this cargo type. @see CargoClass
|
CargoClasses classes; ///< Classes of this cargo type. @see CargoClass
|
||||||
|
|
|
@ -152,8 +152,8 @@ void SetLocalCompany(CompanyID new_company)
|
||||||
*/
|
*/
|
||||||
TextColour GetDrawStringCompanyColour(CompanyID company)
|
TextColour GetDrawStringCompanyColour(CompanyID company)
|
||||||
{
|
{
|
||||||
if (!Company::IsValidID(company)) return (TextColour)GetColourGradient(COLOUR_WHITE, SHADE_NORMAL) | TC_IS_PALETTE_COLOUR;
|
if (!Company::IsValidID(company)) return GetColourGradient(COLOUR_WHITE, SHADE_NORMAL).ToTextColour();
|
||||||
return (TextColour)GetColourGradient(_company_colours[company], SHADE_NORMAL) | TC_IS_PALETTE_COLOUR;
|
return GetColourGradient(_company_colours[company], SHADE_NORMAL).ToTextColour();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2369,7 +2369,7 @@ static bool ConFont(std::span<std::string_view> argv)
|
||||||
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
|
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
|
||||||
/* Make sure all non sprite fonts are loaded. */
|
/* Make sure all non sprite fonts are loaded. */
|
||||||
if (!setting->font.empty() && !fc->HasParent()) {
|
if (!setting->font.empty() && !fc->HasParent()) {
|
||||||
InitFontCache(fs);
|
FontCache::LoadFontCaches(fs);
|
||||||
fc = FontCache::Get(fs);
|
fc = FontCache::Get(fs);
|
||||||
}
|
}
|
||||||
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
|
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
|
||||||
|
|
|
@ -544,7 +544,7 @@ bool IsValidConsoleColour(TextColour c)
|
||||||
* colour gradient, so it must be one of those. */
|
* colour gradient, so it must be one of those. */
|
||||||
c &= ~TC_IS_PALETTE_COLOUR;
|
c &= ~TC_IS_PALETTE_COLOUR;
|
||||||
for (Colours i = COLOUR_BEGIN; i < COLOUR_END; i++) {
|
for (Colours i = COLOUR_BEGIN; i < COLOUR_END; i++) {
|
||||||
if (GetColourGradient(i, SHADE_NORMAL) == c) return true;
|
if (GetColourGradient(i, SHADE_NORMAL).p == c) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -113,13 +113,14 @@ struct SmallStackItem {
|
||||||
* index types of the same length.
|
* index types of the same length.
|
||||||
* @tparam Titem Value type to be used.
|
* @tparam Titem Value type to be used.
|
||||||
* @tparam Tindex Index type to use for the pool.
|
* @tparam Tindex Index type to use for the pool.
|
||||||
* @tparam Tinvalid Invalid item to keep at the bottom of each stack.
|
* @tparam Tinvalid_value Value to construct invalid item to keep at the bottom of each stack.
|
||||||
* @tparam Tgrowth_step Growth step for pool.
|
* @tparam Tgrowth_step Growth step for pool.
|
||||||
* @tparam Tmax_size Maximum size for pool.
|
* @tparam Tmax_size Maximum size for pool.
|
||||||
*/
|
*/
|
||||||
template <typename Titem, typename Tindex, Titem Tinvalid, Tindex Tgrowth_step, Tindex Tmax_size>
|
template <typename Titem, typename Tindex, auto Tinvalid_value, Tindex Tgrowth_step, Tindex Tmax_size>
|
||||||
class SmallStack : public SmallStackItem<Titem, Tindex> {
|
class SmallStack : public SmallStackItem<Titem, Tindex> {
|
||||||
public:
|
public:
|
||||||
|
static constexpr Titem Tinvalid{Tinvalid_value};
|
||||||
|
|
||||||
typedef SmallStackItem<Titem, Tindex> Item;
|
typedef SmallStackItem<Titem, Tindex> Item;
|
||||||
|
|
||||||
|
|
|
@ -413,7 +413,7 @@ struct DepotWindow : Window {
|
||||||
*/
|
*/
|
||||||
if (this->type == VEH_TRAIN && _consistent_train_width != 0) {
|
if (this->type == VEH_TRAIN && _consistent_train_width != 0) {
|
||||||
int w = ScaleSpriteTrad(2 * _consistent_train_width);
|
int w = ScaleSpriteTrad(2 * _consistent_train_width);
|
||||||
int col = GetColourGradient(wid->colour, SHADE_NORMAL);
|
PixelColour col = GetColourGradient(wid->colour, SHADE_NORMAL);
|
||||||
Rect image = ir.Indent(this->header_width, rtl).Indent(this->count_width, !rtl);
|
Rect image = ir.Indent(this->header_width, rtl).Indent(this->count_width, !rtl);
|
||||||
int first_line = w + (-this->hscroll->GetPosition()) % w;
|
int first_line = w + (-this->hscroll->GetPosition()) % w;
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
|
|
|
@ -37,8 +37,8 @@ public:
|
||||||
|
|
||||||
void Draw(const Rect &full, const Rect &, bool, int, Colours bg_colour) const override
|
void Draw(const Rect &full, const Rect &, bool, int, Colours bg_colour) const override
|
||||||
{
|
{
|
||||||
uint8_t c1 = GetColourGradient(bg_colour, SHADE_DARK);
|
PixelColour c1 = GetColourGradient(bg_colour, SHADE_DARK);
|
||||||
uint8_t c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST);
|
PixelColour c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST);
|
||||||
|
|
||||||
int mid = CentreBounds(full.top, full.bottom, 0);
|
int mid = CentreBounds(full.top, full.bottom, 0);
|
||||||
GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1);
|
GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1);
|
||||||
|
|
|
@ -1067,6 +1067,7 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoType cargo_type, uint
|
||||||
|
|
||||||
uint amount = std::min(num_pieces, 0xFFFFu - it->waiting);
|
uint amount = std::min(num_pieces, 0xFFFFu - it->waiting);
|
||||||
it->waiting += amount;
|
it->waiting += amount;
|
||||||
|
it->GetOrCreateHistory()[THIS_MONTH].accepted += amount;
|
||||||
it->last_accepted = TimerGameEconomy::date;
|
it->last_accepted = TimerGameEconomy::date;
|
||||||
num_pieces -= amount;
|
num_pieces -= amount;
|
||||||
accepted += amount;
|
accepted += amount;
|
||||||
|
|
|
@ -9,10 +9,8 @@
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "fontcache.h"
|
#include "fontcache.h"
|
||||||
#include "fontdetection.h"
|
|
||||||
#include "blitter/factory.hpp"
|
#include "blitter/factory.hpp"
|
||||||
#include "gfx_layout.h"
|
#include "gfx_layout.h"
|
||||||
#include "fontcache/spritefontcache.h"
|
|
||||||
#include "openttd.h"
|
#include "openttd.h"
|
||||||
#include "settings_func.h"
|
#include "settings_func.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
|
@ -30,22 +28,38 @@
|
||||||
FontCacheSettings _fcsettings;
|
FontCacheSettings _fcsettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new font cache.
|
* Try loading a font with any fontcache factory.
|
||||||
* @param fs The size of the font.
|
* @param fs Font size to load.
|
||||||
|
* @param fonttype Font type requested.
|
||||||
|
* @return FontCache of the font if loaded, or nullptr.
|
||||||
*/
|
*/
|
||||||
FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs)
|
/* static */ std::unique_ptr<FontCache> FontProviderManager::LoadFont(FontSize fs, FontType fonttype)
|
||||||
{
|
{
|
||||||
assert(this->parent == nullptr || this->fs == this->parent->fs);
|
for (auto &provider : FontProviderManager::GetProviders()) {
|
||||||
FontCache::caches[this->fs] = this;
|
auto fc = provider->LoadFont(fs, fonttype);
|
||||||
Layouter::ResetFontCache(this->fs);
|
if (fc != nullptr) return fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clean everything up. */
|
/**
|
||||||
FontCache::~FontCache()
|
* We would like to have a fallback font as the current one
|
||||||
|
* doesn't contain all characters we need.
|
||||||
|
* This function must set all fonts of settings.
|
||||||
|
* @param settings the settings to overwrite the fontname of.
|
||||||
|
* @param language_isocode the language, e.g. en_GB.
|
||||||
|
* @param callback The function to call to check for missing glyphs.
|
||||||
|
* @return true if a font has been set, false otherwise.
|
||||||
|
*/
|
||||||
|
/* static */ bool FontProviderManager::FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||||
{
|
{
|
||||||
assert(this->parent == nullptr || this->fs == this->parent->fs);
|
for (auto &provider : FontProviderManager::GetProviders()) {
|
||||||
FontCache::caches[this->fs] = this->parent;
|
if (provider->FindFallbackFont(settings, language_isocode, callback)) {
|
||||||
Layouter::ResetFontCache(this->fs);
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FontCache::GetDefaultFontHeight(FontSize fs)
|
int FontCache::GetDefaultFontHeight(FontSize fs)
|
||||||
|
@ -80,12 +94,16 @@ int GetCharacterHeight(FontSize size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* static */ FontCache *FontCache::caches[FS_END];
|
/* static */ std::array<std::unique_ptr<FontCache>, FS_END> FontCache::caches{};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise font caches with the base sprite font cache for all sizes.
|
||||||
|
*/
|
||||||
/* static */ void FontCache::InitializeFontCaches()
|
/* static */ void FontCache::InitializeFontCaches()
|
||||||
{
|
{
|
||||||
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
||||||
if (FontCache::caches[fs] == nullptr) new SpriteFontCache(fs); /* FontCache inserts itself into to the cache. */
|
if (FontCache::Get(fs) != nullptr) continue;
|
||||||
|
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::Sprite));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +144,7 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
||||||
CheckForMissingGlyphs();
|
CheckForMissingGlyphs();
|
||||||
_fcsettings = std::move(backup);
|
_fcsettings = std::move(backup);
|
||||||
} else {
|
} else {
|
||||||
InitFontCache(fontsize);
|
FontCache::LoadFontCaches(fontsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadStringWidthTable(fontsize);
|
LoadStringWidthTable(fontsize);
|
||||||
|
@ -136,15 +154,6 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
||||||
if (_save_config) SaveToConfig();
|
if (_save_config) SaveToConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
|
||||||
extern void LoadFreeTypeFont(FontSize fs);
|
|
||||||
extern void UninitFreeType();
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
extern void LoadWin32Font(FontSize fs);
|
|
||||||
#elif defined(WITH_COCOA)
|
|
||||||
extern void LoadCoreTextFont(FontSize fs);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if a font setting uses the default font.
|
* Test if a font setting uses the default font.
|
||||||
* @return true iff the font is not configured and no fallback font data is present.
|
* @return true iff the font is not configured and no fallback font data is present.
|
||||||
|
@ -211,43 +220,55 @@ std::string GetFontCacheFontName(FontSize fs)
|
||||||
return GetDefaultTruetypeFontFile(fs);
|
return GetDefaultTruetypeFontFile(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a FontCache for its font size.
|
||||||
|
* @param fc FontCache to register.
|
||||||
|
*/
|
||||||
|
/* static */ void FontCache::Register(std::unique_ptr<FontCache> &&fc)
|
||||||
|
{
|
||||||
|
if (fc == nullptr) return;
|
||||||
|
|
||||||
|
FontSize fs = fc->fs;
|
||||||
|
|
||||||
|
fc->parent = std::move(FontCache::caches[fs]);
|
||||||
|
FontCache::caches[fs] = std::move(fc);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
|
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
|
||||||
* @param fontsizes Font sizes to be initialised.
|
* @param fontsizes Font sizes to be initialised.
|
||||||
*/
|
*/
|
||||||
void InitFontCache(FontSizes fontsizes)
|
/* static */ void FontCache::LoadFontCaches(FontSizes fontsizes)
|
||||||
{
|
{
|
||||||
FontCache::InitializeFontCaches();
|
FontCache::InitializeFontCaches();
|
||||||
|
|
||||||
for (FontSize fs : fontsizes) {
|
for (FontSize fs : fontsizes) {
|
||||||
FontCache *fc = FontCache::Get(fs);
|
Layouter::ResetFontCache(fs);
|
||||||
if (fc->HasParent()) delete fc;
|
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
/* Unload everything except the sprite font cache. */
|
||||||
LoadFreeTypeFont(fs);
|
while (FontCache::Get(fs)->HasParent()) {
|
||||||
#elif defined(_WIN32)
|
FontCache::caches[fs] = std::move(FontCache::caches[fs]->parent);
|
||||||
LoadWin32Font(fs);
|
}
|
||||||
#elif defined(WITH_COCOA)
|
|
||||||
LoadCoreTextFont(fs);
|
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType));
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear cached information for the specified font caches.
|
||||||
|
* @param fontsizes Font sizes to clear.
|
||||||
|
*/
|
||||||
|
/* static */ void FontCache::ClearFontCaches(FontSizes fontsizes)
|
||||||
|
{
|
||||||
|
for (FontSize fs : fontsizes) {
|
||||||
|
FontCache::Get(fs)->ClearFontCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free everything allocated w.r.t. fonts.
|
* Free everything allocated w.r.t. fonts.
|
||||||
*/
|
*/
|
||||||
void UninitFontCache()
|
/* static */ void FontCache::UninitializeFontCaches()
|
||||||
{
|
{
|
||||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
std::ranges::generate(FontCache::caches, []() { return nullptr; });
|
||||||
while (FontCache::Get(fs) != nullptr) delete FontCache::Get(fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
|
||||||
UninitFreeType();
|
|
||||||
#endif /* WITH_FREETYPE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
|
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *, const std::string &, MissingGlyphSearcher *) { return false; }
|
|
||||||
#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef FONTCACHE_H
|
#ifndef FONTCACHE_H
|
||||||
#define FONTCACHE_H
|
#define FONTCACHE_H
|
||||||
|
|
||||||
|
#include "provider_manager.h"
|
||||||
#include "string_type.h"
|
#include "string_type.h"
|
||||||
#include "spritecache.h"
|
#include "spritecache.h"
|
||||||
|
|
||||||
|
@ -20,18 +21,23 @@ static const GlyphID SPRITE_GLYPH = 1U << 30;
|
||||||
/** Font cache for basic fonts. */
|
/** Font cache for basic fonts. */
|
||||||
class FontCache {
|
class FontCache {
|
||||||
protected:
|
protected:
|
||||||
static FontCache *caches[FS_END]; ///< All the font caches.
|
static std::array<std::unique_ptr<FontCache>, FS_END> caches; ///< All the font caches.
|
||||||
FontCache *parent; ///< The parent of this font cache.
|
std::unique_ptr<FontCache>parent; ///< The parent of this font cache.
|
||||||
const FontSize fs; ///< The size of the font.
|
const FontSize fs; ///< The size of the font.
|
||||||
int height = 0; ///< The height of the font.
|
int height = 0; ///< The height of the font.
|
||||||
int ascender = 0; ///< The ascender value of the font.
|
int ascender = 0; ///< The ascender value of the font.
|
||||||
int descender = 0; ///< The descender value of the font.
|
int descender = 0; ///< The descender value of the font.
|
||||||
|
|
||||||
|
FontCache(FontSize fs) : fs(fs) {}
|
||||||
|
static void Register(std::unique_ptr<FontCache> &&fc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FontCache(FontSize fs);
|
virtual ~FontCache() {}
|
||||||
virtual ~FontCache();
|
|
||||||
|
|
||||||
static void InitializeFontCaches();
|
static void InitializeFontCaches();
|
||||||
|
static void UninitializeFontCaches();
|
||||||
|
static void LoadFontCaches(FontSizes fontsizes);
|
||||||
|
static void ClearFontCaches(FontSizes fontsizes);
|
||||||
|
|
||||||
/** Default unscaled font heights. */
|
/** Default unscaled font heights. */
|
||||||
static const int DEFAULT_FONT_HEIGHT[FS_END];
|
static const int DEFAULT_FONT_HEIGHT[FS_END];
|
||||||
|
@ -70,16 +76,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual int GetFontSize() const { return this->height; }
|
virtual int GetFontSize() const { return this->height; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Map a SpriteID to the key
|
|
||||||
* @param key The key to map to.
|
|
||||||
* @param sprite The sprite that is being mapped.
|
|
||||||
*/
|
|
||||||
virtual void SetUnicodeGlyph(char32_t key, SpriteID sprite) = 0;
|
|
||||||
|
|
||||||
/** Initialize the glyph map */
|
|
||||||
virtual void InitializeUnicodeGlyphMap() = 0;
|
|
||||||
|
|
||||||
/** Clear the font cache. */
|
/** Clear the font cache. */
|
||||||
virtual void ClearFontCache() = 0;
|
virtual void ClearFontCache() = 0;
|
||||||
|
|
||||||
|
@ -134,7 +130,7 @@ public:
|
||||||
static inline FontCache *Get(FontSize fs)
|
static inline FontCache *Get(FontSize fs)
|
||||||
{
|
{
|
||||||
assert(fs < FS_END);
|
assert(fs < FS_END);
|
||||||
return FontCache::caches[fs];
|
return FontCache::caches[fs].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetName(FontSize fs);
|
static std::string GetName(FontSize fs);
|
||||||
|
@ -153,27 +149,6 @@ public:
|
||||||
virtual bool IsBuiltInFont() = 0;
|
virtual bool IsBuiltInFont() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Map a SpriteID to the font size and key */
|
|
||||||
inline void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite)
|
|
||||||
{
|
|
||||||
FontCache::Get(size)->SetUnicodeGlyph(key, sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Initialize the glyph map */
|
|
||||||
inline void InitializeUnicodeGlyphMap()
|
|
||||||
{
|
|
||||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
|
||||||
FontCache::Get(fs)->InitializeUnicodeGlyphMap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void ClearFontCache(FontSizes fontsizes)
|
|
||||||
{
|
|
||||||
for (FontSize fs : fontsizes) {
|
|
||||||
FontCache::Get(fs)->ClearFontCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the Sprite for a glyph */
|
/** Get the Sprite for a glyph */
|
||||||
inline const Sprite *GetGlyph(FontSize size, char32_t key)
|
inline const Sprite *GetGlyph(FontSize size, char32_t key)
|
||||||
{
|
{
|
||||||
|
@ -231,10 +206,41 @@ inline FontCacheSubSetting *GetFontCacheSubSetting(FontSize fs)
|
||||||
|
|
||||||
uint GetFontCacheFontSize(FontSize fs);
|
uint GetFontCacheFontSize(FontSize fs);
|
||||||
std::string GetFontCacheFontName(FontSize fs);
|
std::string GetFontCacheFontName(FontSize fs);
|
||||||
void InitFontCache(FontSizes fontsizes);
|
|
||||||
void UninitFontCache();
|
|
||||||
|
|
||||||
bool GetFontAAState();
|
bool GetFontAAState();
|
||||||
void SetFont(FontSize fontsize, const std::string &font, uint size);
|
void SetFont(FontSize fontsize, const std::string &font, uint size);
|
||||||
|
|
||||||
|
/** Different types of font that can be loaded. */
|
||||||
|
enum class FontType : uint8_t {
|
||||||
|
Sprite, ///< Bitmap sprites from GRF files.
|
||||||
|
TrueType, ///< Scalable TrueType fonts.
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Factory for FontCaches. */
|
||||||
|
class FontCacheFactory : public BaseProvider<FontCacheFactory> {
|
||||||
|
public:
|
||||||
|
FontCacheFactory(std::string_view name, std::string_view description) : BaseProvider<FontCacheFactory>(name, description)
|
||||||
|
{
|
||||||
|
ProviderManager<FontCacheFactory>::Register(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~FontCacheFactory()
|
||||||
|
{
|
||||||
|
ProviderManager<FontCacheFactory>::Unregister(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) = 0;
|
||||||
|
virtual bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FontProviderManager : ProviderManager<FontCacheFactory> {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype);
|
||||||
|
static bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Implemented in spritefontcache.cpp */
|
||||||
|
void InitializeUnicodeGlyphMap();
|
||||||
|
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);
|
||||||
|
|
||||||
#endif /* FONTCACHE_H */
|
#endif /* FONTCACHE_H */
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
/** @file freetypefontcache.cpp FreeType font cache implementation. */
|
/** @file freetypefontcache.cpp FreeType font cache implementation. */
|
||||||
|
|
||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
|
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../fontcache.h"
|
#include "../fontcache.h"
|
||||||
#include "../fontdetection.h"
|
|
||||||
#include "../blitter/factory.hpp"
|
#include "../blitter/factory.hpp"
|
||||||
#include "../core/math_func.hpp"
|
|
||||||
#include "../zoom_func.h"
|
#include "../zoom_func.h"
|
||||||
#include "../fileio_func.h"
|
#include "../fileio_func.h"
|
||||||
#include "../error_func.h"
|
#include "../error_func.h"
|
||||||
|
#include "../../os/unix/font_unix.h"
|
||||||
#include "truetypefontcache.h"
|
#include "truetypefontcache.h"
|
||||||
|
|
||||||
#include "../table/control_codes.h"
|
#include "../table/control_codes.h"
|
||||||
|
@ -46,9 +46,6 @@ public:
|
||||||
const void *GetOSHandle() override { return &face; }
|
const void *GetOSHandle() override { return &face; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FT_Library _ft_library = nullptr;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new FreeTypeFontCache.
|
* Create a new FreeTypeFontCache.
|
||||||
* @param fs The font size that is going to be cached.
|
* @param fs The font size that is going to be cached.
|
||||||
|
@ -113,93 +110,6 @@ void FreeTypeFontCache::SetFontSize(int pixels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FT_Error LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
|
|
||||||
{
|
|
||||||
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
|
|
||||||
|
|
||||||
/* Attempt to select the unicode character map */
|
|
||||||
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
|
|
||||||
if (error == FT_Err_Ok) goto found_face; // Success
|
|
||||||
|
|
||||||
if (error == FT_Err_Invalid_CharMap_Handle) {
|
|
||||||
/* Try to pick a different character map instead. We default to
|
|
||||||
* the first map, but platform_id 0 encoding_id 0 should also
|
|
||||||
* be unicode (strange system...) */
|
|
||||||
FT_CharMap found = face->charmaps[0];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < face->num_charmaps; i++) {
|
|
||||||
FT_CharMap charmap = face->charmaps[i];
|
|
||||||
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
|
||||||
found = charmap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found != nullptr) {
|
|
||||||
error = FT_Set_Charmap(face, found);
|
|
||||||
if (error == FT_Err_Ok) goto found_face;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Done_Face(face);
|
|
||||||
return error;
|
|
||||||
|
|
||||||
found_face:
|
|
||||||
new FreeTypeFontCache(fs, face, size);
|
|
||||||
return FT_Err_Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the freetype font.
|
|
||||||
* First type to load the fontname as if it were a path. If that fails,
|
|
||||||
* try to resolve the filename of the font using fontconfig, where the
|
|
||||||
* format is 'font family name' or 'font family name, font style'.
|
|
||||||
* @param fs The font size to load.
|
|
||||||
*/
|
|
||||||
void LoadFreeTypeFont(FontSize fs)
|
|
||||||
{
|
|
||||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
|
||||||
|
|
||||||
std::string font = GetFontCacheFontName(fs);
|
|
||||||
if (font.empty()) return;
|
|
||||||
|
|
||||||
if (_ft_library == nullptr) {
|
|
||||||
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
|
|
||||||
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(fontcache, 2, "Initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Face face = nullptr;
|
|
||||||
|
|
||||||
/* If font is an absolute path to a ttf, try loading that first. */
|
|
||||||
int32_t index = 0;
|
|
||||||
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
|
|
||||||
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
|
|
||||||
|
|
||||||
if (error != FT_Err_Ok) {
|
|
||||||
/* Check if font is a relative filename in one of our search-paths. */
|
|
||||||
std::string full_font = FioFindFullPath(BASE_DIR, font);
|
|
||||||
if (!full_font.empty()) {
|
|
||||||
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try loading based on font face name (OS-wide fonts). */
|
|
||||||
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
|
|
||||||
|
|
||||||
if (error == FT_Err_Ok) {
|
|
||||||
error = LoadFont(fs, face, font, GetFontCacheFontSize(fs));
|
|
||||||
if (error != FT_Err_Ok) {
|
|
||||||
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font, FontSizeToName(fs), error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FT_Done_Face(face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free everything that was allocated for this font cache.
|
* Free everything that was allocated for this font cache.
|
||||||
*/
|
*/
|
||||||
|
@ -296,19 +206,116 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
|
||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
FT_Library _ft_library = nullptr;
|
||||||
* Free everything allocated w.r.t. freetype.
|
|
||||||
*/
|
class FreeTypeFontCacheFactory : public FontCacheFactory {
|
||||||
void UninitFreeType()
|
public:
|
||||||
{
|
FreeTypeFontCacheFactory() : FontCacheFactory("freetype", "FreeType font provider") {}
|
||||||
|
|
||||||
|
virtual ~FreeTypeFontCacheFactory()
|
||||||
|
{
|
||||||
FT_Done_FreeType(_ft_library);
|
FT_Done_FreeType(_ft_library);
|
||||||
_ft_library = nullptr;
|
_ft_library = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(WITH_FONTCONFIG)
|
/**
|
||||||
|
* Loads the freetype font.
|
||||||
|
* First type to load the fontname as if it were a path. If that fails,
|
||||||
|
* try to resolve the filename of the font using fontconfig, where the
|
||||||
|
* format is 'font family name' or 'font family name, font style'.
|
||||||
|
* @param fs The font size to load.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::TrueType) return nullptr;
|
||||||
|
|
||||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
|
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||||
|
|
||||||
#endif /* !defined(WITH_FONTCONFIG) */
|
std::string font = GetFontCacheFontName(fs);
|
||||||
|
if (font.empty()) return nullptr;
|
||||||
|
|
||||||
|
if (_ft_library == nullptr) {
|
||||||
|
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
|
||||||
|
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(fontcache, 2, "Initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Face face = nullptr;
|
||||||
|
|
||||||
|
/* If font is an absolute path to a ttf, try loading that first. */
|
||||||
|
int32_t index = 0;
|
||||||
|
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
|
||||||
|
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
|
||||||
|
|
||||||
|
if (error != FT_Err_Ok) {
|
||||||
|
/* Check if font is a relative filename in one of our search-paths. */
|
||||||
|
std::string full_font = FioFindFullPath(BASE_DIR, font);
|
||||||
|
if (!full_font.empty()) {
|
||||||
|
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_FONTCONFIG
|
||||||
|
/* Try loading based on font face name (OS-wide fonts). */
|
||||||
|
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
|
||||||
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
|
if (error != FT_Err_Ok) {
|
||||||
|
FT_Done_Face(face);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadFont(fs, face, font, GetFontCacheFontSize(fs));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) override
|
||||||
|
{
|
||||||
|
#ifdef WITH_FONTCONFIG
|
||||||
|
if (FontConfigFindFallbackFont(settings, language_isocode, callback)) return true;
|
||||||
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
|
||||||
|
{
|
||||||
|
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
|
||||||
|
|
||||||
|
/* Attempt to select the unicode character map */
|
||||||
|
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
|
||||||
|
if (error == FT_Err_Invalid_CharMap_Handle) {
|
||||||
|
/* Try to pick a different character map instead. We default to
|
||||||
|
* the first map, but platform_id 0 encoding_id 0 should also
|
||||||
|
* be unicode (strange system...) */
|
||||||
|
FT_CharMap found = face->charmaps[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < face->num_charmaps; ++i) {
|
||||||
|
FT_CharMap charmap = face->charmaps[i];
|
||||||
|
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
||||||
|
found = charmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != nullptr) {
|
||||||
|
error = FT_Set_Charmap(face, found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != FT_Err_Ok) {
|
||||||
|
FT_Done_Face(face);
|
||||||
|
|
||||||
|
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<FreeTypeFontCache>(fs, face, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static FreeTypeFontCacheFactory s_freetype_fontcache_factory;
|
||||||
|
|
||||||
#endif /* WITH_FREETYPE */
|
#endif /* WITH_FREETYPE */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
#include "../fontcache.h"
|
#include "../fontcache.h"
|
||||||
#include "../gfx_layout.h"
|
#include "../gfx_layout.h"
|
||||||
|
#include "../string_func.h"
|
||||||
#include "../zoom_func.h"
|
#include "../zoom_func.h"
|
||||||
#include "spritefontcache.h"
|
#include "spritefontcache.h"
|
||||||
|
|
||||||
|
@ -31,41 +32,43 @@ static int ScaleFontTrad(int value)
|
||||||
return UnScaleByZoom(value * ZOOM_BASE, _font_zoom);
|
return UnScaleByZoom(value * ZOOM_BASE, _font_zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static std::array<std::unordered_map<char32_t, SpriteID>, FS_END> _char_maps{}; ///< Glyph map for each font size.
|
||||||
* Create a new sprite font cache.
|
|
||||||
* @param fs The font size to create the cache for.
|
|
||||||
*/
|
|
||||||
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
|
|
||||||
{
|
|
||||||
this->InitializeUnicodeGlyphMap();
|
|
||||||
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
|
|
||||||
this->ascender = (this->height - ScaleFontTrad(FontCache::GetDefaultFontHeight(this->fs))) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get SpriteID associated with a character.
|
* Get SpriteID associated with a character.
|
||||||
* @param key Character to find.
|
* @param key Character to find.
|
||||||
* @return SpriteID for character, or 0 if not present.
|
* @return SpriteID for character, or 0 if not present.
|
||||||
*/
|
*/
|
||||||
SpriteID SpriteFontCache::GetUnicodeGlyph(char32_t key)
|
static SpriteID GetUnicodeGlyph(FontSize fs, char32_t key)
|
||||||
{
|
{
|
||||||
const auto found = this->char_map.find(key);
|
auto found = _char_maps[fs].find(key);
|
||||||
if (found == std::end(this->char_map)) return 0;
|
if (found != std::end(_char_maps[fs])) return found->second;
|
||||||
return found->second;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpriteFontCache::SetUnicodeGlyph(char32_t key, SpriteID sprite)
|
/**
|
||||||
|
* Set the SpriteID for a unicode character.
|
||||||
|
* @param fs Font size to set.
|
||||||
|
* @param key Unicode character to set.
|
||||||
|
* @param sprite SpriteID of character.
|
||||||
|
*/
|
||||||
|
void SetUnicodeGlyph(FontSize fs, char32_t key, SpriteID sprite)
|
||||||
{
|
{
|
||||||
this->char_map[key] = sprite;
|
_char_maps[fs][key] = sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpriteFontCache::InitializeUnicodeGlyphMap()
|
/**
|
||||||
|
* Initialize the glyph map for a font size.
|
||||||
|
* This populates the glyph map with the baseset font sprites.
|
||||||
|
* @param fs Font size to initialize.
|
||||||
|
*/
|
||||||
|
void InitializeUnicodeGlyphMap(FontSize fs)
|
||||||
{
|
{
|
||||||
/* Clear out existing glyph map if it exists */
|
/* Clear out existing glyph map if it exists */
|
||||||
this->char_map.clear();
|
_char_maps[fs].clear();
|
||||||
|
|
||||||
SpriteID base;
|
SpriteID base;
|
||||||
switch (this->fs) {
|
switch (fs) {
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
case FS_MONO: // Use normal as default for mono spaced font
|
case FS_MONO: // Use normal as default for mono spaced font
|
||||||
case FS_NORMAL: base = SPR_ASCII_SPACE; break;
|
case FS_NORMAL: base = SPR_ASCII_SPACE; break;
|
||||||
|
@ -76,24 +79,45 @@ void SpriteFontCache::InitializeUnicodeGlyphMap()
|
||||||
for (uint i = ASCII_LETTERSTART; i < 256; i++) {
|
for (uint i = ASCII_LETTERSTART; i < 256; i++) {
|
||||||
SpriteID sprite = base + i - ASCII_LETTERSTART;
|
SpriteID sprite = base + i - ASCII_LETTERSTART;
|
||||||
if (!SpriteExists(sprite)) continue;
|
if (!SpriteExists(sprite)) continue;
|
||||||
this->SetUnicodeGlyph(i, sprite);
|
SetUnicodeGlyph(fs, i, sprite);
|
||||||
this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
|
SetUnicodeGlyph(fs, i + SCC_SPRITE_START, sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Modify map to move non-standard glyphs to a better unicode codepoint. */
|
||||||
for (const auto &unicode_map : _default_unicode_map) {
|
for (const auto &unicode_map : _default_unicode_map) {
|
||||||
uint8_t key = unicode_map.key;
|
uint8_t key = unicode_map.key;
|
||||||
if (key == CLRA) {
|
if (key == CLRA) {
|
||||||
/* Clear the glyph. This happens if the glyph at this code point
|
/* Clear the glyph. This happens if the glyph at this code point
|
||||||
* is non-standard and should be accessed by an SCC_xxx enum
|
* is non-standard and should be accessed by an SCC_xxx enum
|
||||||
* entry only. */
|
* entry only. */
|
||||||
this->SetUnicodeGlyph(unicode_map.code, 0);
|
SetUnicodeGlyph(fs, unicode_map.code, 0);
|
||||||
} else {
|
} else {
|
||||||
SpriteID sprite = base + key - ASCII_LETTERSTART;
|
SpriteID sprite = base + key - ASCII_LETTERSTART;
|
||||||
this->SetUnicodeGlyph(unicode_map.code, sprite);
|
SetUnicodeGlyph(fs, unicode_map.code, sprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the glyph map.
|
||||||
|
*/
|
||||||
|
void InitializeUnicodeGlyphMap()
|
||||||
|
{
|
||||||
|
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
||||||
|
InitializeUnicodeGlyphMap(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new sprite font cache.
|
||||||
|
* @param fs The font size to create the cache for.
|
||||||
|
*/
|
||||||
|
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
|
||||||
|
{
|
||||||
|
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
|
||||||
|
this->ascender = (this->height - ScaleFontTrad(FontCache::GetDefaultFontHeight(this->fs))) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
void SpriteFontCache::ClearFontCache()
|
void SpriteFontCache::ClearFontCache()
|
||||||
{
|
{
|
||||||
Layouter::ResetFontCache(this->fs);
|
Layouter::ResetFontCache(this->fs);
|
||||||
|
@ -104,21 +128,21 @@ void SpriteFontCache::ClearFontCache()
|
||||||
const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
|
const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
|
||||||
{
|
{
|
||||||
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
|
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
|
||||||
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
|
if (sprite == 0) sprite = GetUnicodeGlyph(this->fs, '?');
|
||||||
return GetSprite(sprite, SpriteType::Font);
|
return GetSprite(sprite, SpriteType::Font);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint SpriteFontCache::GetGlyphWidth(GlyphID key)
|
uint SpriteFontCache::GetGlyphWidth(GlyphID key)
|
||||||
{
|
{
|
||||||
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
|
SpriteID sprite = static_cast<SpriteID>(key & ~SPRITE_GLYPH);
|
||||||
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
|
if (sprite == 0) sprite = GetUnicodeGlyph(this->fs, '?');
|
||||||
return SpriteExists(sprite) ? GetSprite(sprite, SpriteType::Font)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
|
return SpriteExists(sprite) ? GetSprite(sprite, SpriteType::Font)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlyphID SpriteFontCache::MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback)
|
GlyphID SpriteFontCache::MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback)
|
||||||
{
|
{
|
||||||
assert(IsPrintable(key));
|
assert(IsPrintable(key));
|
||||||
SpriteID sprite = this->GetUnicodeGlyph(key);
|
SpriteID sprite = GetUnicodeGlyph(this->fs, key);
|
||||||
if (sprite == 0) return 0;
|
if (sprite == 0) return 0;
|
||||||
return SPRITE_GLYPH | sprite;
|
return SPRITE_GLYPH | sprite;
|
||||||
}
|
}
|
||||||
|
@ -127,3 +151,22 @@ bool SpriteFontCache::GetDrawGlyphShadow()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpriteFontCacheFactory : public FontCacheFactory {
|
||||||
|
public:
|
||||||
|
SpriteFontCacheFactory() : FontCacheFactory("sprite", "Sprite font provider") {}
|
||||||
|
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::Sprite) return nullptr;
|
||||||
|
|
||||||
|
return std::make_unique<SpriteFontCache>(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static SpriteFontCacheFactory s_sprite_fontcache_factory;
|
||||||
|
|
|
@ -10,15 +10,12 @@
|
||||||
#ifndef SPRITEFONTCACHE_H
|
#ifndef SPRITEFONTCACHE_H
|
||||||
#define SPRITEFONTCACHE_H
|
#define SPRITEFONTCACHE_H
|
||||||
|
|
||||||
#include "../string_func.h"
|
|
||||||
#include "../fontcache.h"
|
#include "../fontcache.h"
|
||||||
|
|
||||||
/** Font cache for fonts that are based on a freetype font. */
|
/** Font cache for fonts that are based on a freetype font. */
|
||||||
class SpriteFontCache : public FontCache {
|
class SpriteFontCache : public FontCache {
|
||||||
public:
|
public:
|
||||||
SpriteFontCache(FontSize fs);
|
SpriteFontCache(FontSize fs);
|
||||||
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override;
|
|
||||||
void InitializeUnicodeGlyphMap() override;
|
|
||||||
void ClearFontCache() override;
|
void ClearFontCache() override;
|
||||||
const Sprite *GetGlyph(GlyphID key) override;
|
const Sprite *GetGlyph(GlyphID key) override;
|
||||||
uint GetGlyphWidth(GlyphID key) override;
|
uint GetGlyphWidth(GlyphID key) override;
|
||||||
|
@ -26,10 +23,6 @@ public:
|
||||||
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
|
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
|
||||||
std::string GetFontName() override { return "sprite"; }
|
std::string GetFontName() override { return "sprite"; }
|
||||||
bool IsBuiltInFont() override { return true; }
|
bool IsBuiltInFont() override { return true; }
|
||||||
|
|
||||||
private:
|
|
||||||
std::unordered_map<char32_t, SpriteID> char_map{}; ///< Mapping of characters to sprite IDs.
|
|
||||||
SpriteID GetUnicodeGlyph(char32_t key);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SPRITEFONTCACHE_H */
|
#endif /* SPRITEFONTCACHE_H */
|
||||||
|
|
|
@ -46,8 +46,6 @@ public:
|
||||||
TrueTypeFontCache(FontSize fs, int pixels);
|
TrueTypeFontCache(FontSize fs, int pixels);
|
||||||
virtual ~TrueTypeFontCache();
|
virtual ~TrueTypeFontCache();
|
||||||
int GetFontSize() const override { return this->used_size; }
|
int GetFontSize() const override { return this->used_size; }
|
||||||
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override { this->parent->SetUnicodeGlyph(key, sprite); }
|
|
||||||
void InitializeUnicodeGlyphMap() override { this->parent->InitializeUnicodeGlyphMap(); }
|
|
||||||
const Sprite *GetGlyph(GlyphID key) override;
|
const Sprite *GetGlyph(GlyphID key) override;
|
||||||
void ClearFontCache() override;
|
void ClearFontCache() override;
|
||||||
uint GetGlyphWidth(GlyphID key) override;
|
uint GetGlyphWidth(GlyphID key) override;
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of OpenTTD.
|
|
||||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
||||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file fontdetection.h Functions related to detecting/finding the right font. */
|
|
||||||
|
|
||||||
#ifndef FONTDETECTION_H
|
|
||||||
#define FONTDETECTION_H
|
|
||||||
|
|
||||||
#include "fontcache.h"
|
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
|
||||||
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a freetype font face with the given font name.
|
|
||||||
* @param font_name The name of the font to load.
|
|
||||||
* @param face The face that has been found.
|
|
||||||
* @return The error we encountered.
|
|
||||||
*/
|
|
||||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
|
|
||||||
|
|
||||||
#endif /* WITH_FREETYPE */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We would like to have a fallback font as the current one
|
|
||||||
* doesn't contain all characters we need.
|
|
||||||
* This function must set all fonts of settings.
|
|
||||||
* @param settings the settings to overwrite the fontname of.
|
|
||||||
* @param language_isocode the language, e.g. en_GB.
|
|
||||||
* @param callback The function to call to check for missing glyphs.
|
|
||||||
* @return true if a font has been set, false otherwise.
|
|
||||||
*/
|
|
||||||
bool SetFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -867,9 +867,9 @@ struct FrametimeGraphWindow : Window {
|
||||||
const int x_max = r.right;
|
const int x_max = r.right;
|
||||||
const int y_zero = r.top + (int)this->graph_size.height;
|
const int y_zero = r.top + (int)this->graph_size.height;
|
||||||
const int y_max = r.top;
|
const int y_max = r.top;
|
||||||
const int c_grid = PC_DARK_GREY;
|
const PixelColour c_grid = PC_DARK_GREY;
|
||||||
const int c_lines = PC_BLACK;
|
const PixelColour c_lines = PC_BLACK;
|
||||||
const int c_peak = PC_DARK_RED;
|
const PixelColour c_peak = PC_DARK_RED;
|
||||||
|
|
||||||
const TimingMeasurement draw_horz_scale = (TimingMeasurement)this->horizontal_scale * TIMESTAMP_PRECISION / 2;
|
const TimingMeasurement draw_horz_scale = (TimingMeasurement)this->horizontal_scale * TIMESTAMP_PRECISION / 2;
|
||||||
const TimingMeasurement draw_vert_scale = (TimingMeasurement)this->vertical_scale;
|
const TimingMeasurement draw_vert_scale = (TimingMeasurement)this->vertical_scale;
|
||||||
|
@ -959,7 +959,7 @@ struct FrametimeGraphWindow : Window {
|
||||||
|
|
||||||
/* If the peak value is significantly larger than the average, mark and label it */
|
/* If the peak value is significantly larger than the average, mark and label it */
|
||||||
if (points_drawn > 0 && peak_value > TIMESTAMP_PRECISION / 100 && 2 * peak_value > 3 * value_sum / points_drawn) {
|
if (points_drawn > 0 && peak_value > TIMESTAMP_PRECISION / 100 && 2 * peak_value > 3 * value_sum / points_drawn) {
|
||||||
TextColour tc_peak = (TextColour)(TC_IS_PALETTE_COLOUR | c_peak);
|
TextColour tc_peak = c_peak.ToTextColour();
|
||||||
GfxFillRect(peak_point.x - 1, peak_point.y - 1, peak_point.x + 1, peak_point.y + 1, c_peak);
|
GfxFillRect(peak_point.x - 1, peak_point.y - 1, peak_point.x + 1, peak_point.y + 1, c_peak);
|
||||||
uint64_t value = peak_value * 1000 / TIMESTAMP_PRECISION;
|
uint64_t value = peak_value * 1000 / TIMESTAMP_PRECISION;
|
||||||
int label_y = std::max(y_max, peak_point.y - GetCharacterHeight(FS_SMALL));
|
int label_y = std::max(y_max, peak_point.y - GetCharacterHeight(FS_SMALL));
|
||||||
|
|
55
src/gfx.cpp
55
src/gfx.cpp
|
@ -113,7 +113,7 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo)
|
||||||
* FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things)
|
* FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things)
|
||||||
* FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen
|
* FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen
|
||||||
*/
|
*/
|
||||||
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
|
void GfxFillRect(int left, int top, int right, int bottom, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode)
|
||||||
{
|
{
|
||||||
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
||||||
const DrawPixelInfo *dpi = _cur_dpi;
|
const DrawPixelInfo *dpi = _cur_dpi;
|
||||||
|
@ -142,17 +142,18 @@ void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectM
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
default: // FILLRECT_OPAQUE
|
default: // FILLRECT_OPAQUE
|
||||||
blitter->DrawRect(dst, right, bottom, (uint8_t)colour);
|
blitter->DrawRect(dst, right, bottom, std::get<PixelColour>(colour));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FILLRECT_RECOLOUR:
|
case FILLRECT_RECOLOUR:
|
||||||
blitter->DrawColourMappingRect(dst, right, bottom, GB(colour, 0, PALETTE_WIDTH));
|
blitter->DrawColourMappingRect(dst, right, bottom, GB(std::get<PaletteID>(colour), 0, PALETTE_WIDTH));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FILLRECT_CHECKER: {
|
case FILLRECT_CHECKER: {
|
||||||
uint8_t bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
|
uint8_t bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1;
|
||||||
|
PixelColour pc = std::get<PixelColour>(colour);
|
||||||
do {
|
do {
|
||||||
for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8_t)colour);
|
for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, pc);
|
||||||
dst = blitter->MoveTo(dst, 0, 1);
|
dst = blitter->MoveTo(dst, 0, 1);
|
||||||
} while (--bottom > 0);
|
} while (--bottom > 0);
|
||||||
break;
|
break;
|
||||||
|
@ -209,7 +210,7 @@ static std::vector<LineSegment> MakePolygonSegments(std::span<const Point> shape
|
||||||
* FILLRECT_CHECKER: Fill every other pixel with the specified colour, in a checkerboard pattern.
|
* FILLRECT_CHECKER: Fill every other pixel with the specified colour, in a checkerboard pattern.
|
||||||
* FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the polygon.
|
* FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the polygon.
|
||||||
*/
|
*/
|
||||||
void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode)
|
void GfxFillPolygon(std::span<const Point> shape, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode)
|
||||||
{
|
{
|
||||||
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
||||||
const DrawPixelInfo *dpi = _cur_dpi;
|
const DrawPixelInfo *dpi = _cur_dpi;
|
||||||
|
@ -278,20 +279,22 @@ void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode)
|
||||||
void *dst = blitter->MoveTo(dpi->dst_ptr, x1, y);
|
void *dst = blitter->MoveTo(dpi->dst_ptr, x1, y);
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
default: // FILLRECT_OPAQUE
|
default: // FILLRECT_OPAQUE
|
||||||
blitter->DrawRect(dst, x2 - x1, 1, (uint8_t)colour);
|
blitter->DrawRect(dst, x2 - x1, 1, std::get<PixelColour>(colour));
|
||||||
break;
|
break;
|
||||||
case FILLRECT_RECOLOUR:
|
case FILLRECT_RECOLOUR:
|
||||||
blitter->DrawColourMappingRect(dst, x2 - x1, 1, GB(colour, 0, PALETTE_WIDTH));
|
blitter->DrawColourMappingRect(dst, x2 - x1, 1, GB(std::get<PaletteID>(colour), 0, PALETTE_WIDTH));
|
||||||
break;
|
break;
|
||||||
case FILLRECT_CHECKER:
|
case FILLRECT_CHECKER: {
|
||||||
/* Fill every other pixel, offset such that the sum of filled pixels' X and Y coordinates is odd.
|
/* Fill every other pixel, offset such that the sum of filled pixels' X and Y coordinates is odd.
|
||||||
* This creates a checkerboard effect. */
|
* This creates a checkerboard effect. */
|
||||||
|
PixelColour pc = std::get<PixelColour>(colour);
|
||||||
for (int x = (x1 + y) & 1; x < x2 - x1; x += 2) {
|
for (int x = (x1 + y) & 1; x < x2 - x1; x += 2) {
|
||||||
blitter->SetPixel(dst, x, 0, (uint8_t)colour);
|
blitter->SetPixel(dst, x, 0, pc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Next line */
|
/* Next line */
|
||||||
++y;
|
++y;
|
||||||
|
@ -312,7 +315,7 @@ void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode)
|
||||||
* @param width Width of the line.
|
* @param width Width of the line.
|
||||||
* @param dash Length of dashes for dashed lines. 0 means solid line.
|
* @param dash Length of dashes for dashed lines. 0 means solid line.
|
||||||
*/
|
*/
|
||||||
static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8_t colour, int width, int dash = 0)
|
static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash = 0)
|
||||||
{
|
{
|
||||||
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
|
||||||
|
|
||||||
|
@ -385,7 +388,7 @@ static inline bool GfxPreprocessLine(DrawPixelInfo *dpi, int &x, int &y, int &x2
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash)
|
void GfxDrawLine(int x, int y, int x2, int y2, PixelColour colour, int width, int dash)
|
||||||
{
|
{
|
||||||
DrawPixelInfo *dpi = _cur_dpi;
|
DrawPixelInfo *dpi = _cur_dpi;
|
||||||
if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) {
|
if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) {
|
||||||
|
@ -393,7 +396,7 @@ void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour)
|
void GfxDrawLineUnscaled(int x, int y, int x2, int y2, PixelColour colour)
|
||||||
{
|
{
|
||||||
DrawPixelInfo *dpi = _cur_dpi;
|
DrawPixelInfo *dpi = _cur_dpi;
|
||||||
if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) {
|
if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) {
|
||||||
|
@ -434,7 +437,7 @@ void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
|
||||||
* ....V.
|
* ....V.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const uint8_t colour = PC_WHITE;
|
static constexpr PixelColour colour = PC_WHITE;
|
||||||
|
|
||||||
GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour);
|
GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour);
|
||||||
GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour);
|
GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour);
|
||||||
|
@ -455,7 +458,7 @@ void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
|
||||||
* @param width Width of the outline.
|
* @param width Width of the outline.
|
||||||
* @param dash Length of dashes for dashed lines. 0 means solid lines.
|
* @param dash Length of dashes for dashed lines. 0 means solid lines.
|
||||||
*/
|
*/
|
||||||
void DrawRectOutline(const Rect &r, int colour, int width, int dash)
|
void DrawRectOutline(const Rect &r, PixelColour colour, int width, int dash)
|
||||||
{
|
{
|
||||||
GfxDrawLine(r.left, r.top, r.right, r.top, colour, width, dash);
|
GfxDrawLine(r.left, r.top, r.right, r.top, colour, width, dash);
|
||||||
GfxDrawLine(r.left, r.top, r.left, r.bottom, colour, width, dash);
|
GfxDrawLine(r.left, r.top, r.left, r.bottom, colour, width, dash);
|
||||||
|
@ -477,7 +480,7 @@ static void SetColourRemap(TextColour colour)
|
||||||
bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0;
|
bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0;
|
||||||
colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR | TC_FORCED);
|
colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR | TC_FORCED);
|
||||||
|
|
||||||
_string_colourremap[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour];
|
_string_colourremap[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour].p;
|
||||||
_string_colourremap[2] = no_shade ? 0 : 1;
|
_string_colourremap[2] = no_shade ? 0 : 1;
|
||||||
_colour_remap_ptr = _string_colourremap;
|
_colour_remap_ptr = _string_colourremap;
|
||||||
}
|
}
|
||||||
|
@ -580,10 +583,11 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
||||||
|
|
||||||
const uint shadow_offset = ScaleGUITrad(1);
|
const uint shadow_offset = ScaleGUITrad(1);
|
||||||
|
|
||||||
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation, TextColour &last_colour) {
|
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation, TextColour initial_colour) {
|
||||||
const DrawPixelInfo *dpi = _cur_dpi;
|
const DrawPixelInfo *dpi = _cur_dpi;
|
||||||
int dpi_left = dpi->left;
|
int dpi_left = dpi->left;
|
||||||
int dpi_right = dpi->left + dpi->width - 1;
|
int dpi_right = dpi->left + dpi->width - 1;
|
||||||
|
TextColour last_colour = initial_colour;
|
||||||
|
|
||||||
for (int run_index = 0; run_index < line.CountRuns(); run_index++) {
|
for (int run_index = 0; run_index < line.CountRuns(); run_index++) {
|
||||||
const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index);
|
const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index);
|
||||||
|
@ -593,13 +597,10 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
||||||
|
|
||||||
FontCache *fc = f->fc;
|
FontCache *fc = f->fc;
|
||||||
TextColour colour = f->colour;
|
TextColour colour = f->colour;
|
||||||
if (colour == TC_INVALID || HasFlag(last_colour, TC_FORCED)) {
|
if (colour == TC_INVALID || HasFlag(initial_colour, TC_FORCED)) colour = initial_colour;
|
||||||
colour = last_colour;
|
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
|
||||||
} else {
|
|
||||||
/* Update the last colour for the truncation ellipsis. */
|
/* Update the last colour for the truncation ellipsis. */
|
||||||
last_colour = colour;
|
last_colour = colour;
|
||||||
}
|
|
||||||
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
|
|
||||||
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
|
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
|
||||||
SetColourRemap(do_shadow ? TC_BLACK : colour);
|
SetColourRemap(do_shadow ? TC_BLACK : colour);
|
||||||
|
|
||||||
|
@ -625,21 +626,21 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
|
||||||
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), BlitterMode::ColourRemap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return last_colour;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Draw shadow, then foreground */
|
/* Draw shadow, then foreground */
|
||||||
for (bool do_shadow : {true, false}) {
|
for (bool do_shadow : {true, false}) {
|
||||||
TextColour last_colour = default_colour;
|
TextColour colour = draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, default_colour);
|
||||||
draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation, last_colour);
|
|
||||||
|
|
||||||
if (truncation) {
|
if (truncation) {
|
||||||
int x = (_current_text_dir == TD_RTL) ? left : (right - truncation_width);
|
int x = (_current_text_dir == TD_RTL) ? left : (right - truncation_width);
|
||||||
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false, last_colour);
|
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false, colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (underline) {
|
if (underline) {
|
||||||
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, _string_colourremap[1]);
|
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, PixelColour{_string_colourremap[1]});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
|
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
|
||||||
|
@ -1252,7 +1253,7 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode,
|
||||||
*/
|
*/
|
||||||
void LoadStringWidthTable(FontSizes fontsizes)
|
void LoadStringWidthTable(FontSizes fontsizes)
|
||||||
{
|
{
|
||||||
ClearFontCache(fontsizes);
|
FontCache::ClearFontCaches(fontsizes);
|
||||||
|
|
||||||
for (FontSize fs : fontsizes) {
|
for (FontSize fs : fontsizes) {
|
||||||
for (uint i = 0; i != 224; i++) {
|
for (uint i = 0; i != 224; i++) {
|
||||||
|
@ -1819,7 +1820,7 @@ bool AdjustGUIZoom(bool automatic)
|
||||||
if (old_font_zoom != _font_zoom) {
|
if (old_font_zoom != _font_zoom) {
|
||||||
GfxClearFontSpriteCache();
|
GfxClearFontSpriteCache();
|
||||||
}
|
}
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
LoadStringWidthTable();
|
LoadStringWidthTable();
|
||||||
|
|
||||||
SetupWidgetDimensions();
|
SetupWidgetDimensions();
|
||||||
|
|
|
@ -103,11 +103,11 @@ bool DrawStringMultiLineWithClipping(int left, int right, int top, int bottom, s
|
||||||
|
|
||||||
void DrawCharCentered(char32_t c, const Rect &r, TextColour colour);
|
void DrawCharCentered(char32_t c, const Rect &r, TextColour colour);
|
||||||
|
|
||||||
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE);
|
void GfxFillRect(int left, int top, int right, int bottom, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode = FILLRECT_OPAQUE);
|
||||||
void GfxFillPolygon(std::span<const Point> shape, int colour, FillRectMode mode = FILLRECT_OPAQUE);
|
void GfxFillPolygon(std::span<const Point> shape, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode = FILLRECT_OPAQUE);
|
||||||
void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width = 1, int dash = 0);
|
void GfxDrawLine(int left, int top, int right, int bottom, PixelColour colour, int width = 1, int dash = 0);
|
||||||
void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3);
|
void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3);
|
||||||
void DrawRectOutline(const Rect &r, int colour, int width = 1, int dash = 0);
|
void DrawRectOutline(const Rect &r, PixelColour colour, int width = 1, int dash = 0);
|
||||||
|
|
||||||
/* Versions of DrawString/DrawStringMultiLine that accept a Rect instead of separate left, right, top and bottom parameters. */
|
/* Versions of DrawString/DrawStringMultiLine that accept a Rect instead of separate left, right, top and bottom parameters. */
|
||||||
inline int DrawString(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL)
|
inline int DrawString(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL)
|
||||||
|
@ -135,7 +135,7 @@ inline bool DrawStringMultiLineWithClipping(const Rect &r, std::string_view str,
|
||||||
return DrawStringMultiLineWithClipping(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize);
|
return DrawStringMultiLineWithClipping(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void GfxFillRect(const Rect &r, int colour, FillRectMode mode = FILLRECT_OPAQUE)
|
inline void GfxFillRect(const Rect &r, const std::variant<PixelColour, PaletteID> &colour, FillRectMode mode = FILLRECT_OPAQUE)
|
||||||
{
|
{
|
||||||
GfxFillRect(r.left, r.top, r.right, r.bottom, colour, mode);
|
GfxFillRect(r.left, r.top, r.right, r.bottom, colour, mode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,6 @@ using Colour = std::conditional_t<std::endian::native == std::endian::little, Co
|
||||||
|
|
||||||
static_assert(sizeof(Colour) == sizeof(uint32_t));
|
static_assert(sizeof(Colour) == sizeof(uint32_t));
|
||||||
|
|
||||||
|
|
||||||
/** Available font sizes */
|
/** Available font sizes */
|
||||||
enum FontSize : uint8_t {
|
enum FontSize : uint8_t {
|
||||||
FS_NORMAL, ///< Index of the normal font in the font tables.
|
FS_NORMAL, ///< Index of the normal font in the font tables.
|
||||||
|
@ -403,4 +402,14 @@ enum StringAlignment : uint8_t {
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_AS_BIT_SET(StringAlignment)
|
DECLARE_ENUM_AS_BIT_SET(StringAlignment)
|
||||||
|
|
||||||
|
/** Colour for pixel/line drawing. */
|
||||||
|
struct PixelColour {
|
||||||
|
uint8_t p; ///< Palette index.
|
||||||
|
|
||||||
|
constexpr PixelColour() : p(0) {}
|
||||||
|
explicit constexpr PixelColour(uint8_t p) : p(p) {}
|
||||||
|
|
||||||
|
constexpr inline TextColour ToTextColour() const { return static_cast<TextColour>(this->p) | TC_IS_PALETTE_COLOUR; }
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* GFX_TYPE_H */
|
#endif /* GFX_TYPE_H */
|
||||||
|
|
|
@ -245,7 +245,7 @@ static void RealChangeBlitter(std::string_view repl_blitter)
|
||||||
|
|
||||||
/* Clear caches that might have sprites for another blitter. */
|
/* Clear caches that might have sprites for another blitter. */
|
||||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
GfxClearSpriteCache();
|
GfxClearSpriteCache();
|
||||||
ReInitAllWindows(false);
|
ReInitAllWindows(false);
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,7 @@ void CheckBlitter()
|
||||||
{
|
{
|
||||||
if (!SwitchNewGRFBlitter()) return;
|
if (!SwitchNewGRFBlitter()) return;
|
||||||
|
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
GfxClearSpriteCache();
|
GfxClearSpriteCache();
|
||||||
ReInitAllWindows(false);
|
ReInitAllWindows(false);
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,7 @@ void GfxLoadSprites()
|
||||||
|
|
||||||
SwitchNewGRFBlitter();
|
SwitchNewGRFBlitter();
|
||||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
GfxInitSpriteMem();
|
GfxInitSpriteMem();
|
||||||
LoadSpriteTables();
|
LoadSpriteTables();
|
||||||
GfxInitPalettes();
|
GfxInitPalettes();
|
||||||
|
|
|
@ -165,11 +165,11 @@ struct ValuesInterval {
|
||||||
struct BaseGraphWindow : Window {
|
struct BaseGraphWindow : Window {
|
||||||
protected:
|
protected:
|
||||||
static const int GRAPH_MAX_DATASETS = 64;
|
static const int GRAPH_MAX_DATASETS = 64;
|
||||||
static const int GRAPH_BASE_COLOUR = GREY_SCALE(2);
|
static constexpr PixelColour GRAPH_BASE_COLOUR = GREY_SCALE(2);
|
||||||
static const int GRAPH_GRID_COLOUR = GREY_SCALE(3);
|
static constexpr PixelColour GRAPH_GRID_COLOUR = GREY_SCALE(3);
|
||||||
static const int GRAPH_AXIS_LINE_COLOUR = GREY_SCALE(1);
|
static constexpr PixelColour GRAPH_AXIS_LINE_COLOUR = GREY_SCALE(1);
|
||||||
static const int GRAPH_ZERO_LINE_COLOUR = GREY_SCALE(8);
|
static constexpr PixelColour GRAPH_ZERO_LINE_COLOUR = GREY_SCALE(8);
|
||||||
static const int GRAPH_YEAR_LINE_COLOUR = GREY_SCALE(5);
|
static constexpr PixelColour GRAPH_YEAR_LINE_COLOUR = GREY_SCALE(5);
|
||||||
static const int GRAPH_NUM_MONTHS = 24; ///< Number of months displayed in the graph.
|
static const int GRAPH_NUM_MONTHS = 24; ///< Number of months displayed in the graph.
|
||||||
static const int GRAPH_PAYMENT_RATE_STEPS = 20; ///< Number of steps on Payment rate graph.
|
static const int GRAPH_PAYMENT_RATE_STEPS = 20; ///< Number of steps on Payment rate graph.
|
||||||
static const int PAYMENT_GRAPH_X_STEP_DAYS = 10; ///< X-axis step label for cargo payment rates "Days in transit".
|
static const int PAYMENT_GRAPH_X_STEP_DAYS = 10; ///< X-axis step label for cargo payment rates "Days in transit".
|
||||||
|
@ -182,8 +182,9 @@ protected:
|
||||||
static const int MIN_GRAPH_NUM_LINES_Y = 9; ///< Minimal number of horizontal lines to draw.
|
static const int MIN_GRAPH_NUM_LINES_Y = 9; ///< Minimal number of horizontal lines to draw.
|
||||||
static const int MIN_GRID_PIXEL_SIZE = 20; ///< Minimum distance between graph lines.
|
static const int MIN_GRID_PIXEL_SIZE = 20; ///< Minimum distance between graph lines.
|
||||||
|
|
||||||
uint64_t excluded_data = 0; ///< bitmask of the datasets that shouldn't be displayed.
|
uint64_t excluded_data = 0; ///< bitmask of datasets hidden by the player.
|
||||||
uint64_t excluded_range = 0; ///< bitmask of ranges that should not be displayed.
|
uint64_t excluded_range = 0; ///< bitmask of ranges hidden by the player.
|
||||||
|
uint64_t masked_range = 0; ///< bitmask of ranges that are not available for the current data.
|
||||||
uint8_t num_on_x_axis = 0;
|
uint8_t num_on_x_axis = 0;
|
||||||
uint8_t num_vert_lines = GRAPH_NUM_MONTHS;
|
uint8_t num_vert_lines = GRAPH_NUM_MONTHS;
|
||||||
|
|
||||||
|
@ -203,7 +204,7 @@ protected:
|
||||||
|
|
||||||
struct DataSet {
|
struct DataSet {
|
||||||
std::array<OverflowSafeInt64, GRAPH_NUM_MONTHS> values;
|
std::array<OverflowSafeInt64, GRAPH_NUM_MONTHS> values;
|
||||||
uint8_t colour;
|
PixelColour colour;
|
||||||
uint8_t exclude_bit;
|
uint8_t exclude_bit;
|
||||||
uint8_t range_bit;
|
uint8_t range_bit;
|
||||||
uint8_t dash;
|
uint8_t dash;
|
||||||
|
@ -216,13 +217,20 @@ protected:
|
||||||
uint8_t highlight_range = UINT8_MAX; ///< Data range that should be highlighted, or UINT8_MAX for none.
|
uint8_t highlight_range = UINT8_MAX; ///< Data range that should be highlighted, or UINT8_MAX for none.
|
||||||
bool highlight_state = false; ///< Current state of highlight, toggled every TIMER_BLINK_INTERVAL period.
|
bool highlight_state = false; ///< Current state of highlight, toggled every TIMER_BLINK_INTERVAL period.
|
||||||
|
|
||||||
template <typename Tprojection>
|
struct BaseFiller {
|
||||||
struct Filler {
|
|
||||||
DataSet &dataset; ///< Dataset to fill.
|
DataSet &dataset; ///< Dataset to fill.
|
||||||
|
|
||||||
|
inline void MakeZero(uint i) const { this->dataset.values[i] = 0; }
|
||||||
|
inline void MakeInvalid(uint i) const { this->dataset.values[i] = INVALID_DATAPOINT; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Tprojection>
|
||||||
|
struct Filler : BaseFiller {
|
||||||
const Tprojection &proj; ///< Projection to apply.
|
const Tprojection &proj; ///< Projection to apply.
|
||||||
|
|
||||||
|
constexpr Filler(DataSet &dataset, const Tprojection &proj) : BaseFiller(dataset), proj(proj) {}
|
||||||
|
|
||||||
inline void Fill(uint i, const auto &data) const { this->dataset.values[i] = std::invoke(this->proj, data); }
|
inline void Fill(uint i, const auto &data) const { this->dataset.values[i] = std::invoke(this->proj, data); }
|
||||||
inline void MakeInvalid(uint i) const { this->dataset.values[i] = INVALID_DATAPOINT; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -390,7 +398,7 @@ protected:
|
||||||
|
|
||||||
/* Draw the grid lines. */
|
/* Draw the grid lines. */
|
||||||
int gridline_width = WidgetDimensions::scaled.bevel.top;
|
int gridline_width = WidgetDimensions::scaled.bevel.top;
|
||||||
int grid_colour = GRAPH_GRID_COLOUR;
|
PixelColour grid_colour = GRAPH_GRID_COLOUR;
|
||||||
|
|
||||||
/* Don't draw the first line, as that's where the axis will be. */
|
/* Don't draw the first line, as that's where the axis will be. */
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
|
@ -516,7 +524,7 @@ protected:
|
||||||
uint pointoffs1 = pointwidth / 2;
|
uint pointoffs1 = pointwidth / 2;
|
||||||
uint pointoffs2 = pointwidth - pointoffs1;
|
uint pointoffs2 = pointwidth - pointoffs1;
|
||||||
|
|
||||||
auto draw_dataset = [&](const DataSet &dataset, uint8_t colour) {
|
auto draw_dataset = [&](const DataSet &dataset, PixelColour colour) {
|
||||||
if (HasBit(this->excluded_data, dataset.exclude_bit)) return;
|
if (HasBit(this->excluded_data, dataset.exclude_bit)) return;
|
||||||
if (HasBit(this->excluded_range, dataset.range_bit)) return;
|
if (HasBit(this->excluded_range, dataset.range_bit)) return;
|
||||||
|
|
||||||
|
@ -675,13 +683,17 @@ public:
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
Rect line = r.WithHeight(line_height);
|
Rect line = r.WithHeight(line_height);
|
||||||
for (const auto &str : this->ranges) {
|
for (const auto &str : this->ranges) {
|
||||||
bool lowered = !HasBit(this->excluded_range, index);
|
bool lowered = !HasBit(this->excluded_range, index) && !HasBit(this->masked_range, index);
|
||||||
|
|
||||||
/* Redraw frame if lowered */
|
/* Redraw frame if lowered */
|
||||||
if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered);
|
if (lowered) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered);
|
||||||
|
|
||||||
const Rect text = line.Shrink(WidgetDimensions::scaled.framerect);
|
const Rect text = line.Shrink(WidgetDimensions::scaled.framerect);
|
||||||
DrawString(text, str, TC_BLACK, SA_CENTER, false, FS_SMALL);
|
DrawString(text, str, (this->highlight_state && this->highlight_range == index) ? TC_WHITE : TC_BLACK, SA_CENTER, false, FS_SMALL);
|
||||||
|
|
||||||
|
if (HasBit(this->masked_range, index)) {
|
||||||
|
GfxFillRect(line.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_BROWN, SHADE_DARKER), FILLRECT_CHECKER);
|
||||||
|
}
|
||||||
|
|
||||||
line = line.Translate(0, line_height);
|
line = line.Translate(0, line_height);
|
||||||
++index;
|
++index;
|
||||||
|
@ -704,6 +716,7 @@ public:
|
||||||
case WID_GRAPH_RANGE_MATRIX: {
|
case WID_GRAPH_RANGE_MATRIX: {
|
||||||
int row = GetRowFromWidget(pt.y, widget, 0, GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical());
|
int row = GetRowFromWidget(pt.y, widget, 0, GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical());
|
||||||
|
|
||||||
|
if (HasBit(this->masked_range, row)) break;
|
||||||
ToggleBit(this->excluded_range, row);
|
ToggleBit(this->excluded_range, row);
|
||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
break;
|
break;
|
||||||
|
@ -1115,6 +1128,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
|
||||||
{
|
{
|
||||||
this->CreateNestedTree();
|
this->CreateNestedTree();
|
||||||
|
|
||||||
|
this->excluded_range = this->masked_range;
|
||||||
this->cargo_types = this->GetCargoTypes(number);
|
this->cargo_types = this->GetCargoTypes(number);
|
||||||
|
|
||||||
this->vscroll = this->GetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR);
|
this->vscroll = this->GetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR);
|
||||||
|
@ -1208,7 +1222,7 @@ struct BaseCargoGraphWindow : BaseGraphWindow {
|
||||||
/* Cargo-colour box with outline */
|
/* Cargo-colour box with outline */
|
||||||
const Rect cargo = text.WithWidth(this->legend_width, rtl);
|
const Rect cargo = text.WithWidth(this->legend_width, rtl);
|
||||||
GfxFillRect(cargo, PC_BLACK);
|
GfxFillRect(cargo, PC_BLACK);
|
||||||
uint8_t pc = cs->legend_colour;
|
PixelColour pc = cs->legend_colour;
|
||||||
if (this->highlight_data == cs->Index()) pc = this->highlight_state ? PC_WHITE : PC_BLACK;
|
if (this->highlight_data == cs->Index()) pc = this->highlight_state ? PC_WHITE : PC_BLACK;
|
||||||
GfxFillRect(cargo.Shrink(WidgetDimensions::scaled.bevel), pc);
|
GfxFillRect(cargo.Shrink(WidgetDimensions::scaled.bevel), pc);
|
||||||
|
|
||||||
|
@ -1485,8 +1499,8 @@ struct PerformanceRatingDetailWindow : Window {
|
||||||
ScoreID score_type = (ScoreID)(widget - WID_PRD_SCORE_FIRST);
|
ScoreID score_type = (ScoreID)(widget - WID_PRD_SCORE_FIRST);
|
||||||
|
|
||||||
/* The colours used to show how the progress is going */
|
/* The colours used to show how the progress is going */
|
||||||
int colour_done = GetColourGradient(COLOUR_GREEN, SHADE_NORMAL);
|
PixelColour colour_done = GetColourGradient(COLOUR_GREEN, SHADE_NORMAL);
|
||||||
int colour_notdone = GetColourGradient(COLOUR_RED, SHADE_NORMAL);
|
PixelColour colour_notdone = GetColourGradient(COLOUR_RED, SHADE_NORMAL);
|
||||||
|
|
||||||
/* Draw all the score parts */
|
/* Draw all the score parts */
|
||||||
int64_t val = _score_part[company][score_type];
|
int64_t val = _score_part[company][score_type];
|
||||||
|
@ -1608,7 +1622,9 @@ CompanyID PerformanceRatingDetailWindow::company = CompanyID::Invalid();
|
||||||
struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
|
struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
|
||||||
static inline constexpr StringID RANGE_LABELS[] = {
|
static inline constexpr StringID RANGE_LABELS[] = {
|
||||||
STR_GRAPH_INDUSTRY_RANGE_PRODUCED,
|
STR_GRAPH_INDUSTRY_RANGE_PRODUCED,
|
||||||
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED
|
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED,
|
||||||
|
STR_GRAPH_INDUSTRY_RANGE_DELIVERED,
|
||||||
|
STR_GRAPH_INDUSTRY_RANGE_WAITING,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline CargoTypes excluded_cargo_types{};
|
static inline CargoTypes excluded_cargo_types{};
|
||||||
|
@ -1623,6 +1639,10 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
|
||||||
this->draw_dates = !TimerGameEconomy::UsingWallclockUnits();
|
this->draw_dates = !TimerGameEconomy::UsingWallclockUnits();
|
||||||
this->ranges = RANGE_LABELS;
|
this->ranges = RANGE_LABELS;
|
||||||
|
|
||||||
|
const Industry *i = Industry::Get(window_number);
|
||||||
|
if (!i->IsCargoProduced()) this->masked_range = (1U << 0) | (1U << 1);
|
||||||
|
if (!i->IsCargoAccepted()) this->masked_range = (1U << 2) | (1U << 3);
|
||||||
|
|
||||||
this->InitializeWindow(window_number, STR_GRAPH_LAST_24_MINUTES_TIME_LABEL);
|
this->InitializeWindow(window_number, STR_GRAPH_LAST_24_MINUTES_TIME_LABEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1630,6 +1650,9 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
|
||||||
{
|
{
|
||||||
CargoTypes cargo_types{};
|
CargoTypes cargo_types{};
|
||||||
const Industry *i = Industry::Get(window_number);
|
const Industry *i = Industry::Get(window_number);
|
||||||
|
for (const auto &a : i->accepted) {
|
||||||
|
if (IsValidCargoType(a.cargo)) SetBit(cargo_types, a.cargo);
|
||||||
|
}
|
||||||
for (const auto &p : i->produced) {
|
for (const auto &p : i->produced) {
|
||||||
if (IsValidCargoType(p.cargo)) SetBit(cargo_types, p.cargo);
|
if (IsValidCargoType(p.cargo)) SetBit(cargo_types, p.cargo);
|
||||||
}
|
}
|
||||||
|
@ -1643,7 +1666,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
|
||||||
|
|
||||||
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
|
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
|
||||||
{
|
{
|
||||||
if (widget == WID_GRAPH_CAPTION) return GetString(STR_GRAPH_INDUSTRY_PRODUCTION_CAPTION, this->window_number);
|
if (widget == WID_GRAPH_CAPTION) return GetString(STR_GRAPH_INDUSTRY_CAPTION, this->window_number);
|
||||||
|
|
||||||
return this->Window::GetWidgetString(widget, stringid);
|
return this->Window::GetWidgetString(widget, stringid);
|
||||||
}
|
}
|
||||||
|
@ -1691,6 +1714,33 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
|
||||||
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, produced_filler, transported_filler);
|
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, produced_filler, transported_filler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &a : i->accepted) {
|
||||||
|
if (!IsValidCargoType(a.cargo)) continue;
|
||||||
|
const CargoSpec *cs = CargoSpec::Get(a.cargo);
|
||||||
|
|
||||||
|
this->data.reserve(this->data.size() + 2);
|
||||||
|
|
||||||
|
DataSet &accepted = this->data.emplace_back();
|
||||||
|
accepted.colour = cs->legend_colour;
|
||||||
|
accepted.exclude_bit = cs->Index();
|
||||||
|
accepted.range_bit = 2;
|
||||||
|
accepted.dash = 1;
|
||||||
|
auto accepted_filler = Filler{accepted, &Industry::AcceptedHistory::accepted};
|
||||||
|
|
||||||
|
DataSet &waiting = this->data.emplace_back();
|
||||||
|
waiting.colour = cs->legend_colour;
|
||||||
|
waiting.exclude_bit = cs->Index();
|
||||||
|
waiting.range_bit = 3;
|
||||||
|
waiting.dash = 4;
|
||||||
|
auto waiting_filler = Filler{waiting, &Industry::AcceptedHistory::waiting};
|
||||||
|
|
||||||
|
if (a.history == nullptr) {
|
||||||
|
FillFromEmpty<GRAPH_NUM_MONTHS>(i->valid_history, accepted_filler, waiting_filler);
|
||||||
|
} else {
|
||||||
|
FillFromHistory<GRAPH_NUM_MONTHS>(*a.history, i->valid_history, accepted_filler, waiting_filler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -305,7 +305,7 @@ private:
|
||||||
|
|
||||||
const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
|
const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
|
||||||
const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
|
const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
|
||||||
const int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
const PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
||||||
|
|
||||||
if (indent > 0) {
|
if (indent > 0) {
|
||||||
/* Draw tree continuation lines. */
|
/* Draw tree continuation lines. */
|
||||||
|
|
|
@ -77,10 +77,27 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
||||||
HistoryData<ProducedHistory> history{}; ///< History of cargo produced and transported for this month and 24 previous months
|
HistoryData<ProducedHistory> history{}; ///< History of cargo produced and transported for this month and 24 previous months
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AcceptedHistory {
|
||||||
|
uint16_t accepted = 0; /// Total accepted.
|
||||||
|
uint16_t waiting = 0; /// Average waiting.
|
||||||
|
};
|
||||||
|
|
||||||
struct AcceptedCargo {
|
struct AcceptedCargo {
|
||||||
CargoType cargo = 0; ///< Cargo type
|
CargoType cargo = 0; ///< Cargo type
|
||||||
uint16_t waiting = 0; ///< Amount of cargo waiting to processed
|
uint16_t waiting = 0; ///< Amount of cargo waiting to processed
|
||||||
|
uint32_t accumulated_waiting = 0; ///< Accumulated waiting total over the last month, used to calculate average.
|
||||||
TimerGameEconomy::Date last_accepted{}; ///< Last day cargo was accepted by this industry
|
TimerGameEconomy::Date last_accepted{}; ///< Last day cargo was accepted by this industry
|
||||||
|
std::unique_ptr<HistoryData<AcceptedHistory>> history{}; ///< History of accepted and waiting cargo.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get history data, creating it if necessary.
|
||||||
|
* @return Accepted history data.
|
||||||
|
*/
|
||||||
|
inline HistoryData<AcceptedHistory> &GetOrCreateHistory()
|
||||||
|
{
|
||||||
|
if (this->history == nullptr) this->history = std::make_unique<HistoryData<AcceptedHistory>>();
|
||||||
|
return *this->history;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using ProducedCargoes = std::vector<ProducedCargo>;
|
using ProducedCargoes = std::vector<ProducedCargo>;
|
||||||
|
@ -151,7 +168,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
||||||
*/
|
*/
|
||||||
inline const AcceptedCargo &GetAccepted(size_t slot) const
|
inline const AcceptedCargo &GetAccepted(size_t slot) const
|
||||||
{
|
{
|
||||||
static const AcceptedCargo empty{INVALID_CARGO, 0, {}};
|
static const AcceptedCargo empty{INVALID_CARGO, 0, 0, {}, {}};
|
||||||
return slot < this->accepted.size() ? this->accepted[slot] : empty;
|
return slot < this->accepted.size() ? this->accepted[slot] : empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1245,6 +1245,10 @@ void OnTick_Industry()
|
||||||
|
|
||||||
for (Industry *i : Industry::Iterate()) {
|
for (Industry *i : Industry::Iterate()) {
|
||||||
ProduceIndustryGoods(i);
|
ProduceIndustryGoods(i);
|
||||||
|
|
||||||
|
if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
|
||||||
|
for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2505,6 +2509,14 @@ static void UpdateIndustryStatistics(Industry *i)
|
||||||
RotateHistory(p.history);
|
RotateHistory(p.history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &a : i->accepted) {
|
||||||
|
if (!IsValidCargoType(a.cargo)) continue;
|
||||||
|
if (a.history == nullptr) continue;
|
||||||
|
|
||||||
|
(*a.history)[THIS_MONTH].waiting = GetAndResetAccumulatedAverage<uint16_t>(a.accumulated_waiting);
|
||||||
|
RotateHistory(*a.history);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,6 +27,4 @@ DEF_CMD_TRAIT(CMD_INDUSTRY_SET_EXCLUSIVITY, CmdIndustrySetExclusivity, CommandFl
|
||||||
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_TEXT, CmdIndustrySetText, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
|
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_TEXT, CmdIndustrySetText, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT)
|
||||||
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_PRODUCTION, CmdIndustrySetProduction, CommandFlag::Deity, CMDT_OTHER_MANAGEMENT)
|
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_PRODUCTION, CmdIndustrySetProduction, CommandFlag::Deity, CMDT_OTHER_MANAGEMENT)
|
||||||
|
|
||||||
void CcBuildIndustry(Commands cmd, const CommandCost &result, TileIndex tile, IndustryType indtype, uint32_t, bool, uint32_t);
|
|
||||||
|
|
||||||
#endif /* INDUSTRY_CMD_H */
|
#endif /* INDUSTRY_CMD_H */
|
||||||
|
|
|
@ -257,25 +257,6 @@ void SortIndustryTypes()
|
||||||
std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), IndustryTypeNameSorter);
|
std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), IndustryTypeNameSorter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Command callback. In case of failure to build an industry, show an error message.
|
|
||||||
* @param result Result of the command.
|
|
||||||
* @param tile Tile where the industry is placed.
|
|
||||||
* @param indtype Industry type.
|
|
||||||
*/
|
|
||||||
void CcBuildIndustry(Commands, const CommandCost &result, TileIndex tile, IndustryType indtype, uint32_t, bool, uint32_t)
|
|
||||||
{
|
|
||||||
if (result.Succeeded()) return;
|
|
||||||
|
|
||||||
if (indtype < NUM_INDUSTRYTYPES) {
|
|
||||||
const IndustrySpec *indsp = GetIndustrySpec(indtype);
|
|
||||||
if (indsp->enabled) {
|
|
||||||
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_HERE, indsp->name),
|
|
||||||
GetEncodedString(result.GetErrorMessage()), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr NWidgetPart _nested_build_industry_widgets[] = {
|
static constexpr NWidgetPart _nested_build_industry_widgets[] = {
|
||||||
NWidget(NWID_HORIZONTAL),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||||
|
@ -745,7 +726,7 @@ public:
|
||||||
AutoRestoreBackup backup_generating_world(_generating_world, true);
|
AutoRestoreBackup backup_generating_world(_generating_world, true);
|
||||||
AutoRestoreBackup backup_ignore_industry_restritions(_ignore_industry_restrictions, true);
|
AutoRestoreBackup backup_ignore_industry_restritions(_ignore_industry_restrictions, true);
|
||||||
|
|
||||||
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, this->selected_type, layout_index, false, seed);
|
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
|
||||||
} else {
|
} else {
|
||||||
success = Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
|
success = Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
|
||||||
}
|
}
|
||||||
|
@ -845,7 +826,7 @@ public:
|
||||||
nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZoomLevel::Industry));
|
nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZoomLevel::Industry));
|
||||||
|
|
||||||
const Industry *i = Industry::Get(window_number);
|
const Industry *i = Industry::Get(window_number);
|
||||||
if (!i->IsCargoProduced()) this->DisableWidget(WID_IV_GRAPH);
|
if (!i->IsCargoProduced() && !i->IsCargoAccepted()) this->DisableWidget(WID_IV_GRAPH);
|
||||||
|
|
||||||
this->InvalidateData();
|
this->InvalidateData();
|
||||||
}
|
}
|
||||||
|
@ -1242,7 +1223,7 @@ static constexpr NWidgetPart _nested_industry_view_widgets[] = {
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_HORIZONTAL),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
|
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
|
||||||
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_VIEW_PRODUCTION_GRAPH, STR_INDUSTRY_VIEW_PRODUCTION_GRAPH_TOOLTIP),
|
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_VIEW_CARGO_GRAPH, STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP),
|
||||||
NWidget(WWT_RESIZEBOX, COLOUR_CREAM),
|
NWidget(WWT_RESIZEBOX, COLOUR_CREAM),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
};
|
};
|
||||||
|
@ -2005,8 +1986,8 @@ struct CargoesField {
|
||||||
static Dimension cargo_space;
|
static Dimension cargo_space;
|
||||||
static Dimension cargo_stub;
|
static Dimension cargo_stub;
|
||||||
|
|
||||||
static const int INDUSTRY_LINE_COLOUR;
|
static const PixelColour INDUSTRY_LINE_COLOUR;
|
||||||
static const int CARGO_LINE_COLOUR;
|
static const PixelColour CARGO_LINE_COLOUR;
|
||||||
|
|
||||||
static int small_height, normal_height;
|
static int small_height, normal_height;
|
||||||
static int cargo_field_width;
|
static int cargo_field_width;
|
||||||
|
@ -2414,8 +2395,8 @@ int CargoesField::vert_inter_industry_space; ///< Amount of space between two in
|
||||||
|
|
||||||
int CargoesField::blob_distance; ///< Distance of the industry legend colour from the edge of the industry box.
|
int CargoesField::blob_distance; ///< Distance of the industry legend colour from the edge of the industry box.
|
||||||
|
|
||||||
const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box.
|
const PixelColour CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box.
|
||||||
const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo.
|
const PixelColour CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo.
|
||||||
|
|
||||||
/** A single row of #CargoesField. */
|
/** A single row of #CargoesField. */
|
||||||
struct CargoesRow {
|
struct CargoesRow {
|
||||||
|
|
|
@ -119,7 +119,7 @@ struct IndustrySpec {
|
||||||
IndustryLifeTypes life_type; ///< This is also known as Industry production flag, in newgrf specs
|
IndustryLifeTypes life_type; ///< This is also known as Industry production flag, in newgrf specs
|
||||||
LandscapeTypes climate_availability; ///< Bitmask, giving landscape enums as bit position
|
LandscapeTypes climate_availability; ///< Bitmask, giving landscape enums as bit position
|
||||||
IndustryBehaviours behaviour; ///< How this industry will behave, and how others entities can use it
|
IndustryBehaviours behaviour; ///< How this industry will behave, and how others entities can use it
|
||||||
uint8_t map_colour; ///< colour used for the small map
|
PixelColour map_colour; ///< colour used for the small map
|
||||||
StringID name; ///< Displayed name of the industry
|
StringID name; ///< Displayed name of the industry
|
||||||
StringID new_industry_text; ///< Message appearing when the industry is built
|
StringID new_industry_text; ///< Message appearing when the industry is built
|
||||||
StringID closure_text; ///< Message appearing when the industry closes
|
StringID closure_text; ///< Message appearing when the industry closes
|
||||||
|
|
|
@ -634,9 +634,11 @@ STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Display
|
||||||
STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph of this cargo type
|
STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph of this cargo type
|
||||||
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
|
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
|
||||||
|
|
||||||
STR_GRAPH_INDUSTRY_PRODUCTION_CAPTION :{WHITE}{INDUSTRY} - Production History
|
STR_GRAPH_INDUSTRY_CAPTION :{WHITE}{INDUSTRY} - Cargo History
|
||||||
STR_GRAPH_INDUSTRY_RANGE_PRODUCED :Produced
|
STR_GRAPH_INDUSTRY_RANGE_PRODUCED :Produced
|
||||||
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Transported
|
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Transported
|
||||||
|
STR_GRAPH_INDUSTRY_RANGE_DELIVERED :Delivered
|
||||||
|
STR_GRAPH_INDUSTRY_RANGE_WAITING :Waiting
|
||||||
|
|
||||||
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings
|
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings
|
||||||
|
|
||||||
|
@ -4024,8 +4026,8 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Producti
|
||||||
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Production last minute:
|
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Production last minute:
|
||||||
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} ({COMMA}% transported)
|
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} ({COMMA}% transported)
|
||||||
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre the main view on industry location. Ctrl+Click to open a new viewport on industry location
|
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre the main view on industry location. Ctrl+Click to open a new viewport on industry location
|
||||||
STR_INDUSTRY_VIEW_PRODUCTION_GRAPH :{BLACK}Production Graph
|
STR_INDUSTRY_VIEW_CARGO_GRAPH :{BLACK}Cargo Graph
|
||||||
STR_INDUSTRY_VIEW_PRODUCTION_GRAPH_TOOLTIP :{BLACK}Shows the graph of industry production history
|
STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP :{BLACK}Shows the graph of industry cargo history
|
||||||
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}%
|
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}%
|
||||||
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure!
|
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure!
|
||||||
|
|
||||||
|
|
|
@ -30,26 +30,26 @@
|
||||||
* Colours for the various "load" states of links. Ordered from "unused" to
|
* Colours for the various "load" states of links. Ordered from "unused" to
|
||||||
* "overloaded".
|
* "overloaded".
|
||||||
*/
|
*/
|
||||||
const uint8_t LinkGraphOverlay::LINK_COLOURS[][12] = {
|
const PixelColour LinkGraphOverlay::LINK_COLOURS[][12] = {
|
||||||
{
|
{
|
||||||
0x0f, 0xd1, 0xd0, 0x57,
|
PixelColour{0x0f}, PixelColour{0xd1}, PixelColour{0xd0}, PixelColour{0x57},
|
||||||
0x55, 0x53, 0xbf, 0xbd,
|
PixelColour{0x55}, PixelColour{0x53}, PixelColour{0xbf}, PixelColour{0xbd},
|
||||||
0xba, 0xb9, 0xb7, 0xb5
|
PixelColour{0xba}, PixelColour{0xb9}, PixelColour{0xb7}, PixelColour{0xb5}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
0x0f, 0xd1, 0xd0, 0x57,
|
PixelColour{0x0f}, PixelColour{0xd1}, PixelColour{0xd0}, PixelColour{0x57},
|
||||||
0x55, 0x53, 0x96, 0x95,
|
PixelColour{0x55}, PixelColour{0x53}, PixelColour{0x96}, PixelColour{0x95},
|
||||||
0x94, 0x93, 0x92, 0x91
|
PixelColour{0x94}, PixelColour{0x93}, PixelColour{0x92}, PixelColour{0x91}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
0x0f, 0x0b, 0x09, 0x07,
|
PixelColour{0x0f}, PixelColour{0x0b}, PixelColour{0x09}, PixelColour{0x07},
|
||||||
0x05, 0x03, 0xbf, 0xbd,
|
PixelColour{0x05}, PixelColour{0x03}, PixelColour{0xbf}, PixelColour{0xbd},
|
||||||
0xba, 0xb9, 0xb7, 0xb5
|
PixelColour{0xba}, PixelColour{0xb9}, PixelColour{0xb7}, PixelColour{0xb5}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
0x0f, 0x0b, 0x0a, 0x09,
|
PixelColour{0x0f}, PixelColour{0x0b}, PixelColour{0x0a}, PixelColour{0x09},
|
||||||
0x08, 0x07, 0x06, 0x05,
|
PixelColour{0x08}, PixelColour{0x07}, PixelColour{0x06}, PixelColour{0x05},
|
||||||
0x04, 0x03, 0x02, 0x01
|
PixelColour{0x04}, PixelColour{0x03}, PixelColour{0x02}, PixelColour{0x01}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ void LinkGraphOverlay::DrawLinks(const DrawPixelInfo *dpi) const
|
||||||
void LinkGraphOverlay::DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const
|
void LinkGraphOverlay::DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const
|
||||||
{
|
{
|
||||||
uint usage_or_plan = std::min(cargo.capacity * 2 + 1, cargo.Usage());
|
uint usage_or_plan = std::min(cargo.capacity * 2 + 1, cargo.Usage());
|
||||||
int colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][usage_or_plan * lengthof(LinkGraphOverlay::LINK_COLOURS[0]) / (cargo.capacity * 2 + 2)];
|
PixelColour colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][usage_or_plan * lengthof(LinkGraphOverlay::LINK_COLOURS[0]) / (cargo.capacity * 2 + 2)];
|
||||||
int width = ScaleGUITrad(this->scale);
|
int width = ScaleGUITrad(this->scale);
|
||||||
int dash = cargo.shared ? width * 4 : 0;
|
int dash = cargo.shared ? width * 4 : 0;
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ void LinkGraphOverlay::DrawStationDots(const DrawPixelInfo *dpi) const
|
||||||
* @param colour Colour with which the vertex will be filled.
|
* @param colour Colour with which the vertex will be filled.
|
||||||
* @param border_colour Colour for the border of the vertex.
|
* @param border_colour Colour for the border of the vertex.
|
||||||
*/
|
*/
|
||||||
/* static */ void LinkGraphOverlay::DrawVertex(int x, int y, int size, int colour, int border_colour)
|
/* static */ void LinkGraphOverlay::DrawVertex(int x, int y, int size, PixelColour colour, PixelColour border_colour)
|
||||||
{
|
{
|
||||||
size--;
|
size--;
|
||||||
int w1 = size / 2;
|
int w1 = size / 2;
|
||||||
|
@ -607,7 +607,7 @@ void LinkGraphLegendWindow::DrawWidget(const Rect &r, WidgetID widget) const
|
||||||
DrawCompanyIcon(cid, CentreBounds(br.left, br.right, sprite_size.width), CentreBounds(br.top, br.bottom, sprite_size.height));
|
DrawCompanyIcon(cid, CentreBounds(br.left, br.right, sprite_size.width), CentreBounds(br.top, br.bottom, sprite_size.height));
|
||||||
}
|
}
|
||||||
if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
|
if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
|
||||||
uint8_t colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][widget - WID_LGL_SATURATION_FIRST];
|
PixelColour colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][widget - WID_LGL_SATURATION_FIRST];
|
||||||
GfxFillRect(br, colour);
|
GfxFillRect(br, colour);
|
||||||
StringID str = STR_NULL;
|
StringID str = STR_NULL;
|
||||||
if (widget == WID_LGL_SATURATION_FIRST) {
|
if (widget == WID_LGL_SATURATION_FIRST) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
typedef std::map<StationID, StationLinkMap> LinkMap;
|
typedef std::map<StationID, StationLinkMap> LinkMap;
|
||||||
typedef std::vector<std::pair<StationID, uint> > StationSupplyList;
|
typedef std::vector<std::pair<StationID, uint> > StationSupplyList;
|
||||||
|
|
||||||
static const uint8_t LINK_COLOURS[][12];
|
static const PixelColour LINK_COLOURS[][12];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a link graph overlay for the specified window.
|
* Create a link graph overlay for the specified window.
|
||||||
|
@ -95,7 +95,7 @@ protected:
|
||||||
void RebuildCache();
|
void RebuildCache();
|
||||||
|
|
||||||
static void AddStats(CargoType new_cargo, uint new_cap, uint new_usg, uint new_flow, uint32_t time, bool new_shared, LinkProperties &cargo);
|
static void AddStats(CargoType new_cargo, uint new_cap, uint new_usg, uint new_flow, uint32_t time, bool new_shared, LinkProperties &cargo);
|
||||||
static void DrawVertex(int x, int y, int size, int colour, int border_colour);
|
static void DrawVertex(int x, int y, int size, PixelColour colour, PixelColour border_colour);
|
||||||
};
|
};
|
||||||
|
|
||||||
void ShowLinkGraphLegend();
|
void ShowLinkGraphLegend();
|
||||||
|
|
|
@ -42,13 +42,13 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erase all flows originating at a specific node.
|
* Erase all flows originating at a specific station.
|
||||||
* @param from Node to erase flows for.
|
* @param from StationID to erase flows for.
|
||||||
*/
|
*/
|
||||||
void LinkGraphJob::EraseFlows(NodeID from)
|
void LinkGraphJob::EraseFlows(StationID from)
|
||||||
{
|
{
|
||||||
for (NodeID node_id = 0; node_id < this->Size(); ++node_id) {
|
for (NodeID node_id = 0; node_id < this->Size(); ++node_id) {
|
||||||
(*this)[node_id].flows.erase(StationID{from});
|
(*this)[node_id].flows.erase(from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ LinkGraphJob::~LinkGraphJob()
|
||||||
/* The station can have been deleted. Remove all flows originating from it then. */
|
/* The station can have been deleted. Remove all flows originating from it then. */
|
||||||
Station *st = Station::GetIfValid(from.base.station);
|
Station *st = Station::GetIfValid(from.base.station);
|
||||||
if (st == nullptr) {
|
if (st == nullptr) {
|
||||||
this->EraseFlows(node_id);
|
this->EraseFlows(from.base.station);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ LinkGraphJob::~LinkGraphJob()
|
||||||
* sure that everything is still consistent or ignore it otherwise. */
|
* sure that everything is still consistent or ignore it otherwise. */
|
||||||
GoodsEntry &ge = st->goods[this->Cargo()];
|
GoodsEntry &ge = st->goods[this->Cargo()];
|
||||||
if (ge.link_graph != this->link_graph.index || ge.node != node_id) {
|
if (ge.link_graph != this->link_graph.index || ge.node != node_id) {
|
||||||
this->EraseFlows(node_id);
|
this->EraseFlows(from.base.station);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ LinkGraphJob::~LinkGraphJob()
|
||||||
/* Delete old flows for source stations which have been deleted
|
/* Delete old flows for source stations which have been deleted
|
||||||
* from the new flows. This avoids flow cycles between old and
|
* from the new flows. This avoids flow cycles between old and
|
||||||
* new flows. */
|
* new flows. */
|
||||||
while (!erased.IsEmpty()) geflows.erase(StationID{erased.Pop()});
|
while (!erased.IsEmpty()) geflows.erase(erased.Pop());
|
||||||
} else if ((*lg)[node_id][dest_id].last_unrestricted_update == EconomyTime::INVALID_DATE) {
|
} else if ((*lg)[node_id][dest_id].last_unrestricted_update == EconomyTime::INVALID_DATE) {
|
||||||
/* Edge is fully restricted. */
|
/* Edge is fully restricted. */
|
||||||
flows.RestrictFlows(to);
|
flows.RestrictFlows(to);
|
||||||
|
|
|
@ -167,7 +167,7 @@ protected:
|
||||||
std::atomic<bool> job_completed = false; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
std::atomic<bool> job_completed = false; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
||||||
std::atomic<bool> job_aborted = false; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
std::atomic<bool> job_aborted = false; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
||||||
|
|
||||||
void EraseFlows(NodeID from);
|
void EraseFlows(StationID from);
|
||||||
void JoinThread();
|
void JoinThread();
|
||||||
void SpawnThread();
|
void SpawnThread();
|
||||||
|
|
||||||
|
|
|
@ -556,7 +556,7 @@ void SetupColoursAndInitialWindow()
|
||||||
const uint8_t *b = GetNonSprite(GetColourPalette(i), SpriteType::Recolour) + 1;
|
const uint8_t *b = GetNonSprite(GetColourPalette(i), SpriteType::Recolour) + 1;
|
||||||
assert(b != nullptr);
|
assert(b != nullptr);
|
||||||
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
|
||||||
SetColourGradient(i, j, b[0xC6 + j]);
|
SetColourGradient(i, j, PixelColour{b[0xC6 + j]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#define HISTORY_FUNC_HPP
|
#define HISTORY_FUNC_HPP
|
||||||
|
|
||||||
#include "../core/bitmath_func.hpp"
|
#include "../core/bitmath_func.hpp"
|
||||||
|
#include "../core/math_func.hpp"
|
||||||
|
#include "../timer/timer_game_economy.h"
|
||||||
#include "history_type.hpp"
|
#include "history_type.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,6 +36,19 @@ void RotateHistory(HistoryData<T> &history)
|
||||||
history[THIS_MONTH] = {};
|
history[THIS_MONTH] = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an average value for the previous month, as reset for the next month.
|
||||||
|
* @param total Accrued total to average. Will be reset to zero.
|
||||||
|
* @return Average value for the month.
|
||||||
|
*/
|
||||||
|
template <typename T, typename Taccrued>
|
||||||
|
T GetAndResetAccumulatedAverage(Taccrued &total)
|
||||||
|
{
|
||||||
|
T result = ClampTo<T>(total / std::max(1U, TimerGameEconomy::days_since_last_month));
|
||||||
|
total = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill some data with historical data.
|
* Fill some data with historical data.
|
||||||
* @param history Historical data to fill from.
|
* @param history Historical data to fill from.
|
||||||
|
@ -53,4 +68,21 @@ void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_histo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill some data with empty records.
|
||||||
|
* @param valid_history Mask of valid history records.
|
||||||
|
* @param fillers Fillers to fill with history data.
|
||||||
|
*/
|
||||||
|
template <uint N, typename... Tfillers>
|
||||||
|
void FillFromEmpty(ValidHistoryMask valid_history, Tfillers... fillers)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i != N; ++i) {
|
||||||
|
if (HasBit(valid_history, N - i)) {
|
||||||
|
(fillers.MakeZero(i), ...);
|
||||||
|
} else {
|
||||||
|
(fillers.MakeInvalid(i), ...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HISTORY_FUNC_HPP */
|
#endif /* HISTORY_FUNC_HPP */
|
||||||
|
|
|
@ -79,7 +79,6 @@ static constexpr auto _callback_tuple = std::make_tuple(
|
||||||
&CcCreateGroup,
|
&CcCreateGroup,
|
||||||
&CcFoundRandomTown,
|
&CcFoundRandomTown,
|
||||||
&CcRoadStop,
|
&CcRoadStop,
|
||||||
&CcBuildIndustry,
|
|
||||||
&CcStartStopVehicle,
|
&CcStartStopVehicle,
|
||||||
&CcGame,
|
&CcGame,
|
||||||
&CcAddVehicleNewGroup
|
&CcAddVehicleNewGroup
|
||||||
|
|
|
@ -97,11 +97,11 @@ static ChangeInfoResult CargoReserveInfo(uint first, uint last, int prop, ByteRe
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x13: // Colour for station rating bars
|
case 0x13: // Colour for station rating bars
|
||||||
cs->rating_colour = buf.ReadByte();
|
cs->rating_colour = PixelColour{buf.ReadByte()};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x14: // Colour for cargo graph
|
case 0x14: // Colour for cargo graph
|
||||||
cs->legend_colour = buf.ReadByte();
|
cs->legend_colour = PixelColour{buf.ReadByte()};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x15: // Freight status
|
case 0x15: // Freight status
|
||||||
|
|
|
@ -565,7 +565,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x19: // Map colour
|
case 0x19: // Map colour
|
||||||
indsp->map_colour = buf.ReadByte();
|
indsp->map_colour = PixelColour{buf.ReadByte()};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1A: // Special industry flags to define special behavior
|
case 0x1A: // Special industry flags to define special behavior
|
||||||
|
|
|
@ -121,7 +121,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, Byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x16: // Map colour
|
case 0x16: // Map colour
|
||||||
rti->map_colour = buf.ReadByte();
|
rti->map_colour = PixelColour{buf.ReadByte()};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x17: // Introduction date
|
case 0x17: // Introduction date
|
||||||
|
|
|
@ -109,7 +109,7 @@ static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, Byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x16: // Map colour
|
case 0x16: // Map colour
|
||||||
rti->map_colour = buf.ReadByte();
|
rti->map_colour = PixelColour{buf.ReadByte()};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x17: // Introduction date
|
case 0x17: // Introduction date
|
||||||
|
|
|
@ -315,7 +315,7 @@ static void ShutdownGame()
|
||||||
/* No NewGRFs were loaded when it was still bootstrapping. */
|
/* No NewGRFs were loaded when it was still bootstrapping. */
|
||||||
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
|
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
|
||||||
|
|
||||||
UninitFontCache();
|
FontCache::UninitializeFontCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -700,7 +700,7 @@ int openttd_main(std::span<std::string_view> arguments)
|
||||||
InitializeLanguagePacks();
|
InitializeLanguagePacks();
|
||||||
|
|
||||||
/* Initialize the font cache */
|
/* Initialize the font cache */
|
||||||
InitFontCache(FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(FONTSIZES_REQUIRED);
|
||||||
|
|
||||||
/* This must be done early, since functions use the SetWindowDirty* calls */
|
/* This must be done early, since functions use the SetWindowDirty* calls */
|
||||||
InitWindowSystem();
|
InitWindowSystem();
|
||||||
|
|
|
@ -368,7 +368,7 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderI
|
||||||
next = v->cur_implicit_order_index;
|
next = v->cur_implicit_order_index;
|
||||||
if (next >= this->GetNumOrders()) {
|
if (next >= this->GetNumOrders()) {
|
||||||
next = this->GetFirstOrder();
|
next = this->GetFirstOrder();
|
||||||
if (next == INVALID_VEH_ORDER_ID) return StationID::Invalid().base();
|
if (next == INVALID_VEH_ORDER_ID) return StationID::Invalid();
|
||||||
} else {
|
} else {
|
||||||
/* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
|
/* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
|
||||||
* As the given "next" is already valid and a station in the list, we
|
* As the given "next" is already valid and a station in the list, we
|
||||||
|
@ -404,11 +404,11 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderI
|
||||||
if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
|
if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
|
||||||
orders[next].GetDestination() == v->last_station_visited &&
|
orders[next].GetDestination() == v->last_station_visited &&
|
||||||
(orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
|
(orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
|
||||||
return StationID::Invalid().base();
|
return StationID::Invalid();
|
||||||
}
|
}
|
||||||
} while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
|
} while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
|
||||||
|
|
||||||
return orders[next].GetDestination().ToStationID().base();
|
return orders[next].GetDestination().ToStationID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "../../blitter/factory.hpp"
|
#include "../../blitter/factory.hpp"
|
||||||
#include "../../error_func.h"
|
#include "../../error_func.h"
|
||||||
#include "../../fileio_func.h"
|
#include "../../fileio_func.h"
|
||||||
#include "../../fontdetection.h"
|
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../strings_func.h"
|
#include "../../strings_func.h"
|
||||||
#include "../../zoom_func.h"
|
#include "../../zoom_func.h"
|
||||||
|
@ -24,91 +23,6 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
|
||||||
{
|
|
||||||
/* Determine fallback font using CoreText. This uses the language isocode
|
|
||||||
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
|
||||||
std::string lang;
|
|
||||||
if (language_isocode == "zh_TW") {
|
|
||||||
/* Traditional Chinese */
|
|
||||||
lang = "zh-Hant";
|
|
||||||
} else if (language_isocode == "zh_CN") {
|
|
||||||
/* Simplified Chinese */
|
|
||||||
lang = "zh-Hans";
|
|
||||||
} else {
|
|
||||||
/* Just copy the first part of the isocode. */
|
|
||||||
lang = language_isocode.substr(0, language_isocode.find('_'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a font descriptor matching the wanted language and latin (english) glyphs.
|
|
||||||
* Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */
|
|
||||||
CFStringRef lang_codes[2];
|
|
||||||
lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
|
|
||||||
lang_codes[1] = CFSTR("en");
|
|
||||||
CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
|
|
||||||
CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
|
||||||
CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get()));
|
|
||||||
CFRelease(lang_arr);
|
|
||||||
CFRelease(lang_codes[0]);
|
|
||||||
|
|
||||||
/* Get array of all font descriptors for the wanted language. */
|
|
||||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
|
||||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
for (int tries = 0; tries < 2; tries++) {
|
|
||||||
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
|
||||||
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
|
||||||
|
|
||||||
/* Get font traits. */
|
|
||||||
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
|
|
||||||
CTFontSymbolicTraits symbolic_traits;
|
|
||||||
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
|
|
||||||
|
|
||||||
/* Skip symbol fonts and vertical fonts. */
|
|
||||||
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
|
||||||
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
|
||||||
if (symbolic_traits & kCTFontBoldTrait) continue;
|
|
||||||
/* Select monospaced fonts if asked for. */
|
|
||||||
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
|
||||||
|
|
||||||
/* Get font name. */
|
|
||||||
char buffer[128];
|
|
||||||
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
|
||||||
CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
|
|
||||||
|
|
||||||
/* Serif fonts usually look worse on-screen with only small
|
|
||||||
* font sizes. As such, we try for a sans-serif font first.
|
|
||||||
* If we can't find one in the first try, try all fonts. */
|
|
||||||
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
|
||||||
|
|
||||||
/* There are some special fonts starting with an '.' and the last
|
|
||||||
* resort font that aren't usable. Skip them. */
|
|
||||||
std::string_view name{buffer};
|
|
||||||
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
|
|
||||||
|
|
||||||
/* Save result. */
|
|
||||||
callback->SetFontNames(settings, name);
|
|
||||||
if (!callback->FindMissingGlyphs()) {
|
|
||||||
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
|
||||||
result = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
|
||||||
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
|
||||||
callback->SetFontNames(settings, "Arial Unicode MS");
|
|
||||||
result = !callback->FindMissingGlyphs();
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->FindMissingGlyphs();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CoreTextFontCache::CoreTextFontCache(FontSize fs, CFAutoRelease<CTFontDescriptorRef> &&font, int pixels) : TrueTypeFontCache(fs, pixels), font_desc(std::move(font))
|
CoreTextFontCache::CoreTextFontCache(FontSize fs, CFAutoRelease<CTFontDescriptorRef> &&font, int pixels) : TrueTypeFontCache(fs, pixels), font_desc(std::move(font))
|
||||||
{
|
{
|
||||||
this->SetFontSize(pixels);
|
this->SetFontSize(pixels);
|
||||||
|
@ -287,52 +201,24 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
|
||||||
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
|
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
class CoreTextFontCacheFactory : public FontCacheFactory {
|
||||||
{
|
public:
|
||||||
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
CoreTextFontCacheFactory() : FontCacheFactory("coretext", "CoreText font loader") {}
|
||||||
|
|
||||||
/* Might be a font file name, try load it. Direct font loading is
|
/**
|
||||||
* only supported starting on OSX 10.6. */
|
|
||||||
CFAutoRelease<CFStringRef> path;
|
|
||||||
|
|
||||||
/* See if this is an absolute path. */
|
|
||||||
if (FileExists(font_name)) {
|
|
||||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
|
|
||||||
} else {
|
|
||||||
/* Scan the search-paths to see if it can be found. */
|
|
||||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
|
||||||
if (!full_font.empty()) {
|
|
||||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
/* Try getting a font descriptor to see if the system can use it. */
|
|
||||||
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
|
|
||||||
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
|
|
||||||
|
|
||||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
|
||||||
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
|
|
||||||
CFRetain(font_ref);
|
|
||||||
return font_ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the TrueType font.
|
* Loads the TrueType font.
|
||||||
* If a CoreText font description is present, e.g. from the automatic font
|
* If a CoreText font description is present, e.g. from the automatic font
|
||||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||||
* @param fs The font size to load.
|
* @param fs The font size to load.
|
||||||
*/
|
*/
|
||||||
void LoadCoreTextFont(FontSize fs)
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
{
|
{
|
||||||
|
if (fonttype != FontType::TrueType) return nullptr;
|
||||||
|
|
||||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||||
|
|
||||||
std::string font = GetFontCacheFontName(fs);
|
std::string font = GetFontCacheFontName(fs);
|
||||||
if (font.empty()) return;
|
if (font.empty()) return nullptr;
|
||||||
|
|
||||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||||
|
|
||||||
|
@ -367,8 +253,130 @@ void LoadCoreTextFont(FontSize fs)
|
||||||
|
|
||||||
if (!font_ref) {
|
if (!font_ref) {
|
||||||
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
||||||
return;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
return std::make_unique<CoreTextFontCache>(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) override
|
||||||
|
{
|
||||||
|
/* Determine fallback font using CoreText. This uses the language isocode
|
||||||
|
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
||||||
|
std::string lang;
|
||||||
|
if (language_isocode == "zh_TW") {
|
||||||
|
/* Traditional Chinese */
|
||||||
|
lang = "zh-Hant";
|
||||||
|
} else if (language_isocode == "zh_CN") {
|
||||||
|
/* Simplified Chinese */
|
||||||
|
lang = "zh-Hans";
|
||||||
|
} else {
|
||||||
|
/* Just copy the first part of the isocode. */
|
||||||
|
lang = language_isocode.substr(0, language_isocode.find('_'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a font descriptor matching the wanted language and latin (english) glyphs.
|
||||||
|
* Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */
|
||||||
|
CFStringRef lang_codes[2];
|
||||||
|
lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
|
||||||
|
lang_codes[1] = CFSTR("en");
|
||||||
|
CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
|
||||||
|
CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||||
|
CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get()));
|
||||||
|
CFRelease(lang_arr);
|
||||||
|
CFRelease(lang_codes[0]);
|
||||||
|
|
||||||
|
/* Get array of all font descriptors for the wanted language. */
|
||||||
|
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
||||||
|
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
for (int tries = 0; tries < 2; tries++) {
|
||||||
|
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
||||||
|
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
||||||
|
|
||||||
|
/* Get font traits. */
|
||||||
|
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
|
||||||
|
CTFontSymbolicTraits symbolic_traits;
|
||||||
|
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
|
||||||
|
|
||||||
|
/* Skip symbol fonts and vertical fonts. */
|
||||||
|
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
||||||
|
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
||||||
|
if (symbolic_traits & kCTFontBoldTrait) continue;
|
||||||
|
/* Select monospaced fonts if asked for. */
|
||||||
|
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
||||||
|
|
||||||
|
/* Get font name. */
|
||||||
|
char buffer[128];
|
||||||
|
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
||||||
|
CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
/* Serif fonts usually look worse on-screen with only small
|
||||||
|
* font sizes. As such, we try for a sans-serif font first.
|
||||||
|
* If we can't find one in the first try, try all fonts. */
|
||||||
|
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
||||||
|
|
||||||
|
/* There are some special fonts starting with an '.' and the last
|
||||||
|
* resort font that aren't usable. Skip them. */
|
||||||
|
std::string_view name{buffer};
|
||||||
|
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
|
||||||
|
|
||||||
|
/* Save result. */
|
||||||
|
callback->SetFontNames(settings, name);
|
||||||
|
if (!callback->FindMissingGlyphs()) {
|
||||||
|
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
||||||
|
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
||||||
|
callback->SetFontNames(settings, "Arial Unicode MS");
|
||||||
|
result = !callback->FindMissingGlyphs();
|
||||||
|
}
|
||||||
|
|
||||||
|
callback->FindMissingGlyphs();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
||||||
|
{
|
||||||
|
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
||||||
|
|
||||||
|
/* Might be a font file name, try load it. Direct font loading is
|
||||||
|
* only supported starting on OSX 10.6. */
|
||||||
|
CFAutoRelease<CFStringRef> path;
|
||||||
|
|
||||||
|
/* See if this is an absolute path. */
|
||||||
|
if (FileExists(font_name)) {
|
||||||
|
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
|
||||||
|
} else {
|
||||||
|
/* Scan the search-paths to see if it can be found. */
|
||||||
|
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||||
|
if (!full_font.empty()) {
|
||||||
|
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
/* Try getting a font descriptor to see if the system can use it. */
|
||||||
|
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
|
||||||
|
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
|
||||||
|
|
||||||
|
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||||
|
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
|
||||||
|
CFRetain(font_ref);
|
||||||
|
return font_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static CoreTextFontCacheFactory s_coretext_fontcache_Factory;
|
||||||
|
|
|
@ -12,6 +12,7 @@ add_files(
|
||||||
|
|
||||||
add_files(
|
add_files(
|
||||||
font_unix.cpp
|
font_unix.cpp
|
||||||
|
font_unix.h
|
||||||
CONDITION Fontconfig_FOUND
|
CONDITION Fontconfig_FOUND
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,17 @@
|
||||||
|
|
||||||
#include "../../misc/autorelease.hpp"
|
#include "../../misc/autorelease.hpp"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
#include "../../fontdetection.h"
|
#include "../../fontcache.h"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../strings_func.h"
|
#include "../../strings_func.h"
|
||||||
|
#include "font_unix.h"
|
||||||
|
|
||||||
#include <fontconfig/fontconfig.h>
|
#include <fontconfig/fontconfig.h>
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
|
||||||
|
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
extern FT_Library _ft_library;
|
extern FT_Library _ft_library;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +61,12 @@ static std::tuple<std::string, std::string> SplitFontFamilyAndStyle(std::string_
|
||||||
return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) };
|
return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a freetype font face with the given font name.
|
||||||
|
* @param font_name The name of the font to load.
|
||||||
|
* @param face The face that has been found.
|
||||||
|
* @return The error we encountered.
|
||||||
|
*/
|
||||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
||||||
{
|
{
|
||||||
FT_Error err = FT_Err_Cannot_Open_Resource;
|
FT_Error err = FT_Err_Cannot_Open_Resource;
|
||||||
|
@ -117,7 +123,7 @@ FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
|
@ -182,6 +188,6 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
||||||
if (best_font == nullptr) return false;
|
if (best_font == nullptr) return false;
|
||||||
|
|
||||||
callback->SetFontNames(settings, best_font, &best_index);
|
callback->SetFontNames(settings, best_font, &best_index);
|
||||||
InitFontCache(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file font_unix.h Functions related to detecting/finding the right font. */
|
||||||
|
|
||||||
|
#ifndef FONT_UNIX_H
|
||||||
|
#define FONT_UNIX_H
|
||||||
|
|
||||||
|
#ifdef WITH_FONTCONFIG
|
||||||
|
|
||||||
|
#include "../../fontcache.h"
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
|
||||||
|
|
||||||
|
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
|
||||||
|
|
||||||
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
|
#endif /* FONT_UNIX_H */
|
|
@ -15,7 +15,6 @@
|
||||||
#include "../../fileio_func.h"
|
#include "../../fileio_func.h"
|
||||||
#include "../../fontcache.h"
|
#include "../../fontcache.h"
|
||||||
#include "../../fontcache/truetypefontcache.h"
|
#include "../../fontcache/truetypefontcache.h"
|
||||||
#include "../../fontdetection.h"
|
|
||||||
#include "../../library_loader.h"
|
#include "../../library_loader.h"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../strings_func.h"
|
#include "../../strings_func.h"
|
||||||
|
@ -85,32 +84,6 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
|
||||||
return 0; // stop enumerating
|
return 0; // stop enumerating
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
|
||||||
{
|
|
||||||
Debug(fontcache, 1, "Trying fallback fonts");
|
|
||||||
EFCParam langInfo;
|
|
||||||
std::wstring lang = OTTD2FS(language_isocode.substr(0, language_isocode.find('_')));
|
|
||||||
if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE, reinterpret_cast<LPWSTR>(&langInfo.locale), sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
|
|
||||||
/* Invalid isocode or some other mysterious error, can't determine fallback font. */
|
|
||||||
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
langInfo.settings = settings;
|
|
||||||
langInfo.callback = callback;
|
|
||||||
|
|
||||||
LOGFONT font;
|
|
||||||
/* Enumerate all fonts. */
|
|
||||||
font.lfCharSet = DEFAULT_CHARSET;
|
|
||||||
font.lfFaceName[0] = '\0';
|
|
||||||
font.lfPitchAndFamily = 0;
|
|
||||||
|
|
||||||
HDC dc = GetDC(nullptr);
|
|
||||||
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
|
||||||
ReleaseDC(nullptr, dc);
|
|
||||||
return ret == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Win32FontCache.
|
* Create a new Win32FontCache.
|
||||||
* @param fs The font size that is going to be cached.
|
* @param fs The font size that is going to be cached.
|
||||||
|
@ -293,9 +266,88 @@ void Win32FontCache::ClearFontCache()
|
||||||
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
|
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Win32FontCacheFactory : FontCacheFactory {
|
||||||
|
public:
|
||||||
|
Win32FontCacheFactory() : FontCacheFactory("win32", "Win32 font loader") {}
|
||||||
|
|
||||||
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
/**
|
||||||
{
|
* Loads the GDI font.
|
||||||
|
* If a GDI font description is present, e.g. from the automatic font
|
||||||
|
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||||
|
* @param fs The font size to load.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::TrueType) return nullptr;
|
||||||
|
|
||||||
|
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||||
|
|
||||||
|
std::string font = GetFontCacheFontName(fs);
|
||||||
|
if (font.empty()) return nullptr;
|
||||||
|
|
||||||
|
LOGFONT logfont{};
|
||||||
|
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
|
||||||
|
logfont.lfCharSet = DEFAULT_CHARSET;
|
||||||
|
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||||
|
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||||
|
|
||||||
|
if (settings->os_handle != nullptr) {
|
||||||
|
logfont = *(const LOGFONT *)settings->os_handle;
|
||||||
|
} else if (font.find('.') != std::string::npos) {
|
||||||
|
/* Might be a font file name, try load it. */
|
||||||
|
if (!TryLoadFontFromFile(font, logfont)) {
|
||||||
|
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logfont.lfFaceName[0] == 0) {
|
||||||
|
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||||
|
convert_to_fs(font, logfont.lfFaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) override
|
||||||
|
{
|
||||||
|
Debug(fontcache, 1, "Trying fallback fonts");
|
||||||
|
EFCParam langInfo;
|
||||||
|
std::wstring lang = OTTD2FS(language_isocode.substr(0, language_isocode.find('_')));
|
||||||
|
if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE, reinterpret_cast<LPWSTR>(&langInfo.locale), sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
|
||||||
|
/* Invalid isocode or some other mysterious error, can't determine fallback font. */
|
||||||
|
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
langInfo.settings = settings;
|
||||||
|
langInfo.callback = callback;
|
||||||
|
|
||||||
|
LOGFONT font;
|
||||||
|
/* Enumerate all fonts. */
|
||||||
|
font.lfCharSet = DEFAULT_CHARSET;
|
||||||
|
font.lfFaceName[0] = '\0';
|
||||||
|
font.lfPitchAndFamily = 0;
|
||||||
|
|
||||||
|
HDC dc = GetDC(nullptr);
|
||||||
|
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
||||||
|
ReleaseDC(nullptr, dc);
|
||||||
|
return ret == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unique_ptr<FontCache> LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
|
||||||
|
{
|
||||||
|
HFONT font = CreateFontIndirect(&logfont);
|
||||||
|
if (font == nullptr) {
|
||||||
|
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
DeleteObject(font);
|
||||||
|
|
||||||
|
return std::make_unique<Win32FontCache>(fs, logfont, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
||||||
|
{
|
||||||
wchar_t fontPath[MAX_PATH] = {};
|
wchar_t fontPath[MAX_PATH] = {};
|
||||||
|
|
||||||
/* See if this is an absolute path. */
|
/* See if this is an absolute path. */
|
||||||
|
@ -341,51 +393,7 @@ static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
||||||
}
|
}
|
||||||
|
|
||||||
return logfont.lfFaceName[0] != 0;
|
return logfont.lfFaceName[0] != 0;
|
||||||
}
|
|
||||||
|
|
||||||
static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
|
|
||||||
{
|
|
||||||
HFONT font = CreateFontIndirect(&logfont);
|
|
||||||
if (font == nullptr) {
|
|
||||||
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
DeleteObject(font);
|
};
|
||||||
|
|
||||||
new Win32FontCache(fs, logfont, size);
|
static Win32FontCacheFactory s_win32_fontcache_factory;
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Loads the GDI font.
|
|
||||||
* If a GDI font description is present, e.g. from the automatic font
|
|
||||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
|
||||||
* @param fs The font size to load.
|
|
||||||
*/
|
|
||||||
void LoadWin32Font(FontSize fs)
|
|
||||||
{
|
|
||||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
|
||||||
|
|
||||||
std::string font = GetFontCacheFontName(fs);
|
|
||||||
if (font.empty()) return;
|
|
||||||
|
|
||||||
LOGFONT logfont{};
|
|
||||||
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
|
|
||||||
logfont.lfCharSet = DEFAULT_CHARSET;
|
|
||||||
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
|
||||||
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
||||||
|
|
||||||
if (settings->os_handle != nullptr) {
|
|
||||||
logfont = *(const LOGFONT *)settings->os_handle;
|
|
||||||
} else if (font.find('.') != std::string::npos) {
|
|
||||||
/* Might be a font file name, try load it. */
|
|
||||||
if (!TryLoadFontFromFile(font, logfont)) {
|
|
||||||
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logfont.lfFaceName[0] == 0) {
|
|
||||||
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
|
||||||
convert_to_fs(font, logfont.lfFaceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
|
|
||||||
}
|
|
||||||
|
|
|
@ -358,9 +358,9 @@ void DoPaletteAnimations()
|
||||||
* @param threshold Background colour brightness threshold below which the background is considered dark and TC_WHITE is returned, range: 0 - 255, default 128.
|
* @param threshold Background colour brightness threshold below which the background is considered dark and TC_WHITE is returned, range: 0 - 255, default 128.
|
||||||
* @return TC_BLACK or TC_WHITE depending on what gives a better contrast.
|
* @return TC_BLACK or TC_WHITE depending on what gives a better contrast.
|
||||||
*/
|
*/
|
||||||
TextColour GetContrastColour(uint8_t background, uint8_t threshold)
|
TextColour GetContrastColour(PixelColour background, uint8_t threshold)
|
||||||
{
|
{
|
||||||
Colour c = _cur_palette.palette[background];
|
Colour c = _cur_palette.palette[background.p];
|
||||||
/* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast.
|
/* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast.
|
||||||
* The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */
|
* The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */
|
||||||
uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114;
|
uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114;
|
||||||
|
@ -374,7 +374,7 @@ TextColour GetContrastColour(uint8_t background, uint8_t threshold)
|
||||||
*/
|
*/
|
||||||
struct ColourGradients
|
struct ColourGradients
|
||||||
{
|
{
|
||||||
using ColourGradient = std::array<uint8_t, SHADE_END>;
|
using ColourGradient = std::array<PixelColour, SHADE_END>;
|
||||||
|
|
||||||
static inline std::array<ColourGradient, COLOUR_END> gradient{};
|
static inline std::array<ColourGradient, COLOUR_END> gradient{};
|
||||||
};
|
};
|
||||||
|
@ -385,7 +385,7 @@ struct ColourGradients
|
||||||
* @param shade Shade level from 1 to 7.
|
* @param shade Shade level from 1 to 7.
|
||||||
* @returns palette index of colour.
|
* @returns palette index of colour.
|
||||||
*/
|
*/
|
||||||
uint8_t GetColourGradient(Colours colour, ColourShade shade)
|
PixelColour GetColourGradient(Colours colour, ColourShade shade)
|
||||||
{
|
{
|
||||||
return ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END];
|
return ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END];
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ uint8_t GetColourGradient(Colours colour, ColourShade shade)
|
||||||
* @param shade Shade level from 1 to 7.
|
* @param shade Shade level from 1 to 7.
|
||||||
* @param palette_index Palette index to set.
|
* @param palette_index Palette index to set.
|
||||||
*/
|
*/
|
||||||
void SetColourGradient(Colours colour, ColourShade shade, uint8_t palette_index)
|
void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_index)
|
||||||
{
|
{
|
||||||
assert(colour < COLOUR_END);
|
assert(colour < COLOUR_END);
|
||||||
assert(shade < SHADE_END);
|
assert(shade < SHADE_END);
|
||||||
|
|
|
@ -67,7 +67,7 @@ inline bool IsValidColours(Colours colours)
|
||||||
return colours < COLOUR_END;
|
return colours < COLOUR_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextColour GetContrastColour(uint8_t background, uint8_t threshold = 128);
|
TextColour GetContrastColour(PixelColour background, uint8_t threshold = 128);
|
||||||
|
|
||||||
enum ColourShade : uint8_t {
|
enum ColourShade : uint8_t {
|
||||||
SHADE_BEGIN = 0,
|
SHADE_BEGIN = 0,
|
||||||
|
@ -83,45 +83,45 @@ enum ColourShade : uint8_t {
|
||||||
};
|
};
|
||||||
DECLARE_INCREMENT_DECREMENT_OPERATORS(ColourShade)
|
DECLARE_INCREMENT_DECREMENT_OPERATORS(ColourShade)
|
||||||
|
|
||||||
uint8_t GetColourGradient(Colours colour, ColourShade shade);
|
PixelColour GetColourGradient(Colours colour, ColourShade shade);
|
||||||
void SetColourGradient(Colours colour, ColourShade shade, uint8_t palette_colour);
|
void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_colour);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the colour for a particular greyscale level.
|
* Return the colour for a particular greyscale level.
|
||||||
* @param level Intensity, 0 = black, 15 = white
|
* @param level Intensity, 0 = black, 15 = white
|
||||||
* @return colour
|
* @return colour
|
||||||
*/
|
*/
|
||||||
constexpr uint8_t GREY_SCALE(uint8_t level) { return level; }
|
inline constexpr PixelColour GREY_SCALE(uint8_t level) { return PixelColour{level}; }
|
||||||
|
|
||||||
static const uint8_t PC_BLACK = GREY_SCALE(1); ///< Black palette colour.
|
static constexpr PixelColour PC_BLACK {GREY_SCALE(1)}; ///< Black palette colour.
|
||||||
static const uint8_t PC_DARK_GREY = GREY_SCALE(6); ///< Dark grey palette colour.
|
static constexpr PixelColour PC_DARK_GREY {GREY_SCALE(6)}; ///< Dark grey palette colour.
|
||||||
static const uint8_t PC_GREY = GREY_SCALE(10); ///< Grey palette colour.
|
static constexpr PixelColour PC_GREY {GREY_SCALE(10)}; ///< Grey palette colour.
|
||||||
static const uint8_t PC_WHITE = GREY_SCALE(15); ///< White palette colour.
|
static constexpr PixelColour PC_WHITE {GREY_SCALE(15)}; ///< White palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_VERY_DARK_RED = 0xB2; ///< Almost-black red palette colour.
|
static constexpr PixelColour PC_VERY_DARK_RED {0xB2}; ///< Almost-black red palette colour.
|
||||||
static const uint8_t PC_DARK_RED = 0xB4; ///< Dark red palette colour.
|
static constexpr PixelColour PC_DARK_RED {0xB4}; ///< Dark red palette colour.
|
||||||
static const uint8_t PC_RED = 0xB8; ///< Red palette colour.
|
static constexpr PixelColour PC_RED {0xB8}; ///< Red palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_VERY_DARK_BROWN = 0x56; ///< Almost-black brown palette colour.
|
static constexpr PixelColour PC_VERY_DARK_BROWN {0x56}; ///< Almost-black brown palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_ORANGE = 0xC2; ///< Orange palette colour.
|
static constexpr PixelColour PC_ORANGE {0xC2}; ///< Orange palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_YELLOW = 0xBF; ///< Yellow palette colour.
|
static constexpr PixelColour PC_YELLOW {0xBF}; ///< Yellow palette colour.
|
||||||
static const uint8_t PC_LIGHT_YELLOW = 0x44; ///< Light yellow palette colour.
|
static constexpr PixelColour PC_LIGHT_YELLOW {0x44}; ///< Light yellow palette colour.
|
||||||
static const uint8_t PC_VERY_LIGHT_YELLOW = 0x45; ///< Almost-white yellow palette colour.
|
static constexpr PixelColour PC_VERY_LIGHT_YELLOW {0x45}; ///< Almost-white yellow palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_GREEN = 0xD0; ///< Green palette colour.
|
static constexpr PixelColour PC_GREEN {0xD0}; ///< Green palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_VERY_DARK_BLUE = 0x9A; ///< Almost-black blue palette colour.
|
static constexpr PixelColour PC_VERY_DARK_BLUE {0x9A}; ///< Almost-black blue palette colour.
|
||||||
static const uint8_t PC_DARK_BLUE = 0x9D; ///< Dark blue palette colour.
|
static constexpr PixelColour PC_DARK_BLUE {0x9D}; ///< Dark blue palette colour.
|
||||||
static const uint8_t PC_LIGHT_BLUE = 0x98; ///< Light blue palette colour.
|
static constexpr PixelColour PC_LIGHT_BLUE {0x98}; ///< Light blue palette colour.
|
||||||
|
|
||||||
static const uint8_t PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land.
|
static constexpr PixelColour PC_ROUGH_LAND {0x52}; ///< Dark green palette colour for rough land.
|
||||||
static const uint8_t PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land.
|
static constexpr PixelColour PC_GRASS_LAND {0x54}; ///< Dark green palette colour for grass land.
|
||||||
static const uint8_t PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land.
|
static constexpr PixelColour PC_BARE_LAND {0x37}; ///< Brown palette colour for bare land.
|
||||||
static const uint8_t PC_RAINFOREST = 0x5C; ///< Pale green palette colour for rainforest.
|
static constexpr PixelColour PC_RAINFOREST {0x5C}; ///< Pale green palette colour for rainforest.
|
||||||
static const uint8_t PC_FIELDS = 0x25; ///< Light brown palette colour for fields.
|
static constexpr PixelColour PC_FIELDS {0x25}; ///< Light brown palette colour for fields.
|
||||||
static const uint8_t PC_TREES = 0x57; ///< Green palette colour for trees.
|
static constexpr PixelColour PC_TREES {0x57}; ///< Green palette colour for trees.
|
||||||
static const uint8_t PC_WATER = 0xC9; ///< Dark blue palette colour for water.
|
static constexpr PixelColour PC_WATER {0xC9}; ///< Dark blue palette colour for water.
|
||||||
|
|
||||||
#endif /* PALETTE_FUNC_H */
|
#endif /* PALETTE_FUNC_H */
|
||||||
|
|
|
@ -234,7 +234,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Colour on mini-map
|
* Colour on mini-map
|
||||||
*/
|
*/
|
||||||
uint8_t map_colour;
|
PixelColour map_colour;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Introduction date.
|
* Introduction date.
|
||||||
|
|
|
@ -145,7 +145,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Colour on mini-map
|
* Colour on mini-map
|
||||||
*/
|
*/
|
||||||
uint8_t map_colour;
|
PixelColour map_colour;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Introduction date.
|
* Introduction date.
|
||||||
|
|
|
@ -19,12 +19,50 @@
|
||||||
|
|
||||||
static OldPersistentStorage _old_ind_persistent_storage;
|
static OldPersistentStorage _old_ind_persistent_storage;
|
||||||
|
|
||||||
|
class SlIndustryAcceptedHistory : public DefaultSaveLoadHandler<SlIndustryAcceptedHistory, Industry::AcceptedCargo> {
|
||||||
|
public:
|
||||||
|
static inline const SaveLoad description[] = {
|
||||||
|
SLE_VAR(Industry::AcceptedHistory, accepted, SLE_UINT16),
|
||||||
|
SLE_VAR(Industry::AcceptedHistory, waiting, SLE_UINT16),
|
||||||
|
};
|
||||||
|
static inline const SaveLoadCompatTable compat_description = _industry_produced_history_sl_compat;
|
||||||
|
|
||||||
|
void Save(Industry::AcceptedCargo *a) const override
|
||||||
|
{
|
||||||
|
if (!IsValidCargoType(a->cargo) || a->history == nullptr) {
|
||||||
|
/* Don't save any history if cargo slot isn't used. */
|
||||||
|
SlSetStructListLength(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlSetStructListLength(a->history->size());
|
||||||
|
|
||||||
|
for (auto &h : *a->history) {
|
||||||
|
SlObject(&h, this->GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Load(Industry::AcceptedCargo *a) const override
|
||||||
|
{
|
||||||
|
size_t len = SlGetStructListLength(UINT32_MAX);
|
||||||
|
if (len == 0) return;
|
||||||
|
|
||||||
|
auto &history = a->GetOrCreateHistory();
|
||||||
|
for (auto &h : history) {
|
||||||
|
if (--len > history.size()) break; // unsigned so wraps after hitting zero.
|
||||||
|
SlObject(&h, this->GetDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
|
class SlIndustryAccepted : public VectorSaveLoadHandler<SlIndustryAccepted, Industry, Industry::AcceptedCargo, INDUSTRY_NUM_INPUTS> {
|
||||||
public:
|
public:
|
||||||
static inline const SaveLoad description[] = {
|
static inline const SaveLoad description[] = {
|
||||||
SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
|
SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
|
||||||
SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
|
SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
|
||||||
SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32),
|
SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32),
|
||||||
|
SLE_CONDVAR(Industry::AcceptedCargo, accumulated_waiting, SLE_UINT32, SLV_INDUSTRY_ACCEPTED_HISTORY, SL_MAX_VERSION),
|
||||||
|
SLEG_CONDSTRUCTLIST("history", SlIndustryAcceptedHistory, SLV_INDUSTRY_ACCEPTED_HISTORY, SL_MAX_VERSION),
|
||||||
};
|
};
|
||||||
static inline const SaveLoadCompatTable compat_description = _industry_accepts_sl_compat;
|
static inline const SaveLoadCompatTable compat_description = _industry_accepts_sl_compat;
|
||||||
|
|
||||||
|
|
|
@ -858,7 +858,7 @@ static bool LoadOldIndustry(LoadgameState &ls, int num)
|
||||||
|
|
||||||
if (i->location.tile != 0) {
|
if (i->location.tile != 0) {
|
||||||
/* Copy data from old fixed arrays to industry. */
|
/* Copy data from old fixed arrays to industry. */
|
||||||
std::copy(std::begin(_old_accepted), std::end(_old_accepted), std::back_inserter(i->accepted));
|
std::move(std::begin(_old_accepted), std::end(_old_accepted), std::back_inserter(i->accepted));
|
||||||
std::copy(std::begin(_old_produced), std::end(_old_produced), std::back_inserter(i->produced));
|
std::copy(std::begin(_old_produced), std::end(_old_produced), std::back_inserter(i->produced));
|
||||||
|
|
||||||
i->town = RemapTown(i->location.tile);
|
i->town = RemapTown(i->location.tile);
|
||||||
|
|
|
@ -405,6 +405,7 @@ enum SaveLoadVersion : uint16_t {
|
||||||
|
|
||||||
SLV_FACE_STYLES, ///< 355 PR#14319 Addition of face styles, replacing gender and ethnicity.
|
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_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.
|
||||||
|
|
||||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||||
};
|
};
|
||||||
|
|
|
@ -99,7 +99,7 @@ uint BaseSettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int
|
||||||
|
|
||||||
int x = rtl ? right : left;
|
int x = rtl ? right : left;
|
||||||
if (cur_row >= first_row) {
|
if (cur_row >= first_row) {
|
||||||
int colour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
PixelColour colour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
||||||
y += (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position
|
y += (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position
|
||||||
|
|
||||||
/* Draw vertical for parent nesting levels */
|
/* Draw vertical for parent nesting levels */
|
||||||
|
|
|
@ -1036,8 +1036,8 @@ struct GameOptionsWindow : Window {
|
||||||
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
|
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
|
||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
|
|
||||||
InitFontCache(FONTSIZES_ALL);
|
FontCache::LoadFontCaches(FONTSIZES_ALL);
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
CheckForMissingGlyphs();
|
CheckForMissingGlyphs();
|
||||||
SetupWidgetDimensions();
|
SetupWidgetDimensions();
|
||||||
UpdateAllVirtCoords();
|
UpdateAllVirtCoords();
|
||||||
|
@ -1050,7 +1050,7 @@ struct GameOptionsWindow : Window {
|
||||||
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
|
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
|
||||||
MarkWholeScreenDirty();
|
MarkWholeScreenDirty();
|
||||||
|
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
break;
|
break;
|
||||||
#endif /* HAS_TRUETYPE_FONT */
|
#endif /* HAS_TRUETYPE_FONT */
|
||||||
|
|
||||||
|
@ -1849,7 +1849,7 @@ void ShowGameOptions()
|
||||||
*/
|
*/
|
||||||
void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
|
void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
|
||||||
{
|
{
|
||||||
int colour = GetColourGradient(button_colour, SHADE_DARKER);
|
PixelColour colour = GetColourGradient(button_colour, SHADE_DARKER);
|
||||||
Dimension dim = NWidgetScrollbar::GetHorizontalDimension();
|
Dimension dim = NWidgetScrollbar::GetHorizontalDimension();
|
||||||
|
|
||||||
Rect lr = {x, y, x + (int)dim.width - 1, y + (int)dim.height - 1};
|
Rect lr = {x, y, x + (int)dim.width - 1, y + (int)dim.height - 1};
|
||||||
|
@ -1881,7 +1881,7 @@ void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool c
|
||||||
*/
|
*/
|
||||||
void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_up, bool clickable_down)
|
void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_up, bool clickable_down)
|
||||||
{
|
{
|
||||||
int colour = GetColourGradient(button_colour, SHADE_DARKER);
|
PixelColour colour = GetColourGradient(button_colour, SHADE_DARKER);
|
||||||
|
|
||||||
Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
|
Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
|
||||||
Rect ur = r.WithWidth(SETTING_BUTTON_WIDTH / 2, (_current_text_dir == TD_RTL));
|
Rect ur = r.WithWidth(SETTING_BUTTON_WIDTH / 2, (_current_text_dir == TD_RTL));
|
||||||
|
@ -1907,7 +1907,7 @@ void DrawUpDownButtons(int x, int y, Colours button_colour, uint8_t state, bool
|
||||||
*/
|
*/
|
||||||
void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable)
|
void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable)
|
||||||
{
|
{
|
||||||
int colour = GetColourGradient(button_colour, SHADE_DARKER);
|
PixelColour colour = GetColourGradient(button_colour, SHADE_DARKER);
|
||||||
|
|
||||||
Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
|
Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,9 @@ void DrawSliderWidget(Rect r, Colours wedge_colour, Colours handle_colour, TextC
|
||||||
int wx1 = r.left + sw / 2;
|
int wx1 = r.left + sw / 2;
|
||||||
int wx2 = r.right - sw / 2;
|
int wx2 = r.right - sw / 2;
|
||||||
if (_current_text_dir == TD_RTL) std::swap(wx1, wx2);
|
if (_current_text_dir == TD_RTL) std::swap(wx1, wx2);
|
||||||
const uint shadow = GetColourGradient(wedge_colour, SHADE_DARK);
|
const PixelColour shadow = GetColourGradient(wedge_colour, SHADE_DARK);
|
||||||
const uint fill = GetColourGradient(wedge_colour, SHADE_LIGHTER);
|
const PixelColour fill = GetColourGradient(wedge_colour, SHADE_LIGHTER);
|
||||||
const uint light = GetColourGradient(wedge_colour, SHADE_LIGHTEST);
|
const PixelColour light = GetColourGradient(wedge_colour, SHADE_LIGHTEST);
|
||||||
const std::array<Point, 3> wedge{ Point{wx1, r.bottom - ha}, Point{wx2, r.top + ha}, Point{wx2, r.bottom - ha} };
|
const std::array<Point, 3> wedge{ Point{wx1, r.bottom - ha}, Point{wx2, r.top + ha}, Point{wx2, r.bottom - ha} };
|
||||||
GfxFillPolygon(wedge, fill);
|
GfxFillPolygon(wedge, fill);
|
||||||
GfxDrawLine(wedge[0].x, wedge[0].y, wedge[2].x, wedge[2].y, light, t);
|
GfxDrawLine(wedge[0].x, wedge[0].y, wedge[2].x, wedge[2].y, light, t);
|
||||||
|
|
|
@ -44,7 +44,7 @@ static int _smallmap_cargo_count; ///< Number of cargos in the link stats leg
|
||||||
|
|
||||||
/** Structure for holding relevant data for legends in small map */
|
/** Structure for holding relevant data for legends in small map */
|
||||||
struct LegendAndColour {
|
struct LegendAndColour {
|
||||||
uint8_t colour; ///< Colour of the item on the map.
|
PixelColour colour; ///< Colour of the item on the map.
|
||||||
StringID legend; ///< String corresponding to the coloured item.
|
StringID legend; ///< String corresponding to the coloured item.
|
||||||
IndustryType type; ///< Type of industry. Only valid for industry entries.
|
IndustryType type; ///< Type of industry. Only valid for industry entries.
|
||||||
uint8_t height; ///< Height in tiles. Only valid for height legend entries.
|
uint8_t height; ///< Height in tiles. Only valid for height legend entries.
|
||||||
|
@ -63,16 +63,16 @@ static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner
|
||||||
#define MK(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
|
#define MK(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
|
||||||
|
|
||||||
/** Macro for a height legend entry with configurable colour. */
|
/** Macro for a height legend entry with configurable colour. */
|
||||||
#define MC(col_break) {0, STR_TINY_BLACK_HEIGHT, IT_INVALID, 0, CompanyID::Invalid(), true, false, col_break}
|
#define MC(col_break) {{}, STR_TINY_BLACK_HEIGHT, IT_INVALID, 0, CompanyID::Invalid(), true, false, col_break}
|
||||||
|
|
||||||
/** Macro for non-company owned property entry of LegendAndColour */
|
/** Macro for non-company owned property entry of LegendAndColour */
|
||||||
#define MO(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
|
#define MO(a, b) {a, b, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
|
||||||
|
|
||||||
/** Macro used for forcing a rebuild of the owner legend the first time it is used. */
|
/** Macro used for forcing a rebuild of the owner legend the first time it is used. */
|
||||||
#define MOEND() {0, STR_NULL, IT_INVALID, 0, OWNER_NONE, true, true, false}
|
#define MOEND() {{}, STR_NULL, IT_INVALID, 0, OWNER_NONE, true, true, false}
|
||||||
|
|
||||||
/** Macro for end of list marker in arrays of LegendAndColour */
|
/** Macro for end of list marker in arrays of LegendAndColour */
|
||||||
#define MKEND() {0, STR_NULL, IT_INVALID, 0, CompanyID::Invalid(), true, true, false}
|
#define MKEND() {{}, STR_NULL, IT_INVALID, 0, CompanyID::Invalid(), true, true, false}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macro for break marker in arrays of LegendAndColour.
|
* Macro for break marker in arrays of LegendAndColour.
|
||||||
|
@ -149,7 +149,7 @@ static const LegendAndColour _legend_vegetation[] = {
|
||||||
|
|
||||||
static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
|
static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
|
||||||
MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
|
MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
|
||||||
MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
|
MO({}, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
|
||||||
MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
|
MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
|
||||||
MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES),
|
MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES),
|
||||||
/* The legend will be terminated the first time it is used. */
|
/* The legend will be terminated the first time it is used. */
|
||||||
|
@ -258,15 +258,15 @@ static const LegendAndColour * const _legend_table[] = {
|
||||||
|
|
||||||
#define MKCOLOUR(x) TO_LE32(x)
|
#define MKCOLOUR(x) TO_LE32(x)
|
||||||
|
|
||||||
#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x))
|
#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x.p))
|
||||||
#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x))
|
#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x.p))
|
||||||
#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x))
|
#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x.p))
|
||||||
|
|
||||||
#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
|
#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
|
||||||
|
|
||||||
#define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00)
|
#define MKCOLOUR_0000 MKCOLOUR_XXXX(PixelColour{0x00})
|
||||||
#define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF)
|
#define MKCOLOUR_F00F MKCOLOUR_X00X(PixelColour{0xFF})
|
||||||
#define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF)
|
#define MKCOLOUR_FFFF MKCOLOUR_XXXX(PixelColour{0xFF})
|
||||||
|
|
||||||
#include "table/heightmap_colours.h"
|
#include "table/heightmap_colours.h"
|
||||||
|
|
||||||
|
@ -279,9 +279,9 @@ struct SmallMapColourScheme {
|
||||||
|
|
||||||
/** Available colour schemes for height maps. */
|
/** Available colour schemes for height maps. */
|
||||||
static SmallMapColourScheme _heightmap_schemes[] = {
|
static SmallMapColourScheme _heightmap_schemes[] = {
|
||||||
{{}, _green_map_heights, MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme.
|
{{}, _green_map_heights, MKCOLOUR_XXXX(PixelColour{0x54})}, ///< Green colour scheme.
|
||||||
{{}, _dark_green_map_heights, MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme.
|
{{}, _dark_green_map_heights, MKCOLOUR_XXXX(PixelColour{0x62})}, ///< Dark green colour scheme.
|
||||||
{{}, _violet_map_heights, MKCOLOUR_XXXX(0x81)}, ///< Violet colour scheme.
|
{{}, _violet_map_heights, MKCOLOUR_XXXX(PixelColour{0x81})}, ///< Violet colour scheme.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,7 +329,7 @@ void BuildLandLegend()
|
||||||
_legend_land_contours[i].col_break = j % rows == 0;
|
_legend_land_contours[i].col_break = j % rows == 0;
|
||||||
_legend_land_contours[i].end = false;
|
_legend_land_contours[i].end = false;
|
||||||
_legend_land_contours[i].height = j * delta;
|
_legend_land_contours[i].height = j * delta;
|
||||||
_legend_land_contours[i].colour = static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[_legend_land_contours[i].height]);
|
_legend_land_contours[i].colour = PixelColour{static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[_legend_land_contours[i].height])};
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
_legend_land_contours[i].end = true;
|
_legend_land_contours[i].end = true;
|
||||||
|
@ -340,7 +340,7 @@ void BuildLandLegend()
|
||||||
*/
|
*/
|
||||||
void BuildOwnerLegend()
|
void BuildOwnerLegend()
|
||||||
{
|
{
|
||||||
_legend_land_owners[1].colour = static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour);
|
_legend_land_owners[1].colour = PixelColour{static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour)};
|
||||||
|
|
||||||
int i = NUM_NO_COMPANY_ENTRIES;
|
int i = NUM_NO_COMPANY_ENTRIES;
|
||||||
for (const Company *c : Company::Iterate()) {
|
for (const Company *c : Company::Iterate()) {
|
||||||
|
@ -607,7 +607,7 @@ uint32_t GetSmallMapOwnerPixels(TileIndex tile, TileType t, IncludeHeightmap inc
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleType. */
|
/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleType. */
|
||||||
static const uint8_t _vehicle_type_colours[6] = {
|
static const PixelColour _vehicle_type_colours[6] = {
|
||||||
PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED
|
PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -935,7 +935,7 @@ protected:
|
||||||
uint8_t *val8 = (uint8_t *)&val;
|
uint8_t *val8 = (uint8_t *)&val;
|
||||||
int idx = std::max(0, -start_pos);
|
int idx = std::max(0, -start_pos);
|
||||||
for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
|
for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
|
||||||
blitter->SetPixel(dst, idx, 0, val8[idx]);
|
blitter->SetPixel(dst, idx, 0, PixelColour{val8[idx]});
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
/* Switch to next tile in the column */
|
/* Switch to next tile in the column */
|
||||||
|
@ -973,7 +973,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate pointer to pixel and the colour */
|
/* Calculate pointer to pixel and the colour */
|
||||||
uint8_t colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
|
PixelColour colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
|
||||||
|
|
||||||
/* And draw either one or two pixels depending on clipping */
|
/* And draw either one or two pixels depending on clipping */
|
||||||
blitter->SetPixel(dpi->dst_ptr, x, y, colour);
|
blitter->SetPixel(dpi->dst_ptr, x, y, colour);
|
||||||
|
@ -1348,7 +1348,7 @@ protected:
|
||||||
if (type == _smallmap_industry_highlight) {
|
if (type == _smallmap_industry_highlight) {
|
||||||
if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE);
|
if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE);
|
||||||
} else {
|
} else {
|
||||||
return GetIndustrySpec(type)->map_colour * 0x01010101;
|
return GetIndustrySpec(type)->map_colour.p * 0x01010101;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Otherwise make it disappear */
|
/* Otherwise make it disappear */
|
||||||
|
@ -1644,7 +1644,7 @@ public:
|
||||||
i = 1;
|
i = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t legend_colour = tbl->colour;
|
PixelColour legend_colour = tbl->colour;
|
||||||
|
|
||||||
std::array<StringParameter, 2> params{};
|
std::array<StringParameter, 2> params{};
|
||||||
switch (this->map_type) {
|
switch (this->map_type) {
|
||||||
|
|
|
@ -5079,7 +5079,7 @@ StationIDStack FlowStatMap::DeleteFlows(StationID via)
|
||||||
FlowStat &s_flows = f_it->second;
|
FlowStat &s_flows = f_it->second;
|
||||||
s_flows.ChangeShare(via, INT_MIN);
|
s_flows.ChangeShare(via, INT_MIN);
|
||||||
if (s_flows.GetShares()->empty()) {
|
if (s_flows.GetShares()->empty()) {
|
||||||
ret.Push(f_it->first.base());
|
ret.Push(f_it->first);
|
||||||
this->erase(f_it++);
|
this->erase(f_it++);
|
||||||
} else {
|
} else {
|
||||||
++f_it;
|
++f_it;
|
||||||
|
|
|
@ -225,7 +225,7 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoType c
|
||||||
|
|
||||||
int padding = ScaleGUITrad(1);
|
int padding = ScaleGUITrad(1);
|
||||||
int width = right - left;
|
int width = right - left;
|
||||||
int colour = cs->rating_colour;
|
PixelColour colour = cs->rating_colour;
|
||||||
TextColour tc = GetContrastColour(colour);
|
TextColour tc = GetContrastColour(colour);
|
||||||
uint w = std::min(amount + 5, units_full) * width / units_full;
|
uint w = std::min(amount + 5, units_full) * width / units_full;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct RoadStop;
|
||||||
struct StationSpec;
|
struct StationSpec;
|
||||||
struct Waypoint;
|
struct Waypoint;
|
||||||
|
|
||||||
using StationIDStack = SmallStack<StationID::BaseType, StationID::BaseType, StationID::Invalid().base(), 8, StationID::End().base()>;
|
using StationIDStack = SmallStack<StationID, StationID::BaseType, StationID::Invalid().base(), 8, StationID::End().base()>;
|
||||||
|
|
||||||
/** Station types */
|
/** Station types */
|
||||||
enum class StationType : uint8_t {
|
enum class StationType : uint8_t {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "newgrf_text.h"
|
#include "newgrf_text.h"
|
||||||
#include "fileio_func.h"
|
#include "fileio_func.h"
|
||||||
#include "signs_base.h"
|
#include "signs_base.h"
|
||||||
#include "fontdetection.h"
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "error_func.h"
|
#include "error_func.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
|
@ -2278,7 +2277,7 @@ std::string_view GetCurrentLanguageIsoCode()
|
||||||
*/
|
*/
|
||||||
bool MissingGlyphSearcher::FindMissingGlyphs()
|
bool MissingGlyphSearcher::FindMissingGlyphs()
|
||||||
{
|
{
|
||||||
InitFontCache(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||||
|
|
||||||
this->Reset();
|
this->Reset();
|
||||||
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
|
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
|
||||||
|
@ -2376,7 +2375,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
||||||
_fcsettings.mono.os_handle = nullptr;
|
_fcsettings.mono.os_handle = nullptr;
|
||||||
_fcsettings.medium.os_handle = nullptr;
|
_fcsettings.medium.os_handle = nullptr;
|
||||||
|
|
||||||
bad_font = !SetFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
|
bad_font = !FontProviderManager::FindFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
|
||||||
|
|
||||||
_fcsettings = std::move(backup);
|
_fcsettings = std::move(backup);
|
||||||
|
|
||||||
|
@ -2395,7 +2394,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
||||||
/* Our fallback font does miss characters too, so keep the
|
/* Our fallback font does miss characters too, so keep the
|
||||||
* user chosen font as that is more likely to be any good than
|
* user chosen font as that is more likely to be any good than
|
||||||
* the wild guess we made */
|
* the wild guess we made */
|
||||||
InitFontCache(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1134,7 +1134,7 @@ enum IndustryTypes : uint8_t {
|
||||||
{r1, r2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, m, \
|
{r1, r2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, m, \
|
||||||
{INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO}, \
|
{INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO}, \
|
||||||
{{im1, 0}, {im2, 0}, {im3, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, \
|
{{im1, 0}, {im2, 0}, {im3, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, \
|
||||||
pr, clim, bev, col, in, intx, s1, s2, s3, STR_UNDEFINED, {ai1, ai2, ai3, ai4}, {ag1, ag2, ag3, ag4}, \
|
pr, clim, bev, PixelColour{col}, in, intx, s1, s2, s3, STR_UNDEFINED, {ai1, ai2, ai3, ai4}, {ag1, ag2, ag3, ag4}, \
|
||||||
IndustryCallbackMasks{}, true, SubstituteGRFFileProps(IT_INVALID), snd, {}, \
|
IndustryCallbackMasks{}, true, SubstituteGRFFileProps(IT_INVALID), snd, {}, \
|
||||||
{{p1, p2}}, {{a1, a2, a3}}}
|
{{p1, p2}}, {{a1, a2, a3}}}
|
||||||
/* Format:
|
/* Format:
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
* @param classes Classes of this cargo type. @see CargoClass
|
* @param classes Classes of this cargo type. @see CargoClass
|
||||||
*/
|
*/
|
||||||
#define MK(bt, label, colour, weight, mult, ip, td1, td2, freight, tae, str_plural, str_singular, str_volume, classes) \
|
#define MK(bt, label, colour, weight, mult, ip, td1, td2, freight, tae, str_plural, str_singular, str_volume, classes) \
|
||||||
{label, bt, colour, colour, weight, mult, classes, ip, {td1, td2}, freight, tae, INVALID_TPE, TOWN_PRODUCTION_DIVISOR, CargoCallbackMasks{}, \
|
{label, bt, PixelColour{colour}, PixelColour{colour}, weight, mult, classes, ip, {td1, td2}, freight, tae, INVALID_TPE, TOWN_PRODUCTION_DIVISOR, CargoCallbackMasks{}, \
|
||||||
MK_STR_CARGO_PLURAL(str_plural), MK_STR_CARGO_SINGULAR(str_singular), str_volume, MK_STR_QUANTITY(str_plural), MK_STR_ABBREV(str_plural), \
|
MK_STR_CARGO_PLURAL(str_plural), MK_STR_CARGO_SINGULAR(str_singular), str_volume, MK_STR_QUANTITY(str_plural), MK_STR_ABBREV(str_plural), \
|
||||||
MK_SPRITE(str_plural), nullptr, nullptr, 0}
|
MK_SPRITE(str_plural), nullptr, nullptr, 0}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
||||||
RailTypeLabelList(),
|
RailTypeLabelList(),
|
||||||
|
|
||||||
/* map colour */
|
/* map colour */
|
||||||
0x0A,
|
PC_GREY,
|
||||||
|
|
||||||
/* introduction date */
|
/* introduction date */
|
||||||
CalendarTime::INVALID_DATE,
|
CalendarTime::INVALID_DATE,
|
||||||
|
@ -200,7 +200,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
||||||
RailTypeLabelList(),
|
RailTypeLabelList(),
|
||||||
|
|
||||||
/* map colour */
|
/* map colour */
|
||||||
0x0A,
|
PC_GREY,
|
||||||
|
|
||||||
/* introduction date */
|
/* introduction date */
|
||||||
CalendarTime::INVALID_DATE,
|
CalendarTime::INVALID_DATE,
|
||||||
|
@ -298,7 +298,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
||||||
RailTypeLabelList(),
|
RailTypeLabelList(),
|
||||||
|
|
||||||
/* map colour */
|
/* map colour */
|
||||||
0x0A,
|
PC_GREY,
|
||||||
|
|
||||||
/* introduction date */
|
/* introduction date */
|
||||||
CalendarTime::INVALID_DATE,
|
CalendarTime::INVALID_DATE,
|
||||||
|
@ -396,7 +396,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
||||||
RailTypeLabelList(),
|
RailTypeLabelList(),
|
||||||
|
|
||||||
/* map colour */
|
/* map colour */
|
||||||
0x0A,
|
PC_GREY,
|
||||||
|
|
||||||
/* introduction date */
|
/* introduction date */
|
||||||
CalendarTime::INVALID_DATE,
|
CalendarTime::INVALID_DATE,
|
||||||
|
|
|
@ -81,7 +81,7 @@ static const RoadTypeInfo _original_roadtypes[] = {
|
||||||
RoadTypeLabelList(),
|
RoadTypeLabelList(),
|
||||||
|
|
||||||
/* map colour */
|
/* map colour */
|
||||||
0x01,
|
PC_BLACK,
|
||||||
|
|
||||||
/* introduction date */
|
/* introduction date */
|
||||||
CalendarTime::MIN_DATE,
|
CalendarTime::MIN_DATE,
|
||||||
|
@ -162,7 +162,7 @@ static const RoadTypeInfo _original_roadtypes[] = {
|
||||||
RoadTypeLabelList(),
|
RoadTypeLabelList(),
|
||||||
|
|
||||||
/* map colour */
|
/* map colour */
|
||||||
0x01,
|
PC_BLACK,
|
||||||
|
|
||||||
/* introduction date */
|
/* introduction date */
|
||||||
CalendarTime::INVALID_DATE,
|
CalendarTime::INVALID_DATE,
|
||||||
|
|
|
@ -8,22 +8,22 @@
|
||||||
/** @file string_colours.h The colour translation of GRF's strings. */
|
/** @file string_colours.h The colour translation of GRF's strings. */
|
||||||
|
|
||||||
/** Colour mapping for #TextColour. */
|
/** Colour mapping for #TextColour. */
|
||||||
static const uint8_t _string_colourmap[17] = {
|
static constexpr PixelColour _string_colourmap[17] = {
|
||||||
150, // TC_BLUE
|
PixelColour{150}, // TC_BLUE
|
||||||
12, // TC_SILVER
|
PixelColour{ 12}, // TC_SILVER
|
||||||
189, // TC_GOLD
|
PixelColour{189}, // TC_GOLD
|
||||||
184, // TC_RED
|
PixelColour{184}, // TC_RED
|
||||||
174, // TC_PURPLE
|
PixelColour{174}, // TC_PURPLE
|
||||||
30, // TC_LIGHT_BROWN
|
PixelColour{ 30}, // TC_LIGHT_BROWN
|
||||||
195, // TC_ORANGE
|
PixelColour{195}, // TC_ORANGE
|
||||||
209, // TC_GREEN
|
PixelColour{209}, // TC_GREEN
|
||||||
68, // TC_YELLOW
|
PixelColour{ 68}, // TC_YELLOW
|
||||||
95, // TC_DARK_GREEN
|
PixelColour{ 95}, // TC_DARK_GREEN
|
||||||
79, // TC_CREAM
|
PixelColour{ 79}, // TC_CREAM
|
||||||
116, // TC_BROWN
|
PixelColour{116}, // TC_BROWN
|
||||||
15, // TC_WHITE
|
PixelColour{ 15}, // TC_WHITE
|
||||||
152, // TC_LIGHT_BLUE
|
PixelColour{152}, // TC_LIGHT_BLUE
|
||||||
6, // TC_GREY
|
PixelColour{ 6}, // TC_GREY
|
||||||
133, // TC_DARK_BLUE
|
PixelColour{133}, // TC_DARK_BLUE
|
||||||
1, // TC_BLACK
|
PixelColour{ 1}, // TC_BLACK
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,8 +21,6 @@ public:
|
||||||
this->height = FontCache::GetDefaultFontHeight(this->fs);
|
this->height = FontCache::GetDefaultFontHeight(this->fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetUnicodeGlyph(char32_t, SpriteID) override {}
|
|
||||||
void InitializeUnicodeGlyphMap() override {}
|
|
||||||
void ClearFontCache() override {}
|
void ClearFontCache() override {}
|
||||||
const Sprite *GetGlyph(GlyphID) override { return nullptr; }
|
const Sprite *GetGlyph(GlyphID) override { return nullptr; }
|
||||||
uint GetGlyphWidth(GlyphID) override { return this->height / 2; }
|
uint GetGlyphWidth(GlyphID) override { return this->height / 2; }
|
||||||
|
@ -34,7 +32,8 @@ public:
|
||||||
static void InitializeFontCaches()
|
static void InitializeFontCaches()
|
||||||
{
|
{
|
||||||
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
||||||
if (FontCache::caches[fs] == nullptr) new MockFontCache(fs); /* FontCache inserts itself into to the cache. */
|
if (FontCache::Get(fs) != nullptr) continue;
|
||||||
|
FontCache::Register(std::make_unique<MockFontCache>(fs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,6 +37,7 @@ TimerGameEconomy::Year TimerGameEconomy::year = {};
|
||||||
TimerGameEconomy::Month TimerGameEconomy::month = {};
|
TimerGameEconomy::Month TimerGameEconomy::month = {};
|
||||||
TimerGameEconomy::Date TimerGameEconomy::date = {};
|
TimerGameEconomy::Date TimerGameEconomy::date = {};
|
||||||
TimerGameEconomy::DateFract TimerGameEconomy::date_fract = {};
|
TimerGameEconomy::DateFract TimerGameEconomy::date_fract = {};
|
||||||
|
uint TimerGameEconomy::days_since_last_month = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a Date to a Year, Month & Day.
|
* Converts a Date to a Year, Month & Day.
|
||||||
|
@ -133,6 +134,7 @@ bool TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::
|
||||||
|
|
||||||
/* increase day counter */
|
/* increase day counter */
|
||||||
TimerGameEconomy::date++;
|
TimerGameEconomy::date++;
|
||||||
|
++TimerGameEconomy::days_since_last_month;
|
||||||
|
|
||||||
TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date);
|
TimerGameEconomy::YearMonthDay ymd = TimerGameEconomy::ConvertDateToYMD(TimerGameEconomy::date);
|
||||||
|
|
||||||
|
@ -177,6 +179,8 @@ bool TimerManager<TimerGameEconomy>::Elapsed([[maybe_unused]] TimerGameEconomy::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_month) TimerGameEconomy::days_since_last_month = 0;
|
||||||
|
|
||||||
/* check if we reached the maximum year, decrement dates by a year */
|
/* check if we reached the maximum year, decrement dates by a year */
|
||||||
if (TimerGameEconomy::year == EconomyTime::MAX_YEAR + 1) {
|
if (TimerGameEconomy::year == EconomyTime::MAX_YEAR + 1) {
|
||||||
TimerGameEconomy::year--;
|
TimerGameEconomy::year--;
|
||||||
|
|
|
@ -37,6 +37,8 @@ public:
|
||||||
static Date date; ///< Current date in days (day counter).
|
static Date date; ///< Current date in days (day counter).
|
||||||
static DateFract date_fract; ///< Fractional part of the day.
|
static DateFract date_fract; ///< Fractional part of the day.
|
||||||
|
|
||||||
|
static uint days_since_last_month; ///< Number of days that have elapsed since the last month.
|
||||||
|
|
||||||
static YearMonthDay ConvertDateToYMD(Date date);
|
static YearMonthDay ConvertDateToYMD(Date date);
|
||||||
static Date ConvertYMDToDate(Year year, Month month, Day day);
|
static Date ConvertYMDToDate(Year year, Month month, Day day);
|
||||||
static void SetDate(Date date, DateFract fract);
|
static void SetDate(Date date, DateFract fract);
|
||||||
|
|
|
@ -741,7 +741,7 @@ public:
|
||||||
*/
|
*/
|
||||||
inline StationIDStack GetNextStoppingStation() const
|
inline StationIDStack GetNextStoppingStation() const
|
||||||
{
|
{
|
||||||
return (this->orders == nullptr) ? StationID::Invalid().base() : this->orders->GetNextStoppingStation(this);
|
return (this->orders == nullptr) ? StationID::Invalid() : this->orders->GetNextStoppingStation(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetRefitCaps();
|
void ResetRefitCaps();
|
||||||
|
|
|
@ -697,7 +697,7 @@ static void DrawVehicleRefitWindow(const RefitOptions &refits, const RefitOption
|
||||||
bool rtl = _current_text_dir == TD_RTL;
|
bool rtl = _current_text_dir == TD_RTL;
|
||||||
uint iconwidth = std::max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width);
|
uint iconwidth = std::max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width);
|
||||||
uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height;
|
uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height;
|
||||||
int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
||||||
|
|
||||||
int iconleft = rtl ? ir.right - iconwidth : ir.left;
|
int iconleft = rtl ? ir.right - iconwidth : ir.left;
|
||||||
int iconcenter = rtl ? ir.right - iconwidth / 2 : ir.left + iconwidth / 2;
|
int iconcenter = rtl ? ir.right - iconwidth / 2 : ir.left + iconwidth / 2;
|
||||||
|
|
|
@ -1732,13 +1732,13 @@ static void ViewportDrawDirtyBlocks()
|
||||||
int right = UnScaleByZoom(dpi->width, dpi->zoom);
|
int right = UnScaleByZoom(dpi->width, dpi->zoom);
|
||||||
int bottom = UnScaleByZoom(dpi->height, dpi->zoom);
|
int bottom = UnScaleByZoom(dpi->height, dpi->zoom);
|
||||||
|
|
||||||
int colour = _string_colourmap[_dirty_block_colour & 0xF];
|
PixelColour colour = _string_colourmap[_dirty_block_colour & 0xF];
|
||||||
|
|
||||||
dst = dpi->dst_ptr;
|
dst = dpi->dst_ptr;
|
||||||
|
|
||||||
uint8_t bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
|
uint8_t bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1;
|
||||||
do {
|
do {
|
||||||
for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8_t)colour);
|
for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, colour);
|
||||||
dst = blitter->MoveTo(dst, 0, 1);
|
dst = blitter->MoveTo(dst, 0, 1);
|
||||||
} while (--bottom > 0);
|
} while (--bottom > 0);
|
||||||
}
|
}
|
||||||
|
@ -1761,7 +1761,7 @@ static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ss.flags.Test(ViewportStringFlag::TextColour)) {
|
if (ss.flags.Test(ViewportStringFlag::TextColour)) {
|
||||||
if (ss.colour != INVALID_COLOUR) colour = static_cast<TextColour>(GetColourGradient(ss.colour, SHADE_LIGHTER) | TC_IS_PALETTE_COLOUR);
|
if (ss.colour != INVALID_COLOUR) colour = GetColourGradient(ss.colour, SHADE_LIGHTER).ToTextColour();
|
||||||
}
|
}
|
||||||
|
|
||||||
int left = x + WidgetDimensions::scaled.fullbevel.left;
|
int left = x + WidgetDimensions::scaled.fullbevel.left;
|
||||||
|
|
|
@ -302,11 +302,11 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra
|
||||||
} else {
|
} else {
|
||||||
assert(colour < COLOUR_END);
|
assert(colour < COLOUR_END);
|
||||||
|
|
||||||
const uint dark = GetColourGradient(colour, SHADE_DARK);
|
const PixelColour dark = GetColourGradient(colour, SHADE_DARK);
|
||||||
const uint medium_dark = GetColourGradient(colour, SHADE_LIGHT);
|
const PixelColour medium_dark = GetColourGradient(colour, SHADE_LIGHT);
|
||||||
const uint medium_light = GetColourGradient(colour, SHADE_LIGHTER);
|
const PixelColour medium_light = GetColourGradient(colour, SHADE_LIGHTER);
|
||||||
const uint light = GetColourGradient(colour, SHADE_LIGHTEST);
|
const PixelColour light = GetColourGradient(colour, SHADE_LIGHTEST);
|
||||||
uint interior;
|
PixelColour interior;
|
||||||
|
|
||||||
Rect outer = {left, top, right, bottom}; // Outside rectangle
|
Rect outer = {left, top, right, bottom}; // Outside rectangle
|
||||||
Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel); // Inside rectangle
|
Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel); // Inside rectangle
|
||||||
|
@ -469,7 +469,7 @@ static inline void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint3
|
||||||
row_height = r.Height() / num_rows;
|
row_height = r.Height() / num_rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
int col = GetColourGradient(colour, SHADE_LIGHTER);
|
PixelColour col = GetColourGradient(colour, SHADE_LIGHTER);
|
||||||
|
|
||||||
int x = r.left;
|
int x = r.left;
|
||||||
for (int ctr = num_columns; ctr > 1; ctr--) {
|
for (int ctr = num_columns; ctr > 1; ctr--) {
|
||||||
|
@ -515,8 +515,8 @@ static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_
|
||||||
DrawImageButtons(r.WithHeight(height, false), NWID_VSCROLLBAR, colour, up_clicked, SPR_ARROW_UP, SA_CENTER);
|
DrawImageButtons(r.WithHeight(height, false), NWID_VSCROLLBAR, colour, up_clicked, SPR_ARROW_UP, SA_CENTER);
|
||||||
DrawImageButtons(r.WithHeight(height, true), NWID_VSCROLLBAR, colour, down_clicked, SPR_ARROW_DOWN, SA_CENTER);
|
DrawImageButtons(r.WithHeight(height, true), NWID_VSCROLLBAR, colour, down_clicked, SPR_ARROW_DOWN, SA_CENTER);
|
||||||
|
|
||||||
int c1 = GetColourGradient(colour, SHADE_DARK);
|
PixelColour c1 = GetColourGradient(colour, SHADE_DARK);
|
||||||
int c2 = GetColourGradient(colour, SHADE_LIGHTEST);
|
PixelColour c2 = GetColourGradient(colour, SHADE_LIGHTEST);
|
||||||
|
|
||||||
/* draw "shaded" background */
|
/* draw "shaded" background */
|
||||||
GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2);
|
GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2);
|
||||||
|
@ -554,8 +554,8 @@ static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool l
|
||||||
DrawImageButtons(r.WithWidth(width, false), NWID_HSCROLLBAR, colour, left_clicked, SPR_ARROW_LEFT, SA_CENTER);
|
DrawImageButtons(r.WithWidth(width, false), NWID_HSCROLLBAR, colour, left_clicked, SPR_ARROW_LEFT, SA_CENTER);
|
||||||
DrawImageButtons(r.WithWidth(width, true), NWID_HSCROLLBAR, colour, right_clicked, SPR_ARROW_RIGHT, SA_CENTER);
|
DrawImageButtons(r.WithWidth(width, true), NWID_HSCROLLBAR, colour, right_clicked, SPR_ARROW_RIGHT, SA_CENTER);
|
||||||
|
|
||||||
int c1 = GetColourGradient(colour, SHADE_DARK);
|
PixelColour c1 = GetColourGradient(colour, SHADE_DARK);
|
||||||
int c2 = GetColourGradient(colour, SHADE_LIGHTEST);
|
PixelColour c2 = GetColourGradient(colour, SHADE_LIGHTEST);
|
||||||
|
|
||||||
/* draw "shaded" background */
|
/* draw "shaded" background */
|
||||||
GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2);
|
GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2);
|
||||||
|
@ -593,8 +593,8 @@ static inline void DrawFrame(const Rect &r, Colours colour, TextColour text_colo
|
||||||
|
|
||||||
if (!str.empty()) x2 = DrawString(r.left + WidgetDimensions::scaled.frametext.left, r.right - WidgetDimensions::scaled.frametext.right, r.top, str, text_colour, align, false, fs);
|
if (!str.empty()) x2 = DrawString(r.left + WidgetDimensions::scaled.frametext.left, r.right - WidgetDimensions::scaled.frametext.right, r.top, str, text_colour, align, false, fs);
|
||||||
|
|
||||||
int c1 = GetColourGradient(colour, SHADE_DARK);
|
PixelColour c1 = GetColourGradient(colour, SHADE_DARK);
|
||||||
int c2 = GetColourGradient(colour, SHADE_LIGHTEST);
|
PixelColour c2 = GetColourGradient(colour, SHADE_LIGHTEST);
|
||||||
|
|
||||||
/* If the frame has text, adjust the top bar to fit half-way through */
|
/* If the frame has text, adjust the top bar to fit half-way through */
|
||||||
Rect inner = r.Shrink(ScaleGUITrad(1));
|
Rect inner = r.Shrink(ScaleGUITrad(1));
|
||||||
|
@ -791,7 +791,7 @@ void Window::DrawWidgets() const
|
||||||
Rect outer = widget->GetCurrentRect();
|
Rect outer = widget->GetCurrentRect();
|
||||||
Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel).Expand(1);
|
Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel).Expand(1);
|
||||||
|
|
||||||
int colour = _string_colourmap[_window_highlight_colour ? widget->GetHighlightColour() : TC_WHITE];
|
PixelColour colour = _string_colourmap[_window_highlight_colour ? widget->GetHighlightColour() : TC_WHITE];
|
||||||
|
|
||||||
GfxFillRect(outer.left, outer.top, inner.left, inner.bottom, colour);
|
GfxFillRect(outer.left, outer.top, inner.left, inner.bottom, colour);
|
||||||
GfxFillRect(inner.left + 1, outer.top, inner.right - 1, inner.top, colour);
|
GfxFillRect(inner.left + 1, outer.top, inner.right - 1, inner.top, colour);
|
||||||
|
|
Loading…
Reference in New Issue