Skip to content

A working SDL2 client (linux and windows)#79

Open
jezek wants to merge 1 commit into
TomenetGame:masterfrom
jezek:sdl2
Open

A working SDL2 client (linux and windows)#79
jezek wants to merge 1 commit into
TomenetGame:masterfrom
jezek:sdl2

Conversation

@jezek
Copy link
Copy Markdown
Contributor

@jezek jezek commented May 20, 2026

hello, this is a bigger one... i present you a working sdl2 client for linux & windows (windows client is compiled & tested trough mingw/wine only)

Why?

i think it is annoying whenever making some changes in graphics to implement it for linux & windows separately... sdl2 is multi-platform so the same code is for linux and windows client... and not only for graphics... i made it so, that all the code (net, snd, ...), except for some one-liner macros, is the same... no external dependencies

Highlights

  • both SDL2 linux & windows client share the same code and can be build in parallel without affecting each other (windows client does not need wine to build)
  • no external dependencies, uses compiled in libraries with automatic detection at build time
  • separate user and game directory with fallback to game dir
  • graphics preferences can be previewed and changed in-game without restart and client can be drawn with or without window decorations (can be set in config an in game on the fly)
  • changing tile masks from bg, fg, transparency to bg, fg, outline, with automatic outline generation if set (more in docs) and drawing functions are made so we can have more masks per tile and more tiles per coordinate in future
  • github CI/CD with building release assets (server & x11, win, sdl2 linux/win clients) with info on how to build localy via distrobox... see https://github.com/jezek/tomenet/releases/tag/v4.9.4 and https://github.com/jezek/tomenet/actions
  • the releases archives are packaged with all the .so/.dll files, so no packages are needed to install to run

Caveats

  • libarchive doesn't support 7z with password... i've implemented classical zips with passwords and tar archives
  • sdl2-net does not support getting MAC address... i've implemented fake MAC address creation depending on OS specs (should be the same on the same OS and user)
  • linux client runs on wayland by default, which does not move windows to requested positions (for now)... run the linux client with SDL_VIDEODRIVER=x11 environment variable set to fallback to x11 and right windows positions on start

What next?

  • testing and fixing bugs before adoption to releases... i've tried to implement everything what is in the x11/win clients and i tried to test it thoroughly, but mistakes can always happen... if there is anything that needs to be fixed or changed, ping me, i'll try to do my best
  • after adopting, reviewing and releasing these clients, we should deprecate native x11 & windows clients to not end up like this
  • porting the SDL2 client to iOS and android and make it compile under windows (if necessary)... i don't have ios, android nor windows devices at home, so i can't really help with this
  • optimizing tiles & subtiles in-memory images... now when loading tiles/subtiles, all images and layers are stored in memory as big as the underlying bitmaps... the subtiles also use large arrays which need to be traversed often... my idea is to move individual used tiles & subtiles into one synthetic compact image on load before splitting the image into layers... this should drastically reduce memory consumption when using tiles with subtiles... i will try to do this after this is merged

- Increased vesion to 4.9.4.
- Add USE_SDL2 macros thorough the code.
- Add OS_SUB_SDL2 and OS_SUB_GCU_SDL2 and use it in VERSION_OS_SUB.
- Add Unified makefile.sdl2 for linux compiling and windows cross compiling.
  - Compile windows sdl2 client without wine and tolua.exe
  - Remove unnecessary generation rules for common/z_pack
  - Refactor the tolua file generation
  - Make tomenet and tomenet.exe executables in one run in SDL2 client
  - add automatic header-dependency tracking with -MMD/-MP
- Update .gitignore
- Introducing SDL2_GAME_PATH, SDL2_USER_PATH and SDL2_PATH_SEP variables.
- Introduce SDL2 user directory
  - Declare and expose new ANGBAND_USER_DIR* pointers based on ANGBAND_DIR*
  - Inform about creating user directories, refactor
  - Copy default scripts into `ANGBAND_USER_DIR_SCPT` when it's created
  - Redirect SDL2 client file I/O to the SDL2 user directory
  - Store temporary files and logs in the SDL2 temp folder
  - Rename copy_file to my_fcopy.
  - Edit my_fopen to open files with fallback and use instead of fopen in SDL2 client
  - Prefer user dir for fonts/tilesets/macros; install audio packs to user xtra
  - Use user dir when saving sound/music.cfg files
  - Override the user storage dir via TOMENET_SDL2_USER_PATH environment variable
