SDL port: added drag and drop support, added model switch command, fixed macOS audio

This commit is contained in:
Lior Halphon 2017-05-23 23:18:16 +03:00
parent bef89c6604
commit 00439f4d49
3 changed files with 155 additions and 77 deletions

View File

@ -79,16 +79,16 @@ endif
# Define our targets # Define our targets
ifeq ($(PLATFORM),windows32) ifeq ($(PLATFORM),windows32)
SDL_TARGET := $(BIN)/sdl/sameboy.exe $(BIN)/sdl/sameboy_debugger.exe $(BIN)/sdl/SDL2.dll SDL_TARGET := $(BIN)/SDL/sameboy.exe $(BIN)/SDL/sameboy_debugger.exe $(BIN)/SDL/SDL2.dll
TESTER_TARGET := $(BIN)/tester/sameboy_tester.exe TESTER_TARGET := $(BIN)/tester/sameboy_tester.exe
else else
SDL_TARGET := $(BIN)/sdl/sameboy SDL_TARGET := $(BIN)/SDL/sameboy
TESTER_TARGET := $(BIN)/tester/sameboy_tester TESTER_TARGET := $(BIN)/tester/sameboy_tester
endif endif
cocoa: $(BIN)/SameBoy.app cocoa: $(BIN)/SameBoy.app
quicklook: $(BIN)/SameBoy.qlgenerator quicklook: $(BIN)/SameBoy.qlgenerator
sdl: $(SDL_TARGET) $(BIN)/sdl/dmg_boot.bin $(BIN)/sdl/cgb_boot.bin $(BIN)/sdl/LICENSE $(BIN)/sdl/registers.sym sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/drop.bmp
bootroms: $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin bootroms: $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin
all: cocoa sdl tester all: cocoa sdl tester
@ -209,7 +209,7 @@ $(BIN)/SameBoy.qlgenerator/Contents/Resources/cgb_boot_fast.bin: $(BIN)/BootROMs
# SDL Port # SDL Port
# Unix versions build only one binary # Unix versions build only one binary
$(BIN)/sdl/sameboy: $(CORE_OBJECTS) $(SDL_OBJECTS) $(BIN)/SDL/sameboy: $(CORE_OBJECTS) $(SDL_OBJECTS)
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS)
ifeq ($(CONF), release) ifeq ($(CONF), release)
@ -217,11 +217,11 @@ ifeq ($(CONF), release)
endif endif
# Windows version builds two, one with a conole and one without it # Windows version builds two, one with a conole and one without it
$(BIN)/sdl/sameboy.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o $(BIN)/SDL/sameboy.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) -Wl,/subsystem:windows $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) -Wl,/subsystem:windows
$(BIN)/sdl/sameboy_debugger.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o $(BIN)/SDL/sameboy_debugger.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) -Wl,/subsystem:console $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) -Wl,/subsystem:console
@ -235,7 +235,7 @@ $(OBJ)/%.res: %.rc
# We must provide SDL2.dll with the Windows port. This is an AWFUL HACK to find it. # We must provide SDL2.dll with the Windows port. This is an AWFUL HACK to find it.
SPACE := SPACE :=
SPACE += SPACE +=
$(BIN)/sdl/SDL2.dll: $(BIN)/SDL/SDL2.dll:
@$(eval POTENTIAL_MATCHES := $(subst @@@," ",$(patsubst %,%/SDL2.dll,$(subst ;,$(SPACE),$(subst $(SPACE),@@@,$(lib)))))) @$(eval POTENTIAL_MATCHES := $(subst @@@," ",$(patsubst %,%/SDL2.dll,$(subst ;,$(SPACE),$(subst $(SPACE),@@@,$(lib))))))
@$(eval MATCH := $(shell ls $(POTENTIAL_MATCHES) 2> NUL | head -n 1)) @$(eval MATCH := $(shell ls $(POTENTIAL_MATCHES) 2> NUL | head -n 1))
cp "$(MATCH)" $@ cp "$(MATCH)" $@
@ -253,7 +253,7 @@ $(BIN)/tester/sameboy_tester.exe: $(CORE_OBJECTS) $(SDL_OBJECTS)
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS) -Wl,/subsystem:console $(CC) $^ -o $@ $(LDFLAGS) -Wl,/subsystem:console
$(BIN)/sdl/%.bin $(BIN)/tester/%.bin: $(BOOTROMS_DIR)/%.bin $(BIN)/SDL/%.bin $(BIN)/tester/%.bin: $(BOOTROMS_DIR)/%.bin
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
cp -f $^ $@ cp -f $^ $@
@ -261,10 +261,13 @@ $(BIN)/SameBoy.app/Contents/Resources/%.bin: $(BOOTROMS_DIR)/%.bin
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
cp -f $^ $@ cp -f $^ $@
$(BIN)/sdl/LICENSE: LICENSE $(BIN)/SDL/LICENSE: LICENSE
cp -f $^ $@ cp -f $^ $@
$(BIN)/sdl/registers.sym: Misc/registers.sym $(BIN)/SDL/registers.sym: Misc/registers.sym
cp -f $^ $@
$(BIN)/SDL/drop.bmp: SDL/drop.bmp
cp -f $^ $@ cp -f $^ $@
# Boot ROMs # Boot ROMs

