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#import "port.h"
22
23#import <Foundation/Foundation.h>
24#import <QuartzCore/QuartzCore.h>
25#import <OpenGL/OpenGL.h>
26
27#import "mac-prefix.h"
28#import "mac-dialog.h"
29#import "mac-os.h"
30#import "mac-coreimage.h"
31
32enum
33{
34	kCITypeNone    = 0,
35	kCITypeBoolean = 1000,
36	kCITypeScalar,
37	kCITypeColor
38};
39
40#define	mCoreImageFilter		501
41#define	FIXEDRANGE				0x10000
42#define	kCommandFilterMenuBase	0x41000000
43#define	kCommandCheckBoxBase	0x49000000
44#define	kCommandSliderBase		0x51000000
45#define	kCommandColorButtonBase	0x59000000
46#define	kCIFilterNamePrefKey	CFSTR("CoreImageFilterName")
47
48#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
49#define	truncEnd				0
50#endif
51
52typedef struct {
53	char	name[256];
54	char	displayName[256];
55	int		type;
56	union {
57		struct {
58			bool8	cur;
59		}	b;
60
61		struct {
62			float	max, min, cur;
63		}	s;
64
65		struct {
66			float	r, g, b, a;
67		}	c;
68	}	u;
69}	FilterParam;
70
71static NSMutableArray	*ciFilterNameList          = NULL;
72static NSMutableArray	*ciFilterLocalizedNameList = NULL;
73static NSArray			*ciFilterInputKeys         = NULL;
74static CIFilter			*ciFilter                  = NULL;
75static CIContext		*ciContext                 = NULL;
76static FilterParam		*ciFilterParam             = NULL;
77static CFStringRef		ciFilterName               = NULL;
78static HIViewRef		ciFilterUIPane             = NULL;
79static MenuRef			ciFilterMenu               = NULL;
80static CGColorSpaceRef	cgColor                    = NULL;
81static MPSemaphoreID	cisem                      = NULL;
82static bool8			ciFilterHasInputCenter     = false;
83static bool8			ciFilterHasInputImage      = false;
84static int				ciFilterInputKeysCount     = 0;
85
86static void LoadFilterPrefs (void);
87static void SaveFilterPrefs (void);
88static void FilterParamToFilter (void);
89static void FilterToFilterParam (void);
90static void BuildCoreImageFilterListAndMenu (void);
91static void ReleaseCoreImageFilterListAndMenu (void);
92static void ReplaceFilterUI (WindowRef);
93static void FilterUIAddSubviews (WindowRef, HIViewRef);
94static void FilterUISetValues (HIViewRef);
95static bool8 IsCoreImageFilterSupported (CIFilter *);
96static pascal OSStatus CoreImageFilterEventHandler (EventHandlerCallRef, EventRef, void *);
97
98
99void InitCoreImage (void)
100{
101	OSStatus			err;
102	NSAutoreleasePool	*pool;
103
104	pool = [[NSAutoreleasePool alloc] init];
105
106	ciFilterName = (CFStringRef) CFPreferencesCopyAppValue(kCIFilterNamePrefKey, kCFPreferencesCurrentApplication);
107	if (!ciFilterName)
108		ciFilterName = CFStringCreateCopy(kCFAllocatorDefault, CFSTR("CIGammaAdjust"));
109
110	BuildCoreImageFilterListAndMenu();
111
112	err = MPCreateBinarySemaphore(&cisem);
113
114	[pool release];
115}
116
117void DeinitCoreImage (void)
118{
119	OSStatus			err;
120	NSAutoreleasePool	*pool;
121
122	pool = [[NSAutoreleasePool alloc] init];
123
124	err = MPDeleteSemaphore(cisem);
125
126	ReleaseCoreImageFilterListAndMenu();
127
128	CFPreferencesSetAppValue(kCIFilterNamePrefKey, ciFilterName, kCFPreferencesCurrentApplication);
129
130	CFRelease(ciFilterName);
131
132	[pool release];
133}
134
135void InitCoreImageFilter (void)
136{
137	NSAutoreleasePool	*pool;
138
139	pool = [[NSAutoreleasePool alloc] init];
140
141	ciFilter = [[CIFilter filterWithName: (NSString *) ciFilterName] retain];
142	[ciFilter setDefaults];
143
144	ciFilterInputKeys = [[ciFilter inputKeys] retain];
145	ciFilterInputKeysCount = [ciFilterInputKeys count];
146
147	ciFilterParam = new FilterParam [ciFilterInputKeysCount];
148	memset(ciFilterParam, 0, sizeof(FilterParam) * ciFilterInputKeysCount);
149
150	ciFilterHasInputCenter = false;
151	ciFilterHasInputImage  = false;
152
153	LoadFilterPrefs();
154
155	[pool release];
156}
157
158void DeinitCoreImageFilter (void)
159{
160	NSAutoreleasePool	*pool;
161
162	pool = [[NSAutoreleasePool alloc] init];
163
164	SaveFilterPrefs();
165
166	ciFilterHasInputCenter = false;
167	ciFilterHasInputImage  = false;
168
169	delete [] ciFilterParam;
170
171	[ciFilterInputKeys release];
172	ciFilterInputKeysCount = 0;
173
174	[ciFilter release];
175
176	[pool release];
177}
178
179static void LoadFilterPrefs (void)
180{
181	CFDataRef	data;
182	int			n = sizeof(FilterParam) * ciFilterInputKeysCount;
183
184	data = (CFDataRef) CFPreferencesCopyAppValue(ciFilterName, kCFPreferencesCurrentApplication);
185	if (data)
186	{
187		if (CFDataGetLength(data) == n)
188		{
189			CFDataGetBytes(data, CFRangeMake(0, n), (UInt8 *) ciFilterParam);
190			FilterParamToFilter();
191		}
192
193		CFRelease(data);
194	}
195
196	FilterToFilterParam();
197}
198
199static void SaveFilterPrefs (void)
200{
201	CFDataRef	data;
202	int			n = sizeof(FilterParam) * ciFilterInputKeysCount;
203
204	data = CFDataCreate(kCFAllocatorDefault, (UInt8 *) ciFilterParam, n);
205	if (data)
206	{
207		CFPreferencesSetAppValue(ciFilterName, data, kCFPreferencesCurrentApplication);
208		CFRelease(data);
209	}
210}
211
212static void FilterParamToFilter (void)
213{
214	NSString	*key;
215	NSNumber	*num;
216	CIColor		*color;
217
218	for (int i = 0; i < ciFilterInputKeysCount; i++)
219	{
220		key = [NSString stringWithUTF8String: ciFilterParam[i].name];
221		if (key)
222		{
223			switch (ciFilterParam[i].type)
224			{
225				case kCITypeBoolean:
226					num = [NSNumber numberWithBool: ciFilterParam[i].u.b.cur];
227					[ciFilter setValue: num forKey: key];
228					break;
229
230				case kCITypeScalar:
231					num = [NSNumber numberWithFloat: ciFilterParam[i].u.s.cur];
232					[ciFilter setValue: num forKey: key];
233					break;
234
235				case kCITypeColor:
236					color = [CIColor colorWithRed: ciFilterParam[i].u.c.r green: ciFilterParam[i].u.c.g
237											 blue: ciFilterParam[i].u.c.b alpha: ciFilterParam[i].u.c.a];
238					[ciFilter setValue: color forKey: key];
239					break;
240
241				default:
242					break;
243			}
244		}
245	}
246}
247
248static void FilterToFilterParam (void)
249{
250	NSDictionary	*attr;
251	NSString		*key, *label, *className, *typeName;
252	NSNumber		*num;
253	CIColor			*color;
254	id				param;
255
256	attr = [ciFilter attributes];
257	ciFilterHasInputCenter = false;
258	ciFilterHasInputImage  = false;
259
260    for (int i = 0; i < ciFilterInputKeysCount; i++)
261    {
262		key = [ciFilterInputKeys objectAtIndex: i];
263		param = [attr objectForKey: key];
264
265		strncpy(ciFilterParam[i].name, [key UTF8String], sizeof(ciFilterParam[i].name));
266		ciFilterParam[i].displayName[0] = 0;
267
268        if ([param isKindOfClass: [NSDictionary class]])
269        {
270			label = [(NSDictionary *) param objectForKey: kCIAttributeDisplayName];
271			if (!label)
272				label = [NSString stringWithString: key];
273			strncpy(ciFilterParam[i].displayName, [label UTF8String], sizeof(ciFilterParam[i].displayName));
274
275			className = [(NSDictionary *) param objectForKey: kCIAttributeClass];
276
277            if ([className isEqualToString: @"NSNumber"])
278            {
279                typeName = [(NSDictionary *) param objectForKey: kCIAttributeType];
280
281                if ([typeName isEqualToString: kCIAttributeTypeBoolean])
282				{
283					ciFilterParam[i].type = kCITypeBoolean;
284
285					num = [ciFilter valueForKey: key];
286    				ciFilterParam[i].u.b.cur = [num boolValue];
287				}
288                else
289				{
290                    ciFilterParam[i].type = kCITypeScalar;
291
292					num = [ciFilter valueForKey: key];
293    				ciFilterParam[i].u.s.cur = [num floatValue];
294
295					num = [(NSDictionary *) param objectForKey: kCIAttributeSliderMax];
296				    if (!num)
297				        num = [(NSDictionary *) param objectForKey: kCIAttributeMax];
298				    ciFilterParam[i].u.s.max = [num floatValue];
299
300					num = [(NSDictionary *) param objectForKey: kCIAttributeSliderMin];
301				    if (!num)
302				        num = [(NSDictionary *) param objectForKey: kCIAttributeMin];
303				    ciFilterParam[i].u.s.min = [num floatValue];
304				}
305            }
306            else
307			if ([className isEqualToString: @"CIColor"])
308			{
309				ciFilterParam[i].type = kCITypeColor;
310
311				color = [ciFilter valueForKey: key];
312				ciFilterParam[i].u.c.r = [color red];
313				ciFilterParam[i].u.c.g = [color green];
314				ciFilterParam[i].u.c.b = [color blue];
315				ciFilterParam[i].u.c.a = [color alpha];
316			}
317            else
318			{
319				ciFilterParam[i].type = kCITypeNone;
320
321				if ([className isEqualToString: @"CIVector"] && [key isEqualToString: @"inputCenter"])
322					ciFilterHasInputCenter = true;
323
324				if ([className isEqualToString: @"CIImage" ] && [key isEqualToString: @"inputImage" ])
325					ciFilterHasInputImage  = true;
326			}
327		}
328    }
329}
330
331static void BuildCoreImageFilterListAndMenu (void)
332{
333	NSArray		*categories, *filterNames;
334	OSStatus	err;
335
336	categories = [NSArray arrayWithObject: kCICategoryStillImage];
337	filterNames = [CIFilter filterNamesInCategories: categories];
338
339	ciFilterNameList = [[NSMutableArray alloc] initWithCapacity: 1];
340	ciFilterLocalizedNameList = [[NSMutableArray alloc] initWithCapacity: 1];
341	err = CreateNewMenu(mCoreImageFilter, 0, &ciFilterMenu);
342
343	int	n = [filterNames count], m = 0;
344	for (int i = 0; i < n; i++)
345	{
346		CIFilter	*filter;
347		NSString	*name, *localName;
348
349		name = [filterNames objectAtIndex: i];
350		filter = [CIFilter filterWithName: name];
351
352		if (IsCoreImageFilterSupported(filter))
353		{
354			[ciFilterNameList addObject: name];
355
356			localName = [CIFilter localizedNameForFilterName: name];
357			if (!localName)
358				localName = [NSString stringWithString: name];
359
360			[ciFilterLocalizedNameList addObject: localName];
361
362			err = AppendMenuItemTextWithCFString(ciFilterMenu, (CFStringRef) localName, 0, kCommandFilterMenuBase + m, NULL);
363			m++;
364		}
365	}
366}
367
368static void ReleaseCoreImageFilterListAndMenu (void)
369{
370	CFRelease(ciFilterMenu);
371	[ciFilterLocalizedNameList release];
372	[ciFilterNameList release];
373}
374
375static bool8 IsCoreImageFilterSupported (CIFilter *filter)
376{
377	NSDictionary	*attr;
378	NSArray			*inputKeys;
379	NSString		*key, *className;
380	id				param;
381	bool8			result = true, hasInputImage = false;
382
383	attr = [filter attributes];
384	inputKeys = [filter inputKeys];
385
386	int	n = [inputKeys count];
387	for (int i = 0; i < n; i++)
388	{
389	    key = [inputKeys objectAtIndex: i];
390		param = [attr objectForKey: key];
391
392		if ([param isKindOfClass: [NSDictionary class]])
393	    {
394	        className = [(NSDictionary *) param objectForKey: kCIAttributeClass];
395
396			if ([className isEqualToString: @"CIImage"])
397			{
398				if (![key isEqualToString: @"inputImage"])
399					result = false;
400				else
401					hasInputImage = true;
402			}
403			else
404			if ([className isEqualToString: @"CIVector"])
405			{
406				if (![key isEqualToString: @"inputCenter"])
407					result = false;
408			}
409			else
410			if (![className isEqualToString: @"NSNumber"] && ![className isEqualToString: @"CIColor"])
411				result = false;
412		}
413	}
414
415	if (hasInputImage == false)
416		result = false;
417
418	return (result);
419}
420
421void ConfigureCoreImageFilter (void)
422{
423	NSAutoreleasePool	*pool;
424	OSStatus			err;
425	IBNibRef			nibRef;
426
427	pool = [[NSAutoreleasePool alloc] init];
428
429	err = CreateNibReference(kMacS9XCFString, &nibRef);
430	if (err == noErr)
431	{
432		WindowRef	window;
433
434		err = CreateWindowFromNib(nibRef, CFSTR("CIFilter"), &window);
435		if (err == noErr)
436		{
437			EventHandlerRef	eref;
438			EventHandlerUPP	eUPP;
439			EventTypeSpec	event[] = { { kEventClassWindow,  kEventWindowClose         },
440										{ kEventClassCommand, kEventCommandProcess      },
441										{ kEventClassCommand, kEventCommandUpdateStatus } };
442			HIViewRef		ctl, root;
443			HIViewID		cid;
444			Rect			rct;
445			int				value;
446
447			ciFilterUIPane = NULL;
448
449			FilterToFilterParam();
450
451			root = HIViewGetRoot(window);
452
453			SetHIViewID(&cid, 'FILT', 0);
454			rct.left   = 74;
455			rct.top    = 20;
456			rct.right  = 74 + 279;
457			rct.bottom = 20 +  20;
458			err = CreatePopupButtonControl(window, &rct, NULL, -12345, false, 0, 0, 0, &ctl);
459			HIViewSetID(ctl, cid);
460			int	n = CountMenuItems(ciFilterMenu);
461			SetControlPopupMenuHandle(ctl, ciFilterMenu);
462			HIViewSetMaximum(ctl, n);
463			value = [ciFilterNameList indexOfObject: (NSString *) ciFilterName];
464			HIViewSetValue(ctl, value + 1);
465
466			ReplaceFilterUI(window);
467
468			eUPP = NewEventHandlerUPP(CoreImageFilterEventHandler);
469			err = InstallWindowEventHandler(window, eUPP, GetEventTypeCount(event), event, (void *) window, &eref);
470
471			MoveWindowPosition(window, kWindowCoreImageFilter, false);
472			ShowWindow(window);
473			err = RunAppModalLoopForWindow(window);
474			HideWindow(window);
475			SaveWindowPosition(window, kWindowCoreImageFilter);
476
477			err = RemoveEventHandler(eref);
478			DisposeEventHandlerUPP(eUPP);
479
480			FilterParamToFilter();
481
482			CFRelease(window);
483		}
484
485		DisposeNibReference(nibRef);
486	}
487
488	[pool release];
489}
490
491static void ReplaceFilterUI (WindowRef window)
492{
493	OSStatus	err;
494	HIRect		frame;
495	Rect		bounds, rct;
496
497	if (ciFilterUIPane)
498	{
499		HIViewSetVisible(ciFilterUIPane, false);
500		DisposeControl(ciFilterUIPane);
501		ciFilterUIPane = NULL;
502	}
503
504	GetWindowBounds(window, kWindowStructureRgn, &bounds);
505
506	rct.left   = 15;
507	rct.right  = bounds.right - bounds.left - 15;
508	rct.top    = 81;
509	rct.bottom = rct.top + 40;
510	err = CreateUserPaneControl(window, &rct, kControlSupportsEmbedding, &ciFilterUIPane);
511	HIViewSetVisible(ciFilterUIPane, false);
512	FilterUIAddSubviews(window, ciFilterUIPane);
513
514	HIViewGetFrame(ciFilterUIPane, &frame);
515	bounds.bottom = bounds.top + (short) (frame.origin.y + frame.size.height + 30);
516
517	err = TransitionWindow(window, kWindowSlideTransitionEffect, kWindowResizeTransitionAction, &bounds);
518	HIViewSetVisible(ciFilterUIPane, true);
519}
520
521static void FilterUIAddSubviews (WindowRef window, HIViewRef parent)
522{
523	OSStatus			err;
524	CFMutableStringRef	label;
525	CFStringRef			str;
526	HIViewRef			ctl;
527	HIViewID			cid;
528	HIRect				bounds, frame;
529	Rect				rct;
530	SInt32				value;
531
532	HIViewGetFrame(parent, &bounds);
533	rct.left   = 0;
534	rct.top    = 0;
535	rct.right  = 200;
536	rct.bottom = 20;
537
538	int	m = 0;
539	for (int i = 0; i < ciFilterInputKeysCount; i++)
540    {
541		str = CFStringCreateWithCString(kCFAllocatorDefault, ciFilterParam[i].displayName, kCFStringEncodingUTF8);
542		if (!str)
543			str = CFStringCreateCopy(kCFAllocatorDefault, CFSTR("Parameter"));
544		label = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, str);
545		CFRelease(str);
546
547		switch (ciFilterParam[i].type)
548		{
549			case kCITypeBoolean:
550			{
551				err = CreateCheckBoxControl(window, &rct, label, ciFilterParam[i].u.b.cur, true, &ctl);
552				SetHIViewID(&cid, kCommandCheckBoxBase + i, i);
553				HIViewSetID(ctl, cid);
554				HIViewSetCommandID(ctl, cid.signature);
555				err = HIViewAddSubview(parent, ctl);
556				frame.origin.x = 5.0f;
557				frame.origin.y = (float) (m * 28);
558				frame.size.width  = bounds.size.width - 10.0f;
559				frame.size.height = 20.0f;
560				err = HIViewSetFrame(ctl, &frame);
561				m++;
562
563				break;
564			}
565
566			case kCITypeScalar:
567			{
568				CFStringAppend(label, CFSTR(" :"));
569				err = CreateStaticTextControl(window, &rct, label, NULL, &ctl);
570				SetStaticTextTrunc(ctl, truncEnd, true);
571				err = HIViewAddSubview(parent, ctl);
572				frame.origin.x = 5.0f;
573				frame.origin.y = (float) (m * 28);
574				frame.size.width  = 120.0f;
575				frame.size.height = 20.0f;
576				err = HIViewSetFrame(ctl, &frame);
577
578				value = (SInt32) ((ciFilterParam[i].u.s.cur - ciFilterParam[i].u.s.min) / (ciFilterParam[i].u.s.max - ciFilterParam[i].u.s.min) * (float) FIXEDRANGE);
579				err = CreateSliderControl(window, &rct, value, 0, FIXEDRANGE, kControlSliderDoesNotPoint, 0, false, NULL, &ctl);
580				SetHIViewID(&cid, kCommandSliderBase + i, i);
581				HIViewSetID(ctl, cid);
582				HIViewSetCommandID(ctl, cid.signature);
583				err = HIViewAddSubview(parent, ctl);
584				frame.origin.x = 135.0f;
585				frame.origin.y = (float) (m * 28) - 1.0f;
586				frame.size.width  = bounds.size.width - 140.0f;
587				frame.size.height = 20.0f;
588				err = HIViewSetFrame(ctl, &frame);
589				m++;
590
591				break;
592			}
593
594			case kCITypeColor:
595			{
596				CFStringAppend(label, CFSTR("..."));
597				err = CreatePushButtonControl(window, &rct, label, &ctl);
598				SetHIViewID(&cid, kCommandColorButtonBase + i, i);
599				HIViewSetID(ctl, cid);
600				HIViewSetCommandID(ctl, cid.signature);
601				err = HIViewAddSubview(parent, ctl);
602				frame.origin.x = bounds.size.width - 180.0f;
603				frame.origin.y = (float) (m * 28);
604				frame.size.width  = 175.0f;
605				frame.size.height = 20.0f;
606				err = HIViewSetFrame(ctl, &frame);
607				m++;
608
609				break;
610			}
611
612			default:
613				break;
614		}
615
616		CFRelease(label);
617	}
618
619	if (m)
620	{
621		str = CFCopyLocalizedString(CFSTR("ResetCIFilter"), "Reset");
622		err = CreatePushButtonControl(window, &rct, str, &ctl);
623		SetHIViewID(&cid, 'rSET', 0);
624		HIViewSetID(ctl, cid);
625		HIViewSetCommandID(ctl, cid.signature);
626		err = HIViewAddSubview(parent, ctl);
627		frame.origin.x = bounds.size.width - 180.0f;
628		frame.origin.y = (float) (m * 28 + 12);
629		frame.size.width  = 175.0f;
630		frame.size.height = 20.0f;
631		err = HIViewSetFrame(ctl, &frame);
632		CFRelease(str);
633		bounds.size.height = frame.origin.y + 32.0f;
634	}
635	else
636		bounds.size.height = 4.0f;
637
638	err = HIViewSetFrame(parent, &bounds);
639}
640
641static void FilterUISetValues (HIViewRef parent)
642{
643	HIViewRef	ctl;
644	HIViewID	cid;
645	SInt32		value;
646
647	for (int i = 0; i < ciFilterInputKeysCount; i++)
648    {
649		switch (ciFilterParam[i].type)
650		{
651			case kCITypeBoolean:
652				SetHIViewID(&cid, kCommandCheckBoxBase + i, i);
653				HIViewFindByID(parent, cid, &ctl);
654				HIViewSetValue(ctl, ciFilterParam[i].u.b.cur);
655				break;
656
657			case kCITypeScalar:
658				value = (SInt32) ((ciFilterParam[i].u.s.cur - ciFilterParam[i].u.s.min) / (ciFilterParam[i].u.s.max - ciFilterParam[i].u.s.min) * (float) FIXEDRANGE);
659				SetHIViewID(&cid, kCommandSliderBase + i, i);
660				HIViewFindByID(parent, cid, &ctl);
661				HIViewSetValue(ctl, value);
662				break;
663
664			default:
665				break;
666		}
667	}
668}
669
670static pascal OSStatus CoreImageFilterEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
671{
672	OSStatus	err, result = eventNotHandledErr;
673	WindowRef	window = (WindowRef) inUserData;
674
675	switch (GetEventClass(inEvent))
676	{
677		case kEventClassWindow:
678			switch (GetEventKind(inEvent))
679			{
680				case kEventWindowClose:
681					QuitAppModalLoopForWindow(window);
682					result = noErr;
683			}
684
685			break;
686
687		case kEventClassCommand:
688			switch (GetEventKind(inEvent))
689			{
690				HICommandExtended	tHICommand;
691
692				case kEventCommandUpdateStatus:
693					err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommandExtended), NULL, &tHICommand);
694					if (err == noErr && tHICommand.commandID == 'clos')
695					{
696						UpdateMenuCommandStatus(true);
697						result = noErr;
698					}
699
700					break;
701
702				case kEventCommandProcess:
703					err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommandExtended), NULL, &tHICommand);
704					if (err == noErr)
705					{
706						err = MPWaitOnSemaphore(cisem, kDurationForever);
707
708						if (tHICommand.commandID == 'rSET')
709						{
710							[ciFilter setDefaults];
711							FilterToFilterParam();
712							FilterUISetValues(ciFilterUIPane);
713
714							result = noErr;
715						}
716						else
717						{
718							unsigned long	i = tHICommand.commandID & 0x00FFFFFF;
719
720							switch (tHICommand.commandID & 0xFF000000)
721							{
722								case kCommandFilterMenuBase:
723									DeinitCoreImageFilter();
724
725									CFRelease(ciFilterName);
726									ciFilterName = CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef) [ciFilterNameList objectAtIndex: i]);
727
728									InitCoreImageFilter();
729
730									ReplaceFilterUI(window);
731
732									break;
733
734								case kCommandCheckBoxBase:
735									ciFilterParam[i].u.b.cur = !(ciFilterParam[i].u.b.cur);
736									FilterParamToFilter();
737									result = noErr;
738
739									break;
740
741								case kCommandSliderBase:
742									SInt32	value;
743
744									value = HIViewGetValue(tHICommand.source.control);
745									ciFilterParam[i].u.s.cur = ciFilterParam[i].u.s.min + (ciFilterParam[i].u.s.max - ciFilterParam[i].u.s.min) * (float) value / (float) FIXEDRANGE;
746									FilterParamToFilter();
747									result = noErr;
748
749									break;
750
751								case kCommandColorButtonBase:
752									NColorPickerInfo	info;
753
754									memset(&info, 0, sizeof(NColorPickerInfo));
755									info.placeWhere = kCenterOnMainScreen;
756									info.flags      = kColorPickerDialogIsMoveable | kColorPickerDialogIsModal;
757									info.theColor.color.rgb.red   = (int) (65535.0 * ciFilterParam[i].u.c.r);
758									info.theColor.color.rgb.green = (int) (65535.0 * ciFilterParam[i].u.c.g);
759									info.theColor.color.rgb.blue  = (int) (65535.0 * ciFilterParam[i].u.c.b);
760
761									err = NPickColor(&info);
762
763									if ((err == noErr) && info.newColorChosen)
764									{
765										ciFilterParam[i].u.c.r = (float) info.theColor.color.rgb.red   / 65535.0f;
766										ciFilterParam[i].u.c.g = (float) info.theColor.color.rgb.green / 65535.0f;
767										ciFilterParam[i].u.c.b = (float) info.theColor.color.rgb.blue  / 65535.0f;
768									}
769
770									FilterParamToFilter();
771									result = noErr;
772
773									break;
774							}
775						}
776
777						err = MPSignalSemaphore(cisem);
778					}
779			}
780	}
781
782	return (result);
783}
784
785void InitCoreImageContext (CGLContextObj cglctx, CGLPixelFormatObj cglpix)
786{
787	NSAutoreleasePool	*pool;
788
789	pool = [[NSAutoreleasePool alloc] init];
790
791	FilterToFilterParam();
792
793	cgColor = CGColorSpaceCreateDeviceRGB();
794
795#ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
796	ciContext = [[CIContext contextWithCGLContext: cglctx pixelFormat: cglpix options: NULL] retain];
797#else
798	ciContext = [[CIContext contextWithCGLContext: cglctx pixelFormat: cglpix colorSpace: cgColor options: NULL] retain];
799#endif
800
801	[pool release];
802}
803
804void DeinitCoreImageContext (void)
805{
806	NSAutoreleasePool	*pool;
807
808	pool = [[NSAutoreleasePool alloc] init];
809
810	[ciContext release];
811	CGColorSpaceRelease(cgColor);
812
813	[pool release];
814}
815
816void DrawWithCoreImageFilter (CGRect src, CGImageRef img)
817{
818	OSStatus			err;
819	NSAutoreleasePool	*pool;
820
821	pool = [[NSAutoreleasePool alloc] init];
822
823	err = MPWaitOnSemaphore(cisem, kDurationForever);
824
825	if (ciFilterHasInputImage)
826	{
827		CIImage		*image;
828
829		image = [CIImage imageWithCGImage: img];
830		[ciFilter setValue: image  forKey: @"inputImage" ];
831	}
832
833	if (ciFilterHasInputCenter)
834	{
835		CIVector	*vector;
836
837		vector = [CIVector vectorWithX: (src.origin.x + src.size.width / 2) Y: (src.origin.y + src.size.height / 2)];
838		[ciFilter setValue: vector forKey: @"inputCenter"];
839	}
840
841	[ciContext drawImage: [ciFilter valueForKey: @"outputImage"] atPoint: CGPointZero fromRect: src];
842
843	err = MPSignalSemaphore(cisem);
844
845	[pool release];
846}
847