aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/sdl/graphics.cpp429
-rw-r--r--backends/sdl/sdl-common.h23
-rw-r--r--backends/sdl/sdl.cpp14
-rw-r--r--common/scaler.cpp40
-rw-r--r--common/scaler.h1
-rw-r--r--common/system.h39
-rw-r--r--scumm/cursor.cpp3
-rw-r--r--scumm/resource_v7he.cpp14
8 files changed, 355 insertions, 208 deletions
diff --git a/backends/sdl/graphics.cpp b/backends/sdl/graphics.cpp
index daa9906594..1687befdcd 100644
--- a/backends/sdl/graphics.cpp
+++ b/backends/sdl/graphics.cpp
@@ -42,6 +42,16 @@ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
{0, 0, 0}
};
+// Table of relative scalers magnitudes
+// [definedScale-1][_scaleFactor-1]
+static ScalerProc *scalersMagn[3][3] = {
+ { Normal1x, AdvMame2x, AdvMame3x },
+ { Normal1x, Normal1x, Normal1o5x },
+ { Normal1x, Normal1x, Normal1x }
+};
+
+static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY);
+
const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
return s_supportedGraphicsModes;
}
@@ -367,6 +377,9 @@ void OSystem_SDL::hotswapGFXMode() {
SDL_FreeSurface(old_screen);
SDL_FreeSurface(old_tmpscreen);
+ // Update cursor to new scale
+ blitCursor();
+
// Blit everything to the screen
internUpdateScreen();
@@ -399,9 +412,6 @@ void OSystem_SDL::internUpdateScreen() {
_forceFull = true;
}
- // Make sure the mouse is drawn, if it should be drawn.
- drawMouse();
-
// Check whether the palette was changed in the meantime and update the
// screen surface accordingly.
if (_paletteDirtyEnd != 0) {
@@ -434,6 +444,8 @@ void OSystem_SDL::internUpdateScreen() {
}
#endif
+ undrawMouse();
+
// Force a full redraw if requested
if (_forceFull) {
_numDirtyRects = 1;
@@ -522,14 +534,20 @@ void OSystem_SDL::internUpdateScreen() {
_dirtyRectList[0].h = effectiveScreenHeight();
}
+ drawMouse();
+
#ifdef USE_OSD
if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0);
}
#endif
-
+
// Finally, blit all our changes to the screen
SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
+ } else {
+ drawMouse();
+ if (_numDirtyRects)
+ SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
}
_numDirtyRects = 0;
@@ -562,8 +580,6 @@ void OSystem_SDL::setFullscreenMode(bool enable) {
assert(_hwscreen != 0);
_fullscreen ^= true;
- undrawMouse();
-
#if defined(MACOSX) && !SDL_VERSION_ATLEAST(1, 2, 6)
// On OS X, SDL_WM_ToggleFullScreen is currently not implemented. Worse,
// before SDL 1.2.6 it always returned -1 (which would indicate a
@@ -672,9 +688,6 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int
addDirtyRect(x, y, w, h);
}
- /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */
- undrawMouse();
-
// Try to lock the screen surface
if (SDL_LockSurface(_screen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
@@ -696,10 +709,19 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int
}
-void OSystem_SDL::addDirtyRect(int x, int y, int w, int h) {
+void OSystem_SDL::addDirtyRect(int x, int y, int w, int h, bool mouseRect) {
if (_forceFull)
return;
+ if (mouseRect) {
+ SDL_Rect *r = &_dirtyRectList[_numDirtyRects++];
+ r->x = x;
+ r->y = y;
+ r->w = w;
+ r->h = h;
+ return;
+ }
+
if (_numDirtyRects == NUM_DIRTY_RECT)
_forceFull = true;
else {
@@ -846,6 +868,27 @@ void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) {
if (start + num > _paletteDirtyEnd)
_paletteDirtyEnd = start + num;
+
+ // Some games blink cursors with palette
+ if (!_overlayVisible && !_cursorHasOwnPalette)
+ blitCursor();
+}
+
+void OSystem_SDL::setCursorPalette(const byte *colors, uint start, uint num) {
+ const byte *b = colors;
+ uint i;
+ SDL_Color *base = _cursorPalette + start;
+ for (i = 0; i < num; i++) {
+ base[i].r = b[0];
+ base[i].g = b[1];
+ base[i].b = b[2];
+ b += 4;
+ }
+
+ _cursorHasOwnPalette = true;
+
+ if (!_overlayVisible)
+ blitCursor();
}
void OSystem_SDL::setShakePos(int shake_pos) {
@@ -862,9 +905,6 @@ void OSystem_SDL::setShakePos(int shake_pos) {
void OSystem_SDL::showOverlay() {
assert (_transactionMode == kTransactionNone);
- // hide the mouse
- undrawMouse();
-
_overlayVisible = true;
clearOverlay();
}
@@ -872,9 +912,6 @@ void OSystem_SDL::showOverlay() {
void OSystem_SDL::hideOverlay() {
assert (_transactionMode == kTransactionNone);
- // hide the mouse
- undrawMouse();
-
_overlayVisible = false;
_forceFull = true;
}
@@ -887,9 +924,6 @@ void OSystem_SDL::clearOverlay() {
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
- // hide the mouse
- undrawMouse();
-
// Clear the overlay by making the game screen "look through" everywhere.
SDL_Rect src, dst;
src.x = src.y = 0;
@@ -911,9 +945,6 @@ void OSystem_SDL::grabOverlay(OverlayColor *buf, int pitch) {
if (_tmpscreen == NULL)
return;
- // hide the mouse
- undrawMouse();
-
if (SDL_LockSurface(_tmpscreen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
@@ -964,9 +995,6 @@ void OSystem_SDL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, i
_cksumValid = false;
addDirtyRect(x, y, w, h);
- /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */
- undrawMouse();
-
if (SDL_LockSurface(_tmpscreen) == -1)
error("SDL_LockSurface failed: %s", SDL_GetError());
@@ -1000,17 +1028,13 @@ bool OSystem_SDL::showMouse(bool visible) {
bool last = _mouseVisible;
_mouseVisible = visible;
- if (visible)
- drawMouse();
- else
- undrawMouse();
+ updateScreen();
return last;
}
void OSystem_SDL::setMousePos(int x, int y) {
if (x != _mouseCurState.x || y != _mouseCurState.y) {
- undrawMouse();
_mouseCurState.x = x;
_mouseCurState.y = y;
updateScreen();
@@ -1032,187 +1056,236 @@ void OSystem_SDL::warpMouse(int x, int y) {
}
}
-void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor) {
-
- undrawMouse();
-
- assert(w <= MAX_MOUSE_W);
- assert(h <= MAX_MOUSE_H);
- _mouseCurState.w = w;
- _mouseCurState.h = h;
-
+void OSystem_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) {
_mouseHotspotX = hotspot_x;
_mouseHotspotY = hotspot_y;
_mouseKeyColor = keycolor;
+ _cursorTargetScale = cursorTargetScale;
+
+ if (_mouseCurState.w != (int)w || _mouseCurState.h != (int)h) {
+ _mouseCurState.w = w;
+ _mouseCurState.h = h;
+
+ if (_mouseOrigSurface)
+ SDL_FreeSurface(_mouseOrigSurface);
+
+ // Allocate bigger surface because AdvMame2x adds black pixel at [0,0]
+ _mouseOrigSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _mouseCurState.w + 2,
+ _mouseCurState.h + 2,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_mouseOrigSurface == NULL)
+ error("allocating _mouseOrigSurface failed");
+ SDL_SetColorKey(_mouseOrigSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
+ }
+
free(_mouseData);
_mouseData = (byte *)malloc(w * h);
memcpy(_mouseData, buf, w * h);
+ blitCursor();
}
-void OSystem_SDL::toggleMouseGrab() {
- if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
- SDL_WM_GrabInput(SDL_GRAB_ON);
- else
- SDL_WM_GrabInput(SDL_GRAB_OFF);
-}
-
-void OSystem_SDL::drawMouse() {
- if (_mouseDrawn || !_mouseVisible || !_mouseData)
- return;
-
- int x = _mouseCurState.x - _mouseHotspotX;
- int y = _mouseCurState.y - _mouseHotspotY;
- int w = _mouseCurState.w;
- int h = _mouseCurState.h;
+void OSystem_SDL::blitCursor() {
+ byte *dstPtr;
+ const byte *srcPtr = _mouseData;
byte color;
- const byte *src = _mouseData; // Image representing the mouse
-
- // clip the mouse rect, and addjust the src pointer accordingly
- if (x < 0) {
- w += x;
- src -= x;
- x = 0;
- }
- if (y < 0) {
- h += y;
- src -= y * _mouseCurState.w;
- y = 0;
+ int w, h;
+
+ if (!_mouseOrigSurface)
+ return;
+
+ w = _mouseCurState.w;
+ h = _mouseCurState.h;
+
+ SDL_LockSurface(_mouseOrigSurface);
+
+ // Make whole surface transparent
+ for (int i = 0; i < h + 2; i++) {
+ dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch * i;
+ for (int j = 0; j < w + 2; j++) {
+ *(uint16 *)dstPtr = kMouseColorKey;
+ dstPtr += 2;
+ }
}
- if (w > _screenWidth - x)
- w = _screenWidth - x;
- if (h > _screenHeight - y)
- h = _screenHeight - y;
-
- // Quick check to see if anything has to be drawn at all
- if (w <= 0 || h <= 0)
- return;
-
- // Draw the mouse cursor; backup the covered area in "bak"
- if (SDL_LockSurface(_overlayVisible ? _tmpscreen : _screen) == -1)
- error("SDL_LockSurface failed: %s", SDL_GetError());
-
- // Mark as dirty
- addDirtyRect(x, y, w, h);
-
- if (!_overlayVisible) {
- byte *bak = _mouseBackup; // Surface used to backup the area obscured by the mouse
- byte *dst; // Surface we are drawing into
-
- dst = (byte *)_screen->pixels + y * _screenWidth + x;
- while (h > 0) {
- int width = w;
- while (width > 0) {
- *bak++ = *dst;
- color = *src++;
- if (color != _mouseKeyColor) // transparent, don't draw
- *dst = color;
- dst++;
- width--;
+ // Draw from [1,1] since AdvMame2x adds artefact at 0,0
+ dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2;
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ color = *srcPtr;
+ if (color != _mouseKeyColor) { // transparent, don't draw
+ if (_cursorHasOwnPalette && !_overlayVisible)
+ *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format,
+ _cursorPalette[color].r, _cursorPalette[color].g,
+ _cursorPalette[color].b);
+ else
+ *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format,
+ _currentPalette[color].r, _currentPalette[color].g,
+ _currentPalette[color].b);
}
- src += _mouseCurState.w - w;
- bak += MAX_MOUSE_W - w;
- dst += _screenWidth - w;
- h--;
+ dstPtr += 2;
+ srcPtr++;
}
-
- } else {
- uint16 *bak = (uint16 *)_mouseBackup; // Surface used to backup the area obscured by the mouse
- byte *dst; // Surface we are drawing into
-
- dst = (byte *)_tmpscreen->pixels + (y + 1) * _tmpscreen->pitch + (x + 1) * 2;
- while (h > 0) {
- int width = w;
- while (width > 0) {
- *bak++ = *(uint16 *)dst;
- color = *src++;
- if (color != 0xFF) // 0xFF = transparent, don't draw
- *(uint16 *)dst = RGBToColor(_currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b);
- dst += 2;
- width--;
- }
- src += _mouseCurState.w - w;
- bak += MAX_MOUSE_W - w;
- dst += _tmpscreen->pitch - w * 2;
- h--;
- }
- }
+ dstPtr += _mouseOrigSurface->pitch - w * 2;
+ }
- SDL_UnlockSurface(_overlayVisible ? _tmpscreen : _screen);
+ int hW, hH, hH1;
- // Finally, set the flag to indicate the mouse has been drawn
- _mouseDrawn = true;
+ if (_cursorTargetScale >= _scaleFactor) {
+ hW = w;
+ hH = hH1 = h;
+ } else {
+ hW = w * _scaleFactor / _cursorTargetScale;
+ hH = hH1 = h * _scaleFactor / _cursorTargetScale;
+ }
+
+ if (_adjustAspectRatio) {
+ hH = real2Aspect(hH - 1) + 1;
+ }
+
+ if (_mouseCurState.hW != hW || _mouseCurState.hH != hH) {
+ _mouseCurState.hW = hW;
+ _mouseCurState.hH = hH;
+
+ if (_mouseSurface)
+ SDL_FreeSurface(_mouseSurface);
+
+ _mouseSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _mouseCurState.hW,
+ _mouseCurState.hH,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_mouseSurface == NULL)
+ error("allocating _mouseSurface failed");
+
+ SDL_SetColorKey(_mouseSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
+ }
+
+ SDL_LockSurface(_mouseSurface);
+ (scalersMagn[_cursorTargetScale-1][_scaleFactor-1])((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2,
+ _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch,
+ _mouseCurState.w, _mouseCurState.h);
+
+ if (_adjustAspectRatio)
+ cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, hW, hH1, 0, 0, 0);
+
+ SDL_UnlockSurface(_mouseSurface);
+ SDL_UnlockSurface(_mouseOrigSurface);
}
-void OSystem_SDL::undrawMouse() {
- assert (_transactionMode == kTransactionNone || _transactionMode == kTransactionCommit);
+// Basically it is kVeryFastAndUglyAspectMode of stretch200To240 from
+// common/scale/aspect.cpp
+static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) {
+ int maxDstY = real2Aspect(origSrcY + height - 1);
+ int y;
+ const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch;
+ uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch;
+
+ for (y = maxDstY; y >= srcY; y--) {
+ const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch;
+
+ if (srcPtr == dstPtr)
+ break;
+ memcpy(dstPtr, srcPtr, width * 2);
+ dstPtr -= pitch;
+ }
- if (!_mouseDrawn)
- return;
- _mouseDrawn = false;
+ return 1 + maxDstY - srcY;
+}
- int old_mouse_x = _mouseCurState.x - _mouseHotspotX;
- int old_mouse_y = _mouseCurState.y - _mouseHotspotY;
- int old_mouse_w = _mouseCurState.w;
- int old_mouse_h = _mouseCurState.h;
+void OSystem_SDL::toggleMouseGrab() {
+ if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ else
+ SDL_WM_GrabInput(SDL_GRAB_OFF);
+}
- // clip the mouse rect, and addjust the src pointer accordingly
- if (old_mouse_x < 0) {
- old_mouse_w += old_mouse_x;
- old_mouse_x = 0;
- }
- if (old_mouse_y < 0) {
- old_mouse_h += old_mouse_y;
- old_mouse_y = 0;
+void OSystem_SDL::undrawMouse() {
+ if (_mouseBackup.w) {
+ if (_adjustAspectRatio)
+ addDirtyRect(_mouseBackup.x, aspect2Real(_mouseBackup.y), _mouseBackup.w,
+ _mouseBackup.h);
+ else
+ addDirtyRect(_mouseBackup.x, _mouseBackup.y, _mouseBackup.w,
+ _mouseBackup.h);
}
+}
- if (old_mouse_w > _screenWidth - old_mouse_x)
- old_mouse_w = _screenWidth - old_mouse_x;
- if (old_mouse_h > _screenHeight - old_mouse_y)
- old_mouse_h = _screenHeight - old_mouse_y;
-
- // Quick check to see if anything has to be drawn at all
- if (old_mouse_w <= 0 || old_mouse_h <= 0)
- return;
+void OSystem_SDL::drawMouse() {
+ if (!_mouseVisible) {
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
+ return;
+ }
+
+ SDL_Rect src, dst;
+ bool scale;
- if (SDL_LockSurface(_overlayVisible ? _tmpscreen : _screen) == -1)
- error("SDL_LockSurface failed: %s", SDL_GetError());
+ scale = (_scaleFactor > _cursorTargetScale);
- int x, y;
- if (!_overlayVisible) {
- byte *dst, *bak = _mouseBackup;
+ dst.x = _mouseCurState.x - _mouseHotspotX / _cursorTargetScale;
+ dst.y = _mouseCurState.y - _mouseHotspotY / _cursorTargetScale;
- // No need to do clipping here, since drawMouse() did that already
- dst = (byte *)_screen->pixels + old_mouse_y * _screenWidth + old_mouse_x;
- for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _screenWidth) {
- for (x = 0; x < old_mouse_w; ++x) {
- dst[x] = bak[x];
- }
- }
-
- } else {
+ dst.w = _mouseCurState.hW;
+ dst.h = _mouseCurState.hH;
+ src.x = src.y = 0;
- byte *dst;
- uint16 *bak = (uint16 *)_mouseBackup;
-
- // No need to do clipping here, since drawMouse() did that already
- dst = (byte *)_tmpscreen->pixels + (old_mouse_y + 1) * _tmpscreen->pitch + (old_mouse_x + 1) * 2;
- for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _tmpscreen->pitch) {
- for (x = 0; x < old_mouse_w; ++x) {
- *((uint16 *)dst + x) = bak[x];
- }
- }
+ // clip the mouse rect, and adjust the src pointer accordingly
+ int dx, dy;
+
+ dx = dst.x; dy = dst.y;
+ dx = scale ? dst.x * _scaleFactor / _cursorTargetScale : dst.x;
+ dy = scale ? dst.y * _scaleFactor / _cursorTargetScale : dst.y;
+ if (_adjustAspectRatio)
+ dy = real2Aspect(dy);
+
+ if (dst.x < 0) {
+ dst.w += dx;
+ src.x -= dx;
+ dst.x = 0;
+ }
+ if (dst.y < 0) {
+ dst.h += dy;
+ src.y -= dy;
+ dst.y = 0;
}
- addDirtyRect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);
-
- SDL_UnlockSurface(_overlayVisible ? _tmpscreen : _screen);
+ // Quick check to see if anything has to be drawn at all
+ if (dst.w <= 0 || dst.h <= 0)
+ return;
+
+ src.w = dst.w;
+ src.h = dst.h;
+
+ if (_adjustAspectRatio)
+ dst.y = real2Aspect(dst.y);
+
+ _mouseBackup.x = dst.x;
+ _mouseBackup.y = dst.y;
+ _mouseBackup.w = dst.w;
+ _mouseBackup.h = dst.h;
+
+ dst.x *= _scaleFactor;
+ dst.y *= _scaleFactor;
+
+ if (SDL_BlitSurface(_mouseSurface, &src, _hwscreen, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+
+ addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
}
-
#pragma mark -
#pragma mark --- Mouse ---
#pragma mark -
diff --git a/backends/sdl/sdl-common.h b/backends/sdl/sdl-common.h
index e060f3a6b4..7296131b1e 100644
--- a/backends/sdl/sdl-common.h
+++ b/backends/sdl/sdl-common.h
@@ -82,7 +82,10 @@ public:
virtual void warpMouse(int x, int y); // overloaded by CE backend
// Set the bitmap that's used when drawing the cursor.
- void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor);
+ void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale);
+
+ // Set colors of cursor palette
+ void setCursorPalette(const byte *colors, uint start, uint num);
// Shaking is used in SCUMM. Set current shake position.
void setShakePos(int shake_pos);
@@ -258,7 +261,8 @@ protected:
};
struct MousePos {
- int16 x, y, w, h;
+ int16 x, y, w, h, hW, hH;
+ MousePos() : x(0), y(0), w(0), h(0), hW(0), hH(0) {}
};
// mouse
@@ -266,11 +270,18 @@ protected:
bool _mouseVisible;
bool _mouseDrawn;
byte *_mouseData;
- byte *_mouseBackup;
+ SDL_Rect _mouseBackup;
MousePos _mouseCurState;
int16 _mouseHotspotX;
int16 _mouseHotspotY;
byte _mouseKeyColor;
+ int _cursorTargetScale;
+ bool _cursorHasOwnPalette;
+ SDL_Surface *_mouseOrigSurface;
+ SDL_Surface *_mouseSurface;
+ enum {
+ kMouseColorKey = 1
+ };
// joystick
SDL_Joystick *_joystick;
@@ -283,6 +294,9 @@ protected:
SDL_Color *_currentPalette;
uint _paletteDirtyStart, _paletteDirtyEnd;
+ // Cursor palette data
+ SDL_Color *_cursorPalette;
+
/**
* Mutex which prevents multiple threads from interfering with each other
* when accessing the screen.
@@ -293,10 +307,11 @@ protected:
void addDirtyRgnAuto(const byte *buf);
void makeChecksums(const byte *buf);
- virtual void addDirtyRect(int x, int y, int w, int h); // overloaded by CE backend
+ virtual void addDirtyRect(int x, int y, int w, int h, bool mouseRect = false); // overloaded by CE backend
virtual void drawMouse(); // overloaded by CE backend
virtual void undrawMouse(); // overloaded by CE backend
+ void blitCursor();
/** Set the position of the virtual mouse cursor. */
void setMousePos(int x, int y);
diff --git a/backends/sdl/sdl.cpp b/backends/sdl/sdl.cpp
index ece356e13c..0ed0568dd2 100644
--- a/backends/sdl/sdl.cpp
+++ b/backends/sdl/sdl.cpp
@@ -100,8 +100,9 @@ OSystem_SDL::OSystem_SDL()
_tmpscreen(0), _overlayVisible(false),
_samplesPerSec(0),
_cdrom(0), _scalerProc(0), _modeChanged(false), _dirtyChecksums(0),
- _mouseVisible(false), _mouseDrawn(false), _mouseData(0),
- _mouseHotspotX(0), _mouseHotspotY(0),
+ _mouseVisible(false), _mouseDrawn(false), _mouseData(0), _mouseSurface(0),
+ _mouseOrigSurface(0), _mouseHotspotX(0), _mouseHotspotY(0), _cursorTargetScale(1),
+ _cursorHasOwnPalette(false),
_joystick(0),
_currentShakePos(0), _newShakePos(0),
_paletteDirtyStart(0), _paletteDirtyEnd(0),
@@ -109,9 +110,9 @@ OSystem_SDL::OSystem_SDL()
// allocate palette storage
_currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
+ _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
- // allocate the dirty rect storage
- _mouseBackup = (byte *)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING * 2);
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
// reset mouse state
memset(&_km, 0, sizeof(_km));
@@ -123,7 +124,7 @@ OSystem_SDL::OSystem_SDL()
OSystem_SDL::~OSystem_SDL() {
free(_dirtyChecksums);
free(_currentPalette);
- free(_mouseBackup);
+ free(_cursorPalette);
free(_mouseData);
}
@@ -147,7 +148,8 @@ bool OSystem_SDL::hasFeature(Feature f) {
return
(f == kFeatureFullscreenMode) ||
(f == kFeatureAspectRatioCorrection) ||
- (f == kFeatureAutoComputeDirtyRects);
+ (f == kFeatureAutoComputeDirtyRects) ||
+ (f == kFeatureCursorHasPalette);
}
void OSystem_SDL::setFeatureState(Feature f, bool enable) {
diff --git a/common/scaler.cpp b/common/scaler.cpp
index 701afbda90..30de3a7ae6 100644
--- a/common/scaler.cpp
+++ b/common/scaler.cpp
@@ -169,6 +169,46 @@ void Normal3x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPit
}
}
+#define INTERPOLATE INTERPOLATE<bitFormat>
+#define Q_INTERPOLATE Q_INTERPOLATE<bitFormat>
+
+/**
+ * Trivial nearest-neighbour 1.5x scaler.
+ */
+template<int bitFormat>
+void Normal1o5xTemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch,
+ int width, int height) {
+ uint8 *r;
+ const uint32 dstPitch2 = dstPitch * 2;
+ const uint32 dstPitch3 = dstPitch * 3;
+ const uint32 srcPitch2 = srcPitch * 2;
+
+ assert(((int)dstPtr & 1) == 0);
+ while (height) {
+ r = dstPtr;
+ for (int i = 0; i < width; i += 2, r += 6) {
+ uint16 color0 = *(((const uint16 *)srcPtr) + i);
+ uint16 color1 = *(((const uint16 *)srcPtr) + i + 1);
+ uint16 color2 = *(((const uint16 *)(srcPtr + srcPitch)) + i);
+ uint16 color3 = *(((const uint16 *)(srcPtr + srcPitch)) + i + 1);
+
+ *(uint16 *)(r + 0) = color0;
+ *(uint16 *)(r + 2) = INTERPOLATE(color0, color1);
+ *(uint16 *)(r + 4) = color1;
+ *(uint16 *)(r + 0 + dstPitch) = INTERPOLATE(color0, color2);
+ *(uint16 *)(r + 2 + dstPitch) = Q_INTERPOLATE(color0, color1, color2, color3);
+ *(uint16 *)(r + 4 + dstPitch) = INTERPOLATE(color1, color3);
+ *(uint16 *)(r + 0 + dstPitch2) = color2;
+ *(uint16 *)(r + 2 + dstPitch2) = INTERPOLATE(color2, color3);
+ *(uint16 *)(r + 4 + dstPitch2) = color3;
+ }
+ srcPtr += srcPitch2;
+ dstPtr += dstPitch3;
+ height -= 2;
+ }
+}
+MAKE_WRAPPER(Normal1o5x)
+
/**
* The Scale2x filter, also known as AdvMame2x.
* See also http://scale2x.sourceforge.net
diff --git a/common/scaler.h b/common/scaler.h
index e77b8aedc5..c582e71f79 100644
--- a/common/scaler.h
+++ b/common/scaler.h
@@ -41,6 +41,7 @@ DECLARE_SCALER(AdvMame3x);
DECLARE_SCALER(Normal1x);
DECLARE_SCALER(Normal2x);
DECLARE_SCALER(Normal3x);
+DECLARE_SCALER(Normal1o5x);
DECLARE_SCALER(TV2x);
DECLARE_SCALER(DotMatrix);
DECLARE_SCALER(HQ2x);
diff --git a/common/system.h b/common/system.h
index 7d3a0ea8f7..fad4e6c841 100644
--- a/common/system.h
+++ b/common/system.h
@@ -96,7 +96,15 @@ public:
* Implementing this is purely optional, and no harm should arise
* when not doing so (except for decreased speed in said frontends).
*/
- kFeatureAutoComputeDirtyRects
+ kFeatureAutoComputeDirtyRects,
+
+ /**
+ * This flags determines either cursor can have its own palette or not
+ * It is currently used only by some Macintosh versions of Humongous
+ * Entertainment games. If backend doesn't implement this feature then
+ * engine switches to b/w version of cursors.
+ */
+ kFeatureCursorHasPalette
};
/**
@@ -274,6 +282,18 @@ public:
virtual void setPalette(const byte *colors, uint start, uint num) = 0;
/**
+ * Replace the specified range of cursor the palette with new colors.
+ * The palette entries from 'start' till (start+num-1) will be replaced - so
+ * a full palette update is accomplished via start=0, num=256.
+ *
+ * Backends which implement it should have kFeatureCursorHasPalette flag set
+ *
+ * @see setPalette
+ * @see kFeatureCursorHasPalette
+ */
+ virtual void setCursorPalette(const byte *colors, uint start, uint num) {};
+
+ /**
* Blit a bitmap to the virtual screen.
* The real screen will not immediately be updated to reflect the changes.
* Client code has to to call updateScreen to ensure any changes are
@@ -365,14 +385,15 @@ public:
/**
* Set the bitmap used for drawing the cursor.
*
- * @param buf the pixmap data to be used (8bit/pixel)
- * @param w width of the mouse cursor
- * @param h height of the mouse cursor
- * @param hotspotX horizontal offset from the left side to the hotspot
- * @param hotspotY vertical offset from the top side to the hotspot
- * @param keycolor transparency color index
- */
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255) = 0;
+ * @param buf the pixmap data to be used (8bit/pixel)
+ * @param w width of the mouse cursor
+ * @param h height of the mouse cursor
+ * @param hotspotX horizontal offset from the left side to the hotspot
+ * @param hotspotY vertical offset from the top side to the hotspot
+ * @param keycolor transparency color index
+ * @param cursorTargetScale scale factor which cursor is designed for
+ */
+ virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255, int cursorTargetScale = 1) = 0;
//@}
diff --git a/scumm/cursor.cpp b/scumm/cursor.cpp
index bfb5ddc6c2..3d032098ef 100644
--- a/scumm/cursor.cpp
+++ b/scumm/cursor.cpp
@@ -107,7 +107,8 @@ void ScummEngine_v6::setCursorTransparency(int a) {
void ScummEngine::updateCursor() {
_system->setMouseCursor(_grabbedCursor, _cursor.width, _cursor.height,
- _cursor.hotspotX, _cursor.hotspotY);
+ _cursor.hotspotX, _cursor.hotspotY, 255,
+ (_heversion == 70 ? 2 : 1));
}
void ScummEngine_v6::grabCursor(int x, int y, int w, int h) {
diff --git a/scumm/resource_v7he.cpp b/scumm/resource_v7he.cpp
index ab2b2c078c..29f7770529 100644
--- a/scumm/resource_v7he.cpp
+++ b/scumm/resource_v7he.cpp
@@ -1532,10 +1532,9 @@ void MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int
*hotspot_x = dis.readUint16BE();
*w = *h = 16;
- // FIXME
- // Color cursors use their own palette.
- // So we can't use it for now and use B/W version
- return;
+ // Use b/w cursor on backends which don't support cursor palettes
+ if (!_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette))
+ return;
dis.readUint32BE(); // reserved
dis.readUint32BE(); // cursorID
@@ -1600,12 +1599,7 @@ void MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int
palette[c * 4 + 3] = 0;
}
- // TODO: Here we should set separate cursor palette.
- // It requires cursor to be rendered on a different surface at
- // least in SDL backend.
- // HACK: now set global palett just to see if colors are correct.
- // this affects subtitles colors
- _vm->_system->setPalette(palette, 0, ctSize);
+ _vm->_system->setCursorPalette(palette, 0, ctSize);
numBytes =
(iconBounds[2] - iconBounds[0]) *