You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
799 lines
22 KiB
799 lines
22 KiB
//===== Copyright (c) Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose: PS3-specific font code that for historical reasons is hidden
|
|
// in the materialsystem.
|
|
//
|
|
//==================================================================//
|
|
|
|
#include "pch_materialsystem.h"
|
|
|
|
#ifndef _PS3
|
|
#define MATSYS_INTERNAL
|
|
#endif
|
|
|
|
#include "cmaterialsystem.h"
|
|
|
|
#include "colorspace.h"
|
|
#include "materialsystem/materialsystem_config.h"
|
|
#include "materialsystem/imaterialproxyfactory.h"
|
|
#include "IHardwareConfigInternal.h"
|
|
#include "shadersystem.h"
|
|
#include "texturemanager.h"
|
|
#include "shaderlib/ShaderDLL.h"
|
|
#include "tier1/callqueue.h"
|
|
#include "vstdlib/jobthread.h"
|
|
#include "cmatnullrendercontext.h"
|
|
#include "datacache/iresourceaccesscontrol.h"
|
|
#include "filesystem/IQueuedLoader.h"
|
|
#include "filesystem/IXboxInstaller.h"
|
|
#include "cdll_int.h"
|
|
|
|
#include <cell/sysmodule.h>
|
|
#include <cell/font.h>
|
|
#include <cell/fontft.h>
|
|
#include "../common/vgui_surfacelib/vguifont.h"
|
|
|
|
#ifdef _PS3
|
|
#include "ps3_pathinfo.h"
|
|
#endif
|
|
|
|
// NOTE: This must be the last file included!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
static const CellFontLibrary *Fontlib();
|
|
|
|
// in case I make HPS3FONT something other than just a pointer
|
|
static inline CellFont *CellFontFromHandle( HPS3FONT &h )
|
|
{
|
|
return (CellFont *)h;
|
|
}
|
|
|
|
|
|
wchar_t g_wchFallbackGlyph = L'_';
|
|
|
|
static inline bool ShouldFallBackToSystemFontForWChar( wchar_t wch, int &nFontTallAdjustment )
|
|
{
|
|
if ( ( wch == 0x00AE /*(R)*/ ) || ( wch == 0x2122 /*(TM)*/ ) )
|
|
{
|
|
nFontTallAdjustment = 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#define TEXTURE_PAGE_HEIGHT 128 // copied from FontTextureCache.cpp, which for some reason hardcodes this. because there's multiple implementations
|
|
// of the font cache strewn throughout various libraries all linked into the vgui dll, I didn't feel safe changing
|
|
// it to just use larger textures.
|
|
|
|
|
|
class CFallbackFont: public CellFont
|
|
{
|
|
protected:
|
|
int m_nInitError;
|
|
int m_nTall;
|
|
CellFontHorizontalLayout m_hlayout;
|
|
public:
|
|
CFallbackFont(): m_nInitError(-1), m_nTall( -1 )
|
|
{
|
|
|
|
}
|
|
|
|
void Init()
|
|
{
|
|
if( m_nInitError == CELL_OK )
|
|
{
|
|
// already initialized
|
|
return ;
|
|
}
|
|
CellFontType fontType;
|
|
fontType.type = CELL_FONT_TYPE_GOTHIC_JAPANESE_CJK_LATIN_SET;
|
|
fontType.map = CELL_FONT_MAP_UNICODE;
|
|
m_nInitError = cellFontOpenFontset( Fontlib(), &fontType, this );
|
|
if( m_nInitError == CELL_OK )
|
|
{
|
|
Warning("Cannot open fallback font, error 0x%X\n", m_nInitError );
|
|
}
|
|
}
|
|
|
|
CellFontHorizontalLayout *GetHorizontalLayout()
|
|
{
|
|
return &m_hlayout;
|
|
}
|
|
|
|
int SetTall( int nTall )
|
|
{
|
|
if( m_nInitError != CELL_OK )
|
|
{
|
|
return m_nInitError;
|
|
}
|
|
|
|
if( nTall == m_nTall )
|
|
{
|
|
return CELL_OK;
|
|
}
|
|
|
|
float pointSize = nTall * 0.79f;
|
|
|
|
cellFontSetScalePixel( this, pointSize, pointSize );
|
|
// sometimes we ask for bigger fonts than the packer can handle. Also, because of accents etc, the font may poke out of the requested tall value.
|
|
// The packer is for some reason hardcoded to a maximum height of 128.
|
|
cellFontGetHorizontalLayout( this, &m_hlayout );
|
|
if ( m_hlayout.lineHeight + m_hlayout.effectHeight > TEXTURE_PAGE_HEIGHT )
|
|
{
|
|
Warning("FAILSAFE: Fallback Font at '%d' tall is actually %d pixels high, but max texture page is %d. Shrinking to ",
|
|
nTall, (int)(m_hlayout.lineHeight + m_hlayout.effectHeight), TEXTURE_PAGE_HEIGHT );
|
|
|
|
do
|
|
{
|
|
pointSize *= 0.9;
|
|
cellFontSetScalePixel( this, nTall, nTall );
|
|
cellFontGetHorizontalLayout( this, &m_hlayout );
|
|
}
|
|
while ( ( m_hlayout.lineHeight + m_hlayout.effectHeight > TEXTURE_PAGE_HEIGHT ) && ( pointSize >= 1 ) );
|
|
|
|
Warning( "%.2f\n", pointSize );
|
|
}
|
|
m_nTall = nTall;
|
|
return CELL_OK;
|
|
}
|
|
|
|
|
|
void Shutdown()
|
|
{
|
|
if( m_nInitError == CELL_OK )
|
|
{
|
|
int nError = cellFontCloseFont( this );
|
|
if( nError != CELL_OK )
|
|
{
|
|
Warning("Cannot close fallback font, error 0x%X\n", nError );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
CFallbackFont g_fallbackFont;
|
|
|
|
|
|
void CMaterialSystem::InitializePS3Fonts()
|
|
{
|
|
m_vExtantFonts.EnsureCapacity(8);
|
|
}
|
|
|
|
|
|
|
|
class CTempFontHandle
|
|
{
|
|
public:
|
|
CMaterialSystem * m_pMaterialSystem;
|
|
MaterialLock_t m_hLock;
|
|
CellFont * m_pNewFont;
|
|
public:
|
|
CTempFontHandle( CMaterialSystem * pMaterialSystem):
|
|
m_pMaterialSystem( pMaterialSystem )
|
|
{
|
|
m_hLock = pMaterialSystem->Lock();
|
|
m_pNewFont = new CellFont;
|
|
}
|
|
CellFont* DetachFont()
|
|
{
|
|
CellFont * pFont = m_pNewFont;
|
|
m_pNewFont = NULL;
|
|
return pFont;
|
|
}
|
|
~CTempFontHandle()
|
|
{
|
|
if( m_pNewFont )
|
|
{
|
|
delete m_pNewFont;
|
|
}
|
|
m_pMaterialSystem->Unlock( m_hLock );
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
HPS3FONT CMaterialSystem::OpenTrueTypeFont( const char *pFontname, int tall, int style )
|
|
{
|
|
CTempFontHandle hTemp( this );
|
|
|
|
static int sUniquePositiveNumber = 0;
|
|
|
|
// need absolute disk path, look in resource then platform
|
|
char fontpath[MAX_PATH] = {0};
|
|
|
|
struct fontTable_t
|
|
{
|
|
const char *pFontName;
|
|
const char *pPath;
|
|
bool m_bRestrictiveLoadIntoMemory;
|
|
bool m_bAlwaysLoadIntoMemory;
|
|
};
|
|
|
|
int nCellError;
|
|
if( !V_stricmp( pFontname, "system" ) )
|
|
{
|
|
CellFontType fontType;
|
|
fontType.type = CELL_FONT_TYPE_GOTHIC_JAPANESE_CJK_LATIN_SET;
|
|
fontType.map = CELL_FONT_MAP_UNICODE;
|
|
nCellError = cellFontOpenFontset( Fontlib(), &fontType, hTemp.m_pNewFont );
|
|
}
|
|
else if( !V_stricmp( pFontname, "japanese cjk latin" ) )
|
|
{
|
|
CellFontType fontType;
|
|
fontType.type = CELL_FONT_TYPE_GOTHIC_JAPANESE_CJK_LATIN_SET;
|
|
fontType.map = CELL_FONT_MAP_UNICODE;
|
|
nCellError = cellFontOpenFontset( Fontlib(), &fontType, hTemp.m_pNewFont );
|
|
}
|
|
else
|
|
{
|
|
|
|
// explicit mapping required, dvd searching too expensive
|
|
static fontTable_t fontToFilename[] =
|
|
{
|
|
#include "shaderapidx9/fontremaptable.h"
|
|
};
|
|
|
|
// remap typeface to diskname
|
|
char const *pDiskname = NULL;
|
|
for ( int i=0; i<ARRAYSIZE( fontToFilename ); i++ )
|
|
{
|
|
if ( !V_stricmp( pFontname, fontToFilename[i].pFontName ) )
|
|
{
|
|
pDiskname = fontToFilename[i].pPath;
|
|
break;
|
|
}
|
|
}
|
|
if ( !pDiskname )
|
|
{
|
|
// not found
|
|
DevWarning( "PS3: True Type Font: '%s' unknown.\n", pFontname );
|
|
}
|
|
else
|
|
{
|
|
Q_snprintf( fontpath, ARRAYSIZE( fontpath ), "%s/%s", g_pPS3PathInfo->GameImagePath(), pDiskname );
|
|
}
|
|
|
|
// if we failed to find the font, substitute a system font
|
|
if ( fontpath[0] == 0 )
|
|
{
|
|
CellFontType fontType;
|
|
fontType.type = CELL_FONT_TYPE_GOTHIC_JAPANESE_CJK_LATIN_SET;
|
|
fontType.map = CELL_FONT_MAP_UNICODE;
|
|
nCellError = cellFontOpenFontset( Fontlib(), &fontType, hTemp.m_pNewFont );
|
|
}
|
|
else
|
|
{
|
|
nCellError = cellFontOpenFontFile(
|
|
Fontlib(),
|
|
reinterpret_cast<uint8_t *>(fontpath),
|
|
0,
|
|
++sUniquePositiveNumber,
|
|
hTemp.m_pNewFont );
|
|
}
|
|
}
|
|
CellFont *pNewFont = NULL;
|
|
if ( nCellError != CELL_FONT_OK )
|
|
{
|
|
Warning( "could not open font '%s': %x\n", pFontname, nCellError );
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
pNewFont = hTemp.DetachFont(); // do not release the font structure
|
|
m_vExtantFonts.AddToTail( pNewFont );
|
|
}
|
|
|
|
float pointSize = tall * 0.79f;
|
|
|
|
cellFontSetScalePixel( pNewFont, pointSize, pointSize );
|
|
// sometimes we ask for bigger fonts than the packer can handle. Also, because of accents etc, the font may poke out of the requested tall value.
|
|
// The packer is for some reason hardcoded to a maximum height of 128.
|
|
CellFontHorizontalLayout hlayout;
|
|
cellFontGetHorizontalLayout( pNewFont, &hlayout );
|
|
if ( hlayout.lineHeight + hlayout.effectHeight > TEXTURE_PAGE_HEIGHT )
|
|
{
|
|
Warning("FAILSAFE: %s at '%d' tall is actually %d pixels high, but max texture page is %d. Shrinking to ",
|
|
pFontname, tall, (int)(hlayout.lineHeight + hlayout.effectHeight), TEXTURE_PAGE_HEIGHT );
|
|
|
|
do
|
|
{
|
|
pointSize *= 0.9;
|
|
cellFontSetScalePixel( pNewFont, tall, tall );
|
|
cellFontGetHorizontalLayout( pNewFont, &hlayout );
|
|
}
|
|
while ( ( hlayout.lineHeight + hlayout.effectHeight > TEXTURE_PAGE_HEIGHT ) && (pointSize >= 1) );
|
|
|
|
Warning( "%.2f\n", pointSize );
|
|
}
|
|
|
|
/*
|
|
nCellError = cellFontGetHorizontalLayout( &m_sFont, &m_HorizontalLayout );
|
|
AssertMsg2( nCellError == CELL_OK, "Could not get horizontal layout for font %s (%x)\n", m_szName.String(), nCellError );
|
|
*/
|
|
|
|
/*
|
|
nCellError = cellFontGetVerticalLayout( &m_sFont, &m_VerticalLayout );
|
|
AssertMsg2( nCellError == CELL_OK, "Could not get vertical layout for font %s (%x)\n", m_szName.String(), nCellError );
|
|
*/
|
|
|
|
return pNewFont;
|
|
}
|
|
|
|
void CMaterialSystem::CloseTrueTypeFont( HPS3FONT hFont )
|
|
{
|
|
MaterialLock_t hLock = Lock();
|
|
|
|
// find the font in the vector
|
|
CellFont *pFont = CellFontFromHandle( hFont );
|
|
cellFontCloseFont( pFont );
|
|
if ( m_vExtantFonts.FindAndFastRemove( pFont ) )
|
|
{
|
|
delete pFont;
|
|
}
|
|
else
|
|
{
|
|
AssertMsg1( false, "Tried to remove a font %x which wasn't in the material system's library\n", hFont );
|
|
}
|
|
|
|
|
|
Unlock( hLock );
|
|
}
|
|
|
|
|
|
bool CMaterialSystem::GetTrueTypeFontMetrics( HPS3FONT hFont, int nFallbackTall, wchar_t wchFirst, wchar_t wchLast, CPS3FontMetrics * RESTRICT pFontMetrics, CPS3CharMetrics * RESTRICT pCharMetrics )
|
|
{
|
|
MaterialLock_t hLock = Lock();
|
|
|
|
int numChars = wchLast - wchFirst + 1;
|
|
V_memset( pCharMetrics, 0, numChars * sizeof( CPS3CharMetrics ) );
|
|
CellFont * RESTRICT pFont = CellFontFromHandle( hFont );
|
|
|
|
int nCellError = cellFontGetHorizontalLayout( pFont, pFontMetrics );
|
|
AssertMsg1( nCellError == CELL_OK, "Could not get horizontal layout for font (%x)\n", nCellError );
|
|
// we will still need to go and fill in the max width once we've got the data for all the characters
|
|
float fMaxWidth = 0;
|
|
|
|
for ( int i = 0; i < numChars; i++ )
|
|
{
|
|
int nMetricsError = CELL_FONT_ERROR_FATAL;
|
|
int nFallbackFontTallAdjustment = 0;
|
|
if ( !ShouldFallBackToSystemFontForWChar( wchFirst + i, nFallbackFontTallAdjustment ) )
|
|
{
|
|
nMetricsError = cellFontGetCharGlyphMetrics( pFont, wchFirst + i, pCharMetrics + i );
|
|
}
|
|
if( nMetricsError != CELL_OK )
|
|
{
|
|
// try the fallback font
|
|
int nFallbackError = g_fallbackFont.SetTall( nFallbackTall + nFallbackFontTallAdjustment );
|
|
if( nFallbackError == CELL_OK )
|
|
{
|
|
nMetricsError = cellFontGetCharGlyphMetrics( &g_fallbackFont, wchFirst + i, pCharMetrics + i );
|
|
}
|
|
}
|
|
|
|
if( nMetricsError != CELL_OK )
|
|
{
|
|
nMetricsError = cellFontGetCharGlyphMetrics( pFont, g_wchFallbackGlyph, pCharMetrics + i );
|
|
}
|
|
|
|
if ( nMetricsError == CELL_OK )
|
|
{
|
|
fMaxWidth = fmax( fMaxWidth, pCharMetrics[i].Horizontal.advance + 1 );
|
|
}
|
|
else
|
|
{
|
|
memset( pCharMetrics+i, 0, sizeof(*pCharMetrics) );
|
|
}
|
|
}
|
|
|
|
pFontMetrics->fMaxWidth = fMaxWidth;
|
|
|
|
Unlock( hLock );
|
|
return nCellError == CELL_OK;
|
|
}
|
|
|
|
// encapsulates the ps3 fontlib renderer class with a RAII interface
|
|
// so it binds/unbinds automatically
|
|
class CFontRendererRAII
|
|
{
|
|
public:
|
|
CFontRendererRAII( CellFont *pBoundFont );
|
|
~CFontRendererRAII();
|
|
|
|
|
|
bool IsValid() { return m_nInitSuccess == CELL_FONT_OK; }
|
|
protected:
|
|
|
|
CellFontRenderer m_Renderer;
|
|
CellFont *m_pFont;
|
|
int m_nInitSuccess;
|
|
};
|
|
|
|
CFontRendererRAII::CFontRendererRAII( CellFont *pBoundFont ) : m_pFont(NULL)
|
|
{
|
|
CellFontRendererConfig config;
|
|
CellFontRendererConfig_initialize( &config );
|
|
|
|
// proper setup here
|
|
|
|
m_nInitSuccess = cellFontCreateRenderer( Fontlib(), &config, &m_Renderer );
|
|
if ( m_nInitSuccess != CELL_FONT_OK )
|
|
{
|
|
return ; // we have failed. we are failures. the stench of failure hangs upon us.
|
|
}
|
|
|
|
// connect the renderer to the font
|
|
m_nInitSuccess = cellFontBindRenderer( pBoundFont, &m_Renderer );
|
|
if ( m_nInitSuccess != CELL_FONT_OK )
|
|
{
|
|
return ; // we have failed. we are failures. the stench of failure hangs upon us.
|
|
}
|
|
|
|
m_pFont = pBoundFont;
|
|
}
|
|
|
|
CFontRendererRAII::~CFontRendererRAII()
|
|
{
|
|
if ( m_pFont )
|
|
{
|
|
cellFontUnbindRenderer( m_pFont );
|
|
}
|
|
cellFontDestroyRenderer( &m_Renderer );
|
|
}
|
|
|
|
// OPTIMIZATION OPPORTUNITY:
|
|
// This can be made to run on the RSX instead of the PPU, if necessary.
|
|
bool CMaterialSystem::GetTrueTypeGlyphs( HPS3FONT hFont, int nFallbackTall, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int * RESTRICT pWidth, int * RESTRICT pHeight, unsigned char *pRGBA, int *pRGBAOffset )
|
|
{
|
|
VPROF( "CMaterialSystem::GetTrueTypeGlyphs" );
|
|
|
|
MaterialLock_t hLock = Lock();
|
|
|
|
// Figure out the size of surface/texture we need to allocate
|
|
int rtWidth = 0;
|
|
int rtHeight = 0;
|
|
for ( int i = 0; i < numChars; i++ )
|
|
{
|
|
//rtWidth += pWidth[i];
|
|
rtWidth = MAX( rtWidth, pWidth[i] );
|
|
rtHeight = MAX( rtHeight, pHeight[i] );
|
|
}
|
|
|
|
/*
|
|
// per resolve() restrictions
|
|
rtWidth = AlignValue( rtWidth, 32 );
|
|
rtHeight = AlignValue( rtHeight, 32 );
|
|
*/
|
|
|
|
if ( rtWidth == 0 || rtHeight == 0 )
|
|
{
|
|
AssertMsg2( false, "Tried to draw a %dx%d glyph! What are you trying to pull?!\n", rtWidth, rtHeight );
|
|
Unlock( hLock );
|
|
return false;
|
|
}
|
|
|
|
CellFont *pFont = CellFontFromHandle( hFont );
|
|
CFontRendererRAII renderer( pFont ), *pFallbackRenderer = NULL;
|
|
|
|
CellFontRenderSurface surface;
|
|
CellFontGlyphMetrics metrics;
|
|
CellFontImageTransInfo transInfo;
|
|
CellFontHorizontalLayout hlayoutSlowWeShouldMoveThisIntoTheFontClass;
|
|
cellFontRenderSurfaceInit( &surface, NULL, rtWidth, 1, rtWidth, rtHeight ); // the surface doesn't actually use the memory pointer (go figure)
|
|
cellFontRenderSurfaceSetScissor( &surface, 0, 0, rtWidth, rtHeight );
|
|
cellFontGetHorizontalLayout( pFont, &hlayoutSlowWeShouldMoveThisIntoTheFontClass );
|
|
const int baselineY = floor(hlayoutSlowWeShouldMoveThisIntoTheFontClass.baseLineY);
|
|
|
|
// struct XUIRect { int x, int y, int w, int h };
|
|
|
|
// Draw the characters, stepping across the texture
|
|
// int xCursor = 0;
|
|
unsigned int successfulWrites = 0;
|
|
for ( int i = 0; i < numChars; i++)
|
|
{
|
|
/*
|
|
// FIXME: the drawRect params don't make much sense (should use "(xCursor+pWidth[i]), pHeight[i]", but then some characters disappear!)
|
|
XUIRect drawRect = XUIRect( xCursor + pOffsetX[i], pOffsetY[i], rtWidth, rtHeight );
|
|
cellFontRenderSurfaceSetScissor( &surface, drawRect.x, drawRect.y, drawRect.w, drawRect.h );
|
|
wchar_t text[2] = { pWch[i], 0 };
|
|
XuiDrawText( m_hDC, text, XUI_FONT_STYLE_NORMAL|XUI_FONT_STYLE_SINGLE_LINE|XUI_FONT_STYLE_NO_WORDWRAP, 0, &drawRect );
|
|
xCursor += pWidth[i];
|
|
*/
|
|
// draw one glyph to the surface
|
|
int ps3suc = CELL_FONT_ERROR_FATAL;
|
|
int nFallbackFontTallAdjustment = 0;
|
|
if ( !ShouldFallBackToSystemFontForWChar( pWch[i], nFallbackFontTallAdjustment ) )
|
|
{
|
|
ps3suc = cellFontRenderCharGlyphImage( pFont, pWch[i], &surface, 0, 0, &metrics, &transInfo );
|
|
}
|
|
if ( ps3suc != CELL_OK )
|
|
{
|
|
if( CELL_OK == g_fallbackFont.SetTall( nFallbackTall + nFallbackFontTallAdjustment ) )
|
|
{
|
|
if( !pFallbackRenderer )
|
|
pFallbackRenderer = new CFontRendererRAII( &g_fallbackFont );
|
|
ps3suc = cellFontRenderCharGlyphImage( &g_fallbackFont, pWch[i], &surface, 0, 0, &metrics, &transInfo );
|
|
}
|
|
}
|
|
|
|
if( ps3suc != CELL_OK )
|
|
{
|
|
ps3suc = cellFontRenderCharGlyphImage( pFont, g_wchFallbackGlyph, &surface, 0, 0, &metrics, &transInfo );
|
|
}
|
|
|
|
if ( ps3suc == CELL_OK )
|
|
{
|
|
|
|
// blit the glyph to the bitmap
|
|
const int ibw = transInfo.imageWidthByte;
|
|
const int iBearingY = ceilf(metrics.Horizontal.bearingY); // start the conversion early to avoid a LHS
|
|
int destPitch = pWidth[i]*4; // distance between one row and the next IN BYTES
|
|
unsigned char *pLinear = pRGBA + pRGBAOffset[i];
|
|
|
|
// Clear out all pixels to black, since the source glyph size may not match the destination buffer size perfectly
|
|
memset( pLinear, 0, pHeight[i] * destPitch );
|
|
|
|
if ( transInfo.imageHeight==0 || transInfo.imageWidth==0 )
|
|
{
|
|
// this can happen for space or control characters
|
|
// just blank out the destination box
|
|
continue; // bail out and go to next character !
|
|
}
|
|
|
|
// work out the size of the region to copy -- which is the smaller of the source or destination buffer.
|
|
// in theory these two should be identical, but the PS3 OS tends to overallocate space slightly
|
|
// in its render surface, and sometimes the VGUI font code is expecting a blank column of pixels
|
|
// where the PS3 generates none.
|
|
// also we'll try to align the font glyph to the bottom of the destination rect, rather than
|
|
// the top.
|
|
int numLeftPadPixels = ( int )floorf( metrics.Horizontal.bearingX );
|
|
numLeftPadPixels = MAX( 0, numLeftPadPixels );
|
|
int iteratorMaxColumn = MIN( pWidth[i] - numLeftPadPixels, transInfo.imageWidth );
|
|
int iteratorMaxRow = MIN( pHeight[i], transInfo.imageHeight );
|
|
unsigned char *pLinearAligned = pLinear; // work out where to start writing into the image so that chars are aligned to bottom of rect
|
|
|
|
pLinearAligned = pLinear + MAX(0, baselineY-iBearingY)*destPitch;
|
|
// for ( int row = 0 ; row < transInfo.imageHeight ; ++row )
|
|
for ( int row = 0 ; row < iteratorMaxRow; ++row )
|
|
{
|
|
uint32 * pRowStart = reinterpret_cast<uint32 *>(pLinearAligned + (row*destPitch)); // we will write the RGBA one word at a time
|
|
for ( int col = 0 ; col < iteratorMaxColumn; ++col )
|
|
{
|
|
// white characters; only the alpha mask is copied from the rendered glyph
|
|
// exception: totally absent regions are marked as just black
|
|
uint8 a = transInfo.Image[ row * ibw + col ];
|
|
*(pRowStart + col + numLeftPadPixels) = a ? 0xFFFFFF00 | a : 0 ;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if ( FILE *f = fopen( "/app_home/dbgfonts.txt", "a+" ) )
|
|
{
|
|
fprintf( f, "% 4d %C [%dx%d]\n",
|
|
pWch[i], pWch[i],
|
|
transInfo.imageWidth, transInfo.imageHeight
|
|
);
|
|
fprintf( f, " [%d]\n",
|
|
pWidth[i]
|
|
);
|
|
fprintf( f, " %0.5f %0.5f %0.5f\n",
|
|
metrics.Horizontal.bearingX, metrics.width, metrics.Horizontal.advance
|
|
);
|
|
for ( int row = 0; row < MAX( MAX( pHeight[i], ceilf( metrics.height ) ), transInfo.imageHeight ); ++ row )
|
|
{
|
|
for ( int col = 0; col < MAX( pWidth[i], ceilf( metrics.Horizontal.advance ) ); ++ col )
|
|
{
|
|
uint8 a = transInfo.Image[ row * ibw + col ];
|
|
fprintf( f, a ? ( (a>0x20) ? "X" : "*" ) : " " );
|
|
}
|
|
fprintf( f, "|\n" );
|
|
}
|
|
fprintf( f, "-----------------------------\n" );
|
|
fclose(f);
|
|
}
|
|
#endif
|
|
|
|
#if 0 // draw a line around the outer border for debugging
|
|
for ( int row = 0 ; row < pHeight[i]; ++row )
|
|
{
|
|
*(reinterpret_cast<uint32 *>(pLinear + (row*destPitch))+0) = 0xFFFFFFFF;
|
|
*(reinterpret_cast<uint32 *>(pLinear + (row*destPitch))+pWidth[i]-1) = 0xFFFFFFFF;
|
|
}
|
|
// top and bottom row
|
|
memset( pLinear, 0xFF, pWidth[i] * 4 );
|
|
memset( (pLinear + ((pHeight[i]-1)*destPitch)), 0xFF, pWidth[i] * 4 );
|
|
#endif
|
|
|
|
successfulWrites++;
|
|
}
|
|
else
|
|
{
|
|
AssertMsg2( false, "Couldn't draw u'%x', err %x\n", (unsigned int) *(pWch+i), ps3suc );
|
|
}
|
|
}
|
|
|
|
if( pFallbackRenderer )
|
|
delete pFallbackRenderer;
|
|
|
|
Unlock( hLock );
|
|
return successfulWrites > 0;
|
|
}
|
|
|
|
static int load_libfont_module()
|
|
{
|
|
int ret;
|
|
ret = cellSysmoduleLoadModule( CELL_SYSMODULE_FONT );
|
|
if ( ret == CELL_OK ) {
|
|
ret = cellSysmoduleLoadModule( CELL_SYSMODULE_FREETYPE_TT );
|
|
if ( ret == CELL_OK ) {
|
|
ret = cellSysmoduleLoadModule( CELL_SYSMODULE_FONTFT );
|
|
if ( ret == CELL_OK ) {
|
|
return CELL_OK; // Success
|
|
}
|
|
// Error handling as follows (Unload all loads)
|
|
cellSysmoduleUnloadModule( CELL_SYSMODULE_FREETYPE_TT );
|
|
}
|
|
cellSysmoduleUnloadModule( CELL_SYSMODULE_FONT );
|
|
}
|
|
return ret; // Error end
|
|
}
|
|
|
|
|
|
static void* fonts_malloc( void*obj, uint32_t size )
|
|
{
|
|
(void)obj;
|
|
return malloc( size );
|
|
}
|
|
static void fonts_free( void*obj, void*p )
|
|
{
|
|
(void)obj;
|
|
free( p );
|
|
}
|
|
static void* fonts_realloc( void*obj, void* p, uint32_t size )
|
|
{
|
|
(void)obj;
|
|
return realloc( p, size );
|
|
}
|
|
static void* fonts_calloc( void*obj, uint32_t numb, uint32_t blockSize )
|
|
{
|
|
(void)obj;
|
|
return calloc( numb, blockSize );
|
|
}
|
|
|
|
|
|
static int s_FontLibraryRefCount = 0;
|
|
static uint32 *s_FontFileCache = NULL;
|
|
static const CellFontLibrary *s_FontLibrary = NULL;
|
|
static CellFontEntry *s_UserFontEntries = NULL;
|
|
bool CMaterialSystem::PS3InitFontLibrary( unsigned fontFileCacheSizeInBytes, unsigned maxNumFonts )
|
|
{
|
|
if ( s_FontLibraryRefCount > 0 )
|
|
{
|
|
// don't need to load the font library, just add one to refcount
|
|
++s_FontLibraryRefCount;
|
|
return true;
|
|
}
|
|
else if ( s_FontLibraryRefCount < 0 )
|
|
{
|
|
Error( "Font library refcount is %d!\n", s_FontLibraryRefCount );
|
|
}
|
|
else
|
|
{
|
|
++s_FontLibraryRefCount;
|
|
}
|
|
|
|
VPROF("CMaterialSystem::PS3InitFontLibrary");
|
|
if ( s_FontFileCache )
|
|
{
|
|
Warning("Tried to init font library twice without intervening unload\n");
|
|
return false;
|
|
}
|
|
int ret;
|
|
if ( (ret=load_libfont_module()) != CELL_OK )
|
|
{
|
|
Warning("Could not load font library: %x\n", ret);
|
|
}
|
|
maxNumFonts = maxNumFonts ? maxNumFonts : 1;
|
|
|
|
if (s_FontFileCache)
|
|
{
|
|
Assert(false); // wasn't cleaned up?!
|
|
delete[] s_FontFileCache;
|
|
}
|
|
if (s_UserFontEntries)
|
|
{
|
|
Assert(false); // wasn't cleaned up?!
|
|
delete[] s_UserFontEntries;
|
|
}
|
|
s_FontFileCache = new uint32[fontFileCacheSizeInBytes >> 2];
|
|
s_UserFontEntries = new CellFontEntry[maxNumFonts];
|
|
|
|
CellFontConfig config;
|
|
config.FileCache.buffer = s_FontFileCache;
|
|
config.FileCache.size = fontFileCacheSizeInBytes;
|
|
config.userFontEntrys = s_UserFontEntries;
|
|
config.userFontEntryMax = maxNumFonts;
|
|
|
|
ret = cellFontInit(&config);
|
|
if ( ret == CELL_OK )
|
|
{
|
|
// can override malloc/free here:
|
|
CellFontLibraryConfigFT ftConfig;
|
|
CellFontLibraryConfigFT_initialize( &ftConfig );
|
|
|
|
ftConfig.MemoryIF.Object = NULL;
|
|
ftConfig.MemoryIF.Malloc = fonts_malloc;
|
|
ftConfig.MemoryIF.Free = fonts_free;
|
|
ftConfig.MemoryIF.Realloc = fonts_realloc;
|
|
ftConfig.MemoryIF.Calloc = fonts_calloc;
|
|
ret = cellFontInitLibraryFreeType( &ftConfig, &s_FontLibrary );
|
|
if ( ret == CELL_OK )
|
|
{
|
|
g_fallbackFont.Init( );
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Warning( "cellFontInitLibraryFreeType failed, %x\n", ret );
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning( "CellFontInit failed, %x\n", ret );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void *CMaterialSystem::PS3GetFontLibPtr()
|
|
{
|
|
return (void*)s_FontLibrary;
|
|
}
|
|
|
|
void CMaterialSystem::PS3DumpFontLibrary()
|
|
{
|
|
if ( s_FontLibraryRefCount <= 0 )
|
|
{
|
|
Warning("Font library refcount is %d during unload!\n", s_FontLibraryRefCount);
|
|
return;
|
|
}
|
|
else if ( s_FontLibrary == NULL )
|
|
{
|
|
Warning("\t!!!FAILSAFE!!!\nPS3 font library refcount %d but was somehow unloaded!\n", s_FontLibraryRefCount);
|
|
s_FontLibraryRefCount = 0;
|
|
}
|
|
else if ( --s_FontLibraryRefCount > 0 )
|
|
{ // refcount is still greater than one, don't need to unload
|
|
return;
|
|
}
|
|
|
|
// Warning( "Font library was dumped with %d fonts left open.\n", m_vExtantFonts.Count() );
|
|
if ( s_FontLibrary )
|
|
{
|
|
g_fallbackFont.Shutdown();
|
|
|
|
cellFontEndLibrary( s_FontLibrary );
|
|
cellFontEnd();
|
|
|
|
delete[] s_FontFileCache;
|
|
s_FontFileCache = NULL;
|
|
|
|
// handled by cellFontEndLibrary: // delete s_FontLibrary;
|
|
s_FontLibrary = NULL;
|
|
|
|
delete[] s_UserFontEntries;
|
|
s_UserFontEntries = NULL;
|
|
|
|
|
|
cellSysmoduleUnloadModule( CELL_SYSMODULE_FONTFT );
|
|
cellSysmoduleUnloadModule( CELL_SYSMODULE_FREETYPE_TT );
|
|
cellSysmoduleUnloadModule( CELL_SYSMODULE_FONT );
|
|
|
|
}
|
|
}
|
|
|
|
static const CellFontLibrary *Fontlib()
|
|
{
|
|
return s_FontLibrary;
|
|
}
|