diff --git a/Widgets/WidgetImage.cpp b/Widgets/WidgetImage.cpp index a8729e0..539a5ab 100644 --- a/Widgets/WidgetImage.cpp +++ b/Widgets/WidgetImage.cpp @@ -16,7 +16,6 @@ m_valign(valign), m_bg_color(bg_color) { m_image_surface = IMG_Load(m_filename.c_str()); - if (nullptr == m_image_surface) { // TODO: Print errors @@ -39,16 +38,23 @@ void WidgetImage::draw() return; } - SDL_Rect align = surface_align(m_surface, m_image_surface, m_halign, m_valign); + SDL_Rect align; + SDL_Surface* scaled_image = nullptr; switch (m_resize_type) { case RESIZE_NONE: + align = surface_align(m_surface, m_image_surface, m_halign, m_valign); SDL_BlitSurface(m_image_surface, nullptr, m_surface, &align); break; case RESIZE_FIT: - // TODO: This currently stretches - SDL_BlitScaled(m_image_surface, nullptr, m_surface, nullptr); + scaled_image = image_scale_fit(); + if (nullptr != scaled_image) + { + align = surface_align(m_surface, scaled_image, m_halign, m_valign); + SDL_BlitScaled(scaled_image, nullptr, m_surface, &align); + SDL_FreeSurface(scaled_image); + } break; case RESIZE_STRETCH: @@ -82,3 +88,41 @@ std::unique_ptr WidgetImage::builder(const nlohmann::json& j) return std::make_unique(x, y, width, height, filename, resize_type, halign, valign, bg_color); } + +SDL_Surface* WidgetImage::image_scale_fit() +{ + SDL_Rect align = {.x = 0, .y = 0, .w = 0, .h = 0}; + + if ((nullptr == m_surface) || (nullptr == m_image_surface)) + { + return nullptr; + } + + double x_scale = m_surface->w; + x_scale /= m_image_surface->w; + + double y_scale = m_surface->h; + y_scale /= m_image_surface->h; + + // Find smallest scale factor + double min_scale = x_scale; + if (y_scale < min_scale) + { + min_scale = y_scale; + } + + // Scale with double in the front and then clamp to int via SDL_Rect + align.w = min_scale * m_image_surface->w; + align.h = min_scale * m_image_surface->h; + + SDL_Surface* scaled_image_surface = + SDL_CreateRGBSurfaceWithFormat(0, align.w, align.h, 32, SDL_PIXELFORMAT_RGBA8888); + if (nullptr == scaled_image_surface) + { + // TODO: Print Error + return nullptr; + } + + SDL_BlitScaled(m_image_surface, nullptr, scaled_image_surface, nullptr); + return scaled_image_surface; +} diff --git a/Widgets/WidgetImage.h b/Widgets/WidgetImage.h index d940444..8b84c11 100644 --- a/Widgets/WidgetImage.h +++ b/Widgets/WidgetImage.h @@ -42,6 +42,11 @@ public: virtual void draw() override; static std::unique_ptr builder(const nlohmann::json& j); + +protected: + // Create a new surface of the image_surface that is scaled via RESIZE_FIT method + // NOTE: The user MUST free the surface when done with it + SDL_Surface* image_scale_fit(); }; #endif // WIDGET_IMAGE_H_ diff --git a/sdl_helpers.cpp b/sdl_helpers.cpp index 03af385..e6e2d84 100644 --- a/sdl_helpers.cpp +++ b/sdl_helpers.cpp @@ -87,6 +87,10 @@ SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied, return align; } + // These are set in order to handle scaled blits + align.w = applied->w; + align.h = applied->h; + if (nullptr == hint_external) { hint = SDL_Rect{.x = 0, .y = 0, .w = applied->w, .h = applied->h};