diff options
author | athrxx | 2019-02-05 23:04:17 +0100 |
---|---|---|
committer | athrxx | 2019-03-06 20:48:21 +0100 |
commit | 490e41cfad44505a4f742db9092d9a960783da6c (patch) | |
tree | 7d8e0d51c10a8213d364e9ca5898d07958878c8e | |
parent | 7b8c84fa4d3f3d8e1c5fa543fae7ddbd7a495bb7 (diff) | |
download | scummvm-rg350-490e41cfad44505a4f742db9092d9a960783da6c.tar.gz scummvm-rg350-490e41cfad44505a4f742db9092d9a960783da6c.tar.bz2 scummvm-rg350-490e41cfad44505a4f742db9092d9a960783da6c.zip |
KYRA: (EOB1/Amiga) - implement AmigaDOS font support
- only basic support - no kerning, spacing, etc., since EOB doesn't need that
- also improve palette loading
-rw-r--r-- | engines/kyra/graphics/screen.cpp | 6 | ||||
-rw-r--r-- | engines/kyra/graphics/screen.h | 70 | ||||
-rw-r--r-- | engines/kyra/graphics/screen_eob.cpp | 243 | ||||
-rw-r--r-- | engines/kyra/graphics/screen_eob.h | 2 | ||||
-rw-r--r-- | engines/kyra/resource/resource.cpp | 3 |
5 files changed, 310 insertions, 14 deletions
diff --git a/engines/kyra/graphics/screen.cpp b/engines/kyra/graphics/screen.cpp index 6af970eee5..2a5e51162e 100644 --- a/engines/kyra/graphics/screen.cpp +++ b/engines/kyra/graphics/screen.cpp @@ -1361,9 +1361,11 @@ bool Screen::loadFont(FontId fontId, const char *filename) { Font *&fnt = _fonts[fontId]; if (!fnt) { - if (_isAmiga) + if (_vm->game() == GI_KYRA1 && _isAmiga) fnt = new AMIGAFont(); #ifdef ENABLE_EOB + else if (_isAmiga) + fnt = new AmigaDOSFont(_vm->resource()); else if (_vm->game() == GI_EOB1 || _vm->game() == GI_EOB2) // We use normal VGA rendering in EOB II, since we do the complete EGA dithering in updateScreen(). fnt = new OldDOSFont(_useHiResEGADithering ? Common::kRenderVGA : _renderMode); @@ -3725,7 +3727,7 @@ int AMIGAFont::getCharWidth(uint16 c) const { } void AMIGAFont::drawChar(uint16 c, byte *dst, int pitch, int) const { - //if (c >= 255) + if (c >= 255) return; if (_chars[c].yOffset == 255) diff --git a/engines/kyra/graphics/screen.h b/engines/kyra/graphics/screen.h index 8ed17a12f5..23bce6296b 100644 --- a/engines/kyra/graphics/screen.h +++ b/engines/kyra/graphics/screen.h @@ -30,6 +30,7 @@ #include "common/rect.h" #include "common/rendermode.h" #include "common/stream.h" +#include "common/ptr.h" class OSystem; @@ -179,10 +180,77 @@ private: static uint16 *_cgaDitheringTable; static int _numRef; }; + +/** + * Implementation of the Font interface for native AmigaDOS system fonts (normally to be loaded via diskfont.library) + */ +class Resource; +class AmigaDOSFont : public Font { +public: + AmigaDOSFont(Resource *res); + ~AmigaDOSFont() { unload(); } + + bool load(Common::SeekableReadStream &file); + int getHeight() const { return _height; } + int getWidth() const { return _width; } + int getCharWidth(uint16 c) const; + void setColorMap(const uint8 *src) { _colorMap = src; } + void drawChar(uint16 c, byte *dst, int pitch, int) const; + +private: + void unload(); + + struct TextFont { + TextFont() : data(0), bitmap(0), location(0), spacing(0), kerning(0), height(0), width(0), baseLine(0), firstChar(0), lastChar(0), modulo(0) {} + ~TextFont() { + delete[] data; + } + + uint16 height; + uint16 width; + uint16 baseLine; + uint8 firstChar; + uint8 lastChar; + uint16 modulo; + const uint8 *data; + const uint8 *bitmap; + const uint16 *location; + const int16 *spacing; + const int16 *kerning; + }; + + TextFont *loadContentFile(const Common::String fileName); + void selectMode(int mode); + + struct FontContent { + FontContent() : height(0), style(0), flags(0) {} + ~FontContent() { + data.reset(); + } + + Common::String contentFile; + Common::SharedPtr<TextFont> data; + uint16 height; + uint8 style; + uint8 flags; + }; + + int _width, _height; + uint8 _first, _last; + FontContent *_content; + uint16 _numElements; + uint16 _selectedElement; + + const uint8 *_colorMap; + + const uint16 _maxPathLen; + + Resource *_res; +}; #endif // ENABLE_EOB /** - * Implementation of the Font interface for AMIGA fonts. + * Implementation of the Font interface for Kyra 1 style (non-native AmigaDOS) AMIGA fonts. */ class AMIGAFont : public Font { public: diff --git a/engines/kyra/graphics/screen_eob.cpp b/engines/kyra/graphics/screen_eob.cpp index c7bfec92f1..823740cc6a 100644 --- a/engines/kyra/graphics/screen_eob.cpp +++ b/engines/kyra/graphics/screen_eob.cpp @@ -36,6 +36,8 @@ #include "graphics/palette.h" #include "graphics/sjis.h" +#include "gui/error.h" + namespace Kyra { Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount), _cursorColorKey16Bit(0x8000) { @@ -204,11 +206,11 @@ void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, s->read(_pagePtrs[pageNum], size); } -void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2) { +void Screen_EoB::printShadedText(const char *string, int x, int y, int col1, int col2, int shadowCol) { if (_vm->gameFlags().platform != Common::kPlatformFMTowns) { - printText(string, x - 1, y, 12, col2); - printText(string, x, y + 1, 12, 0); - printText(string, x - 1, y + 1, 12, 0); + printText(string, x - 1, y, shadowCol, col2); + printText(string, x, y + 1, shadowCol, 0); + printText(string, x - 1, y + 1, shadowCol, 0); } else if (col2) { fillRect(x, y, x + getTextWidth(string) - 1, y + getFontHeight() - 1, col2); } @@ -220,14 +222,20 @@ void Screen_EoB::loadShapeSetBitmap(const char *file, int tempPage, int destPage _curPage = 2; } -void Screen_EoB::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool) { +void Screen_EoB::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip) { Screen::loadBitmap(filename, tempPage, dstPage, pal); - if (_isAmiga) { - // Yay, this is where EOB1 Amiga hides the palette data - loadPalette(_pagePtrs[dstPage] + 40000, *_palettes[0], 64); - _palettes[0]->fill(0, 1, 0); + Common::SeekableReadStream *str = _vm->resource()->createReadStream(filename); + str->skip(4); + uint32 imgSize = str->readUint32LE(); + delete str; + if (_isAmiga && !skip) { + if ((dstPage == 3 || dstPage == 4) && imgSize == 40064) { + // Yay, this is where EOB1 Amiga hides the palette data + loadPalette(_pagePtrs[dstPage] + 40000, *_palettes[0], 64); + _palettes[0]->fill(0, 1, 0); + } Screen::convertAmigaGfx(getPagePtr(dstPage), 320, 200); } } @@ -1922,6 +1930,223 @@ void OldDOSFont::unload() { _bitmapOffsets = 0; } +AmigaDOSFont::AmigaDOSFont(Resource *res) : _res(res), _width(0), _height(0), _first(0), _last(0), _content(0), _numElements(0), _selectedElement(0), _maxPathLen(256) { + assert(_res); +} + +bool AmigaDOSFont::load(Common::SeekableReadStream &file) { + unload(); + + uint16 id = file.readUint16BE(); + // We only support type 0x0f00, since this is the only type used for EOB + if (id != 0x0f00) + return false; + + _numElements = file.readUint16BE(); + _content = new FontContent[_numElements]; + char *cfile = new char[_maxPathLen]; + + for (int i = 0; i < _numElements; ++i) { + file.read(cfile, _maxPathLen); + _content[i].height = file.readUint16BE();; + _content[i].style = file.readByte(); + _content[i].flags = file.readByte(); + _content[i].contentFile = cfile; + + for (int ii = 0; ii < i; ++ii) { + if (_content[ii].contentFile == _content[i].contentFile && _content[ii].data.get()) + _content[i].data = _content[ii].data; + } + + if (!_content[i].data.get()) { + TextFont *contentData = loadContentFile(cfile); + if (contentData) { + _content[i].data = Common::SharedPtr<TextFont>(contentData); + } else { + unload(); + return false; + } + } + + if (!(_content[i].flags & 0x40) && (_content[i].height != _content[i].data->height)) { + warning("Amiga DOS Font construction / scaling not implemented."); + } + } + + delete[] cfile; + + selectMode(0); + + return true; +} + +int AmigaDOSFont::getCharWidth(uint16 c) const { + if (c < _first || c > _last) + return 0; + c -= _first; + + int width = _content[_selectedElement].data->spacing ? _content[_selectedElement].data->spacing[c] : _content[_selectedElement].data->width; + + /*if (_content[_selectedElement].data->kerning) + width += _content[_selectedElement].data->kerning[c];*/ + + return width; +} + +void AmigaDOSFont::drawChar(uint16 c, byte *dst, int pitch, int) const { + if (c < _first || c > _last || !dst) + return; + + static const uint16 table[] = { + 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, + 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff + }; + + c -= _first; + + int w = _content[_selectedElement].data->spacing ? _content[_selectedElement].data->spacing[c] : _content[_selectedElement].data->width; + int xbits = _content[_selectedElement].data->location[c * 2 + 1]; + int h = _content[_selectedElement].data->height; + + uint16 bitPos = _content[_selectedElement].data->location[c * 2] & 0x0F; + uint16 mod = _content[_selectedElement].data->modulo; + const uint8 *data = _content[_selectedElement].data->bitmap + ((_content[_selectedElement].data->location[c * 2] >> 3) & ~1); + uint32 xbt_mask = xbits ? table[(xbits - 1) & 0x0F] << 16 : 0; + + for (int y = 0; y < h; ++y) { + uint32 mask = 0x80000000; + uint32 bits = (READ_BE_UINT32(data) << bitPos) & xbt_mask; + data += mod; + + for (int x = 0; x < w; ++x) { + if (bits & mask) { + if (_colorMap[1]) + *dst = _colorMap[1]; + } else { + if (_colorMap[0]) + *dst = _colorMap[0]; + } + mask >>= 1; + dst++; + } + dst += (pitch - w); + } +} + +void AmigaDOSFont::unload() { + delete[] _content; +} + +AmigaDOSFont::TextFont *AmigaDOSFont::loadContentFile(const Common::String fileName) { + Common::SeekableReadStreamEndian *str = _res->createEndianAwareReadStream(fileName); + + if (!str && fileName.contains('/')) { + // These content files are usually located in sub directories (i. e. the eobf8.font + // has a sub dir named 'eobf8' with a file '8' in it). In case someone put the content + // files directly in the game directory we still try to open it. + Common::String fileNameAlt = fileName; + while (fileNameAlt.firstChar() != '/') + fileNameAlt.deleteChar(0); + fileNameAlt.deleteChar(0); + + str = _res->createEndianAwareReadStream(fileNameAlt); + + if (!str) { + // Someone might even have copied the floppy disks to the game directory with the + // full sub directory structure. So we also try that... + fileNameAlt = "fonts/"; + fileNameAlt += fileName; + + str = _res->createEndianAwareReadStream(fileNameAlt); + } + + if (!str) { + ::GUI::displayErrorDialog("This AMIGA version requires the following font files:\n\nEOBF6.FONT\nEOBF6/6\nEOBF8.FONT\nEOBF8/8\n\n" + "If you used the orginal installer for the installation these files\nshould be located in the AmigaDOS system 'Fonts/' folder.\n" + "Please copy them into the EOB game data directory.\n"); + error("Failed to load font files."); + } + } + + uint32 hunkId = str->readUint32(); + // Except for some sanity checks we skip all of the Amiga hunk file magic + if (hunkId != 0x03f3) + return 0; + str->seek(20, SEEK_CUR); + + uint32 hunkType = str->readUint32(); + if (hunkType != 0x3E9) + return 0; + uint32 dataSize = str->readUint32() * 4; + int32 hunkStartPos = str->pos(); + + str->seek(34, SEEK_CUR); + TextFont *fnt = new TextFont(); + int32 fntStartPos = str->pos(); + str->seek(44, SEEK_CUR); + fnt->height = str->readUint16(); + str->seek(2, SEEK_CUR); + fnt->width = str->readUint16(); + fnt->baseLine = str->readUint16(); + str->seek(4, SEEK_CUR); + fnt->firstChar = str->readByte(); + fnt->lastChar = str->readByte(); + + str->seek(18, SEEK_CUR); + int32 curPos = str->pos(); + uint32 bufferSize = dataSize - (curPos - fntStartPos); + uint8 *buffer = new uint8[bufferSize]; + str->read(buffer, bufferSize); + + str->seek(curPos - 18, SEEK_SET); + uint32 offset = str->readUint32(); + fnt->bitmap = offset ? buffer + offset - (curPos - hunkStartPos) : 0; + fnt->modulo = str->readUint16(); + + offset = str->readUint32(); + uint16 *loc = (uint16*) (offset ? buffer + offset - (curPos - hunkStartPos) : 0); + for (int i = 0; i <= (fnt->lastChar - fnt->firstChar) * 2 + 1; ++i) + loc[i] = READ_BE_UINT16(&loc[i]); + fnt->location = loc; + + offset = str->readUint32(); + int16 *idat = offset ? (int16*)(buffer + offset - (curPos - hunkStartPos)) : 0; + if (idat) { + for (int i = 0; i <= (fnt->lastChar - fnt->firstChar) * 2 + 1; ++i) + idat[i] = (int16)READ_BE_UINT16(&idat[i]); + } + fnt->spacing = idat; + + offset = str->readUint32(); + // This warning will only show up if someone tries to use this code elsewhere. It cannot happen with EOB fonts. + if (offset) + warning("Trying to load an AmigaDOS font with kerning data. This is not implemented. Font Rendering will not be accurate."); + idat = offset ? (int16*)(buffer + offset - (curPos - hunkStartPos)) : 0; + if (idat) { + for (int i = 0; i <= (fnt->lastChar - fnt->firstChar) * 2 + 1; ++i) + idat[i] = (int16)READ_BE_UINT16(&idat[i]); + } + fnt->kerning = idat; + + fnt->data = buffer; + + delete str; + + return fnt; +} + +void AmigaDOSFont::selectMode(int mode) { + if (mode < 0 || mode > _numElements - 1) + return; + + _selectedElement = mode; + + _width = _content[mode].data->width; + _height = _content[mode].data->height; + _first = _content[mode].data->firstChar; + _last = _content[mode].data->lastChar; +} + SJISFontLarge::SJISFontLarge(Graphics::FontSJIS *font) : SJISFont(font, 0, false, false, false, 0) { _sjisWidth = _font->getMaxFontWidth(); _fontHeight = _font->getFontHeight(); diff --git a/engines/kyra/graphics/screen_eob.h b/engines/kyra/graphics/screen_eob.h index 60290df488..688975548e 100644 --- a/engines/kyra/graphics/screen_eob.h +++ b/engines/kyra/graphics/screen_eob.h @@ -45,7 +45,7 @@ public: void loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size); - void printShadedText(const char *string, int x, int y, int col1, int col2); + void printShadedText(const char *string, int x, int y, int col1, int col2, int shadowCol); virtual void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip = false); void loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage); diff --git a/engines/kyra/resource/resource.cpp b/engines/kyra/resource/resource.cpp index 19603a1cf9..bbafc1bf86 100644 --- a/engines/kyra/resource/resource.cpp +++ b/engines/kyra/resource/resource.cpp @@ -339,7 +339,8 @@ Common::SeekableReadStream *Resource::createReadStream(const Common::String &fil } Common::SeekableReadStreamEndian *Resource::createEndianAwareReadStream(const Common::String &file) { - return new EndianAwareStreamWrapper(_files.createReadStreamForMember(file), _vm->gameFlags().platform == Common::kPlatformAmiga); + Common::SeekableReadStream *stream = _files.createReadStreamForMember(file); + return stream ? new EndianAwareStreamWrapper(stream, _vm->gameFlags().platform == Common::kPlatformAmiga) : 0; } Common::Archive *Resource::loadArchive(const Common::String &name, Common::ArchiveMemberPtr member) { |