Browse Source

Handle scaling for SDL1 (#370)

Only some handheld devices support auto-scaling.
On desktop and some handhelds we need to downscale manually.

Hardware auto-scaler check for jz4760 provided by @jbanes and @scooterpsu
pull/423/head
Gleb Mazovetskiy 6 years ago committed by Anders Jenbo
parent
commit
ddce870dda
  1. 26
      SourceX/DiabloUI/diabloui.cpp
  2. 19
      SourceX/dx.cpp
  3. 23
      SourceX/miniwin/ddraw.cpp
  4. 63
      SourceX/miniwin/ddraw.h
  5. 2
      SourceX/miniwin/dsound.h
  6. 15
      SourceX/miniwin/misc.cpp
  7. 25
      SourceX/miniwin/misc_msg.cpp
  8. 1
      SourceX/storm/storm.cpp

26
SourceX/DiabloUI/diabloui.cpp

@ -283,8 +283,14 @@ bool UiFocusNavigation(SDL_Event *event)
}
}
if (UiItemMouseEvents(event, gUiItems, gUiItemCnt))
return true;
if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) {
// In SDL2 mouse events already use logical coordinates.
#ifdef USE_SDL1
OutputToLogical(&event->button.x, &event->button.y);
#endif
if (UiItemMouseEvents(event, gUiItems, gUiItemCnt))
return true;
}
return false;
}
@ -782,21 +788,7 @@ void DrawMouse()
return;
SDL_GetMouseState(&MouseX, &MouseY);
#ifndef USE_SDL1
if (renderer) {
float scaleX;
SDL_RenderGetScale(renderer, &scaleX, NULL);
MouseX /= scaleX;
MouseY /= scaleX;
SDL_Rect view;
SDL_RenderGetViewport(renderer, &view);
MouseX -= view.x;
MouseY -= view.y;
}
#endif
OutputToLogical(&MouseX, &MouseY);
DrawArt(MouseX, MouseY, &ArtCursor);
}

19
SourceX/dx.cpp

@ -186,12 +186,21 @@ void BltFast(DWORD dwX, DWORD dwY, LPRECT lpSrcRect)
static_cast<decltype(SDL_Rect().y)>(dwY),
w, h
};
// Convert from 8-bit to 32-bit
if (SDL_BlitSurface(pal_surface, &src_rect, GetOutputSurface(), &dst_rect) <= -1) {
ErrSdl();
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();
}
}
bufferUpdated = true;
}

23
SourceX/miniwin/ddraw.cpp

