Serious-Engine/Sources/Engine/Graphics/Font.cpp
2016-03-11 15:57:17 +02:00

199 lines
6.6 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "stdh.h"
#include <Engine/Graphics/Font.h>
#include <Engine/Base/Stream.h>
#include <Engine/Graphics/Texture.h>
#include <Engine/Graphics/Color.h>
#include <Engine/Templates/Stock_CTextureData.h>
// some default fonts
CFontData *_pfdDisplayFont;
CFontData *_pfdConsoleFont;
// constructor deletes letter data
CFontCharData::CFontCharData(void)
{
fcd_pixXOffset = 0;
fcd_pixYOffset = 0;
fcd_pixStart = 0;
fcd_pixEnd = 0;
}
// simple stream functions
void CFontCharData::Read_t( CTStream *inFile)
{
*inFile>>fcd_pixXOffset;
*inFile>>fcd_pixYOffset;
*inFile>>fcd_pixStart;
*inFile>>fcd_pixEnd;
}
void CFontCharData::Write_t( CTStream *outFile)
{
*outFile<<fcd_pixXOffset;
*outFile<<fcd_pixYOffset;
*outFile<<fcd_pixStart;
*outFile<<fcd_pixEnd;
}
CFontData::CFontData()
{
fd_ptdTextureData = NULL;
fd_fnTexture = CTString("");
}
CFontData::~CFontData()
{
Clear();
}
void CFontData::Clear()
{
if( fd_ptdTextureData != NULL) {
fd_fnTexture = CTString("");
_pTextureStock->Release(fd_ptdTextureData);
fd_ptdTextureData = NULL;
}
}
void CFontData::Read_t( CTStream *inFile) // throw char *
{
// clear current font data (if needed)
Clear();
// read the filename of the corresponding texture file.
inFile->ExpectID_t( CChunkID("FTTF"));
*inFile >> fd_fnTexture;
// read maximum width and height of all letters
*inFile >> fd_pixCharWidth;
*inFile >> fd_pixCharHeight;
// read entire letter data table
for( INDEX iLetterData=0; iLetterData<256; iLetterData ++) {
fd_fcdFontCharData[ iLetterData].Read_t( inFile);
}
// load corresponding texture file
fd_ptdTextureData = _pTextureStock->Obtain_t(fd_fnTexture);
// reload corresponding texture if not loaded in largest mip-map
fd_ptdTextureData->Force( TEX_CONSTANT);
// initialize default font variables
SetVariableWidth();
SetCharSpacing(+1);
SetLineSpacing(+1);
SetSpaceWidth(0.5f);
fd_fcdFontCharData[' '].fcd_pixStart = 0;
}
void CFontData::Write_t( CTStream *outFile) // throw char *
{
ASSERT( fd_ptdTextureData != NULL);
// write the filename of the corresponding texture file
outFile->WriteID_t( CChunkID("FTTF"));
*outFile << fd_fnTexture;
// write max letter width and height of all letters
*outFile << fd_pixCharWidth;
*outFile << fd_pixCharHeight;
// write entire letter data table
for( INDEX iLetterData=0; iLetterData<256; iLetterData ++) {
fd_fcdFontCharData[ iLetterData].Write_t( outFile);
}
}
/*
* Function used for creating font data object
*/
void CFontData::Make_t( const CTFileName &fnTexture, PIX pixCharWidth, PIX pixCharHeight,
CTFileName &fnOrderFile, BOOL bUseAlpha)
{
// do it only if font has not been created already
ASSERT( fd_ptdTextureData == NULL);
// remember texture name
fd_fnTexture = fnTexture;
// load texture and cache width
fd_ptdTextureData = _pTextureStock->Obtain_t(fd_fnTexture);
fd_ptdTextureData->Force( TEX_STATIC|TEX_CONSTANT);
PIX pixTexWidth = fd_ptdTextureData->GetPixWidth();
// load ascii order file (no application path necessary)
CTString strLettersOrder;
IgnoreApplicationPath();
strLettersOrder.Load_t( fnOrderFile);
UseApplicationPath();
// remember letter width and height
fd_pixCharWidth = pixCharWidth;
fd_pixCharHeight = pixCharHeight;
// determine address in memory where font definition begins in its larger mip-map
ULONG *pulFont = fd_ptdTextureData->td_pulFrames;
ASSERT( pulFont!=NULL);
// find number of letters in line (assuming that the 1st line represents the width of every line)
INDEX iLettersInLine=0;
while( (strLettersOrder[iLettersInLine]!='\n') && iLettersInLine<strlen(strLettersOrder)) iLettersInLine++;
if( iLettersInLine<=0) FatalError( "Invalid font definition ASCII file.");
// determine pixelcheck mast depending of alpha channel usage
COLOR colPixMask = 0xFFFFFF00; // FC is because of small tolerance for black
if( bUseAlpha) colPixMask = 0xFFFFFFFF;
// how much we must add to jump to character down
PIX pixFontCharModulo = pixTexWidth * fd_pixCharHeight;
// for all letters in font (ranging from space to last letter that user defined)
INDEX iLetter=0;
INDEX iCurrentLetterLine = 0;
while( iLetter<strlen(strLettersOrder))
{ // for letters in one line
for( INDEX iCurrentLetterColumn=0; iCurrentLetterColumn<iLettersInLine; iCurrentLetterColumn++)
{ // test if we at the end of whole array
if( iLetter>=strlen(strLettersOrder)) break;
// get char params
unsigned char chrLetter = strLettersOrder[iLetter++];
// reset current letter's width
PIX pixCurrentStart = fd_pixCharWidth;
PIX pixCurrentEnd = 0;
// for all of the letter's lines
for( INDEX iPixelLine=0; iPixelLine<fd_pixCharHeight; iPixelLine++)
{ // for all of the letter's pixels
for( INDEX iPixelColumn=0; iPixelColumn<fd_pixCharWidth; iPixelColumn++)
{ // calculate current pixel's adress in font's texture
ULONG *puwPixel = (ULONG*)( pulFont + pixFontCharModulo * iCurrentLetterLine + // calc right letter line
fd_pixCharWidth * iCurrentLetterColumn + // move to right letter column
pixTexWidth * iPixelLine + // move trough pixel lines of one letter
iPixelColumn); // move trough pixel columns of one letter
// if we test alpha channel and alpha value is not 0
if( ByteSwap(*puwPixel) & colPixMask) {
// if examined pixel is narrower in letter than last opaque pixel found, remember it as left-most pixel
if( iPixelColumn < pixCurrentStart) pixCurrentStart = iPixelColumn;
// if examined pixel is wider in letter than last opaque pixel found, remember it as right-most pixel
if( iPixelColumn > pixCurrentEnd) pixCurrentEnd = iPixelColumn;
}
}
}
// letter's data is stored into table on appropriate place
fd_fcdFontCharData[chrLetter].fcd_pixXOffset = iCurrentLetterColumn * fd_pixCharWidth;
fd_fcdFontCharData[chrLetter].fcd_pixYOffset = iCurrentLetterLine * fd_pixCharHeight;
fd_fcdFontCharData[chrLetter].fcd_pixStart = pixCurrentStart;
fd_fcdFontCharData[chrLetter].fcd_pixEnd = pixCurrentEnd +1;
}
// advance to next line in text file
iCurrentLetterLine++;
iLetter++; // skip carriage return
}
// set default space width
fd_fcdFontCharData[' '].fcd_pixStart = 0;
SetSpaceWidth(0.5f);
// all done
SetVariableWidth();
_pTextureStock->Release( fd_ptdTextureData);
}