/*!*************************************************************************** @Function PVRTTextureCreate @Input w Size of the texture @Input h Size of the texture @Input wMin Minimum size of a texture level @Input hMin Minimum size of a texture level @Input nBPP Bits per pixel of the format @Input bMIPMap Create memory for MIP-map levels also? @Return Allocated texture memory (must be free()d) @Description Creates a PVR_Texture_Header structure, including room for the specified texture, in memory. *****************************************************************************/ PVR_Texture_Header *PVRTTextureCreate( unsigned int w, unsigned int h, const unsigned int wMin, const unsigned int hMin, const unsigned int nBPP, const bool bMIPMap) { size_t len; unsigned char *p; len = 0; do { len += PVRT_MAX(w, wMin) * PVRT_MAX(h, hMin); w >>= 1; h >>= 1; } while(bMIPMap && (w || h)); len = (len * nBPP) / 8; len += sizeof(PVR_Texture_Header); p = (unsigned char*)malloc(len); _ASSERT(p); return (PVR_Texture_Header*)p; }
/******************************************************************************* * 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 PVRTTextureCreate @Input w Size of the texture @Input h Size of the texture @Input wMin Minimum size of a texture level @Input hMin Minimum size of a texture level @Input nBPP Bits per pixel of the format @Input bMIPMap Create memory for MIP-map levels also? @Return Allocated texture memory (must be free()d) @Description Creates a PVR_Texture_Header structure, including room for the specified texture, in memory. *****************************************************************************/ PVR_Texture_Header *PVRTTextureCreate( const unsigned int w, const unsigned int h, const unsigned int wMin, const unsigned int hMin, const unsigned int nBPP, const bool bMIPMap) { size_t len; unsigned char *p; { unsigned int wTmp = w, hTmp = h; len = 0; do { len += PVRT_MAX(wTmp, wMin) * PVRT_MAX(hTmp, hMin); wTmp >>= 1; hTmp >>= 1; } while(bMIPMap && (wTmp || hTmp)); } len = (len * nBPP) / 8; len += sizeof(PVR_Texture_Header); p = (unsigned char*)malloc(len); _ASSERT(p); if(p) { PVR_Texture_Header * const psTexHeader = (PVR_Texture_Header*)p; psTexHeader->dwHeaderSize = sizeof(PVR_Texture_Header); psTexHeader->dwWidth = w; psTexHeader->dwHeight = h; psTexHeader->dwMipMapCount = 0; psTexHeader->dwpfFlags = 0; psTexHeader->dwTextureDataSize = (PVRTuint32)(len - sizeof(PVR_Texture_Header)); psTexHeader->dwBitCount = nBPP; psTexHeader->dwRBitMask = 0; psTexHeader->dwGBitMask = 0; psTexHeader->dwBBitMask = 0; psTexHeader->dwAlphaBitMask = 0; psTexHeader->dwPVR = 0; psTexHeader->dwNumSurfs = 1; return psTexHeader; } else { return 0; } }
/******************************************************************************* * 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 PVRTTextureCreate @Input w Size of the texture @Input h Size of the texture @Input wMin Minimum size of a texture level @Input hMin Minimum size of a texture level @Input nBPP Bits per pixel of the format @Input bMIPMap Create memory for MIP-map levels also? @Return Allocated texture memory (must be free()d) @Description Creates a PVRTextureHeaderV3 structure, including room for the specified texture, in memory. *****************************************************************************/ PVRTextureHeaderV3 *PVRTTextureCreate( const unsigned int w, const unsigned int h, const unsigned int wMin, const unsigned int hMin, const unsigned int nBPP, const bool bMIPMap) { size_t len; unsigned char *p; { unsigned int wTmp = w, hTmp = h; len = 0; do { len += PVRT_MAX(wTmp, wMin) * PVRT_MAX(hTmp, hMin); wTmp >>= 1; hTmp >>= 1; } while(bMIPMap && (wTmp || hTmp)); } len = (len * nBPP) / 8; len += PVRTEX3_HEADERSIZE; p = (unsigned char*)malloc(len); _ASSERT(p); if(p) { PVRTextureHeaderV3 * const psTexHeader = (PVRTextureHeaderV3*)p; *psTexHeader=PVRTextureHeaderV3(); psTexHeader->u32Width=w; psTexHeader->u32Height=h; return psTexHeader; } else { return 0; } }
/*!**************************************************************************** @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 PVRTTextureLoadFromPointer @Input pointer Pointer to header-texture's structure @Modified texName the OpenGL ES texture name as returned by glBindTexture @Modified psTextureHeader Pointer to a PVR_Texture_Header struct. Modified to contain the header data of the returned texture Ignored if NULL. @Input bAllowDecompress Allow decompression if PVRTC is not supported in hardware. @Input nLoadFromLevel Which mipmap level to start loading from (0=all) @Input texPtr If null, texture follows header, else texture is here. @Return PVR_SUCCESS on success @Description Allows textures to be stored in C header files and loaded in. Can load parts of a mipmaped texture (ie skipping the highest detailed levels).In OpenGL Cube Map, each texture's up direction is defined as next (view direction, up direction), (+x,-y)(-x,-y)(+y,+z)(-y,-z)(+z,-y)(-z,-y). Sets the texture MIN/MAG filter to GL_LINEAR_MIPMAP_NEAREST/GL_LINEAR if mipmaps are present, GL_LINEAR/GL_LINEAR otherwise. *****************************************************************************/ EPVRTError PVRTTextureLoadFromPointer( const void* pointer, GLuint *const texName, const void *psTextureHeader, bool bAllowDecompress, const unsigned int nLoadFromLevel, const void * const texPtr) { PVR_Texture_Header* psPVRHeader = (PVR_Texture_Header*)pointer; unsigned int u32NumSurfs; // perform checks for old PVR psPVRHeader if(psPVRHeader->dwHeaderSize!=sizeof(PVR_Texture_Header)) { // Header V1 if(psPVRHeader->dwHeaderSize==PVRTEX_V1_HEADER_SIZE) { // react to old psPVRHeader: i.e. fill in numsurfs as this is missing from old header PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: this is an old pvr" " - you can use PVRTexTool to update its header.\n"); if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) u32NumSurfs = 6; else u32NumSurfs = 1; } else { // not a pvr at all PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: not a valid pvr.\n"); return PVR_FAIL; } } else { // Header V2 if(psPVRHeader->dwNumSurfs<1) { // encoded with old version of PVRTexTool before zero numsurfs bug found. if(psPVRHeader->dwpfFlags & PVRTEX_CUBEMAP) u32NumSurfs = 6; else u32NumSurfs = 1; } else { u32NumSurfs = psPVRHeader->dwNumSurfs; } } GLuint textureName; GLenum eTextureFormat = 0; GLenum eTextureInternalFormat = 0; // often this is the same as textureFormat, but not for BGRA8888 on the iPhone, for instance GLenum eTextureType = 0; GLenum eTarget; bool bIsPVRTCSupported = CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_texture_compression_pvrtc"); #ifndef TARGET_OS_IPHONE bool bIsBGRA8888Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_texture_format_BGRA8888"); #else bool bIsBGRA8888Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_APPLE_texture_format_BGRA8888"); #endif bool bIsFloat16Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_texture_half_float"); bool bIsFloat32Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_texture_float"); #ifndef TARGET_OS_IPHONE bool bIsETCSupported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_compressed_ETC1_RGB8_texture"); #endif *texName = 0; // install warning value bool bIsCompressedFormatSupported = false, bIsCompressedFormat = false; /* Only accept untwiddled data UNLESS texture format is PVRTC */ if ( ((psPVRHeader->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE) && ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC2) && ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC4) ) { // We need to load untwiddled textures -- GL will twiddle for us. PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: texture should be untwiddled.\n"); return PVR_FAIL; } unsigned int ePixelType = psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE; switch(ePixelType) { case OGL_RGBA_4444: eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_SHORT_4_4_4_4; break; case OGL_RGBA_5551: eTextureFormat = eTextureInternalFormat = GL_RGBA ; eTextureType = GL_UNSIGNED_SHORT_5_5_5_1; break; case OGL_RGBA_8888: eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE ; break; /* New OGL Specific Formats Added */ case OGL_RGB_565: eTextureFormat = eTextureInternalFormat = GL_RGB ; eTextureType = GL_UNSIGNED_SHORT_5_6_5; break; case OGL_RGB_555: PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: pixel type OGL_RGB_555 not supported.\n"); return PVR_FAIL; // Deal with exceptional case case OGL_RGB_888: eTextureFormat = eTextureInternalFormat = GL_RGB ; eTextureType = GL_UNSIGNED_BYTE; break; case OGL_I_8: eTextureFormat = eTextureInternalFormat = GL_LUMINANCE; eTextureType = GL_UNSIGNED_BYTE; break; case OGL_AI_88: eTextureFormat = eTextureInternalFormat = GL_LUMINANCE_ALPHA ; eTextureType = GL_UNSIGNED_BYTE; break; case MGLPT_PVRTC2: case OGL_PVRTC2: if(bIsPVRTCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; eTextureFormat = psPVRHeader->dwAlphaBitMask==0 ? GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG ; // PVRTC2 } else { if(bAllowDecompress) { bIsCompressedFormatSupported = false; bIsCompressedFormat = true; eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: PVRTC2 not supported. Converting to RGBA8888 instead.\n"); } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: PVRTC2 not supported.\n"); return PVR_FAIL; } } break; case MGLPT_PVRTC4: case OGL_PVRTC4: if(bIsPVRTCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; eTextureFormat = psPVRHeader->dwAlphaBitMask==0 ? GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ; // PVRTC4 } else { if(bAllowDecompress) { bIsCompressedFormatSupported = false; bIsCompressedFormat = true; eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: PVRTC4 not supported. Converting to RGBA8888 instead.\n"); } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: PVRTC4 not supported.\n"); return PVR_FAIL; } } break; case OGL_A_8: eTextureFormat = eTextureInternalFormat = GL_ALPHA; eTextureType = GL_UNSIGNED_BYTE; break; case OGL_BGRA_8888: if(bIsBGRA8888Supported) { eTextureType = GL_UNSIGNED_BYTE; #ifndef __APPLE__ eTextureFormat = eTextureInternalFormat = GL_BGRA; #else eTextureFormat = GL_BGRA; eTextureInternalFormat = GL_RGBA; #endif } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Unable to load GL_BGRA texture as extension GL_IMG_texture_format_BGRA8888 is unsupported.\n"); return PVR_FAIL; } break; case D3D_ABGR_16161616F: if(bIsFloat16Supported) { eTextureFormat = eTextureInternalFormat = GL_RGBA ; eTextureType = GL_HALF_FLOAT_OES; } break; case D3D_ABGR_32323232F: if(bIsFloat32Supported) { eTextureFormat = eTextureInternalFormat = GL_RGBA ; eTextureType = GL_FLOAT; } break; #ifndef TARGET_OS_IPHONE case ETC_RGB_4BPP: if(bIsETCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; eTextureFormat = GL_ETC1_RGB8_OES; } else { if(bAllowDecompress) { bIsCompressedFormatSupported = false; bIsCompressedFormat = true; eTextureFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: ETC not supported. Converting to RGBA8888 instead.\n"); } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: ETC not supported.\n"); return PVR_FAIL; } } break; #endif default: // NOT SUPPORTED PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: pixel type not supported.\n"); return PVR_FAIL; } // load the texture up glPixelStorei(GL_UNPACK_ALIGNMENT,1); // Never have row-aligned in psPVRHeaders glGenTextures(1, &textureName); // check that this data is cube map data or not. if(psPVRHeader->dwpfFlags & PVRTEX_CUBEMAP) eTarget = GL_TEXTURE_CUBE_MAP; else eTarget = GL_TEXTURE_2D; glBindTexture(eTarget, textureName); if(glGetError()) { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glBindTexture() failed.\n"); return PVR_FAIL; } for(unsigned int i=0; i<u32NumSurfs; i++) { char *theTexturePtr = (texPtr? (char*)texPtr : (char*)psPVRHeader + psPVRHeader->dwHeaderSize) + psPVRHeader->dwTextureDataSize * i; char *theTextureToLoad = 0; int nMIPMapLevel; int nTextureLevelsNeeded = (psPVRHeader->dwpfFlags & PVRTEX_MIPMAP)? psPVRHeader->dwMipMapCount : 0; unsigned int nSizeX= psPVRHeader->dwWidth, nSizeY = psPVRHeader->dwHeight; unsigned int CompressedImageSize = 0; for(nMIPMapLevel = 0; nMIPMapLevel <= nTextureLevelsNeeded; nSizeX=PVRT_MAX(nSizeX/2, (unsigned int)1), nSizeY=PVRT_MAX(nSizeY/2, (unsigned int)1), nMIPMapLevel++) { theTextureToLoad = theTexturePtr; // Load the Texture // If the texture is PVRTC or ETC then use GLCompressedTexImage2D if(bIsCompressedFormat) { /* Calculate how many bytes this MIP level occupies */ if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { CompressedImageSize = ( PVRT_MAX(nSizeX, PVRTC2_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, PVRTC2_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount) / 8; } else if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC4) { CompressedImageSize = ( PVRT_MAX(nSizeX, PVRTC4_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, PVRTC4_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount) / 8; } else {// ETC CompressedImageSize = ( PVRT_MAX(nSizeX, ETC_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, ETC_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount) / 8; } if(((signed int)nMIPMapLevel - (signed int)nLoadFromLevel) >= 0) { if(bIsCompressedFormatSupported) { if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) { /* Load compressed texture data at selected MIP level */ glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, nMIPMapLevel-nLoadFromLevel, eTextureFormat, nSizeX, nSizeY, 0, CompressedImageSize, theTextureToLoad); } else { /* Load compressed texture data at selected MIP level */ glCompressedTexImage2D(GL_TEXTURE_2D, nMIPMapLevel-nLoadFromLevel, eTextureFormat, nSizeX, nSizeY, 0, CompressedImageSize, theTextureToLoad); } } else { // Convert PVRTC to 32-bit PVRTuint8 *u8TempTexture = (PVRTuint8*)malloc(nSizeX*nSizeY*4); if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { PVRTDecompressPVRTC(theTextureToLoad, 1, nSizeX, nSizeY, u8TempTexture); } else if((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC4) { PVRTDecompressPVRTC(theTextureToLoad, 0, nSizeX, nSizeY, u8TempTexture); } else { // ETC PVRTDecompressETC(theTextureToLoad, nSizeX, nSizeY, u8TempTexture, 0); } if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) {// Load compressed cubemap data at selected MIP level // Upload the texture as 32-bits glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,nMIPMapLevel-nLoadFromLevel,GL_RGBA, nSizeX,nSizeY,0, GL_RGBA,GL_UNSIGNED_BYTE,u8TempTexture); FREE(u8TempTexture); } else {// Load compressed 2D data at selected MIP level // Upload the texture as 32-bits glTexImage2D(GL_TEXTURE_2D,nMIPMapLevel-nLoadFromLevel,GL_RGBA, nSizeX,nSizeY,0, GL_RGBA,GL_UNSIGNED_BYTE,u8TempTexture); FREE(u8TempTexture); } } } } else { if(((signed int)nMIPMapLevel - (signed int)nLoadFromLevel) >= 0) { if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) { /* Load uncompressed texture data at selected MIP level */ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,nMIPMapLevel-nLoadFromLevel,eTextureInternalFormat,nSizeX,nSizeY, 0, eTextureFormat,eTextureType,theTextureToLoad); } else { /* Load uncompressed texture data at selected MIP level */ glTexImage2D(GL_TEXTURE_2D,nMIPMapLevel-nLoadFromLevel,eTextureInternalFormat,nSizeX,nSizeY,0,eTextureFormat,eTextureType,theTextureToLoad); } } } if(glGetError()) { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glTexImage2D() failed.\n"); return PVR_FAIL; } // offset the texture pointer by one mip-map level /* PVRTC case */ if ( bIsCompressedFormat ) { theTexturePtr += CompressedImageSize; } else { /* New formula that takes into account bit counts inferior to 8 (e.g. 1 bpp) */ theTexturePtr += (nSizeX * nSizeY * psPVRHeader->dwBitCount + 7) / 8; } } } *texName = textureName; if(psTextureHeader) { *(PVR_Texture_Header*)psTextureHeader = *psPVRHeader; ((PVR_Texture_Header*)psTextureHeader)->dwPVR = PVRTEX_IDENTIFIER; ((PVR_Texture_Header*)psTextureHeader)->dwNumSurfs = u32NumSurfs; } if(eTextureType==GL_FLOAT || eTextureType==GL_HALF_FLOAT_OES) { if(!psPVRHeader->dwMipMapCount) { // Texture filter modes are limited to these for float textures glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } else { glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } else { if(!psPVRHeader->dwMipMapCount) { glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } } if( (psPVRHeader->dwWidth & (psPVRHeader->dwWidth - 1)) | (psPVRHeader->dwHeight & (psPVRHeader->dwHeight - 1))) { /* NPOT textures requires the wrap mode to be set explicitly to GL_CLAMP_TO_EDGE or the texture will be inconsistent. */ glTexParameteri(eTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(eTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } return PVR_SUCCESS; }
bool TriangulatePolygon(const PVRTCoordinateVector &coordinates, const PVRTPolygon &polygon, PVRTCoordinateVector &triangle_coords, PVRTTriangleVector &triangles) { unsigned int numPoints = polygon.indices.size(); InitialiseTriangulationModule(numPoints, 2*numPoints, NULL); int paths = 1; int pathlens[1] = { polygon.indices.size() }; float maxDimension = -FLT_MAX; float *pCoordinates = new float[polygon.indices.size()*2]; for (unsigned int i=0; i < polygon.indices.size(); i++) { PVRTVec3 coord = coordinates[polygon.indices[i]].position; pCoordinates[i*2] = coord.x; pCoordinates[i*2+1] = coord.y; maxDimension = PVRT_MAX(coord.x, maxDimension); maxDimension = PVRT_MAX(coord.y, maxDimension); } ExternalTrapStruct TrapezoidsResult; TRI_ERROR_TYPES status = BuildPolygonTrapeziation(NULL, //do all subpaths at once maxDimension, // path data paths, pathlens, pCoordinates, // Specify a seed for the random number generator // This isn't critcal if the processing is offline so just use 0 0, // the resulting trap structure &TrapezoidsResult); delete [] pCoordinates; if (!AnalyzeTriangulationError(status)) { FreeTriangulationModuleMemory(); return false; } int MaxFFRecursionDepth = 10000; int FillModeIsOddEven = 0; int numVertices = 0; float *pVertices = NULL; int numTriangles = 0; TriIndicesType *pTriangleIndices = NULL; numTriangles = OutputIndexedTriangles(&TrapezoidsResult, MaxFFRecursionDepth, FillModeIsOddEven, true, &numVertices, &pVertices, &pTriangleIndices); for (int i=0; i < numTriangles; i++) { TriIndicesType triangle = pTriangleIndices[i]; PVRTVertex a = { PVRTVec3(pVertices[triangle.Ind[0]*2], pVertices[triangle.Ind[0]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) }; PVRTVertex b = { PVRTVec3(pVertices[triangle.Ind[1]*2], pVertices[triangle.Ind[1]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) }; PVRTVertex c = { PVRTVec3(pVertices[triangle.Ind[2]*2], pVertices[triangle.Ind[2]*2+1], 0.0f), PVRTVec2(0.0f, 0.0f) }; const unsigned int index_start = triangle_coords.size(); triangle_coords.push_back(a); triangle_coords.push_back(b); triangle_coords.push_back(c); PVRTTriangle tri = { index_start, index_start+1, index_start+2 }; triangles.push_back(tri); } FreeTriangulationModuleMemory(); return true; }
/*!*************************************************************************** @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 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 OGLES2Iridescence::RenderScene() { // Keyboard input (cursor up/down to change thickness variation) if (PVRShellIsKeyPressed(PVRShellKeyNameUP)) { m_fMaxVariation += 1.0f; } else if (PVRShellIsKeyPressed(PVRShellKeyNameDOWN)) { m_fMaxVariation = PVRT_MAX(0.0f, m_fMaxVariation - 1.0f); } // Keyboard input (cursor left/right to change minimum thickness) if (PVRShellIsKeyPressed(PVRShellKeyNameRIGHT)) { m_fMinThickness += 1.0f; } else if (PVRShellIsKeyPressed(PVRShellKeyNameLEFT)) { m_fMinThickness = PVRT_MAX(0.0f, m_fMinThickness - 1.0f); } // Clear the color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use shader program glUseProgram(m_ShaderProgram.uiId); // Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiTexture); // Rotate and Translation the model matrix PVRTMat4 mModel; mModel = PVRTMat4::RotationY(m_fAngleY); m_fAngleY += (2*PVRT_PI/60)/7; // Set model view projection matrix PVRTMat4 mModelView, mMVP; mModelView = m_mView * mModel; mMVP = m_mProjection * mModelView; glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr()); // Set light direction in model space PVRTVec4 vLightDirModel; vLightDirModel = mModel.inverse() * PVRTVec4(1, 1, 1, 0); glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x); // Set eye position in model space PVRTVec4 vEyePosModel; vEyePosModel = mModelView.inverse() * PVRTVec4(0, 0, 0, 1); glUniform3fv(m_ShaderProgram.uiEyePosLoc, 1, &vEyePosModel.x); /* Set the iridescent shading parameters */ // Set the minimum thickness of the coating in nm glUniform1f(m_ShaderProgram.uiMinThicknessLoc, m_fMinThickness); // Set the maximum variation in thickness of the coating in nm glUniform1f(m_ShaderProgram.uiMaxVariationLoc, m_fMaxVariation); /* Now that the uniforms are set, call another function to actually draw the mesh. */ DrawMesh(0); m_Print3D.Print3D(2.0f, 10.0f, 0.75f, 0xffffffff, "Minimum Thickness:"); m_Print3D.Print3D(2.0f, 15.0f, 0.75f, 0xffffffff, "%8.0f nm", m_fMinThickness); m_Print3D.Print3D(2.0f, 20.0f, 0.75f, 0xffffffff, "Maximum Variation:"); m_Print3D.Print3D(2.0f, 25.0f, 0.75f, 0xffffffff, "%8.0f nm", m_fMaxVariation); // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools m_Print3D.DisplayDefaultTitle("Iridescence", "", ePVRTPrint3DLogoIMG); m_Print3D.Flush(); return true; }
unsigned int GLES2D_CreateTexturePVRFromPointer( int *w, int *h, const void * const pointer, GLuint * const texName ) { const void * const texPtr = NULL; const unsigned int nLoadFromLevel = 0; const void *psTextureHeader = NULL; PVR_Texture_Header* psPVRHeader = (PVR_Texture_Header*)pointer; *w = (int) psPVRHeader->dwWidth; *h = (int) psPVRHeader->dwHeight; unsigned int u32NumSurfs; // perform checks for old PVR psPVRHeader if(psPVRHeader->dwHeaderSize!=sizeof(PVR_Texture_Header)) { // Header V1 if(psPVRHeader->dwHeaderSize==PVRTEX_V1_HEADER_SIZE) { // react to old psPVRHeader: i.e. fill in numsurfs as this is missing from old header printf("PVRTTexture:PVRTLoadPartialTextureFromPointer warning: this is an old pvr" " - you can use PVRTexTool to update its header.\n"); if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) u32NumSurfs = 6; else u32NumSurfs = 1; } else { // not a pvr at all printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: not a valid pvr.\n"); return 0; } } else { // Header V2 if(psPVRHeader->dwNumSurfs<1) { // encoded with old version of PVRTexTool before zero numsurfs bug found. if(psPVRHeader->dwpfFlags & PVRTEX_CUBEMAP) u32NumSurfs = 6; else u32NumSurfs = 1; } else { u32NumSurfs = psPVRHeader->dwNumSurfs; } } GLuint textureName; GLenum textureFormat = 0; GLenum textureType = GL_RGB; int IsPVRTCSupported = 1; int IsBGRA8888Supported = 0; *texName = 0; // install warning value int IsCompressedFormatSupported = 0, IsCompressedFormat = 0; /* Only accept untwiddled data UNLESS texture format is PVRTC */ if ( ((psPVRHeader->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE) && ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC2) && ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC4) ) { // We need to load untwiddled textures -- hw will twiddle for us. printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: texture should be untwiddled.\n"); return 0; } switch(psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE) { case OGL_RGBA_4444: textureFormat = GL_UNSIGNED_SHORT_4_4_4_4; textureType = GL_RGBA; break; case OGL_RGBA_5551: textureFormat = GL_UNSIGNED_SHORT_5_5_5_1; textureType = GL_RGBA; break; case OGL_RGBA_8888: textureFormat = GL_UNSIGNED_BYTE; textureType = GL_RGBA; break; /* New OGL Specific Formats Added */ case OGL_RGB_565: textureFormat = GL_UNSIGNED_SHORT_5_6_5; textureType = GL_RGB; break; case OGL_RGB_555: printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: pixel type OGL_RGB_555 not supported.\n"); return 0; // Deal with exceptional case case OGL_RGB_888: textureFormat = GL_UNSIGNED_BYTE; textureType = GL_RGB; break; case OGL_I_8: textureFormat = GL_UNSIGNED_BYTE; textureType = GL_LUMINANCE; break; case OGL_AI_88: textureFormat = GL_UNSIGNED_BYTE; textureType = GL_LUMINANCE_ALPHA; break; case OGL_PVRTC2: if(IsPVRTCSupported) { IsCompressedFormatSupported = IsCompressedFormat = 1; textureFormat = psPVRHeader->dwAlphaBitMask==0 ? GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG ; // PVRTC2 } else { IsCompressedFormatSupported = 0; IsCompressedFormat = 1; textureFormat = GL_UNSIGNED_BYTE; textureType = GL_RGBA; printf("PVRTTexture:PVRTLoadPartialTextureFromPointer warning: PVRTC2 not supported. Converting to RGBA8888 instead.\n"); } break; case OGL_PVRTC4: if(IsPVRTCSupported) { IsCompressedFormatSupported = IsCompressedFormat = 1; textureFormat = psPVRHeader->dwAlphaBitMask==0 ? GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ; // PVRTC4 } else { IsCompressedFormatSupported = 0; IsCompressedFormat = 1; textureFormat = GL_UNSIGNED_BYTE; textureType = GL_RGBA; printf("PVRTTexture:PVRTLoadPartialTextureFromPointer warning: PVRTC4 not supported. Converting to RGBA8888 instead.\n"); } break; case OGL_BGRA_8888: if(IsBGRA8888Supported) { textureFormat = GL_UNSIGNED_BYTE; textureType = GL_BGRA; break; } else { printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: Unable to load GL_BGRA texture as extension GL_IMG_texture_format_BGRA8888 is unsupported.\n"); return 0; } default: // NOT SUPPORTED printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: pixel type not supported.\n"); return 0; } // load the texture up glPixelStorei(GL_UNPACK_ALIGNMENT,1); // Never have row-aligned in psPVRHeaders glGenTextures(1, &textureName); // check that this data is cube map data or not. if(psPVRHeader->dwpfFlags & PVRTEX_CUBEMAP) { // not in OGLES you don't printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: cube map textures are not available in OGLES1.x.\n"); return 0; } else { glBindTexture(GL_TEXTURE_2D, textureName); } if(glGetError()) { printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: glBindTexture() failed.\n"); return 0; } int i; for(i=0; i<u32NumSurfs; i++) { char *theTexturePtr = (texPtr? (char*)texPtr : (char*)psPVRHeader + psPVRHeader->dwHeaderSize) + psPVRHeader->dwTextureDataSize * i; char *theTextureToLoad = 0; int nMIPMapLevel; int nTextureLevelsNeeded = (psPVRHeader->dwpfFlags & PVRTEX_MIPMAP)? psPVRHeader->dwMipMapCount : 0; unsigned int nSizeX= psPVRHeader->dwWidth, nSizeY = psPVRHeader->dwHeight; unsigned int CompressedImageSize = 0; for(nMIPMapLevel = 0; nMIPMapLevel <= nTextureLevelsNeeded; nSizeX = PVRT_MAX(nSizeX/2, (unsigned int)1), nSizeY = PVRT_MAX(nSizeY/2, (unsigned int)1), nMIPMapLevel++) { // Do Alpha-swap if needed theTextureToLoad = theTexturePtr; // Load the Texture /* If the texture is PVRTC then use GLCompressedTexImage2D */ if(IsCompressedFormat) { /* Calculate how many bytes this MIP level occupies */ if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { CompressedImageSize = ( PVRT_MAX(nSizeX, PVRTC2_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, PVRTC2_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount + 7) / 8; } else {// PVRTC4 case CompressedImageSize = ( PVRT_MAX(nSizeX, PVRTC4_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, PVRTC4_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount + 7) / 8; } if(((signed int)nMIPMapLevel - (signed int)nLoadFromLevel) >= 0) { if(IsCompressedFormatSupported) { //if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) //{ // /* Load compressed texture data at selected MIP level */ // glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, nMIPMapLevel-nLoadFromLevel, textureFormat, nSizeX, nSizeY, 0, // CompressedImageSize, theTextureToLoad); //} //else { /* Load compressed texture data at selected MIP level */ glCompressedTexImage2D(GL_TEXTURE_2D, nMIPMapLevel-nLoadFromLevel, textureFormat, nSizeX, nSizeY, 0, CompressedImageSize, theTextureToLoad); } } else { // Convert PVRTC to 32-bit unsigned char *u8TempTexture = (unsigned char*)malloc(nSizeX*nSizeY*4); if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { printf("PVRTCDecompress Unsupported\n"); //PVRTCDecompress(theTextureToLoad, 1, nSizeX, nSizeY, u8TempTexture); } else {// PVRTC4 case printf("PVRTCDecompress Unsupported\n"); //PVRTCDecompress(theTextureToLoad, 0, nSizeX, nSizeY, u8TempTexture); } //if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) //{// Load compressed cubemap data at selected MIP level // // Upload the texture as 32-bits // glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,nMIPMapLevel-nLoadFromLevel,GL_RGBA, // nSizeX,nSizeY,0, GL_RGBA,GL_UNSIGNED_BYTE,u8TempTexture); // FREE(u8TempTexture); //} //else {// Load compressed 2D data at selected MIP level // Upload the texture as 32-bits glTexImage2D(GL_TEXTURE_2D,nMIPMapLevel-nLoadFromLevel,GL_RGBA, nSizeX,nSizeY,0, GL_RGBA,GL_UNSIGNED_BYTE,u8TempTexture); FREE(u8TempTexture); } } } } else { if(((signed int)nMIPMapLevel - (signed int)nLoadFromLevel) >= 0) { //if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) //{ // /* Load uncompressed texture data at selected MIP level */ // glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,nMIPMapLevel-nLoadFromLevel,textureType,nSizeX,nSizeY, // 0, textureType,textureFormat,theTextureToLoad); //} //else { /* Load uncompressed texture data at selected MIP level */ glTexImage2D(GL_TEXTURE_2D,nMIPMapLevel-nLoadFromLevel,textureType,nSizeX,nSizeY,0, textureType,textureFormat,theTextureToLoad); } } } if(glGetError()) { printf("PVRTTexture:PVRTLoadPartialTextureFromPointer failed: glBindTexture() failed.\n"); return 0; } // offset the texture pointer by one mip-map level /* PVRTC case */ if ( IsCompressedFormat ) { theTexturePtr += CompressedImageSize; } else { /* New formula that takes into account bit counts inferior to 8 (e.g. 1 bpp) */ theTexturePtr += (nSizeX * nSizeY * psPVRHeader->dwBitCount + 7) / 8; } } } *texName = textureName; if(psTextureHeader) { *(PVR_Texture_Header*)psTextureHeader = *psPVRHeader; ((PVR_Texture_Header*)psTextureHeader)->dwPVR = PVRTEX_IDENTIFIER; ((PVR_Texture_Header*)psTextureHeader)->dwNumSurfs = u32NumSurfs; } return psPVRHeader->dwpfFlags|0x80000000; // PVR psPVRHeader flags with topmost bit set so that it is non-zero }