From 26ee630756ebdd7c96bccede0881a8c8b98e8f2b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 11 Feb 2006 22:45:04 +0000 Subject: Moved engines to the new engines/ directory svn-id: r20582 --- saga/font.cpp | 681 ---------------------------------------------------------- 1 file changed, 681 deletions(-) delete mode 100644 saga/font.cpp (limited to 'saga/font.cpp') diff --git a/saga/font.cpp b/saga/font.cpp deleted file mode 100644 index 9a91bf4872..0000000000 --- a/saga/font.cpp +++ /dev/null @@ -1,681 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2004-2006 The ScummVM project - * - * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. - * - * 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$ - * - */ - -// Font management and font drawing module -#include "saga/saga.h" -#include "saga/gfx.h" -#include "saga/rscfile.h" - -#include "saga/font.h" -#include "saga/stream.h" - -namespace Saga { - -Font::Font(SagaEngine *vm) : _vm(vm), _initialized(false) { - int i; - - // Load font module resource context - - assert(_vm->getFontsCount() > 0); - - _fonts = (FontData **)calloc(_vm->getFontsCount(), sizeof(*_fonts)); - _loadedFonts = 0; - - for (i = 0; i < _vm->getFontsCount(); i++) { - loadFont(_vm->getFontDescription(i)->fontResourceId); - } - - _initialized = true; -} - -Font::~Font(void) { - debug(8, "Font::~Font(): Freeing fonts."); - int i; - - for (i = 0 ; i < _loadedFonts ; i++) { - if (_fonts[i] != NULL) { - free(_fonts[i]->normal.font); - free(_fonts[i]->outline.font); - } - - free(_fonts[i]); - } -} - - -void Font::loadFont(uint32 fontResourceId) { - FontData *font; - byte *fontResourcePointer; - size_t fontResourceLength; - int numBits; - int c; - ResourceContext *fontContext; - - debug(1, "Font::loadFont(): Reading fontResourceId %d...", fontResourceId); - - fontContext = _vm->_resource->getContext(GAME_RESOURCEFILE); - if (fontContext == NULL) { - error("Font::Font() resource context not found"); - } - - // Load font resource - _vm->_resource->loadResource(fontContext, fontResourceId, fontResourcePointer, fontResourceLength); - - if (fontResourceLength < FONT_DESCSIZE) { - error("Font::loadFont() Invalid font length (%i < %i)", fontResourceLength, FONT_DESCSIZE); - } - - MemoryReadStreamEndian readS(fontResourcePointer, fontResourceLength, fontContext->isBigEndian); - - // Create new font structure - font = (FontData *)malloc(sizeof(*font)); - - // Read font header - font->normal.header.charHeight = readS.readUint16(); - font->normal.header.charWidth = readS.readUint16(); - font->normal.header.rowLength = readS.readUint16(); - - - debug(2, "Character width: %d", font->normal.header.charWidth); - debug(2, "Character height: %d", font->normal.header.charHeight); - debug(2, "Row padding: %d", font->normal.header.rowLength); - - for (c = 0; c < FONT_CHARCOUNT; c++) { - font->normal.fontCharEntry[c].index = readS.readUint16(); - } - - for (c = 0; c < FONT_CHARCOUNT; c++) { - numBits = font->normal.fontCharEntry[c].width = readS.readByte(); - font->normal.fontCharEntry[c].byteWidth = getByteLen(numBits); - } - - for (c = 0; c < FONT_CHARCOUNT; c++) { - font->normal.fontCharEntry[c].flag = readS.readByte(); - } - - for (c = 0; c < FONT_CHARCOUNT; c++) { - font->normal.fontCharEntry[c].tracking = readS.readByte(); - } - - if (readS.pos() != FONT_DESCSIZE) { - error("Invalid font resource size."); - } - - font->normal.font = (byte*)malloc(fontResourceLength - FONT_DESCSIZE); - memcpy(font->normal.font, fontResourcePointer + FONT_DESCSIZE, fontResourceLength - FONT_DESCSIZE); - - free(fontResourcePointer); - - - // Create outline font style - createOutline(font); - - // Set font data - _fonts[_loadedFonts++] = font; -} - -void Font::createOutline(FontData *font) { - int i; - int row; - int newByteWidth; - int oldByteWidth; - int newRowLength = 0; - size_t indexOffset = 0; - int index; - int currentByte; - unsigned char *basePointer; - unsigned char *srcPointer; - unsigned char *destPointer1; - unsigned char *destPointer2; - unsigned char *destPointer3; - unsigned char charRep; - - - // Populate new font style character data - for (i = 0; i < FONT_CHARCOUNT; i++) { - newByteWidth = 0; - oldByteWidth = 0; - index = font->normal.fontCharEntry[i].index; - if ((index > 0) || (i == FONT_FIRSTCHAR)) { - index += indexOffset; - } - - font->outline.fontCharEntry[i].index = index; - font->outline.fontCharEntry[i].tracking = font->normal.fontCharEntry[i].tracking; - font->outline.fontCharEntry[i].flag = font->normal.fontCharEntry[i].flag; - - if (font->normal.fontCharEntry[i].width != 0) { - newByteWidth = getByteLen(font->normal.fontCharEntry[i].width + 2); - oldByteWidth = getByteLen(font->normal.fontCharEntry[i].width); - - if (newByteWidth > oldByteWidth) { - indexOffset++; - } - } - - font->outline.fontCharEntry[i].width = font->normal.fontCharEntry[i].width + 2; - font->outline.fontCharEntry[i].byteWidth = newByteWidth; - newRowLength += newByteWidth; - } - - debug(2, "New row length: %d", newRowLength); - - font->outline.header = font->normal.header; - font->outline.header.charWidth += 2; - font->outline.header.charHeight += 2; - font->outline.header.rowLength = newRowLength; - - // Allocate new font representation storage - font->outline.font = (unsigned char *)calloc(newRowLength, font->outline.header.charHeight); - - - // Generate outline font representation - for (i = 0; i < FONT_CHARCOUNT; i++) { - for (row = 0; row < font->normal.header.charHeight; row++) { - for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) { - basePointer = font->outline.font + font->outline.fontCharEntry[i].index + currentByte; - destPointer1 = basePointer + newRowLength * row; - destPointer2 = basePointer + newRowLength * (row + 1); - destPointer3 = basePointer + newRowLength * (row + 2); - if (currentByte > 0) { - // Get last two columns from previous byte - srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1); - charRep = *srcPointer; - *destPointer1 |= ((charRep << 6) | (charRep << 7)); - *destPointer2 |= ((charRep << 6) | (charRep << 7)); - *destPointer3 |= ((charRep << 6) | (charRep << 7)); - } - - if (currentByte < font->normal.fontCharEntry[i].byteWidth) { - srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte; - charRep = *srcPointer; - *destPointer1 |= charRep | (charRep >> 1) | (charRep >> 2); - *destPointer2 |= charRep | (charRep >> 1) | (charRep >> 2); - *destPointer3 |= charRep | (charRep >> 1) | (charRep >> 2); - } - } - } - - // "Hollow out" character to prevent overdraw - for (row = 0; row < font->normal.header.charHeight; row++) { - for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) { - destPointer2 = font->outline.font + font->outline.header.rowLength * (row + 1) + font->outline.fontCharEntry[i].index + currentByte; - if (currentByte > 0) { - // Get last two columns from previous byte - srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1); - *destPointer2 &= ((*srcPointer << 7) ^ 0xFFU); - } - - if (currentByte < font->normal.fontCharEntry[i].byteWidth) { - srcPointer = font->normal.font + font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte; - *destPointer2 &= ((*srcPointer >> 1) ^ 0xFFU); - } - } - } - } -} - -// Returns the horizontal length in pixels of the graphical representation -// of at most 'count' characters of the string 'text', taking -// into account any formatting options specified by 'flags'. -// If 'count' is 0, all characters of 'test' are counted. -int Font::getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) { - FontData *font; - size_t ct; - int width = 0; - int ch; - const byte *txt; - - - font = getFont(fontId); - - txt = (const byte *) text; - - for (ct = count; *txt && (!count || ct > 0); txt++, ct--) { - ch = *txt & 0xFFU; - // Translate character - ch = _charMap[ch]; - assert(ch < FONT_CHARCOUNT); - width += font->normal.fontCharEntry[ch].tracking; - } - - if ((flags & kFontBold) || (flags & kFontOutline)) { - width += 1; - } - - return width; -} - - -void Font::draw(FontId fontId, Surface *ds, const char *text, size_t count, const Common::Point &point, - int color, int effectColor, FontEffectFlags flags) { - FontData *font; - Point offsetPoint(point); - - font = getFont(fontId); - - if (flags & kFontOutline) { - offsetPoint.x--; - offsetPoint.y--; - outFont(font->outline, ds, text, count, offsetPoint, effectColor, flags); - outFont(font->normal, ds, text, count, point, color, flags); - } else if (flags & kFontShadow) { - offsetPoint.x--; - offsetPoint.y++; - outFont(font->normal, ds, text, count, offsetPoint, effectColor, flags); - outFont(font->normal, ds, text, count, point, color, flags); - } else { // FONT_NORMAL - outFont(font->normal, ds, text, count, point, color, flags); - } -} - -void Font::outFont(const FontStyle &drawFont, Surface *ds, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags) { - const byte *textPointer; - byte *c_dataPointer; - int c_code; - int charRow; - Point textPoint(point); - - byte *outputPointer; - byte *outputPointer_min; - byte *outputPointer_max; - - int row; - int rowLimit; - - int c_byte_len; - int c_byte; - int c_bit; - int ct; - - if ((point.x > ds->w) || (point.y > ds->h)) { - // Output string can't be visible - return; - } - - textPointer = (const byte *)text; - ct = count; - - // Draw string one character at a time, maximum of 'draw_str'_ct - // characters, or no limit if 'draw_str_ct' is 0 - for (; *textPointer && (!count || ct); textPointer++, ct--) { - c_code = *textPointer & 0xFFU; - - // Translate character - if (!(flags & kFontDontmap)) - c_code = _charMap[c_code]; - assert(c_code < FONT_CHARCOUNT); - - // Check if character is defined - if ((drawFont.fontCharEntry[c_code].index == 0) && (c_code != FONT_FIRSTCHAR)) { -#if FONT_SHOWUNDEFINED - if (c_code == FONT_CH_SPACE) { - textPoint.x += drawFont.fontCharEntry[c_code].tracking; - continue; - } - c_code = FONT_CH_QMARK; -#else - // Character code is not defined, but advance tracking - // ( Not defined if offset is 0, except for 33 ('!') which - // is defined ) - textPoint.x += drawFont.fontCharEntry[c_code].tracking; - continue; -#endif - } - - // Get length of character in bytes - c_byte_len = ((drawFont.fontCharEntry[c_code].width - 1) / 8) + 1; - rowLimit = (ds->h < (textPoint.y + drawFont.header.charHeight)) ? ds->h : textPoint.y + drawFont.header.charHeight; - charRow = 0; - - for (row = textPoint.y; row < rowLimit; row++, charRow++) { - // Clip negative rows */ - if (row < 0) { - continue; - } - - outputPointer = (byte *)ds->pixels + (ds->pitch * row) + textPoint.x; - outputPointer_min = (byte *)ds->pixels + (ds->pitch * row) + (textPoint.x > 0 ? textPoint.x : 0); - outputPointer_max = outputPointer + (ds->pitch - textPoint.x); - - // If character starts off the screen, jump to next character - if (outputPointer < outputPointer_min) { - break; - } - - c_dataPointer = drawFont.font + charRow * drawFont.header.rowLength + drawFont.fontCharEntry[c_code].index; - - for (c_byte = 0; c_byte < c_byte_len; c_byte++, c_dataPointer++) { - // Check each bit, draw pixel if bit is set - for (c_bit = 7; c_bit >= 0 && (outputPointer < outputPointer_max); c_bit--) { - if ((*c_dataPointer >> c_bit) & 0x01) { - *outputPointer = (byte)color; - } - outputPointer++; - } // end per-bit processing - } // end per-byte processing - } // end per-row processing - - // Advance tracking position - textPoint.x += drawFont.fontCharEntry[c_code].tracking; - } // end per-character processing -} - - -void Font::textDraw(FontId fontId, Surface *ds, const char *text, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) { - int textWidth; - int textLength; - int fitWidth; - Common::Point textPoint(point); - - textLength = strlen(text); - - if (!(flags & kFontCentered)) { - // Text is not centered; No formatting required - draw(fontId, ds, text, textLength, point, color, effectColor, flags); - return; - } - - // Text is centered... format output - // Enforce minimum and maximum center points for centered text - if (textPoint.x < TEXT_CENTERLIMIT) { - textPoint.x = TEXT_CENTERLIMIT; - } - - if (textPoint.x > ds->w - TEXT_CENTERLIMIT) { - textPoint.x = ds->w - TEXT_CENTERLIMIT; - } - - if (textPoint.x < (TEXT_MARGIN * 2)) { - // Text can't be centered if it's too close to the margin - return; - } - - textWidth = getStringWidth(fontId, text, textLength, flags); - - if (textPoint.x < (ds->w / 2)) { - // Fit to right side - fitWidth = (textPoint.x - TEXT_MARGIN) * 2; - } else { - // Fit to left side - fitWidth = ((ds->w - TEXT_MARGIN) - textPoint.x) * 2; - } - - if (fitWidth < textWidth) { - warning("text too long to be displayed in one line"); - textWidth = fitWidth; - } - // Entire string fits, draw it - textPoint.x = textPoint.x - (textWidth / 2); - draw(fontId, ds, text, textLength, textPoint, color, effectColor, flags); -} - -int Font::getHeight(FontId fontId, const char *text, int width, FontEffectFlags flags) { - int textWidth; - int textLength; - int fitWidth; - const char *startPointer; - const char *searchPointer; - const char *measurePointer; - const char *foundPointer; - int len; - int w; - const char *endPointer; - int h; - int wc; - int w_total; - int len_total; - Common::Point textPoint; - Common::Point textPoint2; - - textLength = strlen(text); - - textWidth = getStringWidth(fontId, text, textLength, flags); - h = getHeight(fontId); - fitWidth = width; - - textPoint.x = (fitWidth / 2); - textPoint.y = 0; - - if (fitWidth >= textWidth) { - return h; - } - - // String won't fit on one line - w_total = 0; - len_total = 0; - wc = 0; - - startPointer = text; - measurePointer = text; - searchPointer = text; - endPointer = text + textLength; - - for (;;) { - foundPointer = strchr(searchPointer, ' '); - if (foundPointer == NULL) { - // Ran to the end of the buffer - len = endPointer - measurePointer; - } else { - len = foundPointer - measurePointer; - } - - w = getStringWidth(fontId, measurePointer, len, flags); - measurePointer = foundPointer; - - if ((w_total + w) > fitWidth) { - // This word won't fit - if (wc == 0) { - // The first word in the line didn't fit. Still print it - searchPointer = measurePointer + 1; - } - // Wrap what we've got and restart - textPoint.y += h + TEXT_LINESPACING; - if (foundPointer == NULL) { - // Since word hit NULL but fit, we are done - return textPoint.y + h; - } - w_total = 0; - len_total = 0; - wc = 0; - measurePointer = searchPointer; - startPointer = searchPointer; - } else { - // Word will fit ok - w_total += w; - len_total += len; - wc++; - if (foundPointer == NULL) { - // Since word hit NULL but fit, we are done - return textPoint.y + h; - } - searchPointer = measurePointer + 1; - } - } -} - -void Font::textDrawRect(FontId fontId, Surface *ds, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags) { - int textWidth; - int textLength; - int fitWidth; - const char *startPointer; - const char *searchPointer; - const char *measurePointer; - const char *foundPointer; - int len; - int w; - const char *endPointer; - int h; - int wc; - int w_total; - int len_total; - Common::Point textPoint; - Common::Point textPoint2; - - textLength = strlen(text); - - textWidth = getStringWidth(fontId, text, textLength, flags); - fitWidth = rect.width(); - - textPoint.x = rect.left + (fitWidth / 2); - textPoint.y = rect.top; - - if (fitWidth >= textWidth) { - // Entire string fits, draw it - textPoint.x -= (textWidth / 2); - draw(fontId, ds, text, textLength, textPoint, color, effectColor, flags); - return; - } - - // String won't fit on one line - h = getHeight(fontId); - w_total = 0; - len_total = 0; - wc = 0; - - startPointer = text; - measurePointer = text; - searchPointer = text; - endPointer = text + textLength; - - for (;;) { - foundPointer = strchr(searchPointer, ' '); - if (foundPointer == NULL) { - // Ran to the end of the buffer - len = endPointer - measurePointer; - } else { - len = foundPointer - measurePointer; - } - - w = getStringWidth(fontId, measurePointer, len, flags); - measurePointer = foundPointer; - - if ((w_total + w) > fitWidth) { - // This word won't fit - if (wc == 0) { - w_total = fitWidth; - len_total = len; - } - - // Wrap what we've got and restart - textPoint2.x = textPoint.x - (w_total / 2); - textPoint2.y = textPoint.y; - draw(fontId, ds, startPointer, len_total, textPoint2, color, effectColor, flags); - textPoint.y += h + TEXT_LINESPACING; - if (textPoint.y >= rect.bottom) { - return; - } - w_total = 0; - len_total = 0; - if (wc == 0) { - searchPointer = measurePointer + 1; - } - wc = 0; - - // Advance the search pointer to the next non-space. - // Otherwise, the first "word" to be measured will be - // an empty string. Measuring or drawing a string of - // length 0 is interpreted as measure/draw the entire - // buffer, which certainly is not what we want here. - // - // This happes because a string may contain several - // spaces in a row, e.g. after a period. - - while (*searchPointer == ' ') - searchPointer++; - - measurePointer = searchPointer; - startPointer = searchPointer; - } else { - // Word will fit ok - w_total += w; - len_total += len; - wc++; - if (foundPointer == NULL) { - // Since word hit NULL but fit, we are done - textPoint2.x = textPoint.x - (w_total / 2); - textPoint2.y = textPoint.y; - draw(fontId, ds, startPointer, len_total, textPoint2, color, - effectColor, flags); - return; - } - searchPointer = measurePointer + 1; - } - } -} - -Font::FontId Font::knownFont2FontIdx(KnownFont font) { - FontId fontId = kSmallFont; - - if (_vm->getGameType() == GType_ITE) { - switch (font) - { - case (kKnownFontSmall): - fontId = kSmallFont; - break; - case (kKnownFontMedium): - fontId = kMediumFont; - break; - case (kKnownFontBig): - fontId = kBigFont; - break; - - case (kKnownFontVerb): - fontId = kSmallFont; - break; - case (kKnownFontScript): - fontId = kMediumFont; - break; - case (kKnownFontPause): - fontId = _vm->_font->valid(kBigFont) ? kBigFont : kMediumFont; - break; - } - } else if (_vm->getGameType() == GType_IHNM) { - switch (font) - { - case (kKnownFontSmall): - fontId = kSmallFont; - break; - case (kKnownFontMedium): - fontId = kMediumFont; - break; - case (kKnownFontBig): - fontId = kBigFont; - break; - - case (kKnownFontVerb): - fontId = kIHNMFont8; - break; - case (kKnownFontScript): - fontId = kIHNMMainFont; - break; - case (kKnownFontPause): - fontId = kMediumFont; // unchecked - break; - } - } - return fontId; -} - -} // End of namespace Saga -- cgit v1.2.3