diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dcd6a6..c7a3c16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,11 +35,9 @@ check_symbol_exists(_vsnprintf stdio.h HAVE__VSNPRINTF) # --------------------------------------------------------------------------- # Third-party libraries # --------------------------------------------------------------------------- -# This codebase targets SDL 1.2 and SDL_image 1.2. CMake's bundled FindSDL -# / FindSDL_image modules locate these directly; on macOS with Homebrew, -# `brew install sdl12-compat sdl_image` works. -find_package(SDL REQUIRED) -find_package(SDL_image REQUIRED) +# Migrating to SDL 3. Homebrew: `brew install sdl3 sdl3_image`. +find_package(SDL3 CONFIG REQUIRED) +find_package(SDL3_image CONFIG REQUIRED) if(KOBO_ENABLE_OPENGL) find_package(OpenGL) @@ -122,9 +120,8 @@ target_compile_definitions(kobo_deps INTERFACE target_include_directories(kobo_deps INTERFACE ${CMAKE_CURRENT_BINARY_DIR} # for generated aconfig.h ${CMAKE_CURRENT_SOURCE_DIR} # for config.h - ${SDL_INCLUDE_DIR} ) -target_link_libraries(kobo_deps INTERFACE ${SDL_LIBRARY} ${SDL_IMAGE_LIBRARIES}) +target_link_libraries(kobo_deps INTERFACE SDL3::SDL3 SDL3_image::SDL3_image) if(HAVE_OPENGL) target_compile_definitions(kobo_deps INTERFACE HAVE_OPENGL) diff --git a/dashboard.cpp b/dashboard.cpp index 385b61f..5a4abd1 100644 --- a/dashboard.cpp +++ b/dashboard.cpp @@ -309,33 +309,32 @@ void dashboard_window_t::nibble(int tool) } gengine->invalidate(); gengine->flip(); - if(gengine->doublebuffer()) + // SDL 3: one logical back buffer; previously a second pass was + // only needed when actual hardware double-buffering was in use. + for(i = 0; i < dt * 4; ++i) { - for(i = 0; i < dt * 4; ++i) + if(last_index >= NIBBLE_TILES) + break; + switch (tool) { - if(last_index >= NIBBLE_TILES) - break; - switch (tool) - { - case 0: - fillrect(x[last_index] + - NIBBLE_W / 2, - y[last_index] + - NIBBLE_H / 2, - NIBBLE_W, - NIBBLE_H); - break; - default: - sprite(x[last_index] - 8 + - NIBBLE_W / 2, - y[last_index] - 8 + - NIBBLE_H / 2, - B_BRUSHES, - tool - 1); - break; - } - ++last_index; + case 0: + fillrect(x[last_index] + + NIBBLE_W / 2, + y[last_index] + + NIBBLE_H / 2, + NIBBLE_W, + NIBBLE_H); + break; + default: + sprite(x[last_index] - 8 + + NIBBLE_W / 2, + y[last_index] - 8 + + NIBBLE_H / 2, + B_BRUSHES, + tool - 1); + break; } + ++last_index; } } mode(DASHBOARD_BLACK); 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 dfdebf2..89af8cf 100644 --- a/gamectl.h +++ b/gamectl.h @@ -23,17 +23,17 @@ #ifndef _KOBO_GAMECTL_H_ #define _KOBO_GAMECTL_H_ -#include "glSDL.h" +#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/CMakeLists.txt b/graphics/CMakeLists.txt index 081aec0..f149d72 100644 --- a/graphics/CMakeLists.txt +++ b/graphics/CMakeLists.txt @@ -2,7 +2,6 @@ add_library(graphics STATIC cs.c sprite.c filters.c - glSDL.c gfxengine.cpp window.cpp sofont.cpp diff --git a/graphics/filters.c b/graphics/filters.c index 106041e..9b744de 100644 --- a/graphics/filters.c +++ b/graphics/filters.c @@ -22,8 +22,8 @@ #include #include #include "logger.h" -#include "glSDL.h" -#include "SDL_image.h" +#include "sdl_compat.h" +#include #include "sprite.h" #include "filters.h" @@ -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 c70a4b1..b618dd3 100644 --- a/graphics/gfxengine.cpp +++ b/graphics/gfxengine.cpp @@ -28,8 +28,8 @@ #include "gfxengine.h" #include "filters.h" -#include "SDL_image.h" -#include "glSDL.h" +#include +#include "sdl_compat.h" #include "sofont.h" #include "window.h" @@ -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; @@ -51,15 +54,10 @@ gfxengine_t::gfxengine_t() sf1 = df = dsf = acf = NULL; gfx = NULL; csengine = NULL; - _driver = GFX_DRIVER_SDL2D; - _shadow = 1; - _doublebuf = 1; - _pages = -1; _vsync = 1; _fullscreen = 0; _centered = 0; use_interpolation = 1; - _depth = 0; _title = "GfxEngine v0.4"; _icontitle = "GfxEngine"; _cursor = 1; @@ -68,11 +66,9 @@ gfxengine_t::gfxengine_t() _autoinvalidate = 1; _scalemode = GFX_SCALE_NEAREST; _clamping = 0; - xflags = 0; _dither = 0; _dither_type = 0; - broken_rgba8 = 0; alpha_threshold = 0; _brightness = 1.0; @@ -91,10 +87,7 @@ gfxengine_t::gfxengine_t() for(int i = 0; i < CS_LAYERS ; ++i) xratio[i] = yratio[i] = 0.0; - dirtyrects[0] = 0; - dirtyrects[1] = 0; - frontpage = 0; - backpage = 1; + dirtyrects = 0; screenshot_count = 0; } @@ -157,75 +150,23 @@ void gfxengine_t::scale(float x, float y) void gfxengine_t::mode(int bits, int fullscreen) { + // SDL 3 uses the renderer's pixel format directly; the legacy depth + // argument is accepted for API compatibility but ignored. + (void)bits; int was_showing = is_showing; hide(); - - int olddepth = _depth; - _depth = bits; - if(_depth != olddepth) - reload(); _fullscreen = fullscreen; - if(was_showing) show(); } -void gfxengine_t::driver(gfx_drivers_t drv) -{ - int was_showing = is_showing; - hide(); - - _driver = drv; - - if(was_showing) - show(); -} - -void gfxengine_t::doublebuffer(int use) -{ - if(_doublebuf == use) - return; - - int was_showing = is_showing; - hide(); - - _doublebuf = use; - - if(was_showing) - show(); -} - -void gfxengine_t::pages(int np) -{ - _pages = np; -} - void gfxengine_t::vsync(int use) { if(_vsync == use) return; - - int was_showing = is_showing; - hide(); - _vsync = use; - - if(was_showing) - show(); -} - -void gfxengine_t::shadow(int use) -{ - if(_shadow == use) - return; - - int was_showing = is_showing; - hide(); - - _shadow = use; - - if(was_showing) - show(); + if(sdl_renderer) + SDL_SetRenderVSync(sdl_renderer, use ? 1 : 0); } void gfxengine_t::autoinvalidate(int use) @@ -432,9 +373,9 @@ void gfxengine_t::clampcolor(Uint8 r, Uint8 g, Uint8 b, Uint8 a) void gfxengine_t::dither(int type, int _broken_rgba8) { + (void)_broken_rgba8; // legacy OpenGL workaround; no-op in SDL 3 _dither = type >= 0; _dither_type = type; - broken_rgba8 = _broken_rgba8; if(!df) return; @@ -443,23 +384,13 @@ void gfxengine_t::dither(int type, int _broken_rgba8) if(_dither) { - if(_driver == GFX_DRIVER_GLSDL) - { - //Klugde for glSDL, which doesn't give us a faked - //screen surface - while we're interested only in - //the *texture* depth; not the display depth! - df->args.r = df->args.g = df->args.b = 0; - //Another kludge, because some cards support RGB8 - //(24 bit) textures, but not RGBA8 (32 bit). - df->args.x = broken_rgba8; - } - else - { - 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); - } + // 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 = 0; + df->args.g = 0; + df->args.b = 0; } else df->args.x = df->args.r = df->args.g = df->args.b = 0; @@ -685,10 +616,8 @@ void gfxengine_t::on_frame(cs_engine_t *e) } -int gfxengine_t::open(int objects, int extraflags) +int gfxengine_t::open(int objects) { - xflags = extraflags; - if(is_open) return show(); @@ -745,8 +674,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); } @@ -756,131 +685,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; } - switch(_driver) - { - case GFX_DRIVER_SDL2D: - break; - case GFX_DRIVER_GLSDL: - if(!_doublebuf) - { - log_printf(WLOG, "Only double buffering is supported" - " with OpenGL drivers!\n"); - doublebuffer(1); - } - if(_shadow) - { - log_printf(WLOG, "Shadow buffer not supported" - " with OpenGL drivers!\n"); - shadow(0); - } - break; - } - - switch(_driver) - { - case GFX_DRIVER_SDL2D: - /* Nothing extra */ - break; - case GFX_DRIVER_GLSDL: - flags |= SDL_GLSDL; - break; - } - - 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; - glSDL_VSync(_vsync); - 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(_driver != GFX_DRIVER_GLSDL) + sdl_renderer = SDL_CreateRenderer(sdl_window, NULL); + if(!sdl_renderer) { - if((screen_surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) - { - 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) + // 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) { - 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); - } - } + 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 - { - 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. - } - } + SDL_HideCursor(); - SDL_WM_SetCaption(_title, _icontitle); - SDL_ShowCursor(_cursor); cs_engine_set_size(csengine, _width, _height); csengine->filter = use_interpolation; @@ -933,12 +825,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; } @@ -946,54 +853,37 @@ void gfxengine_t::hide(void) void gfxengine_t::invalidate(SDL_Rect *rect, window_t *window) { - switch(_pages) - { - case -1: - if(_doublebuf) - __invalidate(1, rect, window); - __invalidate(0, rect, window); - break; - case 0: - __invalidate(0, NULL, NULL); - break; - case 3: - __invalidate(2, rect, window); - // Fallthrough! - case 2: - __invalidate(1, rect, window); - // Fallthrough! - case 1: - __invalidate(0, rect, window); - break; - } + __invalidate(rect, window); } -void gfxengine_t::__invalidate(int page, SDL_Rect *rect, window_t *window) +void gfxengine_t::__invalidate(SDL_Rect *rect, window_t *window) { if(!screen_surface) return; - if(!rect || (_pages == 0)) + if(!rect) { - dirtyrects[page] = 1; - dirtytable[page][0].x = 0; - dirtytable[page][0].y = 0; - dirtytable[page][0].w = screen_surface->w; - dirtytable[page][0].h = screen_surface->h; - dirtywtable[page][0] = NULL; + dirtyrects = 1; + dirtytable[0].x = 0; + dirtytable[0].y = 0; + dirtytable[0].w = screen_surface->w; + dirtytable[0].h = screen_surface->h; + dirtywtable[0] = NULL; return; } /* 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; @@ -1004,8 +894,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; @@ -1016,19 +906,18 @@ void gfxengine_t::__invalidate(int page, SDL_Rect *rect, window_t *window) if(!dr.w || !dr.h) return; - for(int i = 0; i < dirtyrects[page]; ++i) - if(memcmp(&dirtytable[page][i], &dr, sizeof(dr)) == 0) + for(int i = 0; i < dirtyrects; ++i) + if(memcmp(&dirtytable[i], &dr, sizeof(dr)) == 0) return; - if(dirtyrects[page] < MAX_DIRTYRECTS - 1) + if(dirtyrects < MAX_DIRTYRECTS - 1) { - dirtytable[page][dirtyrects[page]] = dr; - dirtywtable[page][dirtyrects[page]] = window; - ++dirtyrects[page]; + dirtytable[dirtyrects] = dr; + dirtywtable[dirtyrects] = window; + ++dirtyrects; } else - log_printf(ELOG, "gfxengine: Page %d out of dirtyrects!\n", - page); + log_printf(ELOG, "gfxengine: Out of dirtyrects!\n"); } @@ -1109,7 +998,12 @@ void gfxengine_t::cursor(int csr) { _cursor = csr; if(screen_surface) - SDL_ShowCursor(csr); + { + if(csr) + SDL_ShowCursor(); + else + SDL_HideCursor(); + } } @@ -1215,8 +1109,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(); } } @@ -1283,82 +1177,31 @@ 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) + // 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. + for(int i = 0; i < dirtyrects; ++i) { - case -1: - if(!_doublebuf) - frontpage = backpage = 0; - else if(frontpage == backpage) + if(dirtywtable[i]) { - 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) - { - if(dirtywtable[backpage][i]) - { - if(!dirtywtable[backpage][i]->visible()) + if(!dirtywtable[i]->visible()) continue; - SDL_Rect dr = dirtytable[backpage][i]; - dirtywtable[backpage][i]->phys_refresh(&dr); + SDL_Rect dr = dirtytable[i]; + dirtywtable[i]->phys_refresh(&dr); } else - refresh_rect(&dirtytable[backpage][i]); + refresh_rect(&dirtytable[i]); } + dirtyrects = 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 b473247..687fe49 100644 --- a/graphics/gfxengine.h +++ b/graphics/gfxengine.h @@ -24,21 +24,14 @@ #define GFX_BANKS 256 #define MAX_DIRTYRECTS 1024 -#define MAX_PAGES 3 #include #include #include -#include "glSDL.h" +#include "sdl_compat.h" #include "sprite.h" #include "cs.h" -enum gfx_drivers_t -{ - GFX_DRIVER_SDL2D = 0, - GFX_DRIVER_GLSDL = 1 -}; - enum gfx_scalemodes_t { GFX_SCALE_NEAREST = 0, @@ -70,25 +63,11 @@ class gfxengine_t void size(int w, int h); void centered(int c); void scale(float x, float y); - void driver(gfx_drivers_t drv); void mode(int bits, int fullscreen); - // 1: Use double buffering if possible - void doublebuffer(int use); - - // -1: Use default for shadow() and doublebuffer() settings - // 0: None; assume flipping gives you a garbage buffer - // 1: Assume flipping leaves the back buffer intact - // 2: Assume two buffers that are swapped when flipping - // 3: Assume three buffers cycled when flipping - void pages(int np); - // 1: Enable vsync, if available void vsync(int use); - // 1: Use a software shadow back buffer, if possible - void shadow(int use); - void autoinvalidate(int use); void interpolation(int inter); @@ -103,12 +82,10 @@ class gfxengine_t void wrap(int x, int y); /* Info */ - int doublebuffer() { return _doublebuf; } - int shadow() { return _shadow; } int autoinvalidate() { return _autoinvalidate; } /* Engine open/close */ - int open(int objects = 1024, int extraflags = 0); + int open(int objects = 1024); void close(); /* Data management (use while engine is open) */ @@ -172,6 +149,7 @@ class gfxengine_t /* Control */ cs_engine_t *cs() { return csengine; } + SDL_Window *window_handle() { return sdl_window; } SDL_Surface *surface(); void flip(); // Flip pages void update(); // Full update, making current draw page visible @@ -206,16 +184,16 @@ class gfxengine_t float yscale() { return ys * (1.f/256.f); } protected: - 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; - int dirtyrects[MAX_PAGES]; - SDL_Rect dirtytable[MAX_PAGES][MAX_DIRTYRECTS]; - window_t *dirtywtable[MAX_PAGES][MAX_DIRTYRECTS]; + int dirtyrects; + SDL_Rect dirtytable[MAX_DIRTYRECTS]; + window_t *dirtywtable[MAX_DIRTYRECTS]; window_t *fullwin; window_t *window; window_t *windows; // Linked list @@ -233,23 +211,17 @@ class gfxengine_t s_container_t *gfx; SoFont *fonts[GFX_BANKS]; // Kludge. cs_engine_t *csengine; - int xflags; - int _doublebuf; - int _pages; int _vsync; - int _shadow; int _fullscreen; int _centered; int _autoinvalidate; int use_interpolation; int _width, _height; - int _depth; const char *_title; const char *_icontitle; int _cursor; int _dither; int _dither_type; - int broken_rgba8; //Klugde for OpenGL (if RGBA8 ==> RGBA4) int alpha_threshold; //For noalpha() float _brightness; float _contrast; @@ -264,8 +236,7 @@ class gfxengine_t int screenshot_count; - void __invalidate(int page, SDL_Rect *rect = NULL, - window_t *window = NULL); + void __invalidate(SDL_Rect *rect = NULL, window_t *window = NULL); void refresh_rect(SDL_Rect *r); static void on_frame(cs_engine_t *e); diff --git a/graphics/glSDL.c b/graphics/glSDL.c deleted file mode 100644 index 599a1ff..0000000 --- a/graphics/glSDL.c +++ /dev/null @@ -1,2328 +0,0 @@ -/*(LGPL) ------------------------------------------------------------- - glSDL 0.9 - SDL 2D API on top of OpenGL ------------------------------------------------------------- - * Copyright (C) 2001-2004, 2006-2007 David Olofson - * This code is released under the terms of the GNU LGPL. - */ - -#define _GLSDL_NO_REDEFINES_ -#include "glSDL.h" - -#ifdef HAVE_OPENGL - -#define LEAK_TRACKING - -#define DBG(x) /*error messages, warnings*/ -#define DBG2(x) /*texture allocation*/ -#define DBG3(x) /*chopping/tiling*/ -#define DBG4(x) /*texture uploading*/ -#define DBG5(x) /*two-way chopping/tiling*/ -#define DBG6(x) /*OpenGL lib loading*/ - -#undef CKSTATS /*colorkey statistics*/ - -/* Keep this on for now! Makes large surfaces faster. */ -#define FAKE_MAXTEXSIZE 256 - -#include -#include -#include - -#if HAS_SDL_OPENGL_H -#include "SDL_opengl.h" -#else -#ifdef WIN32 -#include -#endif -#if defined(__APPLE__) && defined(__MACH__) -#include -#include -#else -#include -#include -#endif -#endif - -#if defined(_WIN32) && !defined(APIENTRY) && \ - !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#include -#endif -#ifndef APIENTRY -#define APIENTRY -#endif - - -static inline void clip_rect(SDL_Rect *r, SDL_Rect *to) -{ - int dx1 = r->x; - int dy1 = r->y; - int dx2 = dx1 + r->w; - int dy2 = dy1 + r->h; - if(dx1 < to->x) - dx1 = to->x; - if(dy1 < to->y) - dy1 = to->y; - if(dx2 > to->x + to->w) - dx2 = to->x + to->w; - if(dy2 > to->y + to->h) - dy2 = to->y + to->h; - if(dx2 < dx1 || dy2 < dy1) - { - r->x = r->y = 0; - r->w = r->h = 0; - } - else - { - r->x = dx1; - r->y = dy1; - r->w = dx2 - dx1; - r->h = dy2 - dy1; - } -} - - -/*---------------------------------------------------------- - OpenGL interface -----------------------------------------------------------*/ - -static struct -{ - void (APIENTRY *Begin)(GLenum); - void (APIENTRY *BindTexture)(GLenum, GLuint); - void (APIENTRY *BlendFunc)(GLenum, GLenum); - void (APIENTRY *Color4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); - void (APIENTRY *DeleteTextures)(GLsizei n, const GLuint *textures); - void (APIENTRY *Disable)(GLenum cap); - void (APIENTRY *Enable)(GLenum cap); - void (APIENTRY *End)(void); - void (APIENTRY *Flush)(void); - void (APIENTRY *GenTextures)(GLsizei n, GLuint *textures); - GLenum (APIENTRY *GetError)(void); - void (APIENTRY *GetIntegerv)(GLenum pname, GLint *params); - void (APIENTRY *LoadIdentity)(void); - void (APIENTRY *MatrixMode)(GLenum mode); - void (APIENTRY *Ortho)(GLdouble left, GLdouble right, GLdouble bottom, - GLdouble top, GLdouble zNear, GLdouble zFar); - void (APIENTRY *PixelStorei)(GLenum pname, GLint param); - void (APIENTRY *ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels); - void (APIENTRY *TexCoord2f)(GLfloat s, GLfloat t); - void (APIENTRY *TexImage2D)(GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLint border, - GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *TexParameteri)(GLenum target, GLenum pname, GLint param); - void (APIENTRY *TexSubImage2D)(GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels); - void (APIENTRY *Translatef)(GLfloat x, GLfloat y, GLfloat z); - void (APIENTRY *Vertex2i)(GLint x, GLint y); - void (APIENTRY *Viewport)(GLint x, GLint y, GLsizei width, GLsizei height); - void (APIENTRY *Rotated)(GLdouble, GLdouble, GLdouble, GLdouble); - void (APIENTRY *Scalef)(GLfloat, GLfloat, GLfloat); - void (APIENTRY *PushMatrix)(void); - void (APIENTRY *PopMatrix)(void); -} gl; - - -static int GetGL(void) -{ - int i; - struct - { - const char *name; - void **fn; - } glfuncs[] = { - {"glBegin", (void *)&gl.Begin }, - {"glBindTexture", (void *)&gl.BindTexture }, - {"glBlendFunc", (void *)&gl.BlendFunc }, - {"glColor4ub", (void *)&gl.Color4ub }, - {"glDeleteTextures", (void *)&gl.DeleteTextures }, - {"glDisable", (void *)&gl.Disable }, - {"glEnable", (void *)&gl.Enable }, - {"glEnd", (void *)&gl.End }, - {"glFlush", (void *)&gl.Flush }, - {"glGenTextures", (void *)&gl.GenTextures }, - {"glGetError", (void *)&gl.GetError }, - {"glGetIntegerv", (void *)&gl.GetIntegerv }, - {"glLoadIdentity", (void *)&gl.LoadIdentity }, - {"glMatrixMode", (void *)&gl.MatrixMode }, - {"glOrtho", (void *)&gl.Ortho }, - {"glPixelStorei", (void *)&gl.PixelStorei }, - {"glReadPixels", (void *)&gl.ReadPixels }, - {"glTexCoord2f", (void *)&gl.TexCoord2f }, - {"glTexImage2D", (void *)&gl.TexImage2D }, - {"glTexParameteri", (void *)&gl.TexParameteri }, - {"glTexSubImage2D", (void *)&gl.TexSubImage2D }, - {"glTranslatef", (void *)&gl.Translatef }, - {"glVertex2i", (void *)&gl.Vertex2i }, - {"glViewport", (void *)&gl.Viewport }, - {"glRotated", (void *)&gl.Rotated }, - {"glScalef", (void *)&gl.Scalef }, - {"glPushMatrix", (void *)&gl.PushMatrix }, - {"glPopMatrix", (void *)&gl.PopMatrix }, - {NULL, NULL } - }; - for(i = 0; glfuncs[i].name; ++i) - { - *glfuncs[i].fn = SDL_GL_GetProcAddress(glfuncs[i].name); - if(!*glfuncs[i].fn) - { - DBG6(fprintf(stderr,"glSDL/wrapper ERROR: Could not get " - "OpenGL function '%s'!\n", - glfuncs[i].name);) - return -1; - } - DBG6(printf("Got OpenGL function '%s'.\n", glfuncs[i].name);) - } - return 0; -} - - -static int LoadGL(void) -{ - if(GetGL() < 0) - { - DBG6(printf("Couldn't get GL funcs! Trying to load lib...\n");) - SDL_GL_LoadLibrary(NULL); - if(GetGL() < 0) - { - DBG6(printf("Still couldn't get GL funcs!\n");) - return -1; - } - } - return 0; -} - - -static void UnloadGL(void) -{ -} - - -static void print_glerror(int point) -{ -#if (DBG(1)+0 == 1) - const char *err = ""; - switch(gl.GetError()) - { - case GL_NO_ERROR: - return; - case GL_INVALID_ENUM: - err = "GL_INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - err = "GL_INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - err = "GL_INVALID_OPERATION"; - break; - case GL_STACK_OVERFLOW: - err = "GL_STACK_OVERFLOW"; - break; - case GL_STACK_UNDERFLOW: - err = "GL_STACK_UNDERFLOW"; - break; - case GL_OUT_OF_MEMORY: - err = "GL_OUT_OF_MEMORY"; - break; - default: - err = ""; - break; - } - fprintf(stderr,"OpenGL error \"%s\" at point %d.\n", err, point); -#endif -} - - -/*---------------------------------------------------------- - OpenGL state wrapper -----------------------------------------------------------*/ - -static struct -{ - int do_blend; - int do_texture; - GLint texture; - GLenum sfactor, dfactor; -} glstate; - -static void gl_reset(void) -{ - glstate.do_blend = -1; - glstate.do_blend = -1; - glstate.texture = -1; - glstate.sfactor = 0xffffffff; - glstate.dfactor = 0xffffffff; -} - -static __inline__ void gl_do_blend(int on) -{ - if(glstate.do_blend == on) - return; - - if(on) - gl.Enable(GL_BLEND); - else - gl.Disable(GL_BLEND); - glstate.do_blend = on; -} - -static __inline__ void gl_do_texture(int on) -{ - if(glstate.do_texture == on) - return; - - if(on) - gl.Enable(GL_TEXTURE_2D); - else - gl.Disable(GL_TEXTURE_2D); - glstate.do_texture = on; -} - -static __inline__ void gl_blendfunc(GLenum sfactor, GLenum dfactor) -{ - if((sfactor == glstate.sfactor) && (dfactor == glstate.dfactor)) - return; - - gl.BlendFunc(sfactor, dfactor); - - glstate.sfactor = sfactor; - glstate.dfactor = dfactor; -} - -static __inline__ void gl_texture(GLuint tx) -{ - if(tx == (unsigned)glstate.texture) - return; - - gl.BindTexture(GL_TEXTURE_2D, tx); - glstate.texture = tx; -} - - -/*---------------------------------------------------------- - Global stuff -----------------------------------------------------------*/ - -static int initialized = 0; - -static int using_glsdl = 0; -#define USING_GLSDL (0 != using_glsdl) - -#define MAX_TEXINFOS 16384 - -static glSDL_TexInfo **texinfotab = NULL; -static GLint maxtexsize = 256; -static SDL_PixelFormat RGBfmt, RGBAfmt; - -static void UnloadTexture(glSDL_TexInfo *txi); - -static int scale = 1; -static int vsync = 1; - -static SDL_Surface *fake_screen = NULL; - - -static int glSDL_BlitGL(SDL_Surface *src, SDL_Rect *srcrect, - SDL_Surface *dst, SDL_Rect *dstrect); - - -/*---------------------------------------------------------- - glSDL Global State -----------------------------------------------------------*/ - -static struct -{ - Uint8 alpha; /* Alpha */ - Uint8 r, g, b; /* Color modulation */ - float cx, cy; /* Transform center offset */ - float sx, sy; /* Scale */ - float rot; /* Rotation */ -} state; - - -void glSDL_SetBlendAlpha(Uint8 alpha) -{ - state.alpha = alpha; -} - - -void glSDL_SetBlendColor(Uint8 r, Uint8 g, Uint8 b) -{ - state.r = r; - state.g = g; - state.b = b; -} - - -void glSDL_SetCenter(float x, float y) -{ - state.cx = x; - state.cy = y; -} - - -void glSDL_SetRotation(float angle) -{ - state.rot = angle; -} - - -void glSDL_SetScale(float x, float y) -{ - state.sx = x; - state.sy = y; -} - - -void glSDL_ResetState(void) -{ - glSDL_SetBlendAlpha(255); - glSDL_SetBlendColor(255, 255, 255); - glSDL_SetCenter(0.0f, 0.0f); - glSDL_SetRotation(0.0f); - glSDL_SetScale(1.0f, 1.0f); -} - - -/*---------------------------------------------------------- - Code -----------------------------------------------------------*/ - -/* Get texinfo for a surface. */ -static __inline__ glSDL_TexInfo *glSDL_GetTexInfo(SDL_Surface *surface) -{ - if(texinfotab) - return texinfotab[surface->unused1]; - else - return NULL; -} - - -/* Allocate a "blank" texinfo for a suface. */ -glSDL_TexInfo *glSDL_AllocTexInfo(SDL_Surface *surface) -{ - int handle, i = 0; - glSDL_TexInfo *txi; - if(!surface) - return NULL; - - txi = glSDL_GetTexInfo(surface); - if(txi) - return txi; /* There already is one! --> */ - - /* Find a free handle... */ - handle = -1; - for(i = 1; i < MAX_TEXINFOS + 1; ++i) - if(NULL == texinfotab[i]) - { - handle = i; - break; - } - - if(handle < 0) - { - DBG(fprintf(stderr, "glSDL/wrapper: Out of handles!\n")); - return NULL; - } - - /* ...and hook a new texinfo struct up to it. */ - texinfotab[handle] = (glSDL_TexInfo*)calloc(1, sizeof(glSDL_TexInfo)); - if(!texinfotab[handle]) - return NULL; - - /* Connect the surface to the new TexInfo. */ - surface->unused1 = (Uint32)handle; - - DBG2(fprintf(stderr, "glSDL/wrapper: Allocated TexInfo %d.\n", handle)); - - return texinfotab[handle]; -} - - -static void FreeTexInfo(Uint32 handle) -{ - if(handle >= MAX_TEXINFOS) - return; - if(!texinfotab[handle]) - return; - - UnloadTexture(texinfotab[handle]); - texinfotab[handle]->textures = 0; - free(texinfotab[handle]->texture); - texinfotab[handle]->texture = NULL; - free(texinfotab[handle]); - texinfotab[handle] = NULL; - DBG2(fprintf(stderr, "glSDL/wrapper: Freed TexInfo %d.\n", handle)); -} - - -/* Detach and free the texinfo of a surface. */ -void glSDL_FreeTexInfo(SDL_Surface *surface) -{ - if(!texinfotab) - return; - - if(!surface) - return; - - if(!glSDL_GetTexInfo(surface)) - return; - - FreeTexInfo(surface->unused1); - GLSDL_FIX_SURFACE(surface); -} - - -/* - * Calculate chopping/tiling of a surface to - * fit it into the smallest possible OpenGL - * texture. - */ -static int CalcChop(SDL_Surface *s, glSDL_TexInfo *txi) -{ - int rows, vw, vh; - int vertical = 0; - int texsize; - int lastw, lasth, minsize; - - vw = s->w; - vh = s->h; - - DBG3(fprintf(stderr, "w=%d, h=%d ", vw, vh)); - if(vh > vw) - { - int t = vw; - vw = vh; - vh = t; - vertical = 1; - DBG3(fprintf(stderr, "(vertical) \t")); - } - - /* - * Check whether this is a "huge" surface - at least one dimension - * must be <= than the maximum texture size, or we'll have to chop - * in both directions. - */ - if(vh > maxtexsize) - { - /* - * Very simple hack for now; we just tile - * both ways with maximum size textures. - */ - texsize = maxtexsize; - - txi->tilemode = GLSDL_TM_HUGE; - txi->texsize = texsize; - txi->tilew = texsize; - txi->tileh = texsize; - txi->tilespertex = 1; - - /* Calculate number of textures needed */ - txi->textures = (vw + texsize - 1) / texsize; - txi->textures *= (vh + texsize - 1) / texsize; - txi->texture = (int*)malloc(txi->textures * sizeof(int)); - memset(txi->texture, -1, txi->textures * sizeof(int)); - DBG5(fprintf(stderr, "two-way tiling; textures=%d\n", txi->textures)); - if(!txi->texture) - { - fprintf(stderr, "glSDL/wrapper: INTERNAL ERROR: Failed to allocate" - " texture name table!\n"); - return -3; - } - return 0; - } - - /* Calculate minimum size */ - rows = 1; - lastw = vw; - lasth = vh; - minsize = lastw > lasth ? lastw : lasth; - while(1) - { - int w, h, size; - ++rows; - w = vw / rows; - h = rows * vh; - size = w > h ? w : h; - if(size >= minsize) - { - --rows; - break; - } - lastw = w; - lasth = h; - minsize = size; - } - if(minsize > maxtexsize) - { - /* Handle multiple textures for very wide/tall surfaces. */ - minsize = maxtexsize; - rows = (vw + minsize-1) / minsize; - } - DBG3(fprintf(stderr, "==> minsize=%d ", minsize)); - DBG3(fprintf(stderr, "(rows=%d) \t", rows)); - - /* Recalculate with nearest higher power-of-2 width. */ - for(texsize = 1; texsize < minsize; texsize <<= 1) - ; - txi->texsize = texsize; - rows = (vw + texsize-1) / texsize; - DBG3(fprintf(stderr, "==> texsize=%d (rows=%d) \t", texsize, rows)); - - /* Calculate number of tiles per texture */ - txi->tilespertex = txi->texsize / vh; - DBG3(fprintf(stderr, "tilespertex=%d \t", txi->tilespertex)); - - /* Calculate number of textures needed */ - txi->textures = (rows + txi->tilespertex-1) / txi->tilespertex; - txi->texture = (int*)malloc(txi->textures * sizeof(int)); - memset(txi->texture, -1, txi->textures * sizeof(int)); - DBG3(fprintf(stderr, "textures=%d, ", txi->textures)); - if(!txi->texture) - { - fprintf(stderr, "glSDL/wrapper: INTERNAL ERROR: Failed to allocate" - " texture name table!\n"); - return -2; - } - - /* Set up tile size. (Only one axis supported here!) */ - if(1 == rows) - { - txi->tilemode = GLSDL_TM_SINGLE; - if(vertical) - { - txi->tilew = vh; - txi->tileh = vw; - } - else - { - txi->tilew = vw; - txi->tileh = vh; - } - } - else if(vertical) - { - txi->tilemode = GLSDL_TM_VERTICAL; - txi->tilew = vh; - txi->tileh = texsize; - } - else - { - txi->tilemode = GLSDL_TM_HORIZONTAL; - txi->tilew = texsize; - txi->tileh = vh; - } - - DBG3(fprintf(stderr, "tilew=%d, tileh=%d\n", txi->tilew, txi->tileh)); - return 0; -} - - -/* Add a glSDL_TexInfo struct to an SDL_Surface */ -static int glSDL_AddTexInfo(SDL_Surface *surface) -{ - glSDL_TexInfo *txi; - - if(!surface) - return -1; - if(IS_GLSDL_SURFACE(surface)) - return 0; /* Do nothing */ - - glSDL_AllocTexInfo(surface); - txi = glSDL_GetTexInfo(surface); - if(!txi) - return -2; /* Oops! Didn't get a texinfo... --> */ - - if(CalcChop(surface, txi) < 0) - return -3; - - SDL_SetClipRect(surface, NULL); - - return 0; -} - - -/* Create a surface of the prefered OpenGL RGB texture format */ -static SDL_Surface *CreateRGBSurface(int w, int h) -{ - SDL_Surface *s; - Uint32 rmask, gmask, bmask; - int bits = 24; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0x00ff0000; - gmask = 0x0000ff00; - bmask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; -#endif - s = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, - bits, rmask, gmask, bmask, 0); - if(s) - GLSDL_FIX_SURFACE(s); - - glSDL_AddTexInfo(s); - return s; -} - - -/* Create a surface of the prefered OpenGL RGBA texture format */ -static SDL_Surface *CreateRGBASurface(int w, int h) -{ - SDL_Surface *s; - Uint32 rmask, gmask, bmask, amask; - int bits = 32; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; -#endif - s = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, - bits, rmask, gmask, bmask, amask); - if(s) - GLSDL_FIX_SURFACE(s); - - glSDL_AddTexInfo(s); - return s; -} - - -static void init_formats(void) -{ - SDL_Surface *s = CreateRGBSurface(1, 1); - if(!s) - return; - RGBfmt = *(s->format); - glSDL_FreeSurface(s); - - s = CreateRGBASurface(1, 1); - if(!s) - return; - RGBAfmt = *(s->format); - glSDL_FreeSurface(s); -} - - -static int FormatIsOk(SDL_Surface *surface) -{ - SDL_PixelFormat *pf; - if(!surface) - return 1; /* Well, there ain't much we can do anyway... */ - - pf = surface->format; - - /* Colorkeying always requires conversion! */ - if(surface->flags & SDL_SRCCOLORKEY) - return 0; - - /* We need pitch == (width * BytesPerPixel) for glTex[Sub]Image2D() */ - if(surface->pitch != (surface->w * pf->BytesPerPixel)) - return 0; - - if(pf->Amask) - { - if(pf->BytesPerPixel != RGBAfmt.BytesPerPixel) - return 0; - if(pf->Rmask != RGBAfmt.Rmask) - return 0; - if(pf->Gmask != RGBAfmt.Gmask) - return 0; - if(pf->Bmask != RGBAfmt.Bmask) - return 0; - if(pf->Amask != RGBAfmt.Amask) - return 0; - } - else - { - if(pf->BytesPerPixel != RGBfmt.BytesPerPixel) - return 0; - if(pf->Rmask != RGBfmt.Rmask) - return 0; - if(pf->Gmask != RGBfmt.Gmask) - return 0; - if(pf->Bmask != RGBfmt.Bmask) - return 0; - } - return 1; -} - - - -static void key2alpha(SDL_Surface *surface) -{ - int x, y; -#ifdef CKSTATS - int transp = 0; -#endif - Uint32 rgbmask = surface->format->Rmask | - surface->format->Gmask | - surface->format->Bmask; - Uint32 ckey = surface->format->colorkey & rgbmask; - if(SDL_LockSurface(surface) < 0) - return; - - for(y = 0; y < surface->h; ++y) - { - Uint32 *px = (Uint32 *)((char *)surface->pixels + y*surface->pitch); - for(x = 0; x < surface->w; ++x) - if((px[x] & rgbmask) == ckey) - { - px[x] = 0; -#ifdef CKSTATS - ++transp; -#endif - } - } -#ifdef CKSTATS - printf("glSDL/wrapper: key2alpha(); %dx%d surface, %d opaque pixels.\n", - surface->w, surface->h, - surface->w * surface->h - transp); -#endif - SDL_UnlockSurface(surface); -} - - - -/*---------------------------------------------------------- - SDL style API -----------------------------------------------------------*/ - -static void KillAllTextures(void) -{ - if(texinfotab) - { - unsigned i; -#ifdef LEAK_TRACKING - int leaked = 0; - for(i = 3; i < MAX_TEXINFOS + 1; ++i) - if(texinfotab[i]) - { - ++leaked; - fprintf(stderr, "glSDL/wrapper: Leaked TexInfo" - " %d! (%d %dx%d textures)\n", - i, - texinfotab[i]->textures, - texinfotab[i]->texsize, - texinfotab[i]->texsize - ); - } - if(leaked) - fprintf(stderr, "glSDL/wrapper: Leaked %d TexInfos!\n", leaked); -#endif - for(i = 1; i < MAX_TEXINFOS + 1; ++i) - FreeTexInfo(i); - free(texinfotab); - texinfotab = NULL; - } -} - -void glSDL_Quit(void) -{ - if(SDL_WasInit(SDL_INIT_VIDEO)) - { - glSDL_FreeTexInfo(SDL_GetVideoSurface()); - if(fake_screen) - { - glSDL_FreeTexInfo(fake_screen); - SDL_FreeSurface(fake_screen); - fake_screen = NULL; - } - UnloadGL(); - SDL_QuitSubSystem(SDL_INIT_VIDEO); - } -#ifndef LEAK_TRACKING - KillAllTextures(); -#endif -} - - -void glSDL_FullQuit(void) -{ -#ifdef LEAK_TRACKING - KillAllTextures(); -#endif - glSDL_Quit(); - SDL_Quit(); -} - - -void glSDL_QuitSubSystem(Uint32 flags) -{ - if(flags & SDL_INIT_VIDEO) - glSDL_Quit(); - SDL_QuitSubSystem(flags); -} - - -SDL_Surface *glSDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) -{ - SDL_Surface *screen; - GLint gl_doublebuf; - - if(!initialized) - { - glSDL_ResetState(); - initialized = 1; - } - - if(USING_GLSDL) - { - glSDL_FreeTexInfo(SDL_GetVideoSurface()); - if(fake_screen) - { - glSDL_FreeTexInfo(fake_screen); - SDL_FreeSurface(fake_screen); - fake_screen = NULL; - } - UnloadGL(); - using_glsdl = 0; - } - - if(!(flags & SDL_GLSDL)) - { - screen = SDL_SetVideoMode(width, height, bpp, flags); - if(screen) - GLSDL_FIX_SURFACE(screen); - return screen; - } - - if((SDL_Linked_Version()->major <= 1) && - (SDL_Linked_Version()->minor <= 2) && - (SDL_Linked_Version()->patch < 5)) - fprintf(stderr, "glSDL/wrapper WARNING: Using SDL version" - " 1.2.5 or later is strongly" - " recommended!\n"); - - if(LoadGL() < 0) - { - fprintf(stderr, "glSDL/wrapper ERROR: Could not load OpenGL library!\n"); - return NULL; - } - -/* - * FIXME: Here's the place to insert proper handling of this call being - * used for resizing the window... For now, just make sure we - * don't end up with invalid texinfos and stuff no matter what. - */ - KillAllTextures(); - - texinfotab = (glSDL_TexInfo**)calloc(MAX_TEXINFOS + 1, sizeof(glSDL_TexInfo *)); - if(!texinfotab) - return NULL; - - /* Remove flag to avoid confusion inside SDL - just in case! */ - flags &= ~SDL_GLSDL; - - flags |= SDL_OPENGL; - if(bpp == 15) - { - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); - } - else if(bpp == 16) - { - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); - } - else if(bpp >= 24) - { - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - } - gl_doublebuf = (flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF; - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, gl_doublebuf); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vsync); - scale = 1; - - screen = SDL_SetVideoMode(width*scale, height*scale, bpp, flags); - if(!screen) - { - KillAllTextures(); - return NULL; - } - - GLSDL_FIX_SURFACE(screen); - -#ifdef FAKE_MAXTEXSIZE - maxtexsize = FAKE_MAXTEXSIZE; -#else - gl.GetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize); -#endif - DBG(fprintf(stderr, "glSDL/wrapper: Max texture size: %d\n", maxtexsize)); - - init_formats(); - gl_reset(); - - if(glSDL_AddTexInfo(screen) < 0) - { - DBG(fprintf(stderr, "glSDL/wrapper: Failed to add info to screen surface!\n")); - SDL_QuitSubSystem(SDL_INIT_VIDEO); - return NULL; - } - - glSDL_SetClipRect(screen, &screen->clip_rect); - - gl.Viewport(0, 0, screen->w * scale, screen->h * scale); - /* - * Note that this projection is upside down in - * relation to the OpenGL coordinate system. - */ - gl.MatrixMode(GL_PROJECTION); - gl.LoadIdentity(); - gl.Ortho(0, scale * (float)screen->w, scale * (float)screen->h, 0, - -1.0, 1.0); - - gl.MatrixMode(GL_MODELVIEW); - gl.LoadIdentity(); - gl.Translatef(0.0f, 0.0f, 0.0f); - - gl.Disable(GL_DEPTH_TEST); - gl.Disable(GL_CULL_FACE); - - /* - * Create a software shadow buffer of the requested size. - * This is used for blit-from-screen and simulation of - * direct software rendering. (Dog slow crap. It's only - * legitimate use is probably screen shots.) - */ - fake_screen = CreateRGBSurface(screen->w / scale, - screen->h / scale); - using_glsdl = 1; - return fake_screen; -} - - -SDL_Surface *glSDL_GetVideoSurface(void) -{ - if(fake_screen) - return fake_screen; - else - return SDL_GetVideoSurface(); -} - - -void glSDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects) -{ - if(IS_GLSDL_SURFACE(screen)) - glSDL_Flip(screen); - else - SDL_UpdateRects(screen, numrects, rects); -} - - -void glSDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h) -{ - SDL_Rect r; - r.x = x; - r.y = y; - r.w = w; - r.h = h; - glSDL_UpdateRects(screen, 1, &r); -} - - -int glSDL_Flip(SDL_Surface *screen) -{ - if(!IS_GLSDL_SURFACE(screen)) - return SDL_Flip(screen); - - SDL_GL_SwapBuffers(); - return 0; -} - - -void glSDL_FreeSurface(SDL_Surface *surface) -{ - if(!surface) - return; - glSDL_FreeTexInfo(surface); - SDL_FreeSurface(surface); -} - - -int glSDL_LockSurface(SDL_Surface *surface) -{ - if(!surface) - return 0; - - if(IS_GLSDL_SURFACE(surface)) - { - if((surface == fake_screen) || - (SDL_GetVideoSurface() == surface)) - { - if(scale > 1) - return -1; - - glSDL_Invalidate(fake_screen, NULL); - - gl.PixelStorei(GL_UNPACK_ROW_LENGTH, - fake_screen->pitch / - fake_screen->format->BytesPerPixel); - - gl.ReadPixels(0, 0, fake_screen->w, fake_screen->h, - GL_RGB, GL_UNSIGNED_BYTE, - fake_screen->pixels); - return 0; - } - else - { - glSDL_Invalidate(surface, NULL); - return SDL_LockSurface(surface); - } - } - else - return SDL_LockSurface(surface); -} - - -void glSDL_UnlockSurface(SDL_Surface *surface) -{ - if(!surface) - return; - - if(IS_GLSDL_SURFACE(surface)) - { - glSDL_UploadSurface(surface); - if((surface == fake_screen) || - (SDL_GetVideoSurface() == surface)) - glSDL_BlitGL(fake_screen, NULL, - SDL_GetVideoSurface(), NULL); - } - else - SDL_UnlockSurface(surface); -} - - -int glSDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key) -{ - int res = SDL_SetColorKey(surface, flag, key); - if(res < 0) - return res; - /* - * If an application does this *after* SDL_DisplayFormat, - * we're basically screwed, unless we want to do an - * in-place surface conversion hack here. - * - * What we do is just kill the glSDL texinfo... No big - * deal in most cases, as glSDL only converts once anyway, - * *unless* you keep modifying the surface. - */ - if(IS_GLSDL_SURFACE(surface)) - glSDL_FreeTexInfo(surface); - return res; -} - - -int glSDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha) -{ - /* - * This is just parameters to OpenGL, so the actual - * "work" is done in glSDL_BlitSurface(). - */ - return SDL_SetAlpha(surface, flag, alpha); -} - - -SDL_bool glSDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect) -{ - SDL_bool res; - SDL_Surface *screen; - SDL_Rect fsr; - if(!surface) - return SDL_FALSE; - - screen = SDL_GetVideoSurface(); - - res = SDL_SetClipRect(surface, rect); - if(!res) - return SDL_FALSE; - - if(!rect) - { - fsr.x = 0; - fsr.y = 0; - fsr.w = screen->w; - fsr.h = screen->h; - rect = &fsr; - } - if(surface == fake_screen) - { - SDL_Rect r; - r.x = rect->x; - r.y = rect->y; - r.w = rect->w; - r.h = rect->h; - surface = screen; - SDL_SetClipRect(surface, rect); - return SDL_TRUE; - } - return res; -} - - -static int glSDL_BlitFromGL(SDL_Rect *srcrect, - SDL_Surface *dst, SDL_Rect *dstrect) -{ - int i, sy0, dy0; - SDL_Rect sr, dr; - - if(scale > 1) - return -1; - - /* In case the destination has an OpenGL texture... */ - glSDL_Invalidate(dst, dstrect); - - /* Abuse the fake screen buffer a little. */ - gl.PixelStorei(GL_UNPACK_ROW_LENGTH, fake_screen->pitch / - fake_screen->format->BytesPerPixel); - if(srcrect) - { - sr = *srcrect; - dr.x = dr.y = 0; - dr.w = fake_screen->w; - dr.h = fake_screen->h; - clip_rect(&sr, &dr); - gl.ReadPixels(sr.x, sr.y, sr.w, sr.h, GL_RGB, GL_UNSIGNED_BYTE, - fake_screen->pixels); - } - else - { - sr.x = sr.y = 0; - sr.w = dst->w; - srcrect = &sr; - gl.ReadPixels(0, 0, fake_screen->w, fake_screen->h, - GL_RGB, GL_UNSIGNED_BYTE, fake_screen->pixels); - } - - /* Blit to the actual target! (Vert. flip... Uuurgh!) */ - if(dstrect) - dr = *dstrect; - else - { - dr.x = dr.y = 0; - dstrect = &dr; - } - - i = srcrect->h; - sy0 = srcrect->y; - dy0 = dstrect->y + dstrect->h - 1; - while(i--) - { - sr.y = sy0 + i; - dr.y = dy0 - i; - sr.h = 1; - if(SDL_BlitSurface(fake_screen, &sr, dst, &dr) < 0) - return -1; - } - return 0; -} - - -static __inline__ void BlitGL_single(glSDL_TexInfo *txi, - float sx1, float sy1, SDL_Rect *dst, unsigned char alpha) -{ - float sx2, sy2, texscale; - if(!txi->textures) - return; - if(-1 == txi->texture[0]) - return; - gl_texture(txi->texture[0]); - - texscale = 1.0 / (float)txi->texsize; - sx2 = (sx1 + (float)dst->w) * texscale; - sy2 = (sy1 + (float)dst->h) * texscale; - sx1 *= texscale; - sy1 *= texscale; - - gl.Begin(GL_QUADS); - gl.Color4ub(state.r, state.g, state.b, alpha); - gl.TexCoord2f(sx1, sy1); - gl.Vertex2i(dst->x, dst->y); - gl.TexCoord2f(sx2, sy1); - gl.Vertex2i(dst->x + dst->w, dst->y); - gl.TexCoord2f(sx2, sy2); - gl.Vertex2i(dst->x + dst->w, dst->y + dst->h); - gl.TexCoord2f(sx1, sy2); - gl.Vertex2i(dst->x, dst->y + dst->h); - gl.End(); -} - - -static void BlitGL_htile(glSDL_TexInfo *txi, - float sx1, float sy1, SDL_Rect *dst, unsigned char alpha) -{ - int tex; - float tile, sx2, sy2, yo; - float texscale = 1.0 / (float)txi->texsize; - float tileh = (float)txi->tileh * texscale; - sx2 = (sx1 + (float)dst->w) * texscale; - sy2 = (sy1 + (float)dst->h) * texscale; - sx1 *= texscale; - sy1 *= texscale; - tile = floor(sx1); - tex = (int)tile / txi->tilespertex; - yo = ((int)tile % txi->tilespertex) * tileh; - - if(tex >= txi->textures) - return; - if(-1 == txi->texture[tex]) - return; - gl_texture(txi->texture[tex]); - - gl.Begin(GL_QUADS); - while(tile < sx2) - { - int tdx1 = dst->x; - int tdx2 = dst->x + dst->w; - float tsx1 = sx1 - tile; - float tsx2 = sx2 - tile; - - /* Clip to current tile */ - if(tsx1 < 0.0) - { - tdx1 -= (int)(tsx1 * txi->texsize); - tsx1 = 0.0; - } - if(tsx2 > 1.0) - { - tdx2 -= (int)((tsx2 - 1.0) * txi->texsize); - tsx2 = 1.0; - } - - /* Maybe select next texture? */ - if(yo + tileh > 1.0) - { - ++tex; - gl.End(); - if(tex >= txi->textures) - return; - if(-1 == txi->texture[tex]) - return; - gl_texture(txi->texture[tex]); - yo = 0.0; - gl.Begin(GL_QUADS); - } - - gl.Color4ub(state.r, state.g, state.b, alpha); - gl.TexCoord2f(tsx1, yo + sy1); - gl.Vertex2i(tdx1, dst->y); - gl.TexCoord2f(tsx2, yo + sy1); - gl.Vertex2i(tdx2, dst->y); - gl.TexCoord2f(tsx2, yo + sy2); - gl.Vertex2i(tdx2, dst->y + dst->h); - gl.TexCoord2f(tsx1, yo + sy2); - gl.Vertex2i(tdx1, dst->y + dst->h); - - tile += 1.0; - yo += tileh; - } - gl.End(); -} - - -static void BlitGL_vtile(glSDL_TexInfo *txi, - float sx1, float sy1, SDL_Rect *dst, unsigned char alpha) -{ - int tex; - float tile, sx2, sy2, xo; - float texscale = 1.0 / (float)txi->texsize; - float tilew = (float)txi->tilew * texscale; - sx2 = (sx1 + (float)dst->w) * texscale; - sy2 = (sy1 + (float)dst->h) * texscale; - sx1 *= texscale; - sy1 *= texscale; - tile = floor(sy1); - tex = (int)tile / txi->tilespertex; - xo = ((int)tile % txi->tilespertex) * tilew; - - if(tex >= txi->textures) - return; - if(-1 == txi->texture[tex]) - return; - gl_texture(txi->texture[tex]); - - gl.Begin(GL_QUADS); - while(tile < sy2) - { - int tdy1 = dst->y; - int tdy2 = dst->y + dst->h; - float tsy1 = sy1 - tile; - float tsy2 = sy2 - tile; - - /* Clip to current tile */ - if(tsy1 < 0.0) - { - tdy1 -= (int)(tsy1 * txi->texsize); - tsy1 = 0.0; - } - if(tsy2 > 1.0) - { - tdy2 -= (int)((tsy2 - 1.0) * txi->texsize); - tsy2 = 1.0; - } - - /* Maybe select next texture? */ - if(xo + tilew > 1.0) - { - ++tex; - gl.End(); - if(tex >= txi->textures) - return; - if(-1 == txi->texture[tex]) - return; - gl_texture(txi->texture[tex]); - xo = 0.0; - gl.Begin(GL_QUADS); - } - - gl.Color4ub(state.r, state.g, state.b, alpha); - gl.TexCoord2f(xo + sx1, tsy1); - gl.Vertex2i(dst->x, tdy1); - gl.TexCoord2f(xo + sx2, tsy1); - gl.Vertex2i(dst->x + dst->w, tdy1); - gl.TexCoord2f(xo + sx2, tsy2); - gl.Vertex2i(dst->x + dst->w, tdy2); - gl.TexCoord2f(xo + sx1, tsy2); - gl.Vertex2i(dst->x, tdy2); - - tile += 1.0; - xo += tilew; - } - gl.End(); -} - - -static void BlitGL_hvtile(SDL_Surface *src, glSDL_TexInfo *txi, - float sx1, float sy1, SDL_Rect *dst, unsigned char alpha) -{ - int x, y, last_tex, tex; - float sx2, sy2; - float texscale = 1.0 / (float)txi->texsize; - int tilesperrow = (src->w + txi->tilew - 1) / txi->tilew; - sx2 = (sx1 + (float)dst->w) * texscale; - sy2 = (sy1 + (float)dst->h) * texscale; - sx1 *= texscale; - sy1 *= texscale; - - last_tex = tex = (int)(floor(sy1) * tilesperrow + floor(sx1)); - if(tex >= txi->textures) - return; - if(-1 == txi->texture[tex]) - return; - gl_texture(txi->texture[tex]); - - gl.Begin(GL_QUADS); - for(y = (int)floor(sy1); y < sy2; ++y) - { - int tdy1 = dst->y; - int tdy2 = dst->y + dst->h; - float tsy1 = sy1 - y; - float tsy2 = sy2 - y; - - /* Clip to current tile */ - if(tsy1 < 0.0) - { - tdy1 -= (int)(tsy1 * txi->texsize); - tsy1 = 0.0; - } - if(tsy2 > 1.0) - { - tdy2 -= (int)((tsy2 - 1.0) * txi->texsize); - tsy2 = 1.0; - } - for(x = (int)floor(sx1); x < sx2; ++x) - { - int tdx1 = dst->x; - int tdx2 = dst->x + dst->w; - float tsx1 = sx1 - x; - float tsx2 = sx2 - x; - - /* Clip to current tile */ - if(tsx1 < 0.0) - { - tdx1 -= (int)(tsx1 * txi->texsize); - tsx1 = 0.0; - } - if(tsx2 > 1.0) - { - tdx2 -= (int)((tsx2 - 1.0) * txi->texsize); - tsx2 = 1.0; - } - - /* Select texture */ - tex = y * tilesperrow + x; - if(tex != last_tex) - { - gl.End(); - if(tex >= txi->textures) - return; - if(-1 == txi->texture[tex]) - return; - gl_texture(txi->texture[tex]); - last_tex = tex; - gl.Begin(GL_QUADS); - } - - gl.Color4ub(state.r, state.g, state.b, alpha); - gl.TexCoord2f(tsx1, tsy1); - gl.Vertex2i(tdx1, tdy1); - gl.TexCoord2f(tsx2, tsy1); - gl.Vertex2i(tdx2, tdy1); - gl.TexCoord2f(tsx2, tsy2); - gl.Vertex2i(tdx2, tdy2); - gl.TexCoord2f(tsx1, tsy2); - gl.Vertex2i(tdx1, tdy2); - } - } - gl.End(); -} - - -/* - * Calculate the actual blit rectangle and source offset - * for a blit from a rectangle in a surface with specified - * size to a surface with a cliprect. - * - * In: rect source rectangle - * w, h source surface size - * (x, y) destination coordinate - * clip destination clip rectangle - * - * Out: (x, y) source top-left offset - * rect destination rectangle - * - * Returns 1 if the result is visible, otherwise 0. - */ -static __inline__ int blitclip(SDL_Rect *rect, int w, int h, - int *x, int *y, SDL_Rect *clip) -{ - int sx1, sy1, sx2, sy2; - int dx1, dy1, dx2, dy2; - - /* Get source and destination coordinates */ - sx1 = rect->x; - sy1 = rect->y; - sx2 = sx1 + rect->w; - sy2 = sy1 + rect->h; - dx1 = *x; - dy1 = *y; - - /* Keep source rect inside source surface */ - if(sx1 < 0) - { - dx1 -= sx1; - sx1 = 0; - } - if(sy1 < 0) - { - dy1 -= sy1; - sy1 = 0; - } - if(sx2 > w) - sx2 = w; - if(sy2 > h) - sy2 = h; - - /* Cull blits from void space */ - if(sx1 >= sx2 || sy1 >= sy2) - return 0; - - /* Calculate destination lower-right */ - dx2 = dx1 + (sx2 - sx1); - dy2 = dy1 + (sy2 - sy1); - - if(clip) - { - /* Clip to destination cliprect */ - if(dx1 < clip->x) - { - sx1 += clip->x - dx1; - dx1 = clip->x; - } - if(dy1 < clip->y) - { - sy1 += clip->y - dy1; - dy1 = clip->y; - } - if(dx2 > clip->x + clip->w) - dx2 = clip->x + clip->w; - if(dy2 > clip->y + clip->h) - dy2 = clip->y + clip->h; - } - - /* Cull nop/off-screen blits */ - if(dx1 >= dx2 || dy1 >= dy2) - return 0; - - *x = sx1; - *y = sy1; - rect->x = dx1; - rect->y = dy1; - rect->w = dx2 - dx1; - rect->h = dy2 - dy1; - return 1; -} - - -static int glSDL_BlitGL(SDL_Surface *src, SDL_Rect *srcrect, - SDL_Surface *dst, SDL_Rect *dstrect) -{ - glSDL_TexInfo *txi; - SDL_Rect r; - int x, y; - unsigned char alpha; - int plain = (state.rot == 0.0f) && - (state.sx == 1.0f) && - (state.sy == 1.0f); - if(!src || !dst) - return -1; - - /* Get source and destination coordinates */ - if(srcrect) - r = *srcrect; - else - { - r.x = r.y = 0; - r.w = src->w; - r.h = src->h; - } - if(dstrect) - { - x = dstrect->x; - y = dstrect->y; - } - else - x = y = 0; - - /* Clip! */ - if(!blitclip(&r, src->w, src->h, &x, &y, - plain ? &dst->clip_rect : NULL)) - { - if(dstrect) - dstrect->w = dstrect->h = 0; - return 0; - } - - /* Write back the resulting cliprect */ - if(dstrect) - *dstrect = r; - - /* Make sure we have a source with a valid texture */ - glSDL_UploadSurface(src); - txi = glSDL_GetTexInfo(src); - if(!txi) - return -1; - - /* Set up blending */ - if(src->flags & (SDL_SRCALPHA | SDL_SRCCOLORKEY) || - (state.alpha != 255)) - { - gl_blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_do_blend(1); - } - else - gl_do_blend(0); - - /* Enable texturing */ - gl_do_texture(1); - - /* - * Note that we actually *prevent* the use of "full surface alpha" - * and alpha channel in combination - to stay SDL 2D compatible. - */ - if((src->flags & SDL_SRCALPHA) && - (!src->format->Amask || (src->flags & SDL_SRCCOLORKEY))) - alpha = src->format->alpha; - else - alpha = 255; - - /* ...however, the GL only global state alpha is always applied! */ - alpha = (Uint32)alpha * state.alpha * 258 >> 16; - - /* Render! */ - if(!plain) - { - int rcx = (r.w >> 1) + state.cx; - int rcy = (r.h >> 1) + state.cy; - gl.PushMatrix(); - gl.Translatef(r.x + rcx, r.y + rcy, 0.0f); - if(state.rot) - gl.Rotated(state.rot, 0.0f, 0.0f, 1.0f); - if(state.sx || state.sy) - gl.Scalef(state.sx, state.sy, 1.0f); - r.x = -rcx; - r.y = -rcy; - } - switch(txi->tilemode) - { - case GLSDL_TM_SINGLE: - BlitGL_single(txi, x, y, &r, alpha); - break; - case GLSDL_TM_HORIZONTAL: - BlitGL_htile(txi, x, y, &r, alpha); - break; - case GLSDL_TM_VERTICAL: - BlitGL_vtile(txi, x, y, &r, alpha); - break; - case GLSDL_TM_HUGE: - BlitGL_hvtile(src, txi, x, y, &r, alpha); - break; - } - if(!plain) - gl.PopMatrix(); - return 0; -} - - -int glSDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, - SDL_Surface *dst, SDL_Rect *dstrect) -{ - SDL_Surface *vs; - if(!src || !dst) - return -1; - - /* - * Figure out what to do: - * Not using glSDL: SDL_BlitSurface() - * screen->screen: _glSDL_BlitFromGL() + _glSDL_BlitGL() - * surface->screen: _glSDL_BlitGL() - * screen->surface: _glSDL_BlitFromGL() - * surface->surface: SDL_BlitSurface() - */ - if(!USING_GLSDL) - return SDL_BlitSurface(src, srcrect, dst, dstrect); - - vs = SDL_GetVideoSurface(); - if(src == fake_screen) - src = vs; - if(dst == fake_screen) - dst = vs; - if(src == vs) - { - if(dst == vs) - { - glSDL_BlitFromGL(srcrect, fake_screen, dstrect); - return glSDL_BlitGL(fake_screen, srcrect, - dst, dstrect); - } - else - { - return glSDL_BlitFromGL(srcrect, dst, dstrect); - } - } - else - { - if(dst == vs) - { - return glSDL_BlitGL(src, srcrect, - dst, dstrect); - } - else - { - glSDL_Invalidate(dst, dstrect); - return SDL_BlitSurface(src, srcrect, dst, dstrect); - } - } -} - - -int glSDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color) -{ - SDL_Surface *vs = SDL_GetVideoSurface(); - SDL_PixelFormat *pf = dst->format; - int dx1, dy1, dx2, dy2; - Uint32 r, g, b; - - if(dst == fake_screen) - dst = vs; - if(vs != dst) - glSDL_Invalidate(dst, dstrect); - if((vs != dst) || !USING_GLSDL) - return SDL_FillRect(dst, dstrect, color); - - if(dstrect) - { - dx1 = dstrect->x; - dy1 = dstrect->y; - dx2 = dx1 + dstrect->w; - dy2 = dy1 + dstrect->h; - if(dx1 < dst->clip_rect.x) - dx1 = dst->clip_rect.x; - if(dy1 < dst->clip_rect.y) - dy1 = dst->clip_rect.y; - if(dx2 > dst->clip_rect.x + dst->clip_rect.w) - dx2 = dst->clip_rect.x + dst->clip_rect.w; - if(dy2 > dst->clip_rect.y + dst->clip_rect.h) - dy2 = dst->clip_rect.y + dst->clip_rect.h; - dstrect->x = dx1; - dstrect->y = dy1; - dstrect->w = dx2 - dx1; - dstrect->h = dy2 - dy1; - if(!dstrect->w || !dstrect->h) - return 0; - } - else - { - dx1 = dst->clip_rect.x; - dy1 = dst->clip_rect.y; - dx2 = dx1 + dst->clip_rect.w; - dy2 = dy1 + dst->clip_rect.h; - } - - r = color & pf->Rmask; - r = r >> pf->Rshift; - r = r << pf->Rloss; - g = color & pf->Gmask; - g = g >> pf->Gshift; - g = g << pf->Gloss; - b = color & pf->Bmask; - b = b >> pf->Bshift; - b = b << pf->Bloss; - - r = r * state.r * 258 >> 16; - g = g * state.g * 258 >> 16; - b = b * state.b * 258 >> 16; - - gl_do_texture(0); - if(state.alpha != 255) - { - gl_blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_do_blend(1); - } - else - gl_do_blend(0); - - gl.Begin(GL_QUADS); - gl.Color4ub(r, g, b, state.alpha); - gl.Vertex2i(dx1, dy1); - gl.Vertex2i(dx2, dy1); - gl.Vertex2i(dx2, dy2); - gl.Vertex2i(dx1, dy2); - gl.End(); - return 0; -} - - -SDL_Surface *glSDL_DisplayFormat(SDL_Surface *surface) -{ - SDL_Surface *s, *tmp; - if(USING_GLSDL) - { - int use_rgba = (surface->flags & SDL_SRCCOLORKEY) || - ((surface->flags & SDL_SRCALPHA) && - surface->format->Amask); - if(use_rgba) - tmp = SDL_ConvertSurface(surface, &RGBAfmt, SDL_SWSURFACE); - else - tmp = SDL_ConvertSurface(surface, &RGBfmt, SDL_SWSURFACE); - if(!tmp) - return NULL; - GLSDL_FIX_SURFACE(tmp); - SDL_SetAlpha(tmp, 0, 0); - - if(surface->flags & SDL_SRCCOLORKEY) - { - /* - * We drop colorkey data here, but we have to, - * or we'll run into trouble when converting, - * in particular from indexed color formats. - */ - SDL_SetColorKey(tmp, SDL_SRCCOLORKEY, - surface->format->colorkey); - key2alpha(tmp); - } - SDL_SetColorKey(tmp, 0, 0); - - if(use_rgba) - s = CreateRGBASurface(surface->w, surface->h); - else - s = CreateRGBSurface(surface->w, surface->h); - if(!s) - { - glSDL_FreeSurface(tmp); - return NULL; - } - SDL_BlitSurface(tmp, NULL, s, NULL); - glSDL_FreeSurface(tmp); - - if(surface->flags & SDL_SRCALPHA) - SDL_SetAlpha(s, SDL_SRCALPHA, - surface->format->alpha); - return s; - } - else - { - s = SDL_DisplayFormat(surface); - if(s) - GLSDL_FIX_SURFACE(s); - return s; - } -} - - -SDL_Surface *glSDL_DisplayFormatAlpha(SDL_Surface *surface) -{ - SDL_Surface *s, *tmp; - if(USING_GLSDL) - { - tmp = SDL_ConvertSurface(surface, &RGBAfmt, SDL_SWSURFACE); - if(!tmp) - return NULL; - GLSDL_FIX_SURFACE(tmp); - - SDL_SetAlpha(tmp, 0, 0); - SDL_SetColorKey(tmp, 0, 0); - s = CreateRGBASurface(surface->w, surface->h); - if(!s) - { - glSDL_FreeSurface(tmp); - return NULL; - } - SDL_BlitSurface(tmp, NULL, s, NULL); - glSDL_FreeSurface(tmp); - - if(surface->flags & SDL_SRCCOLORKEY) - { - SDL_SetColorKey(s, SDL_SRCCOLORKEY, - surface->format->colorkey); - key2alpha(s); - } - if(surface->flags & SDL_SRCALPHA) - SDL_SetAlpha(s, SDL_SRCALPHA, - surface->format->alpha); - return s; - } - else - { - s = SDL_DisplayFormatAlpha(surface); - if(s) - GLSDL_FIX_SURFACE(s); - return s; - } -} - - -SDL_Surface *glSDL_ConvertSurface - (SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags) -{ - SDL_Surface *s = SDL_ConvertSurface(src, fmt, flags); - if(s) - GLSDL_FIX_SURFACE(s); - return s; -} - - -SDL_Surface *glSDL_CreateRGBSurface - (Uint32 flags, int width, int height, int depth, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) -{ - SDL_Surface *s = SDL_CreateRGBSurface(flags, width, height, depth, - Rmask, Gmask, Bmask, Amask); - if(s) - GLSDL_FIX_SURFACE(s); - return s; -} - - -SDL_Surface *glSDL_CreateRGBSurfaceFrom(void *pixels, - int width, int height, int depth, int pitch, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) -{ - SDL_Surface *s = SDL_CreateRGBSurfaceFrom(pixels, - width, height, depth, pitch, - Rmask, Gmask, Bmask, Amask); - if(s) - GLSDL_FIX_SURFACE(s); - return s; -} - - -SDL_Surface *glSDL_LoadBMP(const char *file) -{ - SDL_Surface *s = SDL_LoadBMP(file); - if(s) - GLSDL_FIX_SURFACE(s); - return s; -} - - -int glSDL_SaveBMP(SDL_Surface *surface, const char *file) -{ - SDL_Rect r; - SDL_Surface *buf; - SDL_Surface *screen = SDL_GetVideoSurface(); - - if(!USING_GLSDL) - return SDL_SaveBMP(surface, file); - - if((surface != screen) && (surface != fake_screen)) - return SDL_SaveBMP(surface, file); - - buf = CreateRGBSurface(fake_screen->w, fake_screen->h); - - r.x = 0; - r.y = 0; - r.w = fake_screen->w; - r.h = fake_screen->h; - if(glSDL_BlitFromGL(&r, buf, &r) < 0) - return -1; - - return SDL_SaveBMP(buf, file); - - glSDL_FreeSurface(buf); -} - - - - -static int InitTexture(SDL_Surface *datasurf, glSDL_TexInfo *txi, int tex) -{ - gl.GenTextures(1, (unsigned int *)&txi->texture[tex]); - gl.BindTexture(GL_TEXTURE_2D, txi->texture[tex]); - gl.PixelStorei(GL_UNPACK_ROW_LENGTH, datasurf->pitch / - datasurf->format->BytesPerPixel); - gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl.TexImage2D(GL_TEXTURE_2D, 0, - datasurf->format->Amask ? GL_RGBA8 : GL_RGB8, - txi->texsize, txi->texsize, 0, - datasurf->format->Amask ? GL_RGBA : GL_RGB, - GL_UNSIGNED_BYTE, NULL); - print_glerror(1); - return 0; -} - - -/* Image tiled horizontally (wide surface), or not at all */ -static int UploadHoriz(SDL_Surface *datasurf, glSDL_TexInfo *txi) -{ - int bpp = datasurf->format->BytesPerPixel; - int res; - int tex = 0; - int fromx = 0; - int toy = txi->texsize; /* To init first texture */ - while(1) - { - int thistw = datasurf->w - fromx; - if(thistw > txi->tilew) - thistw = txi->tilew; - else if(thistw <= 0) - break; - if(toy + txi->tileh > txi->texsize) - { - toy = 0; - res = InitTexture(datasurf, txi, tex); - if(res < 0) - return res; - ++tex; - } - gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, toy, - thistw, txi->tileh, - datasurf->format->Amask ? GL_RGBA : GL_RGB, - GL_UNSIGNED_BYTE, - (char *)datasurf->pixels + bpp * fromx); - print_glerror(2); - fromx += txi->tilew; - toy += txi->tileh; - gl.Flush(); - } - return 0; -} - - -/* Image tiled vertically (tall surface) */ -static int UploadVert(SDL_Surface *datasurf, glSDL_TexInfo *txi) -{ - int res; - int tex = 0; - int fromy = 0; - int tox = txi->texsize; /* To init first texture */ - while(1) - { - int thisth = datasurf->h - fromy; - if(thisth > txi->tileh) - thisth = txi->tileh; - else if(thisth <= 0) - break; - if(tox + txi->tilew > txi->texsize) - { - tox = 0; - res = InitTexture(datasurf, txi, tex); - if(res < 0) - return res; - ++tex; - } - gl.TexSubImage2D(GL_TEXTURE_2D, 0, tox, 0, - txi->tilew, thisth, - datasurf->format->Amask ? GL_RGBA : GL_RGB, - GL_UNSIGNED_BYTE, - (char *)datasurf->pixels + datasurf->pitch * fromy); - print_glerror(3); - fromy += txi->tileh; - tox += txi->tilew; - gl.Flush(); - } - return 0; -} - - -/* Image tiled two-way (huge surface) */ -static int UploadHuge(SDL_Surface *datasurf, glSDL_TexInfo *txi) -{ - int bpp = datasurf->format->BytesPerPixel; - int res; - int tex = 0; - int y = 0; - while(y < datasurf->h) - { - int x; - int thisth = datasurf->h - y; - if(thisth > txi->tileh) - thisth = txi->tileh; - x = 0; - while(x < datasurf->w) - { - int thistw = datasurf->w - x; - if(thistw > txi->tilew) - thistw = txi->tilew; - res = InitTexture(datasurf, txi, tex++); - if(res < 0) - return res; - gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, - thistw, thisth, - datasurf->format->Amask ? GL_RGBA : GL_RGB, - GL_UNSIGNED_BYTE, - (char *)datasurf->pixels + - datasurf->pitch * y + bpp * x); - print_glerror(4); - x += txi->tilew; - gl.Flush(); - } - y += txi->tileh; - } - return 0; -} - - -/* Upload all textures for a surface. */ -static int UploadTextures(SDL_Surface *datasurf, glSDL_TexInfo *txi) -{ - switch(txi->tilemode) - { - case GLSDL_TM_SINGLE: - case GLSDL_TM_HORIZONTAL: - UploadHoriz(datasurf, txi); - break; - case GLSDL_TM_VERTICAL: - UploadVert(datasurf, txi); - break; - case GLSDL_TM_HUGE: - UploadHuge(datasurf, txi); - break; - } - return 0; -} - - -SDL_Surface *glSDL_IMG_Load(const char *file) -{ - SDL_Surface *s; - s = IMG_Load(file); - if(s) - GLSDL_FIX_SURFACE(s); - return s; -} - - -/*---------------------------------------------------------- - glSDL specific API extensions -----------------------------------------------------------*/ - -int glSDL_VSync(int use) -{ - int old = vsync; - if(use >= 0) - vsync = use; - return old; -} - - -void glSDL_Invalidate(SDL_Surface *surface, SDL_Rect *area) -{ - glSDL_TexInfo *txi; - if(!surface) - return; - txi = glSDL_GetTexInfo(surface); - if(!txi) - return; - if(!area) - { - txi->invalid_area.x = 0; - txi->invalid_area.y = 0; - txi->invalid_area.w = surface->w; - txi->invalid_area.h = surface->h; - return; - } - txi->invalid_area = *area; -} - - -int glSDL_UploadSurface(SDL_Surface *surface) -{ - SDL_Surface *datasurf = surface; - glSDL_TexInfo *txi; - int i; - /* - * For now, we just assume that *every* texture needs - * conversion before uploading. - */ - - /* If there's no TexInfo, add one. */ - if(!IS_GLSDL_SURFACE(surface)) - glSDL_AddTexInfo(surface); - - txi = glSDL_GetTexInfo(surface); - if(!txi) - return -1; - - /* No partial updates implemented yet... */ - if(txi->invalid_area.w) - glSDL_UnloadSurface(surface); - else - { - int missing = 0; - if(txi->textures) - { - for(i = 0; i < txi->textures; ++i) - if(-1 == txi->texture[i]) - { - missing = 1; - break; - } - if(!missing) - return 0; /* They're already there! */ - } - } - - if(txi->texsize > maxtexsize) - { - fprintf(stderr, "glSDL/wrapper: INTERNAL ERROR: Too large texture!\n"); - return -1; /* This surface wasn't tiled properly... */ - } - - /* - * Kludge: Convert if not of preferred RGB or RGBA format. - * - * Conversion should only be done when *really* needed. - * That is, it should rarely have to be done with OpenGL - * 1.2+. - * - * Besides, any surface that's been SDL_DisplayFormat()ed - * should already be in the best known OpenGL format - - * preferably one that makes DMA w/o conversion possible. - */ - if(FormatIsOk(surface)) - datasurf = surface; - else - { - DBG(fprintf(stderr, "glSDL/wrapper: WARNING: On-the-fly conversion performed!\n")); - if(surface->format->Amask) - datasurf = glSDL_DisplayFormatAlpha(surface); - else - datasurf = glSDL_DisplayFormat(surface); - if(!datasurf) - return -2; - } - - if(UploadTextures(datasurf, txi) < 0) - return -3; - - if(datasurf != surface) - glSDL_FreeSurface(datasurf); - return 0; -} - - -static void UnloadTexture(glSDL_TexInfo *txi) -{ - int i; - if(SDL_WasInit(SDL_INIT_VIDEO)) - for(i = 0; i < txi->textures; ++i) - gl.DeleteTextures(1, (unsigned int *)&txi->texture[i]); - memset(&txi->invalid_area, 0, sizeof(txi->invalid_area)); -} - - -void glSDL_UnloadSurface(SDL_Surface *surface) -{ - glSDL_TexInfo *txi; - if(!IS_GLSDL_SURFACE(surface)) - return; - - txi = glSDL_GetTexInfo(surface); - if(txi) - UnloadTexture(txi); -} - - -#else /* HAVE_OPENGL */ - -/*---------------------------------------------------------- - Dummies for glSDL extensions that require OpenGL -----------------------------------------------------------*/ - -void glSDL_Invalidate(SDL_Surface *surface, SDL_Rect *area) -{ -} - -int glSDL_UploadSurface(SDL_Surface *surface) -{ - return 0; -} - -void glSDL_UnloadSurface(SDL_Surface *surface) -{ -} - -int glSDL_VSync(int use) -{ - return 0; -} - -void glSDL_SetBlendAlpha(Uint8 alpha) -{ -} - -void glSDL_SetBlendColor(Uint8 r, Uint8 g, Uint8 b) -{ -} - -void glSDL_SetCenter(float x, float y) -{ -} - -void glSDL_SetRotation(float angle) -{ -} - -void glSDL_SetScale(float x, float y) -{ -} - -void glSDL_ResetState(void) -{ -} - -#endif /* HAVE_OPENGL */ diff --git a/graphics/glSDL.h b/graphics/glSDL.h deleted file mode 100644 index 7bdf193..0000000 --- a/graphics/glSDL.h +++ /dev/null @@ -1,399 +0,0 @@ -/*(LGPL) ------------------------------------------------------------- - glSDL 0.9 - SDL 2D API on top of OpenGL ------------------------------------------------------------- - * Copyright (C) 2001-2004, 2006-2007 David Olofson - * This code is released under the terms of the GNU LGPL. - */ - -#ifndef _GLSDL_H_ -#define _GLSDL_H_ - -/* - * If you don't use GNU autotools or similar, uncomment this to - * compile with OpenGL enabled: -#define HAVE_OPENGL - * - * NOTE: - * See README about using this glSDL wrapper with - * SDL versions that have the glSDL backend! - */ - -/* We're still using SDL datatypes here - we just add some stuff. */ -#include "SDL.h" - -/* - * Ignore the flag from SDL w/ glSDL backend, since we're going - * to use glSDL/wrapper by default. - */ -#ifdef SDL_GLSDL -#undef SDL_GLSDL -#endif - -#ifndef HAVE_OPENGL - -/* Fakes to make glSDL code compile with SDL. */ -#define SDL_GLSDL 0 -#define GLSDL_FIX_SURFACE(s) - -#else /* HAVE_OPENGL */ - -#ifdef __cplusplus -extern "C" { -#endif - -#if (SDL_MAJOR_VERSION <= 1) && (SDL_MINOR_VERSION <= 2) && \ - (SDL_PATCHLEVEL < 5) -#warning glSDL: Using SDL version 1.2.5 or later is strongly recommended! -#endif - -/*---------------------------------------------------------- - SDL style API -----------------------------------------------------------*/ - -typedef enum glSDL_TileModes -{ - GLSDL_TM_SINGLE, - GLSDL_TM_HORIZONTAL, - GLSDL_TM_VERTICAL, - GLSDL_TM_HUGE -} glSDL_TileModes; - - -typedef struct glSDL_TexInfo -{ - int textures; - int *texture; - int texsize; /* width/height of OpenGL texture */ - glSDL_TileModes tilemode; - int tilew, tileh; /* At least one must equal texsize! */ - int tilespertex; - - /* Area of surface to download when/after unlocking */ - SDL_Rect invalid_area; -} glSDL_TexInfo; - -#define GLSDL_FIX_SURFACE(s) (s)->unused1 = 0; -#define IS_GLSDL_SURFACE(s) ((s) && texinfotab && glSDL_GetTexInfo(s)) - -#ifdef SDL_GLSDL -#undef SDL_GLSDL /* In case SDL has the glSDL backend... */ -#endif -#define SDL_GLSDL 0x00100000 /* Create an OpenGL 2D rendering context */ - - -/* - * Wraps SDL_SetVideoMode(), and adds support for the SDL_GLSDL flag. - * - * If 'flags' contains SDL_GLSDL, glSDL_SetVideoMode() sets up a "pure" - * OpenGL rendering context for use with the glSDL_ calls. - * - * SDL can be closed as usual (using SDL_ calls), but you should call - * glSDL_Quit() (kludge) to allow glSDL to clean up it's internal stuff. - */ -SDL_Surface *glSDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); -void glSDL_Quit(void); - -void glSDL_QuitSubSystem(Uint32 flags); - -/* Replaces SDL_Quit() entirely, when using the override defines */ -void glSDL_FullQuit(void); - -SDL_Surface *glSDL_GetVideoSurface(void); - -void glSDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects); -void glSDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h); - -/* - * Works like SDL_Flip(), but may also perform enqueued blits. - * (That is, it's possible that the implementation renders - * *nothing* until glSDL_Flip() is called.) - */ -int glSDL_Flip(SDL_Surface *screen); - -void glSDL_FreeSurface(SDL_Surface *surface); - -int glSDL_LockSurface(SDL_Surface *surface); -void glSDL_UnlockSurface(SDL_Surface *surface); - -/* - * Like the respective SDL functions, although they ignore - * SDL_RLEACCEL, as it makes no sense in this context. - */ -int glSDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key); -int glSDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha); - -/* - * Sets up clipping for the screen, or a SDL_Surface. - * - * Note that this function takes both SDL_Surfaces and - * glSDL_Surfaces. - */ -SDL_bool glSDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect); - -int glSDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, - SDL_Surface *dst, SDL_Rect *dstrect); - -int glSDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color); - -/* - * Convert the given surface into a SDL_Surface (if it isn't - * one already), and makes sure that the underlying SDL_Surface - * is of a pixel format suitable for fast texture downloading. - * - * Note that you *only* have to use this function if you want - * fast pixel access to surfaces (ie "procedural textures"). - * Any surfaces that aren't converted will be downloaded - * automatically upon the first call to glSDL_BlitSurface(), - * but if conversion is required, it will be required for - * every glSDL_UnlockSurface() call. - * - * IMPORTANT: - * You *can* pass an SDL_Surface directly to this function, - * and it will try to deal with it nicely. However, this - * requires that a temporary SDL_Surface is created, and - * this surface is cached only until the texture memory is - * needed for new surfaces. - */ -SDL_Surface *glSDL_DisplayFormat(SDL_Surface *surface); -SDL_Surface *glSDL_DisplayFormatAlpha(SDL_Surface *surface); - -SDL_Surface *glSDL_ConvertSurface - (SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags); -SDL_Surface *glSDL_CreateRGBSurface - (Uint32 flags, int width, int height, int depth, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); -SDL_Surface *glSDL_CreateRGBSurfaceFrom(void *pixels, - int width, int height, int depth, int pitch, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); -SDL_Surface *glSDL_LoadBMP(const char *file); -int glSDL_SaveBMP(SDL_Surface *surface, const char *file); - -#ifdef __cplusplus -} -#endif - -/* Some ugly "overriding"... */ -#ifndef _GLSDL_NO_REDEFINES_ -/* - * You *always* need to lock and unlock a glSDL surface in - * order to get glSDL to update the OpenGL texture! - */ -#undef SDL_MUSTLOCK -#define SDL_MUSTLOCK(surface) \ - (surface->offset || \ - ((surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_RLEACCEL)) != 0) || \ - IS_GLSDL_SURFACE(surface)) - -#define SDL_SetVideoMode glSDL_SetVideoMode -#define SDL_GetVideoSurface glSDL_GetVideoSurface -#define SDL_Quit glSDL_FullQuit -#define SDL_QuitSubSystem glSDL_QuitSubSystem -#define SDL_UpdateRects glSDL_UpdateRects -#define SDL_UpdateRect glSDL_UpdateRect -#define SDL_Flip glSDL_Flip -#define SDL_FreeSurface glSDL_FreeSurface -#define SDL_LockSurface glSDL_LockSurface -#define SDL_UnlockSurface glSDL_UnlockSurface -#define SDL_SetColorKey glSDL_SetColorKey -#define SDL_SetAlpha glSDL_SetAlpha -#define SDL_SetClipRect glSDL_SetClipRect -#undef SDL_BlitSurface -#define SDL_BlitSurface glSDL_BlitSurface -#define SDL_FillRect glSDL_FillRect -#define SDL_DisplayFormat glSDL_DisplayFormat -#define SDL_DisplayFormatAlpha glSDL_DisplayFormatAlpha -#define SDL_ConvertSurface glSDL_ConvertSurface -#define SDL_CreateRGBSurface glSDL_CreateRGBSurface -#define SDL_CreateRGBSurfaceFrom glSDL_CreateRGBSurfaceFrom -#undef SDL_AllocSurface -#define SDL_AllocSurface glSDL_CreateRGBSurface -#undef SDL_LoadBMP -#define SDL_LoadBMP glSDL_LoadBMP -#undef SDL_SaveBMP -#define SDL_SaveBMP glSDL_SaveBMP -#define IMG_Load(x) glSDL_IMG_Load(x) -#endif - -#endif /* HAVE_OPENGL */ - - -#ifdef HAVE_OPENGL - -/* Some extra overloading for common external lib calls... */ -#include "SDL_image.h" -#ifdef __cplusplus -extern "C" { -#endif -SDL_Surface *glSDL_IMG_Load(const char *file); -#ifdef __cplusplus -} -#endif - -#endif /* HAVE_OPENGL */ - - -/*---------------------------------------------------------- - glSDL API extensions, transparent -----------------------------------------------------------*/ -#ifdef __cplusplus -extern "C" { -#endif -/* - * Invalidate part of a texture. - * - * This function can be used either between calls to - * glSDL_LockSurface() and glSDL_UnlockSurface(), or before - * calling glSDL_DownloadSurface(). - * - * In either case, it causes only the specified area to be - * downloaded when unlocking the surface, or calling - * glSDL_UnlockSurface(), respectively. - * - * Note that if this function is not used, glSDL assumes that - * the entire surface has to be updated. (That is, it's safe - * to ignore this function - it's "just a performance hack.") - * - * Passing a rectangle with zero height or width cancels the - * downloading when/after unlocking the surface. Use if you - * just want to read the texture, but feel like being nice and - * obeying SDL_MUSTLOCK() - which is a good idea, as things - * may change... - * - * Passing NULL for the 'area' argument results in the entire - * surface being invalidated. - * - * NOTE: This function does NOT perform clipping! Weird or - * even Bad Things may happen if you specify areas - * that protrude outside the edges of the actual - * surface. - */ -void glSDL_Invalidate(SDL_Surface *surface, SDL_Rect *area); - -/* - * Make sure that the texture of the specified surface is up - * to date in OpenGL texture memory. - * - * This can be used together with glSDL_UnloadSurface() to - * implement custom texture caching schemes. - * - * Returns 0 on success, or a negative value if something - * went wrong. - */ -int glSDL_UploadSurface(SDL_Surface *surface); - -/* - * Free the texture space used by the specified surface. - * - * Normally, glSDL should download textures when needed, and - * unload the oldest (in terms of use) surfaces, if it runs out - * of texture space. - */ -void glSDL_UnloadSurface(SDL_Surface *surface); - - -/*---------------------------------------------------------- - glSDL API extensions, OpenGL mode ONLY -----------------------------------------------------------*/ - -/* - * Enable, disable or check the state of "vsync" or - * vertical retrace synchronization. Note that enabling - * this does not *guarantee* that the driver actually - * uses vsync; it only instructs OpenGL to do so if - * possible. - * Pass 1 for 'use' to enable vsync, '0' to disable - * it, and -1 to just return the current state without - * changing it. - * Returns the vsync state *before* any change made - * by the call. - * - * NOTE: Ignored when not using OpenGL acceleration! - */ -int glSDL_VSync(int use); - -/* - * Set alpha multiplier. This is multiplied with any full - * surface alpha or alpha channels of surfaces. - * - * The default value is 255, which makes glSDL render like - * the standard SDL 2D backends, ie based only on the - * surface settings. - * - * This function affects the global state of glSDL. - * - * NOTE: NOT available without OpenGL acceleration! - */ -void glSDL_SetBlendAlpha(Uint8 alpha); - -/* - * Set color multipliers. These are multiplied with the - * respective color channers of rendered surfaces, - * modulating the brightness of the resulting output. - * - * The default values are 255, which makes glSDL render - * like the standard SDL 2D backends. - * - * This function affects the global state of glSDL. - * - * NOTE: NOT available without OpenGL acceleration! - */ -void glSDL_SetBlendColor(Uint8 r, Uint8 g, Uint8 b); - -/* - * Set center offset in pixels for scaling and rotation. - * - * The default is (0, 0), which makes surfaces rotate and - * scale around their centers. - * - * This function affects the global state of glSDL. - * - * NOTE: NOT available without OpenGL acceleration! - */ -void glSDL_SetCenter(float x, float y); - - -/* - * Set rotation angle in degrees. Rotation is done around - * the center point, which is defined as - * (w/2 + cx, h/2 + cy) - * where w and h are the width and height of the source - * surface, and cx and cy are the center offsets set by - * glSDL_SetCenter(). - * - * The default value is 0.0f, which makes glSDL render - * like a normal SDL 2D backend. - * - * This function affects the global state of glSDL. - * - * NOTE: NOT available without OpenGL acceleration! - */ -void glSDL_SetRotation(float angle); - -/* - * Set scale factor. Scaling is centered around around - * the point - * (w/2 + cx, h/2 + cy) - * where w and h are the width and height of the source - * surface, and cx and cy are the center offsets set by - * glSDL_SetCenter(). - * - * The default value is 1.0f, which makes glSDL render - * like a normal SDL 2D backend. - * - * This function affects the global state of glSDL. - * - * NOTE: NOT available without OpenGL acceleration! - */ -void glSDL_SetScale(float x, float y); - -/* - * Reset glSDL global state to defaults. - */ -void glSDL_ResetState(void); -#ifdef __cplusplus -} -#endif - - -#endif /* _GLSDL_H_ */ 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/region.h b/graphics/region.h index cb88e62..806f8c4 100644 --- a/graphics/region.h +++ b/graphics/region.h @@ -22,7 +22,7 @@ #ifndef KOBO_REGION_H #define KOBO_REGION_H -#include "glSDL.h" +#include "sdl_compat.h" #ifdef __cplusplus extern "C" { diff --git a/graphics/sdl_compat.h b/graphics/sdl_compat.h new file mode 100644 index 0000000..9c74f44 --- /dev/null +++ b/graphics/sdl_compat.h @@ -0,0 +1,16 @@ +/* + * sdl_compat.h - umbrella SDL 3 include for Kobo Deluxe. + * + * Replaces the legacy graphics/glSDL.h shim that wrapped SDL 1.2 with + * an OpenGL backend. SDL 3's renderer makes that unnecessary. + * + * This header exists so the codebase can use #include "sdl_compat.h" + * rather than scatter across the tree (which would also + * make a later SDL 4 swap painful). + */ +#ifndef _KOBO_SDL_COMPAT_H_ +#define _KOBO_SDL_COMPAT_H_ + +#include + +#endif /* _KOBO_SDL_COMPAT_H_ */ 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/sofont.h b/graphics/sofont.h index 4cf62e1..fa6e0aa 100644 --- a/graphics/sofont.h +++ b/graphics/sofont.h @@ -34,7 +34,7 @@ * Cursor tests first check if '|' is present. * Shadowed variables fixed. * Garbage data in spacing table fixed. (Thanks to - Andreas Spångberg for discovering this one!) + Andreas Sp�ngberg for discovering this one!) * Added ExtraSpace(). (Scaling support hack...) * Disabled colorkeying. (Ruins some RGBA fonts!) */ @@ -42,7 +42,7 @@ #ifndef __SOFONT_H #define __SOFONT_H -#include "glSDL.h" +#include "sdl_compat.h" class SoFont { diff --git a/graphics/sprite.c b/graphics/sprite.c index bb3c582..a4d0722 100644 --- a/graphics/sprite.c +++ b/graphics/sprite.c @@ -29,8 +29,8 @@ TODO: tables as needed when loading banks. #include #include #include "logger.h" -#include "glSDL.h" -#include "SDL_image.h" +#include "sdl_compat.h" +#include #include "sprite.h" #include "filters.h" @@ -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/sprite.h b/graphics/sprite.h index 6897cdc..4f3a664 100644 --- a/graphics/sprite.h +++ b/graphics/sprite.h @@ -26,7 +26,7 @@ extern "C" { #endif -#include "glSDL.h" +#include "sdl_compat.h" typedef enum { diff --git a/graphics/window.cpp b/graphics/window.cpp index 6198c39..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); } @@ -186,13 +182,9 @@ void window_t::invalidate(SDL_Rect *r) rr.w = phys_rect.w; rr.h = phys_rect.h; phys_refresh(&rr); - glSDL_Invalidate(surface, &rr); } else - { phys_refresh(r); - glSDL_Invalidate(surface, r); - } return; } @@ -252,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; } @@ -267,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; } @@ -287,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() @@ -298,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) @@ -309,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); } @@ -480,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); @@ -511,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); } @@ -531,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); } @@ -560,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/graphics/window.h b/graphics/window.h index 702ec1d..fcf5143 100644 --- a/graphics/window.h +++ b/graphics/window.h @@ -213,7 +213,7 @@ #ifndef _WINDOW_H_ #define _WINDOW_H_ -#include "glSDL.h" +#include "sdl_compat.h" class gfxengine_t; diff --git a/kobo.cpp b/kobo.cpp index 5ae1baa..e10dbe0 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; } @@ -637,7 +635,6 @@ int KOBO_main::init_display(prefs_t *p) int dw, dh; // Display size int gw, gh; // Game "window" size gengine->title("Kobo Deluxe " VERSION, "kobodl"); - gengine->driver((gfx_drivers_t)p->videodriver); dw = p->width; dh = p->height; @@ -691,10 +688,7 @@ int KOBO_main::init_display(prefs_t *p) gengine->size(dw, dh); gengine->mode(0, p->fullscreen); - gengine->doublebuffer(p->doublebuf); - gengine->pages(p->pages); gengine->vsync(p->vsync); - gengine->shadow(p->shadow); gengine->cursor(0); gengine->period(game.speed); @@ -1088,7 +1082,7 @@ int KOBO_main::load_graphics(prefs_t *p) if(gd->flags & KOBO_NODITHER || !p->use_dither) gengine->dither(-1); else - gengine->dither(p->dither_type, p->broken_rgba8); + gengine->dither(p->dither_type, 0); // Alpha channels if(gd->flags & KOBO_NOALPHA || !p->alpha) @@ -1205,7 +1199,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,34 +1233,40 @@ 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 */ - 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; - } + // SDL 3 joystick API: SDL_GetJoysticks returns an array of instance + // IDs that must be SDL_free()d. SDL_OpenJoystick takes one of those + // IDs and returns the SDL_Joystick handle. + if(!p->use_joystick) + return 0; + if(!SDL_InitSubSystem(SDL_INIT_JOYSTICK)) + { + log_printf(ELOG, "Error setting up joystick: %s\n", + SDL_GetError()); + return -1; + } + + int count = 0; + SDL_JoystickID *ids = SDL_GetJoysticks(&count); + p->number_of_joysticks = count; + if(count <= 0) + { + SDL_free(ids); + log_printf(ELOG, "No joysticks found!\n"); + joystick = NULL; + return -3; + } + + if(p->joystick_no < 0 || p->joystick_no >= count) + p->joystick_no = 0; + joystick = SDL_OpenJoystick(ids[p->joystick_no]); + SDL_free(ids); + if(!joystick) + { + log_printf(ELOG, "Failed to open joystick: %s\n", + SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return -2; } return 0; } @@ -1276,14 +1276,11 @@ void KOBO_main::close_js() { if(!SDL_WasInit(SDL_INIT_JOYSTICK)) return; - - if(!joystick) - return; - - if(SDL_JoystickOpened(0)) - SDL_JoystickClose(joystick); - joystick = NULL; - + if(joystick) + { + SDL_CloseJoystick(joystick); + joystick = NULL; + } SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } @@ -1597,8 +1594,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 +1604,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 +1623,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,32 +1634,29 @@ 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; - prefs->videodriver = (int)GFX_DRIVER_SDL2D; prefs->width = 640; prefs->height = 480; prefs->aspect = 1000; - prefs->depth = 0; - prefs->doublebuf = 0; - prefs->pages = -1; - prefs->shadow = 1; prefs->scalemode = (int)GFX_SCALE_NEAREST; prefs->brightness = 100; prefs->contrast = 100; @@ -1674,7 +1668,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 +1680,25 @@ void kobo_gfxengine_t::frame() gsm.release(k); } break; - case SDL_VIDEOEXPOSE: + case SDL_EVENT_TEXT_INPUT: + // SDL 3 delivers typed characters via separate text-input + // events when SDL_StartTextInput is active. Forward each + // byte of the UTF-8 string as a unicode value to the + // current gamestate (used by the high-score name-entry). + for(const char *c = ev.text.text; *c; ++c) + gsm.press(-1, (unsigned char)*c); + break; + 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 +1710,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 +1762,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 +1771,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 +1795,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 +2087,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/logger.c b/logger.c index f315c2b..17ccf9a 100644 --- a/logger.c +++ b/logger.c @@ -25,7 +25,7 @@ #include "config.h" #include "logger.h" -#include "glSDL.h" +#include "sdl_compat.h" #define LOG_BUFFER 1024 @@ -100,6 +100,7 @@ static inline int log_write_raw(int target, const char *text) /* We should never get here. */ assert(0); } + return 0; } @@ -187,8 +188,9 @@ static inline void put_timestamp(int level) { if(l_targets[l_levels[level].target].flags & LOG_TIMESTAMP) { - char buf[16]; - snprintf(buf, sizeof(buf)-1, "[%d] ", SDL_GetTicks() - start_time); + char buf[24]; + snprintf(buf, sizeof(buf)-1, "[%llu] ", + (unsigned long long)(SDL_GetTicks() - start_time)); log_write_raw(l_levels[level].target, buf); } } diff --git a/manage.h b/manage.h index 24cd294..c71776b 100644 --- a/manage.h +++ b/manage.h @@ -24,7 +24,7 @@ #ifndef _KOBO_MANAGE_H_ #define _KOBO_MANAGE_H_ -#include "glSDL.h" +#include "sdl_compat.h" #include "score.h" class _manage @@ -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 2161c6c..ed0cf26 100644 --- a/options.cpp +++ b/options.cpp @@ -177,41 +177,7 @@ void video_options_t::build() } space(); yesno("Fullscreen Display", &prf->fullscreen, OS_RESTART_VIDEO); - list("Display Depth", &prf->depth, OS_RESTART_VIDEO); - item("Default", 0); - item("8 bits", 8); - item("15 bits", 15); - item("16 bits", 16); - item("24 bits", 24); - item("32 bits", 32); -#if defined(HAVE_OPENGL) && !defined(GLSDL_OFF) - list("Display Driver", &prf->videodriver, OS_RESTART_VIDEO | - OS_REBUILD); - item("SDL 2D", GFX_DRIVER_SDL2D); - item("OpenGL/glSDL", GFX_DRIVER_GLSDL); -#else - prf->videodriver = GFX_DRIVER_SDL2D; -#endif - 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; - } - list("Display Buffer Pages", &prf->pages, OS_UPDATE_ENGINE); - item("Assume Standard", -1); - item("Always Repaint", 0); - item("Single", 1); - item("Double", 2); - item("Triple", 3); + yesno("Vertical Retrace Sync", &prf->vsync, OS_RESTART_VIDEO); big(); space(); xoffs = 0.5; @@ -250,13 +216,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(); @@ -403,11 +365,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/prefs.cpp b/prefs.cpp index b87bad7..d3a0adf 100644 --- a/prefs.cpp +++ b/prefs.cpp @@ -82,25 +82,18 @@ void prefs_t::init() comment("--- Video settings -------------------------"); yesno("fullscreen", fullscreen, 0); desc("Fullscreen Display"); - key("videodriver", videodriver, GFX_DRIVER_SDL2D); - desc("Display Driver"); key("width", width, 640); desc("Horizontal Resolution"); key("height", height, 480); desc("Vertical Resolution"); key("aspect", aspect, 1000); desc("Pixel Aspect Ratio"); - key("depth", depth, 0); desc("Display Depth"); key("maxfps", max_fps, 100); desc("Maximum fps"); key("maxfpsstrict", max_fps_strict, 0); desc("Strictly Regulated fps"); - key("buffer", doublebuf, 1); desc("Display Buffer Mode"); - yesno("shadow", shadow, 1); desc("Use Software Shadow Buffer"); key("videomode", videomode, 0x04330); desc("Video Mode"); yesno("vsync", vsync, 1); desc("Enable Vertical Sync"); - key("videopages", pages, -1); desc("Number of Video Pages"); comment("--- Graphics settings ----------------------"); key("scalemode", scalemode, 1); desc("Scaling Filter Mode"); yesno("dither", use_dither, 1); desc("Use Dithering"); key("dither_type", dither_type, 0); desc("Dither Type"); - yesno("broken_rgba8", broken_rgba8, 0); desc("Broken RGBA (OpenGL)"); yesno("alpha", alpha, 1); desc("Use Alpha Blending"); key("brightness", brightness, 100); desc("Brightness"); key("contrast", contrast, 100); desc("Contrast"); @@ -120,6 +113,14 @@ void prefs_t::init() key("release", o_release, 50, 0); desc("Limiter Speed"); key("internalres", o_internalres, 1, 0); desc("Texture Resolution"); + // SDL 1.2-era video keys, ignored under SDL 3. + key("videodriver", o_videodriver, 0, 0); desc("Display Driver"); + key("depth", o_depth, 0, 0); desc("Display Depth"); + key("buffer", o_doublebuf, 1, 0); desc("Display Buffer Mode"); + yesno("shadow", o_shadow, 1, 0); desc("Software Shadow Buffer"); + key("videopages", o_pages, -1, 0); desc("Number of Video Pages"); + yesno("broken_rgba8", o_broken_rgba8, 0, 0); desc("Broken RGBA (OpenGL)"); + comment("--- Temporary variables --------------------"); key("last_profile", last_profile, 0); desc("Last used player profile"); @@ -170,8 +171,4 @@ void prefs_t::postload() log_printf(ELOG, "Radar sweep mode broken and disabled!\n"); scrollradar = 2; } - - // Some unimplemented enums were removed in 0.4.1 - if(videodriver != GFX_DRIVER_SDL2D) - videodriver = GFX_DRIVER_GLSDL; } diff --git a/prefs.h b/prefs.h index b56bc43..1f6cca1 100644 --- a/prefs.h +++ b/prefs.h @@ -73,24 +73,18 @@ class prefs_t : public config_parser_t //Video settings int fullscreen; //Use fullscreen mode - int videodriver; //Internal video driver int width; //Screen/window width int height; //Screen/window height int aspect; //Pixel aspect ratio * 1000 - int depth; //Bits per pixel int max_fps; //Maximum fps int max_fps_strict; //Strictly regulated fps limiter - int doublebuf; //Use double buffering - int shadow; //Use software shadow buffer - int videomode; //New video mode codes + int videomode; //Selected entry from the vidmodes table int vsync; //Vertical (retrace) sync - int pages; //Number of physical video pages //Graphics settings int scalemode; //Scaling filter mode int use_dither; int dither_type; - int broken_rgba8; //For some OpenGL setups int alpha; //Alpha blending int brightness; //Graphics brightness int contrast; //Graphics contrast @@ -108,6 +102,13 @@ class prefs_t : public config_parser_t int o_threshold; //Limiter threshold int o_release; //Limiter release rate int o_internalres; //Internal resolution for OpenGL + // SDL 1.2 video settings, read for back-compat but unused under SDL 3 + int o_videodriver; + int o_depth; + int o_doublebuf; + int o_shadow; + int o_pages; + int o_broken_rgba8; //"Hidden" stuff ("to remember until next startup") int last_profile; //Last used player profile diff --git a/random.h b/random.h index 97c69c7..d1756ee 100644 --- a/random.h +++ b/random.h @@ -24,7 +24,7 @@ #define _KOBO_RANDOM_H_ #include -#include "glSDL.h" +#include "sdl_compat.h" class rand_num_t { diff --git a/sound/a_tools.h b/sound/a_tools.h index f37466e..43f314f 100644 --- a/sound/a_tools.h +++ b/sound/a_tools.h @@ -22,7 +22,7 @@ #ifndef _A_TOOLS_H_ #define _A_TOOLS_H_ -#include "glSDL.h" +#include "sdl_compat.h" #include #include "kobolog.h" #include "a_types.h" diff --git a/sound/a_types.h b/sound/a_types.h index 5b18e08..ec519c3 100644 --- a/sound/a_types.h +++ b/sound/a_types.h @@ -22,7 +22,7 @@ #ifndef _A_TYPES_H_ #define _A_TYPES_H_ -#include "glSDL.h" +#include "sdl_compat.h" /* Builtin patch drivers */ typedef enum 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 bbdce24..b987f4b 100644 --- a/sound/audio.c +++ b/sound/audio.c @@ -45,10 +45,25 @@ #include "audiodev.h" #endif -#include "SDL.h" -#include "SDL_audio.h" +#include +#include #include "logger.h" +/* + * SDL 3 audio bridge. + * + * SDL 1.2 pushed callbacks into a fixed output buffer; SDL 3 uses + * SDL_AudioStream as a pull-style queue with an "I want more data" + * callback. The engine's existing _audio_callback() still fills a + * Sint16 stereo buffer of an arbitrary requested byte length, so we + * keep it intact and add a small adapter (sdl3_stream_callback) that + * runs it on a scratch buffer and pushes the result into the stream. + */ +static SDL_AudioStream *_sdl_stream = NULL; +static SDL_AudioDeviceID _sdl_audio_dev = 0; +static Uint8 *_sdl_scratch = NULL; +static int _sdl_scratch_size = 0; + #include "a_struct.h" #include "a_commands.h" #include "a_control.h" @@ -567,50 +582,63 @@ static int _start_oss_output() } +static void SDLCALL _sdl3_stream_callback(void *userdata, + SDL_AudioStream *stream, int additional, int total) +{ + (void)userdata; (void)total; + if(additional <= 0) + return; + if(additional > _sdl_scratch_size) + { + Uint8 *p = realloc(_sdl_scratch, additional); + if(!p) + return; + _sdl_scratch = p; + _sdl_scratch_size = additional; + } + _audio_callback(NULL, _sdl_scratch, additional); + SDL_PutAudioStreamData(stream, _sdl_scratch, additional); +} + + static int _start_SDL_output(void) { - SDL_AudioSpec as; - SDL_AudioSpec audiospec; - - if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + if(!SDL_InitSubSystem(SDL_INIT_AUDIO)) + { + log_printf(ELOG, "audio.c: SDL_InitSubSystem failed: %s\n", + SDL_GetError()); return -2; + } - as.freq = a_settings.samplerate; - as.format = AUDIO_S16SYS; - as.channels = 2; - as.samples = (Uint16)a_settings.output_buffersize; - as.callback = _audio_callback; - if(SDL_OpenAudio(&as, &audiospec) < 0) + SDL_AudioSpec spec; + SDL_zero(spec); + spec.freq = a_settings.samplerate; + spec.format = SDL_AUDIO_S16; + spec.channels = 2; + + _sdl_stream = SDL_OpenAudioDeviceStream( + SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, + &spec, _sdl3_stream_callback, NULL); + if(!_sdl_stream) + { + log_printf(ELOG, "audio.c: SDL_OpenAudioDeviceStream failed: %s\n", + SDL_GetError()); return -3; - - if(audiospec.format != AUDIO_S16SYS) - { - log_printf(ELOG, "audio.c: ERROR: Only 16 bit output supported!\n"); - SDL_CloseAudio(); - return -4; } + _sdl_audio_dev = SDL_GetAudioStreamDevice(_sdl_stream); - if(audiospec.channels != 2) + // SDL 3 may give us a different frequency than requested if the + // device only supports certain rates; query the actual format. + SDL_AudioSpec dev_spec; + int dev_frames = 0; + if(SDL_GetAudioDeviceFormat(_sdl_audio_dev, &dev_spec, &dev_frames)) { - log_printf(ELOG, "audio.c: ERROR: Only stereo output supported!\n"); - SDL_CloseAudio(); - return -5; - } - - if(a_settings.samplerate != audiospec.freq) - { - log_printf(ELOG, "audio.c: Warning: Requested fs=%d Hz, but" - "got %d Hz.\n", a_settings.samplerate, - audiospec.freq); - a_settings.samplerate = audiospec.freq; - } - - if((unsigned)audiospec.samples != a_settings.output_buffersize) - { - log_printf(ELOG, "audio.c: Warning: Requested %u sample" - "buffer, but got %u samples.\n", - a_settings.output_buffersize, audiospec.samples); - a_settings.output_buffersize = audiospec.samples; + if(dev_spec.freq != a_settings.samplerate) + { + log_printf(WLOG, "audio.c: Requested %d Hz, got %d Hz.\n", + a_settings.samplerate, dev_spec.freq); + a_settings.samplerate = dev_spec.freq; + } } if(a_settings.output_buffersize > MAX_BUFFER_SIZE) @@ -622,12 +650,13 @@ static int _start_SDL_output(void) mixbuf = calloc(1, a_settings.buffersize * sizeof(int) * 2); if(!mixbuf) { - SDL_CloseAudio(); + SDL_DestroyAudioStream(_sdl_stream); + _sdl_stream = NULL; return -1; } _audio_running = 1; - SDL_PauseAudio(0); + SDL_ResumeAudioStreamDevice(_sdl_stream); return 0; } @@ -710,7 +739,17 @@ static void _stop_output(void) #endif } else - SDL_CloseAudio(); + { + if(_sdl_stream) + { + SDL_DestroyAudioStream(_sdl_stream); + _sdl_stream = NULL; + _sdl_audio_dev = 0; + } + free(_sdl_scratch); + _sdl_scratch = NULL; + _sdl_scratch_size = 0; + } free(mixbuf); mixbuf = NULL; } @@ -736,8 +775,8 @@ void audio_lock(void) ++_audio_mutex_locked; #endif } - else - SDL_LockAudio(); + else if(_sdl_stream) + SDL_LockAudioStream(_sdl_stream); } @@ -756,8 +795,8 @@ void audio_unlock(void) } #endif } - else - SDL_UnlockAudio(); + else if(_sdl_stream) + SDL_UnlockAudioStream(_sdl_stream); } #endif diff --git a/states.cpp b/states.cpp index 6c1c3a9..116fda5 100644 --- a/states.cpp +++ b/states.cpp @@ -21,7 +21,8 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "glSDL.h" +#include "sdl_compat.h" +#include "gfxengine.h" #include #ifndef M_PI # define M_PI 3.14159265358979323846 /* pi */ @@ -335,16 +336,15 @@ void st_game_t::enter() "Please, check your installation."); gsm.change(&st_error); } - if(prefs->mousecapture) - if(SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) - SDL_WM_GrabInput(SDL_GRAB_ON); + if(prefs->mousecapture && gengine->window_handle()) + SDL_SetWindowMouseGrab(gengine->window_handle(), true); } void st_game_t::leave() { - if(SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON) - SDL_WM_GrabInput(SDL_GRAB_OFF); + if(gengine->window_handle()) + SDL_SetWindowMouseGrab(gengine->window_handle(), false); st_intro_title.inext = &st_intro_instructions; st_intro_title.duration = INTRO_TITLE_TIME + 2000; st_intro_title.mode = 0; @@ -353,16 +353,15 @@ void st_game_t::leave() void st_game_t::yield() { - if(SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON) - SDL_WM_GrabInput(SDL_GRAB_OFF); + if(gengine->window_handle()) + SDL_SetWindowMouseGrab(gengine->window_handle(), false); } void st_game_t::reenter() { - if(prefs->mousecapture) - if(SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) - SDL_WM_GrabInput(SDL_GRAB_ON); + if(prefs->mousecapture && gengine->window_handle()) + SDL_SetWindowMouseGrab(gengine->window_handle(), true); } @@ -878,12 +877,14 @@ void new_player_t::open() currentIndex = 0; editing = 1; build_all(); - SDL_EnableUNICODE(1); + if(gengine->window_handle()) + SDL_StartTextInput(gengine->window_handle()); } void new_player_t::close() { - SDL_EnableUNICODE(0); + if(gengine->window_handle()) + SDL_StopTextInput(gengine->window_handle()); clean(); } @@ -1599,7 +1600,6 @@ void st_options_base_t::select(int tag) gengine->timefilter(prefs->timefilter * 0.01f); gengine->interpolation(prefs->filter); gengine->vsync(prefs->vsync); - gengine->pages(prefs->pages); } cfg_form->clearstatus(OS_UPDATE);