Home | History | Annotate | Download | only in Tools
      1 /******************************************************************************
      2 
      3  @file         PVRTPrint3D.cpp
      4  @copyright    Copyright (c) Imagination Technologies Limited.
      5  @brief        Displays a text string using 3D polygons. Can be done in two ways:
      6                using a window defined by the user or writing straight on the
      7                screen.
      8 
      9 ******************************************************************************/
     10 
     11 /****************************************************************************
     12 ** Includes
     13 ****************************************************************************/
     14 #include <stdarg.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <wchar.h>
     19 
     20 #include "PVRTGlobal.h"
     21 #include "PVRTFixedPoint.h"
     22 #include "PVRTMatrix.h"
     23 #include "PVRTTexture.h"
     24 #include "PVRTPrint3D.h"
     25 #include "PVRTUnicode.h"
     26 #include "PVRTContext.h"
     27 #include "PVRTMap.h"
     28 
     29 /* Print3D texture data */
     30 #include "PVRTPrint3DIMGLogo.h"
     31 #include "PVRTPrint3DHelveticaBold.h"
     32 
     33 static inline float PVRTMakeWhole(float f)
     34 {
     35 	return floorf(f + 0.5f);
     36 }
     37 
     38 
     39 /****************************************************************************
     40 ** Defines
     41 ****************************************************************************/
     42 #define MAX_LETTERS				(5120)
     43 #define MIN_CACHED_VTX			(0x1000)
     44 #define MAX_CACHED_VTX			(0x00100000)
     45 #define LINES_SPACING			(29.0f)
     46 #define PVRPRINT3DVERSION		(1)
     47 
     48 #if defined(_WIN32)
     49 #define vsnprintf _vsnprintf
     50 #endif
     51 
     52 const PVRTuint32 PVRFONT_HEADER			= 0xFCFC0050;
     53 const PVRTuint32 PVRFONT_CHARLIST		= 0xFCFC0051;
     54 const PVRTuint32 PVRFONT_RECTS			= 0xFCFC0052;
     55 const PVRTuint32 PVRFONT_METRICS		= 0xFCFC0053;
     56 const PVRTuint32 PVRFONT_YOFFSET		= 0xFCFC0054;
     57 const PVRTuint32 PVRFONT_KERNING		= 0xFCFC0055;
     58 
     59 /****************************************************************************
     60 ** Constants
     61 ****************************************************************************/
     62 static const unsigned int PVRTPRINT3D_INVALID_CHAR = 0xFDFDFDFD;
     63 
     64 /****************************************************************************
     65 ** Auxiliary functions
     66 ****************************************************************************/
     67 /*!***************************************************************************
     68 @fn       		CharacterCompareFunc
     69 @param[in]		pA
     70 @param[in]		pB
     71 @return			PVRTint32
     72 @brief      	Compares two characters for binary search.
     73 *****************************************************************************/
     74 PVRTint32 CPVRTPrint3D::CharacterCompareFunc(const void* pA, const void* pB)
     75 {
     76 	return (*(PVRTint32*)pA - *(PVRTint32*)pB);
     77 }
     78 
     79 /*!***************************************************************************
     80 @fn       		KerningCompareFunc
     81 @param[in]		pA
     82 @param[in]		pB
     83 @return			PVRTint32
     84 @brief      	Compares two kerning pairs for binary search.
     85 *****************************************************************************/
     86 PVRTint32 CPVRTPrint3D::KerningCompareFunc(const void* pA, const void* pB)
     87 {
     88 	KerningPair* pPairA = (KerningPair*)pA;
     89 	KerningPair* pPairB = (KerningPair*)pB;
     90 
     91 	if(pPairA->uiPair > pPairB->uiPair)		return 1;
     92 	if(pPairA->uiPair < pPairB->uiPair)		return -1;
     93 
     94 	return 0;
     95 }
     96 
     97 /****************************************************************************
     98 ** Class: CPVRTPrint3D
     99 ****************************************************************************/
    100 /*****************************************************************************
    101  @fn       		CPVRTPrint3D
    102  @brief      	Init some values.
    103 *****************************************************************************/
    104 CPVRTPrint3D::CPVRTPrint3D() :	m_pAPI(NULL), m_uLogoToDisplay(ePVRTPrint3DLogoNone), m_pwFacesFont(NULL), m_pPrint3dVtx(NULL), m_bTexturesSet(false), m_pVtxCache(NULL), m_nVtxCache(0),
    105 								m_nVtxCacheMax(0), m_bRotate(false), m_nCachedNumVerts(0), m_pwzPreviousString(NULL), m_pszPreviousString(NULL), m_fPrevScale(0.0f), m_fPrevX(0.0f),
    106 								m_fPrevY(0.0f), m_uiPrevCol(0), m_pUVs(NULL), m_pKerningPairs(NULL), m_pCharMatrics(NULL), m_fTexW(0.0f), m_fTexH(0.0f), m_pRects(NULL), m_pYOffsets(NULL),
    107 								m_uiNextLineH(0), m_uiSpaceWidth(0), m_uiNumCharacters(0), m_uiNumKerningPairs(0), m_uiAscent(0), m_pszCharacterList(NULL), m_bHasMipmaps(false),
    108 								m_bUsingProjection(false)
    109 {
    110 	memset(m_fScreenScale, 0, sizeof(m_fScreenScale));
    111 	memset(m_ui32ScreenDim, 0, sizeof(m_ui32ScreenDim));
    112 
    113 	PVRTMatrixIdentity(m_mModelView);
    114 	PVRTMatrixIdentity(m_mProj);
    115 
    116 	m_pwzPreviousString = new wchar_t[MAX_LETTERS + 1];
    117 	m_pszPreviousString = new char[MAX_LETTERS + 1];
    118 	m_pwzPreviousString[0] = 0;
    119 	m_pszPreviousString[0] = 0;
    120 
    121 	m_eFilterMethod[eFilterProc_Min] = eFilter_Default;
    122 	m_eFilterMethod[eFilterProc_Mag] = eFilter_Default;
    123 	m_eFilterMethod[eFilterProc_Mip] = eFilter_MipDefault;
    124 }
    125 
    126 /*****************************************************************************
    127  @fn       		~CPVRTPrint3D
    128  @brief      	De-allocate the working memory
    129 *****************************************************************************/
    130 CPVRTPrint3D::~CPVRTPrint3D()
    131 {
    132 	delete [] m_pwzPreviousString;
    133 	delete [] m_pszPreviousString;
    134 
    135 	delete [] m_pszCharacterList;
    136 	delete [] m_pYOffsets;
    137 	delete [] m_pCharMatrics;
    138 	delete [] m_pKerningPairs;
    139 	delete [] m_pRects;
    140 	delete [] m_pUVs;
    141 }
    142 
    143 /*!***************************************************************************
    144 @fn       		ReadMetaBlock
    145 @param[in]		pDataCursor
    146 @return			bool	true if successful.
    147 @brief      	Reads a single meta data block from the data file.
    148 *****************************************************************************/
    149 bool CPVRTPrint3D::ReadMetaBlock(const PVRTuint8** pDataCursor)
    150 {
    151 	SPVRTPrint3DHeader* header;
    152 
    153 	unsigned int uiDataSize;
    154 
    155 	MetaDataBlock block;
    156 	if(!block.ReadFromPtr(pDataCursor))
    157 	{
    158 		return false;		// Must have been an error.
    159 	}
    160 
    161 	switch(block.u32Key)
    162 	{
    163 	case PVRFONT_HEADER:
    164 		header = (SPVRTPrint3DHeader*)block.Data;
    165 		if(header->uVersion != PVRTPRINT3D_VERSION)
    166 		{
    167 			return false;
    168 		}
    169 		// Copy options
    170 		m_uiAscent			= header->wAscent;
    171 		m_uiNextLineH		= header->wLineSpace;
    172 		m_uiSpaceWidth		= header->uSpaceWidth;
    173 		m_uiNumCharacters	= header->wNumCharacters & 0xFFFF;
    174 		m_uiNumKerningPairs = header->wNumKerningPairs & 0xFFFF;
    175 		break;
    176 	case PVRFONT_CHARLIST:
    177 		uiDataSize = sizeof(PVRTuint32) * m_uiNumCharacters;
    178 		_ASSERT(block.u32DataSize == uiDataSize);
    179 		m_pszCharacterList = new PVRTuint32[m_uiNumCharacters];
    180 		memcpy(m_pszCharacterList, block.Data, uiDataSize);
    181 		break;
    182 	case PVRFONT_YOFFSET:
    183 		uiDataSize = sizeof(PVRTint32) * m_uiNumCharacters;
    184 		_ASSERT(block.u32DataSize == uiDataSize);
    185 		m_pYOffsets	= new PVRTint32[m_uiNumCharacters];
    186 		memcpy(m_pYOffsets, block.Data, uiDataSize);
    187 		break;
    188 	case PVRFONT_METRICS:
    189 		uiDataSize = sizeof(CharMetrics) * m_uiNumCharacters;
    190 		_ASSERT(block.u32DataSize == uiDataSize);
    191 		m_pCharMatrics = new CharMetrics[m_uiNumCharacters];
    192 		memcpy(m_pCharMatrics, block.Data, uiDataSize);
    193 		break;
    194 	case PVRFONT_KERNING:
    195 		uiDataSize = sizeof(KerningPair) * m_uiNumKerningPairs;
    196 		_ASSERT(block.u32DataSize == uiDataSize);
    197 		m_pKerningPairs = new KerningPair[m_uiNumKerningPairs];
    198 		memcpy(m_pKerningPairs, block.Data, uiDataSize);
    199 		break;
    200 	case PVRFONT_RECTS:
    201 		uiDataSize = sizeof(Rectanglei) * m_uiNumCharacters;
    202 		_ASSERT(block.u32DataSize == uiDataSize);
    203 
    204 		m_pRects = new Rectanglei[m_uiNumCharacters];
    205 		memcpy(m_pRects, block.Data, uiDataSize);
    206 		break;
    207 	default:
    208 		_ASSERT(!"Unhandled key!");
    209 	}
    210 
    211 	return true;
    212 }
    213 
    214 /*!***************************************************************************
    215 @fn       		LoadFontData
    216 @param[in]		texHeader
    217 @param[in]		MetaDataMap
    218 @return			bool	true if successful.
    219 @brief      	Loads font data bundled with the texture file.
    220 *****************************************************************************/
    221 bool CPVRTPrint3D::LoadFontData( const PVRTextureHeaderV3* texHeader, CPVRTMap<PVRTuint32, CPVRTMap<PVRTuint32, MetaDataBlock> >& MetaDataMap )
    222 {
    223 	m_fTexW = (float)texHeader->u32Width;
    224 	m_fTexH = (float)texHeader->u32Height;
    225 
    226 	// Mipmap data is stored in the texture header data.
    227 	m_bHasMipmaps = (texHeader->u32MIPMapCount > 1 ? true : false);
    228 	if(m_bHasMipmaps)
    229 	{
    230 		m_eFilterMethod[eFilterProc_Min] = eFilter_Linear;
    231 		m_eFilterMethod[eFilterProc_Mag] = eFilter_Linear;
    232 		m_eFilterMethod[eFilterProc_Mip] = eFilter_Linear;
    233 	}
    234 	else
    235 	{
    236 		m_eFilterMethod[eFilterProc_Min] = eFilter_Linear;
    237 		m_eFilterMethod[eFilterProc_Mag] = eFilter_Linear;
    238 		m_eFilterMethod[eFilterProc_Mip] = eFilter_None;
    239 	}
    240 
    241 
    242 	// Header
    243 	SPVRTPrint3DHeader* header = (SPVRTPrint3DHeader*)MetaDataMap[PVRTEX3_IDENT][PVRFONT_HEADER].Data;
    244 	if(header->uVersion != PVRTPRINT3D_VERSION)
    245 	{
    246 		return false;
    247 	}
    248 	// Copy options
    249 	m_uiAscent			= header->wAscent;
    250 	m_uiNextLineH		= header->wLineSpace;
    251 	m_uiSpaceWidth		= header->uSpaceWidth;
    252 	m_uiNumCharacters	= header->wNumCharacters & 0xFFFF;
    253 	m_uiNumKerningPairs = header->wNumKerningPairs & 0xFFFF;
    254 
    255 	// Char list
    256 	m_pszCharacterList = new PVRTuint32[m_uiNumCharacters];
    257 	memcpy(m_pszCharacterList, MetaDataMap[PVRTEX3_IDENT][PVRFONT_CHARLIST].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_CHARLIST].u32DataSize);
    258 
    259 	m_pYOffsets	= new PVRTint32[m_uiNumCharacters];
    260 	memcpy(m_pYOffsets, MetaDataMap[PVRTEX3_IDENT][PVRFONT_YOFFSET].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_YOFFSET].u32DataSize);
    261 
    262 	m_pCharMatrics = new CharMetrics[m_uiNumCharacters];
    263 	memcpy(m_pCharMatrics, MetaDataMap[PVRTEX3_IDENT][PVRFONT_METRICS].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_METRICS].u32DataSize);
    264 
    265 	m_pKerningPairs = new KerningPair[m_uiNumKerningPairs];
    266 	memcpy(m_pKerningPairs, MetaDataMap[PVRTEX3_IDENT][PVRFONT_KERNING].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_KERNING].u32DataSize);
    267 
    268 	m_pRects = new Rectanglei[m_uiNumCharacters];
    269 	memcpy(m_pRects, MetaDataMap[PVRTEX3_IDENT][PVRFONT_RECTS].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_RECTS].u32DataSize);
    270 
    271 
    272 	// Build UVs
    273 	m_pUVs = new CharacterUV[m_uiNumCharacters];
    274 	for(unsigned int uiChar = 0; uiChar < m_uiNumCharacters; uiChar++)
    275 	{
    276 		m_pUVs[uiChar].fUL = m_pRects[uiChar].nX / m_fTexW;
    277 		m_pUVs[uiChar].fUR = m_pUVs[uiChar].fUL + m_pRects[uiChar].nW / m_fTexW;
    278 		m_pUVs[uiChar].fVT = m_pRects[uiChar].nY / m_fTexH;
    279 		m_pUVs[uiChar].fVB = m_pUVs[uiChar].fVT + m_pRects[uiChar].nH / m_fTexH;
    280 	}
    281 
    282 	return true;
    283 }
    284 
    285 /*!***************************************************************************
    286 @fn       		FindCharacter
    287 @param[in]		character
    288 @return			The character index, or PVRPRINT3D_INVALID_CHAR if not found.
    289 @brief      	Finds a given character in the binary data and returns it's
    290 				index.
    291 *****************************************************************************/
    292 PVRTuint32 CPVRTPrint3D::FindCharacter(PVRTuint32 character) const
    293 {
    294 	PVRTuint32* pItem = (PVRTuint32*)bsearch(&character, m_pszCharacterList, m_uiNumCharacters, sizeof(PVRTuint32), CharacterCompareFunc);
    295 	if(!pItem)
    296 		return PVRTPRINT3D_INVALID_CHAR;
    297 
    298 	PVRTuint32 uiIdx = (PVRTuint32) (pItem - m_pszCharacterList);
    299 	return uiIdx;
    300 }
    301 
    302 /*!***************************************************************************
    303 @fn       		ApplyKerning
    304 @param[in]		cA
    305 @param[in]		cB
    306 @param[out]		fOffset
    307 @brief      	Calculates kerning offset.
    308 *****************************************************************************/
    309 void CPVRTPrint3D::ApplyKerning(const PVRTuint32 cA, const PVRTuint32 cB, float& fOffset) const
    310 {
    311 	PVRTuint64 uiPairToSearch = ((PVRTuint64)cA << 32) | (PVRTuint64)cB;
    312 	KerningPair* pItem = (KerningPair*)bsearch(&uiPairToSearch, m_pKerningPairs, m_uiNumKerningPairs, sizeof(KerningPair), KerningCompareFunc);
    313 	if(pItem)
    314 		fOffset += (float)pItem->iOffset;
    315 }
    316 
    317 /*!***************************************************************************
    318  @fn       			SetTextures
    319  @param[in]			pContext		Context
    320  @param[in]			dwScreenX		Screen resolution along X
    321  @param[in]			dwScreenY		Screen resolution along Y
    322  @param[in]			bRotate			Rotate print3D by 90 degrees
    323  @param[in]			bMakeCopy		This instance of Print3D creates a copy
    324 									of it's data instead of sharing with previous
    325 									contexts. Set this parameter if you require
    326 									thread safety.
    327  @return			PVR_SUCCESS or PVR_FAIL
    328  @brief      		Initialization and texture upload. Should be called only once
    329 					for a given context.
    330 *****************************************************************************/
    331 EPVRTError CPVRTPrint3D::SetTextures(
    332 	const SPVRTContext	* const pContext,
    333 	const unsigned int	dwScreenX,
    334 	const unsigned int	dwScreenY,
    335 	const bool bRotate,
    336 	const bool bMakeCopy)
    337 {
    338 	// Determine which set of textures to use depending on the screen resolution.
    339 	const unsigned int uiShortestEdge = PVRT_MIN(dwScreenX, dwScreenY);
    340 	const void* pData = NULL;
    341 
    342 	if(uiShortestEdge >= 720)
    343 	{
    344 		pData = (void*)_helvbd_56_pvr;
    345 	}
    346 	else if(uiShortestEdge >= 640)
    347 	{
    348 		pData = (void*)_helvbd_46_pvr;
    349 	}
    350 	else
    351 	{
    352 		pData = (void*)_helvbd_36_pvr;
    353 	}
    354 
    355 	PVRT_UNREFERENCED_PARAMETER(_helvbd_36_pvr_size);
    356 	PVRT_UNREFERENCED_PARAMETER(_helvbd_46_pvr_size);
    357 	PVRT_UNREFERENCED_PARAMETER(_helvbd_56_pvr_size);
    358 
    359 	return SetTextures(pContext, pData, dwScreenX, dwScreenY, bRotate, bMakeCopy);
    360 }
    361 
    362 /*!***************************************************************************
    363 	@fn       		SetTextures
    364 	@param[in]		pContext		Context
    365 	@param[in]		pTexData		User-provided font texture
    366 	@param[in]		uiDataSize		Size of the data provided
    367 	@param[in]		dwScreenX		Screen resolution along X
    368 	@param[in]		dwScreenY		Screen resolution along Y
    369 	@param[in]		bRotate			Rotate print3D by 90 degrees
    370 	@param[in]		bMakeCopy		This instance of Print3D creates a copy
    371 									of it's data instead of sharing with previous
    372 									contexts. Set this parameter if you require
    373 									thread safety.
    374 	@return			PVR_SUCCESS or PVR_FAIL
    375 	@brief      	Initialization and texture upload of user-provided font
    376 					data. Should be called only once for a Print3D object.
    377 *****************************************************************************/
    378 EPVRTError CPVRTPrint3D::SetTextures(
    379 	const SPVRTContext	* const pContext,
    380 	const void * const pTexData,
    381 	const unsigned int	dwScreenX,
    382 	const unsigned int	dwScreenY,
    383 	const bool bRotate,
    384 	const bool bMakeCopy)
    385 {
    386 #if !defined (DISABLE_PRINT3D)
    387 
    388 	unsigned short	i;
    389 	bool			bStatus;
    390 
    391 	// Set the aspect ratio, so we can change it without updating textures or anything else
    392 	float fX, fY;
    393 
    394 	m_bRotate = bRotate;
    395 	m_ui32ScreenDim[0] = bRotate ? dwScreenY : dwScreenX;
    396 	m_ui32ScreenDim[1] = bRotate ? dwScreenX : dwScreenY;
    397 
    398 	// Alter the X, Y resolutions if the screen isn't portrait.
    399 	if(dwScreenX > dwScreenY)
    400 	{
    401 		fX = (float) dwScreenX;
    402 		fY = (float) dwScreenY;
    403 	}
    404 	else
    405 	{
    406 		fX = (float) dwScreenY;
    407 		fY = (float) dwScreenX;
    408 	}
    409 
    410 	m_fScreenScale[0] = (bRotate ? fY : fX) /640.0f;
    411 	m_fScreenScale[1] = (bRotate ? fX : fY) /480.0f;
    412 
    413 	// Check whether textures are already set up just in case
    414 	if (m_bTexturesSet)
    415 		return PVR_SUCCESS;
    416 
    417 	// INDEX BUFFERS
    418 	m_pwFacesFont = (unsigned short*)malloc(PVRTPRINT3D_MAX_RENDERABLE_LETTERS*2*3*sizeof(unsigned short));
    419 
    420 	if(!m_pwFacesFont)
    421 	{
    422 		return PVR_FAIL;
    423 	}
    424 
    425 	// Vertex indices for letters
    426 	for (i=0; i < PVRTPRINT3D_MAX_RENDERABLE_LETTERS; i++)
    427 	{
    428 		m_pwFacesFont[i*6+0] = 0+i*4;
    429 		m_pwFacesFont[i*6+1] = 3+i*4;
    430 		m_pwFacesFont[i*6+2] = 1+i*4;
    431 
    432 		m_pwFacesFont[i*6+3] = 3+i*4;
    433 		m_pwFacesFont[i*6+4] = 0+i*4;
    434 		m_pwFacesFont[i*6+5] = 2+i*4;
    435 	}
    436 
    437 
    438 	if(!APIInit(pContext, bMakeCopy))
    439 	{
    440 		return PVR_FAIL;
    441 	}
    442 	/*
    443 		This is the texture with the fonts.
    444 	*/
    445 	PVRTextureHeaderV3 header;
    446 	CPVRTMap<PVRTuint32, CPVRTMap<PVRTuint32, MetaDataBlock> > MetaDataMap;
    447 	bStatus = APIUpLoadTexture((unsigned char *)pTexData, &header, MetaDataMap);
    448 
    449 	if (!bStatus)
    450 	{
    451 		return PVR_FAIL;
    452 	}
    453 	/*
    454 		This is the associated font data with the default font
    455 	*/
    456 	bStatus = LoadFontData(&header, MetaDataMap);
    457 
    458 	bStatus = APIUpLoadIcons(reinterpret_cast<const PVRTuint8* const>(PVRTPrint3DIMGLogo), reinterpret_cast<const PVRTuint8* const>(PVRTPrint3DPowerVRLogo));
    459 
    460 	if (!bStatus) return PVR_FAIL;
    461 
    462 	m_nVtxCacheMax = MIN_CACHED_VTX;
    463 	m_pVtxCache = (SPVRTPrint3DAPIVertex*)malloc(m_nVtxCacheMax * sizeof(*m_pVtxCache));
    464 	m_nVtxCache = 0;
    465 
    466 	if(!m_pVtxCache)
    467 	{
    468 		return PVR_FAIL;
    469 	}
    470 
    471 	// Everything is OK
    472 	m_bTexturesSet = true;
    473 
    474 	// Return Success
    475 	return PVR_SUCCESS;
    476 
    477 #else
    478 	return PVR_SUCCESS;
    479 #endif
    480 }
    481 
    482 /*!***************************************************************************
    483 @fn       		Print3D
    484 @param[in]		fPosX		X Position
    485 @param[in]		fPosY		Y Position
    486 @param[in]		fScale		Text scale
    487 @param[in]		Colour		ARGB colour
    488 @param[in]		UTF32		Array of UTF32 characters
    489 @param[in]		bUpdate		Whether to update the vertices
    490 @return			EPVRTError	Success of failure
    491 @brief      	Takes an array of UTF32 characters and generates the required mesh.
    492 *****************************************************************************/
    493 EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const CPVRTArray<PVRTuint32>& UTF32, bool bUpdate)
    494 {
    495 	// No textures! so... no window
    496 	if (!m_bTexturesSet)
    497 	{
    498 		PVRTErrorOutputDebug("DisplayWindow : You must call CPVRTPrint3D::SetTextures(...) before using this function.\n");
    499 		return PVR_FAIL;
    500 	}
    501 
    502 	// nothing to be drawn
    503 	if(UTF32.GetSize() == 0)
    504 		return PVR_FAIL;
    505 
    506 	// Adjust input parameters
    507 	if(!m_bUsingProjection)
    508 	{
    509 		fPosX =  (float)((int)(fPosX * (640.0f/100.0f)));
    510 		fPosY = -(float)((int)(fPosY * (480.0f/100.0f)));
    511 	}
    512 
    513 	// Create Vertex Buffer (only if it doesn't exist)
    514 	if(m_pPrint3dVtx == 0)
    515 	{
    516 		m_pPrint3dVtx = (SPVRTPrint3DAPIVertex*)malloc(MAX_LETTERS*4*sizeof(SPVRTPrint3DAPIVertex));
    517 
    518 		if(!m_pPrint3dVtx)
    519 			return PVR_FAIL;
    520 	}
    521 
    522 	// Fill up our buffer
    523 	if(bUpdate)
    524 		m_nCachedNumVerts = UpdateLine(0.0f, fPosX, fPosY, fScale, Colour, UTF32, m_pPrint3dVtx);
    525 
    526 	// Draw the text
    527 	if(!DrawLine(m_pPrint3dVtx, m_nCachedNumVerts))
    528 		return PVR_FAIL;
    529 
    530 	return PVR_SUCCESS;
    531 }
    532 
    533 /*!***************************************************************************
    534  @fn       			Print3D
    535  @param[in]			fPosX		Position of the text along X
    536  @param[in]			fPosY		Position of the text along Y
    537  @param[in]			fScale		Scale of the text
    538  @param[in]			Colour		Colour of the text
    539  @param[in]			pszFormat	Format string for the text
    540  @return			PVR_SUCCESS or PVR_FAIL
    541  @brief      		Display wide-char 3D text on screen.
    542 					CPVRTPrint3D::SetTextures(...) must have been called
    543 					beforehand.
    544 					This function accepts formatting in the printf way.
    545 *****************************************************************************/
    546 EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const wchar_t * const pszFormat, ...)
    547 {
    548 #ifdef DISABLE_PRINT3D
    549 	return PVR_SUCCESS;
    550 #endif
    551 
    552 	static wchar_t s_Text[MAX_LETTERS+1] = {0};
    553 
    554 	/*
    555 		Unfortunately only Windows seems to properly support non-ASCII characters formatted in
    556 		vswprintf.
    557 	*/
    558 #if defined(_WIN32) && !defined(UNDER_CE)
    559 	va_list		args;
    560 	// Reading the arguments to create our Text string
    561 	va_start(args, pszFormat);
    562 	vswprintf(s_Text, MAX_LETTERS+1, pszFormat, args);
    563 	va_end(args);
    564 #else
    565 	wcscpy(s_Text, pszFormat);
    566 #endif
    567 
    568 	bool bUpdate = false;
    569 
    570 	// Optimisation to check that the strings are actually different.
    571 	if(wcscmp(s_Text, m_pwzPreviousString) != 0 || m_fPrevX != fPosX || m_fPrevY != fPosY || m_fPrevScale != fScale || m_uiPrevCol != Colour)
    572 	{
    573 		// Copy strings
    574 		wcscpy(m_pwzPreviousString, s_Text);
    575 		m_fPrevX = fPosX;
    576 		m_fPrevY = fPosY;
    577 		m_fPrevScale = fScale;
    578 		m_uiPrevCol  = Colour;
    579 
    580 		m_CachedUTF32.Clear();
    581 #if PVRTSIZEOFWCHAR == 2			// 2 byte wchar.
    582 		PVRTUnicodeUTF16ToUTF32((PVRTuint16*)s_Text, m_CachedUTF32);
    583 #elif PVRTSIZEOFWCHAR == 4			// 4 byte wchar (POSIX)
    584 		unsigned int uiC = 0;
    585 		PVRTuint32* pUTF32 = (PVRTuint32*)s_Text;
    586 		while(*pUTF32 && uiC < MAX_LETTERS)
    587 		{
    588 			m_CachedUTF32.Append(*pUTF32++);
    589 			uiC++;
    590 		}
    591 #else
    592 		return PVR_FAIL;
    593 #endif
    594 
    595 		bUpdate = true;
    596 	}
    597 
    598 	// Print
    599 	return Print3D(fPosX, fPosY, fScale, Colour, m_CachedUTF32, bUpdate);
    600 }
    601 
    602 /*!***************************************************************************
    603  @fn       			PVRTPrint3D
    604  @param[in]			fPosX		Position of the text along X
    605  @param[in]			fPosY		Position of the text along Y
    606  @param[in]			fScale		Scale of the text
    607  @param[in]			Colour		Colour of the text
    608  @param[in]			pszFormat	Format string for the text
    609  @return			PVR_SUCCESS or PVR_FAIL
    610  @brief      		Display 3D text on screen.
    611 					No window needs to be allocated to use this function.
    612 					However, CPVRTPrint3D::SetTextures(...) must have been called
    613 					beforehand.
    614 					This function accepts formatting in the printf way.
    615 *****************************************************************************/
    616 EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const char * const pszFormat, ...)
    617 {
    618 #ifdef DISABLE_PRINT3D
    619 	return PVR_SUCCESS;
    620 #endif
    621 
    622 	va_list		args;
    623 	static char	s_Text[MAX_LETTERS+1] = {0};
    624 
    625 	// Reading the arguments to create our Text string
    626 	va_start(args, pszFormat);
    627 	vsnprintf(s_Text, MAX_LETTERS+1, pszFormat, args);
    628 	va_end(args);
    629 
    630 	bool bUpdate = false;
    631 
    632 	// Optimisation to check that the strings are actually different.
    633 	if(strcmp(s_Text, m_pszPreviousString) != 0 || m_fPrevX != fPosX || m_fPrevY != fPosY || m_fPrevScale != fScale || m_uiPrevCol != Colour)
    634 	{
    635 		// Copy strings
    636 		strcpy (m_pszPreviousString, s_Text);
    637 		m_fPrevX = fPosX;
    638 		m_fPrevY = fPosY;
    639 		m_fPrevScale = fScale;
    640 		m_uiPrevCol  = Colour;
    641 
    642 		// Convert from UTF8 to UTF32
    643 		m_CachedUTF32.Clear();
    644 		PVRTUnicodeUTF8ToUTF32((const PVRTuint8*)s_Text, m_CachedUTF32);
    645 
    646 		bUpdate = true;
    647 	}
    648 
    649 	// Print
    650 	return Print3D(fPosX, fPosY, fScale, Colour, m_CachedUTF32, bUpdate);
    651 }
    652 
    653 /*!***************************************************************************
    654  @fn       			DisplayDefaultTitle
    655  @param[in]			sTitle				Title to display
    656  @param[in]			sDescription		Description to display
    657  @param[in]			uDisplayLogo		1 = Display the logo
    658  @return			PVR_SUCCESS or PVR_FAIL
    659  @brief      		Creates a default title with predefined position and colours.
    660 					It displays as well company logos when requested:
    661 					0 = No logo
    662 					1 = PowerVR logo
    663 					2 = Img Tech logo
    664 *****************************************************************************/
    665 EPVRTError CPVRTPrint3D::DisplayDefaultTitle(const char * const pszTitle, const char * const pszDescription, const unsigned int uDisplayLogo)
    666 {
    667 	EPVRTError eRet = PVR_SUCCESS;
    668 
    669 #if !defined (DISABLE_PRINT3D)
    670 
    671 	// Display Title
    672 	if(pszTitle)
    673 	{
    674 		if(Print3D(0.0f, -1.0f, 1.0f,  PVRTRGBA(255, 255, 255, 255), pszTitle) != PVR_SUCCESS)
    675 			eRet = PVR_FAIL;
    676 	}
    677 
    678 	float fYVal;
    679 	if(m_bRotate)
    680 		fYVal = m_fScreenScale[0] * 480.0f;
    681 	else
    682 		fYVal = m_fScreenScale[1] * 480.0f;
    683 
    684 	// Display Description
    685 	if(pszDescription)
    686 	{
    687         float fY;
    688 		float a = 320.0f/fYVal;
    689 		fY = m_uiNextLineH / (480.0f/100.0f) * a;
    690 
    691 		if(Print3D(0.0f, fY, 0.8f,  PVRTRGBA(255, 255, 255, 255), pszDescription) != PVR_SUCCESS)
    692 			eRet = PVR_FAIL;
    693 	}
    694 
    695 	m_uLogoToDisplay = uDisplayLogo;
    696 
    697 #endif
    698 
    699 	return eRet;
    700 }
    701 
    702 /*!***************************************************************************
    703  @fn       			MeasureText
    704  @param[out]		pfWidth				Width of the string in pixels
    705  @param[out]		pfHeight			Height of the string in pixels
    706  @param[in]			fFontSize			Font size
    707  @param[in]			sString				String to take the size of
    708  @brief      		Returns the size of a string in pixels.
    709 *****************************************************************************/
    710 void CPVRTPrint3D::MeasureText(
    711 	float		* const pfWidth,
    712 	float		* const pfHeight,
    713 	float				fScale,
    714 	const CPVRTArray<PVRTuint32>& utf32)
    715 {
    716 #if !defined (DISABLE_PRINT3D)
    717 	if(utf32.GetSize() == 0) {
    718 		if(pfWidth)
    719 			*pfWidth = 0;
    720 		if(pfHeight)
    721 			*pfHeight = 0;
    722 		return;
    723 	}
    724 
    725 	float fLength			= 0;
    726 	float fMaxLength		= -1.0f;
    727 	float fMaxHeight		= (float)m_uiNextLineH;
    728 	PVRTuint32 txNextChar	= 0;
    729 	PVRTuint32 uiIdx;
    730 	for(PVRTuint32 uiIndex = 0; uiIndex < utf32.GetSize(); uiIndex++)
    731 	{
    732 		if(utf32[uiIndex] == 0x0D || utf32[uiIndex] == 0x0A)
    733 		{
    734 			if(fLength > fMaxLength)
    735 				fMaxLength = fLength;
    736 
    737 			fLength = 0;
    738 			fMaxHeight += (float)m_uiNextLineH;
    739 		}
    740 		uiIdx = FindCharacter(utf32[uiIndex]);
    741 		if(uiIdx == PVRTPRINT3D_INVALID_CHAR)		// No character found. Add a space.
    742 		{
    743 			fLength += m_uiSpaceWidth;
    744 			continue;
    745 		}
    746 
    747 		txNextChar = utf32[uiIndex + 1];
    748 		float fKernOffset = 0;
    749 		ApplyKerning(utf32[uiIndex], txNextChar, fKernOffset);
    750 
    751 		fLength += m_pCharMatrics[uiIdx].nAdv + fKernOffset;		// Add on this characters width
    752 	}
    753 
    754 	if(fMaxLength < 0.0f)		// Obviously no new line.
    755 		fMaxLength = fLength;
    756 
    757 	if(pfWidth)
    758 		*pfWidth = fMaxLength * fScale;
    759 	if(pfHeight)
    760 		*pfHeight = fMaxHeight * fScale;
    761 #endif
    762 }
    763 
    764 /*!***************************************************************************
    765  @fn       			GetSize
    766  @param[out]		pfWidth				Width of the string in pixels
    767  @param[out]		pfHeight			Height of the string in pixels
    768  @param[in]			pszUTF8				UTF8 string to take the size of
    769  @brief      		Returns the size of a string in pixels.
    770 *****************************************************************************/
    771 void CPVRTPrint3D::MeasureText(
    772 	float		* const pfWidth,
    773 	float		* const pfHeight,
    774 	float				fScale,
    775 	const char	* const pszUTF8)
    776 {
    777 	m_CachedUTF32.Clear();
    778 	PVRTUnicodeUTF8ToUTF32((PVRTuint8*)pszUTF8, m_CachedUTF32);
    779 	MeasureText(pfWidth,pfHeight,fScale,m_CachedUTF32);
    780 }
    781 
    782 /*!***************************************************************************
    783  @fn       			MeasureText
    784  @param[out]		pfWidth		Width of the string in pixels
    785  @param[out]		pfHeight	Height of the string in pixels
    786  @param[in]			pszUnicode	Wide character string to take the length of.
    787  @brief      		Returns the size of a string in pixels.
    788 *****************************************************************************/
    789 void CPVRTPrint3D::MeasureText(
    790 	float		* const pfWidth,
    791 	float		* const pfHeight,
    792 	float				fScale,
    793 	const wchar_t* const pszUnicode)
    794 {
    795 	_ASSERT(pszUnicode);
    796 	m_CachedUTF32.Clear();
    797 
    798 #if PVRTSIZEOFWCHAR == 2			// 2 byte wchar.
    799 	PVRTUnicodeUTF16ToUTF32((PVRTuint16*)pszUnicode, m_CachedUTF32);
    800 #else								// 4 byte wchar (POSIX)
    801 	unsigned int uiC = 0;
    802 	PVRTuint32* pUTF32 = (PVRTuint32*)pszUnicode;
    803 	while(*pUTF32 && uiC < MAX_LETTERS)
    804 	{
    805 		m_CachedUTF32.Append(*pUTF32++);
    806 		uiC++;
    807 	}
    808 #endif
    809 
    810 	MeasureText(pfWidth,pfHeight,fScale,m_CachedUTF32);
    811 }
    812 
    813 /*!***************************************************************************
    814  @fn       			GetAspectRatio
    815  @param[out]		dwScreenX		Screen resolution X
    816  @param[out]		dwScreenY		Screen resolution Y
    817  @brief      		Returns the current resolution used by Print3D
    818 *****************************************************************************/
    819 void CPVRTPrint3D::GetAspectRatio(unsigned int *dwScreenX, unsigned int *dwScreenY)
    820 {
    821 #if !defined (DISABLE_PRINT3D)
    822 
    823 	*dwScreenX = (int)(640.0f * m_fScreenScale[0]);
    824 	*dwScreenY = (int)(480.0f * m_fScreenScale[1]);
    825 #endif
    826 }
    827 
    828 /*************************************************************
    829 *					 PRIVATE FUNCTIONS						 *
    830 **************************************************************/
    831 
    832 /*!***************************************************************************
    833  @brief             Update a single line
    834  @param[in]			fZPos
    835  @param[in]			XPos
    836  @param[in]			YPos
    837  @param[in]			fScale
    838  @param[in]			Colour
    839  @param[in]			Text
    840  @param[in]			pVertices
    841  @return            Number of vertices affected
    842 *****************************************************************************/
    843 unsigned int CPVRTPrint3D::UpdateLine(const float fZPos, float XPos, float YPos, const float fScale, const unsigned int Colour, const CPVRTArray<PVRTuint32>& Text, SPVRTPrint3DAPIVertex * const pVertices)
    844 {
    845 	/* Nothing to update */
    846 	if (Text.GetSize() == 0)
    847 		return 0;
    848 
    849 	if(!m_bUsingProjection)
    850 	{
    851 		XPos *= ((float)m_ui32ScreenDim[0] / 640.0f);
    852 		YPos *= ((float)m_ui32ScreenDim[1] / 480.0f);
    853 	}
    854 
    855 	YPos -= m_uiAscent * fScale;
    856 
    857 	YPos = PVRTMakeWhole(YPos);
    858 
    859 	float fPreXPos	= XPos;		// The original offset (after screen scale modification) of the X coordinate.
    860 
    861 	float		fKernOffset;
    862 	float		fAOff;
    863 	float		fYOffset;
    864 	unsigned int VertexCount = 0;
    865 	PVRTint32 NextChar;
    866 
    867 	unsigned int uiNumCharsInString = Text.GetSize();
    868 	for(unsigned int uiIndex = 0; uiIndex < uiNumCharsInString; uiIndex++)
    869 	{
    870 		if(uiIndex > MAX_LETTERS)
    871 			break;
    872 
    873 		// Newline
    874 		if(Text[uiIndex] == 0x0A)
    875 		{
    876 			XPos = fPreXPos;
    877 			YPos -= PVRTMakeWhole(m_uiNextLineH * fScale);
    878 			continue;
    879 		}
    880 
    881 		// Get the character
    882 		PVRTuint32 uiIdx = FindCharacter(Text[uiIndex]);
    883 
    884 		// Not found. Add a space.
    885 		if(uiIdx == PVRTPRINT3D_INVALID_CHAR)		// No character found. Add a space.
    886 		{
    887 			XPos += PVRTMakeWhole(m_uiSpaceWidth * fScale);
    888 			continue;
    889 		}
    890 
    891 		fKernOffset = 0;
    892 		fYOffset	= m_pYOffsets[uiIdx] * fScale;
    893 		fAOff		= PVRTMakeWhole(m_pCharMatrics[uiIdx].nXOff * fScale);					// The A offset. Could include overhang or underhang.
    894 		if(uiIndex < uiNumCharsInString - 1)
    895 		{
    896 			NextChar = Text[uiIndex + 1];
    897 			ApplyKerning(Text[uiIndex], NextChar, fKernOffset);
    898 		}
    899 
    900 		/* Filling vertex data */
    901 		pVertices[VertexCount+0].sx		= f2vt(XPos + fAOff);
    902 		pVertices[VertexCount+0].sy		= f2vt(YPos + fYOffset);
    903 		pVertices[VertexCount+0].sz		= f2vt(fZPos);
    904 		pVertices[VertexCount+0].rhw	= f2vt(1.0f);
    905 		pVertices[VertexCount+0].tu		= f2vt(m_pUVs[uiIdx].fUL);
    906 		pVertices[VertexCount+0].tv		= f2vt(m_pUVs[uiIdx].fVT);
    907 
    908 		pVertices[VertexCount+1].sx		= f2vt(XPos + fAOff + PVRTMakeWhole(m_pRects[uiIdx].nW * fScale));
    909 		pVertices[VertexCount+1].sy		= f2vt(YPos + fYOffset);
    910 		pVertices[VertexCount+1].sz		= f2vt(fZPos);
    911 		pVertices[VertexCount+1].rhw	= f2vt(1.0f);
    912 		pVertices[VertexCount+1].tu		= f2vt(m_pUVs[uiIdx].fUR);
    913 		pVertices[VertexCount+1].tv		= f2vt(m_pUVs[uiIdx].fVT);
    914 
    915 		pVertices[VertexCount+2].sx		= f2vt(XPos + fAOff);
    916 		pVertices[VertexCount+2].sy		= f2vt(YPos + fYOffset - PVRTMakeWhole(m_pRects[uiIdx].nH * fScale));
    917 		pVertices[VertexCount+2].sz		= f2vt(fZPos);
    918 		pVertices[VertexCount+2].rhw	= f2vt(1.0f);
    919 		pVertices[VertexCount+2].tu		= f2vt(m_pUVs[uiIdx].fUL);
    920 		pVertices[VertexCount+2].tv		= f2vt(m_pUVs[uiIdx].fVB);
    921 
    922 		pVertices[VertexCount+3].sx		= f2vt(XPos + fAOff + PVRTMakeWhole(m_pRects[uiIdx].nW * fScale));
    923 		pVertices[VertexCount+3].sy		= f2vt(YPos + fYOffset - PVRTMakeWhole(m_pRects[uiIdx].nH * fScale));
    924 		pVertices[VertexCount+3].sz		= f2vt(fZPos);
    925 		pVertices[VertexCount+3].rhw	= f2vt(1.0f);
    926 		pVertices[VertexCount+3].tu		= f2vt(m_pUVs[uiIdx].fUR);
    927 		pVertices[VertexCount+3].tv		= f2vt(m_pUVs[uiIdx].fVB);
    928 
    929 		pVertices[VertexCount+0].color	= Colour;
    930 		pVertices[VertexCount+1].color	= Colour;
    931 		pVertices[VertexCount+2].color	= Colour;
    932 		pVertices[VertexCount+3].color	= Colour;
    933 
    934 		XPos = XPos + PVRTMakeWhole((m_pCharMatrics[uiIdx].nAdv + fKernOffset) * fScale);		// Add on this characters width
    935 		VertexCount += 4;
    936 	}
    937 
    938 	return VertexCount;
    939 }
    940 
    941 /*!***************************************************************************
    942  @fn       			DrawLineUP
    943  @return			true or false
    944  @brief      		Draw a single line of text.
    945 *****************************************************************************/
    946 bool CPVRTPrint3D::DrawLine(SPVRTPrint3DAPIVertex *pVtx, unsigned int nVertices)
    947 {
    948 	if(!nVertices)
    949 		return true;
    950 
    951 	_ASSERT((nVertices % 4) == 0);
    952 	_ASSERT((nVertices/4) < MAX_LETTERS);
    953 
    954 	while(m_nVtxCache + (int)nVertices > m_nVtxCacheMax) {
    955 		if(m_nVtxCache + nVertices > MAX_CACHED_VTX) {
    956 			_RPT1(_CRT_WARN, "Print3D: Out of space to cache text! (More than %d vertices!)\n", MAX_CACHED_VTX);
    957 			return false;
    958 		}
    959 
    960 		m_nVtxCacheMax	= PVRT_MIN(m_nVtxCacheMax * 2, MAX_CACHED_VTX);
    961 		SPVRTPrint3DAPIVertex* pTmp = (SPVRTPrint3DAPIVertex*)realloc(m_pVtxCache, m_nVtxCacheMax * sizeof(*m_pVtxCache));
    962 
    963 		_ASSERT(pTmp);
    964 		if(!pTmp)
    965 		{
    966 			free(m_pVtxCache);
    967 			m_pVtxCache = 0;
    968 			return false; // Failed to re-allocate data
    969 		}
    970 
    971 		m_pVtxCache = pTmp;
    972 
    973 		_RPT1(_CRT_WARN, "Print3D: TextCache increased to %d vertices.\n", m_nVtxCacheMax);
    974 	}
    975 
    976 	memcpy(&m_pVtxCache[m_nVtxCache], pVtx, nVertices * sizeof(*pVtx));
    977 	m_nVtxCache += nVertices;
    978 	return true;
    979 }
    980 
    981 /*!***************************************************************************
    982  @fn       			SetProjection
    983  @brief      		Sets projection matrix.
    984 *****************************************************************************/
    985 void CPVRTPrint3D::SetProjection(const PVRTMat4& mProj)
    986 {
    987 	m_mProj				= mProj;
    988 	m_bUsingProjection	= true;
    989 }
    990 
    991 /*!***************************************************************************
    992  @fn       			SetModelView
    993  @brief      		Sets model view matrix.
    994 *****************************************************************************/
    995 void CPVRTPrint3D::SetModelView(const PVRTMat4& mModelView)
    996 {
    997 	m_mModelView = mModelView;
    998 }
    999 
   1000 /*!***************************************************************************
   1001  @fn       		SetFiltering
   1002  @param[in]		eFilter				The method of texture filtering
   1003  @brief      	Sets the method of texture filtering for the font texture.
   1004 					Print3D will attempt to pick the best method by default
   1005 					but this method allows the user to override this.
   1006 *****************************************************************************/
   1007 void CPVRTPrint3D::SetFiltering(ETextureFilter eMin, ETextureFilter eMag, ETextureFilter eMip)
   1008 {
   1009 	if(eMin == eFilter_None) eMin = eFilter_Default;		// Illegal value
   1010 	if(eMag == eFilter_None) eMag = eFilter_Default;		// Illegal value
   1011 
   1012 	m_eFilterMethod[eFilterProc_Min] = eMin;
   1013 	m_eFilterMethod[eFilterProc_Mag] = eMag;
   1014 	m_eFilterMethod[eFilterProc_Mip] = eMip;
   1015 }
   1016 
   1017 /*!***************************************************************************
   1018  @fn       		GetFontAscent
   1019  @return		unsigned int	The ascent.
   1020  @brief      	Returns the 'ascent' of the font. This is typically the
   1021 				height from the baseline of the larget glyph in the set.
   1022 *****************************************************************************/
   1023 unsigned int CPVRTPrint3D::GetFontAscent()
   1024 {
   1025 	return m_uiAscent;
   1026 }
   1027 
   1028 /*!***************************************************************************
   1029  @fn       		GetFontLineSpacing
   1030  @return		unsigned int	The line spacing.
   1031  @brief      	Returns the default line spacing (i.e baseline to baseline)
   1032 				for the font.
   1033 *****************************************************************************/
   1034 unsigned int CPVRTPrint3D::GetFontLineSpacing()
   1035 {
   1036 	return m_uiNextLineH;
   1037 }
   1038 
   1039 /****************************************************************************
   1040 ** Local code
   1041 ****************************************************************************/
   1042 
   1043 /*****************************************************************************
   1044  End of file (PVRTPrint3D.cpp)
   1045 *****************************************************************************/
   1046 
   1047