1/*********************************************************************************** 2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. 3 4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), 5 Jerremy Koot (jkoot@snes9x.com) 6 7 (c) Copyright 2002 - 2004 Matthew Kendora 8 9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) 10 11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) 12 13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) 14 15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), 16 Kris Bleakley (codeviolation@hotmail.com) 17 18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), 19 Nach (n-a-c-h@users.sourceforge.net), 20 21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) 22 23 (c) Copyright 2006 - 2007 nitsuja 24 25 (c) Copyright 2009 - 2016 BearOso, 26 OV2 27 28 29 BS-X C emulator code 30 (c) Copyright 2005 - 2006 Dreamer Nom, 31 zones 32 33 C4 x86 assembler and some C emulation code 34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), 35 Nach, 36 zsKnight (zsknight@zsnes.com) 37 38 C4 C++ code 39 (c) Copyright 2003 - 2006 Brad Jorsch, 40 Nach 41 42 DSP-1 emulator code 43 (c) Copyright 1998 - 2006 _Demo_, 44 Andreas Naive (andreasnaive@gmail.com), 45 Gary Henderson, 46 Ivar (ivar@snes9x.com), 47 John Weidman, 48 Kris Bleakley, 49 Matthew Kendora, 50 Nach, 51 neviksti (neviksti@hotmail.com) 52 53 DSP-2 emulator code 54 (c) Copyright 2003 John Weidman, 55 Kris Bleakley, 56 Lord Nightmare (lord_nightmare@users.sourceforge.net), 57 Matthew Kendora, 58 neviksti 59 60 DSP-3 emulator code 61 (c) Copyright 2003 - 2006 John Weidman, 62 Kris Bleakley, 63 Lancer, 64 z80 gaiden 65 66 DSP-4 emulator code 67 (c) Copyright 2004 - 2006 Dreamer Nom, 68 John Weidman, 69 Kris Bleakley, 70 Nach, 71 z80 gaiden 72 73 OBC1 emulator code 74 (c) Copyright 2001 - 2004 zsKnight, 75 pagefault (pagefault@zsnes.com), 76 Kris Bleakley 77 Ported from x86 assembler to C by sanmaiwashi 78 79 SPC7110 and RTC C++ emulator code used in 1.39-1.51 80 (c) Copyright 2002 Matthew Kendora with research by 81 zsKnight, 82 John Weidman, 83 Dark Force 84 85 SPC7110 and RTC C++ emulator code used in 1.52+ 86 (c) Copyright 2009 byuu, 87 neviksti 88 89 S-DD1 C emulator code 90 (c) Copyright 2003 Brad Jorsch with research by 91 Andreas Naive, 92 John Weidman 93 94 S-RTC C emulator code 95 (c) Copyright 2001 - 2006 byuu, 96 John Weidman 97 98 ST010 C++ emulator code 99 (c) Copyright 2003 Feather, 100 John Weidman, 101 Kris Bleakley, 102 Matthew Kendora 103 104 Super FX x86 assembler emulator code 105 (c) Copyright 1998 - 2003 _Demo_, 106 pagefault, 107 zsKnight 108 109 Super FX C emulator code 110 (c) Copyright 1997 - 1999 Ivar, 111 Gary Henderson, 112 John Weidman 113 114 Sound emulator code used in 1.5-1.51 115 (c) Copyright 1998 - 2003 Brad Martin 116 (c) Copyright 1998 - 2006 Charles Bilyue' 117 118 Sound emulator code used in 1.52+ 119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) 120 121 S-SMP emulator code used in 1.54+ 122 (c) Copyright 2016 byuu 123 124 SH assembler code partly based on x86 assembler code 125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 126 127 2xSaI filter 128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa 129 130 HQ2x, HQ3x, HQ4x filters 131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) 132 133 NTSC filter 134 (c) Copyright 2006 - 2007 Shay Green 135 136 GTK+ GUI code 137 (c) Copyright 2004 - 2016 BearOso 138 139 Win32 GUI code 140 (c) Copyright 2003 - 2006 blip, 141 funkyass, 142 Matthew Kendora, 143 Nach, 144 nitsuja 145 (c) Copyright 2009 - 2016 OV2 146 147 Mac OS GUI code 148 (c) Copyright 1998 - 2001 John Stiles 149 (c) Copyright 2001 - 2011 zones 150 151 152 Specific ports contains the works of other authors. See headers in 153 individual files. 154 155 156 Snes9x homepage: http://www.snes9x.com/ 157 158 Permission to use, copy, modify and/or distribute Snes9x in both binary 159 and source form, for non-commercial purposes, is hereby granted without 160 fee, providing that this license information and copyright notice appear 161 with all copies and any derived work. 162 163 This software is provided 'as-is', without any express or implied 164 warranty. In no event shall the authors be held liable for any damages 165 arising from the use of this software or it's derivatives. 166 167 Snes9x is freeware for PERSONAL USE only. Commercial users should 168 seek permission of the copyright holders first. Commercial use includes, 169 but is not limited to, charging money for Snes9x or software derived from 170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or 171 using Snes9x as a promotion for your commercial product. 172 173 The copyright holders request that bug fixes and improvements to the code 174 should be forwarded to them so everyone can benefit from the modifications 175 in future versions. 176 177 Super NES and Super Nintendo Entertainment System are trademarks of 178 Nintendo Co., Limited and its subsidiary companies. 179 ***********************************************************************************/ 180 181/*********************************************************************************** 182 SNES9X for Mac OS (c) Copyright John Stiles 183 184 Snes9x for Mac OS X 185 186 (c) Copyright 2001 - 2011 zones 187 (c) Copyright 2002 - 2005 107 188 (c) Copyright 2002 PB1400c 189 (c) Copyright 2004 Alexander and Sander 190 (c) Copyright 2004 - 2005 Steven Seeger 191 (c) Copyright 2005 Ryan Vogt 192 ***********************************************************************************/ 193 194 195#import "port.h" 196 197#import <Foundation/Foundation.h> 198#import <QuartzCore/QuartzCore.h> 199#import <OpenGL/OpenGL.h> 200 201#import "mac-prefix.h" 202#import "mac-dialog.h" 203#import "mac-os.h" 204#import "mac-coreimage.h" 205 206enum 207{ 208 kCITypeNone = 0, 209 kCITypeBoolean = 1000, 210 kCITypeScalar, 211 kCITypeColor 212}; 213 214#define mCoreImageFilter 501 215#define FIXEDRANGE 0x10000 216#define kCommandFilterMenuBase 0x41000000 217#define kCommandCheckBoxBase 0x49000000 218#define kCommandSliderBase 0x51000000 219#define kCommandColorButtonBase 0x59000000 220#define kCIFilterNamePrefKey CFSTR("CoreImageFilterName") 221 222typedef struct { 223 char name[256]; 224 char displayName[256]; 225 int type; 226 union { 227 struct { 228 bool8 cur; 229 } b; 230 231 struct { 232 float max, min, cur; 233 } s; 234 235 struct { 236 float r, g, b, a; 237 } c; 238 } u; 239} FilterParam; 240 241static NSMutableArray *ciFilterNameList = NULL; 242static NSMutableArray *ciFilterLocalizedNameList = NULL; 243static NSArray *ciFilterInputKeys = NULL; 244static CIFilter *ciFilter = NULL; 245static CIContext *ciContext = NULL; 246static FilterParam *ciFilterParam = NULL; 247static CFStringRef ciFilterName = NULL; 248static HIViewRef ciFilterUIPane = NULL; 249static MenuRef ciFilterMenu = NULL; 250static CGColorSpaceRef cgColor = NULL; 251static MPSemaphoreID cisem = NULL; 252static bool8 ciFilterHasInputCenter = false; 253static bool8 ciFilterHasInputImage = false; 254static int ciFilterInputKeysCount = 0; 255 256static void LoadFilterPrefs (void); 257static void SaveFilterPrefs (void); 258static void FilterParamToFilter (void); 259static void FilterToFilterParam (void); 260static void BuildCoreImageFilterListAndMenu (void); 261static void ReleaseCoreImageFilterListAndMenu (void); 262static void ReplaceFilterUI (WindowRef); 263static void FilterUIAddSubviews (WindowRef, HIViewRef); 264static void FilterUISetValues (HIViewRef); 265static bool8 IsCoreImageFilterSupported (CIFilter *); 266static pascal OSStatus CoreImageFilterEventHandler (EventHandlerCallRef, EventRef, void *); 267 268 269void InitCoreImage (void) 270{ 271 OSStatus err; 272 NSAutoreleasePool *pool; 273 274 pool = [[NSAutoreleasePool alloc] init]; 275 276 ciFilterName = (CFStringRef) CFPreferencesCopyAppValue(kCIFilterNamePrefKey, kCFPreferencesCurrentApplication); 277 if (!ciFilterName) 278 ciFilterName = CFStringCreateCopy(kCFAllocatorDefault, CFSTR("CIGammaAdjust")); 279 280 BuildCoreImageFilterListAndMenu(); 281 282 err = MPCreateBinarySemaphore(&cisem); 283 284 [pool release]; 285} 286 287void DeinitCoreImage (void) 288{ 289 OSStatus err; 290 NSAutoreleasePool *pool; 291 292 pool = [[NSAutoreleasePool alloc] init]; 293 294 err = MPDeleteSemaphore(cisem); 295 296 ReleaseCoreImageFilterListAndMenu(); 297 298 CFPreferencesSetAppValue(kCIFilterNamePrefKey, ciFilterName, kCFPreferencesCurrentApplication); 299 300 CFRelease(ciFilterName); 301 302 [pool release]; 303} 304 305void InitCoreImageFilter (void) 306{ 307 NSAutoreleasePool *pool; 308 309 pool = [[NSAutoreleasePool alloc] init]; 310 311 ciFilter = [[CIFilter filterWithName: (NSString *) ciFilterName] retain]; 312 [ciFilter setDefaults]; 313 314 ciFilterInputKeys = [[ciFilter inputKeys] retain]; 315 ciFilterInputKeysCount = [ciFilterInputKeys count]; 316 317 ciFilterParam = new FilterParam [ciFilterInputKeysCount]; 318 memset(ciFilterParam, 0, sizeof(FilterParam) * ciFilterInputKeysCount); 319 320 ciFilterHasInputCenter = false; 321 ciFilterHasInputImage = false; 322 323 LoadFilterPrefs(); 324 325 [pool release]; 326} 327 328void DeinitCoreImageFilter (void) 329{ 330 NSAutoreleasePool *pool; 331 332 pool = [[NSAutoreleasePool alloc] init]; 333 334 SaveFilterPrefs(); 335 336 ciFilterHasInputCenter = false; 337 ciFilterHasInputImage = false; 338 339 delete [] ciFilterParam; 340 341 [ciFilterInputKeys release]; 342 ciFilterInputKeysCount = 0; 343 344 [ciFilter release]; 345 346 [pool release]; 347} 348 349static void LoadFilterPrefs (void) 350{ 351 CFDataRef data; 352 int n = sizeof(FilterParam) * ciFilterInputKeysCount; 353 354 data = (CFDataRef) CFPreferencesCopyAppValue(ciFilterName, kCFPreferencesCurrentApplication); 355 if (data) 356 { 357 if (CFDataGetLength(data) == n) 358 { 359 CFDataGetBytes(data, CFRangeMake(0, n), (UInt8 *) ciFilterParam); 360 FilterParamToFilter(); 361 } 362 363 CFRelease(data); 364 } 365 366 FilterToFilterParam(); 367} 368 369static void SaveFilterPrefs (void) 370{ 371 CFDataRef data; 372 int n = sizeof(FilterParam) * ciFilterInputKeysCount; 373 374 data = CFDataCreate(kCFAllocatorDefault, (UInt8 *) ciFilterParam, n); 375 if (data) 376 { 377 CFPreferencesSetAppValue(ciFilterName, data, kCFPreferencesCurrentApplication); 378 CFRelease(data); 379 } 380} 381 382static void FilterParamToFilter (void) 383{ 384 NSString *key; 385 NSNumber *num; 386 CIColor *color; 387 388 for (int i = 0; i < ciFilterInputKeysCount; i++) 389 { 390 key = [NSString stringWithUTF8String: ciFilterParam[i].name]; 391 if (key) 392 { 393 switch (ciFilterParam[i].type) 394 { 395 case kCITypeBoolean: 396 num = [NSNumber numberWithBool: ciFilterParam[i].u.b.cur]; 397 [ciFilter setValue: num forKey: key]; 398 break; 399 400 case kCITypeScalar: 401 num = [NSNumber numberWithFloat: ciFilterParam[i].u.s.cur]; 402 [ciFilter setValue: num forKey: key]; 403 break; 404 405 case kCITypeColor: 406 color = [CIColor colorWithRed: ciFilterParam[i].u.c.r green: ciFilterParam[i].u.c.g 407 blue: ciFilterParam[i].u.c.b alpha: ciFilterParam[i].u.c.a]; 408 [ciFilter setValue: color forKey: key]; 409 break; 410 411 default: 412 break; 413 } 414 } 415 } 416} 417 418static void FilterToFilterParam (void) 419{ 420 NSDictionary *attr; 421 NSString *key, *label, *className, *typeName; 422 NSNumber *num; 423 CIColor *color; 424 id param; 425 426 attr = [ciFilter attributes]; 427 ciFilterHasInputCenter = false; 428 ciFilterHasInputImage = false; 429 430 for (int i = 0; i < ciFilterInputKeysCount; i++) 431 { 432 key = [ciFilterInputKeys objectAtIndex: i]; 433 param = [attr objectForKey: key]; 434 435 strncpy(ciFilterParam[i].name, [key UTF8String], sizeof(ciFilterParam[i].name)); 436 ciFilterParam[i].displayName[0] = 0; 437 438 if ([param isKindOfClass: [NSDictionary class]]) 439 { 440 label = [(NSDictionary *) param objectForKey: kCIAttributeDisplayName]; 441 if (!label) 442 label = [NSString stringWithString: key]; 443 strncpy(ciFilterParam[i].displayName, [label UTF8String], sizeof(ciFilterParam[i].displayName)); 444 445 className = [(NSDictionary *) param objectForKey: kCIAttributeClass]; 446 447 if ([className isEqualToString: @"NSNumber"]) 448 { 449 typeName = [(NSDictionary *) param objectForKey: kCIAttributeType]; 450 451 if ([typeName isEqualToString: kCIAttributeTypeBoolean]) 452 { 453 ciFilterParam[i].type = kCITypeBoolean; 454 455 num = [ciFilter valueForKey: key]; 456 ciFilterParam[i].u.b.cur = [num boolValue]; 457 } 458 else 459 { 460 ciFilterParam[i].type = kCITypeScalar; 461 462 num = [ciFilter valueForKey: key]; 463 ciFilterParam[i].u.s.cur = [num floatValue]; 464 465 num = [(NSDictionary *) param objectForKey: kCIAttributeSliderMax]; 466 if (!num) 467 num = [(NSDictionary *) param objectForKey: kCIAttributeMax]; 468 ciFilterParam[i].u.s.max = [num floatValue]; 469 470 num = [(NSDictionary *) param objectForKey: kCIAttributeSliderMin]; 471 if (!num) 472 num = [(NSDictionary *) param objectForKey: kCIAttributeMin]; 473 ciFilterParam[i].u.s.min = [num floatValue]; 474 } 475 } 476 else 477 if ([className isEqualToString: @"CIColor"]) 478 { 479 ciFilterParam[i].type = kCITypeColor; 480 481 color = [ciFilter valueForKey: key]; 482 ciFilterParam[i].u.c.r = [color red]; 483 ciFilterParam[i].u.c.g = [color green]; 484 ciFilterParam[i].u.c.b = [color blue]; 485 ciFilterParam[i].u.c.a = [color alpha]; 486 } 487 else 488 { 489 ciFilterParam[i].type = kCITypeNone; 490 491 if ([className isEqualToString: @"CIVector"] && [key isEqualToString: @"inputCenter"]) 492 ciFilterHasInputCenter = true; 493 494 if ([className isEqualToString: @"CIImage" ] && [key isEqualToString: @"inputImage" ]) 495 ciFilterHasInputImage = true; 496 } 497 } 498 } 499} 500 501static void BuildCoreImageFilterListAndMenu (void) 502{ 503 NSArray *categories, *filterNames; 504 OSStatus err; 505 506 categories = [NSArray arrayWithObject: kCICategoryStillImage]; 507 filterNames = [CIFilter filterNamesInCategories: categories]; 508 509 ciFilterNameList = [[NSMutableArray alloc] initWithCapacity: 1]; 510 ciFilterLocalizedNameList = [[NSMutableArray alloc] initWithCapacity: 1]; 511 err = CreateNewMenu(mCoreImageFilter, 0, &ciFilterMenu); 512 513 int n = [filterNames count], m = 0; 514 for (int i = 0; i < n; i++) 515 { 516 CIFilter *filter; 517 NSString *name, *localName; 518 519 name = [filterNames objectAtIndex: i]; 520 filter = [CIFilter filterWithName: name]; 521 522 if (IsCoreImageFilterSupported(filter)) 523 { 524 [ciFilterNameList addObject: name]; 525 526 localName = [CIFilter localizedNameForFilterName: name]; 527 if (!localName) 528 localName = [NSString stringWithString: name]; 529 530 [ciFilterLocalizedNameList addObject: localName]; 531 532 err = AppendMenuItemTextWithCFString(ciFilterMenu, (CFStringRef) localName, 0, kCommandFilterMenuBase + m, NULL); 533 m++; 534 } 535 } 536} 537 538static void ReleaseCoreImageFilterListAndMenu (void) 539{ 540 CFRelease(ciFilterMenu); 541 [ciFilterLocalizedNameList release]; 542 [ciFilterNameList release]; 543} 544 545static bool8 IsCoreImageFilterSupported (CIFilter *filter) 546{ 547 NSDictionary *attr; 548 NSArray *inputKeys; 549 NSString *key, *className; 550 id param; 551 bool8 result = true, hasInputImage = false; 552 553 attr = [filter attributes]; 554 inputKeys = [filter inputKeys]; 555 556 int n = [inputKeys count]; 557 for (int i = 0; i < n; i++) 558 { 559 key = [inputKeys objectAtIndex: i]; 560 param = [attr objectForKey: key]; 561 562 if ([param isKindOfClass: [NSDictionary class]]) 563 { 564 className = [(NSDictionary *) param objectForKey: kCIAttributeClass]; 565 566 if ([className isEqualToString: @"CIImage"]) 567 { 568 if (![key isEqualToString: @"inputImage"]) 569 result = false; 570 else 571 hasInputImage = true; 572 } 573 else 574 if ([className isEqualToString: @"CIVector"]) 575 { 576 if (![key isEqualToString: @"inputCenter"]) 577 result = false; 578 } 579 else 580 if (![className isEqualToString: @"NSNumber"] && ![className isEqualToString: @"CIColor"]) 581 result = false; 582 } 583 } 584 585 if (hasInputImage == false) 586 result = false; 587 588 return (result); 589} 590 591void ConfigureCoreImageFilter (void) 592{ 593 NSAutoreleasePool *pool; 594 OSStatus err; 595 IBNibRef nibRef; 596 597 pool = [[NSAutoreleasePool alloc] init]; 598 599 err = CreateNibReference(kMacS9XCFString, &nibRef); 600 if (err == noErr) 601 { 602 WindowRef window; 603 604 err = CreateWindowFromNib(nibRef, CFSTR("CIFilter"), &window); 605 if (err == noErr) 606 { 607 EventHandlerRef eref; 608 EventHandlerUPP eUPP; 609 EventTypeSpec event[] = { { kEventClassWindow, kEventWindowClose }, 610 { kEventClassCommand, kEventCommandProcess }, 611 { kEventClassCommand, kEventCommandUpdateStatus } }; 612 HIViewRef ctl, root; 613 HIViewID cid; 614 Rect rct; 615 int value; 616 617 ciFilterUIPane = NULL; 618 619 FilterToFilterParam(); 620 621 root = HIViewGetRoot(window); 622 623 SetHIViewID(&cid, 'FILT', 0); 624 rct.left = 74; 625 rct.top = 20; 626 rct.right = 74 + 279; 627 rct.bottom = 20 + 20; 628 err = CreatePopupButtonControl(window, &rct, NULL, -12345, false, 0, 0, 0, &ctl); 629 HIViewSetID(ctl, cid); 630 int n = CountMenuItems(ciFilterMenu); 631 SetControlPopupMenuHandle(ctl, ciFilterMenu); 632 HIViewSetMaximum(ctl, n); 633 value = [ciFilterNameList indexOfObject: (NSString *) ciFilterName]; 634 HIViewSetValue(ctl, value + 1); 635 636 ReplaceFilterUI(window); 637 638 eUPP = NewEventHandlerUPP(CoreImageFilterEventHandler); 639 err = InstallWindowEventHandler(window, eUPP, GetEventTypeCount(event), event, (void *) window, &eref); 640 641 MoveWindowPosition(window, kWindowCoreImageFilter, false); 642 ShowWindow(window); 643 err = RunAppModalLoopForWindow(window); 644 HideWindow(window); 645 SaveWindowPosition(window, kWindowCoreImageFilter); 646 647 err = RemoveEventHandler(eref); 648 DisposeEventHandlerUPP(eUPP); 649 650 FilterParamToFilter(); 651 652 CFRelease(window); 653 } 654 655 DisposeNibReference(nibRef); 656 } 657 658 [pool release]; 659} 660 661static void ReplaceFilterUI (WindowRef window) 662{ 663 OSStatus err; 664 HIRect frame; 665 Rect bounds, rct; 666 667 if (ciFilterUIPane) 668 { 669 HIViewSetVisible(ciFilterUIPane, false); 670 DisposeControl(ciFilterUIPane); 671 ciFilterUIPane = NULL; 672 } 673 674 GetWindowBounds(window, kWindowStructureRgn, &bounds); 675 676 rct.left = 15; 677 rct.right = bounds.right - bounds.left - 15; 678 rct.top = 81; 679 rct.bottom = rct.top + 40; 680 err = CreateUserPaneControl(window, &rct, kControlSupportsEmbedding, &ciFilterUIPane); 681 HIViewSetVisible(ciFilterUIPane, false); 682 FilterUIAddSubviews(window, ciFilterUIPane); 683 684 HIViewGetFrame(ciFilterUIPane, &frame); 685 bounds.bottom = bounds.top + (short) (frame.origin.y + frame.size.height + 30); 686 687 err = TransitionWindow(window, kWindowSlideTransitionEffect, kWindowResizeTransitionAction, &bounds); 688 HIViewSetVisible(ciFilterUIPane, true); 689} 690 691static void FilterUIAddSubviews (WindowRef window, HIViewRef parent) 692{ 693 OSStatus err; 694 CFMutableStringRef label; 695 CFStringRef str; 696 HIViewRef ctl; 697 HIViewID cid; 698 HIRect bounds, frame; 699 Rect rct; 700 SInt32 value; 701 702 HIViewGetFrame(parent, &bounds); 703 rct.left = 0; 704 rct.top = 0; 705 rct.right = 200; 706 rct.bottom = 20; 707 708 int m = 0; 709 for (int i = 0; i < ciFilterInputKeysCount; i++) 710 { 711 str = CFStringCreateWithCString(kCFAllocatorDefault, ciFilterParam[i].displayName, kCFStringEncodingUTF8); 712 if (!str) 713 str = CFStringCreateCopy(kCFAllocatorDefault, CFSTR("Parameter")); 714 label = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, str); 715 CFRelease(str); 716 717 switch (ciFilterParam[i].type) 718 { 719 case kCITypeBoolean: 720 { 721 err = CreateCheckBoxControl(window, &rct, label, ciFilterParam[i].u.b.cur, true, &ctl); 722 SetHIViewID(&cid, kCommandCheckBoxBase + i, i); 723 HIViewSetID(ctl, cid); 724 HIViewSetCommandID(ctl, cid.signature); 725 err = HIViewAddSubview(parent, ctl); 726 frame.origin.x = 5.0f; 727 frame.origin.y = (float) (m * 28); 728 frame.size.width = bounds.size.width - 10.0f; 729 frame.size.height = 20.0f; 730 err = HIViewSetFrame(ctl, &frame); 731 m++; 732 733 break; 734 } 735 736 case kCITypeScalar: 737 { 738 CFStringAppend(label, CFSTR(" :")); 739 err = CreateStaticTextControl(window, &rct, label, NULL, &ctl); 740 SetStaticTextTrunc(ctl, truncEnd, true); 741 err = HIViewAddSubview(parent, ctl); 742 frame.origin.x = 5.0f; 743 frame.origin.y = (float) (m * 28); 744 frame.size.width = 120.0f; 745 frame.size.height = 20.0f; 746 err = HIViewSetFrame(ctl, &frame); 747 748 value = (SInt32) ((ciFilterParam[i].u.s.cur - ciFilterParam[i].u.s.min) / (ciFilterParam[i].u.s.max - ciFilterParam[i].u.s.min) * (float) FIXEDRANGE); 749 err = CreateSliderControl(window, &rct, value, 0, FIXEDRANGE, kControlSliderDoesNotPoint, 0, false, NULL, &ctl); 750 SetHIViewID(&cid, kCommandSliderBase + i, i); 751 HIViewSetID(ctl, cid); 752 HIViewSetCommandID(ctl, cid.signature); 753 err = HIViewAddSubview(parent, ctl); 754 frame.origin.x = 135.0f; 755 frame.origin.y = (float) (m * 28) - 1.0f; 756 frame.size.width = bounds.size.width - 140.0f; 757 frame.size.height = 20.0f; 758 err = HIViewSetFrame(ctl, &frame); 759 m++; 760 761 break; 762 } 763 764 case kCITypeColor: 765 { 766 CFStringAppend(label, CFSTR("...")); 767 err = CreatePushButtonControl(window, &rct, label, &ctl); 768 SetHIViewID(&cid, kCommandColorButtonBase + i, i); 769 HIViewSetID(ctl, cid); 770 HIViewSetCommandID(ctl, cid.signature); 771 err = HIViewAddSubview(parent, ctl); 772 frame.origin.x = bounds.size.width - 180.0f; 773 frame.origin.y = (float) (m * 28); 774 frame.size.width = 175.0f; 775 frame.size.height = 20.0f; 776 err = HIViewSetFrame(ctl, &frame); 777 m++; 778 779 break; 780 } 781 782 default: 783 break; 784 } 785 786 CFRelease(label); 787 } 788 789 if (m) 790 { 791 str = CFCopyLocalizedString(CFSTR("ResetCIFilter"), "Reset"); 792 err = CreatePushButtonControl(window, &rct, str, &ctl); 793 SetHIViewID(&cid, 'rSET', 0); 794 HIViewSetID(ctl, cid); 795 HIViewSetCommandID(ctl, cid.signature); 796 err = HIViewAddSubview(parent, ctl); 797 frame.origin.x = bounds.size.width - 180.0f; 798 frame.origin.y = (float) (m * 28 + 12); 799 frame.size.width = 175.0f; 800 frame.size.height = 20.0f; 801 err = HIViewSetFrame(ctl, &frame); 802 CFRelease(str); 803 bounds.size.height = frame.origin.y + 32.0f; 804 } 805 else 806 bounds.size.height = 4.0f; 807 808 err = HIViewSetFrame(parent, &bounds); 809} 810 811static void FilterUISetValues (HIViewRef parent) 812{ 813 HIViewRef ctl; 814 HIViewID cid; 815 SInt32 value; 816 817 for (int i = 0; i < ciFilterInputKeysCount; i++) 818 { 819 switch (ciFilterParam[i].type) 820 { 821 case kCITypeBoolean: 822 SetHIViewID(&cid, kCommandCheckBoxBase + i, i); 823 HIViewFindByID(parent, cid, &ctl); 824 HIViewSetValue(ctl, ciFilterParam[i].u.b.cur); 825 break; 826 827 case kCITypeScalar: 828 value = (SInt32) ((ciFilterParam[i].u.s.cur - ciFilterParam[i].u.s.min) / (ciFilterParam[i].u.s.max - ciFilterParam[i].u.s.min) * (float) FIXEDRANGE); 829 SetHIViewID(&cid, kCommandSliderBase + i, i); 830 HIViewFindByID(parent, cid, &ctl); 831 HIViewSetValue(ctl, value); 832 break; 833 834 default: 835 break; 836 } 837 } 838} 839 840static pascal OSStatus CoreImageFilterEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData) 841{ 842 OSStatus err, result = eventNotHandledErr; 843 WindowRef window = (WindowRef) inUserData; 844 845 switch (GetEventClass(inEvent)) 846 { 847 case kEventClassWindow: 848 switch (GetEventKind(inEvent)) 849 { 850 case kEventWindowClose: 851 QuitAppModalLoopForWindow(window); 852 result = noErr; 853 } 854 855 break; 856 857 case kEventClassCommand: 858 switch (GetEventKind(inEvent)) 859 { 860 HICommandExtended tHICommand; 861 862 case kEventCommandUpdateStatus: 863 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommandExtended), NULL, &tHICommand); 864 if (err == noErr && tHICommand.commandID == 'clos') 865 { 866 UpdateMenuCommandStatus(true); 867 result = noErr; 868 } 869 870 break; 871 872 case kEventCommandProcess: 873 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommandExtended), NULL, &tHICommand); 874 if (err == noErr) 875 { 876 err = MPWaitOnSemaphore(cisem, kDurationForever); 877 878 if (tHICommand.commandID == 'rSET') 879 { 880 [ciFilter setDefaults]; 881 FilterToFilterParam(); 882 FilterUISetValues(ciFilterUIPane); 883 884 result = noErr; 885 } 886 else 887 { 888 unsigned long i = tHICommand.commandID & 0x00FFFFFF; 889 890 switch (tHICommand.commandID & 0xFF000000) 891 { 892 case kCommandFilterMenuBase: 893 DeinitCoreImageFilter(); 894 895 CFRelease(ciFilterName); 896 ciFilterName = CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef) [ciFilterNameList objectAtIndex: i]); 897 898 InitCoreImageFilter(); 899 900 ReplaceFilterUI(window); 901 902 break; 903 904 case kCommandCheckBoxBase: 905 ciFilterParam[i].u.b.cur = !(ciFilterParam[i].u.b.cur); 906 FilterParamToFilter(); 907 result = noErr; 908 909 break; 910 911 case kCommandSliderBase: 912 SInt32 value; 913 914 value = HIViewGetValue(tHICommand.source.control); 915 ciFilterParam[i].u.s.cur = ciFilterParam[i].u.s.min + (ciFilterParam[i].u.s.max - ciFilterParam[i].u.s.min) * (float) value / (float) FIXEDRANGE; 916 FilterParamToFilter(); 917 result = noErr; 918 919 break; 920 921 case kCommandColorButtonBase: 922 NColorPickerInfo info; 923 924 memset(&info, 0, sizeof(NColorPickerInfo)); 925 info.placeWhere = kCenterOnMainScreen; 926 info.flags = kColorPickerDialogIsMoveable | kColorPickerDialogIsModal; 927 info.theColor.color.rgb.red = (int) (65535.0 * ciFilterParam[i].u.c.r); 928 info.theColor.color.rgb.green = (int) (65535.0 * ciFilterParam[i].u.c.g); 929 info.theColor.color.rgb.blue = (int) (65535.0 * ciFilterParam[i].u.c.b); 930 931 err = NPickColor(&info); 932 933 if ((err == noErr) && info.newColorChosen) 934 { 935 ciFilterParam[i].u.c.r = (float) info.theColor.color.rgb.red / 65535.0f; 936 ciFilterParam[i].u.c.g = (float) info.theColor.color.rgb.green / 65535.0f; 937 ciFilterParam[i].u.c.b = (float) info.theColor.color.rgb.blue / 65535.0f; 938 } 939 940 FilterParamToFilter(); 941 result = noErr; 942 943 break; 944 } 945 } 946 947 err = MPSignalSemaphore(cisem); 948 } 949 } 950 } 951 952 return (result); 953} 954 955void InitCoreImageContext (CGLContextObj cglctx, CGLPixelFormatObj cglpix) 956{ 957 NSAutoreleasePool *pool; 958 959 pool = [[NSAutoreleasePool alloc] init]; 960 961 FilterToFilterParam(); 962 963 cgColor = CGColorSpaceCreateDeviceRGB(); 964 965#ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT 966 ciContext = [[CIContext contextWithCGLContext: cglctx pixelFormat: cglpix options: NULL] retain]; 967#else 968 ciContext = [[CIContext contextWithCGLContext: cglctx pixelFormat: cglpix colorSpace: cgColor options: NULL] retain]; 969#endif 970 971 [pool release]; 972} 973 974void DeinitCoreImageContext (void) 975{ 976 NSAutoreleasePool *pool; 977 978 pool = [[NSAutoreleasePool alloc] init]; 979 980 [ciContext release]; 981 CGColorSpaceRelease(cgColor); 982 983 [pool release]; 984} 985 986void DrawWithCoreImageFilter (CGRect src, CGImageRef img) 987{ 988 OSStatus err; 989 NSAutoreleasePool *pool; 990 991 pool = [[NSAutoreleasePool alloc] init]; 992 993 err = MPWaitOnSemaphore(cisem, kDurationForever); 994 995 if (ciFilterHasInputImage) 996 { 997 CIImage *image; 998 999 image = [CIImage imageWithCGImage: img]; 1000 [ciFilter setValue: image forKey: @"inputImage" ]; 1001 } 1002 1003 if (ciFilterHasInputCenter) 1004 { 1005 CIVector *vector; 1006 1007 vector = [CIVector vectorWithX: (src.origin.x + src.size.width / 2) Y: (src.origin.y + src.size.height / 2)]; 1008 [ciFilter setValue: vector forKey: @"inputCenter"]; 1009 } 1010 1011 [ciContext drawImage: [ciFilter valueForKey: @"outputImage"] atPoint: CGPointZero fromRect: src]; 1012 1013 err = MPSignalSemaphore(cisem); 1014 1015 [pool release]; 1016} 1017