Logo Search packages:      
Sourcecode: scummvm version File versions

opengl-graphics.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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
 * of the License, or (at your option) any later version.

 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *
 */

#include "common/scummsys.h"

#if defined(USE_OPENGL)

#include "backends/graphics/opengl/opengl-graphics.h"
#include "backends/graphics/opengl/glerrorcheck.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/mutex.h"
#include "common/textconsole.h"
#include "common/translation.h"
#ifdef USE_OSD
#include "common/tokenizer.h"
#endif
#include "graphics/font.h"
#include "graphics/fontman.h"

OpenGLGraphicsManager::OpenGLGraphicsManager()
      :
#ifdef USE_OSD
      _osdTexture(0), _osdAlpha(0), _osdFadeStartTime(0), _requireOSDUpdate(false),
#endif
      _gameTexture(0), _overlayTexture(0), _cursorTexture(0),
      _screenChangeCount(1 << (sizeof(int) * 8 - 2)), _screenNeedsRedraw(false),
      _shakePos(0),
      _overlayVisible(false), _overlayNeedsRedraw(false),
      _transactionMode(kTransactionNone),
      _cursorNeedsRedraw(false), _cursorPaletteDisabled(true),
      _cursorVisible(false), _cursorKeyColor(0),
      _cursorTargetScale(1),
      _formatBGR(false),
      _displayX(0), _displayY(0), _displayWidth(0), _displayHeight(0) {

      memset(&_oldVideoMode, 0, sizeof(_oldVideoMode));
      memset(&_videoMode, 0, sizeof(_videoMode));
      memset(&_transactionDetails, 0, sizeof(_transactionDetails));

      _videoMode.mode = OpenGL::GFX_NORMAL;
      _videoMode.scaleFactor = 2;
      _videoMode.fullscreen = ConfMan.getBool("fullscreen");
      _videoMode.antialiasing = false;

      _gamePalette = (byte *)calloc(sizeof(byte) * 3, 256);
      _cursorPalette = (byte *)calloc(sizeof(byte) * 3, 256);
}

OpenGLGraphicsManager::~OpenGLGraphicsManager() {
      // Unregister the event observer
      if (g_system->getEventManager()->getEventDispatcher() != NULL)
            g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);

      free(_gamePalette);
      free(_cursorPalette);

      delete _gameTexture;
      delete _overlayTexture;
      delete _cursorTexture;
}

void OpenGLGraphicsManager::initEventObserver() {
      // Register the graphics manager as a event observer
      g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
}

//
// Feature
//

bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) {
      return
            (f == OSystem::kFeatureAspectRatioCorrection) ||
            (f == OSystem::kFeatureCursorHasPalette);
}

void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
      switch (f) {
      case OSystem::kFeatureFullscreenMode:
            setFullscreenMode(enable);
            break;

      case OSystem::kFeatureAspectRatioCorrection:
            _videoMode.aspectRatioCorrection = enable;
            _transactionDetails.needRefresh = true;
            break;

      default:
            break;
      }
}

bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) {
      switch (f) {
      case OSystem::kFeatureFullscreenMode:
            return _videoMode.fullscreen;

      case OSystem::kFeatureAspectRatioCorrection:
            return _videoMode.aspectRatioCorrection;

      default:
            return false;
      }
}

//
// Screen format and modes
//

static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
      {"gl1", _s("OpenGL Normal"), OpenGL::GFX_NORMAL},
      {"gl2", _s("OpenGL Conserve"), OpenGL::GFX_CONSERVE},
      {"gl4", _s("OpenGL Original"), OpenGL::GFX_ORIGINAL},
      {0, 0, 0}
};

const OSystem::GraphicsMode *OpenGLGraphicsManager::supportedGraphicsModes() {
      return s_supportedGraphicsModes;
}

const OSystem::GraphicsMode *OpenGLGraphicsManager::getSupportedGraphicsModes() const {
      return s_supportedGraphicsModes;
}

int OpenGLGraphicsManager::getDefaultGraphicsMode() const {
      return OpenGL::GFX_NORMAL;
}

bool OpenGLGraphicsManager::setGraphicsMode(int mode) {
      assert(_transactionMode == kTransactionActive);

      setScale(2);

      if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
            return true;

      switch (mode) {
      case OpenGL::GFX_NORMAL:
      case OpenGL::GFX_CONSERVE:
      case OpenGL::GFX_ORIGINAL:
            break;
      default:
            warning("Unknown gfx mode %d", mode);
            return false;
      }

      _videoMode.mode = mode;
      _transactionDetails.needRefresh = true;

      return true;
}

int OpenGLGraphicsManager::getGraphicsMode() const {
      assert (_transactionMode == kTransactionNone);
      return _videoMode.mode;
}

void OpenGLGraphicsManager::resetGraphicsScale() {
      setScale(1);
}

#ifdef USE_RGB_COLOR
Graphics::PixelFormat OpenGLGraphicsManager::getScreenFormat() const {
      return _screenFormat;
}
#endif

void OpenGLGraphicsManager::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
      assert(_transactionMode == kTransactionActive);

#ifdef USE_RGB_COLOR
      Graphics::PixelFormat newFormat;
      if (!format)
            newFormat = Graphics::PixelFormat::createFormatCLUT8();
      else
            newFormat = *format;

      assert(newFormat.bytesPerPixel > 0);

      // Avoid redundant format changes
      if (newFormat != _videoMode.format) {
            _videoMode.format = newFormat;
            _transactionDetails.formatChanged = true;
            _screenFormat = newFormat;
      }
#endif

      // Avoid redundant res changes
      if ((int)width == _videoMode.screenWidth && (int)height == _videoMode.screenHeight)
            return;

      _videoMode.screenWidth = width;
      _videoMode.screenHeight = height;

      _transactionDetails.sizeChanged = true;
}

int OpenGLGraphicsManager::getScreenChangeID() const {
      return _screenChangeCount;
}

//
// GFX
//

