Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions src/AnmManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <new>

#include <SDL2/SDL_image.h>
Expand Down Expand Up @@ -1975,6 +1976,11 @@ void AnmManager::TakeScreenshot(i32 textureId, i32 left, i32 top, i32 width, i32
SDL_Rect stretchSrcRect;
SDL_Surface *stretchedSurface = NULL;
SDL_Surface *unstretchedSurface = NULL;
i32 scaledLeft;
i32 scaledTop;
i32 scaledWidth;
i32 scaledHeight;
i32 readY;

// OpenGL throws an error specifically for negative W / H and pixels are undefined for 0 inputs.
if (this->textures[textureId].handle == 0 || width <= 0 || height <= 0)
Expand All @@ -1984,17 +1990,19 @@ void AnmManager::TakeScreenshot(i32 textureId, i32 left, i32 top, i32 width, i32

this->SetCurrentTexture(this->textures[textureId].handle);

backBufferPixels =
new u8[((u32)(width * WIDTH_RESOLUTION_SCALE + 1)) * ((u32)(height * HEIGHT_RESOLUTION_SCALE + 1)) * 4];
scaledLeft = (i32)std::lround(left * WIDTH_RESOLUTION_SCALE + VIEWPORT_OFF_X);
scaledTop = (i32)std::lround(top * HEIGHT_RESOLUTION_SCALE + VIEWPORT_OFF_Y);
scaledWidth = std::max(1, (i32)std::lround(width * WIDTH_RESOLUTION_SCALE));
scaledHeight = std::max(1, (i32)std::lround(height * HEIGHT_RESOLUTION_SCALE));
readY = GAME_WINDOW_HEIGHT_REAL - (scaledTop + scaledHeight);

g_glFuncTable.glReadPixels(left * WIDTH_RESOLUTION_SCALE + VIEWPORT_OFF_X,
GAME_WINDOW_HEIGHT_REAL - ((top + height) * HEIGHT_RESOLUTION_SCALE) - VIEWPORT_OFF_Y,
width * WIDTH_RESOLUTION_SCALE, height * HEIGHT_RESOLUTION_SCALE, GL_RGBA,
GL_UNSIGNED_BYTE, backBufferPixels);
backBufferPixels = new u8[(u32)scaledWidth * (u32)scaledHeight * 4];

unstretchedSurface = SDL_CreateRGBSurfaceWithFormatFrom(backBufferPixels, width * WIDTH_RESOLUTION_SCALE,
height * HEIGHT_RESOLUTION_SCALE, 32,
width * WIDTH_RESOLUTION_SCALE * 4, SDL_PIXELFORMAT_RGBA32);
g_glFuncTable.glReadPixels(scaledLeft, readY, scaledWidth, scaledHeight, GL_RGBA, GL_UNSIGNED_BYTE,
backBufferPixels);

unstretchedSurface = SDL_CreateRGBSurfaceWithFormatFrom(backBufferPixels, scaledWidth, scaledHeight, 32,
scaledWidth * 4, SDL_PIXELFORMAT_RGBA32);
stretchedSurface = SDL_CreateRGBSurfaceWithFormat(0, this->textures[textureId].width,
this->textures[textureId].height, 32, SDL_PIXELFORMAT_RGBA32);

Expand All @@ -2009,8 +2017,8 @@ void AnmManager::TakeScreenshot(i32 textureId, i32 left, i32 top, i32 width, i32

stretchSrcRect.x = 0;
stretchSrcRect.y = 0;
stretchSrcRect.h = height * HEIGHT_RESOLUTION_SCALE;
stretchSrcRect.w = width * WIDTH_RESOLUTION_SCALE;
stretchSrcRect.h = scaledHeight;
stretchSrcRect.w = scaledWidth;

stretchDstRect.x = 0;
stretchDstRect.y = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/Config/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class ConfigUI
int bit;
};

const CheckboxSpec specs[11] = {
const CheckboxSpec specs[12] = {
{"No Vertex Buffer", GCOS_DONT_USE_VERTEX_BUF},
{"No Fog", GCOS_DONT_USE_FOG},
{"16 Bit Textures", GCOS_FORCE_16BIT_COLOR_MODE},
Expand All @@ -197,6 +197,7 @@ class ConfigUI
{"No Depth test", GCOS_TURN_OFF_DEPTH_TEST},
{"Force 60 FPS", GCOS_FORCE_60FPS},
{"No DirectInput pad", GCOS_NO_DIRECTINPUT_PAD},
{"Scale fullscreen image (keep aspect)", GCOS_SCALE_FULLSCREEN_KEEP_ASPECT},
};

const int checkboxCount = sizeof(specs) / sizeof(specs[0]);
Expand Down
53 changes: 51 additions & 2 deletions src/GameWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
GameWindow g_GameWindow;
i32 g_TickCountToEffectiveFramerate;
f64 g_LastFrameTime;
i32 g_GameWindowWidthReal = GAME_WINDOW_WIDTH;
i32 g_GameWindowHeightReal = GAME_WINDOW_HEIGHT;
i32 g_ViewportWidth = GAME_WINDOW_WIDTH;
i32 g_ViewportHeight = GAME_WINDOW_HEIGHT;
i32 g_ViewportOffX = 0;
i32 g_ViewportOffY = 0;
f32 g_WidthResolutionScale = 1.0f;
f32 g_HeightResolutionScale = 1.0f;

#define FRAME_TIME (1000. / 60.)

Expand All @@ -30,6 +38,32 @@ static struct
} s_RenderBackends[] = {{"GL(ES) 2.0 / WebGL", true, WebGL::SetContextFlags, WebGL::Create},
{"Fixed function GL(ES)", false, FixedFunctionGL::SetContextFlags, FixedFunctionGL::Init}};

static void UpdateViewportMetrics(i32 realWidth, i32 realHeight)
{
g_GameWindowWidthReal = realWidth;
g_GameWindowHeightReal = realHeight;

g_ViewportWidth = realWidth;
g_ViewportHeight = realHeight;
g_ViewportOffX = 0;
g_ViewportOffY = 0;

// Keep the original 4:3 gameplay aspect in non-4:3 output windows.
if (realWidth * 3 > realHeight * 4)
{
g_ViewportWidth = (i32)((realHeight / 3.0f) * 4.0f);
g_ViewportOffX = (realWidth - g_ViewportWidth) / 2;
}
else if (realWidth * 3 < realHeight * 4)
{
g_ViewportHeight = (i32)((realWidth / 4.0f) * 3.0f);
g_ViewportOffY = (realHeight - g_ViewportHeight) / 2;
}

g_WidthResolutionScale = (f32)g_ViewportWidth / GAME_WINDOW_WIDTH;
g_HeightResolutionScale = (f32)g_ViewportHeight / GAME_WINDOW_HEIGHT;
}

RenderResult GameWindow::Render()
{
i32 res;
Expand Down Expand Up @@ -183,17 +217,30 @@ void GameWindow::CreateGameWindow()
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER);

u32 flags = SDL_WINDOW_OPENGL;
i32 height = GAME_WINDOW_HEIGHT_REAL;
i32 width = GAME_WINDOW_WIDTH_REAL;
i32 height = GAME_WINDOW_HEIGHT;
i32 width = GAME_WINDOW_WIDTH;
i32 x = SDL_WINDOWPOS_UNDEFINED;
i32 y = SDL_WINDOWPOS_UNDEFINED;
i32 drawableWidth = GAME_WINDOW_WIDTH;
i32 drawableHeight = GAME_WINDOW_HEIGHT;
bool useFullscreenStretch = false;

g_GameWindow.window = NULL;
g_GameWindow.glContext = NULL;

if (g_Supervisor.cfg.windowed == 0)
{
flags |= SDL_WINDOW_FULLSCREEN;
useFullscreenStretch = ((g_Supervisor.cfg.opts >> GCOS_SCALE_FULLSCREEN_KEEP_ASPECT) & 1) != 0;
if (useFullscreenStretch)
{
SDL_DisplayMode mode;
if (SDL_GetCurrentDisplayMode(0, &mode) == 0 && mode.w > 0 && mode.h > 0)
{
width = mode.w;
height = mode.h;
}
}
}

for (u32 i = 0; i < ARRAY_SIZE(s_RenderBackends); i++)
Expand Down Expand Up @@ -221,6 +268,8 @@ void GameWindow::CreateGameWindow()

utils::DebugPrint2("Using renderer backend %s", s_RenderBackends[i].name);
g_glFuncTable.ResolveFunctions(s_RenderBackends[i].isEsContext);
SDL_GL_GetDrawableSize(g_GameWindow.window, &drawableWidth, &drawableHeight);
UpdateViewportMetrics(drawableWidth, drawableHeight);
g_GameWindow.renderBackendIndex = i;
break;
fail:
Expand Down
48 changes: 18 additions & 30 deletions src/GameWindow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,24 @@
#define GAME_WINDOW_HEIGHT (480)

// The actual resolution used for the output window and viewport scaling
// At some point there should be a method to change this without recompiling but for now
// this'll do
#ifndef GAME_WINDOW_WIDTH_REAL
#define GAME_WINDOW_WIDTH_REAL (GAME_WINDOW_WIDTH)
#endif

#ifndef GAME_WINDOW_HEIGHT_REAL
#define GAME_WINDOW_HEIGHT_REAL (GAME_WINDOW_HEIGHT)
#endif

#define VIEWPORT_WIDTH GAME_WINDOW_WIDTH_REAL
#define VIEWPORT_OFF_X 0
#define VIEWPORT_HEIGHT GAME_WINDOW_HEIGHT_REAL
#define VIEWPORT_OFF_Y 0

// Aspect ratio wider than 4:3
#if (GAME_WINDOW_WIDTH_REAL * 3) > (GAME_WINDOW_HEIGHT_REAL * 4)
#undef VIEWPORT_WIDTH
#undef VIEWPORT_OFF_X
#define VIEWPORT_WIDTH ((u32)((GAME_WINDOW_HEIGHT_REAL / 3.0f) * 4.0f))
#define VIEWPORT_OFF_X ((GAME_WINDOW_WIDTH_REAL - VIEWPORT_WIDTH) / 2)
#elif (GAME_WINDOW_WIDTH_REAL * 3) < (GAME_WINDOW_HEIGHT_REAL * 4)
#undef VIEWPORT_HEIGHT
#undef VIEWPORT_OFF_Y
#define VIEWPORT_HEIGHT ((u32)((GAME_WINDOW_WIDTH_REAL / 4.0f) * 3.0f))
#define VIEWPORT_OFF_Y ((GAME_WINDOW_HEIGHT_REAL - VIEWPORT_HEIGHT) / 2)
#endif

#define WIDTH_RESOLUTION_SCALE (((f32)VIEWPORT_WIDTH) / GAME_WINDOW_WIDTH)
#define HEIGHT_RESOLUTION_SCALE (((f32)VIEWPORT_HEIGHT) / GAME_WINDOW_HEIGHT)
// These values are computed at runtime from the created window size.
extern i32 g_GameWindowWidthReal;
extern i32 g_GameWindowHeightReal;
extern i32 g_ViewportWidth;
extern i32 g_ViewportHeight;
extern i32 g_ViewportOffX;
extern i32 g_ViewportOffY;
extern f32 g_WidthResolutionScale;
extern f32 g_HeightResolutionScale;

#define GAME_WINDOW_WIDTH_REAL (g_GameWindowWidthReal)
#define GAME_WINDOW_HEIGHT_REAL (g_GameWindowHeightReal)
#define VIEWPORT_WIDTH (g_ViewportWidth)
#define VIEWPORT_OFF_X (g_ViewportOffX)
#define VIEWPORT_HEIGHT (g_ViewportHeight)
#define VIEWPORT_OFF_Y (g_ViewportOffY)
#define WIDTH_RESOLUTION_SCALE (g_WidthResolutionScale)
#define HEIGHT_RESOLUTION_SCALE (g_HeightResolutionScale)

enum RenderResult
{
Expand Down
1 change: 1 addition & 0 deletions src/Supervisor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ enum GameConfigOptsShifts
GCOS_REFERENCE_RASTERIZER_MODE = 0x9,
GCOS_DONT_USE_FOG = 0xa,
GCOS_NO_DIRECTINPUT_PAD = 0xb,
GCOS_SCALE_FULLSCREEN_KEEP_ASPECT = 0xc,
};

struct ControllerMapping
Expand Down