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)) if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) {
return true; // 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; return false;
} }
@ -782,21 +788,7 @@ void DrawMouse()
return; return;
SDL_GetMouseState(&MouseX, &MouseY); SDL_GetMouseState(&MouseX, &MouseY);
OutputToLogical(&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
DrawArt(MouseX, MouseY, &ArtCursor); 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), static_cast<decltype(SDL_Rect().y)>(dwY),
w, h w, h
}; };
if (OutputRequiresScaling()) {
// Convert from 8-bit to 32-bit ScaleOutputRect(&dst_rect);
if (SDL_BlitSurface(pal_surface, &src_rect, GetOutputSurface(), &dst_rect) <= -1) { // Convert from 8-bit to 32-bit
ErrSdl(); 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; bufferUpdated = true;
} }

23
SourceX/miniwin/ddraw.cpp

@ -4,7 +4,8 @@ namespace dvl {
extern SDL_Surface *renderer_texture_surface; // defined in dx.cpp extern SDL_Surface *renderer_texture_surface; // defined in dx.cpp
SDL_Surface *GetOutputSurface() { SDL_Surface *GetOutputSurface()
{
#ifdef USE_SDL1 #ifdef USE_SDL1
return SDL_GetVideoSurface(); return SDL_GetVideoSurface();
#else #else
@ -14,4 +15,24 @@ SDL_Surface *GetOutputSurface() {
#endif #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 } // namespace dvl

63
SourceX/miniwin/ddraw.h

@ -1,5 +1,8 @@
#pragma once
#include "devilution.h" #include "devilution.h"
#include <SDL.h> #include <SDL.h>
#include <type_traits>
namespace dvl { namespace dvl {
@ -18,4 +21,64 @@ extern bool bufferUpdated;
// SDL2, upscale: Renderer texture surface. // SDL2, upscale: Renderer texture surface.
SDL_Surface *GetOutputSurface(); 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 } // namespace dvl

2
SourceX/miniwin/dsound.h

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

15
SourceX/miniwin/misc.cpp

@ -13,6 +13,10 @@
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
#endif #endif
#if defined(USE_SDL1) && defined(RETROFW)
#include <unistd.h>
#endif
namespace dvl { namespace dvl {
DWORD last_error; DWORD last_error;
@ -143,8 +147,19 @@ bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight)
if (fullscreen) if (fullscreen)
flags |= SDL_FULLSCREEN; flags |= SDL_FULLSCREEN;
SDL_WM_SetCaption(lpWindowName, WINDOW_ICON_NAME); SDL_WM_SetCaption(lpWindowName, WINDOW_ICON_NAME);
#ifndef RETROFW
SDL_SetVideoMode(nWidth, nHeight, /*bpp=*/0, flags); 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(); window = SDL_GetVideoSurface();
SDL_Log("Output surface: %dx%d sw-scaling=%d bpp=%d", window->w, window->h, OutputRequiresScaling(), window->format->BitsPerPixel);
if (grabInput) if (grabInput)
SDL_WM_GrabInput(SDL_GRAB_ON); SDL_WM_GrabInput(SDL_GRAB_ON);
atexit(SDL_VideoQuit); // Without this video mode is not restored after fullscreen. 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/controller_motion.h"
#include "controls/game_controls.h" #include "controls/game_controls.h"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "miniwin/ddraw.h"
/** @file /** @file
* * * *
@ -26,22 +27,8 @@ void SetCursorPos(int X, int Y)
{ {
mouseWarpingX = X; mouseWarpingX = X;
mouseWarpingY = Y; 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; mouseWarping = true;
LogicalToOutput(&X, &Y);
SDL_WarpMouseInWindow(window, X, Y); SDL_WarpMouseInWindow(window, X, Y);
} }
@ -403,6 +390,14 @@ WINBOOL PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilter
return true; 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 (movie_playing) {
if (ShouldSkipMovie(e)) if (ShouldSkipMovie(e))
SetMouseLMBMessage(e, lpMsg); SetMouseLMBMessage(e, lpMsg);

1
SourceX/storm/storm.cpp

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

Loading…
Cancel
Save