void OpenGLGraphicsManager::beginGFXTransaction() {
      assert(_transactionMode == kTransactionNone);

      _transactionMode = kTransactionActive;
      _transactionDetails.sizeChanged = false;
      _transactionDetails.needRefresh = false;
      _transactionDetails.needUpdatescreen = false;
      _transactionDetails.filterChanged = false;
#ifdef USE_RGB_COLOR
      _transactionDetails.formatChanged = false;
#endif

      _oldVideoMode = _videoMode;
}

OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
      int errors = OSystem::kTransactionSuccess;

      assert(_transactionMode != kTransactionNone);

      if (_transactionMode == kTransactionRollback) {
            if (_videoMode.fullscreen != _oldVideoMode.fullscreen) {
                  errors |= OSystem::kTransactionFullscreenFailed;

                  _videoMode.fullscreen = _oldVideoMode.fullscreen;
            } else if (_videoMode.mode != _oldVideoMode.mode) {
                  errors |= OSystem::kTransactionModeSwitchFailed;

                  _videoMode.mode = _oldVideoMode.mode;
                  _videoMode.scaleFactor = _oldVideoMode.scaleFactor;
#ifdef USE_RGB_COLOR
            } else if (_videoMode.format != _oldVideoMode.format) {
                  errors |= OSystem::kTransactionFormatNotSupported;

                  _videoMode.format = _oldVideoMode.format;
                  _screenFormat = _videoMode.format;
#endif
            } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) {
                  errors |= OSystem::kTransactionSizeChangeFailed;

                  _videoMode.screenWidth = _oldVideoMode.screenWidth;
                  _videoMode.screenHeight = _oldVideoMode.screenHeight;
                  _videoMode.overlayWidth = _oldVideoMode.overlayWidth;
                  _videoMode.overlayHeight = _oldVideoMode.overlayHeight;
            }

            if (_videoMode.fullscreen == _oldVideoMode.fullscreen &&
                  _videoMode.mode == _oldVideoMode.mode &&
                  _videoMode.screenWidth == _oldVideoMode.screenWidth &&
                  _videoMode.screenHeight == _oldVideoMode.screenHeight) {

                  _oldVideoMode.setup = false;
            }
      }

      if (_transactionDetails.sizeChanged || _transactionDetails.needRefresh) {
            unloadGFXMode();
            if (!loadGFXMode()) {
                  if (_oldVideoMode.setup) {
                        _transactionMode = kTransactionRollback;
                        errors |= endGFXTransaction();
                  }
            } else {
                  clearOverlay();

                  _videoMode.setup = true;
                  _screenChangeCount++;
            }
#ifdef USE_RGB_COLOR
      } else if (_transactionDetails.filterChanged || _transactionDetails.formatChanged) {
#else
      } else if (_transactionDetails.filterChanged) {
#endif
            loadTextures();
            internUpdateScreen();
      } else if (_transactionDetails.needUpdatescreen) {
            internUpdateScreen();
      }

      _transactionMode = kTransactionNone;
      return (OSystem::TransactionError)errors;
}

//
// Screen
//

int16 OpenGLGraphicsManager::getHeight() {
      return _videoMode.screenHeight;
}

int16 OpenGLGraphicsManager::getWidth() {
      return _videoMode.screenWidth;
}

void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
      assert(colors);

#ifdef USE_RGB_COLOR
      assert(_screenFormat.bytesPerPixel == 1);
#endif

      // Save the screen palette
      memcpy(_gamePalette + start * 3, colors, num * 3);

      _screenNeedsRedraw = true;

      if (_cursorPaletteDisabled)
            _cursorNeedsRedraw = true;
}

void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
      assert(colors);

#ifdef USE_RGB_COLOR
      assert(_screenFormat.bytesPerPixel == 1);
#endif

      // Copies current palette to buffer
      memcpy(colors, _gamePalette + start * 3, num * 3);
}

void OpenGLGraphicsManager::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
      assert(x >= 0 && x < _screenData.w);
      assert(y >= 0 && y < _screenData.h);
      assert(h > 0 && y + h <= _screenData.h);
      assert(w > 0 && x + w <= _screenData.w);

      // Copy buffer data to game screen internal buffer
      const byte *src = buf;
      byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch + x * _screenData.bytesPerPixel;
      for (int i = 0; i < h; i++) {
            memcpy(dst, src, w * _screenData.bytesPerPixel);
            src += pitch;
            dst += _screenData.pitch;
      }

      // Extend dirty area if not full screen redraw is flagged
      if (!_screenNeedsRedraw) {
            const Common::Rect dirtyRect(x, y, x + w, y + h);
            _screenDirtyRect.extend(dirtyRect);
      }
}

Graphics::Surface *OpenGLGraphicsManager::lockScreen() {
      return &_screenData;
}

void OpenGLGraphicsManager::unlockScreen() {
      _screenNeedsRedraw = true;
}

void OpenGLGraphicsManager::fillScreen(uint32 col) {
      if (_gameTexture == NULL)
            return;

#ifdef USE_RGB_COLOR
      if (_screenFormat.bytesPerPixel == 1) {
            memset(_screenData.pixels, col, _screenData.h * _screenData.pitch);
      } else if (_screenFormat.bytesPerPixel == 2) {
            uint16 *pixels = (uint16 *)_screenData.pixels;
            uint16 col16 = (uint16)col;
            for (int i = 0; i < _screenData.w * _screenData.h; i++) {
                  pixels[i] = col16;
            }
      } else if (_screenFormat.bytesPerPixel == 3) {
            uint8 *pixels = (uint8 *)_screenData.pixels;
            byte r = (col >> 16) & 0xFF;
            byte g = (col >> 8) & 0xFF;
            byte b = col & 0xFF;
            for (int i = 0; i < _screenData.w * _screenData.h; i++) {
                  pixels[0] = r;
                  pixels[1] = g;
                  pixels[2] = b;
                  pixels += 3;
            }
      } else if (_screenFormat.bytesPerPixel == 4) {
            uint32 *pixels = (uint32 *)_screenData.pixels;
            for (int i = 0; i < _screenData.w * _screenData.h; i++) {
                  pixels[i] = col;
            }
      }
#else
      memset(_screenData.pixels, col, _screenData.h * _screenData.pitch);
#endif
      _screenNeedsRedraw = true;
}

