void VVirtualThumbStick::SetValidArea(const VRectanglef& validArea) { VRectanglef finalValidArea = validArea; if (!finalValidArea.IsValid()) { // default area: square (width is 50% of screen height) const float fScreenWidth = static_cast<float>(Vision::Video.GetXRes()); const float fScreenHeight = static_cast<float>(Vision::Video.GetYRes()); const float fSquareWidth = hkvMath::Min(fScreenHeight, fScreenWidth) * 0.5f; finalValidArea.Set( hkvVec2(0.0f, fScreenHeight - fSquareWidth), hkvVec2(fSquareWidth, fScreenHeight)); } // create /resize touch area if (m_spTouchArea == NULL) { IVMultiTouchInput& inputDevice = static_cast<IVMultiTouchInput&>( VInputManager::GetInputDevice(INPUT_DEVICE_TOUCHSCREEN)); VASSERT(&inputDevice != &VInputManager::s_NoInputDevice); m_spTouchArea = new VTouchArea(inputDevice, finalValidArea, -1500.0f); } else { m_spTouchArea->SetArea(finalValidArea); } m_validArea = finalValidArea; Reset(); }
void VVirtualThumbStick::Reset() { m_fXValue = 0.0f; m_fYValue = 0.0f; m_iLastTouchPointIndex = -1; // (Re)position thumb stick const VRectanglef finalValidArea = m_spTouchArea->GetArea(); // Outer ring mask const float fInitialX = finalValidArea.m_vMin.x + finalValidArea.GetSizeX() * m_fRelativeInitialX; const float fInitialY = finalValidArea.m_vMin.y + finalValidArea.GetSizeY() * m_fRelativeInitialY; m_spRingMask->GetTextureSize(m_iRingWidth, m_iRingHeight); m_spRingMask->SetPos( fInitialX - static_cast<float>(m_iRingWidth / 2), fInitialY - static_cast<float>(m_iRingHeight / 2)); // Inner circle mask m_iCircleCenterX = static_cast<int>(fInitialX); m_iCircleCenterY = static_cast<int>(fInitialY); m_spCircleMask->GetTextureSize(m_iCircleWidth, m_iCircleHeight); m_spCircleMask->SetPos( fInitialX - static_cast<float>(m_iCircleWidth / 2), fInitialY - static_cast<float>(m_iCircleHeight / 2)); }
int VRTLSupport_cl::DistanceToRightAlignment(VisFont_cl * pFont, const char * pText) { VASSERT(pFont); VRectanglef requiredSpace; pFont->GetTextDimension(pText, requiredSpace); return (int)-requiredSpace.GetSizeX(); }
void VInfoDialog::DoLayout() { const float fResX = (float)Vision::Video.GetXRes(); const float fResY = (float)Vision::Video.GetYRes(); const float fOuterBorderWidth = VUISharedData::GetOuterBorderWidth(); const hkvVec2 buttonSize = hkvVec2(fResX * 0.25f - fOuterBorderWidth * 1.5f, VUISharedData::GetIconSize()); { VRectanglef textDimensions; m_pTextLabel->Text().GetFont()->GetTextDimension(m_pTextLabel->GetText(), textDimensions); float fTextArea = textDimensions.GetArea() * m_pTextLabel->Text().GetScaling() * m_pTextLabel->Text().GetScaling(); // Estimate suitable text width based on text area float fTextWidth = hkvMath::clamp(1.4f * hkvMath::sqrt(fTextArea), fResX * 0.5f, fResX * 0.8f); // Set initial dialog size estimate SetSize(fTextWidth, fTextWidth); // Paint once without graphics to compute actual text size VTextState &state(m_pTextLabel->Text().m_States[m_pTextLabel->GetCurrentState()]); state.Paint(NULL, this, V_RGBA_WHITE); float fTextHeight = state.GetHeight() * m_pTextLabel->Text().GetScaling(); // Reinvalidate computed line wrapping etc. state.UpdateAlignment(); // Set final size float fDialogWidth = fTextWidth + fOuterBorderWidth * 2; float fDialogHeight = hkvMath::Min(fTextHeight + buttonSize.y + fOuterBorderWidth * 3, fResY * 0.8f); SetSize(fDialogWidth, fDialogHeight); } const hkvVec2 dialogSize = GetSize(); SetPosition((fResX - dialogSize.x) * 0.5f, (fResY - dialogSize.y) * 0.5f); m_pTextLabel->SetSize(dialogSize.x - fOuterBorderWidth * 2, dialogSize.y - buttonSize.y - fOuterBorderWidth * 3); m_pTextLabel->SetPosition(fOuterBorderWidth, fOuterBorderWidth); const float fOkButtonWidth = m_pCancelButton->IsVisible() ? buttonSize.x : dialogSize.x - fOuterBorderWidth * 2; m_pOKButton->SetSize(fOkButtonWidth, buttonSize.y); m_pOKButton->SetPosition(fOuterBorderWidth, dialogSize.y - buttonSize.y - fOuterBorderWidth); m_pCancelButton->SetSize(buttonSize.x, buttonSize.y); m_pCancelButton->SetPosition(fOuterBorderWidth * 2 + buttonSize.x, dialogSize.y - buttonSize.y - fOuterBorderWidth); }
void VUINodeImage::OnVariableValueChanged(VisVariable_cl *pVar, const char * value) { VASSERT (pVar); VASSERT (value); if (pVar->name && strcmp(pVar->name, "Texture") == 0) { VTextureObject* spTexture = Vision::TextureManager.Load2DTexture( value ); Image().SetTexture( spTexture ); } else if (pVar->name && strcmp(pVar->name, "m_eTransp") == 0) { sscanf(value,"%d",&m_eTransp); Image().SetTransparency(m_eTransp); } else if (pVar->name && strcmp(pVar->name, "m_eStretcheMode") == 0) { sscanf(value,"%d",&m_eStretcheMode); Image().SetStretchMode( m_eStretcheMode ); } else if (pVar->name && strcmp(pVar->name, "ShaderEffect") == 0) { // Image().SetTechnique( spTexture ); } else if (pVar->name && strcmp(pVar->name, "TextureRange") == 0) { float fComponents[4]; int iCount = sscanf(value,"%f/%f/%f/%f",&fComponents[0],&fComponents[1],&fComponents[2],&fComponents[3]); VRectanglef coord; coord.Add( hkvVec2(fComponents[0],fComponents[1])); coord.Add( hkvVec2(fComponents[2],fComponents[3])); Image().SetTextureRange( coord ); } else if (pVar->name && strcmp(pVar->name, "Color") == 0) { int iComponents[4]; int iCount = sscanf(value,"%i/%i/%i/%i",&iComponents[0],&iComponents[1],&iComponents[2],&iComponents[3]); VColorRef color(iComponents[0],iComponents[1],iComponents[2],iComponents[3]); SetColor( color ); } }
void VLogoOverlay::RefreshLayout() { if (m_spLogoOverlay == NULL) return; float fWidth = 0.0f, fHeight = 0.0f; m_spLogoOverlay->GetTargetSize(fWidth, fHeight); const VRectanglef screenExtents = GetScreenExtents(); const float fVerticalBorder = 2.0f; const float fHorizontalBorder = 18.0f; hkvVec2 vPos; // X-Coordinate if (m_eAlignment == ALIGN_TOPLEFT || m_eAlignment == ALIGN_BOTTOMLEFT) { vPos.x = screenExtents.m_vMin.x + fHorizontalBorder; } else if (m_eAlignment == ALIGN_TOPRIGHT || m_eAlignment == ALIGN_BOTTOMRIGHT) { vPos.x = screenExtents.m_vMax.x - fWidth - fHorizontalBorder; } else { vPos.x = screenExtents.m_vMin.x + (screenExtents.GetSizeX() - fWidth) * 0.5f; } // Y-Coordinate if (m_eAlignment == ALIGN_TOPLEFT || m_eAlignment == ALIGN_TOPRIGHT || m_eAlignment == ALIGN_TOP) { vPos.y = screenExtents.m_vMin.y + fVerticalBorder; } else { vPos.y = screenExtents.m_vMax.y - fHeight - fVerticalBorder; } m_spLogoOverlay->SetPos(vPos.x, vPos.y); }
wchar_t* VArabicSupport_cl::UniformToContextualLine(VisFont_cl * pArabicFont, const wchar_t * pUniformArabic, bool duplicateSpaces) { if(pUniformArabic==NULL) return NULL; //length of the current line int iLength = VArrayHelper_cl<wchar_t>::Length(pUniformArabic); //count spaces int iNumSpaces = 0; if(duplicateSpaces) { for(int i=0;i<iLength;i++) { if(pUniformArabic[i]==L' ') iNumSpaces++; } } //allocate the target buffer (original length + number of duplicates space + terminator) wchar_t *pContextualArabic = (wchar_t *) vMemAlloc(sizeof(wchar_t)*(iLength+iNumSpaces+1)); //pre-terminate buffer pContextualArabic[iLength+iNumSpaces] = 0; wchar_t wcCurLetter = pUniformArabic[0]; //start with the first letter wchar_t wcPrevLetter = 0; //init wcPrevLetter, because the assignment is done at the end of the for loop //is the current (first) letter an Arabic letter? bool bCurIsArabic = isUniformArabic(pUniformArabic[0]); bool bPrevIsArabic = false; //at the beginning the previous letter is never Arabic bool bNextIsArabic; //calculated inside the loop //transform and terminate the target buffer for(int i=0;i<iLength;i++) { //start at the right side with the first character at index 0 (because Arabic is RTL) wcCurLetter = pUniformArabic[i]; bNextIsArabic = i<(iLength-1) ? isUniformArabic(pUniformArabic[i+1]) : false; if(bCurIsArabic) { //first uniform letter is 'alif madda: 0x0622 (maps to contextual representation 0xFE81) int iIndex = wcCurLetter-0x0622; //number of iterations wchar_t wcContextual = 0xFE81; //contextual representation of 'alif madda //calculate contextual representation of current uniform representation //(count up transformation steps) for(int j=0;j<iIndex;j++) { if(s_pArabicLetterMap[j]==0) wcContextual +=2; else if(s_pArabicLetterMap[j]==1) wcContextual +=4; //else skip (-1) } //now adjust character according to the in-word position wchar_t wcCandidate = wcContextual; //we experiment with a candidate character since it's not sure that the candidate exists! //end character if( bPrevIsArabic && isInnerLetter(wcPrevLetter) && (!bNextIsArabic || isEndLetter(wcCurLetter)) ) { wcCandidate+=1; //start character } else if( bNextIsArabic && (!bPrevIsArabic || isEndLetter(wcPrevLetter)) ) { if(s_pArabicLetterMap[iIndex]!=0) wcCandidate+=2; //inner character } else if( i>0 && bPrevIsArabic && bNextIsArabic && isInnerLetter(wcPrevLetter) && isInnerLetter(wcCurLetter) ) { if(s_pArabicLetterMap[iIndex]!=0) wcCandidate+=3; } //else isolated (default) //candidate check (do we have this character in the font..?) VRectanglef requiredSpace = GetCharacterDimension(wcCandidate, pArabicFont); if(requiredSpace.GetSizeX()<=0) { wcCandidate = wcContextual; //restore from backup (because the character is missing) //just in case: fall-back to non-contextual VRectanglef requiredSpace = GetCharacterDimension(wcCandidate, pArabicFont); if(requiredSpace.GetSizeX()<=0) wcCandidate = wcCurLetter; } #ifdef HK_DEBUG_SLOW requiredSpace = GetCharacterDimension(wcCandidate, pArabicFont); VASSERT_MSG(requiredSpace.GetSizeX()>0, "Your text contains a character which is not present in your font!") #endif //candidate approved: pContextualArabic[iLength+iNumSpaces-i-1] = wcCandidate; } else { //invert directional symbols switch(wcCurLetter) { case L'(': wcCurLetter = L')'; break; case L')': wcCurLetter = L'('; break; case L'<': wcCurLetter = L'>'; break; case L'>': wcCurLetter = L'<'; break; case L'{': wcCurLetter = L'}'; break; case L'}': wcCurLetter = L'{'; break; case L'[': wcCurLetter = L']'; break; case L']': wcCurLetter = L'['; break; case L'/': wcCurLetter = L'\\'; break; case L'\\': wcCurLetter = L'/'; break; case L' ': if(duplicateSpaces) { pContextualArabic[iLength+iNumSpaces-i-1] = L' '; iNumSpaces--; } break; default: break; } pContextualArabic[iLength+iNumSpaces-i-1] = wcCurLetter; } //prepare for next loop iteration wcPrevLetter = wcCurLetter; bPrevIsArabic = bCurIsArabic; bCurIsArabic = bNextIsArabic; } return pContextualArabic; }
void VTextState::Paint(VGraphicsInfo *pGraphics, VWindowBase *pParentWnd, VColorRef iColor) { m_iNumTextLines = 0; const char *szText = GetText(); if (!m_spFont || !szText || !szText[0]) return; VSimpleRenderState_t state = VGUIManager::DefaultGUIRenderState(); if (m_fFontScaling!=1.0f) state.SetFlag(RENDERSTATEFLAG_FILTERING); VRectanglef v = pParentWnd->GetBoundingBox(); // clipping box of parent control if (m_bTextWrap) { float fMaxWidth = v.GetSizeX()/m_fFontScaling; float fLineHeight = m_spFont->GetFontHeight() * m_fRelativeFontHeight * m_fFontScaling; hkvVec2 vPos = v.m_vMin; const char *szStart = szText; VMemoryTempBuffer<512> tmpBuffer; while (szStart[0]) { // byte offsets int iOffset; int iNextOffset; // search for next newline const char *pCR = strchr(szStart, '\n'); // compute automatic wrap character index int iCharCount = m_spFont->GetCharacterIndexAtPos(szStart, fMaxWidth, -1, false); int iWrapOffset = VString::GetUTF8CharacterOffset(szStart, iCharCount); if (pCR != NULL && (pCR - szStart) < iCharCount) { // newline occurs before automatic text wrap iOffset = static_cast<int>(pCR - szStart); iNextOffset = iOffset + 1; } else { // automatic text wrap iOffset = iWrapOffset; // try to find white space if (iOffset > 0) { while (iOffset > 0 && szStart[iOffset] != 0 && szStart[iOffset] != ' ') iOffset--; if (iOffset == 0) // no whitespace found? then wrap inside word iOffset = iWrapOffset; } else iOffset = 1; iNextOffset = iOffset; } // put together line const int iLineBufferSize = (iOffset+1) * sizeof(char); tmpBuffer.EnsureCapacity(iLineBufferSize); char *szLineBuffer = static_cast<char*>(tmpBuffer.GetBuffer()); memcpy(szLineBuffer, szStart, iLineBufferSize); szLineBuffer[iOffset] = 0; m_iNumTextLines++; // draw line if (pGraphics) { hkvVec2 vAlignedPos = m_spFont->GetTextPositionOfs(szLineBuffer, v.GetSize(), m_hAlign, m_vAlign) * m_fFontScaling; vAlignedPos.set(vAlignedPos.x + vPos.x, vPos.y); // only consider the x-ofs m_spFont->PrintText(&pGraphics->Renderer, vAlignedPos, szLineBuffer, iColor, state, m_fFontScaling, m_pCustomBBox ? m_pCustomBBox : &v); } vPos.y += fLineHeight; szStart = &szStart[iNextOffset]; while (szStart[0] == ' ') szStart++; } return; } // recompute the alignment offset if (!m_bAlignmentValid) { m_vCurrentOfs = m_vOfs + m_spFont->GetTextPositionOfs(szText, v.GetSize(), m_hAlign,m_vAlign) * m_fFontScaling; m_bAlignmentValid = true; } m_iNumTextLines = 1; if (pGraphics) { m_spFont->PrintText(&pGraphics->Renderer, v.m_vMin+m_vCurrentOfs, szText, iColor, state, m_fFontScaling, m_pCustomBBox ? m_pCustomBBox : &v); } }
// TODO: This doesn't handle opaque fullbright surfaces correctly yet, and translucent fullbright surfaces are simply ignored. void MirrorRenderLoop_cl::OnDoRenderLoop(void *pUserData) { INSERT_PERF_MARKER_SCOPE("MirrorRenderLoop_cl::OnDoRenderLoop"); #if defined (WIN32) || defined (_VISION_XENON) || defined (_VISION_PS3) || defined(_VISION_PSP2) || defined(_VISION_WIIU) if (Vision::Editor.GetIgnoreAdvancedEffects()) { // force a black reflection because it won't work with orthographic views Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, V_RGBA_BLACK); return; } #endif VisRenderContext_cl *pContext = Vision::Contexts.GetCurrentContext(); const int iRenderFlags = pContext->GetRenderFlags(); const float fFarClipDist = m_pMirror->GetActualFarClipDistance(); const VFogParameters &fog = Vision::World.GetFogParameters(); VColorRef clearColor = (fog.depthMode != VFogParameters::Off) ? fog.iDepthColor : Vision::Renderer.GetDefaultClearColor(); Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, clearColor); // set the oblique clipping plane... pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ()); const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesPrimaryOpaquePass; const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesSecondaryOpaquePass; const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesTransparentPass; const VisEntityCollection_cl *pVisEntities; // === Visibility Determination === IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisColl == NULL) return; const VisVisibilityObjectCollection_cl *pVisObjectCollection = pVisColl->GetVisibleVisObjects(); hkvAlignedBBox box; int iVoCount = m_pMirror->GetVisibilityObjectCount(); int iFrustumCount = 0; bool bUseCommonFrustum = false; // === Determine Scissor Rect === hkvVec2 vMinScreenSpace, vMaxScreenSpace; const hkvAlignedBBox &worldSpaceBox = m_pMirror->GetBoundingBox(); hkvVec3 vCorners[8]; worldSpaceBox.getCorners (vCorners); VRectanglef scissorRect; bool bUseScissorRect = true; for (int i=0; i<8; i++) { float x2d, y2d; BOOL bInFrontOfCamera = pContext->Project2D(vCorners[i], x2d, y2d); if (bInFrontOfCamera) { scissorRect.Add(hkvVec2(x2d, y2d)); } else { bUseScissorRect = false; break; } } if (bUseScissorRect) Vision::RenderLoopHelper.SetScissorRect(&scissorRect); for (int iVo = 0; iVo < iVoCount; iVo++) { VisVisibilityObject_cl *pVisObj = m_pMirror->GetVisibilityObject(iVo); if (pVisObj != NULL && pVisObj->WasVisibleInAnyLastFrame()) { if (iFrustumCount <= MAX_SEPARATE_FRUSTA) { const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox(); box.expandToInclude(voBox); if (m_Frustum[iFrustumCount].Set(pContext->GetCamera()->GetPosition(), voBox, true, fFarClipDist)) { iFrustumCount++; } else { bUseCommonFrustum = true; } } else { const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox(); box.expandToInclude(voBox); bUseCommonFrustum = true; } } } if (bUseCommonFrustum) { iFrustumCount = 1; if (!m_Frustum[0].Set(pContext->GetCamera()->GetPosition(), box, true, fFarClipDist)) iFrustumCount = 0; } if (iFrustumCount>0) { for (int i=0; i<iFrustumCount; i++) { m_visiblePrimaryOpaquePassGeoInstances.Clear(); m_visibleSecondaryOpaquePassGeoInstances.Clear(); m_visibleTransparentOpaquePassGeoInstances.Clear(); m_visEntities.Clear(); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visiblePrimaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleSecondaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleTransparentOpaquePassGeoInstances); pVisColl->GetVisibleEntities()->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visEntities); if (iFrustumCount == 1) break; m_visiblePrimaryOpaquePassGeoInstances.TagEntries(); m_visibleSecondaryOpaquePassGeoInstances.TagEntries(); m_visibleTransparentOpaquePassGeoInstances.TagEntries(); m_visEntities.TagEntries(); } if (iFrustumCount > 1) { m_visiblePrimaryOpaquePassGeoInstances.Clear(); m_visibleSecondaryOpaquePassGeoInstances.Clear(); m_visibleTransparentOpaquePassGeoInstances.Clear(); m_visEntities.Clear(); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->GetTaggedEntries(m_visiblePrimaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->GetTaggedEntries(m_visibleSecondaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->GetTaggedEntries(m_visibleTransparentOpaquePassGeoInstances); pVisColl->GetVisibleEntities()->GetTaggedEntries(m_visEntities); } pVisibleGeoInstancesPrimaryOpaquePass = &m_visiblePrimaryOpaquePassGeoInstances; pVisibleGeoInstancesSecondaryOpaquePass = &m_visibleSecondaryOpaquePassGeoInstances; pVisibleGeoInstancesTransparentPass = &m_visibleTransparentOpaquePassGeoInstances; pVisEntities = &m_visEntities; } else { pVisibleGeoInstancesPrimaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass); pVisibleGeoInstancesSecondaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass); pVisibleGeoInstancesTransparentPass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass); pVisEntities = pVisColl->GetVisibleEntities(); } // === End Visibility Determination === if (m_pMirror->GetExecuteRenderHooks()) { VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); } // Render opaque static geometry VASSERT(m_spDefaultLightMapping->m_Shaders.Count()==1); TRIGGER_MIRROR_HOOK(VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY) VisMirror_cl::VReflectionShaderSets_e shaderMode = m_pMirror->m_eReflectionShaderMode; DrawStaticGeometry(*pVisibleGeoInstancesPrimaryOpaquePass, VPT_PrimaryOpaquePass); DrawStaticGeometry(*pVisibleGeoInstancesSecondaryOpaquePass, VPT_SecondaryOpaquePass); // Render entities const VisEntityCollection_cl *pEntities = pVisEntities; int iCount = pEntities->GetNumEntries(); VASSERT(m_spDefaultLightGrid->m_Shaders.Count()==1); //VCompiledShaderPass *pLightgridShader = m_spDefaultLightGrid->m_Shaders.GetAt(0); int i; //bool bUseSimpleShader = shaderMode==VisMirror_cl::AlwaysSimple; Vision::RenderLoopHelper.BeginEntityRendering(); for (i=0;i<iCount;i++) { VisBaseEntity_cl *pEnt = pEntities->GetEntry(i); // Vision::RenderLoopHelper.TrackLightGridInfo(pEnt); // important: need to be done in RenderEntityWithSurfaceShaderList //if (bUseSimpleShader) //{ // Vision::RenderLoopHelper.RenderEntityWithShaders(pEnt,1,&pLightgridShader); //} //else { VisDrawCallInfo_t surfaceShaderList[RLP_MAX_ENTITY_SURFACES]; VDynamicMesh *pMesh = pEnt->GetMesh(); VisSurface_cl **ppSurfaces = pEnt->GetSurfaceArray(); int iNumSubmeshes = pMesh->GetSubmeshCount(); for (int j=0; j<iNumSubmeshes; j++) { VisDrawCallInfo_t &info(surfaceShaderList[j]); VBaseSubmesh* pSubmesh = pMesh->GetSubmesh(j); VisSurface_cl* pSurface = ppSurfaces[pSubmesh->m_iMaterialIndex]; info.Set(pSubmesh, pSurface, GetMirrorShader (pSurface, shaderMode)); } Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEnt, iNumSubmeshes, surfaceShaderList); } } Vision::RenderLoopHelper.EndEntityRendering(); // Render Sky if (VSky::IsVisible()) { // The sky has to be rendered without oblique clipping pContext->SetCustomProjectionMatrix(NULL); Vision::RenderLoopHelper.RenderSky(); // set the oblique clipping plane after sky... pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ()); } if (m_pMirror->GetExecuteRenderHooks()) { VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_OCCLUSION_TESTS); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); } // Render Coronas / Lens Flares VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_CORONAS_AND_FLARES); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); TRIGGER_MIRROR_HOOK(VRH_PRE_OCCLUSION_TESTS) if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_OCCLUSIONQUERY) Vision::RenderLoopHelper.PerformHardwareOcclusionQuery(); if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) Vision::RenderLoopHelper.PerformHardwarePixelCounterQuery(); DrawDynamicLight(); TRIGGER_MIRROR_HOOK(VRH_DECALS) TRIGGER_MIRROR_HOOK(VRH_CORONAS_AND_FLARES) TRIGGER_MIRROR_HOOK(VRH_PRE_TRANSPARENT_PASS_GEOMETRY) DrawStaticGeometry(*pVisibleGeoInstancesTransparentPass, VPT_TransparentPass); TRIGGER_MIRROR_HOOK(VRH_POST_TRANSPARENT_PASS_GEOMETRY) if (bUseScissorRect) Vision::RenderLoopHelper.SetScissorRect(NULL); }
void VTextState::Paint(VGraphicsInfo *pGraphics, VWindowBase *pParentWnd, VColorRef iColor) { const char *szText = GetText(); if (!m_spFont || !szText || !szText[0]) return; VRectanglef vParentRect = pParentWnd->GetClientRect(); // clipping box of parent control if(!m_bCachedLinesValid) { m_lines.Reset(); m_lineOffsets.Reset(); float fLineHeight = m_spFont->GetFontHeight() * m_fRelativeFontHeight * m_fFontScaling; if(!m_bTextWrap) { const char* szCurrentLine = szText; for (const char* szPtr = szCurrentLine; *szPtr != '\0'; ++szPtr) { if (*szPtr == '\n') { VStaticString<512> line; line.Set(szCurrentLine, static_cast<int>(szPtr - szCurrentLine)); m_lines.Add(line.AsChar()); szCurrentLine = szPtr + 1; } } // Add the last line if(*szCurrentLine) { m_lines.Add(szCurrentLine); } } else { float fMaxLineWidth = vParentRect.GetSizeX() / m_fFontScaling; // Wrap text into individual lines { const char *szCurrentLine = szText; while (*szCurrentLine) { // byte offsets int iByteOffsetAtWrapPosition; int iByteOffsetAfterWrapPosition; // search for next newline const char *pNextNewLine = strchr(szCurrentLine, '\n'); // compute automatic wrap character index int iCharCount = m_spFont->GetCharacterIndexAtPos(szCurrentLine, fMaxLineWidth, -1, false); int iWrapOffset = VString::GetUTF8CharacterOffset(szCurrentLine, iCharCount); if (pNextNewLine != NULL && (pNextNewLine - szCurrentLine) <= iWrapOffset) { // newline occurs before automatic text wrap iByteOffsetAtWrapPosition = static_cast<int>(pNextNewLine - szCurrentLine); iByteOffsetAfterWrapPosition = iByteOffsetAtWrapPosition + 1; } else if(strlen(szCurrentLine) <= iWrapOffset) { // End of text occurs before automatic text wrap iByteOffsetAtWrapPosition = static_cast<int>(strlen(szCurrentLine)); iByteOffsetAfterWrapPosition = iByteOffsetAtWrapPosition; } else { // automatic text wrap iByteOffsetAtWrapPosition = iWrapOffset; if (iByteOffsetAtWrapPosition > 0) { // Go backwards and try to find white space while (iByteOffsetAtWrapPosition > 0 && !IsWhiteSpace(szCurrentLine[iByteOffsetAtWrapPosition])) { iByteOffsetAtWrapPosition--; } // no whitespace found? then wrap inside word if (iByteOffsetAtWrapPosition == 0) { iByteOffsetAtWrapPosition = iWrapOffset; } else { // Find end of next word int iEndOfWord = iByteOffsetAtWrapPosition + 1; while(szCurrentLine[iEndOfWord] && !IsWhiteSpace(szCurrentLine[iEndOfWord])) { iEndOfWord++; } // If the word does not fit into a line by itself, it will be wrapped anyway, so wrap it early to avoid ragged looking line endings VRectanglef nextWordSize; m_spFont->GetTextDimension(szCurrentLine + iByteOffsetAtWrapPosition, nextWordSize, iEndOfWord - iByteOffsetAtWrapPosition); if(nextWordSize.GetSizeX() > fMaxLineWidth) { iByteOffsetAtWrapPosition = iWrapOffset; } } } else { // First character is already wider than the line iByteOffsetAtWrapPosition = VString::GetUTF8CharacterOffset(szCurrentLine, 1); } iByteOffsetAfterWrapPosition = iByteOffsetAtWrapPosition; } // put together line VStaticString<512> line; line.Set(szCurrentLine, iByteOffsetAtWrapPosition); m_lines.Add(line.AsChar()); szCurrentLine = &szCurrentLine[iByteOffsetAfterWrapPosition]; while(*szCurrentLine == ' ') szCurrentLine++; } } } // Compute offset for each line for(int iLineIdx = 0; iLineIdx < m_lines.GetLength(); iLineIdx++) { hkvVec2 offset = m_vOffset; offset.x += m_spFont->GetTextPositionOfs(m_lines[iLineIdx], vParentRect.GetSize(), m_hAlign, m_vAlign, m_fFontScaling).x; offset.y += iLineIdx * fLineHeight; if (m_vAlign == VisFont_cl::ALIGN_CENTER) { offset.y += (vParentRect.GetSizeY() - fLineHeight * m_lines.GetSize()) * 0.5f; } else if (m_vAlign == VisFont_cl::ALIGN_BOTTOM) { offset.y += (vParentRect.GetSizeY() - fLineHeight * m_lines.GetSize()); } m_lineOffsets.Add(offset); } m_bCachedLinesValid = true; } // Render lines if (pGraphics) { VSimpleRenderState_t state = VGUIManager::DefaultGUIRenderState(); if (m_fFontScaling!=1.0f) state.SetFlag(RENDERSTATEFLAG_FILTERING); for(int iLineIdx = 0; iLineIdx < m_lines.GetLength(); iLineIdx++) { m_spFont->PrintText(&pGraphics->Renderer, vParentRect.m_vMin + m_lineOffsets[iLineIdx], m_lines[iLineIdx], iColor, state, m_fFontScaling, m_pCustomBBox ? m_pCustomBBox : &vParentRect); } } }
/// \brief Query if the touch is in the given area. /// /// \param area The area to test. /// /// \return true if in area, false if not. /// inline bool IsInArea(const VRectanglef& area) const { return area.IsInside(fXAbsolute, fYAbsolute); }