Maelstrom: Maelstrom SDL3 port in progress

From 36f4ff0a066ab908e42f6d3a16efc5712b4e506d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 9 Mar 2025 13:31:17 -0700
Subject: [PATCH] Maelstrom SDL3 port in progress

---
 controls.cpp               |  48 +++++++-------
 dialog.cpp                 |  29 +++++----
 dialog.h                   |  77 ++++++++++++++--------
 init.cpp                   |  18 ++++--
 load.cpp                   |  32 +++++-----
 logic.h                    |   2 +-
 maclib/Mac_Compat.h        |   4 +-
 maclib/Mac_FontServ.cpp    |  20 +++---
 maclib/Mac_FontServ.h      |   3 +-
 maclib/Mac_Sound.cpp       | 126 ++++++------------------------------
 maclib/Mac_Sound.h         |   9 +--
 maclib/Mac_Wave.cpp        |  46 ++++++-------
 maclib/Mac_Wave.h          |   2 +-
 maclib/bitesex.h           |   6 +-
 maclib/playwave.cpp        |   6 +-
 main.cpp                   |  38 +++++------
 netlogic/about.cpp         |   8 +--
 netlogic/game.cpp          |  10 +--
 netlogic/logic.cpp         |   4 +-
 netlogic/netplay.cpp       | 128 +++++++++++++++++++++++++------------
 netscore.cpp               |  18 +++++-
 scores.cpp                 |  30 ++++-----
 screenlib/SDL_FrameBuf.cpp | 116 ++++++++++++---------------------
 screenlib/SDL_FrameBuf.h   |  21 +++---
 screenlib/pixel.cpp        |  17 -----
 screenlib/pixel.h          |   3 -
 26 files changed, 383 insertions(+), 438 deletions(-)

diff --git a/controls.cpp b/controls.cpp
index eec4a1a4..262e4afe 100644
--- a/controls.cpp
+++ b/controls.cpp
@@ -22,7 +22,7 @@ Controls controls =
 Controls controls =
    { SDLK_PAUSE,SDLK_SPACE,SDLK_UP,SDLK_RIGHT,SDLK_LEFT,SDLK_TAB,SDLK_ESCAPE };
 #endif
-SDL_Keymod gToggleFullscreenMod = KMOD_ALT;
+SDL_Keymod gToggleFullscreenMod = SDL_KMOD_ALT;
 
 #ifdef MOVIE_SUPPORT
 int	gMovie = 0;
@@ -83,7 +83,7 @@ static FILE *OpenData(const char *mode, const char **fname)
 	return(data);
 }
 
