/** * * Renders the Final Texture into the game window. * * @author Jade Abbott * @return Void. * */ void CRadialMenu::RenderFinalTextureToScreen() { assert(m_pRenderer); assert(m_iFinalTextureID != Utility::INVALID_ID); assert(m_uiVertexBufferQuadID != Utility::INVALID_ID); // Prepare the vertices on the quad for rendering. CVertexBuffer* pVertexBuffer = m_pRenderer->GetVertexBufferManager().GetVertexBuffer(m_uiVertexBufferQuadID); assert(pVertexBuffer); if (pVertexBuffer->IsVerticesDynamic()) { CVertex1TexSCSP* pVertices = reinterpret_cast<CVertex1TexSCSP*>(pVertexBuffer->GetDynamicVertices()); assert(pVertices); float fRadius = (m_uiDiameter * 0.5f) + 0.5f; // + 0.5f for rasterisation rules. pVertices[0].SetPos(m_fDrawPositionX - fRadius, m_fDrawPositionY - fRadius); pVertices[1].SetPos(m_fDrawPositionX + fRadius, m_fDrawPositionY - fRadius); pVertices[2].SetPos(m_fDrawPositionX - fRadius, m_fDrawPositionY + fRadius); pVertices[3].SetPos(m_fDrawPositionX + fRadius, m_fDrawPositionY + fRadius); pVertexBuffer->UpdateDynamicVertices(); } // Set the texture to render with. m_pRenderer->GetTextureManager().SetTexture(m_iFinalTextureID); // Render the quad. EnsureTexturedAlphaBlending(); pVertexBuffer->Render(m_pRenderer->GetDeviceManager()); }
/** * * ITS = Into Target Surface (render target). * The icons for each button are drawn into the render target surface. * * @author Jade Abbott * @return Void. * */ void CRadialMenu::DrawIconsITS() { assert(m_pRenderer); assert(m_ucNumButtons); if (m_arrButtonData) { if (m_uiVertexBufferQuadID != Utility::INVALID_ID) { CVertexBuffer* pBuffer = m_pRenderer->GetVertexBufferManager().GetVertexBuffer(m_uiVertexBufferQuadID); assert(pBuffer); if (pBuffer->IsVerticesDynamic()) { CVertex1TexSCSP* pVertices = reinterpret_cast<CVertex1TexSCSP*>(pBuffer->GetDynamicVertices()); assert(pVertices); CTextureManager& rTextureManager = m_pRenderer->GetTextureManager(); CDeviceManager& rDeviceManager = m_pRenderer->GetDeviceManager(); PrepareDeviceData(true); EnsureTexturedAlphaBlending(); rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x0); float fAngle = (2.0f * MathUtility::PI) / m_ucNumButtons; float fRadius = m_uiDiameter * 0.5f; float fHalfScale = m_uiDiameter * 0.0625f; // If diameter is 512, this equals 32 (for 64x64 images). for (unsigned char uc = 0; uc < m_ucNumButtons; ++uc) { if (m_arrButtonData[uc].m_pkReferenceData) { if (m_arrButtonData[uc].m_pkReferenceData->m_iIconTextureID != Utility::INVALID_ID) { float fDistance = m_fInnerRadius + ((fRadius - m_fInnerRadius) * 0.5f); float fPosX = fRadius + (cosf((fAngle * uc) + (fAngle * 0.5f)) * fDistance); float fPosY = fRadius - (sinf((fAngle * uc) + (fAngle * 0.5f)) * fDistance); pVertices[0].SetPos(fPosX - fHalfScale, fPosY - fHalfScale); pVertices[1].SetPos(fPosX + fHalfScale, fPosY - fHalfScale); pVertices[2].SetPos(fPosX - fHalfScale, fPosY + fHalfScale); pVertices[3].SetPos(fPosX + fHalfScale, fPosY + fHalfScale); rTextureManager.SetTexture(m_arrButtonData[uc].m_pkReferenceData->m_iIconTextureID); pBuffer->UpdateDynamicVertices(); pBuffer->Render(rDeviceManager); } } } } } } }
/** * * ITS = Into Target Surface (render target). * The radiant light surface is drawn into the render target surface, using the stencil surface for masking. * m_ucButtonSelected is then highlighted (Utility::INVALID_ID highlights the centre). * * @author Jade Abbott * @return Void. * */ void CRadialMenu::DrawRadianceITS() { assert(m_pRenderer); assert(m_uiVertexBufferQuadID != Utility::INVALID_ID); // Replace the backbuffer with the Radial Menu's render target and stencil, disabling Z-buffer and enabling stencil. PrepareDeviceData(true); CDeviceManager& rDeviceManager = m_pRenderer->GetDeviceManager(); // Set render states that will prevent drawing of the radiant light where the stencil has been marked out. rDeviceManager.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATER); // Greater is less, and less is greater (no friggin idea why). rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x2); // When less than 0x2... rDeviceManager.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); // Do not edit stencil, just draw. // Render the radiant light surface on to the back buffer. m_pRenderer->GetTextureManager().SetTexture(m_iRadiantTextureID); // Set the texture to the radiant light. CVertexBufferManager& rBufferManager = m_pRenderer->GetVertexBufferManager(); CVertexBuffer* pBuffer = rBufferManager.GetVertexBuffer(m_uiVertexBufferQuadID); // Get the dynamic quad mesh. if (pBuffer) { if (pBuffer->IsVerticesDynamic()) { // Update the position of each vertex in the mesh. CVertex1TexSCSP* pVertices = reinterpret_cast<CVertex1TexSCSP*>(pBuffer->GetDynamicVertices()); // Rasterisation rules require minimum values have 0.5 subtracted, and maximum values have 0.5 added. float fDiameter = static_cast<float>(m_uiDiameter) + 0.5f; pVertices[0].SetPos(-0.5f, -0.5f); pVertices[1].SetPos(fDiameter, -0.5f); pVertices[2].SetPos(-0.5f, fDiameter); pVertices[3].SetPos(fDiameter, fDiameter); pBuffer->UpdateDynamicVertices(); // Will update the mesh only when necessary. } rDeviceManager.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); // Have the radiant light replace the entire image. rBufferManager.Render(m_uiVertexBufferQuadID); } }
/** * * Sets up the stencil for the number of buttons provided. * Should only be called in Draw(). * Invalidates the render target surface, as redrawing with the new stencil will not overwrite all of the old image. * * @author Jade Abbott * @return Void. * */ void CRadialMenu::AssembleStencil() { assert(m_ucNumButtons); // Must be non-zero. assert(m_pLine); assert(m_pRenderer); assert(m_uiNumLineVertices >= 2); assert(m_pLineVertices); assert(m_ucFlags & FLG_RAD_REDOSTENCIL); // Should only be called when the stencil needs updating. m_ucFlags = m_ucFlags ^ FLG_RAD_REDOSTENCIL; // Turn off flag. // Set the render target, stencil surface, and render states. PrepareDeviceData(true); // Clear all surfaces, as a change in stencil requires a redraw of everything. CDeviceManager& rDeviceManager = m_pRenderer->GetDeviceManager(); rDeviceManager.DeviceClear(true, false, true, 0x00000000, 0.0f, 0); rDeviceManager.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); // Always... rDeviceManager.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); // Replace the existing stencil values. const float kfFraction((2.0f * MathUtility::PI) / (m_uiNumLineVertices - 1)); // m_uiNumVertices guaranteed >= 2, so no div/0. const float kfOuterRadius(0.5f * m_uiDiameter); // Draw lines into the stencil. if(SUCCEEDED(m_pLine->Begin())) { // Set render states so the line can draw into the stencil. rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x2); // With 0x2. // Draw shapes into stencil, beginning with the circle. for (unsigned int ui = 0; ui < m_uiNumLineVertices; ++ui) { m_pLineVertices[ui].x = kfOuterRadius + (cosf(kfFraction * ui) * m_fInnerRadius); m_pLineVertices[ui].y = kfOuterRadius + (sinf(kfFraction * ui) * m_fInnerRadius); } // Draw circle. m_pLine->Draw(m_pLineVertices, m_uiNumLineVertices, 0x00000000); // Writes 0x2 into the stencil. // Draw each dividing line, if greater than one. if (m_ucNumButtons > 1) { const float kfFraction((2.0f * MathUtility::PI) / m_ucNumButtons); // m_ucNumButtons guaranteed non-zero. for (unsigned char uc = 0; uc < m_ucNumButtons; ++uc) { m_pLineVertices[0].x = kfOuterRadius + (cosf(kfFraction * uc) * m_fInnerRadius); m_pLineVertices[0].y = kfOuterRadius + (sinf(kfFraction * uc) * m_fInnerRadius); m_pLineVertices[1].x = kfOuterRadius + (cosf(kfFraction * uc) * kfOuterRadius); m_pLineVertices[1].y = kfOuterRadius + (sinf(kfFraction * uc) * kfOuterRadius); m_pLine->Draw(m_pLineVertices, 2, 0x00000000); // Writes 0x2 into the stencil. } } // Else there is only one button, so do not draw any dividers. m_pLine->End(); } // Draw stencil'd circle in the middle. CVertexBuffer* pBuffer = m_pRenderer->GetVertexBufferManager().GetVertexBuffer(m_uiVertexBufferMaskID); if (pBuffer) { if (pBuffer->IsVerticesDynamic()) { CVertexSCSP* pVertices = reinterpret_cast<CVertexSCSP*>(pBuffer->GetDynamicVertices()); assert(pVertices); pVertices->SetPos(m_uiDiameter * 0.5f, m_uiDiameter * 0.5f); for (unsigned int ui = 1; ui < pBuffer->GetVertexBufferData().m_uiNumVerts; ++ui) { pVertices[ui].SetPos(kfOuterRadius + (cosf(kfFraction * ui) * m_fInnerRadius), kfOuterRadius + (sinf(kfFraction * ui) * m_fInnerRadius)); } rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x1); pBuffer->UpdateDynamicVertices(); pBuffer->Render(rDeviceManager); } } }
/** * * ITS = Into Target Surface (render target). * This highlights the current button selected. * * @author Jade Abbott * @return Void. * */ void CRadialMenu::DrawHighlightITS() { assert(m_pRenderer); assert(m_uiVertexBufferMaskID != Utility::INVALID_ID); // Replace the backbuffer with the Radial Menu's render target and stencil, disabling Z-buffer and enabling stencil. PrepareDeviceData(true); CDeviceManager& rDeviceManager = m_pRenderer->GetDeviceManager(); CVertexBuffer* pBuffer = m_pRenderer->GetVertexBufferManager().GetVertexBuffer(m_uiVertexBufferMaskID); assert(pBuffer); if (pBuffer->IsVerticesDynamic()) { CVertexSCSP* pVertices = reinterpret_cast<CVertexSCSP*>(pBuffer->GetDynamicVertices()); assert(pVertices); // Set render states. rDeviceManager.SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); // When equal to the value previously provided... rDeviceManager.SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); // Do not edit stencil, just draw. rDeviceManager.SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); // Allow blending. rDeviceManager.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD); // Merge colour components for a highlight effect. rDeviceManager.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_ADD); // Merge alpha components as well, so more of the button is lit. rDeviceManager.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVDESTCOLOR); // To the Radial Menu's colour (make brighter). unsigned int uiNumVerts = 0; // Used later in the for loop. float fRadius = m_uiDiameter * 0.5f; // fRadius == centre of image // Count the number of disabled buttons there are, create a highlight for each, the apply the selection highlight. for (unsigned char ucButton = 0; ucButton <= m_ucNumButtons; ++ucButton) { unsigned char ucButtonToHighlight = MathUtility::kMaxUC; if (ucButton == m_ucNumButtons) // If this is the final run... { ucButtonToHighlight = m_ucButtonSelected; // Apply highlight to the button the user has selected. rDeviceManager.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); // Blend the Radial Menu's colour... } else if (m_arrButtonData[ucButton].m_bDisabled) { ucButtonToHighlight = ucButton; // Apply highlight to the disabled button. rDeviceManager.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTALPHA); // Blend the colourless mask... } else { continue; // This button is neither disabled nor selected. } if (ucButtonToHighlight == MathUtility::kMaxUC || m_ucNumButtons == 1) { if (ucButtonToHighlight == MathUtility::kMaxUC) rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x1); // The value of the centre button. else rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x0); // The value of an ordinary button. // Highlight the entire area. uiNumVerts = 4; pVertices[0].SetPos(-0.5f, -0.5f); pVertices[1].SetPos(m_uiDiameter + 0.5f, -0.5f); pVertices[2].SetPos(m_uiDiameter + 0.5f, m_uiDiameter + 0.5f); pVertices[3].SetPos(-0.5f, m_uiDiameter + 0.5f); } else { rDeviceManager.SetRenderState(D3DRS_STENCILREF, 0x0); // The value of an ordinary button. if (m_ucNumButtons == 2) // Highlight either the top half or bottom half. { uiNumVerts = 4; float fTop = ucButtonToHighlight == 0 ? -0.5f : fRadius; float fBottom = ucButtonToHighlight == 0 ? fRadius : m_uiDiameter + 0.5f; pVertices[0].SetPos(-0.5f, fTop); pVertices[1].SetPos(m_uiDiameter + 0.5f, fTop); pVertices[2].SetPos(m_uiDiameter + 0.5f, fBottom); pVertices[3].SetPos(-0.5f, fBottom); } else // A slice of pie. { uiNumVerts = 3; float fFraction = (2.0f * MathUtility::PI) / m_ucNumButtons; // fFraction = radians per button. pVertices[0].SetPos(fRadius, fRadius); float fY = -sinf(fFraction * (ucButtonToHighlight + 1)) * m_fOuterPlanarLength; pVertices[1].SetPos(fRadius + (cosf(fFraction * (ucButtonToHighlight + 1)) * m_fOuterPlanarLength), fRadius + fY); fY = -sinf(fFraction * ucButtonToHighlight) * m_fOuterPlanarLength; pVertices[2].SetPos(fRadius + (cosf(fFraction * ucButtonToHighlight) * m_fOuterPlanarLength), fRadius + fY); } } pBuffer->UpdateDynamicVertices(uiNumVerts); pBuffer->Render(rDeviceManager, uiNumVerts); } } }