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>
648 lines
12 KiB
C++
648 lines
12 KiB
C++
/*(LGPL)
|
|
---------------------------------------------------------------------------
|
|
window.cpp - Generic Rendering Window
|
|
---------------------------------------------------------------------------
|
|
* Copyright (C) 2001-2003, 2006, 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 "logger.h"
|
|
#include "window.h"
|
|
#include "gfxengine.h"
|
|
#include "sofont.h"
|
|
|
|
#define SELECT if(selected != this) _select();
|
|
|
|
window_t *window_t::selected = NULL;
|
|
|
|
window_t::window_t()
|
|
{
|
|
engine = NULL;
|
|
surface = NULL;
|
|
next = NULL;
|
|
prev = NULL;
|
|
phys_rect.x = phys_rect.y = 0;
|
|
phys_rect.w = 320;
|
|
phys_rect.h = 240;
|
|
fgcolor = bgcolor = 0;
|
|
selected = 0;
|
|
xs = ys = 256;
|
|
bg_bank = -1;
|
|
bg_frame = -1;
|
|
_visible = 1;
|
|
_offscreen = 0;
|
|
}
|
|
|
|
|
|
window_t::~window_t()
|
|
{
|
|
if(_offscreen && surface)
|
|
SDL_DestroySurface(surface);
|
|
if(selected == this)
|
|
selected = NULL;
|
|
unlink();
|
|
}
|
|
|
|
|
|
void window_t::init(gfxengine_t *e)
|
|
{
|
|
link(e);
|
|
xs = engine->xs;
|
|
ys = engine->ys;
|
|
if(_offscreen && surface)
|
|
{
|
|
SDL_DestroySurface(surface);
|
|
surface = NULL;
|
|
}
|
|
_offscreen = 0;
|
|
surface = engine->surface();
|
|
}
|
|
|
|
|
|
void window_t::visible(int vis)
|
|
{
|
|
if(_offscreen)
|
|
return; // Cannot be visible!
|
|
if(_visible == vis)
|
|
return;
|
|
_visible = vis;
|
|
invalidate();
|
|
}
|
|
|
|
|
|
void window_t::link(gfxengine_t *e)
|
|
{
|
|
unlink();
|
|
engine = e;
|
|
next = NULL;
|
|
prev = engine->windows;
|
|
if(prev)
|
|
{
|
|
while(prev->next)
|
|
prev = prev->next;
|
|
prev->next = this;
|
|
}
|
|
else
|
|
engine->windows = this;
|
|
}
|
|
|
|
|
|
void window_t::unlink(void)
|
|
{
|
|
if(engine)
|
|
{
|
|
if(engine->windows == this)
|
|
engine->windows = next;
|
|
if(engine->surface() == surface)
|
|
surface = NULL;
|
|
}
|
|
if(next)
|
|
next->prev = prev;
|
|
if(prev)
|
|
prev->next = next;
|
|
}
|
|
|
|
|
|
void window_t::place(int left, int top, int sizex, int sizey)
|
|
{
|
|
int x2 = ((left + sizex) * xs + 128) >> 8;
|
|
int y2 = ((top + sizey) * ys + 128) >> 8;
|
|
phys_rect.x = (left * xs + 128) >> 8;
|
|
phys_rect.y = (top * ys + 128) >> 8;
|
|
phys_rect.w = x2 - phys_rect.x;
|
|
phys_rect.h = y2 - phys_rect.y;
|
|
}
|
|
|
|
|
|
int window_t::offscreen()
|
|
{
|
|
if(!engine)
|
|
return -1;
|
|
if(!engine->surface())
|
|
return -1;
|
|
if(_offscreen)
|
|
return 0; // Already offscreen!
|
|
visible(0);
|
|
_offscreen = 1;
|
|
// 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;
|
|
}
|
|
|
|
|
|
void window_t::select()
|
|
{
|
|
if(engine)
|
|
_select();
|
|
}
|
|
|
|
|
|
void window_t::_select()
|
|
{
|
|
SDL_Rect r = phys_rect;
|
|
selected = this;
|
|
if(surface)
|
|
SDL_SetSurfaceClipRect(surface, &r);
|
|
}
|
|
|
|
|
|
void window_t::invalidate(SDL_Rect *r)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
if(!engine->surface())
|
|
return;
|
|
|
|
SELECT
|
|
|
|
if(_offscreen)
|
|
{
|
|
if(!r)
|
|
{
|
|
SDL_Rect rr;
|
|
rr.x = 0;
|
|
rr.y = 0;
|
|
rr.w = phys_rect.w;
|
|
rr.h = phys_rect.h;
|
|
phys_refresh(&rr);
|
|
}
|
|
else
|
|
phys_refresh(r);
|
|
return;
|
|
}
|
|
|
|
if(!r)
|
|
engine->invalidate(&phys_rect, this);
|
|
else
|
|
{
|
|
/* Translate to screen coordinates */
|
|
SDL_Rect dr = *r;
|
|
dr.x = (dr.x * xs + 128) >> 8;
|
|
dr.y = (dr.y * ys + 128) >> 8;
|
|
dr.w = (((dr.w + dr.x) * xs + 128) >> 8) - dr.x;
|
|
dr.h = (((dr.h + dr.y) * ys + 128) >> 8) - dr.y;
|
|
dr.x += phys_rect.x;
|
|
dr.y += phys_rect.y;
|
|
|
|
/* Clip to window (stolen from SDL_surface.c) */
|
|
int Amin, Amax, Bmin, Bmax;
|
|
|
|
/* Horizontal intersection */
|
|
Amin = dr.x;
|
|
Amax = Amin + dr.w;
|
|
Bmin = phys_rect.x;
|
|
Bmax = Bmin + phys_rect.w;
|
|
if(Bmin > Amin)
|
|
Amin = Bmin;
|
|
dr.x = Amin;
|
|
if(Bmax < Amax)
|
|
Amax = Bmax;
|
|
dr.w = Amax - Amin > 0 ? Amax - Amin : 0;
|
|
|
|
/* Vertical intersection */
|
|
Amin = dr.y;
|
|
Amax = Amin + dr.h;
|
|
Bmin = phys_rect.y;
|
|
Bmax = Bmin + phys_rect.h;
|
|
if(Bmin > Amin)
|
|
Amin = Bmin;
|
|
dr.y = Amin;
|
|
if(Bmax < Amax)
|
|
Amax = Bmax;
|
|
dr.h = Amax - Amin > 0 ? Amax - Amin : 0;
|
|
|
|
if(dr.w && dr.h)
|
|
engine->invalidate(&dr, this);
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
Rendering API
|
|
---------------------------------------------------------------*/
|
|
|
|
Uint32 window_t::map_rgb(Uint8 r, Uint8 g, Uint8 b)
|
|
{
|
|
if(!engine)
|
|
return 0;
|
|
|
|
if(surface)
|
|
return SDL_MapSurfaceRGB(surface, r, g, b);
|
|
else
|
|
return 0xffffff;
|
|
}
|
|
|
|
Uint32 window_t::map_rgb(Uint32 rgb)
|
|
{
|
|
if(!engine)
|
|
return 0;
|
|
|
|
Uint8 r = (rgb >> 16) & 0xff;
|
|
Uint8 g = (rgb >> 8) & 0xff;
|
|
Uint8 b = rgb & 0xff;
|
|
|
|
if(surface)
|
|
return SDL_MapSurfaceRGB(surface, r, g, b);
|
|
else
|
|
return 0xffffff;
|
|
}
|
|
|
|
void window_t::bgimage(int bank, int frame)
|
|
{
|
|
bg_bank = bank;
|
|
bg_frame = frame;
|
|
}
|
|
|
|
|
|
void window_t::colorkey(Uint32 color)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
if(!engine->surface())
|
|
return;
|
|
if(!_offscreen)
|
|
return;
|
|
SDL_SetSurfaceColorKey(surface, true, color);
|
|
}
|
|
|
|
void window_t::colorkey()
|
|
{
|
|
if(!engine)
|
|
return;
|
|
if(!engine->surface())
|
|
return;
|
|
if(!_offscreen)
|
|
return;
|
|
SDL_SetSurfaceColorKey(surface, false, 0);
|
|
}
|
|
|
|
void window_t::alpha(float a)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
if(!engine->surface())
|
|
return;
|
|
if(!_offscreen)
|
|
return;
|
|
SDL_SetSurfaceAlphaMod(surface, (Uint8)(a * 255.0f));
|
|
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
|
|
}
|
|
|
|
|
|
void window_t::font(int fnt)
|
|
{
|
|
_font = fnt;
|
|
}
|
|
|
|
|
|
void window_t::string(int _x, int _y, const char *txt)
|
|
{
|
|
string_fxp(PIXEL2CS(_x), PIXEL2CS(_y), txt);
|
|
}
|
|
|
|
|
|
void window_t::center(int _y, const char *txt)
|
|
{
|
|
center_fxp(PIXEL2CS(_y), txt);
|
|
}
|
|
|
|
|
|
void window_t::center_token(int _x, int _y, const char *txt, char token)
|
|
{
|
|
center_token_fxp(PIXEL2CS(_x), PIXEL2CS(_y), txt, token);
|
|
}
|
|
|
|
|
|
void window_t::string_fxp(int _x, int _y, const char *txt)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
|
|
_x = CS2PIXEL((_x * xs + 128) >> 8);
|
|
_y = CS2PIXEL((_y * ys + 128) >> 8);
|
|
SoFont *f = engine->get_font(_font);
|
|
if(!f)
|
|
return;
|
|
SELECT
|
|
_x += phys_rect.x;
|
|
_y += phys_rect.y;
|
|
if(surface)
|
|
f->PutString(surface, _x, _y, txt);
|
|
}
|
|
|
|
|
|
void window_t::center_fxp(int _y, const char *txt)
|
|
{
|
|
_y = CS2PIXEL((_y * ys + 128) >> 8);
|
|
|
|
if(!engine)
|
|
return;
|
|
|
|
SoFont *f = engine->get_font(_font);
|
|
if(!f)
|
|
return;
|
|
SELECT
|
|
int _x = (phys_rect.w - f->TextWidth(txt) + 1) / 2;
|
|
_x += phys_rect.x;
|
|
_y += phys_rect.y;
|
|
if(surface)
|
|
f->PutString(surface, _x, _y, txt);
|
|
}
|
|
|
|
|
|
void window_t::center_token_fxp(int _x, int _y, const char *txt, char token)
|
|
{
|
|
_x = CS2PIXEL((_x * xs + 128) >> 8);
|
|
_y = CS2PIXEL((_y * ys + 128) >> 8);
|
|
|
|
if(!engine)
|
|
return;
|
|
|
|
SoFont *f = engine->get_font(_font);
|
|
if(!f)
|
|
return;
|
|
SELECT
|
|
int _cx;
|
|
if(-1 == token)
|
|
_cx = _x - f->TextWidth(txt)/2;
|
|
else
|
|
{
|
|
int tokpos;
|
|
/*
|
|
* My docs won't say if strchr(???, 0) is legal
|
|
* or even defined, so I'm not taking any chances...
|
|
*/
|
|
if(token)
|
|
{
|
|
const char *tok = strchr(txt, token);
|
|
if(tok)
|
|
tokpos = tok-txt;
|
|
else
|
|
tokpos = 255;
|
|
}
|
|
else
|
|
tokpos = 255;
|
|
_cx = _x - f->TextWidth(txt, 0, tokpos);
|
|
}
|
|
_cx += phys_rect.x;
|
|
_y += phys_rect.y;
|
|
if(surface)
|
|
f->PutString(surface, _cx, _y, txt);
|
|
}
|
|
|
|
|
|
int window_t::textwidth_fxp(const char *txt, int min, int max)
|
|
{
|
|
if(!engine)
|
|
return strlen(txt);
|
|
|
|
SoFont *f = engine->get_font(_font);
|
|
if(!f)
|
|
return strlen(txt);
|
|
|
|
return (f->TextWidth(txt, min, max) << 16) / xs;
|
|
}
|
|
|
|
|
|
int window_t::textwidth(const char *txt, int min, int max)
|
|
{
|
|
if(!engine)
|
|
return strlen(txt);
|
|
|
|
SoFont *f = engine->get_font(_font);
|
|
if(!f)
|
|
return strlen(txt);
|
|
|
|
return (f->TextWidth(txt, min, max) << 8) / xs;
|
|
}
|
|
|
|
|
|
int window_t::fontheight()
|
|
{
|
|
if(!engine)
|
|
return 1;
|
|
|
|
SoFont *f = engine->get_font(_font);
|
|
if(!f)
|
|
return 1;
|
|
|
|
return (f->FontHeight() * 256) / ys;
|
|
}
|
|
|
|
|
|
void window_t::clear(SDL_Rect *r)
|
|
{
|
|
SDL_Rect sr, dr;
|
|
if(!engine)
|
|
return;
|
|
if(!surface)
|
|
return;
|
|
SELECT
|
|
if(!r)
|
|
{
|
|
sr = phys_rect;
|
|
sr.x = 0;
|
|
sr.y = 0;
|
|
dr = phys_rect;
|
|
}
|
|
else
|
|
{
|
|
sr.x = ((int)r->x * xs + 128) >> 8;
|
|
sr.y = ((int)r->y * ys + 128) >> 8;
|
|
sr.w = (((int)(r->x + r->w) * xs + 128) >> 8) - sr.x;
|
|
sr.h = (((int)(r->y + r->h) * ys + 128) >> 8) - sr.y;
|
|
dr = sr;
|
|
dr.x += phys_rect.x;
|
|
dr.y += phys_rect.y;
|
|
}
|
|
if((-1 == bg_bank) && (-1 == bg_frame))
|
|
SDL_FillSurfaceRect(surface, &dr, bgcolor);
|
|
else
|
|
{
|
|
s_sprite_t *s = engine->get_sprite(bg_bank, bg_frame);
|
|
if(!s || !s->surface)
|
|
{
|
|
SDL_FillSurfaceRect(surface, &dr, bgcolor);
|
|
return;
|
|
}
|
|
SDL_BlitSurface(s->surface, &sr, surface, &dr);
|
|
}
|
|
}
|
|
|
|
|
|
void window_t::point(int _x, int _y)
|
|
{
|
|
int x2 = ((_x + 1) * xs + 128) >> 8;
|
|
int y2 = ((_y + 1) * ys + 128) >> 8;
|
|
_x = (_x * xs + 128) >> 8;
|
|
_y = (_y * ys + 128) >> 8;
|
|
|
|
if(!engine)
|
|
return;
|
|
SELECT
|
|
/* Quick hack; slow */
|
|
SDL_Rect r;
|
|
r.x = phys_rect.x + _x;
|
|
r.y = phys_rect.y + _y;
|
|
r.w = x2 - _x;
|
|
r.h = y2 - _y;
|
|
if(surface)
|
|
SDL_FillSurfaceRect(surface, &r, fgcolor);
|
|
}
|
|
|
|
|
|
void window_t::fillrect(int _x, int _y, int w, int h)
|
|
{
|
|
int x2 = ((_x + w) * xs + 128) >> 8;
|
|
int y2 = ((_y + h) * ys + 128) >> 8;
|
|
_x = (_x * xs + 128) >> 8;
|
|
_y = (_y * ys + 128) >> 8;
|
|
|
|
if(!engine)
|
|
return;
|
|
SELECT
|
|
SDL_Rect r;
|
|
r.x = phys_rect.x + _x;
|
|
r.y = phys_rect.y + _y;
|
|
r.w = x2 - _x;
|
|
r.h = y2 - _y;
|
|
if(surface)
|
|
SDL_FillSurfaceRect(surface, &r, fgcolor);
|
|
}
|
|
|
|
|
|
void window_t::rectangle(int _x, int _y, int w, int h)
|
|
{
|
|
fillrect(_x, _y, w, 1);
|
|
fillrect(_x, _y + h - 1, w, 1);
|
|
fillrect(_x, _y + 1, 1, h - 2);
|
|
fillrect(_x + w - 1, _y + 1, 1, h - 2);
|
|
}
|
|
|
|
|
|
void window_t::fillrect_fxp(int _x, int _y, int w, int h)
|
|
{
|
|
int xx = CS2PIXEL((_x * xs + 128) >> 8);
|
|
int yy = CS2PIXEL((_y * ys + 128) >> 8);
|
|
w = CS2PIXEL(((w + _x) * xs + 128) >> 8) - xx;
|
|
h = CS2PIXEL(((h + _y) * ys + 128) >> 8) - yy;
|
|
|
|
if(!engine)
|
|
return;
|
|
SELECT
|
|
SDL_Rect r;
|
|
r.x = phys_rect.x + xx;
|
|
r.y = phys_rect.y + yy;
|
|
r.w = w;
|
|
r.h = h;
|
|
if(surface)
|
|
SDL_FillSurfaceRect(surface, &r, fgcolor);
|
|
}
|
|
|
|
|
|
void window_t::sprite(int _x, int _y, int bank, int frame, int inval)
|
|
{
|
|
sprite_fxp(PIXEL2CS(_x), PIXEL2CS(_y), bank, frame, inval);
|
|
}
|
|
|
|
|
|
void window_t::sprite_fxp(int _x, int _y, int bank, int frame, int inval)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
s_sprite_t *s = engine->get_sprite(bank, frame);
|
|
if(!s || !s->surface)
|
|
return;
|
|
_x = CS2PIXEL(((_x - (s->x << 8)) * xs + 128) >> 8);
|
|
_y = CS2PIXEL(((_y - (s->y << 8)) * ys + 128) >> 8);
|
|
SDL_Rect dest_rect;
|
|
|
|
SELECT
|
|
dest_rect.x = phys_rect.x + _x;
|
|
dest_rect.y = phys_rect.y + _y;
|
|
if(surface)
|
|
SDL_BlitSurface(s->surface, NULL, surface, &dest_rect);
|
|
|
|
if(inval && !engine->autoinvalidate())
|
|
{
|
|
dest_rect.w = s->surface->w;
|
|
dest_rect.h = s->surface->h;
|
|
engine->invalidate(&dest_rect, this);
|
|
}
|
|
}
|
|
|
|
|
|
void window_t::blit(int dx, int dy,
|
|
int sx, int sy, int sw, int sh, window_t *src)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
if(!src)
|
|
return;
|
|
if(!surface)
|
|
return;
|
|
if(!src->surface)
|
|
return;
|
|
SELECT
|
|
|
|
SDL_Rect src_rect;
|
|
int sx2 = ((sx + sw) * xs + 128) >> 8;
|
|
int sy2 = ((sy + sh) * ys + 128) >> 8;
|
|
src_rect.x = (sx * xs + 128) >> 8;
|
|
src_rect.y = (sy * ys + 128) >> 8;
|
|
src_rect.w = sx2 - src_rect.x;
|
|
src_rect.h = sy2 - src_rect.y;
|
|
|
|
SDL_Rect dest_rect;
|
|
dest_rect.x = phys_rect.x + ((dx * xs + 128) >> 8);
|
|
dest_rect.y = phys_rect.y + ((dy * ys + 128) >> 8);
|
|
|
|
SDL_BlitSurface(src->surface, &src_rect, surface, &dest_rect);
|
|
}
|
|
|
|
|
|
void window_t::blit(int dx, int dy, window_t *src)
|
|
{
|
|
if(!engine)
|
|
return;
|
|
if(!src)
|
|
return;
|
|
if(!surface)
|
|
return;
|
|
if(!src->surface)
|
|
return;
|
|
|
|
SELECT
|
|
dx = (dx * xs + 128) >> 8;
|
|
dy = (dy * ys + 128) >> 8;
|
|
|
|
SDL_Rect src_rect;
|
|
src_rect.x = 0;
|
|
src_rect.y = 0;
|
|
src_rect.w = src->surface->w;
|
|
src_rect.h = src->surface->h;
|
|
|
|
SDL_Rect dest_rect;
|
|
dest_rect.x = phys_rect.x + dx;
|
|
dest_rect.y = phys_rect.y + dy;
|
|
|
|
SDL_BlitSurface(src->surface, &src_rect, surface, &dest_rect);
|
|
}
|