1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20
21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
22
23 (c) Copyright 2006 - 2007 nitsuja
24
25 (c) Copyright 2009 - 2016 BearOso,
26 OV2
27
28
29 BS-X C emulator code
30 (c) Copyright 2005 - 2006 Dreamer Nom,
31 zones
32
33 C4 x86 assembler and some C emulation code
34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
35 Nach,
36 zsKnight (zsknight@zsnes.com)
37
38 C4 C++ code
39 (c) Copyright 2003 - 2006 Brad Jorsch,
40 Nach
41
42 DSP-1 emulator code
43 (c) Copyright 1998 - 2006 _Demo_,
44 Andreas Naive (andreasnaive@gmail.com),
45 Gary Henderson,
46 Ivar (ivar@snes9x.com),
47 John Weidman,
48 Kris Bleakley,
49 Matthew Kendora,
50 Nach,
51 neviksti (neviksti@hotmail.com)
52
53 DSP-2 emulator code
54 (c) Copyright 2003 John Weidman,
55 Kris Bleakley,
56 Lord Nightmare (lord_nightmare@users.sourceforge.net),
57 Matthew Kendora,
58 neviksti
59
60 DSP-3 emulator code
61 (c) Copyright 2003 - 2006 John Weidman,
62 Kris Bleakley,
63 Lancer,
64 z80 gaiden
65
66 DSP-4 emulator code
67 (c) Copyright 2004 - 2006 Dreamer Nom,
68 John Weidman,
69 Kris Bleakley,
70 Nach,
71 z80 gaiden
72
73 OBC1 emulator code
74 (c) Copyright 2001 - 2004 zsKnight,
75 pagefault (pagefault@zsnes.com),
76 Kris Bleakley
77 Ported from x86 assembler to C by sanmaiwashi
78
79 SPC7110 and RTC C++ emulator code used in 1.39-1.51
80 (c) Copyright 2002 Matthew Kendora with research by
81 zsKnight,
82 John Weidman,
83 Dark Force
84
85 SPC7110 and RTC C++ emulator code used in 1.52+
86 (c) Copyright 2009 byuu,
87 neviksti
88
89 S-DD1 C emulator code
90 (c) Copyright 2003 Brad Jorsch with research by
91 Andreas Naive,
92 John Weidman
93
94 S-RTC C emulator code
95 (c) Copyright 2001 - 2006 byuu,
96 John Weidman
97
98 ST010 C++ emulator code
99 (c) Copyright 2003 Feather,
100 John Weidman,
101 Kris Bleakley,
102 Matthew Kendora
103
104 Super FX x86 assembler emulator code
105 (c) Copyright 1998 - 2003 _Demo_,
106 pagefault,
107 zsKnight
108
109 Super FX C emulator code
110 (c) Copyright 1997 - 1999 Ivar,
111 Gary Henderson,
112 John Weidman
113
114 Sound emulator code used in 1.5-1.51
115 (c) Copyright 1998 - 2003 Brad Martin
116 (c) Copyright 1998 - 2006 Charles Bilyue'
117
118 Sound emulator code used in 1.52+
119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
120
121 S-SMP emulator code used in 1.54+
122 (c) Copyright 2016 byuu
123
124 SH assembler code partly based on x86 assembler code
125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
126
127 2xSaI filter
128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
129
130 HQ2x, HQ3x, HQ4x filters
131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
132
133 NTSC filter
134 (c) Copyright 2006 - 2007 Shay Green
135
136 GTK+ GUI code
137 (c) Copyright 2004 - 2016 BearOso
138
139 Win32 GUI code
140 (c) Copyright 2003 - 2006 blip,
141 funkyass,
142 Matthew Kendora,
143 Nach,
144 nitsuja
145 (c) Copyright 2009 - 2016 OV2
146
147 Mac OS GUI code
148 (c) Copyright 1998 - 2001 John Stiles
149 (c) Copyright 2001 - 2011 zones
150
151
152 Specific ports contains the works of other authors. See headers in
153 individual files.
154
155
156 Snes9x homepage: http://www.snes9x.com/
157
158 Permission to use, copy, modify and/or distribute Snes9x in both binary
159 and source form, for non-commercial purposes, is hereby granted without
160 fee, providing that this license information and copyright notice appear
161 with all copies and any derived work.
162
163 This software is provided 'as-is', without any express or implied
164 warranty. In no event shall the authors be held liable for any damages
165 arising from the use of this software or it's derivatives.
166
167 Snes9x is freeware for PERSONAL USE only. Commercial users should
168 seek permission of the copyright holders first. Commercial use includes,
169 but is not limited to, charging money for Snes9x or software derived from
170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171 using Snes9x as a promotion for your commercial product.
172
173 The copyright holders request that bug fixes and improvements to the code
174 should be forwarded to them so everyone can benefit from the modifications
175 in future versions.
176
177 Super NES and Super Nintendo Entertainment System are trademarks of
178 Nintendo Co., Limited and its subsidiary companies.
179 ***********************************************************************************/
180
181 /***********************************************************************************
182 SNES9X for Mac OS (c) Copyright John Stiles
183
184 Snes9x for Mac OS X
185
186 (c) Copyright 2001 - 2011 zones
187 (c) Copyright 2002 - 2005 107
188 (c) Copyright 2002 PB1400c
189 (c) Copyright 2004 Alexander and Sander
190 (c) Copyright 2004 - 2005 Steven Seeger
191 (c) Copyright 2005 Ryan Vogt
192 ***********************************************************************************/
193
194
195 #include "snes9x.h"
196 #include "memmap.h"
197 #include "screenshot.h"
198
199 #include <QuickTime/QuickTime.h>
200
201 #include "mac-prefix.h"
202 #include "mac-file.h"
203 #include "mac-gworld.h"
204 #include "mac-os.h"
205 #include "mac-render.h"
206 #include "mac-screenshot.h"
207
208 static Handle GetScreenAsRawHandle (int, int);
209 static void ExportCGImageToPNGFile (CGImageRef, const char *);
210
211
GetScreenAsRawHandle(int destWidth,int destHeight)212 static Handle GetScreenAsRawHandle (int destWidth, int destHeight)
213 {
214 CGContextRef ctx;
215 CGColorSpaceRef color;
216 CGImageRef image;
217 Handle data = NULL;
218
219 image = CreateGameScreenCGImage();
220 if (image)
221 {
222 data = NewHandleClear(destWidth * destHeight * 2);
223 if (data)
224 {
225 HLock(data);
226
227 color = CGColorSpaceCreateDeviceRGB();
228 if (color)
229 {
230 ctx = CGBitmapContextCreate(*data, destWidth, destHeight, 5, destWidth * 2, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Big : 0));
231 if (ctx)
232 {
233 CGContextDrawImage(ctx, CGRectMake(0.0f, 0.0f, (float) destWidth, (float) destHeight), image);
234 CGContextRelease(ctx);
235 }
236
237 CGColorSpaceRelease(color);
238 }
239
240 HUnlock(data);
241 }
242
243 CGImageRelease(image);
244 }
245
246 return (data);
247 }
248
WriteThumbnailToResourceFork(FSRef * ref,int destWidth,int destHeight)249 void WriteThumbnailToResourceFork (FSRef *ref, int destWidth, int destHeight)
250 {
251 OSStatus err;
252 HFSUniStr255 fork;
253 SInt16 resf;
254
255 err = FSGetResourceForkName(&fork);
256 if (err == noErr)
257 {
258 err = FSCreateResourceFork(ref, fork.length, fork.unicode, 0);
259 if ((err == noErr) || (err == errFSForkExists))
260 {
261 err = FSOpenResourceFile(ref, fork.length, fork.unicode, fsWrPerm, &resf);
262 if (err == noErr)
263 {
264 Handle pict;
265
266 pict = GetScreenAsRawHandle(destWidth, destHeight);
267 if (pict)
268 {
269 AddResource(pict, 'Thum', 128, "\p");
270 WriteResource(pict);
271 ReleaseResource(pict);
272 }
273
274 CloseResFile(resf);
275 }
276 }
277 }
278 }
279
ExportCGImageToPNGFile(CGImageRef image,const char * path)280 static void ExportCGImageToPNGFile (CGImageRef image, const char *path)
281 {
282 OSStatus err;
283 GraphicsExportComponent exporter;
284 CFStringRef str;
285 CFURLRef url;
286 Handle dataRef;
287 OSType dataRefType;
288
289 str = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
290 if (str)
291 {
292 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLPOSIXPathStyle, false);
293 if (url)
294 {
295 err = QTNewDataReferenceFromCFURL(url, 0, &dataRef, &dataRefType);
296 if (err == noErr)
297 {
298 err = OpenADefaultComponent(GraphicsExporterComponentType, kQTFileTypePNG, &exporter);
299 if (err == noErr)
300 {
301 err = GraphicsExportSetInputCGImage(exporter, image);
302 if (err == noErr)
303 {
304 err = GraphicsExportSetOutputDataReference(exporter, dataRef, dataRefType);
305 if (err == noErr)
306 err = GraphicsExportDoExport(exporter, NULL);
307 }
308
309 CloseComponent(exporter);
310 }
311
312 DisposeHandle(dataRef);
313 }
314
315 CFRelease(url);
316 }
317
318 CFRelease(str);
319 }
320 }
321
CreateGameScreenCGImage(void)322 CGImageRef CreateGameScreenCGImage (void)
323 {
324 CGDataProviderRef prov;
325 CGColorSpaceRef color;
326 CGImageRef image = NULL;
327 int rowbytes;
328
329 rowbytes = IPPU.RenderedScreenWidth * 2;
330
331 prov = CGDataProviderCreateWithData(NULL, GFX.Screen, 512 * 2 * 478, NULL);
332 if (prov)
333 {
334 color = CGColorSpaceCreateDeviceRGB();
335 if (color)
336 {
337 image = CGImageCreate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, 5, 16, rowbytes, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0), prov, NULL, 1, kCGRenderingIntentDefault);
338 CGColorSpaceRelease(color);
339 }
340
341 CGDataProviderRelease(prov);
342 }
343
344 return (image);
345 }
346
CreateBlitScreenCGImage(int width,int height,int rowbytes,uint8 * buffer)347 CGImageRef CreateBlitScreenCGImage (int width, int height, int rowbytes, uint8 *buffer)
348 {
349 CGDataProviderRef prov;
350 CGColorSpaceRef color;
351 CGImageRef image = NULL;
352
353 prov = CGDataProviderCreateWithData(NULL, buffer, rowbytes * height, NULL);
354 if (prov)
355 {
356 color = CGColorSpaceCreateDeviceRGB();
357 if (color)
358 {
359 image = CGImageCreate(width, height, 5, 16, rowbytes, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0), prov, NULL, 1, kCGRenderingIntentDefault);
360 CGColorSpaceRelease(color);
361 }
362
363 CGDataProviderRelease(prov);
364 }
365
366 return (image);
367 }
368
DrawThumbnailResource(FSRef * ref,CGContextRef ctx,CGRect bounds)369 void DrawThumbnailResource (FSRef *ref, CGContextRef ctx, CGRect bounds)
370 {
371 OSStatus err;
372 CGDataProviderRef prov;
373 CGColorSpaceRef color;
374 CGImageRef image;
375 QDPictRef qdpr;
376 Handle pict;
377 HFSUniStr255 fork;
378 SInt16 resf;
379 Size size;
380
381 CGContextSaveGState(ctx);
382
383 CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
384 CGContextFillRect(ctx, bounds);
385
386 err = FSGetResourceForkName(&fork);
387 if (err == noErr)
388 {
389 err = FSOpenResourceFile(ref, fork.length, fork.unicode, fsRdPerm, &resf);
390 if (err == noErr)
391 {
392 pict = Get1Resource('PICT', 128);
393 if (pict)
394 {
395 HLock(pict);
396
397 size = GetHandleSize(pict);
398 prov = CGDataProviderCreateWithData(NULL, (void *) *pict, size, NULL);
399 if (prov)
400 {
401 qdpr = QDPictCreateWithProvider(prov);
402 if (qdpr)
403 {
404 QDPictDrawToCGContext(ctx, bounds, qdpr);
405 QDPictRelease(qdpr);
406 }
407
408 CGDataProviderRelease(prov);
409 }
410
411 HUnlock(pict);
412 ReleaseResource(pict);
413 }
414 else
415 {
416 pict = Get1Resource('Thum', 128);
417 if (pict)
418 {
419 HLock(pict);
420
421 size = GetHandleSize(pict);
422 prov = CGDataProviderCreateWithData(NULL, (void *) *pict, size, NULL);
423 if (prov)
424 {
425 color = CGColorSpaceCreateDeviceRGB();
426 if (color)
427 {
428 image = CGImageCreate(128, 120, 5, 16, 256, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Big : 0), prov, NULL, 0, kCGRenderingIntentDefault);
429 if (image)
430 {
431 CGContextDrawImage(ctx, bounds, image);
432 CGImageRelease(image);
433 }
434
435 CGColorSpaceRelease(color);
436 }
437
438 CGDataProviderRelease(prov);
439 }
440
441 HUnlock(pict);
442 ReleaseResource(pict);
443 }
444 }
445
446 CloseResFile(resf);
447 }
448 }
449
450 CGContextRestoreGState(ctx);
451 }
452
S9xDoScreenshot(int width,int height)453 bool8 S9xDoScreenshot (int width, int height)
454 {
455 Settings.TakeScreenshot = false;
456
457 uint16 *data;
458
459 data = (uint16 *) malloc(512 * 478 * 2);
460 if (data)
461 {
462 uint16 *sp, *dp;
463
464 if (width > 256 && height > 239)
465 {
466 for (int y = 0; y < height; y++)
467 {
468 sp = GFX.Screen + y * GFX.RealPPL;
469 dp = data + y * 512;
470
471 for (int x = 0; x < width; x++)
472 *dp++ = *sp++;
473 }
474 }
475 else
476 if (width > 256)
477 {
478 for (int y = 0; y < height; y++)
479 {
480 sp = GFX.Screen + y * GFX.RealPPL;
481 dp = data + y * 2 * 512;
482
483 for (int x = 0; x < width; x++)
484 {
485 *dp = *(dp + 512) = *sp++;
486 dp++;
487 }
488 }
489 }
490 else
491 {
492 for (int y = 0; y < height; y++)
493 {
494 sp = GFX.Screen + y * GFX.RealPPL;
495 dp = data + y * 2 * 512;
496
497 for (int x = 0; x < width; x++)
498 {
499 *dp = *(dp + 1) = *(dp + 512) = *(dp + 512 + 1) = *sp++;
500 dp += 2;
501 }
502 }
503 }
504
505 CGImageRef image;
506
507 image = CreateBlitScreenCGImage(512, (height > 239) ? height : (height * 2), 1024, (uint8 *) data);
508 if (image)
509 {
510 ExportCGImageToPNGFile(image, S9xGetPNGFilename());
511 CGImageRelease(image);
512 }
513
514 free(data);
515 }
516
517 return (true);
518 }
519