/* main_win32.c - Don Yang (uguu.org) 05/12/03 */ #include"core.h" #define WINDOW_CLASSNAME WINDOW_TITLE static HWND WindowHandle = INVALID_HANDLE_VALUE; static HDC GDIContext = NULL; static HGLRC GLContext = NULL; static int MouseX = 0, MouseY = 0; static int InitRenderWindow(void); static int InitWindowManager(HINSTANCE inst, int state); static void MouseButton(int x, int y, int flags); static void MouseMove(int x, int y, int flags); static void ProcessPaintEvent(void); static LRESULT CALLBACK ProcessWin32Event(HWND handle, UINT msg, WPARAM wparam, LPARAM lparam); /***************************************************************** WinMain */ int WINAPI WinMain(HINSTANCE cinst, HINSTANCE pinst, LPSTR argv, int state) { MSG msg; if( InitWindowManager(cinst, state) != 0 ) return 1; #ifdef WINAMP_HACK /* Hack to start playing background music using Winamp. Assuming you have "shiawase hiyori" loaded (KSCA-29153, track2), the animation and song should be synchronized... Actually, only works for serika and nobody else :( */ if( FindWindow("Winamp v1.x", NULL) != NULL ) { SendMessage(FindWindow("Winamp v1.x", NULL), WM_COMMAND, 40045, 0); Sleep(700); } #endif do { if( PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE) ) { /* Process windows events */ TranslateMessage(&msg); DispatchMessage(&msg); } else { /* Redraw when nothing to process. Here we call the event handler directly, instead of doing a round trip with PostMessage(WM_PAINT) */ ProcessWin32Event(WindowHandle, WM_PAINT, 0, 0); } } while( msg.message != WM_QUIT ); return msg.wParam; } /* WinMain() */ /******************************************************** InitRenderWindow */ static int InitRenderWindow(void) { PIXELFORMATDESCRIPTOR pixel; int pixelformat; if( (GDIContext = GetDC(WindowHandle)) == NULL ) return 1; memset(&pixel, 0, sizeof(PIXELFORMATDESCRIPTOR)); pixel.nSize = sizeof(PIXELFORMATDESCRIPTOR); pixel.nVersion = 1; pixel.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pixel.dwLayerMask = PFD_MAIN_PLANE; pixel.iPixelType = PFD_TYPE_RGBA; pixel.cColorBits = 16; pixel.cDepthBits = 16; pixel.cAccumBits = 0; pixel.cStencilBits = 0; if( (pixelformat = ChoosePixelFormat(GDIContext, &pixel)) == 0 ) return 1; if( (SetPixelFormat(GDIContext, pixelformat, &pixel)) == FALSE ) return 1; if( (GLContext = wglCreateContext(GDIContext)) == NULL ) return 1; wglMakeCurrent(GDIContext, GLContext); Init(); /* (core.c) */ return 0; } /* InitRenderWindow() */ /******************************************************* InitWindowManager */ static int InitWindowManager(HINSTANCE inst, int state) { WNDCLASSA wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = ProcessWin32Event; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; wndclass.hIcon = NULL; /*XXX need custom icon */ wndclass.hCursor = LoadCursor(inst, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WINDOW_CLASSNAME; if( !RegisterClass(&wndclass) ) return 1; WindowHandle = CreateWindowA(WINDOW_CLASSNAME, WINDOW_TITLE, WS_SIZEBOX, WINDOW_INIT_X, WINDOW_INIT_Y, WINDOW_INIT_WIDTH, WINDOW_INIT_HEIGHT, NULL, NULL, inst, NULL); if( WindowHandle == NULL ) return 1; ShowWindow(WindowHandle, state); SetCursor(LoadCursor(NULL, IDC_ARROW)); return 0; } /* InitWindowManager() */ /************************************************************* MouseButton */ static void MouseButton(int x, int y, int flags) { POINT pt; pt.x = (LONG)x; pt.y = (LONG)y; ClientToScreen(WindowHandle, &pt); MouseX = (int)pt.x; MouseY = (int)pt.y; if( (flags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) != 0 ) { /* If any mouse buttons are pressed, change cursor to indicate that window can be moved. */ SetCursor(LoadCursor(NULL, IDC_SIZEALL)); } else { /* Use pointy arrow cursor otherwise */ SetCursor(LoadCursor(NULL, IDC_ARROW)); } } /* MouseButton() */ /*************************************************************** MouseMove */ static void MouseMove(int x, int y, int flags) { RECT rect; POINT pt; int dx, dy; /* Use screen coordinates, since relative coordiates are useless for moving the window itself. */ pt.x = (LONG)x; pt.y = (LONG)y; ClientToScreen(WindowHandle, &pt); dx = (int)pt.x - MouseX; dy = (int)pt.y - MouseY; MouseX = (int)pt.x; MouseY = (int)pt.y; /* Move window if any mouse buttons are pressed */ if( (flags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) != 0 ) { GetWindowRect(WindowHandle, &rect); MoveWindow(WindowHandle, rect.left + dx, rect.top + dy, rect.right - rect.left, rect.bottom - rect.top, TRUE); } } /* MouseMove() */ /******************************************************* ProcessPaintEvent */ static void ProcessPaintEvent(void) { PAINTSTRUCT paint; RECT rect; BeginPaint(WindowHandle, &paint); EndPaint(WindowHandle, &paint); /* OpenGL stuff is outside of the Begin/End block. This is apparently the right order to do it. */ GetWindowRect(WindowHandle, &rect); Render(rect.right - rect.left, rect.bottom - rect.top); /* (core.c) */ SwapBuffers(GDIContext); glFlush(); } /* ProcessPaintEvent() */ /******************************************************* ProcessWin32Event */ static LRESULT CALLBACK ProcessWin32Event(HWND handle, UINT msg, WPARAM wparam, LPARAM lparam) { switch( msg ) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: MouseButton((int)LOWORD(lparam), (int)HIWORD(lparam), (int)wparam); return 0; case WM_MOUSEMOVE: MouseMove((int)LOWORD(lparam), (int)HIWORD(lparam), (int)wparam); return 0; case WM_KEYUP: if( wparam == VK_ESCAPE || wparam == 'Q' || wparam == 'X' ) DestroyWindow(WindowHandle); break; case WM_PAINT: if( GLContext == NULL ) { if( InitRenderWindow() != 0 ) { MessageBoxA(NULL, "Can not initialize rendering context", WINDOW_TITLE, MB_OK | MB_ICONSTOP); DestroyWindow(WindowHandle); } } ProcessPaintEvent(); return 0; case WM_CLOSE: DestroyWindow(WindowHandle); return 0; case WM_DESTROY: glFlush(); Cleanup(); /* (core.c) */ if( GLContext != NULL ) wglDeleteContext(GLContext); if( GDIContext != NULL ) ReleaseDC(WindowHandle, GDIContext); PostQuitMessage(0); return 0; default: break; } return DefWindowProc(handle, msg, wparam, lparam); } /* ProcessWin32Event() */