BACKENDS: ATARI: Move Cursor outside AtariGraphicsManager

This commit is contained in:
Miro Kropacek 2024-07-05 11:12:59 +02:00
parent e9c7c8e03c
commit 957aa15e7e
5 changed files with 240 additions and 187 deletions

View File

@ -0,0 +1,150 @@
/* 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>
extern bool g_unalignedPitch;
void Cursor::update(const Graphics::Surface &screen, bool isModified) {
if (!_buf) {
outOfScreen = true;
return;
}
if (!visible || !isModified)
return;
srcRect = Common::Rect(_width, _height);
dstRect = Common::Rect(
_x - _hotspotX, // left
_y - _hotspotY, // top
_x - _hotspotX + _width, // right
_y - _hotspotY + _height); // bottom
outOfScreen = !screen.clip(srcRect, dstRect);
assert(srcRect.width() == dstRect.width());
assert(srcRect.height() == dstRect.height());
}
void Cursor::updatePosition(int deltaX, int deltaY, const Graphics::Surface &screen) {
_x += deltaX;
_y += deltaY;
if (_x < 0)
_x = 0;
else if (_x >= screen.w)
_x = screen.w - 1;
if (_y < 0)
_y = 0;
else if (_y >= screen.h)
_y = screen.h - 1;
}
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;
}
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++;
}
}
}

View File

@ -0,0 +1,87 @@
/* 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/>.
*
*/
#ifndef BACKENDS_GRAPHICS_ATARI_CURSOR_H
#define BACKENDS_GRAPHICS_ATARI_CURSOR_H
#include "common/rect.h"
#include "common/scummsys.h"
#include "graphics/surface.h"
struct Cursor {
void update(const Graphics::Surface &screen, bool isModified);
bool visible = false;
// position
Common::Point getPosition() const {
return Common::Point(_x, _y);
}
void setPosition(int x, int y) {
_x = x;
_y = y;
}
void updatePosition(int deltaX, int deltaY, const Graphics::Surface &screen);
void swap() {
const int tmpX = _oldX;
const int tmpY = _oldY;
_oldX = _x;
_oldY = _y;
_x = tmpX;
_y = tmpY;
}
// surface
void setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor);
void convertTo(const Graphics::PixelFormat &format);
Graphics::Surface surface;
Graphics::Surface surfaceMask;
// rects (valid only if !outOfScreen)
bool isClipped() const {
return outOfScreen ? false : _width != srcRect.width();
}
bool outOfScreen = true;
Common::Rect srcRect;
Common::Rect dstRect;
// palette (only used for the overlay)
byte palette[256*3] = {};
private:
int _x = -1, _y = -1;
int _oldX = -1, _oldY = -1;
// related to 'surface'
const byte *_buf = nullptr;
int _width;
int _height;
int _hotspotX;
int _hotspotY;
uint32 _keycolor;
int _rShift, _gShift, _bShift;
int _rMask, _gMask, _bMask;
};
#endif // BACKENDS_GRAPHICS_ATARI_CURSOR_H

View File

@ -1050,10 +1050,7 @@ bool AtariGraphicsManager::updateScreenInternal(const Graphics::Surface &srcSurf
//debug("Redraw cursor: %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
if (cursorSurfaceChanged || _cursor.isClipped()) {
if (dstSurface->format.isCLUT8())
_cursor.convertTo<true>(dstSurface->format);
else
_cursor.convertTo<false>(dstSurface->format);
_cursor.convertTo(dstSurface->format);
{
// copy in-place (will do nothing on regular Surface::copyRectToSurface)
Graphics::Surface surf;
@ -1311,128 +1308,3 @@ void AtariGraphicsManager::Screen::restoreBackground(const Common::Rect &rect) {
rect.width() * bitsPerPixel / 8, rect.height(), // fake 4bpp by 8bpp's width/2
offsettedSurf->format.bytesPerPixel);
}
void AtariGraphicsManager::Cursor::update(const Graphics::Surface &screen, bool isModified) {
if (!_buf) {
outOfScreen = true;
return;
}
if (!visible || !isModified)
return;
srcRect = Common::Rect(_width, _height);
dstRect = Common::Rect(
_x - _hotspotX, // left
_y - _hotspotY, // top
_x - _hotspotX + _width, // right
_y - _hotspotY + _height); // bottom
outOfScreen = !screen.clip(srcRect, dstRect);
assert(srcRect.width() == dstRect.width());
assert(srcRect.height() == dstRect.height());
}
void AtariGraphicsManager::Cursor::updatePosition(int deltaX, int deltaY, const Graphics::Surface &screen) {
_x += deltaX;
_y += deltaY;
if (_x < 0)
_x = 0;
else if (_x >= screen.w)
_x = screen.w - 1;
if (_y < 0)
_y = 0;
else if (_y >= screen.h)
_y = screen.h - 1;
}
void AtariGraphicsManager::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;
}
template <bool isClut8> // hopefully compiler optimizes all the branching out
void AtariGraphicsManager::Cursor::convertTo(const Graphics::PixelFormat &format) {
const int cursorWidth = (srcRect.width() + 15) & (-16);
const int cursorHeight = _height;
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++;
}
}
}

View File

@ -29,6 +29,7 @@
#include <mint/ostruct.h>
#include <unordered_set>
#include "atari-cursor.h"
#include "common/rect.h"
#include "graphics/surface.h"
@ -318,64 +319,6 @@ private:
bool _overlayVisible = false;
Graphics::Surface _overlaySurface;
struct Cursor {
void update(const Graphics::Surface &screen, bool isModified);
bool visible = false;
// position
Common::Point getPosition() const {
return Common::Point(_x, _y);
}
void setPosition(int x, int y) {
_x = x;
_y = y;
}
void updatePosition(int deltaX, int deltaY, const Graphics::Surface &screen);
void swap() {
const int tmpX = _oldX;
const int tmpY = _oldY;
_oldX = _x;
_oldY = _y;
_x = tmpX;
_y = tmpY;
}
// surface
void setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor);
template <bool isClut8>
void convertTo(const Graphics::PixelFormat &format);
Graphics::Surface surface;
Graphics::Surface surfaceMask;
// rects (valid only if !outOfScreen)
bool isClipped() const {
return outOfScreen ? false : _width != srcRect.width();
}
bool outOfScreen = true;
Common::Rect srcRect;
Common::Rect dstRect;
// palette (only used for the overlay)
byte palette[256*3] = {};
private:
int _x = -1, _y = -1;
int _oldX = -1, _oldY = -1;
// related to 'surface'
const byte *_buf = nullptr;
int _width;
int _height;
int _hotspotX;
int _hotspotY;
uint32 _keycolor;
int _rShift, _gShift, _bShift;
int _rMask, _gMask, _bMask;
};
Cursor _cursor;
Palette _palette;

View File

@ -368,6 +368,7 @@ ifeq ($(BACKEND),atari)
MODULE_OBJS += \
events/atari/atari-events.o \
graphics/atari/atari-c2p-asm.o \
graphics/atari/atari-cursor.o \
graphics/atari/atari-graphics.o \
graphics/atari/atari-graphics-asm.o \
mixer/atari/atari-mixer.o