void OpenGLGraphicsManager::updateScreen() {
      assert (_transactionMode == kTransactionNone);
      internUpdateScreen();
}

void OpenGLGraphicsManager::setShakePos(int shakeOffset) {
      assert (_transactionMode == kTransactionNone);
      _shakePos = shakeOffset;
}

void OpenGLGraphicsManager::setFocusRectangle(const Common::Rect& rect) {
}

void OpenGLGraphicsManager::clearFocusRectangle() {
}

//
// Overlay
//

void OpenGLGraphicsManager::showOverlay() {
      assert (_transactionMode == kTransactionNone);

      if (_overlayVisible)
            return;

      _overlayVisible = true;

      clearOverlay();
}

void OpenGLGraphicsManager::hideOverlay() {
      assert (_transactionMode == kTransactionNone);

      if (!_overlayVisible)
            return;

      _overlayVisible = false;

      clearOverlay();
}

Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const {
      return _overlayFormat;
}

void OpenGLGraphicsManager::clearOverlay() {
      // Set all pixels to 0
      memset(_overlayData.pixels, 0, _overlayData.h * _overlayData.pitch);
      _overlayNeedsRedraw = true;
}

void OpenGLGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) {
      assert(_overlayData.bytesPerPixel == sizeof(buf[0]));
      const byte *src = (byte *)_overlayData.pixels;
      for (int i = 0; i < _overlayData.h; i++) {
            // Copy overlay data to buffer
            memcpy(buf, src, _overlayData.pitch);
            buf += pitch;
            src += _overlayData.pitch;
      }
}

void OpenGLGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
      assert (_transactionMode == kTransactionNone);

      if (_overlayTexture == NULL)
            return;

      // Clip the coordinates
      if (x < 0) {
            w += x;
            buf -= x;
            x = 0;
      }

      if (y < 0) {
            h += y; buf -= y * pitch;
            y = 0;
      }

      if (w > _overlayData.w - x)
            w = _overlayData.w - x;

      if (h > _overlayData.h - y)
            h = _overlayData.h - y;

      if (w <= 0 || h <= 0)
            return;

      if (_overlayFormat.aBits() == 1) {
            // Copy buffer with the alpha bit on for all pixels for correct
            // overlay drawing.
            const uint16 *src = (const uint16 *)buf;
            uint16 *dst = (uint16 *)_overlayData.pixels + y * _overlayData.w + x;
            for (int i = 0; i < h; i++) {
                  for (int e = 0; e < w; e++)
                        dst[e] = src[e] | 0x1;
                  src += pitch;
                  dst += _overlayData.w;
            }
      } else {
            // Copy buffer data to internal overlay surface
            const byte *src = (const byte *)buf;
            byte *dst = (byte *)_overlayData.pixels + y * _overlayData.pitch;
            for (int i = 0; i < h; i++) {
                  memcpy(dst + x * _overlayData.bytesPerPixel, src, w * _overlayData.bytesPerPixel);
                  src += pitch * sizeof(buf[0]);
                  dst += _overlayData.pitch;
            }
      }

      // Extend dirty area if not full screen redraw is flagged
      if (!_overlayNeedsRedraw) {
            const Common::Rect dirtyRect(x, y, x + w, y + h);
            _overlayDirtyRect.extend(dirtyRect);
      }
}

int16 OpenGLGraphicsManager::getOverlayHeight() {
      return _videoMode.overlayHeight;
}

int16 OpenGLGraphicsManager::getOverlayWidth() {
      return _videoMode.overlayWidth;
}

//
// Cursor
//

bool OpenGLGraphicsManager::showMouse(bool visible) {
      if (_cursorVisible == visible)
            return visible;

      bool last = _cursorVisible;
      _cursorVisible = visible;

      return last;
}

void OpenGLGraphicsManager::warpMouse(int x, int y) {
      int scaledX = x;
      int scaledY = y;

      int16 currentX = _cursorState.x;
      int16 currentY = _cursorState.y;

      adjustMousePosition(currentX, currentY);

      // Do not adjust the real screen position, when the current game / overlay
      // coordinates match the requested coordinates. This avoids a slight
      // movement which might occur otherwise when the mouse is at a subpixel
      // position.
      if (x == currentX && y == currentY)
            return;

      if (_videoMode.mode == OpenGL::GFX_NORMAL) {
            if (_videoMode.hardwareWidth != _videoMode.overlayWidth)
                  scaledX = scaledX * _videoMode.hardwareWidth / _videoMode.overlayWidth;
            if (_videoMode.hardwareHeight != _videoMode.overlayHeight)
                  scaledY = scaledY * _videoMode.hardwareHeight / _videoMode.overlayHeight;

            if (!_overlayVisible) {
                  scaledX *= _videoMode.scaleFactor;
                  scaledY *= _videoMode.scaleFactor;
            }
      } else {
            if (_overlayVisible) {
                  if (_displayWidth != _videoMode.overlayWidth)
                        scaledX = scaledX * _displayWidth / _videoMode.overlayWidth;
                  if (_displayHeight != _videoMode.overlayHeight)
                        scaledY = scaledY * _displayHeight / _videoMode.overlayHeight;
            } else {
                  if (_displayWidth != _videoMode.screenWidth)
                        scaledX = scaledX * _displayWidth / _videoMode.screenWidth;
                  if (_displayHeight != _videoMode.screenHeight)
                        scaledY = scaledY * _displayHeight / _videoMode.screenHeight;
            }

            scaledX += _displayX;
            scaledY += _displayY;
      }

      setInternalMousePosition(scaledX, scaledY);

      _cursorState.x = scaledX;
      _cursorState.y = scaledY;
}

void OpenGLGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
#ifdef USE_RGB_COLOR
      if (format)
            _cursorFormat = *format;
      else
            _cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
#else
      assert(keycolor <= 255);
      _cursorFormat = Graphics::PixelFormat::createFormatCLUT8();
#endif

      // Allocate space for cursor data
      if (_cursorData.w != w || _cursorData.h != h ||
                  _cursorData.bytesPerPixel != _cursorFormat.bytesPerPixel)
            _cursorData.create(w, h, _cursorFormat.bytesPerPixel);

      // Save cursor data
      memcpy(_cursorData.pixels, buf, h * _cursorData.pitch);

      // Set cursor info
      _cursorState.w = w;
      _cursorState.h = h;
      _cursorState.hotX = hotspotX;
      _cursorState.hotY = hotspotY;
      _cursorKeyColor = keycolor;
      _cursorTargetScale = cursorTargetScale;
      _cursorNeedsRedraw = true;

      refreshCursorScale();
}

void OpenGLGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
      assert(colors);
      
      // Save the cursor palette
      memcpy(_cursorPalette + start * 3, colors, num * 3);

      _cursorPaletteDisabled = false;
      _cursorNeedsRedraw = true;
}

void OpenGLGraphicsManager::disableCursorPalette(bool disable) {
      _cursorPaletteDisabled = disable;
      _cursorNeedsRedraw = true;
}

//
// Misc
//

void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) {
      assert(_transactionMode == kTransactionNone);
      assert(msg);

#ifdef USE_OSD
      // Split the message into separate lines.
      _osdLines.clear();

      Common::StringTokenizer tokenizer(msg, "\n");
      while (!tokenizer.empty())
            _osdLines.push_back(tokenizer.nextToken());

      // Request update of the texture
      _requireOSDUpdate = true;

      // Init the OSD display parameters, and the fade out
      _osdAlpha = kOSDInitialAlpha;
      _osdFadeStartTime = g_system->getMillis() + kOSDFadeOutDelay;
#endif
}

//
// Intern
//

void OpenGLGraphicsManager::setFullscreenMode(bool enable) {
      assert(_transactionMode == kTransactionActive);

      if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable)
            return;

      if (_transactionMode == kTransactionActive) {
            _videoMode.fullscreen = enable;
            _transactionDetails.needRefresh = true;
      }
}

void OpenGLGraphicsManager::refreshGameScreen() {
      if (_screenNeedsRedraw)
            _screenDirtyRect = Common::Rect(0, 0, _screenData.w, _screenData.h);

      int x = _screenDirtyRect.left;
      int y = _screenDirtyRect.top;
      int w = _screenDirtyRect.width();
      int h = _screenDirtyRect.height();

      if (_screenData.bytesPerPixel == 1) {
            // Create a temporary RGB888 surface
            byte *surface = new byte[w * h * 3];

            // Convert the paletted buffer to RGB888
            const byte *src = (byte *)_screenData.pixels + y * _screenData.pitch;
            src += x * _screenData.bytesPerPixel;
            byte *dst = surface;
            for (int i = 0; i < h; i++) {
                  for (int j = 0; j < w; j++) {
                        dst[0] = _gamePalette[src[j] * 3];
                        dst[1] = _gamePalette[src[j] * 3 + 1];
                        dst[2] = _gamePalette[src[j] * 3 + 2];
                        dst += 3;
                  }
                  src += _screenData.pitch;
            }

            // Update the texture
            _gameTexture->updateBuffer(surface, w * 3, x, y, w, h);

            // Free the temp surface
            delete[] surface;
      } else {
            // Update the texture
            _gameTexture->updateBuffer((byte *)_screenData.pixels + y * _screenData.pitch +
                  x * _screenData.bytesPerPixel, _screenData.pitch, x, y, w, h);
      }

      _screenNeedsRedraw = false;
      _screenDirtyRect = Common::Rect();
}

void OpenGLGraphicsManager::refreshOverlay() {
      if (_overlayNeedsRedraw)
            _overlayDirtyRect = Common::Rect(0, 0, _overlayData.w, _overlayData.h);

      int x = _overlayDirtyRect.left;
      int y = _overlayDirtyRect.top;
      int w = _overlayDirtyRect.width();
      int h = _overlayDirtyRect.height();

      if (_overlayData.bytesPerPixel == 1) {
            // Create a temporary RGB888 surface
            byte *surface = new byte[w * h * 3];

            // Convert the paletted buffer to RGB888
            const byte *src = (byte *)_overlayData.pixels + y * _overlayData.pitch;
            src += x * _overlayData.bytesPerPixel;
            byte *dst = surface;
            for (int i = 0; i < h; i++) {
                  for (int j = 0; j < w; j++) {
                        dst[0] = _gamePalette[src[j] * 3];
                        dst[1] = _gamePalette[src[j] * 3 + 1];
                        dst[2] = _gamePalette[src[j] * 3 + 2];
                        dst += 3;
                  }
                  src += _screenData.pitch;
            }

            // Update the texture
            _overlayTexture->updateBuffer(surface, w * 3, x, y, w, h);

            // Free the temp surface
            delete[] surface;
      } else {
            // Update the texture
            _overlayTexture->updateBuffer((byte *)_overlayData.pixels + y * _overlayData.pitch +
                  x * _overlayData.bytesPerPixel, _overlayData.pitch, x, y, w, h);
      }

      _overlayNeedsRedraw = false;
      _overlayDirtyRect = Common::Rect();
}

