Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/yabause/src/cocoa/YabauseController.m
2 views
1
/* Copyright 2010, 2012 Lawrence Sebald
2
3
This file is part of Yabause.
4
5
Yabause is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
9
10
Yabause is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with Yabause; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
*/
19
20
#include <sched.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
24
#include "YabauseController.h"
25
#include "YabauseGLView.h"
26
#include "YabausePrefsController.h"
27
28
#include "vdp1.h"
29
#include "vdp2.h"
30
#include "scsp.h"
31
#include "peripheral.h"
32
#include "cdbase.h"
33
#include "yabause.h"
34
#include "yui.h"
35
#include "PerCocoa.h"
36
#include "m68kc68k.h"
37
#include "cs0.h"
38
39
YabauseController *controller;
40
41
@interface YabauseController (InternalFunctions)
42
- (void)startEmulationWithCDCore:(int)cdcore CDPath:(const char *)fn;
43
- (void)emulationThread:(id)ignored;
44
- (void)terminateEmulation;
45
@end
46
47
/* Menu Item tags. */
48
enum {
49
tagVDP1 = 1,
50
tagNBG0 = 2,
51
tagNBG1 = 3,
52
tagNBG2 = 4,
53
tagNBG3 = 5,
54
tagRBG0 = 6,
55
tagFPS = 7
56
};
57
58
static void FlipToggle(NSMenuItem *item) {
59
if([item state] == NSOffState) {
60
[item setState:NSOnState];
61
}
62
else {
63
[item setState:NSOffState];
64
}
65
}
66
67
@implementation YabauseController
68
69
- (void)awakeFromNib
70
{
71
NSUserDefaults *p = [NSUserDefaults standardUserDefaults];
72
73
controller = self;
74
_running = NO;
75
_paused = NO;
76
_runLock = [[NSLock alloc] init];
77
_emuThd = nil;
78
_bramFile = NULL;
79
_doneExecuting = NO;
80
81
if([p boolForKey:@"Enable Frameskip"]) {
82
[frameskip setState:NSOnState];
83
EnableAutoFrameSkip();
84
}
85
else {
86
[frameskip setState:NSOffState];
87
DisableAutoFrameSkip();
88
}
89
}
90
91
- (void)dealloc
92
{
93
[_runLock release];
94
[super dealloc];
95
}
96
97
- (BOOL)windowShouldClose:(id)sender
98
{
99
[self terminateEmulation];
100
return YES;
101
}
102
103
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
104
{
105
[self terminateEmulation];
106
return NSTerminateNow;
107
}
108
109
- (IBAction)showPreferences:(id)sender
110
{
111
[prefsPane makeKeyAndOrderFront:self];
112
}
113
114
- (IBAction)runBIOS:(id)sender
115
{
116
/* This will simply start up the system with the dummy CD core, so there's
117
no way it'll actually read that there's a disc to be played. */
118
[self startEmulationWithCDCore:CDCORE_DUMMY CDPath:NULL];
119
}
120
121
- (IBAction)runCD:(id)sender
122
{
123
[self startEmulationWithCDCore:CDCORE_ARCH CDPath:NULL];
124
}
125
126
- (IBAction)runISO:(id)sender
127
{
128
NSOpenPanel *p = [NSOpenPanel openPanel];
129
NSArray *types = [NSArray arrayWithObjects:@"iso", @"cue", nil];
130
131
[p setAllowedFileTypes:types];
132
if([p runModal] == NSFileHandlingPanelOKButton) {
133
NSString *fn = [[[p URLs] objectAtIndex:0] path];
134
[self startEmulationWithCDCore:CDCORE_ISO
135
CDPath:[fn fileSystemRepresentation]];
136
}
137
}
138
139
- (IBAction)toggleFullscreen:(id)sender
140
{
141
/* The view handles any heavy lifting here... */
142
[view toggleFullscreen];
143
}
144
145
- (IBAction)toggle:(id)sender
146
{
147
/* None of these will work unless we're running... */
148
if(!_running) {
149
return;
150
}
151
152
/* Flip the checkmark on the button. */
153
FlipToggle((NSMenuItem *)sender);
154
155
/* Do whatever this toggle is asking us to do. */
156
switch([sender tag]) {
157
case tagVDP1:
158
ToggleVDP1();
159
break;
160
161
case tagNBG0:
162
ToggleNBG0();
163
break;
164
165
case tagNBG1:
166
ToggleNBG1();
167
break;
168
169
case tagNBG2:
170
ToggleNBG2();
171
break;
172
173
case tagNBG3:
174
ToggleNBG3();
175
break;
176
177
case tagRBG0:
178
ToggleRBG0();
179
break;
180
181
case tagFPS:
182
ToggleFPS();
183
break;
184
}
185
}
186
187
- (IBAction)toggleFrameskip:(id)sender
188
{
189
NSUserDefaults *p = [NSUserDefaults standardUserDefaults];
190
191
if([sender state] == NSOnState) {
192
DisableAutoFrameSkip();
193
[sender setState:NSOffState];
194
[p setBool:NO forKey:@"Enable Frameskip"];
195
}
196
else {
197
EnableAutoFrameSkip();
198
[sender setState:NSOnState];
199
[p setBool:YES forKey:@"Enable Frameskip"];
200
}
201
}
202
203
- (IBAction)pause:(id)sender
204
{
205
if(_running) {
206
if(!_paused) {
207
_paused = YES;
208
209
/* Mute the audio before we actually pause otherwise the user might
210
not like the result... */
211
ScspMuteAudio(SCSP_MUTE_SYSTEM);
212
[_runLock lock];
213
[sender setState:NSOnState];
214
}
215
else {
216
_paused = NO;
217
[_runLock unlock];
218
ScspUnMuteAudio(SCSP_MUTE_SYSTEM);
219
[sender setState:NSOffState];
220
}
221
}
222
}
223
224
- (IBAction)reset:(id)sender
225
{
226
if(_running) {
227
/* Act as if the user pressed the reset button on the console. */
228
YabauseResetButton();
229
}
230
}
231
232
- (YabauseGLView *)view
233
{
234
return view;
235
}
236
237
@end /* @implementation YabauseController */
238
239
@implementation YabauseController (InternalFunctions)
240
241
- (void)startEmulationWithCDCore:(int)cdcore CDPath:(const char *)fn
242
{
243
if(!_running) {
244
yabauseinit_struct yinit;
245
int initok;
246
NSString *bios = [prefs biosPath];
247
NSString *mpeg = [prefs mpegPath];
248
NSString *bram = [prefs bramPath];
249
NSString *cart = [prefs cartPath];
250
251
yinit.percoretype = PERCORE_COCOA;
252
yinit.sh2coretype = SH2CORE_DEFAULT;
253
yinit.vidcoretype = [prefs videoCore];
254
yinit.sndcoretype = [prefs soundCore];
255
yinit.m68kcoretype = M68KCORE_C68K;
256
yinit.cdcoretype = cdcore;
257
yinit.carttype = [prefs cartType];
258
yinit.regionid = [prefs region];
259
yinit.biospath = ([bios length] > 0 && ![prefs emulateBios]) ?
260
[bios UTF8String] : NULL;
261
yinit.cdpath = fn;
262
yinit.buppath = NULL;
263
yinit.mpegpath = ([mpeg length] > 0) ? [mpeg UTF8String] : NULL;
264
yinit.videoformattype = ([prefs region] < 10) ? VIDEOFORMATTYPE_NTSC :
265
VIDEOFORMATTYPE_PAL;
266
yinit.frameskip = [frameskip state] == NSOnState;
267
yinit.clocksync = 0;
268
yinit.basetime = 0;
269
yinit.usethreads = 0;
270
271
/* Set up the internal save ram if specified. */
272
if([bram length] > 0) {
273
const char *tmp = [bram UTF8String];
274
yinit.buppath = _bramFile = strdup(tmp);
275
}
276
277
if(fn)
278
_isoFile = strdup(fn);
279
280
/* Set up the cartridge stuff based on what was selected. */
281
if(yinit.carttype == CART_NETLINK) {
282
yinit.cartpath = NULL;
283
yinit.netlinksetting = ([cart length] > 0) ?
284
[cart UTF8String] : NULL;
285
}
286
else {
287
yinit.cartpath = ([cart length] > 0) ? [cart UTF8String] : NULL;
288
yinit.netlinksetting = NULL;
289
}
290
291
if(cdcore == CDCORE_DUMMY && !yinit.biospath) {
292
NSRunAlertPanel(@"Yabause Error", @"You must specify a BIOS file "
293
"(and have BIOS emulation disabled) in order to "
294
"run the BIOS.", @"OK", NULL, NULL);
295
return;
296
}
297
298
[[view openGLContext] makeCurrentContext];
299
initok = YabauseInit(&yinit);
300
[NSOpenGLContext clearCurrentContext];
301
if (initok != 0) {
302
return;
303
}
304
305
YabauseSetDecilineMode(1);
306
307
_running = YES;
308
_doneExecuting = NO;
309
310
[view showWindow];
311
312
/* The emulation itself takes place in a separate thread from the main
313
GUI thread. */
314
[NSThread detachNewThreadSelector:@selector(emulationThread:)
315
toTarget:self
316
withObject:nil];
317
}
318
}
319
320
- (void)emulationThread:(id)ignored
321
{
322
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
323
CGLContextObj cxt;
324
325
_emuThd = [NSThread currentThread];
326
327
/* Make the OpenGL context current for this thread, otherwise we will be
328
drawing to nothingness. */
329
[[view openGLContext] makeCurrentContext];
330
331
ScspUnMuteAudio(SCSP_MUTE_SYSTEM);
332
333
while(_running) {
334
/* If we get paused from the GUI, we'll end up waiting in this lock
335
here... Maybe not the most clear way to do it, but it works. */
336
[_runLock lock];
337
338
/* Make sure the main thread doesn't attempt to flip the buffer before
339
this thread is done rendering. */
340
cxt = CGLGetCurrentContext();
341
CGLLockContext(cxt);
342
343
/* Shortcut a function call here... We should technically be doing a
344
PERCore->HandleEvents(), but that function simply calls YabauseExec()
345
anyway... so cut out the middleman. */
346
YabauseExec();
347
348
CGLUnlockContext(cxt);
349
[_runLock unlock];
350
}
351
352
ScspMuteAudio(SCSP_MUTE_SYSTEM);
353
354
_doneExecuting = YES;
355
[pool release];
356
}
357
358
- (void)terminateEmulation
359
{
360
_running = NO;
361
362
/* Wait for the thread to die, and then clean up after it. */
363
if(_emuThd) {
364
while(!_doneExecuting) {
365
sched_yield();
366
}
367
368
YabauseDeInit();
369
370
free(_bramFile);
371
_bramFile = NULL;
372
free(_isoFile);
373
_isoFile = NULL;
374
375
_emuThd = nil;
376
}
377
}
378
379
@end /* @implementation YabauseController (InternalFunctions) */
380
381