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 */
22
23 #include "common/endian.h"
24 #include "common/file.h"
25 #include "common/util.h"
26
27 #include "cruise/cruise_main.h"
28 #include "cruise/mouse.h"
29 #include "cruise/staticres.h"
30
31 namespace Cruise {
32
33 const int SPACE_WIDTH = 5;
34
35 /**
36 * Determines the line size by finding the highest character in the given font set
37 */
getLineHeight(int16 charCount,const FontEntry * fontPtr)38 int32 getLineHeight(int16 charCount, const FontEntry *fontPtr) {
39 int32 highestChar = 0;
40
41 if (!charCount)
42 return (0);
43
44 for (int i = 0; i < charCount; ++i) {
45 int charHeight = fontPtr[i].charHeight;
46 if (charHeight > highestChar) highestChar = charHeight;
47 }
48
49 return highestChar;
50 }
51
52 /**
53 * This function determines how many lines the text will have
54 */
getTextLineCount(int32 rightBorder_X,int16 wordSpacingWidth,const FontEntry * fontData,const char * textString)55 int32 getTextLineCount(int32 rightBorder_X, int16 wordSpacingWidth,
56 const FontEntry *fontData, const char *textString) {
57 const char *localString = textString;
58 const char *tempPtr = textString;
59 uint8 ch;
60 int32 total = 0, lineLength = 0;
61
62 if (rightBorder_X == 0)
63 error("getTextLineCount() - invalid parameter");
64
65 if (!*textString)
66 return (0);
67
68 ch = *localString;
69
70 do {
71 int32 charData = fontCharacterTable[ch];
72
73 if (ch == '|') {
74 lineLength = rightBorder_X;
75 localString = tempPtr;
76 } else if (charData >= 0) {
77 lineLength += wordSpacingWidth + (int16)fontData[charData].charWidth;
78 } else if (ch == ' ') {
79 lineLength += wordSpacingWidth + SPACE_WIDTH;
80 localString = tempPtr;
81 }
82
83 if (lineLength >= rightBorder_X) {
84 total += rightBorder_X;
85 tempPtr = localString;
86 lineLength = 0;
87 }
88
89 ch = *++tempPtr;
90 } while (ch);
91
92 if (lineLength > 0)
93 total += rightBorder_X;
94
95
96 return (total / rightBorder_X);
97 }
98
loadFNT(const char * fileName)99 void loadFNT(const char *fileName) {
100 uint8 header[4];
101
102 _systemFNT = NULL;
103
104 Common::File fontFileHandle;
105
106 if (!fontFileHandle.exists(fileName))
107 return;
108
109 fontFileHandle.open((const char *)fileName);
110
111 fontFileHandle.read(header, 4);
112
113 if (strcmp((char *)header, "FNT") == 0) {
114 uint32 fontSize = fontFileHandle.readUint32BE();
115
116 _systemFNT = (uint8 *)mallocAndZero(fontSize);
117
118 if (_systemFNT != NULL) {
119 fontFileHandle.seek(4);
120 fontFileHandle.read(_systemFNT, fontSize);
121
122 // Flip structure values from BE to LE for font files - this is for consistency
123 // with font resources, which are in LE formatt
124 FontInfo *f = (FontInfo *)_systemFNT;
125 bigEndianLongToNative(&f->offset);
126 bigEndianLongToNative(&f->size);
127 flipGen(&f->numChars, 6); // numChars, hSpacing, and vSpacing
128
129 FontEntry *fe = (FontEntry *)(_systemFNT + sizeof(FontInfo));
130
131 for (int i = 0; i < f->numChars; ++i, ++fe) {
132 bigEndianLongToNative(&fe->offset); // Flip 32-bit offset field
133 flipGen(&fe->v1, 8); // Flip remaining 16-bit fields
134 }
135 }
136 }
137
138 fontFileHandle.close();
139 }
140
initSystem()141 void initSystem() {
142 int32 i;
143
144 itemColor = 15;
145 titleColor = 9;
146 selectColor = 13;
147 subColor = 10;
148
149 for (i = 0; i < 64; i++) {
150 strcpy(preloadData[i].name, "");
151 preloadData[i].ptr = NULL;
152 preloadData[i].nofree = 0;
153 }
154
155 doFade = 0;
156 fadeFlag = 0;
157 scroll = 0;
158 switchPal = 0;
159 masterScreen = 0;
160
161 changeCursor(CURSOR_NOMOUSE);
162 changeCursor(CURSOR_NORMAL);
163 mouseOn();
164
165 strcpy(cmdLine, "");
166
167 loadFNT("system.fnt");
168 }
169
freeSystem()170 void freeSystem() {
171 MemFree(_systemFNT);
172 }
173
bigEndianShortToNative(void * var)174 void bigEndianShortToNative(void *var) {
175 WRITE_UINT16(var, READ_BE_UINT16(var));
176 }
177
bigEndianLongToNative(void * var)178 void bigEndianLongToNative(void *var) {
179 WRITE_UINT32(var, READ_BE_UINT32(var));
180 }
181
flipGen(void * var,int32 length)182 void flipGen(void *var, int32 length) {
183 short int *varPtr = (int16 *) var;
184
185 for (int i = 0; i < (length / 2); i++) {
186 bigEndianShortToNative(&varPtr[i]);
187 }
188 }
189
renderWord(const uint8 * fontPtr_Data,uint8 * outBufferPtr,int xOffset,int yOffset,int32 height,int32 param4,int32 stringRenderBufferSize,int32 width,int32 charWidth)190 void renderWord(const uint8 *fontPtr_Data, uint8 *outBufferPtr, int xOffset, int yOffset,
191 int32 height, int32 param4, int32 stringRenderBufferSize, int32 width, int32 charWidth) {
192 const uint8 *fontPtr_Data2 = fontPtr_Data + height * 2;
193 outBufferPtr += yOffset * width + xOffset;
194
195 for (int i = 0; i < height; i++) { // y++
196 uint16 bitSet1 = READ_BE_UINT16(fontPtr_Data);
197 uint16 bitSet2 = READ_BE_UINT16(fontPtr_Data2);
198
199 fontPtr_Data += sizeof(uint16);
200 fontPtr_Data2 += sizeof(uint16);
201
202 for (int j = 0; j < charWidth; j++) {
203 if (((bitSet1 >> 15) & 1)) {
204 *outBufferPtr = ((bitSet2 >> 15) & 1) + 1;
205 }
206 outBufferPtr++;
207
208 bitSet1 <<= 1;
209 bitSet2 <<= 1;
210 }
211 outBufferPtr += width - charWidth;
212 }
213 }
214
215 // returns character count and pixel size (via pointer) per line of the string (old: prepareWordRender(int32 param, int32 var1, int16* out2, uint8* ptr3, uint8* string))
prepareWordRender(int32 inRightBorder_X,int16 wordSpacingWidth,int16 * strPixelLength,const FontEntry * fontData,const char * textString)216 int32 prepareWordRender(int32 inRightBorder_X, int16 wordSpacingWidth,
217 int16 *strPixelLength, const FontEntry *fontData, const char *textString) {
218 const char *localString = textString;
219
220 int32 counter = 0;
221 int32 finish = 0;
222 int32 temp_pc = 0; // var_A // temporary pixel count save
223 int32 temp_cc = 0; // var_C // temporary char count save
224 int32 pixelCount = 0; // si
225
226 do {
227 uint8 character = *(localString++);
228 int16 charData = fontCharacterTable[character];
229
230 if (character == ' ') {
231 temp_cc = counter;
232 temp_pc = pixelCount;
233
234 if (pixelCount + wordSpacingWidth + SPACE_WIDTH >=
235 inRightBorder_X) {
236 finish = 1;
237 } else {
238 pixelCount += wordSpacingWidth + SPACE_WIDTH;
239 }
240 } else {
241 if (character == '|' || !character) {
242 finish = 1;
243 } else {
244 if (charData >= 0) {
245 if (pixelCount + wordSpacingWidth +
246 (int16)fontData[charData].charWidth >= inRightBorder_X) {
247 finish = 1;
248 if (temp_pc) {
249 pixelCount = temp_pc;
250 counter = temp_cc;
251 }
252 } else {
253 pixelCount += wordSpacingWidth +
254 (int16)fontData[charData].charWidth;
255 }
256 }
257 }
258 }
259 counter++;
260 } while (!finish);
261
262 *strPixelLength = (int16) pixelCount;
263 return counter;
264 }
265
drawString(int32 x,int32 y,const char * string,uint8 * buffer,uint8 fontColor,int32 rightBorder_X)266 void drawString(int32 x, int32 y, const char *string, uint8 *buffer, uint8 fontColor, int32 rightBorder_X) {
267
268 // Get the rendered text to display
269 gfxEntryStruct *s = renderText(rightBorder_X, string);
270
271 // Draw the message
272 drawMessage(s, x, y, rightBorder_X - x, fontColor, buffer);
273
274 // Free the data
275 delete s->imagePtr;
276 free(s);
277 }
278
279 // calculates all necessary datas and renders text
renderText(int inRightBorder_X,const char * string)280 gfxEntryStruct *renderText(int inRightBorder_X, const char *string) {
281 const FontInfo *fontPtr;
282 const FontEntry *fontPtr_Desc;
283 const uint8 *fontPtr_Data;
284 int16 wordSpacingWidth; // 0 or -1
285 int16 wordSpacingHeight;// 0 or -1
286 int32 rightBorder_X;
287 int32 lineHeight;
288 int32 numLines;
289 int32 stringHeight;
290 int32 stringFinished;
291 int32 stringWidth; // var_1C
292 int32 stringRenderBufferSize;
293 // int32 useDynamicBuffer;
294 uint8 *currentStrRenderBuffer;
295 // int32 var_8; // don't need that one
296 int32 heightOffset; // var_12 // how much pixel-lines have already been drawn
297 // int32 var_1E;
298 gfxEntryStruct *generatedGfxEntry;
299
300 // check if string is empty
301 if (!string) {
302 return NULL;
303 }
304 // check if font has been loaded, else get system font
305 if (fontFileIndex != -1) {
306 fontPtr = (const FontInfo *)filesDatabase[fontFileIndex].subData.ptr;
307
308 if (!fontPtr) {
309 fontPtr = (const FontInfo *)_systemFNT;
310 }
311 } else {
312 fontPtr = (const FontInfo *)_systemFNT;
313 }
314
315 if (!fontPtr) {
316 return NULL;
317 }
318
319 fontPtr_Desc = (const FontEntry *)((const uint8 *)fontPtr + sizeof(FontInfo));
320 fontPtr_Data = (const uint8 *)fontPtr + fontPtr->offset;
321
322 lineHeight = getLineHeight(fontPtr->numChars, fontPtr_Desc);
323
324 wordSpacingWidth = fontPtr->hSpacing;
325 wordSpacingHeight = fontPtr->vSpacing;
326
327 // if right border is higher then screenwidth (+ spacing), adjust border
328 if (inRightBorder_X > 310) {
329 rightBorder_X = 310;
330 } else {
331 rightBorder_X = inRightBorder_X;
332 }
333 numLines = getTextLineCount(rightBorder_X, wordSpacingWidth, fontPtr_Desc, string); // ok
334
335 if (!numLines) {
336 return NULL;
337 }
338
339 stringHeight = ((wordSpacingHeight + lineHeight + 2) * numLines) + 1;
340 stringFinished = 0;
341 stringWidth = rightBorder_X + 2; // max render width to the right
342 stringRenderBufferSize = stringWidth * stringHeight * 4;
343 inRightBorder_X = rightBorder_X;
344
345 currentStrRenderBuffer =
346 (uint8 *) mallocAndZero(stringRenderBufferSize);
347 resetBitmap(currentStrRenderBuffer, stringRenderBufferSize);
348
349 generatedGfxEntry = (gfxEntryStruct *) MemAlloc(sizeof(gfxEntryStruct));
350 generatedGfxEntry->imagePtr = currentStrRenderBuffer;
351 generatedGfxEntry->imageSize = stringRenderBufferSize / 2;
352 generatedGfxEntry->fontIndex = fontFileIndex;
353 generatedGfxEntry->height = stringHeight;
354 generatedGfxEntry->width = stringWidth; // maximum render width to the right
355
356 // var_8 = 0;
357 heightOffset = 0;
358
359 do {
360 int spacesCount = 0; // si
361 unsigned char character = *string;
362 short int strPixelLength; // var_16
363 const char *ptrStringEnd; // var_4 //ok
364 int drawPosPixel_X; // di
365
366 // find first letter in string, skip all spaces
367 while (character == ' ') {
368 spacesCount++;
369 character = *(string + spacesCount);
370 }
371
372 string += spacesCount;
373
374 // returns character count and pixel length (via pointer) per line of the text string
375 ptrStringEnd = string + prepareWordRender(inRightBorder_X, wordSpacingWidth, &strPixelLength, fontPtr_Desc, string); //ok
376
377 // determine how much space is left to the right and left (center text)
378 if (inRightBorder_X > strPixelLength) {
379 //var_8 = (inRightBorder_X - strPixelLength) / 2;
380 drawPosPixel_X =
381 (inRightBorder_X - strPixelLength) / 2;
382 } else {
383 drawPosPixel_X = 0;
384 }
385 //drawPosPixel_X = var_8;
386
387 // draw textline, character wise
388 do {
389 character = *(string++);
390
391 short int charData = fontCharacterTable[character]; // get character position
392
393 if (character) {
394 if (character == ' ' || character == 0x7C) {
395 drawPosPixel_X += wordSpacingWidth + SPACE_WIDTH; // if char = "space" adjust word starting postion (don't render space though);
396 } else {
397 if (charData >= 0) {
398 const FontEntry &fe = fontPtr_Desc[charData];
399
400 // should ist be stringRenderBufferSize/2 for the second last param?
401 renderWord((const uint8 *)fontPtr_Data + fe.offset,
402 currentStrRenderBuffer,
403 drawPosPixel_X,
404 fe.height2 - fe.charHeight +
405 lineHeight + heightOffset,
406 fe.charHeight,
407 fe.v1,
408 stringRenderBufferSize,
409 stringWidth,
410 (int16)fe.charWidth);
411
412 drawPosPixel_X +=
413 wordSpacingWidth + (int16)fe.charWidth;
414 }
415 }
416 } else {
417 stringFinished = 1; // character = 0x00
418 }
419 } while ((string < ptrStringEnd) && !stringFinished);
420
421 // var_8 = 0;
422 heightOffset += wordSpacingHeight + lineHeight;
423 } while (!stringFinished);
424
425 return generatedGfxEntry;
426 }
427
freeGfx(gfxEntryStruct * pGfx)428 void freeGfx(gfxEntryStruct *pGfx) {
429 if (pGfx->imagePtr) {
430 MemFree(pGfx->imagePtr);
431 }
432
433 MemFree(pGfx);
434 }
435
436
437 } // End of namespace Cruise
438