@ -4,7 +4,8 @@ namespace dvl {
extern SDL_Surface *renderer_texture_surface; // defined in dx.cpp
SDL_Surface *GetOutputSurface() {
SDL_Surface *GetOutputSurface()
{
#ifdef USE_SDL1
return SDL_GetVideoSurface();
#else
@ -14,4 +15,24 @@ SDL_Surface *GetOutputSurface() {
#endif
}
bool OutputRequiresScaling()
{
#ifdef USE_SDL1
return SCREEN_WIDTH != GetOutputSurface()->w || SCREEN_HEIGHT != GetOutputSurface()->h;
#else // SDL2, scaling handled by renderer.
return false;
#endif
}
void ScaleOutputRect(SDL_Rect *rect)
{
if (!OutputRequiresScaling())
return;
const auto *surface = GetOutputSurface();
rect->x = rect->x * surface->w / SCREEN_WIDTH;
rect->y = rect->y * surface->h / SCREEN_HEIGHT;
rect->w = rect->w * surface->w / SCREEN_WIDTH;
rect->h = rect->h * surface->h / SCREEN_HEIGHT;
}
} // namespace dvl

63
SourceX/miniwin/ddraw.h

@ -1,5 +1,8 @@
#pragma once
#include "devilution.h"
#include <SDL.h>
#include <type_traits>
namespace dvl {
@ -18,4 +21,64 @@ extern bool bufferUpdated;
// SDL2, upscale: Renderer texture surface.
SDL_Surface *GetOutputSurface();
// Whether the output surface requires software scaling.
// Always returns false on SDL2.
bool OutputRequiresScaling();
// Scales rect if necessary.
void ScaleOutputRect(SDL_Rect *rect);
// Convert from output coordinates to logical (resolution-independent) coordinates.
template <
typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
void OutputToLogical(T *x, T *y)
{
#ifndef USE_SDL1
if (!renderer)
return;
float scaleX;
SDL_RenderGetScale(renderer, &scaleX, NULL);
*x /= scaleX;
*y /= scaleX;
SDL_Rect view;
SDL_RenderGetViewport(renderer, &view);
*x -= view.x;
*y -= view.y;
#else
if (!OutputRequiresScaling())
return;
const auto *surface = GetOutputSurface();
*x = *x * SCREEN_WIDTH / surface->w;
*y = *y * SCREEN_HEIGHT / surface->h;
#endif
}
template <
typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
void LogicalToOutput(T *x, T *y)
{
#ifndef USE_SDL1
if (!renderer)
return;
SDL_Rect view;
SDL_RenderGetViewport(renderer, &view);
*x += view.x;
*y += view.y;
float scaleX;
SDL_RenderGetScale(renderer, &scaleX, NULL);
*x *= scaleX;
*y *= scaleX;
#else
if (!OutputRequiresScaling())
return;
const auto *surface = GetOutputSurface();
*x = *x * surface->w / SCREEN_WIDTH;
*y = *y * surface->h / SCREEN_HEIGHT;
#endif
}
} // namespace dvl

2
SourceX/miniwin/dsound.h

@ -1,3 +1,5 @@
#pragma once
#include "devilution.h"
#include <SDL_mixer.h>

15
SourceX/miniwin/misc.cpp

@ -13,6 +13,10 @@
#define strncasecmp _strnicmp
#endif
#if defined(USE_SDL1) && defined(RETROFW)
#include <unistd.h>
#endif
namespace dvl {
DWORD last_error;
@ -143,8 +147,19 @@ bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight)
if (fullscreen)
flags |= SDL_FULLSCREEN;
SDL_WM_SetCaption(lpWindowName, WINDOW_ICON_NAME);
#ifndef RETROFW
SDL_SetVideoMode(nWidth, nHeight, /*bpp=*/0, flags);
#else // RETROFW
// JZ4760 IPU scaler (e.g. on RG-300 v2/3) - automatic high-quality scaling.
if (access("/proc/jz/ipu_ratio", F_OK) == 0) {
SDL_SetVideoMode(nWidth, nHeight, /*bpp=*/0, flags);
} else {
// Other RetroFW devices have 320x480 screens with non-square pixels.
SDL_SetVideoMode(320, 480, /*bpp=*/0, flags);
}
#endif
window = SDL_GetVideoSurface();
SDL_Log("Output surface: %dx%d sw-scaling=%d bpp=%d", window->w, window->h, OutputRequiresScaling(), window->format->BitsPerPixel);
if (grabInput)
SDL_WM_GrabInput(SDL_GRAB_ON);
atexit(SDL_VideoQuit); // Without this video mode is not restored after fullscreen.

25
SourceX/miniwin/misc_msg.cpp

@ -8,6 +8,7 @@
#include "controls/controller_motion.h"
#include "controls/game_controls.h"
#include "controls/plrctrls.h"
#include "miniwin/ddraw.h"
/** @file
* *
@ -26,22 +27,8 @@ void SetCursorPos(int X, int Y)
{
mouseWarpingX = X;
mouseWarpingY = Y;
#ifndef USE_SDL1
if (renderer) {
SDL_Rect view;
SDL_RenderGetViewport(renderer, &view);
X += view.x;
Y += view.y;
float scaleX;
SDL_RenderGetScale(renderer, &scaleX, NULL);
X *= scaleX;
Y *= scaleX;
}
#endif
mouseWarping = true;
LogicalToOutput(&X, &Y);
SDL_WarpMouseInWindow(window, X, Y);
}
@ -403,6 +390,14 @@ WINBOOL PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilter
return true;
}
#ifdef USE_SDL1
if (e.type == SDL_MOUSEMOTION) {
OutputToLogical(&e.motion.x, &e.motion.y);
} else if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) {
OutputToLogical(&e.button.x, &e.button.y);
}
#endif
if (movie_playing) {
if (ShouldSkipMovie(e))
SetMouseLMBMessage(e, lpMsg);

1
SourceX/storm/storm.cpp

@ -721,6 +721,7 @@ BOOL SVidPlayContinue(void)
Uint32 format = SDL_GetWindowPixelFormat(window);
SDL_Surface *tmp = SDL_ConvertSurfaceFormat(SVidSurface, format, 0);
#endif
ScaleOutputRect(&pal_surface_offset);
if (SDL_BlitScaled(tmp, NULL, GetOutputSurface(), &pal_surface_offset) <= -1) {
SDL_Log(SDL_GetError());
return false;

Loading…
Cancel
Save