/*************************************************************************** * Brutal Chess * http://brutalchess.sf.net * * File : brutalchess.cpp * Authors : Mike Cook, Joe Flint, Neil Pankey **************************************************************************/ #ifdef WIN32 #include #endif #include #include #include #include #include "SDL.h" #include "SDL_opengl.h" #include "SDL_thread.h" #include "boardtheme.h" #include "chessgame.h" #include "chessplayer.h" #include "config.h" #include "fontloader.h" #include "gamecore.h" #include "pieceset.h" #include "options.h" #include "utils.h" using namespace std; const char * const BRUTAL_CHESS_VERSION = "Brutal Chess 0.5.2"; /** * Resizes the game window, handles updating all OpenGL stuff * @param width - new width of the window * @param height - new height of the window */ bool resizeWindow(int width, int height) { if (height == 0) { height = 1; } // Protect against devide by zero GLfloat aspectRatio; aspectRatio = (float)width/(float)height; glViewport(0, 0, width, height); // Set up our viewport. glMatrixMode(GL_PROJECTION); // Change to the projection matrix and set our viewing volume. glLoadIdentity(); gluPerspective(30.0f, aspectRatio, 0.1f, 151.0f); // Sets our persepective. glMatrixMode(GL_MODELVIEW); // Change to the modelview matrix and set out viewing volume. glLoadIdentity(); return true; } /** * Initializes all the appropriate OpenGL settings */ bool initGL() { glShadeModel(GL_SMOOTH); // Enable smooth shading. glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Set the background color to black. glClearDepth(1.0f); // Depth buffer setup. glEnable(GL_DEPTH_TEST); // Enables Depth Testing glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glEnable( GL_COLOR_MATERIAL ); GLfloat light_position[] = { 3.0, 3.0, 5.0, 0.0 }; const GLfloat light_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f }; const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat specularmat[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT1, GL_POSITION, light_position); glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); glMaterialfv(GL_FRONT, GL_SPECULAR, specularmat); glMaterialf(GL_FRONT, GL_SHININESS, 128); glEnable(GL_NORMALIZE); glEnable(GL_CULL_FACE); return true; } /* * Handles the drawing of the frame at the highest level. Calculates FPS at * five second intervals. * @param core - Current state of the game. */ bool drawGLScene(GameCore * core) { // These are to calculate our fps. static int T0 = 0; static int Frames = 0; // Clear The Screen And The Depth Buffer. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); core->draw(); // Draw it to the screen. SDL_GL_SwapBuffers(); // Gather our frames per second. Frames++; int t = SDL_GetTicks(); if (t - T0 >= 5000) { float sec = (float)((t-T0)/1000.0); float fps = Frames / sec; // cout << Frames << " frames in "<< sec << " seconds = "<< fps << " FPS\n"; T0 = t; Frames = 0; } return true; } /* * Needed for loading the GameCore due to limitations of SDL_Thread * @param gc - GameCore that needs to be loaded */ int callLoad(void * gc) { GameCore* core = (GameCore*)gc; core->load(); return 0; } /* * Come on, its main. */ int main(int argc, char *argv[]) { #ifdef WIN32 // Seems this was removed in SDL 1.2.10 freopen("stdout.txt", "w", stdout); freopen("stderr.txt", "w", stderr); #endif // Options singleton Options* opts = Options::getInstance(); // Parse command line options before doing any screen initialization parseCommandLine(argc, argv); // Screen Settings const int WINDOW_WIDTH = opts->getResolutionWidth(); const int WINDOW_HEIGHT = opts->getResolutionHeight(); const int WINDOW_BPP = 16; // Declares our SDL surface SDL_Surface *surface; // Flags to pass to SDL_SetVideoMode. int videoFlags; // Used to collect events. SDL_Event event; // This holds some info about our display. const SDL_VideoInfo *videoInfo; // Whether or not the window is active. bool isActive = true; // Initialize SDL. if (SDL_Init(SDL_INIT_VIDEO) < 0) { cerr << "Video initialization failed: " << SDL_GetError() << endl; Quit(1); } // Fetch the video info. videoInfo = SDL_GetVideoInfo(); if (!videoInfo) { cerr << "Video query failed: " << SDL_GetError() << endl; Quit(1); } // The flags to pass to SDL_SetVideoMode. videoFlags = SDL_OPENGL; // Enable OpenGL in SDL. videoFlags |= SDL_GL_DOUBLEBUFFER; // Enable double buffering. videoFlags |= SDL_HWPALETTE; // Store the palette in hardware. //videoFlags |= SDL_FULLSCREEN; // Store the palette in hardware. //videoFlags |= SDL_RESIZABLE; // Enable window resizing. // This checks to see if surfaces can be stored in memory. if (videoInfo->hw_available) { videoFlags |= SDL_HWSURFACE; } else { videoFlags |= SDL_SWSURFACE; } // This checks if hardware blits can be done. if (videoInfo->blit_hw) { videoFlags |= SDL_HWACCEL; } // Sets up OpenGL double buffering. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // Need some a bit for the stencil buffer SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); // Sets the string displayed as the title of the window. SDL_WM_SetCaption(BRUTAL_CHESS_VERSION, NULL); // Get a SDL surface. if(opts->fullscreen) { surface = SDL_SetVideoMode(WINDOW_WIDTH,WINDOW_HEIGHT,WINDOW_BPP,videoFlags | SDL_FULLSCREEN); } else { surface = SDL_SetVideoMode(WINDOW_WIDTH,WINDOW_HEIGHT,WINDOW_BPP,videoFlags); } // Verify there is a surface. if (!surface) { cerr << "Video mode set failed: " << SDL_GetError() << endl; Quit(1); } // Initialize all the static board functions Board::init(); ChessPlayer* player1 = toPlayer(opts->player1); ChessPlayer* player2 = toPlayer(opts->player2); BoardTheme* boardTheme = toBoard(opts->board); PieceSet* pieceSet = toPieces(opts->pieces); // Initialize OpenGL. initGL(); // Resize the initial window. resizeWindow(WINDOW_WIDTH, WINDOW_HEIGHT); // Create a chess game object here. ChessGame game(player1, player2); // We delete game core after the player quits the game, the players are // deleted in the ChessGame destructor, and the BoardTheme and PieceSets // are deleted by the GameCore's destructor. GameCore * core = GameCore::get_Instance(); core->init(game, boardTheme, pieceSet); // Call the core's load function in a new thread SDL_Thread *thread = SDL_CreateThread(callLoad, core); core->setLoadThread(thread); if(thread == NULL) { cerr << "Unable to create load thread: " << SDL_GetError() << endl; Quit( 1 ); } bool quit = false; int width = WINDOW_WIDTH, height = WINDOW_HEIGHT; string resolution = opts->getResolutionString(); bool goodfullscreen = opts->fullscreen; int goodwidth = width, goodheight = height; string goodresolution = resolution; // Main event loop while (!quit) { while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) { quit = true; } else if(event.type == SDL_VIDEORESIZE) { core->unloadGL(); SDL_Quit(); SDL_Init(SDL_INIT_VIDEO); // Sets up OpenGL double buffering. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // Need some a bit for the stencil buffer SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); // Sets the string displayed as the title of the window. SDL_WM_SetCaption(BRUTAL_CHESS_VERSION, NULL); surface = SDL_SetVideoMode(event.resize.w, event.resize.h, WINDOW_BPP,videoFlags | (opts->fullscreen ? SDL_FULLSCREEN : 0)); if(!surface) { cerr << "Could not get a surface after resize: "; cerr << SDL_GetError() << endl; cerr << "Using last known good resolution" << endl; // Reset the width and height to the last working ones width = goodwidth; height = goodheight; opts->fullscreen = goodfullscreen; resolution = goodresolution; core->setResolution(resolution); core->setFullscreen(opts->fullscreen); // Apply the new known good resolution SDL_Event e; e.type = SDL_USEREVENT; e.user.code = Menu::eAPPLYRES; SDL_PushEvent(&e); // Process the next event continue; } // This resolution works goodwidth = width; goodheight = height; goodfullscreen = opts->fullscreen; goodresolution = resolution; resizeWindow(event.resize.w, event.resize.h); initGL(); core->loadGL(); FontLoader::reload(); } else if(event.type == SDL_KEYDOWN) { // empty for now } else if(event.type == SDL_USEREVENT) { if(event.user.code == Menu::eFULLSCREENTOG) { opts->fullscreen = !opts->fullscreen; } else if(event.user.code == Menu::eAPPLYRES) { SDL_Event e; e.type = SDL_VIDEORESIZE; e.resize.w = width; e.resize.h = height; SDL_PushEvent(&e); } else if(event.user.code == Menu::e640X480) { width = 640; height = 480; resolution = "640x480"; opts->resolution = r640X480; } else if(event.user.code == Menu::e800X600) { width = 800; height = 600; resolution = "800x600"; opts->resolution = r800X600; } else if(event.user.code == Menu::e1024X768) { width = 1024; height = 768; resolution = "1024x768"; opts->resolution = r1024X768; } else if(event.user.code == Menu::e1280X1024) { width = 1280; height = 1024; resolution = "1280x1024"; opts->resolution = r1280X1024; } else if(event.user.code == Menu::e1400X1050) { width = 1400; height = 1050; resolution = "1400x1050"; opts->resolution = r1400X1050; } else if(event.user.code == Menu::e1600X1200) { width = 1600; height = 1200; resolution = "1600x1200"; opts->resolution = r1600X1200; } } core->handleEvent(event); } drawGLScene(core); SDL_Delay(1); } core->destroy(); // Clean ourselves up and exit. Quit(0); // Should never get here. cerr << "Shouldn't have reached this... End of brutalchess.cpp.\n"; return 0; } // End of file brutalchess.cpp