/***************************************************************** Xmame OpenGL driver Written based on the x11 driver by Mike Oliphant - oliphant@ling.ed.ac.uk http://www.ling.ed.ac.uk/~oliphant/glmame This code may be used and distributed under the terms of the Mame license *****************************************************************/ /* pretend we're x11.c otherwise display and a few other crucial things don't get declared */ #define __X11_C_ #define __XOPENGL_C_ #define RRand(range) (random()%range) #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include "common.h" #include "usrintrf.h" #include "osdepend.h" #include "mame.h" #include "driver.h" #include "MAME32.h" #include "Display.h" #include "Sound.h" #include "Keyboard.h" #include "Joystick.h" #include "Trak.h" #include "resource.h" #include "M32Util.h" #include "wgl.h" /* #ifndef NOSEAL #include "SealSound.h" /* For sound devices. #endif */ struct GameOptions mame_options; static void MamePlayGame(); static int page_index; static game_data_type* game_data; static int game_count; static int last_sort = 0; /* global data--know where to send messages */ static BOOL in_emulation; /* quit after game */ static BOOL quit; /* idle work at startup */ static BOOL idle_work; static int game_index; int winwidth=640; int winheight=480; float fxgamma=1.0; static HDC thisWin; static HWND thisHwnd; /* static wglWnd thisCwnd; */ static HGLRC cx; static int fx=0; static int fxwin=0; extern int screendirty; extern int doublebuffer; extern int dodepth; /*************************************************************************** Function prototypes ***************************************************************************/ static LRESULT CALLBACK MAME32_MessageProc(HWND, UINT, WPARAM, LPARAM); static HWND MAME32_CreateWindow(void); static void MAME32_ProcessMessages(void); static BOOL MAME32_PumpAndReturnMessage(MSG* pMsg); static void MAME32_Quit(void); static BOOL OnMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT* pResult); static void OnActivateApp(HWND hWnd, BOOL fActivate, DWORD dwThreadId); static void OnSysCommand(HWND hWnd, UINT cmd, int x, int y); static void OnClose(HWND hWnd); /*************************************************************************** External variables ***************************************************************************/ /* struct tMAME32App MAME32App = { { NULL }, /* m_hwndUI { NULL }, /* m_hWnd { "MAME32" }, /* m_pName { FALSE }, /* m_bIsInitialized { FALSE }, /* m_bIsActive { FALSE }, /* m_bPaused { FALSE }, /* m_bMMXDetected { FALSE }, /* m_bUseAIMouse { NULL }, /* m_pDisplay { NULL }, /* m_pSound { NULL }, /* m_pKeyboard { NULL }, /* m_pJoystick { NULL }, /* m_pTrak { NULL }, /* m_pFMSynth { MAME32_CreateWindow }, /* CreateMAMEWindow { MAME32_ProcessMessages }, /* ProcessMessages { MAME32_PumpAndReturnMessage }, /* PumpAndReturnMessage { MAME32_Quit }, /* Quit { NULL } /* detect MMX }; */ /*************************************************************************** Internal structures ***************************************************************************/ /*************************************************************************** Internal variables ***************************************************************************/ static BOOL auto_pause; /*************************************************************************** External functions ***************************************************************************/ /* void MAME32App_init(options_type *options) { MAME32App.m_hWnd = NULL; MAME32App.m_bIsInitialized = FALSE; MAME32App.m_bIsActive = FALSE; MAME32App.m_bIsPaused = FALSE; MAME32App.m_pDisplay = NULL; MAME32App.m_pSound = NULL; MAME32App.m_pKeyboard = NULL; MAME32App.m_pJoystick = NULL; MAME32App.m_pTrak = NULL; MAME32App.m_pFMSynth = NULL; auto_pause = options->auto_pause; /* Machine->scrbitmap is not initialized in the mame source until after the call to osd_create_display(). This causes a problem if osd_create_display() detects an error, then shows the error message box, which causes focus to change, which causes OnPause() to be called, which uses Machine->scrbitmap. Whew. So it needs to be set to NULL so it doesn't crash in OnPause(). / Machine->scrbitmap = NULL; } */ /*************************************************************************** Internal OPENGL functions ***************************************************************************/ // Color Palette handle HPALETTE hPalette = NULL; // Set Pixel Format function - forward declaration void SetDCPixelFormat(HDC hDC); HPALETTE GetOpenGLPalette(HDC hDC); HGLRC tempRC; static HGLRC get_GC( HDC hDC ) { if( hDC == 0 ) return 0; /* printf( "get_GC: Error, HDC is zero\n"); */ // Select the pixel format SetDCPixelFormat(hDC); // Create palette if needed hPalette = GetOpenGLPalette(hDC); tempRC = wglCreateContext( hDC ); /* check if the context could be created */ if( tempRC == NULL ) { /* fprintf(stderr, "getGC context could NOT be created \n"); */ return( 0 ); } /* associated the context with the X window */ if( wglMakeCurrent( hDC, tempRC ) == FALSE) { wglDeleteContext( tempRC ); return( 0 ); } return tempRC; } // Select the pixel format for a given device context void SetDCPixelFormat(HDC hDC) { int nPixelFormat=0; static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure 1, // Version of this structure PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap) PFD_SUPPORT_OPENGL | // Support OpenGL calls in window PFD_DOUBLEBUFFER, // Double buffered PFD_TYPE_RGBA, // RGBA Color mode 24, // Want 24bit color 0,0,0,0,0,0, // Not used to select mode 0,0, // Not used to select mode 0,0,0,0,0, // Not used to select mode 32, // Size of depth buffer 0, // Not used to select mode 0, // Not used to select mode PFD_MAIN_PLANE, // Draw in main plane 0, // Not used to select mode 0,0,0 }; // Not used to select mode // Choose a pixel format that best matches that described in pfd nPixelFormat = ChoosePixelFormat(hDC, &pfd); // Set the pixel format for the device context if(SetPixelFormat(hDC, nPixelFormat, &pfd)==FALSE) MessageBox(thisHwnd, "could not set PixelFormat", "ERROR", MB_OK|MB_ICONERROR); } // If necessary, creates a 3-3-2 palette for the device context listed. HPALETTE GetOpenGLPalette(HDC hDC) { HPALETTE hRetPal = NULL; // Handle to palette to be created PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor LOGPALETTE *pPal; // Pointer to memory for logical palette int nPixelFormat; // Pixel format index int nColors; // Number of entries in palette int i; // Counting variable BYTE RedRange,GreenRange,BlueRange; // Range for each color entry (7,7,and 3) // Get the pixel format index and retrieve the pixel format description nPixelFormat = GetPixelFormat(hDC); DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); // Does this pixel format require a palette? If not, do not create a // palette and just return NULL if(!(pfd.dwFlags & PFD_NEED_PALETTE)) return NULL; // Number of entries in palette. 8 bits yeilds 256 entries nColors = 1 << pfd.cColorBits; // Allocate space for a logical palette structure plus all the palette entries pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + nColors*sizeof(PALETTEENTRY)); // Fill in palette header pPal->palVersion = 0x300; // Windows 3.0 pPal->palNumEntries = nColors; // table size // Build mask of all 1's. This creates a number represented by having // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and // pfd.cBlueBits. RedRange = (1 << pfd.cRedBits) -1; GreenRange = (1 << pfd.cGreenBits) - 1; BlueRange = (1 << pfd.cBlueBits) -1; // Loop through all the palette entries for(i = 0; i < nColors; i++) { // Fill in the 8-bit equivalents for each component pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange; pPal->palPalEntry[i].peRed = (unsigned char)( (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange); pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange; pPal->palPalEntry[i].peGreen = (unsigned char)( (double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange); pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange; pPal->palPalEntry[i].peBlue = (unsigned char)( (double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange); pPal->palPalEntry[i].peFlags = (unsigned char) NULL; } // Create the palette hRetPal = CreatePalette(pPal); // Go ahead and select and realize the palette for this device context SelectPalette(hDC,hRetPal,FALSE); RealizePalette(hDC); // Free the memory used for the logical palette structure free(pPal); // Return the handle to the new palette return hRetPal; } /*************************************************************************** Internal functions ***************************************************************************/ /* Create display */ static BOOL Win32UI_init(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow) { static BOOL bRegistered = FALSE; if (bRegistered == FALSE) { WNDCLASS WndClass; WndClass.style = CS_SAVEBITS | CS_BYTEALIGNCLIENT | CS_OWNDC; WndClass.lpfnWndProc = MAME32_MessageProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hInstance; WndClass.hIcon = LoadIcon(hInstance, MAKEINTATOM(IDI_MAME32_ICON)); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = (LPCSTR)"classMAME32"; if (RegisterClass(&WndClass) == 0) return FALSE; bRegistered = TRUE; } thisHwnd = CreateWindowEx(0, "classMAME32", "WGLMAME" , WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME | WS_BORDER, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL); ShowWindow(thisHwnd, nCmdShow); /* thisCwnd.attach(thisHwnd); */ thisWin = GetDC(thisHwnd); wglMakeCurrent(NULL, NULL); /* get the graphics context for this widget */ if( (cx = get_GC( thisWin )) == 0 ) { MessageBox(thisHwnd, "could not create GLContext", "ERROR", MB_OK|MB_ICONERROR); } else { MessageBox(thisHwnd, "could create GLContext", "OK", MB_OK); } SetFocus(thisHwnd); return thisHwnd!=NULL; } static LRESULT CALLBACK MAME32_MessageProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { LRESULT Result = 0; HDC hdc = 0; switch(Msg) { case WM_DESTROY: PostQuitMessage(0); return 0L; case WM_QUIT: OnClose(thisHwnd); return 0; case WM_PAINT: hdc = (HDC) wParam; return DefWindowProc(hWnd, Msg, wParam, lParam); } return DefWindowProc(hWnd, Msg, wParam, lParam); } static void OnClose(HWND hWnd) { /* Don't call DestroyWindow, it will be called by osd_exit. */ wglMakeCurrent(NULL, NULL); DestroyWindow(thisHwnd); } static BOOL idle_work; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; if (!Win32UI_init(hInstance, lpCmdLine, nCmdShow)) { MessageBox(thisHwnd, "could not create window ...", "ERROR", MB_OK|MB_ICONERROR); OnClose(thisHwnd); return 1; } /* Set the samplerate to 0 if sound is disabled, this should notify mame not to "render" it (speed improvement) */ Machine->sample_rate = 0; mame_options.samplerate = 0; /* Simplified MFC Run() alg. See mfc/src/thrdcore.cpp. */ /* phase2: pump messages while available */ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } void MamePlayGame() { char buf[1000]; int index = 0; if (run_game(index ,&mame_options) != 0) { const struct RomModule *romp = drivers[index]->rom; /* This needs to be changed to use a window with a scrollbar * because the list can be too large to fit on the screen. */ sprintf(buf, "Unable to initialize machine emulation.\r\n\r\n" "Most likely you have a corrupt ROM file.\r\n" "The following files must exist in the specified\r\n" "directory or .zip file for %s to run.\r\n\r\n", drivers[index]->description); sprintf(buf + strlen(buf), "Directory:\r\n"); GetCurrentDirectory(sizeof(buf) - strlen(buf), buf + strlen(buf)); sprintf(buf + strlen(buf), "\\%s\r\n\r\n", drivers[index]->name); sprintf(buf + strlen(buf), "or .zip file:\r\n"); GetCurrentDirectory(sizeof(buf) - strlen(buf), buf + strlen(buf)); sprintf(buf + strlen(buf), "\\roms\\%s.zip\r\n\r\n", drivers[index]->name); sprintf(buf + strlen(buf), "Files:\r\n"); while (romp->name || romp->offset || romp->length) { romp++; /* skip memory region definition */ while (romp->length) { char name[100]; int length; sprintf(name, romp->name, drivers[index]->name); length = 0; do { /* ROM_RELOAD */ if (romp->name == (char *)-1) length = 0; /* restart */ length += romp->length & ~0x80000000; romp++; } while (romp->length && (romp->name == 0 || romp->name == (char *)-1)); sprintf(buf + strlen(buf), "%-12s\t%u bytes\n", name, length); } } MessageBox(thisHwnd, buf, "MAME32 Error", MB_OK | MB_ICONERROR); } in_emulation = FALSE; if (quit) { PostMessage(thisHwnd, WM_CLOSE, 0, 0); return; } }