scummvm/engines/scumm/cursor.cpp

1084 lines
38 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 "common/macresman.h"
#include "common/util.h"
#include "graphics/cursorman.h"
#include "graphics/maccursor.h"
#ifdef ENABLE_HE
#include "graphics/wincursor.h"
#endif
#include "scumm/bomp.h"
#include "scumm/charset.h"
#include "scumm/he/intern_he.h"
#include "scumm/object.h"
#include "scumm/he/resource_he.h"
#include "scumm/scumm.h"
#include "scumm/scumm_v2.h"
#include "scumm/scumm_v5.h"
#include "scumm/scumm_v8.h"
#include "scumm/smush/smush_player.h"
namespace Scumm {
/*
* Mouse cursor cycle colors (for the default crosshair).
*/
static const byte default_v0_cursor_colors[4] = {
1, 1, 12, 11
};
static const uint16 default_pce_cursor_colors[4] = {
0x01FF, 0x01FF, 0x016D, 0x0092
};
static const byte default_cursor_colors[4] = {
15, 15, 7, 8
};
// 2bpp
static const uint16 default_he_cursor[128] = {
0x0a80, 0x0000, 0x0000, 0x0000, 0x2568, 0x0000, 0x0000, 0x0000,
0x9556, 0x8000, 0x0000, 0x0000, 0x9955, 0x6800, 0x0000, 0x0000,
0x9955, 0x5680, 0x0000, 0x0000, 0x2655, 0x5568, 0x0000, 0x0000,
0x2695, 0x5556, 0x8000, 0x0000, 0x0995, 0x5555, 0x6800, 0x0000,
0x09a5, 0x5555, 0x5600, 0x0000, 0x0269, 0x5555, 0x5580, 0x0000,
0x0269, 0x5555, 0x5560, 0x0000, 0x009a, 0x5555, 0x5560, 0x0000,
0x009a, 0x9555, 0x5580, 0x0000, 0x0026, 0x9555, 0x5600, 0x0000,
0x0026, 0xa555, 0x5580, 0x0000, 0x0009, 0xa955, 0x5560, 0x0000,
0x0009, 0xa9a9, 0x5558, 0x0000, 0x0002, 0x6aaa, 0x5558, 0x0000,
0x0002, 0x6a9a, 0xaa58, 0x0000, 0x0000, 0x9a66, 0xaa60, 0x0000,
0x0000, 0x2589, 0xa980, 0x0000, 0x0000, 0x0a02, 0x5600, 0x0000,
0x0000, 0x0000, 0xa800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
static const byte default_v6_cursor[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0F,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, 0x0F,0x0F,0x0F, 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,
0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0F,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
static const byte c64_dos_snail_cursor[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x0F,0x0F,0xFF,0xFF,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x0F,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x0F,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x0F,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x0F,0x0F,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,
0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,
0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,
0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0xFF,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,
// Blank pixels...
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
static const byte amiga_snail_cursor[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x06,0x06,0x00,0x06,0x00,0x00,0x06,0x06,0x00,0xFF,
0xFF,0xFF,0x0F,0xFF,0x00,0x06,0x06,0x00,0x06,0x06,0x06,0x06,0x00,0x06,0x06,0x00,
0x0F,0xFF,0xFF,0x0F,0x00,0x06,0x00,0x06,0x06,0x00,0x00,0x06,0x06,0x00,0x06,0x00,
0xFF,0x0F,0xFF,0x0F,0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x00,0x06,0x00,0x06,0x00,
0xFF,0x0F,0xFF,0x0F,0x00,0x06,0x00,0x06,0x00,0x06,0x06,0x00,0x06,0x00,0x06,0x00,
0xFF,0x0F,0xFF,0x0F,0x00,0x06,0x06,0x06,0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x00,
0xFF,0x0F,0x0F,0x0F,0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x06,0x00,0x06,0x06,0x00,
0x0F,0x06,0x0F,0x0F,0x00,0x06,0x06,0x00,0x06,0x00,0x00,0x00,0x06,0x06,0x00,0xFF,
0x0F,0x0F,0x0F,0x0F,0x00,0x06,0x06,0x00,0x06,0x06,0x06,0x06,0x06,0x00,0xFF,0xFF,
0xFF,0xFF,0x0F,0x0F,0x0F,0x00,0x06,0x06,0x00,0x00,0x06,0x00,0x06,0x06,0x00,0xFF,
0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0xFF,
0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
};
static const byte atari_main_cursor[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0x0F,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,
0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,
0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,
0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,
0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0x0F,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
static const byte atari_snail_cursor[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,
0x0F,0xFF,0xFF,0xFF,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,
0xFF,0x0F,0xFF,0x0F,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,
0xFF,0xFF,0x0F,0x0F,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,
0xFF,0xFF,0xFF,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
#ifdef ENABLE_SCUMM_7_8
static const byte default_v7_cursor[] = {
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x00,0x00,0x00,0x00, 0x01,0x01,0x01, 0x00,0x00,0x00,0x00,
0x0F,0x0F,0x0F,0x0F, 0x01,0x01,0x01, 0x0F,0x0F,0x0F,0x0F,
0x00,0x00,0x00,0x00, 0x01,0x01,0x01, 0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
0x00,0x00,0x00,
};
static const byte default_v8_cursor[] = {
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xFE,0xFE,0xFE,0xFE, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, 0xFE,0xFE,0xFE,0xFE, 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, 0xFE,0xFE,0xFE,0xFE, 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xFE,0xFE,0xFE,0xFE, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
};
#endif
void ScummEngine_v5::animateCursor() {
if (_cursor.animate) {
if (!(_cursor.animateIndex & 0x1)) {
setBuiltinCursor((_cursor.animateIndex >> 1) & 3);
}
_cursor.animateIndex++;
}
}
void ScummEngine_v6::setCursorHotspot(int x, int y) {
if (_enableEGADithering) {
x <<= 1;
y <<= 1;
}
_cursor.hotspotX = x;
_cursor.hotspotY = y;
}
void ScummEngine_v6::setCursorTransparency(int a) {
int i, size;
size = _cursor.width * _cursor.height;
if (_enableEGADithering) {
for (i = 0; i < size; i += 2) {
int st = 1 ^ ((i / (_cursor.width << 1)) & 1);
if (_grabbedCursor[i] == _egaColorMap[st][a] && _grabbedCursor[i + 1] == _egaColorMap[st ^ 1][a])
_grabbedCursor[i] = _grabbedCursor[i + 1] = 0xFF;
}
} else {
for (i = 0; i < size; i++)
if (_grabbedCursor[i] == (byte)a)
_grabbedCursor[i] = 0xFF;
}
updateCursor();
}
void ScummEngine::updateCursor() {
int transColor = (_game.heversion >= 80) ? 5 : 255;
#ifdef USE_RGB_COLOR
Graphics::PixelFormat format = _system->getScreenFormat();
CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height,
_cursor.hotspotX, _cursor.hotspotY,
(_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor),
(_game.heversion == 70 ? true : false),
&format);
#else
CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height,
_cursor.hotspotX, _cursor.hotspotY,
(_game.platform == Common::kPlatformNES ? _grabbedCursor[63] : transColor),
(_game.heversion == 70 ? true : false));
#endif
}
void ScummEngine_v6::grabCursor(int x, int y, int w, int h) {
VirtScreen *vs = findVirtScreen(y);
if (vs == nullptr) {
debug(0, "grabCursor: invalid Y %d", y);
return;
}
setCursorFromBuffer((byte *)vs->getBasePtr(x, y - vs->topline), w, h, vs->pitch);
}
void ScummEngine_v6::setDefaultCursor() {
setCursorHotspot(7, 6);
setCursorFromBuffer(default_v6_cursor, 16, 13, 16);
}
#ifdef ENABLE_SCUMM_7_8
void ScummEngine_v7::setDefaultCursor() {
byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
byte cursorBuffer[124];
byte cursorPixel;
int black, white, inverseRgbIdx;
int rgbIdx = 0;
do {
black = getPaletteColorFromRGB(palette, rgbIdx, rgbIdx, rgbIdx);
++rgbIdx;
} while (black == 1 && rgbIdx != 100);
rgbIdx = 0;
do {
inverseRgbIdx = 0xFF - rgbIdx++;
white = getPaletteColorFromRGB(palette, inverseRgbIdx, inverseRgbIdx, inverseRgbIdx);
} while (white == 1 && rgbIdx != 100);
for (int i = 0; i < ARRAYSIZE(default_v7_cursor); i++) {
cursorPixel = default_v7_cursor[i];
if (cursorPixel == 0x0F)
cursorPixel = white;
cursorBuffer[i] = (byte)(cursorPixel & 0xFF);
}
setCursorHotspot(5, 5);
setCursorFromBuffer(cursorBuffer, 11, 11, 11);
setCursorTransparency(0x01);
}
void ScummEngine_v8::setDefaultCursor() {
byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
byte cursorBuffer[400];
byte cursorPixel;
int /* black,*/ white, inverseRgbIdx;
int rgbIdx = 0;
/* The interpreter does this, but we don't need it, at least for v8.
* See below for details.
*
* do {
* black = getPaletteColorFromRGB(palette, rgbIdx, rgbIdx, rgbIdx);
* ++rgbIdx;
* } while (black == 1 && rgbIdx != 100);
* rgbIdx = 0;
*/
do {
inverseRgbIdx = 0xFF - rgbIdx++;
white = getPaletteColorFromRGB(palette, inverseRgbIdx, inverseRgbIdx, inverseRgbIdx);
} while (white == 1 && rgbIdx != 100);
for (int i = 0; i < ARRAYSIZE(default_v8_cursor); i++) {
cursorPixel = default_v8_cursor[i];
if (isSmushActive() && cursorPixel == 0x0F)
cursorPixel = white;
/* The interpreter also performs this substitution.
* we can't since we handle the palette in a different way and we wouldn't
* find the same color the interpreter finds.
*
* if (cursorPixel == 0x00)
* cursorPixel = black;
*/
cursorBuffer[i] = (byte)(cursorPixel & 0xFF);
}
setCursorHotspot(9, 9);
setCursorFromBuffer(cursorBuffer, 20, 20, 20);
setCursorTransparency(0xFE);
}
void ScummEngine_v7::setCursorTransparency(int a) {
int i, size;
size = _cursor.width * _cursor.height;
for (i = 0; i < size; i++) {
if (_grabbedCursor[i] == (byte)a) {
if (_game.version == 8) {
_grabbedCursor[i] = isSmushActive() ? 0xFE : 0xFF;
} else {
_grabbedCursor[i] = isSmushActive() ? 0x01 : 0xFF;
}
}
}
updateCursor();
}
void ScummEngine_v7::updateCursor() {
int transColor;
if (_game.version == 8) {
transColor = isSmushActive() ? 0xFE : 0xFF;
} else {
transColor = isSmushActive() ? 0x01 : 0xFF;
}
#ifdef USE_RGB_COLOR
Graphics::PixelFormat format = _system->getScreenFormat();
CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height,
_cursor.hotspotX, _cursor.hotspotY,
transColor,
false,
&format);
#else
CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height,
_cursor.hotspotX, _cursor.hotspotY,
transColor,
false);
#endif
}
#endif
void ScummEngine_v6::setCursorFromBuffer(const byte *ptr, int width, int height, int pitch, bool preventScale) {
uint size;
byte *dst;
bool needsDithering = (_enableEGADithering && !preventScale);
size = width * height * _bytesPerPixel;
if (needsDithering)
size <<= 2;
if (size > sizeof(_grabbedCursor))
error("grabCursor: grabbed cursor too big");
_cursor.width = width;
_cursor.height = height;
_cursor.animate = 0;
dst = needsDithering ? _compositeBuf : _grabbedCursor;
for (; height; height--) {
memcpy(dst, ptr, width * _bytesPerPixel);
dst += width * _bytesPerPixel;
ptr += pitch;
}
if (needsDithering)
ditherCursor();
updateCursor();
}
void ScummEngine_v6::ditherCursor() {
int x = 0;
int y = 0;
int pitch = _cursor.width;
// We temporarily put the transparency color in the EGA color tables.
uint8 backupEGA0 = _egaColorMap[0][255];
uint8 backupEGA1 = _egaColorMap[1][255];
_egaColorMap[0][255] = _egaColorMap[1][255] = 0xFF;
ditherVGAtoEGA(pitch, x, y, _cursor.width, _cursor.height);
_egaColorMap[0][255] = backupEGA0;
_egaColorMap[1][255] = backupEGA1;
memcpy(_grabbedCursor, _hercCGAScaleBuf, _cursor.width * _cursor.height);
}
void ScummEngine_v70he::setCursorFromImg(uint img, uint room, uint imgindex) {
_resExtractor->setCursor(img);
}
void ScummEngine_v70he::setDefaultCursor() {
const uint16 *src;
int i, j;
static const byte palette[] = {0, 0, 0,
0xff, 0xff, 0xff,
0, 0, 0, };
memset(_grabbedCursor, 5, sizeof(_grabbedCursor));
_cursor.hotspotX = _cursor.hotspotY = 2;
src = default_he_cursor;
_cursor.width = 32;
_cursor.height = 32;
for (i = 0; i < 32; i++) {
uint p = *src;
for (j = 0; j < 32; j++) {
switch ((p & (0x3 << 14)) >> 14) {
case 1:
_grabbedCursor[32 * i + j] = 0xfe;
break;
case 2:
_grabbedCursor[32 * i + j] = 0xfd;
break;
default:
break;
}
p <<= 2;
if (j == 31)
++src;
else if ((j + 1) % 8 == 0)
p = *(++src);
}
}
// Since white color position is not guaranteed
// we setup our own palette if supported by backend
CursorMan.disableCursorPalette(false);
CursorMan.replaceCursorPalette(palette, 0xfd, 3);
updateCursor();
}
#ifdef ENABLE_HE
void ScummEngine_v80he::setDefaultCursor() {
// v80+ games use the default Windows cursor instead of the usual
// default HE cursor.
Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor();
// Clear the cursor
if (_bytesPerPixel == 2) {
for (int i = 0; i < 1024; i++)
WRITE_UINT16(_grabbedCursor + i * 2, 5);
} else {
memset(_grabbedCursor, 5, sizeof(_grabbedCursor));
}
_cursor.width = cursor->getWidth();
_cursor.height = cursor->getHeight();
_cursor.hotspotX = cursor->getHotspotX();
_cursor.hotspotY = cursor->getHotspotY();
const byte *surface = cursor->getSurface();
const byte *palette = cursor->getPalette();
for (uint16 y = 0; y < _cursor.height; y++) {
for (uint16 x = 0; x < _cursor.width; x++) {
byte pixel = *surface++;
if (pixel != cursor->getKeyColor()) {
pixel -= cursor->getPaletteStartIndex();
if (_bytesPerPixel == 2)
WRITE_UINT16(_grabbedCursor + (y * _cursor.width + x) * 2, get16BitColor(palette[pixel * 3], palette[pixel * 3 + 1], palette[pixel * 3 + 2]));
else
_grabbedCursor[y * _cursor.width + x] = (pixel == 0) ? 0xfd : 0xfe;
}
}
}
if (_bytesPerPixel == 1) {
// Since white color position is not guaranteed
// we setup our own palette if supported by backend
CursorMan.disableCursorPalette(false);
CursorMan.replaceCursorPalette(palette, 0xfd, cursor->getPaletteCount());
}
delete cursor;
updateCursor();
}
#endif
void ScummEngine_v6::setCursorFromImg(uint img, uint room, uint imgindex) {
int w, h;
const byte *dataptr, *bomp;
uint32 size;
FindObjectInRoom foir;
const ImageHeader *imhd;
if (room == (uint) - 1)
room = getObjectRoom(img);
findObjectInRoom(&foir, foCodeHeader | foImageHeader | foCheckAlreadyLoaded, img, room);
imhd = (const ImageHeader *)findResourceData(MKTAG('I','M','H','D'), foir.obim);
if (_game.version == 8) {
setCursorHotspot(READ_LE_UINT32(&imhd->v8.hotspot[0].x),
READ_LE_UINT32(&imhd->v8.hotspot[0].y));
w = READ_LE_UINT32(&imhd->v8.width) / 8;
h = READ_LE_UINT32(&imhd->v8.height) / 8;
} else if (_game.version == 7) {
setCursorHotspot(READ_LE_UINT16(&imhd->v7.hotspot[0].x),
READ_LE_UINT16(&imhd->v7.hotspot[0].y));
w = READ_LE_UINT16(&imhd->v7.width) / 8;
h = READ_LE_UINT16(&imhd->v7.height) / 8;
} else {
if (_game.heversion == 0) {
setCursorHotspot(READ_LE_UINT16(&imhd->old.hotspot[0].x),
READ_LE_UINT16(&imhd->old.hotspot[0].y));
}
w = READ_LE_UINT16(&foir.cdhd->v6.w) / 8;
h = READ_LE_UINT16(&foir.cdhd->v6.h) / 8;
}
dataptr = getObjectImage(foir.obim, imgindex);
assert(dataptr);
if (_game.version == 8) {
bomp = dataptr;
} else {
size = READ_BE_UINT32(dataptr + 4);
if (size > sizeof(_grabbedCursor))
error("setCursorFromImg: Cursor image too large");
bomp = findResource(MKTAG('B','O','M','P'), dataptr);
}
if (bomp != nullptr)
useBompCursor(bomp, w, h);
else
useIm01Cursor(dataptr, w, h);
}
#ifdef ENABLE_SCUMM_7_8
void ScummEngine_v7::setCursorFromImg(uint img, uint room, uint imgindex) {
ScummEngine_v6::setCursorFromImg(img, room, imgindex);
// There are several occasions in which the screen is not updated
// between subsequent cursor changes, and as a result we would never
// be able to see some of those updates (i.e. the loading cursors in
// The Dig and The Curse of Monkey Island). This forced screen update
// addresses that.
_system->updateScreen();
}
#endif
void ScummEngine_v6::useIm01Cursor(const byte *im, int w, int h) {
VirtScreen *vs = &_virtscr[kMainVirtScreen];
byte *buf, *dst;
const byte *src;
int i;
w *= 8;
h *= 8;
// Backup the screen content
dst = buf = (byte *)malloc(w * h);
src = vs->getPixels(0, 0);
for (i = 0; i < h; i++) {
memcpy(dst, src, w);
dst += w;
src += vs->pitch;
}
// Do some drawing
drawBox(0, 0, w - 1, h - 1, 0xFF);
vs->hasTwoBuffers = false;
_gdi->disableZBuffer();
_gdi->drawBitmap(im, vs, _screenStartStrip, 0, w, h, 0, w / 8, 0);
vs->hasTwoBuffers = true;
_gdi->enableZBuffer();
// Grab the data we just drew and setup the cursor with it
setCursorFromBuffer(vs->getPixels(0, 0), w, h, vs->pitch);
// Restore the screen content
src = buf;
dst = vs->getPixels(0, 0);
for (i = 0; i < h; i++) {
memcpy(dst, src, w);
dst += vs->pitch;
src += w;
}
free(buf);
}
void ScummEngine_v6::useBompCursor(const byte *im, int width, int height) {
uint size;
width *= 8;
height *= 8;
size = width * height;
if (_enableEGADithering)
size <<= 2;
if (size > sizeof(_grabbedCursor))
error("useBompCursor: cursor too big (%d)", size);
_cursor.width = width;
_cursor.height = height;
_cursor.animate = 0;
// Skip the header
if (_game.version == 8) {
im += 16;
} else {
im += 18;
}
decompressBomp(_enableEGADithering ? _compositeBuf : _grabbedCursor, im, width, height);
if (_enableEGADithering)
ditherCursor();
updateCursor();
}
void ScummEngine_v5::redefineBuiltinCursorFromChar(int index, int chr) {
if (!_macCursorFile.empty())
return;
// Cursor image in both Loom versions are based on images from charset.
// This function is *only* supported for Loom!
assert(_game.id == GID_LOOM);
assert(index >= 0 && index < 4);
// const int oldID = _charset->getCurID();
uint16 *ptr = _cursorImages[index];
int h;
if (index == 1 && _game.platform == Common::kPlatformPCEngine) {
uint16 cursorPCE[] = {
0x8000, 0xC000, 0xE000, 0xF000, 0xF800, 0xFC00, 0xFE00, 0xFF00,
0xF180, 0xF800, 0x8C00, 0x0C00, 0x0600, 0x0600, 0x0300, 0x0000
};
for (h = 0; h < ARRAYSIZE(cursorPCE); h++) {
*ptr++ = cursorPCE[h];
}
} else {
if (_game.version == 3) {
_charset->setCurID(0);
} else if (_game.version >= 4) {
_charset->setCurID(1);
}
Graphics::Surface s;
byte buf[16*17];
memset(buf, 123, 16*17);
// For correct rendering, we need to use original (non-CJK) fonts
bool oldCJKMode = _useCJKMode;
_useCJKMode = false;
s.init(_charset->getCharWidth(chr), _charset->getFontHeight(),
_charset->getCharWidth(chr), buf,
Graphics::PixelFormat::createFormatCLUT8());
// s.h = 17 for FM-TOWNS Loom Japanese. Fixes bug #1964
assert(s.w <= 16 && s.h <= 17);
_charset->drawChar(chr, s, 0, 0);
_useCJKMode = oldCJKMode;
memset(ptr, 0, 17 * sizeof(uint16));
for (h = 0; h < s.h; h++) {
for (int w = 0; w < s.w; w++) {
if (buf[s.pitch * h + w] != 123)
*ptr |= 1 << (15 - w);
}
ptr++;
}
}
// _charset->setCurID(oldID);
}
void ScummEngine_v5::redefineBuiltinCursorHotspot(int index, int x, int y) {
// Cursor image in both Looms are based on images from charset.
// This function is *only* supported for Loom!
assert(_game.id == GID_LOOM);
assert(index >= 0 && index < 4);
_cursorHotspots[index * 2] = x;
_cursorHotspots[index * 2 + 1] = y;
}
void ScummEngine_v2::setBuiltinCursor(int idx) {
int i, j;
byte color;
memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
if (_game.platform == Common::kPlatformC64)
color = default_v0_cursor_colors[idx];
else if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderCGAComp)
color = (idx & 1) * 3;
else if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG || _renderMode == Common::kRenderCGA_BW)
color = idx & 1;
else
color = default_cursor_colors[idx];
if (_game.platform == Common::kPlatformNES) {
_cursor.width = 8;
_cursor.height = 8;
_cursor.hotspotX = 0;
_cursor.hotspotY = 0;
byte *dst = _grabbedCursor;
byte *src = &_NESPatTable[0][0xfa * 16];
byte *palette = _NESPalette[1];
for (i = 0; i < 8; i++) {
byte c0 = src[i];
byte c1 = src[i + 8];
for (j = 0; j < 8; j++)
*dst++ = palette[((c0 >> (7 - j)) & 1) | (((c1 >> (7 - j)) & 1) << 1) | ((idx == 3) ? 4 : 0)];
}
} else if (_game.platform == Common::kPlatformAtariST) {
_cursor.width = 16;
_cursor.height = 16;
_cursor.hotspotX = 8;
_cursor.hotspotY = 8;
memcpy(_grabbedCursor, atari_main_cursor, sizeof(atari_main_cursor));
for (i = 0; i < ARRAYSIZE(_grabbedCursor); i++) {
if (_grabbedCursor[i] == 0x0F) {
_grabbedCursor[i] = color;
}
}
} else if (_game.platform == Common::kPlatformAmiga) {
_cursor.width = 15;
_cursor.height = 15;
_cursor.hotspotX = 7;
_cursor.hotspotY = 7;
byte *hotspot = _grabbedCursor + _cursor.hotspotY * _cursor.width + _cursor.hotspotX;
// Crosshair, symmetric
// TODO: Instead of setting this up via code, we should simply extend
// default_cursor_images to contain this shape.
for (i = 0; i < 5; i++) {
*(hotspot - 3 - i) = color;
*(hotspot + 3 + i) = color;
*(hotspot - _cursor.width * (3 + i)) = color;
*(hotspot + _cursor.width * (3 + i)) = color;
}
// Arrow heads, diagonal lines
for (i = 1; i <= 2; i++) {
*(hotspot - _cursor.width * i - (3 + i)) = color;
*(hotspot + _cursor.width * i - (3 + i)) = color;
*(hotspot - _cursor.width * i + (3 + i)) = color;
*(hotspot + _cursor.width * i + (3 + i)) = color;
*(hotspot - _cursor.width * (3 + i) - i) = color;
*(hotspot + _cursor.width * (3 + i) - i) = color;
*(hotspot - _cursor.width * (3 + i) + i) = color;
*(hotspot + _cursor.width * (3 + i) + i) = color;
}
} else {
_cursor.width = 23;
_cursor.height = 21;
_cursor.hotspotX = 11;
_cursor.hotspotY = 10;
byte *hotspot = _grabbedCursor + _cursor.hotspotY * _cursor.width + _cursor.hotspotX;
// Crosshair, slightly assymetric
// TODO: Instead of setting this up via code, we should simply extend
// default_cursor_images to contain this shape.
for (i = 0; i < 7; i++) {
*(hotspot - 5 - i) = color;
*(hotspot + 5 + i) = color;
}
for (i = 0; i < 8; i++) {
*(hotspot - _cursor.width * (3 + i)) = color;
*(hotspot + _cursor.width * (3 + i)) = color;
}
// Arrow heads, diagonal lines
for (i = 1; i <= 3; i++) {
*(hotspot - _cursor.width * i - 5 - i) = color;
*(hotspot + _cursor.width * i - 5 - i) = color;
*(hotspot - _cursor.width * i + 5 + i) = color;
*(hotspot + _cursor.width * i + 5 + i) = color;
*(hotspot - _cursor.width * (i + 3) - i) = color;
*(hotspot - _cursor.width * (i + 3) + i) = color;
*(hotspot + _cursor.width * (i + 3) - i) = color;
*(hotspot + _cursor.width * (i + 3) + i) = color;
}
// Final touches
*(hotspot - _cursor.width - 7) = color;
*(hotspot - _cursor.width + 7) = color;
*(hotspot + _cursor.width - 7) = color;
*(hotspot + _cursor.width + 7) = color;
*(hotspot - (_cursor.width * 5) - 1) = color;
*(hotspot - (_cursor.width * 5) + 1) = color;
*(hotspot + (_cursor.width * 5) - 1) = color;
*(hotspot + (_cursor.width * 5) + 1) = color;
if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG || _renderMode == Common::kRenderCGA_BW) {
const byte *src = &_grabbedCursor[_cursor.width * _cursor.height - 1];
_cursor.width <<= 1;
_cursor.height <<= 1;
_cursor.hotspotX <<= 1;
_cursor.hotspotY <<= 1;
byte *dst1 = &_grabbedCursor[_cursor.width * _cursor.height - 1];
byte *dst2 = dst1 - _cursor.width;
while (dst2 >= _grabbedCursor) {
for (i = _cursor.width >> 1; i; --i) {
uint8 col2 = (_renderMode == Common::kRenderCGA_BW) ? *src : 0xFF;
*dst1-- = col2;
*dst1-- = col2;
*dst2-- = *src;
*dst2-- = *src--;
}
dst1 -= _cursor.width;
dst2 -= _cursor.width;
}
}
}
updateCursor();
}
void ScummEngine_v2::setSnailCursor() {
if (_game.platform == Common::kPlatformAmiga) {
memcpy(_grabbedCursor, amiga_snail_cursor, sizeof(amiga_snail_cursor));
_cursor.width = 16;
_cursor.height = 16;
_cursor.hotspotX = 7;
_cursor.hotspotY = 7;
} else if (_game.platform == Common::kPlatformAtariST) {
memcpy(_grabbedCursor, atari_snail_cursor, sizeof(atari_snail_cursor));
_cursor.width = 16;
_cursor.height = 16;
_cursor.hotspotX = 8;
_cursor.hotspotY = 8;
} else {
memcpy(_grabbedCursor, c64_dos_snail_cursor, sizeof(c64_dos_snail_cursor));
if (_game.platform == Common::kPlatformC64) {
for (uint i = 0; i < sizeof(c64_dos_snail_cursor); i++) {
if (_grabbedCursor[i] == 0x0F)
_grabbedCursor[i] = 0x01;
}
}
_cursor.width = 24;
_cursor.height = 21;
_cursor.hotspotX = 11;
_cursor.hotspotY = 10;
}
updateCursor();
}
void ScummEngine_v5::resetCursors() {
static const uint16 default_cursor_images[4][16] = {
/* cross-hair */
{ 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000, 0x7e3f,
0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0000 },
/* hourglass */
{ 0x0000, 0x7ffe, 0x6006, 0x300c, 0x1818, 0x0c30, 0x0660, 0x03c0,
0x0660, 0x0c30, 0x1998, 0x33cc, 0x67e6, 0x7ffe, 0x0000, 0x0000 },
/* arrow */
{ 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
0x7f80, 0x78c0, 0x7c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0180 },
/* hand */
{ 0x1e00, 0x1200, 0x1200, 0x1200, 0x1200, 0x13ff, 0x1249, 0x1249,
0xf249, 0x9001, 0x9001, 0x9001, 0x8001, 0x8001, 0x8001, 0xffff },
};
static const byte default_cursor_hotspots[10] = {
8, 7, 8, 7, 1, 1, 5, 0,
8, 7, //zak256
};
for (int i = 0; i < 4; i++) {
memcpy(_cursorImages[i], default_cursor_images[i], 32);
}
memcpy(_cursorHotspots, default_cursor_hotspots, 8);
}
void ScummEngine_v5::setBuiltinCursor(int idx) {
if (!_macCursorFile.empty()) {
Common::MacResManager resource;
if (resource.open(_macCursorFile)) {
Common::MacResIDArray resArray = resource.getResIDArray(MKTAG('C', 'U', 'R', 'S'));
Common::SeekableReadStream *curs = resource.getResource(MKTAG('C', 'U', 'R', 'S'), resArray[0]);
Graphics::MacCursor macCursor;
if (macCursor.readFromStream(*curs)) {
_cursor.animate = 0;
CursorMan.replaceCursor(&macCursor);
delete curs;
return;
}
delete curs;
}
}
if (_game.id == GID_INDY3 && _macScreen) {
const byte buf[15 * 15] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0xFF, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
_cursor.animate = 0;
CursorMan.replaceCursor(buf, 15, 15, 7, 7, 0xFF);
return;
}
int i, j;
uint16 color;
const uint16 *src = _cursorImages[_currentCursor];
if (_outputPixelFormat.bytesPerPixel == 2) {
if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine) {
byte r, g, b;
colorPCEToRGB(default_pce_cursor_colors[idx], &r, &g, &b);
color = get16BitColor(r, g, b);
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
} else if (_game.platform == Common::kPlatformFMTowns) {
byte *palEntry = &_textPalette[default_cursor_colors[idx] * 3];
color = get16BitColor(palEntry[0], palEntry[1], palEntry[2]);
#endif
} else {
color = _16BitPalette[default_cursor_colors[idx]];
}
for (i = 0; i < 1024; i++)
WRITE_UINT16(_grabbedCursor + i * 2, 0xFF);
} else {
// Indy4 Amiga uses its own color set for the cursor image.
// This is patchwork code to make the cursor flash in correct colors.
if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
static const uint8 indy4AmigaColors[4] = {
252, 252, 253, 254
};
color = indy4AmigaColors[idx];
} else if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) {
color = idx & 1;
} else {
color = default_cursor_colors[idx];
}
memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
}
int sclW = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG || _enableEGADithering) ? 2 : _textSurfaceMultiplier;
int sclH = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) ? 1 : (_enableEGADithering ? 2 : _textSurfaceMultiplier);
int sclW2 = _outputPixelFormat.bytesPerPixel * sclW;
_cursor.hotspotX = _cursorHotspots[2 * _currentCursor] * sclW;
_cursor.hotspotY = _cursorHotspots[2 * _currentCursor + 1] * sclH;
_cursor.width = 16 * sclW;
_cursor.height = 16 * sclH;
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
if (src[i] & (1 << j)) {
byte *dst1 = _grabbedCursor + 16 * sclW2 * i * sclH + (15 - j) * sclW2;
byte *dst2 = (sclH == 2) ? dst1 + 16 * sclW2 : dst1;
if (_outputPixelFormat.bytesPerPixel == 2) {
for (int b = 0; b < sclW; b++) {
*((uint16 *)dst1) = *((uint16 *)dst2) = color;
dst1 += 2;
dst2 += 2;
}
} else {
for (int b = 0; b < sclW; b++)
*dst1++ = *dst2++ = color;
}
}
}
}
updateCursor();
}
} // End of namespace Scumm