1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * Text utilities.
22 */
23
24 #include "tinsel/dw.h"
25 #include "tinsel/graphics.h" // object plotting
26 #include "tinsel/handle.h"
27 #include "tinsel/sched.h" // process scheduler defines
28 #include "tinsel/strres.h" // g_bMultiByte
29 #include "tinsel/text.h" // text defines
30
31 namespace Tinsel {
32
33 /**
34 * Returns the length of one line of a string in pixels.
35 * @param szStr String
36 * @param pFont Which font to use for dimensions
37 */
StringLengthPix(char * szStr,const FONT * pFont)38 int StringLengthPix(char *szStr, const FONT *pFont) {
39 int strLen; // accumulated length of string
40 byte c;
41 SCNHANDLE hImg;
42
43 // while not end of string or end of line
44 for (strLen = 0; (c = *szStr) != EOS_CHAR && c != LF_CHAR; szStr++) {
45 if (g_bMultiByte) {
46 if (c & 0x80)
47 c = ((c & ~0x80) << 8) + *++szStr;
48 }
49 hImg = FROM_32(pFont->fontDef[c]);
50
51 if (hImg) {
52 // there is a IMAGE for this character
53 const IMAGE *pChar = (const IMAGE *)LockMem(hImg);
54
55 // add width of font bitmap
56 strLen += FROM_16(pChar->imgWidth);
57 } else
58 // use width of space character
59 strLen += FROM_32(pFont->spaceSize);
60
61 // finally add the inter-character spacing
62 strLen += FROM_32(pFont->xSpacing);
63 }
64
65 // return length of line in pixels - minus inter-char spacing for last character
66 strLen -= FROM_32(pFont->xSpacing);
67 return (strLen > 0) ? strLen : 0;
68 }
69
70 /**
71 * Returns the justified x start position of a line of text.
72 * @param szStr String to output
73 * @param xPos X position of string
74 * @param pFont Which font to use
75 * @param mode Mode flags for the string
76 */
JustifyText(char * szStr,int xPos,const FONT * pFont,int mode)77 int JustifyText(char *szStr, int xPos, const FONT *pFont, int mode) {
78 if (mode & TXT_CENTER) {
79 // center justify the text
80
81 // adjust x positioning by half the length of line in pixels
82 xPos -= StringLengthPix(szStr, pFont) / 2;
83 } else if (mode & TXT_RIGHT) {
84 // right justify the text
85
86 // adjust x positioning by length of line in pixels
87 xPos -= StringLengthPix(szStr, pFont);
88 }
89
90 // return text line x start position
91 return xPos;
92 }
93
94 /**
95 * Main text outputting routine. If a object list is specified a
96 * multi-object is created for the whole text and a pointer to the head
97 * of the list is returned.
98 * @param pList Object list to add text to
99 * @param szStr String to output
100 * @param color Color for monochrome text
101 * @param xPos X position of string
102 * @param yPos Y position of string
103 * @param hFont Which font to use
104 * @param mode Mode flags for the string
105 * @param sleepTime Sleep time between each character (if non-zero)
106 */
ObjectTextOut(OBJECT ** pList,char * szStr,int color,int xPos,int yPos,SCNHANDLE hFont,int mode,int sleepTime)107 OBJECT *ObjectTextOut(OBJECT **pList, char *szStr, int color,
108 int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime) {
109 int xJustify; // x position of text after justification
110 int yOffset; // offset to next line of text
111 OBJECT *pFirst; // head of multi-object text list
112 OBJECT *pChar = 0; // object ptr for the character
113 byte c;
114 SCNHANDLE hImg;
115 const IMAGE *pImg;
116
117 // make sure there is a linked list to add text to
118 assert(pList);
119
120 // get font pointer
121 const FONT *pFont = (const FONT *)LockMem(hFont);
122
123 // init head of text list
124 pFirst = NULL;
125
126 // get image for capital W
127 assert(pFont->fontDef[(int)'W']);
128 pImg = (const IMAGE *)LockMem(FROM_32(pFont->fontDef[(int)'W']));
129
130 // get height of capital W for offset to next line
131 yOffset = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK;
132
133 while (*szStr) {
134 // x justify the text according to the mode flags
135 xJustify = JustifyText(szStr, xPos, pFont, mode);
136
137 // repeat until end of string or end of line
138 while ((c = *szStr) != EOS_CHAR && c != LF_CHAR) {
139 if (g_bMultiByte) {
140 if (c & 0x80)
141 c = ((c & ~0x80) << 8) + *++szStr;
142 }
143 hImg = FROM_32(pFont->fontDef[c]);
144
145 if (hImg == 0) {
146 // no image for this character
147
148 // add font spacing for a space character
149 xJustify += FROM_32(pFont->spaceSize);
150 } else { // printable character
151
152 int aniX, aniY; // char image animation offsets
153
154 OBJ_INIT oi;
155 oi.hObjImg = FROM_32(pFont->fontInit.hObjImg);
156 oi.objFlags = FROM_32(pFont->fontInit.objFlags);
157 oi.objID = FROM_32(pFont->fontInit.objID);
158 oi.objX = FROM_32(pFont->fontInit.objX);
159 oi.objY = FROM_32(pFont->fontInit.objY);
160 oi.objZ = FROM_32(pFont->fontInit.objZ);
161
162 // allocate and init a character object
163 if (pFirst == NULL)
164 // first time - init head of list
165 pFirst = pChar = InitObject(&oi); // FIXME: endian issue using fontInit!!!
166 else
167 // chain to multi-char list
168 pChar = pChar->pSlave = InitObject(&oi); // FIXME: endian issue using fontInit!!!
169
170 // convert image handle to pointer
171 pImg = (const IMAGE *)LockMem(hImg);
172
173 // fill in character object
174 pChar->hImg = hImg; // image def
175 pChar->width = FROM_16(pImg->imgWidth); // width of chars bitmap
176 pChar->height = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK; // height of chars bitmap
177 pChar->hBits = FROM_32(pImg->hImgBits); // bitmap
178
179 // check for absolute positioning
180 if (mode & TXT_ABSOLUTE)
181 pChar->flags |= DMA_ABS;
182
183 // set characters color - only effective for mono fonts
184 pChar->constant = color;
185
186 // get Y animation offset
187 GetAniOffset(hImg, pChar->flags, &aniX, &aniY);
188
189 // set x position - ignore animation point
190 pChar->xPos = intToFrac(xJustify);
191
192 // set y position - adjust for animation point
193 pChar->yPos = intToFrac(yPos - aniY);
194
195 if (mode & TXT_SHADOW) {
196 // we want to shadow the character
197 OBJECT *pShad;
198
199 // allocate a object for the shadow and chain to multi-char list
200 pShad = pChar->pSlave = AllocObject();
201
202 // copy the character for a shadow
203 CopyObject(pShad, pChar);
204
205 // add shadow offsets to characters position
206 pShad->xPos += intToFrac(FROM_32(pFont->xShadow));
207 pShad->yPos += intToFrac(FROM_32(pFont->yShadow));
208
209 // shadow is behind the character
210 pShad->zPos--;
211
212 // shadow is always mono
213 pShad->flags = DMA_CNZ | DMA_CHANGED;
214
215 // check for absolute positioning
216 if (mode & TXT_ABSOLUTE)
217 pShad->flags |= DMA_ABS;
218
219 // shadow always uses first palette entry
220 // should really alloc a palette here also ????
221 pShad->constant = 1;
222
223 // add shadow to object list
224 InsertObject(pList, pShad);
225 }
226
227 // add character to object list
228 InsertObject(pList, pChar);
229
230 // move to end of list
231 if (pChar->pSlave)
232 pChar = pChar->pSlave;
233
234 // add character spacing
235 xJustify += FROM_16(pImg->imgWidth);
236 }
237
238 // finally add the inter-character spacing
239 xJustify += FROM_32(pFont->xSpacing);
240
241 // next character in string
242 ++szStr;
243 }
244
245 // adjust the text y position and add the inter-line spacing
246 yPos += yOffset + FROM_32(pFont->ySpacing);
247
248 // check for newline
249 if (c == LF_CHAR)
250 // next character in string
251 ++szStr;
252 }
253
254 // return head of list
255 return pFirst;
256 }
257
258 /**
259 * Is there an image for this character in this font?
260 * @param hFont which font to use
261 * @param c character to test
262 */
IsCharImage(SCNHANDLE hFont,char c)263 bool IsCharImage(SCNHANDLE hFont, char c) {
264 byte c2 = (byte)c;
265
266 // Inventory save game name editor needs to be more clever for
267 // multi-byte characters. This bodge will stop it erring.
268 if (g_bMultiByte && (c2 & 0x80))
269 return false;
270
271 // get font pointer
272 const FONT *pFont = (const FONT *)LockMem(hFont);
273
274 return pFont->fontDef[c2] != 0;
275 }
276
277 } // End of namespace Tinsel
278