void OpenGLGraphicsManager::refreshCursor() {
      _cursorNeedsRedraw = false;

      // Allocate a texture big enough for cursor
      _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);

      // Create a temporary RGBA8888 surface
      byte *surface = new byte[_cursorState.w * _cursorState.h * 4];
      memset(surface, 0, _cursorState.w * _cursorState.h * 4);

      byte *dst = surface;

      // Convert the paletted cursor to RGBA8888
      if (_cursorFormat.bytesPerPixel == 1) {
            // Select palette
            byte *palette;
            if (_cursorPaletteDisabled)
                  palette = _gamePalette;
            else
                  palette = _cursorPalette;

            // Convert the paletted cursor to RGBA8888
            const byte *src = (byte *)_cursorData.pixels;
            for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
                  // Check for keycolor
                  if (src[i] != _cursorKeyColor) {
                        dst[0] = palette[src[i] * 3];
                        dst[1] = palette[src[i] * 3 + 1];
                        dst[2] = palette[src[i] * 3 + 2];
                        dst[3] = 255;
                  }
                  dst += 4;
            }
      } else {
            const bool gotNoAlpha = (_cursorFormat.aLoss == 8);

            // Convert the RGB cursor to RGBA8888
            if (_cursorFormat.bytesPerPixel == 2) {
                  const uint16 *src = (uint16 *)_cursorData.pixels;
                  for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
                        // Check for keycolor
                        if (src[i] != _cursorKeyColor) {
                              _cursorFormat.colorToARGB(src[i], dst[3], dst[0], dst[1], dst[2]);

                              if (gotNoAlpha)
                                    dst[3] = 255;
                        }
                        dst += 4;
                  }
            } else if (_cursorFormat.bytesPerPixel == 4) {
                  const uint32 *src = (uint32 *)_cursorData.pixels;
                  for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
                        // Check for keycolor
                        if (src[i] != _cursorKeyColor) {
                              _cursorFormat.colorToARGB(src[i], dst[3], dst[0], dst[1], dst[2]);

                              if (gotNoAlpha)
                                    dst[3] = 255;
                        }
                        dst += 4;
                  }
            }
      }

      // Update the texture with new cursor
      _cursorTexture->updateBuffer(surface, _cursorState.w * 4, 0, 0, _cursorState.w, _cursorState.h);

      // Free the temp surface
      delete[] surface;
}

void OpenGLGraphicsManager::refreshCursorScale() {
      // Get the window minimum scale factor. The cursor will mantain its original aspect
      // ratio, and we do not want it to get too big if only one dimension is resized
      uint screenScaleFactor = MIN(_videoMode.hardwareWidth * 10000 / _videoMode.screenWidth,
            _videoMode.hardwareHeight * 10000 / _videoMode.screenHeight);

      // Do not scale cursor if original size is used
      if (_videoMode.mode == OpenGL::GFX_ORIGINAL)
            screenScaleFactor = _videoMode.scaleFactor * 10000;

      if ((uint)_cursorTargetScale * 10000 >= screenScaleFactor && (uint)_videoMode.scaleFactor * 10000 >= screenScaleFactor) {
            // If the cursor target scale and the video mode scale factor are bigger than
            // the current window scale, do not scale the cursor for the overlay
            _cursorState.rW = _cursorState.w;
            _cursorState.rH = _cursorState.h;
            _cursorState.rHotX = _cursorState.hotX;
            _cursorState.rHotY = _cursorState.hotY;
      } else {
            // Otherwise, scale the cursor for the overlay
            int targetScaleFactor = MIN(_cursorTargetScale, _videoMode.scaleFactor);
            // We limit the maximum scale to 3 here to avoid too big cursors, for large overlay resolutions
            int actualFactor = MIN<uint>(3, screenScaleFactor - (targetScaleFactor - 1)) * 10000;
            _cursorState.rW = (int16)(_cursorState.w * actualFactor / 10000);
            _cursorState.rH = (int16)(_cursorState.h * actualFactor / 10000);
            _cursorState.rHotX = (int16)(_cursorState.hotX * actualFactor / 10000);
            _cursorState.rHotY = (int16)(_cursorState.hotY * actualFactor / 10000);
      }

      // Always scale the cursor for the game
      _cursorState.vW = (int16)(_cursorState.w * screenScaleFactor / 10000);
      _cursorState.vH = (int16)(_cursorState.h * screenScaleFactor / 10000);
      _cursorState.vHotX = (int16)(_cursorState.hotX * screenScaleFactor / 10000);
      _cursorState.vHotY = (int16)(_cursorState.hotY * screenScaleFactor / 10000);
}

void OpenGLGraphicsManager::calculateDisplaySize(int &width, int &height) {
      if (_videoMode.mode == OpenGL::GFX_ORIGINAL) {
            width = _videoMode.screenWidth;
            height = _videoMode.screenHeight;
      } else {
            width = _videoMode.hardwareWidth;
            height = _videoMode.hardwareHeight;

            uint aspectRatio = (_videoMode.hardwareWidth * 10000 + 5000) / _videoMode.hardwareHeight;
            uint desiredAspectRatio = getAspectRatio();

            // Adjust one screen dimension for mantaining the aspect ratio
            if (aspectRatio < desiredAspectRatio)
                  height = (width * 10000 + 5000) / desiredAspectRatio;
            else if (aspectRatio > desiredAspectRatio)
                  width = (height * desiredAspectRatio + 5000) / 10000;
      }
}

void OpenGLGraphicsManager::refreshDisplaySize() {
      calculateDisplaySize(_displayWidth, _displayHeight);

      // Adjust x and y for centering the screen
      _displayX = (_videoMode.hardwareWidth - _displayWidth) / 2;
      _displayY = (_videoMode.hardwareHeight - _displayHeight) / 2;
}

