• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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