- Using a dir in sdl2 user path as tmpdir when no env value is set.
- Add common/net-sdl2.c using the SDL2 SDL_net library and use it with sdl2 clients.
- Add main-sdl2.c based on main-x11.c and use it in SDL2 client.
- Add multi-layer multi-masks tiles support.
- Add tile cache support, but turn it off (not needed, it is fast).
- Graphic tiles are initialized after pref file is loaded.
- Graphics pref file now contains information about masks colors.
- Per-subtileset mask colors are now loaded from .prf files and used.
- Support PCF and TTF fonts in the SDL2 fonts menu, handle PCF fonts as graphical
  - Add pcf fonts to lib/xtra/font for sdl2 clients
- Add window decorations toggle to settings file and in-game window flags menu
  - On window move, store coordinates considering decorations.
  - Windows are created without decorations by default.
- Using tomenet.cfg in sdl2 user path as config (based on .tomenetrc).
- Make check_guide_checksums work for sdl2 with curl & ssl.
- Removing goto from client/client.c in mangrc read function.
- Use SDL2_image library for screenshots, but it is optional.
  - If not using SDL2_image, save screenshots to BMP instead of PNG.
- Add SDL2_STICKY_KEYS macro and disable by default
- Create snd-sdl2.c file based on snd-sdl.c
  - switch SDL2 client sound to SDL2
  - allow sound code to compile with either `SOUND_SDL` or `SOUND_SDL2`
  - fix sdl2 quit on music quit, add debug logs to sdl2 unarchive
  - guard SDL mixer shutdown
  - determine fd availability by opening null files on init
  - fix SDL2 audio FD accounting for samples vs music
  - fix wrong mutex unlock when loading music (also in snd-sdl.c)
  - refactor sound_sdl_init function
  - fix audio init failure cleanup
  - Add subset logic
  - Fix jukebox autoplay finish and destuctive pack-switch
  - Fix post-autoplay cursor restore
  - Ix autoplay stop after first song after a/u/e session
  - Stabilize jukebox restore/fadeout/shutdown state across mixer reloads and previews
  - Preserve force-disabled and runtime-disabled SDL2 audio state correctly in config and toggles
  - Ignore transient EMFILE/ENFILE when loading audio events
- Add libarchive-based unzipping sound/music pack 7zipped files.
  - detect libarchive in makefile.sdl2 via pkg-config and link when available
  - Notify when unpacking unsupprted 7z encrypted archive
  - More archives support in sdl2 clients (.zip, .tar, .tar.gz).
- Use SDL_OpenURL for file and link opening
- Hide disable_tile_cache into TILE_CACHE_SIZE ifdef macro
- Fix double separator in lua scripts.
- Using semi-transparent black as top tile outline color for UG_2MASK mode
- Graphics tiles outline layer generation for fg/bg tiles when UG_2MASK
  mode. Option to force outline generation of specific width.
- Graphics tiles preferences on-the-fly change and
  tiles with layers preview in in-game graphics menu.
- Graphic subtiles implemenation. Respects subtiles in preview an cache.
- Graphics cache resets subset/index during init and teardown to keep entries clean before reuse.
- Loading graphics images of tiles and subtiles from user location first
- Add tileset resize modes support, default is NEAREST.
- Treating the SDL2 Delete key separately from Backspace so prompts
  receive '\177' (0x7F), while keeping the Backspace handling unchanged.
- In knowledge menu, open last screenshot instead of conversion
  - Open user folders in in-game knowledge menu too.
- Make macroset scan OS independent for SDL2 test clients
- Add basic player sounds according to sound.cfg.default content.
- Create fake but deterministic MAC depending on PC stats
- Add .prf files to lib/user for sdl2 clients
- Get rid of most compiler warnings.
- Build sdl2 linux client to prefer .so beside the binary.
- Make SDL2 ip_iface return IPv4 string like Windows client.
- Add optional GCU support for SDL2 Linux client build, default is off
- Added build scripts for fedora 41 & 43 distrobox build containers.
- Added CI for github with Fedora 41 build image and compile-check workflow
- Added CI for building client/server release archives on tag push and
  append them if release is made.
