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