mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-26 04:35:16 +00:00
272 lines
8.7 KiB
C++
272 lines
8.7 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 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
#include "common/memstream.h"
|
|
#include "common/textconsole.h"
|
|
#include "dragons/bigfile.h"
|
|
#include "dragons/cursor.h"
|
|
#include "dragons/font.h"
|
|
#include "dragons/scene.h"
|
|
#include "dragons/screen.h"
|
|
#include "dragons/dragons.h"
|
|
|
|
namespace Dragons {
|
|
|
|
Font::Font(Common::SeekableReadStream &stream, uint32 mapSize, uint32 pixelOffset, uint32 pixelSize) {
|
|
_size = mapSize / 2;
|
|
_map = (uint16 *)malloc(mapSize);
|
|
if (!_map) {
|
|
error("Allocating memory for font map.");
|
|
}
|
|
|
|
for (uint i = 0; i < _size; i++) {
|
|
_map[i] = stream.readUint16LE();
|
|
}
|
|
|
|
_pixels = (byte *)malloc(pixelSize);
|
|
if (!_pixels) {
|
|
error("Allocating memory for font pixels.");
|
|
}
|
|
stream.seek(pixelOffset);
|
|
stream.read(_pixels, pixelSize);
|
|
_numChars = pixelSize / 64;
|
|
}
|
|
|
|
Font::~Font() {
|
|
free(_map);
|
|
free(_pixels);
|
|
}
|
|
|
|
uint16 Font::mapChar(uint16 in) {
|
|
return _map[in - _map[0x03] + 0x05];
|
|
}
|
|
|
|
Graphics::Surface *Font::render(uint16 *text, uint16 length) {
|
|
Graphics::Surface *surface = new Graphics::Surface();
|
|
surface->create(length * 8, 8, Graphics::PixelFormat::createFormatCLUT8());
|
|
|
|
renderToSurface(surface, 0, 0, text, length);
|
|
|
|
return surface;
|
|
}
|
|
|
|
void Font::renderToSurface(Graphics::Surface *surface, int16 x, int16 y, uint16 *text, uint16 length) {
|
|
if (x < 0 || y < 0 || x + length * 8 > surface->w || y + 8 > surface->h) {
|
|
return;
|
|
}
|
|
byte *startPixelOffset = (byte *)surface->getPixels() + y * surface->pitch + x * surface->format.bytesPerPixel;
|
|
for (int i = 0; i < length; i++) {
|
|
byte *pixels = startPixelOffset;
|
|
pixels += i * 8;
|
|
byte *data = _pixels + mapChar(text[i]) * 64;
|
|
for (int j = 0; j < 8; j++) {
|
|
memcpy(pixels, data, 8);
|
|
data += 8;
|
|
pixels += surface->pitch;
|
|
}
|
|
}
|
|
}
|
|
|
|
FontManager::FontManager(DragonsEngine *vm, Screen *screen, BigfileArchive *bigfileArchive): _vm(vm), _screen(screen), _numTextEntries(0) {
|
|
uint32 fileSize;
|
|
byte *data = bigfileArchive->load("fntfiles.dat", fileSize);
|
|
Common::SeekableReadStream *readStream = new Common::MemoryReadStream(data, fileSize, DisposeAfterUse::YES);
|
|
|
|
_fonts[0] = loadFont(0, *readStream);
|
|
_fonts[1] = loadFont(1, *readStream);
|
|
_fonts[2] = loadFont(2, *readStream);
|
|
|
|
delete readStream;
|
|
|
|
_dat_80086f48_fontColor_flag = 0;
|
|
|
|
_surface = new Graphics::Surface();
|
|
_surface->create(DRAGONS_SCREEN_WIDTH, DRAGONS_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
|
|
clearText(); //clear backing surface.
|
|
|
|
_boxFontChr = bigfileArchive->load("boxfont.chr", fileSize);
|
|
}
|
|
|
|
FontManager::~FontManager() {
|
|
delete _fonts[0];
|
|
delete _fonts[1];
|
|
delete _fonts[2];
|
|
|
|
_surface->free();
|
|
delete _surface;
|
|
|
|
free(_boxFontChr);
|
|
}
|
|
|
|
void FontManager::addText(int16 x, int16 y, uint16 *text, uint16 length, uint8 fontType) {
|
|
assert(length < 1024);
|
|
assert(fontType < 4);
|
|
_fonts[fontType]->renderToSurface(_surface, x, y, text, length);
|
|
++_numTextEntries;
|
|
}
|
|
|
|
void FontManager::draw() {
|
|
if(_numTextEntries > 0) {
|
|
_screen->copyRectToSurface8bpp(*_surface, _screen->getPalette(2), 0, 0, Common::Rect(_surface->w, _surface->h), false, NORMAL);
|
|
}
|
|
}
|
|
|
|
void FontManager::clearText() {
|
|
_numTextEntries = 0;
|
|
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
|
|
}
|
|
|
|
Font *FontManager::loadFont(uint16 index, Common::SeekableReadStream &stream) {
|
|
Common::File fd;
|
|
if (!fd.open("dragon.exe")) {
|
|
error("Failed to open dragon.exe");
|
|
}
|
|
fd.seek(_vm->getFontOffsetFromDragonEXE());
|
|
fd.skip((index * 2) * 28);
|
|
|
|
fd.skip(16); //filename
|
|
uint32 mapOffset = fd.readUint32LE();
|
|
uint32 mapSize = fd.readUint32LE();
|
|
fd.skip(4); //unk
|
|
|
|
fd.skip(16); //filename
|
|
uint32 pixelsOffset = fd.readUint32LE();
|
|
uint32 pixelsSize = fd.readUint32LE();
|
|
|
|
fd.close();
|
|
|
|
stream.seek(mapOffset);
|
|
return new Font(stream, mapSize, pixelsOffset, pixelsSize);
|
|
}
|
|
|
|
void updatePalEntry(uint16 *pal, uint16 index, uint16 newValue) {
|
|
newValue = (uint16)(((uint16)newValue & 0x1f) << 10) | (uint16)(((uint16)newValue & 0x7c00) >> 10) |
|
|
(newValue & 0x3e0) | (newValue & 0x8000);
|
|
WRITE_LE_INT16(pal + index, newValue);
|
|
}
|
|
|
|
void FontManager::updatePalette() {
|
|
uint16 *palette_f2_font_maybe = (uint16 *)_screen->getPalette(2);
|
|
const uint16 cursor3 = 0x14a5 | 0x8000;
|
|
if (_vm->isInMenu() || _vm->isFlagSet(ENGINE_FLAG_200)) {
|
|
updatePalEntry(palette_f2_font_maybe, 3, cursor3); //TODO move this to palette initialisation
|
|
if (!_vm->isUnkFlagSet(ENGINE_UNK1_FLAG_1)) {
|
|
updatePalEntry(palette_f2_font_maybe, 16, cursor3);
|
|
} else {
|
|
updatePalEntry(palette_f2_font_maybe, 16, 0);
|
|
}
|
|
if (_vm->isUnkFlagSet(ENGINE_UNK1_FLAG_4) && _dat_80086f48_fontColor_flag != 0) {
|
|
updatePalEntry(palette_f2_font_maybe, 17, 0x421);
|
|
} else {
|
|
updatePalEntry(palette_f2_font_maybe, 17, 0xfff);
|
|
}
|
|
updatePalEntry(palette_f2_font_maybe, 18, 0x421);
|
|
updatePalEntry(palette_f2_font_maybe, 19, 0x3def);
|
|
updatePalEntry(palette_f2_font_maybe, 32, cursor3);
|
|
updatePalEntry(palette_f2_font_maybe, 49, 0xfff);
|
|
updatePalEntry(palette_f2_font_maybe, 1, 0x8000);
|
|
|
|
updatePalEntry(palette_f2_font_maybe, 34, 0x421);
|
|
updatePalEntry(palette_f2_font_maybe, 35, 0x3def);
|
|
updatePalEntry(palette_f2_font_maybe, 48, cursor3);
|
|
updatePalEntry(palette_f2_font_maybe, 50, 0x421);
|
|
updatePalEntry(palette_f2_font_maybe, 51, 0x3def);
|
|
//TODO WRITE_LE_INT16(&palette_f2_font_maybe[33], READ_LE_INT16(&palette_f0[_dat_80084f58 >> 8]) & 0x7fff); //_dat_80084f58 is set in ActuallyShowMessage()
|
|
updatePalEntry(palette_f2_font_maybe, 33, 0x3def); //temporarily put in standard gray
|
|
if (_vm->isUnkFlagSet(ENGINE_UNK1_FLAG_1)) {
|
|
updatePalEntry(palette_f2_font_maybe, 17, 0x3bee);
|
|
updatePalEntry(palette_f2_font_maybe, 33, 0x3bee);
|
|
updatePalEntry(palette_f2_font_maybe, 49, 0x3bee);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FontManager::drawTextDialogBox(uint32 x1, uint32 y1, uint32 x2, uint32 y2) {
|
|
const uint16 kTileBaseIndex = 1;
|
|
const uint16 kTileIndexTop = kTileBaseIndex + 10;
|
|
const uint16 kTileIndexBottom = kTileBaseIndex + 16;
|
|
const uint16 kTileIndexLeft = kTileBaseIndex + 12;
|
|
const uint16 kTileIndexRight = kTileBaseIndex + 14;
|
|
const uint16 kTileIndexBackground = kTileBaseIndex + 13;
|
|
const uint16 kTileIndexTopLeft = kTileBaseIndex + 9;
|
|
const uint16 kTileIndexTopRight = kTileBaseIndex + 11;
|
|
const uint16 kTileIndexBottomLeft = kTileBaseIndex + 15;
|
|
const uint16 kTileIndexBottomRight = kTileBaseIndex + 17;
|
|
// Fill background
|
|
for (uint yc = y1 + 1; yc <= y2 - 1; ++yc) {
|
|
for (uint xc = x1 + 1; xc <= x2 - 1; ++xc) {
|
|
drawBoxChar(xc, yc, kTileIndexBackground);
|
|
}
|
|
}
|
|
// Fill top and bottom rows
|
|
for (uint xc = x1 + 1; xc <= x2 - 1; ++xc) {
|
|
drawBoxChar(xc, y1, kTileIndexTop);
|
|
drawBoxChar(xc, y2, kTileIndexBottom);
|
|
}
|
|
// Fill left and right columns
|
|
for (uint yc = y1 + 1; yc <= y2 - 1; ++yc) {
|
|
drawBoxChar(x1, yc, kTileIndexLeft);
|
|
drawBoxChar(x2, yc, kTileIndexRight);
|
|
}
|
|
// Fill corners
|
|
drawBoxChar(x1, y1, kTileIndexTopLeft);
|
|
drawBoxChar(x2, y1, kTileIndexTopRight);
|
|
drawBoxChar(x1, y2, kTileIndexBottomLeft);
|
|
drawBoxChar(x2, y2, kTileIndexBottomRight);
|
|
_numTextEntries++;
|
|
}
|
|
|
|
void FontManager::clearTextDialog(uint32 x1, uint32 y1, uint32 x2, uint32 y2) {
|
|
debug(3, "Clear text (%d,%d) -> (%d,%d)", x1, y1, x2, y2);
|
|
// assert(x1 > 0);
|
|
// assert(y1 > 0);
|
|
_surface->fillRect(Common::Rect((x1-1) * 8, (y1-1) * 8, (x2 + 1) * 8 + 1, (y2 + 1) * 8 + 1), 0);
|
|
if (_numTextEntries > 0) {
|
|
_numTextEntries--; //TODO need a better way to check if we should still draw the font surface.
|
|
}
|
|
}
|
|
|
|
void FontManager::drawBoxChar(uint32 x, uint32 y, uint8 tileIndex) {
|
|
byte *pixels = (byte *)_surface->getBasePtr(x * 8, y * 8);
|
|
byte *data = _boxFontChr + tileIndex * 64;
|
|
for (int j = 0; j < 8; j++) {
|
|
memcpy(pixels, data, 8);
|
|
data += 8;
|
|
pixels += _surface->pitch;
|
|
}
|
|
}
|
|
|
|
void FontManager::addAsciiText(int16 x, int16 y, const char *text, uint16 length, uint8 fontType) {
|
|
uint16 wText[41];
|
|
memset(wText, 0, sizeof(wText));
|
|
if (length > 40) {
|
|
length = 40;
|
|
}
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
wText[i] = text[i];
|
|
}
|
|
|
|
addText(x, y, wText, length, fontType);
|
|
}
|
|
|
|
} // End of namespace Dragons
|