Completes phases 3-6 of the migration plan. After this commit, the
codebase compiles and links against pure SDL 3 (no compat shim). The
binary is unverified at runtime but the build is clean.
Renderer (graphics/gfxengine.{cpp,h}):
- Replace SDL_SetVideoMode + SDL_Flip + page-flip machinery with
SDL_CreateWindow + SDL_CreateRenderer + a streaming SDL_Texture.
The CPU-side back buffer (softbuf) is now always ARGB8888; legacy
HW/double-buffer/page flags are dead.
- flip() does a single full-frame SDL_UpdateTexture + SDL_RenderClear
+ SDL_RenderTexture + SDL_RenderPresent each frame. The dirtyrect
iteration is retained only to drive widget phys_refresh() callbacks.
- SDL_SetRenderLogicalPresentation gives us letterbox scaling for free.
- SDL_SetRenderVSync replaces glSDL_VSync.
- title()/cursor() ported to SDL 3 window/cursor APIs.
Surface API (graphics/sprite.c, filters.c, window.cpp, sofont.cpp,
region.c):
- SDL_FreeSurface → SDL_DestroySurface
- SDL_FillRect → SDL_FillSurfaceRect
- SDL_SetClipRect → SDL_SetSurfaceClipRect
- SDL_SetColorKey(s, flags, key) → SDL_SetSurfaceColorKey(s, bool, key)
- SDL_SetAlpha(s, flags, a) → SDL_SetSurfaceAlphaMod + BlendMode
- SDL_SetColors → SDL_SetSurfacePalette
- SDL_CreateRGBSurface(...) → SDL_CreateSurface(w, h, format_enum)
- SDL_DisplayFormat[Alpha] → SDL_ConvertSurface(s, ARGB8888)
- SDL_MapRGB(surf->format, ...) → SDL_MapSurfaceRGB(surf, ...)
- surface->format->Field → SDL_GetPixelFormatDetails(surf->format)->field
- surface->format->Amask test → SDL_ISPIXELFORMAT_ALPHA
- surface->clip_rect → SDL_GetSurfaceClipRect
Events (kobo.cpp):
- SDL_{KEYDOWN,KEYUP,QUIT,VIDEOEXPOSE,MOUSE*,JOY*} → SDL_EVENT_*
- SDL_ACTIVEEVENT (with gain check) → SDL_EVENT_WINDOW_FOCUS_LOST
- ev.key.keysym.sym → ev.key.key (.unicode → text input, deferred)
- SDLK_PRINT/SYSREQ → SDLK_PRINTSCREEN; lowercase SDLK_p/y/n → uppercase
- ev.motion.x/y for button events → ev.button.x/y (struct layout differs)
- KMOD_META → SDL_KMOD_GUI
- SDL_INIT_NOPARACHUTE → SDL_Init(0) (no parachute by default in SDL 3)
Keymap (gamectl.{cpp,h}):
- SDLKey → SDL_Keycode
- SDLK_KP{1..9} → SDLK_KP_{1..9}
Stubs deferred for later phases (binary will run but with degraded
behavior):
- sound/audio.c: _start_SDL_output returns -1 immediately; SDL 1.2
audio callback model needs full rewrite onto SDL_AudioStream.
- kobo.cpp init_js/close_js: SDL 3 joystick API uses instance IDs;
re-port deferred.
- states.cpp SDL_WM_GrabInput/SDL_EnableUNICODE: need window pointer
exposed from gfxengine; stubbed.
- gamectl.cpp SDL_EnableKeyRepeat: removed; relies on ev.key.repeat.
Other adjustments:
- options.cpp: GFX_DRIVER_GLSDL menu paths removed; show vsync option
always (renderer handles it).
- sound/a_wave.c: AUDIO_S8/AUDIO_S16SYS → SDL_AUDIO_S8/S16, SDL_FreeWAV
→ SDL_free.
- gfxengine.cpp: SDL_putenv("SDL_VIDEO_CENTERED=1") obsolete (handled
by SDL_CreateWindow defaults).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
223 lines
4.4 KiB
C
223 lines
4.4 KiB
C
/*(LGPL)
|
|
----------------------------------------------------------------------
|
|
region.c - Graphics Engine
|
|
----------------------------------------------------------------------
|
|
* Copyright (C) 2007 David Olofson
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "region.h"
|
|
#include <stdlib.h>
|
|
|
|
static struct
|
|
{
|
|
RGN_region *region;
|
|
int x, y;
|
|
SDL_Surface *target;
|
|
} s;
|
|
|
|
|
|
static Uint32 gp1(SDL_Surface *surface, int x, int y)
|
|
{
|
|
return *((Uint8 *)surface->pixels + y * surface->pitch + x);
|
|
}
|
|
|
|
|
|
static Uint32 gp2(SDL_Surface *surface, int x, int y)
|
|
{
|
|
return *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x);
|
|
}
|
|
|
|
|
|
static Uint32 gp3(SDL_Surface *surface, int x, int y)
|
|
{
|
|
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];
|
|
#else
|
|
return p[0] | p[1] << 8 | p[2] << 16;
|
|
#endif
|
|
}
|
|
|
|
|
|
static Uint32 gp4(SDL_Surface *surface, int x, int y)
|
|
{
|
|
return *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x);
|
|
}
|
|
|
|
|
|
RGN_region *RGN_ScanMask(SDL_Surface *src, Uint32 key)
|
|
{
|
|
RGN_region *rgn = (RGN_region *)calloc(1, sizeof(RGN_region));
|
|
Uint32 (*gp)(SDL_Surface *surface, int x, int y);
|
|
int x, y;
|
|
if(!rgn)
|
|
return NULL;
|
|
rgn->rows = src->h;
|
|
rgn->spans = (Uint16 **)calloc(1, sizeof(Uint16 *) * src->h);
|
|
if(!rgn->spans)
|
|
{
|
|
RGN_FreeRegion(rgn);
|
|
return NULL;
|
|
}
|
|
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;
|
|
break;
|
|
case 2:
|
|
gp = gp2;
|
|
break;
|
|
case 3:
|
|
gp = gp3;
|
|
break;
|
|
case 4:
|
|
gp = gp4;
|
|
break;
|
|
default:
|
|
RGN_FreeRegion(rgn);
|
|
return NULL;
|
|
}
|
|
SDL_LockSurface(src);
|
|
for(y = 0; y < src->h; ++y)
|
|
{
|
|
int i = 0;
|
|
int drawing = 0;
|
|
Uint16 *sp = (Uint16 *)malloc(sizeof(Uint16) * 2 * (src->w + 1));
|
|
if(!sp)
|
|
{
|
|
SDL_UnlockSurface(src);
|
|
RGN_FreeRegion(rgn);
|
|
return NULL;
|
|
}
|
|
for(x = 0; x < src->w; ++x)
|
|
{
|
|
int nd = (gp(src, x, y) == key);
|
|
if(nd != drawing)
|
|
{
|
|
sp[i++] = x;
|
|
drawing = nd;
|
|
}
|
|
}
|
|
if(drawing)
|
|
sp[i++] = src->w;
|
|
sp[i++] = 0;
|
|
sp[i++] = 0;
|
|
rgn->spans[y] = (Uint16 *)realloc(sp, sizeof(Uint16) * i);
|
|
if(!rgn->spans[y])
|
|
rgn->spans[y] = sp;
|
|
}
|
|
SDL_UnlockSurface(src);
|
|
return rgn;
|
|
}
|
|
|
|
|
|
void RGN_FreeRegion(RGN_region *rgn)
|
|
{
|
|
if(!rgn)
|
|
return;
|
|
if(rgn->spans)
|
|
{
|
|
int i;
|
|
for(i = rgn->rows - 1; i >= 0; --i)
|
|
free(rgn->spans[i]);
|
|
free(rgn->spans);
|
|
}
|
|
free(rgn);
|
|
}
|
|
|
|
|
|
void RGN_Target(SDL_Surface *tgt)
|
|
{
|
|
s.target = tgt;
|
|
}
|
|
|
|
|
|
void RGN_SetRegion(RGN_region *rgn, int xpos, int ypos)
|
|
{
|
|
s.region = rgn;
|
|
s.x = xpos;
|
|
s.y = ypos;
|
|
}
|
|
|
|
|
|
int RGN_Blit(SDL_Surface *src, SDL_Rect *sr, int x, int y)
|
|
{
|
|
// FIXME: Clipping is only half done here...
|
|
int yy0, yy, yy1;
|
|
int sxmin, sxmax, symin, symax;
|
|
SDL_Rect sr2;
|
|
if(!s.region)
|
|
{
|
|
SDL_Rect dr;
|
|
dr.x = x;
|
|
dr.y = y;
|
|
return SDL_BlitSurface(src, sr, s.target, &dr);
|
|
}
|
|
if(sr)
|
|
{
|
|
sxmin = sr->x;
|
|
symin = sr->y;
|
|
sxmax = sxmin + sr->w;
|
|
symax = symin + sr->h;
|
|
}
|
|
else
|
|
{
|
|
sxmin = 0;
|
|
symin = 0;
|
|
sxmax = src->w;
|
|
symax = src->h;
|
|
}
|
|
yy0 = s.y;
|
|
if(yy0 >= y + (symax - symin))
|
|
return 0;
|
|
if(yy0 < y)
|
|
yy0 = y;
|
|
yy1 = s.y + s.region->rows;
|
|
if(y >= yy1)
|
|
return 0;
|
|
if(yy1 > y + (symax - symin))
|
|
yy1 = y + (symax - symin);
|
|
sr2.h = 1;
|
|
for(yy = yy0; yy < yy1; ++yy)
|
|
{
|
|
SDL_Rect dr;
|
|
Uint16 *spans = s.region->spans[yy - s.y];
|
|
sr2.y = symin + y - yy0;
|
|
dr.y = yy;
|
|
for( ; spans[0] && spans[1] ; spans += 2)
|
|
{
|
|
int x0 = s.x + spans[0];
|
|
int x1 = s.x + spans[1];
|
|
dr.x = x0;
|
|
sr2.x = sxmin + x0 - x;
|
|
sr2.w = x1 - x0;
|
|
SDL_BlitSurface(src, &sr2, s.target, &dr);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|