Files
scummvm-cursorfix/engines/sci/graphics/drivers/win256col.cpp
2026-02-02 04:50:13 +01:00

260 lines
8.4 KiB
C++

/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "graphics/cursorman.h"
#include "sci/graphics/drivers/gfxdriver_intern.h"
namespace Sci {
class WindowsGfx256ColorsDriver final : public UpscaledGfxDriver {
public:
WindowsGfx256ColorsDriver(bool coloredDosStyleCursors, bool smallWindow, bool rgbRendering);
~WindowsGfx256ColorsDriver() override {}
void initScreen(const Graphics::PixelFormat *format) override;
void copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) override;
void replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) override;
Common::Point getRealCoords(Common::Point &pos) const override;
void setColorMap(const byte *colorMap) override { _colorMap = colorMap; }
void setFlags(uint32 flags) override;
void clearFlags(uint32 flags) override;
bool supportsHiResGraphics() const override { return !_smallWindow; }
bool driverBasedTextRendering() const override { return false; }
protected:
typedef void (*LineProc)(byte*&, const byte*, int, int, int);
LineProc _renderLine;
private:
typedef void (*LineProcSpec)(byte*&, const byte*, int, int, const byte*);
LineProcSpec _renderLine2;
void renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) override;
uint32 _flags;
const byte *_colorMap;
const bool _smallWindow;
const bool _dosStyleCursors;
uint16 _vScaleMult2;
};
WindowsGfx256ColorsDriver::WindowsGfx256ColorsDriver(bool coloredDosStyleCursors, bool smallWindow,bool rgbRendering) :
UpscaledGfxDriver(smallWindow ? 320 : 640, smallWindow ? 240 : 440, 1, coloredDosStyleCursors && !smallWindow, rgbRendering), _dosStyleCursors(coloredDosStyleCursors), _smallWindow(smallWindow),
_renderLine(nullptr), _renderLine2(nullptr), _flags(0), _colorMap(nullptr), _vScaleMult2(smallWindow ? 1 : 2) {
_virtualW = 320;
_virtualH = 200;
if (smallWindow)
_hScaleMult = 1;
_vScaleMult = _smallWindow ? 6 : 11;
_vScaleDiv = 5;
}
void largeWindowRenderLine(byte *&dst, const byte *src, int pitch, int w, int ty) {
int dstPitch = pitch;
int dstPitch2 = pitch - (w << 1);
byte *d1 = dst;
byte *d2 = d1 + dstPitch;
if (ty == 5) {
byte *d3 = d2 + dstPitch;
for (int i = 0; i < w; ++i) {
d1[0] = d1[1] = d2[0] = d2[1] = d3[0] = d3[1] = *src++;
d1 += 2;
d2 += 2;
d3 += 2;
}
dst = d3 + dstPitch2;
} else {
for (int i = 0; i < w; ++i) {
d1[0] = d1[1] = d2[0] = d2[1] = *src++;
d1 += 2;
d2 += 2;
}
dst = d2 + dstPitch2;
}
}
void largeWindowRenderLineMovie(byte *&dst, const byte *src, int pitch, int w, const byte*) {
int dstPitch = pitch;
int dstPitch2 = pitch - (w << 1);
byte *d1 = dst;
byte *d2 = d1 + dstPitch;
for (int i = 0; i < w; ++i) {
d1[0] = d1[1] = d2[0] = d2[1] = *src++;
d1 += 2;
d2 += 2;
}
dst = d2 + dstPitch2;
}
void smallWindowRenderLine(byte *&dst, const byte *src, int pitch, int w, int ty) {
int dstPitch = pitch;
int dstPitch2 = pitch - w;
byte *d1 = dst;
if (ty == 5) {
byte *d2 = d1 + dstPitch;
for (int i = 0; i < w; ++i)
*d1++ = *d2++ = *src++;
dst = d2 + dstPitch2;
} else {
for (int i = 0; i < w; ++i)
*d1++ = *src++;
dst = d1 + dstPitch2;
}
}
void smallWindowRenderLineMovie(byte *&dst, const byte *src, int pitch, int w, const byte*) {
int dstPitch = pitch - w;
byte *d1 = dst;
for (int i = 0; i < w; ++i)
*d1++ = *src++;
dst = d1 + dstPitch;
}
void hiresRenderLine(byte *&dst, const byte *src, int pitch, int w, const byte *colorMap) {
if (!colorMap) {
memcpy(dst, src, w);
} else {
byte *d = dst;
for (int i = 0; i < w; ++i)
*d++ = colorMap[*src++];
}
dst += pitch;
}
void renderLineDummy(byte *&, const byte* , int, int, const byte*) {
}
void WindowsGfx256ColorsDriver::initScreen(const Graphics::PixelFormat *format) {
UpscaledGfxDriver::initScreen(format);
_renderLine = _smallWindow ? &smallWindowRenderLine : &largeWindowRenderLine;
_renderLine2 = _smallWindow ? &renderLineDummy : &hiresRenderLine;
}
void WindowsGfx256ColorsDriver::copyRectToScreen(const byte *src, int srcX, int srcY, int pitch, int destX, int destY, int w, int h, const PaletteMod *palMods, const byte *palModMapping) {
GFXDRV_ASSERT_READY;
assert (h >= 0 && w >= 0);
if (!(_flags & (kHiResMode | kMovieMode))) {
UpscaledGfxDriver::copyRectToScreen(src, srcX, srcY, pitch, destX, destY, w, h, palMods, palModMapping);
return;
}
if (_flags & kMovieMode) {
destX = (_screenW >> 1) - (w & ~1) * _hScaleMult / 2;
destY = (_screenH >> 1) - (h & ~1) * _vScaleMult2 / 2;
}
src += (srcY * pitch + srcX * _srcPixelSize);
byte *dst = _scaledBitmap + destY * _screenW * _srcPixelSize + destX * _srcPixelSize;
for (int i = 0; i < h; ++i) {
_renderLine2(dst, src, _screenW, w, _colorMap);
src += pitch;
}
if (_flags & kMovieMode) {
w *= _hScaleMult;
h *= _vScaleMult2;
}
updateScreen(destX, destY, w, h, palMods, palModMapping);
}
void WindowsGfx256ColorsDriver::replaceCursor(const void *cursor, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor) {
GFXDRV_ASSERT_READY;
if (_dosStyleCursors) {
// The original windows interpreter always renders the cursor as b/w, regardless of which cursor views (the DOS
// cursors or the new Windows ones) the user selects. This is also regardless of color mode (16 or 256 colors).
// It is a technical limitation on Windows 95 with VGA hardware that mouse cursors have to be b/w.
// Instead, we use the colored DOS style cursors as a default, since there was consensus to do that.
UpscaledGfxDriver::replaceCursor(cursor, w, h, hotspotX, hotspotY, keycolor);
return;
}
adjustCursorBuffer(w << 1, h << 1);
if (_pixelSize == 1)
copyCurrentPalette(_currentPalette, 0, _numColors);
byte col1 = SciGfxDrvInternal::findColorInPalette(0x00000000, _currentPalette, _numColors);
byte col2 = SciGfxDrvInternal::findColorInPalette(0x00FFFFFF, _currentPalette, _numColors);
SciGfxDrvInternal::renderWinMonochromeCursor(_compositeBuffer, cursor, _currentPalette, w, h, hotspotX, hotspotY, col1, col2, keycolor, _smallWindow);
CursorMan.replaceCursor(_compositeBuffer, w, h, hotspotX, hotspotY, keycolor);
}
Common::Point WindowsGfx256ColorsDriver::getRealCoords(Common::Point &pos) const {
return Common::Point(pos.x * _hScaleMult, pos.y * _vScaleMult2 + (pos.y + 4) / 5);
}
void WindowsGfx256ColorsDriver::setFlags(uint32 flags) {
flags ^= (_flags & flags);
if (!flags)
return;
if (flags & kMovieMode)
_renderLine2 = _smallWindow ? &smallWindowRenderLineMovie : &largeWindowRenderLineMovie;
_flags |= flags;
}
void WindowsGfx256ColorsDriver::clearFlags(uint32 flags) {
flags &= _flags;
if (!flags)
return;
if (flags & kMovieMode)
_renderLine2 = _smallWindow ? &renderLineDummy : &hiresRenderLine;
_flags &= ~flags;
}
void WindowsGfx256ColorsDriver::renderBitmap(const byte *src, int pitch, int dx, int dy, int w, int h, int &realWidth, int &realHeight) {
assert(_renderLine);
byte *dst = _scaledBitmap + (dy * _vScaleMult2 + (dy + 4) / 5) * _screenW * _srcPixelSize + dx *_hScaleMult * _srcPixelSize;
const byte *dstart = dst;
dy = (dy + 4) % 5;
while (h--) {
_renderLine(dst, src, _screenW, w, ++dy);
dy %= 5;
src += pitch;
}
realWidth = w * _hScaleMult;
realHeight = (dst - dstart) / _screenW;
}
GfxDriver *WindowsGfx256ColorsDriver_create(int rgbRendering, ...) {
va_list args;
va_start(args, rgbRendering);
int config = va_arg(args, int);
va_arg(args, int);
va_arg(args, int);
va_arg(args, int);
bool winCursors = (va_arg(args, int) != 0);
va_end(args);
return new WindowsGfx256ColorsDriver(!winCursors, config == 0, rgbRendering != 0);
}
} // End of namespace Sci