Browse Source

DiabloUI/credits: Render TTF only once

Re-use the same TTF surface for text and shadow.
This is significantly faster.
pull/356/head
Gleb Mazovetskiy 7 years ago committed by Anders Jenbo
parent
commit
d76e577ee4
  1. 63
      SourceX/DiabloUI/credits.cpp

63
SourceX/DiabloUI/credits.cpp

@ -16,6 +16,8 @@ namespace dvl {
namespace {
const SDL_Rect VIEWPORT = { SCREEN_X, SCREEN_Y + 114, SCREEN_WIDTH, 251 };
constexpr int SHADOW_OFFSET_X = 2;
constexpr int SHADOW_OFFSET_Y = 2;
constexpr int LINE_H = 22;
struct SurfaceDeleter {
@ -25,31 +27,31 @@ struct SurfaceDeleter {
}
};
using SurfacePtr = std::unique_ptr<SDL_Surface, SurfaceDeleter>;
struct CachedLine {
CachedLine() = default;
explicit CachedLine(std::size_t index, SDL_Surface *text, SDL_Surface *shadow)
explicit CachedLine(std::size_t index, SurfacePtr surface)
: index(index)
, text(text)
, shadow(shadow)
, surface(std::move(surface))
, palette_version(pal_surface_palette_version)
{
}
std::size_t index;
std::unique_ptr<SDL_Surface, SurfaceDeleter> text;
std::unique_ptr<SDL_Surface, SurfaceDeleter> shadow;
SurfacePtr surface;
decltype(pal_surface_palette_version) palette_version;
};
SDL_Surface *RenderText(const char *text, SDL_Color color)
SurfacePtr RenderText(const char *text, SDL_Color color)
{
if (text[0] == '\0')
return nullptr;
SDL_Surface *result = TTF_RenderUTF8_Solid(font, text, color);
if (result == nullptr)
SDL_Log(TTF_GetError());
return result;
return SurfacePtr(result);
}
CachedLine PrepareLine(std::size_t index)
@ -57,7 +59,47 @@ CachedLine PrepareLine(std::size_t index)
const char *contents = CREDITS_LINES[index];
if (contents[0] == '\t')
++contents;
return CachedLine(index, RenderText(contents, palette->colors[224]), RenderText(contents, { 0, 0, 0, 0 }));
const SDL_Color shadow_color = { 0, 0, 0, 0 };
auto text = RenderText(contents, shadow_color);
// Precompose shadow and text:
SurfacePtr surface;
if (text != nullptr) {
// Set up the target surface to have 3 colors: mask, text, and shadow.
surface.reset(
SDL_CreateRGBSurfaceWithFormat(0, text->w + SHADOW_OFFSET_X, text->h + SHADOW_OFFSET_Y, 8, SDL_PIXELFORMAT_INDEX8));
const SDL_Color &mask_color = palette->colors[50]; // Any color different from both shadow and text
const SDL_Color &text_color = palette->colors[224];
SDL_Color colors[3] = { mask_color, text_color, shadow_color };
SDL_SetPaletteColors(surface->format->palette, colors, 0, 3);
#ifdef USE_SDL1
SDL_SetColorKey(surface.get(), SDL_SRCCOLORKEY, 0);
#else
SDL_SetColorKey(surface.get(), SDL_TRUE, 0);
#endif
// Blit the shadow first:
SDL_Rect shadow_rect = { SHADOW_OFFSET_X, SHADOW_OFFSET_Y, 0, 0 };
if (SDL_BlitSurface(text.get(), nullptr, surface.get(), &shadow_rect) <= -1)
SDL_Log(SDL_GetError());
// Change the text surface color and blit again:
#ifdef USE_SDL1
SDL_SetColorKey(text.get(), SDL_SRCCOLORKEY, 0);
SDL_Color text_colors[2] = { mask_color, text_color };
if (SDL_SetPalette(text.get(), SDL_LOGPAL, text_colors, 0, 2) != 1)
SDL_Log(SDL_GetError());
#else
text->format->palette->colors[0] = mask_color;
text->format->palette->colors[1] = text_color;
SDL_SetColorKey(text.get(), SDL_TRUE, 0);
#endif
if (SDL_BlitSurface(text.get(), nullptr, surface.get(), nullptr) <= -1)
SDL_Log(SDL_GetError());
}
return CachedLine(index, std::move(surface));
}
/**
@ -198,7 +240,7 @@ void CreditsRenderer::Render()
int dest_y = VIEWPORT.y - (offset_y - lines_begin * LINE_H);
for (std::size_t i = 0; i < lines_.size(); ++i, dest_y += LINE_H) {
auto &line = lines_[i];
if (line.text == nullptr)
if (line.surface == nullptr)
continue;
// Still fading in: the cached line was drawn with a different fade level.
@ -209,8 +251,7 @@ void CreditsRenderer::Render()
if (CREDITS_LINES[line.index][0] == '\t')
dest_x += 40;
BlitToViewport(line.shadow.get(), dest_x + 2, dest_y + 2);
BlitToViewport(line.text.get(), dest_x, dest_y);
BlitToViewport(line.surface.get(), dest_x, dest_y);
}
SDL_SetClipRect(pal_surface, nullptr);
}

Loading…
Cancel
Save