/******************************************************************************* * Function Name : DoShearCentered * Description : Demonstrate the effect of shearing centred on a * shape. Each path is transformed separately. *******************************************************************************/ void CTransforms::DoShearCentered() { // Make sure we're operating on the path user-to-surface matrix vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); // Load Identity matrix. This clears all previous transformations vgLoadIdentity(); // To be independent of screen resolution, we need to scale the // coordinates so everything in the range [0, 1] will be visible vgScale((float)PVRShellGet(prefWidth), (float)PVRShellGet(prefHeight)); // Unlike OpenGL, OpenVG does not maintain a matrix stack. So instead of // pushing the current matrix to the stack, we have to store it ourselves float afUnitMatrix[3 * 3]; vgGetMatrix(afUnitMatrix); // turn time(ms) into a clipped periodic triangle function int i32Zigzag1 = m_ui32AbsTime % 2000; if(i32Zigzag1 > 1000) i32Zigzag1 = 2000 - i32Zigzag1; i32Zigzag1 = PVRT_MAX(250, PVRT_MIN(750, i32Zigzag1)) - 500; // and again, now with shifted phase int i32Zigzag2 = (m_ui32AbsTime + 500) % 2000; if(i32Zigzag2 > 1000) i32Zigzag2 = 2000 - i32Zigzag2; i32Zigzag2 = PVRT_MAX(250, PVRT_MIN(750, i32Zigzag2)) - 500; // Scaling a shape from its center is identical to moving it to the // origin, scaling it there, and moving it back where it was. // // IMPORTANT: // Since OpenVG right-multiplies matrices, you conceptually need to // call the transformation functions in backwards order. vgTranslate(0.5f, 0.75f); vgShear(0.001f * i32Zigzag1, 0); vgTranslate(-0.5f, -0.75f); // draw first path vgDrawPath(m_avgPaths[0], VG_STROKE_PATH | VG_FILL_PATH); // restore the unit matrix ([0, 1] visible) vgLoadMatrix(afUnitMatrix); // transformation for second path vgTranslate(0.5f, 0.25f); vgShear(0.001f * i32Zigzag2, 0); vgTranslate(-0.5f, -0.25f); // draw second path vgDrawPath(m_avgPaths[1], VG_STROKE_PATH | VG_FILL_PATH); }
/******************************************************************************* * Function Name : DoTranslate * Description : Demonstrate the effect of translations. Each path is * translated separately *******************************************************************************/ void CTransforms::DoTranslate() { // Make sure we're operating on the path user-to-surface matrix vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); // Load Identity matrix. This clears all previous transformations vgLoadIdentity(); // To be independent of screen resolution, we need to scale the // coordinates so everything in the range [0, 1] will be visible vgScale((float) PVRShellGet(prefWidth), (float) PVRShellGet(prefHeight)); // Unlike OpenGL, OpenVG does not maintain a matrix stack. So instead of // pushing the current matrix to the stack, we have to store it ourselves float afUnitMatrix[3 * 3]; vgGetMatrix(afUnitMatrix); // turn time(ms) into a clipped periodic triangle function int i32Zigzag1 = m_ui32AbsTime % 2000; if(i32Zigzag1 > 1000) i32Zigzag1 = 2000 - i32Zigzag1; i32Zigzag1 = PVRT_MAX(250, PVRT_MIN(750, i32Zigzag1)) - 500; // and again, now with shifted phase int i32Zigzag2 = (m_ui32AbsTime + 500) % 2000; if(i32Zigzag2 > 1000) i32Zigzag2 = 2000 - i32Zigzag2; i32Zigzag2 = PVRT_MAX(250, PVRT_MIN(750, i32Zigzag2)) - 250; // translation for first path vgTranslate(-0.001f * i32Zigzag1, -0.001f * i32Zigzag2); // draw first path vgDrawPath(m_avgPaths[0], VG_STROKE_PATH | VG_FILL_PATH); // restore the unit matrix ([0, 1] visible) vgLoadMatrix(afUnitMatrix); // translation for second path vgTranslate(0.001f * i32Zigzag1, 0.001f * i32Zigzag2); // draw second path vgDrawPath(m_avgPaths[1], VG_STROKE_PATH | VG_FILL_PATH); }
/******************************************************************************* * Function Name : DoShearOrigin * Description : Demonstrate the effect of shearing from the origin. *******************************************************************************/ void CTransforms::DoShearOrigin() { // Make sure we're operating on the path user-to-surface matrix vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); // Load Identity matrix. This clears all previous transformations vgLoadIdentity(); // To be independent of screen resolution, we need to scale the // coordinates so everything in the range [0, 1] will be visible vgScale((float)PVRShellGet(prefWidth), (float)PVRShellGet(prefHeight)); // turn time(ms) into a periodic triangle function int i32Zigzag = m_ui32AbsTime % 2000; if(i32Zigzag > 1000) i32Zigzag = 2000 - i32Zigzag; i32Zigzag = PVRT_MAX(100, PVRT_MIN(900, i32Zigzag)) - 500; vgShear(i32Zigzag * 0.001f, 0); // draw first path vgDrawPath(m_avgPaths[0], VG_STROKE_PATH | VG_FILL_PATH); // draw second path vgDrawPath(m_avgPaths[1], VG_STROKE_PATH | VG_FILL_PATH); }
/******************************************************************************* * Function Name : DoScaleOrigin * Description : Demonstrate the effect of scaling from the origin. *******************************************************************************/ void CTransforms::DoScaleOrigin() { // Make sure we're operating on the path user-to-surface matrix vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); // Load Identity matrix. This clears all previous transformations vgLoadIdentity(); // To be independent of screen resolution, we need to scale the // coordinates so everything in the range [0, 1] will be visible vgScale((float) PVRShellGet(prefWidth), (float) PVRShellGet(prefHeight)); // turn time(ms) into a periodic triangle function int i32Zigzag = m_ui32AbsTime % 2000; if(i32Zigzag > 1000) i32Zigzag = 2000 - i32Zigzag; i32Zigzag = PVRT_MAX(100, PVRT_MIN(900, i32Zigzag)); float fScaleFactor = 0.3f + (i32Zigzag * 0.0009f); // Scaling a scene from the origin means that objects will // either get pulled towards the origin or move away from it // along with being resized. vgScale(fScaleFactor, fScaleFactor); // draw first path vgDrawPath(m_avgPaths[0], VG_STROKE_PATH | VG_FILL_PATH); // draw second path vgDrawPath(m_avgPaths[1], VG_STROKE_PATH | VG_FILL_PATH); }
/*!*********************************************************************** @Function copy @Modified _Ptr A string to copy to @Input _Count Size of _Ptr @Input _Off Position to start copying from @Returns Number of bytes copied @Description Copies the string to _Ptr *************************************************************************/ size_t CPVRTString::copy(char* _Ptr, size_t _Count, size_t _Off) const { if(memcpy(_Ptr, &m_pString[_Off], PVRT_MIN(_Count, m_Size - _Off))) return _Count; return 0; }
/*!*************************************************************************** @Function SetTextures @Input pContext Context @Input dwScreenX Screen resolution along X @Input dwScreenY Screen resolution along Y @Input bRotate Rotate print3D by 90 degrees @Input 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 @Description 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; unsigned int uiDataSize = 0; if(uiShortestEdge >= 720) { pData = (void*)_arialbd_56_pvr; uiDataSize = _arialbd_56_pvr_size; } else if(uiShortestEdge >= 640) { pData = (void*)_arialbd_46_pvr; uiDataSize = _arialbd_46_pvr_size; } else { pData = (void*)_arialbd_36_pvr; uiDataSize = _arialbd_36_pvr_size; } return SetTextures(pContext, pData, dwScreenX, dwScreenY, bRotate, bMakeCopy); }
/*!*************************************************************************** @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; }
/*!*********************************************************************** @Function compare @Input _Pos1 Position to start comparing from @Input _Num1 Number of chars to compare @Input _Str A string to compare with @Input _Off Position in _Str to compare from @Input _Count Number of chars in _Str to compare with @Returns 0 if the strings match @Description Compares the string with _Str *************************************************************************/ int CPVRTString::compare(size_t _Pos1, size_t _Num1, const CPVRTString& _Str, size_t /*_Off*/, size_t _Count) const { assert(_Pos1<=m_Size); // check comparison starts within lhs CPVRTString int i32Ret; // value to return if no difference in actual comparisons between chars size_t stLhsLength = m_Size-_Pos1; size_t stSearchLength = PVRT_MIN(stLhsLength,PVRT_MIN(_Str.m_Size,PVRT_MIN(_Num1,_Count))); // number of comparisons to do if(PVRT_MIN(stLhsLength,_Num1)<PVRT_MIN(_Str.m_Size,_Count)) { i32Ret = -1; } else if(PVRT_MIN(stLhsLength,_Num1)>PVRT_MIN(_Str.m_Size,_Count)) { i32Ret = 1; } else { i32Ret = 0; } // do actual comparison char* lhptr = &m_pString[_Pos1]; char* rhptr = _Str.m_pString; for(size_t i=0;i<stSearchLength;++i) { if(*lhptr<*rhptr) return -1; else if (*lhptr>*rhptr) return 1; lhptr++;rhptr++; } // no difference found in compared characters return i32Ret; }
/*!*************************************************************************** @Function SetTitle @Input dwWin Window handle @Input dwBackgroundColor Background color @Input fFontSize Font size @Input dwFontColorLeft @Input sTitleLeft @Input dwFontColorRight @Input sTitleRight @Description Set window title. *****************************************************************************/ void CPVRTPrint3D::SetTitle(unsigned int dwWin, unsigned int dwBackgroundColor, float fFontSize, unsigned int dwFontColorLeft, const char * const sTitleLeft, unsigned int dwFontColorRight, const char * const sTitleRight) { #if !defined (DISABLE_PRINT3D) FREE(m_pWin[dwWin].pTitleVtxL); FREE(m_pWin[dwWin].pTitleVtxR); if(sTitleLeft) memcpy(m_pWin[dwWin].bTitleTextL, sTitleLeft , PVRT_MIN((size_t)(MAX_LETTERS-1), strlen(sTitleLeft )+1)); if(sTitleRight) memcpy(m_pWin[dwWin].bTitleTextR, sTitleRight, PVRT_MIN((size_t)(MAX_LETTERS-1), strlen(sTitleRight)+1)); /* Set title properties */ m_pWin[dwWin].fTitleFontSize = fFontSize; m_pWin[dwWin].dwTitleFontColorL = dwFontColorLeft; m_pWin[dwWin].dwTitleFontColorR = dwFontColorRight; m_pWin[dwWin].dwTitleBaseColor = dwBackgroundColor; m_pWin[dwWin].fTextRMinPos = GetLength(m_pWin[dwWin].fTitleFontSize, m_pWin[dwWin].bTitleTextL) + 10.0f; m_pWin[dwWin].bNeedUpdated = true; #endif }
/*!*************************************************************************** @Function Flush @Description Flushes all the print text commands *****************************************************************************/ int CPVRTPrint3D::Flush() { #if !defined (DISABLE_PRINT3D) int nTris, nVtx, nVtxBase, nTrisTot = 0; _ASSERT((m_nVtxCache % 4) == 0); _ASSERT(m_nVtxCache <= m_nVtxCacheMax); // Save render states APIRenderStates(INIT_PRINT3D_STATE); // Draw font if(m_nVtxCache) { SPVRTPrint3DAPI::SInstanceData& Data = (m_pAPI->m_pInstanceData ? *m_pAPI->m_pInstanceData : SPVRTPrint3DAPI::s_InstanceData); float fW = m_fScreenScale[0] * 640.0f; float fH = m_fScreenScale[1] * 480.0f; PVRTMat4 mxOrtho = PVRTMat4::Ortho(0.0f, 0.0f, fW, -fH, -1.0f, 1.0f, PVRTMat4::OGL, m_bRotate); if(m_bRotate) { PVRTMat4 mxTrans = PVRTMat4::Translation(-fH,fW,0.0f); mxOrtho = mxOrtho * mxTrans; } // Use the shader _ASSERT(Data.uProgramFont != UNDEFINED_HANDLE); glUseProgram(Data.uProgramFont); // Bind the projection and modelview matrices to the shader PVRTMat4& mProj = (m_bUsingProjection ? m_mProj : mxOrtho); PVRTMat4 mMVP = mProj * m_mModelView; glUniformMatrix4fv(Data.mvpLocationFont, 1, GL_FALSE, mMVP.f); // Reset m_bUsingProjection = false; PVRTMatrixIdentity(m_mModelView); // Set client states glEnableVertexAttribArray(VERTEX_ARRAY); glEnableVertexAttribArray(COLOR_ARRAY); glEnableVertexAttribArray(UV_ARRAY); // texture glBindTexture(GL_TEXTURE_2D, m_pAPI->m_uTextureFont); unsigned int uiIndex = m_eFilterMethod[eFilterProc_Min] + (m_eFilterMethod[eFilterProc_Mip]*2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, c_eMagTable[m_eFilterMethod[eFilterProc_Mag]]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_eMinTable[uiIndex]); nTrisTot = m_nVtxCache >> 1; // Render the text then. Might need several submissions. nVtxBase = 0; while(m_nVtxCache) { nVtx = PVRT_MIN(m_nVtxCache, 0xFFFC); nTris = nVtx >> 1; _ASSERT(nTris <= (PVRTPRINT3D_MAX_RENDERABLE_LETTERS*2)); _ASSERT((nVtx % 4) == 0); // Draw triangles glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(SPVRTPrint3DAPIVertex), (const void*)&m_pVtxCache[nVtxBase].sx); glVertexAttribPointer(COLOR_ARRAY, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SPVRTPrint3DAPIVertex), (const void*)&m_pVtxCache[nVtxBase].color); glVertexAttribPointer(UV_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(SPVRTPrint3DAPIVertex), (const void*)&m_pVtxCache[nVtxBase].tu); glDrawElements(GL_TRIANGLES, nTris * 3, GL_UNSIGNED_SHORT, m_pwFacesFont); if(glGetError()) { PVRTERROR_OUTPUT_DEBUG("glDrawElements(GL_TRIANGLES, (VertexCount/2)*3, GL_UNSIGNED_SHORT, m_pFacesFont); failed\n"); } nVtxBase += nVtx; m_nVtxCache -= nVtx; } // Restore render states glDisableVertexAttribArray(VERTEX_ARRAY); glDisableVertexAttribArray(COLOR_ARRAY); glDisableVertexAttribArray(UV_ARRAY); } // Draw a logo if requested #if !defined(FORCE_NO_LOGO) // User selected logos if(m_uLogoToDisplay & ePVRTPrint3DLogoPowerVR && m_uLogoToDisplay & ePVRTPrint3DLogoIMG) { APIDrawLogo(ePVRTPrint3DLogoIMG, eBottom | eRight); // IMG to the right APIDrawLogo(ePVRTPrint3DLogoPowerVR, eBottom | eLeft); // PVR to the left } else if(m_uLogoToDisplay & ePVRTPrint3DLogoPowerVR) { APIDrawLogo(ePVRTPrint3DLogoPowerVR, eBottom | eRight); // logo to the right } else if(m_uLogoToDisplay & ePVRTPrint3DLogoIMG) { APIDrawLogo(ePVRTPrint3DLogoIMG, eBottom | eRight); // logo to the right } #endif // Restore render states APIRenderStates(DEINIT_PRINT3D_STATE); return nTrisTot; #else return 0; #endif }
/**************************************************************************** @Function Fill @Input pOb Object to fill with @Return int -1 if the block if the best option is already full @Description Note: Ask Aaron ****************************************************************************/ int CBlock::Fill( CObject * const pOb) { SVtx *pVtx; int i; SMesh *pMesh; /* Build blocks from the large meshes */ if(!pOb->m_vMeshLg.empty()) { pMesh = &pOb->m_vMeshLg.back(); // _RPT1(_CRT_WARN, "Fill() using large with %d vtx\n", pMesh->nVtxNum); // Find the vertex with the fewest unused triangles for(i = 0; i < pMesh->nVtxNum; ++i) { pVtx = pMesh->ppVtx[i]; if(pVtx->nTriNumFree == 1) { if(FillFrom(pMesh, pVtx, pOb)) return Fill(pOb); } } if(m_sOptBest.IsEmpty()) { // Just start from any old vertex for(i = 0; i < pMesh->nVtxNum; ++i) { pVtx = pMesh->ppVtx[i]; if(pVtx->nTriNumFree) { if(FillFrom(pMesh, pVtx, pOb)) return Fill(pOb); break; } } if(m_sOptBest.IsEmpty()) { pOb->m_vMeshLg.pop_back(); // Delete the mesh from the list return Fill(pOb); } } if(m_sOptBest.IsFull()) return -1; } /* Match together the small meshes into blocks */ _ASSERT(m_sOptBest.IsEmpty()); i = m_nVtxLimit - m_sOptBest.nVtxNum - 3; // _RPT0(_CRT_WARN, "Fill() grouping small "); // Starting with the largest meshes, lump them into this block while(i >= 0 && (m_nVtxLimit - m_sOptBest.nVtxNum) >= 3) { if(pOb->m_pvMesh[i].empty()) { --i; continue; } pMesh = &pOb->m_pvMesh[i].back(); m_sOptBest.Add(pMesh); // _RPT1(_CRT_WARN, "+%d", pMesh->nVtxNum); pOb->m_pvMesh[i].pop_back(); i = PVRT_MIN(i, m_nVtxLimit - m_sOptBest.nVtxNum - 3); } // If there's any space left in this block (and clearly there are no blocks // just the right size to fit) then take SOME of the largest block available. if(!m_sOptBest.IsFull()) { m_sOpt.Copy(&m_sOptBest); // Note: This loop purposely does not check m_pvMesh[0] - any block // which is looking to grab more geometry would have already sucked // up those meshes for(i = (m_nVtxLimit-3); i; --i) { if(!pOb->m_pvMesh[i].empty()) { pMesh = &pOb->m_pvMesh[i].back(); _ASSERT(pMesh->ppVtx[0]->nTriNumFree); _ASSERT(!m_sOpt.UsingVertex(pMesh->ppVtx[0])); m_sOpt.AddVertex(pMesh->ppVtx[0]); // _RPT1(_CRT_WARN, "(+%d)\n", pMesh->nVtxNum); AddBestTriangles(pOb); m_sOptBest.Copy(&m_sOpt); _ASSERT(m_sOptBest.IsFull()); return i; } } } // _RPT0(_CRT_WARN, "\n"); return -1; }
/*!**************************************************************************** @Function CreateFBOorPBuffer @Return bool true if no error occured @Description Attempts to create our FBO if supported or a PBuffer if they are not. ******************************************************************************/ bool OGLESRenderToTexture::CreateFBOorPBuffer() { #if !defined(EGL_NOT_PRESENT) EGLConfig eglConfig = 0; EGLint list[9]; #endif // Find the largest square power of two texture that fits into the viewport m_i32TexSize = 1; int iSize = PVRT_MIN(PVRShellGet(prefWidth), PVRShellGet(prefHeight)); while (m_i32TexSize * 2 < iSize) m_i32TexSize *= 2; // Check for FBO extension if(CPVRTglesExt::IsGLExtensionSupported("GL_OES_framebuffer_object")) { // FBOs are present so we're going to use them m_eR2TType = eFBO; // Load the extensions as they are required m_Extensions.LoadExtensions(); // Check to see if the GL_EXT_discard_framebuffer extension is supported by seeing if // CPVRTglesExt has a valid pointer for glDiscardFramebufferEXT m_bDiscard = m_Extensions.glDiscardFramebufferEXT != 0; // Get the currently bound frame buffer object. On most platforms this just gives 0. glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &m_i32OriginalFbo); // Generate and bind a render buffer which will become a depth buffer shared between our two FBOs m_Extensions.glGenRenderbuffersOES(1, &m_uDepthBuffer); m_Extensions.glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_uDepthBuffer); /* Currently it is unknown to GL that we want our new render buffer to be a depth buffer. glRenderbufferStorage will fix this and in this case will allocate a depth buffer m_i32TexSize by m_i32TexSize. */ m_Extensions.glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, m_i32TexSize, m_i32TexSize); } #if !defined(EGL_NOT_PRESENT) else { // FBOs aren't present so we're going to use PBuffers m_eR2TType = ePBuffer; // Set up a configuration and attribute list used for creating a PBuffer surface. eglConfig = SelectEGLConfig(); // First we specify the width of the surface... list[0] = EGL_WIDTH; list[1] = m_i32TexSize; // ...then the height of the surface... list[2] = EGL_HEIGHT; list[3] = m_i32TexSize; /* ... then we specifiy the target for the texture that will be created when the pbuffer is created...*/ list[4] = EGL_TEXTURE_TARGET; list[5] = EGL_TEXTURE_2D; /*..then the format of the texture that will be created when the pBuffer is bound to a texture...*/ list[6] = EGL_TEXTURE_FORMAT; list[7] = EGL_TEXTURE_RGB; // The final thing is EGL_NONE which signifies the end. list[8] = EGL_NONE; /* Get the current display, context and surface so we can switch between the PBuffer surface and the main render surface. */ m_CurrentDisplay = eglGetCurrentDisplay(); m_CurrentContext = eglGetCurrentContext(); m_CurrentSurface = eglGetCurrentSurface(EGL_DRAW); } #else else {
/*!*************************************************************************** @Function PVRTMatrixQuaternionSlerpF @Output qOut Result of the interpolation @Input qA First quaternion to interpolate from @Input qB Second quaternion to interpolate from @Input t Coefficient of interpolation @Description Perform a Spherical Linear intERPolation between quaternion A and quaternion B at time t. t must be between 0.0f and 1.0f *****************************************************************************/ void PVRTMatrixQuaternionSlerpF( PVRTQUATERNIONf &qOut, const PVRTQUATERNIONf &qA, const PVRTQUATERNIONf &qB, const float t) { float fCosine, fAngle, A, B; /* Parameter checking */ if (t<0.0f || t>1.0f) { _RPT0(_CRT_WARN, "PVRTMatrixQuaternionSlerp : Bad parameters\n"); qOut.x = 0; qOut.y = 0; qOut.z = 0; qOut.w = 1; return; } /* Find sine of Angle between Quaternion A and B (dot product between quaternion A and B) */ fCosine = qA.w*qB.w + qA.x*qB.x + qA.y*qB.y + qA.z*qB.z; if (fCosine < 0) { PVRTQUATERNIONf qi; /* <http://www.magic-software.com/Documentation/Quaternions.pdf> "It is important to note that the quaternions q and -q represent the same rotation... while either quaternion will do, the interpolation methods require choosing one over the other. "Although q1 and -q1 represent the same rotation, the values of Slerp(t; q0, q1) and Slerp(t; q0,-q1) are not the same. It is customary to choose the sign... on q1 so that... the angle between q0 and q1 is acute. This choice avoids extra spinning caused by the interpolated rotations." */ qi.x = -qB.x; qi.y = -qB.y; qi.z = -qB.z; qi.w = -qB.w; PVRTMatrixQuaternionSlerpF(qOut, qA, qi, t); return; } fCosine = PVRT_MIN(fCosine, 1.0f); fAngle = (float)PVRTFACOS(fCosine); /* Avoid a division by zero */ if (fAngle==0.0f) { qOut = qA; return; } /* Precompute some values */ A = (float)(PVRTFSIN((1.0f-t)*fAngle) / PVRTFSIN(fAngle)); B = (float)(PVRTFSIN(t*fAngle) / PVRTFSIN(fAngle)); /* Compute resulting quaternion */ qOut.x = A * qA.x + B * qB.x; qOut.y = A * qA.y + B * qB.y; qOut.z = A * qA.z + B * qB.z; qOut.w = A * qA.w + B * qB.w; /* Normalise result */ PVRTMatrixQuaternionNormalizeF(qOut); }
/*!**************************************************************************** @Function RenderScene @Return bool true if no error occured @Description Main rendering loop function of the program. The shell will call this function every frame. eglSwapBuffers() will be performed by PVRShell automatically. PVRShell will also manage important OS events. Will also manage relevent OS events. The user has access to these events through an abstraction layer provided by PVRShell. ******************************************************************************/ bool OGLES2LevelOfDetail::RenderScene() { // Clear the color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use shader program glUseProgram(m_ShaderProgram.uiId); // Bind textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiReflectTex); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, m_uiNormalTex); // Rotate and Translate the model matrix PVRTMat4 mModel, mRotY, mTrans; float fDistance = 1400.0f * cos(m_fPositionZ) - 1350.0f; mTrans = PVRTMat4::Translation(0.0, 0.0, fDistance); mRotY = PVRTMat4::RotationY(m_fAngleY); mModel = mTrans * mRotY; m_fAngleY += PVRT_PI / 210; m_fPositionZ += 2 * PVRT_PI * 0.0008f; // Set model view projection matrix PVRTMat4 mModelView, mMVP; mModelView = m_mView * mModel; mMVP = m_mProjection * mModelView; glUniformMatrix4fv(m_ShaderProgram.auiLoc[eMVPMatrix], 1, GL_FALSE, mMVP.ptr()); // Set model matrix PVRTMat3 Model3x3 = PVRTMat3(mModel); glUniformMatrix3fv(m_ShaderProgram.auiLoc[eModelWorld], 1, GL_FALSE, Model3x3.ptr()); // Set eye position in model space PVRTVec4 vEyePosModel; vEyePosModel = mModelView.inverse() * PVRTVec4(0, 0, 0, 1); glUniform3fv(m_ShaderProgram.auiLoc[eEyePosModel], 1, &vEyePosModel.x); // Calculate the square of the pixel area that the mesh takes up on screen // This is done by projecting the vertices of the bounding box to screen space // then taking the axis aligned 2D bounding box of the projected vertices. // This is a very conservative estimate float fMinX, fMaxX, fMinY, fMaxY, fX, fY; ProjectVertex(m_avBoundingBox[0], mMVP, fX, fY); fMinX = fMaxX = fX; fMinY = fMaxY = fY; for (int i = 1; i < 8; ++i) { ProjectVertex(m_avBoundingBox[i], mMVP, fX, fY); fMinX = PVRT_MIN(fMinX, fX); fMinY = PVRT_MIN(fMinY, fY); fMaxX = PVRT_MAX(fMaxX, fX); fMaxY = PVRT_MAX(fMaxY, fY); } // Choose high detail if the mesh bounding box covers more than 2% of the screen m_bHighDetail = ((fMaxX - fMinX) * (fMaxY - fMinY) > 0.02); glUniform1i(m_ShaderProgram.auiLoc[eHighDetail], m_bHighDetail); /* Now that the uniforms are set, call another function to actually draw the mesh. */ DrawMesh(m_bHighDetail ? 0 : 1); // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools m_Print3D.DisplayDefaultTitle("Level of detail", (m_bHighDetail) ? "Detail: high" : "Detail: low", ePVRTPrint3DLogoIMG); m_Print3D.Flush(); return true; }
/*!**************************************************************************** @Function LoadVbos @Description Loads the mesh data required for this training course into vertex buffer objects ******************************************************************************/ void OGLES2LevelOfDetail::LoadVbos() { if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh]; if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh]; /* Load vertex data of all meshes in the scene into VBOs The meshes have been exported with the "Interleave Vectors" option, so all data is interleaved in the buffer at pMesh->pInterleaved. Interleaving data improves the memory access pattern and cache efficiency, thus it can be read faster by the hardware. */ glGenBuffers(m_Scene.nNumMesh, m_puiVbo); for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i) { // Load vertex data into buffer object SPODMesh& Mesh = m_Scene.pMesh[i]; unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride; glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]); glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW); // Load index data into buffer object if available m_puiIndexVbo[i] = 0; if (Mesh.sFaces.pData) { glGenBuffers(1, &m_puiIndexVbo[i]); uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW); } if (i == 0) { PVRTVec3 vBoundingBoxMin, vBoundingBoxMax; // calculate bounding box for mesh 0 float* pfData = (float*)Mesh.pInterleaved; vBoundingBoxMin.x = vBoundingBoxMax.x = pfData[0]; vBoundingBoxMin.y = vBoundingBoxMax.y = pfData[1]; vBoundingBoxMin.z = vBoundingBoxMax.z = pfData[2]; for(unsigned int i = 1; i < Mesh.nNumVertex; ++i) { pfData = (float*)(((char*)pfData) + Mesh.sVertex.nStride); vBoundingBoxMin.x = PVRT_MIN(vBoundingBoxMin.x, pfData[0]); vBoundingBoxMin.y = PVRT_MIN(vBoundingBoxMin.y, pfData[1]); vBoundingBoxMin.z = PVRT_MIN(vBoundingBoxMin.z, pfData[2]); vBoundingBoxMax.x = PVRT_MAX(vBoundingBoxMax.x, pfData[0]); vBoundingBoxMax.y = PVRT_MAX(vBoundingBoxMax.y, pfData[1]); vBoundingBoxMax.z = PVRT_MAX(vBoundingBoxMax.z, pfData[2]); } for (int i = 0; i < 8; ++i) { m_avBoundingBox[i].x = (i & 1) ? vBoundingBoxMin.x : vBoundingBoxMax.x; m_avBoundingBox[i].y = (i & 2) ? vBoundingBoxMin.y : vBoundingBoxMax.y; m_avBoundingBox[i].z = (i & 4) ? vBoundingBoxMin.z : vBoundingBoxMax.z; m_avBoundingBox[i].w = 1.0f; } } } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); }
/*!*************************************************************************** @Function Draw @Input i32StartPath Path to start drawing from @Input i32EndPath Path to end drawing on @Returns True on success @Description Draw a set of the paths loaded from the file. If no argument is specified this function will draw all paths. *****************************************************************************/ bool CPVRTPVGObject::Draw(int i32StartPath, int i32EndPath) { if (!m_bInitialized) { // This set has not been initialised so return. return false; } if(i32EndPath < i32StartPath) { i32EndPath = m_i32NumPaths; } i32StartPath = PVRT_MAX(0, i32StartPath); i32EndPath = PVRT_MIN(i32EndPath, m_i32NumPaths); for(int i = i32StartPath; i < i32EndPath; ++i) { // Set the blending options. PVG files only support standard translucency. if(m_pPaths[i].m_bNeedsBlending) { vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER); } else { vgSeti(VG_BLEND_MODE, VG_BLEND_SRC); } // Check whether this one is a path without fill or stroke and ignore it. if(m_pPaths[i].m_paintMode == 0) { continue; } // Fill the parameters for the current Fill Paint // Check if the paint is present, if it is different than the previous one or if it is the first one. if(((m_pPaths[i].m_paintMode & VG_FILL_PATH) && m_pPaths[i].m_bIsNewFill) || (i==i32StartPath)) { vgSeti(VG_FILL_RULE, m_pPaths[i].m_fillRule); vgSetPaint(m_pPaths[i].m_fillPaint, VG_FILL_PATH); } // Fill the parameters for the current Stroke Paint if(((m_pPaths[i].m_paintMode & VG_STROKE_PATH) && m_pPaths[i].m_bIsNewStroke) || (i==i32StartPath)) { vgSetf(VG_STROKE_LINE_WIDTH, m_pPaths[i].m_fStrokeWidth); vgSeti(VG_STROKE_CAP_STYLE, m_pPaths[i].m_capStyle); vgSeti(VG_STROKE_JOIN_STYLE, m_pPaths[i].m_joinStyle); vgSetf(VG_STROKE_MITER_LIMIT,m_pPaths[i].m_fMiterLimit); // Get current stroke 'dash' if any if (m_pPaths[i].m_ui32DashID != 666) { vgSetf(VG_STROKE_DASH_PHASE, m_pPaths[i].m_fDashPhase); vgSetfv(VG_STROKE_DASH_PATTERN, m_pPaths[i].m_ui32NumDashes, m_pPaths[i].m_fDashValues); } else { vgSetfv(VG_STROKE_DASH_PATTERN, 0, (VGfloat *) 0); // disable dashes } vgSetPaint(m_pPaths[i].m_strokePaint, VG_STROKE_PATH); } // Draw this path. vgDrawPath(m_pPaths[i].m_path, m_pPaths[i].m_paintMode); } // Success! return true; }
/*!**************************************************************************** @Function InitView @Return bool true if no error occurred @Description Code in InitView() will be called by PVRShell upon initialization or after a change in the rendering context. Used to initialize variables that are dependant on the rendering context (e.g. textures, vertex buffers, etc.) ******************************************************************************/ bool OGLES2FilmTV::InitView() { CPVRTString ErrorStr; // Initialize VBO data if(!LoadVbos(&ErrorStr)) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } // Load textures if(!LoadTextures(&ErrorStr)) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } // Load and compile the shaders & link programs if(!LoadShaders(&ErrorStr)) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } // Initialize Print3D bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n"); return false; } //Set OpenGL ES render states needed for this demo // Enable backface culling and depth test glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Find the largest square power of two texture that fits into the viewport m_i32TexSize = 1; int iSize = PVRT_MIN(PVRShellGet(prefWidth), PVRShellGet(prefHeight)); while (m_i32TexSize * 2 < iSize) m_i32TexSize *= 2; // Get the currently bound frame buffer object. On most platforms this just gives 0. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFB); for(int i = 0; i < 2; ++i) { // Create texture for the FBO glGenTextures(1, &m_uiTexture[i]); glBindTexture(GL_TEXTURE_2D, m_uiTexture[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_i32TexSize, m_i32TexSize, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Create FBO glGenFramebuffers(1, &m_uiFbo[i]); glBindFramebuffer(GL_FRAMEBUFFER, m_uiFbo[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTexture[i], 0); glGenRenderbuffers(1, &m_uiDepthBuffer[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthBuffer[i]); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, m_i32TexSize, m_i32TexSize); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthBuffer[i]); // Check that our FBO creation was successful GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(uStatus != GL_FRAMEBUFFER_COMPLETE) { m_bFBOsCreated = false; PVRShellOutputDebug("ERROR: Failed to initialise FBO"); break; } // Clear the colour buffer for this FBO glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFB); // Setup the main camera PVRTVec3 vFrom, vTo(0.0f), vUp(0.0f, 1.0f, 0.0f); float fFOV; // Camera nodes are after the mesh and light nodes in the array int i32CamID = m_Scene.pNode[m_Scene.nNumMeshNode + m_Scene.nNumLight + g_ui32Camera].nIdx; // Get the camera position, target and field of view (fov) if(m_Scene.pCamera[i32CamID].nIdxTarget != -1) // Does the camera have a target? fFOV = m_Scene.GetCameraPos( vFrom, vTo, g_ui32Camera); // vTo is taken from the target node else fFOV = m_Scene.GetCamera( vFrom, vTo, vUp, g_ui32Camera); // vTo is calculated from the rotation m_View = PVRTMat4::LookAtRH(vFrom, vTo, vUp); // Calculate the projection matrix PVRTMat4 mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate); m_ViewProjection = mProjection * m_View; // Check to see if the GL_EXT_discard_framebuffer extension is supported if(m_bFBOsCreated && (m_bDiscard = CPVRTgles2Ext::IsGLExtensionSupported("GL_EXT_discard_framebuffer")) != false) { m_Extensions.LoadExtensions(); m_bDiscard = m_Extensions.glDiscardFramebufferEXT != 0; } return true; }
/*!**************************************************************************** @Function InitView @Return bool true if no error occured @Description Code in InitView() will be called by PVRShell upon initialization or after a change in the rendering context. Used to initialize variables that are dependant on the rendering context (e.g. textures, vertex buffers, etc.) ******************************************************************************/ bool OGLES2RenderToTexture::InitView() { // Find the largest square power of two texture that fits into the viewport m_i32TexSize = 1; int iSize = PVRT_MIN(PVRShellGet(prefWidth), PVRShellGet(prefHeight)); while (m_i32TexSize * 2 < iSize) m_i32TexSize *= 2; srand(PVRShellGetTime()); m_ui32Framenum = rand() % 5000; // Get the initial time m_ui32Time = PVRShellGetTime(); /* Initialize VBO data and load textures */ LoadVbos(); LoadTextures(); /* Load and compile the shaders & link programs */ CPVRTString ErrorStr; if (!LoadShaders(&ErrorStr)) { PVRShellSet(prefExitMessage, ErrorStr.c_str()); return false; } // Set the sampler2D uniforms to corresponding texture units glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sTexture"), 0); /* Initialize Print3D */ // Is the screen rotated? bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n"); return false; } glClearColor(0.0f, 0.0f, 0.0f, 0.0f); /* Create two handles for a frame buffer object. */ glGenFramebuffers(2, m_auiFbo); m_i32CurrentFbo = 1; /* Get the currently bound frame buffer object. On most platforms this just gives 0. */ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo); /* Attach the renderable objects (e.g. textures) to the frame buffer object now as they will stay attached to the frame buffer object even when it is not bound. */ // We have two FBOs so we're doing the same for each for(int i = 0; i < 2; ++i) { /* Firstly, to do anything with a frame buffer object we need to bind it. In the case below we are binding our frame buffer object to the frame buffer. */ glBindFramebuffer(GL_FRAMEBUFFER, m_auiFbo[i]); /* To render to a texture we need to attach it texture to the frame buffer object. GL_COLOR_ATTACHMENT0 tells it to attach the texture to the colour buffer, the 0 on the end refers to the colour buffer we want to attach it to as a frame buffer object can have more than one colour buffer. */ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_auiTexture[i], 0); // Clear the color buffer for this FBO glClear(GL_COLOR_BUFFER_BIT); /* Create and bind a depth buffer to the frame buffer object. A depth buffer isn't needed for this training course but will likely be required for most uses of frame buffer objects so its attachment is being demonstrated here. */ // Generate and bind the handle for the render buffer (which will become our depth buffer) glGenRenderbuffers(1, &m_auiDepthBuffer[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_auiDepthBuffer[i]); /* Currently it is unknown to GL that we want our new render buffer to be a depth buffer. glRenderbufferStorage will fix this and in this case will allocate a depth buffer of m_i32TexSize by m_i32TexSize. */ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, m_i32TexSize, m_i32TexSize); // Now we have our depth buffer attach it to our frame buffer object. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_auiDepthBuffer[i]); } /* Unbind the frame buffer object so rendering returns back to the backbuffer. */ glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo); // Use a nice bright blue as clear colour glClearColor(0.6f, 0.8f, 1.0f, 1.0f); return true; }
/*!**************************************************************************** @Function InitView @Return bool true if no error occured @Description Code in InitView() will be called by PVRShell upon initialization or after a change in the rendering context. Used to initialize variables that are dependant on the rendering context (e.g. textures, vertex buffers, etc.) ******************************************************************************/ bool OGLESAntialiasedLines::InitView() { bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); m_iWidth = PVRShellGet(prefWidth); m_iHeight = PVRShellGet(prefHeight); myglClearColor(f2vt(0.6f), f2vt(0.8f), f2vt(1.0f), f2vt(1.0f)); // Initialise Print3D if(m_Print3D.SetTextures(0, m_iWidth, m_iHeight, bRotate) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D.\n"); return false; } // Initialise the texture if (PVRTTextureLoadFromPVR("LineRound.pvr", &m_uiTexture) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Failed to load texture.\n"); return false; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Initialise geometry SVertex *paVertices = new SVertex[c_iNumLines * 2]; // 2 vertices per GL_LINE STexVertex *paTexVertices = new STexVertex[c_iNumLines * 8]; // 8 vertices per AA line (includes caps) GLushort *paui16Indices = new GLushort[c_iNumLines * 18]; // 18 indices per AA line (6 triangles) if(!paVertices || !paTexVertices || !paui16Indices) { delete[] paVertices; delete[] paTexVertices; delete[] paui16Indices; PVRShellSet(prefExitMessage, "ERROR: Failed to allocate line vertices and indices.\n"); return false; } srand(0); float fAngleStep = PVRT_TWO_PI / c_iNumLines; VERTTYPE fSize = f2vt(PVRT_MIN(m_iWidth, m_iHeight) * 0.4f); for (int i = 0; i < c_iNumLines; ++i) { // Place the line vertices on a circle paVertices[i*2].vPosition.x = VERTTYPEMUL(fSize, PVRTSIN(fAngleStep * (i + c_fLineArc))); paVertices[i*2].vPosition.y = VERTTYPEMUL(fSize, PVRTCOS(fAngleStep * (i + c_fLineArc))); paVertices[i*2+1].vPosition.x = VERTTYPEMUL(fSize, PVRTSIN(fAngleStep * i)); paVertices[i*2+1].vPosition.y = VERTTYPEMUL(fSize, PVRTCOS(fAngleStep * i)); // Pick a random RGB color paVertices[i*2].uiColor = (0xFF << 24) + ((rand() & 0xFF) << 16) + ((rand() & 0xFF) << 8) + (rand() & 0xFF); paVertices[i*2+1].uiColor = paVertices[i*2].uiColor; // Tessellate the antialiased line TessellateLine(paVertices[i*2].vPosition, paVertices[i*2+1].vPosition, c_fLineWidth, paVertices[i*2].uiColor, &paTexVertices[i * 8], i * 8, &paui16Indices[i * 18]); } // We use 3 VBOs for clarity: // 0: AA line vertex data // 1: AA line index data // 2: GL_LINES vertex data glGenBuffers(3, m_uiVbos); // Bind the VBOs and fill them with data glBindBuffer(GL_ARRAY_BUFFER, m_uiVbos[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(*paTexVertices) * c_iNumLines * 8, paTexVertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uiVbos[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(*paui16Indices) * c_iNumLines * 18, paui16Indices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, m_uiVbos[2]); glBufferData(GL_ARRAY_BUFFER, sizeof(*paVertices) * c_iNumLines * 2, paVertices, GL_STATIC_DRAW); // Unbind buffers glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Set projection to use pixel coordinates glMatrixMode(GL_PROJECTION); glLoadIdentity(); myglOrtho(0, f2vt((float)PVRShellGet(prefWidth)), f2vt((float)PVRShellGet(prefHeight)), 0, 0, 1); delete[] paVertices; delete[] paTexVertices; delete[] paui16Indices; return true; }
/*!*************************************************************************** @Function PVRTMatrixQuaternionSlerpX @Output qOut Result of the interpolation @Input qA First quaternion to interpolate from @Input qB Second quaternion to interpolate from @Input t Coefficient of interpolation @Description Perform a Spherical Linear intERPolation between quaternion A and quaternion B at time t. t must be between 0.0f and 1.0f Requires input quaternions to be normalized *****************************************************************************/ void PVRTMatrixQuaternionSlerpX( PVRTQUATERNIONx &qOut, const PVRTQUATERNIONx &qA, const PVRTQUATERNIONx &qB, const int t) { int fCosine, fAngle, A, B; /* Parameter checking */ if (t<PVRTF2X(0.0f) || t>PVRTF2X(1.0f)) { _RPT0(_CRT_WARN, "PVRTMatrixQuaternionSlerp : Bad parameters\n"); qOut.x = PVRTF2X(0.0f); qOut.y = PVRTF2X(0.0f); qOut.z = PVRTF2X(0.0f); qOut.w = PVRTF2X(1.0f); return; } /* Find sine of Angle between Quaternion A and B (dot product between quaternion A and B) */ fCosine = PVRTXMUL(qA.w, qB.w) + PVRTXMUL(qA.x, qB.x) + PVRTXMUL(qA.y, qB.y) + PVRTXMUL(qA.z, qB.z); if(fCosine < PVRTF2X(0.0f)) { PVRTQUATERNIONx qi; /* <http://www.magic-software.com/Documentation/Quaternions.pdf> "It is important to note that the quaternions q and -q represent the same rotation... while either quaternion will do, the interpolation methods require choosing one over the other. "Although q1 and -q1 represent the same rotation, the values of Slerp(t; q0, q1) and Slerp(t; q0,-q1) are not the same. It is customary to choose the sign... on q1 so that... the angle between q0 and q1 is acute. This choice avoids extra spinning caused by the interpolated rotations." */ qi.x = -qB.x; qi.y = -qB.y; qi.z = -qB.z; qi.w = -qB.w; PVRTMatrixQuaternionSlerpX(qOut, qA, qi, t); return; } fCosine = PVRT_MIN(fCosine, PVRTF2X(1.0f)); fAngle = PVRTXACOS(fCosine); /* Avoid a division by zero */ if (fAngle==PVRTF2X(0.0f)) { qOut = qA; return; } /* Precompute some values */ A = PVRTXDIV(PVRTXSIN(PVRTXMUL((PVRTF2X(1.0f)-t), fAngle)), PVRTXSIN(fAngle)); B = PVRTXDIV(PVRTXSIN(PVRTXMUL(t, fAngle)), PVRTXSIN(fAngle)); /* Compute resulting quaternion */ qOut.x = PVRTXMUL(A, qA.x) + PVRTXMUL(B, qB.x); qOut.y = PVRTXMUL(A, qA.y) + PVRTXMUL(B, qB.y); qOut.z = PVRTXMUL(A, qA.z) + PVRTXMUL(B, qB.z); qOut.w = PVRTXMUL(A, qA.w) + PVRTXMUL(B, qB.w); /* Normalise result */ PVRTMatrixQuaternionNormalizeX(qOut); }
/*!**************************************************************************** @Function InitView @Return bool true if no error occurred @Description Code in InitView() will be called by PVRShell upon initialization or after a change in the rendering context. Used to initialize variables that are dependent on the rendering context (e.g. textures, vertex buffers, etc.) ******************************************************************************/ bool OGLES2IntroducingPrint3D::InitView() { /* Initialize the textures used by Print3D. To properly display text, Print3D needs to know the viewport dimensions and whether the text should be rotated. We get the dimensions using the shell function PVRShellGet(prefWidth/prefHeight). We can also get the rotate parameter by checking prefIsRotated and prefFullScreen. */ bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); // Retrieve screen metrics from PVRShell unsigned int uiWidth = PVRShellGet(prefWidth); unsigned int uiHeight = PVRShellGet(prefHeight); /* The fonts are loaded here using a PVRTool's ResourceFile wrapper. However, it is possible to load the textures in any way that provides access to a pointer to memory, and the size of the file. */ CPVRTResourceFile CustomFont(c_szTextFile); if(!CustomFont.IsOpen()) { PVRShellSet(prefExitMessage, "ERROR: Failed to load font file!"); return false; } CPVRTResourceFile IntroFont(c_szIntroFile); if(!IntroFont.IsOpen()) { PVRShellSet(prefExitMessage, "ERROR: Failed to load font file!"); return false; } // Determine which size title font to use. unsigned int uiMinScreenLen = PVRT_MIN(uiWidth, uiHeight); const char* pTitleFontFile = NULL; if(uiMinScreenLen >= 720) pTitleFontFile = c_szTitleFont[eFontSize_56]; else if(uiMinScreenLen >= 640) pTitleFontFile = c_szTitleFont[eFontSize_46]; else pTitleFontFile = c_szTitleFont[eFontSize_36]; CPVRTResourceFile TitleFont(pTitleFontFile); if(!TitleFont.IsOpen()) { PVRShellSet(prefExitMessage, "ERROR: Failed to load font file!"); return false; } /* The first version of Print3D.SetTextures() presented here sets up m_Print3D with default, built-in textures. The overloaded functions provided allow user-defined textures to be loaded instead. Please refer to PVRTexTool's user manual for instructions on generating fonts files. */ m_Print3D.SetTextures(NULL, uiWidth, uiHeight, bRotate); m_CentralText.SetTextures(NULL, CustomFont.DataPtr(), uiWidth, uiHeight, bRotate); m_IntroText.SetTextures(NULL, IntroFont.DataPtr(), uiWidth, uiHeight, bRotate); m_TitleText.SetTextures(NULL, TitleFont.DataPtr(), uiWidth, uiHeight, bRotate); // Sets the clear color glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Generate background texture GenerateBackgroundTexture(uiWidth, uiHeight); m_ulStartTime = PVRShellGetTime(); return true; }