-static bool ControlsUseKey(SDL_KeyCode key)
+static bool ControlsUseKey(SDL_Keycode key)
 {
 	return (controls.gPauseControl == key ||
 	        controls.gShieldControl == key ||
@@ -97,13 +97,13 @@ static bool ControlsUseKey(SDL_KeyCode key)
 void UpdateToggleFullscreenShortcut()
 {
 	if (!ControlsUseKey(SDLK_LALT) && !ControlsUseKey(SDLK_RALT)) {
-		gToggleFullscreenMod = KMOD_ALT;
+		gToggleFullscreenMod = SDL_KMOD_ALT;
 	} else if (!ControlsUseKey(SDLK_LSHIFT) && !ControlsUseKey(SDLK_RSHIFT)) {
-		gToggleFullscreenMod = KMOD_SHIFT;
+		gToggleFullscreenMod = SDL_KMOD_SHIFT;
 	} else if (!ControlsUseKey(SDLK_LCTRL) && !ControlsUseKey(SDLK_RCTRL)) {
-		gToggleFullscreenMod = KMOD_CTRL;
+		gToggleFullscreenMod = SDL_KMOD_CTRL;
 	} else {
-		gToggleFullscreenMod = KMOD_NONE;
+		gToggleFullscreenMod = SDL_KMOD_NONE;
 	}
 }
 
@@ -205,20 +205,20 @@ static int Cancel_callback(void) {
 	valid = 0;
 	return(1);
 }
-static void BoxKeyPress(SDL_Keysym key, int *doneflag)
+static void BoxKeyPress(SDL_Keycode key, int *doneflag)
 {
 	SDL_Color black = { 0x00, 0x00, 0x00, 0 };
 	SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
 	int i;
 	char keyname[128];
 
-	if ( key.sym == *checkboxes[currentbox].control )
+	if ( key == *checkboxes[currentbox].control )
 		return;
 
 	/* Make sure the key isn't in use! */
 	for ( i=0; i<NUM_CTLS; ++i ) {
-		if ( key.sym == *checkboxes[i].control ) {
-			key.sym = (SDL_Keycode)*checkboxes[currentbox].control;
+		if ( key == *checkboxes[i].control ) {
+			key = (SDL_Keycode)*checkboxes[currentbox].control;
 
 			/* Clear the current text */
 			fontserv->InvertText(keynames[currentbox]);
@@ -252,7 +252,7 @@ static void BoxKeyPress(SDL_Keysym key, int *doneflag)
 	fontserv->FreeText(keynames[currentbox]);
 
 	/* Display the new key */
-	*checkboxes[currentbox].control = key.sym;
+	*checkboxes[currentbox].control = key;
 	KeyName(*checkboxes[currentbox].control, keyname);
 	keynames[currentbox] = fontserv->TextImage(keyname, chicago, STYLE_NORM,
 								black, white);
@@ -367,7 +367,7 @@ static void HandleEvent(SDL_Event *event)
 	switch (event->type) {
 #ifdef SDL_INIT_JOYSTICK
 		/* -- Handle joystick axis motion */
-		case SDL_JOYAXISMOTION:
+		case SDL_EVENT_JOYSTICK_AXIS_MOTION:
 			/* X-Axis - rotate right/left */
 			if ( event->jaxis.axis == 0 ) {
 				if ( event->jaxis.value < -8000 ) {
@@ -393,9 +393,9 @@ static void HandleEvent(SDL_Event *event)
 			break;
 
 		/* -- Handle joystick button presses/releases */
-		case SDL_JOYBUTTONDOWN:
-		case SDL_JOYBUTTONUP:
-			if ( event->jbutton.state == SDL_PRESSED ) {
+		case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
+		case SDL_EVENT_JOYSTICK_BUTTON_UP:
+			if ( event->jbutton.down ) {
 				if ( event->jbutton.button == 0 ) {
 					SetControl(FIRE_KEY, 1);
 				} else
@@ -414,17 +414,17 @@ static void HandleEvent(SDL_Event *event)
 #endif
 
 		/* -- Handle key presses/releases */
-		case SDL_KEYDOWN:
+		case SDL_EVENT_KEY_DOWN:
 			/* -- Handle ALT-ENTER hotkey */
-			if ( (event->key.keysym.sym == SDLK_RETURN) &&
-			     (event->key.keysym.mod & gToggleFullscreenMod) ) {
+			if ( (event->key.key == SDLK_RETURN) &&
+			     (event->key.mod & gToggleFullscreenMod) ) {
 				screen->ToggleFullScreen();
 				break;
 			}
-		case SDL_KEYUP:
+		case SDL_EVENT_KEY_UP:
 			/* -- Handle normal key bindings */
-			key = event->key.keysym.sym;
-			if ( event->key.state == SDL_PRESSED ) {
+			key = event->key.key;
+			if ( event->key.down) {
 				/* Check for various control keys */
 				if ( key == controls.gFireControl )
 					SetControl(FIRE_KEY, 1);
@@ -440,7 +440,7 @@ static void HandleEvent(SDL_Event *event)
 					SetControl(PAUSE_KEY, 1);
 				else if ( key == controls.gQuitControl )
 					SetControl(ABORT_KEY, 1);
-				else if ( SpecialKey(event->key.keysym) == 0 )
+				else if ( SpecialKey(key) == 0 )
 					/* The key has been handled */;
 				else if ( key == SDLK_F3 ) {
 					/* Special key --
@@ -476,7 +476,7 @@ mesg("Movie is %s...\n", gMovie ? "started" : "stopped");
 			}
 			break;
 
-		case SDL_QUIT:
+		case SDL_EVENT_QUIT:
 			SetControl(ABORT_KEY, 1);
 			break;
 	}
@@ -507,7 +507,7 @@ int DropEvents(void)
 	int keys = 0;
 
 	while ( SDL_PollEvent(&event) ) {
-		if ( event.type == SDL_KEYDOWN ) {
+		if ( event.type == SDL_EVENT_KEY_DOWN ) {
 			++keys;
 		}
 	}
diff --git a/dialog.cpp b/dialog.cpp
index 0178273f..e19d1749 100644
--- a/dialog.cpp
+++ b/dialog.cpp
@@ -26,18 +26,21 @@ Mac_Button::Mac_Button(int x, int y, int width, int height,
 	Height = height;
 
 	/* Build image of the button */
-	button = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height,
-						8, 0, 0, 0, 0);
+	button = SDL_CreateSurface(Width, Height, SDL_PIXELFORMAT_INDEX8);
 	if ( button == NULL ) {
 		SetError("%s", SDL_GetError());
 		return;
 	}
-	button->format->palette->colors[0].r = 0xFF;
-	button->format->palette->colors[0].g = 0xFF;
-	button->format->palette->colors[0].b = 0xFF;
-	button->format->palette->colors[1].r = 0x00;
-	button->format->palette->colors[1].g = 0x00;
-	button->format->palette->colors[1].b = 0x00;
+	SDL_Palette* palette = SDL_GetSurfacePalette(button);
+	if (palette) {
+		palette->colors[0].r = 0xFF;
+		palette->colors[0].g = 0xFF;
+		palette->colors[0].b = 0xFF;
+		palette->colors[1].r = 0x00;
+		palette->colors[1].g = 0x00;
+		palette->colors[1].b = 0x00;
+		SDL_SetSurfacePalette(button, palette);
+	}
 	textb = fontserv->TextImage(text, font, STYLE_NORM,
 					0x00, 0x00, 0x00);
 	if ( textb != NULL ) {
@@ -281,15 +284,15 @@ Maclike_Dialog:: Run(int expand_steps)
 
 		switch (event.type) {
 			/* -- Handle mouse clicks */
-			case SDL_MOUSEBUTTONDOWN:
+			case SDL_EVENT_MOUSE_BUTTON_DOWN:
 	for ( delem = dialog_list.next; delem; delem = delem->next )
-		(delem->dialog)->HandleButtonPress(event.button.x, 
-				event.button.y, event.button.button, &done);
+		(delem->dialog)->HandleButtonPress((int)event.button.x, 
+				(int)event.button.y, event.button.button, &done);
 				break;
 			/* -- Handle key presses */
-			case SDL_KEYDOWN:
+			case SDL_EVENT_KEY_DOWN:
 	for ( delem = dialog_list.next; delem; delem = delem->next )
-		(delem->dialog)->HandleKeyPress(event.key.keysym, &done);
+		(delem->dialog)->HandleKeyPress(event.key.key, &done);
 				break;
 		}
 	}
diff --git a/dialog.h b/dialog.h
index 5a4f2488..76cdb275 100644
--- a/dialog.h
+++ b/dialog.h
@@ -36,10 +36,10 @@ class Mac_Dialog {
 		}
 	}
 	virtual void SetKeyPress(void (*new_key_callback)
-				(SDL_Keysym key, int *doneflag)) {
+				(SDL_Keycode key, int *doneflag)) {
 		key_callback = new_key_callback;
 	}
-	virtual void HandleKeyPress(SDL_Keysym key, int *doneflag) {
+	virtual void HandleKeyPress(SDL_Keycode key, int *doneflag) {
 		if ( key_callback ) {
 			(*key_callback)(key, doneflag);
 		}
@@ -58,12 +58,20 @@ class Mac_Dialog {
 
 	static void EnableText(void) {
 		if ( text_enabled++ == 0 ) {
-			SDL_StartTextInput();
+			SDL_Window **windows = SDL_GetWindows(NULL);
+			if (windows) {
+				SDL_StartTextInput(windows[0]);
+				SDL_free(windows);
+			}
 		}
 	}
 	static void DisableText(void) {
 		if ( --text_enabled == 0 ) {
-			SDL_StopTextInput();
+			SDL_Window **windows = SDL_GetWindows(NULL);
+			if (windows) {
+				SDL_StopTextInput(windows[0]);
+				SDL_free(windows);
+			}
 		}
 	}
 
@@ -77,7 +85,7 @@ class Mac_Dialog {
 	FrameBuf *Screen;
 	int  X, Y;
 	void (*button_callback)(int x, int y, int button, int *doneflag);
-	void (*key_callback)(SDL_Keysym key, int *doneflag);
+	void (*key_callback)(SDL_Keycode key, int *doneflag);
 
 	/* Utility routines for dialogs */
 	int IsSensitive(SDL_Rect *area, int x, int y) {
@@ -112,7 +120,7 @@ class Mac_Button : public Mac_Dialog {
 		const char *text, MFont *font, FontServ *fontserv, 
 				int (*callback)(void));
 	virtual ~Mac_Button() {
-		SDL_FreeSurface(button);
+		SDL_DestroySurface(button);
 	}
 
 	virtual void Map(int Xoff, int Yoff, FrameBuf *screen,
@@ -129,12 +137,16 @@ class Mac_Button : public Mac_Dialog {
 		sensitive.h = Height;
 
 		/* Map the bitmap image */
-		button->format->palette->colors[0].r = R_bg;
-		button->format->palette->colors[0].g = G_bg;
-		button->format->palette->colors[0].b = B_bg;
-		button->format->palette->colors[1].r = R_fg;
-		button->format->palette->colors[1].g = G_fg;
-		button->format->palette->colors[1].b = B_fg;
+		SDL_Palette* palette = SDL_GetSurfacePalette(button);
+		if (palette) {
+			palette->colors[0].r = R_bg;
+			palette->colors[0].g = G_bg;
+			palette->colors[0].b = B_bg;
+			palette->colors[1].r = R_fg;
+			palette->colors[1].g = G_fg;
+			palette->colors[1].b = B_fg;
+			SDL_SetSurfacePalette(button, palette);
+		}
 	}
 	virtual void Show(void) {
 		Screen->QueueBlit(X, Y, button, NOCLIP);
@@ -221,8 +233,8 @@ class Mac_DefaultButton : public Mac_Button {
 						int (*callback)(void));
 	virtual ~Mac_DefaultButton() { }
 
-	virtual void HandleKeyPress(SDL_Keysym key, int *doneflag) {
-		if ( key.sym == SDLK_RETURN )
+	virtual void HandleKeyPress(SDL_Keycode key, int *doneflag) {
+		if ( key == SDLK_RETURN )
 			ActivateButton(doneflag);
 	}
 
@@ -320,9 +332,13 @@ class Mac_CheckBox : public Mac_Dialog {
 		Bg = Screen->MapRGB(R_bg, G_bg, B_bg);
 
 		/* Map the checkbox text */
-		label->format->palette->colors[1].r = R_fg;
-		label->format->palette->colors[1].g = G_fg;
-		label->format->palette->colors[1].b = B_fg;
+		SDL_Palette* palette = SDL_GetSurfacePalette(label);
+		if (palette) {
+			palette->colors[1].r = R_fg;
+			palette->colors[1].g = G_fg;
+			palette->colors[1].b = B_fg;
+			SDL_SetSurfacePalette(label, palette);
+		}
 	}
 	virtual void Show(void) {
 		Screen->DrawRect(X, Y, CHECKBOX_SIZE, CHECKBOX_SIZE, Fg);
@@ -440,9 +456,14 @@ class Mac_RadioList : public Mac_Dialog {
 			radio->y += Yoff;
 			radio->sensitive.x += Xoff;
 			radio->sensitive.y += Yoff;
-			radio->label->format->palette->colors[1].r = R_fg;
-			radio->label->format->palette->colors[1].g = G_fg;
-			radio->label->format->palette->colors[1].b = B_fg;
+
+			SDL_Palette* palette = SDL_GetSurfacePalette(radio->label);
+			if (palette) {
+				palette->colors[1].r = R_fg;
+				palette->colors[1].g = G_fg;
+				palette->colors[1].b = B_fg;
+				SDL_SetSurfacePalette(radio->label, palette);
+			}
 		}
 	}
 	virtual void Show(void) {
@@ -536,10 +557,10 @@ class Mac_TextEntry : public Mac_Dialog {
 			}
 		}
 	}
-	virtual void HandleKeyPress(SDL_Keysym key, int *doneflag) {
+	virtual void HandleKeyPress(SDL_Keycode key, int *doneflag) {
 		int n;
 
-		switch (key.sym) {
+		switch (key) {
 			case SDLK_TAB:
 				current->hilite = 0;
 				Update_Entry(current);
@@ -567,11 +588,11 @@ class Mac_TextEntry : public Mac_Dialog {
 			default:
 				if ( (current->end+Cwidth) > current->width )
 					return;
-				// FIXME: We should use SDL_TEXTINPUT, but this class isn't used, so...
-				if ( key.sym <= 0x7F ) {
+				// FIXME: We should use SDL_EVENT_TEXT_INPUT, but this class isn't used, so...
+				if ( key <= 0x7F ) {
 					current->hilite = 0;
 					n = strlen(current->variable);
-					current->variable[n] = (char)key.sym;
+					current->variable[n] = (char)key;
 					current->variable[n+1] = '\0';
 					Update_Entry(current);
 					DrawCursor(current);
@@ -729,10 +750,10 @@ class Mac_NumericEntry : public Mac_Dialog {
 			}
 		}
 	}
-	virtual void HandleKeyPress(SDL_Keysym key, int *doneflag) {
+	virtual void HandleKeyPress(SDL_Keycode key, int *doneflag) {
 		int n;
 
-		switch (key.sym) {
+		switch (key) {
 			case SDLK_TAB:
 				current->hilite = 0;
 				Update_Entry(current);
@@ -765,7 +786,7 @@ class Mac_NumericEntry : public Mac_Dialog {
 			case SDLK_7:
 			case SDLK_8:
 			case SDLK_9:
-				n = (key.sym-SDLK_0);
+				n = (key-SDLK_0);
 				if ( (current->end+Cwidth) > current->width )
 					return;
 				if ( current->hilite ) {
diff --git a/init.cpp b/init.cpp
index 27bdfd01..68f9d512 100644
--- a/init.cpp
+++ b/init.cpp
@@ -726,9 +726,9 @@ int DoInitializations(Uint32 video_flags)
 #ifdef SDL_INIT_JOYSTICK
 	init_flags |= SDL_INIT_JOYSTICK;
 #endif
-	if ( SDL_Init(init_flags) < 0 ) {
+	if ( !SDL_Init(init_flags) ) {
 		init_flags &= ~SDL_INIT_JOYSTICK;
-		if ( SDL_Init(init_flags) < 0 ) {
+		if ( !SDL_Init(init_flags) ) {
 			error("Couldn't initialize SDL: %s\n", SDL_GetError());
 			return(-1);
 		}
@@ -744,11 +744,15 @@ int DoInitializations(Uint32 video_flags)
 
 #ifdef SDL_INIT_JOYSTICK
 	/* Initialize the first joystick */
-	if ( SDL_NumJoysticks() > 0 ) {
-		if ( SDL_JoystickOpen(0) == NULL ) {
-			error("Warning: Couldn't open joystick '%s' : %s\n",
-				SDL_JoystickName(0), SDL_GetError());
+	SDL_JoystickID* joysticks = SDL_GetJoysticks(NULL);
+	if (joysticks) {
+		if (joysticks[0]) {
+			if (SDL_OpenJoystick(joysticks[0]) == NULL) {
+				error("Warning: Couldn't open joystick '%s' : %s\n",
+					SDL_GetJoystickName(0), SDL_GetError());
+			}
 		}
+		SDL_free(joysticks);
 	}
 #endif
 
@@ -782,7 +786,7 @@ int DoInitializations(Uint32 video_flags)
 	}
 	screen->SetCaption("Maelstrom");
 	atexit(CleanUp);		// Need to reset this under X11 DGA
-	SDL_FreeSurface(icon);
+	SDL_DestroySurface(icon);
 
 	/* -- We want to access the FULL screen! */
 	SetRect(&gScrnRect, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
diff --git a/load.cpp b/load.cpp
index bee1c05c..c693b4cb 100644
--- a/load.cpp
+++ b/load.cpp
@@ -2,7 +2,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "SDL_endian.h"
+#include <SDL3/SDL.h>
 
 #include "load.h"
 #include "myerror.h"
@@ -36,12 +36,13 @@ SDL_Surface *Load_Icon(char **xpm)
 	}
 
 	/* Allocate a surface of the appropriate type */
-	icon = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0,0,0,0);
+	icon = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_INDEX8);
 	if ( icon == NULL ) {
 		return(NULL);
 	}
 
 	/* Fill in the palette */
+	SDL_Palette* palette = SDL_GetSurfacePalette(icon);
 	for ( i=0; i<num_colors; ++i ) {
 		buf = xpm[index++];
 		p = *buf;
@@ -60,10 +61,11 @@ SDL_Surface *Load_Icon(char **xpm)
 			}
 			++buf;
 		}
-		icon->format->palette->colors[p].r = rgb[0];
-		icon->format->palette->colors[p].g = rgb[1];
-		icon->format->palette->colors[p].b = rgb[2];
+		palette->colors[p].r = rgb[0];
+		palette->colors[p].g = rgb[1];
+		palette->colors[p].b = rgb[2];
 	}
+	SDL_SetSurfacePalette(icon, palette);
 
 	/* Fill in the pixels */
 	buf = (char *)icon->pixels;
@@ -89,7 +91,7 @@ SDL_Surface *Load_Title(FrameBuf *screen, int title_id)
 
 	/* Create an image from the BMP */
 	title = screen->LoadImage(bmp->w, bmp->h, (Uint8 *)bmp->pixels, NULL);
-	SDL_FreeSurface(bmp);
+	SDL_DestroySurface(bmp);
 	return(title);
 }
 
@@ -98,36 +100,36 @@ SDL_Surface *GetCIcon(FrameBuf *screen, short cicn_id)
 	char file[256];
 	LibPath path;
 	SDL_Surface *cicn;
-	SDL_RWops *cicn_src;
+	SDL_IOStream *cicn_src;
 	Uint8 *pixels, *mask;
 	Uint16 w, h;
 	
 	/* Open the cicn sprite file.. */
 	SDL_snprintf(file, sizeof(file), "Images" DIR_SEP "Maelstrom_Icon#%hd.cicn", cicn_id);
-	if ( (cicn_src=SDL_RWFromFile(path.Path(file), "r")) == NULL ) {
+	if ( (cicn_src=SDL_IOFromFile(path.Path(file), "r")) == NULL ) {
 		error("GetCIcon(%hd): Can't open CICN %s: ",
 					cicn_id, path.Path(file));
 		return(NULL);
 	}
 
-	w = SDL_ReadBE16(cicn_src);
-	h = SDL_ReadBE16(cicn_src);
+	SDL_ReadU16BE(cicn_src, &w);
+	SDL_ReadU16BE(cicn_src, &h);
         pixels = new Uint8[w*h];
-        if ( SDL_RWread(cicn_src, pixels, 1, w*h) != (w*h) ) {
+        if ( SDL_ReadIO(cicn_src, pixels, w*h) != (w*h) ) {
 		error("GetCIcon(%hd): Corrupt CICN!\n", cicn_id);
 		delete[] pixels;
-		SDL_RWclose(cicn_src);
+		SDL_CloseIO(cicn_src);
 		return(NULL);
 	}
         mask = new Uint8[(w/8)*h];
-        if ( SDL_RWread(cicn_src, mask, 1, (w/8)*h) != ((w/8)*h) ) {
+        if ( SDL_ReadIO(cicn_src, mask, (w/8)*h) != ((w/8)*h) ) {
 		error("GetCIcon(%hd): Corrupt CICN!\n", cicn_id);
 		delete[] pixels;
 		delete[] mask;
-		SDL_RWclose(cicn_src);
+		SDL_CloseIO(cicn_src);
 		return(NULL);
 	}
-	SDL_RWclose(cicn_src);
+	SDL_CloseIO(cicn_src);
 
 	cicn = screen->LoadImage(w, h, pixels, mask);
 	delete[] pixels;
diff --git a/logic.h b/logic.h
index df1063b9..62d84af9 100644
--- a/logic.h
+++ b/logic.h
@@ -11,7 +11,7 @@ extern int  InitLogic(void);
 extern int  InitPlayerSprites(void);
 extern void HaltLogic(void);
 extern void SetControl(unsigned char which, int toggle);
-extern int  SpecialKey(SDL_Keysym key);
+extern int  SpecialKey(SDL_Keycode key);
 extern int GetScore(void);
 
 /* From game.cpp */
diff --git a/maclib/Mac_Compat.h b/maclib/Mac_Compat.h
index 92686bf8..067b5728 100644
--- a/maclib/Mac_Compat.h
+++ b/maclib/Mac_Compat.h
@@ -20,13 +20,13 @@
 #ifndef _Mac_Compat_h
 #define _Mac_Compat_h
 
-#include "SDL_timer.h"
+#include <SDL3/SDL.h>
 
 /* Some simple inline Macintosh compatibility routines */
 
 /* Delay(x) -- sleep for x number of 1/60 second slices */
 #define Delay(x)	SDL_Delay(((x)*1000)/60)
 /* Ticks -- a global variable containing current time in 1/60 second slices */
-#define Ticks		((SDL_GetTicks()*60)/1000)
+#define Ticks		((((Uint32)SDL_GetTicks())*60)/1000)
 
 #endif /* _Mac_Compat_h */
diff --git a/maclib/Mac_FontServ.cpp b/maclib/Mac_FontServ.cpp
index b050d278..5fd01a95 100644
--- a/maclib/Mac_FontServ.cpp
+++ b/maclib/Mac_FontServ.cpp
@@ -327,7 +327,7 @@ FontServ:: TextImage(const char *text, MFont *font, Uint8 style,
 	height = (font->header)->fRectHeight;
 
 	/* Allocate the text bitmap image */
-	image = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 1, 0,0,0,0);
+	image = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_INDEX1MSB);
 	if ( image == NULL ) {
 		SetError("Unable to allocate bitmap: %s", SDL_GetError());
 		return(NULL);
@@ -382,9 +382,10 @@ FontServ:: TextImage(const char *text, MFont *font, Uint8 style,
 	}
 
 	/* Map the image and return */
-	SDL_SetColorKey(image, SDL_TRUE, 0);
-	image->format->palette->colors[0] = background;
-	image->format->palette->colors[1] = foreground;
+	SDL_SetSurfaceColorKey(image, true, 0);
+	SDL_Palette* palette = SDL_GetSurfacePalette(image);
+	SDL_SetPaletteColors(palette, &background, 0, 1);
+	SDL_SetPaletteColors(palette, &foreground, 1, 1);
 	++text_allocated;
 	return(image);
 }
@@ -392,7 +393,7 @@ void
 FontServ:: FreeText(SDL_Surface *text)
 {
 	--text_allocated;
-	SDL_FreeSurface(text);
+	SDL_DestroySurface(text);
 }
 int
 FontServ:: InvertText(SDL_Surface *text)
@@ -400,14 +401,15 @@ FontServ:: InvertText(SDL_Surface *text)
 	SDL_Color colors[2];
 
 	/* Only works on bitmap images */
-	if ( text->format->BitsPerPixel != 1 ) {
+	if ( SDL_BITSPERPIXEL(text->format) != 1 ) {
 		SetError("Not a text bitmap");
 		return(-1);
 	}
 
 	/* Swap background and foreground colors */
-	colors[0] = text->format->palette->colors[1];
-	colors[1] = text->format->palette->colors[0];
-	SDL_SetPaletteColors(text->format->palette, colors, 0, 2);
+	SDL_Palette* palette = SDL_GetSurfacePalette(text);
+	colors[0] = palette->colors[1];
+	colors[1] = palette->colors[0];
+	SDL_SetPaletteColors(palette, colors, 0, 2);
 	return(0);
 }
diff --git a/maclib/Mac_FontServ.h b/maclib/Mac_FontServ.h
index 72ffd0c3..5159f499 100644
--- a/maclib/Mac_FontServ.h
+++ b/maclib/Mac_FontServ.h
@@ -103,12 +103,13 @@ class FontServ {
 				SDL_Color background, SDL_Color foreground);
 	SDL_Surface *TextImage(const char *text, MFont *font, Uint8 style,
 						Uint8 R, Uint8 G, Uint8 B) {
-		SDL_Color background = { 0xFF, 0xFF, 0xFF, 0 };
+		SDL_Color background = { 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE };
 		SDL_Color foreground;
 
 		foreground.r = R;
 		foreground.g = G;
 		foreground.b = B;
+		foreground.a = SDL_ALPHA_OPAQUE;
 		return(TextImage(text, font, style, foreground, background));
 	}
 	void FreeText(SDL_Surface *text);
diff --git a/maclib/Mac_Sound.cpp b/maclib/Mac_Sound.cpp
index 8e942373..49a3b0c5 100644
--- a/maclib/Mac_Sound.cpp
+++ b/maclib/Mac_Sound.cpp
@@ -22,80 +22,30 @@
 #include "Mac_Sound.h"
 #include "Mac_Compat.h"
 
-static int bogus_running = 0;
-
-extern "C" {
-static int BogusAudioThread(void *data)
+static void SDLCALL FillAudio(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount)
 {
-	SDL_AudioSpec *spec;
-	void (*fill)(void *userdata, Uint8 *stream, int len);
-	Uint32 then;
-	Uint32 playticks;
-	Sint32 ticksleft;
-	Uint8 *stream;
-
-#ifdef NSIG
-	/* Clear out any signal handlers */
-	for ( int i = 0; i<NSIG; ++i )
-		signal(i, SIG_DFL);
-#else
-	signal(SIGINT, SIG_DFL);
-	signal(SIGSEGV, SIG_DFL);
-	signal(SIGTERM, SIG_DFL);
-#endif
-
-	/* Get ready to roll.. */
-	spec = (SDL_AudioSpec *)data;
-	if ( spec->callback == NULL ) {
-		for ( ; ; )
-			Delay(60*60*60);	/* Delay 1 hour */
-	}
-	fill = spec->callback;
-	playticks = ((Uint32)spec->samples*1000)/spec->freq;
-	/* Fill in the spec */
-	spec->size = (spec->format&0xFF)/8;
-	spec->size *= spec->channels;
-	spec->size *= spec->samples;
-	stream = new Uint8[spec->size];
-
-	while ( bogus_running ) {
-		then = SDL_GetTicks();
-
-		/* Fill buffer */
-		if ( fill )
-			(*fill)(spec->userdata, stream, spec->size);
-
-		/* Calculate time left, and sleep */
-		ticksleft = playticks-(SDL_GetTicks()-then);
-		if ( ticksleft > 0 )
-			SDL_Delay(ticksleft);
+	Sound *sound = (Sound *)userdata;
+
+	if (additional_amount > 0) {
+		Uint8* data = SDL_stack_alloc(Uint8, additional_amount);
+		if (data) {
+			Sound::FillAudioU8(sound, data, additional_amount);
+			SDL_PutAudioStreamData(stream, data, additional_amount);
+			SDL_stack_free(data);
+		}
 	}
-	delete[] stream;
-
-	return(0);
-}
-
-static void FillAudio(void *udata, Uint8 *stream, int len)
-{
-	Sound *sound = (Sound *)udata;
-	
-	Sound::FillAudioU8(sound, stream, len);
 }
-/* extern "C" */
-};
 
 Sound:: Sound(const char *soundfile, Uint8 vol)
 {
 	Wave         *wave;
 	Mac_Resource *soundres;
-	int           i, p;
+	int           i;
 	Uint16       *ids;
 	Mac_ResData  *snd;
 
 	/* Initialize variables */
 	volume  = 0;
-	playing = 0;
-	bogus_audio = NULL;
 	InitHash();
 	errstr = NULL;
 
@@ -129,6 +79,8 @@ Sound:: Sound(const char *soundfile, Uint8 vol)
 	}
 	delete soundres;
 	spec = wave->Spec();
+
+#if 0
 	/* Allow ~ 1/30 second time-lag in audio buffer -- samples is x^2  */
 	spec->samples = (wave->Frequency()*wave->SampleSize())/30;
 	for ( p = 0; spec->samples > 1; ++p )
@@ -136,69 +88,29 @@ Sound:: Sound(const char *soundfile, Uint8 vol)
 	++p;
 	for ( i = 0; i < p; ++i )
 		spec->samples *= 2;
-	spec->callback = FillAudio;
-	spec->userdata = (void *)this;
+#endif
+
+	stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, spec, FillAudio, this);
 
 	/* Empty the channels and start the music :-) */
 	HaltSound();
-	if ( vol == 0 ) {
-		bogus_running = 1;
-		bogus_audio = SDL_CreateThread(BogusAudioThread, "Maelstrom Audio", spec);
-	} else {
-		Volume(vol);
-	}
+	Volume(vol);
+	SDL_ResumeAudioStreamDevice(stream);
 }
 
 Sound:: ~Sound()
 {
-	if ( playing )
-		SDL_CloseAudio();
-	else
-	if ( bogus_audio ) {
-		bogus_running = 0;
-		SDL_WaitThread(bogus_audio, NULL);
-		bogus_audio = NULL;
-	}
+	SDL_DestroyAudioStream(stream);
 	FreeHash();
 }
 
 Uint8
 Sound:: Volume(Uint8 vol)
 {
-	Uint8 active;
-
-	active = playing;
-	if ( (volume == 0) && (vol > 0) ) {
-		/* Kill bogus sound thread */
-		if ( bogus_audio ) {
-			bogus_running = 0;
-			SDL_WaitThread(bogus_audio, NULL);
-			bogus_audio = NULL;
-		}
-
-		/* Try to open the audio */
-		if ( SDL_OpenAudio(spec, NULL) < 0 )
-			vol = 0;		/* Fake sound */
-		active = 1;
-		SDL_PauseAudio(0);		/* Go! */
-	}
 	if ( vol > MAX_VOLUME )
 		vol = MAX_VOLUME;
 	volume = vol;
 
-	if ( active && (volume == 0) ) {
-		if ( playing )
-			SDL_CloseAudio();
-		active = 0;
-
-		/* Run bogus sound thread */
-		bogus_running = 1;
-		bogus_audio = SDL_CreateThread(BogusAudioThread, "Maelstrom Audio", spec);
-		if ( bogus_audio == NULL ) {
-			/* Oh well... :-) */
-		}
-	}
-	playing = active;
 	return(volume);
 }
 
diff --git a/maclib/Mac_Sound.h b/maclib/Mac_Sound.h
index ffff3b99..41f386aa 100644
--- a/maclib/Mac_Sound.h
+++ b/maclib/Mac_Sound.h
@@ -25,9 +25,6 @@
 #include <stdarg.h>
 #include <string.h>
 #include <SDL3/SDL.h>
-#include "SDL_mutex.h"
-#include "SDL_thread.h"
-#include "SDL_audio.h"
 #include "Mac_Wave.h"
 
 #define MAX_VOLUME	8		/* Software volume ranges from 0 - 8 */
@@ -118,8 +115,6 @@ class Sound {
 	static void FillAudioU8(Sound *sound, Uint8 *stream, int len);
 
 private:
-	Uint8 playing;
-
 	struct channel {
 		Uint16 ID;
 		Sint16 priority;
@@ -130,9 +125,7 @@ class Sound {
 
 	SDL_AudioSpec *spec;
 	Uint8      volume;
-
-	/* Fake audio handler, in case we can't open the real thing */
-	SDL_Thread *bogus_audio;
+	SDL_AudioStream* stream = nullptr;
 
 	/* Functions for getting and setting a hash indexed by Uint16 */
 	/* We use a sparse tiered pointer page scheme :-)
diff --git a/maclib/Mac_Wave.cpp b/maclib/Mac_Wave.cpp
index 1d9a11b8..5c9f7df9 100644
--- a/maclib/Mac_Wave.cpp
+++ b/maclib/Mac_Wave.cpp
@@ -21,8 +21,7 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include "SDL_endian.h"
-#include "SDL_rwops.h"
+#include <SDL3/SDL.h>
 #include "Mac_Wave.h"
 
 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
@@ -115,7 +114,7 @@ Wave:: Load(const char *wavefile, Uint16 desired_rate)
 	/* Copy malloc()'d data to new'd data */
 	sound_data = new Uint8[sound_datalen];
 	memcpy(sound_data, samples, sound_datalen);
-	SDL_FreeWAV(samples);
+	SDL_free(samples);
 
 	/* Set the desired sample frequency */
 	Frequency(desired_rate);
@@ -290,11 +289,8 @@ Wave:: Load(Mac_ResData *snd, Uint16 desired_rate)
 
 		/* Fill in the audio spec */
 		spec.freq = sample_rate;
-		spec.format = AUDIO_U8;		/* The only format? */
+		spec.format = SDL_AUDIO_U8;		/* The only format? */
 		spec.channels = snd_channels;
-		spec.samples = 4096;
-		spec.callback = NULL;
-		spec.userdata = NULL;
 
 		/* Save the audio data */
 		sound_datalen = num_samples*snd_channels;
@@ -507,7 +503,7 @@ int
 Wave:: Save(const char *wavefile)
 {
 	/* Normally, these chunks come consecutively in a WAVE file */
-	SDL_RWops *dst;
+	SDL_IOStream *dst;
 	Uint32 wavelen;
 	struct WaveFMT {
 		Uint32	FMTchunk;
@@ -521,7 +517,7 @@ Wave:: Save(const char *wavefile)
 	} format;
 
 	/* Open the WAV file for writing */
-	dst = SDL_RWFromFile(wavefile, "wb");
+	dst = SDL_IOFromFile(wavefile, "wb");
 	if ( dst == NULL ) {
 		error("Couldn't open %s for writing", wavefile);
 		return(-1);
@@ -538,28 +534,28 @@ Wave:: Save(const char *wavefile)
 	format.bitspersample = (spec.format&0xFF);
 
 	/* Swap the WAVE format information to little-endian format */
-	format.fmtlen		= SDL_SwapLE32(format.fmtlen);
-	format.encoding		= SDL_SwapLE16(format.encoding);
-	format.channels		= SDL_SwapLE16(format.channels);
-	format.frequency	= SDL_SwapLE32(format.frequency);
-	format.byterate		= SDL_SwapLE32(format.byterate);
-	format.samplesize	= SDL_SwapLE16(format.samplesize);
-	format.bitspersample	= SDL_SwapLE16(format.bitspersample);
+	format.fmtlen		= SDL_Swap32LE(format.fmtlen);
+	format.encoding		= SDL_Swap16LE(format.encoding);
+	format.channels		= SDL_Swap16LE(format.channels);
+	format.frequency	= SDL_Swap32LE(format.frequency);
+	format.byterate		= SDL_Swap32LE(format.byterate);
+	format.samplesize	= SDL_Swap16LE(format.samplesize);
+	format.bitspersample	= SDL_Swap16LE(format.bitspersample);
 
 	/* Figure out how big the RIFF chunk will be */
 	wavelen = sizeof(Uint32)+sizeof(format)+2*sizeof(Uint32)+sound_datalen;
 
 	/* Save the WAVE */
-	if ( ! SDL_RWwrite(dst, "RIFF", sizeof(Uint32), 1) ||
-	     ! SDL_WriteLE32(dst, wavelen) ||
-	     ! SDL_RWwrite(dst, "WAVE", sizeof(Uint32), 1) ||
-	     ! SDL_RWwrite(dst, &format, sizeof(format), 1) ||
-	     ! SDL_RWwrite(dst, "data", sizeof(Uint32), 1) ||
-	     ! SDL_WriteLE32(dst, sound_datalen) ||
-	     ! SDL_RWwrite(dst, sound_data, sound_datalen, 1) ||
-	     					(SDL_RWclose(dst) != 0) ) {
+	if ( ! SDL_WriteIO(dst, "RIFF", sizeof(Uint32)) ||
+	     ! SDL_WriteU32LE(dst, wavelen) ||
+	     ! SDL_WriteIO(dst, "WAVE", sizeof(Uint32)) ||
+	     ! SDL_WriteIO(dst, &format, sizeof(format)) ||
+	     ! SDL_WriteIO(dst, "data", sizeof(Uint32)) ||
+	     ! SDL_WriteU32LE(dst, sound_datalen) ||
+	     ! SDL_WriteIO(dst, sound_data, sound_datalen) ||
+	     					(SDL_CloseIO(dst) != 0) ) {
 		error("Couldn't write to %s", wavefile);
-		SDL_RWclose(dst);
+		SDL_CloseIO(dst);
 		return(-1);
 	}
 	return(0);
diff --git a/maclib/Mac_Wave.h b/maclib/Mac_Wave.h
index 0c179897..b228e87b 100644
--- a/maclib/Mac_Wave.h
+++ b/maclib/Mac_Wave.h
@@ -21,7 +21,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
-#include "SDL_audio.h"
+#include <SDL3/SDL.h>
 #include "Mac_Resource.h"
 
 class Wave {
diff --git a/maclib/bitesex.h b/maclib/bitesex.h
index 1fbeb864..df937bbe 100644
--- a/maclib/bitesex.h
+++ b/maclib/bitesex.h
@@ -1,10 +1,10 @@
 #ifndef _bitesex_h
 #define _bitesex_h
 
-#include "SDL_endian.h"
+#include <SDL3/SDL.h>
 
-#define bytesex32(x)	(x = SDL_SwapBE32(x))
-#define bytesex16(x)	(x = SDL_SwapBE16(x))
+#define bytesex32(x)	(x = SDL_Swap32BE(x))
+#define bytesex16(x)	(x = SDL_Swap16BE(x))
 
 /* Swap bytes from big-endian to this machine's type.
    The input data is assumed to be always in big-endian format.
diff --git a/maclib/playwave.cpp b/maclib/playwave.cpp
index c9e941c3..b7935c20 100644
--- a/maclib/playwave.cpp
+++ b/maclib/playwave.cpp
@@ -25,10 +25,10 @@
 
 #include "SDL.h"
 #include "SDL_audio.h"
-#include "SDL_mutex.h"
+#include "SDL_Mutex.h"
 #include "Mac_Wave.h"
 
-static SDL_mutex *done;
+static SDL_Mutex *done;
 static Wave *wave;
 static Uint8 silence;
 
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
 			exit(1);
 	}
 	spec = wave->Spec();
-	silence = ((spec->format&AUDIO_U8) ? 0x80 : 0x00);
+	silence = ((spec->format&SDL_AUDIO_U8) ? 0x80 : 0x00);
 	spec->callback = fillerup;
 
 #ifdef SAVE_THE_WAVES
diff --git a/main.cpp b/main.cpp
index 732e9f2c..667208e3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -10,

(Patch may be truncated, please check the link at the top of this post.)