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
33static 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
52const PVRTuint32 PVRFONT_HEADER			= 0xFCFC0050;
53const PVRTuint32 PVRFONT_CHARLIST		= 0xFCFC0051;
54const PVRTuint32 PVRFONT_RECTS			= 0xFCFC0052;
55const PVRTuint32 PVRFONT_METRICS		= 0xFCFC0053;
56const PVRTuint32 PVRFONT_YOFFSET		= 0xFCFC0054;
57const PVRTuint32 PVRFONT_KERNING		= 0xFCFC0055;
58
59/****************************************************************************
60** Constants
61****************************************************************************/
62static 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*****************************************************************************/
74PVRTint32 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*****************************************************************************/
86PVRTint32 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*****************************************************************************/
104CPVRTPrint3D::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*****************************************************************************/
130CPVRTPrint3D::~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*****************************************************************************/
149bool 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*****************************************************************************/
221bool 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*****************************************************************************/
292PVRTuint32 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*****************************************************************************/
309void 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*****************************************************************************/
331EPVRTError 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*****************************************************************************/
378EPVRTError 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*****************************************************************************/
493EPVRTError 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*****************************************************************************/
546EPVRTError 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*****************************************************************************/
616EPVRTError 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*****************************************************************************/
665EPVRTError 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*****************************************************************************/
710void 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*****************************************************************************/
771void 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*****************************************************************************/
789void 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*****************************************************************************/
819void 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*****************************************************************************/
843unsigned 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*****************************************************************************/
946bool 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*****************************************************************************/
985void 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*****************************************************************************/
995void 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*****************************************************************************/
1007void 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*****************************************************************************/
1023unsigned 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*****************************************************************************/
1034unsigned 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