/* God.cpp Written by Matthew Fisher The God class glues the operating system, the graphics device, the application interface, and the window manager together. It is essentially the first and the last code that is executed. See God.h for a description of the class and member functions. */ //All source files include Main.h #include "Main.h" const int GraphicsDeviceType = GD_D3D; //GraphicsDeviceType tells God what type of graphics device/API to use. //possible choices are: //GD_D3D -> DirectX API //GD_OpenGL -> OpenGL API //GD_Software -> Software rendering //DirectX offers more functionality, but many people find it harder to understand and it's Windows only //OpenGL is more widely supported but doesn't have nice things like N-Patching built in //Software is written by me, by hand, and is slow and has very limited functionality //you'll need #define USE_DIRECTX or #define USE_OPENGL (in Main.h) to use DirectX or OpenGL const int ScreenWidth = 1280; const int ScreenHeight = 800; //only one full screen mode is supported; this is the full screen width/height const int WindowWidth = 720 + WindowBorderWidth; const int WindowHeight = 640 + WindowBorderHeight; //the default windowed-mode window width and height. The window can be manually resized. const bool FullScreenStart = false; //true to start in full screen mode. If you're debugging, windowed mode is usually better const bool VSync = true; //true to wait for the monitor to finish the entire display (vertical retracing) before //the front buffer is flipped. Setting this to false results in higher frame rate, but may //induce flickering. const bool CapturingScreen = false; //true if capturing of the screen to an AVI file is requested. press "C" to start capturing. const int CaptureWidth = 800; //width and height of the captured video file images const int CaptureHeight = 600; const char AVIFileName[] = "C:\\test.avi"; //file name to save the captured images to const float AvgFrameRate = 20.0f; //target frame rate to advance the scene at when capturing files const int MilliSecondsPerFrame = int(1000.0f / AvgFrameRate); //milliseconds elapsed per frame in the target frame rate provided above const int SleepBetweenFrames = 0; //time to sleep between frame, in milliseconds. void God::Init(HINSTANCE hInstance, int nCmdShow) { #ifdef USE_VIDEO_TEXTURES CoInitialize(NULL); //initalize COM objects. So far I use only one COM object, DirectX video textures. //so this line is skipped if they are not used. #endif for(UINT i=0;i<256;i++) { key[i] = 0; //by default all keys are not pressed } //create a new GraphicsDevice object based upon the type of graphics device requested in GraphicsDeviceType if(GraphicsDeviceType == GD_Software) GD = new SoftwareGraphicsDevice; #ifdef USE_DIRECTX else if(GraphicsDeviceType == GD_D3D) GD = new D3DGraphicsDevice; #endif #ifdef USE_OPENGL else if(GraphicsDeviceType == GD_OpenGL) GD = new OpenGLGraphicsDevice; #endif else FatalMB("Invalid choice of graphics device type."); CaptureStarted = false; //don't capture from the very beginning, wait for the user to give the signal FullScreen = FullScreenStart; //start in the requested full screen mode IgnoreReSize = true; //when we create a new window we want to ignore Win32's resize command if(FullScreen) WM.InitAll(hInstance, nCmdShow, FullScreen, ScreenWidth, ScreenHeight); //create a new full screen sized window else WM.InitAll(hInstance, nCmdShow, FullScreen, WindowWidth, WindowHeight); //create a new windowed window if(CapturingScreen) Capture.OpenFile(AVIFileName,MilliSecondsPerFrame,CaptureWidth,CaptureHeight); //open the AVI if requested GD->SetVSync(VSync); //set the GD vertical synchronization property GD->Init3D(WM); //initalize the graphics device's 3D properties if(FullScreen) ShowCursor(FALSE); //hide the cursor if we're in full screen GD->SetScreenColor(RGBColor(0,0,0)); //default clear color is black GD->SetWireframe(); //wireframe is on by default T.Start(60.0f); //start at a guessed frame rate of 60 fps; this will be fixed in a few seconds to the "real" value T.Pause(); //ignore the first few frames from causing an abnormally low FPS App.Init(*GD, WM); //initalize this application's graphics objects } void God::RenderFrame() { GD->StartRender(WM); //have the Graphics device prepare a new frame if(GD->GetSystemActive()) //if we are good to render (we wouldn't be if say we were in the middle of a window change) { T.Frame(); //update the FPS counter App.Render(*GD, WM); //have the application render its objects through the graphics device GD->DrawDouble("fps - > ", T.GetFramesPerSec(), 0, 0); //draw the FPS if(SleepBetweenFrames) Sleep(SleepBetweenFrames); } else { T.Pause(); //if we aren't good to render, don't update the FPS counter } GD->FinishRender(WM, App); //put the rendered scene onto the screen } void God::CaptureFrame() { if(key[KEY_C]) CaptureStarted = true; //if the user requests it, begin capturing frames to the AVI file if(CaptureStarted) { Capture.ScreenFrame(); //get the current frame and put it into the file T.SetFPS(AvgFrameRate); //control the frame rate directly; otherwise we'd factor in the time it took to compress //the scene, which would be bad. } } void God::FullScreenMouseChange() { if(FullScreen) { ShowCursor(FALSE); SetCursor(NULL); //hide the cursor if full screen } else { ShowCursor(TRUE); SetCursor(LoadCursor(NULL, IDC_ARROW)); //show the cursor if windowed } } void God::ResetGraphicsObjects() { T.Pause(); App.ReInit(*GD, WM); //reinialize all the scene objects } void God::HandleAltEnter() { T.Pause(); key[KEY_ALT_ENTER] = 0; FullScreen = !FullScreen; IgnoreReSize = true; if(FullScreen) WM.ResetWindow(FullScreen, SW_SHOW, ScreenWidth, ScreenHeight); else WM.ResetWindow(FullScreen, SW_SHOW, WindowWidth, WindowHeight); //toggle full screen mode GD->ReSizeFullScreen(WM, App); //tell the graphics device what we did ShowWindow(WM.GetHWND(),SW_SHOW); SetForegroundWindow(WM.GetHWND()); SetFocus(WM.GetHWND()); //make sure our window is visible and has focus FullScreenMouseChange(); //update the mouse } void God::HandleReSize() { T.Pause(); //avoid jerkiness in the frame timer ReSizeDevice = false; if(IgnoreReSize) IgnoreReSize = false; //if this is a new resize event to us, else GD->ReSize(WM, App); //tell the graphics device to resize } void God::MessageLoop(HINSTANCE hInstance, int nCmdShow) { //the main Windows message loop MSG msg; BOOL bGotMsg; PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE ); //get a new message while( WM_QUIT != msg.message ) //while we don't have the quit message { bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); //get a new message if( bGotMsg ) //if we have a message { TranslateMessage( &msg ); //send it out DispatchMessage( &msg ); } else { //if we have no messages we decide it's a good time to render RenderFrame(); //render a new frame if(CapturingScreen) CaptureFrame(); //if we're capturing the screen, do so if(key[KEY_ALT_ENTER]) HandleAltEnter(); //toggle full screen display if the user Alt+Enters if(ReSizeDevice && !FullScreen) HandleReSize(); //if we're in a window and the user resizes it if(GD->NeedToRestoreDevices()) //if we've lost devices, { T.Pause(); //pause the timer for a short bit, ResetGraphicsObjects(); //reset the graphics objects, GD->DevicesRestored(); //tell the GD everything's okay } } } } void God::FreeMemory() { App.End(); //free application data WM.FreeMemory(); //free the window GD->FreeMemory(); //free the graphics API data delete GD; //delete the graphics device if(CapturingScreen) Capture.CloseFile(); //if we were capturing the screen, finalize the file #ifdef USE_VIDEO_TEXTURES CoUninitialize(); //frees COM objects, if we're using them #endif }