1 /*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6
7 /***********************************************************************************
8 SNES9X for Mac OS (c) Copyright John Stiles
9
10 Snes9x for Mac OS X
11
12 (c) Copyright 2001 - 2011 zones
13 (c) Copyright 2002 - 2005 107
14 (c) Copyright 2002 PB1400c
15 (c) Copyright 2004 Alexander and Sander
16 (c) Copyright 2004 - 2005 Steven Seeger
17 (c) Copyright 2005 Ryan Vogt
18 ***********************************************************************************/
19
20
21 #include "snes9x.h"
22 #include "memmap.h"
23 #include "apu.h"
24 #include "display.h"
25 #include "blit.h"
26
27 #include <OpenGL/OpenGL.h>
28 #include <OpenGL/CGLRenderers.h>
29 #include <OpenGL/gl.h>
30 #include <OpenGL/glu.h>
31 #include <OpenGL/glext.h>
32 #include <AGL/agl.h>
33 #include <sys/time.h>
34
35 #include "mac-prefix.h"
36 #include "mac-cheatfinder.h"
37 #include "mac-coreimage.h"
38 #include "mac-os.h"
39 #include "mac-quicktime.h"
40 #include "mac-screenshot.h"
41 #include "mac-render.h"
42
43 typedef void (* Blitter) (uint8 *, int, uint8 *, int, int, int);
44
45 static OSStatus BlitMPGLTask (void *);
46 static OSStatus PrepareMPBlitGL (void);
47 static void S9xInitFullScreen (void);
48 static void S9xDeinitFullScreen (void);
49 static void S9xInitWindowMode (void);
50 static void S9xDeinitWindowMode (void);
51 static void S9xInitOpenGLFullScreen (void);
52 static void S9xDeinitOpenGLFullScreen (void);
53 static void S9xInitOpenGLWindowMode (void);
54 static void S9xDeinitOpenGLWindowMode (void);
55 static void S9xInitBlitGL (void);
56 static void S9xDeinitBlitGL (void);
57 static void S9xInitOpenGLContext (void);
58 static void S9xDeinitOpenGLContext (void);
59 static void S9xInitCoreImage (void);
60 static void S9xDeinitCoreImage (void);
61 static void S9xPutImageOpenGL (int, int);
62 static void S9xPutImageBlitGL (int, int);
63 static void S9xPutImageBlitGL2 (int, int);
64 static void GLMakeScreenMesh (GLfloat *, int, int);
65 static void GLMakeTextureMesh (GLfloat *, int, int, float, float);
66 static void GLPrepareTexture (bool8, int, int, int, int, int, int);
67 static inline void RenderBlitScreen (Blitter, int, int, int, int, int, uint16 *);
68 #ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
69 static void SetBestDisplayMode (int, int);
70 #endif
71
72 enum
73 {
74 kMPBlitFrame = 1,
75 kMPBlitDone,
76 kMPBlitNone
77 };
78
79 enum
80 {
81 kGL256256 = 0,
82 kGL256512,
83 kGL512256,
84 kGL512512,
85 kGLBlit2x,
86 kGLBlit3x,
87 kGLBlit4x,
88 kGLNTS256,
89 kGLNTS512,
90 kGLNumTextures
91 };
92
93 enum
94 {
95 kSC2xNormal = 0,
96 kSC2xExtend,
97 kSC2xNHiRes,
98 kSC2xEHiRes,
99 kSC2xNInter,
100 kSC2xEInter,
101 kSC3xNormal,
102 kSC3xExtend,
103 kSC3xNHiRes,
104 kSC3xEHiRes,
105 kSCNTNormal,
106 kSCNTExtend,
107 kSCNumTextures
108 };
109
110 enum
111 {
112 kSCMeshX = 10,
113 kSCMeshY = 9
114 };
115
116 typedef struct
117 {
118 Blitter blitFn;
119 int nx;
120 int srcWidth;
121 int srcHeight;
122 int copyWidth;
123 int copyHeight;
124 uint16 *gfxBuffer;
125 } MPData;
126
127 typedef struct
128 {
129 GLint internal_format;
130 GLint format;
131 GLint type;
132 GLenum target;
133 GLuint textures[kGLNumTextures];
134 GLfloat vertex[kGLNumTextures][8];
135 GLint texW[kGLNumTextures];
136 GLint texH[kGLNumTextures];
137 GLboolean rangeExt;
138 GLint storage_hint;
139 GLint storage_apple;
140 GLfloat agp_texturing;
141 } OpenGLData;
142
143 static uint16 *gfxScreen[2],
144 *snesScreenA,
145 *snesScreenB;
146 static uint8 *blitGLBuffer;
147
148 static CGDirectDisplayID gGameDisplayID;
149
150 static MPTaskID taskID = NULL;
151 static MPQueueID notificationQueue = NULL,
152 taskQueue = NULL;
153 static MPSemaphoreID readySemaphore = NULL;
154 static MPData *mpBlit = NULL;
155
156 static OpenGLData OpenGL;
157 static CGLContextObj glContext;
158 static AGLContext agContext;
159 static CGLPixelFormatObj cglpix;
160 static AGLPixelFormat aglpix;
161 static GLint glSwapInterval = 0;
162 static GLint agSwapInterval = 0;
163 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
164 static CFDictionaryRef oldDisplayMode;
165 #else
166 static CGDisplayModeRef oldDisplayModeRef;
167 #endif
168 static CGImageRef cgGameImage = NULL,
169 cgBlitImage = NULL;
170
171 static int whichBuf = 0;
172 static int textureNum = 0;
173 static int prevBlitWidth, prevBlitHeight;
174 static int imageWidth[2], imageHeight[2];
175 static int nx = 2;
176
177 static GLfloat *scTexArray[kSCNumTextures];
178 static GLfloat *scScnArray;
179
180 static struct timeval bencht1, bencht2;
181
182 static const int ntsc_width = SNES_NTSC_OUT_WIDTH(SNES_WIDTH); // 602
183
184
InitGraphics(void)185 void InitGraphics (void)
186 {
187 int safemarginbytes = (520 * 520 - 512 * 512) * 2;
188
189 snesScreenA = (uint16 *) calloc( 520 * 520 * 2, 1);
190 snesScreenB = (uint16 *) calloc( 520 * 520 * 2, 1);
191 blitGLBuffer = (uint8 *) calloc(1024 * 1024 * 2, 1);
192
193 gfxScreen[0] = snesScreenA + (safemarginbytes >> 2);
194 gfxScreen[1] = snesScreenB + (safemarginbytes >> 2);
195
196 GFX.Pitch = 512 * 2;
197 GFX.Screen = gfxScreen[0];
198
199 if (!snesScreenA || !snesScreenB || !blitGLBuffer)
200 QuitWithFatalError(0, "render 01");
201
202 if (!S9xBlitFilterInit() |
203 !S9xBlit2xSaIFilterInit() |
204 !S9xBlitHQ2xFilterInit() |
205 !S9xBlitNTSCFilterInit())
206 QuitWithFatalError(0, "render 02");
207
208 switch (videoMode)
209 {
210 default:
211 case VIDEOMODE_NTSC_C:
212 case VIDEOMODE_NTSC_TV_C:
213 S9xBlitNTSCFilterSet(&snes_ntsc_composite);
214 break;
215
216 case VIDEOMODE_NTSC_S:
217 case VIDEOMODE_NTSC_TV_S:
218 S9xBlitNTSCFilterSet(&snes_ntsc_svideo);
219 break;
220
221 case VIDEOMODE_NTSC_R:
222 case VIDEOMODE_NTSC_TV_R:
223 S9xBlitNTSCFilterSet(&snes_ntsc_rgb);
224 break;
225
226 case VIDEOMODE_NTSC_M:
227 case VIDEOMODE_NTSC_TV_M:
228 S9xBlitNTSCFilterSet(&snes_ntsc_monochrome);
229 break;
230 }
231 }
232
DeinitGraphics(void)233 void DeinitGraphics (void)
234 {
235 S9xBlitNTSCFilterDeinit();
236 S9xBlitHQ2xFilterDeinit();
237 S9xBlit2xSaIFilterDeinit();
238 S9xBlitFilterDeinit();
239
240 if (snesScreenA)
241 {
242 free(snesScreenA);
243 snesScreenA = NULL;
244 }
245
246 if (snesScreenB)
247 {
248 free(snesScreenB);
249 snesScreenB = NULL;
250 }
251
252 if (blitGLBuffer)
253 {
254 free(blitGLBuffer);
255 blitGLBuffer = NULL;
256 }
257 }
258
DrawPauseScreen(CGContextRef ctx,HIRect bounds)259 void DrawPauseScreen (CGContextRef ctx, HIRect bounds)
260 {
261 CGImageRef image;
262 CGRect rct;
263 float sh, mh, rofs, ry;
264
265 if ((IPPU.RenderedScreenWidth == 0) || (IPPU.RenderedScreenHeight == 0))
266 return;
267
268 sh = (float) ((IPPU.RenderedScreenHeight > 256) ? IPPU.RenderedScreenHeight : IPPU.RenderedScreenHeight * 2);
269 mh = (float) (SNES_HEIGHT_EXTENDED * 2);
270
271 if (drawoverscan)
272 {
273 rofs = (mh - sh) / mh;
274 ry = sh / mh;
275 }
276 else
277 if (windowExtend)
278 {
279 rofs = (mh - sh) / mh / 2.0f;
280 ry = sh / mh;
281 }
282 else
283 {
284 rofs = 0.0f;
285 ry = 1.0f;
286 }
287
288 image = CreateGameScreenCGImage();
289 if (image)
290 {
291 CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
292 CGContextFillRect(ctx, bounds);
293
294 rct = CGRectMake(0.0f, bounds.size.height * rofs, bounds.size.width, bounds.size.height * ry);
295 CGContextDrawImage(ctx, rct, image);
296
297 CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 0.5f);
298 CGContextFillRect(ctx, bounds);
299
300 CGImageRelease(image);
301 }
302 }
303
DrawFreezeDefrostScreen(uint8 * draw)304 void DrawFreezeDefrostScreen (uint8 *draw)
305 {
306 const int w = SNES_WIDTH << 1, h = kMacWindowHeight;
307
308 imageWidth[0] = imageHeight[0] = 0;
309 imageWidth[1] = imageHeight[1] = 0;
310 prevBlitWidth = prevBlitHeight = 0;
311
312 if ((drawingMethod == kDrawingBlitGL) && multiprocessor)
313 {
314 MPWaitOnSemaphore(readySemaphore, kDurationForever);
315 printf("MP: Send dummy signal.\n");
316 MPNotifyQueue(taskQueue, (void *) kMPBlitNone, 0, 0);
317 }
318
319 if (nx < 0 && !ciFilterEnable)
320 {
321 for (int y = 0; y < h; y++)
322 memcpy(blitGLBuffer + y * 1024 * 2, draw + y * w * 2, w * 2);
323 }
324 else
325 memcpy(blitGLBuffer, draw, w * h * 2);
326
327 S9xPutImageBlitGL2(512, kMacWindowHeight);
328 }
329
ClearGFXScreen(void)330 void ClearGFXScreen (void)
331 {
332 memset(gfxScreen[0], 0, 512 * 512 * 2);
333 memset(gfxScreen[1], 0, 512 * 512 * 2);
334 memset(blitGLBuffer, 0, 1024 * 1024 * 2);
335
336 S9xBlitClearDelta();
337
338 imageWidth[0] = imageHeight[0] = 0;
339 imageWidth[1] = imageHeight[1] = 0;
340 prevBlitWidth = prevBlitHeight = 0;
341
342 if (fullscreen)
343 {
344 CGLSetCurrentContext(glContext);
345 glViewport(0, 0, glScreenW, glScreenH);
346 }
347 else
348 {
349 aglSetCurrentContext(agContext);
350 aglUpdateContext(agContext);
351 glViewport(0, 0, (GLsizei) gWindowRect.size.width, (GLsizei) gWindowRect.size.height);
352 }
353
354 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
355
356 for (int i = 0; i < 2; i++)
357 {
358 glClear(GL_COLOR_BUFFER_BIT);
359
360 if (fullscreen)
361 CGLFlushDrawable(glContext);
362 else
363 aglSwapBuffers(agContext);
364 }
365 }
366
367 #ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
SetBestDisplayMode(int width,int height)368 static void SetBestDisplayMode (int width, int height)
369 {
370 if (autoRes || !gl32bit)
371 {
372 CGError err;
373 CGDisplayModeRef mode;
374 CFArrayRef array;
375 CFStringRef pixenc, pix;
376 CFIndex n, i;
377 size_t w, h;
378 bool r;
379
380 pixenc = gl32bit ? CFSTR(IO32BitDirectPixels) : CFSTR(IO16BitDirectPixels);
381
382 array = CGDisplayCopyAllDisplayModes(gGameDisplayID, NULL);
383 n = CFArrayGetCount(array);
384
385 for (i = 0; i < n; i++)
386 {
387 mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(array, i);
388
389 w = CGDisplayModeGetWidth(mode);
390 h = CGDisplayModeGetHeight(mode);
391 pix = CGDisplayModeCopyPixelEncoding(mode);
392 r = CFStringCompare(pix, pixenc, 0) == kCFCompareEqualTo;
393 CFRelease(pix);
394
395 if (w == (size_t) width && h == (size_t) height && r)
396 break;
397 }
398
399 if (i < n)
400 err = CGDisplaySetDisplayMode(gGameDisplayID, mode, NULL);
401
402 CFRelease(array);
403 }
404 }
405 #endif
406
S9xInitFullScreen(void)407 static void S9xInitFullScreen (void)
408 {
409 DeinitGameWindow();
410
411 size_t width, height;
412
413 width = autoRes ? 640 : CGDisplayPixelsWide(gGameDisplayID);
414 height = autoRes ? 480 : CGDisplayPixelsHigh(gGameDisplayID);
415
416 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
417 CFDictionaryRef mode;
418 boolean_t exactMatch;
419 size_t depth = gl32bit ? 32 : 16;
420
421 oldDisplayMode = CGDisplayCurrentMode(gGameDisplayID);
422 mode = CGDisplayBestModeForParameters(gGameDisplayID, depth, width, height, &exactMatch);
423 CGDisplayCapture(gGameDisplayID);
424 CGDisplaySwitchToMode(gGameDisplayID, mode);
425 #else
426 oldDisplayModeRef = CGDisplayCopyDisplayMode(gGameDisplayID);
427 CGDisplayCapture(gGameDisplayID);
428 SetBestDisplayMode(width, height);
429 #endif
430
431 CGDisplayErr cgErr;
432 CGDisplayCount numDisplays, maxDisplays = 32;
433 CGDirectDisplayID activeDisplays[32];
434
435 cgErr = CGGetActiveDisplayList(maxDisplays, activeDisplays, &numDisplays);
436 if (cgErr == noErr)
437 {
438 if ((macControllerOption == SNES_MOUSE) || (macControllerOption == SNES_MOUSE_SWAPPED) || (numDisplays == 1))
439 CGDisplayHideCursor(gGameDisplayID);
440
441 if ((macControllerOption == SNES_MOUSE) || (macControllerOption == SNES_MOUSE_SWAPPED))
442 {
443 CGDisplayMoveCursorToPoint(gGameDisplayID, CGPointMake((float) (width >> 1), (float) (height >> 1)));
444 CGAssociateMouseAndMouseCursorPosition(false);
445 }
446 }
447 }
448
S9xDeinitFullScreen(void)449 static void S9xDeinitFullScreen (void)
450 {
451 CGAssociateMouseAndMouseCursorPosition(true);
452 CGDisplayShowCursor(gGameDisplayID);
453
454 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
455 CGDisplaySwitchToMode(gGameDisplayID, oldDisplayMode);
456 #else
457 CGError err;
458
459 err = CGDisplaySetDisplayMode(gGameDisplayID, oldDisplayModeRef, NULL);
460 CGDisplayModeRelease(oldDisplayModeRef);
461 #endif
462
463 CGDisplayRelease(gGameDisplayID);
464 }
465
S9xInitWindowMode(void)466 static void S9xInitWindowMode (void)
467 {
468 Rect rct;
469 size_t width, height;
470
471 width = CGDisplayPixelsWide(gGameDisplayID);
472 height = CGDisplayPixelsHigh(gGameDisplayID);
473
474 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
475 CFDictionaryRef mode;
476 boolean_t exactMatch;
477 size_t depth = gl32bit ? 32 : 16;
478
479 oldDisplayMode = CGDisplayCurrentMode(gGameDisplayID);
480 mode = CGDisplayBestModeForParameters(gGameDisplayID, depth, width, height, &exactMatch);
481 if (exactMatch)
482 CGDisplaySwitchToMode(gGameDisplayID, mode);
483 #else
484 oldDisplayModeRef = CGDisplayCopyDisplayMode(gGameDisplayID);
485 SetBestDisplayMode(width, height);
486 #endif
487
488 InitGameWindow();
489 ShowWindow(gWindow);
490
491 GetWindowBounds(gWindow, kWindowContentRgn, &rct);
492 gWindowRect = CGRectMake((float) rct.left, (float) rct.top, (float) (rct.right - rct.left), (float) (rct.bottom - rct.top));
493
494 UpdateGameWindow();
495 }
496
S9xDeinitWindowMode(void)497 static void S9xDeinitWindowMode (void)
498 {
499 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
500 CGDisplaySwitchToMode(gGameDisplayID, oldDisplayMode);
501 #else
502 CGError err;
503
504 err = CGDisplaySetDisplayMode(gGameDisplayID, oldDisplayModeRef, NULL);
505 CGDisplayModeRelease(oldDisplayModeRef);
506 #endif
507
508 UpdateGameWindow();
509 }
510
S9xInitOpenGLFullScreen(void)511 static void S9xInitOpenGLFullScreen (void)
512 {
513 CGOpenGLDisplayMask displayMask;
514 GLint numPixelFormats;
515
516 displayMask = CGDisplayIDToOpenGLDisplayMask(gGameDisplayID);
517 CGLPixelFormatAttribute attribs[] = { (CGLPixelFormatAttribute) kCGLPFAFullScreen,
518 (CGLPixelFormatAttribute) kCGLPFADoubleBuffer,
519 (CGLPixelFormatAttribute) kCGLPFAAccelerated,
520 (CGLPixelFormatAttribute) kCGLPFANoRecovery,
521 (CGLPixelFormatAttribute) kCGLPFAColorSize,
522 (CGLPixelFormatAttribute) (gl32bit ? 32 : 16),
523 (CGLPixelFormatAttribute) kCGLPFADisplayMask,
524 (CGLPixelFormatAttribute) displayMask,
525 (CGLPixelFormatAttribute) 0 };
526
527 CGLChoosePixelFormat(attribs, &cglpix, &numPixelFormats);
528 CGLCreateContext(cglpix, NULL, &glContext);
529 glSwapInterval = vsync ? 1 : 0;
530 if (extraOptions.benchmark)
531 glSwapInterval = 0;
532 CGLSetParameter(glContext, kCGLCPSwapInterval, &glSwapInterval);
533 CGLSetCurrentContext(glContext);
534
535 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
536 CGLSetFullScreen(glContext);
537 #else
538 CGLSetFullScreenOnDisplay(glContext, CGDisplayIDToOpenGLDisplayMask(gGameDisplayID));
539 #endif
540
541 glScreenW = CGDisplayPixelsWide(gGameDisplayID);
542 glScreenH = CGDisplayPixelsHigh(gGameDisplayID);
543 }
544
S9xDeinitOpenGLFullScreen(void)545 static void S9xDeinitOpenGLFullScreen (void)
546 {
547 if (glContext)
548 {
549 CGLSetCurrentContext(NULL);
550 CGLClearDrawable(glContext);
551 CGLDestroyContext(glContext);
552 CGLDestroyPixelFormat(cglpix);
553 }
554 }
555
S9xInitOpenGLWindowMode(void)556 static void S9xInitOpenGLWindowMode (void)
557 {
558 GLint attribs[] = { AGL_RGBA,
559 AGL_DOUBLEBUFFER,
560 AGL_ACCELERATED,
561 AGL_NO_RECOVERY,
562 AGL_PIXEL_SIZE, gl32bit ? 32 : 16,
563 AGL_NONE };
564
565 aglpix = aglChoosePixelFormat(NULL, 0, attribs);
566 agContext = aglCreateContext(aglpix, NULL);
567
568 if (systemVersion >= 0x1050)
569 aglSetWindowRef(agContext, gWindow);
570 #ifdef MAC_TIGER_PANTHER_SUPPORT
571 else
572 aglSetDrawable(agContext, GetWindowPort(gWindow));
573 #endif
574
575 agSwapInterval = vsync ? 1 : 0;
576 if (extraOptions.benchmark)
577 agSwapInterval = 0;
578 aglSetInteger(agContext, AGL_SWAP_INTERVAL, &agSwapInterval);
579 aglSetCurrentContext(agContext);
580
581 if (systemVersion >= 0x1040)
582 {
583 aglGetCGLPixelFormat(aglpix, (void **) &cglpix);
584 aglGetCGLContext(agContext, (void **) &glContext);
585 }
586 }
587
S9xDeinitOpenGLWindowMode(void)588 static void S9xDeinitOpenGLWindowMode (void)
589 {
590 if (agContext)
591 {
592 if (systemVersion >= 0x1050)
593 aglSetWindowRef(agContext, NULL);
594 #ifdef MAC_TIGER_PANTHER_SUPPORT
595 else
596 aglSetDrawable(agContext, NULL);
597 #endif
598
599 aglSetCurrentContext(NULL);
600 aglDestroyContext(agContext);
601 aglDestroyPixelFormat(aglpix);
602 }
603 }
604
S9xInitBlitGL(void)605 static void S9xInitBlitGL (void)
606 {
607 if (multiprocessor)
608 {
609 printf("MP: Creating BlitGL thread.\n");
610
611 if (noErr != PrepareMPBlitGL())
612 multiprocessor = false;
613 }
614 }
615
S9xDeinitBlitGL(void)616 static void S9xDeinitBlitGL (void)
617 {
618 if (multiprocessor)
619 {
620 MPNotifyQueue(taskQueue, (void *) kMPBlitDone, 0, 0);
621 MPWaitOnQueue(notificationQueue, NULL, NULL, NULL, kDurationForever);
622 MPDeleteQueue(notificationQueue);
623 notificationQueue = NULL;
624
625 printf("MP: Successfully received terminate signal from BlitGL thread.\n");
626 }
627 }
628
GLPrepareTexture(bool8 useRange,int texNo,int rangeOnW,int rangeOnH,int rangeOffW,int rangeOffH,int filter)629 static void GLPrepareTexture (bool8 useRange, int texNo, int rangeOnW, int rangeOnH, int rangeOffW, int rangeOffH, int filter)
630 {
631 bool8 rangeAvailable = OpenGL.rangeExt & useRange;
632
633 OpenGL.texW[texNo] = rangeAvailable ? rangeOnW : rangeOffW;
634 OpenGL.texH[texNo] = rangeAvailable ? rangeOnH : rangeOffH;
635
636 OpenGL.vertex[texNo][0] = 0;
637 OpenGL.vertex[texNo][1] = 0;
638 OpenGL.vertex[texNo][2] = rangeAvailable ? rangeOnW : 1;
639 OpenGL.vertex[texNo][3] = 0;
640 OpenGL.vertex[texNo][4] = rangeAvailable ? rangeOnW : 1;
641 OpenGL.vertex[texNo][5] = rangeAvailable ? rangeOnH : 1;
642 OpenGL.vertex[texNo][6] = 0;
643 OpenGL.vertex[texNo][7] = rangeAvailable ? rangeOnH : 1;
644
645 glBindTexture(OpenGL.target, OpenGL.textures[texNo]);
646
647 if (rangeAvailable)
648 {
649 glTextureRangeAPPLE(OpenGL.target, OpenGL.texW[texNo] * OpenGL.texH[texNo] * 2, GFX.Screen);
650 glTexParameteri(OpenGL.target, GL_TEXTURE_STORAGE_HINT_APPLE, OpenGL.storage_hint);
651 }
652
653 glTexParameterf(OpenGL.target, GL_TEXTURE_PRIORITY, OpenGL.agp_texturing);
654 glTexParameteri(OpenGL.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
655 glTexParameteri(OpenGL.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
656 glTexParameteri(OpenGL.target, GL_TEXTURE_MAG_FILTER, filter);
657 glTexParameteri(OpenGL.target, GL_TEXTURE_MIN_FILTER, filter);
658 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
659 glTexImage2D(OpenGL.target, 0, OpenGL.internal_format, OpenGL.texW[texNo], OpenGL.texH[texNo], 0, OpenGL.format, OpenGL.type, GFX.Screen);
660 }
661
GLMakeScreenMesh(GLfloat * vertex3D,int meshx,int meshy)662 static void GLMakeScreenMesh (GLfloat *vertex3D, int meshx, int meshy)
663 {
664 GLfloat *v;
665 float warp;
666
667 v = vertex3D;
668 warp = macCurvatureWarp * 0.001f;
669
670 for (int y = 0; y < meshy; y++)
671 {
672 for (int x = 0; x <= meshx; x++)
673 {
674 float u1, v1, v2;
675
676 u1 = -1.0f + 2.0f / (float) meshx * (float) x;
677 v1 = -1.0f + 2.0f / (float) meshy * (float) y;
678 v2 = -1.0f + 2.0f / (float) meshy * (float) (y + 1);
679
680 *v++ = u1;
681 *v++ = v2;
682 *v++ = -1.0f - (u1 * u1 + v2 * v2) * warp;
683
684 *v++ = u1;
685 *v++ = v1;
686 *v++ = -1.0f - (u1 * u1 + v1 * v1) * warp;
687 }
688 }
689 }
690
GLMakeTextureMesh(GLfloat * vertex2D,int meshx,int meshy,float lx,float ly)691 static void GLMakeTextureMesh (GLfloat *vertex2D, int meshx, int meshy, float lx, float ly)
692 {
693 GLfloat *v;
694
695 v = vertex2D;
696
697 for (int y = meshy; y > 0; y--)
698 {
699 for (int x = 0; x <= meshx; x++)
700 {
701 float u1, v1, v2;
702
703 u1 = lx / (float) meshx * (float) x;
704 v1 = ly / (float) meshy * (float) y;
705 v2 = ly / (float) meshy * (float) (y - 1);
706
707 *v++ = u1;
708 *v++ = v2;
709
710 *v++ = u1;
711 *v++ = v1;
712 }
713 }
714 }
715
S9xInitOpenGLContext(void)716 static void S9xInitOpenGLContext (void)
717 {
718 OpenGL.internal_format = GL_RGB5_A1;
719 OpenGL.format = GL_BGRA;
720 OpenGL.type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
721 OpenGL.rangeExt = gluCheckExtension((const GLubyte *) "GL_APPLE_texture_range", glGetString(GL_EXTENSIONS));
722 OpenGL.target = OpenGL.rangeExt ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D;
723
724 OpenGL.storage_apple = extraOptions.glUseClientStrageApple ? 1 : 0;
725 OpenGL.agp_texturing = extraOptions.glUseTexturePriority ? 0.0f : 1.0f;
726 switch (extraOptions.glStorageHint)
727 {
728 case 1: OpenGL.storage_hint = GL_STORAGE_PRIVATE_APPLE; break;
729 case 2: OpenGL.storage_hint = GL_STORAGE_CACHED_APPLE; break;
730 case 3: OpenGL.storage_hint = GL_STORAGE_SHARED_APPLE; break;
731 }
732
733 if (screencurvature || videoMode >= VIDEOMODE_NTSC_C || extraOptions.glForceNoTextureRectangle)
734 {
735 OpenGL.rangeExt = false;
736 OpenGL.target = GL_TEXTURE_2D;
737 }
738
739 printf("TextureRange: %s\n", OpenGL.rangeExt ? "enable" : "disable");
740
741 glDisable(GL_BLEND);
742 glDisable(GL_DITHER);
743 glDisable(GL_LIGHTING);
744 glDisable(GL_DEPTH_TEST);
745
746 glEnable(GL_CULL_FACE);
747 glPolygonMode(GL_FRONT, GL_FILL);
748 glCullFace(GL_BACK);
749
750 glDisable(GL_TEXTURE_2D);
751 glDisable(GL_TEXTURE_RECTANGLE_EXT);
752 glEnable(OpenGL.target);
753
754 glGenTextures(kGLNumTextures, OpenGL.textures);
755
756 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, OpenGL.storage_apple);
757 glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
758
759 int filter = (videoMode == VIDEOMODE_SMOOTH) ? GL_LINEAR : GL_NEAREST;
760 GLPrepareTexture(true, kGL256256, SNES_WIDTH, SNES_HEIGHT_EXTENDED, 256, 256, filter);
761 GLPrepareTexture(true, kGL256512, SNES_WIDTH, SNES_HEIGHT_EXTENDED * 2, 256, 512, filter);
762 GLPrepareTexture(true, kGL512256, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED, 512, 256, filter);
763 GLPrepareTexture(true, kGL512512, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2, 512, 512, filter);
764 GLPrepareTexture(true, kGLBlit2x, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2, 512, 512, GL_LINEAR);
765 GLPrepareTexture(true, kGLBlit3x, SNES_WIDTH * 3, SNES_HEIGHT_EXTENDED * 3, 1024, 1024, GL_LINEAR);
766 GLPrepareTexture(true, kGLBlit4x, SNES_WIDTH * 4, SNES_HEIGHT_EXTENDED * 4, 1024, 1024, GL_LINEAR);
767 GLPrepareTexture(false, kGLNTS256, 1024, 256, 1024, 256, GL_LINEAR);
768 GLPrepareTexture(false, kGLNTS512, 1024, 512, 1024, 512, GL_LINEAR);
769
770 if (!screencurvature)
771 {
772 glMatrixMode(GL_PROJECTION);
773 glLoadIdentity();
774
775 glMatrixMode(GL_MODELVIEW);
776 glLoadIdentity();
777
778 glDisableClientState(GL_VERTEX_ARRAY);
779 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
780 }
781 else
782 {
783 glMatrixMode(GL_PROJECTION);
784 glLoadIdentity();
785 glFrustum(-1.0, 1.0, -1.0, 1.0, 0.95, 5.0);
786
787 glMatrixMode(GL_MODELVIEW);
788 glLoadIdentity();
789
790 glEnableClientState(GL_VERTEX_ARRAY);
791 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
792
793 int mesh = (kSCMeshX + 1) * 2 * kSCMeshY * 2;
794 scTexArray[kSC2xNormal] = new GLfloat [mesh];
795 scTexArray[kSC2xExtend] = new GLfloat [mesh];
796 scTexArray[kSC2xNHiRes] = new GLfloat [mesh];
797 scTexArray[kSC2xEHiRes] = new GLfloat [mesh];
798 scTexArray[kSC2xNInter] = new GLfloat [mesh];
799 scTexArray[kSC2xEInter] = new GLfloat [mesh];
800 scTexArray[kSC3xNormal] = new GLfloat [mesh];
801 scTexArray[kSC3xExtend] = new GLfloat [mesh];
802 scTexArray[kSC3xNHiRes] = new GLfloat [mesh];
803 scTexArray[kSC3xEHiRes] = new GLfloat [mesh];
804 scTexArray[kSCNTNormal] = new GLfloat [mesh];
805 scTexArray[kSCNTExtend] = new GLfloat [mesh];
806
807 GLMakeTextureMesh(scTexArray[kSC2xNormal], kSCMeshX, kSCMeshY, 1.0f, 224.0f / 256.0f);
808 GLMakeTextureMesh(scTexArray[kSC2xExtend], kSCMeshX, kSCMeshY, 1.0f, 239.0f / 256.0f);
809 GLMakeTextureMesh(scTexArray[kSC2xNHiRes], kSCMeshX, kSCMeshY, 1.0f, 224.0f / 512.0f);
810 GLMakeTextureMesh(scTexArray[kSC2xEHiRes], kSCMeshX, kSCMeshY, 1.0f, 239.0f / 512.0f);
811 GLMakeTextureMesh(scTexArray[kSC2xNInter], kSCMeshX, kSCMeshY, 256.0f / 512.0f, 224.0f / 256.0f);
812 GLMakeTextureMesh(scTexArray[kSC2xEInter], kSCMeshX, kSCMeshY, 256.0f / 512.0f, 239.0f / 256.0f);
813 GLMakeTextureMesh(scTexArray[kSC3xNormal], kSCMeshX, kSCMeshY, 768.0f / 1024.0f, 672.0f / 1024.0f);
814 GLMakeTextureMesh(scTexArray[kSC3xExtend], kSCMeshX, kSCMeshY, 768.0f / 1024.0f, 717.0f / 1024.0f);
815 GLMakeTextureMesh(scTexArray[kSC3xNHiRes], kSCMeshX, kSCMeshY, 768.0f / 1024.0f, 672.0f / 2048.0f);
816 GLMakeTextureMesh(scTexArray[kSC3xEHiRes], kSCMeshX, kSCMeshY, 768.0f / 1024.0f, 717.0f / 2048.0f);
817 GLMakeTextureMesh(scTexArray[kSCNTNormal], kSCMeshX, kSCMeshY, (float) ntsc_width / 1024.0f, 224.0f / 256.0f);
818 GLMakeTextureMesh(scTexArray[kSCNTExtend], kSCMeshX, kSCMeshY, (float) ntsc_width / 1024.0f, 239.0f / 256.0f);
819
820 scScnArray = new GLfloat [(kSCMeshX + 1) * 2 * kSCMeshY * 3];
821 GLMakeScreenMesh(scScnArray, kSCMeshX, kSCMeshY);
822 }
823
824 if (fullscreen)
825 {
826 CGLSetCurrentContext(glContext);
827 glViewport(0, 0, glScreenW, glScreenH);
828 }
829 else
830 {
831 aglSetCurrentContext(agContext);
832 aglUpdateContext(agContext);
833 glViewport(0, 0, (GLsizei) gWindowRect.size.width, (GLsizei) gWindowRect.size.height);
834 }
835
836 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
837
838 for (int i = 0; i < 2; i++)
839 {
840 glClear(GL_COLOR_BUFFER_BIT);
841
842 if (fullscreen)
843 CGLFlushDrawable(glContext);
844 else
845 aglSwapBuffers(agContext);
846 }
847 }
848
S9xDeinitOpenGLContext(void)849 static void S9xDeinitOpenGLContext (void)
850 {
851 if (screencurvature)
852 {
853 delete [] scTexArray[kSC2xNormal];
854 delete [] scTexArray[kSC2xExtend];
855 delete [] scTexArray[kSC2xNHiRes];
856 delete [] scTexArray[kSC2xEHiRes];
857 delete [] scTexArray[kSC2xNInter];
858 delete [] scTexArray[kSC2xEInter];
859 delete [] scTexArray[kSC3xNormal];
860 delete [] scTexArray[kSC3xExtend];
861 delete [] scTexArray[kSC3xNHiRes];
862 delete [] scTexArray[kSC3xEHiRes];
863 delete [] scTexArray[kSCNTNormal];
864 delete [] scTexArray[kSCNTExtend];
865 delete [] scScnArray;
866
867 scTexArray[kSC2xNormal] = NULL;
868 scTexArray[kSC2xExtend] = NULL;
869 scTexArray[kSC2xNHiRes] = NULL;
870 scTexArray[kSC2xEHiRes] = NULL;
871 scTexArray[kSC2xNInter] = NULL;
872 scTexArray[kSC2xEInter] = NULL;
873 scTexArray[kSC3xNormal] = NULL;
874 scTexArray[kSC3xExtend] = NULL;
875 scTexArray[kSC3xNHiRes] = NULL;
876 scTexArray[kSC3xEHiRes] = NULL;
877 scTexArray[kSCNTNormal] = NULL;
878 scTexArray[kSCNTExtend] = NULL;
879 scScnArray = NULL;
880 }
881
882 glDeleteTextures(kGLNumTextures, OpenGL.textures);
883 }
884
S9xInitCoreImage(void)885 static void S9xInitCoreImage (void)
886 {
887 cgGameImage = NULL;
888 cgBlitImage = NULL;
889
890 InitCoreImageContext(glContext, cglpix);
891 }
892
S9xDeinitCoreImage(void)893 static void S9xDeinitCoreImage (void)
894 {
895 DeinitCoreImageContext();
896
897 if (cgGameImage)
898 {
899 CGImageRelease(cgGameImage);
900 cgGameImage = NULL;
901 }
902
903 if (cgBlitImage)
904 {
905 CGImageRelease(cgBlitImage);
906 cgBlitImage = NULL;
907 }
908 }
909
GetGameDisplay(int * w,int * h)910 void GetGameDisplay (int *w, int *h)
911 {
912 CGDisplayErr cgErr;
913 CGDisplayCount numDisplays, maxDisplays = 32;
914 CGDirectDisplayID activeDisplays[32];
915 CGPoint windowAt;
916
917 gGameDisplayID = CGMainDisplayID();
918
919 windowAt = CGPointMake((float) windowPos[kWindowScreen].h, (float) windowPos[kWindowScreen].v);
920
921 cgErr = CGGetDisplaysWithPoint(windowAt, maxDisplays, activeDisplays, &numDisplays);
922 if ((cgErr == noErr) && (numDisplays > 0))
923 {
924 for (unsigned int i = 0; i < numDisplays; i++)
925 {
926 if (activeDisplays[i] != CGMainDisplayID())
927 gGameDisplayID = activeDisplays[i];
928 }
929 }
930
931 if (w != NULL && h != NULL)
932 {
933 *w = CGDisplayPixelsWide(gGameDisplayID);
934 *h = CGDisplayPixelsHigh(gGameDisplayID);
935 }
936 }
937
S9xInitDisplay(int argc,char ** argv)938 void S9xInitDisplay (int argc, char **argv)
939 {
940 if (directDisplay)
941 return;
942
943 GetGameDisplay(NULL, NULL);
944
945 glScreenBounds = CGDisplayBounds(gGameDisplayID);
946
947 unlimitedCursor = CGPointMake(0.0f, 0.0f);
948
949 imageWidth[0] = imageHeight[0] = 0;
950 imageWidth[1] = imageHeight[1] = 0;
951 prevBlitWidth = prevBlitHeight = 0;
952 GFX.Screen = gfxScreen[0];
953 whichBuf = 0;
954 textureNum = 0;
955
956 switch (videoMode)
957 {
958 case VIDEOMODE_HQ4X:
959 nx = 4;
960 break;
961
962 case VIDEOMODE_HQ3X:
963 nx = 3;
964 break;
965
966 case VIDEOMODE_NTSC_C:
967 case VIDEOMODE_NTSC_S:
968 case VIDEOMODE_NTSC_R:
969 case VIDEOMODE_NTSC_M:
970 nx = -1;
971 break;
972
973 case VIDEOMODE_NTSC_TV_C:
974 case VIDEOMODE_NTSC_TV_S:
975 case VIDEOMODE_NTSC_TV_R:
976 case VIDEOMODE_NTSC_TV_M:
977 nx = -2;
978 break;
979
980 default:
981 nx = 2;
982 break;
983 }
984
985 if (fullscreen)
986 {
987 S9xInitFullScreen();
988 S9xInitOpenGLFullScreen();
989 }
990 else
991 {
992 S9xInitWindowMode();
993 S9xInitOpenGLWindowMode();
994 }
995
996 S9xInitOpenGLContext();
997 if (ciFilterEnable)
998 S9xInitCoreImage();
999 if (drawingMethod == kDrawingBlitGL)
1000 S9xInitBlitGL();
1001
1002 S9xSetSoundMute(false);
1003 Microseconds((UnsignedWide *) &lastFrame);
1004
1005 windowResizeCount = 1;
1006
1007 gettimeofday(&bencht1, NULL);
1008
1009 directDisplay = true;
1010 }
1011
S9xDeinitDisplay(void)1012 void S9xDeinitDisplay (void)
1013 {
1014 if (!directDisplay)
1015 return;
1016
1017 S9xSetSoundMute(true);
1018
1019 if (drawingMethod == kDrawingBlitGL)
1020 S9xDeinitBlitGL();
1021 if (ciFilterEnable)
1022 S9xDeinitCoreImage();
1023 S9xDeinitOpenGLContext();
1024
1025 if (fullscreen)
1026 {
1027 S9xDeinitOpenGLFullScreen();
1028 S9xDeinitFullScreen();
1029 }
1030 else
1031 {
1032 S9xDeinitOpenGLWindowMode();
1033 S9xDeinitWindowMode();
1034 }
1035
1036 directDisplay = false;
1037 }
1038
S9xInitUpdate(void)1039 bool8 S9xInitUpdate (void)
1040 {
1041 return (true);
1042 }
1043
S9xDeinitUpdate(int width,int height)1044 bool8 S9xDeinitUpdate (int width, int height)
1045 {
1046 if (directDisplay)
1047 S9xPutImage(width, height);
1048
1049 return (true);
1050 }
1051
S9xContinueUpdate(int width,int height)1052 bool8 S9xContinueUpdate (int width, int height)
1053 {
1054 return (true);
1055 }
1056
RenderBlitScreen(Blitter Fn,int x,int sW,int sH,int cW,int cH,uint16 * buf)1057 static inline void RenderBlitScreen (Blitter Fn, int x, int sW, int sH, int cW, int cH, uint16 *buf)
1058 {
1059 switch (x)
1060 {
1061 case -1:
1062 (Fn) ((uint8 *) buf, sW * 2, blitGLBuffer, 1024 * 2, sW, sH);
1063 break;
1064
1065 case -2:
1066 if (sH > SNES_HEIGHT_EXTENDED)
1067 (Fn) ((uint8 *) buf, sW * 2, blitGLBuffer, 1024 * 2, sW, sH);
1068 else
1069 {
1070 uint8 *tmpBuffer = blitGLBuffer + (1024 * 512 * 2);
1071 int aligned = ((ntsc_width + 2) >> 1) << 1;
1072 (Fn) ((uint8 *) buf, sW * 2, tmpBuffer, 1024 * 2, sW, sH);
1073 S9xBlitPixMixedTV1x2(tmpBuffer, 1024 * 2, blitGLBuffer, 1024 * 2, aligned, cH);
1074 cH *= 2;
1075 }
1076
1077 break;
1078
1079 default:
1080 int dstbytes = (OpenGL.rangeExt ? cW : ((cW > 512) ? 1024 : ((cW > 256) ? 512 : 256))) * 2;
1081 (Fn) ((uint8 *) buf, sW * 2, blitGLBuffer, dstbytes, sW, sH);
1082 break;
1083 }
1084
1085 S9xPutImageBlitGL2(cW, cH);
1086 }
1087
PrepareMPBlitGL(void)1088 static OSStatus PrepareMPBlitGL (void)
1089 {
1090 OSStatus err;
1091
1092 mpBlit = (MPData *) MPAllocateAligned(sizeof(MPData), kMPAllocateDefaultAligned, kMPAllocateClearMask);
1093 if (!mpBlit)
1094 return (memFullErr);
1095
1096 err = MPCreateQueue(¬ificationQueue);
1097 if (err == noErr)
1098 {
1099 err = MPCreateQueue(&taskQueue);
1100 if (err == noErr)
1101 {
1102 err = MPCreateBinarySemaphore(&readySemaphore);
1103 if (err == noErr)
1104 {
1105 MPSignalSemaphore(readySemaphore);
1106 err = MPCreateTask(BlitMPGLTask, NULL, 0, notificationQueue, NULL, NULL, 0, &taskID);
1107 }
1108 }
1109 }
1110
1111 return (err);
1112 }
1113
BlitMPGLTask(void * parameter)1114 static OSStatus BlitMPGLTask (void *parameter)
1115 {
1116 OSStatus err = noErr;
1117 int32 theCommand, param1, param2;
1118
1119 printf("MP: Entered BlitGL thread.\n");
1120
1121 for (;;)
1122 {
1123 err = MPWaitOnQueue(taskQueue, (void **) &theCommand, (void **) ¶m1, (void **) ¶m2, kDurationForever);
1124 if (err)
1125 break;
1126
1127 if (theCommand == kMPBlitFrame)
1128 {
1129 RenderBlitScreen(mpBlit->blitFn, mpBlit->nx, mpBlit->srcWidth, mpBlit->srcHeight, mpBlit->copyWidth, mpBlit->copyHeight, mpBlit->gfxBuffer);
1130 MPSignalSemaphore(readySemaphore);
1131 }
1132 else
1133 if (theCommand == kMPBlitNone)
1134 MPSignalSemaphore(readySemaphore);
1135 else
1136 if (theCommand == kMPBlitDone)
1137 break;
1138 else
1139 {
1140 err = userCanceledErr;
1141 break;
1142 }
1143 }
1144
1145 MPFree(mpBlit);
1146 MPDeleteSemaphore(readySemaphore);
1147 MPDeleteQueue(taskQueue);
1148 mpBlit = NULL;
1149 readySemaphore = NULL;
1150 taskQueue = NULL;
1151
1152 printf("MP: Exited BlitGL thread.\n");
1153
1154 return (err);
1155 }
1156
S9xPutImage(int width,int height)1157 void S9xPutImage (int width, int height)
1158 {
1159 static float fps = 0.0f;
1160 static long count = 0;
1161 static char text[32];
1162
1163 if (extraOptions.benchmark)
1164 {
1165 uint16 *basePtr;
1166 long delta;
1167 size_t len;
1168
1169 count++;
1170
1171 gettimeofday(&bencht2, NULL);
1172
1173 delta = 1000000 * (bencht2.tv_sec - bencht1.tv_sec) + (bencht2.tv_usec - bencht1.tv_usec);
1174 if (delta > 1000000)
1175 {
1176 fps = (1000000.0f * (float) count) / (float) delta;
1177 count = 0;
1178
1179 gettimeofday(&bencht1, NULL);
1180 }
1181
1182 sprintf(text, "%.1f", fps);
1183
1184 basePtr = GFX.Screen + 1;
1185 len = strlen(text);
1186
1187 for (unsigned int i = 0; i < len; i++)
1188 {
1189 S9xDisplayChar(basePtr, text[i]);
1190 basePtr += (8 - 1);
1191 }
1192 }
1193 else
1194 {
1195 if (cfIsWatching)
1196 CheatFinderDrawWatchAddr();
1197
1198 if (Settings.DisplayFrameRate)
1199 {
1200 static int drawnFrames[60] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1201 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
1202 static int tableIndex = 0;
1203 int frameCalc = 0;
1204
1205 drawnFrames[tableIndex] = skipFrames;
1206
1207 if (Settings.TurboMode)
1208 {
1209 drawnFrames[tableIndex] = (drawnFrames[tableIndex] + (macFastForwardRate / 2)) / macFastForwardRate;
1210 if (drawnFrames[tableIndex] == 0)
1211 drawnFrames[tableIndex] = 1;
1212 }
1213
1214 tableIndex = (tableIndex + 1) % 60;
1215
1216 for (int i = 0; i < 60; i++)
1217 frameCalc += drawnFrames[i];
1218
1219 IPPU.DisplayedRenderedFrameCount = (Memory.ROMFramesPerSecond * 60) / frameCalc;
1220 }
1221 }
1222
1223 switch (drawingMethod)
1224 {
1225 case kDrawingOpenGL:
1226 S9xPutImageOpenGL(width, height);
1227 break;
1228
1229 case kDrawingBlitGL:
1230 S9xPutImageBlitGL(width, height);
1231 break;
1232 }
1233 }
1234
S9xPutImageOpenGL(int width,int height)1235 static void S9xPutImageOpenGL (int width, int height)
1236 {
1237 int orig_height = height;
1238
1239 if ((imageWidth[0] != width) || (imageHeight[0] != height))
1240 windowResizeCount += 2;
1241
1242 if (windowResizeCount > 0)
1243 {
1244 if (drawoverscan && (height % SNES_HEIGHT == 0))
1245 {
1246 int pitch = width << 1;
1247 int extbtm = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1248 uint32 *extarea = (uint32 *) ((uint8 *) GFX.Screen + height * pitch);
1249
1250 for (int i = 0; i < (((extbtm - height) * pitch) >> 2); i++)
1251 extarea[i] = 0;
1252
1253 height = extbtm;
1254 }
1255
1256 int vh = (height > 256) ? height : (height << 1);
1257
1258 if (fullscreen)
1259 {
1260 CGLSetCurrentContext(glContext);
1261
1262 glViewport(0, 0, glScreenW, glScreenH);
1263 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1264 glClear(GL_COLOR_BUFFER_BIT);
1265
1266 if (glstretch)
1267 {
1268 float fpw = (float) glScreenH / vh * 512.0f;
1269 int pw = (int) (fpw + ((float) glScreenW - fpw) * (float) macAspectRatio / 10000.0);
1270
1271 glViewport((glScreenW - pw) >> 1, 0, pw, glScreenH);
1272 }
1273 else
1274 glViewport((glScreenW - 512) >> 1, (glScreenH - vh) >> 1, 512, vh);
1275 }
1276 else
1277 {
1278 int ww = (int) gWindowRect.size.width,
1279 wh = (int) gWindowRect.size.height;
1280
1281 aglSetCurrentContext(agContext);
1282 aglUpdateContext(agContext);
1283
1284 glViewport(0, 0, ww, wh);
1285 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1286 glClear(GL_COLOR_BUFFER_BIT);
1287
1288 if (windowExtend)
1289 glViewport(0, ((kMacWindowHeight - vh) >> 1) * wh / kMacWindowHeight, ww, vh * wh / kMacWindowHeight);
1290 }
1291
1292 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1293
1294 if (!ciFilterEnable)
1295 {
1296 textureNum = (width <= 256) ? ((height <= 256) ? kGL256256 : kGL256512) : ((height <= 256) ? kGL512256 : kGL512512);
1297 OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = OpenGL.rangeExt ? height : (vh / 512.0f);
1298 glBindTexture(OpenGL.target, OpenGL.textures[textureNum]);
1299 }
1300 else
1301 {
1302 glMatrixMode(GL_PROJECTION);
1303 glLoadIdentity();
1304 glOrtho(0, width, orig_height - height, orig_height, -1, 1);
1305
1306 if (cgGameImage)
1307 CGImageRelease(cgGameImage);
1308 cgGameImage = CreateGameScreenCGImage();
1309 }
1310
1311 imageWidth[0] = width;
1312 imageHeight[0] = height;
1313
1314 windowResizeCount--;
1315 }
1316 else
1317 {
1318 if (drawoverscan)
1319 height = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1320 }
1321
1322 if (!ciFilterEnable)
1323 {
1324 glTexSubImage2D(OpenGL.target, 0, 0, 0, OpenGL.texW[textureNum], OpenGL.texH[textureNum], OpenGL.format, OpenGL.type, GFX.Screen);
1325
1326 if (!screencurvature)
1327 {
1328 glBegin(GL_QUADS);
1329
1330 glTexCoord2fv(&OpenGL.vertex[textureNum][6]);
1331 glVertex2f(-1.0f, -1.0f);
1332 glTexCoord2fv(&OpenGL.vertex[textureNum][4]);
1333 glVertex2f( 1.0f, -1.0f);
1334 glTexCoord2fv(&OpenGL.vertex[textureNum][2]);
1335 glVertex2f( 1.0f, 1.0f);
1336 glTexCoord2fv(&OpenGL.vertex[textureNum][0]);
1337 glVertex2f(-1.0f, 1.0f);
1338
1339 glEnd();
1340 }
1341 else
1342 {
1343 GLfloat *t, *s;
1344
1345 t = scTexArray[(height % SNES_HEIGHT) ? kSC2xExtend : kSC2xNormal];
1346 s = scScnArray;
1347
1348 for (int i = 0; i < kSCMeshY; i++)
1349 {
1350 glTexCoordPointer(2, GL_FLOAT, 0, t);
1351 glVertexPointer(3, GL_FLOAT, 0, s);
1352 glDrawArrays(GL_TRIANGLE_STRIP, 0, (kSCMeshX + 1) * 2);
1353
1354 t += (kSCMeshX + 1) * 2 * 2;
1355 s += (kSCMeshX + 1) * 2 * 3;
1356 }
1357 }
1358
1359 glFinishObjectAPPLE(GL_TEXTURE, OpenGL.textures[textureNum]);
1360 }
1361 else
1362 {
1363 CGRect src;
1364
1365 src = CGRectMake(0, 0, width, orig_height);
1366 DrawWithCoreImageFilter(src, cgGameImage);
1367 }
1368
1369 if (fullscreen)
1370 CGLFlushDrawable(glContext);
1371 else
1372 aglSwapBuffers(agContext);
1373 }
1374
S9xPutImageBlitGL(int width,int height)1375 static void S9xPutImageBlitGL (int width, int height)
1376 {
1377 Blitter blitFn;
1378 int copyWidth, copyHeight;
1379
1380 if ((imageWidth[whichBuf] != width) || (imageHeight[whichBuf] != height))
1381 {
1382 if ((videoMode == VIDEOMODE_TV) && (width <= 256))
1383 S9xBlitClearDelta();
1384
1385 if (drawoverscan && (height % SNES_HEIGHT == 0))
1386 {
1387 memset(blitGLBuffer, 0, 1024 * 1024 * 2);
1388
1389 int pitch = width << 1;
1390 int extbtm = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1391 uint32 *extarea = (uint32 *) ((uint8 *) GFX.Screen + height * pitch);
1392
1393 for (int i = 0; i < (((extbtm - height) * pitch) >> 2); i++)
1394 extarea[i] = 0;
1395
1396 height = extbtm;
1397 }
1398 }
1399 else
1400 {
1401 if (drawoverscan)
1402 height = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1403 }
1404
1405 switch (nx)
1406 {
1407 default:
1408 case 2:
1409 if (videoMode == VIDEOMODE_BLEND)
1410 {
1411 if (width <= 256)
1412 {
1413 copyWidth = width * 2;
1414 copyHeight = height;
1415 blitFn = S9xBlitPixBlend2x1;
1416 }
1417 else
1418 {
1419 copyWidth = width;
1420 copyHeight = height;
1421 blitFn = S9xBlitPixBlend1x1;
1422 }
1423 }
1424 else
1425 if (height <= 256)
1426 {
1427 if (width <= 256)
1428 {
1429 copyWidth = width * 2;
1430 copyHeight = height * 2;
1431
1432 switch (videoMode)
1433 {
1434 default:
1435 case VIDEOMODE_TV: blitFn = S9xBlitPixTV2x2; break;
1436 case VIDEOMODE_SUPEREAGLE: blitFn = S9xBlitPixSuperEagle16; break;
1437 case VIDEOMODE_2XSAI: blitFn = S9xBlitPix2xSaI16; break;
1438 case VIDEOMODE_SUPER2XSAI: blitFn = S9xBlitPixSuper2xSaI16; break;
1439 case VIDEOMODE_EPX: blitFn = S9xBlitPixEPX16; break;
1440 case VIDEOMODE_HQ2X: blitFn = S9xBlitPixHQ2x16; break;
1441 }
1442 }
1443 else
1444 {
1445 if (videoMode == VIDEOMODE_TV)
1446 {
1447 copyWidth = width;
1448 copyHeight = height * 2;
1449 blitFn = S9xBlitPixTV1x2;
1450 }
1451 else
1452 {
1453 copyWidth = width;
1454 copyHeight = height;
1455 blitFn = S9xBlitPixSimple1x1;
1456 }
1457 }
1458 }
1459 else
1460 {
1461 copyWidth = width;
1462 copyHeight = height;
1463 blitFn = S9xBlitPixSimple1x1;
1464 }
1465
1466 break;
1467
1468 case 3:
1469 if (width <= 256 && height <= 256)
1470 {
1471 copyWidth = width * 3;
1472 copyHeight = height * 3;
1473 blitFn = S9xBlitPixHQ3x16;
1474 }
1475 else
1476 {
1477 copyWidth = width;
1478 copyHeight = height;
1479 blitFn = S9xBlitPixSimple1x1;
1480 }
1481
1482 break;
1483
1484 case 4:
1485 if (width <= 256 && height <= 256)
1486 {
1487 copyWidth = width * 4;
1488 copyHeight = height * 4;
1489 blitFn = S9xBlitPixHQ4x16;
1490 }
1491 else
1492 if (width > 256 && height > 256)
1493 {
1494 copyWidth = width * 2;
1495 copyHeight = height * 2;
1496 blitFn = S9xBlitPixHQ2x16;
1497 }
1498 else
1499 {
1500 copyWidth = width;
1501 copyHeight = height;
1502 blitFn = S9xBlitPixSimple1x1;
1503 }
1504
1505 break;
1506
1507 case -1:
1508 case -2:
1509 copyWidth = ntsc_width;
1510 copyHeight = height;
1511
1512 if (width <= 256)
1513 blitFn = S9xBlitPixNTSC16;
1514 else
1515 blitFn = S9xBlitPixHiResNTSC16;
1516
1517 break;
1518 }
1519
1520 imageWidth[whichBuf] = width;
1521 imageHeight[whichBuf] = height;
1522
1523 if (multiprocessor)
1524 {
1525 MPWaitOnSemaphore(readySemaphore, kDurationForever);
1526
1527 mpBlit->nx = nx;
1528 mpBlit->blitFn = blitFn;
1529 mpBlit->srcWidth = width;
1530 mpBlit->srcHeight = height;
1531 mpBlit->copyWidth = copyWidth;
1532 mpBlit->copyHeight = copyHeight;
1533 mpBlit->gfxBuffer = GFX.Screen;
1534
1535 MPNotifyQueue(taskQueue, (void *) kMPBlitFrame, 0, 0);
1536
1537 whichBuf = 1 - whichBuf;
1538 GFX.Screen = gfxScreen[whichBuf];
1539 }
1540 else
1541 RenderBlitScreen(blitFn, nx, width, height, copyWidth, copyHeight, GFX.Screen);
1542 }
1543
S9xPutImageBlitGL2(int blit_width,int blit_height)1544 static void S9xPutImageBlitGL2 (int blit_width, int blit_height)
1545 {
1546 if ((prevBlitWidth != blit_width) || (prevBlitHeight != blit_height))
1547 windowResizeCount += 2;
1548
1549 if (windowResizeCount > 0)
1550 {
1551 if (fullscreen)
1552 {
1553 CGLSetCurrentContext(glContext);
1554
1555 glViewport(0, 0, glScreenW, glScreenH);
1556 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1557 glClear(GL_COLOR_BUFFER_BIT);
1558
1559 if (glstretch)
1560 {
1561 int sh = (blit_width < blit_height) ? (blit_height >> 1) : ((blit_width > blit_height * 2) ? (blit_height << 1) : blit_height);
1562 float fpw = (float) glScreenH / (float) sh * (float) blit_width;
1563 int pw = (int) (fpw + ((float) glScreenW - fpw) * (float) macAspectRatio / 10000.0);
1564
1565 glViewport((glScreenW - pw) >> 1, 0, pw, glScreenH);
1566 }
1567 else
1568 {
1569 int sw, sh;
1570
1571 if (nx < 0)
1572 {
1573 sw = ntsc_width;
1574 sh = ((blit_height % SNES_HEIGHT) ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * 2;
1575 }
1576 else
1577 {
1578 sw = SNES_WIDTH * nx;
1579 sh = ((blit_height % SNES_HEIGHT) ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * nx;
1580 }
1581
1582 glViewport((glScreenW - sw) >> 1, (glScreenH - sh) >> 1, sw, sh);
1583 }
1584 }
1585 else
1586 {
1587 int ww = (int) gWindowRect.size.width,
1588 wh = (int) gWindowRect.size.height;
1589
1590 aglSetCurrentContext(agContext);
1591 aglUpdateContext(agContext);
1592
1593 glViewport(0, 0, ww, wh);
1594 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1595 glClear(GL_COLOR_BUFFER_BIT);
1596
1597 if (windowExtend)
1598 {
1599 int bh = (blit_height % SNES_HEIGHT) ? (SNES_HEIGHT_EXTENDED << 1) : (SNES_HEIGHT << 1);
1600 glViewport(0, ((kMacWindowHeight - bh) >> 1) * wh / kMacWindowHeight, ww, bh * wh / kMacWindowHeight);
1601 }
1602 }
1603
1604 if (!ciFilterEnable)
1605 {
1606 if (nx < 0)
1607 textureNum = (blit_height > 256) ? kGLNTS512 : kGLNTS256;
1608 else
1609 {
1610 switch (blit_width / SNES_WIDTH)
1611 {
1612 default:
1613 case 1:
1614 case 2: textureNum = kGLBlit2x; break;
1615 case 3: textureNum = kGLBlit3x; break;
1616 case 4: textureNum = kGLBlit4x; break;
1617 }
1618 }
1619
1620 if (nx < 0)
1621 {
1622 int sh = (blit_height > 256) ? 512 : 256;
1623 OpenGL.vertex[textureNum][2] = OpenGL.vertex[textureNum][4] = blit_width / 1024.0f;
1624 OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = blit_height / (float) sh;
1625 glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024);
1626 }
1627 else
1628 {
1629 if (OpenGL.rangeExt)
1630 {
1631 OpenGL.vertex[textureNum][2] = OpenGL.vertex[textureNum][4] = blit_width;
1632 OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = blit_height;
1633 glPixelStorei(GL_UNPACK_ROW_LENGTH, blit_width);
1634 }
1635 else
1636 {
1637 int sl = (blit_width > 512) ? 1024 : 512;
1638 int sh = (blit_height > 512) ? 1024 : 512;
1639 OpenGL.vertex[textureNum][2] = OpenGL.vertex[textureNum][4] = blit_width / (float) sl;
1640 OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = blit_height / (float) sh;
1641 glPixelStorei(GL_UNPACK_ROW_LENGTH, (blit_width > 512) ? 1024 : ((blit_width > 256) ? 512 : 256));
1642 }
1643 }
1644
1645 glBindTexture(OpenGL.target, OpenGL.textures[textureNum]);
1646 }
1647 else
1648 {
1649 int sl = OpenGL.rangeExt ? blit_width : ((blit_width > 512) ? 1024 : ((blit_width > 256) ? 512 : 256));
1650
1651 glPixelStorei(GL_UNPACK_ROW_LENGTH, sl);
1652 glMatrixMode(GL_PROJECTION);
1653 glLoadIdentity();
1654 glOrtho(0, blit_width, 0, blit_height, -1, 1);
1655
1656 if (cgBlitImage)
1657 CGImageRelease(cgBlitImage);
1658 cgBlitImage = CreateBlitScreenCGImage(blit_width, blit_height, sl << 1, blitGLBuffer);
1659 }
1660
1661 prevBlitWidth = blit_width;
1662 prevBlitHeight = blit_height;
1663
1664 windowResizeCount--;
1665 }
1666
1667 if (!ciFilterEnable)
1668 {
1669 glTexSubImage2D(OpenGL.target, 0, 0, 0, OpenGL.texW[textureNum], OpenGL.texH[textureNum], OpenGL.format, OpenGL.type, blitGLBuffer);
1670
1671 if (!screencurvature)
1672 {
1673 glBegin(GL_QUADS);
1674
1675 glTexCoord2fv(&OpenGL.vertex[textureNum][6]);
1676 glVertex2f(-1.0f, -1.0f);
1677 glTexCoord2fv(&OpenGL.vertex[textureNum][4]);
1678 glVertex2f( 1.0f, -1.0f);
1679 glTexCoord2fv(&OpenGL.vertex[textureNum][2]);
1680 glVertex2f( 1.0f, 1.0f);
1681 glTexCoord2fv(&OpenGL.vertex[textureNum][0]);
1682 glVertex2f(-1.0f, 1.0f);
1683
1684 glEnd();
1685 }
1686 else
1687 {
1688 GLfloat *t, *s;
1689 int tex;
1690
1691 if (nx < 0)
1692 tex = (blit_height % SNES_HEIGHT) ? kSCNTExtend : kSCNTNormal;
1693 else
1694 if (blit_width > blit_height * 2)
1695 {
1696 if (blit_width / SNES_WIDTH != 3)
1697 tex = (blit_height % SNES_HEIGHT) ? kSC2xEHiRes : kSC2xNHiRes;
1698 else
1699 tex = (blit_height % SNES_HEIGHT) ? kSC3xEHiRes : kSC3xNHiRes;
1700 }
1701 else
1702 if (blit_width > blit_height)
1703 {
1704 if (blit_width / SNES_WIDTH != 3)
1705 tex = (blit_height % SNES_HEIGHT) ? kSC2xExtend : kSC2xNormal;
1706 else
1707 tex = (blit_height % SNES_HEIGHT) ? kSC3xExtend : kSC3xNormal;
1708 }
1709 else
1710 tex = (blit_height % SNES_HEIGHT) ? kSC2xEInter : kSC2xNInter;
1711
1712 t = scTexArray[tex];
1713 s = scScnArray;
1714
1715 for (int i = 0; i < kSCMeshY; i++)
1716 {
1717 glTexCoordPointer(2, GL_FLOAT, 0, t);
1718 glVertexPointer(3, GL_FLOAT, 0, s);
1719 glDrawArrays(GL_TRIANGLE_STRIP, 0, (kSCMeshX + 1) * 2);
1720
1721 t += (kSCMeshX + 1) * 2 * 2;
1722 s += (kSCMeshX + 1) * 2 * 3;
1723 }
1724 }
1725
1726 glFinishObjectAPPLE(GL_TEXTURE, OpenGL.textures[textureNum]);
1727 }
1728 else
1729 {
1730 CGRect src;
1731
1732 src = CGRectMake(0, 0, blit_width, blit_height);
1733 DrawWithCoreImageFilter(src, cgBlitImage);
1734 }
1735
1736 if (fullscreen)
1737 CGLFlushDrawable(glContext);
1738 else
1739 aglSwapBuffers(agContext);
1740 }
1741
S9xTextMode(void)1742 void S9xTextMode (void)
1743 {
1744 return;
1745 }
1746
S9xGraphicsMode(void)1747 void S9xGraphicsMode (void)
1748 {
1749 return;
1750 }
1751
S9xSetPalette(void)1752 void S9xSetPalette (void)
1753 {
1754 return;
1755 }
1756