Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / api / frontend.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-core - api/frontend.c                                     *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2012 CasualJames                                        *
5  *   Copyright (C) 2009 Richard Goedeken                                   *
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
21  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22                        
23 /* This file contains the Core front-end functions which will be exported
24  * outside of the core library.
25  */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <SDL.h>
31
32 #define M64P_CORE_PROTOTYPES 1
33 #include "m64p_types.h"
34 #include "callbacks.h"
35 #include "m64p_config.h"
36 #include "m64p_frontend.h"
37 #include "config.h"
38 #include "vidext.h"
39
40 #include "main/cheat.h"
41 #include "main/eventloop.h"
42 #include "main/main.h"
43 #include "main/rom.h"
44 #include "main/savestates.h"
45 #include "main/version.h"
46 #include "main/util.h"
47 #include "main/workqueue.h"
48 #include "osd/screenshot.h"
49 #include "plugin/plugin.h"
50
51 /* some local state variables */
52 static int l_CoreInit = 0;
53 static int l_ROMOpen = 0;
54
55 /* functions exported outside of libmupen64plus to front-end application */
56 EXPORT m64p_error CALL CoreStartup(int APIVersion, const char *ConfigPath, const char *DataPath, void *Context,
57                                    void (*DebugCallback)(void *, int, const char *), void *Context2,
58                                    void (*StateCallback)(void *, m64p_core_param, int))
59 {
60     if (l_CoreInit)
61         return M64ERR_ALREADY_INIT;
62
63     /* very first thing is to set the callback functions for debug info and state changing*/
64     SetDebugCallback(DebugCallback, Context);
65     SetStateCallback(StateCallback, Context2);
66
67     /* check front-end's API version */
68     if ((APIVersion & 0xffff0000) != (FRONTEND_API_VERSION & 0xffff0000))
69     {
70         DebugMessage(M64MSG_ERROR, "CoreStartup(): Front-end (API version %i.%i.%i) is incompatible with this core (API %i.%i.%i)",
71                      VERSION_PRINTF_SPLIT(APIVersion), VERSION_PRINTF_SPLIT(FRONTEND_API_VERSION));
72         return M64ERR_INCOMPATIBLE;
73     }
74
75     /* set up the default (dummy) plugins */
76     plugin_connect(M64PLUGIN_GFX, NULL);
77     plugin_connect(M64PLUGIN_AUDIO, NULL);
78     plugin_connect(M64PLUGIN_INPUT, NULL);
79     plugin_connect(M64PLUGIN_CORE, NULL);
80
81     savestates_init();
82
83     /* next, start up the configuration handling code by loading and parsing the config file */
84     if (ConfigInit(ConfigPath, DataPath) != M64ERR_SUCCESS)
85         return M64ERR_INTERNAL;
86
87     /* set default configuration parameter values for Core */
88     if (ConfigOpenSection("Core", &g_CoreConfig) != M64ERR_SUCCESS || g_CoreConfig == NULL)
89         return M64ERR_INTERNAL;
90
91     if (!main_set_core_defaults())
92         return M64ERR_INTERNAL;
93
94     /* The ROM database contains MD5 hashes, goodnames, and some game-specific parameters */
95     romdatabase_open();
96
97     workqueue_init();
98
99     l_CoreInit = 1;
100     return M64ERR_SUCCESS;
101 }
102
103 EXPORT m64p_error CALL CoreShutdown(void)
104 {
105     if (!l_CoreInit)
106         return M64ERR_NOT_INIT;
107
108     /* close down some core sub-systems */
109     romdatabase_close();
110     ConfigShutdown();
111     workqueue_shutdown();
112     savestates_deinit();
113
114     /* tell SDL to shut down */
115     SDL_Quit();
116
117     l_CoreInit = 0;
118     return M64ERR_SUCCESS;
119 }
120
121 EXPORT m64p_error CALL CoreAttachPlugin(m64p_plugin_type PluginType, m64p_dynlib_handle PluginLibHandle)
122 {
123     m64p_error rval;
124
125     if (!l_CoreInit)
126         return M64ERR_NOT_INIT;
127     if (g_EmulatorRunning || !l_ROMOpen)
128         return M64ERR_INVALID_STATE;
129
130     rval = plugin_connect(PluginType, PluginLibHandle);
131     if (rval != M64ERR_SUCCESS)
132         return rval;
133
134     rval = plugin_start(PluginType);
135     if (rval != M64ERR_SUCCESS)
136         return rval;
137
138     return M64ERR_SUCCESS;
139 }
140
141 EXPORT m64p_error CALL CoreDetachPlugin(m64p_plugin_type PluginType)
142 {
143     if (!l_CoreInit)
144         return M64ERR_NOT_INIT;
145     if (g_EmulatorRunning)
146         return M64ERR_INVALID_STATE;
147
148     return plugin_connect(PluginType, NULL);
149 }
150
151 EXPORT m64p_error CALL CoreDoCommand(m64p_command Command, int ParamInt, void *ParamPtr)
152 {
153     m64p_error rval;
154     int keysym, keymod;
155
156     if (!l_CoreInit)
157         return M64ERR_NOT_INIT;
158
159     switch(Command)
160     {
161         case M64CMD_NOP:
162             return M64ERR_SUCCESS;
163         case M64CMD_ROM_OPEN:
164             if (g_EmulatorRunning || l_ROMOpen)
165                 return M64ERR_INVALID_STATE;
166             if (ParamPtr == NULL || ParamInt < 4096)
167                 return M64ERR_INPUT_ASSERT;
168             rval = open_rom((const unsigned char *) ParamPtr, ParamInt);
169             if (rval == M64ERR_SUCCESS)
170             {
171                 l_ROMOpen = 1;
172                 ScreenshotRomOpen();
173                 cheat_init();
174             }
175             return rval;
176         case M64CMD_ROM_CLOSE:
177             if (g_EmulatorRunning || !l_ROMOpen)
178                 return M64ERR_INVALID_STATE;
179             l_ROMOpen = 0;
180             cheat_delete_all();
181             cheat_uninit();
182             return close_rom();
183         case M64CMD_ROM_GET_HEADER:
184             if (!l_ROMOpen)
185                 return M64ERR_INVALID_STATE;
186             if (ParamPtr == NULL)
187                 return M64ERR_INPUT_ASSERT;
188             if (sizeof(m64p_rom_header) < ParamInt)
189                 ParamInt = sizeof(m64p_rom_header);
190             memcpy(ParamPtr, &ROM_HEADER, ParamInt);
191             // Mupen64Plus used to keep a m64p_rom_header with a clean ROM name
192             // Keep returning a clean ROM name for backwards compatibility
193             if (ParamInt >= 0x20)
194             {
195                 int size = (ParamInt >= 0x20 + 20) ? 20 : (ParamInt - 0x20);
196                 memcpy((char *)ParamPtr + 0x20, ROM_PARAMS.headername, size);
197             }
198             return M64ERR_SUCCESS;
199         case M64CMD_ROM_GET_SETTINGS:
200             if (!l_ROMOpen)
201                 return M64ERR_INVALID_STATE;
202             if (ParamPtr == NULL)
203                 return M64ERR_INPUT_ASSERT;
204             if (sizeof(m64p_rom_settings) < ParamInt)
205                 ParamInt = sizeof(m64p_rom_settings);
206             memcpy(ParamPtr, &ROM_SETTINGS, ParamInt);
207             return M64ERR_SUCCESS;
208         case M64CMD_EXECUTE:
209             if (g_EmulatorRunning || !l_ROMOpen)
210                 return M64ERR_INVALID_STATE;
211             /* print out plugin-related warning messages */
212             plugin_check();
213             /* the main_run() function will not return until the player has quit the game */
214             rval = main_run();
215             return rval;
216         case M64CMD_STOP:
217             if (!g_EmulatorRunning)
218                 return M64ERR_INVALID_STATE;
219             /* this stop function is asynchronous.  The emulator may not terminate until later */
220             return main_core_state_set(M64CORE_EMU_STATE, M64EMU_STOPPED);
221         case M64CMD_PAUSE:
222             if (!g_EmulatorRunning)
223                 return M64ERR_INVALID_STATE;
224             return main_core_state_set(M64CORE_EMU_STATE, M64EMU_PAUSED);
225         case M64CMD_RESUME:
226             if (!g_EmulatorRunning)
227                 return M64ERR_INVALID_STATE;
228             return main_core_state_set(M64CORE_EMU_STATE, M64EMU_RUNNING);
229         case M64CMD_CORE_STATE_QUERY:
230             if (ParamPtr == NULL)
231                 return M64ERR_INPUT_ASSERT;
232             return main_core_state_query((m64p_core_param) ParamInt, (int *) ParamPtr);
233         case M64CMD_CORE_STATE_SET:
234             if (ParamPtr == NULL)
235                 return M64ERR_INPUT_ASSERT;
236             return main_core_state_set((m64p_core_param) ParamInt, *((int *)ParamPtr));
237         case M64CMD_STATE_LOAD:
238             if (!g_EmulatorRunning)
239                 return M64ERR_INVALID_STATE;
240             main_state_load((char *) ParamPtr);
241             return M64ERR_SUCCESS;
242         case M64CMD_STATE_SAVE:
243             if (!g_EmulatorRunning)
244                 return M64ERR_INVALID_STATE;
245             if (ParamPtr != NULL && (ParamInt < 1 || ParamInt > 3))
246                 return M64ERR_INPUT_INVALID;
247             main_state_save(ParamInt, (char *) ParamPtr);
248             return M64ERR_SUCCESS;
249         case M64CMD_STATE_SET_SLOT:
250             if (ParamInt < 0 || ParamInt > 9)
251                 return M64ERR_INPUT_INVALID;
252             return main_core_state_set(M64CORE_SAVESTATE_SLOT, ParamInt);
253         case M64CMD_SEND_SDL_KEYDOWN:
254             if (!g_EmulatorRunning)
255                 return M64ERR_INVALID_STATE;
256             keysym = ParamInt & 0xffff;
257             keymod = (ParamInt >> 16) & 0xffff;
258             event_sdl_keydown(keysym, keymod);
259             return M64ERR_SUCCESS;
260         case M64CMD_SEND_SDL_KEYUP:
261             if (!g_EmulatorRunning)
262                 return M64ERR_INVALID_STATE;
263             keysym = ParamInt & 0xffff;
264             keymod = (ParamInt >> 16) & 0xffff;
265             event_sdl_keyup(keysym, keymod);
266             return M64ERR_SUCCESS;
267         case M64CMD_SET_FRAME_CALLBACK:
268             g_FrameCallback = (m64p_frame_callback) ParamPtr;
269             return M64ERR_SUCCESS;
270         case M64CMD_TAKE_NEXT_SCREENSHOT:
271             if (!g_EmulatorRunning)
272                 return M64ERR_INVALID_STATE;
273             main_take_next_screenshot();
274             return M64ERR_SUCCESS;
275         case M64CMD_READ_SCREEN:
276             if (!g_EmulatorRunning)
277                 return M64ERR_INVALID_STATE;
278             if (ParamPtr == NULL)
279                 return M64ERR_INPUT_ASSERT;
280             if (ParamInt < 0 || ParamInt > 1)
281                 return M64ERR_INPUT_INVALID;
282             return main_read_screen(ParamPtr, ParamInt);
283         case M64CMD_RESET:
284             if (!g_EmulatorRunning)
285                 return M64ERR_INVALID_STATE;
286             if (ParamInt < 0 || ParamInt > 1)
287                 return M64ERR_INPUT_INVALID;
288             return main_reset(ParamInt);
289         case M64CMD_ADVANCE_FRAME:
290             if (!g_EmulatorRunning)
291                 return M64ERR_INVALID_STATE;
292             main_advance_one();
293             return M64ERR_SUCCESS;
294         default:
295             return M64ERR_INPUT_INVALID;
296     }
297
298     return M64ERR_INTERNAL;
299 }
300
301 EXPORT m64p_error CALL CoreOverrideVidExt(m64p_video_extension_functions *VideoFunctionStruct)
302 {
303     if (!l_CoreInit)
304         return M64ERR_NOT_INIT;
305
306     return OverrideVideoFunctions(VideoFunctionStruct); /* in vidext.c */
307 }
308
309 EXPORT m64p_error CALL CoreAddCheat(const char *CheatName, m64p_cheat_code *CodeList, int NumCodes)
310 {
311     if (!l_CoreInit)
312         return M64ERR_NOT_INIT;
313     if (CheatName == NULL || CodeList == NULL)
314         return M64ERR_INPUT_ASSERT;
315     if (strlen(CheatName) < 1 || NumCodes < 1)
316         return M64ERR_INPUT_INVALID;
317
318     if (cheat_add_new(CheatName, CodeList, NumCodes))
319         return M64ERR_SUCCESS;
320
321     return M64ERR_INPUT_INVALID;
322 }
323
324 EXPORT m64p_error CALL CoreCheatEnabled(const char *CheatName, int Enabled)
325 {
326     if (!l_CoreInit)
327         return M64ERR_NOT_INIT;
328     if (CheatName == NULL)
329         return M64ERR_INPUT_ASSERT;
330
331     if (cheat_set_enabled(CheatName, Enabled))
332         return M64ERR_SUCCESS;
333
334     return M64ERR_INPUT_INVALID;
335 }
336
337 EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *RomSettings, int RomSettingsLength, int Crc1, int Crc2)
338 {
339     romdatabase_entry* entry;
340     int i;
341
342     if (!l_CoreInit)
343         return M64ERR_NOT_INIT;
344     if (RomSettings == NULL)
345         return M64ERR_INPUT_ASSERT;
346     if (RomSettingsLength < sizeof(m64p_rom_settings))
347         return M64ERR_INPUT_INVALID;
348
349     /* Look up this ROM in the .ini file and fill in goodname, etc */
350     entry = ini_search_by_crc(Crc1, Crc2);
351     if (entry == NULL)
352         return M64ERR_INPUT_NOT_FOUND;
353
354     strncpy(RomSettings->goodname, entry->goodname, 255);
355     RomSettings->goodname[255] = '\0';
356     for (i = 0; i < 16; i++)
357         sprintf(RomSettings->MD5 + i*2, "%02X", entry->md5[i]);
358     RomSettings->MD5[32] = '\0';
359     RomSettings->savetype = entry->savetype;
360     RomSettings->status = entry->status;
361     RomSettings->players = entry->players;
362     RomSettings->rumble = entry->rumble;
363
364     return M64ERR_SUCCESS;
365 }
366
367