• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PVRTMakeWhole(float f)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 *****************************************************************************/
CharacterCompareFunc(const void * pA,const void * pB)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 *****************************************************************************/
KerningCompareFunc(const void * pA,const void * pB)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 *****************************************************************************/
CPVRTPrint3D()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 *****************************************************************************/
~CPVRTPrint3D()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 *****************************************************************************/
ReadMetaBlock(const PVRTuint8 ** pDataCursor)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 *****************************************************************************/
LoadFontData(const PVRTextureHeaderV3 * texHeader,CPVRTMap<PVRTuint32,CPVRTMap<PVRTuint32,MetaDataBlock>> & MetaDataMap)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 *****************************************************************************/
FindCharacter(PVRTuint32 character) const292 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 *****************************************************************************/
ApplyKerning(const PVRTuint32 cA,const PVRTuint32 cB,float & fOffset) const309 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 *****************************************************************************/
SetTextures(const SPVRTContext * const pContext,const unsigned int dwScreenX,const unsigned int dwScreenY,const bool bRotate,const bool bMakeCopy)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 *****************************************************************************/
SetTextures(const SPVRTContext * const pContext,const void * const pTexData,const unsigned int dwScreenX,const unsigned int dwScreenY,const bool bRotate,const bool bMakeCopy)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 *****************************************************************************/
Print3D(float fPosX,float fPosY,const float fScale,unsigned int Colour,const CPVRTArray<PVRTuint32> & UTF32,bool bUpdate)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 *****************************************************************************/
Print3D(float fPosX,float fPosY,const float fScale,unsigned int Colour,const wchar_t * const pszFormat,...)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 *****************************************************************************/
Print3D(float fPosX,float fPosY,const float fScale,unsigned int Colour,const char * const pszFormat,...)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 *****************************************************************************/
DisplayDefaultTitle(const char * const pszTitle,const char * const pszDescription,const unsigned int uDisplayLogo)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 *****************************************************************************/
MeasureText(float * const pfWidth,float * const pfHeight,float fScale,const CPVRTArray<PVRTuint32> & utf32)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 *****************************************************************************/
MeasureText(float * const pfWidth,float * const pfHeight,float fScale,const char * const pszUTF8)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 *****************************************************************************/
MeasureText(float * const pfWidth,float * const pfHeight,float fScale,const wchar_t * const pszUnicode)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 *****************************************************************************/
GetAspectRatio(unsigned int * dwScreenX,unsigned int * dwScreenY)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 *****************************************************************************/
UpdateLine(const float fZPos,float XPos,float YPos,const float fScale,const unsigned int Colour,const CPVRTArray<PVRTuint32> & Text,SPVRTPrint3DAPIVertex * const pVertices)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 *****************************************************************************/
DrawLine(SPVRTPrint3DAPIVertex * pVtx,unsigned int nVertices)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 *****************************************************************************/
SetProjection(const PVRTMat4 & mProj)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 *****************************************************************************/
SetModelView(const PVRTMat4 & mModelView)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 *****************************************************************************/
SetFiltering(ETextureFilter eMin,ETextureFilter eMag,ETextureFilter eMip)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 *****************************************************************************/
GetFontAscent()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 *****************************************************************************/
GetFontLineSpacing()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