void OpenGLGraphicsManager::getGLPixelFormat(Graphics::PixelFormat pixelFormat, byte &bpp, GLenum &intFormat, GLenum &glFormat, GLenum &gltype) {
      if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { // RGBA8888
            bpp = 4;
            intFormat = GL_RGBA;
            glFormat = GL_RGBA;
            gltype = GL_UNSIGNED_BYTE;
      } else if (pixelFormat == Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) { // RGB888
            bpp = 3;
            intFormat = GL_RGB;
            glFormat = GL_RGB;
            gltype = GL_UNSIGNED_BYTE;
      } else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { // RGB565
            bpp = 2;
            intFormat = GL_RGB;
            glFormat = GL_RGB;
            gltype = GL_UNSIGNED_SHORT_5_6_5;
      } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { // RGB5551
            bpp = 2;
            intFormat = GL_RGBA;
            glFormat = GL_RGBA;
            gltype = GL_UNSIGNED_SHORT_5_5_5_1;
      } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) { // RGB555
            bpp = 2;
            intFormat = GL_RGB;
            glFormat = GL_BGRA;
            gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
      } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { // RGBA4444
            bpp = 2;
            intFormat = GL_RGBA;
            glFormat = GL_RGBA;
            gltype = GL_UNSIGNED_SHORT_4_4_4_4;
      } else if (pixelFormat.bytesPerPixel == 1) { // CLUT8
            // If uses a palette, create texture as RGB888. The pixel data will be converted
            // later.
            bpp = 3;
            intFormat = GL_RGB;
            glFormat = GL_RGB;
            gltype = GL_UNSIGNED_BYTE;
#ifndef USE_GLES
      } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)) { // ARGB8888
            bpp = 4;
            intFormat = GL_RGBA;
            glFormat = GL_BGRA;
            gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
      } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12)) { // ARGB4444
            bpp = 2;
            intFormat = GL_RGBA;
            glFormat = GL_BGRA;
            gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV;
      } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)) { // ABGR8888
            bpp = 4;
            intFormat = GL_RGBA;
            glFormat = GL_RGBA;
            gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
      } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0)) { // BGRA8888
            bpp = 4;
            intFormat = GL_RGBA;
            glFormat = GL_BGRA;
            gltype = GL_UNSIGNED_BYTE;
      } else if (pixelFormat == Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0)) { // BGR888
            bpp = 3;
            intFormat = GL_RGB;
            glFormat = GL_BGR;
            gltype = GL_UNSIGNED_BYTE;
      } else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0)) { // BGR565
            bpp = 2;
            intFormat = GL_RGB;
            glFormat = GL_BGR;
            gltype = GL_UNSIGNED_SHORT_5_6_5;
      } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0)) { // BGRA5551
            bpp = 2;
            intFormat = GL_RGBA;
            glFormat = GL_BGRA;
            gltype = GL_UNSIGNED_SHORT_5_5_5_1;
      } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12)) { // ABGR4444
            bpp = 2;
            intFormat = GL_RGBA;
            glFormat = GL_RGBA;
            gltype = GL_UNSIGNED_SHORT_4_4_4_4_REV;
      } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0)) { // BGRA4444
            bpp = 2;
            intFormat = GL_RGBA;
            glFormat = GL_BGRA;
            gltype = GL_UNSIGNED_SHORT_4_4_4_4;
#endif
      } else {
            error("OpenGLGraphicsManager: Pixel format not supported");
      }
}

void OpenGLGraphicsManager::internUpdateScreen() {
      // Clear the screen buffer
      glClear(GL_COLOR_BUFFER_BIT); CHECK_GL_ERROR();

      if (_screenNeedsRedraw || !_screenDirtyRect.isEmpty())
            // Refresh texture if dirty
            refreshGameScreen();

      int scaleFactor = _videoMode.hardwareHeight / _videoMode.screenHeight;

      glPushMatrix();

      // Adjust game screen shake position
      glTranslatef(0, _shakePos * scaleFactor, 0); CHECK_GL_ERROR();

      // Draw the game screen
      _gameTexture->drawTexture(_displayX, _displayY, _displayWidth, _displayHeight);

      glPopMatrix();

      if (_overlayVisible) {
            if (_overlayNeedsRedraw || !_overlayDirtyRect.isEmpty())
                  // Refresh texture if dirty
                  refreshOverlay();

            // Draw the overlay
            _overlayTexture->drawTexture(0, 0, _videoMode.overlayWidth, _videoMode.overlayHeight);
      }

      if (_cursorVisible) {
            if (_cursorNeedsRedraw)
                  // Refresh texture if dirty
                  refreshCursor();

            glPushMatrix();

            // Adjust mouse shake position, unless the overlay is visible
            glTranslatef(0, _overlayVisible ? 0 : _shakePos * scaleFactor, 0); CHECK_GL_ERROR();

            // Draw the cursor
            if (_overlayVisible)
                  _cursorTexture->drawTexture(_cursorState.x - _cursorState.rHotX,
                        _cursorState.y - _cursorState.rHotY, _cursorState.rW, _cursorState.rH);
            else
                  _cursorTexture->drawTexture(_cursorState.x - _cursorState.vHotX,
                        _cursorState.y - _cursorState.vHotY, _cursorState.vW, _cursorState.vH);

            glPopMatrix();
      }

#ifdef USE_OSD
      if (_osdAlpha > 0) {
            if (_requireOSDUpdate) {
                  updateOSD();
                  _requireOSDUpdate = false;
            }

            // Update alpha value
            const int diff = g_system->getMillis() - _osdFadeStartTime;
            if (diff > 0) {
                  if (diff >= kOSDFadeOutDuration) {
                        // Back to full transparency
                        _osdAlpha = 0;
                  } else {
                        // Do a fade out
                        _osdAlpha = kOSDInitialAlpha - diff * kOSDInitialAlpha / kOSDFadeOutDuration;
                  }
            }
            // Set the osd transparency
            glColor4f(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f); CHECK_GL_ERROR();

            // Draw the osd texture
            _osdTexture->drawTexture(0, 0, _videoMode.hardwareWidth, _videoMode.hardwareHeight);

            // Reset color
            glColor4f(1.0f, 1.0f, 1.0f, 1.0f); CHECK_GL_ERROR();
      }
#endif
}

