@@ -62,9 +62,16 @@ entirely with `--no-save`. | |||
Add `--debug` (`-g`) to show logging information while running. Pass it twice | |||
(`-gg`) to show more detailed logs, including an emulator trace. | |||
crater tries to reproduce the Game Gear's native display resolution, which had | |||
a pixel aspect ratio (PAR) of [8:7][par]; this means the pixels were slightly | |||
wider than square, unlike modern LCD displays with a 1:1 PAR. Add `--square` | |||
(`-q`) to force square pixels. | |||
`./crater -h` gives (fairly basic) command-line usage, and `./crater -v` gives | |||
the current version. | |||
[par]: https://pineight.com/mw/index.php?title=Dot_clock_rates | |||
### Input | |||
crater supports keyboard and joystick/controller input. | |||
@@ -44,6 +44,8 @@ static void print_help(const char *arg1) | |||
" the Game Gear does not usually require BIOS)\n" | |||
" -x, --scale <n> scale the game screen by an integer factor\n" | |||
" (applies to windowed mode only; defaults to 4)\n" | |||
" -q, --square force a square pixel aspect ratio instead of the more\n" | |||
" faithful 8:7 PAR\n" | |||
" -a, --assemble <in> [<out>]\n" | |||
" convert z80 assembly source code into a binary file that\n" | |||
" can be run by crater\n" | |||
@@ -269,6 +271,9 @@ static int parse_opt_arg(Config *config, Arguments *args, const char *arg) | |||
} | |||
config->scale = scale; | |||
} | |||
else if (arg_check(arg, "q", "square")) { | |||
config->square_par = true; | |||
} | |||
else if (arg_check(arg, "a", "assemble")) { | |||
if (args->paths_read >= 1) { | |||
config->src_path = config->rom_path; | |||
@@ -367,7 +372,8 @@ static bool sanity_check(Config *config) | |||
} else if (config->assemble && config->disassemble) { | |||
ERROR("cannot assemble and disassemble at the same time") | |||
return false; | |||
} else if (assembler && (config->fullscreen || config->scale)) { | |||
} else if (assembler && (config->fullscreen || config->scale || | |||
config->square_par)) { | |||
ERROR("cannot specify emulator options in assembler mode") | |||
return false; | |||
} else if (assembler && !config->src_path) { | |||
@@ -424,6 +430,7 @@ int config_create(Config** config_ptr, int argc, char* argv[]) | |||
config->fullscreen = false; | |||
config->no_saving = false; | |||
config->scale = 0; | |||
config->square_par = false; | |||
config->rom_path = NULL; | |||
config->sav_path = NULL; | |||
config->bios_path = NULL; | |||
@@ -469,6 +476,7 @@ void config_dump_args(const Config* config) | |||
DEBUG("- fullscreen: %s", config->fullscreen ? "true" : "false") | |||
DEBUG("- no_saving: %s", config->no_saving ? "true" : "false") | |||
DEBUG("- scale: %d", config->scale) | |||
DEBUG("- square_par: %s", config->square_par ? "true" : "false") | |||
DEBUG("- rom_path: %s", config->rom_path ? config->rom_path : "(null)") | |||
DEBUG("- sav_path: %s", config->sav_path ? config->sav_path : "(null)") | |||
DEBUG("- bios_path: %s", config->bios_path ? config->bios_path : "(null)") | |||
@@ -14,10 +14,9 @@ | |||
/* | |||
We need some sort of maximum scale - with a native resolution of 160 x 144, | |||
a scale factor of 1024 will let us go up to 163,840 x 147,456 pixels. | |||
No one has a screen this large. | |||
a scale factor of 128 will let us go up to 20,480 x 18,432 pixels. | |||
*/ | |||
#define SCALE_MAX 1024 | |||
#define SCALE_MAX 128 | |||
/* Structs */ | |||
@@ -28,6 +27,7 @@ typedef struct { | |||
bool fullscreen; | |||
bool no_saving; | |||
unsigned scale; | |||
bool square_par; | |||
char *rom_path; | |||
char *sav_path; | |||
char *bios_path; | |||
@@ -88,19 +88,22 @@ static void setup_input() | |||
/* | |||
Set up SDL for drawing the game. | |||
*/ | |||
static void setup_graphics(bool fullscreen, unsigned scale) | |||
static void setup_graphics(Config *config) | |||
{ | |||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); | |||
uint32_t flags; | |||
if (fullscreen) | |||
if (config->fullscreen) | |||
flags = SDL_WINDOW_FULLSCREEN_DESKTOP; | |||
else | |||
flags = SDL_WINDOW_RESIZABLE; | |||
SDL_CreateWindowAndRenderer( | |||
scale * GG_SCREEN_WIDTH, scale * GG_SCREEN_HEIGHT, | |||
flags, &emu.window, &emu.renderer); | |||
int width = config->scale * GG_SCREEN_WIDTH; | |||
int height = config->scale * GG_SCREEN_HEIGHT; | |||
if (!config->square_par) | |||
height = height * GG_PIXEL_HEIGHT / GG_PIXEL_WIDTH; | |||
SDL_CreateWindowAndRenderer(width, height, flags, | |||
&emu.window, &emu.renderer); | |||
if (!emu.window) | |||
FATAL("SDL failed to create a window: %s", SDL_GetError()); | |||
@@ -116,7 +119,9 @@ static void setup_graphics(bool fullscreen, unsigned scale) | |||
emu.pixels = cr_malloc( | |||
sizeof(uint32_t) * GG_SCREEN_WIDTH * GG_SCREEN_HEIGHT); | |||
SDL_RenderSetLogicalSize(emu.renderer, GG_SCREEN_WIDTH, GG_SCREEN_HEIGHT); | |||
SDL_RenderSetLogicalSize(emu.renderer, | |||
config->square_par ? GG_SCREEN_WIDTH : GG_LOGICAL_WIDTH, | |||
config->square_par ? GG_SCREEN_HEIGHT : GG_LOGICAL_HEIGHT); | |||
SDL_SetTextureBlendMode(emu.texture, SDL_BLENDMODE_BLEND); | |||
SDL_SetWindowTitle(emu.window, "crater"); | |||
SDL_ShowCursor(SDL_DISABLE); | |||
@@ -130,13 +135,13 @@ static void setup_graphics(bool fullscreen, unsigned scale) | |||
/* | |||
Set up SDL. | |||
*/ | |||
static void setup_sdl(bool fullscreen, unsigned scale) | |||
static void setup_sdl(Config *config) | |||
{ | |||
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_GAMECONTROLLER) < 0) | |||
FATAL("SDL failed to initialize: %s", SDL_GetError()); | |||
setup_input(); | |||
setup_graphics(fullscreen, scale); | |||
setup_graphics(config); | |||
} | |||
/* | |||
@@ -370,7 +375,7 @@ void emulate(ROM *rom, Config *config) | |||
emu.gg = gamegear_create(); | |||
signal(SIGINT, handle_sigint); | |||
setup_sdl(config->fullscreen, config->scale); | |||
setup_sdl(config); | |||
gamegear_attach_callback(emu.gg, frame_callback); | |||
gamegear_attach_display(emu.gg, emu.pixels); | |||
@@ -15,6 +15,10 @@ | |||
#define GG_SCREEN_WIDTH 160 | |||
#define GG_SCREEN_HEIGHT 144 | |||
#define GG_PIXEL_WIDTH 8 | |||
#define GG_PIXEL_HEIGHT 7 | |||
#define GG_LOGICAL_WIDTH (GG_SCREEN_WIDTH * GG_PIXEL_WIDTH) | |||
#define GG_LOGICAL_HEIGHT (GG_SCREEN_HEIGHT * GG_PIXEL_HEIGHT) | |||
#define GG_FPS 60 | |||
#define GG_EXC_BUFF_SIZE 128 | |||