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