1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - main.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2012 CasualJames *
5 * Copyright (C) 2008-2009 Richard Goedeken *
6 * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
7 * Copyright (C) 2002 Hacktarux *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the *
21 * Free Software Foundation, Inc., *
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
23 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25 /* This is MUPEN64's main entry point. It contains code that is common
26 * to both the gui and non-gui versions of mupen64. See
27 * gui subdirectories for the gui-specific code.
28 * if you want to implement an interface, you should look here
36 #define M64P_CORE_PROTOTYPES 1
37 #include "api/m64p_types.h"
38 #include "api/callbacks.h"
39 #include "api/config.h"
40 #include "api/m64p_config.h"
41 #include "api/debugger.h"
42 #include "api/vidext.h"
45 #include "eventloop.h"
47 #include "savestates.h"
50 #include "memory/memory.h"
51 #include "osal/files.h"
52 #include "osal/preproc.h"
54 #include "osd/screenshot.h"
55 #include "plugin/plugin.h"
56 #include "r4300/r4300.h"
57 #include "r4300/interupt.h"
58 #include "r4300/reset.h"
61 #include "debugger/dbg_types.h"
62 #include "debugger/debugger.h"
69 /* version number for Core config section */
70 #define CONFIG_PARAM_VERSION 1.01
73 m64p_handle g_CoreConfig = NULL;
75 m64p_frame_callback g_FrameCallback = NULL;
77 int g_MemHasBeenBSwapped = 0; // store byte-swapped flag so we don't swap twice when re-playing game
78 int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
80 /** static (local) variables **/
81 static int l_CurrentFrame = 0; // frame counter
82 static int l_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
83 static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running
84 static int l_FrameAdvance = 0; // variable to check if we pause on next frame
85 static int l_MainSpeedLimit = 1; // insert delay during vi_interrupt to keep speed at real-time
87 static osd_message_t *l_msgVol = NULL;
88 static osd_message_t *l_msgFF = NULL;
89 static osd_message_t *l_msgPause = NULL;
91 /*********************************************************************************************************
95 static const char *get_savepathdefault(const char *configpath)
97 static char path[1024];
99 if (!configpath || (strlen(configpath) == 0)) {
100 snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]);
103 snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]);
107 /* create directory if it doesn't exist */
108 osal_mkdirp(path, 0700);
114 /*********************************************************************************************************
119 const char *get_savestatepath(void)
121 /* try to get the SaveStatePath string variable in the Core configuration section */
122 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath"));
125 const char *get_savesrampath(void)
127 /* try to get the SaveSRAMPath string variable in the Core configuration section */
128 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath"));
131 void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...)
135 va_start(ap, format);
136 vsnprintf(buffer, 2047, format, ap);
140 /* send message to on-screen-display if enabled */
141 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
142 osd_new_message((enum osd_corner) corner, "%s", buffer);
143 /* send message to front-end */
144 DebugMessage(level, "%s", buffer);
148 /*********************************************************************************************************
149 * global functions, for adjusting the core emulator behavior
152 int main_set_core_defaults(void)
154 float fConfigParamsVersion;
155 int bSaveConfig = 0, bUpgrade = 0;
157 if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
159 DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults.");
160 ConfigDeleteSection("Core");
161 ConfigOpenSection("Core", &g_CoreConfig);
164 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
166 DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Core' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
167 ConfigDeleteSection("Core");
168 ConfigOpenSection("Core", &g_CoreConfig);
171 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
173 float fVersion = (float) CONFIG_PARAM_VERSION;
174 ConfigSetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fVersion);
175 DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Core' config section to %.2f", fVersion);
180 /* parameters controlling the operation of the core */
181 ConfigSetDefaultFloat(g_CoreConfig, "Version", (float) CONFIG_PARAM_VERSION, "Mupen64Plus Core config parameter set version number. Please don't change this version number.");
182 ConfigSetDefaultBool(g_CoreConfig, "OnScreenDisplay", 1, "Draw on-screen display if True, otherwise don't draw OSD");
184 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
186 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
188 ConfigSetDefaultBool(g_CoreConfig, "NoCompiledJump", 0, "Disable compiled jump commands in dynamic recompiler (should be set to False) ");
189 ConfigSetDefaultBool(g_CoreConfig, "DisableExtraMem", 0, "Disable 4MB expansion RAM pack. May be necessary for some games");
190 ConfigSetDefaultBool(g_CoreConfig, "AutoStateSlotIncrement", 0, "Increment the save state slot after each save operation");
191 ConfigSetDefaultBool(g_CoreConfig, "EnableDebugger", 0, "Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support");
192 ConfigSetDefaultInt(g_CoreConfig, "CurrentStateSlot", 0, "Save state slot (0-9) to use when saving/loading the emulator state");
193 ConfigSetDefaultString(g_CoreConfig, "ScreenshotPath", "", "Path to directory where screenshots are saved. If this is blank, the default value of ${UserConfigPath}/screenshot will be used");
194 ConfigSetDefaultString(g_CoreConfig, "SaveStatePath", "", "Path to directory where emulator save states (snapshots) are saved. If this is blank, the default value of ${UserConfigPath}/save will be used");
195 ConfigSetDefaultString(g_CoreConfig, "SaveSRAMPath", "", "Path to directory where SRAM/EEPROM data (in-game saves) are stored. If this is blank, the default value of ${UserConfigPath}/save will be used");
196 ConfigSetDefaultString(g_CoreConfig, "SharedDataPath", "", "Path to a directory to search when looking for shared data files");
198 /* handle upgrades */
201 if (fConfigParamsVersion < 1.01f)
202 { // added separate SaveSRAMPath parameter in v1.01
203 const char *pccSaveStatePath = ConfigGetParamString(g_CoreConfig, "SaveStatePath");
204 if (pccSaveStatePath != NULL)
205 ConfigSetParameter(g_CoreConfig, "SaveSRAMPath", M64TYPE_STRING, pccSaveStatePath);
210 ConfigSaveSection("Core");
212 /* set config parameters for keyboard and joystick commands */
213 return event_set_core_defaults();
216 void main_speeddown(int percent)
218 if (l_SpeedFactor - percent > 10) /* 10% minimum speed */
220 l_SpeedFactor -= percent;
221 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
222 audio.setSpeedFactor(l_SpeedFactor);
223 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
227 void main_speedup(int percent)
229 if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
231 l_SpeedFactor += percent;
232 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
233 audio.setSpeedFactor(l_SpeedFactor);
234 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
238 static void main_speedset(int percent)
240 if (percent < 1 || percent > 1000)
242 DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent);
245 // disable fast-forward if it's enabled
246 main_set_fastforward(0);
248 l_SpeedFactor = percent;
249 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
250 audio.setSpeedFactor(l_SpeedFactor);
251 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
254 void main_set_fastforward(int enable)
256 static int ff_state = 0;
257 static int SavedSpeedFactor = 100;
259 if (enable && !ff_state)
261 ff_state = 1; /* activate fast-forward */
262 SavedSpeedFactor = l_SpeedFactor;
264 audio.setSpeedFactor(l_SpeedFactor);
265 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
266 // set fast-forward indicator
267 l_msgFF = osd_new_message(OSD_TOP_RIGHT, "Fast Forward");
268 osd_message_set_static(l_msgFF);
269 osd_message_set_user_managed(l_msgFF);
271 else if (!enable && ff_state)
273 ff_state = 0; /* de-activate fast-forward */
274 l_SpeedFactor = SavedSpeedFactor;
275 audio.setSpeedFactor(l_SpeedFactor);
276 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
278 osd_delete_message(l_msgFF);
284 static void main_set_speedlimiter(int enable)
286 l_MainSpeedLimit = enable ? 1 : 0;
289 static int main_is_paused(void)
291 return (g_EmulatorRunning && rompause);
294 void main_toggle_pause(void)
296 if (!g_EmulatorRunning)
301 DebugMessage(M64MSG_STATUS, "Emulation continued.");
304 osd_delete_message(l_msgPause);
307 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
312 osd_delete_message(l_msgPause);
314 DebugMessage(M64MSG_STATUS, "Emulation paused.");
315 l_msgPause = osd_new_message(OSD_MIDDLE_CENTER, "Paused");
316 osd_message_set_static(l_msgPause);
317 osd_message_set_user_managed(l_msgPause);
318 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
321 rompause = !rompause;
325 void main_advance_one(void)
329 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
332 static void main_draw_volume_osd(void)
335 const char *volString;
337 // this calls into the audio plugin
338 volString = audio.volumeGetString();
339 if (volString == NULL)
341 strcpy(msgString, "Volume Not Supported.");
345 sprintf(msgString, "%s: %s", "Volume", volString);
348 // create a new message or update an existing one
349 if (l_msgVol != NULL)
350 osd_update_message(l_msgVol, "%s", msgString);
352 l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString);
353 osd_message_set_user_managed(l_msgVol);
357 /* this function could be called as a result of a keypress, joystick/button movement,
358 LIRC command, or 'testshots' command-line option timer */
359 void main_take_next_screenshot(void)
361 l_TakeScreenshot = l_CurrentFrame + 1;
364 void main_state_set_slot(int slot)
366 if (slot < 0 || slot > 9)
368 DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot(). Using 0", slot);
372 savestates_select_slot(slot);
373 StateChanged(M64CORE_SAVESTATE_SLOT, slot);
376 void main_state_inc_slot(void)
378 savestates_inc_slot();
381 static unsigned char StopRumble[64] = {0x23, 0x01, 0x03, 0xc0, 0x1b, 0x00, 0x00, 0x00,
382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385 0, 0, 0, 0, 0, 0, 0, 0};
387 void main_state_load(const char *filename)
389 input.controllerCommand(0, StopRumble);
390 input.controllerCommand(1, StopRumble);
391 input.controllerCommand(2, StopRumble);
392 input.controllerCommand(3, StopRumble);
394 if (filename == NULL) // Save to slot
395 savestates_set_job(savestates_job_load, savestates_type_m64p, NULL);
397 savestates_set_job(savestates_job_load, savestates_type_unknown, filename);
400 void main_state_save(int format, const char *filename)
402 if (filename == NULL) // Save to slot
403 savestates_set_job(savestates_job_save, savestates_type_m64p, NULL);
405 savestates_set_job(savestates_job_save, (savestates_type)format, filename);
408 m64p_error main_core_state_query(m64p_core_param param, int *rval)
412 case M64CORE_EMU_STATE:
413 if (!g_EmulatorRunning)
414 *rval = M64EMU_STOPPED;
416 *rval = M64EMU_PAUSED;
418 *rval = M64EMU_RUNNING;
420 case M64CORE_VIDEO_MODE:
421 if (!VidExt_VideoRunning())
422 *rval = M64VIDEO_NONE;
423 else if (VidExt_InFullscreenMode())
424 *rval = M64VIDEO_FULLSCREEN;
426 *rval = M64VIDEO_WINDOWED;
428 case M64CORE_SAVESTATE_SLOT:
429 *rval = savestates_get_slot();
431 case M64CORE_SPEED_FACTOR:
432 *rval = l_SpeedFactor;
434 case M64CORE_SPEED_LIMITER:
435 *rval = l_MainSpeedLimit;
437 case M64CORE_VIDEO_SIZE:
440 if (!g_EmulatorRunning)
441 return M64ERR_INVALID_STATE;
442 main_get_screen_size(&width, &height);
443 *rval = (width << 16) + height;
446 case M64CORE_AUDIO_VOLUME:
448 if (!g_EmulatorRunning)
449 return M64ERR_INVALID_STATE;
450 return main_volume_get_level(rval);
452 case M64CORE_AUDIO_MUTE:
453 *rval = main_volume_get_muted();
455 case M64CORE_INPUT_GAMESHARK:
456 *rval = event_gameshark_active();
458 // these are only used for callbacks; they cannot be queried or set
459 case M64CORE_STATE_LOADCOMPLETE:
460 case M64CORE_STATE_SAVECOMPLETE:
461 return M64ERR_INPUT_INVALID;
463 return M64ERR_INPUT_INVALID;
466 return M64ERR_SUCCESS;
469 m64p_error main_core_state_set(m64p_core_param param, int val)
473 case M64CORE_EMU_STATE:
474 if (!g_EmulatorRunning)
475 return M64ERR_INVALID_STATE;
476 if (val == M64EMU_STOPPED)
478 /* this stop function is asynchronous. The emulator may not terminate until later */
480 return M64ERR_SUCCESS;
482 else if (val == M64EMU_RUNNING)
484 if (main_is_paused())
486 return M64ERR_SUCCESS;
488 else if (val == M64EMU_PAUSED)
490 if (!main_is_paused())
492 return M64ERR_SUCCESS;
494 return M64ERR_INPUT_INVALID;
495 case M64CORE_VIDEO_MODE:
496 if (!g_EmulatorRunning)
497 return M64ERR_INVALID_STATE;
498 if (val == M64VIDEO_WINDOWED)
500 if (VidExt_InFullscreenMode())
502 return M64ERR_SUCCESS;
504 else if (val == M64VIDEO_FULLSCREEN)
506 if (!VidExt_InFullscreenMode())
508 return M64ERR_SUCCESS;
510 return M64ERR_INPUT_INVALID;
511 case M64CORE_SAVESTATE_SLOT:
512 if (val < 0 || val > 9)
513 return M64ERR_INPUT_INVALID;
514 savestates_select_slot(val);
515 return M64ERR_SUCCESS;
516 case M64CORE_SPEED_FACTOR:
517 if (!g_EmulatorRunning)
518 return M64ERR_INVALID_STATE;
520 return M64ERR_SUCCESS;
521 case M64CORE_SPEED_LIMITER:
522 main_set_speedlimiter(val);
523 return M64ERR_SUCCESS;
524 case M64CORE_VIDEO_SIZE:
526 // the front-end app is telling us that the user has resized the video output frame, and so
527 // we should try to update the video plugin accordingly. First, check state
529 if (!g_EmulatorRunning)
530 return M64ERR_INVALID_STATE;
531 width = (val >> 16) & 0xffff;
532 height = val & 0xffff;
533 // then call the video plugin. if the video plugin supports resizing, it will resize its viewport and call
534 // VidExt_ResizeWindow to update the window manager handling our opengl output window
535 gfx.resizeVideoOutput(width, height);
536 return M64ERR_SUCCESS;
538 case M64CORE_AUDIO_VOLUME:
539 if (!g_EmulatorRunning)
540 return M64ERR_INVALID_STATE;
541 if (val < 0 || val > 100)
542 return M64ERR_INPUT_INVALID;
543 return main_volume_set_level(val);
544 case M64CORE_AUDIO_MUTE:
545 if ((main_volume_get_muted() && !val) || (!main_volume_get_muted() && val))
546 return main_volume_mute();
547 return M64ERR_SUCCESS;
548 case M64CORE_INPUT_GAMESHARK:
549 if (!g_EmulatorRunning)
550 return M64ERR_INVALID_STATE;
551 event_set_gameshark(val);
552 return M64ERR_SUCCESS;
553 // these are only used for callbacks; they cannot be queried or set
554 case M64CORE_STATE_LOADCOMPLETE:
555 case M64CORE_STATE_SAVECOMPLETE:
556 return M64ERR_INPUT_INVALID;
558 return M64ERR_INPUT_INVALID;
562 m64p_error main_get_screen_size(int *width, int *height)
564 gfx.readScreen(NULL, width, height, 0);
565 return M64ERR_SUCCESS;
568 m64p_error main_read_screen(void *pixels, int bFront)
570 int width_trash, height_trash;
571 gfx.readScreen(pixels, &width_trash, &height_trash, bFront);
572 return M64ERR_SUCCESS;
575 m64p_error main_volume_up(void)
579 main_draw_volume_osd();
580 main_volume_get_level(&level);
581 StateChanged(M64CORE_AUDIO_VOLUME, level);
582 return M64ERR_SUCCESS;
585 m64p_error main_volume_down(void)
589 main_draw_volume_osd();
590 main_volume_get_level(&level);
591 StateChanged(M64CORE_AUDIO_VOLUME, level);
592 return M64ERR_SUCCESS;
595 m64p_error main_volume_get_level(int *level)
597 *level = audio.volumeGetLevel();
598 return M64ERR_SUCCESS;
601 m64p_error main_volume_set_level(int level)
603 audio.volumeSetLevel(level);
604 main_draw_volume_osd();
605 level = audio.volumeGetLevel();
606 StateChanged(M64CORE_AUDIO_VOLUME, level);
607 return M64ERR_SUCCESS;
610 m64p_error main_volume_mute(void)
613 main_draw_volume_osd();
614 StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted());
615 return M64ERR_SUCCESS;
618 int main_volume_get_muted(void)
620 return (audio.volumeGetLevel() == 0);
623 m64p_error main_reset(int do_hard_reset)
629 return M64ERR_SUCCESS;
632 /*********************************************************************************************************
633 * global functions, callbacks from the r4300 core or from other plugins
636 static void video_plugin_render_callback(int bScreenRedrawn)
638 int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay");
640 // if the flag is set to take a screenshot, then grab it now
641 if (l_TakeScreenshot != 0)
643 // if the OSD is enabled, and the screen has not been recently redrawn, then we cannot take a screenshot now because
644 // it contains the OSD text. Wait until the next redraw
645 if (!bOSD || bScreenRedrawn)
647 TakeScreenshot(l_TakeScreenshot - 1); // current frame number +1 is in l_TakeScreenshot
648 l_TakeScreenshot = 0; // reset flag
652 // if the OSD is enabled, then draw it now
661 if (g_FrameCallback != NULL)
662 (*g_FrameCallback)(l_CurrentFrame);
664 /* advance the current frame */
667 if (l_FrameAdvance) {
670 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
677 unsigned int CurrentFPSTime;
678 static unsigned int LastFPSTime = 0;
679 static unsigned int CounterTime = 0;
680 static unsigned int CalculatedTime ;
681 static int VI_Counter = 0;
683 double VILimitMilliseconds = 1000.0 / ROM_PARAMS.vilimit;
684 double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor; // adjust for selected emulator speed
687 start_section(IDLE_SECTION);
691 if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0);
696 LastFPSTime = CounterTime = SDL_GetTicks();
699 CurrentFPSTime = SDL_GetTicks();
701 Dif = CurrentFPSTime - LastFPSTime;
703 if (Dif < AdjustedLimit)
705 CalculatedTime = (unsigned int) (CounterTime + AdjustedLimit * VI_Counter);
706 time = (int)(CalculatedTime - CurrentFPSTime);
707 if (time > 0 && l_MainSpeedLimit)
709 DebugMessage(M64MSG_VERBOSE, " new_vi(): Waiting %ims", time);
712 CurrentFPSTime = CurrentFPSTime + time;
715 if (CurrentFPSTime - CounterTime >= 1000.0 )
717 CounterTime = SDL_GetTicks();
721 LastFPSTime = CurrentFPSTime ;
722 end_section(IDLE_SECTION);
725 /*********************************************************************************************************
726 * emulation thread - runs the core
728 m64p_error main_run(void)
730 /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */
731 r4300emu = ConfigGetParamInt(g_CoreConfig, "R4300Emulator");
733 /* set some other core parameters based on the config file values */
734 savestates_set_autoinc_slot(ConfigGetParamBool(g_CoreConfig, "AutoStateSlotIncrement"));
735 savestates_select_slot(ConfigGetParamInt(g_CoreConfig, "CurrentStateSlot"));
736 no_compiled_jump = ConfigGetParamBool(g_CoreConfig, "NoCompiledJump");
738 // initialize memory, and do byte-swapping if it's not been done yet
739 if (g_MemHasBeenBSwapped == 0)
742 g_MemHasBeenBSwapped = 1;
748 // Attach rom to plugins
751 free_memory(); return M64ERR_PLUGIN_FAIL;
753 if (!audio.romOpen())
755 gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
757 if (!input.romOpen())
759 audio.romClosed(); gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
763 /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */
766 /* initialize the on-screen display */
767 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
769 // init on-screen display
770 int width = 640, height = 480;
771 gfx.readScreen(NULL, &width, &height, 0); // read screen to get width and height
772 osd_init(width, height);
775 // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
776 gfx.setRenderingCallback(video_plugin_render_callback);
783 if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger"))
786 /* Startup message on the OSD */
787 osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started...");
788 g_EmulatorRunning = 1;
789 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
790 /* call r4300 CPU core and run the game */
795 /* now begin to shut down */
801 if (g_DebuggerActive)
805 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
817 g_EmulatorRunning = 0;
818 StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED);
820 return M64ERR_SUCCESS;
825 /* note: this operation is asynchronous. It may be called from a thread other than the
826 main emulator thread, and may return before the emulator is completely stopped */
827 if (!g_EmulatorRunning)
830 DebugMessage(M64MSG_STATUS, "Stopping emulation.");
833 osd_delete_message(l_msgPause);
838 osd_delete_message(l_msgFF);
843 osd_delete_message(l_msgVol);
849 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
860 /*********************************************************************************************************
863 int main(int argc, char *argv[])