29 * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. |
29 * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. |
30 */ |
30 */ |
31 |
31 |
32 |
32 |
33 /* Portions of CPS.h */ |
33 /* Portions of CPS.h */ |
34 typedef struct CPSProcessSerNum { |
34 struct CPSProcessSerNum { |
35 UInt32 lo; |
35 UInt32 lo; |
36 UInt32 hi; |
36 UInt32 hi; |
37 } CPSProcessSerNum; |
37 }; |
38 |
38 |
39 extern "C" OSErr CPSGetCurrentProcess(CPSProcessSerNum* psn); |
39 extern "C" OSErr CPSGetCurrentProcess(CPSProcessSerNum* psn); |
40 extern "C" OSErr CPSEnableForegroundOperation(CPSProcessSerNum* psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); |
40 extern "C" OSErr CPSEnableForegroundOperation(CPSProcessSerNum* psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); |
41 extern "C" OSErr CPSSetFrontProcess(CPSProcessSerNum* psn); |
41 extern "C" OSErr CPSSetFrontProcess(CPSProcessSerNum* psn); |
42 |
42 |
43 /* From Menus.h (according to Xcode Developer Documentation) */ |
43 /* From Menus.h (according to Xcode Developer Documentation) */ |
44 extern "C" void ShowMenuBar(void); |
44 extern "C" void ShowMenuBar(); |
45 extern "C" void HideMenuBar(void); |
45 extern "C" void HideMenuBar(); |
46 |
46 |
47 /* Disables a warning. This is needed since the method exists but has been dropped from the header, supposedly as of 10.4. */ |
47 /* Disables a warning. This is needed since the method exists but has been dropped from the header, supposedly as of 10.4. */ |
48 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
48 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
49 @interface NSApplication(NSAppleMenu) |
49 @interface NSApplication(NSAppleMenu) |
50 - (void)setAppleMenu:(NSMenu *)menu; |
50 - (void)setAppleMenu:(NSMenu *)menu; |
101 /* Structure for rez switch gamma fades |
102 /* Structure for rez switch gamma fades |
102 * We can hide the monitor flicker by setting the gamma tables to 0 |
103 * We can hide the monitor flicker by setting the gamma tables to 0 |
103 */ |
104 */ |
104 #define QZ_GAMMA_TABLE_SIZE 256 |
105 #define QZ_GAMMA_TABLE_SIZE 256 |
105 |
106 |
106 typedef struct { |
107 struct OTTD_QuartzGammaTable { |
107 CGGammaValue red[QZ_GAMMA_TABLE_SIZE]; |
108 CGGammaValue red[QZ_GAMMA_TABLE_SIZE]; |
108 CGGammaValue green[QZ_GAMMA_TABLE_SIZE]; |
109 CGGammaValue green[QZ_GAMMA_TABLE_SIZE]; |
109 CGGammaValue blue[QZ_GAMMA_TABLE_SIZE]; |
110 CGGammaValue blue[QZ_GAMMA_TABLE_SIZE]; |
110 } OTTD_QuartzGammaTable; |
111 }; |
111 |
112 |
112 /* Add methods to get at private members of NSScreen. |
113 /* Add methods to get at private members of NSScreen. |
113 * Since there is a bug in Apple's screen switching code that does not update |
114 * Since there is a bug in Apple's screen switching code that does not update |
114 * this variable when switching to fullscreen, we'll set it manually (but only |
115 * this variable when switching to fullscreen, we'll set it manually (but only |
115 * for the main screen). |
116 * for the main screen). |
124 _frame = frame; |
125 _frame = frame; |
125 } |
126 } |
126 @end |
127 @end |
127 |
128 |
128 |
129 |
129 static void QZ_Draw(void); |
130 static void QZ_Draw(); |
130 static void QZ_UnsetVideoMode(void); |
131 static void QZ_UnsetVideoMode(); |
131 static void QZ_UpdatePalette(uint start, uint count); |
132 static void QZ_UpdatePalette(uint start, uint count); |
132 static void QZ_WarpCursor(int x, int y); |
133 static void QZ_WarpCursor(int x, int y); |
133 static void QZ_ShowMouse(void); |
134 static void QZ_ShowMouse(); |
134 static void QZ_HideMouse(void); |
135 static void QZ_HideMouse(); |
135 static void CocoaVideoFullScreen(bool full_screen); |
136 static void CocoaVideoFullScreen(bool full_screen); |
136 |
137 |
137 |
138 |
138 static NSAutoreleasePool *_ottd_autorelease_pool; |
139 static NSAutoreleasePool *_ottd_autorelease_pool; |
139 static OTTDMain *_ottd_main; |
140 static OTTDMain *_ottd_main; |
190 |
191 |
191 /****************************************************************************** |
192 /****************************************************************************** |
192 * Game loop and accessories * |
193 * Game loop and accessories * |
193 ******************************************************************************/ |
194 ******************************************************************************/ |
194 |
195 |
195 static uint32 GetTick(void) |
196 static uint32 GetTick() |
196 { |
197 { |
197 struct timeval tim; |
198 struct timeval tim; |
198 |
199 |
199 gettimeofday(&tim, NULL); |
200 gettimeofday(&tim, NULL); |
200 return tim.tv_usec / 1000 + tim.tv_sec * 1000; |
201 return tim.tv_usec / 1000 + tim.tv_sec * 1000; |
201 } |
202 } |
202 |
203 |
203 static void QZ_CheckPaletteAnim(void) |
204 static void QZ_CheckPaletteAnim() |
204 { |
205 { |
205 if (_pal_last_dirty != -1) { |
206 if (_pal_last_dirty != -1) { |
206 QZ_UpdatePalette(_pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1); |
207 QZ_UpdatePalette(_pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1); |
207 _pal_last_dirty = -1; |
208 _pal_last_dirty = -1; |
208 } |
209 } |
209 } |
210 } |
210 |
211 |
211 |
212 |
212 |
213 |
213 typedef struct VkMapping { |
214 struct VkMapping { |
214 unsigned short vk_from; |
215 unsigned short vk_from; |
215 byte map_to; |
216 byte map_to; |
216 } VkMapping; |
217 }; |
217 |
218 |
218 #define AS(x, z) {x, z} |
219 #define AS(x, z) {x, z} |
219 |
220 |
220 static const VkMapping _vk_mapping[] = { |
221 static const VkMapping _vk_mapping[] = { |
221 AS(QZ_BACKQUOTE, WKC_BACKQUOTE), // key left of '1' |
222 AS(QZ_BACKQUOTE, WKC_BACKQUOTE), // key left of '1' |
651 if ([ event deltaY ] > 0.0) { /* Scroll up */ |
652 if ([ event deltaY ] > 0.0) { /* Scroll up */ |
652 _cursor.wheel--; |
653 _cursor.wheel--; |
653 } else if ([ event deltaY ] < 0.0) { /* Scroll down */ |
654 } else if ([ event deltaY ] < 0.0) { /* Scroll down */ |
654 _cursor.wheel++; |
655 _cursor.wheel++; |
655 } /* else: deltaY was 0.0 and we don't want to do anything */ |
656 } /* else: deltaY was 0.0 and we don't want to do anything */ |
|
657 |
|
658 /* Set the scroll count for scrollwheel scrolling */ |
|
659 _cursor.h_wheel -= (int)([ event deltaX ]* 5 * _patches.scrollwheel_multiplier); |
|
660 _cursor.v_wheel -= (int)([ event deltaY ]* 5 * _patches.scrollwheel_multiplier); |
656 break; |
661 break; |
657 |
662 |
658 default: |
663 default: |
659 [NSApp sendEvent:event]; |
664 [NSApp sendEvent:event]; |
660 } |
665 } |
661 |
666 |
662 return true; |
667 return true; |
663 } |
668 } |
664 |
669 |
665 |
670 |
666 static void QZ_GameLoop(void) |
671 static void QZ_GameLoop() |
667 { |
672 { |
668 uint32 cur_ticks = GetTick(); |
673 uint32 cur_ticks = GetTick(); |
669 uint32 next_tick = cur_ticks + 30; |
674 uint32 next_tick = cur_ticks + 30; |
670 uint32 pal_tick = 0; |
675 uint32 pal_tick = 0; |
671 #ifdef _DEBUG |
676 #ifdef _DEBUG |
710 } else if (_fast_forward & 2) { |
715 } else if (_fast_forward & 2) { |
711 _fast_forward = 0; |
716 _fast_forward = 0; |
712 } |
717 } |
713 |
718 |
714 cur_ticks = GetTick(); |
719 cur_ticks = GetTick(); |
715 if (cur_ticks >= next_tick || (_fast_forward && !_pause) || cur_ticks < prev_cur_ticks) { |
720 if (cur_ticks >= next_tick || (_fast_forward && !_pause_game) || cur_ticks < prev_cur_ticks) { |
716 next_tick = cur_ticks + 30; |
721 next_tick = cur_ticks + 30; |
717 |
722 |
718 _ctrl_pressed = !!(_cocoa_video_data.current_mods & NSControlKeyMask); |
723 _ctrl_pressed = !!(_cocoa_video_data.current_mods & NSControlKeyMask); |
719 _shift_pressed = !!(_cocoa_video_data.current_mods & NSShiftKeyMask); |
724 _shift_pressed = !!(_cocoa_video_data.current_mods & NSShiftKeyMask); |
720 #ifdef _DEBUG |
725 #ifdef _DEBUG |
762 |
767 |
763 /* This function makes the *game region* of the window 100% opaque. |
768 /* This function makes the *game region* of the window 100% opaque. |
764 * The genie effect uses the alpha component. Otherwise, |
769 * The genie effect uses the alpha component. Otherwise, |
765 * it doesn't seem to matter what value it has. |
770 * it doesn't seem to matter what value it has. |
766 */ |
771 */ |
767 static void QZ_SetPortAlphaOpaque(void) |
772 static void QZ_SetPortAlphaOpaque() |
768 { |
773 { |
769 if (_cocoa_video_data.device_bpp == 32) { |
774 if (_cocoa_video_data.device_bpp == 32) { |
770 uint32* pixels = (uint32*)_cocoa_video_data.realpixels; |
775 uint32* pixels = (uint32*)_cocoa_video_data.realpixels; |
771 uint32 rowPixels = _cocoa_video_data.pitch / 4; |
776 uint32 rowPixels = _cocoa_video_data.pitch / 4; |
772 uint32 i; |
777 uint32 i; |
1030 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, |
1035 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, |
1031 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, |
1036 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, |
1032 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 |
1037 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 |
1033 }; |
1038 }; |
1034 |
1039 |
1035 static void QZ_DrawResizeIcon(void) |
1040 static void QZ_DrawResizeIcon() |
1036 { |
1041 { |
1037 int xoff = _cocoa_video_data.width - 16; |
1042 int xoff = _cocoa_video_data.width - 16; |
1038 int yoff = _cocoa_video_data.height - 16; |
1043 int yoff = _cocoa_video_data.height - 16; |
1039 int x; |
1044 int x; |
1040 int y; |
1045 int y; |
1419 |
1424 |
1420 CGDisplaySetPalette(_cocoa_video_data.display_id, _cocoa_video_data.palette); |
1425 CGDisplaySetPalette(_cocoa_video_data.display_id, _cocoa_video_data.palette); |
1421 } |
1426 } |
1422 |
1427 |
1423 /* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */ |
1428 /* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */ |
1424 static void QZ_WaitForVerticalBlank(void) |
1429 static void QZ_WaitForVerticalBlank() |
1425 { |
1430 { |
1426 /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */ |
1431 /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */ |
1427 double refreshRate; |
1432 double refreshRate; |
1428 double linesPerSecond; |
1433 double linesPerSecond; |
1429 double target; |
1434 double target; |
1450 |
1455 |
1451 CSleep((uint32)(adjustment * 1000)); |
1456 CSleep((uint32)(adjustment * 1000)); |
1452 } |
1457 } |
1453 |
1458 |
1454 |
1459 |
1455 static void QZ_DrawScreen(void) |
1460 static void QZ_DrawScreen() |
1456 { |
1461 { |
1457 const uint8* src = _cocoa_video_data.pixels; |
1462 const uint8* src = _cocoa_video_data.pixels; |
1458 uint8* dst = (uint8*)_cocoa_video_data.realpixels; |
1463 uint8* dst = (uint8*)_cocoa_video_data.realpixels; |
1459 uint pitch = _cocoa_video_data.pitch; |
1464 uint pitch = _cocoa_video_data.pitch; |
1460 uint width = _cocoa_video_data.width; |
1465 uint width = _cocoa_video_data.width; |
1577 } else { |
1582 } else { |
1578 QZ_UpdateWindowPalette(start, count); |
1583 QZ_UpdateWindowPalette(start, count); |
1579 } |
1584 } |
1580 } |
1585 } |
1581 |
1586 |
1582 static void QZ_InitPalette(void) |
1587 static void QZ_InitPalette() |
1583 { |
1588 { |
1584 QZ_UpdatePalette(0, 256); |
1589 QZ_UpdatePalette(0, 256); |
1585 } |
1590 } |
1586 |
1591 |
1587 static void QZ_Draw(void) |
1592 static void QZ_Draw() |
1588 { |
1593 { |
1589 if (_cocoa_video_data.fullscreen) { |
1594 if (_cocoa_video_data.fullscreen) { |
1590 QZ_DrawScreen(); |
1595 QZ_DrawScreen(); |
1591 } else { |
1596 } else { |
1592 QZ_DrawWindow(); |
1597 QZ_DrawWindow(); |
1717 if (ret != NULL && wasset) QZ_SetVideoMode(oldwidth, oldheight, oldfullscreen); |
1722 if (ret != NULL && wasset) QZ_SetVideoMode(oldwidth, oldheight, oldfullscreen); |
1718 |
1723 |
1719 return ret; |
1724 return ret; |
1720 } |
1725 } |
1721 |
1726 |
1722 static void QZ_VideoInit(void) |
1727 static void QZ_VideoInit() |
1723 { |
1728 { |
1724 memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data)); |
1729 memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data)); |
1725 |
1730 |
1726 /* Initialize the video settings; this data persists between mode switches */ |
1731 /* Initialize the video settings; this data persists between mode switches */ |
1727 _cocoa_video_data.display_id = kCGDirectMainDisplay; |
1732 _cocoa_video_data.display_id = kCGDirectMainDisplay; |
1787 CGWarpMouseCursorPosition(cgp); |
1792 CGWarpMouseCursorPosition(cgp); |
1788 |
1793 |
1789 /* Generate the mouse moved event */ |
1794 /* Generate the mouse moved event */ |
1790 } |
1795 } |
1791 |
1796 |
1792 static void QZ_ShowMouse(void) |
1797 static void QZ_ShowMouse() |
1793 { |
1798 { |
1794 if (!_cocoa_video_data.cursor_visible) { |
1799 if (!_cocoa_video_data.cursor_visible) { |
1795 [ NSCursor unhide ]; |
1800 [ NSCursor unhide ]; |
1796 _cocoa_video_data.cursor_visible = true; |
1801 _cocoa_video_data.cursor_visible = true; |
1797 |
1802 |
1911 /* Finally give up our references to the objects */ |
1916 /* Finally give up our references to the objects */ |
1912 [windowMenu release]; |
1917 [windowMenu release]; |
1913 [windowMenuItem release]; |
1918 [windowMenuItem release]; |
1914 } |
1919 } |
1915 |
1920 |
1916 static void setupApplication(void) |
1921 static void setupApplication() |
1917 { |
1922 { |
1918 CPSProcessSerNum PSN; |
1923 CPSProcessSerNum PSN; |
1919 |
1924 |
1920 /* Ensure the application object is initialised */ |
1925 /* Ensure the application object is initialised */ |
1921 [NSApplication sharedApplication]; |
1926 [NSApplication sharedApplication]; |
1940 |
1945 |
1941 /****************************************************************************** |
1946 /****************************************************************************** |
1942 * Video driver interface * |
1947 * Video driver interface * |
1943 ******************************************************************************/ |
1948 ******************************************************************************/ |
1944 |
1949 |
1945 static void CocoaVideoStop(void) |
1950 static void CocoaVideoStop() |
1946 { |
1951 { |
1947 if (!_cocoa_video_started) return; |
1952 if (!_cocoa_video_started) return; |
1948 |
1953 |
1949 if (_cocoa_video_data.isset) QZ_UnsetVideoMode(); |
1954 if (_cocoa_video_data.isset) QZ_UnsetVideoMode(); |
1950 |
1955 |
2040 if (!wasstarted) CocoaVideoStop(); |
2045 if (!wasstarted) CocoaVideoStop(); |
2041 |
2046 |
2042 _cocoa_video_dialog = false; |
2047 _cocoa_video_dialog = false; |
2043 } |
2048 } |
2044 |
2049 |
2045 |
|
2046 /* This is needed since OS X applications are started with the working dir set to / when double-clicked */ |
|
2047 void cocoaSetWorkingDirectory(void) |
|
2048 { |
|
2049 char parentdir[MAXPATHLEN]; |
|
2050 int chdir_ret; |
|
2051 CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); |
|
2052 CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); |
|
2053 if (CFURLGetFileSystemRepresentation(url2, true, (unsigned char*)parentdir, MAXPATHLEN)) { |
|
2054 chdir_ret = chdir(parentdir); /* chdir to the binary app's parent */ |
|
2055 assert(chdir_ret == 0); |
|
2056 } |
|
2057 CFRelease(url); |
|
2058 CFRelease(url2); |
|
2059 } |
|
2060 |
|
2061 /* These are called from main() to prevent a _NSAutoreleaseNoPool error when |
2050 /* These are called from main() to prevent a _NSAutoreleaseNoPool error when |
2062 * exiting before the cocoa video driver has been loaded |
2051 * exiting before the cocoa video driver has been loaded |
2063 */ |
2052 */ |
2064 void cocoaSetupAutoreleasePool(void) |
2053 void cocoaSetupAutoreleasePool() |
2065 { |
2054 { |
2066 _ottd_autorelease_pool = [[NSAutoreleasePool alloc] init]; |
2055 _ottd_autorelease_pool = [[NSAutoreleasePool alloc] init]; |
2067 } |
2056 } |
2068 |
2057 |
2069 void cocoaReleaseAutoreleasePool(void) |
2058 void cocoaReleaseAutoreleasePool() |
2070 { |
2059 { |
2071 [_ottd_autorelease_pool release]; |
2060 [_ottd_autorelease_pool release]; |
2072 } |
2061 } |
2073 |
2062 |
2074 #endif /* WITH_COCOA */ |
2063 #endif /* WITH_COCOA */ |