diff options
author | Martin Kiewitz | 2016-02-06 23:41:20 +0100 |
---|---|---|
committer | Martin Kiewitz | 2016-02-06 23:41:20 +0100 |
commit | 209907d01ea2ddfb2ec4bdc252bbd010ed67171d (patch) | |
tree | 9168a8a07ee2b660aba233df3ec65b6908a7b8c9 /engines | |
parent | 1b7ed6a7cc42bdaca0b21ff97ca3fd1307e182c5 (diff) | |
download | scummvm-rg350-209907d01ea2ddfb2ec4bdc252bbd010ed67171d.tar.gz scummvm-rg350-209907d01ea2ddfb2ec4bdc252bbd010ed67171d.tar.bz2 scummvm-rg350-209907d01ea2ddfb2ec4bdc252bbd010ed67171d.zip |
SCI: Screen pixel optimizations
Put things like putPixel() into screen.h, so that it can be inlined.
Also don't use look up tables for those methods anymore and instead
calculate offsets manually, because that should be faster.
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/graphics/screen.cpp | 255 | ||||
-rw-r--r-- | engines/sci/graphics/screen.h | 310 |
2 files changed, 297 insertions, 268 deletions
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index e77c74bb2a..c977a93817 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -214,36 +214,6 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { error("Unknown SCI1.1 Mac game"); } else initGraphics(_displayWidth, _displayHeight, _displayWidth > 320); - - // Initialize code pointers - _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinateNOP; - _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinatesNOP; - _vectorIsFillMatchPtr = &GfxScreen::vectorIsFillMatchNormal; - _vectorPutPixelPtr = &GfxScreen::putPixelNormal; - _vectorPutLinePixelPtr = &GfxScreen::putPixel; - _vectorGetPixelPtr = &GfxScreen::getPixelNormal; - _putPixelPtr = &GfxScreen::putPixelNormal; - _getPixelPtr = &GfxScreen::getPixelNormal; - - switch (_upscaledHires) { - case GFX_SCREEN_UPSCALED_480x300: - _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinate480x300Mac; - _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinates480x300Mac; - // vectorPutPixel -> we already adjust coordinates for vector code, that's why we can set pixels directly - // vectorGetPixel -> see vectorPutPixel - _vectorPutLinePixelPtr = &GfxScreen::vectorPutLinePixel480x300Mac; - _putPixelPtr = &GfxScreen::putPixelAllUpscaled; - _getPixelPtr = &GfxScreen::getPixelUpscaled; - break; - case GFX_SCREEN_UPSCALED_640x400: - case GFX_SCREEN_UPSCALED_640x440: - case GFX_SCREEN_UPSCALED_640x480: - _vectorPutPixelPtr = &GfxScreen::putPixelDisplayUpscaled; - _putPixelPtr = &GfxScreen::putPixelDisplayUpscaled; - break; - case GFX_SCREEN_UPSCALED_DISABLED: - break; - } } GfxScreen::~GfxScreen() { @@ -334,40 +304,68 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) { return flag; } -void GfxScreen::vectorAdjustCoordinateNOP(int16 *x, int16 *y) { +void GfxScreen::vectorAdjustLineCoordinates(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: { + int16 displayLeft = (*left * 3) / 2; + int16 displayRight = (*right * 3) / 2; + int16 displayTop = (*top * 3) / 2; + int16 displayBottom = (*bottom * 3) / 2; + + if (displayLeft < displayRight) { + // one more pixel to the left, one more pixel to the right + if (displayLeft > 0) + vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control); + vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control); + } else if (displayLeft > displayRight) { + if (displayRight > 0) + vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control); + vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control); + } + *left = displayLeft; + *top = displayTop; + *right = displayRight; + *bottom = displayBottom; + break; + } + default: + break; + } } -void GfxScreen::vectorAdjustCoordinate480x300Mac(int16 *x, int16 *y) { - *x = _upscaledWidthMapping[*x]; - *y = _upscaledHeightMapping[*y]; +// This is called from vector drawing to put a pixel at a certain location +void GfxScreen::vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + if (_upscaledHires == GFX_SCREEN_UPSCALED_480x300) { + vectorPutLinePixel480x300(x, y, drawMask, color, priority, control); + return; + } + + // For anything else forward to the regular putPixel + putPixel(x, y, drawMask, color, priority, control); } -void GfxScreen::vectorAdjustLineCoordinatesNOP(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { +// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one +void GfxScreen::vectorPutLinePixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + // also set pixel below actual pixel + _visualScreen[offset] = color; + _visualScreen[offset + _width] = color; + _displayScreen[offset] = color; + _displayScreen[offset + _displayWidth] = color; + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + _priorityScreen[offset + _width] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + _controlScreen[offset + _width] = control; + } } -void GfxScreen::vectorAdjustLineCoordinates480x300Mac(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { - int16 displayLeft = _upscaledWidthMapping[*left]; - int16 displayRight = _upscaledWidthMapping[*right]; - int16 displayTop = _upscaledHeightMapping[*top]; - int16 displayBottom = _upscaledHeightMapping[*bottom]; - - if (displayLeft < displayRight) { - // one more pixel to the left, one more pixel to the right - if (displayLeft > 0) - vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control); - vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control); - } else if (displayLeft > displayRight) { - if (displayRight > 0) - vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control); - vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control); - } - *left = displayLeft; - *top = displayTop; - *right = displayRight; - *bottom = displayBottom; -} - -byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) { +byte GfxScreen::vectorIsFillMatch(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) { int offset = y * _width + x; byte match = 0; @@ -397,132 +395,6 @@ byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte return match; } -// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one -void GfxScreen::vectorPutLinePixel480x300Mac(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - _visualScreen[offset + _width] = color; - _displayScreen[offset] = color; - // also set pixel below actual pixel - _displayScreen[offset + _displayWidth] = color; - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) { - _priorityScreen[offset] = priority; - _priorityScreen[offset + _width] = priority; - } - if (drawMask & GFX_SCREEN_MASK_CONTROL) { - _controlScreen[offset] = control; - _controlScreen[offset + _width] = control; - } -} - -// Directly sets a pixel on various screens, display is not upscaled -void GfxScreen::putPixelNormal(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - _displayScreen[offset] = color; - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) - _priorityScreen[offset] = priority; - if (drawMask & GFX_SCREEN_MASK_CONTROL) - _controlScreen[offset] = control; -} - -// Directly sets a pixel on various screens, display IS upscaled -void GfxScreen::putPixelDisplayUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - putScaledPixelOnScreen(_displayScreen, x, y, color); - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) - _priorityScreen[offset] = priority; - if (drawMask & GFX_SCREEN_MASK_CONTROL) - _controlScreen[offset] = control; -} - -// Directly sets a pixel on various screens, ALL screens ARE upscaled -void GfxScreen::putPixelAllUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - putScaledPixelOnScreen(_visualScreen, x, y, color); - putScaledPixelOnScreen(_displayScreen, x, y, color); - } - if (drawMask & GFX_SCREEN_MASK_PRIORITY) - putScaledPixelOnScreen(_priorityScreen, x, y, priority); - if (drawMask & GFX_SCREEN_MASK_CONTROL) - putScaledPixelOnScreen(_controlScreen, x, y, control); -} - -/** - * This is used to put font pixels onto the screen - we adjust differently, so that we won't - * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted - * Sierra SCI didn't do this - */ -void GfxScreen::putFontPixel(int16 startingY, int16 x, int16 y, byte color) { - int16 actualY = startingY + y; - if (_fontIsUpscaled) { - // Do not scale ourselves, but put it on the display directly - putPixelOnDisplay(x, actualY, color); - } else { - int offset = actualY * _width + x; - - _visualScreen[offset] = color; - switch (_upscaledHires) { - case GFX_SCREEN_UPSCALED_DISABLED: - _displayScreen[offset] = color; - break; - case GFX_SCREEN_UPSCALED_640x400: - case GFX_SCREEN_UPSCALED_640x440: - case GFX_SCREEN_UPSCALED_640x480: { - // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird - int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2; - _displayScreen[displayOffset] = color; - _displayScreen[displayOffset + 1] = color; - displayOffset += _displayWidth; - _displayScreen[displayOffset] = color; - _displayScreen[displayOffset + 1] = color; - break; - } - default: - putScaledPixelOnScreen(_displayScreen, x, actualY, color); - break; - } - } -} - -/** - * This will just change a pixel directly on displayscreen. It is supposed to be - * only used on upscaled-Hires games where hires content needs to get drawn ONTO - * the upscaled display screen (like japanese fonts, hires portraits, etc.). - */ -void GfxScreen::putPixelOnDisplay(int16 x, int16 y, byte color) { - int offset = y * _displayWidth + x; - _displayScreen[offset] = color; -} - -//void GfxScreen::putScaledPixelOnDisplay(int16 x, int16 y, byte color) { -//} - -void GfxScreen::putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte data) { - int displayOffset = _upscaledHeightMapping[y] * _displayWidth + _upscaledWidthMapping[x]; - int heightOffsetBreak = (_upscaledHeightMapping[y + 1] - _upscaledHeightMapping[y]) * _displayWidth; - int heightOffset = 0; - int widthOffsetBreak = _upscaledWidthMapping[x + 1] - _upscaledWidthMapping[x]; - do { - int widthOffset = 0; - do { - screen[displayOffset + heightOffset + widthOffset] = data; - widthOffset++; - } while (widthOffset != widthOffsetBreak); - heightOffset += _displayWidth; - } while (heightOffset != heightOffsetBreak); -} - /** * Sierra's Bresenham line drawing. * WARNING: Do not replace this with Graphics::drawLine(), as this causes issues @@ -604,16 +476,6 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1); } -byte GfxScreen::getPixelNormal(byte *screen, int16 x, int16 y) { - return screen[y * _width + x]; -} - -byte GfxScreen::getPixelUpscaled(byte *screen, int16 x, int16 y) { - int16 mappedX = _upscaledWidthMapping[x]; - int16 mappedY = _upscaledHeightMapping[y]; - return screen[mappedY * _width + mappedX]; -} - int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) { int byteCount = sizeof(rect) + sizeof(mask); int pixels = rect.width() * rect.height(); @@ -638,7 +500,6 @@ int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) { error("bitsGetDataSize() called w/o being in upscaled hires mode"); byteCount += pixels; // _displayScreen (coordinates actually are given to us for hires displayScreen) } - return byteCount; } @@ -805,7 +666,7 @@ void GfxScreen::dither(bool addToFlag) { *displayPtr = color; break; default: - putScaledPixelOnScreen(_displayScreen, x, y, color); + putScaledPixelOnDisplay(x, y, color); break; } *visualPtr = color; @@ -837,7 +698,7 @@ void GfxScreen::dither(bool addToFlag) { *displayPtr = ditheredColor; break; default: - putScaledPixelOnScreen(_displayScreen, x, y, ditheredColor); + putScaledPixelOnDisplay(x, y, ditheredColor); break; } color = ((x^y) & 1) ? color >> 4 : color & 0x0F; diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h index 1c946ef02f..49c63d4681 100644 --- a/engines/sci/graphics/screen.h +++ b/engines/sci/graphics/screen.h @@ -84,51 +84,16 @@ public: void copyDisplayRectToScreen(const Common::Rect &rect); void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y); - // calls to code pointers - void inline vectorAdjustCoordinate (int16 *x, int16 *y) { - (this->*_vectorAdjustCoordinatePtr)(x, y); - } - void inline vectorAdjustLineCoordinates (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { - (this->*_vectorAdjustLineCoordinatesPtr)(left, top, right, bottom, drawMask, color, priority, control); - } - byte inline vectorIsFillMatch (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) { - return (this->*_vectorIsFillMatchPtr)(x, y, screenMask, t_color, t_pri, t_con, isEGA); - } - void inline vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - (this->*_vectorPutPixelPtr)(x, y, drawMask, color, priority, control); - } - void inline vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - (this->*_vectorPutLinePixelPtr)(x, y, drawMask, color, priority, control); - } - byte inline vectorGetVisual(int16 x, int16 y) { - return (this->*_vectorGetPixelPtr)(_visualScreen, x, y); - } - byte inline vectorGetPriority(int16 x, int16 y) { - return (this->*_vectorGetPixelPtr)(_priorityScreen, x, y); - } - byte inline vectorGetControl(int16 x, int16 y) { - return (this->*_vectorGetPixelPtr)(_controlScreen, x, y); - } - - - void inline putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { - (this->*_putPixelPtr)(x, y, drawMask, color, priority, control); - } + // Vector drawing +private: + void vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void vectorPutLinePixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - byte inline getVisual(int16 x, int16 y) { - return (this->*_getPixelPtr)(_visualScreen, x, y); - } - byte inline getPriority(int16 x, int16 y) { - return (this->*_getPixelPtr)(_priorityScreen, x, y); - } - byte inline getControl(int16 x, int16 y) { - return (this->*_getPixelPtr)(_controlScreen, x, y); - } +public: + void vectorAdjustLineCoordinates(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); + byte vectorIsFillMatch(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA); byte getDrawingMask(byte color, byte prio, byte control); - //void putPixel(int16 x, int16 y, byte drawMask, byte color, byte prio, byte control); - void putFontPixel(int16 startingY, int16 x, int16 y, byte color); - void putPixelOnDisplay(int16 x, int16 y, byte color); void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control); void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) { drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control); @@ -206,8 +171,8 @@ private: byte *_controlScreen; /** - * This screen is the one that is actually displayed to the user. It may be - * 640x400 for japanese SCI1 games. SCI0 games may be undithered in here. + * This screen is the one, where pixels are copied out of into the frame buffer. + * It may be 640x400 for japanese SCI1 games. SCI0 games may be undithered in here. * Only read from this buffer for Save/ShowBits usage. */ byte *_displayScreen; @@ -215,8 +180,8 @@ private: ResourceManager *_resMan; /** - * Pointer to the currently active screen (changing it only required for - * debug purposes). + * Pointer to the currently active screen (changing only required for + * debug purposes, to show for example the priority screen). */ byte *_activeScreen; @@ -239,38 +204,241 @@ private: */ bool _fontIsUpscaled; - // dynamic code - void (GfxScreen::*_vectorAdjustCoordinatePtr) (int16 *x, int16 *y); - void vectorAdjustCoordinateNOP (int16 *x, int16 *y); - void vectorAdjustCoordinate480x300Mac (int16 *x, int16 *y); - void (GfxScreen::*_vectorAdjustLineCoordinatesPtr) (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); - void vectorAdjustLineCoordinatesNOP (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); - void vectorAdjustLineCoordinates480x300Mac (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); - - byte (GfxScreen::*_vectorIsFillMatchPtr) (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); - byte vectorIsFillMatchNormal (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); - byte vectorIsFillMatch480x300Mac (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); + // pixel related code, in header so that it can be inlined for performance +public: + void putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + if (_upscaledHires == GFX_SCREEN_UPSCALED_480x300) { + putPixel480x300(x, y, drawMask, color, priority, control); + return; + } + + // Set pixel for visual, priority and control map directly, those are not upscaled + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + + int displayOffset = 0; + + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_DISABLED: + displayOffset = offset; + _displayScreen[displayOffset] = color; + break; + + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: + putScaledPixelOnDisplay(x, y, color); + break; + default: + break; + } + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + } + } - void (GfxScreen::*_vectorPutPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void vectorPutPixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void putPixel480x300(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = ((y * 3) / 2 * _width) + ((x * 3) / 2); + + // All maps are upscaled + // TODO: figure out, what Sierra exactly did on Mac for these games + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + putPixel480x300Worker(x, y, offset, _visualScreen, color); + putPixel480x300Worker(x, y, offset, _displayScreen, color); + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + putPixel480x300Worker(x, y, offset, _priorityScreen, priority); + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + putPixel480x300Worker(x, y, offset, _controlScreen, control); + } + } + void putPixel480x300Worker(int16 x, int16 y, int offset, byte *screen, byte byteToSet) { + screen[offset] = byteToSet; + if (x & 1) + screen[offset + 1] = byteToSet; + if (y & 1) + screen[offset + _width] = byteToSet; + if ((x & 1) && (y & 1)) + screen[offset + _width + 1] = byteToSet; + } - void (GfxScreen::*_vectorPutLinePixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void vectorPutLinePixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + // This is called from vector drawing to put a pixel at a certain location + void vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: + // For regular upscaled modes forward to the regular putPixel + putPixel(x, y, drawMask, color, priority, control); + return; + break; + + default: + break; + } + + // For non-upscaled mode and 480x300 Mac put pixels directly + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + _displayScreen[offset] = color; + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + } + } - byte (GfxScreen::*_vectorGetPixelPtr) (byte *screen, int16 x, int16 y); + /** + * This will just change a pixel directly on displayscreen. It is supposed to be + * only used on upscaled-Hires games where hires content needs to get drawn ONTO + * the upscaled display screen (like japanese fonts, hires portraits, etc.). + */ + void putPixelOnDisplay(int16 x, int16 y, byte color) { + int offset = y * _displayWidth + x; + _displayScreen[offset] = color; + } + + // Upscales a pixel and puts it on display screen only + void putScaledPixelOnDisplay(int16 x, int16 y, byte color) { + int displayOffset = 0; + + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_640x400: + displayOffset = (y * 2) * _displayWidth + x * 2; // straight 1 pixel -> 2 mapping + + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + _displayScreen[displayOffset + _displayWidth] = color; + _displayScreen[displayOffset + _displayWidth + 1] = color; + break; + + case GFX_SCREEN_UPSCALED_640x440: { + int16 startY = (y * 11) / 5; + int16 endY = ((y + 1) * 11) / 5; + displayOffset = (startY * _displayWidth) + x * 2; + + for (int16 curY = startY; curY < endY; curY++) { + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + } + break; + } + case GFX_SCREEN_UPSCALED_640x480: { + int16 startY = (y * 12) / 5; + int16 endY = ((y + 1) * 12) / 5; + displayOffset = (startY * _displayWidth) + x * 2; + + for (int16 curY = startY; curY < endY; curY++) { + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + } + break; + } + default: + break; + } + } + + /** + * This is used to put font pixels onto the screen - we adjust differently, so that we won't + * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted + * Sierra SCI didn't do this + */ + void putFontPixel(int16 startingY, int16 x, int16 y, byte color) { + int16 actualY = startingY + y; + if (_fontIsUpscaled) { + // Do not scale ourselves, but put it on the display directly + putPixelOnDisplay(x, actualY, color); + } else { + int offset = actualY * _width + x; + + _visualScreen[offset] = color; + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_DISABLED: + _displayScreen[offset] = color; + break; + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: { + // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird + int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + break; + } + default: + putScaledPixelOnDisplay(x, actualY, color); + break; + } + } + } + + byte getPixel(byte *screen, int16 x, int16 y) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: { + int offset = ((y * 3) / 2) * _width + ((y * 3) / 2); + + return screen[offset]; + break; + } + default: + break; + } + return screen[y * _width + x]; + } + + byte getVisual(int16 x, int16 y) { + return getPixel(_visualScreen, x, y); + } + byte getPriority(int16 x, int16 y) { + return getPixel(_priorityScreen, x, y); + } + byte getControl(int16 x, int16 y) { + return getPixel(_controlScreen, x, y); + } - void (GfxScreen::*_putPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void putPixelNormal (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void putPixelDisplayUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); - void putPixelAllUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + // Vector related public code - in here, so that it can be inlined + byte vectorGetPixel(byte *screen, int16 x, int16 y) { + return screen[y * _width + x]; + } - byte (GfxScreen::*_getPixelPtr) (byte *screen, int16 x, int16 y); - byte getPixelNormal (byte *screen, int16 x, int16 y); - byte getPixelUpscaled (byte *screen, int16 x, int16 y); + byte vectorGetVisual(int16 x, int16 y) { + return vectorGetPixel(_visualScreen, x, y); + } + byte vectorGetPriority(int16 x, int16 y) { + return vectorGetPixel(_priorityScreen, x, y); + } + byte vectorGetControl(int16 x, int16 y) { + return vectorGetPixel(_controlScreen, x, y); + } - // pixel helper - void putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte color); + void vectorAdjustCoordinate(int16 *x, int16 *y) { + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: + *x = (*x * 3) / 2; + *y = (*y * 3) / 2; + break; + default: + break; + } + } }; } // End of namespace Sci |