/* 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 . * * Text utilities. */ #include "tinsel/dw.h" #include "tinsel/graphics.h" // object plotting #include "tinsel/handle.h" #include "tinsel/sched.h" // process scheduler defines #include "tinsel/strres.h" // g_bMultiByte #include "tinsel/text.h" // text defines namespace Tinsel { //----------------- LOCAL GLOBAL DATA -------------------- /** TinselV3, base color for the text color replacement */ static uint32 g_t3fontBaseColor; /** * Returns the length of one line of a string in pixels. * @param szStr String * @param pFont Which font to use for dimensions */ int StringLengthPix(char *szStr, const FONT *pFont) { int strLen; // accumulated length of string byte c; SCNHANDLE hImg; // while not end of string or end of line for (strLen = 0; (c = *szStr) != EOS_CHAR && c != LF_CHAR; szStr++) { if (g_bMultiByte) { if (c & 0x80) c = ((c & ~0x80) << 8) + *++szStr; } hImg = pFont->fontDef[c]; if (hImg) { // there is a IMAGE for this character const IMAGE *pChar = _vm->_handle->GetImage(hImg); // add width of font bitmap strLen += pChar->imgWidth; delete pChar; } else // use width of space character strLen += pFont->spaceSize; // finally add the inter-character spacing strLen += pFont->xSpacing; } // return length of line in pixels - minus inter-char spacing for last character strLen -= pFont->xSpacing; return (strLen > 0) ? strLen : 0; } /** * Returns the justified x start position of a line of text. * @param szStr String to output * @param xPos X position of string * @param pFont Which font to use * @param mode Mode flags for the string */ int JustifyText(char *szStr, int xPos, const FONT *pFont, int mode) { if (mode & TXT_CENTER) { // center justify the text // adjust x positioning by half the length of line in pixels xPos -= StringLengthPix(szStr, pFont) / 2; } else if (mode & TXT_RIGHT) { // right justify the text // adjust x positioning by length of line in pixels xPos -= StringLengthPix(szStr, pFont); } // return text line x start position return xPos; } /** * Main text outputting routine. If a object list is specified a * multi-object is created for the whole text and a pointer to the head * of the list is returned. * @param pList Object list to add text to * @param szStr String to output * @param color Color for monochrome text * @param xPos X position of string * @param yPos Y position of string * @param hFont Which font to use * @param mode Mode flags for the string * @param sleepTime Sleep time between each character (if non-zero) */ OBJECT *ObjectTextOut(OBJECT **pList, char *szStr, int color, int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime) { int xJustify; // x position of text after justification int yOffset; // offset to next line of text OBJECT *pFirst; // head of multi-object text list OBJECT *pChar = 0; // object ptr for the character byte c; SCNHANDLE hImg; // make sure there is a linked list to add text to assert(pList); // get font pointer FONT *pFont = _vm->_handle->GetFont(hFont); const OBJ_INIT *pFontInit = &pFont->fontInit; // init head of text list pFirst = nullptr; // get image for capital W SCNHANDLE imgHandle = pFont->fontDef[(int)'W']; assert(imgHandle); // get height of capital W for offset to next line const IMAGE *pImgCapitalW = _vm->_handle->GetImage(imgHandle); yOffset = pImgCapitalW->imgHeight & ~C16_FLAG_MASK; delete pImgCapitalW; while (*szStr) { // x justify the text according to the mode flags xJustify = JustifyText(szStr, xPos, pFont, mode); // repeat until end of string or end of line while ((c = *szStr) != EOS_CHAR && c != LF_CHAR) { if (g_bMultiByte) { if (c & 0x80) c = ((c & ~0x80) << 8) + *++szStr; } hImg = pFont->fontDef[c]; if (hImg == 0) { // no image for this character // add font spacing for a space character xJustify += pFont->spaceSize; } else { // printable character int aniX, aniY; // char image animation offsets // allocate and init a character object if (pFirst == NULL) // first time - init head of list pFirst = pChar = InitObject(pFontInit); else // chain to multi-char list pChar = pChar->pSlave = InitObject(pFontInit); // convert image handle to pointer const IMAGE *pImg = _vm->_handle->GetImage(hImg); // fill in character object pChar->hImg = hImg; // image def pChar->width = pImg->imgWidth; // width of chars bitmap pChar->height = pImg->imgHeight & ~C16_FLAG_MASK; // height of chars bitmap pChar->hBits = pImg->hImgBits; // bitmap // check for absolute positioning if (mode & TXT_ABSOLUTE) pChar->flags |= DMA_ABS; // set characters color - only effective for mono fonts pChar->constant = color; // set the base font color to be replaced with supplied color, only for Tinsel V3 g_t3fontBaseColor = TinselV3 ? pFont->baseColor : 0; // get Y animation offset GetAniOffset(hImg, pChar->flags, &aniX, &aniY); // set x position - ignore animation point pChar->xPos = intToFrac(xJustify); // set y position - adjust for animation point pChar->yPos = intToFrac(yPos - aniY); if (mode & TXT_SHADOW) { // we want to shadow the character OBJECT *pShad; // allocate a object for the shadow and chain to multi-char list pShad = pChar->pSlave = AllocObject(); // copy the character for a shadow CopyObject(pShad, pChar); // add shadow offsets to characters position pShad->xPos += intToFrac(pFont->xShadow); pShad->yPos += intToFrac(pFont->yShadow); // shadow is behind the character pShad->zPos--; // shadow is always mono pShad->flags = DMA_CNZ | DMA_CHANGED; // check for absolute positioning if (mode & TXT_ABSOLUTE) pShad->flags |= DMA_ABS; // shadow always uses first palette entry // should really alloc a palette here also ???? pShad->constant = 1; // add shadow to object list InsertObject(pList, pShad); } // add character to object list InsertObject(pList, pChar); // move to end of list if (pChar->pSlave) pChar = pChar->pSlave; // add character spacing xJustify += pImg->imgWidth; delete pImg; } // finally add the inter-character spacing xJustify += pFont->xSpacing; // next character in string ++szStr; } // adjust the text y position and add the inter-line spacing yPos += yOffset + pFont->ySpacing; // check for newline if (c == LF_CHAR) // next character in string ++szStr; } delete pFont; // return head of list return pFirst; } /** * Is there an image for this character in this font? * @param hFont which font to use * @param c character to test */ bool IsCharImage(SCNHANDLE hFont, char c) { byte c2 = (byte)c; // Inventory save game name editor needs to be more clever for // multi-byte characters. This bodge will stop it erring. if (g_bMultiByte && (c2 & 0x80)) return false; // get font pointer FONT *pFont = _vm->_handle->GetFont(hFont); bool result = pFont->fontDef[c2] != 0; delete pFont; return result; } uint32 t3GetBaseColor() { return g_t3fontBaseColor; } } // End of namespace Tinsel