mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
This shaves off a good 800 KB from all the engines. However, do keep local atari debug messages for diagnostic purposes. Also, use natfeats for debug output when possible else the classic stdout/stderr (not both as before).
271 lines
7.8 KiB
C++
271 lines
7.8 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 "atari-cursor.h"
|
|
|
|
#include <cassert>
|
|
|
|
#include "graphics/blit.h"
|
|
|
|
#include "atari-graphics.h"
|
|
#include "atari-screen.h"
|
|
|
|
extern bool g_unalignedPitch;
|
|
|
|
byte Cursor::_palette[256*3] = {};
|
|
|
|
void Cursor::update() {
|
|
if (!_buf) {
|
|
_outOfScreen = true;
|
|
return;
|
|
}
|
|
|
|
if (!_visible || (!_positionChanged && !_surfaceChanged))
|
|
return;
|
|
|
|
_srcRect = Common::Rect(_width, _height);
|
|
|
|
_dstRect = Common::Rect(
|
|
_x - _hotspotX, // left
|
|
_y - _hotspotY, // top
|
|
_x - _hotspotX + _width, // right
|
|
_y - _hotspotY + _height); // bottom
|
|
|
|
_outOfScreen = !_parentScreen->offsettedSurf->clip(_srcRect, _dstRect);
|
|
|
|
assert(_srcRect.width() == _dstRect.width());
|
|
assert(_srcRect.height() == _dstRect.height());
|
|
}
|
|
|
|
void Cursor::updatePosition(int deltaX, int deltaY) {
|
|
if (deltaX == 0 && deltaY == 0)
|
|
return;
|
|
|
|
_x += deltaX;
|
|
_y += deltaY;
|
|
|
|
if (_x < 0)
|
|
_x = 0;
|
|
else if (_x >= _parentScreen->offsettedSurf->w)
|
|
_x = _parentScreen->offsettedSurf->w - 1;
|
|
|
|
if (_y < 0)
|
|
_y = 0;
|
|
else if (_y >= _parentScreen->offsettedSurf->h)
|
|
_y = _parentScreen->offsettedSurf->h - 1;
|
|
|
|
_positionChanged = true;
|
|
}
|
|
|
|
void Cursor::setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor) {
|
|
if (w == 0 || h == 0 || buf == nullptr) {
|
|
_buf = nullptr;
|
|
return;
|
|
}
|
|
|
|
_buf = (const byte *)buf;
|
|
_width = w;
|
|
_height = h;
|
|
_hotspotX = hotspotX;
|
|
_hotspotY = hotspotY;
|
|
_keycolor = keycolor;
|
|
|
|
_surfaceChanged = true;
|
|
}
|
|
|
|
void Cursor::setPalette(const byte *colors, uint start, uint num) {
|
|
memcpy(&_palette[start * 3], colors, num * 3);
|
|
|
|
_surfaceChanged = true;
|
|
}
|
|
|
|
void Cursor::convertTo(const Graphics::PixelFormat &format) {
|
|
const int cursorWidth = (_srcRect.width() + 15) & (-16);
|
|
const int cursorHeight = _height;
|
|
const bool isCLUT8 = format.isCLUT8();
|
|
|
|
if (_surface.w != cursorWidth || _surface.h != cursorHeight || _surface.format != format) {
|
|
if (!isCLUT8 && _surface.format != format) {
|
|
_rShift = format.rLoss - format.rShift;
|
|
_gShift = format.gLoss - format.gShift;
|
|
_bShift = format.bLoss - format.bShift;
|
|
|
|
_rMask = format.rMax() << format.rShift;
|
|
_gMask = format.gMax() << format.gShift;
|
|
_bMask = format.bMax() << format.bShift;
|
|
}
|
|
|
|
_surface.create(cursorWidth, cursorHeight, format);
|
|
|
|
const bool old_unalignedPitch = g_unalignedPitch;
|
|
g_unalignedPitch = true;
|
|
_surfaceMask.create(_surface.w / 8, _surface.h, format); // 1 bpl
|
|
g_unalignedPitch = old_unalignedPitch;
|
|
}
|
|
|
|
const int srcRectWidth = _srcRect.width();
|
|
|
|
const byte *src = _buf + _srcRect.left;
|
|
byte *dst = (byte *)_surface.getPixels();
|
|
uint16 *dstMask = (uint16 *)_surfaceMask.getPixels();
|
|
const int srcPadding = _width - srcRectWidth;
|
|
const int dstPadding = _surface.w - srcRectWidth;
|
|
|
|
for (int j = 0; j < cursorHeight; ++j) {
|
|
for (int i = 0; i < srcRectWidth; ++i) {
|
|
const uint32 color = *src++;
|
|
const uint16 bit = 1 << (15 - (i % 16));
|
|
|
|
if (color != _keycolor) {
|
|
if (!isCLUT8) {
|
|
// Convert CLUT8 to RGB332/RGB121 palette
|
|
*dst++ = ((_palette[color*3 + 0] >> _rShift) & _rMask)
|
|
| ((_palette[color*3 + 1] >> _gShift) & _gMask)
|
|
| ((_palette[color*3 + 2] >> _bShift) & _bMask);
|
|
} else {
|
|
*dst++ = color;
|
|
}
|
|
|
|
// clear bit
|
|
*dstMask &= ~bit;
|
|
} else {
|
|
*dst++ = 0x00;
|
|
|
|
// set bit
|
|
*dstMask |= bit;
|
|
}
|
|
|
|
if (bit == 0x0001)
|
|
dstMask++;
|
|
}
|
|
|
|
src += srcPadding;
|
|
|
|
if (dstPadding) {
|
|
memset(dst, 0x00, dstPadding);
|
|
dst += dstPadding;
|
|
|
|
*dstMask |= ((1 << dstPadding) - 1);
|
|
dstMask++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Cursor::flushBackground(const Graphics::Surface &srcSurface, const Common::Rect &rect) {
|
|
if (_savedRect.isEmpty())
|
|
return;
|
|
|
|
if (rect.contains(_savedRect)) {
|
|
_savedRect = Common::Rect();
|
|
} else if (rect.intersects(_savedRect)) {
|
|
restoreBackground(srcSurface, true);
|
|
}
|
|
}
|
|
|
|
bool Cursor::restoreBackground(const Graphics::Surface &srcSurface, bool force) {
|
|
if (_savedRect.isEmpty() || (!force && !isChanged()))
|
|
return false;
|
|
|
|
Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
|
|
const int dstBitsPerPixel = _manager->getBitsPerPixel(dstSurface.format);
|
|
|
|
//atari_debug("Cursor::restoreBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
|
|
|
|
if (srcSurface.getPixels()) {
|
|
_manager->copyRectToSurface(
|
|
dstSurface, dstBitsPerPixel, srcSurface,
|
|
_savedRect.left, _savedRect.top,
|
|
_savedRect);
|
|
} else {
|
|
const int bytesPerPixel = dstSurface.format.bytesPerPixel;
|
|
|
|
// restore native pixels (i.e. bitplanes)
|
|
Graphics::copyBlit(
|
|
(byte *)dstSurface.getPixels() + _savedRect.top * dstSurface.pitch + _savedRect.left * dstBitsPerPixel / 8,
|
|
(const byte *)_savedBackground.getPixels(),
|
|
dstSurface.pitch, _savedBackground.pitch,
|
|
_savedRect.width() * dstBitsPerPixel / 8, _savedRect.height(), // fake 4bpp by 8bpp's width/2
|
|
bytesPerPixel);
|
|
}
|
|
|
|
_savedRect = Common::Rect();
|
|
return true;
|
|
}
|
|
|
|
bool Cursor::draw(bool directRendering, bool force) {
|
|
if (!isVisible() || (!force && !isChanged()))
|
|
return false;
|
|
|
|
Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
|
|
const int dstBitsPerPixel = _manager->getBitsPerPixel(dstSurface.format);
|
|
|
|
//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
|
|
|
|
// always work with aligned rect
|
|
_savedRect = _manager->alignRect(_dstRect);
|
|
|
|
if (_surfaceChanged || _width != _srcRect.width()) {
|
|
// TODO: check for change, not just different width so it's not called over and over again ...
|
|
// TODO: some sort of in-place C2P directly into convertTo() ...
|
|
convertTo(dstSurface.format);
|
|
{
|
|
// c2p in-place (will do nothing on regular Surface::copyRectToSurface)
|
|
Graphics::Surface surf;
|
|
surf.init(
|
|
_surface.w,
|
|
_surface.h,
|
|
_surface.pitch * dstBitsPerPixel / 8, // 4bpp is not byte per pixel anymore
|
|
_surface.getPixels(),
|
|
_surface.format);
|
|
_manager->copyRectToSurface(
|
|
surf, dstBitsPerPixel, _surface,
|
|
0, 0,
|
|
Common::Rect(_surface.w, _surface.h));
|
|
}
|
|
}
|
|
|
|
if (directRendering) {
|
|
// store native pixels (i.e. bitplanes)
|
|
if (_savedBackground.w != _savedRect.width()
|
|
|| _savedBackground.h != _savedRect.height()
|
|
|| _savedBackground.format != dstSurface.format) {
|
|
_savedBackground.create(_savedRect.width(), _savedRect.height(), dstSurface.format);
|
|
_savedBackground.pitch = _savedBackground.pitch * dstBitsPerPixel / 8;
|
|
}
|
|
|
|
Graphics::copyBlit(
|
|
(byte *)_savedBackground.getPixels(),
|
|
(const byte *)dstSurface.getPixels() + _savedRect.top * dstSurface.pitch + _savedRect.left * dstBitsPerPixel / 8,
|
|
_savedBackground.pitch, dstSurface.pitch,
|
|
_savedRect.width() * dstBitsPerPixel / 8, _savedRect.height(), // fake 4bpp by 8bpp's width/2
|
|
dstSurface.format.bytesPerPixel);
|
|
}
|
|
|
|
// don't use _srcRect.right as 'x2' as this must be aligned first
|
|
// (_surface.w is recalculated thanks to convertTo())
|
|
_manager->drawMaskedSprite(
|
|
dstSurface, dstBitsPerPixel, _surface, _surfaceMask,
|
|
_dstRect.left, _dstRect.top,
|
|
Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
|
|
|
|
_visibilityChanged = _positionChanged = _surfaceChanged = false;
|
|
return true;
|
|
}
|