diff --git a/SourceX/DiabloUI/credits.cpp b/SourceX/DiabloUI/credits.cpp index be5a1f0d7..277cd5b47 100644 --- a/SourceX/DiabloUI/credits.cpp +++ b/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; + 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 text; - std::unique_ptr 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); }