void OpenGLGraphicsManager::initGL() {
      // Check available GL Extensions
      GLTexture::initGLExtensions();

      // Disable 3D properties
      glDisable(GL_CULL_FACE); CHECK_GL_ERROR();
      glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR();
      glDisable(GL_LIGHTING); CHECK_GL_ERROR();
      glDisable(GL_FOG); CHECK_GL_ERROR();
      glDisable(GL_DITHER); CHECK_GL_ERROR();
      glShadeModel(GL_FLAT); CHECK_GL_ERROR();
      glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); CHECK_GL_ERROR();

      // Setup alpha blend (For overlay and cursor)
      glEnable(GL_BLEND); CHECK_GL_ERROR();
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CHECK_GL_ERROR();

      // Enable rendering with vertex and coord arrays
      glEnableClientState(GL_VERTEX_ARRAY); CHECK_GL_ERROR();
      glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_GL_ERROR();

      glEnable(GL_TEXTURE_2D); CHECK_GL_ERROR();

      // Setup the GL viewport
      glViewport(0, 0, _videoMode.hardwareWidth, _videoMode.hardwareHeight); CHECK_GL_ERROR();

      // Setup coordinates system
      glMatrixMode(GL_PROJECTION); CHECK_GL_ERROR();
      glLoadIdentity(); CHECK_GL_ERROR();
#ifdef USE_GLES
      glOrthof(0, _videoMode.hardwareWidth, _videoMode.hardwareHeight, 0, -1, 1); CHECK_GL_ERROR();
#else
      glOrtho(0, _videoMode.hardwareWidth, _videoMode.hardwareHeight, 0, -1, 1); CHECK_GL_ERROR();
#endif
      glMatrixMode(GL_MODELVIEW); CHECK_GL_ERROR();
      glLoadIdentity(); CHECK_GL_ERROR();
}

void OpenGLGraphicsManager::loadTextures() {
#ifdef USE_RGB_COLOR
      if (_transactionDetails.formatChanged && _gameTexture) {
            delete _gameTexture;
            _gameTexture = 0;
      }
#endif

      uint gameScreenBPP = 0;

      if (!_gameTexture) {
            byte bpp;
            GLenum intformat;
            GLenum format;
            GLenum type;
#ifdef USE_RGB_COLOR
            getGLPixelFormat(_screenFormat, bpp, intformat, format, type);
#else
            getGLPixelFormat(Graphics::PixelFormat::createFormatCLUT8(), bpp, intformat, format, type);
#endif
            gameScreenBPP = bpp;
            _gameTexture = new GLTexture(bpp, intformat, format, type);
      } else
            _gameTexture->refresh();

      _overlayFormat = Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0);

      if (!_overlayTexture) {
            byte bpp;
            GLenum intformat;
            GLenum format;
            GLenum type;
            getGLPixelFormat(_overlayFormat, bpp, intformat, format, type);
            _overlayTexture = new GLTexture(bpp, intformat, format, type);
      } else
            _overlayTexture->refresh();

      if (!_cursorTexture)
            _cursorTexture = new GLTexture(4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
      else
            _cursorTexture->refresh();

      GLint filter = _videoMode.antialiasing ? GL_LINEAR : GL_NEAREST;
      _gameTexture->setFilter(filter);
      _overlayTexture->setFilter(filter);
      _cursorTexture->setFilter(filter);

      // Allocate texture memory and finish refreshing
      _gameTexture->allocBuffer(_videoMode.screenWidth, _videoMode.screenHeight);
      _overlayTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight);
      _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);

      if (
#ifdef USE_RGB_COLOR
                  _transactionDetails.formatChanged ||
#endif
                  _oldVideoMode.screenWidth != _videoMode.screenWidth ||
                  _oldVideoMode.screenHeight != _videoMode.screenHeight)
            _screenData.create(_videoMode.screenWidth, _videoMode.screenHeight,
#ifdef USE_RGB_COLOR
                  _screenFormat.bytesPerPixel
#else
                  1
#endif
                  );


      if (_oldVideoMode.overlayWidth != _videoMode.overlayWidth ||
            _oldVideoMode.overlayHeight != _videoMode.overlayHeight)
            _overlayData.create(_videoMode.overlayWidth, _videoMode.overlayHeight,
                  _overlayFormat.bytesPerPixel);

      _screenNeedsRedraw = true;
      _overlayNeedsRedraw = true;
      _cursorNeedsRedraw = true;

      // We need to setup a proper unpack alignment value here, else we will
      // get problems with the texture updates, in case the surface data is
      // not properly aligned.
      // For now we use the gcd of the game screen format and 2, since 2 is
      // the BPP value for the overlay and the OSD.
      if (gameScreenBPP)
            glPixelStorei(GL_UNPACK_ALIGNMENT, Common::gcd<uint>(gameScreenBPP, 2));

      // We use a "pack" alignment (when reading from textures) to 4 here,
      // since the only place where we really use it is the BMP screenshot
      // code and that requires the same alignment too.
      glPixelStorei(GL_PACK_ALIGNMENT, 4);

#ifdef USE_OSD
      if (!_osdTexture)
            _osdTexture = new GLTexture(2, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
      else
            _osdTexture->refresh();

      _osdTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight);

      // Update the OSD in case it is used right now
      _requireOSDUpdate = true;
#endif
}

bool OpenGLGraphicsManager::loadGFXMode() {
      // Initialize OpenGL settings
      initGL();

      loadTextures();

      refreshCursorScale();

      refreshDisplaySize();

      internUpdateScreen();

      return true;
}

void OpenGLGraphicsManager::unloadGFXMode() {

}

void OpenGLGraphicsManager::setScale(int newScale) {
      assert(_transactionMode == kTransactionActive);

      if (newScale == _videoMode.scaleFactor)
            return;

      _videoMode.scaleFactor = newScale;
      _transactionDetails.sizeChanged = true;
}

void OpenGLGraphicsManager::toggleAntialiasing() {
      assert(_transactionMode == kTransactionActive);

      _videoMode.antialiasing = !_videoMode.antialiasing;
      _transactionDetails.filterChanged = true;
}

