diff --git a/SourceS/sdl2_to_1_2_backports.h b/SourceS/sdl2_to_1_2_backports.h index 97bb566e7..fe9ed24d9 100644 --- a/SourceS/sdl2_to_1_2_backports.h +++ b/SourceS/sdl2_to_1_2_backports.h @@ -215,6 +215,11 @@ SDL_FreePalette(SDL_Palette *palette) SDL_free(palette); } +inline bool SDL_HasColorKey(SDL_Surface *surface) +{ + return (surface->flags & SDL_SRCCOLORKEY) != 0; +} + //= Pixel formats #define SDL_PIXELFORMAT_INDEX8 1 @@ -259,7 +264,8 @@ inline void SDLBackport_PixelformatToMask(int pixelformat, Uint32 *flags, Uint32 */ inline bool SDLBackport_PixelFormatFormatEq(const SDL_PixelFormat *a, const SDL_PixelFormat *b) { - return a->BitsPerPixel == b->BitsPerPixel && (a->palette != nullptr) == (b->palette != nullptr); + return a->BitsPerPixel == b->BitsPerPixel && (a->palette != nullptr) == (b->palette != nullptr) + && a->Rmask == b->Rmask && a->Gmask == b->Gmask && a->Bmask == b->Bmask; } /** diff --git a/SourceX/DiabloUI/art.cpp b/SourceX/DiabloUI/art.cpp index 3d9087f18..4e517f767 100644 --- a/SourceX/DiabloUI/art.cpp +++ b/SourceX/DiabloUI/art.cpp @@ -1,4 +1,5 @@ #include "DiabloUI/art.h" +#include "display.h" namespace dvl { @@ -40,6 +41,8 @@ void LoadArt(const char *pszFile, Art *art, int frames, SDL_Color *pPalette) art->surface = art_surface; art->frame_height = height / frames; + + ScaleSurfaceToOutput(&art->surface); } void LoadMaskedArt(const char *pszFile, Art *art, int frames, int mask) @@ -55,6 +58,7 @@ void LoadArt(Art *art, const BYTE *artData, int w, int h, int frames) art->surface = SDL_CreateRGBSurfaceWithFormatFrom( const_cast(artData), w, h, 8, w, SDL_PIXELFORMAT_INDEX8); art->frame_height = h / frames; + ScaleSurfaceToOutput(&art->surface); } } // namespace dvl diff --git a/SourceX/DiabloUI/art_draw.cpp b/SourceX/DiabloUI/art_draw.cpp index 8cf426ad0..52a116caa 100644 --- a/SourceX/DiabloUI/art_draw.cpp +++ b/SourceX/DiabloUI/art_draw.cpp @@ -1,4 +1,5 @@ #include "DiabloUI/art_draw.h" +#include "display.h" namespace dvl { @@ -18,11 +19,14 @@ void DrawArt(int screenX, int screenY, Art *art, int nFrame, static_cast(art->w()), static_cast(art->h()) }; + ScaleOutputRect(&src_rect); + if (srcW && srcW < src_rect.w) src_rect.w = srcW; if (srcH && srcH < src_rect.h) src_rect.h = srcH; SDL_Rect dst_rect = { screenX, screenY, src_rect.w, src_rect.h }; + ScaleOutputRect(&dst_rect); if (art->surface->format->BitsPerPixel == 8 && art->palette_version != pal_surface_palette_version) { if (SDLC_SetSurfaceColors(art->surface, pal_surface->format->palette) <= -1) @@ -30,7 +34,8 @@ void DrawArt(int screenX, int screenY, Art *art, int nFrame, art->palette_version = pal_surface_palette_version; } - Blit(art->surface, &src_rect, &dst_rect); + if (SDL_BlitSurface(art->surface, &src_rect, GetOutputSurface(), &dst_rect) < 0) + ErrSdl(); } void DrawAnimatedArt(Art *art, int screenX, int screenY) { diff --git a/SourceX/DiabloUI/credits.cpp b/SourceX/DiabloUI/credits.cpp index d405d6443..71edf0575 100644 --- a/SourceX/DiabloUI/credits.cpp +++ b/SourceX/DiabloUI/credits.cpp @@ -95,6 +95,10 @@ CachedLine PrepareLine(std::size_t index) if (SDL_BlitSurface(text.get(), nullptr, surface.get(), nullptr) <= -1) ErrSdl(); + + SDL_Surface *surface_ptr = surface.release(); + ScaleSurfaceToOutput(&surface_ptr); + surface.reset(surface_ptr); } return CachedLine(index, std::move(surface)); @@ -224,7 +228,11 @@ void CreditsRenderer::Render() while (lines_.back().index + 1 != lines_end) lines_.push_back(PrepareLine(lines_.back().index + 1)); - SDL_SetClipRect(GetOutputSurface(), &VIEWPORT); + SDL_Rect viewport = VIEWPORT; + ScaleOutputRect(&viewport); + SDL_SetClipRect(GetOutputSurface(), &viewport); + + // We use unscaled coordinates for calculation throughout. decltype(SDL_Rect().y) 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]; @@ -239,8 +247,12 @@ void CreditsRenderer::Render() if (CREDITS_LINES[line.index][0] == '\t') dest_x += 40; - SDL_Rect dest_rect = { dest_x, dest_y, line.surface.get()->w, line.surface.get()->h }; - Blit(line.surface.get(), nullptr, &dest_rect); + SDL_Rect dst_rect = { dest_x, dest_y, 0, 0 }; + ScaleOutputRect(&dst_rect); + dst_rect.w = line.surface.get()->w; + dst_rect.h = line.surface.get()->h; + if (SDL_BlitSurface(line.surface.get(), nullptr, GetOutputSurface(), &dst_rect) < 0) + ErrSdl(); } SDL_SetClipRect(GetOutputSurface(), nullptr); } diff --git a/SourceX/display.cpp b/SourceX/display.cpp index 812e584cc..9490edfc8 100644 --- a/SourceX/display.cpp +++ b/SourceX/display.cpp @@ -171,4 +171,40 @@ void ScaleOutputRect(SDL_Rect *rect) rect->h = rect->h * surface->h / SCREEN_HEIGHT; } +#ifdef USE_SDL1 +namespace { + +SDL_Surface *CreateScaledSurface(SDL_Surface *src) +{ + SDL_Rect stretched_rect = { 0, 0, static_cast(src->w), static_cast(src->h) }; + ScaleOutputRect(&stretched_rect); + SDL_Surface *stretched = SDL_CreateRGBSurface( + SDL_SWSURFACE, stretched_rect.w, stretched_rect.h, src->format->BitsPerPixel, + src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask); + if (SDL_HasColorKey(src)) { + SDL_SetColorKey(stretched, SDL_SRCCOLORKEY, src->format->colorkey); + if (src->format->palette != nullptr) + SDL_SetPalette(stretched, SDL_LOGPAL, src->format->palette->colors, 0, src->format->palette->ncolors); + } + if (SDL_SoftStretch((src), nullptr, stretched, &stretched_rect) < 0) { + SDL_FreeSurface(stretched); + ErrSdl(); + } + return stretched; +} + +} // namespace +#endif // USE_SDL1 + +void ScaleSurfaceToOutput(SDL_Surface **surface) +{ +#ifdef USE_SDL1 + if (!OutputRequiresScaling()) + return; + SDL_Surface *stretched = CreateScaledSurface(*surface); + SDL_FreeSurface((*surface)); + *surface = stretched; +#endif +} + } // namespace dvl diff --git a/SourceX/display.h b/SourceX/display.h index 3873cf8f2..e1a2eac53 100644 --- a/SourceX/display.h +++ b/SourceX/display.h @@ -28,6 +28,9 @@ bool OutputRequiresScaling(); // Scales rect if necessary. void ScaleOutputRect(SDL_Rect *rect); +// If the output requires software scaling, replaces the given surface with a scaled one. +void ScaleSurfaceToOutput(SDL_Surface **surface); + // Convert from output coordinates to logical (resolution-independent) coordinates. template < typename T, diff --git a/SourceX/dx.cpp b/SourceX/dx.cpp index 3fc9b044c..29d996009 100644 --- a/SourceX/dx.cpp +++ b/SourceX/dx.cpp @@ -173,40 +173,57 @@ void CreatePalette() void BltFast(SDL_Rect *src_rect, SDL_Rect *dst_rect) { - if (OutputRequiresScaling()) { - ScaleOutputRect(dst_rect); - // Convert from 8-bit to 32-bit - SDL_Surface *tmp = SDL_ConvertSurface(pal_surface, GetOutputSurface()->format, 0); - if (SDL_BlitScaled(tmp, src_rect, GetOutputSurface(), dst_rect) <= -1) { - SDL_FreeSurface(tmp); - ErrSdl(); - } - SDL_FreeSurface(tmp); - } else { - // Convert from 8-bit to 32-bit - if (SDL_BlitSurface(pal_surface, src_rect, GetOutputSurface(), dst_rect) <= -1) { - ErrSdl(); - } - } + Blit(pal_surface, src_rect, dst_rect); } void Blit(SDL_Surface *src, SDL_Rect *src_rect, SDL_Rect *dst_rect) { - if (OutputRequiresScaling()) { - ScaleOutputRect(dst_rect); - // Convert from 8-bit to 32-bit - SDL_Surface *tmp = SDL_ConvertSurface(src, GetOutputSurface()->format, 0); - if (SDL_BlitScaled(tmp, src_rect, GetOutputSurface(), dst_rect) <= -1) { - SDL_FreeSurface(tmp); + SDL_Surface *dst = GetOutputSurface(); +#ifndef USE_SDL1 + if (SDL_BlitSurface(src, src_rect, dst, dst_rect) < 0) ErrSdl(); - } - SDL_FreeSurface(tmp); - } else { - // Convert from 8-bit to 32-bit - if (SDL_BlitSurface(src, src_rect, GetOutputSurface(), dst_rect) <= -1) { + return; +#else + if (!OutputRequiresScaling()) { + if (SDL_BlitSurface(src, src_rect, dst, dst_rect) < 0) + ErrSdl(); + return; + } + if (dst_rect != nullptr) ScaleOutputRect(dst_rect); + + // Same pixel format: We can call BlitScaled directly. + if (SDLBackport_PixelFormatFormatEq(src->format, dst->format)) { + if (SDL_BlitScaled(src, src_rect, dst, dst_rect) < 0) + ErrSdl(); + return; + } + + // If the surface has a color key, we must stretch first and can then call BlitSurface. + if (SDL_HasColorKey(src)) { + SDL_Surface *stretched = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_rect->w, dst_rect->h, src->format->BitsPerPixel, + src->format->Rmask, src->format->Gmask, src->format->BitsPerPixel, src->format->Amask); + SDL_SetColorKey(stretched, SDL_SRCCOLORKEY, src->format->colorkey); + if (src->format->palette != nullptr) + SDL_SetPalette(stretched, SDL_LOGPAL, src->format->palette->colors, 0, src->format->palette->ncolors); + SDL_Rect stretched_rect = { 0, 0, dst_rect->w, dst_rect->h }; + if (SDL_SoftStretch(src, src_rect, stretched, &stretched_rect) < 0 + || SDL_BlitSurface(stretched, &stretched_rect, dst, dst_rect) < 0) { + SDL_FreeSurface(stretched); ErrSdl(); } + SDL_FreeSurface(stretched); + return; + } + + // A surface with a non-output pixel format but without a color key needs scaling. + // We can convert the format and then call BlitScaled. + SDL_Surface *converted = SDL_ConvertSurface(src, dst->format, 0); + if (SDL_BlitScaled(converted, src_rect, dst, dst_rect) < 0) { + SDL_FreeSurface(converted); + ErrSdl(); } + SDL_FreeSurface(converted); +#endif } /**