Skip to content

Commit

Permalink
Merge branch 'high-dpi-scaling'
Browse files Browse the repository at this point in the history
  • Loading branch information
kuroneko committed Jul 20, 2020
2 parents bb15ce1 + 5905a5d commit 096898f
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 63 deletions.
1 change: 1 addition & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ cmake_policy(SET CMP0091 NEW)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED 14)

# on macos, target 10.11
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.11)

project(strange VERSION 1.6.1 LANGUAGES C CXX)

option(USE_CONAN "Use conan for dependencies" OFF)
Expand Down Expand Up @@ -122,6 +125,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Darwin)
if(BUILD_DEMO)
set_target_properties(strangedemo PROPERTIES
OUTPUT_NAME "Strange Adventures in Infinite Space Demo"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in"
MACOSX_FRAMEWORK_IDENTIFIER "au.com.ecsim.saisgpldemo"
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME "Strange Adventures Demo"
Expand All @@ -136,6 +140,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Darwin)
else()
set_target_properties(strange PROPERTIES
OUTPUT_NAME "Strange Adventures in Infinite Space"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in"
MACOSX_FRAMEWORK_IDENTIFIER "au.com.ecsim.saisgpl"
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME "Strange Adventures"
Expand Down
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pipeline {
deleteDir()
sh '''
export PATH=/usr/local/bin:$PATH
export MACOS_DEPLOYMENT_TARGET=10.9
export MACOS_DEPLOYMENT_TARGET=10.11
conan install ../saisgpl --build --update --profile=default
'''
}
Expand Down
36 changes: 36 additions & 0 deletions MacOSXBundleInfo.plist.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>au.com.ecsim.SAISGPL</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ Key changes to the game source include:

* Make use of writable local directories for scores and config

* Support rescaling to native resolution full-screen including "whole multiple"
scaling. (I'd like pixel perfect, but the scaled blit always filters)
* Support rescaling to native resolution full-screen including pixel perfect
scaling.

* Allow the main window to be resized on the fly. Doesn't redraw whilst you're
resizing (yet), but it will once the resize is complete.
Expand Down
4 changes: 3 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,8 @@ int32 intro_screen()

case 8:
globalsettings.opt_whole_multiple_rescale_ratio = !globalsettings.opt_whole_multiple_rescale_ratio;
vid_reset_settings();

break;
default: ;
}
Expand Down Expand Up @@ -962,7 +964,7 @@ int32 intro_screen()
ik_dsprite(screen, bx+16, by+y-5, spr_IFbutton->spr[globalsettings.opt_fullscreen], 2+(MAIN_INTERFACE_COLOR<<8));

y+=16;
ik_print(screen, font_6x8, bx+32, by+y, MAIN_INTERFACE_COLOR, "LIMIT TO WHOLE MULTIPLE SCALING");
ik_print(screen, font_6x8, bx+32, by+y, MAIN_INTERFACE_COLOR, "PIXEL PERFECT SCALING");
ik_dsprite(screen, bx+16, by+y-5, spr_IFbutton->spr[globalsettings.opt_whole_multiple_rescale_ratio], 2 + (MAIN_INTERFACE_COLOR << 8));

y+=16;
Expand Down
67 changes: 54 additions & 13 deletions src/sdl_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,54 @@ int sound_init();
extern SDL_Window *sdlWind;
extern SDL_Surface *sdlsurf;
SDL_Surface *blitIntermedSurf = nullptr;

SDL_Renderer *sdlRend = nullptr;
SDL_Texture *sdlWindTexture = nullptr;
// directory paths for our core.

std::string fsBaseDir;
std::string fsPreferencesDir;

static int8 isPixelPerfect = -1;
static int8 isFullscreen = -1;

int
vid_reset_settings() {
if (sdlWind != nullptr) {
if (globalsettings.opt_fullscreen) {
SDL_SetWindowFullscreen(sdlWind, SDL_WINDOW_FULLSCREEN_DESKTOP);
} else {
SDL_SetWindowFullscreen(sdlWind, SDL_WINDOW_RESIZABLE);
SDL_SetWindowSize(sdlWind, 640, 480);
SDL_SetWindowMinimumSize(sdlWind, 640, 480);
sdl_screen_scale = 1.0;
sdl_x_offset = 0;
sdl_y_offset = 0;
if (isFullscreen != globalsettings.opt_fullscreen) {
isFullscreen = globalsettings.opt_fullscreen;
if (isFullscreen) {
SDL_SetWindowFullscreen(sdlWind, SDL_WINDOW_FULLSCREEN_DESKTOP);
} else {
SDL_SetWindowFullscreen(sdlWind, SDL_WINDOW_RESIZABLE);
SDL_SetWindowSize(sdlWind, 640, 480);
SDL_SetWindowMinimumSize(sdlWind, 640, 480);
sdl_screen_scale = 1.0;
sdl_x_offset = 0;
sdl_y_offset = 0;
}
}
if (sdlRend != nullptr) {
if (globalsettings.opt_whole_multiple_rescale_ratio != isPixelPerfect
|| sdlWindTexture == nullptr) {
isPixelPerfect = globalsettings.opt_whole_multiple_rescale_ratio;
if (isPixelPerfect) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
} else {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
}
if (sdlWindTexture != nullptr) {
SDL_DestroyTexture(sdlWindTexture);
sdlWindTexture = nullptr;
}
// and create the streaming texture.
sdlWindTexture = SDL_CreateTexture(sdlRend, blitIntermedSurf->format->format,
SDL_TEXTUREACCESS_STREAMING, 640, 480);
if (sdlWindTexture == nullptr) {
SDL_Log("Failed to create intermediate window texture (for fullscreen scaling): %s",
SDL_GetError());
return 1;
}
}
}
}
return 0;
Expand Down Expand Up @@ -141,7 +171,7 @@ int main(int argc, char *argv[]) {
sound_init();

// create the application window
int sdlFlags = SDL_WINDOW_RESIZABLE;
int sdlFlags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
if (globalsettings.opt_fullscreen) {
sdlFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
}
Expand All @@ -157,6 +187,14 @@ int main(int argc, char *argv[]) {
}
SDL_SetWindowMinimumSize(sdlWind, 640, 480);


// create the SDL Renderer we use to stream from the intermed blitting surface to the window.
sdlRend = SDL_CreateRenderer(sdlWind, -1, SDL_RENDERER_ACCELERATED);
if (sdlRend == nullptr) {
SDL_Log("Failed to create SDL Renderer: %s", SDL_GetError());
return 1;
}

// create the i8 surface
sdlsurf = SDL_CreateRGBSurfaceWithFormat(0, 640, 480, 8, SDL_PIXELFORMAT_INDEX8);
if (sdlsurf == nullptr) {
Expand All @@ -165,8 +203,11 @@ int main(int argc, char *argv[]) {
}

// create the intermediate blitting surface (needed for fullscreen support)
auto *realSurf = SDL_GetWindowSurface(sdlWind);
blitIntermedSurf = SDL_ConvertSurface(sdlsurf, realSurf->format, 0);
blitIntermedSurf = SDL_CreateRGBSurfaceWithFormat(0, 640, 480, 32, SDL_PIXELFORMAT_RGBA8888);

// make sure our video state matches what we think it should be. This also
// creates the SDL_Texture we use to do the screen copy.
vid_reset_settings();

my_main();
return 0;
Expand Down
115 changes: 69 additions & 46 deletions src/w32_gfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ All DIRECTDRAW stuff here
extern SDL_Window *sdlWind;
extern SDL_Surface *sdlsurf;
extern SDL_Surface *blitIntermedSurf;
extern SDL_Renderer *sdlRend;
extern SDL_Texture *sdlWindTexture;

#ifdef MOVIE
int when = 0;
Expand All @@ -53,57 +55,78 @@ int sdl_y_offset = 0;
float sdl_screen_scale = 1.0f;

void gfx_refresh_screen() {
auto *realsurf = SDL_GetWindowSurface(sdlWind);

// calculate scale factor.
if (realsurf->w != sdlsurf->w || realsurf->h != sdlsurf->h) {
if (globalsettings.opt_whole_multiple_rescale_ratio) {
// for pixel perfect scaling, use integer ratios only.
int yrat = realsurf->h / sdlsurf->h;
int xrat = realsurf->w / sdlsurf->w;
sdl_screen_scale = static_cast<float>(std::min<int>(xrat, yrat));
if (sdl_screen_scale < 1) {
sdl_screen_scale = 1;
}
} else {
float yrat = static_cast<float>(realsurf->h) / static_cast<float>(sdlsurf->h);
float xrat = static_cast<float>(realsurf->w) / static_cast<float>(sdlsurf->w);
sdl_screen_scale = std::min<float>(xrat, yrat);
}

int targetXSize = static_cast<int>(sdlsurf->w * sdl_screen_scale);
int targetYSize = static_cast<int>(sdlsurf->h * sdl_screen_scale);
sdl_x_offset = (realsurf->w - targetXSize) / 2;
sdl_y_offset = (realsurf->h - targetYSize) / 2;

SDL_Rect destRect{
sdl_x_offset,
sdl_y_offset,
targetXSize,
targetYSize,
};
// clear the surface first.
SDL_FillRect(realsurf, nullptr, 0);
// convert the surface.
if (SDL_BlitSurface(sdlsurf, nullptr, blitIntermedSurf, nullptr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Blit to correct format failed: %s", SDL_GetError());
abort();
}
// now blit in the scaled window
if (SDL_BlitScaled(blitIntermedSurf, nullptr, realsurf, &destRect)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "BlitScaled failed: %s", SDL_GetError());
abort();
int outw,outh,inw,inh,render_offx,render_offy;
float render_scale = 1.0f;
SDL_GetWindowSize(sdlWind, &inw, &inh);
SDL_GetRendererOutputSize(sdlRend, &outw, &outh);

// calculate scale factor. This is based on output sizes.
if (globalsettings.opt_whole_multiple_rescale_ratio) {
// for pixel perfect scaling, use integer ratios only.
int yrat = outh / sdlsurf->h;
int xrat = outw / sdlsurf->w;
render_scale = static_cast<float>(std::min<int>(xrat, yrat));
if (render_scale < 1) {
render_scale = 1;
}
} else {
if (SDL_BlitSurface(sdlsurf, nullptr, realsurf, nullptr)) {
SDL_Log("Blit Failed?: %s", SDL_GetError());
abort();
}
float yrat = static_cast<float>(outh) / static_cast<float>(sdlsurf->h);
float xrat = static_cast<float>(outw) / static_cast<float>(sdlsurf->w);
render_scale = std::min<float>(xrat, yrat);
}
if (SDL_UpdateWindowSurface(sdlWind)) {
SDL_Log("Update Surface Failed: %s", SDL_GetError());

// damnit SDL! When we're on a HighDPI device, we have to work in two separate scales.
//
// Input is always in logical pixels, whereas output is in actual display pixels.
//
// this means we need to calculate our ratios twice - once to position the actual output rect
// and the second time to get the equivalent input transform information.

sdl_screen_scale = render_scale * static_cast<float>(inw) / static_cast<float>(outw);

int targetXSize = static_cast<int>(sdlsurf->w * sdl_screen_scale);
int targetYSize = static_cast<int>(sdlsurf->h * sdl_screen_scale);
sdl_x_offset = (inw - targetXSize) / 2;
sdl_y_offset = (inh - targetYSize) / 2;

targetXSize = static_cast<int>(sdlsurf->w * render_scale);
targetYSize = static_cast<int>(sdlsurf->h * render_scale);
render_offx = (outw - targetXSize) / 2;
render_offy = (outh - targetYSize) / 2;


SDL_Rect destRect{
render_offx,
render_offy,
targetXSize,
targetYSize,
};
// clear the surface first.
SDL_RenderClear(sdlRend);

// now, blit the 8I surface to the RGBA32 surface
if (SDL_BlitSurface(sdlsurf, nullptr, blitIntermedSurf, nullptr)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Blit to correct format failed: %s", SDL_GetError());
abort();
}

// now, copy the surface data to the texture.
char *TexPixelData = nullptr; int pitch = 0;
if (!SDL_LockTexture(sdlWindTexture, nullptr, reinterpret_cast<void**>(&TexPixelData), &pitch)) {
SDL_LockSurface(blitIntermedSurf);
const int lineLength = blitIntermedSurf->format->BytesPerPixel * blitIntermedSurf->w;
for (int y = 0; y < blitIntermedSurf->h; y++) {
const int lOffset = pitch * y;
const int sOffset = blitIntermedSurf->pitch * y;
memcpy(TexPixelData + lOffset, reinterpret_cast<char *>(blitIntermedSurf->pixels) + sOffset, lineLength);
}
SDL_UnlockSurface(blitIntermedSurf);
SDL_UnlockTexture(sdlWindTexture);
}

// and blat the texture onto the screen.
SDL_RenderCopy(sdlRend, sdlWindTexture, nullptr, &destRect);
SDL_RenderPresent(sdlRend);
}

// blit screen
Expand Down

0 comments on commit 096898f

Please sign in to comment.