/* 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. * * $URL$ * $Id$ * */ #include "common/file.h" #include "common/util.h" #include "cruise/cruise_main.h" namespace Cruise { // (old: fontProc1(int16 param, uint8* ptr1, uint8* ptr2)) int32 getLineHeight(int16 charCount, uint8 * fontPtr, uint8 * fontPrt_Desc) { uint8 *dest; int32 highestChar = 0; int32 i; if (!charCount) { return (0); } dest = fontPrt_Desc + 6; // fontPtr + 20 // char height for (i = 0; i < charCount; i++) { if ((*(int16 *) dest) > highestChar) { highestChar = *(int16 *) dest; } dest += 12; } return highestChar; } // this function determins how many lines the text will have (old: fontProc2(int32 param1, int32 param2, uint8* ptr, uint8* string)) int32 getTextLineCount(int32 rightBorder_X, int32 wordSpacingWidth, uint8 *ptr, const uint8 *textString) { const uint8 *localString = textString; const uint8 *currentStringPtr; uint8 character; int32 var_6 = 0; int32 lineLength = 0; const uint8 *tempPtr = 0; if (!*localString) { return (0); } currentStringPtr = localString; character = *localString; do { int32 charData = fontCharacterTable[character]; if (character == '|') { lineLength = rightBorder_X; localString = tempPtr; } else { if (charData >= 0) { // + 0xA jump to last 2 bytes of the 12 bytes slice = letter width lineLength += wordSpacingWidth + *(int16 *) (ptr + 0xA + charData * 12); } else { if (character == ' ') { lineLength += wordSpacingWidth + 5; localString = currentStringPtr; } } } tempPtr = currentStringPtr; if (rightBorder_X <= lineLength) { var_6 += rightBorder_X; currentStringPtr = localString; tempPtr = localString; lineLength = 0; } character = *(tempPtr++); currentStringPtr = tempPtr; } while (character); if (lineLength == 0) { return (var_6 / rightBorder_X); } else { return ((var_6 + rightBorder_X) / rightBorder_X); } } void loadFNT(const char *fileName) { uint8 header[6]; int32 fontSize; int32 data2; uint8 data3[6]; _systemFNT = NULL; Common::File fontFileHandle; if (!fontFileHandle.exists(fileName)) { return; } fontFileHandle.open((const char *)fileName); fontFileHandle.read(header, 4); if (strcmp((char*)header, "FNT") == 0) { fontFileHandle.read(&fontSize, 4); flipLong(&fontSize); fontFileHandle.read(&data2, 4); flipLong(&data2); fontFileHandle.read(data3, 6); // may need an endian flip ? flipGen(&data3, 6); _systemFNT = (uint8 *)mallocAndZero(fontSize); if (_systemFNT != NULL) { int32 i; uint8 *currentPtr; fontFileHandle.seek(0); fontFileHandle.read(header, 4); // not really require, we could fseek to 4 fontFileHandle.read(_systemFNT, fontSize); flipLong((int32 *) _systemFNT); flipLong((int32 *) (_systemFNT + 4)); flipGen(_systemFNT + 8, 6); currentPtr = _systemFNT + 14; for (i = 0; i < *(int16 *)(_systemFNT + 8); i++) { flipLong((int32 *)currentPtr); currentPtr += 4; flipGen(currentPtr, 8); currentPtr += 8; } } } fontFileHandle.close(); } void initSystem(void) { int32 i; itemColor = 15; titleColor = 9; selectColor = 13; subColor = 10; for (i = 0; i < 64; i++) { strcpy(preloadData[i].name, ""); preloadData[i].ptr = NULL; preloadData[i].nofree = 0; } lowMemory = 0; doFade = 0; fadeFlag = 0; scroll = 0; switchPal = 0; masterScreen = 0; changeCursor(CURSOR_NORMAL); strcpy(cmdLine, ""); loadFNT("system.fnt"); } void flipShort(int16 *var) { uint8 *varPtr = (uint8 *) var; SWAP(varPtr[0], varPtr[1]); } void flipShort(uint16 *var) { uint8 *varPtr = (uint8 *) var; SWAP(varPtr[0], varPtr[1]); } void flipLong(int32 *var) { char *varPtr = (char *)var; SWAP(varPtr[0], varPtr[3]); SWAP(varPtr[1], varPtr[2]); } void flipLong(uint32 *var) { char *varPtr = (char *)var; SWAP(varPtr[0], varPtr[3]); SWAP(varPtr[1], varPtr[2]); } void flipGen(void *var, int32 length) { int i; short int *varPtr = (int16 *) var; for (i = 0; i < (length / 2); i++) { flipShort(&varPtr[i]); } } void renderWord(uint8 * fontPtr_Data, uint8 * outBufferPtr, int32 drawPosPixel_X, int32 heightOff, int32 height, int32 param4, int32 stringRenderBufferSize, int32 width, int32 charWidth) { int i; int j; uint8 *fontPtr_Data2 = fontPtr_Data + height * 2; outBufferPtr += heightOff * width * 2; // param2 = height , param6 = width outBufferPtr += drawPosPixel_X; // param1 = drawPosPixel_X for (i = 0; i < height; i++) { // y++ uint16 currentColor1 = (*(fontPtr_Data) << 8) | *(fontPtr_Data + 1); uint16 currentColor2 = (*(fontPtr_Data2) << 8) | *(fontPtr_Data2 + 1); fontPtr_Data += 2; fontPtr_Data2 += 2; for (j = 0; j < charWidth; j++) { *outBufferPtr = ((currentColor1 >> 15) & 1) | ((currentColor2 >> 14) & 2); outBufferPtr++; currentColor1 <<= 1; currentColor2 <<= 1; } outBufferPtr += (width * 2) - charWidth; } } // 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)) int32 prepareWordRender(int32 inRightBorder_X, int32 wordSpacingWidth, int16 * strPixelLength, uint8 * ptr3, const uint8 * textString) { const uint8 *localString = textString; int32 counter = 0; int32 finish = 0; int32 temp_pc = 0; // var_A // temporary pixel count save int32 temp_cc = 0; // var_C // temporary char count save int32 pixelCount = 0; // si do { uint8 character = *(localString++); int16 charData = fontCharacterTable[character]; if (character == ' ') { temp_cc = counter; temp_pc = pixelCount; if (pixelCount + wordSpacingWidth + 5 >= inRightBorder_X) { finish = 1; } else { pixelCount += wordSpacingWidth + 5; } } else { if (character == '|' || !character) { finish = 1; } else { if (charData) { if (pixelCount + wordSpacingWidth + *(int16 *) ((ptr3 + charData * 12) + 0xA) >= inRightBorder_X) { finish = 1; if (temp_pc) { pixelCount = temp_pc; counter = temp_cc; } } else { pixelCount += wordSpacingWidth + *(int16 *) ((ptr3 + charData * 12) + 0xA); } } } } counter++; } while (!finish); *strPixelLength = (int16) pixelCount; return counter; } void drawString(int32 x, int32 y, uint8 *string, uint8 *buffer, uint8 color, int32 inRightBorder_X) { uint8 *fontPtr; uint8 *fontPtr_Data; // ptr2 uint8 *fontPtr_Desc; // ptr3 int32 wordSpacingWidth; // var1 int32 wordSpacingHeight; // var2 int32 rightBorder_X; // param2 int32 lineHeight; // fontProc1result int32 numLines; int32 stringHeight; int32 stringFinished; int32 stringWidth; // var_1C int32 stringRenderBufferSize; int32 useDynamicBuffer; uint8 *currentStrRenderBuffer; // int32 var_8; // don't need that on int32 heightOffset; // var_12 int32 renderBufferSize; // var_1E int needFlip; if (!buffer || !string) { return; } if (fontFileIndex != -1) { fontPtr = filesDatabase[fontFileIndex].subData.ptr; if (!fontPtr) { fontPtr = _systemFNT; } } else { fontPtr = _systemFNT; } if (!fontPtr) { return; } fontPtr_Data = fontPtr + *(int16 *) (fontPtr + 4); fontPtr_Desc = fontPtr + 14; lineHeight = getLineHeight(*(int16 *) (fontPtr + 8), fontPtr, fontPtr_Desc); // ok wordSpacingWidth = *(int16 *) (fontPtr + 10); wordSpacingHeight = *(int16 *) (fontPtr + 12); if (inRightBorder_X > 310) { rightBorder_X = 310; } else { rightBorder_X = inRightBorder_X; } if (x + rightBorder_X > 319) { x = 319 - rightBorder_X; } if (y < 0) { y = 0; } if (x < 0) { x = 0; } numLines = getTextLineCount(rightBorder_X, wordSpacingWidth, fontPtr_Desc, string); // ok if (!numLines) { return; } stringHeight = ((wordSpacingHeight + lineHeight + 2) * numLines) + 1; if (y + stringHeight > 199) { y = 200 - stringHeight; } stringFinished = 0; stringWidth = (rightBorder_X / 16) + 2; stringRenderBufferSize = stringWidth * stringHeight * 4; inRightBorder_X = rightBorder_X; if (stringRenderBufferSize > 0x2000) { currentStrRenderBuffer = (uint8 *) mallocAndZero(stringRenderBufferSize); if (!currentStrRenderBuffer) { return; } useDynamicBuffer = 1; } else { currentStrRenderBuffer = (uint8 *) workBuffer; useDynamicBuffer = 0; } resetRaster(currentStrRenderBuffer, stringRenderBufferSize); // var_8 = 0; heightOffset = 0; renderBufferSize = stringRenderBufferSize; do { int spacesCount = 0; // si char character = *(string); short int strPixelLength; // var_16; uint8 *ptrStringEnd; // var_4 //ok int drawPosPixel_X; // di while (character == ' ') { spacesCount++; character = *(string + spacesCount); } string += spacesCount; ptrStringEnd = string + prepareWordRender(inRightBorder_X, wordSpacingWidth, &strPixelLength, fontPtr_Desc, string); //ok if (inRightBorder_X > strPixelLength) { drawPosPixel_X = (inRightBorder_X - strPixelLength) / 2; } else { drawPosPixel_X = 0; } // drawPosPixel_X = var_8; do { character = *(string++); short int data = fontCharacterTable[(int)character]; if (character) { if (character == ' ' || character == 0x7D) { drawPosPixel_X += wordSpacingWidth + 5; } else { if (data) { short int *si = (int16 *) (fontPtr_Desc + data * 12); //int var_2 = si[5]; renderWord(fontPtr_Data + si[0], currentStrRenderBuffer, drawPosPixel_X, si[4] - si[3] + lineHeight + heightOffset, si[3], si[2], renderBufferSize / 2, stringWidth * 2, si[5]); drawPosPixel_X += wordSpacingWidth + si[5]; } } } else { stringFinished = 1; } if (ptrStringEnd <= string) { break; } } while (!stringFinished); // var_8 = 0; heightOffset = wordSpacingHeight + lineHeight; } while (!stringFinished); needFlip = 0; if (buffer == gfxModuleData.pPage00) { if (gfxModuleData.field_1 != 0) { needFlip = 1; gfxModuleData_field_90(); } gfxModuleData_gfxWaitVSync(); } gfxModuleData_field_64((char *)currentStrRenderBuffer, stringWidth, stringHeight, (char *)buffer, x, y, 0); gfxModuleData_field_64((char *)currentStrRenderBuffer, stringWidth, stringHeight, (char *)buffer, x, y, color); if (needFlip) { gfxModuleData_flip(); } if (useDynamicBuffer) { free(currentStrRenderBuffer); } } // calculates all necessary datas and renders text gfxEntryStruct *renderText(int inRightBorder_X, const uint8 *string) { uint8 *fontPtr; uint8 *fontPtr_Data; // pt2 uint8 *fontPtr_Desc; // ptr3 int32 wordSpacingWidth; // var1 //0 or -1 int32 wordSpacingHeight; // var2 //0 or -1 int32 rightBorder_X; int32 lineHeight; // fontProc1result int32 numLines; int32 stringHeight; int32 stringFinished; int32 stringWidth; // var_1C int32 stringRenderBufferSize; // int32 useDynamicBuffer; uint8 *currentStrRenderBuffer; // int32 var_8; // don't need that one int32 heightOffset; // var_12 // how much pixel-lines have already been drawn // int32 var_1E; gfxEntryStruct *generatedGfxEntry; // check if string is empty if (!string) { return NULL; } // check if font has been loaded, else get system font if (fontFileIndex != -1) { fontPtr = filesDatabase[fontFileIndex].subData.ptr; if (!fontPtr) { fontPtr = _systemFNT; } } else { fontPtr = _systemFNT; } if (!fontPtr) { return NULL; } fontPtr_Data = fontPtr + *(int16 *) (fontPtr + 4); // offset to char data fontPtr_Desc = fontPtr + 14; // offset to char description lineHeight = getLineHeight(*(int16 *) (fontPtr + 8), fontPtr, fontPtr_Desc); // ok wordSpacingWidth = *(int16 *) (fontPtr + 10); wordSpacingHeight = *(int16 *) (fontPtr + 12); // if right border is higher then screenwidth (+ spacing), adjust border if (inRightBorder_X > 310) { rightBorder_X = 310; } else { rightBorder_X = inRightBorder_X; } numLines = getTextLineCount(rightBorder_X, wordSpacingWidth, fontPtr_Desc, string); // ok if (!numLines) { return NULL; } stringHeight = ((wordSpacingHeight + lineHeight + 2) * numLines) + 1; stringFinished = 0; stringWidth = rightBorder_X + 2; // max render width to the right stringRenderBufferSize = stringWidth * stringHeight * 4; inRightBorder_X = rightBorder_X; currentStrRenderBuffer = (uint8 *) mallocAndZero(stringRenderBufferSize); resetRaster(currentStrRenderBuffer, stringRenderBufferSize); generatedGfxEntry = (gfxEntryStruct *) malloc(sizeof(gfxEntryStruct)); generatedGfxEntry->imagePtr = currentStrRenderBuffer; generatedGfxEntry->imageSize = stringRenderBufferSize / 2; generatedGfxEntry->fontIndex = fontFileIndex; generatedGfxEntry->height = stringHeight; generatedGfxEntry->width = stringWidth; // maximum render width to the right // var_8 = 0; heightOffset = 0; do { int spacesCount = 0; // si unsigned char character = *string; short int strPixelLength; // var_16 const uint8 *ptrStringEnd; // var_4 //ok int drawPosPixel_X; // di // find first letter in string, skip all spaces while (character == ' ') { spacesCount++; character = *(string + spacesCount); } string += spacesCount; // returns character count and pixel length (via pointer) per line of the text string ptrStringEnd = string + prepareWordRender(inRightBorder_X, wordSpacingWidth, &strPixelLength, fontPtr_Desc, string); //ok // determine how much space is left to the right and left (center text) if (inRightBorder_X > strPixelLength) { //var_8 = (inRightBorder_X - strPixelLength) / 2; drawPosPixel_X = (inRightBorder_X - strPixelLength) / 2; } else { drawPosPixel_X = 0; } //drawPosPixel_X = var_8; // draw textline, character wise do { character = *(string++); short int charData = fontCharacterTable[character]; // get character position if (character) { if (character == ' ' || character == 0x7C) { drawPosPixel_X += wordSpacingWidth + 5; // if char = "space" adjust word starting postion (don't render space though); } else { if (charData >= 0) { short int *si = (int16 *) (fontPtr_Desc + charData * 12); // offset font data // int var_2 = si[5]; // don't need this // should ist be stringRenderBufferSize/2 for the second last param? renderWord(fontPtr_Data + si[0], currentStrRenderBuffer, drawPosPixel_X, si[4] - si[3] + lineHeight + heightOffset, si[3], si[2], stringRenderBufferSize, stringWidth / 2, si[5]); drawPosPixel_X += wordSpacingWidth + si[5]; } } } else { stringFinished = 1; // character = 0x00 } // check if string already reached the end if (ptrStringEnd <= string) { break; } } while (!stringFinished); // var_8 = 0; heightOffset += wordSpacingHeight + lineHeight; } while (!stringFinished); return generatedGfxEntry; } } // End of namespace Cruise