bool PVRTTextureAtlas::GetTextureSpan(const std::string &szTextureName, PVRTVec2 &span) const { map<string, TexRegistrationInfo>::const_iterator iter = m_vRegistrationMap.find(szTextureName); if (iter == m_vRegistrationMap.end()) { span = PVRTVec2(0.0f, 0.0f); return false; } span = iter->second.uv_coords.span; return true; }
bool PVRTTextureAtlas::GetTextureOffset(const std::string &szTextureName, PVRTVec2 &offset) const { map<string, TexRegistrationInfo>::const_iterator iter = m_vRegistrationMap.find(szTextureName); if (iter == m_vRegistrationMap.end()) { offset = PVRTVec2(0.0f, 0.0f); return false; } offset = iter->second.uv_coords.offset; return true; }
/*!*********************************************************************** @Function BuildQuads @Access private @Returns void @Description *************************************************************************/ void Particle::BuildQuads() { // Quads require 4 vertices with Position, Colour and UVs. const PVRTMat3 mxRot = PVRTMat3::RotationZ(m_desc.m_fRotCur); const Float32 fHW = (m_pParent->m_tex->GetWidth() * 0.5f) * m_desc.m_vScale.x; const Float32 fHH = (m_pParent->m_tex->GetHeight() * 0.5f) * m_desc.m_vScale.y; const RGBA& rgba = m_desc.m_RGBA; PrimQuad* pPrim = (PrimQuad*)m_pPrimitive; static const PVRTVec2 UVs[4] = { PVRTVec2(0.0f, 0.0f), // TL PVRTVec2(0.0f, 1.0f), // BL PVRTVec2(1.0f, 0.0f), // TR PVRTVec2(1.0f, 1.0f), // BR }; static const Float32 fSigns[4*2] = { -1.0f, +1.0f, // TL -1.0f, -1.0f, // BL +1.0f, +1.0f, // TR +1.0f, -1.0f, // BR }; PrimVertex* pV = NULL; for(Uint32 i = 0; i < 4; ++i) { pV = &pPrim->vert[i]; memset(pV, 0, sizeof(PrimVertex)); pV->v.x = fHW*fSigns[i*2]; pV->v.y = fHH*fSigns[i*2+1]; pV->uv = UVs[i]; pV->rgba[0] = rgba.RedChannel(); pV->rgba[1] = rgba.GreenChannel(); pV->rgba[2] = rgba.BlueChannel(); pV->rgba[3] = rgba.AlphaChannel(); pV->v *= mxRot; pV->v += m_desc.m_vPos; } }
/*!*********************************************************************** @Function OnTouchUp @Access public @Param Touch * pTouches @Param Uint32 uiNum @Returns void @Description *************************************************************************/ void ViewGameFinished::OnTouchUp(Touch* pTouches, Uint32 uiNum) { if(m_eGUIState & enumGUISTATE_Off_Mask) return; // Scale touch to our local view coords (iPad or Retina) Float32 fCoordX = (Float32)GetScreenDimensions(false).x; Float32 fCoordY = (Float32)GetScreenDimensions(false).y; PVRTVec2 vTouchWorld((pTouches[0].fX / (Float32)GFX->GetDeviceWidth()) * fCoordX, (pTouches[0].fY / (Float32)GFX->GetDeviceHeight()) * fCoordY); PVRTVec2 vTouch = PVRTVec2(vTouchWorld.x, fCoordY - vTouchWorld.y); if(m_RectMainMenu.Contains(vTouch)) Close(); }
bool PVRTTextureAtlas::LoadAtlasDefinitionFromFile(PVRParser &parser) { unsigned int ui32Width = parser.parse_unsigned_int(); unsigned int ui32Height = parser.parse_unsigned_int(); const unsigned int numTextures = parser.parse_unsigned_int(); for (unsigned int i=0; i < numTextures; i++) { string name = parser.parse_string(); TexRegistrationInfo info; info.uv_coords.offset.x = parser.parse_float(); info.uv_coords.offset.y = parser.parse_float(); info.uv_coords.span.x = parser.parse_float(); info.uv_coords.span.y = parser.parse_float(); info.transformation = CalculateTransformation(info.uv_coords.offset, info.uv_coords.span, PVRTVec2(0.0f, 0.0f)); m_vRegistrationMap[name] = info; } return true; }
void OGLESAntialiasedLines::TessellateLine(const PVRTVec2& vPointA, const PVRTVec2& vPointB, float fWidth, GLuint uiColor, STexVertex* pVertexArray, GLushort u16StartIndex, GLushort* pu16IndexArray) { // Calculate the normalised tangent and normal for the line, // multiplied by the line width PVRTVec2 vDiff = vPointA - vPointB; PVRTVec2 vTangent = vDiff * VERTTYPEDIV(f2vt(fWidth), vDiff.length()); PVRTVec2 vNormal = vTangent.rotated90(); /* We write eight vertices to the vertex array. The rectangles (0,1,2,3) and (4,5,6,7) represent the round line caps. The rectangle (2,3,4,5) is the main line segment. -t +t 0---->2-- ... --4<----6 ^\ |\_ |\ ^ +n | \ | \ | \ | A \ | ... | \ B | \ | \_ | \ | v \| \| \v -n 1---->3-- ... --5<----7 cap line cap Note that for this example the caps are entirely between the end points (A and B in the diagram above). Even vertices are displaced along the positive normal (+n), odd vertices are displaced along the negative normal. The pairs (2, 3) and (4, 5) are shifted inwards along the line tangent. To achieve the antialiasing we use a special texture where on the U-axis there is an opaque segment from 0.25 to 0.5. We then use 0.125 as texcoord for the even vertices and 0.625 for the odd vertices. This is necessary so it still looks ok when the 4 texel wide mip level is used. Texture filtering and blending then results in smooth lines. The method breaks down when the line geometry gets less than 2 pixels wide (actual line width < 1). In this case we should clamp the line width to 1 and use the actual line width as an alpha factor, so very thin lines will smoothly fade out. texcoords: 0 1/8 5/8 1 | | | | miplevel 2: | 0 1 0 0 | miplevel 1: | 0 0 1 1 0 0 0 0 | miplevel 0: |0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0| */ pVertexArray[0].vPosition = vPointA + vNormal; pVertexArray[0].vTexcoord = PVRTVec2(f2vt(1/8.f), f2vt(0.245f)); pVertexArray[1].vPosition = vPointA - vNormal; pVertexArray[1].vTexcoord = PVRTVec2(f2vt(5/8.f), f2vt(0.245f)); pVertexArray[2].vPosition = vPointA + vNormal - vTangent; pVertexArray[2].vTexcoord = PVRTVec2(f2vt(1/8.f), f2vt(0.75f)); pVertexArray[3].vPosition = vPointA - vNormal - vTangent; pVertexArray[3].vTexcoord = PVRTVec2(f2vt(5/8.f), f2vt(0.75f)); pVertexArray[4].vPosition = vPointB + vNormal + vTangent; pVertexArray[4].vTexcoord = PVRTVec2(f2vt(1/8.f), f2vt(0.75f)); pVertexArray[5].vPosition = vPointB - vNormal + vTangent; pVertexArray[5].vTexcoord = PVRTVec2(f2vt(5/8.f), f2vt(0.75f)); pVertexArray[6].vPosition = vPointB + vNormal; pVertexArray[6].vTexcoord = PVRTVec2(f2vt(1/8.f), f2vt(0.245f)); pVertexArray[7].vPosition = vPointB - vNormal; pVertexArray[7].vTexcoord = PVRTVec2(f2vt(5/8.f), f2vt(0.245f)); // The color is constant for each line, but we write it to the vertex // array so we can render multiple lines in one draw call int i; for (i = 0; i < 8; ++i) { pVertexArray[i].uiColor = uiColor; } // Write indices to index buffer GLushort au16Indices[18] = { 0, 1, 2, 2, 1, 3, 2, 3, 4, 4, 3, 5, 4, 5, 6, 6, 5, 7 }; for (i = 0; i < 18; ++i) { pu16IndexArray[i] = au16Indices[i] + u16StartIndex; } }
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; }
// --------------------------------------------------------------- void MyPVRDemo::RenderBloom(const PVRTMat4& mxModel, const PVRTMat4& mxCam, const PVRTVec3& vLightPos) { // --- Bind an empty frame buffer. glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO[enumFB_1]); glViewport(0, 0, RTT_SIZE, RTT_SIZE); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // --- Render the statue with Bloom Stage 1 Shader. This basically renders the statue with the normal map // and uses a texture lookup to effectively high-pass filter the resultant output. glUseProgram(m_Bloom1Shader.uiID); glUniform1f(m_Bloom1Shader.uiBloomMulti, m_fBloomMulti); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_tex[enumTEXTURE_StatueNormals]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, m_tex[enumTEXTURE_BloomMap]); RenderStatue(mxModel, mxCam, vLightPos, &m_Bloom1Shader); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); // --- BLUR PASSES glUseProgram(m_BloomBlurShader.uiID); // Horizontal blur glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO[enumFB_2]); glViewport(0, 0, RTT_SIZE, RTT_SIZE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, m_uiRTT[enumFB_1]); glUniform2f(m_BloomBlurShader.uiTexelOffset, m_fTexelOffset, 0.0f); RenderScreenAlignedTexture(PVRTVec2(-1.0f, 1.0f), PVRTVec2(1.0f, -1.0f), PVRTVec2(0.0f, 1.0f), PVRTVec2(1.0f, 0.0f)); // Vertical blur glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO[enumFB_1]); glViewport(0, 0, RTT_SIZE, RTT_SIZE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, m_uiRTT[enumFB_2]); glUniform2f(m_BloomBlurShader.uiTexelOffset, 0.0f, m_fTexelOffset); RenderScreenAlignedTexture(PVRTVec2(-1.0f, 1.0f), PVRTVec2(1.0f, -1.0f), PVRTVec2(0.0f, 1.0f), PVRTVec2(1.0f, 0.0f)); // --- OVERLAY PASS glBindFramebuffer(GL_FRAMEBUFFER, m_nOrigFBO); // Done. Use the original framebuffer. glViewport(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight)); // --- Render the texture to a screen aligned quad over the original mode. NOTE: We should use scissor or bounding rect instead. glUseProgram(m_SATexShader.uiID); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); // Additive blending glBindTexture(GL_TEXTURE_2D, m_uiRTT[enumFB_1]); // This needs to be recalculated whenever either of the following change: PVRTMat4 mxMVP = m_mxProjection * m_mxCam * mxModel; PVRTVec4 vTL = mxMVP * m_bbStatueTL; PVRTVec4 vBR = mxMVP * m_bbStatueBR; vTL /= vTL.w; vBR /= vBR.w; if(m_bRotated) { float fTmp = vBR.y; // Swap coordinates around if the screen is rotated. vBR.y = vTL.y; vTL.y = fTmp; } PVRTVec2 vTTL(vTL.x * 0.5f + 0.5f, vTL.y * 0.5f + 0.5f); PVRTVec2 vTBR(vBR.x * 0.5f + 0.5f, vBR.y * 0.5f + 0.5f); RenderScreenAlignedTexture(PVRTVec2(vTL.x, vTL.y), PVRTVec2(vBR.x, vBR.y), vTTL, vTBR); glDisable(GL_BLEND); }
/*!**************************************************************************** @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 OGLES2Bloom::RenderScene() { HandleInput(); // Calculate the mask and light rotation based on the passed time static unsigned long ulPreviousTime = PVRShellGetTime(); unsigned long ulNowTime = PVRShellGetTime(); m_fRotation += PVRT_PI * (ulNowTime - ulPreviousTime) * 0.0002f; ulPreviousTime = ulNowTime; if (m_fRotation > (PVRT_PI * 2.0f)) m_fRotation -= PVRT_PI * 2.0f; // Calculate the model, view and projection matrix float fModelAngleY = m_fRotation; float fLightAngleY = -m_fRotation; PVRTMat4 mWorld = PVRTMat4::RotationY(fModelAngleY); PVRTMat4 mLight = PVRTMat4::RotationY(fLightAngleY); PVRTMat4 mView = PVRTMat4::LookAtRH(PVRTVec3(0, 0, 150), PVRTVec3(0, 0, 0), PVRTVec3(0, 1, 0)); bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); PVRTMat4 mProjection = PVRTMat4::PerspectiveFovRH(g_fCameraFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate); PVRTMat4 mMVP = mProjection * mView * mWorld; // Simple rotating directional light in model-space PVRTVec4 vMsLightPos = mWorld.inverse() * mLight * PVRTVec4(0.5f, -1, -0.5f, 0).normalize(); glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo); glClearColor(0.075f, 0.1f, 0.125f, 0.0f); glViewport(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight)); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use simple shader program to render the mask glUseProgram(m_ShaderProgram.uiId); glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.f); glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vMsLightPos.x); // Draw the mesh glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiBaseTex); DrawMesh(0); if (m_bApplyBloom) { // First render the objects which shall have the bloom effect to a texture glBindFramebuffer(GL_FRAMEBUFFER, m_uiBlurFramebufferObjects[0]); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glViewport(0, 0, m_i32TexSize, m_i32TexSize); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(m_PreBloomShaderProgram.uiId); glUniformMatrix4fv(m_PreBloomShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.f); glUniform3fv(m_PreBloomShaderProgram.uiLightDirLoc, 1, &vMsLightPos.x); glUniform1f(m_PreBloomShaderProgram.uiBloomIntensity, m_fBloomIntensity); // Draw the mesh glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiBloomMappingTexture); DrawMesh(0); if(m_bDiscard) // Was GL_EXT_discard_framebuffer supported? { //Give the drivers a hint that we don't want depth information to be stored for later. const GLenum attachment = GL_DEPTH_ATTACHMENT; m_Extensions.glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachment); } /* Blur the generated image n-times */ for (unsigned int i=0; i < m_ui32BlurPasses; i++) { /* Apply horizontal blur */ glBindFramebuffer(GL_FRAMEBUFFER, m_uiBlurFramebufferObjects[1]); glViewport(0, 0, m_i32TexSize, m_i32TexSize); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiBlurTextures[0]); // Use the shader program for the scene glUseProgram(m_BlurShaderProgram.uiId); glUniform1f(m_BlurShaderProgram.uiTexelOffsetX, m_fTexelOffset); glUniform1f(m_BlurShaderProgram.uiTexelOffsetY, 0.0f); DrawAxisAlignedQuad(PVRTVec2(-1, -1), PVRTVec2(1, 1)); //No attachments we can invalidate here, as only color was used which is necessary. /* Apply vertical blur */ glBindFramebuffer(GL_FRAMEBUFFER, m_uiBlurFramebufferObjects[0]); glViewport(0, 0, m_i32TexSize, m_i32TexSize); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiBlurTextures[1]); // Use the shader program for the scene glUseProgram(m_BlurShaderProgram.uiId); glUniform1f(m_BlurShaderProgram.uiTexelOffsetX, 0.0f); glUniform1f(m_BlurShaderProgram.uiTexelOffsetY, m_fTexelOffset); DrawAxisAlignedQuad(PVRTVec2(-1, -1), PVRTVec2(1, 1)); if(m_bDiscard) // Was GL_EXT_discard_framebuffer supported? { //Give the drivers a hint that we don't want depth information to be stored for later. const GLenum attachment = GL_DEPTH_ATTACHMENT; m_Extensions.glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachment); } } /* Draw scene with bloom */ glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo); glViewport(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight)); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiBlurTextures[0]); // Use the shader program for the scene glUseProgram(m_PostBloomShaderProgram.uiId); /* The following section will draw a quad on the screen where the post processing pixel shader shall be executed. Try to minimize the area by only drawing where the actual post processing should happen, as this is a very costly operation. */ if (PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen)) { DrawAxisAlignedQuad(PVRTVec2(-0.875f, -0.5f), PVRTVec2(0.0625f, 0.25f), PVRTVec2(0.8755f, 0.5f), PVRTVec2(0.9375f, 0.75f)); } else { DrawAxisAlignedQuad(PVRTVec2(-0.5f, -0.875f), PVRTVec2(0.25f, 0.0625f), PVRTVec2(0.5f, 0.875f), PVRTVec2(0.75f, 0.9375f)); } glDisable(GL_BLEND); } // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools m_Print3D.DisplayDefaultTitle("Bloom", NULL, ePVRTPrint3DSDKLogo); m_Print3D.Flush(); return true; }