uint OpenGLGraphicsManager::getAspectRatio() {
      // In case we enable aspect ratio correction we force a 4/3 ratio.
      // TODO: This makes OpenGL Normal behave like OpenGL Conserve, when aspect
      // ratio correction is enabled, but it's better than the previous 4/3 mode
      // mess at least...
      if (_videoMode.aspectRatioCorrection)
            return 13333;
      else if (_videoMode.mode == OpenGL::GFX_NORMAL)
            return _videoMode.hardwareWidth * 10000 / _videoMode.hardwareHeight;
      else
            return _videoMode.screenWidth * 10000 / _videoMode.screenHeight;
}

void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) {
      if (_overlayVisible)
            return;

      if (!_overlayVisible) {
            x -= _displayX;
            y -= _displayY;

            if (_displayWidth != _videoMode.screenWidth)
                  x = x * _videoMode.screenWidth / _displayWidth;
            if (_displayHeight != _videoMode.screenHeight)
                  y = y * _videoMode.screenHeight / _displayHeight;
      }
}

bool OpenGLGraphicsManager::notifyEvent(const Common::Event &event) {
      switch (event.type) {
      case Common::EVENT_MOUSEMOVE:
            if (!event.synthetic) {
                  _cursorState.x = event.mouse.x;
                  _cursorState.y = event.mouse.y;
            }
      case Common::EVENT_LBUTTONDOWN:
      case Common::EVENT_RBUTTONDOWN:
      case Common::EVENT_WHEELUP:
      case Common::EVENT_WHEELDOWN:
      case Common::EVENT_MBUTTONDOWN:
      case Common::EVENT_LBUTTONUP:
      case Common::EVENT_RBUTTONUP:
      case Common::EVENT_MBUTTONUP:
            if (!event.synthetic) {
                  Common::Event newEvent(event);
                  newEvent.synthetic = true;
                  adjustMousePosition(newEvent.mouse.x, newEvent.mouse.y);
                  g_system->getEventManager()->pushEvent(newEvent);
            }
            return !event.synthetic;

      default:
            break;
      }

      return false;
}

bool OpenGLGraphicsManager::saveScreenshot(const char *filename) {
      int width = _videoMode.hardwareWidth;
      int height = _videoMode.hardwareHeight;
      
      // A line of a BMP image must have a size divisible by 4.
      // We calculate the padding bytes needed here.
      // Since we use a 3 byte per pixel mode, we can use width % 4 here, since
      // it is equal to 4 - (width * 3) % 4. (4 - (width * Bpp) % 4, is the
      // usual way of computing the padding bytes required).
      const int linePaddingSize = width % 4;
      const int lineSize = width * 3 + linePaddingSize;

      // Allocate memory for screenshot
      uint8 *pixels = new uint8[lineSize * height];

      // Get pixel data from OpenGL buffer
#ifdef USE_GLES
      glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); CHECK_GL_ERROR();
#else
      if (_formatBGR) {
            glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, pixels); CHECK_GL_ERROR();
      } else {
            glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); CHECK_GL_ERROR();
      }
#endif

      // Open file
      Common::DumpFile out;
      out.open(filename);

      // Write BMP header
      out.writeByte('B');
      out.writeByte('M');
      out.writeUint32LE(height * lineSize + 54);
      out.writeUint32LE(0);
      out.writeUint32LE(54);
      out.writeUint32LE(40);
      out.writeUint32LE(width);
      out.writeUint32LE(height);
      out.writeUint16LE(1);
      out.writeUint16LE(24);
      out.writeUint32LE(0);
      out.writeUint32LE(0);
      out.writeUint32LE(0);
      out.writeUint32LE(0);
      out.writeUint32LE(0);
      out.writeUint32LE(0); 

      // Write pixel data to BMP
      out.write(pixels, lineSize * height);

      // Free allocated memory
      delete[] pixels;

      return true;
}

const char *OpenGLGraphicsManager::getCurrentModeName() {
      const char *modeName = 0;
      const OSystem::GraphicsMode *g = getSupportedGraphicsModes();
      while (g->name) {
            if (g->id == _videoMode.mode) {
                  modeName = g->description;
                  break;
            }
            g++;
      }
      return modeName;
}

#ifdef USE_OSD
void OpenGLGraphicsManager::updateOSD() {
      // The font we are going to use:
      const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont);

      if (_osdSurface.w != _osdTexture->getWidth() || _osdSurface.h != _osdTexture->getHeight())
            _osdSurface.create(_osdTexture->getWidth(), _osdTexture->getHeight(), 2);
      else
            // Clear everything
            memset(_osdSurface.pixels, 0, _osdSurface.h * _osdSurface.pitch);

      // Determine a rect which would contain the message string (clipped to the
      // screen dimensions).
      const int vOffset = 6;
      const int lineSpacing = 1;
      const int lineHeight = font->getFontHeight() + 2 * lineSpacing;
      int width = 0;
      int height = lineHeight * _osdLines.size() + 2 * vOffset;
      for (uint i = 0; i < _osdLines.size(); i++) {
            width = MAX(width, font->getStringWidth(_osdLines[i]) + 14);
      }

      // Clip the rect
      if (width > _osdSurface.w)
            width = _osdSurface.w;
      if (height > _osdSurface.h)
            height = _osdSurface.h;

      int dstX = (_osdSurface.w - width) / 2;
      int dstY = (_osdSurface.h - height) / 2;

      // Draw a dark gray rect
      const uint16 color = 0x294B;
      _osdSurface.fillRect(Common::Rect(dstX, dstY, dstX + width, dstY + height), color);

      // Render the message, centered, and in white
      for (uint i = 0; i < _osdLines.size(); i++) {
            font->drawString(&_osdSurface, _osdLines[i],
                             dstX, dstY + i * lineHeight + vOffset + lineSpacing, width,
                             0xFFFF, Graphics::kTextAlignCenter);
      }
 
      // Update the texture
      _osdTexture->updateBuffer(_osdSurface.pixels, _osdSurface.pitch, 0, 0, 
                                _osdSurface.w, _osdSurface.h);
}
#endif

#endif

Generated by  Doxygen 1.6.0   Back to index