add simple advmame2x cpu scaling

This commit is contained in:
Tim Felgentreff 2020-04-19 08:26:31 +02:00
parent 8ad0f536d6
commit 96f0360d29
4 changed files with 115 additions and 46 deletions
src

View file

@ -209,11 +209,13 @@ struct EventCallback {
#define AMASK 0x000000ff
#endif
extern void* NullScaler(SDL_Surface *pixels);
extern void* Epx_Scale2x_AdvMame2x_Scaler(SDL_Surface *pixels);
class CVideo
{
public:
CVideo() : Width(0), Height(0), WindowWidth(0), WindowHeight(0), Depth(0), FullScreen(false) {}
CVideo() : Width(0), Height(0), WindowWidth(0), WindowHeight(0), Depth(0), Scale(1), Scaler(NullScaler), FullScreen(false) {}
void LockScreen();
void UnlockScreen();
@ -290,6 +292,8 @@ public:
int WindowHeight;
SDL_Cursor *blankCursor;
int Depth;
int Scale;
void* (*Scaler)(SDL_Surface* pixels);
bool FullScreen;
};

View file

@ -451,7 +451,9 @@ static void Usage()
"\t-S speed\tSync speed (100 = 30 frames/s)\n"
"\t-u userpath\tPath where stratagus saves preferences, log and savegame\n"
"\t-v mode\t\tVideo mode resolution in format <xres>x<yres>\n"
"\t-W\t\tWindowed video mode\n"
"\t-W\t\tWindowed video mode. Optionally takes a window size in <xres>x<yres>\n"
"\t-x\tPostprocessing. Currently available\n"
"\t\tscale2x - Double thei nternal pixel the output using the AdvMAME2x scaler.\n"
"map is relative to StratagusLibPath=datapath, use ./map for relative to cwd\n",
Parameters::Instance.applicationName.c_str());
}
@ -498,7 +500,7 @@ void ParseCommandLine(int argc, char **argv, Parameters &parameters)
{
char *sep;
for (;;) {
switch (getopt(argc, argv, "ac:d:D:eE:FG:hiI:lN:oOP:ps:S:u:v:Wx:Z:?-")) {
switch (getopt(argc, argv, "ac:d:D:eE:FG:hiI:lN:oOP:ps:S:u:v:Wx:?-")) {
case 'a':
EnableAssert = true;
continue;
@ -600,6 +602,12 @@ void ParseCommandLine(int argc, char **argv, Parameters &parameters)
VideoForceFullScreen = 1;
Video.FullScreen = 0;
continue;
case 'x':
if (!strcmp(optarg, "scale2x")) {
Video.Scale = 2;
Video.Scaler = Epx_Scale2x_AdvMame2x_Scaler;
}
continue;
case -1:
break;
case '?':

View file

@ -344,18 +344,8 @@ void InitVideoSdl()
exit(1);
}
if (!TheRenderer) TheRenderer = SDL_CreateRenderer(TheWindow, -1, 0);
SDL_RenderSetLogicalSize(TheRenderer, Video.Width, Video.Height);
SDL_SetRenderDrawColor(TheRenderer, 0, 0, 0, 255);
TheScreen = SDL_CreateRGBSurface(0, Video.Width, Video.Height, 32,
0x00FF0000,
0x0000FF00,
0x000000FF,
0); //0xFF000000);
Assert(SDL_MUSTLOCK(TheScreen) == 0);
TheTexture = SDL_CreateTexture(TheRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
Video.Width, Video.Height);
Video.ResizeScreen(Video.Width, Video.Height);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
#if ! defined(USE_WIN32) && ! defined(USE_MAEMO)
@ -667,7 +657,7 @@ void RealizeVideoMemory()
{
if (NumRects) {
//SDL_UpdateWindowSurfaceRects(TheWindow, Rects, NumRects);
SDL_UpdateTexture(TheTexture, NULL, TheScreen->pixels, TheScreen->pitch);
SDL_UpdateTexture(TheTexture, NULL, Video.Scaler(TheScreen), TheScreen->pitch * Video.Scale);
SDL_RenderClear(TheRenderer);
//for (int i = 0; i < NumRects; i++)
// SDL_UpdateTexture(TheTexture, &Rects[i], TheScreen->pixels, TheScreen->pitch);

View file

@ -266,38 +266,44 @@ void CVideo::ClearScreen()
*/
bool CVideo::ResizeScreen(int w, int h)
{
if (VideoValidResolution(w, h)) {
Width = w;
Height = h;
if (!(SDL_GetWindowFlags(TheWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP)) {
SDL_SetWindowSize(TheWindow, w, h);
}
SDL_RenderSetLogicalSize(TheRenderer, w, h);
// new surface
Uint32 flags = TheScreen->flags;
Uint32 rmask = TheScreen->format->Rmask;
Uint32 gmask = TheScreen->format->Gmask;
Uint32 bmask = TheScreen->format->Bmask;
Uint32 amask = TheScreen->format->Amask;
Uint8 bpp = TheScreen->format->BitsPerPixel;
SDL_FreeSurface(TheScreen);
TheScreen = SDL_CreateRGBSurface(flags, w, h, bpp, rmask, gmask, bmask, amask);
Assert(SDL_MUSTLOCK(TheScreen) == 0);
// new texture
Uint32 format;
int access, oldW, oldH;
SDL_QueryTexture(TheTexture, &format, &access, &oldW, &oldH);
SDL_DestroyTexture(TheTexture);
TheTexture = SDL_CreateTexture(TheRenderer, format, access, w, h);
SetClipping(0, 0, w - 1, h - 1);
return true;
if (!(SDL_GetWindowFlags(TheWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP)
&& Video.Width == Video.WindowWidth
&& Video.Height == Video.WindowHeight) {
// if initially window was the same size as res, keep it that way
SDL_SetWindowSize(TheWindow, w, h);
}
return false;
Width = w;
Height = h;
SDL_RenderSetLogicalSize(TheRenderer, w, h);
// new surface
if (TheScreen) {
if (TheScreen->userdata) {
free(TheScreen->userdata);
}
SDL_FreeSurface(TheScreen);
}
TheScreen = SDL_CreateRGBSurface(0, w, h, 32,
0x00ff0000,
0x0000ff00,
0x000000ff,
0); // 0xff000000);
Assert(SDL_MUSTLOCK(TheScreen) == 0);
TheScreen->userdata = calloc(w * Video.Scale * h * Video.Scale, sizeof(Uint32));
// new texture
if (TheTexture) {
SDL_DestroyTexture(TheTexture);
}
TheTexture = SDL_CreateTexture(TheRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
w * Video.Scale, h * Video.Scale);
SetClipping(0, 0, w - 1, h - 1);
return true;
}
/**
@ -475,4 +481,65 @@ void RestoreColorCyclingSurface()
#endif
void* NullScaler(SDL_Surface *s) {
return s->pixels;
}
void* Epx_Scale2x_AdvMame2x_Scaler(SDL_Surface *s) {
Assert(Video.Scale == 2);
Assert(s->format->BitsPerPixel == 32);
Assert(Video.Height * Video.Width == s->h * 2 * s->w * 2);
Uint32 *in = (Uint32*) s->pixels;
Uint32 *out = (Uint32*) s->userdata;
int inputW = s->w;
int outputW = s->w * 2;
// Just the algo from wikipedia.
//
// Input +-----+-----+-----+
// | | A | |
// +-----+-----+-----+
// | C | P | B |
// +-----+-----+-----+
// | | D | |
// +-----+-----+-----+
// ||
// Output +-----+-----+
// for P | o1 | o2 |
// +-----+-----+
// | o3 | o4 |
// +-----+-----+
Uint32 a, b, c, d, p, o1, o2, o3, o4;
for (int y = 1, y2 = 1; y < Video.Height - 1; y++, y2 += 2) {
for (int x = 1, x2 = 1; x < Video.Width - 1; x++, x2 += 2) {
o1 = o2 = o3 = o4 = p = in[x + y * inputW];
a = in[x + (y - 1) * inputW];
b = in[x + 1 + y * inputW];
c = in[x - 1 + y * inputW];
d = in[x + (y + 1) * inputW];
if ((c == a) && (c != d) && (a != b)) {
o1 = a;
}
if ((a == b) && (a != c) && (b != d)) {
o2 = b;
}
if ((d == c) && (d != b) && (c != a)) {
o3 = c;
}
if ((b == d) && (b != a) && (d != c)) {
o4 = d;
}
out[x2 + y2 * outputW] = o1;
out[x2 + 1 + y2 * outputW] = o2;
out[x2 + (y2 + 1) * outputW] = o3;
out[x2 + 1 + (y2 + 1) * outputW] = o4;
}
}
return out;
}
//@}