1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 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 (at) 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 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 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 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 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 138 static void DisposeGammaTable (Ptr pGamma) 139 { 140 if (pGamma) 141 DisposePtr((Ptr) pGamma); /* get rid of it */ 142 } 143 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 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 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 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 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 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 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 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 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 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