From 4e51e02924e2c2c183445f6f540856b3365c1c01 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 4 Jan 2023 17:15:32 -0800 Subject: [PATCH] move SDL shims to a new DFSDL module --- library/CMakeLists.txt | 2 + library/Core.cpp | 7 ++ library/include/modules/DFSDL.h | 92 ++++++++++++++++++++++ library/include/modules/Graphic.h | 54 +------------ library/include/modules/Textures.h | 1 - library/modules/DFSDL.cpp | 120 +++++++++++++++++++++++++++++ library/modules/Textures.cpp | 82 +++----------------- 7 files changed, 233 insertions(+), 125 deletions(-) create mode 100644 library/include/modules/DFSDL.h create mode 100644 library/modules/DFSDL.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 0edf10c0b..87f869493 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -124,6 +124,7 @@ set(MODULE_HEADERS include/modules/Buildings.h include/modules/Burrows.h include/modules/Constructions.h + include/modules/DFSDL.h include/modules/Designations.h include/modules/EventManager.h include/modules/Filesystem.h @@ -151,6 +152,7 @@ set(MODULE_SOURCES modules/Buildings.cpp modules/Burrows.cpp modules/Constructions.cpp + modules/DFSDL.cpp modules/Designations.cpp modules/EventManager.cpp modules/Filesystem.cpp diff --git a/library/Core.cpp b/library/Core.cpp index 69e033c02..a3979ee2f 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -49,6 +49,7 @@ using namespace std; #include "VersionInfo.h" #include "PluginManager.h" #include "ModuleFactory.h" +#include "modules/DFSDL.h" #include "modules/EventManager.h" #include "modules/Filesystem.h" #include "modules/Gui.h" @@ -1671,6 +1672,11 @@ bool Core::Init() return false; } + cerr << "Binding to SDL.\n"; + if (!DFSDL::init(con)) { + fatal("cannot bind SDL libraries"); + return false; + } cerr << "Initializing textures.\n"; Textures::init(con); // create mutex for syncing with interactive tasks @@ -2258,6 +2264,7 @@ int Core::Shutdown ( void ) // invalidate all modules allModules.clear(); Textures::cleanup(); + DFSDL::cleanup(); memset(&(s_mods), 0, sizeof(s_mods)); d.reset(); return -1; diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h new file mode 100644 index 000000000..b5fd119f7 --- /dev/null +++ b/library/include/modules/DFSDL.h @@ -0,0 +1,92 @@ +#pragma once + +#include "Export.h" +#include "ColorText.h" + +namespace DFHack +{ + // SDL stand-in type definitions + typedef signed short SINT16; + typedef void DFSDL_sem; + + typedef struct + { + int16_t x, y; + uint16_t w, h; + } DFSDL_Rect; + typedef struct + { + void *palette; // SDL_Palette* + uint8_t BitsPerPixel; + uint8_t BytesPerPixel; + uint8_t Rloss; + uint8_t Gloss; + uint8_t Bloss; + uint8_t Aloss; + uint8_t Rshift; + uint8_t Gshift; + uint8_t Bshift; + uint8_t Ashift; + uint32_t Rmask; + uint32_t Gmask; + uint32_t Bmask; + uint32_t Amask; + uint32_t colorkey; + uint8_t alpha; + } DFSDL_PixelFormat; + typedef struct + { + uint32_t flags; + DFSDL_PixelFormat* format; + int w, h; + int pitch; + void* pixels; + void* userdata; // as far as i could see DF doesnt use this + int locked; + void* lock_data; + DFSDL_Rect clip_rect; + void* map; + int refcount; + } DFSDL_Surface; + + // ========= + struct DFTileSurface + { + bool paintOver; // draw over original tile? + DFSDL_Surface* surface; // from where it should be drawn + DFSDL_Rect* rect; // from which coords (NULL to draw whole surface) + DFSDL_Rect* dstResize; // if not NULL dst rect will be resized (x/y/w/h will be added to original dst) + }; + +/** + * The DFSDL module - provides access to SDL functions without actually + * requiring build-time linkage to SDL + * \ingroup grp_modules + * \ingroup grp_dfsdl + */ +namespace DFSDL +{ + +/** + * Call this on DFHack init so we can load the SDL functions. Returns false on + * failure. + */ +bool init(DFHack::color_ostream &out); + +/** + * Call this when DFHack is being unloaded. + */ +void cleanup(); + +DFHACK_EXPORT DFSDL_Surface * DFIMG_Load(const char *file); +DFHACK_EXPORT int DFSDL_SetAlpha(DFSDL_Surface *surface, uint32_t flag, uint8_t alpha); +DFHACK_EXPORT DFSDL_Surface * DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); +DFHACK_EXPORT int DFSDL_UpperBlit(DFSDL_Surface *src, const DFSDL_Rect *srcrect, DFSDL_Surface *dst, DFSDL_Rect *dstrect); +DFHACK_EXPORT DFSDL_Surface * DFSDL_ConvertSurface(DFSDL_Surface *src, const DFSDL_PixelFormat *fmt, uint32_t flags); +DFHACK_EXPORT void DFSDL_FreeSurface(DFSDL_Surface *surface); +DFHACK_EXPORT int DFSDL_SemWait(DFSDL_sem *sem); +DFHACK_EXPORT int DFSDL_SemPost(DFSDL_sem *sem); + +} + +} diff --git a/library/include/modules/Graphic.h b/library/include/modules/Graphic.h index ba5bf98c3..22a5d4913 100644 --- a/library/include/modules/Graphic.h +++ b/library/include/modules/Graphic.h @@ -33,62 +33,11 @@ distribution. #include #include "Export.h" #include "Module.h" +#include "DFSDL.h" #include namespace DFHack { - // SDL stuff - typedef signed short SINT16; - typedef struct - { - int16_t x, y; - uint16_t w, h; - } DFSDL_Rect; - typedef struct - { - void *palette; // SDL_Palette* - uint8_t BitsPerPixel; - uint8_t BytesPerPixel; - uint8_t Rloss; - uint8_t Gloss; - uint8_t Bloss; - uint8_t Aloss; - uint8_t Rshift; - uint8_t Gshift; - uint8_t Bshift; - uint8_t Ashift; - uint32_t Rmask; - uint32_t Gmask; - uint32_t Bmask; - uint32_t Amask; - uint32_t colorkey; - uint8_t alpha; - } DFSDL_PixelFormat; - typedef struct - { - uint32_t flags; - DFSDL_PixelFormat* format; - int w, h; - int pitch; - void* pixels; - void* userdata; // as far as i could see DF doesnt use this - int locked; - void* lock_data; - DFSDL_Rect clip_rect; - void* map; - int refcount; - } DFSDL_Surface; - - // ========= - struct DFTileSurface - { - bool paintOver; // draw over original tile? - DFSDL_Surface* surface; // from where it should be drawn - DFSDL_Rect* rect; // from which coords (NULL to draw whole surface) - DFSDL_Rect* dstResize; // if not NULL dst rect will be resized (x/y/w/h will be added to original dst) - }; - - class DFHACK_EXPORT Graphic : public Module { public: @@ -103,7 +52,6 @@ namespace DFHack private: std::vector funcs; }; - } #endif diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 390bbeed6..2ef172bff 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,7 +1,6 @@ #pragma once #include "Export.h" - #include "ColorText.h" namespace DFHack { diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp new file mode 100644 index 000000000..a7847fdb5 --- /dev/null +++ b/library/modules/DFSDL.cpp @@ -0,0 +1,120 @@ +#include "Internal.h" + +#include "modules/DFSDL.h" + +#include "Debug.h" +#include "PluginManager.h" + +namespace DFHack { + DBG_DECLARE(core, dfsdl, DebugCategory::LINFO); +} + +using namespace DFHack; + +static DFLibrary *g_sdl_handle = nullptr; +static DFLibrary *g_sdl_image_handle = nullptr; +static const std::vector SDL_LIBS { + "SDLreal.dll", // TODO: change to SDL.dll once we move to dfhooks + "SDL.framework/Versions/A/SDL", + "SDL.framework/SDL", + "libSDL-1.2.so.0" +}; +static const std::vector SDL_IMAGE_LIBS { + "SDL_image.dll", + "SDL_image.framework/Versions/A/SDL_image", + "SDL_image.framework/SDL_image", + "libSDL_image-1.2.so.0" +}; + +DFSDL_Surface * (*g_IMG_Load)(const char *) = nullptr; +int (*g_SDL_SetAlpha)(DFSDL_Surface *, uint32_t, uint8_t) = nullptr; +DFSDL_Surface * (*g_SDL_CreateRGBSurface)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t); +int (*g_SDL_UpperBlit)(DFSDL_Surface *, const DFSDL_Rect *, DFSDL_Surface *, DFSDL_Rect *); +DFSDL_Surface * (*g_SDL_ConvertSurface)(DFSDL_Surface *, const DFSDL_PixelFormat *, uint32_t); +void (*g_SDL_FreeSurface)(DFSDL_Surface *); +int (*g_SDL_SemWait)(DFSDL_sem *); +int (*g_SDL_SemPost)(DFSDL_sem *); + +bool DFSDL::init(color_ostream &out) { + for (auto &lib_str : SDL_LIBS) { + if ((g_sdl_handle = OpenPlugin(lib_str.c_str()))) + break; + } + if (!g_sdl_handle) { + out.printerr("DFHack could not find SDL\n"); + return false; + } + + for (auto &lib_str : SDL_IMAGE_LIBS) { + if ((g_sdl_image_handle = OpenPlugin(lib_str.c_str()))) + break; + } + if (!g_sdl_image_handle) { + out.printerr("DFHack could not find SDL_image\n"); + return false; + } + + #define bind(handle, name) \ + g_##name = (decltype(g_##name))LookupPlugin(handle, #name); \ + if (!g_##name) { \ + out.printerr("DFHack could not find: " #name "\n"); \ + return false; \ + } + + bind(g_sdl_image_handle, IMG_Load); + bind(g_sdl_handle, SDL_SetAlpha); + bind(g_sdl_handle, SDL_CreateRGBSurface); + bind(g_sdl_handle, SDL_UpperBlit); + bind(g_sdl_handle, SDL_ConvertSurface); + bind(g_sdl_handle, SDL_FreeSurface); + bind(g_sdl_handle, SDL_SemWait); + bind(g_sdl_handle, SDL_SemPost); + #undef bind + + DEBUG(dfsdl,out).print("sdl successfully loaded\n"); + return true; +} + +// It's ok to leave NULLs in the raws list (according to usage in g_src) +void DFSDL::cleanup() { + if (g_sdl_handle) { + ClosePlugin(g_sdl_handle); + g_sdl_handle = nullptr; + } + if (g_sdl_image_handle) { + ClosePlugin(g_sdl_image_handle); + g_sdl_image_handle = nullptr; + } +} + +DFSDL_Surface * DFSDL::DFIMG_Load(const char *file) { + return g_IMG_Load(file); +} + +int DFSDL::DFSDL_SetAlpha(DFSDL_Surface *surface, uint32_t flag, uint8_t alpha) { + return g_SDL_SetAlpha(surface, flag, alpha); +} + +DFSDL_Surface * DFSDL::DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) { + return g_SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask); +} + +int DFSDL::DFSDL_UpperBlit(DFSDL_Surface *src, const DFSDL_Rect *srcrect, DFSDL_Surface *dst, DFSDL_Rect *dstrect) { + return g_SDL_UpperBlit(src, srcrect, dst, dstrect); +} + +DFSDL_Surface * DFSDL::DFSDL_ConvertSurface(DFSDL_Surface *src, const DFSDL_PixelFormat *fmt, uint32_t flags) { + return g_SDL_ConvertSurface(src, fmt, flags); +} + +void DFSDL::DFSDL_FreeSurface(DFSDL_Surface *surface) { + g_SDL_FreeSurface(surface); +} + +int DFSDL::DFSDL_SemWait(DFSDL_sem *sem) { + return g_SDL_SemWait(sem); +} + +int DFSDL::DFSDL_SemPost(DFSDL_sem *sem) { + return g_SDL_SemPost(sem); +} diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index efbd1cdf4..32ed6453c 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,5 +1,6 @@ #include "Internal.h" +#include "modules/DFSDL.h" #include "modules/Textures.h" #include "Debug.h" @@ -9,6 +10,7 @@ using df::global::enabler; using namespace DFHack; +using namespace DFHack::DFSDL; namespace DFHack { DBG_DECLARE(core, textures, DebugCategory::LINFO); @@ -18,29 +20,6 @@ static bool g_loaded = false; static long g_num_dfhack_textures = 0; static long g_dfhack_logo_texpos_start = -1; -static DFLibrary *g_sdl_handle = nullptr; -static DFLibrary *g_sdl_image_handle = nullptr; -static const std::vector SDL_LIBS { - "SDLreal.dll", - "SDL.framework/Versions/A/SDL", - "SDL.framework/SDL", - "libSDL-1.2.so.0" -}; -static const std::vector SDL_IMAGE_LIBS { - "SDL_image.dll", - "SDL_image.framework/Versions/A/SDL_image", - "SDL_image.framework/SDL_image", - "libSDL_image-1.2.so.0" -}; - -DFSDL_Surface * (*g_IMG_Load)(const char *) = nullptr; -int (*g_SDL_SetAlpha)(DFSDL_Surface *, uint32_t, uint8_t) = nullptr; -DFSDL_Surface * (*g_SDL_CreateRGBSurface)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t); -int (*g_SDL_UpperBlit)(DFSDL_Surface *, DFSDL_Rect *, DFSDL_Surface *, DFSDL_Rect *); -DFSDL_Surface * (*g_SDL_ConvertSurface)(DFSDL_Surface *, const DFSDL_PixelFormat *, uint32_t); - -void (*g_SDL_FreeSurface)(DFSDL_Surface *); - // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -66,8 +45,8 @@ DFSDL_Surface * canonicalize_format(DFSDL_Surface *src) { fmt.colorkey = 0; fmt.alpha = 255; - DFSDL_Surface *tgt = g_SDL_ConvertSurface(src, &fmt, 0); // SDL_SWSURFACE - g_SDL_FreeSurface(src); + DFSDL_Surface *tgt = DFSDL_ConvertSurface(src, &fmt, 0); // SDL_SWSURFACE + DFSDL_FreeSurface(src); return tgt; } @@ -76,41 +55,36 @@ const uint32_t TILE_HEIGHT_PX = 12; static size_t load_textures(color_ostream & out, const char * fname, long *texpos_start) { - if (!g_sdl_handle || !g_sdl_image_handle || !g_IMG_Load || !g_SDL_SetAlpha - || !g_SDL_CreateRGBSurface || !g_SDL_UpperBlit - || !g_SDL_ConvertSurface || !g_SDL_FreeSurface) - return 0; - - DFSDL_Surface *s = g_IMG_Load(fname); + DFSDL_Surface *s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); return 0; } s = canonicalize_format(s); - g_SDL_SetAlpha(s, 0, 255); + DFSDL_SetAlpha(s, 0, 255); int dimx = s->w / TILE_WIDTH_PX; int dimy = s->h / TILE_HEIGHT_PX; long count = 0; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { - DFSDL_Surface *tile = g_SDL_CreateRGBSurface(0, // SDL_SWSURFACE + DFSDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE TILE_WIDTH_PX, TILE_HEIGHT_PX, 32, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask); - g_SDL_SetAlpha(tile, 0,255); + DFSDL_SetAlpha(tile, 0,255); DFSDL_Rect vp; vp.x = TILE_WIDTH_PX * x; vp.y = TILE_HEIGHT_PX * y; vp.w = TILE_WIDTH_PX; vp.h = TILE_HEIGHT_PX; - g_SDL_UpperBlit(s, &vp, tile, NULL); + DFSDL_UpperBlit(s, &vp, tile, NULL); if (!count++) *texpos_start = enabler->textures.raws.size(); enabler->textures.raws.push_back(tile); } } - g_SDL_FreeSurface(s); + DFSDL_FreeSurface(s); DEBUG(textures,out).print("loaded %zd textures from '%s'\n", count, fname); return count; @@ -133,35 +107,6 @@ void Textures::init(color_ostream &out) { if (g_loaded) return; - for (auto &lib_str : SDL_LIBS) { - if ((g_sdl_handle = OpenPlugin(lib_str.c_str()))) - break; - } - for (auto &lib_str : SDL_IMAGE_LIBS) { - if ((g_sdl_image_handle = OpenPlugin(lib_str.c_str()))) - break; - } - - if (!g_sdl_handle) { - out.printerr("Could not find SDL; DFHack textures not loaded.\n"); - } else if (!g_sdl_image_handle) { - out.printerr("Could not find SDL_image; DFHack textures not loaded.\n"); - } else { - #define bind(handle, name) \ - g_##name = (decltype(g_##name))LookupPlugin(handle, #name); \ - if (!g_##name) { \ - out.printerr("Could not find: " #name "; DFHack textures not loaded\n"); \ - } - - bind(g_sdl_image_handle, IMG_Load); - bind(g_sdl_handle, SDL_SetAlpha); - bind(g_sdl_handle, SDL_CreateRGBSurface); - bind(g_sdl_handle, SDL_UpperBlit); - bind(g_sdl_handle, SDL_ConvertSurface); - bind(g_sdl_handle, SDL_FreeSurface); - #undef bind - } - bool is_pre_world = num_textures == textures.init_texture_size; g_num_dfhack_textures = load_textures(out, "hack/data/art/dfhack.png", @@ -186,7 +131,7 @@ void Textures::cleanup() { auto &raws = textures.raws; size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures; for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { - SDL_FreeSurface(raws[idx]); + DFSDL_FreeSurface((DFSDL_Surface *)raws[idx]); raws[idx] = NULL; } @@ -196,11 +141,6 @@ void Textures::cleanup() { g_loaded = false; g_num_dfhack_textures = 0; g_dfhack_logo_texpos_start = -1; - - if (g_sdl_handle) { - ClosePlugin(g_sdl_handle); - g_sdl_handle = nullptr; - } } long Textures::getDfhackLogoTexposStart() {