/* Copyright 2006 Guillaume Duhamel Copyright 2006 Anders Montonen This file is part of Yabause. Yabause is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Yabause is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Yabause; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "settings.h" #include "cpustatus.h" #define YUI_MENU_EMULATION 1 #define YUI_MENU_DEBUG 2 #define YUI_COMMAND_RUN 1 #define YUI_COMMAND_PAUSE 2 #define YUI_COMMAND_RESUME 3 #define YUI_COMMAND_SHOW_CPU 4 #define YUI_COMMAND_HIDE_CPU 5 #define YUI_COMMAND_TOGGLE_NBG0 6 #define YUI_COMMAND_TOGGLE_NBG1 7 #define YUI_COMMAND_TOGGLE_NBG2 8 #define YUI_COMMAND_TOGGLE_NBG3 9 #define YUI_COMMAND_TOGGLE_RBG0 10 #define YUI_COMMAND_TOGGLE_VDP1 11 #define YUI_COMMAND_TOGGLE_FULLSCREEN 12 AGLContext myAGLContext = NULL; WindowRef myWindow = NULL; yabauseinit_struct yinit; extern const char * key_names[] = { "Up", "Right", "Down", "Left", "Right trigger", "Left trigger", "Start", "A", "B", "C", "X", "Y", "Z", NULL }; M68K_struct * M68KCoreList[] = { &M68KDummy, &M68KC68K, NULL }; SH2Interface_struct *SH2CoreList[] = { &SH2Interpreter, &SH2DebugInterpreter, NULL }; PerInterface_struct *PERCoreList[] = { &PERDummy, NULL }; CDInterface *CDCoreList[] = { &DummyCD, &ISOCD, &ArchCD, NULL }; SoundInterface_struct *SNDCoreList[] = { &SNDDummy, #ifdef HAVE_LIBSDL &SNDSDL, #endif NULL }; VideoInterface_struct *VIDCoreList[] = { &VIDDummy, &VIDOGL, &VIDSoft, NULL }; static EventLoopTimerRef EventTimer; void YuiIdle(EventLoopTimerRef a, void * b) { int i; for(i = 0;i < 200;i++) { YabauseExec(); } } void read_settings(void) { int i; CFStringRef s; yinit.percoretype = PERCORE_DUMMY; yinit.sh2coretype = SH2CORE_INTERPRETER; yinit.vidcoretype = VIDCORE_OGL; yinit.m68kcoretype = M68KCORE_C68K; s = CFPreferencesCopyAppValue(CFSTR("VideoCore"), kCFPreferencesCurrentApplication); if (s) yinit.vidcoretype = CFStringGetIntValue(s) - 1; yinit.sndcoretype = SNDCORE_DUMMY; s = CFPreferencesCopyAppValue(CFSTR("SoundCore"), kCFPreferencesCurrentApplication); if (s) yinit.sndcoretype = CFStringGetIntValue(s) - 1; yinit.cdcoretype = CDCORE_ARCH; s = CFPreferencesCopyAppValue(CFSTR("CDROMCore"), kCFPreferencesCurrentApplication); if (s) yinit.cdcoretype = CFStringGetIntValue(s) - 1; yinit.carttype = CART_NONE; s = CFPreferencesCopyAppValue(CFSTR("CartType"), kCFPreferencesCurrentApplication); if (s) yinit.carttype = CFStringGetIntValue(s) - 1; yinit.regionid = 0; s = CFPreferencesCopyAppValue(CFSTR("Region"), kCFPreferencesCurrentApplication); if (s) yinit.regionid = CFStringGetIntValue(s) - 1; yinit.biospath = 0; s = CFPreferencesCopyAppValue(CFSTR("BiosPath"), kCFPreferencesCurrentApplication); if (s) yinit.biospath = strdup(CFStringGetCStringPtr(s, 0)); yinit.cdpath = 0; s = CFPreferencesCopyAppValue(CFSTR("CDROMDrive"), kCFPreferencesCurrentApplication); if (s) yinit.cdpath = strdup(CFStringGetCStringPtr(s, 0)); yinit.buppath = 0; s = CFPreferencesCopyAppValue(CFSTR("BackupRamPath"), kCFPreferencesCurrentApplication); if (s) yinit.buppath = strdup(CFStringGetCStringPtr(s, 0)); yinit.mpegpath = 0; s = CFPreferencesCopyAppValue(CFSTR("MpegRomPath"), kCFPreferencesCurrentApplication); if (s) yinit.mpegpath = strdup(CFStringGetCStringPtr(s, 0)); yinit.cartpath = 0; s = CFPreferencesCopyAppValue(CFSTR("CartPath"), kCFPreferencesCurrentApplication); if (s) yinit.cartpath = strdup(CFStringGetCStringPtr(s, 0)); yinit.flags = VIDEOFORMATTYPE_NTSC; s = CFPreferencesCopyAppValue(CFSTR("AutoFrameSkip"), kCFPreferencesCurrentApplication); if (s) yinit.frameskip = CFStringGetIntValue(s); i = 0; while(key_names[i]) { s = CFPreferencesCopyAppValue( CFStringCreateWithCString(0, key_names[i], 0), kCFPreferencesCurrentApplication); if (s) PerSetKey(CFStringGetIntValue(s), key_names[i]); i++; } } static void YuiPause(const int Pause) { EventTimerInterval Interval; if(Pause) { Interval = kEventDurationForever; ScspMuteAudio(); } else { Interval = kEventDurationMillisecond; ScspUnMuteAudio(); } SetEventLoopTimerNextFireTime(EventTimer, Interval); } void YuiRun(void) { static int FirstRun = 1; EventLoopTimerUPP myFrameUPP; if(FirstRun) { myFrameUPP = NewEventLoopTimerUPP(YuiIdle); InstallEventLoopTimer(GetCurrentEventLoop(), kEventDurationNoWait, kEventDurationMillisecond, myFrameUPP, NULL, &EventTimer); FirstRun = 0; } else { YuiPause(0); YabauseDeInit(); } read_settings(); YabauseInit(&yinit); } static void TogglePairedMenuItems(MenuRef menu, MenuItemIndex BaseItemIndex) { MenuItemAttributes ItemAttributes; GetMenuItemAttributes(menu, BaseItemIndex, &ItemAttributes); if(ItemAttributes & kMenuItemAttrHidden) { ChangeMenuItemAttributes(menu, BaseItemIndex, 0, kMenuItemAttrHidden); ChangeMenuItemAttributes(menu, BaseItemIndex+1, kMenuItemAttrHidden, 0); } else { ChangeMenuItemAttributes(menu, BaseItemIndex, kMenuItemAttrHidden, 0); ChangeMenuItemAttributes(menu, BaseItemIndex+1, 0, kMenuItemAttrHidden); } } OSStatus MyWindowEventHandler (EventHandlerCallRef myHandler, EventRef theEvent, void* userData) { OSStatus ret = noErr; MenuRef menu; switch(GetEventClass(theEvent)) { case kEventClassWindow: switch (GetEventKind (theEvent)) { case kEventWindowClose: YabauseDeInit(); QuitApplicationEventLoop(); break; case kEventWindowBoundsChanged: aglUpdateContext(myAGLContext); { Rect bounds; GetEventParameter(theEvent, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &bounds); glViewport(0, 0, bounds.right - bounds.left, bounds.bottom - bounds.top); } break; } break; case kEventClassCommand: { HICommand command; GetEventParameter(theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &command); switch(command.commandID) { case kHICommandPreferences: CreateSettingsWindow(); break; case kHICommandQuit: YabauseDeInit(); QuitApplicationEventLoop(); break; case YUI_COMMAND_RUN: YuiRun(); menu = GetMenuRef(YUI_MENU_EMULATION); ChangeMenuItemAttributes(menu, 2, 0, kMenuItemAttrHidden); ChangeMenuItemAttributes(menu, 3, kMenuItemAttrHidden, 0); break; case YUI_COMMAND_PAUSE: YuiPause(1); menu = GetMenuRef(YUI_MENU_EMULATION); TogglePairedMenuItems(menu, 2); UpdateCPUStatusWindow(); break; case YUI_COMMAND_RESUME: YuiPause(0); menu = GetMenuRef(YUI_MENU_EMULATION); TogglePairedMenuItems(menu, 2); break; case YUI_COMMAND_SHOW_CPU: ShowCPUStatusWindow(); menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 1); break; case YUI_COMMAND_HIDE_CPU: HideCPUStatusWindow(); menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 1); break; case YUI_COMMAND_TOGGLE_NBG0: if(VIDCore) { menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 4); ToggleNBG0(); } break; case YUI_COMMAND_TOGGLE_NBG1: if(VIDCore) { menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 6); ToggleNBG1(); } break; case YUI_COMMAND_TOGGLE_NBG2: if(VIDCore) { menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 8); ToggleNBG2(); } break; case YUI_COMMAND_TOGGLE_NBG3: if(VIDCore) { menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 10); ToggleNBG3(); } break; case YUI_COMMAND_TOGGLE_RBG0: if(VIDCore) { menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 12); ToggleRBG0(); } break; case YUI_COMMAND_TOGGLE_VDP1: if(VIDCore) { menu = GetMenuRef(YUI_MENU_DEBUG); TogglePairedMenuItems(menu, 14); ToggleVDP1(); } break; case YUI_COMMAND_TOGGLE_FULLSCREEN: if(VIDCore) { menu = GetMenuRef(YUI_MENU_EMULATION); TogglePairedMenuItems(menu, 5); ToggleFullScreen(); } break; default: ret = eventNotHandledErr; printf("unhandled command\n"); break; } } break; case kEventClassKeyboard: switch(GetEventKind(theEvent)) { int i; UInt32 key; case kEventRawKeyDown: GetEventParameter(theEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key); PerKeyDown(key); break; case kEventRawKeyUp: GetEventParameter(theEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key); PerKeyUp(key); break; } break; } return ret; } static WindowRef CreateMyWindow() { WindowRef myWindow; Rect contentBounds; CFStringRef windowTitle = CFSTR("Yabause"); WindowClass windowClass = kDocumentWindowClass; WindowAttributes attributes = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute; EventTypeSpec eventList[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassCommand, kEventCommandProcess }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyUp } }; SetRect(&contentBounds, 200, 200, 520, 424); CreateNewWindow (windowClass, attributes, &contentBounds, &myWindow); SetWindowTitleWithCFString (myWindow, windowTitle); CFRelease(windowTitle); ShowWindow(myWindow); InstallWindowEventHandler(myWindow, NewEventHandlerUPP (MyWindowEventHandler), GetEventTypeCount(eventList), eventList, myWindow, NULL); return myWindow; } static OSStatus MyAGLReportError (void) { GLenum err = aglGetError(); if (err == AGL_NO_ERROR) return noErr; else return (OSStatus) err; } static OSStatus MySetWindowAsDrawableObject (WindowRef window) { OSStatus err = noErr; GLint attributes[] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 24, AGL_NONE }; AGLPixelFormat myAGLPixelFormat; myAGLPixelFormat = aglChoosePixelFormat (NULL, 0, attributes); err = MyAGLReportError (); if (myAGLPixelFormat) { myAGLContext = aglCreateContext (myAGLPixelFormat, NULL); err = MyAGLReportError (); aglDestroyPixelFormat(myAGLPixelFormat); } if (! aglSetDrawable (myAGLContext, GetWindowPort (window))) err = MyAGLReportError (); if (!aglSetCurrentContext (myAGLContext)) err = MyAGLReportError (); return err; } int main () { MenuRef menu; EventLoopTimerRef nextFrameTimer; IBNibRef menuNib; myWindow = CreateMyWindow(); MySetWindowAsDrawableObject(myWindow); CreateNibReference(CFSTR("menu"), &menuNib); SetMenuBarFromNib(menuNib, CFSTR("MenuBar")); EnableMenuCommand(NULL, kHICommandPreferences); read_settings(); RunApplicationEventLoop(); return 0; } void YuiErrorMsg(const char * string) { printf("%s\n", string); } void YuiVideoResize(unsigned int w, unsigned int h, int isfullscreen) { } void YuiSetVideoAttribute(int type, int val) { } int YuiSetVideoMode(int width, int height, int bpp, int fullscreen) { static CFDictionaryRef oldDisplayMode = 0; static int oldDisplayModeValid = 0; AGLPixelFormat myAGLPixelFormat; AGLDrawable myDrawable = aglGetDrawable(myAGLContext); OSStatus err = noErr; GLint attributesFullscreen[] = { AGL_RGBA, AGL_FULLSCREEN, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 24, AGL_NONE }; CGDirectDisplayID displayId = kCGDirectMainDisplay; if(myDrawable) { if(fullscreen) { Rect bounds; CGPoint point; CGDisplayCount displayCount; GetWindowBounds(myWindow, kWindowGlobalPortRgn, &bounds); point.x = (float)bounds.left; point.y = (float)bounds.top; CGGetDisplaysWithPoint(point, 1, &displayId, &displayCount); CFDictionaryRef refDisplayMode = CGDisplayBestModeForParameters(displayId, bpp, width, height, NULL); if(refDisplayMode) { GDHandle gdhDisplay; oldDisplayMode = CGDisplayCurrentMode(displayId); oldDisplayModeValid = 1; aglSetDrawable(myAGLContext, NULL); aglSetCurrentContext(NULL); aglDestroyContext(myAGLContext); myAGLContext = NULL; CGCaptureAllDisplays(); CGDisplaySwitchToMode(displayId, refDisplayMode); CGDisplayHideCursor(displayId); DMGetGDeviceByDisplayID((DisplayIDType)displayId, &gdhDisplay, 0); myAGLPixelFormat = aglChoosePixelFormat(&gdhDisplay, 1, attributesFullscreen); if(myAGLPixelFormat) { myAGLContext = aglCreateContext(myAGLPixelFormat, NULL); if(myAGLContext) { aglSetCurrentContext(myAGLContext); aglSetFullScreen(myAGLContext, width, height, 0, 0); } err = MyAGLReportError(); aglDestroyPixelFormat(myAGLPixelFormat); } else { err = MyAGLReportError(); CGReleaseAllDisplays(); CGDisplayShowCursor(displayId); } } else { err = MyAGLReportError(); } } else { if(oldDisplayModeValid) { oldDisplayModeValid = 0; aglSetDrawable(myAGLContext, NULL); aglSetCurrentContext(NULL); aglDestroyContext(myAGLContext); myAGLContext = NULL; CGDisplayShowCursor(displayId); CGDisplaySwitchToMode(displayId, oldDisplayMode); CGReleaseAllDisplays(); MySetWindowAsDrawableObject(myWindow); } } } return !(err == noErr); } void YuiSwapBuffers(void) { aglSwapBuffers(myAGLContext); }