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