/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program 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, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_GRAPHICS #include "graphics_engine.h" #include "resource_manager.h" #include "event_handler.h" #include "debug.h" #include "text_engine.h" #include "ini_parser.h" #include "substring.h" using namespace std; /** \brief standard constructor \todo this constructor is not jet implemented - do it */ GraphicsEngine::GraphicsEngine () { this->setClassID(CL_GRAPHICS_ENGINE, "GraphicsEngine"); this->setName("GraphicsEngine"); this->isInit = false; this->bDisplayFPS = false; this->minFPS = 9999; this->maxFPS = 0; this->fullscreenFlag = 0; } /** \brief The Pointer to this GraphicsEngine */ GraphicsEngine* GraphicsEngine::singletonRef = NULL; /** \brief destructs the graphicsEngine. */ GraphicsEngine::~GraphicsEngine () { // delete what has to be deleted here EventHandler::getInstance()->unsubscribe(this); } /** * initializes the GraphicsEngine with default settings. */ int GraphicsEngine::init() { if (this->isInit) return -1; this->initVideo(640, 480, 16); } /** * loads the GraphicsEngine's settings from a given ini-file and section * @param iniParser the iniParser to load from * @param section the Section in the ini-file to load from * @returns nothing usefull */ int GraphicsEngine::initFromIniFile(IniParser* iniParser) { // looking if we are in fullscreen-mode const char* fullscreen = iniParser->getVar(CONFIG_NAME_FULLSCREEN, CONFIG_SECTION_VIDEO, "0"); if (strchr(fullscreen, '1')) this->fullscreenFlag = SDL_FULLSCREEN; // looking if we are in fullscreen-mode const char* textures = iniParser->getVar(CONFIG_NAME_TEXTURES, CONFIG_SECTION_VIDEO_ADVANCED, "0"); if (strchr(textures, '1')) this->texturesEnabled = true; else this->texturesEnabled = false; // searching for a usefull resolution // SubString resolution(iniParser->getVar(CONFIG_NAME_RESOLUTION, CONFIG_SECTION_VIDEO, "640x480"), 'x'); //resolution.debug(); //this->initVideo(atoi(resolution.getString(0)), atoi(resolution.getString(1)), 16); this->initVideo(640,480,16); } /** \brief initializes the Video for openGL. This has to be done only once when starting orxonox. */ int GraphicsEngine::initVideo(unsigned int resX, unsigned int resY, unsigned int bbp) { if (this->isInit) return -1; // initialize SDL_VIDEO if (SDL_Init(SDL_INIT_VIDEO) == -1) { PRINTF(1)("could not initialize SDL Video\n"); // return -1; } // initialize SDL_GL-settings this->setGLattribs(); // setting the Video Flags. this->videoFlags = SDL_OPENGL | SDL_HWPALETTE | SDL_RESIZABLE | SDL_DOUBLEBUF; /* query SDL for information about our video hardware */ const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo (); if( videoInfo == NULL) { PRINTF(1)("Failed getting Video Info :%s\n", SDL_GetError()); SDL_Quit (); } if( videoInfo->hw_available) this->videoFlags |= SDL_HWSURFACE; else this->videoFlags |= SDL_SWSURFACE; /* if(VideoInfo -> blit_hw) VideoFlags |= SDL_HWACCEL; */ // setting up the Resolution this->setResolution(resX, resY, bbp); // TO DO: Create a cool icon and use it here char* loadPic = new char[strlen(ResourceManager::getInstance()->getDataDir())+ 100]; sprintf(loadPic, "%s%s", ResourceManager::getInstance()->getDataDir(), "pictures/orxonox-icon32x32.bmp"); SDL_WM_SetIcon(SDL_LoadBMP(loadPic), NULL); delete loadPic; // Enable default GL stuff glEnable(GL_DEPTH_TEST); // subscribe the resolutionChanged-event //EventHandler::getInstance()->subscribe(this, ES_GAME, EV_VIDEO_RESIZE); //! @todo eventSystem craps up the Starting of orxonox -> see why. this->isInit = true; } /** * sets the Window Captions and the Name of the icon. * @param windowName The name of the Window * @param icon The name of the Icon on the Disc */ void GraphicsEngine::setWindowName(const char* windowName, const char* icon) { // Set window labeling SDL_WM_SetCaption (windowName, icon); } /** \brief Sets the GL-attributes */ int GraphicsEngine::setGLattribs() { // Set video mode // TO DO: parse arguments for settings //SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); //SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); //SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0); SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 0); SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 0); SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 0); SDL_GL_SetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, 0); } /** \brief sets the Resolution of the Screen to display the Graphics to. \param width The width of the window \param height The height of the window \param bpp bits per pixel */ int GraphicsEngine::setResolution(int width, int height, int bpp) { this->resolutionX = width; this->resolutionY = height; this->bitsPerPixel = bpp; if((this->screen = SDL_SetVideoMode(this->resolutionX, this->resolutionY, this->bitsPerPixel, this->videoFlags | this->fullscreenFlag)) == NULL) { PRINTF(1)("Could not SDL_SetVideoMode(%d, %d, %d, %d): %s\n", this->resolutionX, this->resolutionY, this->bitsPerPixel, this->videoFlags, SDL_GetError()); SDL_Quit(); // return -1; } } /** \brief sets Fullscreen mode \param fullscreen true if fullscreen, false if windowed */ void GraphicsEngine::setFullscreen(bool fullscreen) { if (fullscreen) fullscreenFlag = SDL_FULLSCREEN; else fullscreenFlag = 0; this->setResolution(this->resolutionX, this->resolutionY, this->bitsPerPixel); } /** \brief sets the background color \param red the red part of the background \param blue the blue part of the background \param green the green part of the background \param alpha the alpha part of the background */ void GraphicsEngine::setBackgroundColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { glClearColor(red, green, blue, alpha); } /** \brief Signalhandler, for when the resolution has changed \param resizeInfo SDL information about the size of the new screen size */ int GraphicsEngine::resolutionChanged(const SDL_ResizeEvent& resizeInfo) { this->setResolution(resizeInfo.w, resizeInfo.h, this->bitsPerPixel); } /** * if Textures should be enabled */ bool GraphicsEngine::texturesEnabled = true; /** * * @param show if The mouse-cursor should be visible */ void GraphicsEngine::showMouse(bool show) { if (show) SDL_ShowCursor(SDL_ENABLE); else SDL_ShowCursor(SDL_DISABLE); } /** * * @returns The Visinility of the mouse-cursor (true if visible, false if it is invisible) */ bool GraphicsEngine::isMouseVisible() { if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) return true; else return false; } /** * * @param steal If the Winodow-Managers Events should be stolen to this app * (steals the mouse, and all WM-clicks) * * This only happens, if the HARD-Debug-level is set to 0,1,2, because otherwise a Segfault could * result in the loss of System-controll */ void GraphicsEngine::stealWMEvents(bool steal) { #if DEBUG < 3 if (steal) SDL_WM_GrabInput(SDL_GRAB_ON); else SDL_WM_GrabInput(SDL_GRAB_OFF); #endif } /** * * @returns true if Events are stolen from the WM, false if not. */ bool GraphicsEngine::isStealingEvents() { if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON) return true; else return false; }; /** \brief entering 2D Mode this is a GL-Projection-mode, that is orthogonal, for placing the font in fron of everything else */ void GraphicsEngine::enter2DMode() { GraphicsEngine::storeMatrices(); SDL_Surface *screen = SDL_GetVideoSurface(); /* Note, there may be other things you need to change, depending on how you have your OpenGL state set up. */ glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); // will be set back when leaving 2D-mode glViewport(0, 0, screen->w, screen->h); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } /** \brief leaves the 2DMode again also \see Font::enter2DMode() */ void GraphicsEngine::leave2DMode() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); } /** \brief stores the GL_matrices */ void GraphicsEngine::storeMatrices() { glGetDoublev(GL_PROJECTION_MATRIX, GraphicsEngine::projMat); glGetDoublev(GL_MODELVIEW_MATRIX, GraphicsEngine::modMat); glGetIntegerv(GL_VIEWPORT, GraphicsEngine::viewPort); } //! the stored ModelView Matrix. GLdouble GraphicsEngine::modMat[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //! the stored Projection Matrix GLdouble GraphicsEngine::projMat[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //! The ViewPort GLint GraphicsEngine::viewPort[4] = {0,0,0,0}; /** \brief outputs all the Fullscreen modes. */ void GraphicsEngine::listModes() { /* Get available fullscreen/hardware modes */ this->videoModes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); /* Check is there are any modes available */ if(this->videoModes == (SDL_Rect **)0){ PRINTF(1)("No modes available!\n"); exit(-1); } /* Check if our resolution is restricted */ if(this->videoModes == (SDL_Rect **)-1){ PRINTF(2)("All resolutions available.\n"); } else{ /* Print valid modes */ PRINT(0)("Available Resoulution Modes are\n"); for(int i = 0; this->videoModes[i]; ++i) PRINT(4)(" | %d x %d\n", this->videoModes[i]->w, this->videoModes[i]->h); } } /** \brief ticks the Text \param dt the time passed */ void GraphicsEngine::tick(float dt) { if( unlikely(this->bDisplayFPS)) { this->currentFPS = 1.0/dt; if( unlikely(this->currentFPS > this->maxFPS)) this->maxFPS = this->currentFPS; if( unlikely(this->currentFPS < this->minFPS)) this->minFPS = this->currentFPS; #ifndef NO_TEXT char tmpChar1[20]; sprintf(tmpChar1, "Current: %4.0f", this->currentFPS); this->geTextCFPS->setText(tmpChar1); char tmpChar2[20]; sprintf(tmpChar2, "Max: %4.0f", this->maxFPS); this->geTextMaxFPS->setText(tmpChar2); char tmpChar3[20]; sprintf(tmpChar3, "Min: %4.0f", this->minFPS); this->geTextMinFPS->setText(tmpChar3); #endif /* NO_TEXT */ } } /** \brief displays the Frames per second \param display if the text should be displayed \todo this is dangerous */ void GraphicsEngine::displayFPS(bool display) { if( display) { #ifndef NO_TEXT this->geTextCFPS = TextEngine::getInstance()->createText("fonts/arial_black.ttf", 15, TEXT_DYNAMIC, 0, 255, 0); this->geTextCFPS->setAlignment(TEXT_ALIGN_LEFT); this->geTextCFPS->setPosition(5, 5); this->geTextMaxFPS = TextEngine::getInstance()->createText("fonts/arial_black.ttf", 15, TEXT_DYNAMIC, 0, 255, 0); this->geTextMaxFPS->setAlignment(TEXT_ALIGN_LEFT); this->geTextMaxFPS->setPosition(5, 35); this->geTextMinFPS = TextEngine::getInstance()->createText("fonts/arial_black.ttf", 35, TEXT_DYNAMIC, 0, 255, 0); this->geTextMinFPS->setAlignment(TEXT_ALIGN_LEFT); this->geTextMinFPS->setPosition(5, 65); #endif /* NO_TEXT */ } this->bDisplayFPS = display; } /** \brief processes the events for orxonox main class \param the event to handle */ void GraphicsEngine::process(const Event &event) { switch (event.type) { case EV_VIDEO_RESIZE: this->resolutionChanged(event.resize); break; } }