Remove circular dependencies between libs, use callback function pointers instead
[mercenary-reloaded.git] / src / mercenary / main.c
index c0d5150..4dce2fb 100644 (file)
@@ -250,143 +250,121 @@ static void main_loop(void)
        }
 }
 
-int main(int argc, char *argv[])
+static uint16_t io_read(uint32_t address)
 {
-       int rc;
-       int sdl_sound_chunk;
-
-       home_dir = getenv("HOME");
-       if (!home_dir)
-               home_dir = "";
-
-       rc = parse_args(argc, argv);
-       if (rc)
-               return 0;
+       uint16_t value = 0xffff;
 
-       /* allocate image */
-       image = calloc(IMAGE_WIDTH * IMAGE_HEIGHT * ((double_size) ? 4 : 1), 3);
-       if (!image) {
-               fprintf(stderr, "Failed to allocate image buffer\n");
-               goto done;
-       }
+       /* joystick and fire button */
+       if (address == 0xbfe000 || address == 0xdff00c)
+               value &= emulate_joystick_read(address);
+       /* keyboard */
+       if (address == 0xbfec00 || address == 0xbfed00 || address == 0xbfee00)
+               value &= emulate_keyboard_read(address);
+       /* diskette */
+       if (address == 0xbfd100 || address == 0xbfe000 || address == 0xdff01a || address == 0xdff01e)
+               value &= emulate_disk_read(address);
 
-       if ((SOUND_SAMPLERATE % IRQ_RATE)) {
-               fprintf(stderr, "Sample rate must be a multiple of IRQ rate, please fix!\n");
-               goto done;
-       }
-       if ((1000 % IRQ_RATE)) {
-               fprintf(stderr, "1000 (Ticks per second) rate must be a multiple of IRQ rate, please fix!\n");
-               goto done;
-       }
+       return value;
+}
 
-       /* calculate SDL chunk size for audio
-        * it must be a power of two, but not more than the chunk size for each IRQ!
-        */
-       for (sdl_sound_chunk = 2; sdl_sound_chunk <= (SOUND_SAMPLERATE / IRQ_RATE); sdl_sound_chunk <<= 1)
-               ;
-       sdl_sound_chunk >>= 1;
-//     printf("samples per IRQ = %d, samples per SDL audio = %d\n", SOUND_SAMPLERATE / IRQ_RATE, sdl_sound_chunk); exit(0);
+static void io_write(uint32_t address, uint16_t value)
+{
+       /* dmacon and sound registers */
+       if (address == 0xdff096 || (address >= 0xdff0a0 && address <= 0xdff0df))
+               emulate_sound_write(address, value, SOUND_SAMPLERATE);
+       if (address == 0xbfd100 || (address >= 0xdff020 && address <= 0xdff024))
+               emulate_disk_write(address, value);
+}
 
-       /* allocate sound buffers */
-       sound_buffer_size = SOUND_SAMPLERATE / IRQ_RATE * SOUND_CHUNKS;
-       sound_buffer = calloc(sound_buffer_size, sizeof(*sound_buffer));
-       if (!sound_buffer) {
-               fprintf(stderr, "Failed to allocate image buffer\n");
-               goto done;
-       }
+/* two tracks with 0x1820 words of length */
+static uint8_t game_save[2][0x1820 << 1];
+static int last_track = 0;
 
