1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
|
/***************************************************************************
PluginWindowController.m
The big bad boy that controls/creates the game window, the openGLView, and
communicates with PCSXR itself
PeopsOpenGPU
Created by Gil Pedersen on Tue April 12 2004.
Copyright (c) 2004 Gil Pedersen.
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. See also the license.txt file for *
* additional informations. *
* *
***************************************************************************/
#import "PluginWindowController.h"
#import "PluginWindow.h"
#import "Carbon/Carbon.h"
#include <OpenGL/gl.h> // OpenGL needed for "externals.h"
#include "externals.h"
#include "draw.h" // for CreateScanLines()
#undef BOOL
// not sure why these aren't class or instance variables...
NSWindow *gameWindow;
PluginWindowController *gameController;
NSRect windowFrame;
NSRect windowDefaultRect; // default window size (needed to go back into window mode)
NSRect FitRectInRect(NSRect source, NSRect destination)
{
NSRect newRect;
if (NSContainsRect(destination,source))
return source;
if (source.size.width > destination.size.width || source.size.height > destination.size.height){
// have to rescale
float ratio = source.size.width/source.size.height;
if (ratio > destination.size.width/destination.size.height){
source.size.width = destination.size.width;
source.size.height = source.size.width / ratio ;
}
else{
source.size.height = destination.size.height;
source.size.width = source.size.height * ratio;
}
}
// center horizontally and take top vertical
newRect.origin.x = destination.origin.x + (destination.size.width - source.size.width)/2;
newRect.origin.y = destination.origin.y + destination.size.height - source.size.height;
newRect.size = source.size;
return newRect;
}
@implementation PluginWindowController
{
BOOL inFullscreen;
}
+ (id)openGameView
{
// create a window for the GPU and return
// the controller that controls it
if (gameWindow == nil) {
if (gameController == nil) {
gameController = [[PluginWindowController alloc] initWithWindowNibName:@"NetSfPeopsOpenGLGPUInterface"];
}
gameWindow = [gameController window];
}
else {
NSLog(@"Well, we have a game window open already, which is kinda bad.");
abort();
return nil;
}
[gameWindow setBackgroundColor: [NSColor blackColor]];
windowFrame.size.width=iResX;
windowFrame.size.height=iResY;
if (windowFrame.size.width != 0)
[gameWindow setFrame:windowFrame display:NO];
[gameWindow center];
windowDefaultRect = [gameWindow frame];
[gameWindow makeKeyAndOrderFront:nil];
[gameController showWindow:nil];
NSOpenGLView* glInstance = [gameController openGLView];
[glInstance setFrameSize: windowDefaultRect.size];
[glInstance reshape];
// [glView update];
CGDirectDisplayID display = (CGDirectDisplayID)[[[gameWindow screen] deviceDescription][@"NSScreenNumber"] unsignedIntValue];
if (CGDisplayIsCaptured(display)) {
[gameController setFullscreen:YES];
}
return gameController;
}
- (void)subscribeToEvents
{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(applicationDidChangeScreenParameters:)
name:NSApplicationDidChangeScreenParametersNotification object:NSApp];
/* not used ATM:
[nc addObserver:self selector:@selector(applicationWillResignActive:) name:NSApplicationWillResignActiveNotification object:NSApp];
[nc addObserver:self selector:@selector(applicationWillBecomeActive:) name:NSApplicationWillBecomeActiveNotification object:NSApp];
[nc addObserver:self selector:@selector(applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:NSApp];
*/
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
[self subscribeToEvents];
return self;
}
- (id)initWithWindow:(NSWindow*)theWindow {
self = [super initWithWindow:theWindow];
[self subscribeToEvents];
return self;
}
- (NSRect) screenFrame
{
NSWindow* wind = [self window];
CGDirectDisplayID display = (CGDirectDisplayID)[[[wind screen] deviceDescription][@"NSScreenNumber"] unsignedIntValue];
return NSMakeRect (0,0,CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
}
- (void) applicationDidChangeScreenParameters:(NSNotification*)aNotice
{
// TODO: There could be issues with more drastic things like
// openGL pixel format, etc. when screen changes...
// if fullscreen, conform to new size.
if ([self fullscreen]){
if (NSEqualRects([[self window] frame], [self screenFrame])){
return;
}
[self adaptToFrame: [self screenFrame]];
}
else {
// if windowed, recenter.
// TODO: scale window if screen size is too small
[[self window] center];
}
}
- (PluginGLView *)openGLView
{
return (PluginGLView *)self.glView;
}
- (void) cureAllIlls
{
// try to reset the GPU without discarding textures, etc.
// when a resize takes place, all hell breaks loose, so
// this is necessarily ugly.
// all this should be in draw.c, actually
// needed, but I don't know what it's for...
rRatioRect.left = rRatioRect.top=0;
rRatioRect.right = iResX;
rRatioRect.bottom = iResY;
[[self.glView openGLContext] makeCurrentContext];
glFlush();
glFinish();
glViewport(rRatioRect.left, // init viewport by ratio rect
iResY-(rRatioRect.top+rRatioRect.bottom),
rRatioRect.right,
rRatioRect.bottom);
glScissor(0, 0, iResX, iResY); // init clipping (fullscreen)
glEnable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION); // init projection with psx resolution
glLoadIdentity();
glOrtho(0,PSXDisplay.DisplayMode.x,
PSXDisplay.DisplayMode.y, 0, -1, 1);
CreateScanLines();
// if(bKeepRatio) SetAspectRatio(); // set ratio
glFlush();
glFinish();
[NSOpenGLContext clearCurrentContext];
[self.glView reshape]; // to get rid of fuglies on screen
// GLinitialize(); // blunt instrument method of setting a proper state.
}
- (void)dealloc
{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
windowFrame = [[self window] frame]; // huh?
}
// forget keyDownEvents
- (void)keyDown:(NSEvent *)theEvent
{
// Not required any more
}
- (void)mouseDown:(NSEvent *)theEvent
{
if ([self fullscreen]) {
[self setFullscreen:NO];
}
}
- (BOOL)fullscreen
{
return inFullscreen;
}
- (void)setFullscreen:(BOOL)flag
{
// this is called by cocoa, not the main PSX thread.
// Messing with the opengl context is a Bad Thing.
// Therefore, just set a global flag, and
// wait around for a frame until
// gpu.c calls fullscreenswap() from
// the right thread
if ([self fullscreen] == flag)
return;
if (flag)
bChangeWinMode = 2;
else
bChangeWinMode = 1;
}
- (void)performFullscreenSwap
{
// ah, that's better. We are called from the main PSX thread
// after a screen update, so we're clean.
// bChangeWinMode is a global set from PSX
int flag = bChangeWinMode - 1; // 1 = go to window, 2 = go to fullscreen
bChangeWinMode = 0; // this is our flag that launched us, so 0 now
NSWindow *window = [self window];
NSScreen *screen = [window screen];
CGDirectDisplayID display = (CGDirectDisplayID)[[screen deviceDescription][@"NSScreenNumber"] unsignedIntValue];
NSRect newPlace;
if (flag){
[window setLevel: NSScreenSaverWindowLevel];
newPlace = [self screenFrame] ;
CGDisplayHideCursor(display);
CGAssociateMouseAndMouseCursorPosition(NO); // this could be bad since it disables mouse somewhat
}
else{
[window setLevel: NSNormalWindowLevel];
newPlace = windowDefaultRect;
CGDisplayShowCursor(display);
CGAssociateMouseAndMouseCursorPosition(YES);
}
if (flag) inFullscreen = TRUE;
else inFullscreen = FALSE;
if (!inFullscreen)
newPlace = FitRectInRect(newPlace, NSMakeRect(0,0,CGDisplayPixelsWide(display),CGDisplayPixelsHigh(display)-24)); // with menu bar room
[self adaptToFrame: newPlace];
}
- (BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame
{
[self setFullscreen:YES];
return NO;
}
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize
{
// we don't bother
return proposedFrameSize;
if (!(([sender resizeFlags] & NSShiftKeyMask) == NSShiftKeyMask)) {
NSRect oldSize = [sender frame];
NSRect viewSize = [self.glView frame];
float xDiff = NSWidth(oldSize) - NSWidth(viewSize);
float yDiff = NSHeight(oldSize) - NSHeight(viewSize);
//if ((proposedFrameSize.height / proposedFrameSize.width) < (3.0/4.0))
// proposedFrameSize.height = ((proposedFrameSize.width - xDiff) * 3.0) / 4.0 + yDiff;
//else
proposedFrameSize.width = ((proposedFrameSize.height - yDiff) * 4.0) / 3.0 + xDiff;
}
return proposedFrameSize;
}
- (void)windowWillMiniaturize:(NSNotification *)aNotification
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"emuWindowWantPause" object:self];
}
- (void)windowDidDeminiaturize:(NSNotification *)aNotification
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"emuWindowWantResume" object:self];
}
- (BOOL)windowShouldClose:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"emuWindowDidClose" object:self];
gameController = nil;
gameWindow = nil;
CGReleaseAllDisplays();
return YES;
}
// these two funcs should be handled by the window class but
// since we do fullscreen tweaking (hiding mouse, etc),
// the controller must do it ATM...
- (void)windowDidBecomeKey:(NSNotification*)aNotice
{
// if in fullscreen, we must restore level and mouse hiding.
// it might be cooler if window goes to "window" size or hides
// instead of taking up full screen in background.
NSWindow *window = [self window];
NSScreen *screen = [window screen];
CGDirectDisplayID display = (CGDirectDisplayID)[[screen deviceDescription][@"NSScreenNumber"] unsignedIntValue];
if ([self fullscreen]){
[window setLevel: NSScreenSaverWindowLevel];
CGDisplayHideCursor(display);
}
}
- (void)windowDidResignKey:(NSNotification*)aNotice
{
// if in fullscreen, we must abdicate mouse hiding and level.
NSWindow *window = [self window];
NSScreen *screen = [window screen];
CGDirectDisplayID display = (CGDirectDisplayID)[[screen deviceDescription][@"NSScreenNumber"] unsignedIntValue];
if ([self fullscreen]){
[window setLevel: NSNormalWindowLevel];
CGDisplayShowCursor(display);
}
}
- (void) adaptToFrame:(NSRect)aFrame
{
// do magic so everything goes as planned
// when the window area changes
int proportionalWidth, proportionalHeight;
NSWindow* window = [self window];
[window setFrame:aFrame display:NO];
// assume square pixel ratio on the monitor
if ((aFrame.size.width*3)/4 <= aFrame.size.height) { // is window skinnier than it needs to be?
proportionalHeight = (aFrame.size.width*3)/4; // then shrink the content height (letterbox)
proportionalWidth = aFrame.size.width; // and conform to width
} else {
proportionalWidth = (aFrame.size.height*4)/3;
proportionalHeight = aFrame.size.height;
}
NSRect fitToWindow = NSMakeRect(
roundf((aFrame.size.width - proportionalWidth)/2.0),
roundf((aFrame.size.height - proportionalHeight)/2.0),
roundf(proportionalWidth), roundf(proportionalHeight));
[self.glView setFrame:fitToWindow];
[self.glView reshape];
iResX = roundf(proportionalWidth);
iResY = roundf(proportionalHeight);
[self cureAllIlls]; // do some fixin'
return;
}
@end
void ChangeWindowMode(void)
{
// glue from PSX thread. Globals are already set
[ gameController performFullscreenSwap];
}
|