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 "screenshot.h"
24
25 #include <QuickTime/QuickTime.h>
26
27 #include "mac-prefix.h"
28 #include "mac-file.h"
29 #include "mac-gworld.h"
30 #include "mac-os.h"
31 #include "mac-render.h"
32 #include "mac-screenshot.h"
33
34 static Handle GetScreenAsRawHandle (int, int);
35 static void ExportCGImageToPNGFile (CGImageRef, const char *);
36
37 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
38 typedef struct QDPict* QDPictRef;
39 extern "C" QDPictRef QDPictCreateWithProvider (CGDataProviderRef provider);
40 extern "C" void QDPictRelease (QDPictRef pictRef);
41 extern "C" OSStatus QDPictDrawToCGContext (CGContextRef ctx, CGRect rect, QDPictRef pictRef);
42 #endif
43
GetScreenAsRawHandle(int destWidth,int destHeight)44 static Handle GetScreenAsRawHandle (int destWidth, int destHeight)
45 {
46 CGContextRef ctx;
47 CGColorSpaceRef color;
48 CGImageRef image;
49 Handle data = NULL;
50
51 image = CreateGameScreenCGImage();
52 if (image)
53 {
54 data = NewHandleClear(destWidth * destHeight * 2);
55 if (data)
56 {
57 HLock(data);
58
59 color = CGColorSpaceCreateDeviceRGB();
60 if (color)
61 {
62 ctx = CGBitmapContextCreate(*data, destWidth, destHeight, 5, destWidth * 2, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Big : 0));
63 if (ctx)
64 {
65 CGContextDrawImage(ctx, CGRectMake(0.0f, 0.0f, (float) destWidth, (float) destHeight), image);
66 CGContextRelease(ctx);
67 }
68
69 CGColorSpaceRelease(color);
70 }
71
72 HUnlock(data);
73 }
74
75 CGImageRelease(image);
76 }
77
78 return (data);
79 }
80
WriteThumbnailToResourceFork(FSRef * ref,int destWidth,int destHeight)81 void WriteThumbnailToResourceFork (FSRef *ref, int destWidth, int destHeight)
82 {
83 OSStatus err;
84 HFSUniStr255 fork;
85 SInt16 resf;
86
87 err = FSGetResourceForkName(&fork);
88 if (err == noErr)
89 {
90 err = FSCreateResourceFork(ref, fork.length, fork.unicode, 0);
91 if ((err == noErr) || (err == errFSForkExists))
92 {
93 err = FSOpenResourceFile(ref, fork.length, fork.unicode, fsWrPerm, &resf);
94 if (err == noErr)
95 {
96 Handle pict;
97
98 pict = GetScreenAsRawHandle(destWidth, destHeight);
99 if (pict)
100 {
101 AddResource(pict, 'Thum', 128, "\p");
102 WriteResource(pict);
103 ReleaseResource(pict);
104 }
105
106 CloseResFile(resf);
107 }
108 }
109 }
110 }
111
ExportCGImageToPNGFile(CGImageRef image,const char * path)112 static void ExportCGImageToPNGFile (CGImageRef image, const char *path)
113 {
114 OSStatus err;
115 GraphicsExportComponent exporter;
116 CFStringRef str;
117 CFURLRef url;
118 Handle dataRef;
119 OSType dataRefType;
120
121 str = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
122 if (str)
123 {
124 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLPOSIXPathStyle, false);
125 if (url)
126 {
127 err = QTNewDataReferenceFromCFURL(url, 0, &dataRef, &dataRefType);
128 if (err == noErr)
129 {
130 err = OpenADefaultComponent(GraphicsExporterComponentType, kQTFileTypePNG, &exporter);
131 if (err == noErr)
132 {
133 err = GraphicsExportSetInputCGImage(exporter, image);
134 if (err == noErr)
135 {
136 err = GraphicsExportSetOutputDataReference(exporter, dataRef, dataRefType);
137 if (err == noErr)
138 err = GraphicsExportDoExport(exporter, NULL);
139 }
140
141 CloseComponent(exporter);
142 }
143
144 DisposeHandle(dataRef);
145 }
146
147 CFRelease(url);
148 }
149
150 CFRelease(str);
151 }
152 }
153
CreateGameScreenCGImage(void)154 CGImageRef CreateGameScreenCGImage (void)
155 {
156 CGDataProviderRef prov;
157 CGColorSpaceRef color;
158 CGImageRef image = NULL;
159 int rowbytes;
160
161 rowbytes = IPPU.RenderedScreenWidth * 2;
162
163 prov = CGDataProviderCreateWithData(NULL, GFX.Screen, 512 * 2 * 478, NULL);
164 if (prov)
165 {
166 color = CGColorSpaceCreateDeviceRGB();
167 if (color)
168 {
169 image = CGImageCreate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, 5, 16, rowbytes, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0), prov, NULL, 1, kCGRenderingIntentDefault);
170 CGColorSpaceRelease(color);
171 }
172
173 CGDataProviderRelease(prov);
174 }
175
176 return (image);
177 }
178
CreateBlitScreenCGImage(int width,int height,int rowbytes,uint8 * buffer)179 CGImageRef CreateBlitScreenCGImage (int width, int height, int rowbytes, uint8 *buffer)
180 {
181 CGDataProviderRef prov;
182 CGColorSpaceRef color;
183 CGImageRef image = NULL;
184
185 prov = CGDataProviderCreateWithData(NULL, buffer, rowbytes * height, NULL);
186 if (prov)
187 {
188 color = CGColorSpaceCreateDeviceRGB();
189 if (color)
190 {
191 image = CGImageCreate(width, height, 5, 16, rowbytes, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0), prov, NULL, 1, kCGRenderingIntentDefault);
192 CGColorSpaceRelease(color);
193 }
194
195 CGDataProviderRelease(prov);
196 }
197
198 return (image);
199 }
200
DrawThumbnailResource(FSRef * ref,CGContextRef ctx,CGRect bounds)201 void DrawThumbnailResource (FSRef *ref, CGContextRef ctx, CGRect bounds)
202 {
203 OSStatus err;
204 CGDataProviderRef prov;
205 CGColorSpaceRef color;
206 CGImageRef image;
207 QDPictRef qdpr;
208 Handle pict;
209 HFSUniStr255 fork;
210 SInt16 resf;
211 Size size;
212
213 CGContextSaveGState(ctx);
214
215 CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
216 CGContextFillRect(ctx, bounds);
217
218 err = FSGetResourceForkName(&fork);
219 if (err == noErr)
220 {
221 err = FSOpenResourceFile(ref, fork.length, fork.unicode, fsRdPerm, &resf);
222 if (err == noErr)
223 {
224 pict = Get1Resource('PICT', 128);
225 if (pict)
226 {
227 HLock(pict);
228
229 size = GetHandleSize(pict);
230 prov = CGDataProviderCreateWithData(NULL, (void *) *pict, size, NULL);
231 if (prov)
232 {
233 qdpr = QDPictCreateWithProvider(prov);
234 if (qdpr)
235 {
236 QDPictDrawToCGContext(ctx, bounds, qdpr);
237 QDPictRelease(qdpr);
238 }
239
240 CGDataProviderRelease(prov);
241 }
242
243 HUnlock(pict);
244 ReleaseResource(pict);
245 }
246 else
247 {
248 pict = Get1Resource('Thum', 128);
249 if (pict)
250 {
251 HLock(pict);
252
253 size = GetHandleSize(pict);
254 prov = CGDataProviderCreateWithData(NULL, (void *) *pict, size, NULL);
255 if (prov)
256 {
257 color = CGColorSpaceCreateDeviceRGB();
258 if (color)
259 {
260 image = CGImageCreate(128, 120, 5, 16, 256, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Big : 0), prov, NULL, 0, kCGRenderingIntentDefault);
261 if (image)
262 {
263 CGContextDrawImage(ctx, bounds, image);
264 CGImageRelease(image);
265 }
266
267 CGColorSpaceRelease(color);
268 }
269
270 CGDataProviderRelease(prov);
271 }
272
273 HUnlock(pict);
274 ReleaseResource(pict);
275 }
276 }
277
278 CloseResFile(resf);
279 }
280 }
281
282 CGContextRestoreGState(ctx);
283 }
284
S9xDoScreenshot(int width,int height)285 bool8 S9xDoScreenshot (int width, int height)
286 {
287 Settings.TakeScreenshot = false;
288
289 uint16 *data;
290
291 data = (uint16 *) malloc(512 * 478 * 2);
292 if (data)
293 {
294 uint16 *sp, *dp;
295
296 if (width > 256 && height > 239)
297 {
298 for (int y = 0; y < height; y++)
299 {
300 sp = GFX.Screen + y * GFX.RealPPL;
301 dp = data + y * 512;
302
303 for (int x = 0; x < width; x++)
304 *dp++ = *sp++;
305 }
306 }
307 else
308 if (width > 256)
309 {
310 for (int y = 0; y < height; y++)
311 {
312 sp = GFX.Screen + y * GFX.RealPPL;
313 dp = data + y * 2 * 512;
314
315 for (int x = 0; x < width; x++)
316 {
317 *dp = *(dp + 512) = *sp++;
318 dp++;
319 }
320 }
321 }
322 else
323 {
324 for (int y = 0; y < height; y++)
325 {
326 sp = GFX.Screen + y * GFX.RealPPL;
327 dp = data + y * 2 * 512;
328
329 for (int x = 0; x < width; x++)
330 {
331 *dp = *(dp + 1) = *(dp + 512) = *(dp + 512 + 1) = *sp++;
332 dp += 2;
333 }
334 }
335 }
336
337 CGImageRef image;
338
339 image = CreateBlitScreenCGImage(512, (height > 239) ? height : (height * 2), 1024, (uint8 *) data);
340 if (image)
341 {
342 ExportCGImageToPNGFile(image, S9xGetPNGFilename());
343 CGImageRelease(image);
344 }
345
346 free(data);
347 }
348
349 return (true);
350 }
351