-       /* allocate memory */
-       memory = calloc(MEMORY_SIZE, 1);
-       if (!memory) {
-               fprintf(stderr, "Failed to allocate cpu's memory\n");
-               goto done;
-       }
-       chipreg = calloc(IOSIZE, 1);
-       if (!chipreg) {
-               fprintf(stderr, "Failed to allocate chip register\n");
-               goto done;
+/* game reads track with saved game */
+static void disk_read(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
+{
+       if (length > sizeof(game_save[0])) {
+               fprintf(stderr, "loading game state failed, because length exceeds game save data size, please fix!\n");
+               return;
        }
 
-       /* init cpu code */
-       execute_init(MEMORY_SIZE, memory, chipreg);
-
-       /* load binary */
-       mercenary_load();
-
-       /* patch some stuff */
-       mercenary_patch();
-
-       /* init SDL and OpenGL */
-       rc = init_sdl(argv[0], SCREEN_WIDTH, SCREEN_HEIGHT, SOUND_SAMPLERATE, sdl_sound_chunk);
-       if (rc < 0)
-               goto done;
-       rc = init_opengl((double_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
-       if (rc < 0)
-               goto done;
-       resize_opengl(SCREEN_WIDTH, SCREEN_HEIGHT);
-
-       /* init audio filter */
-       sound_init_filter(SOUND_SAMPLERATE);
+       /* if even track is selected, load game */
+       if (!(track & 1)) {
+               char filename[256];
+               int gamesave_num = (track - 2) >> 1;
+               int got;
+               FILE *fp;
 
-       /* start cpu */
-       reset_cpu();
+               memset(game_save, 0, sizeof(game_save)); /* clear so make the game fail, if we fail */
+               sprintf(filename, "%s/%s/%d.gamesave", home_dir, config_gamesave_dir, gamesave_num);
+               fp = fopen(filename, "r");
+               if (!fp) {
+fail:
+                       fprintf(stderr, "failed to load game from '%s'\n", filename);
+                       goto copy;
+               }
+               got = fread(game_save, sizeof(game_save[0]), 2, fp);
+               fclose(fp);
+               if (got != 2)
+                       goto fail;
+       }
 
-       printf("**********************************\n");
-       printf("* Welcome to Mercenary Reloaded! *\n");
-       printf("**********************************\n\n");
-       printf("Press CTRL + cursor keys to select inventory or pickup/drop item.\n");
-       printf("Press CTRL + f to toggle full screen.\n");
-       printf("Press CTRL + s to toggle rendering speed.\n");
-       printf("Press CTRL + v to toggle video filter.\n");
-       printf("Press CTRL + a to toggle audio filter.\n");
-       printf("Press CTRL + c to exit game.\n\n");
-       printf("Use '--help' as command line option for configuration settings.\n\n");
+copy:
+       /* copy track */
+       memcpy(memory + data, game_save[track & 1], length /* sizeof(game_save[0])*/);
+}
 
-       /* run game */
-       main_loop();
+/* game writes track with saved game */
+static void disk_write(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
+{
+       /* skip sync info that is provided by game and only relevant for a real disk track */
+       data += 0x200;
+       length -= 0x200;
 
-done:
-       exit_opengl();
-       exit_sdl();
+       if (length != sizeof(game_save[0])) {
+               fprintf(stderr, "saving game state failed, because length of data does not match, please fix!\n");
+               return;
+       }
 
-       if (chipreg)
-               free(chipreg);
-       if (memory)
-               free(memory);
-       if (sound_buffer)
-               free(sound_buffer);
-       if (image)
-               free(image);
+       /* don't save if last track is the same, because disk is written on both sides with the same data */
+       if (track == last_track) {
+               if (memcmp(memory + data, game_save[track & 1], length)) {
+                       fprintf(stderr, "saving game data on other side of the disk is different, please fix!\n");
+               }
+               return;
+       }
+       last_track = track;
 
-       return 0;
-}
+       /* save game data */
+       memcpy(game_save[track & 1], memory + data, length);
 
-void audio_sdl(float *data, int length)
-{
-       int fill, s;
+       /* if done with saving */
+       if ((track & 1)) {
+               char filename[256];
+               int gamesave_num = (track - 2) >> 1;
+               int wrote;
+               FILE *fp;
 
-       /* read sound from sound buffer
-        * buffer pointer read and write is atomic, so no locking required!
-        */
-       fill = (sound_buffer_writep - sound_buffer_readp + sound_buffer_size) % sound_buffer_size;
-       if (fill < length) {
-#ifdef DEBUG_SOUND_BUFFERING
-               fprintf(stderr, "sound buffer underrun\n");
-#endif
-               /* correct read pointer as if the buffer would have 'length' of samples stored inside */
-               sound_buffer_readp = (sound_buffer_readp + fill - length + sound_buffer_size) % sound_buffer_size;
+               sprintf(filename, "%s/%s", home_dir, config_gamesave_dir);
+               mkdir(filename, 0777);
+               sprintf(filename + strlen(filename), "/%d.gamesave", gamesave_num);
+               fp = fopen(filename, "w");
+               if (!fp) {
+fail:
+                       fprintf(stderr, "failed to save game to '%s'\n", filename);
+                       return;
+               }
+               printf("Game state saved to '%s'\n", filename);
+               wrote = fwrite(game_save, sizeof(game_save[0]), 2, fp);
+               fclose(fp);
+               if (wrote != 2)
+                       goto fail;
        }
-       for (s = 0; s < length; s++)
-               *data++ = sound_buffer[(sound_buffer_readp + s) % sound_buffer_size];
-#ifdef DEBUG_SOUND_BUFFERING
-       printf("fill %d = %.4f\n", length, sound_buffer[sound_buffer_readp]);
-#endif
-       sound_buffer_readp =(sound_buffer_readp + length) % sound_buffer_size;
 }
 
 static int shift = 0, ctrl = 0;
 
-void keyboard_sdl(int down, SDL_Keycode sym)
+static void keyboard_sdl(int down, SDL_Keycode sym)
 {
        switch (sym) {
        case SDLK_LCTRL:
@@ -544,114 +522,140 @@ void keyboard_sdl(int down, SDL_Keycode sym)
        }
 }
 
-uint16_t emulate_io_read(uint32_t address)
+void audio_sdl(float *data, int length)
 {
-       uint16_t value = 0xffff;
-
-       /* joystick and fire button */
-       if (address == 0xbfe000 || address == 0xdff00c)
-               value &= emulate_joystick_read(address);
-       /* keyboard */
-       if (address == 0xbfec00 || address == 0xbfed00 || address == 0xbfee00)
-               value &= emulate_keyboard_read(address);
-       /* diskette */
-       if (address == 0xbfd100 || address == 0xbfe000 || address == 0xdff01a || address == 0xdff01e)
-               value &= emulate_disk_read(address);
+       int fill, s;
 
-       return value;
+       /* read sound from sound buffer
+        * buffer pointer read and write is atomic, so no locking required!
+        */
+       fill = (sound_buffer_writep - sound_buffer_readp + sound_buffer_size) % sound_buffer_size;
+       if (fill < length) {
+#ifdef DEBUG_SOUND_BUFFERING
+               fprintf(stderr, "sound buffer underrun\n");
+#endif
+               /* correct read pointer as if the buffer would have 'length' of samples stored inside */
+               sound_buffer_readp = (sound_buffer_readp + fill - length + sound_buffer_size) % sound_buffer_size;
+       }
+       for (s = 0; s < length; s++)
+               *data++ = sound_buffer[(sound_buffer_readp + s) % sound_buffer_size];
+#ifdef DEBUG_SOUND_BUFFERING
+       printf("fill %d = %.4f\n", length, sound_buffer[sound_buffer_readp]);
+#endif
+       sound_buffer_readp =(sound_buffer_readp + length) % sound_buffer_size;
 }
 
-void emulate_io_write(uint32_t address, uint16_t value)
+int main(int argc, char *argv[])
 {
-       /* dmacon and sound registers */
-       if (address == 0xdff096 || (address >= 0xdff0a0 && address <= 0xdff0df))
-               emulate_sound_write(address, value, SOUND_SAMPLERATE);
-       if (address == 0xbfd100 || (address >= 0xdff020 && address <= 0xdff024))
-               emulate_disk_write(address, value);
-}
-
-/* two tracks with 0x1820 words of length */
-static uint8_t game_save[2][0x1820 << 1];
-static int last_track = 0;
+       int rc;
+       int sdl_sound_chunk;
 
-/* game reads track with saved game */
-void disk_read(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
-{
-       if (length > sizeof(game_save[0])) {
-               fprintf(stderr, "loading game state failed, because length exceeds game save data size, please fix!\n");
-               return;
-       }
+       home_dir = getenv("HOME");
+       if (!home_dir)
+               home_dir = "";
 
-       /* if even track is selected, load game */
-       if (!(track & 1)) {
-               char filename[256];
-               int gamesave_num = (track - 2) >> 1;
-               int got;
-               FILE *fp;
+       rc = parse_args(argc, argv);
+       if (rc)
+               return 0;
 
-               memset(game_save, 0, sizeof(game_save)); /* clear so make the game fail, if we fail */
-               sprintf(filename, "%s/%s/%d.gamesave", home_dir, config_gamesave_dir, gamesave_num);
-               fp = fopen(filename, "r");
-               if (!fp) {
-fail:
-                       fprintf(stderr, "failed to load game from '%s'\n", filename);
-                       goto copy;
-               }
-               got = fread(game_save, sizeof(game_save[0]), 2, fp);
-               fclose(fp);
-               if (got != 2)
-                       goto fail;
+       /* allocate image */
+       image = calloc(IMAGE_WIDTH * IMAGE_HEIGHT * ((double_size) ? 4 : 1), 3);
+       if (!image) {
+               fprintf(stderr, "Failed to allocate image buffer\n");
+               goto done;
        }
 
-copy:
-       /* copy track */
-       memcpy(memory + data, game_save[track & 1], length /* sizeof(game_save[0])*/);
-}
+       if ((SOUND_SAMPLERATE % IRQ_RATE)) {
+               fprintf(stderr, "Sample rate must be a multiple of IRQ rate, please fix!\n");
+               goto done;
+       }
+       if ((1000 % IRQ_RATE)) {
+               fprintf(stderr, "1000 (Ticks per second) rate must be a multiple of IRQ rate, please fix!\n");
+               goto done;
+       }
 
-/* game writes track with saved game */
-void disk_write(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
-{
-       /* skip sync info that is provided by game and only relevant for a real disk track */
-       data += 0x200;
-       length -= 0x200;
+       /* calculate SDL chunk size for audio
+        * it must be a power of two, but not more than the chunk size for each IRQ!
+        */
+       for (sdl_sound_chunk = 2; sdl_sound_chunk <= (SOUND_SAMPLERATE / IRQ_RATE); sdl_sound_chunk <<= 1)
+               ;
+       sdl_sound_chunk >>= 1;
+//     printf("samples per IRQ = %d, samples per SDL audio = %d\n", SOUND_SAMPLERATE / IRQ_RATE, sdl_sound_chunk); exit(0);
 
-       if (length != sizeof(game_save[0])) {
-               fprintf(stderr, "saving game state failed, because length of data does not match, please fix!\n");
-               return;
+       /* allocate sound buffers */
+       sound_buffer_size = SOUND_SAMPLERATE / IRQ_RATE * SOUND_CHUNKS;
+       sound_buffer = calloc(sound_buffer_size, sizeof(*sound_buffer));
+       if (!sound_buffer) {
+               fprintf(stderr, "Failed to allocate image buffer\n");
+               goto done;
        }
 
-       /* don't save if last track is the same, because disk is written on both sides with the same data */
-       if (track == last_track) {
-               if (memcmp(memory + data, game_save[track & 1], length)) {
-                       fprintf(stderr, "saving game data on other side of the disk is different, please fix!\n");
-               }
-               return;
+       /* allocate memory */
+       memory = calloc(MEMORY_SIZE, 1);
+       if (!memory) {
+               fprintf(stderr, "Failed to allocate cpu's memory\n");
+               goto done;
+       }
+       chipreg = calloc(IOSIZE, 1);
+       if (!chipreg) {
+               fprintf(stderr, "Failed to allocate chip register\n");
+               goto done;
        }
-       last_track = track;
 
-       /* save game data */
-       memcpy(game_save[track & 1], memory + data, length);
+       /* init cpu code */
+       execute_init(MEMORY_SIZE, memory, chipreg, io_read, io_write);
 
-       /* if done with saving */
-       if ((track & 1)) {
-               char filename[256];
-               int gamesave_num = (track - 2) >> 1;
-               int wrote;
-               FILE *fp;
+       /* init disk emulation */
+       disk_init(disk_read, disk_write);
 
-               sprintf(filename, "%s/%s", home_dir, config_gamesave_dir);
-               mkdir(filename, 0777);
-               sprintf(filename + strlen(filename), "/%d.gamesave", gamesave_num);
-               fp = fopen(filename, "w");
-               if (!fp) {
-fail:
-                       fprintf(stderr, "failed to save game to '%s'\n", filename);
-                       return;
-               }
-               printf("Game state saved to '%s'\n", filename);
-               wrote = fwrite(game_save, sizeof(game_save[0]), 2, fp);
-               fclose(fp);
-               if (wrote != 2)
-                       goto fail;
-       }
+       /* load binary */
+       mercenary_load();
+
+       /* patch some stuff */
+       mercenary_patch();
+
+       /* init SDL and OpenGL */
+       rc = init_sdl(argv[0], SCREEN_WIDTH, SCREEN_HEIGHT, SOUND_SAMPLERATE, sdl_sound_chunk, keyboard_sdl, audio_sdl);
+       if (rc < 0)
+               goto done;
+       rc = init_opengl((double_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
+       if (rc < 0)
+               goto done;
+       resize_opengl(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+       /* init audio filter */
+       sound_init_filter(SOUND_SAMPLERATE);
+
+       /* start cpu */
+       reset_cpu();
+
+       printf("**********************************\n");
+       printf("* Welcome to Mercenary Reloaded! *\n");
+       printf("**********************************\n\n");
+       printf("Press CTRL + cursor keys to select inventory or pickup/drop item.\n");
+       printf("Press CTRL + f to toggle full screen.\n");
+       printf("Press CTRL + s to toggle rendering speed.\n");
+       printf("Press CTRL + v to toggle video filter.\n");
+       printf("Press CTRL + a to toggle audio filter.\n");
+       printf("Press CTRL + c to exit game.\n\n");
+       printf("Use '--help' as command line option for configuration settings.\n\n");
+
+       /* run game */
+       main_loop();
+
+done:
+       exit_opengl();
+       exit_sdl();
+
+       if (chipreg)
+               free(chipreg);
+       if (memory)
+               free(memory);
+       if (sound_buffer)
+               free(sound_buffer);
+       if (image)
+               free(image);
+
+       return 0;
 }
+