| /****************************************************************************** | 
 |  | 
 |  @file         PVRTPrint3D.cpp | 
 |  @copyright    Copyright (c) Imagination Technologies Limited. | 
 |  @brief        Displays a text string using 3D polygons. Can be done in two ways: | 
 |                using a window defined by the user or writing straight on the | 
 |                screen. | 
 |  | 
 | ******************************************************************************/ | 
 |  | 
 | /**************************************************************************** | 
 | ** Includes | 
 | ****************************************************************************/ | 
 | #include <stdarg.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <wchar.h> | 
 |  | 
 | #include "PVRTGlobal.h" | 
 | #include "PVRTFixedPoint.h" | 
 | #include "PVRTMatrix.h" | 
 | #include "PVRTTexture.h" | 
 | #include "PVRTPrint3D.h" | 
 | #include "PVRTUnicode.h" | 
 | #include "PVRTContext.h" | 
 | #include "PVRTMap.h" | 
 |  | 
 | /* Print3D texture data */ | 
 | #include "PVRTPrint3DIMGLogo.h" | 
 | #include "PVRTPrint3DHelveticaBold.h" | 
 |  | 
 | static inline float PVRTMakeWhole(float f) | 
 | { | 
 | 	return floorf(f + 0.5f); | 
 | } | 
 |  | 
 |  | 
 | /**************************************************************************** | 
 | ** Defines | 
 | ****************************************************************************/ | 
 | #define MAX_LETTERS				(5120) | 
 | #define MIN_CACHED_VTX			(0x1000) | 
 | #define MAX_CACHED_VTX			(0x00100000) | 
 | #define LINES_SPACING			(29.0f) | 
 | #define PVRPRINT3DVERSION		(1) | 
 |  | 
 | #if defined(_WIN32) | 
 | #define vsnprintf _vsnprintf | 
 | #endif | 
 |  | 
 | const PVRTuint32 PVRFONT_HEADER			= 0xFCFC0050; | 
 | const PVRTuint32 PVRFONT_CHARLIST		= 0xFCFC0051; | 
 | const PVRTuint32 PVRFONT_RECTS			= 0xFCFC0052; | 
 | const PVRTuint32 PVRFONT_METRICS		= 0xFCFC0053; | 
 | const PVRTuint32 PVRFONT_YOFFSET		= 0xFCFC0054; | 
 | const PVRTuint32 PVRFONT_KERNING		= 0xFCFC0055; | 
 |  | 
 | /**************************************************************************** | 
 | ** Constants | 
 | ****************************************************************************/ | 
 | static const unsigned int PVRTPRINT3D_INVALID_CHAR = 0xFDFDFDFD; | 
 |  | 
 | /**************************************************************************** | 
 | ** Auxiliary functions | 
 | ****************************************************************************/ | 
 | /*!*************************************************************************** | 
 | @fn       		CharacterCompareFunc | 
 | @param[in]		pA | 
 | @param[in]		pB | 
 | @return			PVRTint32	 | 
 | @brief      	Compares two characters for binary search. | 
 | *****************************************************************************/ | 
 | PVRTint32 CPVRTPrint3D::CharacterCompareFunc(const void* pA, const void* pB) | 
 | { | 
 | 	return (*(PVRTint32*)pA - *(PVRTint32*)pB); | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | @fn       		KerningCompareFunc | 
 | @param[in]		pA | 
 | @param[in]		pB | 
 | @return			PVRTint32	 | 
 | @brief      	Compares two kerning pairs for binary search. | 
 | *****************************************************************************/ | 
 | PVRTint32 CPVRTPrint3D::KerningCompareFunc(const void* pA, const void* pB) | 
 | { | 
 | 	KerningPair* pPairA = (KerningPair*)pA; | 
 | 	KerningPair* pPairB = (KerningPair*)pB; | 
 |  | 
 | 	if(pPairA->uiPair > pPairB->uiPair)		return 1; | 
 | 	if(pPairA->uiPair < pPairB->uiPair)		return -1; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /**************************************************************************** | 
 | ** Class: CPVRTPrint3D | 
 | ****************************************************************************/ | 
 | /***************************************************************************** | 
 |  @fn       		CPVRTPrint3D | 
 |  @brief      	Init some values. | 
 | *****************************************************************************/ | 
 | CPVRTPrint3D::CPVRTPrint3D() :	m_pAPI(NULL), m_uLogoToDisplay(ePVRTPrint3DLogoNone), m_pwFacesFont(NULL), m_pPrint3dVtx(NULL), m_bTexturesSet(false), m_pVtxCache(NULL), m_nVtxCache(0), | 
 | 								m_nVtxCacheMax(0), m_bRotate(false), m_nCachedNumVerts(0), m_pwzPreviousString(NULL), m_pszPreviousString(NULL), m_fPrevScale(0.0f), m_fPrevX(0.0f), | 
 | 								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),  | 
 | 								m_uiNextLineH(0), m_uiSpaceWidth(0), m_uiNumCharacters(0), m_uiNumKerningPairs(0), m_uiAscent(0), m_pszCharacterList(NULL), m_bHasMipmaps(false),  | 
 | 								m_bUsingProjection(false) | 
 | { | 
 | 	memset(m_fScreenScale, 0, sizeof(m_fScreenScale)); | 
 | 	memset(m_ui32ScreenDim, 0, sizeof(m_ui32ScreenDim)); | 
 |  | 
 | 	PVRTMatrixIdentity(m_mModelView); | 
 | 	PVRTMatrixIdentity(m_mProj); | 
 |  | 
 | 	m_pwzPreviousString = new wchar_t[MAX_LETTERS + 1]; | 
 | 	m_pszPreviousString = new char[MAX_LETTERS + 1]; | 
 | 	m_pwzPreviousString[0] = 0; | 
 | 	m_pszPreviousString[0] = 0; | 
 |  | 
 | 	m_eFilterMethod[eFilterProc_Min] = eFilter_Default; | 
 | 	m_eFilterMethod[eFilterProc_Mag] = eFilter_Default; | 
 | 	m_eFilterMethod[eFilterProc_Mip] = eFilter_MipDefault; | 
 | } | 
 |  | 
 | /***************************************************************************** | 
 |  @fn       		~CPVRTPrint3D | 
 |  @brief      	De-allocate the working memory | 
 | *****************************************************************************/ | 
 | CPVRTPrint3D::~CPVRTPrint3D() | 
 | { | 
 | 	delete [] m_pwzPreviousString; | 
 | 	delete [] m_pszPreviousString; | 
 |  | 
 | 	delete [] m_pszCharacterList; | 
 | 	delete [] m_pYOffsets; | 
 | 	delete [] m_pCharMatrics; | 
 | 	delete [] m_pKerningPairs; | 
 | 	delete [] m_pRects; | 
 | 	delete [] m_pUVs; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | @fn       		ReadMetaBlock | 
 | @param[in]		pDataCursor | 
 | @return			bool	true if successful. | 
 | @brief      	Reads a single meta data block from the data file. | 
 | *****************************************************************************/ | 
 | bool CPVRTPrint3D::ReadMetaBlock(const PVRTuint8** pDataCursor) | 
 | { | 
 | 	SPVRTPrint3DHeader* header; | 
 |  | 
 | 	unsigned int uiDataSize; | 
 |  | 
 | 	MetaDataBlock block; | 
 | 	if(!block.ReadFromPtr(pDataCursor)) | 
 | 	{ | 
 | 		return false;		// Must have been an error. | 
 | 	} | 
 |  | 
 | 	switch(block.u32Key) | 
 | 	{ | 
 | 	case PVRFONT_HEADER: | 
 | 		header = (SPVRTPrint3DHeader*)block.Data; | 
 | 		if(header->uVersion != PVRTPRINT3D_VERSION) | 
 | 		{ | 
 | 			return false; | 
 | 		} | 
 | 		// Copy options | 
 | 		m_uiAscent			= header->wAscent; | 
 | 		m_uiNextLineH		= header->wLineSpace; | 
 | 		m_uiSpaceWidth		= header->uSpaceWidth; | 
 | 		m_uiNumCharacters	= header->wNumCharacters & 0xFFFF; | 
 | 		m_uiNumKerningPairs = header->wNumKerningPairs & 0xFFFF;	 | 
 | 		break; | 
 | 	case PVRFONT_CHARLIST: | 
 | 		uiDataSize = sizeof(PVRTuint32) * m_uiNumCharacters; | 
 | 		_ASSERT(block.u32DataSize == uiDataSize); | 
 | 		m_pszCharacterList = new PVRTuint32[m_uiNumCharacters]; | 
 | 		memcpy(m_pszCharacterList, block.Data, uiDataSize); | 
 | 		break; | 
 | 	case PVRFONT_YOFFSET: | 
 | 		uiDataSize = sizeof(PVRTint32) * m_uiNumCharacters; | 
 | 		_ASSERT(block.u32DataSize == uiDataSize); | 
 | 		m_pYOffsets	= new PVRTint32[m_uiNumCharacters]; | 
 | 		memcpy(m_pYOffsets, block.Data, uiDataSize); | 
 | 		break; | 
 | 	case PVRFONT_METRICS: | 
 | 		uiDataSize = sizeof(CharMetrics) * m_uiNumCharacters; | 
 | 		_ASSERT(block.u32DataSize == uiDataSize); | 
 | 		m_pCharMatrics = new CharMetrics[m_uiNumCharacters]; | 
 | 		memcpy(m_pCharMatrics, block.Data, uiDataSize); | 
 | 		break; | 
 | 	case PVRFONT_KERNING: | 
 | 		uiDataSize = sizeof(KerningPair) * m_uiNumKerningPairs; | 
 | 		_ASSERT(block.u32DataSize == uiDataSize); | 
 | 		m_pKerningPairs = new KerningPair[m_uiNumKerningPairs]; | 
 | 		memcpy(m_pKerningPairs, block.Data, uiDataSize); | 
 | 		break; | 
 | 	case PVRFONT_RECTS: | 
 | 		uiDataSize = sizeof(Rectanglei) * m_uiNumCharacters; | 
 | 		_ASSERT(block.u32DataSize == uiDataSize); | 
 |  | 
 | 		m_pRects = new Rectanglei[m_uiNumCharacters]; | 
 | 		memcpy(m_pRects, block.Data, uiDataSize); | 
 | 		break; | 
 | 	default: | 
 | 		_ASSERT(!"Unhandled key!"); | 
 | 	} | 
 |  | 
 | 	return true; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | @fn       		LoadFontData | 
 | @param[in]		texHeader | 
 | @param[in]		MetaDataMap | 
 | @return			bool	true if successful. | 
 | @brief      	Loads font data bundled with the texture file. | 
 | *****************************************************************************/ | 
 | bool CPVRTPrint3D::LoadFontData( const PVRTextureHeaderV3* texHeader, CPVRTMap<PVRTuint32, CPVRTMap<PVRTuint32, MetaDataBlock> >& MetaDataMap ) | 
 | { | 
 | 	m_fTexW = (float)texHeader->u32Width; | 
 | 	m_fTexH = (float)texHeader->u32Height; | 
 |  | 
 | 	// Mipmap data is stored in the texture header data. | 
 | 	m_bHasMipmaps = (texHeader->u32MIPMapCount > 1 ? true : false); | 
 | 	if(m_bHasMipmaps) | 
 | 	{ | 
 | 		m_eFilterMethod[eFilterProc_Min] = eFilter_Linear; | 
 | 		m_eFilterMethod[eFilterProc_Mag] = eFilter_Linear; | 
 | 		m_eFilterMethod[eFilterProc_Mip] = eFilter_Linear; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		m_eFilterMethod[eFilterProc_Min] = eFilter_Linear; | 
 | 		m_eFilterMethod[eFilterProc_Mag] = eFilter_Linear; | 
 | 		m_eFilterMethod[eFilterProc_Mip] = eFilter_None; | 
 | 	} | 
 |  | 
 |  | 
 | 	// Header | 
 | 	SPVRTPrint3DHeader* header = (SPVRTPrint3DHeader*)MetaDataMap[PVRTEX3_IDENT][PVRFONT_HEADER].Data; | 
 | 	if(header->uVersion != PVRTPRINT3D_VERSION) | 
 | 	{ | 
 | 		return false; | 
 | 	} | 
 | 	// Copy options | 
 | 	m_uiAscent			= header->wAscent; | 
 | 	m_uiNextLineH		= header->wLineSpace; | 
 | 	m_uiSpaceWidth		= header->uSpaceWidth; | 
 | 	m_uiNumCharacters	= header->wNumCharacters & 0xFFFF; | 
 | 	m_uiNumKerningPairs = header->wNumKerningPairs & 0xFFFF;	 | 
 |  | 
 | 	// Char list | 
 | 	m_pszCharacterList = new PVRTuint32[m_uiNumCharacters]; | 
 | 	memcpy(m_pszCharacterList, MetaDataMap[PVRTEX3_IDENT][PVRFONT_CHARLIST].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_CHARLIST].u32DataSize); | 
 | 	 | 
 | 	m_pYOffsets	= new PVRTint32[m_uiNumCharacters]; | 
 | 	memcpy(m_pYOffsets, MetaDataMap[PVRTEX3_IDENT][PVRFONT_YOFFSET].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_YOFFSET].u32DataSize); | 
 |  | 
 | 	m_pCharMatrics = new CharMetrics[m_uiNumCharacters]; | 
 | 	memcpy(m_pCharMatrics, MetaDataMap[PVRTEX3_IDENT][PVRFONT_METRICS].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_METRICS].u32DataSize); | 
 | 	 | 
 | 	m_pKerningPairs = new KerningPair[m_uiNumKerningPairs]; | 
 | 	memcpy(m_pKerningPairs, MetaDataMap[PVRTEX3_IDENT][PVRFONT_KERNING].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_KERNING].u32DataSize); | 
 |  | 
 | 	m_pRects = new Rectanglei[m_uiNumCharacters]; | 
 | 	memcpy(m_pRects, MetaDataMap[PVRTEX3_IDENT][PVRFONT_RECTS].Data, MetaDataMap[PVRTEX3_IDENT][PVRFONT_RECTS].u32DataSize); | 
 | 	 | 
 |  | 
 | 	// Build UVs | 
 | 	m_pUVs = new CharacterUV[m_uiNumCharacters]; | 
 | 	for(unsigned int uiChar = 0; uiChar < m_uiNumCharacters; uiChar++) | 
 | 	{ | 
 | 		m_pUVs[uiChar].fUL = m_pRects[uiChar].nX / m_fTexW; | 
 | 		m_pUVs[uiChar].fUR = m_pUVs[uiChar].fUL + m_pRects[uiChar].nW / m_fTexW; | 
 | 		m_pUVs[uiChar].fVT = m_pRects[uiChar].nY / m_fTexH; | 
 | 		m_pUVs[uiChar].fVB = m_pUVs[uiChar].fVT + m_pRects[uiChar].nH / m_fTexH; | 
 | 	}	 | 
 |  | 
 | 	return true; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | @fn       		FindCharacter | 
 | @param[in]		character | 
 | @return			The character index, or PVRPRINT3D_INVALID_CHAR if not found. | 
 | @brief      	Finds a given character in the binary data and returns it's | 
 | 				index. | 
 | *****************************************************************************/ | 
 | PVRTuint32 CPVRTPrint3D::FindCharacter(PVRTuint32 character) const | 
 | { | 
 | 	PVRTuint32* pItem = (PVRTuint32*)bsearch(&character, m_pszCharacterList, m_uiNumCharacters, sizeof(PVRTuint32), CharacterCompareFunc); | 
 | 	if(!pItem) | 
 | 		return PVRTPRINT3D_INVALID_CHAR; | 
 |  | 
 | 	PVRTuint32 uiIdx = (PVRTuint32) (pItem - m_pszCharacterList); | 
 | 	return uiIdx; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | @fn       		ApplyKerning | 
 | @param[in]		cA | 
 | @param[in]		cB | 
 | @param[out]		fOffset | 
 | @brief      	Calculates kerning offset. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::ApplyKerning(const PVRTuint32 cA, const PVRTuint32 cB, float& fOffset) const | 
 | {	 | 
 | 	PVRTuint64 uiPairToSearch = ((PVRTuint64)cA << 32) | (PVRTuint64)cB; | 
 | 	KerningPair* pItem = (KerningPair*)bsearch(&uiPairToSearch, m_pKerningPairs, m_uiNumKerningPairs, sizeof(KerningPair), KerningCompareFunc); | 
 | 	if(pItem) | 
 | 		fOffset += (float)pItem->iOffset; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			SetTextures | 
 |  @param[in]			pContext		Context | 
 |  @param[in]			dwScreenX		Screen resolution along X | 
 |  @param[in]			dwScreenY		Screen resolution along Y | 
 |  @param[in]			bRotate			Rotate print3D by 90 degrees | 
 |  @param[in]			bMakeCopy		This instance of Print3D creates a copy | 
 | 									of it's data instead of sharing with previous | 
 | 									contexts. Set this parameter if you require | 
 | 									thread safety.	 | 
 |  @return			PVR_SUCCESS or PVR_FAIL | 
 |  @brief      		Initialization and texture upload. Should be called only once | 
 | 					for a given context. | 
 | *****************************************************************************/ | 
 | EPVRTError CPVRTPrint3D::SetTextures( | 
 | 	const SPVRTContext	* const pContext, | 
 | 	const unsigned int	dwScreenX, | 
 | 	const unsigned int	dwScreenY, | 
 | 	const bool bRotate, | 
 | 	const bool bMakeCopy) | 
 | { | 
 | 	// Determine which set of textures to use depending on the screen resolution. | 
 | 	const unsigned int uiShortestEdge = PVRT_MIN(dwScreenX, dwScreenY); | 
 | 	const void* pData = NULL; | 
 |  | 
 | 	if(uiShortestEdge >= 720) | 
 | 	{ | 
 | 		pData = (void*)_helvbd_56_pvr; | 
 | 	} | 
 | 	else if(uiShortestEdge >= 640) | 
 | 	{ | 
 | 		pData = (void*)_helvbd_46_pvr; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		pData = (void*)_helvbd_36_pvr; | 
 | 	} | 
 | 	 | 
 | 	PVRT_UNREFERENCED_PARAMETER(_helvbd_36_pvr_size); | 
 | 	PVRT_UNREFERENCED_PARAMETER(_helvbd_46_pvr_size); | 
 | 	PVRT_UNREFERENCED_PARAMETER(_helvbd_56_pvr_size); | 
 |  | 
 | 	return SetTextures(pContext, pData, dwScreenX, dwScreenY, bRotate, bMakeCopy); | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | 	@fn       		SetTextures | 
 | 	@param[in]		pContext		Context | 
 | 	@param[in]		pTexData		User-provided font texture | 
 | 	@param[in]		uiDataSize		Size of the data provided | 
 | 	@param[in]		dwScreenX		Screen resolution along X | 
 | 	@param[in]		dwScreenY		Screen resolution along Y | 
 | 	@param[in]		bRotate			Rotate print3D by 90 degrees | 
 | 	@param[in]		bMakeCopy		This instance of Print3D creates a copy | 
 | 									of it's data instead of sharing with previous | 
 | 									contexts. Set this parameter if you require | 
 | 									thread safety.	 | 
 | 	@return			PVR_SUCCESS or PVR_FAIL | 
 | 	@brief      	Initialization and texture upload of user-provided font  | 
 | 					data. Should be called only once for a Print3D object. | 
 | *****************************************************************************/ | 
 | EPVRTError CPVRTPrint3D::SetTextures( | 
 | 	const SPVRTContext	* const pContext, | 
 | 	const void * const pTexData, | 
 | 	const unsigned int	dwScreenX, | 
 | 	const unsigned int	dwScreenY, | 
 | 	const bool bRotate, | 
 | 	const bool bMakeCopy) | 
 | { | 
 | #if !defined (DISABLE_PRINT3D) | 
 |  | 
 | 	unsigned short	i; | 
 | 	bool			bStatus; | 
 |  | 
 | 	// Set the aspect ratio, so we can change it without updating textures or anything else | 
 | 	float fX, fY; | 
 |  | 
 | 	m_bRotate = bRotate; | 
 | 	m_ui32ScreenDim[0] = bRotate ? dwScreenY : dwScreenX; | 
 | 	m_ui32ScreenDim[1] = bRotate ? dwScreenX : dwScreenY; | 
 |  | 
 | 	// Alter the X, Y resolutions if the screen isn't portrait. | 
 | 	if(dwScreenX > dwScreenY) | 
 | 	{ | 
 | 		fX = (float) dwScreenX; | 
 | 		fY = (float) dwScreenY; | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		fX = (float) dwScreenY; | 
 | 		fY = (float) dwScreenX; | 
 | 	} | 
 |  | 
 | 	m_fScreenScale[0] = (bRotate ? fY : fX) /640.0f; | 
 | 	m_fScreenScale[1] = (bRotate ? fX : fY) /480.0f; | 
 |  | 
 | 	// Check whether textures are already set up just in case | 
 | 	if (m_bTexturesSet) | 
 | 		return PVR_SUCCESS; | 
 |  | 
 | 	// INDEX BUFFERS | 
 | 	m_pwFacesFont = (unsigned short*)malloc(PVRTPRINT3D_MAX_RENDERABLE_LETTERS*2*3*sizeof(unsigned short)); | 
 |  | 
 | 	if(!m_pwFacesFont) | 
 | 	{ | 
 | 		return PVR_FAIL; | 
 | 	} | 
 |  | 
 | 	// Vertex indices for letters | 
 | 	for (i=0; i < PVRTPRINT3D_MAX_RENDERABLE_LETTERS; i++) | 
 | 	{ | 
 | 		m_pwFacesFont[i*6+0] = 0+i*4; | 
 | 		m_pwFacesFont[i*6+1] = 3+i*4; | 
 | 		m_pwFacesFont[i*6+2] = 1+i*4; | 
 |  | 
 | 		m_pwFacesFont[i*6+3] = 3+i*4; | 
 | 		m_pwFacesFont[i*6+4] = 0+i*4; | 
 | 		m_pwFacesFont[i*6+5] = 2+i*4; | 
 | 	} | 
 |  | 
 |  | 
 | 	if(!APIInit(pContext, bMakeCopy)) | 
 | 	{ | 
 | 		return PVR_FAIL; | 
 | 	} | 
 | 	/* | 
 | 		This is the texture with the fonts. | 
 | 	*/ | 
 | 	PVRTextureHeaderV3 header; | 
 | 	CPVRTMap<PVRTuint32, CPVRTMap<PVRTuint32, MetaDataBlock> > MetaDataMap; | 
 | 	bStatus = APIUpLoadTexture((unsigned char *)pTexData, &header, MetaDataMap); | 
 |  | 
 | 	if (!bStatus) | 
 | 	{ | 
 | 		return PVR_FAIL; | 
 | 	} | 
 | 	/* | 
 | 		This is the associated font data with the default font | 
 | 	*/ | 
 | 	bStatus = LoadFontData(&header, MetaDataMap); | 
 | 	 | 
 | 	bStatus = APIUpLoadIcons(reinterpret_cast<const PVRTuint8* const>(PVRTPrint3DIMGLogo), reinterpret_cast<const PVRTuint8* const>(PVRTPrint3DPowerVRLogo)); | 
 |  | 
 | 	if (!bStatus) return PVR_FAIL; | 
 |  | 
 | 	m_nVtxCacheMax = MIN_CACHED_VTX; | 
 | 	m_pVtxCache = (SPVRTPrint3DAPIVertex*)malloc(m_nVtxCacheMax * sizeof(*m_pVtxCache)); | 
 | 	m_nVtxCache = 0; | 
 |  | 
 | 	if(!m_pVtxCache) | 
 | 	{ | 
 | 		return PVR_FAIL; | 
 | 	} | 
 |  | 
 | 	// Everything is OK | 
 | 	m_bTexturesSet = true; | 
 |  | 
 | 	// Return Success | 
 | 	return PVR_SUCCESS; | 
 |  | 
 | #else | 
 | 	return PVR_SUCCESS; | 
 | #endif | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 | @fn       		Print3D | 
 | @param[in]		fPosX		X Position | 
 | @param[in]		fPosY		Y Position | 
 | @param[in]		fScale		Text scale | 
 | @param[in]		Colour		ARGB colour | 
 | @param[in]		UTF32		Array of UTF32 characters | 
 | @param[in]		bUpdate		Whether to update the vertices | 
 | @return			EPVRTError	Success of failure | 
 | @brief      	Takes an array of UTF32 characters and generates the required mesh. | 
 | *****************************************************************************/ | 
 | EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const CPVRTArray<PVRTuint32>& UTF32, bool bUpdate) | 
 | { | 
 | 	// No textures! so... no window | 
 | 	if (!m_bTexturesSet) | 
 | 	{ | 
 | 		PVRTErrorOutputDebug("DisplayWindow : You must call CPVRTPrint3D::SetTextures(...) before using this function.\n"); | 
 | 		return PVR_FAIL; | 
 | 	} | 
 |  | 
 | 	// nothing to be drawn | 
 | 	if(UTF32.GetSize() == 0) | 
 | 		return PVR_FAIL; | 
 |  | 
 | 	// Adjust input parameters | 
 | 	if(!m_bUsingProjection) | 
 | 	{ | 
 | 		fPosX =  (float)((int)(fPosX * (640.0f/100.0f))); | 
 | 		fPosY = -(float)((int)(fPosY * (480.0f/100.0f))); | 
 | 	} | 
 |  | 
 | 	// Create Vertex Buffer (only if it doesn't exist) | 
 | 	if(m_pPrint3dVtx == 0) | 
 | 	{ | 
 | 		m_pPrint3dVtx = (SPVRTPrint3DAPIVertex*)malloc(MAX_LETTERS*4*sizeof(SPVRTPrint3DAPIVertex)); | 
 |  | 
 | 		if(!m_pPrint3dVtx) | 
 | 			return PVR_FAIL; | 
 | 	} | 
 |  | 
 | 	// Fill up our buffer | 
 | 	if(bUpdate) | 
 | 		m_nCachedNumVerts = UpdateLine(0.0f, fPosX, fPosY, fScale, Colour, UTF32, m_pPrint3dVtx); | 
 |  | 
 | 	// Draw the text | 
 | 	if(!DrawLine(m_pPrint3dVtx, m_nCachedNumVerts)) | 
 | 		return PVR_FAIL; | 
 |  | 
 | 	return PVR_SUCCESS; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			Print3D | 
 |  @param[in]			fPosX		Position of the text along X | 
 |  @param[in]			fPosY		Position of the text along Y | 
 |  @param[in]			fScale		Scale of the text | 
 |  @param[in]			Colour		Colour of the text | 
 |  @param[in]			pszFormat	Format string for the text | 
 |  @return			PVR_SUCCESS or PVR_FAIL | 
 |  @brief      		Display wide-char 3D text on screen. | 
 | 					CPVRTPrint3D::SetTextures(...) must have been called | 
 | 					beforehand. | 
 | 					This function accepts formatting in the printf way. | 
 | *****************************************************************************/ | 
 | EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const wchar_t * const pszFormat, ...) | 
 | { | 
 | #ifdef DISABLE_PRINT3D | 
 | 	return PVR_SUCCESS; | 
 | #endif | 
 |  | 
 | 	static wchar_t s_Text[MAX_LETTERS+1] = {0}; | 
 |  | 
 | 	/* | 
 | 		Unfortunately only Windows seems to properly support non-ASCII characters formatted in | 
 | 		vswprintf. | 
 | 	*/ | 
 | #if defined(_WIN32) && !defined(UNDER_CE) | 
 | 	va_list		args; | 
 | 	// Reading the arguments to create our Text string | 
 | 	va_start(args, pszFormat); | 
 | 	vswprintf(s_Text, MAX_LETTERS+1, pszFormat, args); | 
 | 	va_end(args); | 
 | #else | 
 | 	wcscpy(s_Text, pszFormat); | 
 | #endif | 
 |  | 
 | 	bool bUpdate = false; | 
 |  | 
 | 	// Optimisation to check that the strings are actually different. | 
 | 	if(wcscmp(s_Text, m_pwzPreviousString) != 0 || m_fPrevX != fPosX || m_fPrevY != fPosY || m_fPrevScale != fScale || m_uiPrevCol != Colour) | 
 | 	{ | 
 | 		// Copy strings | 
 | 		wcscpy(m_pwzPreviousString, s_Text); | 
 | 		m_fPrevX = fPosX; | 
 | 		m_fPrevY = fPosY; | 
 | 		m_fPrevScale = fScale; | 
 | 		m_uiPrevCol  = Colour; | 
 | 		 | 
 | 		m_CachedUTF32.Clear(); | 
 | #if PVRTSIZEOFWCHAR == 2			// 2 byte wchar. | 
 | 		PVRTUnicodeUTF16ToUTF32((PVRTuint16*)s_Text, m_CachedUTF32); | 
 | #elif PVRTSIZEOFWCHAR == 4			// 4 byte wchar (POSIX) | 
 | 		unsigned int uiC = 0; | 
 | 		PVRTuint32* pUTF32 = (PVRTuint32*)s_Text; | 
 | 		while(*pUTF32 && uiC < MAX_LETTERS) | 
 | 		{ | 
 | 			m_CachedUTF32.Append(*pUTF32++); | 
 | 			uiC++; | 
 | 		} | 
 | #else | 
 | 		return PVR_FAIL; | 
 | #endif | 
 |  | 
 | 		bUpdate = true; | 
 | 	} | 
 |  | 
 | 	// Print | 
 | 	return Print3D(fPosX, fPosY, fScale, Colour, m_CachedUTF32, bUpdate); | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			PVRTPrint3D | 
 |  @param[in]			fPosX		Position of the text along X | 
 |  @param[in]			fPosY		Position of the text along Y | 
 |  @param[in]			fScale		Scale of the text | 
 |  @param[in]			Colour		Colour of the text | 
 |  @param[in]			pszFormat	Format string for the text | 
 |  @return			PVR_SUCCESS or PVR_FAIL | 
 |  @brief      		Display 3D text on screen. | 
 | 					No window needs to be allocated to use this function. | 
 | 					However, CPVRTPrint3D::SetTextures(...) must have been called | 
 | 					beforehand. | 
 | 					This function accepts formatting in the printf way. | 
 | *****************************************************************************/ | 
 | EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const char * const pszFormat, ...) | 
 | { | 
 | #ifdef DISABLE_PRINT3D | 
 | 	return PVR_SUCCESS; | 
 | #endif | 
 |  | 
 | 	va_list		args; | 
 | 	static char	s_Text[MAX_LETTERS+1] = {0}; | 
 | 	 | 
 | 	// Reading the arguments to create our Text string | 
 | 	va_start(args, pszFormat); | 
 | 	vsnprintf(s_Text, MAX_LETTERS+1, pszFormat, args); | 
 | 	va_end(args); | 
 |  | 
 | 	bool bUpdate = false; | 
 |  | 
 | 	// Optimisation to check that the strings are actually different. | 
 | 	if(strcmp(s_Text, m_pszPreviousString) != 0 || m_fPrevX != fPosX || m_fPrevY != fPosY || m_fPrevScale != fScale || m_uiPrevCol != Colour) | 
 | 	{ | 
 | 		// Copy strings | 
 | 		strcpy (m_pszPreviousString, s_Text); | 
 | 		m_fPrevX = fPosX; | 
 | 		m_fPrevY = fPosY; | 
 | 		m_fPrevScale = fScale; | 
 | 		m_uiPrevCol  = Colour; | 
 |  | 
 | 		// Convert from UTF8 to UTF32 | 
 | 		m_CachedUTF32.Clear(); | 
 | 		PVRTUnicodeUTF8ToUTF32((const PVRTuint8*)s_Text, m_CachedUTF32); | 
 |  | 
 | 		bUpdate = true; | 
 | 	} | 
 |  | 
 | 	// Print | 
 | 	return Print3D(fPosX, fPosY, fScale, Colour, m_CachedUTF32, bUpdate); | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			DisplayDefaultTitle | 
 |  @param[in]			sTitle				Title to display | 
 |  @param[in]			sDescription		Description to display | 
 |  @param[in]			uDisplayLogo		1 = Display the logo | 
 |  @return			PVR_SUCCESS or PVR_FAIL | 
 |  @brief      		Creates a default title with predefined position and colours. | 
 | 					It displays as well company logos when requested: | 
 | 					0 = No logo | 
 | 					1 = PowerVR logo | 
 | 					2 = Img Tech logo | 
 | *****************************************************************************/ | 
 | EPVRTError CPVRTPrint3D::DisplayDefaultTitle(const char * const pszTitle, const char * const pszDescription, const unsigned int uDisplayLogo) | 
 | { | 
 | 	EPVRTError eRet = PVR_SUCCESS; | 
 |  | 
 | #if !defined (DISABLE_PRINT3D) | 
 |  | 
 | 	// Display Title | 
 | 	if(pszTitle) | 
 | 	{ | 
 | 		if(Print3D(0.0f, -1.0f, 1.0f,  PVRTRGBA(255, 255, 255, 255), pszTitle) != PVR_SUCCESS) | 
 | 			eRet = PVR_FAIL; | 
 | 	} | 
 | 	 | 
 | 	float fYVal; | 
 | 	if(m_bRotate) | 
 | 		fYVal = m_fScreenScale[0] * 480.0f; | 
 | 	else | 
 | 		fYVal = m_fScreenScale[1] * 480.0f; | 
 |  | 
 | 	// Display Description | 
 | 	if(pszDescription) | 
 | 	{ | 
 |         float fY; | 
 | 		float a = 320.0f/fYVal; | 
 | 		fY = m_uiNextLineH / (480.0f/100.0f) * a; | 
 | 		 | 
 | 		if(Print3D(0.0f, fY, 0.8f,  PVRTRGBA(255, 255, 255, 255), pszDescription) != PVR_SUCCESS) | 
 | 			eRet = PVR_FAIL; | 
 | 	} | 
 |  | 
 | 	m_uLogoToDisplay = uDisplayLogo; | 
 |  | 
 | #endif | 
 |  | 
 | 	return eRet; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			MeasureText | 
 |  @param[out]		pfWidth				Width of the string in pixels | 
 |  @param[out]		pfHeight			Height of the string in pixels | 
 |  @param[in]			fFontSize			Font size | 
 |  @param[in]			sString				String to take the size of | 
 |  @brief      		Returns the size of a string in pixels. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::MeasureText( | 
 | 	float		* const pfWidth, | 
 | 	float		* const pfHeight, | 
 | 	float				fScale, | 
 | 	const CPVRTArray<PVRTuint32>& utf32) | 
 | { | 
 | #if !defined (DISABLE_PRINT3D) | 
 | 	if(utf32.GetSize() == 0) { | 
 | 		if(pfWidth) | 
 | 			*pfWidth = 0; | 
 | 		if(pfHeight) | 
 | 			*pfHeight = 0; | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	float fLength			= 0; | 
 | 	float fMaxLength		= -1.0f; | 
 | 	float fMaxHeight		= (float)m_uiNextLineH; | 
 | 	PVRTuint32 txNextChar	= 0; | 
 | 	PVRTuint32 uiIdx; | 
 | 	for(PVRTuint32 uiIndex = 0; uiIndex < utf32.GetSize(); uiIndex++) | 
 | 	{ | 
 | 		if(utf32[uiIndex] == 0x0D || utf32[uiIndex] == 0x0A) | 
 | 		{ | 
 | 			if(fLength > fMaxLength) | 
 | 				fMaxLength = fLength; | 
 |  | 
 | 			fLength = 0; | 
 | 			fMaxHeight += (float)m_uiNextLineH; | 
 | 		} | 
 | 		uiIdx = FindCharacter(utf32[uiIndex]); | 
 | 		if(uiIdx == PVRTPRINT3D_INVALID_CHAR)		// No character found. Add a space. | 
 | 		{ | 
 | 			fLength += m_uiSpaceWidth; | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		txNextChar = utf32[uiIndex + 1]; | 
 | 		float fKernOffset = 0; | 
 | 		ApplyKerning(utf32[uiIndex], txNextChar, fKernOffset); | 
 |  | 
 | 		fLength += m_pCharMatrics[uiIdx].nAdv + fKernOffset;		// Add on this characters width | 
 | 	} | 
 |  | 
 | 	if(fMaxLength < 0.0f)		// Obviously no new line. | 
 | 		fMaxLength = fLength; | 
 |  | 
 | 	if(pfWidth) | 
 | 		*pfWidth = fMaxLength * fScale; | 
 | 	if(pfHeight) | 
 | 		*pfHeight = fMaxHeight * fScale; | 
 | #endif | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			GetSize | 
 |  @param[out]		pfWidth				Width of the string in pixels | 
 |  @param[out]		pfHeight			Height of the string in pixels | 
 |  @param[in]			pszUTF8				UTF8 string to take the size of | 
 |  @brief      		Returns the size of a string in pixels. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::MeasureText( | 
 | 	float		* const pfWidth, | 
 | 	float		* const pfHeight, | 
 | 	float				fScale, | 
 | 	const char	* const pszUTF8) | 
 | { | 
 | 	m_CachedUTF32.Clear(); | 
 | 	PVRTUnicodeUTF8ToUTF32((PVRTuint8*)pszUTF8, m_CachedUTF32); | 
 | 	MeasureText(pfWidth,pfHeight,fScale,m_CachedUTF32); | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			MeasureText | 
 |  @param[out]		pfWidth		Width of the string in pixels | 
 |  @param[out]		pfHeight	Height of the string in pixels | 
 |  @param[in]			pszUnicode	Wide character string to take the length of. | 
 |  @brief      		Returns the size of a string in pixels. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::MeasureText( | 
 | 	float		* const pfWidth, | 
 | 	float		* const pfHeight, | 
 | 	float				fScale, | 
 | 	const wchar_t* const pszUnicode) | 
 | { | 
 | 	_ASSERT(pszUnicode); | 
 | 	m_CachedUTF32.Clear(); | 
 |  | 
 | #if PVRTSIZEOFWCHAR == 2			// 2 byte wchar. | 
 | 	PVRTUnicodeUTF16ToUTF32((PVRTuint16*)pszUnicode, m_CachedUTF32); | 
 | #else								// 4 byte wchar (POSIX) | 
 | 	unsigned int uiC = 0; | 
 | 	PVRTuint32* pUTF32 = (PVRTuint32*)pszUnicode; | 
 | 	while(*pUTF32 && uiC < MAX_LETTERS) | 
 | 	{ | 
 | 		m_CachedUTF32.Append(*pUTF32++); | 
 | 		uiC++; | 
 | 	} | 
 | #endif | 
 | 	 | 
 | 	MeasureText(pfWidth,pfHeight,fScale,m_CachedUTF32); | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			GetAspectRatio | 
 |  @param[out]		dwScreenX		Screen resolution X | 
 |  @param[out]		dwScreenY		Screen resolution Y | 
 |  @brief      		Returns the current resolution used by Print3D | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::GetAspectRatio(unsigned int *dwScreenX, unsigned int *dwScreenY) | 
 | { | 
 | #if !defined (DISABLE_PRINT3D) | 
 |  | 
 | 	*dwScreenX = (int)(640.0f * m_fScreenScale[0]); | 
 | 	*dwScreenY = (int)(480.0f * m_fScreenScale[1]); | 
 | #endif | 
 | } | 
 |  | 
 | /************************************************************* | 
 | *					 PRIVATE FUNCTIONS						 * | 
 | **************************************************************/ | 
 |  | 
 | /*!*************************************************************************** | 
 |  @brief             Update a single line | 
 |  @param[in]			fZPos | 
 |  @param[in]			XPos | 
 |  @param[in]			YPos | 
 |  @param[in]			fScale | 
 |  @param[in]			Colour | 
 |  @param[in]			Text | 
 |  @param[in]			pVertices | 
 |  @return            Number of vertices affected | 
 | *****************************************************************************/ | 
 | 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) | 
 | { | 
 | 	/* Nothing to update */ | 
 | 	if (Text.GetSize() == 0)  | 
 | 		return 0; | 
 |  | 
 | 	if(!m_bUsingProjection) | 
 | 	{ | 
 | 		XPos *= ((float)m_ui32ScreenDim[0] / 640.0f); | 
 | 		YPos *= ((float)m_ui32ScreenDim[1] / 480.0f); | 
 | 	} | 
 |  | 
 | 	YPos -= m_uiAscent * fScale; | 
 | 	 | 
 | 	YPos = PVRTMakeWhole(YPos); | 
 |  | 
 | 	float fPreXPos	= XPos;		// The original offset (after screen scale modification) of the X coordinate. | 
 |  | 
 | 	float		fKernOffset; | 
 | 	float		fAOff; | 
 | 	float		fYOffset; | 
 | 	unsigned int VertexCount = 0; | 
 | 	PVRTint32 NextChar; | 
 |  | 
 | 	unsigned int uiNumCharsInString = Text.GetSize(); | 
 | 	for(unsigned int uiIndex = 0; uiIndex < uiNumCharsInString; uiIndex++) | 
 | 	{ | 
 | 		if(uiIndex > MAX_LETTERS)  | 
 | 			break; | 
 |  | 
 | 		// Newline | 
 | 		if(Text[uiIndex] == 0x0A) | 
 | 		{ | 
 | 			XPos = fPreXPos; | 
 | 			YPos -= PVRTMakeWhole(m_uiNextLineH * fScale); | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		// Get the character | 
 | 		PVRTuint32 uiIdx = FindCharacter(Text[uiIndex]); | 
 |  | 
 | 		// Not found. Add a space. | 
 | 		if(uiIdx == PVRTPRINT3D_INVALID_CHAR)		// No character found. Add a space. | 
 | 		{ | 
 | 			XPos += PVRTMakeWhole(m_uiSpaceWidth * fScale); | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		fKernOffset = 0; | 
 | 		fYOffset	= m_pYOffsets[uiIdx] * fScale; | 
 | 		fAOff		= PVRTMakeWhole(m_pCharMatrics[uiIdx].nXOff * fScale);					// The A offset. Could include overhang or underhang. | 
 | 		if(uiIndex < uiNumCharsInString - 1) | 
 | 		{ | 
 | 			NextChar = Text[uiIndex + 1]; | 
 | 			ApplyKerning(Text[uiIndex], NextChar, fKernOffset); | 
 | 		} | 
 |  | 
 | 		/* Filling vertex data */ | 
 | 		pVertices[VertexCount+0].sx		= f2vt(XPos + fAOff); | 
 | 		pVertices[VertexCount+0].sy		= f2vt(YPos + fYOffset); | 
 | 		pVertices[VertexCount+0].sz		= f2vt(fZPos); | 
 | 		pVertices[VertexCount+0].rhw	= f2vt(1.0f); | 
 | 		pVertices[VertexCount+0].tu		= f2vt(m_pUVs[uiIdx].fUL); | 
 | 		pVertices[VertexCount+0].tv		= f2vt(m_pUVs[uiIdx].fVT); | 
 |  | 
 | 		pVertices[VertexCount+1].sx		= f2vt(XPos + fAOff + PVRTMakeWhole(m_pRects[uiIdx].nW * fScale)); | 
 | 		pVertices[VertexCount+1].sy		= f2vt(YPos + fYOffset); | 
 | 		pVertices[VertexCount+1].sz		= f2vt(fZPos); | 
 | 		pVertices[VertexCount+1].rhw	= f2vt(1.0f); | 
 | 		pVertices[VertexCount+1].tu		= f2vt(m_pUVs[uiIdx].fUR); | 
 | 		pVertices[VertexCount+1].tv		= f2vt(m_pUVs[uiIdx].fVT); | 
 |  | 
 | 		pVertices[VertexCount+2].sx		= f2vt(XPos + fAOff); | 
 | 		pVertices[VertexCount+2].sy		= f2vt(YPos + fYOffset - PVRTMakeWhole(m_pRects[uiIdx].nH * fScale)); | 
 | 		pVertices[VertexCount+2].sz		= f2vt(fZPos); | 
 | 		pVertices[VertexCount+2].rhw	= f2vt(1.0f); | 
 | 		pVertices[VertexCount+2].tu		= f2vt(m_pUVs[uiIdx].fUL); | 
 | 		pVertices[VertexCount+2].tv		= f2vt(m_pUVs[uiIdx].fVB); | 
 |  | 
 | 		pVertices[VertexCount+3].sx		= f2vt(XPos + fAOff + PVRTMakeWhole(m_pRects[uiIdx].nW * fScale)); | 
 | 		pVertices[VertexCount+3].sy		= f2vt(YPos + fYOffset - PVRTMakeWhole(m_pRects[uiIdx].nH * fScale)); | 
 | 		pVertices[VertexCount+3].sz		= f2vt(fZPos); | 
 | 		pVertices[VertexCount+3].rhw	= f2vt(1.0f); | 
 | 		pVertices[VertexCount+3].tu		= f2vt(m_pUVs[uiIdx].fUR); | 
 | 		pVertices[VertexCount+3].tv		= f2vt(m_pUVs[uiIdx].fVB); | 
 |  | 
 | 		pVertices[VertexCount+0].color	= Colour; | 
 | 		pVertices[VertexCount+1].color	= Colour; | 
 | 		pVertices[VertexCount+2].color	= Colour; | 
 | 		pVertices[VertexCount+3].color	= Colour; | 
 |  | 
 | 		XPos = XPos + PVRTMakeWhole((m_pCharMatrics[uiIdx].nAdv + fKernOffset) * fScale);		// Add on this characters width | 
 | 		VertexCount += 4; | 
 | 	} | 
 |  | 
 | 	return VertexCount; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			DrawLineUP | 
 |  @return			true or false | 
 |  @brief      		Draw a single line of text. | 
 | *****************************************************************************/ | 
 | bool CPVRTPrint3D::DrawLine(SPVRTPrint3DAPIVertex *pVtx, unsigned int nVertices) | 
 | { | 
 | 	if(!nVertices) | 
 | 		return true; | 
 |  | 
 | 	_ASSERT((nVertices % 4) == 0); | 
 | 	_ASSERT((nVertices/4) < MAX_LETTERS); | 
 |  | 
 | 	while(m_nVtxCache + (int)nVertices > m_nVtxCacheMax) { | 
 | 		if(m_nVtxCache + nVertices > MAX_CACHED_VTX) { | 
 | 			_RPT1(_CRT_WARN, "Print3D: Out of space to cache text! (More than %d vertices!)\n", MAX_CACHED_VTX); | 
 | 			return false; | 
 | 		} | 
 |  | 
 | 		m_nVtxCacheMax	= PVRT_MIN(m_nVtxCacheMax * 2, MAX_CACHED_VTX); | 
 | 		SPVRTPrint3DAPIVertex* pTmp = (SPVRTPrint3DAPIVertex*)realloc(m_pVtxCache, m_nVtxCacheMax * sizeof(*m_pVtxCache)); | 
 |  | 
 | 		_ASSERT(pTmp); | 
 | 		if(!pTmp) | 
 | 		{ | 
 | 			free(m_pVtxCache); | 
 | 			m_pVtxCache = 0; | 
 | 			return false; // Failed to re-allocate data | 
 | 		} | 
 |  | 
 | 		m_pVtxCache = pTmp; | 
 | 		 | 
 | 		_RPT1(_CRT_WARN, "Print3D: TextCache increased to %d vertices.\n", m_nVtxCacheMax); | 
 | 	} | 
 |  | 
 | 	memcpy(&m_pVtxCache[m_nVtxCache], pVtx, nVertices * sizeof(*pVtx)); | 
 | 	m_nVtxCache += nVertices; | 
 | 	return true; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			SetProjection | 
 |  @brief      		Sets projection matrix. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::SetProjection(const PVRTMat4& mProj) | 
 | { | 
 | 	m_mProj				= mProj; | 
 | 	m_bUsingProjection	= true; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       			SetModelView | 
 |  @brief      		Sets model view matrix. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::SetModelView(const PVRTMat4& mModelView) | 
 | { | 
 | 	m_mModelView = mModelView; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       		SetFiltering | 
 |  @param[in]		eFilter				The method of texture filtering | 
 |  @brief      	Sets the method of texture filtering for the font texture. | 
 | 					Print3D will attempt to pick the best method by default | 
 | 					but this method allows the user to override this. | 
 | *****************************************************************************/ | 
 | void CPVRTPrint3D::SetFiltering(ETextureFilter eMin, ETextureFilter eMag, ETextureFilter eMip) | 
 | { | 
 | 	if(eMin == eFilter_None) eMin = eFilter_Default;		// Illegal value | 
 | 	if(eMag == eFilter_None) eMag = eFilter_Default;		// Illegal value | 
 |  | 
 | 	m_eFilterMethod[eFilterProc_Min] = eMin; | 
 | 	m_eFilterMethod[eFilterProc_Mag] = eMag; | 
 | 	m_eFilterMethod[eFilterProc_Mip] = eMip; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       		GetFontAscent | 
 |  @return		unsigned int	The ascent. | 
 |  @brief      	Returns the 'ascent' of the font. This is typically the  | 
 | 				height from the baseline of the larget glyph in the set. | 
 | *****************************************************************************/ | 
 | unsigned int CPVRTPrint3D::GetFontAscent() | 
 | { | 
 | 	return m_uiAscent; | 
 | } | 
 |  | 
 | /*!*************************************************************************** | 
 |  @fn       		GetFontLineSpacing | 
 |  @return		unsigned int	The line spacing. | 
 |  @brief      	Returns the default line spacing (i.e baseline to baseline)  | 
 | 				for the font. | 
 | *****************************************************************************/ | 
 | unsigned int CPVRTPrint3D::GetFontLineSpacing() | 
 | { | 
 | 	return m_uiNextLineH; | 
 | } | 
 |  | 
 | /**************************************************************************** | 
 | ** Local code | 
 | ****************************************************************************/ | 
 |  | 
 | /***************************************************************************** | 
 |  End of file (PVRTPrint3D.cpp) | 
 | *****************************************************************************/ | 
 |  |