/** * Sets up all the internal display flags depending on * the current video settings. */ void Screen::makeVideoFlags() { _flags = SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_HWPALETTE; if (Options::asyncBlit) { _flags |= SDL_ASYNCBLIT; } if (isOpenGLEnabled()) { _flags = SDL_OPENGL; 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 ); } if (Options::allowResize) { _flags |= SDL_RESIZABLE; } // Handle window positioning if (Options::windowedModePositionX != -1 || Options::windowedModePositionY != -1) { std::ostringstream ss; ss << "SDL_VIDEO_WINDOW_POS=" << std::dec << Options::windowedModePositionX << "," << Options::windowedModePositionY; SDL_putenv(const_cast<char*>(ss.str().c_str())); SDL_putenv(const_cast<char*>("SDL_VIDEO_CENTERED=")); } else if (Options::borderless) { SDL_putenv(const_cast<char*>("SDL_VIDEO_WINDOW_POS=")); SDL_putenv(const_cast<char*>("SDL_VIDEO_CENTERED=center")); } else { SDL_putenv(const_cast<char*>("SDL_VIDEO_WINDOW_POS=")); SDL_putenv(const_cast<char*>("SDL_VIDEO_CENTERED=")); } // Handle display mode if (Options::fullscreen) { _flags |= SDL_FULLSCREEN; } if (Options::borderless) { _flags |= SDL_NOFRAME; SDL_putenv(const_cast<char*>("SDL_VIDEO_CENTERED=center")); } else { SDL_putenv(const_cast<char*>("SDL_VIDEO_CENTERED=")); } _bpp = (is32bitEnabled() || isOpenGLEnabled()) ? 32 : 8; _baseWidth = Options::baseXResolution; _baseHeight = Options::baseYResolution; }
/** * Saves a screenshot of the screen's contents. * @param filename Filename of the PNG file. */ void Screen::screenshot(const std::string &filename) const { SDL_Surface *screenshot = SDL_AllocSurface(0, getWidth() - getWidth()%4, getHeight(), 24, 0xff, 0xff00, 0xff0000, 0); if (isOpenGLEnabled()) { #ifndef __NO_OPENGL GLenum format = GL_RGB; for (int y = 0; y < getHeight(); ++y) { glReadPixels(0, getHeight()-(y+1), getWidth() - getWidth()%4, 1, format, GL_UNSIGNED_BYTE, ((Uint8*)screenshot->pixels) + y*screenshot->pitch); } glErrorCheck(); #endif } else { SDL_BlitSurface(_screen, 0, screenshot, 0); } unsigned error = lodepng::encode(filename, (const unsigned char *)(screenshot->pixels), getWidth() - getWidth()%4, getHeight(), LCT_RGB); if (error) { Log(LOG_ERROR) << "Saving to PNG failed: " << lodepng_error_text(error); } SDL_FreeSurface(screenshot); }
/** * Renders the buffer's contents onto the screen, applying * any necessary filters or conversions in the process. * If the scaling factor is bigger than 1, the entire contents * of the buffer are resized by that factor (eg. 2 = doubled) * before being put on screen. */ void Screen::flip() { if (getWidth() != _baseWidth || getHeight() != _baseHeight || isOpenGLEnabled()) { Zoom::flipWithZoom(_surface->getSurface(), _screen, _topBlackBand, _bottomBlackBand, _leftBlackBand, _rightBlackBand, &glOutput); } else { SDL_BlitSurface(_surface->getSurface(), 0, _screen, 0); } // perform any requested palette update if (_pushPalette && _numColors && _screen->format->BitsPerPixel == 8) { if (_screen->format->BitsPerPixel == 8 && SDL_SetColors(_screen, &(deferredPalette[_firstColor]), _firstColor, _numColors) == 0) { Log(LOG_DEBUG) << "Display palette doesn't match requested palette"; } _numColors = 0; _pushPalette = false; } if (SDL_Flip(_screen) == -1) { throw Exception(SDL_GetError()); } }
/// Sets the _flags and _bpp variables based on game options; needed in more than one place now void Screen::makeVideoFlags() { _flags = SDL_SWSURFACE|SDL_HWPALETTE; if (Options::getBool("asyncBlit")) _flags |= SDL_ASYNCBLIT; if (isOpenGLEnabled()) _flags = SDL_OPENGL; if (Options::getBool("allowResize")) _flags |= SDL_RESIZABLE; if (_fullscreen) { _flags |= SDL_FULLSCREEN; } _bpp = (Screen::isHQXEnabled() || Screen::isOpenGLEnabled()) ? 32 : 8; }
/** * Changes the screen's resolution. The display surface * and palette have to be reset for this to happen properly. * @param width Width in pixels. * @param height Height in pixels. */ void Screen::setResolution(int width, int height) { makeVideoFlags(); if (!_surface || (_surface && (_surface->getSurface()->format->BitsPerPixel != _bpp || _surface->getSurface()->w != BASE_WIDTH || _surface->getSurface()->h != BASE_HEIGHT))) // don't reallocate _surface if not necessary, it's a waste of CPU cycles { if (_surface) delete _surface; _surface = new Surface((int)BASE_WIDTH, (int)BASE_HEIGHT, 0, 0, Screen::isHQXEnabled() ? 32 : 8); // only HQX needs 32bpp for this surface; the OpenGL class has its own 32bpp buffer if (_surface->getSurface()->format->BitsPerPixel == 8) _surface->setPalette(deferredPalette); } SDL_SetColorKey(_surface->getSurface(), 0, 0); // turn off color key! Log(LOG_INFO) << "Attempting to set display to " << width << "x" << height << "x" << _bpp << "..."; _screen = SDL_SetVideoMode(width, height, _bpp, _flags); if (_screen == 0) { throw Exception(SDL_GetError()); } _scaleX = getWidth() / (double)BASE_WIDTH; _scaleY = getHeight() / (double)BASE_HEIGHT; if (isOpenGLEnabled()) { glOutput.init(BASE_WIDTH, BASE_HEIGHT); glOutput.linear = Options::getBool("useOpenGLSmoothing"); // setting from shader file will override this, though glOutput.set_shader(CrossPlatform::getDataFile(Options::getString("useOpenGLShader")).c_str()); glOutput.setVSync(Options::getBool("vSyncForOpenGL")); OpenGL::checkErrors = Options::getBool("checkOpenGLErrors"); } Log(LOG_INFO) << "Display set to " << getWidth() << "x" << getHeight() << "x" << (int)_screen->format->BitsPerPixel << "."; if (_screen->format->BitsPerPixel == 8) { setPalette(getPalette()); } }
/** * Resets the screen surfaces based on the current display options, * as they don't automatically take effect. * @param resetVideo Reset display surface. */ void Screen::resetDisplay(bool resetVideo) { int width = Options::displayWidth; int height = Options::displayHeight; #ifdef __linux__ Uint32 oldFlags = _flags; #endif makeVideoFlags(); if (!_surface || (_surface && (_surface->getSurface()->format->BitsPerPixel != _bpp || _surface->getSurface()->w != _baseWidth || _surface->getSurface()->h != _baseHeight))) // don't reallocate _surface if not necessary, it's a waste of CPU cycles { if (_surface) delete _surface; _surface = new Surface(_baseWidth, _baseHeight, 0, 0, Screen::is32bitEnabled() ? 32 : 8); // only HQX needs 32bpp for this surface; the OpenGL class has its own 32bpp buffer if (_surface->getSurface()->format->BitsPerPixel == 8) _surface->setPalette(deferredPalette); } SDL_SetColorKey(_surface->getSurface(), 0, 0); // turn off color key! if (resetVideo || _screen->format->BitsPerPixel != _bpp) { #ifdef __linux__ // Workaround for segfault when switching to opengl if (!(oldFlags & SDL_OPENGL) && (_flags & SDL_OPENGL)) { Uint8 cursor = 0; char *_oldtitle = 0; SDL_WM_GetCaption(&_oldtitle, NULL); std::string title(_oldtitle); SDL_QuitSubSystem(SDL_INIT_VIDEO); SDL_InitSubSystem(SDL_INIT_VIDEO); SDL_ShowCursor(SDL_ENABLE); SDL_EnableUNICODE(1); SDL_WM_SetCaption(title.c_str(), 0); SDL_SetCursor(SDL_CreateCursor(&cursor, &cursor, 1,1,0,0)); } #endif Log(LOG_INFO) << "Attempting to set display to " << width << "x" << height << "x" << _bpp << "..."; _screen = SDL_SetVideoMode(width, height, _bpp, _flags); if (_screen == 0) { Log(LOG_ERROR) << SDL_GetError(); Log(LOG_INFO) << "Attempting to set display to default resolution..."; _screen = SDL_SetVideoMode(640, 400, _bpp, _flags); if (_screen == 0) { throw Exception(SDL_GetError()); } } Log(LOG_INFO) << "Display set to " << getWidth() << "x" << getHeight() << "x" << (int)_screen->format->BitsPerPixel << "."; } else { clear(); } Options::displayWidth = getWidth(); Options::displayHeight = getHeight(); _scaleX = getWidth() / (double)_baseWidth; _scaleY = getHeight() / (double)_baseHeight; _clear.x = 0; _clear.y = 0; _clear.w = getWidth(); _clear.h = getHeight(); double pixelRatioY = 1.0; if (Options::nonSquarePixelRatio && !Options::allowResize) { pixelRatioY = 1.2; } bool cursorInBlackBands; if (!Options::keepAspectRatio) { cursorInBlackBands = false; } else if (Options::fullscreen) { cursorInBlackBands = Options::cursorInBlackBandsInFullscreen; } else if (!Options::borderless) { cursorInBlackBands = Options::cursorInBlackBandsInWindow; } else { cursorInBlackBands = Options::cursorInBlackBandsInBorderlessWindow; } if (_scaleX > _scaleY && Options::keepAspectRatio) { int targetWidth = (int)floor(_scaleY * (double)_baseWidth); _topBlackBand = _bottomBlackBand = 0; _leftBlackBand = (getWidth() - targetWidth) / 2; if (_leftBlackBand < 0) { _leftBlackBand = 0; } _rightBlackBand = getWidth() - targetWidth - _leftBlackBand; _cursorTopBlackBand = 0; if (cursorInBlackBands) { _scaleX = _scaleY; _cursorLeftBlackBand = _leftBlackBand; } else { _cursorLeftBlackBand = 0; } } else if (_scaleY > _scaleX && Options::keepAspectRatio) { int targetHeight = (int)floor(_scaleX * (double)_baseHeight * pixelRatioY); _topBlackBand = (getHeight() - targetHeight) / 2; if (_topBlackBand < 0) { _topBlackBand = 0; } _bottomBlackBand = getHeight() - targetHeight - _topBlackBand; if (_bottomBlackBand < 0) { _bottomBlackBand = 0; } _leftBlackBand = _rightBlackBand = 0; _cursorLeftBlackBand = 0; if (cursorInBlackBands) { _scaleY = _scaleX; _cursorTopBlackBand = _topBlackBand; } else { _cursorTopBlackBand = 0; } } else { _topBlackBand = _bottomBlackBand = _leftBlackBand = _rightBlackBand = _cursorTopBlackBand = _cursorLeftBlackBand = 0; } if (isOpenGLEnabled()) { #ifndef __NO_OPENGL glOutput.init(_baseWidth, _baseHeight); glOutput.linear = Options::useOpenGLSmoothing; // setting from shader file will override this, though glOutput.set_shader(FileMap::getFilePath(Options::useOpenGLShader).c_str()); glOutput.setVSync(Options::vSyncForOpenGL); OpenGL::checkErrors = Options::checkOpenGLErrors; #endif } if (_screen->format->BitsPerPixel == 8) { setPalette(getPalette()); } }