From f11b6516dafee0b225763b0010fbe955566928c9 Mon Sep 17 00:00:00 2001 From: Ville Lindholm Date: Thu, 28 May 2026 21:54:55 +0300 Subject: [PATCH] WIP: port renderer + supporting layers to SDL 3 (builds clean) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes phases 3-6 of the migration plan. After this commit, the codebase compiles and links against pure SDL 3 (no compat shim). The binary is unverified at runtime but the build is clean. Renderer (graphics/gfxengine.{cpp,h}): - Replace SDL_SetVideoMode + SDL_Flip + page-flip machinery with SDL_CreateWindow + SDL_CreateRenderer + a streaming SDL_Texture. The CPU-side back buffer (softbuf) is now always ARGB8888; legacy HW/double-buffer/page flags are dead. - flip() does a single full-frame SDL_UpdateTexture + SDL_RenderClear + SDL_RenderTexture + SDL_RenderPresent each frame. The dirtyrect iteration is retained only to drive widget phys_refresh() callbacks. - SDL_SetRenderLogicalPresentation gives us letterbox scaling for free. - SDL_SetRenderVSync replaces glSDL_VSync. - title()/cursor() ported to SDL 3 window/cursor APIs. Surface API (graphics/sprite.c, filters.c, window.cpp, sofont.cpp, region.c): - SDL_FreeSurface → SDL_DestroySurface - SDL_FillRect → SDL_FillSurfaceRect - SDL_SetClipRect → SDL_SetSurfaceClipRect - SDL_SetColorKey(s, flags, key) → SDL_SetSurfaceColorKey(s, bool, key) - SDL_SetAlpha(s, flags, a) → SDL_SetSurfaceAlphaMod + BlendMode - SDL_SetColors → SDL_SetSurfacePalette - SDL_CreateRGBSurface(...) → SDL_CreateSurface(w, h, format_enum) - SDL_DisplayFormat[Alpha] → SDL_ConvertSurface(s, ARGB8888) - SDL_MapRGB(surf->format, ...) → SDL_MapSurfaceRGB(surf, ...) - surface->format->Field → SDL_GetPixelFormatDetails(surf->format)->field - surface->format->Amask test → SDL_ISPIXELFORMAT_ALPHA - surface->clip_rect → SDL_GetSurfaceClipRect Events (kobo.cpp): - SDL_{KEYDOWN,KEYUP,QUIT,VIDEOEXPOSE,MOUSE*,JOY*} → SDL_EVENT_* - SDL_ACTIVEEVENT (with gain check) → SDL_EVENT_WINDOW_FOCUS_LOST - ev.key.keysym.sym → ev.key.key (.unicode → text input, deferred) - SDLK_PRINT/SYSREQ → SDLK_PRINTSCREEN; lowercase SDLK_p/y/n → uppercase - ev.motion.x/y for button events → ev.button.x/y (struct layout differs) - KMOD_META → SDL_KMOD_GUI - SDL_INIT_NOPARACHUTE → SDL_Init(0) (no parachute by default in SDL 3) Keymap (gamectl.{cpp,h}): - SDLKey → SDL_Keycode - SDLK_KP{1..9} → SDLK_KP_{1..9} Stubs deferred for later phases (binary will run but with degraded behavior): - sound/audio.c: _start_SDL_output returns -1 immediately; SDL 1.2 audio callback model needs full rewrite onto SDL_AudioStream. - kobo.cpp init_js/close_js: SDL 3 joystick API uses instance IDs; re-port deferred. - states.cpp SDL_WM_GrabInput/SDL_EnableUNICODE: need window pointer exposed from gfxengine; stubbed. - gamectl.cpp SDL_EnableKeyRepeat: removed; relies on ev.key.repeat. Other adjustments: - options.cpp: GFX_DRIVER_GLSDL menu paths removed; show vsync option always (renderer handles it). - sound/a_wave.c: AUDIO_S8/AUDIO_S16SYS → SDL_AUDIO_S8/S16, SDL_FreeWAV → SDL_free. - gfxengine.cpp: SDL_putenv("SDL_VIDEO_CENTERED=1") obsolete (handled by SDL_CreateWindow defaults). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- gamectl.cpp | 18 +-- gamectl.h | 18 +-- graphics/filters.c | 87 ++++++-------- graphics/gfxengine.cpp | 263 +++++++++++++++++++---------------------- graphics/gfxengine.h | 5 +- graphics/region.c | 13 +- graphics/sofont.cpp | 43 ++++--- graphics/sprite.c | 67 ++++++----- graphics/window.cpp | 39 +++--- kobo.cpp | 120 +++++++------------ manage.h | 4 +- options.cpp | 37 +++--- sound/a_wave.c | 8 +- sound/audio.c | 28 +++++ states.cpp | 14 +++ 15 files changed, 378 insertions(+), 386 deletions(-) diff --git a/gamectl.cpp b/gamectl.cpp index 48c7054..1307e41 100644 --- a/gamectl.cpp +++ b/gamectl.cpp @@ -54,7 +54,10 @@ void gamecontrol_t::init(int always_fire) down = 0; shot = 0; movekey_pressed = 0; - SDL_EnableKeyRepeat(r_delay, r_interval); + // SDL 3 removed SDL_EnableKeyRepeat; OS-level key repeat fires + // SDL_EVENT_KEY_DOWN with ev.key.repeat set. r_delay/r_interval + // retained in case we re-implement software repeat later. + (void)r_delay; (void)r_interval; } @@ -68,9 +71,8 @@ void gamecontrol_t::repeat(int delay, int interval) { r_delay = delay; r_interval = interval; - //Temporary kludge - should apply repeat to - //all switch inputs, not just the keyboard! - SDL_EnableKeyRepeat(delay, interval); + // SDL_EnableKeyRepeat is gone in SDL 3. Stored for future + // software-side repeat handling. } @@ -80,7 +82,7 @@ void gamecontrol_t::clear() } -int gamecontrol_t::map(SDLKey sym) +int gamecontrol_t::map(SDL_Keycode sym) { /* FIXME: This should be replaced by a configurable mapping system. @@ -137,7 +139,7 @@ FIXME: This should be replaced by a configurable mapping system. case SDLK_ESCAPE: return BTN_EXIT; case SDLK_PAUSE: - case SDLK_p: + case SDLK_P: return BTN_PAUSE; case SDLK_SPACE: return BTN_START; @@ -148,9 +150,9 @@ FIXME: This should be replaced by a configurable mapping system. return BTN_INC; case SDLK_KP_MINUS: return BTN_DEC; - case SDLK_y: + case SDLK_Y: return BTN_YES; - case SDLK_n: + case SDLK_N: return BTN_NO; case SDLK_BACKSPACE: return BTN_BACK; diff --git a/gamectl.h b/gamectl.h index 640e945..89af8cf 100644 --- a/gamectl.h +++ b/gamectl.h @@ -26,14 +26,14 @@ #include "sdl_compat.h" #include "config.h" -#define KEY_KP_DOWN SDLK_KP2 -#define KEY_KP_LEFT SDLK_KP4 -#define KEY_KP_UP SDLK_KP8 -#define KEY_KP_RIGHT SDLK_KP6 -#define KEY_KP_DL SDLK_KP1 -#define KEY_KP_DR SDLK_KP3 -#define KEY_KP_UL SDLK_KP7 -#define KEY_KP_UR SDLK_KP9 +#define KEY_KP_DOWN SDLK_KP_2 +#define KEY_KP_LEFT SDLK_KP_4 +#define KEY_KP_UP SDLK_KP_8 +#define KEY_KP_RIGHT SDLK_KP_6 +#define KEY_KP_DL SDLK_KP_1 +#define KEY_KP_DR SDLK_KP_3 +#define KEY_KP_UL SDLK_KP_7 +#define KEY_KP_UR SDLK_KP_9 enum buttons_t @@ -105,7 +105,7 @@ class gamecontrol_t static void init(int always_fire); static void repeat(int delay, int interval); static void clear(); - static int map(SDLKey sym); + static int map(SDL_Keycode sym); static void process(); // Call every frame! static void press(int k); static void release(int k); diff --git a/graphics/filters.c b/graphics/filters.c index 37d8d22..9b744de 100644 --- a/graphics/filters.c +++ b/graphics/filters.c @@ -235,33 +235,17 @@ int s_filter_rgba8(s_bank_t *b, unsigned first, unsigned frames, s_filter_args_t *args) { unsigned i; - SDL_PixelFormat fmt; - memset(&fmt, 0, sizeof(fmt)); - fmt.BitsPerPixel = 32; - fmt.BytesPerPixel = 4; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - fmt.Rmask = 0xff000000; - fmt.Gmask = 0x00ff0000; - fmt.Bmask = 0x0000ff00; - fmt.Amask = 0x000000ff; -#else - fmt.Rmask = 0x000000ff; - fmt.Gmask = 0x0000ff00; - fmt.Bmask = 0x00ff0000; - fmt.Amask = 0xff000000; -#endif for(i = 0; i < frames; ++i) { SDL_Surface *tmp; s_sprite_t *s = s_get_sprite_b(b, first+i); if(!s) continue; - tmp = SDL_ConvertSurface(s->surface, &fmt, - SDL_SWSURFACE); + tmp = SDL_ConvertSurface(s->surface, SDL_PIXELFORMAT_RGBA32); if(!tmp) return -1; - SDL_FreeSurface(s->surface); + SDL_DestroySurface(s->surface); s->surface = tmp; } return 0; @@ -289,7 +273,7 @@ int s_filter_dither(s_bank_t *b, unsigned first, unsigned frames, switch (s_blitmode) { case S_BLITMODE_AUTO: - if(s->surface->format->Amask) + if(SDL_ISPIXELFORMAT_ALPHA(s->surface->format)) ar = ag = ab = 8; break; case S_BLITMODE_OPAQUE: @@ -458,7 +442,8 @@ int s_filter_dither(s_bank_t *b, unsigned first, unsigned frames, static void tweak_ck(SDL_Surface *s) { int x, y; - if(s->format->BitsPerPixel != 32) + const SDL_PixelFormatDetails *fmt = SDL_GetPixelFormatDetails(s->format); + if(!fmt || fmt->bits_per_pixel != 32) return; for(y = 0; y < s->h; ++y) { @@ -488,53 +473,54 @@ int s_filter_displayformat(s_bank_t * b, unsigned first, unsigned frames, switch(s_blitmode) { case S_BLITMODE_AUTO: - if(s->surface->format->Amask) - SDL_SetAlpha(s->surface, - SDL_SRCALPHA | - SDL_RLEACCEL, + if(SDL_ISPIXELFORMAT_ALPHA(s->surface->format)) + { + SDL_SetSurfaceAlphaMod(s->surface, SDL_ALPHA_OPAQUE); + SDL_SetSurfaceBlendMode(s->surface, + SDL_BLENDMODE_BLEND); + } else - SDL_SetColorKey(s->surface, SDL_RLEACCEL, 0); + SDL_SetSurfaceColorKey(s->surface, false, 0); break; case S_BLITMODE_OPAQUE: - SDL_SetColorKey(s->surface, SDL_RLEACCEL, 0); + SDL_SetSurfaceColorKey(s->surface, false, 0); break; case S_BLITMODE_COLORKEY: - SDL_SetColorKey(s->surface, - SDL_SRCCOLORKEY | SDL_RLEACCEL, - SDL_MapRGB(s->surface->format, + SDL_SetSurfaceColorKey(s->surface, true, + SDL_MapSurfaceRGB(s->surface, s_colorkey.r, s_colorkey.g, s_colorkey.b)); break; case S_BLITMODE_ALPHA: - SDL_SetAlpha(s->surface, - SDL_SRCALPHA | SDL_RLEACCEL, - s_alpha); + SDL_SetSurfaceAlphaMod(s->surface, s_alpha); + SDL_SetSurfaceBlendMode(s->surface, + SDL_BLENDMODE_BLEND); break; } + // SDL 3 dropped SDL_DisplayFormat. We always convert sprites + // to the back-buffer format (ARGB8888); see gfxengine.cpp. if(args->x) { - if(s->surface->format->Amask) + if(SDL_ISPIXELFORMAT_ALPHA(s->surface->format)) tweak_ck(s->surface); - tmp = SDL_DisplayFormat(s->surface); - if(s->surface->format->Amask) - SDL_SetColorKey(tmp, - SDL_SRCCOLORKEY | SDL_RLEACCEL, - SDL_MapRGB(tmp->format, 0,0,0)); + tmp = SDL_ConvertSurface(s->surface, + SDL_PIXELFORMAT_ARGB8888); + if(tmp && SDL_ISPIXELFORMAT_ALPHA(s->surface->format)) + SDL_SetSurfaceColorKey(tmp, true, + SDL_MapSurfaceRGB(tmp, 0,0,0)); } else { - if(s->surface->format->Amask) - tmp = SDL_DisplayFormatAlpha(s->surface); - else - tmp = SDL_DisplayFormat(s->surface); + tmp = SDL_ConvertSurface(s->surface, + SDL_PIXELFORMAT_ARGB8888); } if(!tmp) return -1; - SDL_FreeSurface(s->surface); + SDL_DestroySurface(s->surface); s->surface = tmp; } return 0; @@ -900,18 +886,13 @@ int s_filter_scale(s_bank_t *b, unsigned first, unsigned frames, if(!s) continue; params.src = s->surface; - params.dst = SDL_CreateRGBSurface(SDL_SWSURFACE, - params.max_x, params.max_y, 32, -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); -#else - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); -#endif + params.dst = SDL_CreateSurface(params.max_x, params.max_y, + SDL_PIXELFORMAT_RGBA32); if(!params.dst) return -1; #ifdef DEBUG - SDL_FillRect(params.dst, NULL, - SDL_MapRGB(params.dst->format, 255, 128, 0)); + SDL_FillSurfaceRect(params.dst, NULL, + SDL_MapSurfaceRGB(params.dst, 255, 128, 0)); #endif /* Deal with SFont marker row */ @@ -957,7 +938,7 @@ int s_filter_scale(s_bank_t *b, unsigned first, unsigned frames, break; } - SDL_FreeSurface(s->surface); + SDL_DestroySurface(s->surface); s->surface = params.dst; } b->w = params.max_x; diff --git a/graphics/gfxengine.cpp b/graphics/gfxengine.cpp index a8a3b32..b848deb 100644 --- a/graphics/gfxengine.cpp +++ b/graphics/gfxengine.cpp @@ -40,6 +40,9 @@ gfxengine_t::gfxengine_t() { gfxengine = this; /* Uurgh! Kludge. */ + sdl_window = NULL; + sdl_renderer = NULL; + fb_texture = NULL; screen_surface = NULL; softbuf = NULL; fullwin = NULL; @@ -443,10 +446,13 @@ void gfxengine_t::dither(int type, int _broken_rgba8) if(_dither) { + // SDL 3: back buffer is always ARGB8888 (8 bits per channel, + // no loss). The legacy formula was 1 << (Rloss - 1); for 8 bpc + // the dithering amplitude collapses to 0. df->args.x = 0; - df->args.r = 1<<(screen_surface->format->Rloss-1); - df->args.g = 1<<(screen_surface->format->Gloss-1); - df->args.b = 1<<(screen_surface->format->Bloss-1); + df->args.r = 0; + df->args.g = 0; + df->args.b = 0; } else df->args.x = df->args.r = df->args.g = df->args.b = 0; @@ -732,8 +738,8 @@ void gfxengine_t::title(const char *win, const char *icon) { _title = win; _icontitle = icon; - if(screen_surface) - SDL_WM_SetCaption(_title, _icontitle); + if(sdl_window) + SDL_SetWindowTitle(sdl_window, _title); } @@ -743,97 +749,94 @@ void gfxengine_t::title(const char *win, const char *icon) int gfxengine_t::show() { - int flags = 0; - if(!is_open) return -1; if(is_showing) return 0; - if(_centered && !_fullscreen) - SDL_putenv((char *)"SDL_VIDEO_CENTERED=1"); - log_printf(DLOG, "Opening screen...\n"); if(!SDL_WasInit(SDL_INIT_VIDEO)) - if(SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) + if(!SDL_InitSubSystem(SDL_INIT_VIDEO)) { - log_printf(ELOG, "Failed to initialize SDL!\n"); + log_printf(ELOG, "Failed to initialize SDL: %s\n", + SDL_GetError()); return -2; } - if(_doublebuf) - flags |= SDL_DOUBLEBUF | SDL_HWSURFACE; - else - { - if(!_shadow) - flags |= SDL_HWSURFACE; - } - + // SDL 3 window + renderer model. + // + // The kobo engine renders into a CPU-side back buffer (softbuf) via + // SDL_BlitSurface/SDL_FillSurfaceRect, and uploads the result to a + // streaming SDL_Texture once per frame. This preserves the entire + // software-compositing code path inherited from SDL 1.2 (window.cpp, + // sprite.c, filters.c, sofont.cpp), while letting the GPU handle + // scaling and presentation. SDL_DOUBLEBUF / SDL_HWSURFACE / page- + // flipping flags are obsolete and ignored. + Uint64 win_flags = 0; if(_fullscreen) - flags |= SDL_FULLSCREEN; + win_flags |= SDL_WINDOW_FULLSCREEN; - flags |= xflags; - - screen_surface = SDL_SetVideoMode(_width, _height, _depth, flags); - if(!screen_surface) + sdl_window = SDL_CreateWindow(_title ? _title : "Kobo Deluxe", + _width, _height, win_flags); + if(!sdl_window) { - log_printf(ELOG, "Failed to open display!\n"); + log_printf(ELOG, "Failed to open window: %s\n", SDL_GetError()); return -3; } - if((screen_surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) + sdl_renderer = SDL_CreateRenderer(sdl_window, NULL); + if(!sdl_renderer) { - if(!_doublebuf) - { - log_printf(WLOG, "Could not get" - " single buffered display.\n"); - doublebuffer(1); - } - } - else - { - if(_doublebuf) - { - log_printf(WLOG, "Could not get" - " double buffered display.\n"); - doublebuffer(0); - } + log_printf(ELOG, "Failed to create renderer: %s\n", + SDL_GetError()); + SDL_DestroyWindow(sdl_window); + sdl_window = NULL; + return -4; } - if((screen_surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE) - { - if(_shadow) - { - softbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, - _width, _height, - screen_surface->format->BitsPerPixel, - screen_surface->format->Rmask, - screen_surface->format->Gmask, - screen_surface->format->Bmask, - screen_surface->format->Amask); - if(!softbuf) - { - log_printf(WLOG, "Failed to create shadow buffer! " - "Trying direct rendering.\n"); - shadow(0); - } - } - } - else - { - if(_shadow) - log_printf(WLOG, "Shadow buffer requested; " - "relying on SDL's shadow buffer.\n"); - else - { - log_printf(WLOG, "Could not get h/w display surface.\n"); - shadow(0); //...which means we're using SDL's shadow. - } - } + // Letterbox the back buffer when the window is resized / fullscreen. + SDL_SetRenderLogicalPresentation(sdl_renderer, _width, _height, + SDL_LOGICAL_PRESENTATION_LETTERBOX); + SDL_SetRenderVSync(sdl_renderer, _vsync ? 1 : 0); + + // The back buffer is always a CPU-side ARGB8888 surface. + softbuf = SDL_CreateSurface(_width, _height, SDL_PIXELFORMAT_ARGB8888); + if(!softbuf) + { + log_printf(ELOG, "Failed to create back buffer: %s\n", + SDL_GetError()); + SDL_DestroyRenderer(sdl_renderer); + SDL_DestroyWindow(sdl_window); + sdl_renderer = NULL; + sdl_window = NULL; + return -5; + } + screen_surface = softbuf; // alias for legacy code paths + + fb_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, _width, _height); + if(!fb_texture) + { + log_printf(ELOG, "Failed to create framebuffer texture: %s\n", + SDL_GetError()); + SDL_DestroySurface(softbuf); + SDL_DestroyRenderer(sdl_renderer); + SDL_DestroyWindow(sdl_window); + softbuf = screen_surface = NULL; + sdl_renderer = NULL; + sdl_window = NULL; + return -6; + } + SDL_SetTextureScaleMode(fb_texture, + (_scalemode == GFX_SCALE_NEAREST) ? + SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR); + + if(_cursor) + SDL_ShowCursor(); + else + SDL_HideCursor(); - SDL_WM_SetCaption(_title, _icontitle); - SDL_ShowCursor(_cursor); cs_engine_set_size(csengine, _width, _height); csengine->filter = use_interpolation; @@ -886,12 +889,27 @@ void gfxengine_t::hide(void) w = w->next; } + if(fb_texture) + { + SDL_DestroyTexture(fb_texture); + fb_texture = NULL; + } if(softbuf) { - SDL_FreeSurface(softbuf); + SDL_DestroySurface(softbuf); softbuf = NULL; } screen_surface = NULL; + if(sdl_renderer) + { + SDL_DestroyRenderer(sdl_renderer); + sdl_renderer = NULL; + } + if(sdl_window) + { + SDL_DestroyWindow(sdl_window); + sdl_window = NULL; + } is_showing = 0; } @@ -940,13 +958,15 @@ void gfxengine_t::__invalidate(int page, SDL_Rect *rect, window_t *window) /* Clip to screen (stolen from SDL_surface.c) */ SDL_Rect dr = *rect; + SDL_Rect screen_clip; + SDL_GetSurfaceClipRect(screen_surface, &screen_clip); int Amin, Amax, Bmin, Bmax; /* Horizontal intersection */ Amin = dr.x; Amax = Amin + dr.w; - Bmin = screen_surface->clip_rect.x; - Bmax = Bmin + screen_surface->clip_rect.w; + Bmin = screen_clip.x; + Bmax = Bmin + screen_clip.w; if(Bmin > Amin) Amin = Bmin; dr.x = Amin; @@ -957,8 +977,8 @@ void gfxengine_t::__invalidate(int page, SDL_Rect *rect, window_t *window) /* Vertical intersection */ Amin = dr.y; Amax = Amin + dr.h; - Bmin = screen_surface->clip_rect.y; - Bmax = Bmin + screen_surface->clip_rect.h; + Bmin = screen_clip.y; + Bmax = Bmin + screen_clip.h; if(Bmin > Amin) Amin = Bmin; dr.y = Amin; @@ -1062,7 +1082,12 @@ void gfxengine_t::cursor(int csr) { _cursor = csr; if(screen_surface) - SDL_ShowCursor(csr); + { + if(csr) + SDL_ShowCursor(); + else + SDL_HideCursor(); + } } @@ -1168,8 +1193,8 @@ void gfxengine_t::frame() SDL_Event ev; while(SDL_PollEvent(&ev)) { - if(ev.type == SDL_KEYDOWN) - if(ev.key.keysym.sym == SDLK_ESCAPE) + if(ev.type == SDL_EVENT_KEY_DOWN) + if(ev.key.key == SDLK_ESCAPE) stop(); } } @@ -1236,41 +1261,15 @@ void gfxengine_t::refresh_rect(SDL_Rect *r) void gfxengine_t::flip() { - if(!screen_surface) + if(!screen_surface || !sdl_renderer || !fb_texture) return; - // Init dirtyrect table flipping, if necessary. - switch(_pages) - { - case -1: - if(!_doublebuf) - frontpage = backpage = 0; - else if(frontpage == backpage) - { - frontpage = 0; - backpage = 1; - } - break; - case 0: - frontpage = backpage = 0; - invalidate(); - break; - case 1: - frontpage = backpage = 0; - break; - case 2: - case 3: - if(frontpage == backpage) - { - frontpage = 0; - backpage = 1; - } - break; - } - - // Process the dirtyrects. - int i; - for(i = 0; i < dirtyrects[backpage]; ++i) + // SDL 3 has no hardware page flipping; we always present one back + // buffer per frame. Keep the dirtyrect iteration only to drive the + // phys_refresh() callbacks that window widgets rely on; the upload + // is a single full-surface copy regardless. + frontpage = backpage = 0; + for(int i = 0; i < dirtyrects[backpage]; ++i) { if(dirtywtable[backpage][i]) { @@ -1282,36 +1281,12 @@ void gfxengine_t::flip() else refresh_rect(&dirtytable[backpage][i]); } + dirtyrects[backpage] = 0; - // Perform the actual flip or update - if(_shadow) - { - for(i = 0; i < dirtyrects[backpage]; ++i) - SDL_BlitSurface(softbuf, - &dirtytable[backpage][i], - screen_surface, - &dirtytable[backpage][i]); - } - if(_doublebuf) - { - dirtyrects[backpage] = 0; - if(_pages == -1) - { - backpage = !backpage; - frontpage = !frontpage; - } - else if(_pages > 1) - { - backpage = (backpage + 1) % _pages; - frontpage = (frontpage + 1) % _pages; - } - SDL_Flip(screen_surface); - } - else - { - SDL_UpdateRects(screen_surface, dirtyrects[0], dirtytable[0]); - dirtyrects[0] = 0; - } + SDL_UpdateTexture(fb_texture, NULL, softbuf->pixels, softbuf->pitch); + SDL_RenderClear(sdl_renderer); + SDL_RenderTexture(sdl_renderer, fb_texture, NULL, NULL); + SDL_RenderPresent(sdl_renderer); } diff --git a/graphics/gfxengine.h b/graphics/gfxengine.h index d937d01..5e02a9c 100644 --- a/graphics/gfxengine.h +++ b/graphics/gfxengine.h @@ -208,7 +208,10 @@ class gfxengine_t gfx_drivers_t _driver; gfx_scalemodes_t _scalemode; int _clamping; - SDL_Surface *screen_surface; + SDL_Window *sdl_window; + SDL_Renderer *sdl_renderer; + SDL_Texture *fb_texture; + SDL_Surface *screen_surface; // alias for softbuf in SDL 3 SDL_Surface *softbuf; int backpage; int frontpage; diff --git a/graphics/region.c b/graphics/region.c index f72b45d..7cb0029 100644 --- a/graphics/region.c +++ b/graphics/region.c @@ -44,7 +44,9 @@ static Uint32 gp2(SDL_Surface *surface, int x, int y) static Uint32 gp3(SDL_Surface *surface, int x, int y) { - int bpp = surface->format->BytesPerPixel; + const SDL_PixelFormatDetails *fmt = + SDL_GetPixelFormatDetails(surface->format); + int bpp = fmt ? fmt->bytes_per_pixel : 3; Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; #if (SDL_BYTEORDER == SDL_BIG_ENDIAN) return p[0] << 16 | p[1] << 8 | p[2]; @@ -74,7 +76,14 @@ RGN_region *RGN_ScanMask(SDL_Surface *src, Uint32 key) RGN_FreeRegion(rgn); return NULL; } - switch(src->format->BytesPerPixel) + const SDL_PixelFormatDetails *src_fmt = + SDL_GetPixelFormatDetails(src->format); + if(!src_fmt) + { + RGN_FreeRegion(rgn); + return NULL; + } + switch(src_fmt->bytes_per_pixel) { case 1: gp = gp1; diff --git a/graphics/sofont.cpp b/graphics/sofont.cpp index 3ade135..032ffd9 100644 --- a/graphics/sofont.cpp +++ b/graphics/sofont.cpp @@ -20,7 +20,7 @@ SoFont::SoFont() SoFont::~SoFont() { if(picture) - SDL_FreeSurface(picture); + SDL_DestroySurface(picture); delete[]CharPos; delete[]CharOffset; delete[]Spacing; @@ -45,7 +45,11 @@ namespace SoFontUtilities return 0; } - Bpp = Surface->format->BytesPerPixel; + const SDL_PixelFormatDetails *fmt = + SDL_GetPixelFormatDetails(Surface->format); + if(!fmt) + return 0; + Bpp = fmt->bytes_per_pixel; bits = ((Uint8 *) Surface->pixels) + Y * Surface->pitch + X * Bpp; @@ -63,10 +67,10 @@ namespace SoFontUtilities case 3: // Format/endian independent Uint8 r, g, b; - r = *((bits) + Surface->format->Rshift / 8); - g = *((bits) + Surface->format->Gshift / 8); - b = *((bits) + Surface->format->Bshift / 8); - return SDL_MapRGB(Surface->format, r, g, b); + r = *((bits) + fmt->Rshift / 8); + g = *((bits) + fmt->Gshift / 8); + b = *((bits) + fmt->Bshift / 8); + return SDL_MapSurfaceRGB(Surface, r, g, b); break; case 4: return *((Uint32 *) Surface->pixels + @@ -94,7 +98,11 @@ namespace SoFontUtilities return; } - Bpp = Surface->format->BytesPerPixel; + const SDL_PixelFormatDetails *fmt = + SDL_GetPixelFormatDetails(Surface->format); + if(!fmt) + return; + Bpp = fmt->bytes_per_pixel; bits = ((Uint8 *) Surface->pixels) + Y * Surface->pitch + X * Bpp; @@ -113,10 +121,11 @@ namespace SoFontUtilities case 3: // Format/endian independent Uint8 r, g, b; - SDL_GetRGB(c, Surface->format, &r, &g, &b); - *((bits) + Surface->format->Rshift / 8) = r; - *((bits) + Surface->format->Gshift / 8) = g; - *((bits) + Surface->format->Bshift / 8) = b; + SDL_GetRGB(c, fmt, SDL_GetSurfacePalette(Surface), + &r, &g, &b); + *((bits) + fmt->Rshift / 8) = r; + *((bits) + fmt->Gshift / 8) = g; + *((bits) + fmt->Bshift / 8) = b; break; case 4: *((Uint32 *) Surface->pixels + @@ -224,7 +233,7 @@ bool SoFont::DoStartNewChar(Sint32 x) if(!picture) return false; return SoFontGetPixel(picture, x, 0) == - SDL_MapRGB(picture->format, 255, 0, 255); + SDL_MapSurfaceRGB(picture, 255, 0, 255); } void SoFont::CleanSurface() @@ -233,7 +242,7 @@ void SoFont::CleanSurface() return; int x = 0, y = 0; - Uint32 pix = SDL_MapRGB(picture->format, 255, 0, 255); + Uint32 pix = SDL_MapSurfaceRGB(picture, 255, 0, 255); while(x < picture->w) { @@ -259,7 +268,7 @@ bool SoFont::load(SDL_Surface * FontSurface) return false; } if(picture) - SDL_FreeSurface(picture); + SDL_DestroySurface(picture); picture = FontSurface; height = picture->h - 1; while(x < picture->w) @@ -499,8 +508,10 @@ void SoFont::CenteredString(SDL_Surface * Surface, const char *text, { if(!picture) return; - CenteredString(Surface, Surface->clip_rect.w / 2, - Surface->clip_rect.h / 2, text, clip); + SDL_Rect surf_clip; + SDL_GetSurfaceClipRect(Surface, &surf_clip); + CenteredString(Surface, surf_clip.w / 2, + surf_clip.h / 2, text, clip); } void SoFont::PutStringCleverCursor(SDL_Surface * Surface, const char *text, diff --git a/graphics/sprite.c b/graphics/sprite.c index 31c6ee1..a4d0722 100644 --- a/graphics/sprite.c +++ b/graphics/sprite.c @@ -177,7 +177,7 @@ s_sprite_t *s_new_sprite_b(s_bank_t *b, unsigned frame) else { if(s->surface) - SDL_FreeSurface(s->surface); + SDL_DestroySurface(s->surface); s->surface = NULL; } return s; @@ -212,7 +212,7 @@ void s_delete_sprite_b(s_bank_t *b, unsigned frame) if(!b->sprites[frame]) return; if(b->sprites[frame]->surface) - SDL_FreeSurface(b->sprites[frame]->surface); + SDL_DestroySurface(b->sprites[frame]->surface); b->sprites[frame]->surface = NULL; free(b->sprites[frame]); b->sprites[frame] = NULL; @@ -355,44 +355,51 @@ static int extract_sprite(s_bank_t *bank, unsigned frame, if(!s_new_sprite_b(bank, frame)) return -2; - tmp = SDL_CreateRGBSurface(src->flags, - from->w, from->h, - src->format->BitsPerPixel, - src->format->Rmask, - src->format->Gmask, - src->format->Bmask, - src->format->Amask ); + const SDL_PixelFormatDetails *src_fmt = + SDL_GetPixelFormatDetails(src->format); + if(!src_fmt) + return -3; + + tmp = SDL_CreateSurface(from->w, from->h, src->format); if(!tmp) return -3; /* Copy the pixel data */ - if(SDL_LockSurface(src) < 0) + if(!SDL_LockSurface(src)) { log_printf(ELOG, "sprite: extract_sprite() failed to lock surface!\n"); - SDL_FreeSurface(tmp); + SDL_DestroySurface(tmp); return -4; } for(y = 0; y < tmp->h; ++y) { char *s = (char *)src->pixels + src->pitch * (y + from->y) + - from->x * src->format->BytesPerPixel; + from->x * src_fmt->bytes_per_pixel; char *d = (char *)tmp->pixels + tmp->pitch * y; - memcpy(d, s, src->format->BytesPerPixel * tmp->w); + memcpy(d, s, src_fmt->bytes_per_pixel * tmp->w); } SDL_UnlockSurface(src); /* Copy palette, if any */ - if(src->format->palette) - SDL_SetColors(tmp, src->format->palette->colors, 0, - src->format->palette->ncolors); + SDL_Palette *src_palette = SDL_GetSurfacePalette(src); + if(src_palette) + SDL_SetSurfacePalette(tmp, src_palette); - /* Copy alpha and colorkey */ - if(src->flags & SDL_SRCALPHA) - SDL_SetAlpha(tmp, src->flags & (SDL_SRCALPHA | SDL_RLEACCEL), - src->format->alpha); - if(src->flags & SDL_SRCCOLORKEY) - SDL_SetColorKey(tmp, src->flags & (SDL_SRCCOLORKEY | SDL_RLEACCEL), - src->format->colorkey); + /* Copy alpha modulation and blend mode */ + Uint8 src_alpha = SDL_ALPHA_OPAQUE; + SDL_GetSurfaceAlphaMod(src, &src_alpha); + SDL_SetSurfaceAlphaMod(tmp, src_alpha); + SDL_BlendMode src_blend = SDL_BLENDMODE_NONE; + SDL_GetSurfaceBlendMode(src, &src_blend); + SDL_SetSurfaceBlendMode(tmp, src_blend); + + /* Copy colorkey */ + if(SDL_SurfaceHasColorKey(src)) + { + Uint32 src_key = 0; + SDL_GetSurfaceColorKey(src, &src_key); + SDL_SetSurfaceColorKey(tmp, true, src_key); + } bank->sprites[frame]->surface = tmp; @@ -466,21 +473,23 @@ int s_load_image(s_container_t *c, unsigned bank, const char *name) return -1; } - b = s_new_bank(c, bank, 1, src->clip_rect.w, src->clip_rect.h); + SDL_Rect src_clip; + SDL_GetSurfaceClipRect(src, &src_clip); + b = s_new_bank(c, bank, 1, src_clip.w, src_clip.h); if(!b) { log_printf(ELOG, "sprite: Failed to allocate bank for \"%s\"!\n", name); return -2; } - if(extract_sprite(b, 0, src, &src->clip_rect) < 0) + if(extract_sprite(b, 0, src, &src_clip) < 0) { log_printf(ELOG, "sprite: Something went wrong while" " extracting sprite \"%s\".\n", name); return -3; } - SDL_FreeSurface(src); + SDL_DestroySurface(src); __run_plugins(b, 0, 1); return 0; } @@ -506,7 +515,7 @@ int s_load_sprite(s_container_t *c, unsigned bank, unsigned frame, return -1; } - from = src->clip_rect; + SDL_GetSurfaceClipRect(src, &from); if( (from.w != b->w) || (from.h != b->h) ) { log_printf(ELOG, "sprite: Warning: Sprite \"%s\" cropped" @@ -522,7 +531,7 @@ int s_load_sprite(s_container_t *c, unsigned bank, unsigned frame, return -3; } - SDL_FreeSurface(src); + SDL_DestroySurface(src); __run_plugins(b, frame, 1); return 0; } @@ -582,7 +591,7 @@ int s_load_bank(s_container_t *c, unsigned bank, unsigned w, unsigned h, } ++frame; } - SDL_FreeSurface(src); + SDL_DestroySurface(src); __run_plugins(b, 0, frames); return 0; } diff --git a/graphics/window.cpp b/graphics/window.cpp index 29c4332..9ba0d18 100644 --- a/graphics/window.cpp +++ b/graphics/window.cpp @@ -50,7 +50,7 @@ window_t::window_t() window_t::~window_t() { if(_offscreen && surface) - SDL_FreeSurface(surface); + SDL_DestroySurface(surface); if(selected == this) selected = NULL; unlink(); @@ -64,7 +64,7 @@ void window_t::init(gfxengine_t *e) ys = engine->ys; if(_offscreen && surface) { - SDL_FreeSurface(surface); + SDL_DestroySurface(surface); surface = NULL; } _offscreen = 0; @@ -137,14 +137,10 @@ int window_t::offscreen() return 0; // Already offscreen! visible(0); _offscreen = 1; - SDL_Surface *s = SDL_CreateRGBSurface(SDL_SWSURFACE, - phys_rect.w, phys_rect.h, - 32, 0xff000000, 0x00ff0000, - 0x0000ff00, 0x000000ff); - if(!s) - return -1; - surface = SDL_DisplayFormat(s); - SDL_FreeSurface(s); + // SDL 3: back buffer is always ARGB8888; offscreen windows use + // the same format to allow direct blits without conversion. + surface = SDL_CreateSurface(phys_rect.w, phys_rect.h, + SDL_PIXELFORMAT_ARGB8888); if(!surface) return -1; return 0; @@ -163,7 +159,7 @@ void window_t::_select() SDL_Rect r = phys_rect; selected = this; if(surface) - SDL_SetClipRect(surface, &r); + SDL_SetSurfaceClipRect(surface, &r); } @@ -248,7 +244,7 @@ Uint32 window_t::map_rgb(Uint8 r, Uint8 g, Uint8 b) return 0; if(surface) - return SDL_MapRGB(surface->format, r, g, b); + return SDL_MapSurfaceRGB(surface, r, g, b); else return 0xffffff; } @@ -263,7 +259,7 @@ Uint32 window_t::map_rgb(Uint32 rgb) Uint8 b = rgb & 0xff; if(surface) - return SDL_MapRGB(surface->format, r, g, b); + return SDL_MapSurfaceRGB(surface, r, g, b); else return 0xffffff; } @@ -283,7 +279,7 @@ void window_t::colorkey(Uint32 color) return; if(!_offscreen) return; - SDL_SetColorKey(surface, SDL_SRCCOLORKEY, color); + SDL_SetSurfaceColorKey(surface, true, color); } void window_t::colorkey() @@ -294,7 +290,7 @@ void window_t::colorkey() return; if(!_offscreen) return; - SDL_SetColorKey(surface, 0, 0); + SDL_SetSurfaceColorKey(surface, false, 0); } void window_t::alpha(float a) @@ -305,7 +301,8 @@ void window_t::alpha(float a) return; if(!_offscreen) return; - SDL_SetAlpha(surface, SDL_SRCALPHA, (int)(a * 255.0)); + SDL_SetSurfaceAlphaMod(surface, (Uint8)(a * 255.0f)); + SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND); } @@ -476,13 +473,13 @@ void window_t::clear(SDL_Rect *r) dr.y += phys_rect.y; } if((-1 == bg_bank) && (-1 == bg_frame)) - SDL_FillRect(surface, &dr, bgcolor); + SDL_FillSurfaceRect(surface, &dr, bgcolor); else { s_sprite_t *s = engine->get_sprite(bg_bank, bg_frame); if(!s || !s->surface) { - SDL_FillRect(surface, &dr, bgcolor); + SDL_FillSurfaceRect(surface, &dr, bgcolor); return; } SDL_BlitSurface(s->surface, &sr, surface, &dr); @@ -507,7 +504,7 @@ void window_t::point(int _x, int _y) r.w = x2 - _x; r.h = y2 - _y; if(surface) - SDL_FillRect(surface, &r, fgcolor); + SDL_FillSurfaceRect(surface, &r, fgcolor); } @@ -527,7 +524,7 @@ void window_t::fillrect(int _x, int _y, int w, int h) r.w = x2 - _x; r.h = y2 - _y; if(surface) - SDL_FillRect(surface, &r, fgcolor); + SDL_FillSurfaceRect(surface, &r, fgcolor); } @@ -556,7 +553,7 @@ void window_t::fillrect_fxp(int _x, int _y, int w, int h) r.w = w; r.h = h; if(surface) - SDL_FillRect(surface, &r, fgcolor); + SDL_FillSurfaceRect(surface, &r, fgcolor); } diff --git a/kobo.cpp b/kobo.cpp index 5ae1baa..efb3d8b 100644 --- a/kobo.cpp +++ b/kobo.cpp @@ -440,14 +440,14 @@ int KOBO_main::quit_requested() { switch(e.type) { - case SDL_QUIT: + case SDL_EVENT_QUIT: exit_game_fast = 1; break; - case SDL_VIDEOEXPOSE: + case SDL_EVENT_WINDOW_EXPOSED: gengine->invalidate(); break; - case SDL_KEYUP: - switch(e.key.keysym.sym) + case SDL_EVENT_KEY_UP: + switch(e.key.key) { case SDLK_ESCAPE: if(escape_hammering()) @@ -459,9 +459,7 @@ int KOBO_main::quit_requested() break; } } - if(exit_game_fast) - return 1; - return SDL_QuitRequested(); + return exit_game_fast ? 1 : 0; } @@ -1205,7 +1203,7 @@ int KOBO_main::load_graphics(prefs_t *p) return -10; RGN_FreeRegion(logo_region); logo_region = RGN_ScanMask(s->surface, - SDL_MapRGB(s->surface->format, 255, 255, 255)); + SDL_MapSurfaceRGB(s->surface, 255, 255, 255)); if(!logo_region) { log_printf(ELOG, "Could not create logo region!\n"); @@ -1239,52 +1237,20 @@ int KOBO_main::load_sounds(prefs_t *p, int render_all) int KOBO_main::init_js(prefs_t *p) { - /* Activate Joystick sub-sys if we are using it */ + // SDL 3 joystick API uses instance IDs and SDL_GetJoysticks / + // SDL_OpenJoystick. Port deferred — disabled for now. if(p->use_joystick) - { - if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) - { - log_printf(ELOG, "Error setting up joystick!\n"); - return -1; - } - p->number_of_joysticks = SDL_NumJoysticks(); - if(p->number_of_joysticks > 0) - { - SDL_JoystickEventState(SDL_ENABLE); - if(p->joystick_no >= p->number_of_joysticks) - p->joystick_no = 0; - joystick = SDL_JoystickOpen(p->joystick_no); - if(!joystick) - { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - return -2; - } - } - else - { - log_printf(ELOG, "No joysticks found!\n"); - joystick = NULL; - return -3; - } - - } + log_printf(WLOG, "Joystick support not yet ported to SDL 3.\n"); + p->number_of_joysticks = 0; + joystick = NULL; return 0; } void KOBO_main::close_js() { - if(!SDL_WasInit(SDL_INIT_JOYSTICK)) - return; - - if(!joystick) - return; - - if(SDL_JoystickOpened(0)) - SDL_JoystickClose(joystick); + // Stub: see init_js. Joystick port pending. joystick = NULL; - - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } @@ -1597,8 +1563,8 @@ void kobo_gfxengine_t::frame() int k, ms; switch (ev.type) { - case SDL_KEYDOWN: - switch(ev.key.keysym.sym) + case SDL_EVENT_KEY_DOWN: + switch(ev.key.key) { #ifdef PROFILE_AUDIO case SDLK_F10: @@ -1607,7 +1573,7 @@ void kobo_gfxengine_t::frame() case SDLK_F12: audio_print_info(); break; - case SDLK_r: + case SDLK_R: { audio_channel_stop(-1, -1); int startt = SDL_GetTicks(); @@ -1626,9 +1592,9 @@ void kobo_gfxengine_t::frame() break; case SDLK_RETURN: ms = SDL_GetModState(); - if(ms & (KMOD_CTRL | KMOD_SHIFT | KMOD_META)) + if(ms & (SDL_KMOD_CTRL | SDL_KMOD_SHIFT | SDL_KMOD_GUI)) break; - if(!(ms & KMOD_ALT)) + if(!(ms & SDL_KMOD_ALT)) break; km.pause_game(); prefs->fullscreen = !prefs->fullscreen; @@ -1637,21 +1603,23 @@ void kobo_gfxengine_t::frame() OS_RESTART_VIDEO; stop(); return; - case SDLK_PRINT: - case SDLK_SYSREQ: + case SDLK_PRINTSCREEN: // FIXME: Doesn't this trigger when entering names and stuff...? - case SDLK_s: + case SDLK_S: gengine->screenshot(); break; default: break; } - k = gamecontrol.map(ev.key.keysym.sym); + k = gamecontrol.map(ev.key.key); gamecontrol.press(k); - gsm.press(k, ev.key.keysym.unicode); + // SDL 3 dropped per-keydown unicode; text input is via + // SDL_EVENT_TEXT_INPUT. Pass 0 for the unicode arg until + // the high-score name-entry path is re-wired. + gsm.press(k, 0); break; - case SDL_KEYUP: - if((ev.key.keysym.sym == SDLK_ESCAPE) && km.escape_hammering()) + case SDL_EVENT_KEY_UP: + if((ev.key.key == SDLK_ESCAPE) && km.escape_hammering()) { km.pause_game(); prefs->fullscreen = 0; @@ -1674,7 +1642,7 @@ void kobo_gfxengine_t::frame() gsm.push(&st_error); return; } - k = gamecontrol.map(ev.key.keysym.sym); + k = gamecontrol.map(ev.key.key); if(k == SDLK_PAUSE) { gamecontrol.press(BTN_PAUSE); @@ -1686,19 +1654,17 @@ void kobo_gfxengine_t::frame() gsm.release(k); } break; - case SDL_VIDEOEXPOSE: + case SDL_EVENT_WINDOW_EXPOSED: gengine->invalidate(); break; - case SDL_ACTIVEEVENT: - // Any type of focus loss should activate pause mode! - if(!ev.active.gain) - km.pause_game(); + case SDL_EVENT_WINDOW_FOCUS_LOST: + km.pause_game(); break; - case SDL_QUIT: + case SDL_EVENT_QUIT: /*gsm.press(BTN_CLOSE);*/ km.brutal_quit(); break; - case SDL_JOYBUTTONDOWN: + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: if(ev.jbutton.button == km.js_fire) { gamecontrol.press(BTN_FIRE); @@ -1710,14 +1676,14 @@ void kobo_gfxengine_t::frame() gsm.press(BTN_START); } break; - case SDL_JOYBUTTONUP: + case SDL_EVENT_JOYSTICK_BUTTON_UP: if(ev.jbutton.button == km.js_fire) { gamecontrol.release(BTN_FIRE); gsm.release(BTN_FIRE); } break; - case SDL_JOYAXISMOTION: + case SDL_EVENT_JOYSTICK_AXIS_MOTION: // FIXME: We will want to allow these to be // redefined, but for now, this works ;-) if(ev.jaxis.axis == km.js_lr) @@ -1762,7 +1728,8 @@ void kobo_gfxengine_t::frame() } } - case SDL_MOUSEMOTION: + break; + case SDL_EVENT_MOUSE_MOTION: mouse_x = (int)(ev.motion.x / gengine->xscale()) - km.xoffs; mouse_y = (int)(ev.motion.y / gengine->yscale()) - km.yoffs; if(prefs->use_mouse) @@ -1770,9 +1737,9 @@ void kobo_gfxengine_t::frame() mouse_x - 8 - MARGIN - WSIZE/2, mouse_y - MARGIN - WSIZE/2); break; - case SDL_MOUSEBUTTONDOWN: - mouse_x = (int)(ev.motion.x / gengine->xscale()) - km.xoffs; - mouse_y = (int)(ev.motion.y / gengine->yscale()) - km.yoffs; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + mouse_x = (int)(ev.button.x / gengine->xscale()) - km.xoffs; + mouse_y = (int)(ev.button.y / gengine->yscale()) - km.yoffs; gsm.press(BTN_FIRE); if(prefs->use_mouse) { @@ -1794,9 +1761,9 @@ void kobo_gfxengine_t::frame() gamecontrol.press(BTN_FIRE); } break; - case SDL_MOUSEBUTTONUP: - mouse_x = (int)(ev.motion.x / gengine->xscale()) - km.xoffs; - mouse_y = (int)(ev.motion.y / gengine->yscale()) - km.yoffs; + case SDL_EVENT_MOUSE_BUTTON_UP: + mouse_x = (int)(ev.button.x / gengine->xscale()) - km.xoffs; + mouse_y = (int)(ev.button.y / gengine->yscale()) - km.yoffs; if(prefs->use_mouse) { gamecontrol.mouse_position( @@ -2086,8 +2053,9 @@ int main(int argc, char *argv[]) if(prefs->cmd_noparachute) { + // SDL 3 has no parachute / signal handler by default. SDL_Quit(); - SDL_Init(SDL_INIT_NOPARACHUTE); + SDL_Init(0); } km.open_logging(prefs); diff --git a/manage.h b/manage.h index 6f90932..c71776b 100644 --- a/manage.h +++ b/manage.h @@ -87,8 +87,8 @@ class _manage static void lost_myship(); static void destroyed_a_core(); static void add_score(int sc); - static void key_down(SDLKey sym); - static void key_up(SDLKey sym); + static void key_down(SDL_Keycode sym); + static void key_up(SDL_Keycode sym); static int title_blank() { return blank; } static void select_next(int redraw_map = 1); static void select_prev(int redraw_map = 1); diff --git a/options.cpp b/options.cpp index 97b5ac5..6c21648 100644 --- a/options.cpp +++ b/options.cpp @@ -187,18 +187,13 @@ void video_options_t::build() prf->videodriver = GFX_DRIVER_SDL2D; space(); xoffs = 0.55; - switch(prf->videodriver) - { - case GFX_DRIVER_SDL2D: - list("Display Buffering Mode", &prf->doublebuf, OS_RESTART_VIDEO); - item("Single", 0); - item("Double", 1); - yesno("Software Shadow Buffer", &prf->shadow, OS_RESTART_VIDEO); - break; - case GFX_DRIVER_GLSDL: - yesno("Vertical Retrace Sync", &prf->vsync, OS_RESTART_VIDEO); - break; - } + // Only the SDL 2D driver remains since the SDL 3 migration; the + // OpenGL driver is now handled by the SDL renderer itself. + list("Display Buffering Mode", &prf->doublebuf, OS_RESTART_VIDEO); + item("Single", 0); + item("Double", 1); + yesno("Software Shadow Buffer", &prf->shadow, OS_RESTART_VIDEO); + yesno("Vertical Retrace Sync", &prf->vsync, OS_RESTART_VIDEO); list("Display Buffer Pages", &prf->pages, OS_UPDATE_ENGINE); item("Assume Standard", -1); item("Always Repaint", 0); @@ -243,13 +238,9 @@ void graphics_options_t::build() item("2x2 Filter", 0); item("4x4 Filter", 1); item("Random", 2); - switch(prf->videodriver) - { - case GFX_DRIVER_GLSDL: - yesno("Broken RGBA8 (OpenGL)", &prf->broken_rgba8, - OS_RELOAD_GRAPHICS); - break; - } + // "Broken RGBA8" was a glSDL workaround for cards that supported + // RGB8 but not RGBA8 textures; SDL 3's renderer handles this + // transparently. space(); yesno("Alpha Blending", &prf->alpha, OS_RELOAD_GRAPHICS); space(); @@ -396,11 +387,15 @@ void control_options_t::build() item("5 frames", 5); space(); - if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) + if(!SDL_InitSubSystem(SDL_INIT_JOYSTICK)) label("Could not initialize joysticks!"); else { - prf->number_of_joysticks = SDL_NumJoysticks(); + // SDL 3: SDL_NumJoysticks → SDL_GetJoysticks(&count). + int njs = 0; + SDL_JoystickID *jids = SDL_GetJoysticks(&njs); + SDL_free(jids); + prf->number_of_joysticks = njs; yesno("Use Joystick", &prf->use_joystick, OS_RESTART_INPUT | OS_REBUILD); if(prf->use_joystick) diff --git a/sound/a_wave.c b/sound/a_wave.c index aacbbfc..81c2c4f 100644 --- a/sound/a_wave.c +++ b/sound/a_wave.c @@ -832,15 +832,15 @@ int audio_wave_load(int wid, const char *name, int looped) { switch (spec.format) { - case AUDIO_S8: + case SDL_AUDIO_S8: wavetab[wid].format = AF_MONO8; break; - case AUDIO_S16SYS: + case SDL_AUDIO_S16: wavetab[wid].format = AF_MONO16; break; default: log_printf(ELOG, "sound_load(): Unsupported wave format!\n"); - SDL_FreeWAV((Uint8 *)(wavetab[wid].data.si8)); + SDL_free(wavetab[wid].data.si8); res = -1; break; } @@ -862,7 +862,7 @@ int audio_wave_load(int wid, const char *name, int looped) audio_wave_load_mem(wid, data, size, looped); if(using_loadwav) - SDL_FreeWAV(data); + SDL_free(data); else free(data); diff --git a/sound/audio.c b/sound/audio.c index 61f7007..cd498ab 100644 --- a/sound/audio.c +++ b/sound/audio.c @@ -49,6 +49,29 @@ #include #include "logger.h" +/* + * SDL 3 migration: the SDL 1.2 audio API (SDL_OpenAudio + callback model, + * AUDIO_S16SYS, SDL_LockAudio/PauseAudio/CloseAudio, SDL_AudioSpec.samples + * and .callback) is gone. SDL 3 uses SDL_OpenAudioDeviceStream with a + * pull-stream callback. Porting that bridge is a separate phase; for now + * we provide local stubs so the engine links, and _start_SDL_output() + * below returns -1 so audio is silently disabled. + */ +#define AUDIO_S16SYS 0 +#define SDL_OpenAudio(a, b) (-1) +#define SDL_CloseAudio() ((void)0) +#define SDL_PauseAudio(x) ((void)0) +#define SDL_LockAudio() ((void)0) +#define SDL_UnlockAudio() ((void)0) +typedef struct { + int freq; + Uint16 format; + Uint8 channels; + Uint16 samples; + void (*callback)(void *userdata, Uint8 *stream, int len); +} kobo_legacy_audio_spec_t; +#define SDL_AudioSpec kobo_legacy_audio_spec_t + #include "a_struct.h" #include "a_commands.h" #include "a_control.h" @@ -569,6 +592,10 @@ static int _start_oss_output() static int _start_SDL_output(void) { + log_printf(WLOG, "audio.c: SDL 3 audio backend not yet ported;" + " sound disabled.\n"); + return -1; +#if 0 SDL_AudioSpec as; SDL_AudioSpec audiospec; @@ -629,6 +656,7 @@ static int _start_SDL_output(void) _audio_running = 1; SDL_PauseAudio(0); return 0; +#endif } diff --git a/states.cpp b/states.cpp index efe78cf..1a34af5 100644 --- a/states.cpp +++ b/states.cpp @@ -23,6 +23,20 @@ #include "sdl_compat.h" #include + +/* + * SDL 3 migration: SDL_WM_GrabInput and SDL_EnableUNICODE are gone. + * Replacements (SDL_SetWindowMouseGrab and SDL_StartTextInput) both + * require the window pointer, which we don't yet expose from gfxengine. + * Stub them out so the code links; mouse-capture and unicode text-input + * (high-score name entry) will be re-wired once gfxengine exposes the + * SDL_Window handle. + */ +#define SDL_GRAB_QUERY 0 +#define SDL_GRAB_ON 1 +#define SDL_GRAB_OFF 0 +#define SDL_WM_GrabInput(x) (SDL_GRAB_OFF) +#define SDL_EnableUNICODE(x) ((void)0) #ifndef M_PI # define M_PI 3.14159265358979323846 /* pi */ #endif