/* 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. * * 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 { /** * 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 = FROM_32(pFont->fontDef[c]); if (hImg) { // there is a IMAGE for this character const IMAGE *pChar = (const IMAGE *)LockMem(hImg); // add width of font bitmap strLen += FROM_16(pChar->imgWidth); } else // use width of space character strLen += FROM_32(pFont->spaceSize); // finally add the inter-character spacing strLen += FROM_32(pFont->xSpacing); } // return length of line in pixels - minus inter-char spacing for last character strLen -= FROM_32(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; const IMAGE *pImg; // make sure there is a linked list to add text to assert(pList); // get font pointer const FONT *pFont = (const FONT *)LockMem(hFont); // init head of text list pFirst = NULL; // get image for capital W assert(pFont->fontDef[(int)'W']); pImg = (const IMAGE *)LockMem(FROM_32(pFont->fontDef[(int)'W'])); // get height of capital W for offset to next line yOffset = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK; 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 = FROM_32(pFont->fontDef[c]); if (hImg == 0) { // no image for this character // add font spacing for a space character xJustify += FROM_32(pFont->spaceSize); } else { // printable character int aniX, aniY; // char image animation offsets OBJ_INIT oi; oi.hObjImg = FROM_32(pFont->fontInit.hObjImg); oi.objFlags = FROM_32(pFont->fontInit.objFlags); oi.objID = FROM_32(pFont->fontInit.objID); oi.objX = FROM_32(pFont->fontInit.objX); oi.objY = FROM_32(pFont->fontInit.objY); oi.objZ = FROM_32(pFont->fontInit.objZ); // allocate and init a character object if (pFirst == NULL) // first time - init head of list pFirst = pChar = InitObject(&oi); // FIXME: endian issue using fontInit!!! else // chain to multi-char list pChar = pChar->pSlave = InitObject(&oi); // FIXME: endian issue using fontInit!!! // convert image handle to pointer pImg = (const IMAGE *)LockMem(hImg); // fill in character object pChar->hImg = hImg; // image def pChar->width = FROM_16(pImg->imgWidth); // width of chars bitmap pChar->height = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK; // height of chars bitmap pChar->hBits = FROM_32(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; // 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(FROM_32(pFont->xShadow)); pShad->yPos += intToFrac(FROM_32(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 += FROM_16(pImg->imgWidth); } // finally add the inter-character spacing xJustify += FROM_32(pFont->xSpacing); // next character in string ++szStr; } // adjust the text y position and add the inter-line spacing yPos += yOffset + FROM_32(pFont->ySpacing); // check for newline if (c == LF_CHAR) // next character in string ++szStr; } // 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 const FONT *pFont = (const FONT *)LockMem(hFont); return pFont->fontDef[c2] != 0; } } // End of namespace Tinsel