Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / api / frontend.c
diff --git a/source/mupen64plus-core/src/api/frontend.c b/source/mupen64plus-core/src/api/frontend.c
new file mode 100755 (executable)
index 0000000..b3fefab
--- /dev/null
@@ -0,0 +1,367 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   Mupen64plus-core - api/frontend.c                                     *
+ *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
+ *   Copyright (C) 2012 CasualJames                                        *
+ *   Copyright (C) 2009 Richard Goedeken                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+                       
+/* This file contains the Core front-end functions which will be exported
+ * outside of the core library.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <SDL.h>
+
+#define M64P_CORE_PROTOTYPES 1
+#include "m64p_types.h"
+#include "callbacks.h"
+#include "m64p_config.h"
+#include "m64p_frontend.h"
+#include "config.h"
+#include "vidext.h"
+
+#include "main/cheat.h"
+#include "main/eventloop.h"
+#include "main/main.h"
+#include "main/rom.h"
+#include "main/savestates.h"
+#include "main/version.h"
+#include "main/util.h"
+#include "main/workqueue.h"
+#include "osd/screenshot.h"
+#include "plugin/plugin.h"
+
+/* some local state variables */
+static int l_CoreInit = 0;
+static int l_ROMOpen = 0;
+
+/* functions exported outside of libmupen64plus to front-end application */
+EXPORT m64p_error CALL CoreStartup(int APIVersion, const char *ConfigPath, const char *DataPath, void *Context,
+                                   void (*DebugCallback)(void *, int, const char *), void *Context2,
+                                   void (*StateCallback)(void *, m64p_core_param, int))
+{
+    if (l_CoreInit)
+        return M64ERR_ALREADY_INIT;
+
+    /* very first thing is to set the callback functions for debug info and state changing*/
+    SetDebugCallback(DebugCallback, Context);
+    SetStateCallback(StateCallback, Context2);
+
+    /* check front-end's API version */
+    if ((APIVersion & 0xffff0000) != (FRONTEND_API_VERSION & 0xffff0000))
+    {
+        DebugMessage(M64MSG_ERROR, "CoreStartup(): Front-end (API version %i.%i.%i) is incompatible with this core (API %i.%i.%i)",
+                     VERSION_PRINTF_SPLIT(APIVersion), VERSION_PRINTF_SPLIT(FRONTEND_API_VERSION));
+        return M64ERR_INCOMPATIBLE;
+    }
+
+    /* set up the default (dummy) plugins */
+    plugin_connect(M64PLUGIN_GFX, NULL);
+    plugin_connect(M64PLUGIN_AUDIO, NULL);
+    plugin_connect(M64PLUGIN_INPUT, NULL);
+    plugin_connect(M64PLUGIN_CORE, NULL);
+
+    savestates_init();
+
+    /* next, start up the configuration handling code by loading and parsing the config file */
+    if (ConfigInit(ConfigPath, DataPath) != M64ERR_SUCCESS)
+        return M64ERR_INTERNAL;
+
+    /* set default configuration parameter values for Core */
+    if (ConfigOpenSection("Core", &g_CoreConfig) != M64ERR_SUCCESS || g_CoreConfig == NULL)
+        return M64ERR_INTERNAL;
+
+    if (!main_set_core_defaults())
+        return M64ERR_INTERNAL;
+
+    /* The ROM database contains MD5 hashes, goodnames, and some game-specific parameters */
+    romdatabase_open();
+
+    workqueue_init();
+
+    l_CoreInit = 1;
+    return M64ERR_SUCCESS;
+}
+
+EXPORT m64p_error CALL CoreShutdown(void)
+{
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+
+    /* close down some core sub-systems */
+    romdatabase_close();
+    ConfigShutdown();
+    workqueue_shutdown();
+    savestates_deinit();
+
+    /* tell SDL to shut down */
+    SDL_Quit();
+
+    l_CoreInit = 0;
+    return M64ERR_SUCCESS;
+}
+
+EXPORT m64p_error CALL CoreAttachPlugin(m64p_plugin_type PluginType, m64p_dynlib_handle PluginLibHandle)
+{
+    m64p_error rval;
+
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+    if (g_EmulatorRunning || !l_ROMOpen)
+        return M64ERR_INVALID_STATE;
+
+    rval = plugin_connect(PluginType, PluginLibHandle);
+    if (rval != M64ERR_SUCCESS)
+        return rval;
+
+    rval = plugin_start(PluginType);
+    if (rval != M64ERR_SUCCESS)
+        return rval;
+
+    return M64ERR_SUCCESS;
+}
+
+EXPORT m64p_error CALL CoreDetachPlugin(m64p_plugin_type PluginType)
+{
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+    if (g_EmulatorRunning)
+        return M64ERR_INVALID_STATE;
+
+    return plugin_connect(PluginType, NULL);
+}
+
+EXPORT m64p_error CALL CoreDoCommand(m64p_command Command, int ParamInt, void *ParamPtr)
+{
+    m64p_error rval;
+    int keysym, keymod;
+
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+
+    switch(Command)
+    {
+        case M64CMD_NOP:
+            return M64ERR_SUCCESS;
+        case M64CMD_ROM_OPEN:
+            if (g_EmulatorRunning || l_ROMOpen)
+                return M64ERR_INVALID_STATE;
+            if (ParamPtr == NULL || ParamInt < 4096)
+                return M64ERR_INPUT_ASSERT;
+            rval = open_rom((const unsigned char *) ParamPtr, ParamInt);
+            if (rval == M64ERR_SUCCESS)
+            {
+                l_ROMOpen = 1;
+                ScreenshotRomOpen();
+                cheat_init();
+            }
+            return rval;
+        case M64CMD_ROM_CLOSE:
+            if (g_EmulatorRunning || !l_ROMOpen)
+                return M64ERR_INVALID_STATE;
+            l_ROMOpen = 0;
+            cheat_delete_all();
+            cheat_uninit();
+            return close_rom();
+        case M64CMD_ROM_GET_HEADER:
+            if (!l_ROMOpen)
+                return M64ERR_INVALID_STATE;
+            if (ParamPtr == NULL)
+                return M64ERR_INPUT_ASSERT;
+            if (sizeof(m64p_rom_header) < ParamInt)
+                ParamInt = sizeof(m64p_rom_header);
+            memcpy(ParamPtr, &ROM_HEADER, ParamInt);
+            // Mupen64Plus used to keep a m64p_rom_header with a clean ROM name
+            // Keep returning a clean ROM name for backwards compatibility
+            if (ParamInt >= 0x20)
+            {
+                int size = (ParamInt >= 0x20 + 20) ? 20 : (ParamInt - 0x20);
+                memcpy((char *)ParamPtr + 0x20, ROM_PARAMS.headername, size);
+            }
+            return M64ERR_SUCCESS;
+        case M64CMD_ROM_GET_SETTINGS:
+            if (!l_ROMOpen)
+                return M64ERR_INVALID_STATE;
+            if (ParamPtr == NULL)
+                return M64ERR_INPUT_ASSERT;
+            if (sizeof(m64p_rom_settings) < ParamInt)
+                ParamInt = sizeof(m64p_rom_settings);
+            memcpy(ParamPtr, &ROM_SETTINGS, ParamInt);
+            return M64ERR_SUCCESS;
+        case M64CMD_EXECUTE:
+            if (g_EmulatorRunning || !l_ROMOpen)
+                return M64ERR_INVALID_STATE;
+            /* print out plugin-related warning messages */
+            plugin_check();
+            /* the main_run() function will not return until the player has quit the game */
+            rval = main_run();
+            return rval;
+        case M64CMD_STOP:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            /* this stop function is asynchronous.  The emulator may not terminate until later */
+            return main_core_state_set(M64CORE_EMU_STATE, M64EMU_STOPPED);
+        case M64CMD_PAUSE:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            return main_core_state_set(M64CORE_EMU_STATE, M64EMU_PAUSED);
+        case M64CMD_RESUME:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            return main_core_state_set(M64CORE_EMU_STATE, M64EMU_RUNNING);
+        case M64CMD_CORE_STATE_QUERY:
+            if (ParamPtr == NULL)
+                return M64ERR_INPUT_ASSERT;
+            return main_core_state_query((m64p_core_param) ParamInt, (int *) ParamPtr);
+        case M64CMD_CORE_STATE_SET:
+            if (ParamPtr == NULL)
+                return M64ERR_INPUT_ASSERT;
+            return main_core_state_set((m64p_core_param) ParamInt, *((int *)ParamPtr));
+        case M64CMD_STATE_LOAD:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            main_state_load((char *) ParamPtr);
+            return M64ERR_SUCCESS;
+        case M64CMD_STATE_SAVE:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            if (ParamPtr != NULL && (ParamInt < 1 || ParamInt > 3))
+                return M64ERR_INPUT_INVALID;
+            main_state_save(ParamInt, (char *) ParamPtr);
+            return M64ERR_SUCCESS;
+        case M64CMD_STATE_SET_SLOT:
+            if (ParamInt < 0 || ParamInt > 9)
+                return M64ERR_INPUT_INVALID;
+            return main_core_state_set(M64CORE_SAVESTATE_SLOT, ParamInt);
+        case M64CMD_SEND_SDL_KEYDOWN:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            keysym = ParamInt & 0xffff;
+            keymod = (ParamInt >> 16) & 0xffff;
+            event_sdl_keydown(keysym, keymod);
+            return M64ERR_SUCCESS;
+        case M64CMD_SEND_SDL_KEYUP:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            keysym = ParamInt & 0xffff;
+            keymod = (ParamInt >> 16) & 0xffff;
+            event_sdl_keyup(keysym, keymod);
+            return M64ERR_SUCCESS;
+        case M64CMD_SET_FRAME_CALLBACK:
+            g_FrameCallback = (m64p_frame_callback) ParamPtr;
+            return M64ERR_SUCCESS;
+        case M64CMD_TAKE_NEXT_SCREENSHOT:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            main_take_next_screenshot();
+            return M64ERR_SUCCESS;
+        case M64CMD_READ_SCREEN:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            if (ParamPtr == NULL)
+                return M64ERR_INPUT_ASSERT;
+            if (ParamInt < 0 || ParamInt > 1)
+                return M64ERR_INPUT_INVALID;
+            return main_read_screen(ParamPtr, ParamInt);
+        case M64CMD_RESET:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            if (ParamInt < 0 || ParamInt > 1)
+                return M64ERR_INPUT_INVALID;
+            return main_reset(ParamInt);
+        case M64CMD_ADVANCE_FRAME:
+            if (!g_EmulatorRunning)
+                return M64ERR_INVALID_STATE;
+            main_advance_one();
+            return M64ERR_SUCCESS;
+        default:
+            return M64ERR_INPUT_INVALID;
+    }
+
+    return M64ERR_INTERNAL;
+}
+
+EXPORT m64p_error CALL CoreOverrideVidExt(m64p_video_extension_functions *VideoFunctionStruct)
+{
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+
+    return OverrideVideoFunctions(VideoFunctionStruct); /* in vidext.c */
+}
+
+EXPORT m64p_error CALL CoreAddCheat(const char *CheatName, m64p_cheat_code *CodeList, int NumCodes)
+{
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+    if (CheatName == NULL || CodeList == NULL)
+        return M64ERR_INPUT_ASSERT;
+    if (strlen(CheatName) < 1 || NumCodes < 1)
+        return M64ERR_INPUT_INVALID;
+
+    if (cheat_add_new(CheatName, CodeList, NumCodes))
+        return M64ERR_SUCCESS;
+
+    return M64ERR_INPUT_INVALID;
+}
+
+EXPORT m64p_error CALL CoreCheatEnabled(const char *CheatName, int Enabled)
+{
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+    if (CheatName == NULL)
+        return M64ERR_INPUT_ASSERT;
+
+    if (cheat_set_enabled(CheatName, Enabled))
+        return M64ERR_SUCCESS;
+
+    return M64ERR_INPUT_INVALID;
+}
+
+EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *RomSettings, int RomSettingsLength, int Crc1, int Crc2)
+{
+    romdatabase_entry* entry;
+    int i;
+
+    if (!l_CoreInit)
+        return M64ERR_NOT_INIT;
+    if (RomSettings == NULL)
+        return M64ERR_INPUT_ASSERT;
+    if (RomSettingsLength < sizeof(m64p_rom_settings))
+        return M64ERR_INPUT_INVALID;
+
+    /* Look up this ROM in the .ini file and fill in goodname, etc */
+    entry = ini_search_by_crc(Crc1, Crc2);
+    if (entry == NULL)
+        return M64ERR_INPUT_NOT_FOUND;
+
+    strncpy(RomSettings->goodname, entry->goodname, 255);
+    RomSettings->goodname[255] = '\0';
+    for (i = 0; i < 16; i++)
+        sprintf(RomSettings->MD5 + i*2, "%02X", entry->md5[i]);
+    RomSettings->MD5[32] = '\0';
+    RomSettings->savetype = entry->savetype;
+    RomSettings->status = entry->status;
+    RomSettings->players = entry->players;
+    RomSettings->rumble = entry->rumble;
+
+    return M64ERR_SUCCESS;
+}
+
+