mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 09:49:11 +00:00
4c5efaecf4
svn-id: r35870
659 lines
16 KiB
C++
659 lines
16 KiB
C++
/* 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
|