~ubuntu-branches/ubuntu/quantal/mupen64plus/quantal

« back to all changes in this revision

Viewing changes to .pc/xdg-basedir.patch/main/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Sven Eckelmann, Sven Eckelmann, Piotr Ożarowski
  • Date: 2010-05-06 11:34:46 UTC
  • mfrom: (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20100506113446-jfcd6uk7waudel82
Tags: 1.5+dfsg1-10
[ Sven Eckelmann ]
* debian/patches:
  - Add rsp_ucode2_reset.patch, Reset status of specific ucode2 hacks after
    starting again
  - Add rsp_hle_bigendian.patch, Fix wrong high level emulation of rsp on big
    endian systems
  - Add rice-crash-vendorstring.patch, Don't crash on long OpenGL vendor
    string (Closes: #580480, LP: #575968)

[ Piotr Ożarowski ]
* DMUA flag set to yes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
2
 *   Mupen64plus - main.c                                                  *
 
3
 *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
 
4
 *   Copyright (C) 2008 Richard42 Ebenblues Nmn Okaygo Tillin9             *
 
5
 *   Copyright (C) 2002 Hacktarux                                          *
 
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 is MUPEN64's main entry point. It contains code that is common
 
24
 * to both the gui and non-gui versions of mupen64. See
 
25
 * gui subdirectories for the gui-specific code.
 
26
 * if you want to implement an interface, you should look here
 
27
 */
 
28
 
 
29
#ifdef __APPLE__
 
30
#include <CoreFoundation/CoreFoundation.h>
 
31
#define _7ZIP_UINT32_DEFINED // avoid stupid conflicts between native types and 7zip types
 
32
#endif
 
33
 
 
34
#ifndef __WIN32__
 
35
# include <ucontext.h> // extra signal types (for portability)
 
36
# include <libgen.h> // basename, dirname
 
37
#endif
 
38
 
 
39
#include <sys/time.h>
 
40
#include <sys/stat.h> /* mkdir() */
 
41
#include <errno.h>
 
42
#include <stdio.h>
 
43
#include <string.h>
 
44
#include <unistd.h>  // POSIX macros and standard types.
 
45
#include <signal.h> // signals
 
46
#include <getopt.h> // getopt_long
 
47
#include <dirent.h>
 
48
 
 
49
#include <png.h>    // for writing screenshot PNG files
 
50
 
 
51
#include <SDL.h>
 
52
#include <SDL_thread.h>
 
53
 
 
54
#include "main.h"
 
55
#include "version.h"
 
56
#include "config.h"
 
57
#include "plugin.h"
 
58
#include "rom.h"
 
59
#include "romcache.h"
 
60
#include "savestates.h"
 
61
#include "util.h"
 
62
#include "translate.h"
 
63
#include "cheat.h"
 
64
 
 
65
#include "../r4300/r4300.h"
 
66
#include "../r4300/recomph.h"
 
67
#include "../r4300/interupt.h"
 
68
 
 
69
#include "../memory/memory.h"
 
70
 
 
71
#include "../opengl/osd.h"
 
72
#include "../opengl/screenshot.h"
 
73
 
 
74
#ifndef NO_GUI
 
75
#include "gui.h"
 
76
#endif
 
77
 
 
78
#ifdef DBG
 
79
#include <glib.h>
 
80
#include "../debugger/debugger.h"
 
81
#endif
 
82
 
 
83
#ifdef WITH_LIRC
 
84
#include "lirc.h"
 
85
#endif //WITH_LIRC
 
86
 
 
87
#ifdef __APPLE__
 
88
// dynamic data path detection onmac
 
89
bool macSetBundlePath(char* buffer)
 
90
{
 
91
    printf("checking whether we are using an app bundle... ");
 
92
    // the following code will enable mupen to find its plugins when placed in an app bundle on mac OS X.
 
93
    // returns true if path is set, returns false if path was not set
 
94
    char path[1024];
 
95
    CFBundleRef main_bundle = CFBundleGetMainBundle(); assert(main_bundle);
 
96
    CFURLRef main_bundle_URL = CFBundleCopyBundleURL(main_bundle); assert(main_bundle_URL);
 
97
    CFStringRef cf_string_ref = CFURLCopyFileSystemPath( main_bundle_URL, kCFURLPOSIXPathStyle); assert(cf_string_ref);
 
98
    CFStringGetCString(cf_string_ref, path, 1024, kCFStringEncodingASCII);
 
99
    CFRelease(main_bundle_URL);
 
100
    CFRelease(cf_string_ref);
 
101
    
 
102
    if(strstr( path, ".app" ) != 0)
 
103
    {
 
104
        printf("yes\n");
 
105
        // executable is inside an app bundle, use app bundle-relative paths
 
106
        sprintf(buffer, "%s/Contents/Resources/", path);
 
107
        return true;
 
108
    }
 
109
    else
 
110
    {
 
111
        printf("no\n");
 
112
        return false;
 
113
    }
 
114
}
 
115
#endif
 
116
 
 
117
/** function prototypes **/
 
118
static void parseCommandLine(int argc, char **argv);
 
119
static int emulationThread( void *_arg );
 
120
extern int rom_cache_system( void *_arg );
 
121
 
 
122
 
 
123
#ifdef __WIN32__
 
124
static void sighandler( int signal );
 
125
#else
 
126
static void sighandler( int signal, siginfo_t *info, void *context );
 
127
#endif
 
128
 
 
129
/** threads **/
 
130
SDL_Thread * g_EmulationThread;         // core thread handle
 
131
SDL_Thread * g_RomCacheThread;          // rom cache thread handle
 
132
 
 
133
/** globals **/
 
134
int         g_Noask = 0;                // don't ask to force load on bad dumps
 
135
int         g_NoaskParam = 0;           // was --noask passed at the commandline?
 
136
int         g_MemHasBeenBSwapped = 0;   // store byte-swapped flag so we don't swap twice when re-playing game
 
137
int         g_EmulatorRunning = 0;      // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
 
138
int         g_OsdEnabled = 1;           // On Screen Display enabled?
 
139
int         g_Fullscreen = 0;           // fullscreen enabled?
 
140
int         g_TakeScreenshot = 0;       // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
 
141
 
 
142
char        *g_GfxPlugin = NULL;        // pointer to graphics plugin specified at commandline (if any)
 
143
char        *g_AudioPlugin = NULL;      // pointer to audio plugin specified at commandline (if any)
 
144
char        *g_InputPlugin = NULL;      // pointer to input plugin specified at commandline (if any)
 
145
char        *g_RspPlugin = NULL;        // pointer to rsp plugin specified at commandline (if any)
 
146
 
 
147
/** static (local) variables **/
 
148
#ifdef NO_GUI
 
149
static int  l_GuiEnabled = 0;           // GUI enabled?
 
150
#else
 
151
static int  l_GuiEnabled = 1;           // GUI enabled?
 
152
#endif
 
153
 
 
154
static char l_ConfigDir[PATH_MAX] = {'\0'};
 
155
static char l_InstallDir[PATH_MAX] = {'\0'};
 
156
 
 
157
static int   l_EmuMode = 0;              // emumode specified at commandline?
 
158
static int   l_CurrentFrame = 0;         // frame counter
 
159
static int  *l_TestShotList = NULL;      // list of screenshots to take for regression test support
 
160
static int   l_TestShotIdx = 0;          // index of next screenshot frame in list
 
161
static char *l_Filename = NULL;          // filename to load & run at startup (if given at command line)
 
162
static int   l_RomNumber = 0;            // rom number in archive (if given at command line)
 
163
static int   l_SpeedFactor = 100;        // percentage of nominal game speed at which emulator is running
 
164
static int   l_FrameAdvance = 0;         // variable to check if we pause on next frame
 
165
 
 
166
static osd_message_t *l_volMsg = NULL;
 
167
 
 
168
/*********************************************************************************************************
 
169
* exported gui funcs
 
170
*/
 
171
char *get_configpath()
 
172
{
 
173
    return l_ConfigDir;
 
174
}
 
175
 
 
176
char *get_installpath()
 
177
{
 
178
    return l_InstallDir;
 
179
}
 
180
 
 
181
char *get_savespath()
 
182
{
 
183
    static char path[PATH_MAX];
 
184
    strncpy(path, get_configpath(), PATH_MAX-5);
 
185
    strcat(path, "save/");
 
186
    return path;
 
187
}
 
188
 
 
189
char *get_iconspath()
 
190
{
 
191
    static char path[PATH_MAX];
 
192
    strncpy(path, get_installpath(), PATH_MAX-6);
 
193
    strcat(path, "icons/");
 
194
    return path;
 
195
}
 
196
 
 
197
char *get_iconpath(const char *iconfile)
 
198
{
 
199
    static char path[PATH_MAX];
 
200
    strncpy(path, get_iconspath(), PATH_MAX-strlen(iconfile));
 
201
    strcat(path, iconfile);
 
202
    return path;
 
203
}
 
204
 
 
205
int gui_enabled(void)
 
206
{
 
207
    return l_GuiEnabled;
 
208
}
 
209
 
 
210
void main_message(unsigned int console, unsigned int statusbar, unsigned int osd, unsigned int osd_corner, const char *format, ...)
 
211
{
 
212
    va_list ap;
 
213
    char buffer[2049];
 
214
    va_start(ap, format);
 
215
    vsnprintf(buffer, 2047, format, ap);
 
216
    buffer[2048]='\0';
 
217
    va_end(ap);
 
218
 
 
219
    if (g_OsdEnabled && osd)
 
220
        osd_new_message(osd_corner, buffer);
 
221
#ifndef NO_GUI
 
222
    if (l_GuiEnabled && statusbar)
 
223
        gui_message(GUI_MESSAGE_INFO, buffer);
 
224
#endif
 
225
    if (console)
 
226
        printf("%s\n", buffer);
 
227
}
 
228
 
 
229
void error_message(const char *format, ...)
 
230
{
 
231
    va_list ap;
 
232
    char buffer[2049];
 
233
    va_start(ap, format);
 
234
    vsnprintf(buffer, 2047, format, ap);
 
235
    buffer[2048]='\0';
 
236
    va_end(ap);
 
237
 
 
238
#ifndef NO_GUI
 
239
    if (l_GuiEnabled)
 
240
        gui_message(GUI_MESSAGE_ERROR, buffer);
 
241
#endif
 
242
    printf("%s: %s\n", tr("Error"), buffer);
 
243
}
 
244
 
 
245
 
 
246
/*********************************************************************************************************
 
247
* timer functions
 
248
*/
 
249
static float VILimit = 60.0;
 
250
static double VILimitMilliseconds = 1000.0/60.0;
 
251
 
 
252
static int GetVILimit(void)
 
253
{
 
254
    switch (ROM_HEADER->Country_code&0xFF)
 
255
    {
 
256
        // PAL codes
 
257
        case 0x44:
 
258
        case 0x46:
 
259
        case 0x49:
 
260
        case 0x50:
 
261
        case 0x53:
 
262
        case 0x55:
 
263
        case 0x58:
 
264
        case 0x59:
 
265
            return 50;
 
266
            break;
 
267
 
 
268
        // NTSC codes
 
269
        case 0x37:
 
270
        case 0x41:
 
271
        case 0x45:
 
272
        case 0x4a:
 
273
            return 60;
 
274
            break;
 
275
 
 
276
        // Fallback for unknown codes
 
277
        default:
 
278
            return 60;
 
279
    }
 
280
}
 
281
 
 
282
static unsigned int gettimeofday_msec(void)
 
283
{
 
284
    unsigned int foo;
 
285
#if defined(__WIN32__)
 
286
    FILETIME ft;
 
287
    unsigned __int64 tmpres = 0;
 
288
    GetSystemTimeAsFileTime(&ft);
 
289
    tmpres |= ft.dwHighDateTime;
 
290
    tmpres <<= 32;
 
291
    tmpres |= ft.dwLowDateTime;
 
292
    foo = (((tmpres / 1000000UL) % 1000000) * 1000) + (tmpres % 1000000UL / 1000);
 
293
#else
 
294
    struct timeval tv;
 
295
 
 
296
    gettimeofday(&tv, NULL);
 
297
    foo = ((tv.tv_sec % 1000000) * 1000) + (tv.tv_usec / 1000);
 
298
#endif
 
299
    return foo;
 
300
}
 
301
 
 
302
/*********************************************************************************************************
 
303
* global functions, for adjusting the core emulator behavior
 
304
*/
 
305
 
 
306
void main_speeddown(int percent)
 
307
{
 
308
    if (l_SpeedFactor - percent > 10)  /* 10% minimum speed */
 
309
    {
 
310
        l_SpeedFactor -= percent;
 
311
        main_message(0, 1, 1, OSD_BOTTOM_LEFT, "%s %d%%", tr("Playback speed:"), l_SpeedFactor);
 
312
        setSpeedFactor(l_SpeedFactor);  // call to audio plugin
 
313
    }
 
314
}
 
315
 
 
316
void main_speedup(int percent)
 
317
{
 
318
    if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
 
319
    {
 
320
        l_SpeedFactor += percent;
 
321
        main_message(0, 1, 1, OSD_BOTTOM_LEFT, "%s %d%%", tr("Playback speed:"), l_SpeedFactor);
 
322
        setSpeedFactor(l_SpeedFactor);  // call to audio plugin
 
323
    }
 
324
}
 
325
 
 
326
void main_pause(void)
 
327
{
 
328
    pauseContinueEmulation();
 
329
    l_FrameAdvance = 0;
 
330
}
 
331
 
 
332
void main_advance_one(void)
 
333
{
 
334
    l_FrameAdvance = 1;
 
335
    rompause = 0;
 
336
}
 
337
 
 
338
void main_draw_volume_osd(void)
 
339
{
 
340
    char msgString[32];
 
341
    const char *volString;
 
342
 
 
343
    // if we had a volume message, make sure that it's still in the OSD list, or set it to NULL
 
344
    if (l_volMsg != NULL && !osd_message_valid(l_volMsg))
 
345
        l_volMsg = NULL;
 
346
 
 
347
    // this calls into the audio plugin
 
348
    volString = volumeGetString();
 
349
    if (volString == NULL)
 
350
    {
 
351
        strcpy(msgString, tr("Volume Not Supported."));
 
352
    }
 
353
    else
 
354
    {
 
355
        sprintf(msgString, "%s: %s", tr("Volume"), volString);
 
356
        if (msgString[strlen(msgString) - 1] == '%')
 
357
            strcat(msgString, "%");
 
358
    }
 
359
 
 
360
    // create a new message or update an existing one
 
361
    if (l_volMsg != NULL)
 
362
        osd_update_message(l_volMsg, msgString);
 
363
    else
 
364
        l_volMsg = osd_new_message(OSD_MIDDLE_CENTER, msgString);
 
365
}
 
366
 
 
367
/* this function could be called as a result of a keypress, joystick/button movement,
 
368
   LIRC command, or 'testshots' command-line option timer */
 
369
void take_next_screenshot(void)
 
370
{
 
371
    g_TakeScreenshot = l_CurrentFrame + 1;
 
372
}
 
373
 
 
374
void startEmulation(void)
 
375
{
 
376
    VILimit = GetVILimit();
 
377
    VILimitMilliseconds = (double) 1000.0/VILimit; 
 
378
    printf("init timer!\n");
 
379
 
 
380
    const char *gfx_plugin = NULL,
 
381
               *audio_plugin = NULL,
 
382
               *input_plugin = NULL,
 
383
               *RSP_plugin = NULL;
 
384
 
 
385
    // make sure rom is loaded before running
 
386
    if(!rom)
 
387
    {
 
388
        error_message(tr("There is no Rom loaded."));
 
389
        return;
 
390
    }
 
391
 
 
392
    /* Determine which plugins to use:
 
393
    *  -If valid plugin was specified at the commandline, use it
 
394
    *  -Else, get plugin from config. NOTE: gui code must change config if user switches plugin in the gui)
 
395
    */
 
396
    if(g_GfxPlugin)
 
397
    {
 
398
        gfx_plugin = plugin_name_by_filename(g_GfxPlugin);
 
399
    }
 
400
    else
 
401
    {
 
402
        gfx_plugin = plugin_name_by_filename(config_get_string("Gfx Plugin", ""));
 
403
    }
 
404
 
 
405
    if(!gfx_plugin)
 
406
    {
 
407
        error_message(tr("No graphics plugin specified."));
 
408
        return;
 
409
    }
 
410
 
 
411
    if(g_AudioPlugin)
 
412
        audio_plugin = plugin_name_by_filename(g_AudioPlugin);
 
413
    else
 
414
        audio_plugin = plugin_name_by_filename(config_get_string("Audio Plugin", ""));
 
415
 
 
416
    if(!audio_plugin)
 
417
    {
 
418
        error_message(tr("No audio plugin specified."));
 
419
        return;
 
420
    }
 
421
 
 
422
    if(g_InputPlugin)
 
423
        input_plugin = plugin_name_by_filename(g_InputPlugin);
 
424
    else
 
425
        input_plugin = plugin_name_by_filename(config_get_string("Input Plugin", ""));
 
426
 
 
427
    if(!input_plugin)
 
428
    {
 
429
        error_message(tr("No input plugin specified."));
 
430
        return;
 
431
    }
 
432
 
 
433
    if(g_RspPlugin)
 
434
        RSP_plugin = plugin_name_by_filename(g_RspPlugin);
 
435
    else
 
436
        RSP_plugin = plugin_name_by_filename(config_get_string("RSP Plugin", ""));
 
437
 
 
438
    if(!RSP_plugin)
 
439
    {
 
440
        error_message(tr("No RSP plugin specified."));
 
441
        return;
 
442
    }
 
443
 
 
444
    // load the plugins. Do this outside the emulation thread for GUI
 
445
    // related things which cannot be done outside the main thread.
 
446
    // Examples: GTK Icon theme setup in Rice which otherwise hangs forever
 
447
    // with the Qt4 interface.
 
448
    plugin_load_plugins(gfx_plugin, audio_plugin, input_plugin, RSP_plugin);
 
449
 
 
450
    // in nogui mode, just start the emulator in the main thread
 
451
    if(!l_GuiEnabled)
 
452
    {
 
453
        emulationThread(NULL);
 
454
    }
 
455
    else if(!g_EmulatorRunning)
 
456
    {
 
457
        // spawn emulation thread
 
458
        g_EmulationThread = SDL_CreateThread(emulationThread, NULL);
 
459
        if(g_EmulationThread == NULL)
 
460
        {
 
461
            printf("Unable to create thread: %s\n", SDL_GetError());
 
462
            error_message(tr("Couldn't spawn core thread!"));
 
463
            return;
 
464
        }
 
465
 
 
466
        main_message(0, 1, 0, OSD_BOTTOM_LEFT,  tr("Emulation started (PID: %d)"), g_EmulationThread);
 
467
    }
 
468
    // if emulation is already running, but it's paused, unpause it
 
469
    else if(rompause)
 
470
    {
 
471
        main_pause();
 
472
    }
 
473
}
 
474
 
 
475
void stopEmulation(void)
 
476
{
 
477
    if(g_EmulatorRunning)
 
478
    {
 
479
        main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Stopping emulation.\n"));
 
480
        rompause = 0;
 
481
        stop_it();
 
482
#ifdef DBG
 
483
        if(debugger_mode)
 
484
        {
 
485
            
 
486
            debugger_step();
 
487
        }
 
488
#endif        
 
489
 
 
490
        // wait until emulation thread is done before continuing
 
491
        if(g_EmulatorRunning)
 
492
            SDL_WaitThread(g_EmulationThread, NULL);
 
493
 
 
494
#ifdef __WIN32__
 
495
        plugin_close_plugins();
 
496
#endif
 
497
        g_EmulatorRunning = 0;
 
498
        g_EmulationThread = 0;
 
499
 
 
500
#ifndef NO_GUI
 
501
        gui_set_state(GUI_STATE_STOPPED);
 
502
        g_romcache.rcspause = 0;
 
503
#endif
 
504
 
 
505
        main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Emulation stopped.\n"));
 
506
    }
 
507
}
 
508
 
 
509
int pauseContinueEmulation(void)
 
510
{
 
511
    static osd_message_t *msg = NULL;
 
512
 
 
513
    if (!g_EmulatorRunning)
 
514
        return 1;
 
515
 
 
516
    if (rompause)
 
517
    {
 
518
#ifndef NO_GUI
 
519
        gui_set_state(GUI_STATE_RUNNING);
 
520
        g_romcache.rcspause = 1;
 
521
#endif
 
522
        main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Emulation continued.\n"));
 
523
        if(msg)
 
524
        {
 
525
            osd_delete_message(msg);
 
526
            msg = NULL;
 
527
        }
 
528
    }
 
529
    else
 
530
    {
 
531
#ifndef NO_GUI
 
532
        gui_set_state(GUI_STATE_PAUSED);
 
533
        g_romcache.rcspause = 0;
 
534
#endif
 
535
        if(msg)
 
536
            osd_delete_message(msg);
 
537
 
 
538
        main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Paused\n"));
 
539
        msg = osd_new_message(OSD_MIDDLE_CENTER, tr("Paused\n"));
 
540
        osd_message_set_static(msg);
 
541
    }
 
542
 
 
543
    rompause = !rompause;
 
544
    return rompause;
 
545
}
 
546
 
 
547
/*********************************************************************************************************
 
548
* global functions, callbacks from the r4300 core or from other plugins
 
549
*/
 
550
 
 
551
void video_plugin_render_callback(void)
 
552
{
 
553
    // if the flag is set to take a screenshot, then grab it now
 
554
    if (g_TakeScreenshot != 0)
 
555
    {
 
556
        TakeScreenshot(g_TakeScreenshot - 1);  // current frame number +1 is in g_TakeScreenshot
 
557
        g_TakeScreenshot = 0; // reset flag
 
558
    }
 
559
 
 
560
    // if the OSD is enabled, then draw it now
 
561
    if (g_OsdEnabled)
 
562
    {
 
563
        osd_render();
 
564
    }
 
565
}
 
566
 
 
567
void new_frame(void)
 
568
{
 
569
    // take a screenshot if we need to
 
570
    if (l_TestShotList != NULL)
 
571
    {
 
572
        int nextshot = l_TestShotList[l_TestShotIdx];
 
573
        if (nextshot == l_CurrentFrame)
 
574
        {
 
575
            // set global variable so screenshot will be taken just before OSD is drawn at the end of frame rendering
 
576
            take_next_screenshot();
 
577
            // advance list index to next screenshot frame number.  If it's 0, then quit
 
578
            l_TestShotIdx++;
 
579
        }
 
580
        else if (nextshot == 0)
 
581
        {
 
582
            stopEmulation();
 
583
            free(l_TestShotList);
 
584
            l_TestShotList = NULL;
 
585
        }
 
586
    }
 
587
 
 
588
    // advance the current frame
 
589
    l_CurrentFrame++;
 
590
}
 
591
 
 
592
void new_vi(void)
 
593
{
 
594
    int Dif;
 
595
    unsigned int CurrentFPSTime;
 
596
    static unsigned int LastFPSTime = 0;
 
597
    static unsigned int CounterTime = 0;
 
598
    static unsigned int CalculatedTime ;
 
599
    static int VI_Counter = 0;
 
600
 
 
601
    double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor;  // adjust for selected emulator speed
 
602
    int time;
 
603
 
 
604
    start_section(IDLE_SECTION);
 
605
    VI_Counter++;
 
606
    
 
607
#ifdef DBG
 
608
    if(debugger_mode) debugger_frontend_vi();
 
609
#endif
 
610
 
 
611
    if(LastFPSTime == 0)
 
612
    {
 
613
        LastFPSTime = gettimeofday_msec();
 
614
        CounterTime = gettimeofday_msec();
 
615
        return;
 
616
    }
 
617
    CurrentFPSTime = gettimeofday_msec();
 
618
    
 
619
    Dif = CurrentFPSTime - LastFPSTime;
 
620
    
 
621
    if (Dif < AdjustedLimit) 
 
622
    {
 
623
        CalculatedTime = CounterTime + AdjustedLimit * VI_Counter;
 
624
        time = (int)(CalculatedTime - CurrentFPSTime);
 
625
        if (time > 0)
 
626
        {
 
627
#ifdef __WIN32__
 
628
            Sleep(time);
 
629
#else
 
630
            usleep(time * 1000);
 
631
#endif
 
632
        }
 
633
        CurrentFPSTime = CurrentFPSTime + time;
 
634
    }
 
635
 
 
636
    if (CurrentFPSTime - CounterTime >= 1000.0 ) 
 
637
    {
 
638
        CounterTime = gettimeofday_msec();
 
639
        VI_Counter = 0 ;
 
640
    }
 
641
    
 
642
    LastFPSTime = CurrentFPSTime ;
 
643
    end_section(IDLE_SECTION);
 
644
    if (l_FrameAdvance) {
 
645
        rompause = 1;
 
646
        l_FrameAdvance = 0;
 
647
    }
 
648
}
 
649
 
 
650
/*********************************************************************************************************
 
651
* sdl event filter
 
652
*/
 
653
static int sdl_event_filter( const SDL_Event *event )
 
654
{
 
655
    static osd_message_t *msgFF = NULL;
 
656
    static int SavedSpeedFactor = 100;
 
657
    static BYTE StopRumble[6] = {0x23, 0x01, 0x03, 0xc0, 0x1b, 0x00};
 
658
    char *event_str = NULL;
 
659
 
 
660
    switch( event->type )
 
661
    {
 
662
        // user clicked on window close button
 
663
        case SDL_QUIT:
 
664
            stopEmulation();
 
665
            break;
 
666
        case SDL_KEYDOWN:
 
667
            /* check for the only 2 hard-coded key commands: Alt-enter for fullscreen and 0-9 for save state slot */
 
668
            if (event->key.keysym.sym == SDLK_RETURN && event->key.keysym.mod & (KMOD_LALT | KMOD_RALT))
 
669
            {
 
670
                changeWindow();
 
671
            }
 
672
            else if (event->key.keysym.unicode >= '0' && event->key.keysym.unicode <= '9')
 
673
            {
 
674
                savestates_select_slot( event->key.keysym.unicode - '0' );
 
675
            }
 
676
            /* check all of the configurable commands */
 
677
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Stop", SDLK_ESCAPE))
 
678
                stopEmulation();
 
679
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Fullscreen", 0))
 
680
                changeWindow();
 
681
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Save State", SDLK_F5))
 
682
                savestates_job |= SAVESTATE;
 
683
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Load State", SDLK_F7))
 
684
            {
 
685
                savestates_job |= LOADSTATE;
 
686
                controllerCommand(0, StopRumble);
 
687
                controllerCommand(1, StopRumble);
 
688
                controllerCommand(2, StopRumble);
 
689
                controllerCommand(3, StopRumble);
 
690
            }
 
691
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Increment Slot", 0))
 
692
                savestates_inc_slot();
 
693
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Reset", SDLK_F9))
 
694
            {
 
695
                add_interupt_event(HW2_INT, 0);  /* Hardware 2 Interrupt immediately */
 
696
                add_interupt_event(NMI_INT, 50000000);  /* Non maskable Interrupt after 1/2 second */
 
697
            }
 
698
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Speed Down", SDLK_F10))
 
699
                main_speeddown(5);
 
700
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Speed Up",SDLK_F11))
 
701
                main_speedup(5);
 
702
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Screenshot", SDLK_F12))
 
703
                // set flag so that screenshot will be taken at the end of frame rendering
 
704
                take_next_screenshot();
 
705
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Pause", SDLK_p))
 
706
                main_pause();
 
707
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Mute", SDLK_m))
 
708
            {
 
709
                volumeMute();
 
710
                main_draw_volume_osd();
 
711
            }
 
712
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Increase Volume", SDLK_RIGHTBRACKET))
 
713
            {
 
714
                volumeUp();
 
715
                main_draw_volume_osd();
 
716
            }
 
717
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Decrease Volume", SDLK_LEFTBRACKET))
 
718
            {
 
719
                volumeDown();
 
720
                main_draw_volume_osd();
 
721
            }
 
722
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Fast Forward", SDLK_f))
 
723
            {
 
724
                SavedSpeedFactor = l_SpeedFactor;
 
725
                l_SpeedFactor = 250;
 
726
                setSpeedFactor(l_SpeedFactor);  // call to audio plugin
 
727
                // set fast-forward indicator
 
728
                msgFF = osd_new_message(OSD_TOP_RIGHT, tr("Fast Forward"));
 
729
                osd_message_set_static(msgFF);
 
730
            }
 
731
            else if (event->key.keysym.sym == config_get_number("Kbd Mapping Frame Advance", SDLK_SLASH))
 
732
                main_advance_one();
 
733
            // pass all other keypresses to the input plugin
 
734
            else keyDown( 0, event->key.keysym.sym );
 
735
 
 
736
            return 0;
 
737
 
 
738
        case SDL_KEYUP:
 
739
            if(event->key.keysym.sym == config_get_number("Kbd Mapping Stop", SDLK_ESCAPE))
 
740
            {
 
741
                return 0;
 
742
            }
 
743
            else if(event->key.keysym.sym == config_get_number("Kbd Mapping Fast Forward", SDLK_f))
 
744
            {
 
745
                // cancel fast-forward
 
746
                l_SpeedFactor = SavedSpeedFactor;
 
747
                setSpeedFactor(l_SpeedFactor);  // call to audio plugin
 
748
                // remove message
 
749
                osd_delete_message(msgFF);
 
750
            }
 
751
            else keyUp( 0, event->key.keysym.sym );
 
752
 
 
753
            return 0;
 
754
 
 
755
        // if joystick action is detected, check if it's mapped to a special function
 
756
        case SDL_JOYAXISMOTION:
 
757
            // axis events have to be above a certain threshold to be valid
 
758
            if(event->jaxis.value > -15000 && event->jaxis.value < 15000)
 
759
                break;
 
760
        case SDL_JOYBUTTONDOWN:
 
761
        case SDL_JOYHATMOTION:
 
762
            event_str = event_to_str(event);
 
763
 
 
764
            if(!event_str) return 0;
 
765
 
 
766
            if(strcmp(event_str, config_get_string("Joy Mapping Fullscreen", "")) == 0)
 
767
                changeWindow();
 
768
            else if(strcmp(event_str, config_get_string("Joy Mapping Stop", "")) == 0)
 
769
                stopEmulation();
 
770
            else if(strcmp(event_str, config_get_string("Joy Mapping Pause", "")) == 0)
 
771
                main_pause();
 
772
            else if(strcmp(event_str, config_get_string("Joy Mapping Save State", "")) == 0)
 
773
                savestates_job |= SAVESTATE;
 
774
            else if(strcmp(event_str, config_get_string("Joy Mapping Load State", "")) == 0)
 
775
                savestates_job |= LOADSTATE;
 
776
            else if(strcmp(event_str, config_get_string("Joy Mapping Increment Slot", "")) == 0)
 
777
                savestates_inc_slot();
 
778
            else if(strcmp(event_str, config_get_string("Joy Mapping Screenshot", "")) == 0)
 
779
                take_next_screenshot();
 
780
            else if(strcmp(event_str, config_get_string("Joy Mapping Mute", "")) == 0)
 
781
            {
 
782
                volumeMute();
 
783
                main_draw_volume_osd();
 
784
            }
 
785
            else if(strcmp(event_str, config_get_string("Joy Mapping Decrease Volume", "")) == 0)
 
786
            {
 
787
                volumeDown();
 
788
                main_draw_volume_osd();
 
789
            }
 
790
            else if(strcmp(event_str, config_get_string("Joy Mapping Increase Volume", "")) == 0)
 
791
            {
 
792
                volumeUp();
 
793
                main_draw_volume_osd();
 
794
            }
 
795
 
 
796
            free(event_str);
 
797
            return 0;
 
798
            break;
 
799
    }
 
800
 
 
801
    return 1;
 
802
}
 
803
 
 
804
/*********************************************************************************************************
 
805
* emulation thread - runs the core
 
806
*/
 
807
static int emulationThread( void *_arg )
 
808
{
 
809
#if !defined(__WIN32__)
 
810
    struct sigaction sa;
 
811
#endif
 
812
    const char *gfx_plugin = NULL,
 
813
               *audio_plugin = NULL,
 
814
           *input_plugin = NULL,
 
815
           *RSP_plugin = NULL;
 
816
 
 
817
    // install signal handler, but only if we're running in GUI mode
 
818
    // in non-GUI mode, we don't need to catch exceptions (there's no GUI to take down)
 
819
    if (l_GuiEnabled)
 
820
    {
 
821
#if defined(__WIN32__)
 
822
        signal( SIGSEGV, sighandler );
 
823
        signal( SIGILL, sighandler );
 
824
        signal( SIGFPE, sighandler );
 
825
#else
 
826
        memset( &sa, 0, sizeof( struct sigaction ) );
 
827
        sa.sa_sigaction = sighandler;
 
828
        sa.sa_flags = SA_SIGINFO;
 
829
        sigaction( SIGSEGV, &sa, NULL );
 
830
        sigaction( SIGILL, &sa, NULL );
 
831
        sigaction( SIGFPE, &sa, NULL );
 
832
        sigaction( SIGCHLD, &sa, NULL );
 
833
#endif 
 
834
    }
 
835
 
 
836
    g_EmulatorRunning = 1;
 
837
    // if emu mode wasn't specified at the commandline, set from config file
 
838
    if(!l_EmuMode)
 
839
        dynacore = config_get_number( "Core", CORE_DYNAREC );
 
840
#ifdef NO_ASM
 
841
    if(dynacore==CORE_DYNAREC)
 
842
        dynacore = CORE_INTERPRETER;
 
843
#endif
 
844
 
 
845
    no_compiled_jump = config_get_bool("NoCompiledJump", FALSE);
 
846
 
 
847
    // init sdl
 
848
    SDL_Init(SDL_INIT_VIDEO);
 
849
    SDL_ShowCursor(0);
 
850
    SDL_EnableKeyRepeat(0, 0);
 
851
 
 
852
    SDL_SetEventFilter(sdl_event_filter);
 
853
    SDL_EnableUNICODE(1);
 
854
 
 
855
    // initialize memory, and do byte-swapping if it's not been done yet
 
856
    if (g_MemHasBeenBSwapped == 0)
 
857
    {
 
858
        init_memory(1);
 
859
        g_MemHasBeenBSwapped = 1;
 
860
    }
 
861
    else
 
862
    {
 
863
        init_memory(0);
 
864
    }
 
865
 
 
866
    // Attach rom to plugins
 
867
    romOpen_gfx();
 
868
    romOpen_audio();
 
869
    romOpen_input();
 
870
 
 
871
    // switch to fullscreen if enabled
 
872
    if (g_Fullscreen)
 
873
        changeWindow();
 
874
 
 
875
    if (g_OsdEnabled)
 
876
    {
 
877
        // init on-screen display
 
878
        void *pvPixels = NULL;
 
879
        int width = 640, height = 480;
 
880
        readScreen(&pvPixels, &width, &height); // read screen to get width and height
 
881
        if (pvPixels != NULL)
 
882
        {
 
883
            free(pvPixels);
 
884
            pvPixels = NULL;
 
885
        }
 
886
        osd_init(width, height);
 
887
    }
 
888
 
 
889
    // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
 
890
    setRenderingCallback(video_plugin_render_callback);
 
891
 
 
892
#ifndef NO_GUI
 
893
    gui_set_state(GUI_STATE_RUNNING);
 
894
    g_romcache.rcspause = 1;
 
895
#endif
 
896
 
 
897
#ifdef WITH_LIRC
 
898
    lircStart();
 
899
#endif // WITH_LIRC
 
900
 
 
901
#ifdef DBG
 
902
    if (g_DebuggerEnabled)
 
903
        init_debugger();
 
904
#endif
 
905
 
 
906
    /* load cheats for the current rom  */
 
907
    cheat_load_current_rom();
 
908
 
 
909
    /* Startup message on the OSD */
 
910
    osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started...");
 
911
 
 
912
    /* call r4300 CPU core and run the game */
 
913
    r4300_reset_hard();
 
914
    r4300_reset_soft();
 
915
    r4300_execute();
 
916
 
 
917
#ifdef WITH_LIRC
 
918
    lircStop();
 
919
#endif // WITH_LIRC
 
920
 
 
921
#ifdef DBG
 
922
    if (debugger_mode)
 
923
        destroy_debugger();
 
924
#endif
 
925
 
 
926
    if (g_OsdEnabled)
 
927
    {
 
928
        osd_exit();
 
929
    }
 
930
 
 
931
    romClosed_RSP();
 
932
    romClosed_input();
 
933
    romClosed_audio();
 
934
    romClosed_gfx();
 
935
    closeDLL_RSP();
 
936
    closeDLL_input();
 
937
    closeDLL_audio();
 
938
    closeDLL_gfx();
 
939
    free_memory();
 
940
 
 
941
    // clean up
 
942
    g_EmulatorRunning = 0;
 
943
 
 
944
    SDL_Quit();
 
945
 
 
946
    return 0;
 
947
}
 
948
 
 
949
/*********************************************************************************************************
 
950
* signal handler
 
951
*/
 
952
#ifdef __WIN32__
 
953
static void sighandler(int signal)
 
954
{
 
955
    printf( "Signal number %d caught\n", signal );
 
956
}
 
957
#else
 
958
static void sighandler(int signal, siginfo_t *info, void *context)
 
959
{
 
960
    SDL_Thread *emuThread = g_EmulationThread;
 
961
 
 
962
    switch( signal )
 
963
    {
 
964
        case SIGSEGV:
 
965
            error_message(tr("The core thread recieved a SIGSEGV signal.\n"
 
966
                            "This means it tried to access protected memory.\n"
 
967
                            "Maybe you have set a wrong ucode for one of the plugins!"));
 
968
            printf( "SIGSEGV in core thread caught:\n" );
 
969
            printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
 
970
            printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
 
971
#ifdef SEGV_MAPERR
 
972
            switch( info->si_code )
 
973
            {
 
974
                case SEGV_MAPERR: printf( "                address not mapped to object\n" ); break;
 
975
                case SEGV_ACCERR: printf( "                invalid permissions for mapped object\n" ); break;
 
976
            }
 
977
#endif
 
978
            break;
 
979
        case SIGILL:
 
980
            printf( "SIGILL in core thread caught:\n" );
 
981
            printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
 
982
            printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
 
983
#ifdef ILL_ILLOPC
 
984
            switch( info->si_code )
 
985
            {
 
986
                case ILL_ILLOPC: printf( "\tillegal opcode\n" ); break;
 
987
                case ILL_ILLOPN: printf( "\tillegal operand\n" ); break;
 
988
                case ILL_ILLADR: printf( "\tillegal addressing mode\n" ); break;
 
989
                case ILL_ILLTRP: printf( "\tillegal trap\n" ); break;
 
990
                case ILL_PRVOPC: printf( "\tprivileged opcode\n" ); break;
 
991
                case ILL_PRVREG: printf( "\tprivileged register\n" ); break;
 
992
                case ILL_COPROC: printf( "\tcoprocessor error\n" ); break;
 
993
                case ILL_BADSTK: printf( "\tinternal stack error\n" ); break;
 
994
            }
 
995
#endif
 
996
            break;
 
997
        case SIGFPE:
 
998
            printf( "SIGFPE in core thread caught:\n" );
 
999
            printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
 
1000
            printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
 
1001
            switch( info->si_code )
 
1002
            {
 
1003
                case FPE_INTDIV: printf( "\tinteger divide by zero\n" ); break;
 
1004
                case FPE_INTOVF: printf( "\tinteger overflow\n" ); break;
 
1005
                case FPE_FLTDIV: printf( "\tfloating point divide by zero\n" ); break;
 
1006
                case FPE_FLTOVF: printf( "\tfloating point overflow\n" ); break;
 
1007
                case FPE_FLTUND: printf( "\tfloating point underflow\n" ); break;
 
1008
                case FPE_FLTRES: printf( "\tfloating point inexact result\n" ); break;
 
1009
                case FPE_FLTINV: printf( "\tfloating point invalid operation\n" ); break;
 
1010
                case FPE_FLTSUB: printf( "\tsubscript out of range\n" ); break;
 
1011
            }
 
1012
            break;
 
1013
        default:
 
1014
            printf( "Signal number %d in core thread caught:\n", signal );
 
1015
            printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
 
1016
    }
 
1017
 
 
1018
    g_EmulationThread = 0;
 
1019
    g_EmulatorRunning = 0;
 
1020
 
 
1021
    if (emuThread != NULL)
 
1022
        SDL_KillThread(emuThread);
 
1023
}
 
1024
#endif /* __WIN32__ */
 
1025
 
 
1026
 
 
1027
static void printUsage(const char *progname)
 
1028
{
 
1029
    char *str = strdup(progname);
 
1030
 
 
1031
    printf("Usage: %s [parameter(s)] [romfile]\n"
 
1032
           "\n"
 
1033
           "Parameters:\n"
 
1034
           "    --nogui               : do not display GUI.\n"
 
1035
           "    --noask               : do not prompt user if rom file is hacked or a bad dump.\n"
 
1036
           "    --noosd               : disable onscreen display.\n"
 
1037
           "    --fullscreen          : turn fullscreen mode on.\n"
 
1038
           "    --romnumber (number)  : specify which rom in romfile, if multirom archive.\n"
 
1039
           "    --gfx (plugin-file)   : use gfx plugin given by (path)\n"
 
1040
           "    --audio (plugin-file) : use audio plugin given by (path)\n"
 
1041
           "    --input (plugin-file) : use input plugin given by (path)\n"
 
1042
           "    --rsp (plugin-file)   : use rsp plugin given by (path)\n"
 
1043
           "    --emumode (mode)      : set emu mode to: 0=Interpreter 1=DynaRec 2=Pure Interpreter\n"
 
1044
           "    --sshotdir (dir)      : set screenshot directory to (dir)\n"
 
1045
           "    --configdir (dir)     : force config dir (must contain mupen64plus.conf)\n"
 
1046
           "    --installdir (dir)    : force install dir (place to look for plugins, icons, lang, etc)\n"
 
1047
           "    --testshots (list)    : take screenshots at frames given in comma-separated (list), then quit\n"
 
1048
#ifdef DBG
 
1049
           "    --debugger            : start with debugger enabled\n"
 
1050
#endif 
 
1051
           "    -h, --help            : see this help message\n"
 
1052
           "\n", str);
 
1053
 
 
1054
    free(str);
 
1055
 
 
1056
    return;
 
1057
}
 
1058
 
 
1059
/* parseCommandLine
 
1060
 *  Parses commandline options and sets global variables accordingly
 
1061
 */
 
1062
void parseCommandLine(int argc, char **argv)
 
1063
{
 
1064
    int i, shots;
 
1065
    char *str = NULL;
 
1066
 
 
1067
    // option parsing vars
 
1068
    int opt, option_index;
 
1069
    enum
 
1070
    {
 
1071
        OPT_GFX = 1,
 
1072
        OPT_AUDIO,
 
1073
        OPT_INPUT,
 
1074
        OPT_RSP,
 
1075
        OPT_EMUMODE,
 
1076
        OPT_SSHOTDIR,
 
1077
        OPT_CONFIGDIR,
 
1078
        OPT_INSTALLDIR,
 
1079
#ifdef DBG
 
1080
    OPT_DEBUGGER,
 
1081
#endif
 
1082
        OPT_NOASK,
 
1083
        OPT_TESTSHOTS,
 
1084
        OPT_ROMNUMBER
 
1085
    };
 
1086
    struct option long_options[] =
 
1087
    {
 
1088
        {"nogui", no_argument, &l_GuiEnabled, FALSE},
 
1089
        {"noosd", no_argument, &g_OsdEnabled, FALSE},
 
1090
        {"fullscreen", no_argument, &g_Fullscreen, TRUE},
 
1091
        {"romnumber", required_argument, NULL, OPT_ROMNUMBER},
 
1092
        {"gfx", required_argument, NULL, OPT_GFX},
 
1093
        {"audio", required_argument, NULL, OPT_AUDIO},
 
1094
        {"input", required_argument, NULL, OPT_INPUT},
 
1095
        {"rsp", required_argument, NULL, OPT_RSP},
 
1096
        {"emumode", required_argument, NULL, OPT_EMUMODE},
 
1097
        {"sshotdir", required_argument, NULL, OPT_SSHOTDIR},
 
1098
        {"configdir", required_argument, NULL, OPT_CONFIGDIR},
 
1099
        {"installdir", required_argument, NULL, OPT_INSTALLDIR},
 
1100
#ifdef DBG
 
1101
        {"debugger", no_argument, NULL, OPT_DEBUGGER},
 
1102
#endif
 
1103
        {"noask", no_argument, NULL, OPT_NOASK},
 
1104
        {"testshots", required_argument, NULL, OPT_TESTSHOTS},
 
1105
        {"help", no_argument, NULL, 'h'},
 
1106
        {0, 0, 0, 0}    // last opt must be empty
 
1107
    };
 
1108
    char opt_str[] = "h";
 
1109
 
 
1110
    /* parse commandline options */
 
1111
    while((opt = getopt_long(argc, argv, opt_str,
 
1112
                 long_options, &option_index)) != -1)
 
1113
    {
 
1114
        switch(opt)
 
1115
        {
 
1116
            // if getopt_long returns 0, it already set the global for us, so do nothing
 
1117
            case 0:
 
1118
                break;
 
1119
            case OPT_GFX:
 
1120
                if(plugin_scan_file(optarg, PLUGIN_TYPE_GFX))
 
1121
                {
 
1122
                    g_GfxPlugin = optarg;
 
1123
                }
 
1124
                else
 
1125
                {
 
1126
                    printf("***Warning: GFX Plugin '%s' couldn't be loaded!\n", optarg);
 
1127
                }
 
1128
                break;
 
1129
            case OPT_AUDIO:
 
1130
                if(plugin_scan_file(optarg, PLUGIN_TYPE_AUDIO))
 
1131
                {
 
1132
                    g_AudioPlugin = optarg;
 
1133
                }
 
1134
                else
 
1135
                {
 
1136
                    printf("***Warning: Audio Plugin '%s' couldn't be loaded!\n", optarg);
 
1137
                }
 
1138
                break;
 
1139
            case OPT_INPUT:
 
1140
                if(plugin_scan_file(optarg, PLUGIN_TYPE_CONTROLLER))
 
1141
                {
 
1142
                    g_InputPlugin = optarg;
 
1143
                }
 
1144
                else
 
1145
                {
 
1146
                    printf("***Warning: Input Plugin '%s' couldn't be loaded!\n", optarg);
 
1147
                }
 
1148
                break;
 
1149
            case OPT_RSP:
 
1150
                if(plugin_scan_file(optarg, PLUGIN_TYPE_RSP))
 
1151
                {
 
1152
                    g_RspPlugin = optarg;
 
1153
                }
 
1154
                else
 
1155
                {
 
1156
                    printf("***Warning: RSP Plugin '%s' couldn't be loaded!\n", optarg);
 
1157
                }
 
1158
                break;
 
1159
            case OPT_EMUMODE:
 
1160
                i = atoi(optarg);
 
1161
                if(i >= CORE_INTERPRETER && i <= CORE_PURE_INTERPRETER)
 
1162
                {
 
1163
                    l_EmuMode = TRUE;
 
1164
                    dynacore = i;
 
1165
                }
 
1166
                else
 
1167
                {
 
1168
                    printf("***Warning: Invalid Emumode: %s\n", optarg);
 
1169
                }
 
1170
                break;
 
1171
            case OPT_SSHOTDIR:
 
1172
                if(isdir(optarg))
 
1173
                    SetScreenshotDir(optarg);
 
1174
                else
 
1175
                    printf("***Warning: Screen shot directory '%s' is not accessible or not a directory.\n", optarg);
 
1176
                break;
 
1177
            case OPT_CONFIGDIR:
 
1178
                if(isdir(optarg))
 
1179
                    strncpy(l_ConfigDir, optarg, PATH_MAX);
 
1180
                else
 
1181
                    printf("***Warning: Config directory '%s' is not accessible or not a directory.\n", optarg);
 
1182
                break;
 
1183
            case OPT_INSTALLDIR:
 
1184
                if(isdir(optarg))
 
1185
                    strncpy(l_InstallDir, optarg, PATH_MAX);
 
1186
                else
 
1187
                    printf("***Warning: Install directory '%s' is not accessible or not a directory.\n", optarg);
 
1188
                break;
 
1189
            case OPT_NOASK:
 
1190
                g_Noask = g_NoaskParam = TRUE;
 
1191
                break;
 
1192
            case OPT_TESTSHOTS:
 
1193
                // count the number of integers in the list
 
1194
                shots = 1;
 
1195
                str = optarg;
 
1196
                while ((str = strchr(str, ',')) != NULL)
 
1197
                {
 
1198
                    str++;
 
1199
                    shots++;
 
1200
                }
 
1201
                // create a list and populate it with the frame counter values at which to take screenshots
 
1202
                if ((l_TestShotList = malloc(sizeof(int) * (shots + 1))) != NULL)
 
1203
                {
 
1204
                    int idx = 0;
 
1205
                    str = optarg;
 
1206
                    while (str != NULL)
 
1207
                    {
 
1208
                        l_TestShotList[idx++] = atoi(str);
 
1209
                        str = strchr(str, ',');
 
1210
                        if (str != NULL) str++;
 
1211
                    }
 
1212
                    l_TestShotList[idx] = 0;
 
1213
                }
 
1214
                break;
 
1215
#ifdef DBG
 
1216
            case OPT_DEBUGGER:
 
1217
                g_DebuggerEnabled = TRUE;
 
1218
                break;
 
1219
#endif
 
1220
            case OPT_ROMNUMBER:
 
1221
                l_RomNumber = atoi(optarg);
 
1222
                break;
 
1223
            // print help
 
1224
            case 'h':
 
1225
            case '?':
 
1226
            default:
 
1227
                printUsage(argv[0]);
 
1228
                exit(1);
 
1229
                break;
 
1230
        }
 
1231
    }
 
1232
 
 
1233
    // if there are still parameters left after option parsing, assume it's the rom filename
 
1234
    if(optind < argc)
 
1235
    {
 
1236
        l_Filename = argv[optind];
 
1237
    }
 
1238
 
 
1239
    // if executable name contains "_nogui", set l_GuiEnabled to FALSE.
 
1240
    // This allows creation of a mupen64plus_nogui symlink to mupen64plus instead of passing --nogui
 
1241
    // for backwards compatability with old mupen64_nogui program name.
 
1242
    str = strdup(argv[0]);
 
1243
    if(strstr(str, "_nogui") != NULL)
 
1244
    {
 
1245
        l_GuiEnabled = FALSE;
 
1246
    }
 
1247
    free(str);
 
1248
}
 
1249
 
 
1250
/** setPaths
 
1251
 *  setup paths to config/install/screenshot directories. The config dir is the dir where all
 
1252
 *  user config information is stored, e.g. mupen64plus.conf, save files, and plugin conf files.
 
1253
 *  The install dir is where mupen64plus looks for common files, e.g. plugins, icons, language
 
1254
 *  translation files.
 
1255
 */
 
1256
static void setPaths(void)
 
1257
{
 
1258
#ifdef __WIN32__
 
1259
    strncpy(l_ConfigDir, "./", PATH_MAX);
 
1260
    strncpy(l_InstallDir, "./", PATH_MAX);
 
1261
    return;
 
1262
#else
 
1263
    char buf[PATH_MAX], buf2[PATH_MAX];
 
1264
 
 
1265
    // if the config dir was not specified at the commandline, look for ~/.mupen64plus dir
 
1266
    if (strlen(l_ConfigDir) == 0)
 
1267
    {
 
1268
        strncpy(l_ConfigDir, getenv("HOME"), PATH_MAX);
 
1269
        strncat(l_ConfigDir, "/.mupen64plus", PATH_MAX - strlen(l_ConfigDir));
 
1270
 
 
1271
        // if ~/.mupen64plus dir is not found, create it
 
1272
        if(!isdir(l_ConfigDir))
 
1273
        {
 
1274
            printf("Creating %s to store user data\n", l_ConfigDir);
 
1275
            if(mkdir(l_ConfigDir, (mode_t)0755) != 0)
 
1276
            {
 
1277
                printf("Error: Could not create %s: ", l_ConfigDir);
 
1278
                perror(NULL);
 
1279
                exit(errno);
 
1280
            }
 
1281
 
 
1282
            // create save subdir
 
1283
            strncpy(buf, l_ConfigDir, PATH_MAX);
 
1284
            strncat(buf, "/save", PATH_MAX - strlen(buf));
 
1285
            if(mkdir(buf, (mode_t)0755) != 0)
 
1286
            {
 
1287
                // report error, but don't exit
 
1288
                printf("Warning: Could not create %s: %s", buf, strerror(errno));
 
1289
            }
 
1290
 
 
1291
            // create screenshots subdir
 
1292
            strncpy(buf, l_ConfigDir, PATH_MAX);
 
1293
            strncat(buf, "/screenshots", PATH_MAX - strlen(buf));
 
1294
            if(mkdir(buf, (mode_t)0755) != 0)
 
1295
            {
 
1296
                // report error, but don't exit
 
1297
                printf("Warning: Could not create %s: %s", buf, strerror(errno));
 
1298
            }
 
1299
        }
 
1300
    }
 
1301
 
 
1302
    // make sure config dir has a '/' on the end.
 
1303
    if(l_ConfigDir[strlen(l_ConfigDir)-1] != '/')
 
1304
        strncat(l_ConfigDir, "/", PATH_MAX - strlen(l_ConfigDir));
 
1305
 
 
1306
    // if install dir was not specified at the commandline, look for it in the executable's directory
 
1307
    if (strlen(l_InstallDir) == 0)
 
1308
    {
 
1309
#ifdef __APPLE__
 
1310
        macSetBundlePath(buf);
 
1311
        strncpy(l_InstallDir, buf, PATH_MAX);
 
1312
        strncat(buf, "/config/mupen64plus.conf", PATH_MAX - strlen(buf));
 
1313
#else
 
1314
        buf[0] = '\0';
 
1315
        int n = readlink("/proc/self/exe", buf, PATH_MAX);
 
1316
        if (n > 0)
 
1317
        {
 
1318
            buf[n] = '\0';
 
1319
            dirname(buf);
 
1320
            strncpy(l_InstallDir, buf, PATH_MAX);
 
1321
            strncat(buf, "/config/mupen64plus.conf", PATH_MAX - strlen(buf));
 
1322
        }
 
1323
#endif
 
1324
        // if it's not in the executable's directory, try a couple of default locations
 
1325
        if (buf[0] == '\0' || !isfile(buf))
 
1326
        {
 
1327
            strcpy(l_InstallDir, "/usr/local/share/mupen64plus");
 
1328
            strcpy(buf, l_InstallDir);
 
1329
            strcat(buf, "/config/mupen64plus.conf");
 
1330
            if (!isfile(buf))
 
1331
            {
 
1332
                strcpy(l_InstallDir, "/usr/share/mupen64plus");
 
1333
                strcpy(buf, l_InstallDir);
 
1334
                strcat(buf, "/config/mupen64plus.conf");
 
1335
                // if install dir is not in the default locations, try the same dir as the binary
 
1336
                if (!isfile(buf))
 
1337
                {
 
1338
                    // try cwd as last resort
 
1339
                    getcwd(l_InstallDir, PATH_MAX);
 
1340
                }
 
1341
            }
 
1342
        }
 
1343
    }
 
1344
 
 
1345
    // make sure install dir has a '/' on the end.
 
1346
    if(l_InstallDir[strlen(l_InstallDir)-1] != '/')
 
1347
        strncat(l_InstallDir, "/", PATH_MAX - strlen(l_InstallDir));
 
1348
 
 
1349
    // make sure install dir is valid
 
1350
    strncpy(buf, l_InstallDir, PATH_MAX);
 
1351
    strncat(buf, "config/mupen64plus.conf", PATH_MAX - strlen(buf));
 
1352
    if(!isfile(buf))
 
1353
    {
 
1354
        printf("Could not locate valid install directory\n");
 
1355
        exit(1);
 
1356
    }
 
1357
 
 
1358
    // check user config dir for mupen64plus.conf file. If it's not there, copy all
 
1359
    // config files from install dir over to user dir.
 
1360
    strncpy(buf, l_ConfigDir, PATH_MAX);
 
1361
    strncat(buf, "mupen64plus.conf", PATH_MAX - strlen(buf));
 
1362
    if(!isfile(buf))
 
1363
    {
 
1364
        DIR *dir;
 
1365
        struct dirent *entry;
 
1366
 
 
1367
        strncpy(buf, l_InstallDir, PATH_MAX);
 
1368
        strncat(buf, "config", PATH_MAX - strlen(buf));
 
1369
        dir = opendir(buf);
 
1370
 
 
1371
        // should never hit this error because of previous checks
 
1372
        if(!dir)
 
1373
        {
 
1374
            perror(buf);
 
1375
            return;
 
1376
        }
 
1377
 
 
1378
        while((entry = readdir(dir)) != NULL)
 
1379
        {
 
1380
            strncpy(buf, l_InstallDir, PATH_MAX);
 
1381
            strncat(buf, "config/", PATH_MAX - strlen(buf));
 
1382
            strncat(buf, entry->d_name, PATH_MAX - strlen(buf));
 
1383
 
 
1384
            // only copy regular files
 
1385
            if(isfile(buf))
 
1386
            {
 
1387
                strncpy(buf2, l_ConfigDir, PATH_MAX);
 
1388
                strncat(buf2, entry->d_name, PATH_MAX - strlen(buf2));
 
1389
 
 
1390
                printf("Copying %s to %s\n", buf, l_ConfigDir);
 
1391
                if(copyfile(buf, buf2) != 0)
 
1392
                    printf("Error copying file\n");
 
1393
            }
 
1394
        }
 
1395
 
 
1396
        closedir(dir);
 
1397
    }
 
1398
 
 
1399
    // set screenshot dir if it wasn't specified by the user
 
1400
    if (!ValidScreenshotDir())
 
1401
    {
 
1402
        char chDefaultDir[PATH_MAX + 1];
 
1403
        snprintf(chDefaultDir, PATH_MAX, "%sscreenshots/", l_ConfigDir);
 
1404
        SetScreenshotDir(chDefaultDir);
 
1405
    }
 
1406
#endif /* __WIN32__ */
 
1407
}
 
1408
 
 
1409
/*********************************************************************************************************
 
1410
* main function
 
1411
*/
 
1412
int main(int argc, char *argv[])
 
1413
{
 
1414
    char dirpath[PATH_MAX];
 
1415
    int i;
 
1416
    int retval = EXIT_SUCCESS;
 
1417
    printf(" __  __                         __   _  _   ____  _             \n");  
 
1418
    printf("|  \\/  |_   _ _ __   ___ _ __  / /_ | || | |  _ \\| |_   _ ___ \n");
 
1419
    printf("| |\\/| | | | | '_ \\ / _ \\ '_ \\| '_ \\| || |_| |_) | | | | / __|  \n");
 
1420
    printf("| |  | | |_| | |_) |  __/ | | | (_) |__   _|  __/| | |_| \\__ \\  \n");
 
1421
    printf("|_|  |_|\\__,_| .__/ \\___|_| |_|\\___/   |_| |_|   |_|\\__,_|___/  \n");
 
1422
    printf("             |_|         http://code.google.com/p/mupen64plus/  \n");
 
1423
    printf("Version %s\n\n",MUPEN_VERSION);
 
1424
 
 
1425
    parseCommandLine(argc, argv);
 
1426
    setPaths();
 
1427
    config_read();
 
1428
 
 
1429
    if (l_GuiEnabled)
 
1430
    {
 
1431
        i = config_get_bool("OsdEnabled", 2);
 
1432
        if (i == 2)
 
1433
        {
 
1434
            config_put_bool("OsdEnabled", 1);
 
1435
        }
 
1436
        else if (g_OsdEnabled == 1)
 
1437
        {
 
1438
            g_OsdEnabled = i;
 
1439
        }
 
1440
        // check "GUI always start fullscreen" setting in config file
 
1441
        i = config_get_bool("GuiStartFullscreen", 2);
 
1442
        if (i == 2)
 
1443
        {
 
1444
            config_put_bool("GuiStartFullscreen", 0);
 
1445
        }
 
1446
        else if (g_Fullscreen == 0)
 
1447
        {
 
1448
            g_Fullscreen = i;
 
1449
        }
 
1450
 
 
1451
    }
 
1452
 
 
1453
    // init multi-language support
 
1454
    tr_init();
 
1455
 
 
1456
    // if --noask was not specified at the commandline, default to true in nogui mode, 
 
1457
    // otherwise check the config file.
 
1458
    if(!g_NoaskParam)
 
1459
        {
 
1460
        if(!l_GuiEnabled)
 
1461
            {
 
1462
            g_Noask = TRUE;
 
1463
            }
 
1464
        else
 
1465
            {
 
1466
            g_Noask = config_get_bool("No Ask", FALSE);
 
1467
            }
 
1468
        }
 
1469
 
 
1470
    cheat_read_config();
 
1471
 
 
1472
    // try to get plugin folder path from the mupen64plus config file (except on mac where app bundles may be used)
 
1473
    strncpy(dirpath, config_get_string("PluginDirectory", ""), PATH_MAX-1);
 
1474
        
 
1475
    dirpath[PATH_MAX-1] = '\0';
 
1476
    // if it's not set in the config file, use the /plugins/ sub-folder of the installation directory
 
1477
    if (strlen(dirpath) < 2)
 
1478
    {
 
1479
        strncpy(dirpath, "/usr/lib/mupen64plus/", PATH_MAX);
 
1480
        dirpath[PATH_MAX-1] = '\0';
 
1481
    }
 
1482
    // scan the plugin directory and set the config dir for the plugins
 
1483
    plugin_scan_directory(dirpath);
 
1484
    plugin_set_dirs(l_ConfigDir, l_InstallDir);
 
1485
 
 
1486
#ifndef NO_GUI
 
1487
    if(l_GuiEnabled)
 
1488
        gui_init(&argc, &argv);
 
1489
#endif
 
1490
    // must be called after building gui
 
1491
    // look for plugins in the install dir and set plugin config dir
 
1492
    savestates_set_autoinc_slot(config_get_bool("AutoIncSaveSlot", FALSE));
 
1493
 
 
1494
    if((i=config_get_number("CurrentSaveSlot",10))!=10)
 
1495
    {
 
1496
        savestates_select_slot((unsigned int)i);
 
1497
    }
 
1498
    else
 
1499
    {
 
1500
        config_put_number("CurrentSaveSlot",0);
 
1501
    }
 
1502
 
 
1503
    main_message(1, 0, 0, 0, tr("Config Dir:  %s\nInstall Dir: %s\nPlugin Dir:  %s\n"), l_ConfigDir, l_InstallDir, dirpath);
 
1504
    main_message(0, 1, 0, 0, tr("Config Dir: \"%s\", Install Dir: \"%s\", Plugin Dir:  \"%s\""), l_ConfigDir, l_InstallDir, dirpath);
 
1505
 
 
1506
    //The database needs to be opened regardless of GUI mode.
 
1507
    romdatabase_open();
 
1508
#ifndef NO_GUI
 
1509
    // only create the ROM Cache Thread if GUI is enabled
 
1510
    if (l_GuiEnabled)
 
1511
    {  
 
1512
        g_romcache.rcstask = RCS_INIT;
 
1513
        g_RomCacheThread = SDL_CreateThread(rom_cache_system, NULL);
 
1514
        
 
1515
        if(g_RomCacheThread == NULL)
 
1516
        {
 
1517
            error_message(tr("Couldn't spawn rom cache thread!"));
 
1518
        }
 
1519
    }
 
1520
 
 
1521
    // only display gui if user wants it
 
1522
    if (l_GuiEnabled)
 
1523
        gui_display();
 
1524
#endif
 
1525
 
 
1526
    // if rom file was specified, run it
 
1527
    if (l_Filename)
 
1528
    {
 
1529
        if (open_rom(l_Filename, l_RomNumber) >= 0)
 
1530
        {
 
1531
            startEmulation();
 
1532
        }
 
1533
        else if (!l_GuiEnabled)
 
1534
        {
 
1535
            retval = 1;
 
1536
        }
 
1537
    }
 
1538
    // Rom file must be specified in nogui mode
 
1539
    else if (!l_GuiEnabled)
 
1540
    {
 
1541
        error_message("Rom file must be specified in nogui mode.");
 
1542
        printUsage(argv[0]);
 
1543
        retval = 1;
 
1544
    }
 
1545
 
 
1546
#ifndef NO_GUI
 
1547
    // give control of this thread to the gui
 
1548
    if (l_GuiEnabled)
 
1549
    {
 
1550
        gui_main_loop();
 
1551
        stopEmulation();
 
1552
    }
 
1553
#endif
 
1554
 
 
1555
    // free allocated memory
 
1556
    if (l_TestShotList != NULL)
 
1557
        free(l_TestShotList);
 
1558
 
 
1559
    // cleanup and exit
 
1560
    config_write();
 
1561
    cheat_write_config();
 
1562
    cheat_delete_all();
 
1563
#ifndef NO_GUI
 
1564
    g_romcache.rcstask = RCS_SHUTDOWN;
 
1565
#endif
 
1566
    romdatabase_close();
 
1567
    plugin_delete_list();
 
1568
    tr_delete_languages();
 
1569
    config_delete();
 
1570
 
 
1571
    return retval;
 
1572
}
 
1573
 
 
1574
#ifdef __WIN32__
 
1575
 
 
1576
static const char* programName = "mupen64plus.exe";
 
1577
 
 
1578
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParamarg, int cmdShow)
 
1579
{
 
1580
    list_t arguments = NULL;
 
1581
    list_node_t*  node = NULL;
 
1582
    int i = 0;
 
1583
    char* arg = NULL;
 
1584
    char* wrk = NULL;
 
1585
    char** argv = NULL;
 
1586
 
 
1587
    g_ProgramInstance = instance;
 
1588
    
 
1589
    wrk = malloc(strlen(programName) + 1);
 
1590
    strcpy(wrk, programName);
 
1591
    list_append(&arguments, wrk);
 
1592
    
 
1593
    for (arg = strtok(cmdParamarg, " ");
 
1594
         arg != NULL;
 
1595
         arg = strtok(NULL, " "))
 
1596
    {
 
1597
        wrk = malloc(strlen(arg) + 1);
 
1598
        strcpy(wrk, arg);
 
1599
        list_append(&arguments, arg);
 
1600
    }
 
1601
    
 
1602
    argv = malloc(list_length(arguments) + 1 * sizeof(char*));
 
1603
    list_foreach(arguments, node)
 
1604
    {
 
1605
        argv[i++] = node->data;
 
1606
    }
 
1607
    
 
1608
    return main(i, argv);
 
1609
}
 
1610
#endif
 
1611