/*!*************************************************************************** @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; } float fKernOffset = 0; if ((uiIndex + 1) < utf32.GetSize()) { txNextChar = utf32[uiIndex + 1]; 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 }
/*!*************************************************************************** @Function PVRTUnicodeUTF8ToUTF32 @Input pUTF8 A UTF8 string, which is null terminated. @Output aUTF32 An array of Unicode code points. @Returns Success or failure. @Description Decodes a UTF8-encoded string in to Unicode code points (UTF32). If pUTF8 is not null terminated, the results are undefined. *****************************************************************************/ EPVRTError PVRTUnicodeUTF8ToUTF32(const PVRTuint8* const pUTF8, CPVRTArray<PVRTuint32>& aUTF32) { unsigned int uiTailLen, uiIndex; unsigned int uiBytes = (unsigned int) strlen((const char*)pUTF8); PVRTuint32 c32; const PVRTuint8* pC = pUTF8; while(*pC) { // Quick optimisation for ASCII characters while(*pC && *pC < VALID_ASCII) { aUTF32.Append(*pC++); } // Done if(!*pC) break; c32 = *pC++; uiTailLen = c_u8UTF8Lengths[c32]; // Check for invalid tail length. Maximum 4 bytes for each UTF8 character. // Also check to make sure the tail length is inside the provided buffer. if(uiTailLen == 0 || (pC + uiTailLen > pUTF8 + uiBytes)) return PVR_OVERFLOW; c32 &= (TAIL_MASK >> uiTailLen); // Get the data out of the first byte. This depends on the length of the tail. // Get the data out of each tail byte uiIndex = 0; while(uiIndex < uiTailLen) { if((pC[uiIndex] & 0xC0) != 0x80) return PVR_FAIL; // Invalid tail byte! c32 = (c32 << BYTES_PER_TAIL) + (pC[uiIndex] & TAIL_MASK); uiIndex++; } pC += uiIndex; // Check overlong values. if(c32 < c_u32MinVals[uiTailLen]) return PVR_FAIL; if(!CheckGenericUnicode(c32)) return PVR_FAIL; // OK aUTF32.Append(c32); } return PVR_SUCCESS; }
/*!**************************************************************************** @Function QuitApplication @Return bool true if no error occurred @Description Code in QuitApplication() will be called by PVRShell once per run, just before exiting the program. If the rendering context is lost, QuitApplication() will not be called. ******************************************************************************/ bool OGLES2IntroducingPrint3D::QuitApplication() { for(unsigned int uiIndex = 0; uiIndex < m_TextLines.GetSize(); ++uiIndex) { delete [] m_TextLines[uiIndex]; } return true; }
/*!**************************************************************************** @Function SetCollisionSpheres @Input pSpheres Pointer to an array of Sphere structs @Input uiNumSpheres The number of spheres @Description Sets the physical model of the collision spheres and initializes them. ******************************************************************************/ bool ParticleSystemGPU::SetCollisionSpheres(const CPVRTArray<Sphere>& spheres) { size_t size; if (size = spheres.GetSize()) { glBindBuffer(GL_UNIFORM_BUFFER, m_SpheresUbo); glBufferData(GL_UNIFORM_BUFFER, size * sizeof(Sphere), &spheres[0], GL_STATIC_DRAW); glBindBufferBase(GL_UNIFORM_BUFFER, SPHERES_UBO_BINDING_INDEX, m_SpheresUbo); glBindBuffer(GL_UNIFORM_BUFFER, 0); } return true; }
/*!*************************************************************************** @Function PVRTUnicodeUTF16ToUTF32 @Input pUTF16 A UTF16 string, which is null terminated. @Output aUTF32 An array of Unicode code points. @Returns Success or failure. @Description Decodes a UTF16-encoded string in to Unicode code points (UTF32). If pUTF16 is not null terminated, the results are undefined. *****************************************************************************/ EPVRTError PVRTUnicodeUTF16ToUTF32(const PVRTuint16* const pUTF16, CPVRTArray<PVRTuint32>& aUTF32) { const PVRTuint16* pC = pUTF16; // Determine the number of shorts while(*++pC && (pC - pUTF16) < MAX_LEN); unsigned int uiBufferLen = (unsigned int) (pC - pUTF16); if(uiBufferLen == MAX_LEN) return PVR_OVERFLOW; // Probably not NULL terminated. // Reset to start. pC = pUTF16; PVRTuint32 c32; while(*pC) { // Straight copy. We'll check for surrogate pairs next... c32 = *pC++; // Check surrogate pair if(c32 >= UTF16_SURG_H_MARK && c32 <= UTF16_SURG_H_END) { // Make sure the next 2 bytes are in range... if(pC + 1 > pUTF16 + uiBufferLen || *pC == 0) return PVR_OVERFLOW; // Check that the next value is in the low surrogate range if(*pC < UTF16_SURG_L_MARK || *pC > UTF16_SURG_L_END) return PVR_FAIL; // Decode c32 = ((c32 - UTF16_SURG_H_MARK) << 10) + (*pC - UTF16_SURG_L_MARK) + 0x10000; pC++; } if(!CheckGenericUnicode(c32)) return PVR_FAIL; // OK aUTF32.Append(c32); } return PVR_SUCCESS; }
std::string NSStringFromSPVRTPFXParserEffect( PFXClassPtr pSPVRTPFXParserEffect ) { SPVRTPFXParserEffect* pfxEffect = (SPVRTPFXParserEffect*)pSPVRTPFXParserEffect; std::string desc = ""; desc += CC3String::stringWithFormat( (char*)"SPVRTPFXParserEffect" ); desc += CC3String::stringWithFormat( (char*)" named %s", pfxEffect->Name.c_str() ); desc += CC3String::stringWithFormat( (char*)"\n\tvertex shader: %s", pfxEffect->VertexShaderName.c_str() ); desc += CC3String::stringWithFormat( (char*)"\n\tfragment shader: %s", pfxEffect->FragmentShaderName.c_str() ); CPVRTArray<SPVRTPFXParserSemantic> attributes = pfxEffect->Attributes; GLuint attrCount = attributes.GetSize(); desc += CC3String::stringWithFormat( (char*)"\n\twith %d attributes:", attrCount ); for(GLuint i = 0; i < attrCount; i++) { desc += CC3String::stringWithFormat( (char*)"\n\t\t%s:", NSStringFromSPVRTPFXParserSemantic(&attributes[i], "attribute").c_str() ); } CPVRTArray<SPVRTPFXParserSemantic> uniforms = pfxEffect->Uniforms; GLuint uniformCount = uniforms.GetSize(); desc += CC3String::stringWithFormat( (char*)"\n\twith %d uniforms:", uniformCount ); for(GLuint i = 0; i < uniformCount; i++) { desc += CC3String::stringWithFormat( (char*)"\n\t\t%s:", NSStringFromSPVRTPFXParserSemantic(&uniforms[i], "uniform").c_str() ); } CPVRTArray<SPVRTPFXParserEffectTexture> textures = pfxEffect->Textures; GLuint texCount = textures.GetSize(); desc += CC3String::stringWithFormat( (char*)"\n\twith %d textures:", texCount ); for(GLuint i = 0; i < texCount; i++) { desc += CC3String::stringWithFormat( (char*)"\n\t\t%s:", NSStringFromSPVRTPFXParserEffectTexture(&textures[i]).c_str() ); } CPVRTArray<SPVRTTargetPair> targets = pfxEffect->Targets; GLuint targCount = targets.GetSize(); desc += CC3String::stringWithFormat( (char*)"\n\twith %d targets:", targCount ); for(GLuint i = 0; i < targCount; i++) { desc += CC3String::stringWithFormat( (char*)"\n\t\ttarget named %s of type %s", targets[i].TargetName.c_str(), targets[i].BufferType.c_str() ); } desc += CC3String::stringWithFormat( (char*)"\n\tannotation: %s", pfxEffect->Annotation.c_str() ); return desc; }
/*!*************************************************************************** @Function Print3D @Input fPosX X Position @Input fPosY Y Position @Input fScale Text scale @Input Colour ARGB colour @Input UTF32 Array of UTF32 characters @Input bUpdate Whether to update the vertices @Return EPVRTError Success of failure @Description 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; }
/*!*************************************************************************** @Function UpdateLine @Description *****************************************************************************/ 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 *= m_fScreenScale[0]; YPos *= m_fScreenScale[1]; } YPos -= PVRTMakeWhole(m_uiAscent * fScale); 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 = PVRTMakeWhole(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 + 0.0f); pVertices[VertexCount+0].sy = f2vt(YPos + fYOffset + 0.0f); 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 + 0.0f); 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 + 0.0f); 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; }
/*!*************************************************************************** @Function RenderText @Description Draws the 3D text and scrolls in to the screen. *****************************************************************************/ void OGLES2IntroducingPrint3D::RenderText() { float fAspect = (float)PVRShellGet(prefWidth) / (float)PVRShellGet(prefHeight); bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); // Calculate the frame delta. unsigned long ulNow = PVRShellGetTime(); if(m_ulPrevFrameT == 0) m_ulPrevFrameT = ulNow; float fDT = (ulNow - m_ulPrevFrameT) * 0.001f; m_ulPrevFrameT = ulNow; // Calculate the FPS scale. float fFPSScale = fDT / c_fTargetFPS; // Move the text. Progressively speed up. float fSpeedInc = 0.0f; if(m_fTextOffset > 0.0f) fSpeedInc = m_fTextOffset / TEXT_END_Y; m_fTextOffset += (0.75f + (1.0f * fSpeedInc)) * fFPSScale; if(m_fTextOffset > TEXT_END_Y) m_fTextOffset = TEXT_START_Y; PVRTMat4 mProjection = PVRTMat4::PerspectiveFovRH(0.7f, fAspect, 1.0f, 2000.0f, PVRTMat4::OGL, bRotate); PVRTMat4 mScale = PVRTMat4::Scale(PVRTVec3(1.0f, -1.0f, 1.0f)); PVRTMat4 mCamera = PVRTMat4::LookAtRH(PVRTVec3(0.0f, -900.0f, 700.0f), PVRTVec3(0.0f,-200.0f,0.0f), PVRTVec3(0.0f,1.0f,0.0f)); PVRTMat4 mTrans = PVRTMat4::Translation(PVRTVec3(0.0f, m_fTextOffset, 0.0f)); PVRTMat4 mModelView = mCamera * mTrans; float fStrWidth = 0.0f; /* Print3D can optionally be provided with user-defined projection and model-view matrices which allow custom layout of text. Here we are proving both a projection and model-view matrix. The projection matrix specified here uses perspective projection which will provide the 3D effect. The model-view matrix positions the the text in world space providing the 'camera' position and the scrolling of the text. */ m_CentralText.SetProjection(mProjection); m_CentralText.SetModelView(mModelView); /* The previous method (RenderTitle()) explains the following functions in more detail however put simply, we are looping the entire array of loaded text which is encoded in UTF-8. Print3D batches this internally and the call to Flush() will render the text to the frame buffer. We are also fading out the text over a certain distance. */ float fPos, fFade; unsigned int uiCol; for(unsigned int uiIndex = 0; uiIndex < m_TextLines.GetSize(); ++uiIndex) { fPos = (m_fTextOffset - (uiIndex * 36.0f)); fFade = 1.0f; if(fPos > TEXT_FADE_START) { fFade = PVRTClamp(1.0f - ((fPos - TEXT_FADE_START) / (TEXT_FADE_END - TEXT_FADE_START)), 0.0f, 1.0f); } uiCol = (((unsigned int)(fFade * 255)) << 24) | 0x00FFFF; m_CentralText.MeasureText(&fStrWidth, NULL, 1.0f, (const char*)m_TextLines[uiIndex]); m_CentralText.Print3D(-(fStrWidth*0.5f), -(uiIndex * 36.0f), 1.0f, uiCol, (const char*)m_TextLines[uiIndex]); } m_CentralText.Flush(); }
/*!**************************************************************************** @Function InitApplication @Return bool true if no error occurred @Description Code in InitApplication() will be called by PVRShell once per run, before the rendering context is created. Used to initialize variables that are not dependent on it (e.g. external modules, loading meshes, etc.) If the rendering context is lost, InitApplication() will not be called again. ******************************************************************************/ bool OGLES2IntroducingPrint3D::InitApplication() { /* CPVRTResourceFile is a resource file helper class. Resource files can be placed on disk next to the executable or in a platform dependent read path. We need to tell the class where that read path is. Additionally, it is possible to wrap files into cpp modules and link them directly into the executable. In this case no path will be used. Files on disk will override "memory files". */ // Get and set the read path for content files CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath)); /* Get and set the load/release functions for loading external files. In the majority of cases the PVRShell will return NULL function pointers implying that nothing special is required to load external files. */ CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc)); /* Because the C++ standard states that only ASCII characters are valid in compiled code, we are instead using an external resource file which contains all of the text to be rendered. This allows complete control over the encoding of the resource file which in this case is encoded as UTF-8. */ CPVRTResourceFile TextResource(c_szResTextFile); if(!TextResource.IsOpen()) { PVRShellSet(prefExitMessage, "ERROR: Failed to load text resource file!"); return false; } /* The following code simply pulls out each line in the resource file and adds it to an array so we can render each line separately. */ const PVRTuint8* pStart = (PVRTuint8*)TextResource.DataPtr(); const PVRTuint8* pC = pStart; while(*pC && ((unsigned int)(pC - pStart) < TextResource.Size())) { // Read how many characters on this line. const PVRTuint8* pLStart = pC; while(*pC && *pC != '\n') pC++; unsigned int uiDataLen = (unsigned int) (pC - pLStart + 1); PVRTuint8* pLineData = new PVRTuint8[uiDataLen + 1]; memset(pLineData, 0, uiDataLen + 1); pC = pLStart; unsigned int uiIndex; for(uiIndex = 0; uiIndex < uiDataLen; ++uiIndex) pLineData[uiIndex] = pC[uiIndex]; pC += uiDataLen; m_TextLines.Append(pLineData); } m_fTextOffset = TEXT_START_Y; m_ulPrevFrameT = 0; m_eTitleLang = eLang_English; return true; }