- Updated guide with info about sdl2 clients how to build them
- Startup logo is graphic only when all used solid tiles are loaded
- Add mask color documentation for sdl2 clients tileset bitmap
@jezek
Copy link
Copy Markdown
Contributor Author

jezek commented May 20, 2026

for those who like to read, here is more exhausting list with differences from native x11 client

  • To make checking guide checksums OS agnostic, checks aren't hanled by external programs (wget,...), but checked internally using curl & openssl libraries. [client/c-files.c, SDL2_CURL_SSL]

  • There are two storage folders SDL2_GAME_PATH and SDL2_USER_PATH, filled by SDL_GetBasePath, resp. SDL_GetPrefPath. The SDL2_USER_PATH can be overriden by TOMENET_SDL2_USER_PATH environment variable. [client/client.c]

  • Default config file for sdl client is called tomenet.cfg and resides in SDL2 preferences path (SDL2_USER_PATH). [client/client.c, common/externs.h, tomenet.cfg]

  • The executable directory is stored at SDL2_GAME_PATH [common/externs.h]

  • Rewrote part of read_mangrc(...) function to get rid of the goto command. Please don't use goto, it's a bad habit. [client/client.c]

  • Using SDL2_PATH_SEP as separator instead of PATH_SEP. The SDL2_PATH_SEP is taken from the last chararacter of SDL2_GAME_PATH [client/client.c, common/externs.h]

  • Using temp directory in SDL2 preferences location as default [common/common.c]

  • Added OS_SUB_SDL2 (4) & OS_SUB_GCU_SDL2 (5) constant and using in VERSION_OS for SDL2 client [common/defines.h]

  • On server side, added the OS_SUB_SDL2 and OS_SUB_GCU_SDL2 to player os version checking. [server/cmd4.c]

  • Replaced __MINGW32__ macro with MINGW macro

  • SDL2 client uses common/net-sdl2.c for networking, which uses SDL2/SDL_net.h and is OS independent. Currently networking functions necessary only for client are implemented. [common/nes-sdl2.c, common/net-sdl2.h, common/h-net.h]

  • Fix macros indenting in [h-config.h, common/h-net.h, common/sockbuf.c]

  • New makefile.sdl2 for buiding the SDL2 client. Both linux and windows (mingw) version, using -MMD and .d files for dependency tracking.

  • Masks colors for graphics tiles are now defined in the graphics tiles preferences file. [client/c-files.c, m:<num>:<hexRGB>]

  • Introducing maximum number of masks per tile GRAPHICS_MAX_MPT and tiles per coordinate GRAPHICS_MAX_TPC. [common/defines-features.h]

  • Hid #define UG_2MASK 2 into #ifdef GRAPHICS_BG_MASK. UG_2MASK makes no sense outside of GRAPHICS_BG_MASK. [common/defines-features.h]

  • Client can load PCF and TTF fonts. The size of an TTF font is extracted from font name in config "<font_name> " (eg. "Term-Main_Font Hack-Regular.ttf 12"). Fonts are loaded from lib/xtra/font. [client/main-sdl2.c]

  • Client can be run with or without window decorations and can be set in config and changed in window flags menu during game.

  • There is a tiles preview in in-game graphics menu when in bigscreen. [client/c-util.c]

  • New graphicsForceOutline option in tomenet.cfg. If in 2-mask graphics mode and option is set to 0 or more, it makes an outline of set width around tile automaticaly. It is for using bitmaps with only fg/bg masks in 2-mask mode with outline, or ignoring preset outline in fg/bg/bg2 mask images and making a new one with intended width. [client/main-sdl2.c]

  • All changes to graphics tiles in ingame graphics menu can be applied on-the-fly, without restarting client. [client/c-util.c]

  • SDL2 library key handling is not accounting for sticky keys. For me it's an essential thing, so I made a sticky keys emulation. Activating sticky keys can be configured in makefile by setting the SDL2_STICKY_KEYS flag. Stickiness is indicated by changing border color of main window. Note: During coding the client, sticky keys started magicaly working without emulation, I left the logic there just for sure. It's disabled by default.

  • In makefile.sdl2 renamed w_play to w_player, to match the name of player.pre file and use fewer rules for the .pkg and .c files generation from the .pre files.

  • Copied client/snd-sdl.c to client/snd-sdl2.c, removed WINDOWS macros and changed to SOUND_SDL2 and forced to include SDL2 headers. In makefile.sdl2 using only the snd-sdl2.c and SOUND_SDL2 flag. Changed all other #ifdef SOUND_SDL to work with SOUND_SDL2 too. [client/snd-sdl2.c]

  • Added universal file descriptor probing (try to open null files up to SDL2_FD_PROBE_MAX) to snd-sdl2.c and use the value to cap the number of loaded audio files. [client/snd-sdl2.c]

  • Found out, samples are cached to memory and use no file descriptors, so the cap of audio files is only for music files now. [client/snd-sdl2.c]

  • For extracting 7zip archives, client uses libarchive, so no external program is needed.

  • All the ANGBAND_DIR_ variables use absolute paths.

  • Opening urls and files is handled bu SDL_OpenURL function.

  • Add ANGBAND_USER_DIR and ANGBAND_USER_DIR_(USER, SCPT, ...) variables pointing to user storage inside SDL2_USER_PATH.

  • Use user storage to write all files. When reading, try user storage first, then fallback to game storage. This is handled mainly in my_fopen fuction (thus rewrites were made to use my_fopen instead fopen).

  • Installing sound and music packs is made from game dir or user storage and to user storage.

  • Use user dir when saving sound/music.cfg files

  • Search for samples and songs in user dir first

  • Fixes to jukebox, saving, preview and state after force_disabled was introduced.

  • Macro, font and tileset file scanning is done in user and game storage.

  • Differentiating between Backspace and Delete key (unlike POSIX clients). Delete is '\177' or 0x7F now.

  • In knowledge menu, open last screenshot instead of conversion

  • Create fake but deterministic MAC depending on PC stats

  • Added github CI and release creation + local distrobox init, build and release scripts for server, sdl2 clients (linux + win), x11 client and windows client.

  • Default scaling mode is NEAREST for sdl2 clients

  • Startup logo is graphic only when all used solid tiles are loaded (.prf is loaded before logo is drawn)

