#ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 // voor vista #endif /* ******************************************************************************** Copyright 2006, 2007 Ben Ruyl This file is part of Sokoban 3D. Sokoban 3D 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. Sokoban 3D 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 Sokoban 3D; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************** */ // This is a modified OpenGL basecode. // Thank you to: // Jeff Molofee // Maxwell Sayles // Peter Puck // and http://nehe.gamedev.net #include // Header File For The Windows Library #include // Header File For The OpenGL32 Library #include // Header File For The GLu32 Library #include "sokomain.h" #include "gamemain.h" #include "menumain.h" #include "main.h" #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "glu32.lib") #pragma comment (lib, "fmodex_vc.lib") // VC only!! #define WM_TOGGLEFULLSCREEN (WM_USER+1) // Application Define Message For Toggling static BOOL g_isProgramLooping; // Window Creation Loop, For FullScreen/Windowed Toggle // Between Fullscreen / Windowed Mode static BOOL g_createFullScreen; #include "ARB_MULTISAMPLE.h" int screencenterx, screencentery; // If TRUE, Then Create Fullscreen void TerminateApplication (GL_Window* window) // Terminate The Application { PostMessage (window->hWnd, WM_QUIT, 0, 0); // Send A WM_QUIT Message g_isProgramLooping = FALSE; // Stop Looping Of The Program } void ToggleFullscreen (GL_Window* window) // Toggle Fullscreen/Windowed { PostMessage (window->hWnd, WM_TOGGLEFULLSCREEN, 0, 0); // Send A WM_TOGGLEFULLSCREEN Message } void ReshapeGL (int width, int height) // Reshape The Window When It's Moved Or Resized { if (height == 0) height = 1; screencenterx = width / 2; screencentery = height / 2; glViewport (0, 0, (GLsizei)(width), (GLsizei)(height)); // Reset The Current Viewport glMatrixMode (GL_PROJECTION); // Select The Projection Matrix glLoadIdentity (); // Reset The Projection Matrix gluPerspective (45.0f, (GLfloat)(width)/(GLfloat)(height), // Calculate The Aspect Ratio Of The Window 1.0f, 1500.0f); glMatrixMode (GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity (); // Reset The Modelview Matrix } BOOL ChangeScreenResolution (int width, int height, int bitsPerPixel) // Change The Screen Resolution { DEVMODE dmScreenSettings; // Device Mode ZeroMemory (&dmScreenSettings, sizeof (DEVMODE)); // Make Sure Memory Is Cleared dmScreenSettings.dmSize = sizeof (DEVMODE); // Size Of The Devmode Structure dmScreenSettings.dmPelsWidth = width; // Select Screen Width dmScreenSettings.dmPelsHeight = height; // Select Screen Height dmScreenSettings.dmBitsPerPel = bitsPerPixel; // Select Bits Per Pixel dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; if (ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { return FALSE; // Display Change Failed, Return False } return TRUE; // Display Change Was Successful, Return True } BOOL DestroyWindowGL (GL_Window* window) // Destroy The OpenGL Window & Release Resources { ShowWindow(window->hWnd, SW_HIDE); if (window->hWnd != 0) // Does The Window Have A Handle? { if (window->hDC != 0) // Does The Window Have A Device Context? { wglMakeCurrent (window->hDC, 0); // Set The Current Active Rendering Context To Zero if (window->hRC != 0) // Does The Window Have A Rendering Context? { wglDeleteContext (window->hRC); // Release The Rendering Context window->hRC = 0; // Zero The Rendering Context } ReleaseDC (window->hWnd, window->hDC); // Release The Device Context window->hDC = 0; // Zero The Device Context } DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle } if (window->init.isFullScreen) // Is Window In Fullscreen Mode { ChangeDisplaySettings (NULL,0); // Switch Back To Desktop Resolution // ShowCursor (TRUE); // Show The Cursor } return TRUE; // Return True } BOOL CreateWindowGL (GL_Window* window) // This Code Creates Our OpenGL Window { DWORD windowStyle = WS_TILED | WS_MINIMIZEBOX | WS_SYSMENU; // Define Our Window Style DWORD windowExtendedStyle = WS_EX_APPWINDOW; // Define The Window's Extended Style PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be { sizeof (PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format window->init.bitsPerPixel, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 16, // 16Bit Z-Buffer (Depth Buffer) 1, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; RECT windowRect = {0, 0, window->init.width, window->init.height}; // Define Our Window Coordinates GLuint PixelFormat; // Will Hold The Selected Pixel Format if (window->init.isFullScreen == TRUE) // Fullscreen Requested, Try Changing Video Modes { windowStyle = WS_POPUP; // Set The WindowStyle To WS_POPUP (Popup Window) windowExtendedStyle |= WS_EX_TOPMOST; // (Top Window Covering Everything Else) } else // If Fullscreen Was Not Selected { // Adjust Window, Account For Window Borders AdjustWindowRectEx (&windowRect, windowStyle, 0, windowExtendedStyle); } // Create The OpenGL Window window->hWnd = CreateWindowEx (windowExtendedStyle, // Extended Style window->init.application->className, // Class Name window->init.title, // Window Title windowStyle, // Window Style 0, 0, // Window X,Y Position windowRect.right, // Window Width windowRect.bottom, // Window Height HWND_DESKTOP, // Desktop Is Window's Parent 0, // No Menu window->init.application->hInstance, // Pass The Window Instance window); if (window->hWnd == 0) // Was Window Creation A Success? { return FALSE; // If Not Return False } window->hDC = GetDC (window->hWnd); // Grab A Device Context For This Window if (window->hDC == 0) // Did We Get A Device Context? { // Failed DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } if(!arbMultisampleSupported) { PixelFormat = ChoosePixelFormat (window->hDC, &pfd); // Find A Compatible Pixel Format if (PixelFormat == 0) // Did We Find A Compatible Format? { // Failed ReleaseDC (window->hWnd, window->hDC); // Release Our Device Context window->hDC = 0; // Zero The Device Context DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } } else PixelFormat = arbMultisampleFormat; if (SetPixelFormat (window->hDC, PixelFormat, &pfd) == FALSE) // Try To Set The Pixel Format { // Failed ReleaseDC (window->hWnd, window->hDC); // Release Our Device Context window->hDC = 0; // Zero The Device Context DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } window->hRC = wglCreateContext (window->hDC); // Try To Get A Rendering Context if (window->hRC == 0) // Did We Get A Rendering Context? { // Failed ReleaseDC (window->hWnd, window->hDC); // Release Our Device Context window->hDC = 0; // Zero The Device Context DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } // Make The Rendering Context Our Current Rendering Context if (wglMakeCurrent (window->hDC, window->hRC) == FALSE) { // Failed wglDeleteContext (window->hRC); // Delete The Rendering Context window->hRC = 0; // Zero The Rendering Context ReleaseDC (window->hWnd, window->hDC); // Release Our Device Context window->hDC = 0; // Zero The Device Context DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } if(!arbMultisampleSupported && FGameOptions.FSamples > 0) { if(InitMultisample(window->init.application->hInstance,window->hWnd,pfd)) { DestroyWindowGL (window); return CreateWindowGL(window); } } // ShowWindow(window->hWnd, SW_SHOWNORMAL); // window->isVisible = TRUE; /* else // Otherwise (If Fullscreen Mode Was Successful) { //ShowCursor (FALSE); // Turn Off The Cursor windowStyle = WS_POPUP; // Set The WindowStyle To WS_POPUP (Popup Window) windowExtendedStyle |= WS_EX_TOPMOST; // Set The Extended Window Style To WS_EX_TOPMOST }*/ // ShowWindow (window->hWnd, SW_NORMAL); // Make The Window Visible // window->isVisible = TRUE; // Set isVisible To True ReshapeGL (window->init.width, window->init.height); // Reshape Our GL Window ZeroMemory (window->keys, sizeof (Keys)); // Clear All Keys // window->lastTickCount = GetTickCount (); // Get Tick Count return TRUE; // Window Creating Was A Success // Initialization Will Be Done In WM_CREATE } // Process Window Message Callbacks LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Get The Window Context GL_Window* window = (GL_Window*)(GetWindowLong (hWnd, GWL_USERDATA)); switch (uMsg) // Evaluate Window Message { case WM_SYSCOMMAND: // Intercept System Commands { switch (wParam) // Check System Calls { case SC_SCREENSAVE: // Screensaver Trying To Start? case SC_MONITORPOWER: // Monitor Trying To Enter Powersave? return 0; // Prevent From Happening } break; // Exit } return 0; // Return case WM_TIMER: // frequency 1 Hz { fps = framescount; framescount = 0; if (GameState == GS_GAME) FGameClock++; } return 0; case WM_CREATE: // Window Creation { CREATESTRUCT* creation = (CREATESTRUCT*)(lParam); // Store Window Structure Pointer window = (GL_Window*)(creation->lpCreateParams); SetWindowLong (hWnd, GWL_USERDATA, (LONG)(window)); SetTimer(hWnd, 1, 1000, NULL); } return 0; // Return case WM_CLOSE: // Closing The Window TerminateApplication(window); // Terminate The Application return 0; // Return case WM_ACTIVATE: if (wParam == WA_INACTIVE) window->isVisible = FALSE; else window->isVisible = TRUE; return 0; case WM_SIZE: // Size Action Has Taken Place switch (wParam) // Evaluate Size Action { case SIZE_MINIMIZED: // Was Window Minimized? window->isVisible = FALSE; // Set isVisible To False return 0; // Return case SIZE_MAXIMIZED: // Was Window Maximized? window->isVisible = TRUE; // Set isVisible To True ReshapeGL (LOWORD (lParam), HIWORD (lParam)); // Reshape Window - LoWord=Width, HiWord=Height return 0; // Return case SIZE_RESTORED: // Was Window Restored? window->isVisible = TRUE; // Set isVisible To True ReshapeGL (LOWORD (lParam), HIWORD (lParam)); // Reshape Window - LoWord=Width, HiWord=Height return 0; // Return } break; // Break case WM_KEYDOWN: // Update Keyboard Buffers For Keys Pressed if ((wParam >= 0) && (wParam <= 255)) // Is Key (wParam) In A Valid Range? { window->keys->keyDown[wParam] = TRUE; // Set The Selected Key (wParam) To True return 0; // Return } break; case WM_LBUTTONUP: mouseclicked = true; mode = SELECT; //if (GameState == GS_MENU) // mode = SELECT; cursorX = LOWORD(lParam); cursorY = HIWORD(lParam); break; case WM_MOUSEWHEEL: if (!FIsPlayingNewLevelAnimation && GameState == GS_GAME) { float shift = GET_WHEEL_DELTA_WPARAM(wParam) / 20.0f; zpos += shift; if (zpos > -1) zpos = -1; if (zpos < -200) zpos = -200; } if (GameState == GS_MENU && MenuGameState == GSM_LEVELLIST) ScrollShift = GET_WHEEL_DELTA_WPARAM(wParam) / 60; break; case WM_MOUSEMOVE: cursorX = LOWORD(lParam); cursorY = HIWORD(lParam); if (GameState == GS_GAME) { cursorPosX = MAKEPOINTS(lParam).x; cursorPosY = MAKEPOINTS(lParam).y; float diffx; diffx = MAKEPOINTS(lParam).x - screencenterx; float diffy; diffy = MAKEPOINTS(lParam).y - screencentery; if ((window->keys->RMB_Down) && (wParam & MK_RBUTTON) && !FIsPlayingNewLevelAnimation) { heading -= diffx * 0.1f; if (heading > 360) heading -= 360; if (heading < -360) heading += 360; yrot = heading; ypos += diffy * 0.1f; if (ypos < -200) ypos = -200; if (ypos > 0) ypos = 0; } window->keys->RMB_Down = wParam & MK_RBUTTON; if (!(window->keys->RMB_Down) && MouseInMenu) mode = SELECT; } if (GameState == GS_MENU) mode = SELECT; break; // Break case WM_KEYUP: // Update Keyboard Buffers For Keys Released if ((wParam >= 0) && (wParam <= 255)) // Is Key (wParam) In A Valid Range? { window->keys->keyDown [wParam] = FALSE; // Set The Selected Key (wParam) To False return 0; // Return } break; // Break case WM_TOGGLEFULLSCREEN: // Toggle FullScreen Mode On/Off g_createFullScreen = (g_createFullScreen == TRUE) ? FALSE : TRUE; PostMessage (hWnd, WM_QUIT, 0, 0); break; // Break } return DefWindowProc (hWnd, uMsg, wParam, lParam); // Pass Unhandled Messages To DefWindowProc } BOOL RegisterWindowClass (Application* application) // Register A Window Class For This Application. { // TRUE If Successful // Register A Window Class WNDCLASSEX windowClass; // Window Class ZeroMemory (&windowClass, sizeof (WNDCLASSEX)); // Make Sure Memory Is Cleared windowClass.cbSize = sizeof (WNDCLASSEX); // Size Of The windowClass Structure windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraws The Window For Any Movement / Resizing windowClass.lpfnWndProc = (WNDPROC)(WindowProc); // WindowProc Handles Messages windowClass.hInstance = application->hInstance; // Set The Instance windowClass.hbrBackground = (HBRUSH)1; // Class Background Brush Color windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer windowClass.lpszClassName = application->className; // Sets The Applications Classname if (RegisterClassEx (&windowClass) == 0) // Did Registering The Class Fail? { // NOTE: Failure, Should Never Happen MessageBox (HWND_DESKTOP, "Could not create a window class!", "Error", MB_OK | MB_ICONEXCLAMATION); return FALSE; // Return False (Failure) } return TRUE; // Return True (Success) } // Program Entry (WinMain) int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { Application application; // Application Structure GL_Window window; // Window Structure Keys keys; // Key Structure BOOL isMessagePumpActive; // Message Pump Active? MSG msg; // Window Message Structure DWORD tickCount; // Used For The Tick Counter // Fill Out Application Data application.className = "OpenGL"; // Application Class Name application.hInstance = hInstance; // Application Instance if (strcmp(lpCmdLine, "devmode") == 0) { AllocConsole(); freopen("CONOUT$", "wt", stdout); SetConsoleTitle("Sokoban 3D Debug Console"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); printf("Sokoban 3D started in developer's mode\n"); DEV_MODE = true; } else DEV_MODE = false; LoadSettings(); // load the game settings, we do it here, because we have to know // the samples for the anti-alias in the window creation procedure SaveSettings(); // and save them, if the values were already there nothing happens, // else the default is set now ZeroMemory (&window, sizeof (GL_Window)); // Make Sure Memory Is Zeroed window.init.width = 800; window.init.height = 600; switch(FGameOptions.FScreenResolution) { case 0: window.init.width = 640; window.init.height = 480; break; case 1: window.init.width = 800; window.init.height = 600; break; case 2: window.init.width = 1024; window.init.height = 768; break; case 3: window.init.width = 1280; window.init.height = 1024; break; } window.keys = &keys; // Window Key Structure window.init.application = &application; // Window Application window.init.title = "Sokoban 3D"; window.init.bitsPerPixel = 32; window.init.isFullScreen = FGameOptions.FFullScreen; ZeroMemory (&keys, sizeof (Keys)); // Zero keys Structure /* if (MessageBox (HWND_DESKTOP, "Would you like to run Sokoban 3D in full-screen mode?", "Full-screen", MB_YESNO | MB_ICONQUESTION) == IDNO) { window.init.isFullScreen = FALSE; // If Not, Run In Windowed Mode window.init.width = 800; window.init.height = 600; }*/ // Register A Class For Our Window To Use if (RegisterWindowClass (&application) == FALSE) // Did Registering A Class Fail? { // Failure MessageBox (HWND_DESKTOP, "Error registering window class!", "Error", MB_OK | MB_ICONEXCLAMATION); return -1; // Terminate Application } window.isVisible = FALSE; g_isProgramLooping = TRUE; // Program Looping Is Set To TRUE g_createFullScreen = window.init.isFullScreen; // g_createFullScreen Is Set To User Default while (g_isProgramLooping) // Loop Until WM_QUIT Is Received { // Create A Window window.init.isFullScreen = g_createFullScreen; // Set Init Param Of Window Creation To Fullscreen? if (CreateWindowGL (&window) == TRUE) // Was Window Creation Successful? { // ShowWindow(window.hWnd, SW_HIDE); // At This Point We Should Have A Window That Is Setup To Render OpenGL if (Initialize (&window, &keys) == FALSE) // Call User Intialization { // Failure TerminateApplication (&window); // Close Window, This Will Handle The Shutdown } else // Otherwise (Start The Message Pump) { // Initialize was a success ShowCursor(FALSE); // hide the cursor ShowWindow(window.hWnd, SW_SHOWNORMAL); window.isVisible = TRUE; if (window.init.isFullScreen) if (ChangeScreenResolution (window.init.width, window.init.height, window.init.bitsPerPixel) == FALSE) { // Fullscreen Mode Failed. Run In Windowed Mode Instead MessageBox (HWND_DESKTOP, "Sokoban 3D cannot run in the desired resolution. \nAuto-Switching to a lower resolution. Please restart the application.", "Error", MB_OK | MB_ICONEXCLAMATION); FGameOptions.FScreenResolution = 0; // 640 x 480 SaveSettings(); // save the lower resolution isMessagePumpActive = FALSE; // quit the application } else isMessagePumpActive = TRUE; isMessagePumpActive = TRUE; // Set isMessagePumpActive To TRUE while (isMessagePumpActive == TRUE) // While The Message Pump Is Active { // Success Creating Window. Check For Window Messages if (PeekMessage (&msg, window.hWnd, 0, 0, PM_REMOVE) != 0) { // Check For WM_QUIT Message if (msg.message != WM_QUIT) // Is The Message A WM_QUIT Message? { DispatchMessage (&msg); // If Not, Dispatch The Message } else // Otherwise (If Message Is WM_QUIT) { isMessagePumpActive = FALSE; // Terminate The Message Pump } } else // If There Are No Messages { if (window.isVisible == FALSE) // If Window Is Not Visible { WaitMessage (); // Application Is Minimized Wait For A Message } else // If Window Is Visible { Update(0); } mode = RENDER; // set back to render // Draw (); } } // Loop While isMessagePumpActive == TRUE } // If (Initialize (... // Application Is Finished Deinitialize (); // User Defined DeInitialization DestroyWindowGL (&window); // Destroy The Active Window } else // If Window Creation Failed { // Error Creating Window MessageBox (HWND_DESKTOP, "A critical error has occured while creating the window. \nSokoban 3D will close now.", "Error", MB_OK | MB_ICONEXCLAMATION); g_isProgramLooping = FALSE; // Terminate The Loop } } FreeConsole(); UnregisterClass (application.className, application.hInstance); // UnRegister Window Class return 0; } // End Of WinMain()