diff --git a/CMakeLists.txt b/CMakeLists.txt index 41fa9fbf..aa19d1f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,11 @@ if(NIGHTLY_BUILD OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") set(CPACK ON) endif() +if(USE_SDL1) + list(APPEND VCPKG_MANIFEST_FEATURES "sdl1") +else() + list(APPEND VCPKG_MANIFEST_FEATURES "sdl2") +endif() if(PACKET_ENCRYPTION) list(APPEND VCPKG_MANIFEST_FEATURES "encryption") endif() diff --git a/Source/control.cpp b/Source/control.cpp index 737ba737..5c588405 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -379,7 +379,7 @@ void PrintSBookHotkey(const Surface &out, Point position, const std::string &tex */ void DrawFlaskTop(const Surface &out, Point position, const Surface &celBuf, int y0, int y1) { - out.BlitFrom(celBuf, SDL_Rect { 0, static_cast(y0), celBuf.w(), y1 - y0 }, position); + out.BlitFrom(celBuf, MakeSdlRect(0, static_cast(y0), celBuf.w(), y1 - y0), position); } /** @@ -436,7 +436,7 @@ void DrawFlaskLower(const Surface &out, const Surface &sourceBuffer, int offset, // It appears that the panel defaults to having a filled flask and DrawFlaskTop only overlays the appropriate amount of empty space. // This draw might not be necessary? if (filled > 0) - DrawPanelBox(out, { offset, 85 - filled, 88, filled }, { PANEL_X + offset, PANEL_Y + 69 - filled }); + DrawPanelBox(out, MakeSdlRect(offset, 85 - filled, 88, filled), { PANEL_X + offset, PANEL_Y + 69 - filled }); } void SetButtonStateDown(int btnId) @@ -1037,7 +1037,7 @@ void InitControlPan() void DrawCtrlPan(const Surface &out) { - DrawPanelBox(out, { 0, sgbPlrTalkTbl + 16, PANEL_WIDTH, PANEL_HEIGHT }, { PANEL_X, PANEL_Y }); + DrawPanelBox(out, MakeSdlRect(0, sgbPlrTalkTbl + 16, PANEL_WIDTH, PANEL_HEIGHT), { PANEL_X, PANEL_Y }); DrawInfoBox(out); } @@ -1045,7 +1045,7 @@ void DrawCtrlBtns(const Surface &out) { for (int i = 0; i < 6; i++) { if (!PanelButtons[i]) { - DrawPanelBox(out, { PanBtnPos[i].x, PanBtnPos[i].y + 16, 71, 20 }, { PanBtnPos[i].x + PANEL_X, PanBtnPos[i].y + PANEL_Y }); + DrawPanelBox(out, MakeSdlRect(PanBtnPos[i].x, PanBtnPos[i].y + 16, 71, 20), { PanBtnPos[i].x + PANEL_X, PanBtnPos[i].y + PANEL_Y }); } else { Point position { PanBtnPos[i].x + PANEL_X, PanBtnPos[i].y + PANEL_Y + 18 }; CelDrawTo(out, position, *pPanelButtons, i + 1); @@ -1696,17 +1696,17 @@ void DrawTalkPan(const Surface &out) force_redraw = 255; - DrawPanelBox(out, { 175, sgbPlrTalkTbl + 20, 294, 5 }, { PANEL_X + 175, PANEL_Y + 4 }); + DrawPanelBox(out, MakeSdlRect(175, sgbPlrTalkTbl + 20, 294, 5), { PANEL_X + 175, PANEL_Y + 4 }); int off = 0; for (int i = 293; i > 283; off++, i--) { - DrawPanelBox(out, { (off / 2) + 175, sgbPlrTalkTbl + off + 25, i, 1 }, { (off / 2) + PANEL_X + 175, off + PANEL_Y + 9 }); + DrawPanelBox(out, MakeSdlRect((off / 2) + 175, sgbPlrTalkTbl + off + 25, i, 1), { (off / 2) + PANEL_X + 175, off + PANEL_Y + 9 }); } - DrawPanelBox(out, { 185, sgbPlrTalkTbl + 35, 274, 30 }, { PANEL_X + 185, PANEL_Y + 19 }); - DrawPanelBox(out, { 180, sgbPlrTalkTbl + 65, 284, 5 }, { PANEL_X + 180, PANEL_Y + 49 }); + DrawPanelBox(out, MakeSdlRect(185, sgbPlrTalkTbl + 35, 274, 30), { PANEL_X + 185, PANEL_Y + 19 }); + DrawPanelBox(out, MakeSdlRect(180, sgbPlrTalkTbl + 65, 284, 5), { PANEL_X + 180, PANEL_Y + 49 }); for (int i = 0; i < 10; i++) { - DrawPanelBox(out, { 180, sgbPlrTalkTbl + i + 70, i + 284, 1 }, { PANEL_X + 180, i + PANEL_Y + 54 }); + DrawPanelBox(out, MakeSdlRect(180, sgbPlrTalkTbl + i + 70, i + 284, 1), { PANEL_X + 180, i + PANEL_Y + 54 }); } - DrawPanelBox(out, { 170, sgbPlrTalkTbl + 80, 310, 55 }, { PANEL_X + 170, PANEL_Y + 64 }); + DrawPanelBox(out, MakeSdlRect(170, sgbPlrTalkTbl + 80, 310, 55), { PANEL_X + 170, PANEL_Y + 64 }); int x = PANEL_LEFT + 200; int y = PANEL_Y + 10; diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index 496c2eb3..e7fc2564 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -132,7 +132,7 @@ bool SpawnWindow(const char *lpWindowName) SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); #endif -#ifdef _WIN32 +#if defined(_WIN32) && !defined(USE_SDL1) // The default WASAPI backend causes distortions // https://github.com/diasurgical/devilutionX/issues/1434 SDL_setenv("SDL_AUDIODRIVER", "winmm", /*overwrite=*/false); diff --git a/Source/utils/sdl2_to_1_2_backports.cpp b/Source/utils/sdl2_to_1_2_backports.cpp index b723f811..832acbbc 100644 --- a/Source/utils/sdl2_to_1_2_backports.cpp +++ b/Source/utils/sdl2_to_1_2_backports.cpp @@ -5,6 +5,14 @@ #include "./console.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX 1 +#define UNICODE 1 +#include +#include +#endif + #define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL #define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN #define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO @@ -477,6 +485,216 @@ int SDL_BlitScaled(SDL_Surface *src, SDL_Rect *srcrect, // = Filesystem +Sint64 SDL_RWsize(SDL_RWops *context) +{ + const int current = SDL_RWtell(context); + if (current == -1) + return -1; + + const int begin = SDL_RWseek(context, 0, RW_SEEK_SET); + if (begin == -1) + return -1; + + const int end = SDL_RWseek(context, 0, RW_SEEK_END); + if (end == -1) + return -1; + + if (SDL_RWseek(context, current, RW_SEEK_SET) == -1) + return -1; + + return end - begin; +} + +#ifdef _WIN32 + +namespace { + +// From sdl2-2.0.9/src/core/windows/SDL_windows.h +#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (wcslen(S) + 1) * sizeof(WCHAR)) +#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (char *)(S), SDL_strlen(S) + 1) + +/* Sets an error message based on an HRESULT */ +int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr) +{ + // From sdl2-2.0.9/src/core/windows/SDL_windows.c + + TCHAR buffer[1024]; + char *message; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, + buffer, SDL_arraysize(buffer), NULL); + message = WIN_StringToUTF8(buffer); + SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message); + SDL_free(message); + return -1; +} + +/* Sets an error message based on GetLastError() */ +int WIN_SetError(const char *prefix) +{ + // From sdl2-2.0.9/src/core/windows/SDL_windows.c + + return WIN_SetErrorFromHRESULT(prefix, GetLastError()); +} + +} // namespace + +char *SDL_GetBasePath(void) +{ + // From sdl2-2.0.9/src/filesystem/windows/SDL_sysfilesystem.c + + typedef DWORD(WINAPI * GetModuleFileNameExW_t)(HANDLE, HMODULE, LPWSTR, DWORD); + GetModuleFileNameExW_t pGetModuleFileNameExW; + DWORD buflen = 128; + WCHAR *path = NULL; + HMODULE psapi = LoadLibrary(L"psapi.dll"); + char *retval = NULL; + DWORD len = 0; + int i; + + if (!psapi) { + WIN_SetError("Couldn't load psapi.dll"); + return NULL; + } + + pGetModuleFileNameExW = (GetModuleFileNameExW_t)GetProcAddress(psapi, "GetModuleFileNameExW"); + if (!pGetModuleFileNameExW) { + WIN_SetError("Couldn't find GetModuleFileNameExW"); + FreeLibrary(psapi); + return NULL; + } + + while (SDL_TRUE) { + void *ptr = SDL_realloc(path, buflen * sizeof(WCHAR)); + if (!ptr) { + SDL_free(path); + FreeLibrary(psapi); + SDL_OutOfMemory(); + return NULL; + } + + path = (WCHAR *)ptr; + + len = pGetModuleFileNameExW(GetCurrentProcess(), NULL, path, buflen); + if (len != buflen) { + break; + } + + /* buffer too small? Try again. */ + buflen *= 2; + } + + FreeLibrary(psapi); + + if (len == 0) { + SDL_free(path); + WIN_SetError("Couldn't locate our .exe"); + return NULL; + } + + for (i = len - 1; i > 0; i--) { + if (path[i] == '\\') { + break; + } + } + + path[i + 1] = '\0'; /* chop off filename. */ + + retval = WIN_StringToUTF8(path); + SDL_free(path); + + return retval; +} + +char *SDL_GetPrefPath(const char *org, const char *app) +{ + // From sdl2-2.0.9/src/filesystem/windows/SDL_sysfilesystem.c + + /* + * Vista and later has a new API for this, but SHGetFolderPath works there, + * and apparently just wraps the new API. This is the new way to do it: + * + * SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, + * NULL, &wszPath); + */ + + WCHAR path[MAX_PATH]; + char *retval = NULL; + WCHAR *worg = NULL; + WCHAR *wapp = NULL; + size_t new_wpath_len = 0; + BOOL api_result = FALSE; + + if (!app) { + SDL_InvalidParamError("app"); + return NULL; + } + if (!org) { + org = ""; + } + + if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path))) { + WIN_SetError("Couldn't locate our prefpath"); + return NULL; + } + + worg = WIN_UTF8ToString(org); + if (worg == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + wapp = WIN_UTF8ToString(app); + if (wapp == NULL) { + SDL_free(worg); + SDL_OutOfMemory(); + return NULL; + } + + new_wpath_len = lstrlenW(worg) + lstrlenW(wapp) + lstrlenW(path) + 3; + + if ((new_wpath_len + 1) > MAX_PATH) { + SDL_free(worg); + SDL_free(wapp); + WIN_SetError("Path too long."); + return NULL; + } + + if (*worg) { + lstrcatW(path, L"\\"); + lstrcatW(path, worg); + } + SDL_free(worg); + + api_result = CreateDirectoryW(path, NULL); + if (api_result == FALSE) { + if (GetLastError() != ERROR_ALREADY_EXISTS) { + SDL_free(wapp); + WIN_SetError("Couldn't create a prefpath."); + return NULL; + } + } + + lstrcatW(path, L"\\"); + lstrcatW(path, wapp); + SDL_free(wapp); + + api_result = CreateDirectoryW(path, NULL); + if (api_result == FALSE) { + if (GetLastError() != ERROR_ALREADY_EXISTS) { + WIN_SetError("Couldn't create a prefpath."); + return NULL; + } + } + + lstrcatW(path, L"\\"); + + retval = WIN_StringToUTF8(path); + + return retval; +} + +#else + namespace { #if !defined(__QNXNTO__) char *readSymLink(const char *path) @@ -512,26 +730,6 @@ char *readSymLink(const char *path) #endif } // namespace -Sint64 SDL_RWsize(SDL_RWops *context) -{ - const int current = SDL_RWtell(context); - if (current == -1) - return -1; - - const int begin = SDL_RWseek(context, 0, RW_SEEK_SET); - if (begin == -1) - return -1; - - const int end = SDL_RWseek(context, 0, RW_SEEK_END); - if (end == -1) - return -1; - - if (SDL_RWseek(context, current, RW_SEEK_SET) == -1) - return -1; - - return end - begin; -} - char *SDL_GetBasePath() { // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c @@ -719,3 +917,5 @@ char *SDL_GetPrefPath(const char *org, const char *app) return retval; } + +#endif diff --git a/Source/utils/sdl2_to_1_2_backports.h b/Source/utils/sdl2_to_1_2_backports.h index c5cec1f2..1552939a 100644 --- a/Source/utils/sdl2_to_1_2_backports.h +++ b/Source/utils/sdl2_to_1_2_backports.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -12,6 +11,10 @@ #include "utils/attributes.h" #include "utils/console.h" +#ifndef _WIN32 +#include +#endif + #define WINDOW_ICON_NAME 0 //== Utility diff --git a/vcpkg.json b/vcpkg.json index 924901d5..09cb6263 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,11 +2,17 @@ "name": "devilutionx", "version-string": "1.2.1", "dependencies": [ - "fmt", - "sdl2", - "sdl2-image" + "fmt" ], "features": { + "sdl1": { + "description": "Use SDL1.2 instead of SDL2", + "dependencies": [ "sdl1", "libpng" ] + }, + "sdl2": { + "description": "Use SDL2", + "dependencies": [ "sdl2", "sdl2-image" ] + }, "encryption": { "description": "Build libsodium for packet encryption", "dependencies": [ "libsodium" ]