@mhirki
Copy link
Copy Markdown
Contributor

mhirki commented May 25, 2026

Great work! Here are some quick comments:

We usually don't bump the version number until just before a release. Obviously, this feature would be the highlight of the actual 4.9.4 release and we would like to get it released soon.

I'm not sure if sdl2-net is worth it given that it's an extra dependency.

I tried the SDL2 client on my Linux desktop machine. All the windows appeared without borders making it difficult to move them:

Screenshot_tomenet_sdl2_20260525_130307

I was able to move them by selecting the move option from the taskbar. Closing the windows through the taskbar wasn't working. I'm running KDE Plasma on X11.

Movement using the numpad wasn't working (with or without numlock). Player list (@ key) and options menu (= key) weren't working. The macro menu (% key) was working.

SDL2 client was randomly failing to connect to the metaserver.

I'm going to test the SDL2 client on Windows when I have more time.

@mhirki
Copy link
Copy Markdown
Contributor

mhirki commented May 25, 2026

Ok, I found the windowDecorations setting from tomenet.cfg and got my borders back. I think the borders should be enabled by default.

Having the configuration file in a new location ($HOME/.local/share/TomenetGame/tomenet/tomenet.cfg) was a bit confusing. You did add the new location to the guide which is good. I just wonder if it's possible to make the configuration file easier to find.

@mhirki
Copy link
Copy Markdown
Contributor

mhirki commented May 30, 2026

I tested the SDL2 client on Windows and it works but it has pretty much the same bugs as the Linux client. I tried editing %APPDATA%/TomenetGame/tomenet/tomenet.cfg to enable window borders but it didn't work.

SDL_TEXTINPUT event probably needs to be used to get the keyboard input working correctly with respect to layout. Both Angband and MAngband are using SDL_TEXTINPUT.

@jezek
Copy link
Copy Markdown
Contributor Author

jezek commented May 31, 2026

@mhirki thx, i know about the SDL_TEXTINPUT, i'm working on it... but it is not that easy... something works with SDL_TEXTINPUT, something (most ctrl combinations, special keys, ...) only with SDL_KEYDOWN, i have to make an hybrid approach... and if that isn't enough, in the SDL_KEYDOWN you can't figure out the keycode when shift was pressed in SDL2... i'm really considering closing this PR and rewriting to SDL3 (which has this figured out)...

however, i have mostly figured out all the issues you reported, i'm testing it now... when i'm satisfied with the test, i'll push and ping you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants