RICE: OOT Fix from mupen64plus-ae team
[mupen64plus-pandora.git] / source / mupen64plus-core / src / main / main.c
CommitLineData
451ab91e 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 *
8 * *
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. *
13 * *
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. *
18 * *
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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
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
29 */
30
31#include <string.h>
32#include <stdlib.h>
33
34#include <SDL.h>
35
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"
43
44#include "main.h"
45#include "eventloop.h"
46#include "rom.h"
47#include "savestates.h"
48#include "util.h"
49
50#include "memory/memory.h"
51#include "osal/files.h"
52#include "osal/preproc.h"
53#include "osd/osd.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"
59
60#ifdef DBG
61#include "debugger/dbg_types.h"
62#include "debugger/debugger.h"
63#endif
64
65#ifdef WITH_LIRC
66#include "lirc.h"
67#endif //WITH_LIRC
68
69/* version number for Core config section */
70#define CONFIG_PARAM_VERSION 1.01
71
72/** globals **/
73m64p_handle g_CoreConfig = NULL;
74
75m64p_frame_callback g_FrameCallback = NULL;
76
77int g_MemHasBeenBSwapped = 0; // store byte-swapped flag so we don't swap twice when re-playing game
78int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
79
80/** static (local) variables **/
81static int l_CurrentFrame = 0; // frame counter
82static int l_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
83static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running
84static int l_FrameAdvance = 0; // variable to check if we pause on next frame
85static int l_MainSpeedLimit = 1; // insert delay during vi_interrupt to keep speed at real-time
86
87static osd_message_t *l_msgVol = NULL;
88static osd_message_t *l_msgFF = NULL;
89static osd_message_t *l_msgPause = NULL;
90
91/*********************************************************************************************************
92* static functions
93*/
94
95static const char *get_savepathdefault(const char *configpath)
96{
97 static char path[1024];
98
99 if (!configpath || (strlen(configpath) == 0)) {
100 snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]);
101 path[1023] = 0;
102 } else {
103 snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]);
104 path[1023] = 0;
105 }
106
107 /* create directory if it doesn't exist */
108 osal_mkdirp(path, 0700);
109
110 return path;
111}
112
113
114/*********************************************************************************************************
115* helper functions
116*/
117
118
119const char *get_savestatepath(void)
120{
121 /* try to get the SaveStatePath string variable in the Core configuration section */
122 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath"));
123}
124
125const char *get_savesrampath(void)
126{
127 /* try to get the SaveSRAMPath string variable in the Core configuration section */
128 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath"));
129}
130
131void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...)
132{
133 va_list ap;
134 char buffer[2049];
135 va_start(ap, format);
136 vsnprintf(buffer, 2047, format, ap);
137 buffer[2048]='\0';
138 va_end(ap);
139
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);
145}
146
147
148/*********************************************************************************************************
149* global functions, for adjusting the core emulator behavior
150*/
151
152int main_set_core_defaults(void)
153{
154 float fConfigParamsVersion;
155 int bSaveConfig = 0, bUpgrade = 0;
156
157 if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
158 {
159 DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults.");
160 ConfigDeleteSection("Core");
161 ConfigOpenSection("Core", &g_CoreConfig);
162 bSaveConfig = 1;
163 }
164 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
165 {
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);
169 bSaveConfig = 1;
170 }
171 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
172 {
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);
176 bUpgrade = 1;
177 bSaveConfig = 1;
178 }
179
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");
183#if defined(DYNAREC)
184 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
185#else
186 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
187#endif
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");
197
198 /* handle upgrades */
199 if (bUpgrade)
200 {
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);
206 }
207 }
208
209 if (bSaveConfig)
210 ConfigSaveSection("Core");
211
212 /* set config parameters for keyboard and joystick commands */
213 return event_set_core_defaults();
214}
215
216void main_speeddown(int percent)
217{
218 if (l_SpeedFactor - percent > 10) /* 10% minimum speed */
219 {
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);
224 }
225}
226
227void main_speedup(int percent)
228{
229 if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
230 {
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);
235 }
236}
237
238static void main_speedset(int percent)
239{
240 if (percent < 1 || percent > 1000)
241 {
242 DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent);
243 return;
244 }
245 // disable fast-forward if it's enabled
246 main_set_fastforward(0);
247 // set speed
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);
252}
253
254void main_set_fastforward(int enable)
255{
256 static int ff_state = 0;
257 static int SavedSpeedFactor = 100;
258
259 if (enable && !ff_state)
260 {
261 ff_state = 1; /* activate fast-forward */
262 SavedSpeedFactor = l_SpeedFactor;
263 l_SpeedFactor = 250;
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);
270 }
271 else if (!enable && ff_state)
272 {
273 ff_state = 0; /* de-activate fast-forward */
274 l_SpeedFactor = SavedSpeedFactor;
275 audio.setSpeedFactor(l_SpeedFactor);
276 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
277 // remove message
278 osd_delete_message(l_msgFF);
279 l_msgFF = NULL;
280 }
281
282}
283
284static void main_set_speedlimiter(int enable)
285{
286 l_MainSpeedLimit = enable ? 1 : 0;
287}
288
289static int main_is_paused(void)
290{
291 return (g_EmulatorRunning && rompause);
292}
293
294void main_toggle_pause(void)
295{
296 if (!g_EmulatorRunning)
297 return;
298
299 if (rompause)
300 {
301 DebugMessage(M64MSG_STATUS, "Emulation continued.");
302 if(l_msgPause)
303 {
304 osd_delete_message(l_msgPause);
305 l_msgPause = NULL;
306 }
307 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
308 }
309 else
310 {
311 if(l_msgPause)
312 osd_delete_message(l_msgPause);
313
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);
319 }
320
321 rompause = !rompause;
322 l_FrameAdvance = 0;
323}
324
325void main_advance_one(void)
326{
327 l_FrameAdvance = 1;
328 rompause = 0;
329 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
330}
331
332static void main_draw_volume_osd(void)
333{
334 char msgString[64];
335 const char *volString;
336
337 // this calls into the audio plugin
338 volString = audio.volumeGetString();
339 if (volString == NULL)
340 {
341 strcpy(msgString, "Volume Not Supported.");
342 }
343 else
344 {
345 sprintf(msgString, "%s: %s", "Volume", volString);
346 }
347
348 // create a new message or update an existing one
349 if (l_msgVol != NULL)
350 osd_update_message(l_msgVol, "%s", msgString);
351 else {
352 l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString);
353 osd_message_set_user_managed(l_msgVol);
354 }
355}
356
357/* this function could be called as a result of a keypress, joystick/button movement,
358 LIRC command, or 'testshots' command-line option timer */
359void main_take_next_screenshot(void)
360{
361 l_TakeScreenshot = l_CurrentFrame + 1;
362}
363
364void main_state_set_slot(int slot)
365{
366 if (slot < 0 || slot > 9)
367 {
368 DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot(). Using 0", slot);
369 slot = 0;
370 }
371
372 savestates_select_slot(slot);
373 StateChanged(M64CORE_SAVESTATE_SLOT, slot);
374}
375
376void main_state_inc_slot(void)
377{
378 savestates_inc_slot();
379}
380
381static 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};
386
387void main_state_load(const char *filename)
388{
389 input.controllerCommand(0, StopRumble);
390 input.controllerCommand(1, StopRumble);
391 input.controllerCommand(2, StopRumble);
392 input.controllerCommand(3, StopRumble);
393
394 if (filename == NULL) // Save to slot
395 savestates_set_job(savestates_job_load, savestates_type_m64p, NULL);
396 else
397 savestates_set_job(savestates_job_load, savestates_type_unknown, filename);
398}
399
400void main_state_save(int format, const char *filename)
401{
402 if (filename == NULL) // Save to slot
403 savestates_set_job(savestates_job_save, savestates_type_m64p, NULL);
404 else // Save to file
405 savestates_set_job(savestates_job_save, (savestates_type)format, filename);
406}
407
408m64p_error main_core_state_query(m64p_core_param param, int *rval)
409{
410 switch (param)
411 {
412 case M64CORE_EMU_STATE:
413 if (!g_EmulatorRunning)
414 *rval = M64EMU_STOPPED;
415 else if (rompause)
416 *rval = M64EMU_PAUSED;
417 else
418 *rval = M64EMU_RUNNING;
419 break;
420 case M64CORE_VIDEO_MODE:
421 if (!VidExt_VideoRunning())
422 *rval = M64VIDEO_NONE;
423 else if (VidExt_InFullscreenMode())
424 *rval = M64VIDEO_FULLSCREEN;
425 else
426 *rval = M64VIDEO_WINDOWED;
427 break;
428 case M64CORE_SAVESTATE_SLOT:
429 *rval = savestates_get_slot();
430 break;
431 case M64CORE_SPEED_FACTOR:
432 *rval = l_SpeedFactor;
433 break;
434 case M64CORE_SPEED_LIMITER:
435 *rval = l_MainSpeedLimit;
436 break;
437 case M64CORE_VIDEO_SIZE:
438 {
439 int width, height;
440 if (!g_EmulatorRunning)
441 return M64ERR_INVALID_STATE;
442 main_get_screen_size(&width, &height);
443 *rval = (width << 16) + height;
444 break;
445 }
446 case M64CORE_AUDIO_VOLUME:
447 {
448 if (!g_EmulatorRunning)
449 return M64ERR_INVALID_STATE;
450 return main_volume_get_level(rval);
451 }
452 case M64CORE_AUDIO_MUTE:
453 *rval = main_volume_get_muted();
454 break;
455 case M64CORE_INPUT_GAMESHARK:
456 *rval = event_gameshark_active();
457 break;
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;
462 default:
463 return M64ERR_INPUT_INVALID;
464 }
465
466 return M64ERR_SUCCESS;
467}
468
469m64p_error main_core_state_set(m64p_core_param param, int val)
470{
471 switch (param)
472 {
473 case M64CORE_EMU_STATE:
474 if (!g_EmulatorRunning)
475 return M64ERR_INVALID_STATE;
476 if (val == M64EMU_STOPPED)
477 {
478 /* this stop function is asynchronous. The emulator may not terminate until later */
479 main_stop();
480 return M64ERR_SUCCESS;
481 }
482 else if (val == M64EMU_RUNNING)
483 {
484 if (main_is_paused())
485 main_toggle_pause();
486 return M64ERR_SUCCESS;
487 }
488 else if (val == M64EMU_PAUSED)
489 {
490 if (!main_is_paused())
491 main_toggle_pause();
492 return M64ERR_SUCCESS;
493 }
494 return M64ERR_INPUT_INVALID;
495 case M64CORE_VIDEO_MODE:
496 if (!g_EmulatorRunning)
497 return M64ERR_INVALID_STATE;
498 if (val == M64VIDEO_WINDOWED)
499 {
500 if (VidExt_InFullscreenMode())
501 gfx.changeWindow();
502 return M64ERR_SUCCESS;
503 }
504 else if (val == M64VIDEO_FULLSCREEN)
505 {
506 if (!VidExt_InFullscreenMode())
507 gfx.changeWindow();
508 return M64ERR_SUCCESS;
509 }
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;
519 main_speedset(val);
520 return M64ERR_SUCCESS;
521 case M64CORE_SPEED_LIMITER:
522 main_set_speedlimiter(val);
523 return M64ERR_SUCCESS;
524 case M64CORE_VIDEO_SIZE:
525 {
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
528 int width, height;
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;
537 }
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;
557 default:
558 return M64ERR_INPUT_INVALID;
559 }
560}
561
562m64p_error main_get_screen_size(int *width, int *height)
563{
564 gfx.readScreen(NULL, width, height, 0);
565 return M64ERR_SUCCESS;
566}
567
568m64p_error main_read_screen(void *pixels, int bFront)
569{
570 int width_trash, height_trash;
571 gfx.readScreen(pixels, &width_trash, &height_trash, bFront);
572 return M64ERR_SUCCESS;
573}
574
575m64p_error main_volume_up(void)
576{
577 int level = 0;
578 audio.volumeUp();
579 main_draw_volume_osd();
580 main_volume_get_level(&level);
581 StateChanged(M64CORE_AUDIO_VOLUME, level);
582 return M64ERR_SUCCESS;
583}
584
585m64p_error main_volume_down(void)
586{
587 int level = 0;
588 audio.volumeDown();
589 main_draw_volume_osd();
590 main_volume_get_level(&level);
591 StateChanged(M64CORE_AUDIO_VOLUME, level);
592 return M64ERR_SUCCESS;
593}
594
595m64p_error main_volume_get_level(int *level)
596{
597 *level = audio.volumeGetLevel();
598 return M64ERR_SUCCESS;
599}
600
601m64p_error main_volume_set_level(int level)
602{
603 audio.volumeSetLevel(level);
604 main_draw_volume_osd();
605 level = audio.volumeGetLevel();
606 StateChanged(M64CORE_AUDIO_VOLUME, level);
607 return M64ERR_SUCCESS;
608}
609
610m64p_error main_volume_mute(void)
611{
612 audio.volumeMute();
613 main_draw_volume_osd();
614 StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted());
615 return M64ERR_SUCCESS;
616}
617
618int main_volume_get_muted(void)
619{
620 return (audio.volumeGetLevel() == 0);
621}
622
623m64p_error main_reset(int do_hard_reset)
624{
625 if (do_hard_reset)
626 reset_hard_job |= 1;
627 else
628 reset_soft();
629 return M64ERR_SUCCESS;
630}
631
632/*********************************************************************************************************
633* global functions, callbacks from the r4300 core or from other plugins
634*/
635
636static void video_plugin_render_callback(int bScreenRedrawn)
637{
638 int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay");
639
640 // if the flag is set to take a screenshot, then grab it now
641 if (l_TakeScreenshot != 0)
642 {
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)
646 {
647 TakeScreenshot(l_TakeScreenshot - 1); // current frame number +1 is in l_TakeScreenshot
648 l_TakeScreenshot = 0; // reset flag
649 }
650 }
651
652 // if the OSD is enabled, then draw it now
653 if (bOSD)
654 {
655 osd_render();
656 }
657}
658
659void new_frame(void)
660{
661 if (g_FrameCallback != NULL)
662 (*g_FrameCallback)(l_CurrentFrame);
663
664 /* advance the current frame */
665 l_CurrentFrame++;
666
667 if (l_FrameAdvance) {
668 rompause = 1;
669 l_FrameAdvance = 0;
670 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
671 }
672}
673
674void new_vi(void)
675{
676 int Dif;
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;
682
683 double VILimitMilliseconds = 1000.0 / ROM_PARAMS.vilimit;
684 double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor; // adjust for selected emulator speed
685 int time;
686
687 start_section(IDLE_SECTION);
688 VI_Counter++;
689
690#ifdef DBG
691 if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0);
692#endif
693
694 if(LastFPSTime == 0)
695 {
696 LastFPSTime = CounterTime = SDL_GetTicks();
697 return;
698 }
699 CurrentFPSTime = SDL_GetTicks();
700
701 Dif = CurrentFPSTime - LastFPSTime;
702
703 if (Dif < AdjustedLimit)
704 {
705 CalculatedTime = (unsigned int) (CounterTime + AdjustedLimit * VI_Counter);
706 time = (int)(CalculatedTime - CurrentFPSTime);
707 if (time > 0 && l_MainSpeedLimit)
708 {
709 DebugMessage(M64MSG_VERBOSE, " new_vi(): Waiting %ims", time);
710 SDL_Delay(time);
711 }
712 CurrentFPSTime = CurrentFPSTime + time;
713 }
714
715 if (CurrentFPSTime - CounterTime >= 1000.0 )
716 {
717 CounterTime = SDL_GetTicks();
718 VI_Counter = 0 ;
719 }
720
721 LastFPSTime = CurrentFPSTime ;
722 end_section(IDLE_SECTION);
723}
724
725/*********************************************************************************************************
726* emulation thread - runs the core
727*/
728m64p_error main_run(void)
729{
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");
732
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");
737
738 // initialize memory, and do byte-swapping if it's not been done yet
739 if (g_MemHasBeenBSwapped == 0)
740 {
741 init_memory(1);
742 g_MemHasBeenBSwapped = 1;
743 }
744 else
745 {
746 init_memory(0);
747 }
748 // Attach rom to plugins
749 if (!gfx.romOpen())
750 {
751 free_memory(); return M64ERR_PLUGIN_FAIL;
752 }
753 if (!audio.romOpen())
754 {
755 gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
756 }
757 if (!input.romOpen())
758 {
759 audio.romClosed(); gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
760 }
761
762
763 /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */
764 event_initialize();
765
766 /* initialize the on-screen display */
767 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
768 {
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);
773 }
774
775 // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
776 gfx.setRenderingCallback(video_plugin_render_callback);
777
778#ifdef WITH_LIRC
779 lircStart();
780#endif // WITH_LIRC
781
782#ifdef DBG
783 if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger"))
784 init_debugger();
785#endif
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 */
791 r4300_reset_hard();
792 r4300_reset_soft();
793 r4300_execute();
794
795 /* now begin to shut down */
796#ifdef WITH_LIRC
797 lircStop();
798#endif // WITH_LIRC
799
800#ifdef DBG
801 if (g_DebuggerActive)
802 destroy_debugger();
803#endif
804
805 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
806 {
807 osd_exit();
808 }
809
810 rsp.romClosed();
811 input.romClosed();
812 audio.romClosed();
813 gfx.romClosed();
814 free_memory();
815
816 // clean up
817 g_EmulatorRunning = 0;
818 StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED);
819
820 return M64ERR_SUCCESS;
821}
822
823void main_stop(void)
824{
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)
828 return;
829
830 DebugMessage(M64MSG_STATUS, "Stopping emulation.");
831 if(l_msgPause)
832 {
833 osd_delete_message(l_msgPause);
834 l_msgPause = NULL;
835 }
836 if(l_msgFF)
837 {
838 osd_delete_message(l_msgFF);
839 l_msgFF = NULL;
840 }
841 if(l_msgVol)
842 {
843 osd_delete_message(l_msgVol);
844 l_msgVol = NULL;
845 }
846 if (rompause)
847 {
848 rompause = 0;
849 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
850 }
851 stop = 1;
852#ifdef DBG
853 if(g_DebuggerActive)
854 {
855 debugger_step();
856 }
857#endif
858}
859
860/*********************************************************************************************************
861* main function
862*/
863int main(int argc, char *argv[])
864{
865 return 1;
866}
867