aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/platform/sdl/graphics.cpp244
-rw-r--r--backends/platform/sdl/sdl.cpp3
-rw-r--r--backends/platform/sdl/sdl.h32
-rw-r--r--base/main.cpp3
-rw-r--r--common/system.h55
5 files changed, 232 insertions, 105 deletions
diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp
index 2872c71f44..142fa94dba 100644
--- a/backends/platform/sdl/graphics.cpp
+++ b/backends/platform/sdl/graphics.cpp
@@ -97,6 +97,9 @@ void OSystem_SDL::beginGFXTransaction(void) {
_transactionDetails.needUpdatescreen = false;
_transactionDetails.normal1xScaler = false;
+#ifdef ENABLE_16BIT
+ _transactionDetails.formatChanged = false;
+#endif
_oldVideoMode = _videoMode;
}
@@ -127,6 +130,12 @@ OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) {
_videoMode.screenHeight = _oldVideoMode.screenHeight;
_videoMode.overlayWidth = _oldVideoMode.overlayWidth;
_videoMode.overlayHeight = _oldVideoMode.overlayHeight;
+#ifdef ENABLE_16BIT
+ } else if (_videoMode.format != _oldVideoMode.format) {
+ errors |= kTransactionPixelFormatNotSupported;
+
+ _videoMode.format = _oldVideoMode.format;
+#endif
}
if (_videoMode.fullscreen == _oldVideoMode.fullscreen &&
@@ -143,6 +152,32 @@ OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) {
}
}
+#ifdef ENABLE_16BIT
+ if (_transactionDetails.formatChanged) {
+ _screenFormat = getPixelFormat(_videoMode.format);
+ if (!_transactionDetails.sizeChanged) {
+ unloadGFXMode();
+ if (!loadGFXMode()) {
+ if (_oldVideoMode.setup) {
+ _transactionMode = kTransactionRollback;
+ errors |= endGFXTransaction();
+ }
+ } else {
+ setGraphicsModeIntern();
+ clearOverlay();
+
+ _videoMode.setup = true;
+ _modeChanged = true;
+ // OSystem_SDL::pollEvent used to update the screen change count,
+ // but actually it gives problems when a video mode was changed
+ // but OSystem_SDL::pollEvent was not called. This for example
+ // caused a crash under certain circumstances when doing an RTL.
+ // To fix this issue we update the screen change count right here.
+ _screenChangeCount++;
+ }
+ }
+ }
+#endif
if (_transactionDetails.sizeChanged) {
unloadGFXMode();
if (!loadGFXMode()) {
@@ -186,7 +221,7 @@ OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) {
} else if (_transactionDetails.needUpdatescreen) {
setGraphicsModeIntern();
internUpdateScreen();
- }
+ }
_transactionMode = kTransactionNone;
return (TransactionError)errors;
@@ -339,6 +374,102 @@ int OSystem_SDL::getGraphicsMode() const {
assert (_transactionMode == kTransactionNone);
return _videoMode.mode;
}
+#ifdef ENABLE_16BIT
+Graphics::ColorFormat OSystem_SDL::findCompatibleFormat(Common::List<Graphics::ColorFormat> formatList)
+{
+ bool typeAccepted = false;
+ Graphics::ColorFormat format;
+
+ while (!formatList.empty() && !typeAccepted)
+ {
+ typeAccepted = false;
+ format = formatList.front();
+
+ //no need to keep searching if the screen
+ //is already in one of the desired formats
+ if (format == _videoMode.format)
+ return format;
+
+ formatList.pop_front();
+ switch (format & Graphics::kFormatTypeMask)
+ {
+ case Graphics::kFormat8Bit:
+ if (format == Graphics::kFormat8Bit)
+ return format;
+ break;
+ case Graphics::kFormatRGB555:
+ case Graphics::kFormatARGB1555:
+ case Graphics::kFormatRGB565:
+ typeAccepted = true;
+ break;
+ }
+
+ if (!typeAccepted)
+ continue;
+
+ switch (format & Graphics::kFormatOrderMask) {
+ case Graphics::kFormatRGB:
+ case Graphics::kFormatRGBA:
+ return format;
+ default:
+ break;
+ }
+ }
+ return Graphics::kFormat8Bit;
+}
+
+void OSystem_SDL::initFormat(Graphics::ColorFormat format) {
+ assert(_transactionMode == kTransactionActive);
+
+ //avoid redundant format changes
+ if (format == _videoMode.format)
+ return;
+
+ _videoMode.format = format;
+ _transactionDetails.formatChanged = true;
+
+}
+
+//This should only ever be called with a format that is known supported.
+Graphics::PixelFormat OSystem_SDL::getPixelFormat(Graphics::ColorFormat format) {
+ Graphics::PixelFormat result;
+ switch (format & Graphics::kFormatTypeMask) {
+ case Graphics::kFormatARGB1555:
+ result.aLoss = 7;
+ result.bytesPerPixel = 2;
+ result.rLoss = result.gLoss = result.bLoss = 3;
+ case Graphics::kFormatRGB555:
+ result.aLoss = 8;
+ result.bytesPerPixel = 2;
+ result.rLoss = result.gLoss = result.bLoss = 3;
+ break;
+ case Graphics::kFormatRGB565:
+ result.bytesPerPixel = 2;
+ result.aLoss = 8;
+ result.gLoss = 2;
+ result.rLoss = result.bLoss = 3;
+ break;
+ case Graphics::kFormat8Bit:
+ default:
+ result.bytesPerPixel = 1;
+ result.rShift = result.gShift = result.bShift = result.aShift = 0;
+ result.rLoss = result.gLoss = result.bLoss = result.aLoss = 8;
+ return result;
+ }
+ switch (format & Graphics::kFormatOrderMask)
+ {
+ default:
+ case Graphics::kFormatRGBA:
+ result.aShift = 0;
+ case Graphics::kFormatRGB:
+ result.bShift = result.aBits();
+ result.gShift = result.bShift + result.bBits();
+ result.rShift = result.gShift + result.gBits();
+ break;
+ }
+ return result;
+}
+#endif
void OSystem_SDL::initSize(uint w, uint h) {
assert(_transactionMode == kTransactionActive);
@@ -384,9 +515,21 @@ bool OSystem_SDL::loadGFXMode() {
//
// Create the surface that contains the 8 bit game data
//
+#ifdef ENABLE_16BIT
+ _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight,
+ _screenFormat.bytesPerPixel << 3,
+ ((1 << _screenFormat.rBits()) - 1) << _screenFormat.rShift ,
+ ((1 << _screenFormat.gBits()) - 1) << _screenFormat.gShift ,
+ ((1 << _screenFormat.bBits()) - 1) << _screenFormat.bShift ,
+ ((1 << _screenFormat.aBits()) - 1) << _screenFormat.aShift );
+ if (_screen == NULL)
+ error("allocating _screen failed");
+
+#else
_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0);
if (_screen == NULL)
error("allocating _screen failed");
+#endif
//
// Create the surface that contains the scaled graphics in 16 bit mode
@@ -407,20 +550,6 @@ bool OSystem_SDL::loadGFXMode() {
}
}
-#ifdef ENABLE_16BIT
- //
- // Create the surface that contains the 16 bit game data
- //
- _screen16 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight,
- 16,
- 0x7C00,
- 0x3E0,
- 0x1F,
- 0); //555, not 565
- if (_screen16 == NULL)
- error("allocating _screen16 failed");
-#endif
-
//
// Create the surface used for the graphics in 16 bit before scaling, and also the overlay
//
@@ -498,17 +627,10 @@ bool OSystem_SDL::loadGFXMode() {
}
void OSystem_SDL::unloadGFXMode() {
-#ifdef ENABLE_16BIT
- if (_screen16) {
- SDL_FreeSurface(_screen16);
- _screen16 = NULL;
- }
-#else
if (_screen) {
SDL_FreeSurface(_screen);
_screen = NULL;
}
-#endif
if (_hwscreen) {
SDL_FreeSurface(_hwscreen);
@@ -540,22 +662,13 @@ void OSystem_SDL::unloadGFXMode() {
}
bool OSystem_SDL::hotswapGFXMode() {
-#ifdef ENABLE_16BIT
- if (!_screen16)
-#else
if (!_screen)
-#endif
return false;
// Keep around the old _screen & _overlayscreen so we can restore the screen data
// after the mode switch.
-#ifdef ENABLE_16BIT
- SDL_Surface *old_screen = _screen16;
- _screen16 = NULL;
-#else
SDL_Surface *old_screen = _screen;
_screen = NULL;
-#endif
SDL_Surface *old_overlayscreen = _overlayscreen;
_overlayscreen = NULL;
@@ -574,11 +687,7 @@ bool OSystem_SDL::hotswapGFXMode() {
if (!loadGFXMode()) {
unloadGFXMode();
-#ifdef ENABLE_16BIT
- _screen16 = old_screen;
-#else
_screen = old_screen;
-#endif
_overlayscreen = old_overlayscreen;
return false;
@@ -588,11 +697,7 @@ bool OSystem_SDL::hotswapGFXMode() {
SDL_SetColors(_screen, _currentPalette, 0, 256);
// Restore old screen content
-#ifdef ENABLE_16BIT
- SDL_BlitSurface(old_screen, NULL, _screen16, NULL);
-#else
SDL_BlitSurface(old_screen, NULL, _screen, NULL);
-#endif
SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
// Free the old surfaces
@@ -674,11 +779,7 @@ void OSystem_SDL::internUpdateScreen() {
#endif
if (!_overlayVisible) {
-#ifdef ENABLE_16BIT
- origSurf = _screen16;
-#else
origSurf = _screen;
-#endif
srcSurf = _tmpscreen;
width = _videoMode.screenWidth;
height = _videoMode.screenHeight;
@@ -823,12 +924,6 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int
assert (_transactionMode == kTransactionNone);
assert(src);
-#ifdef ENABLE_16BIT
- if (_screen16 == NULL) {
- warning("OSystem_SDL::copyRectToScreen: _screen16 == NULL");
- return;
- }
-#endif
if (_screen == NULL) {
warning("OSystem_SDL::copyRectToScreen: _screen == NULL");
return;
@@ -877,27 +972,20 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int
}
// Try to lock the screen surface
-#ifdef ENABLE_16BIT
- if (SDL_LockSurface(_screen16) == -1)
-#else
if (SDL_LockSurface(_screen) == -1)
-#endif
error("SDL_LockSurface failed: %s", SDL_GetError());
#ifdef ENABLE_16BIT
- byte *dst = (byte *)_screen16->pixels + y * _videoMode.screenWidth * 2 + x * 2;
- if (_videoMode.screenWidth == w && pitch == w * 2) {
- memcpy(dst, src, h*w*2);
+ byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth * _screenFormat.bytesPerPixel + x * _screenFormat.bytesPerPixel;
+ if (_videoMode.screenWidth == w && pitch == w * _screenFormat.bytesPerPixel) {
+ memcpy(dst, src, h*w*_screenFormat.bytesPerPixel);
} else {
do {
- memcpy(dst, src, w * 2);
+ memcpy(dst, src, w * _screenFormat.bytesPerPixel);
src += pitch;
- dst += _videoMode.screenWidth * 2;
+ dst += _videoMode.screenWidth * _screenFormat.bytesPerPixel;
} while (--h);
}
-
- // Unlock the screen surface
- SDL_UnlockSurface(_screen16);
#else
byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
if (_videoMode.screenWidth == pitch && pitch == w) {
@@ -909,10 +997,10 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int
dst += _videoMode.screenWidth;
} while (--h);
}
+#endif
// Unlock the screen surface
SDL_UnlockSurface(_screen);
-#endif
}
Graphics::Surface *OSystem_SDL::lockScreen() {
@@ -926,24 +1014,16 @@ Graphics::Surface *OSystem_SDL::lockScreen() {
_screenIsLocked = true;
// Try to lock the screen surface
-#ifdef ENABLE_16BIT
- if (SDL_LockSurface(_screen16) == -1)
-#else
if (SDL_LockSurface(_screen) == -1)
-#endif
error("SDL_LockSurface failed: %s", SDL_GetError());
-#ifdef ENABLE_16BIT
- _framebuffer.pixels = _screen16->pixels;
- _framebuffer.w = _screen16->w;
- _framebuffer.h = _screen16->h;
- _framebuffer.pitch = _screen16->pitch;
- _framebuffer.bytesPerPixel = 2;
-#else
_framebuffer.pixels = _screen->pixels;
_framebuffer.w = _screen->w;
_framebuffer.h = _screen->h;
_framebuffer.pitch = _screen->pitch;
+#ifdef ENABLE_16BIT
+ _framebuffer.bytesPerPixel = _screenFormat.bytesPerPixel;
+#else
_framebuffer.bytesPerPixel = 1;
#endif
@@ -958,11 +1038,7 @@ void OSystem_SDL::unlockScreen() {
_screenIsLocked = false;
// Unlock the screen surface
-#ifdef ENABLE_16BIT
- SDL_UnlockSurface(_screen16);
-#else
SDL_UnlockSurface(_screen);
-#endif
// Trigger a full screen update
_forceFull = true;
@@ -1133,17 +1209,17 @@ int16 OSystem_SDL::getWidth() {
void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) {
assert(colors);
+#ifdef ENABLE_16BIT
+ if (_screenFormat.bytesPerPixel > 1)
+ return; //not using a paletted pixel format
+#endif
+
// Setting the palette before _screen is created is allowed - for now -
// since we don't actually set the palette until the screen is updated.
// But it could indicate a programming error, so let's warn about it.
-#ifdef ENABLE_16BIT
- if (!_screen16)
- warning("OSystem_SDL::setPalette: _screen16 == NULL");
-#else
if (!_screen)
warning("OSystem_SDL::setPalette: _screen == NULL");
-#endif
const byte *b = colors;
uint i;
@@ -1267,11 +1343,7 @@ void OSystem_SDL::clearOverlay() {
dst.x = dst.y = 1;
src.w = dst.w = _videoMode.screenWidth;
src.h = dst.h = _videoMode.screenHeight;
-#ifdef ENABLE_16BIT
- if (SDL_BlitSurface(_screen16, &src, _tmpscreen, &dst) != 0)
-#else
if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0)
-#endif
error("SDL_BlitSurface failed: %s", SDL_GetError());
SDL_LockSurface(_tmpscreen);
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index 3e8cefc86a..3ec4da1196 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -197,7 +197,8 @@ OSystem_SDL::OSystem_SDL()
#endif
_hwscreen(0), _screen(0), _tmpscreen(0),
#ifdef ENABLE_16BIT
- _screen16(0), _cursorBitDepth(8),
+ _screenFormat(getPixelFormat(Graphics::kFormat8Bit)),
+ _cursorBitDepth(8),
#endif
_overlayVisible(false),
_overlayscreen(0), _tmpscreen2(0),
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 22d3d41b00..513ad73934 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -81,6 +81,22 @@ public:
void beginGFXTransaction(void);
TransactionError endGFXTransaction(void);
+#ifdef ENABLE_16BIT
+ // Find a compatible format from the list of formats supported by the engine
+ // Fallback to CLUT8 if none found
+ virtual Graphics::ColorFormat findCompatibleFormat(Common::List<Graphics::ColorFormat> formatList);
+
+ // Set the depth and format of the video bitmap
+ // Typically, CLUT8
+ virtual void initFormat(Graphics::ColorFormat format);
+
+ // Game screen
+ virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; }
+
+ //Create a Graphics::PixelFormat to describe the requested color mode
+ virtual Graphics::PixelFormat getPixelFormat(Graphics::ColorFormat format);
+#endif
+
// Set the size of the video bitmap.
// Typically, 320x200
virtual void initSize(uint w, uint h); // overloaded by CE backend
@@ -179,11 +195,6 @@ public:
// Overlay
virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
-#ifdef ENABLE_16BIT
- // Game screen
- virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; }
-#endif
-
virtual void showOverlay();
virtual void hideOverlay();
virtual void clearOverlay();
@@ -239,11 +250,6 @@ protected:
SDL_Surface *_screen;
#ifdef ENABLE_16BIT
Graphics::PixelFormat _screenFormat;
-
- //HACK This is a temporary hack to get 16-bit graphics
- //displaying quickly, which will be removed in favor of
- //configuring the format of _screen on a per-game basis
- SDL_Surface *_screen16;
#endif
// temporary screen (for scalers)
@@ -278,6 +284,9 @@ protected:
bool needHotswap;
bool needUpdatescreen;
bool normal1xScaler;
+#ifdef ENABLE_16BIT
+ bool formatChanged;
+#endif
};
TransactionDetails _transactionDetails;
@@ -292,6 +301,9 @@ protected:
int screenWidth, screenHeight;
int overlayWidth, overlayHeight;
+#ifdef ENABLE_16BIT
+ Graphics::ColorFormat format;
+#endif
};
VideoState _videoMode, _oldVideoMode;
diff --git a/base/main.cpp b/base/main.cpp
index dba4aeccaa..d76d8828a1 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -226,6 +226,9 @@ static void setupGraphics(OSystem &system) {
// Set the user specified graphics mode (if any).
system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
+#ifdef ENABLE_16BIT
+ system.initFormat(Graphics::kFormat8Bit);
+#endif
system.initSize(320, 200);
if (ConfMan.hasKey("aspect_ratio"))
diff --git a/common/system.h b/common/system.h
index 50d00bb8e2..59da28c990 100644
--- a/common/system.h
+++ b/common/system.h
@@ -343,6 +343,53 @@ public:
*/
virtual int getGraphicsMode() const = 0;
+#ifdef ENABLE_16BIT
+ /**
+ * Find a supported color format from a list of requested formats. Typical formats include:
+ * CLUT8 (e.g. 256 color, for most games), all backends must provide support for this format
+ * RGB555 (e.g. 16-bit color, for later SCUMM HE games)
+ * RGB565 (e.g. 16-bit color, for Urban Runner)
+ *
+ * These are the pixel formats for which the client code can generates data;
+ * they are not necessarily equal to the hardware pixel format. For example,
+ * a backend may perform color lookup of 8-bit graphics before pushing the
+ * screen buffer to hardware, or perform transformations of the ARGB color order.
+ *
+ * @param formatList A list of requested pixel formats, ordered by priority
+ *
+ * @return a supported ColorFormat from the list, or kFormat8Bit if no supported format was found
+ */
+ virtual Graphics::ColorFormat findCompatibleFormat(Common::List<Graphics::ColorFormat> formatList) = 0;
+
+ /**
+ * Set the color format of the virtual screen. Typical formats include:
+ * CLUT8 (e.g. 256 color, for most games)
+ * RGB555 (e.g. 16-bit color, for later SCUMM HE games)
+ * RGB565 (e.g. 16-bit color, for Urban Runner)
+ *
+ * This is the pixel format for which the client code generates data;
+ * this is not necessarily equal to the hardware pixel format. For example,
+ * a backend may perform color lookup of 8-bit graphics before pushing
+ * a screen to hardware, or correct the ARGB color order.
+ *
+ * @param format A pixel format that the backend screen will use
+ */
+ virtual void initFormat(Graphics::ColorFormat format) = 0;
+
+ /**
+ * Returns the pixel format description of the screen.
+ * @see Graphics::PixelFormat
+ */
+ virtual Graphics::PixelFormat getScreenFormat() const = 0;
+
+ /**
+ * Returns the pixel format description of the requested color mode
+ * @see Graphics::PixelFormat
+ */
+ virtual Graphics::PixelFormat getPixelFormat(Graphics::ColorFormat format) = 0;
+
+#endif
+
/**
* Set the size of the virtual screen. Typical sizes include:
* - 320x200 (e.g. for most SCUMM games, and Simon)
@@ -608,14 +655,6 @@ public:
*/
virtual Graphics::PixelFormat getOverlayFormat() const = 0;
-#ifdef ENABLE_16BIT
- /**
- * Returns the pixel format description of the game screen.
- * @see Graphics::PixelFormat
- */
- virtual Graphics::PixelFormat getScreenFormat() const = 0;
-#endif
-
/**
* Reset the overlay.
*