Scanline screen effect

It can be activated by the -scanline command line flag, system3.ini, or
the menubar on Windows. Effective especially for games with 200-line
screen mode, such as Little Vampire and Intruder.
This commit is contained in:
kichikuou
2023-04-09 18:23:42 +09:00
parent ec1dfbffcf
commit 7f6a085f56
7 changed files with 73 additions and 2 deletions
+4
View File
@@ -104,6 +104,8 @@ Config::Config(int argc, char *argv[])
title = argv[++i];
else if (strcmp(argv[i], "-timiditycfg") == 0)
timidity_cfg = argv[++i];
else if (strcmp(argv[i], "-scanline") == 0)
scanline = true;
}
}
@@ -158,6 +160,8 @@ void Config::load_ini()
title = val;
else if (!strcasecmp(key, "timiditycfg"))
timidity_cfg = normalize_path(val);
else if (!strcasecmp(key, "scanline"))
scanline = to_bool(val, lineno);
else
WARNING(INIFILENAME ":%d unknown key '%s'", lineno, key);
} else if (current_section == STRING) {
+1
View File
@@ -31,6 +31,7 @@ struct Config {
std::string timidity_cfg;
bool use_fm = false;
bool no_antialias = false;
bool scanline = false;
private:
void load_ini();
+49
View File
@@ -36,6 +36,28 @@ static SDL_Surface* display_surface;
box[n].ey = y2; \
}
namespace {
const uint32 SCANLINE_ALPHA = 0x38; // 0-255
SDL_Texture* create_scanline_texture(SDL_Renderer* renderer, int width, int height)
{
SDL_Surface* sf = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ARGB8888);
for (int y = 0; y < height; y++) {
uint32* p = surface_line(sf, y);
uint32 v = y % 2 ? (SCANLINE_ALPHA << 24) : 0;
for (int x = 0; x < width; x++) {
p[x] = v;
}
}
SDL_Texture* tx = SDL_CreateTextureFromSurface(renderer, sf);
SDL_SetTextureBlendMode(tx, SDL_BLENDMODE_BLEND);
SDL_FreeSurface(sf);
return tx;
}
} // namespace
AGS::AGS(NACT* parent, const Config& config) : nact(parent), dirty(false)
{
// 画面サイズ
@@ -52,6 +74,7 @@ AGS::AGS(NACT* parent, const Config& config) : nact(parent), dirty(false)
SDL_SetWindowSize(g_window, window_width, window_height);
SDL_RenderSetLogicalSize(g_renderer, window_width, window_height);
sdlTexture = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, screen_width, screen_height); // TOOD: pixelformat?
scanline_texture = NULL;
// DIBSection 8bpp * 3 (表, 裏, メニュー)
for(int i = 0; i < 3; i++) {
@@ -358,6 +381,8 @@ AGS::AGS(NACT* parent, const Config& config) : nact(parent), dirty(false)
// マウスカーソル
cursor_color = 15;
cursor_index = 0;
set_scanline_mode(config.scanline);
}
AGS::~AGS()
@@ -527,10 +552,26 @@ void AGS::update_screen()
SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 255);
SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_NONE);
}
if (scanline_texture)
SDL_RenderCopy(g_renderer, scanline_texture, NULL, NULL);
SDL_RenderPresent(g_renderer);
dirty = false;
}
void AGS::set_scanline_mode(bool enable)
{
if (enable && !scanline_texture) {
scanline_texture = create_scanline_texture(g_renderer, screen_width, screen_height);
dirty = true;
update_screen();
} else if (!enable && scanline_texture) {
SDL_DestroyTexture(scanline_texture);
scanline_texture = NULL;
dirty = true;
update_screen();
}
}
void AGS::save_screenshot(const char* path)
{
SDL_Surface* sf = SDL_CreateRGBSurface(0, screen_width, screen_height, 32, 0, 0, 0, 0);
@@ -539,6 +580,14 @@ void AGS::save_screenshot(const char* path)
SDL_BlitSurface(hBmpDest, &r, sf, NULL);
SDL_LockSurface(hBmpDest);
if (scanline_texture) {
SDL_Renderer* renderer = SDL_CreateSoftwareRenderer(sf);
SDL_Texture *tx = create_scanline_texture(renderer, screen_width, screen_height);
SDL_RenderCopy(renderer, tx, NULL, NULL);
SDL_DestroyTexture(tx);
SDL_DestroyRenderer(renderer);
}
if (SDL_SaveBMP(sf, path) != 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "system3",
SDL_GetError(), g_window);
+3
View File
@@ -40,6 +40,7 @@ protected:
NACT* nact;
private:
SDL_Texture* sdlTexture;
SDL_Texture* scanline_texture;
// Surface
SDL_Surface* hBmpScreen[3]; // 8bpp * 3 (表, 裏, メニュー)
@@ -128,6 +129,8 @@ public:
void select_cursor();
void translate_mouse_coords(int* x, int* y);
bool get_scanline_mode() const { return scanline_texture; }
void set_scanline_mode(bool enable);
void save_screenshot(const char* path);
int calculate_menu_max(int window);
+9 -2
View File
@@ -21,13 +21,15 @@ HWND get_hwnd(SDL_Window* window) {
return info.info.win.window;
}
void init_menu(bool mouse_move_enabled)
void init_menu(bool mouse_move_enabled, bool scanline_enabled)
{
HINSTANCE hinst = (HINSTANCE)GetModuleHandle(NULL);
HMENU hmenu = LoadMenu(hinst, MAKEINTRESOURCE(IDR_MENU1));
SetMenu(get_hwnd(g_window), hmenu);
if (mouse_move_enabled)
CheckMenuItem(hmenu, ID_OPTION_MOUSE_MOVE, MF_BYCOMMAND | MFS_CHECKED);
if (scanline_enabled)
CheckMenuItem(hmenu, ID_SCANLINE, MF_BYCOMMAND | MFS_CHECKED);
}
void init_console(int sys_ver)
@@ -129,7 +131,7 @@ void NACT::text_dialog()
void NACT::platform_initialize()
{
init_menu(mouse_move_enabled);
init_menu(mouse_move_enabled, config.scanline);
init_console(sys_ver);
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
}
@@ -188,6 +190,11 @@ bool NACT::handle_platform_event(const SDL_Event& e)
SDL_SetWindowFullscreen(g_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
ags->flush_screen(true);
break;
case ID_SCANLINE:
ags->set_scanline_mode(!ags->get_scanline_mode());
CheckMenuItem(GetMenu(get_hwnd(g_window)), ID_SCANLINE, MF_BYCOMMAND |
ags->get_scanline_mode() ? MFS_CHECKED : MFS_UNCHECKED);
break;
case ID_OPTION_MOUSE_MOVE:
mouse_move_enabled = !mouse_move_enabled;
CheckMenuItem(GetMenu(get_hwnd(g_window)), ID_OPTION_MOUSE_MOVE,
+1
View File
@@ -24,6 +24,7 @@
#define ID_EXIT 40002
#define ID_SCREEN_WINDOW 40010
#define ID_SCREEN_FULL 40011
#define ID_SCANLINE 40012
#define ID_OPTION_MOUSE_MOVE 40020
#define ID_OPTION_FM 40021
#define ID_OPTION_MIDI 40022
+6
View File
@@ -97,6 +97,8 @@ BEGIN
BEGIN
MENUITEM "Window", ID_SCREEN_WINDOW
MENUITEM "Fullscreen", ID_SCREEN_FULL
MENUITEM SEPARATOR
MENUITEM "Scanline effect", ID_SCANLINE
END
POPUP "Option"
BEGIN
@@ -153,6 +155,8 @@ BEGIN
BEGIN
MENUITEM "ウィンドウ", ID_SCREEN_WINDOW
MENUITEM "フルスクリーン", ID_SCREEN_FULL
MENUITEM SEPARATOR
MENUITEM "走査線エフェクト", ID_SCANLINE
END
POPUP "オプション"
BEGIN
@@ -209,6 +213,8 @@ BEGIN
BEGIN
MENUITEM "窗口化", ID_SCREEN_WINDOW
MENUITEM "全屏化", ID_SCREEN_FULL
MENUITEM SEPARATOR
MENUITEM "Scanline effect", ID_SCANLINE
END
POPUP "选项"
BEGIN