mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
920 lines
24 KiB
C++
920 lines
24 KiB
C++
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <core/defines.h>
|
||
|
#include <core/debug.h>
|
||
|
#include <core/string/stringutils.h>
|
||
|
#include <core/macros.h>
|
||
|
#include <gfx/nxfontman.h>
|
||
|
#include <sys/config/config.h>
|
||
|
#include <sys/file/filesys.h>
|
||
|
|
||
|
#include "nx_init.h"
|
||
|
#include "render.h"
|
||
|
#include "chars.h"
|
||
|
#include "xbmemfnt.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
|
||
|
|
||
|
.fnt file format (by Ryan)
|
||
|
--------------------------
|
||
|
|
||
|
4 File size in bytes
|
||
|
4 Number of characters
|
||
|
4 Default height
|
||
|
4 Default base
|
||
|
|
||
|
? Character table (see below)
|
||
|
? Texture (see below)
|
||
|
|
||
|
Character
|
||
|
2 Baseline (how many pixels down relative to top of image)
|
||
|
2 Ascii value
|
||
|
|
||
|
Texture
|
||
|
4 Size of texture
|
||
|
2 Width
|
||
|
2 Height
|
||
|
2 Bit depth
|
||
|
6 Padding
|
||
|
W*H Raw data
|
||
|
0-3 Padding for uint32 alignment
|
||
|
1K Palette data
|
||
|
4 Number of subtextures
|
||
|
? Subtexture table (see below)
|
||
|
|
||
|
Subtexture
|
||
|
2 X
|
||
|
2 Y
|
||
|
2 W
|
||
|
2 H
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
namespace NxXbox
|
||
|
{
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
typedef struct
|
||
|
{
|
||
|
float x, y, z;
|
||
|
float rhw;
|
||
|
D3DCOLOR col;
|
||
|
float u, v;
|
||
|
}
|
||
|
sFontVert;
|
||
|
|
||
|
|
||
|
SFont *pFontList;
|
||
|
SFont *pButtonsFont = NULL;
|
||
|
SFont *SText::spOverrideFont = NULL;
|
||
|
|
||
|
const uint32 CHARS_PER_BUFFER = 256;
|
||
|
static int font_vertex_offset = 0;
|
||
|
static BYTE* p_locked_font_vertex_buffer = NULL;
|
||
|
static BYTE font_vertex_buffer[CHARS_PER_BUFFER * 4 * sizeof( sFontVert )];
|
||
|
|
||
|
static uint32 swizzle_table[4096];
|
||
|
static bool swizzle_table_generated = false;
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
static void generateSwizzleTable( void )
|
||
|
{
|
||
|
if( !swizzle_table_generated )
|
||
|
{
|
||
|
for( uint32 i = 0, value = 0; i < 4096; i++ )
|
||
|
{
|
||
|
swizzle_table[i] = value;
|
||
|
value += 0x2AAAAAAB;
|
||
|
value &= 0x55555555;
|
||
|
}
|
||
|
swizzle_table_generated = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#define TWIDDLE(_u, _v) ((swizzle_table[(_v)] << 1) | (swizzle_table[(_u)]))
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SwizzleTexture( void *dstBuffer, void *srcBuffer, int width, int height, int32 depth, int32 stride )
|
||
|
{
|
||
|
int32 tilesX, tilesY;
|
||
|
int32 tilesSizeX, tilesSizeY;
|
||
|
int32 tileSize;
|
||
|
|
||
|
generateSwizzleTable();
|
||
|
|
||
|
if( width > height )
|
||
|
{
|
||
|
tilesX = width / height;
|
||
|
tilesY = 1;
|
||
|
|
||
|
tilesSizeX = width / tilesX;
|
||
|
tilesSizeY = height;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tilesX = 1;
|
||
|
tilesY = height / width;
|
||
|
|
||
|
tilesSizeX = width;
|
||
|
tilesSizeY = height / tilesY;
|
||
|
}
|
||
|
|
||
|
tileSize = tilesSizeX * tilesSizeY;
|
||
|
|
||
|
switch (depth)
|
||
|
{
|
||
|
case 4:
|
||
|
case 8:
|
||
|
{
|
||
|
int32 j;
|
||
|
|
||
|
for (j = 0; j < tilesY; j++)
|
||
|
{
|
||
|
int32 i;
|
||
|
|
||
|
for (i = 0; i < tilesX; i++)
|
||
|
{
|
||
|
int32 y;
|
||
|
uint8 *base;
|
||
|
|
||
|
base = (uint8 *)(((uint8 *)dstBuffer) +
|
||
|
((tileSize * tilesX) * j) +
|
||
|
(tileSize * i));
|
||
|
|
||
|
for (y = 0; y < tilesSizeY; y++)
|
||
|
{
|
||
|
uint8 *srcPixel;
|
||
|
int32 x;
|
||
|
|
||
|
srcPixel = (uint8 *)(((uint8 *)srcBuffer) +
|
||
|
(stride * (tilesSizeY * j)) +
|
||
|
(tilesSizeX * i) +
|
||
|
(stride * y));
|
||
|
|
||
|
for (x = 0; x < tilesSizeX; x++)
|
||
|
{
|
||
|
uint8 *dstPixel;
|
||
|
dstPixel = (uint8 *)(base + TWIDDLE(x, y));
|
||
|
*dstPixel = *srcPixel;
|
||
|
|
||
|
srcPixel++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 16:
|
||
|
{
|
||
|
int32 j;
|
||
|
|
||
|
for (j = 0; j < tilesY; j++)
|
||
|
{
|
||
|
int32 i;
|
||
|
|
||
|
for (i = 0; i < tilesX; i++)
|
||
|
{
|
||
|
int32 y;
|
||
|
uint8 *base;
|
||
|
|
||
|
base = (uint8 *)(((uint16 *)dstBuffer) +
|
||
|
((tileSize * tilesX) * j) +
|
||
|
(tileSize * i));
|
||
|
|
||
|
for (y = 0; y < tilesSizeY; y++)
|
||
|
{
|
||
|
uint16 *srcPixel;
|
||
|
int32 x;
|
||
|
|
||
|
srcPixel = (uint16 *)(((uint8 *)srcBuffer) +
|
||
|
(stride * (tilesSizeY * j)) +
|
||
|
(2 * tilesSizeX * i) +
|
||
|
(stride * y));
|
||
|
|
||
|
for (x = 0; x < tilesSizeX; x++)
|
||
|
{
|
||
|
uint16 *dstPixel;
|
||
|
dstPixel = (uint16 *)(base + (TWIDDLE(x, y) << 1));
|
||
|
*dstPixel = *srcPixel;
|
||
|
|
||
|
srcPixel++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 24:
|
||
|
case 32:
|
||
|
{
|
||
|
int32 j;
|
||
|
|
||
|
for (j = 0; j < tilesY; j++)
|
||
|
{
|
||
|
int32 i;
|
||
|
|
||
|
for (i = 0; i < tilesX; i++)
|
||
|
{
|
||
|
int32 y;
|
||
|
uint8 *base;
|
||
|
|
||
|
base = (uint8 *)(((uint32 *)dstBuffer) +
|
||
|
((tileSize * tilesX) * j) +
|
||
|
(tileSize * i));
|
||
|
|
||
|
for (y = 0; y < tilesSizeY; y++)
|
||
|
{
|
||
|
uint32 *srcPixel;
|
||
|
int32 x;
|
||
|
|
||
|
srcPixel = (uint32 *)(((uint8 *)srcBuffer) +
|
||
|
(stride * (tilesSizeY * j)) +
|
||
|
(4 * tilesSizeX * i) +
|
||
|
(stride * y));
|
||
|
|
||
|
for (x = 0; x < tilesSizeX; x++)
|
||
|
{
|
||
|
uint32 *dstPixel;
|
||
|
dstPixel = (uint32 *)(base + (TWIDDLE(x, y) << 2));
|
||
|
*dstPixel = *srcPixel;
|
||
|
|
||
|
srcPixel++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
exit( 0 );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
SFont* InitialiseMemoryResidentFont( void )
|
||
|
{
|
||
|
return LoadFont((const char*)xbmemfnt, true );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
SFont* LoadFont( const char *Filename, bool memory_resident )
|
||
|
{
|
||
|
SFont* pFont;
|
||
|
SChar* pChar;
|
||
|
uint8* pData;
|
||
|
void* p_FH;
|
||
|
int i,Len,NumChars,Width,Height,Depth,NumBytes;
|
||
|
|
||
|
// Build the full filename.
|
||
|
char filename[128];
|
||
|
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
strcpy( filename, "fonts/" );
|
||
|
strcat( filename, Filename );
|
||
|
strcat( filename, ".fnt.xbx" );
|
||
|
}
|
||
|
|
||
|
// Open the font file.
|
||
|
if( !memory_resident )
|
||
|
p_FH = File::Open( filename, "rb" );
|
||
|
|
||
|
// Allocate memory for the font structure.
|
||
|
pFont = new SFont();
|
||
|
|
||
|
// Allocate a temporary buffer.
|
||
|
uint8 FontBuf[2048];
|
||
|
|
||
|
// Load file header.
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
Len = File::Read( FontBuf, 16, 1, p_FH );
|
||
|
Dbg_MsgAssert( Len == 16, ( "couldn't read file header from font file %s", Filename ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory( FontBuf, Filename, 16 );
|
||
|
Filename += 16;
|
||
|
}
|
||
|
|
||
|
NumChars = ((uint32 *)FontBuf)[1];
|
||
|
pFont->DefaultHeight = ((uint32 *)FontBuf)[2];
|
||
|
pFont->DefaultBase = ((uint32 *)FontBuf)[3];
|
||
|
|
||
|
// Clear character map to zero.
|
||
|
memset( pFont->Map, 0, 256 );
|
||
|
memset( pFont->SpecialMap, 0, 32 );
|
||
|
|
||
|
// Allocate memory for character table.
|
||
|
pFont->pChars = new SChar[NumChars];
|
||
|
|
||
|
// Load character map and character table.
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
Len = File::Read( FontBuf, NumChars << 2, 1, p_FH );
|
||
|
Dbg_MsgAssert( Len == ( NumChars << 2 ), ( "couldn't read character table in font file %s", Filename ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory( FontBuf, Filename, NumChars << 2 );
|
||
|
Filename += NumChars << 2;
|
||
|
}
|
||
|
|
||
|
for( i = 0, pChar = pFont->pChars, pData = FontBuf; i < NumChars; i++,pChar++,pData += 4 )
|
||
|
{
|
||
|
pChar->Baseline = ((uint16 *)pData)[0];
|
||
|
sint16 ascii_val = ((sint16 *)pData)[1];
|
||
|
if (ascii_val >= 0)
|
||
|
pFont->Map[(uint8) ascii_val] = i;
|
||
|
else
|
||
|
{
|
||
|
Dbg_Assert(ascii_val >= -32)
|
||
|
pFont->SpecialMap[(uint8) (-ascii_val - 1)] = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If there is a null character in the font, make characters that could not be found
|
||
|
// in the font display that instead of 'A'
|
||
|
if( pFont->SpecialMap[31] != 0 )
|
||
|
{
|
||
|
for( i = 0; i < 256; ++i )
|
||
|
{
|
||
|
if( pFont->Map[i] == 0 && i != 'A' && i != 'a')
|
||
|
pFont->Map[i] = pFont->SpecialMap[31];
|
||
|
|
||
|
if( i < 31 && pFont->SpecialMap[i] == 0 )
|
||
|
pFont->SpecialMap[i] = pFont->SpecialMap[31];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Load texture header.
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
Len = File::Read( FontBuf, 16, 1, p_FH );
|
||
|
Dbg_MsgAssert( Len == 16, ( "couldn't read texture header from font file %s", Filename ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory( FontBuf, Filename, 16 );
|
||
|
Filename += 16;
|
||
|
}
|
||
|
|
||
|
Width = ((uint16 *)FontBuf)[2];
|
||
|
Height = ((uint16 *)FontBuf)[3];
|
||
|
Depth = ((uint16 *)FontBuf)[4];
|
||
|
|
||
|
// Create texture.
|
||
|
Dbg_Assert( Depth == 8 );
|
||
|
if( D3D_OK != D3DDevice_CreateTexture( Width, Height, 1, 0, D3DFMT_P8, 0, &pFont->pD3DTexture ))
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Read texture bitmap data (into temp buffer so we can then swizzle it).
|
||
|
NumBytes = ( Width * Height + 3 ) & 0xFFFFFFFC;
|
||
|
|
||
|
uint8* p_temp_texel_data = new uint8[NumBytes];
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
Len = File::Read( p_temp_texel_data, NumBytes, 1, p_FH );
|
||
|
Dbg_MsgAssert( Len == NumBytes, ( "Couldn't read texture bitmap from font file %s", Filename ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory( p_temp_texel_data, Filename, NumBytes );
|
||
|
Filename += NumBytes;
|
||
|
}
|
||
|
|
||
|
// Lock the texture so we can swizzle into it directly.
|
||
|
D3DLOCKED_RECT locked_rect;
|
||
|
if( D3D_OK != pFont->pD3DTexture->LockRect( 0, &locked_rect, NULL, 0 ))
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Swizzle the texture data.
|
||
|
SwizzleTexture( locked_rect.pBits, p_temp_texel_data, Width, Height, 8, Width );
|
||
|
|
||
|
// No longer need this data.
|
||
|
delete[] p_temp_texel_data;
|
||
|
|
||
|
// Create palette.
|
||
|
if( D3D_OK != D3DDevice_CreatePalette( D3DPALETTE_256, &pFont->pD3DPalette ))
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Read clut bitmap data.
|
||
|
D3DCOLOR *p_clut;
|
||
|
pFont->pD3DPalette->Lock( &p_clut, 0 );
|
||
|
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
Len = File::Read( p_clut, 1024, 1, p_FH );
|
||
|
Dbg_MsgAssert( Len == 1024, ( "couldn't read clut bitmap from font file %s", Filename ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory( p_clut, Filename, 1024 );
|
||
|
Filename += 1024;
|
||
|
}
|
||
|
|
||
|
// Switch from RGBA to BGRA format palette.
|
||
|
for( i = 0; i < 256; ++i )
|
||
|
{
|
||
|
uint32 red = p_clut[i] & 0xFF;
|
||
|
uint32 blu = ( p_clut[i] >> 16 ) & 0xFF;
|
||
|
|
||
|
// Double the alpha in the clut (currently limited to 0x80).
|
||
|
uint32 alpha = p_clut[i] >> 24;
|
||
|
alpha = ( alpha >= 0x80 ) ? 0xFF : ( alpha * 2 );
|
||
|
p_clut[i] = ( alpha << 24 ) | ( p_clut[i] & 0x0000FF00 ) | ( red << 16 ) | ( blu );
|
||
|
}
|
||
|
|
||
|
// Skip numsubtextures, and load subtextures.
|
||
|
if( !memory_resident )
|
||
|
{
|
||
|
Len = File::Read( FontBuf, ( NumChars << 3 ) + 4, 1, p_FH );
|
||
|
Dbg_MsgAssert( Len == ( NumChars << 3 ) + 4, ( "couldn't read subtexture table from font file %s", Filename ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyMemory( FontBuf, Filename, ( NumChars << 3 ) + 4 );
|
||
|
Filename += ( NumChars << 3 ) + 4;
|
||
|
}
|
||
|
|
||
|
for( i = 0, pChar = pFont->pChars, pData = FontBuf + 4; i < NumChars; i++, pChar++, pData += 8 )
|
||
|
{
|
||
|
uint16 x = ((uint16 *)pData )[0];
|
||
|
uint16 y = ((uint16 *)pData )[1];
|
||
|
uint16 w = ((uint16 *)pData )[2];
|
||
|
uint16 h = ((uint16 *)pData )[3];
|
||
|
|
||
|
pChar->w = w;
|
||
|
pChar->h = h;
|
||
|
pChar->u0 = (float)x / (float)Width;
|
||
|
pChar->v0 = (float)y / (float)Height;
|
||
|
pChar->u1 = pChar->u0 + ((float)w / (float)Width );
|
||
|
pChar->v1 = pChar->v0 + ((float)h / (float)Height );
|
||
|
}
|
||
|
|
||
|
// Add font to font list.
|
||
|
pFont->pNext = pFontList;
|
||
|
pFontList = pFont;
|
||
|
|
||
|
// We're done with the font file now.
|
||
|
if( !memory_resident )
|
||
|
File::Close( p_FH );
|
||
|
|
||
|
// this will serve as the default spacing
|
||
|
pFont->mSpaceSpacing = pFont->pChars[pFont->Map['I']].w;
|
||
|
|
||
|
return pFont;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void UnloadFont( SFont *pFont )
|
||
|
{
|
||
|
SFont* pPrevFont;
|
||
|
int found = 0;
|
||
|
|
||
|
// Find font and unchain from list.
|
||
|
if( pFontList == pFont )
|
||
|
{
|
||
|
found=1;
|
||
|
pFontList = pFontList->pNext;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( pPrevFont=pFontList; pPrevFont->pNext; pPrevFont=pPrevFont->pNext )
|
||
|
{
|
||
|
if( pPrevFont->pNext == pFont )
|
||
|
{
|
||
|
found = 1;
|
||
|
pPrevFont->pNext = pFont->pNext;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Dbg_MsgAssert( found, ( "Attempt to unload font which has not been loaded" ));
|
||
|
|
||
|
// Free memory.
|
||
|
delete [] pFont->pChars;
|
||
|
delete pFont;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
uint32 SFont::GetDefaultHeight() const
|
||
|
{
|
||
|
return DefaultHeight;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
uint32 SFont::GetDefaultBase() const
|
||
|
{
|
||
|
return DefaultBase;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SFont::QueryString( char *String, float &width, float &height )
|
||
|
{
|
||
|
SChar *pChar;
|
||
|
char *pLetter;
|
||
|
int x0,x1;
|
||
|
|
||
|
x0 = 0;
|
||
|
|
||
|
for (pLetter=String;; pLetter++)
|
||
|
{
|
||
|
pChar = NULL;
|
||
|
// may be overridden by the '\b' tag
|
||
|
SFont *p_font = this;
|
||
|
|
||
|
// acount for tags (might be multiple ones in a row)
|
||
|
bool got_char_tag = false; // tag resulting in output of character
|
||
|
while (*pLetter == '\\' && !got_char_tag)
|
||
|
{
|
||
|
pLetter++;
|
||
|
if (*pLetter == '\\')
|
||
|
break;
|
||
|
|
||
|
switch(*pLetter)
|
||
|
{
|
||
|
case '\\':
|
||
|
got_char_tag = true;
|
||
|
break;
|
||
|
case 'c':
|
||
|
case 'C':
|
||
|
pLetter += 2; // skip over "c#"
|
||
|
break;
|
||
|
case 's':
|
||
|
case 'S':
|
||
|
{
|
||
|
pLetter++; // skip "s"
|
||
|
uint digit = Str::DehexifyDigit(pLetter);
|
||
|
pChar = pChars + SpecialMap[digit];
|
||
|
got_char_tag = true;
|
||
|
break;
|
||
|
}
|
||
|
case 'b':
|
||
|
case 'B':
|
||
|
{
|
||
|
pLetter++; // skip "b"
|
||
|
uint digit = Str::DehexifyDigit(pLetter);
|
||
|
|
||
|
// switch over to buttons font, the regular font will be used again on the next character
|
||
|
|
||
|
p_font = pButtonsFont;
|
||
|
Dbg_Assert(p_font);
|
||
|
pChar = p_font->pChars + p_font->SpecialMap[digit];
|
||
|
got_char_tag = true;
|
||
|
break;
|
||
|
}
|
||
|
case 'm':
|
||
|
case 'M':
|
||
|
{
|
||
|
pLetter++; // skip "m"
|
||
|
char button_char = Nx::CFontManager::sMapMetaCharacterToButton(pLetter);
|
||
|
uint digit = Str::DehexifyDigit(&button_char);
|
||
|
|
||
|
p_font = pButtonsFont;
|
||
|
Dbg_Assert(p_font);
|
||
|
pChar = p_font->pChars + p_font->SpecialMap[digit];
|
||
|
got_char_tag = true;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
Dbg_MsgAssert(0, ("unknown tag"));
|
||
|
break;
|
||
|
}
|
||
|
} // end while
|
||
|
|
||
|
if (*pLetter == '\0') break;
|
||
|
|
||
|
if (*pLetter!=' ' || pChar)
|
||
|
{
|
||
|
if (!pChar)
|
||
|
pChar = p_font->pChars + p_font->Map[(uint8)*pLetter];
|
||
|
x1 = x0 + pChar->w;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x1 = x0 + mSpaceSpacing;
|
||
|
}
|
||
|
|
||
|
//x0 = x1 + mCharSpacing + 1;
|
||
|
x0 = x1 + mCharSpacing;
|
||
|
}
|
||
|
|
||
|
width = (float)x0;
|
||
|
height = (float)DefaultHeight;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
SText::SText( float pri ) : SDraw2D( pri, true )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
SText::~SText( void )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SText::BeginDraw( void )
|
||
|
{
|
||
|
p_locked_font_vertex_buffer = &( font_vertex_buffer[0] );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SText::Draw( void )
|
||
|
{
|
||
|
SChar *pChar;
|
||
|
char *pLetter;
|
||
|
float u0,v0,x0,y0,u1,v1,x1,y1,yt;
|
||
|
|
||
|
x0 = SCREEN_CONV_X( m_xpos );
|
||
|
y0 = SCREEN_CONV_Y( m_ypos );
|
||
|
|
||
|
float char_spacing = (float)mp_font->mCharSpacing * m_xscale;
|
||
|
float space_spacing = (float)mp_font->mSpaceSpacing * m_xscale;
|
||
|
|
||
|
DWORD current_color = ( m_rgba & 0xFF00FF00 ) | (( m_rgba & 0xFF ) << 16 ) | (( m_rgba & 0xFF0000 ) >> 16 );
|
||
|
|
||
|
float text_z = GetZValue();
|
||
|
|
||
|
for( pLetter = mp_string;; pLetter++ )
|
||
|
{
|
||
|
pChar = NULL;
|
||
|
SFont *p_font = mp_font;
|
||
|
|
||
|
sFontVert* p_vert = ((sFontVert*)p_locked_font_vertex_buffer ) + font_vertex_offset;
|
||
|
|
||
|
// acount for tags (might be multiple ones in a row)
|
||
|
bool got_char_tag = false; // tag resulting in output of character
|
||
|
while (*pLetter == '\\' && !got_char_tag)
|
||
|
{
|
||
|
pLetter++;
|
||
|
|
||
|
switch(*pLetter)
|
||
|
{
|
||
|
case '\\':
|
||
|
got_char_tag = true;
|
||
|
break;
|
||
|
case 'c':
|
||
|
case 'C':
|
||
|
{
|
||
|
pLetter++; // skip "c"
|
||
|
uint digit = Str::DehexifyDigit(pLetter);
|
||
|
pLetter++; // skip "#"
|
||
|
|
||
|
// Set active color from font.
|
||
|
if( digit == 0 || m_color_override)
|
||
|
{
|
||
|
// Switch from RGBA to BGRA format.
|
||
|
current_color = ( m_rgba & 0xFF00FF00 ) | (( m_rgba & 0xFF ) << 16 ) | (( m_rgba & 0xFF0000 ) >> 16 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Switch from RGBA to BGRA format.
|
||
|
uint32 color = mp_font->mRGBATab[digit-1];
|
||
|
current_color = ( color & 0xFF00FF00 ) | (( color & 0xFF ) << 16 ) | (( color & 0xFF0000 ) >> 16 );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case 's':
|
||
|
case 'S':
|
||
|
{
|
||
|
pLetter++; // skip "s"
|
||
|
uint digit = Str::DehexifyDigit(pLetter);
|
||
|
|
||
|
pChar = mp_font->pChars + mp_font->SpecialMap[digit];
|
||
|
got_char_tag = true;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case 'b':
|
||
|
case 'B':
|
||
|
{
|
||
|
// 'B' stands for button, accesses the button font
|
||
|
|
||
|
pLetter++; // skip "b"
|
||
|
uint digit = Str::DehexifyDigit( pLetter );
|
||
|
|
||
|
// switch to the buttons font!
|
||
|
p_font = pButtonsFont;
|
||
|
Dbg_Assert( p_font );
|
||
|
|
||
|
pChar = p_font->pChars + p_font->SpecialMap[digit];
|
||
|
got_char_tag = true;
|
||
|
|
||
|
EndDraw();
|
||
|
BeginDraw();
|
||
|
|
||
|
// Reset the vertex data pointer.
|
||
|
p_vert = ((sFontVert*)p_locked_font_vertex_buffer ) + font_vertex_offset;
|
||
|
|
||
|
spOverrideFont = p_font;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
Dbg_MsgAssert( 0, ( "unknown tag" ));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} // end while
|
||
|
|
||
|
if (*pLetter == '\0') break;
|
||
|
|
||
|
if( *pLetter != ' ' || pChar)
|
||
|
{
|
||
|
if (!pChar)
|
||
|
pChar = p_font->pChars + p_font->Map[(uint8) *pLetter];
|
||
|
yt = y0 + ((float)( p_font->DefaultBase - pChar->Baseline ) * m_yscale ) * EngineGlobals.screen_conv_y_multiplier;
|
||
|
u0 = pChar->u0;
|
||
|
v0 = pChar->v0;
|
||
|
u1 = pChar->u1;
|
||
|
v1 = pChar->v1;
|
||
|
x1 = x0 + ( pChar->w * m_xscale * EngineGlobals.screen_conv_x_multiplier );
|
||
|
y1 = yt + ( pChar->h * m_yscale * EngineGlobals.screen_conv_y_multiplier );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x0 += ( space_spacing + char_spacing ) * EngineGlobals.screen_conv_x_multiplier;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
p_vert->x = x0;
|
||
|
p_vert->y = yt;
|
||
|
p_vert->z = text_z;
|
||
|
p_vert->rhw = 0.0f;
|
||
|
p_vert->col = current_color;
|
||
|
p_vert->u = u0;
|
||
|
p_vert->v = v0;
|
||
|
++p_vert;
|
||
|
|
||
|
p_vert->x = x0;
|
||
|
p_vert->y = y1;
|
||
|
p_vert->z = text_z;
|
||
|
p_vert->rhw = 0.0f;
|
||
|
p_vert->col = current_color;
|
||
|
p_vert->u = u0;
|
||
|
p_vert->v = v1;
|
||
|
++p_vert;
|
||
|
|
||
|
p_vert->x = x1;
|
||
|
p_vert->y = y1;
|
||
|
p_vert->z = text_z;
|
||
|
p_vert->rhw = 0.0f;
|
||
|
p_vert->col = current_color;
|
||
|
p_vert->u = u1;
|
||
|
p_vert->v = v1;
|
||
|
++p_vert;
|
||
|
|
||
|
p_vert->x = x1;
|
||
|
p_vert->y = yt;
|
||
|
p_vert->z = text_z;
|
||
|
p_vert->rhw = 0.0f;
|
||
|
p_vert->col = current_color;
|
||
|
p_vert->u = u1;
|
||
|
p_vert->v = v0;
|
||
|
|
||
|
font_vertex_offset += 4;
|
||
|
|
||
|
if( font_vertex_offset >= ( CHARS_PER_BUFFER * 4 ))
|
||
|
{
|
||
|
// Draw this buffer and cycle through to the next.
|
||
|
EndDraw();
|
||
|
BeginDraw();
|
||
|
}
|
||
|
|
||
|
x0 = x1 + ( char_spacing * EngineGlobals.screen_conv_x_multiplier );
|
||
|
|
||
|
if( p_font != mp_font )
|
||
|
{
|
||
|
// We just used the button font, so return to the regular one.
|
||
|
EndDraw();
|
||
|
BeginDraw();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SText::EndDraw( void )
|
||
|
{
|
||
|
if( font_vertex_offset > 0 )
|
||
|
{
|
||
|
// Subsequent processing within Draw() will use this font
|
||
|
// Draw() may call this function to temporarily switch fonts
|
||
|
SFont *p_font = ( spOverrideFont ) ? spOverrideFont : mp_font;
|
||
|
|
||
|
// Set up the render state and submit.
|
||
|
set_pixel_shader( PixelShader4 );
|
||
|
set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2( 0 ));
|
||
|
|
||
|
set_texture( 0, p_font->pD3DTexture, p_font->pD3DPalette );
|
||
|
|
||
|
EngineGlobals.p_Device->DrawVerticesUP( D3DPT_QUADLIST, font_vertex_offset, &( font_vertex_buffer[0] ), sizeof( sFontVert ));
|
||
|
|
||
|
// Reset offset.
|
||
|
font_vertex_offset = 0;
|
||
|
|
||
|
// We can now return to using the regular font (no override).
|
||
|
spOverrideFont = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SetTextWindow( uint16 x0, uint16 x1, uint16 y0, uint16 y1 )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
} // namespace Xbox
|
||
|
|