BIN
SDL/drop.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -15,13 +15,10 @@
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
#if defined(__APPLE__) && SDL_MAJOR_VERSION == 2 && SDL_MINOR_VERSION == 0 && SDL_PATCHLEVEL == 5
#error You are using SDL2-2.0.5, which contains a bug that prevents 96KHz audio playback on macOS. Use SDL2-2.0.4 or alternatively modify this file to reduce the frequency to 44100 and disable this error.
#endif
#include "gb.h" #include "gb.h"
static char *filename; static char *filename = NULL;
static bool should_free_filename = false;
static char *battery_save_path_ptr; static char *battery_save_path_ptr;
static void replace_extension(const char *src, size_t length, char *dest, const char *ext); static void replace_extension(const char *src, size_t length, char *dest, const char *ext);
@ -29,6 +26,8 @@ static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL; static SDL_Renderer *renderer = NULL;
static SDL_Texture *texture = NULL; static SDL_Texture *texture = NULL;
static SDL_PixelFormat *pixel_format = NULL; static SDL_PixelFormat *pixel_format = NULL;
static SDL_AudioSpec want_aspec, have_aspec;
static uint32_t pixels[160*144]; static uint32_t pixels[160*144];
GB_gameboy_t gb; GB_gameboy_t gb;
@ -37,6 +36,8 @@ static enum {
GB_SDL_SAVE_STATE_COMMAND, GB_SDL_SAVE_STATE_COMMAND,
GB_SDL_LOAD_STATE_COMMAND, GB_SDL_LOAD_STATE_COMMAND,
GB_SDL_RESET_COMMAND, GB_SDL_RESET_COMMAND,
GB_SDL_NEW_FILE_COMMAND,
GB_SDL_TOGGLE_MODEL_COMMAND,
} pending_command; } pending_command;
static unsigned command_parameter; static unsigned command_parameter;
@ -58,6 +59,16 @@ static void handle_events(GB_gameboy_t *gb)
GB_save_battery(gb, battery_save_path_ptr); GB_save_battery(gb, battery_save_path_ptr);
exit(0); exit(0);
case SDL_DROPFILE: {
if (should_free_filename) {
SDL_free(filename);
}
filename = event.drop.file;
should_free_filename = true;
pending_command = GB_SDL_NEW_FILE_COMMAND;
break;
}
case SDL_KEYDOWN: case SDL_KEYDOWN:
switch (event.key.keysym.sym) { switch (event.key.keysym.sym) {
case SDLK_c: case SDLK_c:
@ -74,10 +85,16 @@ static void handle_events(GB_gameboy_t *gb)
} }
break; break;
case SDLK_t:
if (MODIFIER) {
pending_command = GB_SDL_TOGGLE_MODEL_COMMAND;
}
break;
case SDLK_m: case SDLK_m:
if (MODIFIER) { if (MODIFIER) {
#ifdef __APPLE__ #ifdef __APPLE__
// Can't over CMD+M (Minimize) in SDL // Can't override CMD+M (Minimize) in SDL
if (!shift) { if (!shift) {
break; break;
} }
@ -230,7 +247,12 @@ static void debugger_interrupt(int ignore)
static void audio_callback(void *gb, Uint8 *stream, int len) static void audio_callback(void *gb, Uint8 *stream, int len)
{ {
GB_apu_copy_buffer(gb, (GB_sample_t *) stream, len / sizeof(GB_sample_t)); if (GB_is_inited(gb)) {
GB_apu_copy_buffer(gb, (GB_sample_t *) stream, len / sizeof(GB_sample_t));
}
else {
memset(stream, 0, len);
}
} }
static void replace_extension(const char *src, size_t length, char *dest, const char *ext) static void replace_extension(const char *src, size_t length, char *dest, const char *ext)
@ -251,70 +273,46 @@ static void replace_extension(const char *src, size_t length, char *dest, const
strcat(dest, ext); strcat(dest, ext);
} }
int main(int argc, char **argv) static bool dmg = false;
static void run(void)
{ {
bool dmg = false; restart:
if (GB_is_inited(&gb)) {
#define str(x) #x GB_switch_model_and_reset(&gb, !dmg);
#define xstr(x) str(x)
fprintf(stderr, "SameBoy v" xstr(VERSION) "\n");
if (argc == 1 || argc > 3) {
usage:
fprintf(stderr, "Usage: %s [--dmg] rom\n", argv[0]);
exit(1);
} }
else {
if (argc == 3) { if (dmg) {
if (strcmp(argv[1], "--dmg") == 0) { GB_init(&gb);
dmg = true;
} }
else { else {
goto usage; GB_init_cgb(&gb);
} }
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
GB_set_pixels_output(&gb, pixels);
GB_set_rgb_encode_callback(&gb, rgb_encode);
GB_set_sample_rate(&gb, have_aspec.freq);
} }
if (dmg) { if (dmg) {
GB_init(&gb);
if (GB_load_boot_rom(&gb, executable_relative_path("dmg_boot.bin"))) { if (GB_load_boot_rom(&gb, executable_relative_path("dmg_boot.bin"))) {
perror("Failed to load boot ROM"); perror("Failed to load boot ROM");
exit(1); exit(1);
} }
} }
else { else {
GB_init_cgb(&gb);
if (GB_load_boot_rom(&gb, executable_relative_path("cgb_boot.bin"))) { if (GB_load_boot_rom(&gb, executable_relative_path("cgb_boot.bin"))) {
perror("Failed to load boot ROM"); perror("Failed to load boot ROM");
exit(1); exit(1);
} }
} }
filename = argv[argc - 1];
if (GB_load_rom(&gb, filename)) { if (GB_load_rom(&gb, filename)) {
perror("Failed to load ROM"); perror("Failed to load ROM");
exit(1); exit(1);
} }
signal(SIGINT, debugger_interrupt);
SDL_Init( SDL_INIT_EVERYTHING );
window = SDL_CreateWindow("SameBoy v" xstr(VERSION), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
160, 144, SDL_WINDOW_OPENGL);
renderer = SDL_CreateRenderer(window, -1, 0);
texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, 160, 144);
pixel_format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
/* Configure Screen */
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
GB_set_pixels_output(&gb, pixels);
GB_set_rgb_encode_callback(&gb, rgb_encode);
size_t path_length = strlen(filename); size_t path_length = strlen(filename);
/* Configure battery */ /* Configure battery */
@ -330,21 +328,6 @@ usage:
replace_extension(filename, path_length, symbols_path, ".sym"); replace_extension(filename, path_length, symbols_path, ".sym");
GB_debugger_load_symbol_file(&gb, symbols_path); GB_debugger_load_symbol_file(&gb, symbols_path);
/* Configure Audio */
SDL_AudioSpec want, have;
SDL_memset(&want, 0, sizeof(want));
want.freq = AUDIO_FREQUENCY;
want.format = AUDIO_S16SYS;
want.channels = 2;
want.samples = 512;
want.callback = audio_callback;
want.userdata = &gb;
SDL_OpenAudio(&want, &have);
GB_set_sample_rate(&gb, have.freq);
/* Start Audio */
SDL_PauseAudio(false);
/* Run emulation */ /* Run emulation */
while (true) { while (true) {
GB_run(&gb); GB_run(&gb);
@ -362,7 +345,7 @@ usage:
else { else {
GB_save_state(&gb, save_path); GB_save_state(&gb, save_path);
} }
break; break;
} }
case GB_SDL_RESET_COMMAND: case GB_SDL_RESET_COMMAND:
@ -371,8 +354,100 @@ usage:
case GB_SDL_NO_COMMAND: case GB_SDL_NO_COMMAND:
break; break;
case GB_SDL_NEW_FILE_COMMAND:
pending_command = GB_SDL_NO_COMMAND;
goto restart;
case GB_SDL_TOGGLE_MODEL_COMMAND:
dmg = !dmg;
pending_command = GB_SDL_NO_COMMAND;
goto restart;
} }
pending_command = GB_SDL_NO_COMMAND; pending_command = GB_SDL_NO_COMMAND;
} }
} }
int main(int argc, char **argv)
{
#define str(x) #x
#define xstr(x) str(x)
fprintf(stderr, "SameBoy v" xstr(VERSION) "\n");
if (argc > 3) {
usage:
fprintf(stderr, "Usage: %s [--dmg] [rom]\n", argv[0]);
exit(1);
}
for (unsigned i = 1; i < argc; i++) {
if (strcmp(argv[i], "--dmg") == 0) {
if (dmg) {
goto usage;
}
dmg = true;
}
else if (!filename) {
filename = argv[i];
}
else {
goto usage;
}
}
signal(SIGINT, debugger_interrupt);
SDL_Init( SDL_INIT_EVERYTHING );
window = SDL_CreateWindow("SameBoy v" xstr(VERSION), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
160, 144, SDL_WINDOW_OPENGL);
renderer = SDL_CreateRenderer(window, -1, 0);
texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, 160, 144);
pixel_format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
/* Configure Audio */
memset(&want_aspec, 0, sizeof(want_aspec));
want_aspec.freq = AUDIO_FREQUENCY;
want_aspec.format = AUDIO_S16SYS;
want_aspec.channels = 2;
want_aspec.samples = 2048;
want_aspec.callback = audio_callback;
want_aspec.userdata = &gb;
SDL_OpenAudio(&want_aspec, &have_aspec);
/* Start Audio */
SDL_PauseAudio(false);
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
if (filename == NULL) {
/* Draw the "Drop file" screen */
SDL_Surface *drop_backround = SDL_LoadBMP(executable_relative_path("drop.bmp"));
SDL_Surface *drop_converted = SDL_ConvertSurface(drop_backround, pixel_format, 0);
SDL_LockSurface(drop_converted);
SDL_UpdateTexture(texture, NULL, drop_converted->pixels, drop_converted->pitch);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_FreeSurface(drop_converted);
SDL_FreeSurface(drop_backround)
;
SDL_Event event;
while (SDL_WaitEvent(&event))
{
if (event.type == SDL_QUIT) {
exit(0);
}
else if (event.type == SDL_DROPFILE) {
filename = event.drop.file;
should_free_filename = true;
break;
}
}
}
run(); // Never returns
return 0;
}