An emulator, assembler, and disassembler for the Sega Game Gear
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

157 lines
3.9 KiB

  1. /* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <signal.h>
  4. #include <stdint.h>
  5. #include <SDL.h>
  6. #include "emulator.h"
  7. #include "gamegear.h"
  8. #include "logging.h"
  9. #include "util.h"
  10. typedef struct {
  11. GameGear *gg;
  12. SDL_Window *window;
  13. SDL_Renderer *renderer;
  14. SDL_Texture *texture;
  15. uint32_t *pixels;
  16. } Emulator;
  17. static Emulator emu;
  18. /*
  19. Signal handler for SIGINT. Tells the GameGear to power off, if it exists.
  20. */
  21. static void handle_sigint(int sig)
  22. {
  23. (void) sig;
  24. if (emu.gg)
  25. gamegear_power_off(emu.gg); // Safe!
  26. }
  27. /*
  28. Set up SDL for drawing the game.
  29. */
  30. static void setup_graphics(bool fullscreen, unsigned scale)
  31. {
  32. if (SDL_Init(SDL_INIT_VIDEO) < 0)
  33. FATAL("SDL failed to initialize: %s", SDL_GetError());
  34. uint32_t flags;
  35. if (fullscreen)
  36. flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
  37. else
  38. flags = SDL_WINDOW_BORDERLESS|SDL_WINDOW_RESIZABLE;
  39. SDL_CreateWindowAndRenderer(
  40. scale * GG_SCREEN_WIDTH, scale * GG_SCREEN_HEIGHT,
  41. flags, &emu.window, &emu.renderer);
  42. if (!emu.window)
  43. FATAL("SDL failed to create a window: %s", SDL_GetError());
  44. if (!emu.renderer)
  45. FATAL("SDL failed to create a renderer: %s", SDL_GetError());
  46. emu.texture = SDL_CreateTexture(emu.renderer, SDL_PIXELFORMAT_ARGB8888,
  47. SDL_TEXTUREACCESS_STREAMING, GG_SCREEN_WIDTH, GG_SCREEN_HEIGHT);
  48. if (!emu.texture)
  49. FATAL("SDL failed to create a texture: %s", SDL_GetError());
  50. emu.pixels = cr_malloc(
  51. sizeof(uint32_t) * GG_SCREEN_WIDTH * GG_SCREEN_HEIGHT);
  52. SDL_RenderSetLogicalSize(emu.renderer, GG_SCREEN_WIDTH, GG_SCREEN_HEIGHT);
  53. SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
  54. SDL_SetWindowTitle(emu.window, "crater");
  55. SDL_ShowCursor(SDL_DISABLE);
  56. SDL_SetRenderDrawColor(emu.renderer, 0x00, 0x00, 0x00, 0xFF);
  57. SDL_RenderClear(emu.renderer);
  58. SDL_RenderPresent(emu.renderer);
  59. }
  60. /*
  61. Actually send the pixel data to the screen.
  62. */
  63. static void draw_frame()
  64. {
  65. SDL_UpdateTexture(emu.texture, NULL, emu.pixels,
  66. GG_SCREEN_WIDTH * sizeof(uint32_t));
  67. SDL_SetRenderDrawColor(emu.renderer, 0x00, 0x00, 0x00, 0xFF);
  68. SDL_RenderClear(emu.renderer);
  69. SDL_RenderCopy(emu.renderer, emu.texture, NULL, NULL);
  70. SDL_RenderPresent(emu.renderer);
  71. }
  72. /*
  73. Handle SDL events, mainly quit events and button presses.
  74. */
  75. static void handle_events(GameGear *gg)
  76. {
  77. SDL_Event e;
  78. while (SDL_PollEvent(&e)) {
  79. if (e.type == SDL_QUIT) {
  80. gamegear_power_off(gg);
  81. return;
  82. }
  83. // TODO: buttons
  84. }
  85. }
  86. /*
  87. GameGear callback: Draw the current frame and handle SDL event logic.
  88. */
  89. static void frame_callback(GameGear *gg)
  90. {
  91. draw_frame();
  92. handle_events(gg);
  93. }
  94. /*
  95. Clean up SDL stuff allocated in setup_graphics().
  96. */
  97. static void cleanup_graphics()
  98. {
  99. free(emu.pixels);
  100. SDL_DestroyTexture(emu.texture);
  101. SDL_DestroyRenderer(emu.renderer);
  102. SDL_DestroyWindow(emu.window);
  103. SDL_Quit();
  104. emu.window = NULL;
  105. emu.renderer = NULL;
  106. emu.texture = NULL;
  107. }
  108. /*
  109. Emulate a ROM in a Game Gear while handling I/O with the host computer.
  110. Block until emulation is finished.
  111. */
  112. void emulate(ROM *rom, bool fullscreen, unsigned scale)
  113. {
  114. emu.gg = gamegear_create();
  115. signal(SIGINT, handle_sigint);
  116. setup_graphics(fullscreen, scale);
  117. gamegear_attach_callback(emu.gg, frame_callback);
  118. gamegear_attach_display(emu.gg, emu.pixels);
  119. gamegear_load(emu.gg, rom);
  120. gamegear_simulate(emu.gg);
  121. if (gamegear_get_exception(emu.gg))
  122. ERROR("caught exception: %s", gamegear_get_exception(emu.gg))
  123. else
  124. WARN("caught signal, stopping...")
  125. if (DEBUG_LEVEL)
  126. gamegear_print_state(emu.gg);
  127. cleanup_graphics();
  128. signal(SIGINT, SIG_DFL);
  129. gamegear_destroy(emu.gg);
  130. emu.gg = NULL;
  131. }