模擬器 - RetroArch - Load Core(Template)



參考資訊:
http://emulation.gametechwiki.com/index.php/Building_RetroArch

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>

#include "libretro.h"

typedef void (*retro_run_t)(void);
typedef void (*retro_init_t)(void);
typedef void (*retro_deinit_t)(void);
typedef void (*retro_unload_game_t)(void);
typedef bool (*retro_load_game_t)(const struct retro_game_info *);
typedef void (*retro_set_input_poll_t)(retro_input_poll_t);
typedef void (*retro_set_input_state_t)(retro_input_state_t);
typedef void (*retro_set_environment_t)(retro_environment_t);
typedef void (*retro_set_video_refresh_t)(retro_video_refresh_t);
typedef void (*retro_set_audio_sample_batch_t)(retro_audio_sample_batch_t);
typedef void (*retro_audio_sample_t)(int16_t, int16_t);
typedef void (*retro_set_audio_sample_t)(retro_audio_sample_t);
typedef size_t (*retro_audio_sample_batch_t)(const int16_t *, size_t);
typedef unsigned (*retro_api_version_t)(void);

static void video_cb(const void *data, unsigned width, unsigned height, size_t pitch)
{
}

static size_t audio_batch_cb(const int16_t *data, size_t frames)
{
    return frames;
}

static void audio_sample_cb(int16_t left, int16_t right)
{
    int16_t frame[2] = { left, right };

    audio_batch_cb(frame, 1);
}

static void input_poll_cb(void)
{
}

static int16_t input_state_cb(unsigned port, unsigned device, unsigned index, unsigned id)
{
    return 0;
}

static bool env_cb(unsigned cmd, void *data)
{
    switch (cmd) {
    case RETRO_ENVIRONMENT_GET_CAN_DUPE:
        *((bool *)data) = true;
        return true;
    }
    return true;
}

static bool load_rom(const char *path, void **data, size_t *size)
{
    FILE *fp = fopen(path, "rb");

    if (!fp) {
        printf("failed to open %s\n", path);
        return false;
    }

    fseek(fp, 0, SEEK_END);
    long len = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    if (len <= 0) {
        fclose(fp);
        return false;
    }

    void *buf = malloc(len);
    if (!buf) {
        fclose(fp);
        return false;
    }

    fread(buf, 1, len, fp);
    fclose(fp);

    *data = buf;
    *size = len;

    return true;
}

int main(int argc, char *argv[])
{
    const char *rom_path = argv[2];
    const char *core_path = argv[1];

    retro_run_t retro_run;
    retro_init_t retro_init;
    retro_deinit_t retro_deinit;
    retro_load_game_t retro_load_game;
    retro_unload_game_t retro_unload_game;
    retro_api_version_t retro_api_version;
    retro_set_input_poll_t retro_set_input_poll;
    retro_set_input_state_t retro_set_input_state;
    retro_set_environment_t retro_set_environment;
    retro_set_audio_sample_t retro_set_audio_sample;
    retro_set_video_refresh_t retro_set_video_refresh;
    retro_set_audio_sample_batch_t retro_set_audio_sample_batch;

    if (argc != 3) {
        printf("usage:\n  %s xxx.so xxx.rom\n", argv[0]);
        return -1;
    }

    void *handle = dlopen(core_path, RTLD_NOW);
    if (!handle) {
        printf("failed to load shared library: %s\n", dlerror());
        return -1;
    }

    retro_run = dlsym(handle, "retro_run");
    retro_init = dlsym(handle, "retro_init");
    retro_deinit = dlsym(handle, "retro_deinit");
    retro_load_game = dlsym(handle, "retro_load_game");
    retro_unload_game = dlsym(handle, "retro_unload_game");
    retro_api_version = dlsym(handle, "retro_api_version");
    retro_set_input_poll = dlsym(handle, "retro_set_input_poll");
    retro_set_input_state = dlsym(handle, "retro_set_input_state");
    retro_set_environment = dlsym(handle, "retro_set_environment");
    retro_set_audio_sample = dlsym(handle, "retro_set_audio_sample");
    retro_set_video_refresh = dlsym(handle, "retro_set_video_refresh");
    retro_set_audio_sample_batch = dlsym(handle, "retro_set_audio_sample_batch");

    printf("api version: %u\n", retro_api_version());

    retro_set_environment(env_cb);
    retro_set_video_refresh(video_cb);
    retro_set_audio_sample(audio_sample_cb);
    retro_set_audio_sample_batch(audio_batch_cb);
    retro_set_input_poll(input_poll_cb);
    retro_set_input_state(input_state_cb);
    retro_init();

    size_t rom_size = 0;
    void *rom_data = NULL;
    if (!load_rom(rom_path, &rom_data, &rom_size)) {
        return -1;
    }

    struct retro_game_info info = { 0 };
    info.path = rom_path;
    info.data = rom_data;
    info.size = rom_size;

    if (!retro_load_game(&info)) {
        printf("failed to do retro_load_game\n");
        return -1;
    }

    int running = 1;

    while (running) {
        retro_run();
    }

    retro_deinit();
    dlclose(handle);

    return 0;
}