/* ScummVM - Scumm Interpreter * Copyright (C) 2006 The ScummVM project * * 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. * * $URL$ * $Id$ * */ #include "common/stdafx.h" #include "common/endian.h" #include "common/stream.h" #include "parallaction/defs.h" #include "parallaction/graphics.h" #include "parallaction/parallaction.h" namespace Parallaction { class DosFont : public Font { protected: // drawing properties byte *_cp; byte _color; Cnv *_data; byte _pitch; uint32 _bufPitch; protected: virtual uint16 drawChar(char c) = 0; virtual uint16 width(byte c) = 0; virtual uint16 height() = 0; byte mapChar(byte c) { if (c == 0xA5) return 0x5F; if (c == 0xDF) return 0x60; if (c > 0x7F) return c - 0x7F; return c - 0x20; } public: DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width) { } ~DosFont() { if (_data) delete _data; } void setData() { } void setColor(byte color) { _color = color; } uint32 getStringWidth(const char *s) { uint32 len = 0; while (*s) { byte c = mapChar(*s); len += width(c); s++; } return len; } void drawString(byte* buffer, uint32 pitch, const char *s) { if (s == NULL) return; _bufPitch = pitch; _cp = buffer; while (*s) { byte c = mapChar(*s); _cp += drawChar(c); s++; } } }; class DosDialogueFont : public DosFont { private: static const byte _glyphWidths[126]; protected: uint16 width(byte c) { return _glyphWidths[c]; } uint16 height() { return _data->_height; } public: DosDialogueFont(Cnv *cnv) : DosFont(cnv) { } protected: uint16 drawChar(char c) { byte *src = _data->getFramePtr(c); byte *dst = _cp; uint16 w = width(c); for (uint16 j = 0; j < height(); j++) { for (uint16 k = 0; k < w; k++) { *dst = (*src) ? 1 : _color; dst++; src++; } src += (_pitch - w); dst += (_bufPitch - w); } return w; } }; const byte DosDialogueFont::_glyphWidths[126] = { 0x04, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, 0x06, 0x03, 0x05, 0x03, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x03, 0x05, 0x04, 0x05, 0x05, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x07, 0x05, 0x06, 0x05, 0x08, 0x07, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x04, 0x05, 0x05, 0x06, 0x06, 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x06, 0x07, 0x05, 0x05, 0x05, 0x05, 0x02, 0x05, 0x05, 0x07, 0x08, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x05, 0x05 }; class DosMonospacedFont : public DosFont { protected: uint16 _width; protected: uint16 width(byte c) { return _width; } uint16 height() { return _data->_height; } public: DosMonospacedFont(Cnv *cnv) : DosFont(cnv) { _width = 8; } }; class DosMenuFont : public DosMonospacedFont { public: DosMenuFont(Cnv *cnv) : DosMonospacedFont(cnv) { } protected: uint16 drawChar(char c) { byte *src = _data->getFramePtr(c); byte *dst = _cp; for (uint16 i = 0; i < height(); i++) { for (uint16 j = 0; j < _width; j++) { if (*src) *dst = *src; src++; dst++; } dst += (_bufPitch - _width); src += (_pitch - _width); } return _width; } }; class DosLabelFont : public DosMonospacedFont { public: DosLabelFont(Cnv *cnv) : DosMonospacedFont(cnv) { } protected: uint16 drawChar(char c) { byte *src = _data->getFramePtr(c); byte *dst = _cp; for (uint16 i = 0; i < height(); i++) { memcpy(dst, src, _width); dst += _bufPitch; src += _pitch; } return _width; } }; // this flags comes from Aros Projects #define FPB_PROPORTIONAL 5 #define FPF_PROPORTIONAL (1<<5) class AmigaFont : public Font { #include "common/pack-start.h" struct CharLoc { uint16 _offset; uint16 _length; }; struct AmigaDiskFont { uint16 _ySize; byte _style; byte _flags; uint16 _xSize; uint16 _baseline; uint16 _boldSmear; uint16 _accessors; // unused byte _loChar; byte _hiChar; uint32 _charData; uint16 _modulo; uint32 _charLoc; uint32 _charSpace; uint32 _charKern; }; #include "common/pack-end.h" AmigaDiskFont *_font; uint32 _dataSize; byte *_data; bool _proportional; byte *_charData; CharLoc *_charLoc; uint16 *_charSpace; uint16 *_charKern; byte *_cp; uint32 _pitch; byte _color; protected: uint16 getSpacing(char c); void blitData(char c); uint16 getKerning(char c); uint16 getPixels(char c); uint16 getOffset(char c); uint16 width(char c); uint16 height(); void drawChar(char c); char mapChar(byte c); public: AmigaFont(Common::SeekableReadStream &stream); ~AmigaFont(); uint32 getStringWidth(const char *s); void drawString(byte *buf, uint32 pitch, const char *s); }; AmigaFont::AmigaFont(Common::SeekableReadStream &stream) { stream.seek(32); // skips dummy header _dataSize = stream.size() - stream.pos(); _data = (byte*)malloc(_dataSize); stream.read(_data, _dataSize); _font = (AmigaDiskFont*)(_data + 78); _font->_ySize = FROM_BE_16(_font->_ySize); _font->_xSize = FROM_BE_16(_font->_xSize); _font->_baseline = FROM_BE_16(_font->_baseline); _font->_modulo = FROM_BE_16(_font->_modulo); /* _font->_charLoc = (CharLoc*)(_data + FROM_BE_32((uint32)_font->_charLoc)); _font->_charData = _data + FROM_BE_32((uint32)_font->_charData); _font->_charSpace = (uint16*)(_data + FROM_BE_32((uint32)_font->_charSpace)); _font->_charKern = (uint16*)(_data + FROM_BE_32((uint32)_font->_charKern)); */ _charLoc = (CharLoc*)(_data + FROM_BE_32(_font->_charLoc)); _charData = _data + FROM_BE_32(_font->_charData); _charSpace = (uint16*)(_data + FROM_BE_32(_font->_charSpace)); _charKern = (uint16*)(_data + FROM_BE_32(_font->_charKern)); /* printf("H = %i, W = %i\n", _font->_ySize, _font->_xSize); printf("_data = %p\n", _data); printf("_charLoc = %p (%x)\n", _font->_charLoc, _font->_charLoc[0]._offset); printf("_charData = %p\n", _font->_charData); printf("_charSpace = %p\n", _font->_charSpace); printf("_charKern = %p\n", _font->_charKern); */ _proportional = (_font->_flags & FPF_PROPORTIONAL) == FPF_PROPORTIONAL; } AmigaFont::~AmigaFont() { if (_data) free(_data); } uint16 AmigaFont::getSpacing(char c) { return FROM_BE_16(_proportional ? _charSpace[c] : _font->_xSize); } uint16 AmigaFont::getKerning(char c) { return FROM_BE_16(_charKern[c]); } uint16 AmigaFont::getPixels(char c) { return FROM_BE_16(_charLoc[c]._length); } uint16 AmigaFont::getOffset(char c) { return FROM_BE_16(_charLoc[c]._offset); } void AmigaFont::blitData(char c) { int num = getPixels(c); int bitOffset = getOffset(c); byte *d = _cp; byte *s = _charData; for (int i = 0; i < _font->_ySize; i++) { for (int j = bitOffset; j < bitOffset + num; j++) { byte *b = s + (j >> 3); byte bit = *b & (0x80 >> (j & 7)); if (bit) *d = _color; d++; } s += _font->_modulo; d += _pitch - num; } } uint16 AmigaFont::width(char c) { return getKerning(c) + getSpacing(c); } uint16 AmigaFont::height() { return _font->_ySize; } char AmigaFont::mapChar(byte c) { if (c < _font->_loChar || c > _font->_hiChar) error("character '%c (%x)' not supported by font", c, c); return c - _font->_loChar; } uint32 AmigaFont::getStringWidth(const char *s) { uint32 len = 0; while (*s) { byte c = mapChar(*s); len += width(c); s++; } return len; } void AmigaFont::drawString(byte *buffer, uint32 pitch, const char *s) { _cp = buffer; _pitch = pitch; char c; while (*s) { c = mapChar(*s); _cp += getKerning(c); blitData(c); _cp += getSpacing(c); s++; } } Font *DosDisk::createFont(const char *name, Cnv* cnv) { Font *f = 0; if (!scumm_stricmp(name, "comic")) f = new DosDialogueFont(cnv); else if (!scumm_stricmp(name, "topaz")) f = new DosLabelFont(cnv); else if (!scumm_stricmp(name, "slide")) f = new DosMenuFont(cnv); else error("unknown dos font '%s'", name); return f; } Font *AmigaDisk::createFont(const char *name, Common::SeekableReadStream &stream) { // TODO: implement AmigaLabelFont for labels return new AmigaFont(stream); } void Gfx::initFonts() { if (_vm->getPlatform() == Common::kPlatformPC) { _fonts[kFontDialogue] = _vm->_disk->loadFont("comic"); _fonts[kFontLabel] = _vm->_disk->loadFont("topaz"); _fonts[kFontMenu] = _vm->_disk->loadFont("slide"); } else { _fonts[kFontDialogue] = _vm->_disk->loadFont("comic"); _fonts[kFontLabel] = _vm->_disk->loadFont("intro"); _fonts[kFontMenu] = _vm->_disk->loadFont("slide"); } } }