1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library 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 GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #if defined(__APPLE__) && defined(__MACH__)
25 #include <Carbon/Carbon.h>
26 #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
27 #include <Carbon.h>
28 #else
29 #include <Windows.h>
30 #include <Strings.h>
31 #endif
32
33 #if SDL_MACCLASSIC_GAMMA_SUPPORT
34 #include <Devices.h>
35 #include <Files.h>
36 #include <MacTypes.h>
37 #include <QDOffscreen.h>
38 #include <Quickdraw.h>
39 #include <Video.h>
40 #endif
41
42 #include "SDL_stdinc.h"
43 #include "SDL_macwm_c.h"
44
Mac_SetCaption(_THIS,const char * title,const char * icon)45 void Mac_SetCaption(_THIS, const char *title, const char *icon)
46 {
47 /* Don't convert C to P string in place, because it may be read-only */
48 Str255 ptitle; /* MJS */
49 ptitle[0] = strlen (title);
50 SDL_memcpy(ptitle+1, title, ptitle[0]); /* MJS */
51 if (SDL_Window)
52 SetWTitle(SDL_Window, ptitle); /* MJS */
53 }
54
55 #if SDL_MACCLASSIC_GAMMA_SUPPORT
56 /*
57 * ADC Gamma Ramp support...
58 *
59 * Mac Gamma Ramp code was originally from sample code provided by
60 * Apple Developer Connection, and not written specifically for SDL:
61 * "Contains: Functions to enable Mac OS device gamma adjustments using 3 channel 256 element 8 bit gamma ramps
62 * Written by: Geoff Stahl (ggs)
63 * Copyright: Copyright (c) 1999 Apple Computer, Inc., All Rights Reserved
64 * Disclaimer: You may incorporate this sample code into your applications without
65 * restriction, though the sample code has been provided "AS IS" and the
66 * responsibility for its operation is 100% yours. However, what you are
67 * not permitted to do is to redistribute the source as "DSC Sample Code"
68 * after having made changes. If you're going to re-distribute the source,
69 * we require that you make it clear in the source that the code was
70 * descended from Apple Sample Code, but that you've made changes."
71 * (The sample code has been integrated into this file, and thus is modified from the original Apple sources.)
72 */
73
74 typedef struct recDeviceGamma /* storage for device handle and gamma table */
75 {
76 GDHandle hGD; /* handle to device */
77 GammaTblPtr pDeviceGamma; /* pointer to device gamma table */
78 } recDeviceGamma;
79 typedef recDeviceGamma * precDeviceGamma;
80
81 typedef struct recSystemGamma /* storage for system devices and gamma tables */
82 {
83 short numDevices; /* number of devices */
84 precDeviceGamma * devGamma; /* array of pointers to device gamma records */
85 } recSystemGamma;
86 typedef recSystemGamma * precSystemGamma;
87
CopyGammaTable(GammaTblPtr pTableGammaIn)88 static Ptr CopyGammaTable (GammaTblPtr pTableGammaIn)
89 {
90 GammaTblPtr pTableGammaOut = NULL;
91 short tableSize, dataWidth;
92
93 if (pTableGammaIn) /* if there is a table to copy */
94 {
95 dataWidth = (pTableGammaIn->gDataWidth + 7) / 8; /* number of bytes per entry */
96 tableSize = sizeof (GammaTbl) + pTableGammaIn->gFormulaSize +
97 (pTableGammaIn->gChanCnt * pTableGammaIn->gDataCnt * dataWidth);
98 pTableGammaOut = (GammaTblPtr) NewPtr (tableSize); /* allocate new table */
99 if (pTableGammaOut)
100 BlockMove( (Ptr)pTableGammaIn, (Ptr)pTableGammaOut, tableSize); /* move everything */
101 }
102 return (Ptr)pTableGammaOut; /* return whatever we allocated, could be NULL */
103 }
104
GetGammaTable(GDHandle hGD,GammaTblPtr * ppTableGammaOut)105 static OSErr GetGammaTable (GDHandle hGD, GammaTblPtr * ppTableGammaOut)
106 {
107 VDGammaRecord DeviceGammaRec;
108 CntrlParam cParam;
109 OSErr err;
110
111 cParam.ioCompletion = NULL; /* set up control params */
112 cParam.ioNamePtr = NULL;
113 cParam.ioVRefNum = 0;
114 cParam.ioCRefNum = (**hGD).gdRefNum;
115 cParam.csCode = cscGetGamma; /* Get Gamma commnd to device */
116 *(Ptr *)cParam.csParam = (Ptr) &DeviceGammaRec; /* record for gamma */
117
118 err = PBStatusSync( (ParmBlkPtr)&cParam ); /* get gamma */
119
120 *ppTableGammaOut = (GammaTblPtr)(DeviceGammaRec.csGTable); /* pull table out of record */
121
122 return err;
123 }
124
GetDeviceGamma(GDHandle hGD)125 static Ptr GetDeviceGamma (GDHandle hGD)
126 {
127 GammaTblPtr pTableGammaDevice = NULL;
128 GammaTblPtr pTableGammaReturn = NULL;
129 OSErr err;
130
131 err = GetGammaTable (hGD, &pTableGammaDevice); /* get a pointer to the devices table */
132 if ((noErr == err) && pTableGammaDevice) /* if succesful */
133 pTableGammaReturn = (GammaTblPtr) CopyGammaTable (pTableGammaDevice); /* copy to global */
134
135 return (Ptr) pTableGammaReturn;
136 }
137
DisposeGammaTable(Ptr pGamma)138 static void DisposeGammaTable (Ptr pGamma)
139 {
140 if (pGamma)
141 DisposePtr((Ptr) pGamma); /* get rid of it */
142 }
143
DisposeSystemGammas(Ptr * ppSystemGammas)144 static void DisposeSystemGammas (Ptr* ppSystemGammas)
145 {
146 precSystemGamma pSysGammaIn;
147 if (ppSystemGammas)
148 {
149 pSysGammaIn = (precSystemGamma) *ppSystemGammas;
150 if (pSysGammaIn)
151 {
152 short i;
153 for (i = 0; i < pSysGammaIn->numDevices; i++) /* for all devices */
154 if (pSysGammaIn->devGamma [i]) /* if pointer is valid */
155 {
156 DisposeGammaTable ((Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); /* dump gamma table */
157 DisposePtr ((Ptr) pSysGammaIn->devGamma [i]); /* dump device info */
158 }
159 DisposePtr ((Ptr) pSysGammaIn->devGamma); /* dump device pointer array */
160 DisposePtr ((Ptr) pSysGammaIn); /* dump system structure */
161 *ppSystemGammas = NULL;
162 }
163 }
164 }
165
GetDeviceGammaRampGD(GDHandle hGD,Ptr pRamp)166 static Boolean GetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp)
167 {
168 GammaTblPtr pTableGammaTemp = NULL;
169 long indexChan, indexEntry;
170 OSErr err;
171
172 if (pRamp) /* ensure pRamp is allocated */
173 {
174 err = GetGammaTable (hGD, &pTableGammaTemp); /* get a pointer to the current gamma */
175 if ((noErr == err) && pTableGammaTemp) /* if successful */
176 {
177 /* fill ramp */
178 unsigned char * pEntry = (unsigned char *) &pTableGammaTemp->gFormulaData + pTableGammaTemp->gFormulaSize; /* base of table */
179 short bytesPerEntry = (pTableGammaTemp->gDataWidth + 7) / 8; /* size, in bytes, of the device table entries */
180 short shiftRightValue = pTableGammaTemp->gDataWidth - 8; /* number of right shifts device -> ramp */
181 short channels = pTableGammaTemp->gChanCnt;
182 short entries = pTableGammaTemp->gDataCnt;
183 if (3 == channels) /* RGB format */
184 { /* note, this will create runs of entries if dest. is bigger (not linear interpolate) */
185 for (indexChan = 0; indexChan < channels; indexChan++)
186 for (indexEntry = 0; indexEntry < 256; indexEntry++)
187 *((unsigned char *) pRamp + (indexChan * 256) + indexEntry) =
188 *(pEntry + indexChan * entries * bytesPerEntry + indexEntry * entries * bytesPerEntry / 256) >> shiftRightValue;
189 }
190 else /* single channel format */
191 {
192 for (indexChan = 0; indexChan < 768; indexChan += 256) /* repeat for all 3 channels (step by ramp size) */
193 for (indexEntry = 0; indexEntry < 256; indexEntry++) /* for all entries set vramp value */
194 *((unsigned char *) pRamp + indexChan + indexEntry) =
195 *(pEntry + indexEntry * entries * bytesPerEntry / 256) >> shiftRightValue;
196 }
197 return true;
198 }
199 }
200 return false;
201 }
202
GetSystemGammas(void)203 static Ptr GetSystemGammas (void)
204 {
205 precSystemGamma pSysGammaOut; /* return pointer to system device gamma info */
206 short devCount = 0; /* number of devices attached */
207 Boolean fail = false;
208 GDHandle hGDevice;
209
210 pSysGammaOut = (precSystemGamma) NewPtr (sizeof (recSystemGamma)); /* allocate for structure */
211
212 hGDevice = GetDeviceList (); /* top of device list */
213 do /* iterate */
214 {
215 devCount++; /* count devices */
216 hGDevice = GetNextDevice (hGDevice); /* next device */
217 } while (hGDevice);
218
219 pSysGammaOut->devGamma = (precDeviceGamma *) NewPtr (sizeof (precDeviceGamma) * devCount); /* allocate for array of pointers to device records */
220 if (pSysGammaOut)
221 {
222 pSysGammaOut->numDevices = devCount; /* stuff count */
223
224 devCount = 0; /* reset iteration */
225 hGDevice = GetDeviceList ();
226 do
227 {
228 pSysGammaOut->devGamma [devCount] = (precDeviceGamma) NewPtr (sizeof (recDeviceGamma)); /* new device record */
229 if (pSysGammaOut->devGamma [devCount]) /* if we actually allocated memory */
230 {
231 pSysGammaOut->devGamma [devCount]->hGD = hGDevice; /* stuff handle */
232 pSysGammaOut->devGamma [devCount]->pDeviceGamma = (GammaTblPtr)GetDeviceGamma (hGDevice); /* copy gamma table */
233 }
234 else /* otherwise dump record on exit */
235 fail = true;
236 devCount++; /* next device */
237 hGDevice = GetNextDevice (hGDevice);
238 } while (hGDevice);
239 }
240 if (!fail) /* if we did not fail */
241 return (Ptr) pSysGammaOut; /* return pointer to structure */
242 else
243 {
244 DisposeSystemGammas ((Ptr *) &pSysGammaOut); /* otherwise dump the current structures (dispose does error checking) */
245 return NULL; /* could not complete */
246 }
247 }
248
RestoreDeviceGamma(GDHandle hGD,Ptr pGammaTable)249 static void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable)
250 {
251 VDSetEntryRecord setEntriesRec;
252 VDGammaRecord gameRecRestore;
253 CTabHandle hCTabDeviceColors;
254 Ptr csPtr;
255 OSErr err = noErr;
256
257 if (pGammaTable) /* if we have a table to restore */
258 {
259 gameRecRestore.csGTable = pGammaTable; /* setup restore record */
260 csPtr = (Ptr) &gameRecRestore;
261 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); /* restore gamma */
262
263 if ((noErr == err) && (8 == (**(**hGD).gdPMap).pixelSize)) /* if successful and on an 8 bit device */
264 {
265 hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; /* do SetEntries to force CLUT update */
266 setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
267 setEntriesRec.csStart = 0;
268 setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
269 csPtr = (Ptr) &setEntriesRec;
270
271 err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); /* SetEntries in CLUT */
272 }
273 }
274 }
275
RestoreSystemGammas(Ptr pSystemGammas)276 static void RestoreSystemGammas (Ptr pSystemGammas)
277 {
278 short i;
279 precSystemGamma pSysGammaIn = (precSystemGamma) pSystemGammas;
280 if (pSysGammaIn)
281 for (i = 0; i < pSysGammaIn->numDevices; i++) /* for all devices */
282 RestoreDeviceGamma (pSysGammaIn->devGamma [i]->hGD, (Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); /* restore gamma */
283 }
284
CreateEmptyGammaTable(short channels,short entries,short bits)285 static Ptr CreateEmptyGammaTable (short channels, short entries, short bits)
286 {
287 GammaTblPtr pTableGammaOut = NULL;
288 short tableSize, dataWidth;
289
290 dataWidth = (bits + 7) / 8; /* number of bytes per entry */
291 tableSize = sizeof (GammaTbl) + (channels * entries * dataWidth);
292 pTableGammaOut = (GammaTblPtr) NewPtrClear (tableSize); /* allocate new tabel */
293
294 if (pTableGammaOut) /* if we successfully allocated */
295 {
296 pTableGammaOut->gVersion = 0; /* set parameters based on input */
297 pTableGammaOut->gType = 0;
298 pTableGammaOut->gFormulaSize = 0;
299 pTableGammaOut->gChanCnt = channels;
300 pTableGammaOut->gDataCnt = entries;
301 pTableGammaOut->gDataWidth = bits;
302 }
303 return (Ptr)pTableGammaOut; /* return whatever we allocated */
304 }
305
SetDeviceGammaRampGD(GDHandle hGD,Ptr pRamp)306 static Boolean SetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp)
307 {
308 VDSetEntryRecord setEntriesRec;
309 VDGammaRecord gameRecRestore;
310 GammaTblPtr pTableGammaNew;
311 GammaTblPtr pTableGammaCurrent = NULL;
312 CTabHandle hCTabDeviceColors;
313 Ptr csPtr;
314 OSErr err;
315 short dataBits, entries, channels = 3; /* force three channels in the gamma table */
316
317 if (pRamp) /* ensure pRamp is allocated */
318 {
319 err= GetGammaTable (hGD, &pTableGammaCurrent); /* get pointer to current table */
320 if ((noErr == err) && pTableGammaCurrent)
321 {
322 dataBits = pTableGammaCurrent->gDataWidth; /* table must have same data width */
323 entries = pTableGammaCurrent->gDataCnt; /* table must be same size */
324 pTableGammaNew = (GammaTblPtr) CreateEmptyGammaTable (channels, entries, dataBits); /* our new table */
325 if (pTableGammaNew) /* if successful fill table */
326 {
327 unsigned char * pGammaBase = (unsigned char *) &pTableGammaNew->gFormulaData + pTableGammaNew->gFormulaSize; /* base of table */
328 if ((256 == entries) && (8 == dataBits)) /* simple case: direct mapping */
329 BlockMove ((Ptr)pRamp, (Ptr)pGammaBase, channels * entries); /* move everything */
330 else /* tough case handle entry, channel and data size disparities */
331 {
332 short indexChan, indexEntry;
333 short bytesPerEntry = (dataBits + 7) / 8; /* size, in bytes, of the device table entries */
334 short shiftRightValue = 8 - dataBits; /* number of right shifts ramp -> device */
335 shiftRightValue += ((bytesPerEntry - 1) * 8); /* multibyte entries and the need to map a byte at a time most sig. to least sig. */
336 for (indexChan = 0; indexChan < channels; indexChan++) /* for all the channels */
337 for (indexEntry = 0; indexEntry < entries; indexEntry++) /* for all the entries */
338 {
339 short currentShift = shiftRightValue; /* reset current bit shift */
340 long temp = *((unsigned char *)pRamp + (indexChan << 8) + (indexEntry << 8) / entries); /* get data from ramp */
341 short indexByte;
342 for (indexByte = 0; indexByte < bytesPerEntry; indexByte++) /* for all bytes */
343 {
344 if (currentShift < 0) /* shift data correctly for current byte */
345 *(pGammaBase++) = temp << -currentShift;
346 else
347 *(pGammaBase++) = temp >> currentShift;
348 currentShift -= 8; /* increment shift to align to next less sig. byte */
349 }
350 }
351 }
352
353 /* set gamma */
354 gameRecRestore.csGTable = (Ptr) pTableGammaNew; /* setup restore record */
355 csPtr = (Ptr) &gameRecRestore;
356 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); /* restore gamma (note, display drivers may delay returning from this until VBL) */
357
358 if ((8 == (**(**hGD).gdPMap).pixelSize) && (noErr == err)) /* if successful and on an 8 bit device */
359 {
360 hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; /* do SetEntries to force CLUT update */
361 setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
362 setEntriesRec.csStart = 0;
363 setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
364 csPtr = (Ptr) &setEntriesRec;
365 err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); /* SetEntries in CLUT */
366 }
367 DisposeGammaTable ((Ptr) pTableGammaNew); /* dump table */
368 if (noErr == err)
369 return true;
370 }
371 }
372 }
373 else /* set NULL gamma -> results in linear map */
374 {
375 gameRecRestore.csGTable = (Ptr) NULL; /* setup restore record */
376 csPtr = (Ptr) &gameRecRestore;
377 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); /* restore gamma */
378
379 if ((8 == (**(**hGD).gdPMap).pixelSize) && (noErr == err)) /* if successful and on an 8 bit device */
380 {
381 hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; /* do SetEntries to force CLUT update */
382 setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
383 setEntriesRec.csStart = 0;
384 setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
385 csPtr = (Ptr) &setEntriesRec;
386 err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); /* SetEntries in CLUT */
387 }
388 if (noErr == err)
389 return true;
390 }
391 return false; /* memory allocation or device control failed if we get here */
392 }
393
394 /* end of ADC Gamma Ramp support code... */
395
396 static Ptr systemGammaPtr;
397
Mac_QuitGamma(_THIS)398 void Mac_QuitGamma(_THIS)
399 {
400 if (systemGammaPtr)
401 {
402 RestoreSystemGammas(systemGammaPtr);
403 DisposeSystemGammas(&systemGammaPtr);
404 }
405 }
406
407 static unsigned char shiftedRamp[3 * 256];
408
Mac_SetGammaRamp(_THIS,Uint16 * ramp)409 int Mac_SetGammaRamp(_THIS, Uint16 *ramp)
410 {
411 int i;
412 if (!systemGammaPtr)
413 systemGammaPtr = GetSystemGammas();
414 for (i = 0; i < 3 * 256; i++)
415 {
416 shiftedRamp[i] = ramp[i] >> 8;
417 }
418
419 if (SetDeviceGammaRampGD(GetMainDevice(), (Ptr) shiftedRamp))
420 return 0;
421 else
422 return -1;
423 }
424
Mac_GetGammaRamp(_THIS,Uint16 * ramp)425 int Mac_GetGammaRamp(_THIS, Uint16 *ramp)
426 {
427 if (GetDeviceGammaRampGD(GetMainDevice(), (Ptr) shiftedRamp))
428 {
429 int i;
430 for (i = 0; i < 3 * 256; i++)
431 {
432 ramp[i] = shiftedRamp[i] << 8;
433 }
434 return 0;
435 }
436 else
437 return -1;
438 }
439
440 #endif /* SDL_MACCLASSIC_GAMMA_SUPPORT */
441
442
443